3.1.7 branch.
[minix.git] / kernel / arch / i386 / exception.c
blob89c5dbcb5fa1d2c1ad6877bf3a1827fbf4dd5315
1 /* This file contains a simple exception handler. Exceptions in user
2 * processes are converted to signals. Exceptions in a kernel task cause
3 * a panic.
4 */
6 #include "kernel/kernel.h"
7 #include "proto.h"
8 #include <signal.h>
9 #include <string.h>
10 #include <assert.h>
11 #include "kernel/proc.h"
12 #include "kernel/proto.h"
14 extern int catch_pagefaults = 0;
16 PRIVATE void pagefault( struct proc *pr,
17 struct exception_frame * frame,
18 int is_nested)
20 int in_physcopy = 0;
22 reg_t pagefaultcr2;
23 message m_pagefault;
24 int err;
26 assert(frame);
28 pagefaultcr2 = read_cr2();
30 #if 0
31 printf("kernel: pagefault in pr %d, addr 0x%lx, his cr3 0x%lx, actual cr3 0x%lx\n",
32 pr->p_endpoint, pagefaultcr2, pr->p_seg.p_cr3, read_cr3());
33 #endif
35 if(pr->p_seg.p_cr3) {
36 assert(pr->p_seg.p_cr3 == read_cr3());
39 in_physcopy = (frame->eip > (vir_bytes) phys_copy) &&
40 (frame->eip < (vir_bytes) phys_copy_fault);
42 if((is_nested || iskernelp(pr)) &&
43 catch_pagefaults && in_physcopy) {
44 #if 0
45 printf("pf caught! addr 0x%lx\n", pagefaultcr2);
46 #endif
47 if (is_nested) {
48 frame->eip = (reg_t) phys_copy_fault_in_kernel;
50 else {
51 pr->p_reg.pc = (reg_t) phys_copy_fault;
52 pr->p_reg.retreg = pagefaultcr2;
55 return;
58 if(is_nested) {
59 panic("pagefault in kernel at pc 0x%lx address 0x%lx", frame->eip, pagefaultcr2);
62 /* System processes that don't have their own page table can't
63 * have page faults. VM does have its own page table but also
64 * can't have page faults (because VM has to handle them).
66 if((pr->p_endpoint <= INIT_PROC_NR &&
67 !(pr->p_misc_flags & MF_FULLVM)) || pr->p_endpoint == VM_PROC_NR) {
68 /* Page fault we can't / don't want to
69 * handle.
71 printf("pagefault for process %d ('%s'), pc = 0x%x, addr = 0x%x, flags = 0x%x, is_nested %d\n",
72 pr->p_endpoint, pr->p_name, pr->p_reg.pc,
73 pagefaultcr2, frame->errcode, is_nested);
74 proc_stacktrace(pr);
75 printf("pc of pagefault: 0x%lx\n", frame->eip);
76 panic("page fault in system process: %d", pr->p_endpoint);
78 return;
81 /* Don't schedule this process until pagefault is handled. */
82 assert(pr->p_seg.p_cr3 == read_cr3());
83 assert(!RTS_ISSET(pr, RTS_PAGEFAULT));
84 RTS_SET(pr, RTS_PAGEFAULT);
86 /* tell Vm about the pagefault */
87 m_pagefault.m_source = pr->p_endpoint;
88 m_pagefault.m_type = VM_PAGEFAULT;
89 m_pagefault.VPF_ADDR = pagefaultcr2;
90 m_pagefault.VPF_FLAGS = frame->errcode;
92 if ((err = mini_send(pr, VM_PROC_NR,
93 &m_pagefault, FROM_KERNEL))) {
94 panic("WARNING: pagefault: mini_send returned %d\n", err);
97 return;
100 /*===========================================================================*
101 * exception *
102 *===========================================================================*/
103 PUBLIC void exception_handler(int is_nested, struct exception_frame * frame)
105 /* An exception or unexpected interrupt has occurred. */
107 struct ex_s {
108 char *msg;
109 int signum;
110 int minprocessor;
112 static struct ex_s ex_data[] = {
113 { "Divide error", SIGFPE, 86 },
114 { "Debug exception", SIGTRAP, 86 },
115 { "Nonmaskable interrupt", SIGBUS, 86 },
116 { "Breakpoint", SIGEMT, 86 },
117 { "Overflow", SIGFPE, 86 },
118 { "Bounds check", SIGFPE, 186 },
119 { "Invalid opcode", SIGILL, 186 },
120 { "Coprocessor not available", SIGFPE, 186 },
121 { "Double fault", SIGBUS, 286 },
122 { "Coprocessor segment overrun", SIGSEGV, 286 },
123 { "Invalid TSS", SIGSEGV, 286 },
124 { "Segment not present", SIGSEGV, 286 },
125 { "Stack exception", SIGSEGV, 286 }, /* STACK_FAULT already used */
126 { "General protection", SIGSEGV, 286 },
127 { "Page fault", SIGSEGV, 386 }, /* not close */
128 { NULL, SIGILL, 0 }, /* probably software trap */
129 { "Coprocessor error", SIGFPE, 386 },
130 { "Alignment check", SIGBUS, 386 },
131 { "Machine check", SIGBUS, 386 },
132 { "SIMD exception", SIGFPE, 386 },
134 register struct ex_s *ep;
135 struct proc *saved_proc;
137 /* Save proc_ptr, because it may be changed by debug statements. */
138 saved_proc = proc_ptr;
140 ep = &ex_data[frame->vector];
142 if (frame->vector == 2) { /* spurious NMI on some machines */
143 printf("got spurious NMI\n");
144 return;
148 * handle special cases for nested problems as they might be tricky or filter
149 * them out quickly if the traps are not nested
151 if (is_nested) {
153 * if a problem occured while copying a message from userspace because
154 * of a wrong pointer supplied by userland, handle it the only way we
155 * can handle it ...
157 if (((void*)frame->eip >= (void*)copy_msg_to_user &&
158 (void*)frame->eip <= (void*)__copy_msg_to_user_end) ||
159 ((void*)frame->eip >= (void*)copy_msg_from_user &&
160 (void*)frame->eip <= (void*)__copy_msg_from_user_end)) {
161 switch(frame->vector) {
162 /* these error are expected */
163 case PAGE_FAULT_VECTOR:
164 case PROTECTION_VECTOR:
165 frame->eip = (reg_t) __user_copy_msg_pointer_failure;
166 return;
167 default:
168 panic("Copy involving a user pointer failed unexpectedly!");
173 if(frame->vector == PAGE_FAULT_VECTOR) {
174 pagefault(saved_proc, frame, is_nested);
175 return;
178 /* If an exception occurs while running a process, the is_nested variable
179 * will be zero. Exceptions in interrupt handlers or system traps will make
180 * is_nested non-zero.
182 if (is_nested == 0 && ! iskernelp(saved_proc)) {
183 #if 0
186 printf(
187 "vec_nr= %d, trap_errno= 0x%lx, eip= 0x%lx, cs= 0x%x, eflags= 0x%lx\n",
188 frame->vector, (unsigned long)frame->errcode,
189 (unsigned long)frame->eip, frame->cs,
190 (unsigned long)frame->eflags);
191 printseg("cs: ", 1, saved_proc, frame->cs);
192 printseg("ds: ", 0, saved_proc, saved_proc->p_reg.ds);
193 if(saved_proc->p_reg.ds != saved_proc->p_reg.ss) {
194 printseg("ss: ", 0, saved_proc, saved_proc->p_reg.ss);
196 proc_stacktrace(saved_proc);
199 #endif
200 cause_sig(proc_nr(saved_proc), ep->signum);
201 return;
204 /* Exception in system code. This is not supposed to happen. */
205 if (ep->msg == NULL || machine.processor < ep->minprocessor)
206 printf("\nIntel-reserved exception %d\n", frame->vector);
207 else
208 printf("\n%s\n", ep->msg);
209 printf("is_nested = %d ", is_nested);
211 printf("vec_nr= %d, trap_errno= 0x%x, eip= 0x%x, "
212 "cs= 0x%x, eflags= 0x%x trap_esp 0x%08x\n",
213 frame->vector, frame->errcode, frame->eip,
214 frame->cs, frame->eflags, frame);
215 printf("KERNEL registers :\n");
216 printf(
217 "\t%%eax 0x%08x %%ebx 0x%08x %%ecx 0x%08x %%edx 0x%08x\n"
218 "\t%%esp 0x%08x %%ebp 0x%08x %%esi 0x%08x %%edi 0x%08x\n",
219 ((u32_t *)frame)[-1],
220 ((u32_t *)frame)[-2],
221 ((u32_t *)frame)[-3],
222 ((u32_t *)frame)[-4],
223 ((u32_t *)frame)[-5],
224 ((u32_t *)frame)[-6],
225 ((u32_t *)frame)[-7],
226 ((u32_t *)frame)[-8]
228 printseg("ker cs: ", 1, NULL, frame->cs);
229 printseg("ker ds: ", 0, NULL, DS_SELECTOR);
230 /* TODO should we enable this only when compiled for some debug mode? */
231 if (saved_proc) {
232 printf("scheduled was: process %d (%s), ", proc_nr(saved_proc), saved_proc->p_name);
233 printf("pc = %u:0x%x\n", (unsigned) saved_proc->p_reg.cs,
234 (unsigned) saved_proc->p_reg.pc);
235 proc_stacktrace(saved_proc);
237 panic("Unhandled kernel exception");
239 else {
240 /* in an early stage of boot process we don't have processes yet */
241 panic("exception in kernel while booting");
245 /*===========================================================================*
246 * stacktrace *
247 *===========================================================================*/
248 PUBLIC void proc_stacktrace(struct proc *whichproc)
250 reg_t v_bp, v_pc, v_hbp;
251 int iskernel;
253 v_bp = whichproc->p_reg.fp;
255 iskernel = iskernelp(whichproc);
257 printf("%-8.8s %6d 0x%lx ",
258 whichproc->p_name, whichproc->p_endpoint, whichproc->p_reg.pc);
260 while(v_bp) {
262 #define PRCOPY(pr, pv, v, n) \
263 (iskernel ? (memcpy((char *) v, (char *) pv, n), OK) : \
264 data_copy(pr->p_endpoint, pv, KERNEL, (vir_bytes) (v), n))
266 if(PRCOPY(whichproc, v_bp, &v_hbp, sizeof(v_hbp)) != OK) {
267 printf("(v_bp 0x%lx ?)", v_bp);
268 break;
270 if(PRCOPY(whichproc, v_bp + sizeof(v_pc), &v_pc, sizeof(v_pc)) != OK) {
271 printf("(v_pc 0x%lx ?)", v_bp + sizeof(v_pc));
272 break;
274 printf("0x%lx ", (unsigned long) v_pc);
275 if(v_hbp != 0 && v_hbp <= v_bp) {
276 printf("(hbp %lx ?)", v_hbp);
277 break;
279 v_bp = v_hbp;
281 printf("\n");