ia64/xen-unstable

view xen/arch/ia64/xen/hypercall.c @ 9563:9bee4875a848

Rename sched_op->sched_op_compat and sched_op_new->sched_op
after Christian's interface cleanup.

Signed-off-by: Keir Fraser <keir@xensource.com>
author kaf24@firebug.cl.cam.ac.uk
date Sat Apr 01 11:08:50 2006 +0100 (2006-04-01)
parents 263901a2a995
children 99b2e765d643
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>
25 extern unsigned long translate_domain_mpaddr(unsigned long);
26 /* FIXME: where these declarations should be there ? */
27 extern int dump_privop_counts_to_user(char *, int);
28 extern int zero_privop_counts_to_user(char *, int);
30 unsigned long idle_when_pending = 0;
31 unsigned long pal_halt_light_count = 0;
33 hypercall_t ia64_hypercall_table[] =
34 {
35 (hypercall_t)do_ni_hypercall, /* do_set_trap_table */ /* 0 */
36 (hypercall_t)do_ni_hypercall, /* do_mmu_update */
37 (hypercall_t)do_ni_hypercall, /* do_set_gdt */
38 (hypercall_t)do_ni_hypercall, /* do_stack_switch */
39 (hypercall_t)do_ni_hypercall, /* do_set_callbacks */
40 (hypercall_t)do_ni_hypercall, /* do_fpu_taskswitch */ /* 5 */
41 (hypercall_t)do_ni_hypercall, /* do_sched_op_compat */
42 (hypercall_t)do_dom0_op,
43 (hypercall_t)do_ni_hypercall, /* do_set_debugreg */
44 (hypercall_t)do_ni_hypercall, /* do_get_debugreg */
45 (hypercall_t)do_ni_hypercall, /* do_update_descriptor */ /* 10 */
46 (hypercall_t)do_ni_hypercall, /* do_ni_hypercall */
47 (hypercall_t)do_memory_op,
48 (hypercall_t)do_multicall,
49 (hypercall_t)do_ni_hypercall, /* do_update_va_mapping */
50 (hypercall_t)do_ni_hypercall, /* do_set_timer_op */ /* 15 */
51 (hypercall_t)do_event_channel_op,
52 (hypercall_t)do_xen_version,
53 (hypercall_t)do_console_io,
54 (hypercall_t)do_ni_hypercall, /* do_physdev_op */
55 (hypercall_t)do_grant_table_op, /* 20 */
56 (hypercall_t)do_ni_hypercall, /* do_vm_assist */
57 (hypercall_t)do_ni_hypercall, /* do_update_va_mapping_otherdomain */
58 (hypercall_t)do_ni_hypercall, /* (x86 only) */
59 (hypercall_t)do_ni_hypercall, /* do_vcpu_op */
60 (hypercall_t)do_ni_hypercall, /* (x86_64 only) */ /* 25 */
61 (hypercall_t)do_ni_hypercall, /* do_mmuext_op */
62 (hypercall_t)do_ni_hypercall, /* do_acm_op */
63 (hypercall_t)do_ni_hypercall, /* do_nmi_op */
64 (hypercall_t)do_ni_hypercall, /* */
65 (hypercall_t)do_ni_hypercall, /* */ /* 30 */
66 (hypercall_t)do_ni_hypercall /* */
67 };
69 static int
70 xen_hypercall (struct pt_regs *regs)
71 {
72 switch (regs->r2) {
73 case __HYPERVISOR_dom0_op:
74 regs->r8 = do_dom0_op(guest_handle_from_ptr(regs->r14,
75 dom0_op_t));
76 break;
78 case __HYPERVISOR_memory_op:
79 /* we don't handle reservations; just return success */
80 {
81 struct xen_memory_reservation reservation;
82 void *arg = (void *) regs->r15;
84 switch(regs->r14) {
85 case XENMEM_increase_reservation:
86 case XENMEM_decrease_reservation:
87 if (copy_from_user(&reservation, arg,
88 sizeof(reservation)))
89 regs->r8 = -EFAULT;
90 else
91 regs->r8 = reservation.nr_extents;
92 break;
93 default:
94 regs->r8 = do_memory_op((int) regs->r14, guest_handle_from_ptr(regs->r15, void));
95 break;
96 }
97 }
98 break;
100 case __HYPERVISOR_event_channel_op:
101 regs->r8 = do_event_channel_op(guest_handle_from_ptr(regs->r14, evtchn_op_t));
102 break;
104 case __HYPERVISOR_grant_table_op:
105 regs->r8 = do_grant_table_op((unsigned int) regs->r14, guest_handle_from_ptr(regs->r15, void), (unsigned int) regs->r16);
106 break;
108 case __HYPERVISOR_console_io:
109 regs->r8 = do_console_io((int) regs->r14, (int) regs->r15, guest_handle_from_ptr(regs->r16, char));
110 break;
112 case __HYPERVISOR_xen_version:
113 regs->r8 = do_xen_version((int) regs->r14, guest_handle_from_ptr(regs->r15, void));
114 break;
116 case __HYPERVISOR_multicall:
117 regs->r8 = do_multicall(guest_handle_from_ptr(regs->r14, multicall_entry_t), (unsigned int) regs->r15);
118 break;
120 default:
121 printf("unknown xen hypercall %lx\n", regs->r2);
122 regs->r8 = do_ni_hypercall();
123 }
124 return 1;
125 }
128 static int
129 fw_hypercall (struct pt_regs *regs)
130 {
131 struct vcpu *v = current;
132 struct sal_ret_values x;
133 unsigned long *tv, *tc;
135 switch (regs->r2) {
136 case FW_HYPERCALL_PAL_CALL:
137 //printf("*** PAL hypercall: index=%d\n",regs->r28);
138 //FIXME: This should call a C routine
139 #if 0
140 // This is very conservative, but avoids a possible
141 // (and deadly) freeze in paravirtualized domains due
142 // to a yet-to-be-found bug where pending_interruption
143 // is zero when it shouldn't be. Since PAL is called
144 // in the idle loop, this should resolve it
145 VCPU(v,pending_interruption) = 1;
146 #endif
147 if (regs->r28 == PAL_HALT_LIGHT) {
148 int pi;
149 #define SPURIOUS_VECTOR 15
150 pi = vcpu_check_pending_interrupts(v);
151 if (pi != SPURIOUS_VECTOR) {
152 if (!VCPU(v,pending_interruption))
153 idle_when_pending++;
154 vcpu_pend_unspecified_interrupt(v);
155 //printf("idle w/int#%d pending!\n",pi);
156 //this shouldn't happen, but it apparently does quite a bit! so don't
157 //allow it to happen... i.e. if a domain has an interrupt pending and
158 //it tries to halt itself because it thinks it is idle, just return here
159 //as deliver_pending_interrupt is called on the way out and will deliver it
160 }
161 else {
162 pal_halt_light_count++;
163 do_sched_op_compat(SCHEDOP_yield, 0);
164 }
165 regs->r8 = 0;
166 regs->r9 = 0;
167 regs->r10 = 0;
168 regs->r11 = 0;
169 }
170 else {
171 struct ia64_pal_retval y;
173 if (regs->r28 >= PAL_COPY_PAL)
174 y = xen_pal_emulator
175 (regs->r28, vcpu_get_gr (v, 33),
176 vcpu_get_gr (v, 34),
177 vcpu_get_gr (v, 35));
178 else
179 y = xen_pal_emulator(regs->r28,regs->r29,
180 regs->r30,regs->r31);
181 regs->r8 = y.status; regs->r9 = y.v0;
182 regs->r10 = y.v1; regs->r11 = y.v2;
183 }
184 break;
185 case FW_HYPERCALL_SAL_CALL:
186 x = sal_emulator(vcpu_get_gr(v,32),vcpu_get_gr(v,33),
187 vcpu_get_gr(v,34),vcpu_get_gr(v,35),
188 vcpu_get_gr(v,36),vcpu_get_gr(v,37),
189 vcpu_get_gr(v,38),vcpu_get_gr(v,39));
190 regs->r8 = x.r8; regs->r9 = x.r9;
191 regs->r10 = x.r10; regs->r11 = x.r11;
192 break;
193 case FW_HYPERCALL_EFI_RESET_SYSTEM:
194 printf("efi.reset_system called ");
195 if (current->domain == dom0) {
196 printf("(by dom0)\n ");
197 (*efi.reset_system)(EFI_RESET_WARM,0,0,NULL);
198 }
199 else
200 domain_shutdown (current->domain, SHUTDOWN_reboot);
201 regs->r8 = EFI_UNSUPPORTED;
202 break;
203 case FW_HYPERCALL_EFI_GET_TIME:
204 tv = (unsigned long *) vcpu_get_gr(v,32);
205 tc = (unsigned long *) vcpu_get_gr(v,33);
206 //printf("efi_get_time(%p,%p) called...",tv,tc);
207 tv = (unsigned long *) __va(translate_domain_mpaddr((unsigned long) tv));
208 if (tc) tc = (unsigned long *) __va(translate_domain_mpaddr((unsigned long) tc));
209 regs->r8 = (*efi.get_time)((efi_time_t *) tv, (efi_time_cap_t *) tc);
210 //printf("and returns %lx\n",regs->r8);
211 break;
212 case FW_HYPERCALL_EFI_SET_TIME:
213 case FW_HYPERCALL_EFI_GET_WAKEUP_TIME:
214 case FW_HYPERCALL_EFI_SET_WAKEUP_TIME:
215 // FIXME: need fixes in efi.h from 2.6.9
216 case FW_HYPERCALL_EFI_SET_VIRTUAL_ADDRESS_MAP:
217 // FIXME: WARNING!! IF THIS EVER GETS IMPLEMENTED
218 // SOME OF THE OTHER EFI EMULATIONS WILL CHANGE AS
219 // POINTER ARGUMENTS WILL BE VIRTUAL!!
220 case FW_HYPERCALL_EFI_GET_VARIABLE:
221 // FIXME: need fixes in efi.h from 2.6.9
222 case FW_HYPERCALL_EFI_GET_NEXT_VARIABLE:
223 case FW_HYPERCALL_EFI_SET_VARIABLE:
224 case FW_HYPERCALL_EFI_GET_NEXT_HIGH_MONO_COUNT:
225 // FIXME: need fixes in efi.h from 2.6.9
226 regs->r8 = EFI_UNSUPPORTED;
227 break;
228 default:
229 printf("unknown ia64 fw hypercall %lx\n", regs->r2);
230 regs->r8 = do_ni_hypercall();
231 }
232 return 1;
233 }
235 /* opt_unsafe_hypercall: If true, unsafe debugging hypercalls are allowed.
236 These can create security hole. */
237 static int opt_unsafe_hypercall = 0;
238 boolean_param("unsafe_hypercall", opt_unsafe_hypercall);
240 int
241 ia64_hypercall (struct pt_regs *regs)
242 {
243 struct vcpu *v = current;
244 unsigned long index = regs->r2;
245 int privlvl = (regs->cr_ipsr & IA64_PSR_CPL) >> IA64_PSR_CPL0_BIT;
247 if (index >= FW_HYPERCALL_FIRST_USER) {
248 /* Note: user hypercalls are not safe, since Xen doesn't
249 check memory access privilege: Xen does not deny reading
250 or writing to kernel memory. */
251 if (!opt_unsafe_hypercall) {
252 printf("user xen/ia64 hypercalls disabled\n");
253 regs->r8 = -1;
254 }
255 else switch (index) {
256 case 0xffff:
257 regs->r8 = dump_privop_counts_to_user(
258 (char *) vcpu_get_gr(v,32),
259 (int) vcpu_get_gr(v,33));
260 break;
261 case 0xfffe:
262 regs->r8 = zero_privop_counts_to_user(
263 (char *) vcpu_get_gr(v,32),
264 (int) vcpu_get_gr(v,33));
265 break;
266 default:
267 printf("unknown user xen/ia64 hypercall %lx\n", index);
268 regs->r8 = do_ni_hypercall();
269 }
270 return 1;
271 }
273 /* Hypercalls are only allowed by kernel.
274 Kernel checks memory accesses. */
275 if (privlvl != 2) {
276 /* FIXME: Return a better error value ?
277 Reflection ? Illegal operation ? */
278 regs->r8 = -1;
279 return 1;
280 }
282 if (index >= FW_HYPERCALL_FIRST_ARCH)
283 return fw_hypercall (regs);
284 else
285 return xen_hypercall (regs);
286 }