panic() cleanup.
[minix.git] / kernel / arch / i386 / exception.c
blob004b67a05781b2a817ac4fa2f34bc225d173eb91
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.h"
7 #include "proto.h"
8 #include <signal.h>
9 #include <string.h>
10 #include "../../proc.h"
11 #include "../../proto.h"
13 extern int vm_copy_in_progress, catch_pagefaults;
14 extern struct proc *vm_copy_from, *vm_copy_to;
16 void pagefault( struct proc *pr,
17 struct exception_frame * frame,
18 int is_nested)
20 int in_physcopy = 0;
22 reg_t pagefaultcr2;
24 vmassert(frame);
26 pagefaultcr2 = read_cr2();
28 #if 0
29 printf("kernel: pagefault in pr %d, addr 0x%lx, his cr3 0x%lx, actual cr3 0x%lx\n",
30 pr->p_endpoint, pagefaultcr2, pr->p_seg.p_cr3, read_cr3());
31 #endif
33 if(pr->p_seg.p_cr3) {
34 vmassert(pr->p_seg.p_cr3 == read_cr3());
37 in_physcopy = (frame->eip > (vir_bytes) phys_copy) &&
38 (frame->eip < (vir_bytes) phys_copy_fault);
40 if((is_nested || iskernelp(pr)) &&
41 catch_pagefaults && in_physcopy) {
42 #if 0
43 printf("pf caught! addr 0x%lx\n", pagefaultcr2);
44 #endif
45 if (is_nested) {
46 frame->eip = (reg_t) phys_copy_fault_in_kernel;
48 else {
49 pr->p_reg.pc = (reg_t) phys_copy_fault;
50 pr->p_reg.retreg = pagefaultcr2;
53 return;
56 /* System processes that don't have their own page table can't
57 * have page faults. VM does have its own page table but also
58 * can't have page faults (because VM has to handle them).
60 if(is_nested || (pr->p_endpoint <= INIT_PROC_NR &&
61 !(pr->p_misc_flags & MF_FULLVM)) || pr->p_endpoint == VM_PROC_NR) {
62 /* Page fault we can't / don't want to
63 * handle.
65 printf("pagefault for process %d ('%s'), pc = 0x%x, addr = 0x%x, flags = 0x%x, is_nested %d\n",
66 pr->p_endpoint, pr->p_name, pr->p_reg.pc,
67 pagefaultcr2, frame->errcode, is_nested);
68 proc_stacktrace(pr);
69 if(pr->p_endpoint != SYSTEM) {
70 proc_stacktrace(proc_addr(SYSTEM));
72 printf("pc of pagefault: 0x%lx\n", frame->eip);
73 panic("page fault in system process: %d", pr->p_endpoint);
75 return;
78 /* Don't schedule this process until pagefault is handled. */
79 vmassert(pr->p_seg.p_cr3 == read_cr3());
80 vmassert(!RTS_ISSET(pr, RTS_PAGEFAULT));
81 RTS_SET(pr, RTS_PAGEFAULT);
83 /* Save pagefault details, suspend process,
84 * add process to pagefault chain,
85 * and tell VM there is a pagefault to be
86 * handled.
88 pr->p_pagefault.pf_virtual = pagefaultcr2;
89 pr->p_pagefault.pf_flags = frame->errcode;
90 pr->p_nextpagefault = pagefaults;
91 pagefaults = pr;
93 mini_notify(proc_addr(HARDWARE), VM_PROC_NR);
95 return;
98 /*===========================================================================*
99 * exception *
100 *===========================================================================*/
101 PUBLIC void exception_handler(int is_nested, struct exception_frame * frame)
103 /* An exception or unexpected interrupt has occurred. */
105 struct ex_s {
106 char *msg;
107 int signum;
108 int minprocessor;
110 static struct ex_s ex_data[] = {
111 { "Divide error", SIGFPE, 86 },
112 { "Debug exception", SIGTRAP, 86 },
113 { "Nonmaskable interrupt", SIGBUS, 86 },
114 { "Breakpoint", SIGEMT, 86 },
115 { "Overflow", SIGFPE, 86 },
116 { "Bounds check", SIGFPE, 186 },
117 { "Invalid opcode", SIGILL, 186 },
118 { "Coprocessor not available", SIGFPE, 186 },
119 { "Double fault", SIGBUS, 286 },
120 { "Coprocessor segment overrun", SIGSEGV, 286 },
121 { "Invalid TSS", SIGSEGV, 286 },
122 { "Segment not present", SIGSEGV, 286 },
123 { "Stack exception", SIGSEGV, 286 }, /* STACK_FAULT already used */
124 { "General protection", SIGSEGV, 286 },
125 { "Page fault", SIGSEGV, 386 }, /* not close */
126 { NIL_PTR, SIGILL, 0 }, /* probably software trap */
127 { "Coprocessor error", SIGFPE, 386 },
128 { "Alignment check", SIGBUS, 386 },
129 { "Machine check", SIGBUS, 386 },
130 { "SIMD exception", SIGFPE, 386 },
132 register struct ex_s *ep;
133 struct proc *saved_proc;
135 /* Save proc_ptr, because it may be changed by debug statements. */
136 saved_proc = proc_ptr;
138 ep = &ex_data[frame->vector];
140 if (frame->vector == 2) { /* spurious NMI on some machines */
141 printf("got spurious NMI\n");
142 return;
146 * handle special cases for nested problems as they might be tricky or filter
147 * them out quickly if the traps are not nested
149 if (is_nested) {
151 * if a problem occured while copying a message from userspace because
152 * of a wrong pointer supplied by userland, handle it the only way we
153 * can handle it ...
155 if (((void*)frame->eip >= (void*)copy_msg_to_user &&
156 (void*)frame->eip <= (void*)__copy_msg_to_user_end) ||
157 ((void*)frame->eip >= (void*)copy_msg_from_user &&
158 (void*)frame->eip <= (void*)__copy_msg_from_user_end)) {
159 switch(frame->vector) {
160 /* these error are expected */
161 case PAGE_FAULT_VECTOR:
162 case PROTECTION_VECTOR:
163 frame->eip = (reg_t) __user_copy_msg_pointer_failure;
164 return;
165 default:
166 panic("Copy involving a user pointer failed unexpectedly!");
171 if(frame->vector == PAGE_FAULT_VECTOR) {
172 pagefault(saved_proc, frame, is_nested);
173 return;
176 /* If an exception occurs while running a process, the is_nested variable
177 * will be zero. Exceptions in interrupt handlers or system traps will make
178 * is_nested non-zero.
180 if (is_nested == 0 && ! iskernelp(saved_proc)) {
181 #if 0
184 printf(
185 "vec_nr= %d, trap_errno= 0x%lx, eip= 0x%lx, cs= 0x%x, eflags= 0x%lx\n",
186 frame->vector, (unsigned long)frame->errcode,
187 (unsigned long)frame->eip, frame->cs,
188 (unsigned long)frame->eflags);
189 printseg("cs: ", 1, saved_proc, frame->cs);
190 printseg("ds: ", 0, saved_proc, saved_proc->p_reg.ds);
191 if(saved_proc->p_reg.ds != saved_proc->p_reg.ss) {
192 printseg("ss: ", 0, saved_proc, saved_proc->p_reg.ss);
194 proc_stacktrace(saved_proc);
197 #endif
198 cause_sig(proc_nr(saved_proc), ep->signum);
199 return;
202 /* Exception in system code. This is not supposed to happen. */
203 if (ep->msg == NIL_PTR || machine.processor < ep->minprocessor)
204 printf("\nIntel-reserved exception %d\n", frame->vector);
205 else
206 printf("\n%s\n", ep->msg);
207 printf("is_nested = %d ", is_nested);
209 printf("vec_nr= %d, trap_errno= 0x%x, eip= 0x%x, cs= 0x%x, eflags= 0x%x trap_esp 0x%08x\n",
210 frame->vector, frame->errcode, frame->eip, frame->cs, frame->eflags, frame);
211 /* TODO should we enable this only when compiled for some debug mode? */
212 if (saved_proc) {
213 printf("scheduled was: process %d (%s), ", proc_nr(saved_proc), saved_proc->p_name);
214 printf("pc = %u:0x%x\n", (unsigned) saved_proc->p_reg.cs,
215 (unsigned) saved_proc->p_reg.pc);
216 proc_stacktrace(saved_proc);
218 panic("exception in a kernel task: %d", saved_proc->p_endpoint);
220 else {
221 /* in an early stage of boot process we don't have processes yet */
222 panic("exception in kernel while booting");
226 /*===========================================================================*
227 * stacktrace *
228 *===========================================================================*/
229 PUBLIC void proc_stacktrace(struct proc *whichproc)
231 reg_t v_bp, v_pc, v_hbp;
232 int iskernel;
234 v_bp = whichproc->p_reg.fp;
236 iskernel = iskernelp(whichproc);
238 printf("%-8.8s %6d 0x%lx ",
239 whichproc->p_name, whichproc->p_endpoint, whichproc->p_reg.pc);
241 while(v_bp) {
243 #define PRCOPY(pr, pv, v, n) \
244 (iskernel ? (memcpy((char *) v, (char *) pv, n), OK) : \
245 data_copy(pr->p_endpoint, pv, KERNEL, (vir_bytes) (v), n))
247 if(PRCOPY(whichproc, v_bp, &v_hbp, sizeof(v_hbp)) != OK) {
248 printf("(v_bp 0x%lx ?)", v_bp);
249 break;
251 if(PRCOPY(whichproc, v_bp + sizeof(v_pc), &v_pc, sizeof(v_pc)) != OK) {
252 printf("(v_pc 0x%lx ?)", v_bp + sizeof(v_pc));
253 break;
255 printf("0x%lx ", (unsigned long) v_pc);
256 if(v_hbp != 0 && v_hbp <= v_bp) {
257 printf("(hbp %lx ?)", v_hbp);
258 break;
260 v_bp = v_hbp;
262 printf("\n");