ia64/xen-unstable

view extras/mini-os/arch/x86/traps.c @ 18106:f4135a620f59

mini-os: add stack walking debug

Signed-off-by: Samuel Thibault <samuel.thibault@eu.citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Fri Jul 18 14:09:14 2008 +0100 (2008-07-18)
parents 2197a263a300
children
line source
2 #include <os.h>
3 #include <traps.h>
4 #include <hypervisor.h>
5 #include <mm.h>
6 #include <lib.h>
7 #include <sched.h>
9 /*
10 * These are assembler stubs in entry.S.
11 * They are the actual entry points for virtual exceptions.
12 */
13 void divide_error(void);
14 void debug(void);
15 void int3(void);
16 void overflow(void);
17 void bounds(void);
18 void invalid_op(void);
19 void device_not_available(void);
20 void coprocessor_segment_overrun(void);
21 void invalid_TSS(void);
22 void segment_not_present(void);
23 void stack_segment(void);
24 void general_protection(void);
25 void page_fault(void);
26 void coprocessor_error(void);
27 void simd_coprocessor_error(void);
28 void alignment_check(void);
29 void spurious_interrupt_bug(void);
30 void machine_check(void);
33 void dump_regs(struct pt_regs *regs)
34 {
35 printk("Thread: %s\n", current->name);
36 #ifdef __i386__
37 printk("EIP: %x, EFLAGS %x.\n", regs->eip, regs->eflags);
38 printk("EBX: %08x ECX: %08x EDX: %08x\n",
39 regs->ebx, regs->ecx, regs->edx);
40 printk("ESI: %08x EDI: %08x EBP: %08x EAX: %08x\n",
41 regs->esi, regs->edi, regs->ebp, regs->eax);
42 printk("DS: %04x ES: %04x orig_eax: %08x, eip: %08x\n",
43 regs->xds, regs->xes, regs->orig_eax, regs->eip);
44 printk("CS: %04x EFLAGS: %08x esp: %08x ss: %04x\n",
45 regs->xcs, regs->eflags, regs->esp, regs->xss);
46 #else
47 printk("RIP: %04lx:[<%016lx>] ", regs->cs & 0xffff, regs->rip);
48 printk("\nRSP: %04lx:%016lx EFLAGS: %08lx\n",
49 regs->ss, regs->rsp, regs->eflags);
50 printk("RAX: %016lx RBX: %016lx RCX: %016lx\n",
51 regs->rax, regs->rbx, regs->rcx);
52 printk("RDX: %016lx RSI: %016lx RDI: %016lx\n",
53 regs->rdx, regs->rsi, regs->rdi);
54 printk("RBP: %016lx R08: %016lx R09: %016lx\n",
55 regs->rbp, regs->r8, regs->r9);
56 printk("R10: %016lx R11: %016lx R12: %016lx\n",
57 regs->r10, regs->r11, regs->r12);
58 printk("R13: %016lx R14: %016lx R15: %016lx\n",
59 regs->r13, regs->r14, regs->r15);
60 #endif
61 }
63 static void do_trap(int trapnr, char *str, struct pt_regs * regs, unsigned long error_code)
64 {
65 printk("FATAL: Unhandled Trap %d (%s), error code=0x%lx\n", trapnr, str, error_code);
66 printk("Regs address %p\n", regs);
67 dump_regs(regs);
68 do_exit();
69 }
71 #define DO_ERROR(trapnr, str, name) \
72 void do_##name(struct pt_regs * regs, unsigned long error_code) \
73 { \
74 do_trap(trapnr, str, regs, error_code); \
75 }
77 #define DO_ERROR_INFO(trapnr, str, name, sicode, siaddr) \
78 void do_##name(struct pt_regs * regs, unsigned long error_code) \
79 { \
80 do_trap(trapnr, str, regs, error_code); \
81 }
83 DO_ERROR_INFO( 0, "divide error", divide_error, FPE_INTDIV, regs->eip)
84 DO_ERROR( 3, "int3", int3)
85 DO_ERROR( 4, "overflow", overflow)
86 DO_ERROR( 5, "bounds", bounds)
87 DO_ERROR_INFO( 6, "invalid operand", invalid_op, ILL_ILLOPN, regs->eip)
88 DO_ERROR( 7, "device not available", device_not_available)
89 DO_ERROR( 9, "coprocessor segment overrun", coprocessor_segment_overrun)
90 DO_ERROR(10, "invalid TSS", invalid_TSS)
91 DO_ERROR(11, "segment not present", segment_not_present)
92 DO_ERROR(12, "stack segment", stack_segment)
93 DO_ERROR_INFO(17, "alignment check", alignment_check, BUS_ADRALN, 0)
94 DO_ERROR(18, "machine check", machine_check)
96 void page_walk(unsigned long virt_address)
97 {
98 pgentry_t *tab = (pgentry_t *)start_info.pt_base, page;
99 unsigned long addr = virt_address;
100 printk("Pagetable walk from virt %lx, base %lx:\n", virt_address, start_info.pt_base);
102 #if defined(__x86_64__)
103 page = tab[l4_table_offset(addr)];
104 tab = pte_to_virt(page);
105 printk(" L4 = %"PRIpte" (%p) [offset = %lx]\n", page, tab, l4_table_offset(addr));
106 #endif
107 page = tab[l3_table_offset(addr)];
108 tab = pte_to_virt(page);
109 printk(" L3 = %"PRIpte" (%p) [offset = %lx]\n", page, tab, l3_table_offset(addr));
110 page = tab[l2_table_offset(addr)];
111 tab = pte_to_virt(page);
112 printk(" L2 = %"PRIpte" (%p) [offset = %lx]\n", page, tab, l2_table_offset(addr));
114 page = tab[l1_table_offset(addr)];
115 printk(" L1 = %"PRIpte" [offset = %lx]\n", page, l1_table_offset(addr));
117 }
119 static int handle_cow(unsigned long addr) {
120 pgentry_t *tab = (pgentry_t *)start_info.pt_base, page;
121 unsigned long new_page;
122 int rc;
124 #if defined(__x86_64__)
125 page = tab[l4_table_offset(addr)];
126 if (!(page & _PAGE_PRESENT))
127 return 0;
128 tab = pte_to_virt(page);
129 #endif
130 page = tab[l3_table_offset(addr)];
131 if (!(page & _PAGE_PRESENT))
132 return 0;
133 tab = pte_to_virt(page);
135 page = tab[l2_table_offset(addr)];
136 if (!(page & _PAGE_PRESENT))
137 return 0;
138 tab = pte_to_virt(page);
140 page = tab[l1_table_offset(addr)];
141 if (!(page & _PAGE_PRESENT))
142 return 0;
143 /* Only support CoW for the zero page. */
144 if (PHYS_PFN(page) != mfn_zero)
145 return 0;
147 new_page = alloc_pages(0);
148 memset((void*) new_page, 0, PAGE_SIZE);
150 rc = HYPERVISOR_update_va_mapping(addr & PAGE_MASK, __pte(virt_to_mach(new_page) | L1_PROT), UVMF_INVLPG);
151 if (!rc)
152 return 1;
154 printk("Map zero page to %lx failed: %d.\n", addr, rc);
155 return 0;
156 }
158 static void do_stack_walk(unsigned long frame_base)
159 {
160 unsigned long *frame = (void*) frame_base;
161 printk("base is %#lx ", frame_base);
162 printk("caller is %#lx\n", frame[1]);
163 if (frame[0])
164 do_stack_walk(frame[0]);
165 }
167 void stack_walk(void)
168 {
169 unsigned long bp;
170 #ifdef __x86_64__
171 asm("movq %%rbp, %0":"=r"(bp));
172 #else
173 asm("movl %%ebp, %0":"=r"(bp));
174 #endif
175 do_stack_walk(bp);
176 }
178 static void dump_mem(unsigned long addr)
179 {
180 unsigned long i;
181 if (addr < PAGE_SIZE)
182 return;
184 for (i = ((addr)-16 ) & ~15; i < (((addr)+48 ) & ~15); i++)
185 {
186 if (!(i%16))
187 printk("\n%lx:", i);
188 printk(" %02x", *(unsigned char *)i);
189 }
190 printk("\n");
191 }
192 #define read_cr2() \
193 (HYPERVISOR_shared_info->vcpu_info[smp_processor_id()].arch.cr2)
195 static int handling_pg_fault = 0;
197 void do_page_fault(struct pt_regs *regs, unsigned long error_code)
198 {
199 unsigned long addr = read_cr2();
200 struct sched_shutdown sched_shutdown = { .reason = SHUTDOWN_crash };
202 if ((error_code & TRAP_PF_WRITE) && handle_cow(addr))
203 return;
205 /* If we are already handling a page fault, and got another one
206 that means we faulted in pagetable walk. Continuing here would cause
207 a recursive fault */
208 if(handling_pg_fault == 1)
209 {
210 printk("Page fault in pagetable walk (access to invalid memory?).\n");
211 HYPERVISOR_sched_op(SCHEDOP_shutdown, &sched_shutdown);
212 }
213 handling_pg_fault++;
214 barrier();
216 #if defined(__x86_64__)
217 printk("Page fault at linear address %p, rip %p, regs %p, sp %p, our_sp %p, code %lx\n",
218 addr, regs->rip, regs, regs->rsp, &addr, error_code);
219 #else
220 printk("Page fault at linear address %p, eip %p, regs %p, sp %p, our_sp %p, code %lx\n",
221 addr, regs->eip, regs, regs->esp, &addr, error_code);
222 #endif
224 dump_regs(regs);
225 #if defined(__x86_64__)
226 do_stack_walk(regs->rbp);
227 dump_mem(regs->rsp);
228 dump_mem(regs->rbp);
229 dump_mem(regs->rip);
230 #else
231 do_stack_walk(regs->ebp);
232 dump_mem(regs->esp);
233 dump_mem(regs->ebp);
234 dump_mem(regs->eip);
235 #endif
236 page_walk(addr);
237 HYPERVISOR_sched_op(SCHEDOP_shutdown, &sched_shutdown);
238 /* We should never get here ... but still */
239 handling_pg_fault--;
240 }
242 void do_general_protection(struct pt_regs *regs, long error_code)
243 {
244 struct sched_shutdown sched_shutdown = { .reason = SHUTDOWN_crash };
245 #ifdef __i386__
246 printk("GPF eip: %p, error_code=%lx\n", regs->eip, error_code);
247 #else
248 printk("GPF rip: %p, error_code=%lx\n", regs->rip, error_code);
249 #endif
250 dump_regs(regs);
251 #if defined(__x86_64__)
252 do_stack_walk(regs->rbp);
253 dump_mem(regs->rsp);
254 dump_mem(regs->rbp);
255 dump_mem(regs->rip);
256 #else
257 do_stack_walk(regs->ebp);
258 dump_mem(regs->esp);
259 dump_mem(regs->ebp);
260 dump_mem(regs->eip);
261 #endif
262 HYPERVISOR_sched_op(SCHEDOP_shutdown, &sched_shutdown);
263 }
266 void do_debug(struct pt_regs * regs)
267 {
268 printk("Debug exception\n");
269 #define TF_MASK 0x100
270 regs->eflags &= ~TF_MASK;
271 dump_regs(regs);
272 do_exit();
273 }
275 void do_coprocessor_error(struct pt_regs * regs)
276 {
277 printk("Copro error\n");
278 dump_regs(regs);
279 do_exit();
280 }
282 void simd_math_error(void *eip)
283 {
284 printk("SIMD error\n");
285 }
287 void do_simd_coprocessor_error(struct pt_regs * regs)
288 {
289 printk("SIMD copro error\n");
290 }
292 void do_spurious_interrupt_bug(struct pt_regs * regs)
293 {
294 }
296 /*
297 * Submit a virtual IDT to teh hypervisor. This consists of tuples
298 * (interrupt vector, privilege ring, CS:EIP of handler).
299 * The 'privilege ring' field specifies the least-privileged ring that
300 * can trap to that vector using a software-interrupt instruction (INT).
301 */
302 static trap_info_t trap_table[] = {
303 { 0, 0, __KERNEL_CS, (unsigned long)divide_error },
304 { 1, 0, __KERNEL_CS, (unsigned long)debug },
305 { 3, 3, __KERNEL_CS, (unsigned long)int3 },
306 { 4, 3, __KERNEL_CS, (unsigned long)overflow },
307 { 5, 3, __KERNEL_CS, (unsigned long)bounds },
308 { 6, 0, __KERNEL_CS, (unsigned long)invalid_op },
309 { 7, 0, __KERNEL_CS, (unsigned long)device_not_available },
310 { 9, 0, __KERNEL_CS, (unsigned long)coprocessor_segment_overrun },
311 { 10, 0, __KERNEL_CS, (unsigned long)invalid_TSS },
312 { 11, 0, __KERNEL_CS, (unsigned long)segment_not_present },
313 { 12, 0, __KERNEL_CS, (unsigned long)stack_segment },
314 { 13, 0, __KERNEL_CS, (unsigned long)general_protection },
315 { 14, 0, __KERNEL_CS, (unsigned long)page_fault },
316 { 15, 0, __KERNEL_CS, (unsigned long)spurious_interrupt_bug },
317 { 16, 0, __KERNEL_CS, (unsigned long)coprocessor_error },
318 { 17, 0, __KERNEL_CS, (unsigned long)alignment_check },
319 { 19, 0, __KERNEL_CS, (unsigned long)simd_coprocessor_error },
320 { 0, 0, 0, 0 }
321 };
325 void trap_init(void)
326 {
327 HYPERVISOR_set_trap_table(trap_table);
328 }
330 void trap_fini(void)
331 {
332 HYPERVISOR_set_trap_table(NULL);
333 }