ia64/xen-unstable

view xen/arch/x86/x86_64/compat/traps.c @ 17965:14fd83fe71c3

Add facility to get notification of domain suspend by event channel.
This event channel will be notified when the domain transitions to the
suspended state, which can be much faster than raising VIRQ_DOM_EXC
and waiting for the notification to be propagated via xenstore.

No attempt is made here to prevent multiple subscribers (last one
wins), or to detect that the subscriber has gone away. Userspace tools
should take care.

Signed-off-by: Brendan Cully <brendan@cs.ubc.ca>
author Keir Fraser <keir.fraser@citrix.com>
date Fri Jul 04 12:00:24 2008 +0100 (2008-07-04)
parents 23582bcda6e1
children d711529e3de1
line source
1 #ifdef CONFIG_COMPAT
3 #include <xen/event.h>
4 #include <asm/regs.h>
5 #include <compat/callback.h>
6 #include <compat/arch-x86_32.h>
8 void compat_show_guest_stack(struct cpu_user_regs *regs, int debug_stack_lines)
9 {
10 unsigned int i, *stack, addr;
12 stack = (unsigned int *)(unsigned long)regs->_esp;
13 printk("Guest stack trace from esp=%08lx:\n ", (unsigned long)stack);
15 for ( i = 0; i < debug_stack_lines * 8; i++ )
16 {
17 if ( (((long)stack + 3) & (STACK_SIZE - 4)) == 0 )
18 break;
19 if ( get_user(addr, stack) )
20 {
21 if ( i != 0 )
22 printk("\n ");
23 printk("Fault while accessing guest memory.");
24 i = 1;
25 break;
26 }
27 if ( (i != 0) && ((i % 8) == 0) )
28 printk("\n ");
29 printk(" %08x", addr);
30 stack++;
31 }
32 if ( i == 0 )
33 printk("Stack empty.");
34 printk("\n");
35 }
37 unsigned int compat_iret(void)
38 {
39 struct cpu_user_regs *regs = guest_cpu_user_regs();
40 struct vcpu *v = current;
41 u32 eflags;
43 /* Trim stack pointer to 32 bits. */
44 regs->rsp = (u32)regs->rsp;
46 /* Restore EAX (clobbered by hypercall). */
47 if ( unlikely(__get_user(regs->_eax, (u32 *)regs->rsp)) )
48 goto exit_and_crash;
50 /* Restore CS and EIP. */
51 if ( unlikely(__get_user(regs->_eip, (u32 *)regs->rsp + 1)) ||
52 unlikely(__get_user(regs->cs, (u32 *)regs->rsp + 2)) )
53 goto exit_and_crash;
55 /*
56 * Fix up and restore EFLAGS. We fix up in a local staging area
57 * to avoid firing the BUG_ON(IOPL) check in arch_get_info_guest.
58 */
59 if ( unlikely(__get_user(eflags, (u32 *)regs->rsp + 3)) )
60 goto exit_and_crash;
61 regs->_eflags = (eflags & ~X86_EFLAGS_IOPL) | X86_EFLAGS_IF;
63 if ( unlikely(eflags & X86_EFLAGS_VM) )
64 {
65 /*
66 * Cannot return to VM86 mode: inject a GP fault instead. Note that
67 * the GP fault is reported on the first VM86 mode instruction, not on
68 * the IRET (which is why we can simply leave the stack frame as-is
69 * (except for perhaps having to copy it), which in turn seems better
70 * than teaching create_bounce_frame() to needlessly deal with vm86
71 * mode frames).
72 */
73 const struct trap_info *ti;
74 u32 x, ksp = v->arch.guest_context.kernel_sp - 40;
75 unsigned int i;
76 int rc = 0;
78 gdprintk(XENLOG_ERR, "VM86 mode unavailable (ksp:%08X->%08X)\n",
79 regs->_esp, ksp);
80 if ( ksp < regs->_esp )
81 {
82 for (i = 1; i < 10; ++i)
83 {
84 rc |= __get_user(x, (u32 *)regs->rsp + i);
85 rc |= __put_user(x, (u32 *)(unsigned long)ksp + i);
86 }
87 }
88 else if ( ksp > regs->_esp )
89 {
90 for (i = 9; i > 0; ++i)
91 {
92 rc |= __get_user(x, (u32 *)regs->rsp + i);
93 rc |= __put_user(x, (u32 *)(unsigned long)ksp + i);
94 }
95 }
96 if ( rc )
97 goto exit_and_crash;
98 regs->_esp = ksp;
99 regs->ss = v->arch.guest_context.kernel_ss;
101 ti = &v->arch.guest_context.trap_ctxt[13];
102 if ( TI_GET_IF(ti) )
103 eflags &= ~X86_EFLAGS_IF;
104 regs->_eflags = eflags & ~(X86_EFLAGS_VM|X86_EFLAGS_RF|
105 X86_EFLAGS_NT|X86_EFLAGS_TF);
107 if ( unlikely(__put_user(0, (u32 *)regs->rsp)) )
108 goto exit_and_crash;
109 regs->_eip = ti->address;
110 regs->cs = ti->cs;
111 }
112 else if ( unlikely(ring_0(regs)) )
113 goto exit_and_crash;
114 else if ( !ring_1(regs) )
115 {
116 /* Return to ring 2/3: restore ESP and SS. */
117 if ( __get_user(regs->ss, (u32 *)regs->rsp + 5)
118 || __get_user(regs->_esp, (u32 *)regs->rsp + 4))
119 goto exit_and_crash;
120 }
121 else
122 regs->_esp += 16;
124 /* Restore affinity. */
125 if (!cpus_equal(v->cpu_affinity_tmp, v->cpu_affinity))
126 vcpu_set_affinity(v, &v->cpu_affinity_tmp);
128 /* No longer in NMI context. */
129 v->nmi_masked = 0;
131 /* Restore upcall mask from supplied EFLAGS.IF. */
132 vcpu_info(v, evtchn_upcall_mask) = !(eflags & X86_EFLAGS_IF);
134 /*
135 * The hypercall exit path will overwrite EAX with this return
136 * value.
137 */
138 return regs->_eax;
140 exit_and_crash:
141 gdprintk(XENLOG_ERR, "Fatal error\n");
142 domain_crash(v->domain);
143 return 0;
144 }
146 static long compat_register_guest_callback(
147 struct compat_callback_register *reg)
148 {
149 long ret = 0;
150 struct vcpu *v = current;
152 fixup_guest_code_selector(v->domain, reg->address.cs);
154 switch ( reg->type )
155 {
156 case CALLBACKTYPE_event:
157 v->arch.guest_context.event_callback_cs = reg->address.cs;
158 v->arch.guest_context.event_callback_eip = reg->address.eip;
159 break;
161 case CALLBACKTYPE_failsafe:
162 v->arch.guest_context.failsafe_callback_cs = reg->address.cs;
163 v->arch.guest_context.failsafe_callback_eip = reg->address.eip;
164 if ( reg->flags & CALLBACKF_mask_events )
165 set_bit(_VGCF_failsafe_disables_events,
166 &v->arch.guest_context.flags);
167 else
168 clear_bit(_VGCF_failsafe_disables_events,
169 &v->arch.guest_context.flags);
170 break;
172 case CALLBACKTYPE_syscall32:
173 v->arch.syscall32_callback_cs = reg->address.cs;
174 v->arch.syscall32_callback_eip = reg->address.eip;
175 v->arch.syscall32_disables_events =
176 (reg->flags & CALLBACKF_mask_events) != 0;
177 break;
179 case CALLBACKTYPE_sysenter:
180 v->arch.sysenter_callback_cs = reg->address.cs;
181 v->arch.sysenter_callback_eip = reg->address.eip;
182 v->arch.sysenter_disables_events =
183 (reg->flags & CALLBACKF_mask_events) != 0;
184 break;
186 case CALLBACKTYPE_nmi:
187 ret = register_guest_nmi_callback(reg->address.eip);
188 break;
190 default:
191 ret = -ENOSYS;
192 break;
193 }
195 return ret;
196 }
198 static long compat_unregister_guest_callback(
199 struct compat_callback_unregister *unreg)
200 {
201 long ret;
203 switch ( unreg->type )
204 {
205 case CALLBACKTYPE_event:
206 case CALLBACKTYPE_failsafe:
207 case CALLBACKTYPE_syscall32:
208 case CALLBACKTYPE_sysenter:
209 ret = -EINVAL;
210 break;
212 case CALLBACKTYPE_nmi:
213 ret = unregister_guest_nmi_callback();
214 break;
216 default:
217 ret = -ENOSYS;
218 break;
219 }
221 return ret;
222 }
225 long compat_callback_op(int cmd, XEN_GUEST_HANDLE(void) arg)
226 {
227 long ret;
229 switch ( cmd )
230 {
231 case CALLBACKOP_register:
232 {
233 struct compat_callback_register reg;
235 ret = -EFAULT;
236 if ( copy_from_guest(&reg, arg, 1) )
237 break;
239 ret = compat_register_guest_callback(&reg);
240 }
241 break;
243 case CALLBACKOP_unregister:
244 {
245 struct compat_callback_unregister unreg;
247 ret = -EFAULT;
248 if ( copy_from_guest(&unreg, arg, 1) )
249 break;
251 ret = compat_unregister_guest_callback(&unreg);
252 }
253 break;
255 default:
256 ret = -EINVAL;
257 break;
258 }
260 return ret;
261 }
263 long compat_set_callbacks(unsigned long event_selector,
264 unsigned long event_address,
265 unsigned long failsafe_selector,
266 unsigned long failsafe_address)
267 {
268 struct compat_callback_register event = {
269 .type = CALLBACKTYPE_event,
270 .address = {
271 .cs = event_selector,
272 .eip = event_address
273 }
274 };
275 struct compat_callback_register failsafe = {
276 .type = CALLBACKTYPE_failsafe,
277 .address = {
278 .cs = failsafe_selector,
279 .eip = failsafe_address
280 }
281 };
283 compat_register_guest_callback(&event);
284 compat_register_guest_callback(&failsafe);
286 return 0;
287 }
289 DEFINE_XEN_GUEST_HANDLE(trap_info_compat_t);
291 int compat_set_trap_table(XEN_GUEST_HANDLE(trap_info_compat_t) traps)
292 {
293 struct compat_trap_info cur;
294 struct trap_info *dst = current->arch.guest_context.trap_ctxt;
295 long rc = 0;
297 /* If no table is presented then clear the entire virtual IDT. */
298 if ( guest_handle_is_null(traps) )
299 {
300 memset(dst, 0, 256 * sizeof(*dst));
301 return 0;
302 }
304 for ( ; ; )
305 {
306 if ( hypercall_preempt_check() )
307 {
308 rc = hypercall_create_continuation(
309 __HYPERVISOR_set_trap_table, "h", traps);
310 break;
311 }
313 if ( copy_from_guest(&cur, traps, 1) )
314 {
315 rc = -EFAULT;
316 break;
317 }
319 if ( cur.address == 0 )
320 break;
322 fixup_guest_code_selector(current->domain, cur.cs);
324 XLAT_trap_info(dst + cur.vector, &cur);
326 if ( cur.vector == 0x80 )
327 init_int80_direct_trap(current);
329 guest_handle_add_offset(traps, 1);
330 }
332 return rc;
333 }
335 #endif /* CONFIG_COMPAT */
337 static void hypercall_page_initialise_ring1_kernel(void *hypercall_page)
338 {
339 char *p;
340 int i;
342 /* Fill in all the transfer points with template machine code. */
344 for ( i = 0; i < (PAGE_SIZE / 32); i++ )
345 {
346 p = (char *)(hypercall_page + (i * 32));
347 *(u8 *)(p+ 0) = 0xb8; /* mov $<i>,%eax */
348 *(u32 *)(p+ 1) = i;
349 *(u16 *)(p+ 5) = 0x82cd; /* int $0x82 */
350 *(u8 *)(p+ 7) = 0xc3; /* ret */
351 }
353 /*
354 * HYPERVISOR_iret is special because it doesn't return and expects a
355 * special stack frame. Guests jump at this transfer point instead of
356 * calling it.
357 */
358 p = (char *)(hypercall_page + (__HYPERVISOR_iret * 32));
359 *(u8 *)(p+ 0) = 0x50; /* push %eax */
360 *(u8 *)(p+ 1) = 0xb8; /* mov $__HYPERVISOR_iret,%eax */
361 *(u32 *)(p+ 2) = __HYPERVISOR_iret;
362 *(u16 *)(p+ 6) = 0x82cd; /* int $0x82 */
363 }
365 /*
366 * Local variables:
367 * mode: C
368 * c-set-style: "BSD"
369 * c-basic-offset: 4
370 * tab-width: 4
371 * indent-tabs-mode: nil
372 * End:
373 */