1 /* This file contains a simple exception handler. Exceptions in user
2 * processes are converted to signals. Exceptions in a kernel task cause
6 #include "kernel/kernel.h"
7 #include "arch_proto.h"
11 #include <machine/vm.h>
19 static struct ex_s ex_data
[] = {
20 { "Divide error", SIGFPE
, 86 },
21 { "Debug exception", SIGTRAP
, 86 },
22 { "Nonmaskable interrupt", SIGBUS
, 86 },
23 { "Breakpoint", SIGEMT
, 86 },
24 { "Overflow", SIGFPE
, 86 },
25 { "Bounds check", SIGFPE
, 186 },
26 { "Invalid opcode", SIGILL
, 186 },
27 { "Coprocessor not available", SIGFPE
, 186 },
28 { "Double fault", SIGBUS
, 286 },
29 { "Coprocessor segment overrun", SIGSEGV
, 286 },
30 { "Invalid TSS", SIGSEGV
, 286 },
31 { "Segment not present", SIGSEGV
, 286 },
32 { "Stack exception", SIGSEGV
, 286 }, /* STACK_FAULT already used */
33 { "General protection", SIGSEGV
, 286 },
34 { "Page fault", SIGSEGV
, 386 }, /* not close */
35 { NULL
, SIGILL
, 0 }, /* probably software trap */
36 { "Coprocessor error", SIGFPE
, 386 },
37 { "Alignment check", SIGBUS
, 386 },
38 { "Machine check", SIGBUS
, 386 },
39 { "SIMD exception", SIGFPE
, 386 },
42 static void inkernel_disaster(struct proc
*saved_proc
,
43 struct exception_frame
*frame
, struct ex_s
*ep
, int is_nested
);
45 extern int catch_pagefaults
;
47 static void proc_stacktrace_execute(struct proc
*whichproc
, reg_t v_bp
, reg_t pc
);
49 static void pagefault( struct proc
*pr
,
50 struct exception_frame
* frame
,
53 int in_physcopy
= 0, in_memset
= 0;
59 pagefaultcr2
= read_cr2();
62 printf("kernel: pagefault in pr %d, addr 0x%lx, his cr3 0x%lx, actual cr3 0x%lx\n",
63 pr
->p_endpoint
, pagefaultcr2
, pr
->p_seg
.p_cr3
, read_cr3());
66 in_physcopy
= (frame
->eip
> (vir_bytes
) phys_copy
) &&
67 (frame
->eip
< (vir_bytes
) phys_copy_fault
);
69 in_memset
= (frame
->eip
> (vir_bytes
) phys_memset
) &&
70 (frame
->eip
< (vir_bytes
) memset_fault
);
72 if((is_nested
|| iskernelp(pr
)) &&
73 catch_pagefaults
&& (in_physcopy
|| in_memset
)) {
75 printf("pf caught! addr 0x%lx\n", pagefaultcr2
);
80 frame
->eip
= (reg_t
) phys_copy_fault_in_kernel
;
82 frame
->eip
= (reg_t
) memset_fault_in_kernel
;
86 pr
->p_reg
.pc
= (reg_t
) phys_copy_fault
;
87 pr
->p_reg
.retreg
= pagefaultcr2
;
94 printf("pagefault in kernel at pc 0x%lx address 0x%lx\n",
95 frame
->eip
, pagefaultcr2
);
96 inkernel_disaster(pr
, frame
, NULL
, is_nested
);
99 /* VM can't handle page faults. */
100 if(pr
->p_endpoint
== VM_PROC_NR
) {
101 /* Page fault we can't / don't want to
104 printf("pagefault for VM on CPU %d, "
105 "pc = 0x%x, addr = 0x%x, flags = 0x%x, is_nested %d\n",
106 cpuid
, pr
->p_reg
.pc
, pagefaultcr2
, frame
->errcode
,
109 printf("pc of pagefault: 0x%lx\n", frame
->eip
);
110 panic("pagefault in VM");
115 /* Don't schedule this process until pagefault is handled. */
116 RTS_SET(pr
, RTS_PAGEFAULT
);
118 /* tell Vm about the pagefault */
119 m_pagefault
.m_source
= pr
->p_endpoint
;
120 m_pagefault
.m_type
= VM_PAGEFAULT
;
121 m_pagefault
.VPF_ADDR
= pagefaultcr2
;
122 m_pagefault
.VPF_FLAGS
= frame
->errcode
;
124 if ((err
= mini_send(pr
, VM_PROC_NR
,
125 &m_pagefault
, FROM_KERNEL
))) {
126 panic("WARNING: pagefault: mini_send returned %d\n", err
);
132 static void inkernel_disaster(struct proc
*saved_proc
,
133 struct exception_frame
* frame
, struct ex_s
*ep
,
139 printf("\nIntel-reserved exception %d\n", frame
->vector
);
141 printf("\n%s\n", ep
->msg
);
144 printf("cpu %d is_nested = %d ", cpuid
, is_nested
);
146 printf("vec_nr= %d, trap_errno= 0x%x, eip= 0x%x, "
147 "cs= 0x%x, eflags= 0x%x trap_esp 0x%08x\n",
148 frame
->vector
, frame
->errcode
, frame
->eip
,
149 frame
->cs
, frame
->eflags
, frame
);
150 printf("KERNEL registers :\n");
151 #define REG(n) (((u32_t *)frame)[-n])
153 "\t%%eax 0x%08x %%ebx 0x%08x %%ecx 0x%08x %%edx 0x%08x\n"
154 "\t%%esp 0x%08x %%ebp 0x%08x %%esi 0x%08x %%edi 0x%08x\n",
155 REG(1), REG(2), REG(3), REG(4),
156 REG(5), REG(6), REG(7), REG(8));
159 reg_t k_ebp
= REG(6);
160 printf("KERNEL stacktrace, starting with ebp = 0x%lx:\n", k_ebp
);
161 proc_stacktrace_execute(proc_addr(SYSTEM
), k_ebp
, frame
->eip
);
165 printf("scheduled was: process %d (%s), ", saved_proc
->p_endpoint
, saved_proc
->p_name
);
166 printf("pc = 0x%x\n", (unsigned) saved_proc
->p_reg
.pc
);
167 proc_stacktrace(saved_proc
);
169 panic("Unhandled kernel exception");
172 /* in an early stage of boot process we don't have processes yet */
173 panic("exception in kernel while booting, no saved_proc yet");
174 #endif /* USE_SYSDEBUG */
177 /*===========================================================================*
179 *===========================================================================*/
180 void exception_handler(int is_nested
, struct exception_frame
* frame
)
182 /* An exception or unexpected interrupt has occurred. */
183 register struct ex_s
*ep
;
184 struct proc
*saved_proc
;
186 /* Save proc_ptr, because it may be changed by debug statements. */
187 saved_proc
= get_cpulocal_var(proc_ptr
);
189 ep
= &ex_data
[frame
->vector
];
191 if (frame
->vector
== 2) { /* spurious NMI on some machines */
192 printf("got spurious NMI\n");
197 * handle special cases for nested problems as they might be tricky or filter
198 * them out quickly if the traps are not nested
202 * if a problem occured while copying a message from userspace because
203 * of a wrong pointer supplied by userland, handle it the only way we
206 if (((void*)frame
->eip
>= (void*)copy_msg_to_user
&&
207 (void*)frame
->eip
<= (void*)__copy_msg_to_user_end
) ||
208 ((void*)frame
->eip
>= (void*)copy_msg_from_user
&&
209 (void*)frame
->eip
<= (void*)__copy_msg_from_user_end
)) {
210 switch(frame
->vector
) {
211 /* these error are expected */
212 case PAGE_FAULT_VECTOR
:
213 case PROTECTION_VECTOR
:
214 frame
->eip
= (reg_t
) __user_copy_msg_pointer_failure
;
217 panic("Copy involving a user pointer failed unexpectedly!");
221 /* Pass any error resulting from restoring FPU state, as a FPU
222 * exception to the process.
224 if (((void*)frame
->eip
>= (void*)fxrstor
&&
225 (void *)frame
->eip
<= (void*)__fxrstor_end
) ||
226 ((void*)frame
->eip
>= (void*)frstor
&&
227 (void *)frame
->eip
<= (void*)__frstor_end
)) {
228 frame
->eip
= (reg_t
) __frstor_failure
;
232 if(frame
->vector
== DEBUG_VECTOR
233 && (saved_proc
->p_reg
.psw
& TRACEBIT
)
234 && (saved_proc
->p_seg
.p_kern_trap_style
== KTS_NONE
)) {
235 /* Getting a debug trap in the kernel is legitimate
236 * if a traced process entered the kernel using sysenter
237 * or syscall; the trap flag is not cleared then.
239 * It triggers on the first kernel entry so the trap
240 * style is still KTS_NONE.
243 frame
->eflags
&= ~TRACEBIT
;
247 /* If control passes, this case is not recognized as legitimate
248 * and we panic later on after all.
253 if(frame
->vector
== PAGE_FAULT_VECTOR
) {
254 pagefault(saved_proc
, frame
, is_nested
);
258 /* If an exception occurs while running a process, the is_nested variable
259 * will be zero. Exceptions in interrupt handlers or system traps will make
260 * is_nested non-zero.
262 if (is_nested
== 0 && ! iskernelp(saved_proc
)) {
267 "vec_nr= %d, trap_errno= 0x%lx, eip= 0x%lx, cs= 0x%x, eflags= 0x%lx\n",
268 frame
->vector
, (unsigned long)frame
->errcode
,
269 (unsigned long)frame
->eip
, frame
->cs
,
270 (unsigned long)frame
->eflags
);
271 proc_stacktrace(saved_proc
);
275 cause_sig(proc_nr(saved_proc
), ep
->signum
);
279 /* Exception in system code. This is not supposed to happen. */
280 inkernel_disaster(saved_proc
, frame
, ep
, is_nested
);
282 panic("return from inkernel_disaster");
286 /*===========================================================================*
287 * proc_stacktrace_execute *
288 *===========================================================================*/
289 static void proc_stacktrace_execute(struct proc
*whichproc
, reg_t v_bp
, reg_t pc
)
295 iskernel
= iskernelp(whichproc
);
297 printf("%-8.8s %6d 0x%lx ",
298 whichproc
->p_name
, whichproc
->p_endpoint
, pc
);
303 #define PRCOPY(pr, pv, v, n) \
304 (iskernel ? (memcpy((char *) v, (char *) pv, n), OK) : \
305 data_copy(pr->p_endpoint, pv, KERNEL, (vir_bytes) (v), n))
307 if(PRCOPY(whichproc
, v_bp
, &v_hbp
, sizeof(v_hbp
)) != OK
) {
308 printf("(v_bp 0x%lx ?)", v_bp
);
311 if(PRCOPY(whichproc
, v_bp
+ sizeof(v_pc
), &v_pc
, sizeof(v_pc
)) != OK
) {
312 printf("(v_pc 0x%lx ?)", v_bp
+ sizeof(v_pc
));
315 printf("0x%lx ", (unsigned long) v_pc
);
316 if(v_hbp
!= 0 && v_hbp
<= v_bp
) {
317 printf("(hbp 0x%lx ?)", v_hbp
);
322 printf("(truncated after %d steps) ", n
);
328 #endif /* USE_SYSDEBUG */
330 /*===========================================================================*
332 *===========================================================================*/
333 void proc_stacktrace(struct proc
*whichproc
)
337 if(whichproc
->p_seg
.p_kern_trap_style
== KTS_NONE
) {
338 printf("WARNING: stacktrace of running process\n");
341 switch(whichproc
->p_seg
.p_kern_trap_style
) {
345 u32_t sp
= whichproc
->p_reg
.sp
;
347 /* Full context is not available in the p_reg
348 * struct. Obtain it from the user's stack.
349 * The use stack pointer is always available.
350 * The fact that it's there, and the 16 byte offset,
351 * is a dependency on the trap code in
352 * kernel/arch/i386/usermapped_glo_ipc.S.
355 if(data_copy(whichproc
->p_endpoint
, sp
+16,
356 KERNEL
, (vir_bytes
) &use_bp
,
357 sizeof(use_bp
)) != OK
) {
358 printf("stacktrace: aborting, copy failed\n");
365 /* Full context is available; use the stored ebp */
366 use_bp
= whichproc
->p_reg
.fp
;
371 proc_stacktrace_execute(whichproc
, use_bp
, whichproc
->p_reg
.pc
);
372 #endif /* USE_SYSDEBUG */
375 void enable_fpu_exception(void)
377 u32_t cr0
= read_cr0();
378 if(!(cr0
& I386_CR0_TS
))
379 write_cr0(cr0
| I386_CR0_TS
);
382 void disable_fpu_exception(void)