ia64/xen-unstable

view xen/arch/ia64/xen/hypercall.c @ 9912:d7e6e5f29226

Fix ia64 build. do_physdev_op* declared incorrectly
Signed-off-by: Dan Magenheimer <dan.magenheimer@hp.com>
author kaf24@firebug.cl.cam.ac.uk
date Tue May 02 09:16:02 2006 +0100 (2006-05-02)
parents 42a8e3101c6c
children ada6dba78b6e
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 };
77 uint32_t nr_hypercalls =
78 sizeof(ia64_hypercall_table) / sizeof(hypercall_t);
80 static int
81 xen_hypercall (struct pt_regs *regs)
82 {
83 uint32_t cmd = (uint32_t)regs->r2;
85 if (cmd < nr_hypercalls)
86 regs->r8 = (*ia64_hypercall_table[cmd])(
87 regs->r14,
88 regs->r15,
89 regs->r16,
90 regs->r17,
91 regs->r18,
92 regs->r19);
93 else
94 #ifdef CONFIG_XEN_IA64_DOM0_VP
95 if (cmd == __HYPERVISOR_ia64_dom0vp_op)
96 regs->r8 = do_dom0vp_op(regs->r14, regs->r15, regs->r16,
97 regs->r17, regs->r18);
98 else
99 #endif
100 regs->r8 = -ENOSYS;
102 return 1;
103 }
106 static void
107 fw_hypercall_ipi (struct pt_regs *regs)
108 {
109 int cpu = regs->r14;
110 int vector = regs->r15;
111 struct vcpu *targ;
113 if (0 && vector == 254)
114 printf ("send_ipi from %d to %d vector=%d\n",
115 current->vcpu_id, cpu, vector);
117 if (cpu > MAX_VIRT_CPUS)
118 return;
120 targ = current->domain->vcpu[cpu];
121 if (targ == NULL)
122 return;
124 if (vector == XEN_SAL_BOOT_RENDEZ_VEC
125 && !test_bit(_VCPUF_initialised, &targ->vcpu_flags)) {
126 struct pt_regs *targ_regs = vcpu_regs (targ);
127 struct vcpu_guest_context c;
129 printf ("arch_boot_vcpu: %p %p\n",
130 (void *)targ_regs->cr_iip,
131 (void *)targ_regs->r1);
132 memset (&c, 0, sizeof (c));
133 /* Copy regs. */
134 c.regs.cr_iip = targ_regs->cr_iip;
135 c.regs.r1 = targ_regs->r1;
137 /* Copy from vcpu 0. */
138 c.vcpu.evtchn_vector =
139 current->domain->vcpu[0]->vcpu_info->arch.evtchn_vector;
140 if (arch_set_info_guest (targ, &c) != 0) {
141 printf ("arch_boot_vcpu: failure\n");
142 return;
143 }
144 if (test_and_clear_bit(_VCPUF_down,
145 &targ->vcpu_flags)) {
146 vcpu_wake(targ);
147 printf ("arch_boot_vcpu: vcpu %d awaken %016lx!\n",
148 targ->vcpu_id, targ_regs->cr_iip);
149 }
150 else
151 printf ("arch_boot_vcpu: huu, already awaken!");
152 }
153 else {
154 int running = test_bit(_VCPUF_running,
155 &targ->vcpu_flags);
157 vcpu_pend_interrupt(targ, vector);
158 vcpu_unblock(targ);
159 if (running)
160 smp_send_event_check_cpu(targ->processor);
161 }
162 return;
163 }
165 static int
166 fw_hypercall (struct pt_regs *regs)
167 {
168 struct vcpu *v = current;
169 struct sal_ret_values x;
170 unsigned long *tv, *tc;
172 switch (regs->r2) {
173 case FW_HYPERCALL_PAL_CALL:
174 //printf("*** PAL hypercall: index=%d\n",regs->r28);
175 //FIXME: This should call a C routine
176 #if 0
177 // This is very conservative, but avoids a possible
178 // (and deadly) freeze in paravirtualized domains due
179 // to a yet-to-be-found bug where pending_interruption
180 // is zero when it shouldn't be. Since PAL is called
181 // in the idle loop, this should resolve it
182 VCPU(v,pending_interruption) = 1;
183 #endif
184 if (regs->r28 == PAL_HALT_LIGHT) {
185 int pi;
186 #define SPURIOUS_VECTOR 15
187 pi = vcpu_check_pending_interrupts(v);
188 if (pi != SPURIOUS_VECTOR) {
189 if (!VCPU(v,pending_interruption))
190 idle_when_pending++;
191 vcpu_pend_unspecified_interrupt(v);
192 //printf("idle w/int#%d pending!\n",pi);
193 //this shouldn't happen, but it apparently does quite a bit! so don't
194 //allow it to happen... i.e. if a domain has an interrupt pending and
195 //it tries to halt itself because it thinks it is idle, just return here
196 //as deliver_pending_interrupt is called on the way out and will deliver it
197 }
198 else {
199 pal_halt_light_count++;
200 do_sched_op_compat(SCHEDOP_yield, 0);
201 }
202 regs->r8 = 0;
203 regs->r9 = 0;
204 regs->r10 = 0;
205 regs->r11 = 0;
206 }
207 else {
208 struct ia64_pal_retval y;
210 if (regs->r28 >= PAL_COPY_PAL)
211 y = xen_pal_emulator
212 (regs->r28, vcpu_get_gr (v, 33),
213 vcpu_get_gr (v, 34),
214 vcpu_get_gr (v, 35));
215 else
216 y = xen_pal_emulator(regs->r28,regs->r29,
217 regs->r30,regs->r31);
218 regs->r8 = y.status; regs->r9 = y.v0;
219 regs->r10 = y.v1; regs->r11 = y.v2;
220 }
221 break;
222 case FW_HYPERCALL_SAL_CALL:
223 x = sal_emulator(vcpu_get_gr(v,32),vcpu_get_gr(v,33),
224 vcpu_get_gr(v,34),vcpu_get_gr(v,35),
225 vcpu_get_gr(v,36),vcpu_get_gr(v,37),
226 vcpu_get_gr(v,38),vcpu_get_gr(v,39));
227 regs->r8 = x.r8; regs->r9 = x.r9;
228 regs->r10 = x.r10; regs->r11 = x.r11;
229 break;
230 case FW_HYPERCALL_EFI_RESET_SYSTEM:
231 printf("efi.reset_system called ");
232 if (current->domain == dom0) {
233 printf("(by dom0)\n ");
234 (*efi.reset_system)(EFI_RESET_WARM,0,0,NULL);
235 }
236 else
237 domain_shutdown (current->domain, SHUTDOWN_reboot);
238 regs->r8 = EFI_UNSUPPORTED;
239 break;
240 case FW_HYPERCALL_EFI_GET_TIME:
241 tv = (unsigned long *) vcpu_get_gr(v,32);
242 tc = (unsigned long *) vcpu_get_gr(v,33);
243 //printf("efi_get_time(%p,%p) called...",tv,tc);
244 tv = (unsigned long *) __va(translate_domain_mpaddr((unsigned long) tv));
245 if (tc) tc = (unsigned long *) __va(translate_domain_mpaddr((unsigned long) tc));
246 regs->r8 = (*efi.get_time)((efi_time_t *) tv, (efi_time_cap_t *) tc);
247 //printf("and returns %lx\n",regs->r8);
248 break;
249 case FW_HYPERCALL_EFI_SET_TIME:
250 case FW_HYPERCALL_EFI_GET_WAKEUP_TIME:
251 case FW_HYPERCALL_EFI_SET_WAKEUP_TIME:
252 // FIXME: need fixes in efi.h from 2.6.9
253 case FW_HYPERCALL_EFI_SET_VIRTUAL_ADDRESS_MAP:
254 // FIXME: WARNING!! IF THIS EVER GETS IMPLEMENTED
255 // SOME OF THE OTHER EFI EMULATIONS WILL CHANGE AS
256 // POINTER ARGUMENTS WILL BE VIRTUAL!!
257 case FW_HYPERCALL_EFI_GET_VARIABLE:
258 // FIXME: need fixes in efi.h from 2.6.9
259 case FW_HYPERCALL_EFI_GET_NEXT_VARIABLE:
260 case FW_HYPERCALL_EFI_SET_VARIABLE:
261 case FW_HYPERCALL_EFI_GET_NEXT_HIGH_MONO_COUNT:
262 // FIXME: need fixes in efi.h from 2.6.9
263 regs->r8 = EFI_UNSUPPORTED;
264 break;
265 case FW_HYPERCALL_IPI:
266 fw_hypercall_ipi (regs);
267 break;
268 default:
269 printf("unknown ia64 fw hypercall %lx\n", regs->r2);
270 regs->r8 = do_ni_hypercall();
271 }
272 return 1;
273 }
275 /* opt_unsafe_hypercall: If true, unsafe debugging hypercalls are allowed.
276 These can create security hole. */
277 static int opt_unsafe_hypercall = 0;
278 boolean_param("unsafe_hypercall", opt_unsafe_hypercall);
280 int
281 ia64_hypercall (struct pt_regs *regs)
282 {
283 struct vcpu *v = current;
284 unsigned long index = regs->r2;
285 int privlvl = (regs->cr_ipsr & IA64_PSR_CPL) >> IA64_PSR_CPL0_BIT;
287 if (index >= FW_HYPERCALL_FIRST_USER) {
288 /* Note: user hypercalls are not safe, since Xen doesn't
289 check memory access privilege: Xen does not deny reading
290 or writing to kernel memory. */
291 if (!opt_unsafe_hypercall) {
292 printf("user xen/ia64 hypercalls disabled\n");
293 regs->r8 = -1;
294 }
295 else switch (index) {
296 case 0xffff:
297 regs->r8 = dump_privop_counts_to_user(
298 (char *) vcpu_get_gr(v,32),
299 (int) vcpu_get_gr(v,33));
300 break;
301 case 0xfffe:
302 regs->r8 = zero_privop_counts_to_user(
303 (char *) vcpu_get_gr(v,32),
304 (int) vcpu_get_gr(v,33));
305 break;
306 default:
307 printf("unknown user xen/ia64 hypercall %lx\n", index);
308 regs->r8 = do_ni_hypercall();
309 }
310 return 1;
311 }
313 /* Hypercalls are only allowed by kernel.
314 Kernel checks memory accesses. */
315 if (privlvl != 2) {
316 /* FIXME: Return a better error value ?
317 Reflection ? Illegal operation ? */
318 regs->r8 = -1;
319 return 1;
320 }
322 if (index >= FW_HYPERCALL_FIRST_ARCH)
323 return fw_hypercall (regs);
324 else
325 return xen_hypercall (regs);
326 }
328 /* Need make this function common */
329 extern int
330 iosapic_guest_read(
331 unsigned long physbase, unsigned int reg, u32 *pval);
332 extern int
333 iosapic_guest_write(
334 unsigned long physbase, unsigned int reg, u32 pval);
336 static long do_physdev_op(int cmd, XEN_GUEST_HANDLE(void) arg)
337 {
338 int irq;
339 long ret;
341 switch ( cmd )
342 {
343 case PHYSDEVOP_eoi: {
344 struct physdev_eoi eoi;
345 ret = -EFAULT;
346 if ( copy_from_guest(&eoi, arg, 1) != 0 )
347 break;
348 ret = pirq_guest_eoi(current->domain, eoi.irq);
349 break;
350 }
352 /* Legacy since 0x00030202. */
353 case PHYSDEVOP_IRQ_UNMASK_NOTIFY: {
354 ret = pirq_guest_unmask(current->domain);
355 break;
356 }
358 case PHYSDEVOP_irq_status_query: {
359 struct physdev_irq_status_query irq_status_query;
360 ret = -EFAULT;
361 if ( copy_from_guest(&irq_status_query, arg, 1) != 0 )
362 break;
363 irq = irq_status_query.irq;
364 ret = -EINVAL;
365 if ( (irq < 0) || (irq >= NR_IRQS) )
366 break;
367 irq_status_query.flags = 0;
368 /* Edge-triggered interrupts don't need an explicit unmask downcall. */
369 if ( !strstr(irq_desc[irq_to_vector(irq)].handler->typename, "edge") )
370 irq_status_query.flags |= XENIRQSTAT_needs_eoi;
371 ret = copy_to_guest(arg, &irq_status_query, 1) ? -EFAULT : 0;
372 break;
373 }
375 case PHYSDEVOP_apic_read: {
376 struct physdev_apic apic;
377 ret = -EFAULT;
378 if ( copy_from_guest(&apic, arg, 1) != 0 )
379 break;
380 ret = -EPERM;
381 if ( !IS_PRIV(current->domain) )
382 break;
383 ret = iosapic_guest_read(apic.apic_physbase, apic.reg, &apic.value);
384 if ( copy_to_guest(arg, &apic, 1) != 0 )
385 ret = -EFAULT;
386 break;
387 }
389 case PHYSDEVOP_apic_write: {
390 struct physdev_apic apic;
391 ret = -EFAULT;
392 if ( copy_from_guest(&apic, arg, 1) != 0 )
393 break;
394 ret = -EPERM;
395 if ( !IS_PRIV(current->domain) )
396 break;
397 ret = iosapic_guest_write(apic.apic_physbase, apic.reg, apic.value);
398 break;
399 }
401 case PHYSDEVOP_alloc_irq_vector: {
402 struct physdev_irq irq_op;
404 ret = -EFAULT;
405 if ( copy_from_guest(&irq_op, arg, 1) != 0 )
406 break;
408 ret = -EPERM;
409 if ( !IS_PRIV(current->domain) )
410 break;
412 ret = -EINVAL;
413 if ( (irq = irq_op.irq) >= NR_IRQS )
414 break;
416 irq_op.vector = assign_irq_vector(irq);
417 ret = copy_to_guest(arg, &irq_op, 1) ? -EFAULT : 0;
418 break;
419 }
421 default:
422 ret = -EINVAL;
423 break;
424 }
426 return ret;
427 }
429 /* Legacy hypercall (as of 0x00030202). */
430 static long do_physdev_op_compat(XEN_GUEST_HANDLE(physdev_op_t) uop)
431 {
432 struct physdev_op op;
434 if ( unlikely(copy_from_guest(&op, uop, 1) != 0) )
435 return -EFAULT;
437 return do_physdev_op(op.cmd, guest_handle_from_ptr(&uop.p->u, void));
438 }
440 /* Legacy hypercall (as of 0x00030202). */
441 long do_event_channel_op_compat(XEN_GUEST_HANDLE(evtchn_op_t) uop)
442 {
443 struct evtchn_op op;
445 if ( unlikely(copy_from_guest(&op, uop, 1) != 0) )
446 return -EFAULT;
448 return do_event_channel_op(op.cmd, guest_handle_from_ptr(&uop.p->u, void));
449 }