ia64/xen-unstable

view xen/arch/ia64/xen/hypercall.c @ 9971:ada6dba78b6e

[IA64] xen: hypercall no clean up

use __HYERCALL_arch_0 for dom0vp hypercall.

Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
author awilliam@xenbuild.aw
date Tue May 09 11:33:29 2006 -0600 (2006-05-09)
parents d7e6e5f29226
children 9de9ad0685bf
line source
1 /*
2 * Hypercall implementations
3 *
4 * Copyright (C) 2005 Hewlett-Packard Co.
5 * Dan Magenheimer (dan.magenheimer@hp.com)
6 *
7 */
9 #include <xen/config.h>
10 #include <xen/sched.h>
11 #include <xen/hypercall.h>
12 #include <xen/multicall.h>
13 #include <xen/guest_access.h>
15 #include <linux/efi.h> /* FOR EFI_UNIMPLEMENTED */
16 #include <asm/sal.h> /* FOR struct ia64_sal_retval */
18 #include <asm/vcpu.h>
19 #include <asm/dom_fw.h>
20 #include <public/dom0_ops.h>
21 #include <public/event_channel.h>
22 #include <public/memory.h>
23 #include <public/sched.h>
24 #include <xen/irq.h>
25 #include <asm/hw_irq.h>
26 #include <public/physdev.h>
27 #include <xen/domain.h>
29 extern unsigned long translate_domain_mpaddr(unsigned long);
30 static long do_physdev_op_compat(XEN_GUEST_HANDLE(physdev_op_t) uop);
31 static long do_physdev_op(int cmd, XEN_GUEST_HANDLE(void) arg);
32 /* FIXME: where these declarations should be there ? */
33 extern int dump_privop_counts_to_user(char *, int);
34 extern int zero_privop_counts_to_user(char *, int);
36 unsigned long idle_when_pending = 0;
37 unsigned long pal_halt_light_count = 0;
39 hypercall_t ia64_hypercall_table[] =
40 {
41 (hypercall_t)do_ni_hypercall, /* do_set_trap_table */ /* 0 */
42 (hypercall_t)do_ni_hypercall, /* do_mmu_update */
43 (hypercall_t)do_ni_hypercall, /* do_set_gdt */
44 (hypercall_t)do_ni_hypercall, /* do_stack_switch */
45 (hypercall_t)do_ni_hypercall, /* do_set_callbacks */
46 (hypercall_t)do_ni_hypercall, /* do_fpu_taskswitch */ /* 5 */
47 (hypercall_t)do_sched_op_compat,
48 (hypercall_t)do_dom0_op,
49 (hypercall_t)do_ni_hypercall, /* do_set_debugreg */
50 (hypercall_t)do_ni_hypercall, /* do_get_debugreg */
51 (hypercall_t)do_ni_hypercall, /* do_update_descriptor */ /* 10 */
52 (hypercall_t)do_ni_hypercall, /* do_ni_hypercall */
53 (hypercall_t)do_memory_op,
54 (hypercall_t)do_multicall,
55 (hypercall_t)do_ni_hypercall, /* do_update_va_mapping */
56 (hypercall_t)do_ni_hypercall, /* do_set_timer_op */ /* 15 */
57 (hypercall_t)do_event_channel_op_compat,
58 (hypercall_t)do_xen_version,
59 (hypercall_t)do_console_io,
60 (hypercall_t)do_physdev_op_compat,
61 (hypercall_t)do_grant_table_op, /* 20 */
62 (hypercall_t)do_ni_hypercall, /* do_vm_assist */
63 (hypercall_t)do_ni_hypercall, /* do_update_va_mapping_otherdomain */
64 (hypercall_t)do_ni_hypercall, /* (x86 only) */
65 (hypercall_t)do_ni_hypercall, /* do_vcpu_op */
66 (hypercall_t)do_ni_hypercall, /* (x86_64 only) */ /* 25 */
67 (hypercall_t)do_ni_hypercall, /* do_mmuext_op */
68 (hypercall_t)do_ni_hypercall, /* do_acm_op */
69 (hypercall_t)do_ni_hypercall, /* do_nmi_op */
70 (hypercall_t)do_sched_op,
71 (hypercall_t)do_ni_hypercall, /* */ /* 30 */
72 (hypercall_t)do_ni_hypercall, /* */
73 (hypercall_t)do_event_channel_op,
74 (hypercall_t)do_physdev_op,
75 (hypercall_t)do_ni_hypercall, /* */
76 (hypercall_t)do_ni_hypercall, /* */ /* 35 */
77 (hypercall_t)do_ni_hypercall, /* */
78 (hypercall_t)do_ni_hypercall, /* */
79 (hypercall_t)do_ni_hypercall, /* */
80 (hypercall_t)do_ni_hypercall, /* */
81 (hypercall_t)do_ni_hypercall, /* */ /* 40 */
82 (hypercall_t)do_ni_hypercall, /* */
83 (hypercall_t)do_ni_hypercall, /* */
84 (hypercall_t)do_ni_hypercall, /* */
85 (hypercall_t)do_ni_hypercall, /* */
86 (hypercall_t)do_ni_hypercall, /* */ /* 45 */
87 (hypercall_t)do_ni_hypercall, /* */
88 (hypercall_t)do_ni_hypercall, /* */
89 #ifdef CONFIG_XEN_IA64_DOM0_VP
90 (hypercall_t)do_dom0vp_op, /* dom0vp_op */
91 #else
92 (hypercall_t)do_ni_hypercall, /* arch_0 */
93 #endif
94 (hypercall_t)do_ni_hypercall, /* arch_1 */
95 (hypercall_t)do_ni_hypercall, /* arch_2 */ /* 50 */
96 (hypercall_t)do_ni_hypercall, /* arch_3 */
97 (hypercall_t)do_ni_hypercall, /* arch_4 */
98 (hypercall_t)do_ni_hypercall, /* arch_5 */
99 (hypercall_t)do_ni_hypercall, /* arch_6 */
100 (hypercall_t)do_ni_hypercall /* arch_7 */ /* 55 */
101 };
103 uint32_t nr_hypercalls =
104 sizeof(ia64_hypercall_table) / sizeof(hypercall_t);
106 static int
107 xen_hypercall (struct pt_regs *regs)
108 {
109 uint32_t cmd = (uint32_t)regs->r2;
111 if (cmd < nr_hypercalls)
112 regs->r8 = (*ia64_hypercall_table[cmd])(
113 regs->r14,
114 regs->r15,
115 regs->r16,
116 regs->r17,
117 regs->r18,
118 regs->r19);
119 else
120 regs->r8 = -ENOSYS;
122 return 1;
123 }
126 static void
127 fw_hypercall_ipi (struct pt_regs *regs)
128 {
129 int cpu = regs->r14;
130 int vector = regs->r15;
131 struct vcpu *targ;
133 if (0 && vector == 254)
134 printf ("send_ipi from %d to %d vector=%d\n",
135 current->vcpu_id, cpu, vector);
137 if (cpu > MAX_VIRT_CPUS)
138 return;
140 targ = current->domain->vcpu[cpu];
141 if (targ == NULL)
142 return;
144 if (vector == XEN_SAL_BOOT_RENDEZ_VEC
145 && !test_bit(_VCPUF_initialised, &targ->vcpu_flags)) {
146 struct pt_regs *targ_regs = vcpu_regs (targ);
147 struct vcpu_guest_context c;
149 printf ("arch_boot_vcpu: %p %p\n",
150 (void *)targ_regs->cr_iip,
151 (void *)targ_regs->r1);
152 memset (&c, 0, sizeof (c));
153 /* Copy regs. */
154 c.regs.cr_iip = targ_regs->cr_iip;
155 c.regs.r1 = targ_regs->r1;
157 /* Copy from vcpu 0. */
158 c.vcpu.evtchn_vector =
159 current->domain->vcpu[0]->vcpu_info->arch.evtchn_vector;
160 if (arch_set_info_guest (targ, &c) != 0) {
161 printf ("arch_boot_vcpu: failure\n");
162 return;
163 }
164 if (test_and_clear_bit(_VCPUF_down,
165 &targ->vcpu_flags)) {
166 vcpu_wake(targ);
167 printf ("arch_boot_vcpu: vcpu %d awaken %016lx!\n",
168 targ->vcpu_id, targ_regs->cr_iip);
169 }
170 else
171 printf ("arch_boot_vcpu: huu, already awaken!");
172 }
173 else {
174 int running = test_bit(_VCPUF_running,
175 &targ->vcpu_flags);
177 vcpu_pend_interrupt(targ, vector);
178 vcpu_unblock(targ);
179 if (running)
180 smp_send_event_check_cpu(targ->processor);
181 }
182 return;
183 }
185 static int
186 fw_hypercall (struct pt_regs *regs)
187 {
188 struct vcpu *v = current;
189 struct sal_ret_values x;
190 unsigned long *tv, *tc;
192 switch (regs->r2) {
193 case FW_HYPERCALL_PAL_CALL:
194 //printf("*** PAL hypercall: index=%d\n",regs->r28);
195 //FIXME: This should call a C routine
196 #if 0
197 // This is very conservative, but avoids a possible
198 // (and deadly) freeze in paravirtualized domains due
199 // to a yet-to-be-found bug where pending_interruption
200 // is zero when it shouldn't be. Since PAL is called
201 // in the idle loop, this should resolve it
202 VCPU(v,pending_interruption) = 1;
203 #endif
204 if (regs->r28 == PAL_HALT_LIGHT) {
205 int pi;
206 #define SPURIOUS_VECTOR 15
207 pi = vcpu_check_pending_interrupts(v);
208 if (pi != SPURIOUS_VECTOR) {
209 if (!VCPU(v,pending_interruption))
210 idle_when_pending++;
211 vcpu_pend_unspecified_interrupt(v);
212 //printf("idle w/int#%d pending!\n",pi);
213 //this shouldn't happen, but it apparently does quite a bit! so don't
214 //allow it to happen... i.e. if a domain has an interrupt pending and
215 //it tries to halt itself because it thinks it is idle, just return here
216 //as deliver_pending_interrupt is called on the way out and will deliver it
217 }
218 else {
219 pal_halt_light_count++;
220 do_sched_op_compat(SCHEDOP_yield, 0);
221 }
222 regs->r8 = 0;
223 regs->r9 = 0;
224 regs->r10 = 0;
225 regs->r11 = 0;
226 }
227 else {
228 struct ia64_pal_retval y;
230 if (regs->r28 >= PAL_COPY_PAL)
231 y = xen_pal_emulator
232 (regs->r28, vcpu_get_gr (v, 33),
233 vcpu_get_gr (v, 34),
234 vcpu_get_gr (v, 35));
235 else
236 y = xen_pal_emulator(regs->r28,regs->r29,
237 regs->r30,regs->r31);
238 regs->r8 = y.status; regs->r9 = y.v0;
239 regs->r10 = y.v1; regs->r11 = y.v2;
240 }
241 break;
242 case FW_HYPERCALL_SAL_CALL:
243 x = sal_emulator(vcpu_get_gr(v,32),vcpu_get_gr(v,33),
244 vcpu_get_gr(v,34),vcpu_get_gr(v,35),
245 vcpu_get_gr(v,36),vcpu_get_gr(v,37),
246 vcpu_get_gr(v,38),vcpu_get_gr(v,39));
247 regs->r8 = x.r8; regs->r9 = x.r9;
248 regs->r10 = x.r10; regs->r11 = x.r11;
249 break;
250 case FW_HYPERCALL_EFI_RESET_SYSTEM:
251 printf("efi.reset_system called ");
252 if (current->domain == dom0) {
253 printf("(by dom0)\n ");
254 (*efi.reset_system)(EFI_RESET_WARM,0,0,NULL);
255 }
256 else
257 domain_shutdown (current->domain, SHUTDOWN_reboot);
258 regs->r8 = EFI_UNSUPPORTED;
259 break;
260 case FW_HYPERCALL_EFI_GET_TIME:
261 tv = (unsigned long *) vcpu_get_gr(v,32);
262 tc = (unsigned long *) vcpu_get_gr(v,33);
263 //printf("efi_get_time(%p,%p) called...",tv,tc);
264 tv = (unsigned long *) __va(translate_domain_mpaddr((unsigned long) tv));
265 if (tc) tc = (unsigned long *) __va(translate_domain_mpaddr((unsigned long) tc));
266 regs->r8 = (*efi.get_time)((efi_time_t *) tv, (efi_time_cap_t *) tc);
267 //printf("and returns %lx\n",regs->r8);
268 break;
269 case FW_HYPERCALL_EFI_SET_TIME:
270 case FW_HYPERCALL_EFI_GET_WAKEUP_TIME:
271 case FW_HYPERCALL_EFI_SET_WAKEUP_TIME:
272 // FIXME: need fixes in efi.h from 2.6.9
273 case FW_HYPERCALL_EFI_SET_VIRTUAL_ADDRESS_MAP:
274 // FIXME: WARNING!! IF THIS EVER GETS IMPLEMENTED
275 // SOME OF THE OTHER EFI EMULATIONS WILL CHANGE AS
276 // POINTER ARGUMENTS WILL BE VIRTUAL!!
277 case FW_HYPERCALL_EFI_GET_VARIABLE:
278 // FIXME: need fixes in efi.h from 2.6.9
279 case FW_HYPERCALL_EFI_GET_NEXT_VARIABLE:
280 case FW_HYPERCALL_EFI_SET_VARIABLE:
281 case FW_HYPERCALL_EFI_GET_NEXT_HIGH_MONO_COUNT:
282 // FIXME: need fixes in efi.h from 2.6.9
283 regs->r8 = EFI_UNSUPPORTED;
284 break;
285 case FW_HYPERCALL_IPI:
286 fw_hypercall_ipi (regs);
287 break;
288 default:
289 printf("unknown ia64 fw hypercall %lx\n", regs->r2);
290 regs->r8 = do_ni_hypercall();
291 }
292 return 1;
293 }
295 /* opt_unsafe_hypercall: If true, unsafe debugging hypercalls are allowed.
296 These can create security hole. */
297 static int opt_unsafe_hypercall = 0;
298 boolean_param("unsafe_hypercall", opt_unsafe_hypercall);
300 int
301 ia64_hypercall (struct pt_regs *regs)
302 {
303 struct vcpu *v = current;
304 unsigned long index = regs->r2;
305 int privlvl = (regs->cr_ipsr & IA64_PSR_CPL) >> IA64_PSR_CPL0_BIT;
307 if (index >= FW_HYPERCALL_FIRST_USER) {
308 /* Note: user hypercalls are not safe, since Xen doesn't
309 check memory access privilege: Xen does not deny reading
310 or writing to kernel memory. */
311 if (!opt_unsafe_hypercall) {
312 printf("user xen/ia64 hypercalls disabled\n");
313 regs->r8 = -1;
314 }
315 else switch (index) {
316 case 0xffff:
317 regs->r8 = dump_privop_counts_to_user(
318 (char *) vcpu_get_gr(v,32),
319 (int) vcpu_get_gr(v,33));
320 break;
321 case 0xfffe:
322 regs->r8 = zero_privop_counts_to_user(
323 (char *) vcpu_get_gr(v,32),
324 (int) vcpu_get_gr(v,33));
325 break;
326 default:
327 printf("unknown user xen/ia64 hypercall %lx\n", index);
328 regs->r8 = do_ni_hypercall();
329 }
330 return 1;
331 }
333 /* Hypercalls are only allowed by kernel.
334 Kernel checks memory accesses. */
335 if (privlvl != 2) {
336 /* FIXME: Return a better error value ?
337 Reflection ? Illegal operation ? */
338 regs->r8 = -1;
339 return 1;
340 }
342 if (index >= FW_HYPERCALL_FIRST_ARCH)
343 return fw_hypercall (regs);
344 else
345 return xen_hypercall (regs);
346 }
348 /* Need make this function common */
349 extern int
350 iosapic_guest_read(
351 unsigned long physbase, unsigned int reg, u32 *pval);
352 extern int
353 iosapic_guest_write(
354 unsigned long physbase, unsigned int reg, u32 pval);
356 static long do_physdev_op(int cmd, XEN_GUEST_HANDLE(void) arg)
357 {
358 int irq;
359 long ret;
361 switch ( cmd )
362 {
363 case PHYSDEVOP_eoi: {
364 struct physdev_eoi eoi;
365 ret = -EFAULT;
366 if ( copy_from_guest(&eoi, arg, 1) != 0 )
367 break;
368 ret = pirq_guest_eoi(current->domain, eoi.irq);
369 break;
370 }
372 /* Legacy since 0x00030202. */
373 case PHYSDEVOP_IRQ_UNMASK_NOTIFY: {
374 ret = pirq_guest_unmask(current->domain);
375 break;
376 }
378 case PHYSDEVOP_irq_status_query: {
379 struct physdev_irq_status_query irq_status_query;
380 ret = -EFAULT;
381 if ( copy_from_guest(&irq_status_query, arg, 1) != 0 )
382 break;
383 irq = irq_status_query.irq;
384 ret = -EINVAL;
385 if ( (irq < 0) || (irq >= NR_IRQS) )
386 break;
387 irq_status_query.flags = 0;
388 /* Edge-triggered interrupts don't need an explicit unmask downcall. */
389 if ( !strstr(irq_desc[irq_to_vector(irq)].handler->typename, "edge") )
390 irq_status_query.flags |= XENIRQSTAT_needs_eoi;
391 ret = copy_to_guest(arg, &irq_status_query, 1) ? -EFAULT : 0;
392 break;
393 }
395 case PHYSDEVOP_apic_read: {
396 struct physdev_apic apic;
397 ret = -EFAULT;
398 if ( copy_from_guest(&apic, arg, 1) != 0 )
399 break;
400 ret = -EPERM;
401 if ( !IS_PRIV(current->domain) )
402 break;
403 ret = iosapic_guest_read(apic.apic_physbase, apic.reg, &apic.value);
404 if ( copy_to_guest(arg, &apic, 1) != 0 )
405 ret = -EFAULT;
406 break;
407 }
409 case PHYSDEVOP_apic_write: {
410 struct physdev_apic apic;
411 ret = -EFAULT;
412 if ( copy_from_guest(&apic, arg, 1) != 0 )
413 break;
414 ret = -EPERM;
415 if ( !IS_PRIV(current->domain) )
416 break;
417 ret = iosapic_guest_write(apic.apic_physbase, apic.reg, apic.value);
418 break;
419 }
421 case PHYSDEVOP_alloc_irq_vector: {
422 struct physdev_irq irq_op;
424 ret = -EFAULT;
425 if ( copy_from_guest(&irq_op, arg, 1) != 0 )
426 break;
428 ret = -EPERM;
429 if ( !IS_PRIV(current->domain) )
430 break;
432 ret = -EINVAL;
433 if ( (irq = irq_op.irq) >= NR_IRQS )
434 break;
436 irq_op.vector = assign_irq_vector(irq);
437 ret = copy_to_guest(arg, &irq_op, 1) ? -EFAULT : 0;
438 break;
439 }
441 default:
442 ret = -EINVAL;
443 break;
444 }
446 return ret;
447 }
449 /* Legacy hypercall (as of 0x00030202). */
450 static long do_physdev_op_compat(XEN_GUEST_HANDLE(physdev_op_t) uop)
451 {
452 struct physdev_op op;
454 if ( unlikely(copy_from_guest(&op, uop, 1) != 0) )
455 return -EFAULT;
457 return do_physdev_op(op.cmd, guest_handle_from_ptr(&uop.p->u, void));
458 }
460 /* Legacy hypercall (as of 0x00030202). */
461 long do_event_channel_op_compat(XEN_GUEST_HANDLE(evtchn_op_t) uop)
462 {
463 struct evtchn_op op;
465 if ( unlikely(copy_from_guest(&op, uop, 1) != 0) )
466 return -EFAULT;
468 return do_event_channel_op(op.cmd, guest_handle_from_ptr(&uop.p->u, void));
469 }