debuggers.hg

view xen/arch/x86/x86_64/compat/traps.c @ 19806:67a0ffade665

x86: improve output resulting from sending '0' over serial

While the original logic already implied that the kernel part of the
guest's address space is identical on all vCPU-s (i.e. for all guest
processes), it didn't fully leverage the potential here: As long as
the top page table currently active is owned by the subject domain
(currently only Dom0), the stack dump can be done without extra
effort.

For x86-64, additionally add page table traversal so that the stack
can be dumped in all cases (unless it's invalid or user space).

I left the 32-bit variant of do_page_walk() unimplemented for the
moment as I couldn't convince myself using map_domain_page() there is
a good idea, and didn't want to introduce new fixmap entries either.

Signed-off-by: Jan Beulich <jbeulich@novell.com>
author Keir Fraser <keir.fraser@citrix.com>
date Tue Jun 16 13:57:18 2009 +0100 (2009-06-16)
parents a49673cd23d2
children 5d779377a9ae
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 vcpu *v, struct cpu_user_regs *regs,
9 int debug_stack_lines)
10 {
11 unsigned int i, *stack, addr, mask = STACK_SIZE;
13 stack = (unsigned int *)(unsigned long)regs->_esp;
14 printk("Guest stack trace from esp=%08lx:\n ", (unsigned long)stack);
16 if ( !__compat_access_ok(v->domain, stack, sizeof(*stack)) )
17 {
18 printk("Guest-inaccessible memory.\n");
19 return;
20 }
22 if ( v != current )
23 {
24 struct vcpu *vcpu;
26 ASSERT(guest_kernel_mode(v, regs));
27 addr = read_cr3() >> PAGE_SHIFT;
28 for_each_vcpu( v->domain, vcpu )
29 if ( pagetable_get_pfn(vcpu->arch.guest_table) == addr )
30 break;
31 if ( !vcpu )
32 {
33 stack = do_page_walk(v, (unsigned long)stack);
34 if ( (unsigned long)stack < PAGE_SIZE )
35 {
36 printk("Inaccessible guest memory.\n");
37 return;
38 }
39 mask = PAGE_SIZE;
40 }
41 }
43 for ( i = 0; i < debug_stack_lines * 8; i++ )
44 {
45 if ( (((long)stack - 1) ^ ((long)(stack + 1) - 1)) & mask )
46 break;
47 if ( __get_user(addr, stack) )
48 {
49 if ( i != 0 )
50 printk("\n ");
51 printk("Fault while accessing guest memory.");
52 i = 1;
53 break;
54 }
55 if ( (i != 0) && ((i % 8) == 0) )
56 printk("\n ");
57 printk(" %08x", addr);
58 stack++;
59 }
60 if ( i == 0 )
61 printk("Stack empty.");
62 printk("\n");
63 }
65 unsigned int compat_iret(void)
66 {
67 struct cpu_user_regs *regs = guest_cpu_user_regs();
68 struct vcpu *v = current;
69 u32 eflags;
71 /* Trim stack pointer to 32 bits. */
72 regs->rsp = (u32)regs->rsp;
74 /* Restore EAX (clobbered by hypercall). */
75 if ( unlikely(__get_user(regs->_eax, (u32 *)regs->rsp)) )
76 goto exit_and_crash;
78 /* Restore CS and EIP. */
79 if ( unlikely(__get_user(regs->_eip, (u32 *)regs->rsp + 1)) ||
80 unlikely(__get_user(regs->cs, (u32 *)regs->rsp + 2)) )
81 goto exit_and_crash;
83 /*
84 * Fix up and restore EFLAGS. We fix up in a local staging area
85 * to avoid firing the BUG_ON(IOPL) check in arch_get_info_guest.
86 */
87 if ( unlikely(__get_user(eflags, (u32 *)regs->rsp + 3)) )
88 goto exit_and_crash;
89 regs->_eflags = (eflags & ~X86_EFLAGS_IOPL) | X86_EFLAGS_IF;
91 if ( unlikely(eflags & X86_EFLAGS_VM) )
92 {
93 /*
94 * Cannot return to VM86 mode: inject a GP fault instead. Note that
95 * the GP fault is reported on the first VM86 mode instruction, not on
96 * the IRET (which is why we can simply leave the stack frame as-is
97 * (except for perhaps having to copy it), which in turn seems better
98 * than teaching create_bounce_frame() to needlessly deal with vm86
99 * mode frames).
100 */
101 const struct trap_info *ti;
102 u32 x, ksp = v->arch.guest_context.kernel_sp - 40;
103 unsigned int i;
104 int rc = 0;
106 gdprintk(XENLOG_ERR, "VM86 mode unavailable (ksp:%08X->%08X)\n",
107 regs->_esp, ksp);
108 if ( ksp < regs->_esp )
109 {
110 for (i = 1; i < 10; ++i)
111 {
112 rc |= __get_user(x, (u32 *)regs->rsp + i);
113 rc |= __put_user(x, (u32 *)(unsigned long)ksp + i);
114 }
115 }
116 else if ( ksp > regs->_esp )
117 {
118 for (i = 9; i > 0; ++i)
119 {
120 rc |= __get_user(x, (u32 *)regs->rsp + i);
121 rc |= __put_user(x, (u32 *)(unsigned long)ksp + i);
122 }
123 }
124 if ( rc )
125 goto exit_and_crash;
126 regs->_esp = ksp;
127 regs->ss = v->arch.guest_context.kernel_ss;
129 ti = &v->arch.guest_context.trap_ctxt[13];
130 if ( TI_GET_IF(ti) )
131 eflags &= ~X86_EFLAGS_IF;
132 regs->_eflags = eflags & ~(X86_EFLAGS_VM|X86_EFLAGS_RF|
133 X86_EFLAGS_NT|X86_EFLAGS_TF);
135 if ( unlikely(__put_user(0, (u32 *)regs->rsp)) )
136 goto exit_and_crash;
137 regs->_eip = ti->address;
138 regs->cs = ti->cs;
139 }
140 else if ( unlikely(ring_0(regs)) )
141 goto exit_and_crash;
142 else if ( !ring_1(regs) )
143 {
144 /* Return to ring 2/3: restore ESP and SS. */
145 if ( __get_user(regs->ss, (u32 *)regs->rsp + 5)
146 || __get_user(regs->_esp, (u32 *)regs->rsp + 4))
147 goto exit_and_crash;
148 }
149 else
150 regs->_esp += 16;
152 /* Restore affinity. */
153 if ((v->trap_priority >= VCPU_TRAP_NMI)
154 && !cpus_equal(v->cpu_affinity_tmp, v->cpu_affinity))
155 vcpu_set_affinity(v, &v->cpu_affinity_tmp);
157 /* Restore previous trap priority */
158 v->trap_priority = v->old_trap_priority;
160 /* Restore upcall mask from supplied EFLAGS.IF. */
161 vcpu_info(v, evtchn_upcall_mask) = !(eflags & X86_EFLAGS_IF);
163 /*
164 * The hypercall exit path will overwrite EAX with this return
165 * value.
166 */
167 return regs->_eax;
169 exit_and_crash:
170 gdprintk(XENLOG_ERR, "Fatal error\n");
171 domain_crash(v->domain);
172 return 0;
173 }
175 static long compat_register_guest_callback(
176 struct compat_callback_register *reg)
177 {
178 long ret = 0;
179 struct vcpu *v = current;
181 fixup_guest_code_selector(v->domain, reg->address.cs);
183 switch ( reg->type )
184 {
185 case CALLBACKTYPE_event:
186 v->arch.guest_context.event_callback_cs = reg->address.cs;
187 v->arch.guest_context.event_callback_eip = reg->address.eip;
188 break;
190 case CALLBACKTYPE_failsafe:
191 v->arch.guest_context.failsafe_callback_cs = reg->address.cs;
192 v->arch.guest_context.failsafe_callback_eip = reg->address.eip;
193 if ( reg->flags & CALLBACKF_mask_events )
194 set_bit(_VGCF_failsafe_disables_events,
195 &v->arch.guest_context.flags);
196 else
197 clear_bit(_VGCF_failsafe_disables_events,
198 &v->arch.guest_context.flags);
199 break;
201 case CALLBACKTYPE_syscall32:
202 v->arch.syscall32_callback_cs = reg->address.cs;
203 v->arch.syscall32_callback_eip = reg->address.eip;
204 v->arch.syscall32_disables_events =
205 (reg->flags & CALLBACKF_mask_events) != 0;
206 break;
208 case CALLBACKTYPE_sysenter:
209 v->arch.sysenter_callback_cs = reg->address.cs;
210 v->arch.sysenter_callback_eip = reg->address.eip;
211 v->arch.sysenter_disables_events =
212 (reg->flags & CALLBACKF_mask_events) != 0;
213 break;
215 case CALLBACKTYPE_nmi:
216 ret = register_guest_nmi_callback(reg->address.eip);
217 break;
219 default:
220 ret = -ENOSYS;
221 break;
222 }
224 return ret;
225 }
227 static long compat_unregister_guest_callback(
228 struct compat_callback_unregister *unreg)
229 {
230 long ret;
232 switch ( unreg->type )
233 {
234 case CALLBACKTYPE_event:
235 case CALLBACKTYPE_failsafe:
236 case CALLBACKTYPE_syscall32:
237 case CALLBACKTYPE_sysenter:
238 ret = -EINVAL;
239 break;
241 case CALLBACKTYPE_nmi:
242 ret = unregister_guest_nmi_callback();
243 break;
245 default:
246 ret = -ENOSYS;
247 break;
248 }
250 return ret;
251 }
254 long compat_callback_op(int cmd, XEN_GUEST_HANDLE(void) arg)
255 {
256 long ret;
258 switch ( cmd )
259 {
260 case CALLBACKOP_register:
261 {
262 struct compat_callback_register reg;
264 ret = -EFAULT;
265 if ( copy_from_guest(&reg, arg, 1) )
266 break;
268 ret = compat_register_guest_callback(&reg);
269 }
270 break;
272 case CALLBACKOP_unregister:
273 {
274 struct compat_callback_unregister unreg;
276 ret = -EFAULT;
277 if ( copy_from_guest(&unreg, arg, 1) )
278 break;
280 ret = compat_unregister_guest_callback(&unreg);
281 }
282 break;
284 default:
285 ret = -EINVAL;
286 break;
287 }
289 return ret;
290 }
292 long compat_set_callbacks(unsigned long event_selector,
293 unsigned long event_address,
294 unsigned long failsafe_selector,
295 unsigned long failsafe_address)
296 {
297 struct compat_callback_register event = {
298 .type = CALLBACKTYPE_event,
299 .address = {
300 .cs = event_selector,
301 .eip = event_address
302 }
303 };
304 struct compat_callback_register failsafe = {
305 .type = CALLBACKTYPE_failsafe,
306 .address = {
307 .cs = failsafe_selector,
308 .eip = failsafe_address
309 }
310 };
312 compat_register_guest_callback(&event);
313 compat_register_guest_callback(&failsafe);
315 return 0;
316 }
318 DEFINE_XEN_GUEST_HANDLE(trap_info_compat_t);
320 int compat_set_trap_table(XEN_GUEST_HANDLE(trap_info_compat_t) traps)
321 {
322 struct compat_trap_info cur;
323 struct trap_info *dst = current->arch.guest_context.trap_ctxt;
324 long rc = 0;
326 /* If no table is presented then clear the entire virtual IDT. */
327 if ( guest_handle_is_null(traps) )
328 {
329 memset(dst, 0, 256 * sizeof(*dst));
330 return 0;
331 }
333 for ( ; ; )
334 {
335 if ( hypercall_preempt_check() )
336 {
337 rc = hypercall_create_continuation(
338 __HYPERVISOR_set_trap_table, "h", traps);
339 break;
340 }
342 if ( copy_from_guest(&cur, traps, 1) )
343 {
344 rc = -EFAULT;
345 break;
346 }
348 if ( cur.address == 0 )
349 break;
351 fixup_guest_code_selector(current->domain, cur.cs);
353 XLAT_trap_info(dst + cur.vector, &cur);
355 if ( cur.vector == 0x80 )
356 init_int80_direct_trap(current);
358 guest_handle_add_offset(traps, 1);
359 }
361 return rc;
362 }
364 #endif /* CONFIG_COMPAT */
366 static void hypercall_page_initialise_ring1_kernel(void *hypercall_page)
367 {
368 char *p;
369 int i;
371 /* Fill in all the transfer points with template machine code. */
373 for ( i = 0; i < (PAGE_SIZE / 32); i++ )
374 {
375 p = (char *)(hypercall_page + (i * 32));
376 *(u8 *)(p+ 0) = 0xb8; /* mov $<i>,%eax */
377 *(u32 *)(p+ 1) = i;
378 *(u16 *)(p+ 5) = 0x82cd; /* int $0x82 */
379 *(u8 *)(p+ 7) = 0xc3; /* ret */
380 }
382 /*
383 * HYPERVISOR_iret is special because it doesn't return and expects a
384 * special stack frame. Guests jump at this transfer point instead of
385 * calling it.
386 */
387 p = (char *)(hypercall_page + (__HYPERVISOR_iret * 32));
388 *(u8 *)(p+ 0) = 0x50; /* push %eax */
389 *(u8 *)(p+ 1) = 0xb8; /* mov $__HYPERVISOR_iret,%eax */
390 *(u32 *)(p+ 2) = __HYPERVISOR_iret;
391 *(u16 *)(p+ 6) = 0x82cd; /* int $0x82 */
392 }
394 /*
395 * Local variables:
396 * mode: C
397 * c-set-style: "BSD"
398 * c-basic-offset: 4
399 * tab-width: 4
400 * indent-tabs-mode: nil
401 * End:
402 */