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.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
,
26 pagefaultcr2
= read_cr2();
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());
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
) {
43 printf("pf caught! addr 0x%lx\n", pagefaultcr2
);
46 frame
->eip
= (reg_t
) phys_copy_fault_in_kernel
;
49 pr
->p_reg
.pc
= (reg_t
) phys_copy_fault
;
50 pr
->p_reg
.retreg
= pagefaultcr2
;
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
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
);
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
);
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
88 pr
->p_pagefault
.pf_virtual
= pagefaultcr2
;
89 pr
->p_pagefault
.pf_flags
= frame
->errcode
;
90 pr
->p_nextpagefault
= pagefaults
;
93 mini_notify(proc_addr(HARDWARE
), VM_PROC_NR
);
98 /*===========================================================================*
100 *===========================================================================*/
101 PUBLIC
void exception_handler(int is_nested
, struct exception_frame
* frame
)
103 /* An exception or unexpected interrupt has occurred. */
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");
146 * handle special cases for nested problems as they might be tricky or filter
147 * them out quickly if the traps are not 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
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
;
166 panic("Copy involving a user pointer failed unexpectedly!");
171 if(frame
->vector
== PAGE_FAULT_VECTOR
) {
172 pagefault(saved_proc
, frame
, is_nested
);
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
)) {
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
);
198 cause_sig(proc_nr(saved_proc
), ep
->signum
);
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
);
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? */
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
);
221 /* in an early stage of boot process we don't have processes yet */
222 panic("exception in kernel while booting");
226 /*===========================================================================*
228 *===========================================================================*/
229 PUBLIC
void proc_stacktrace(struct proc
*whichproc
)
231 reg_t v_bp
, v_pc
, v_hbp
;
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
);
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
);
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
));
255 printf("0x%lx ", (unsigned long) v_pc
);
256 if(v_hbp
!= 0 && v_hbp
<= v_bp
) {
257 printf("(hbp %lx ?)", v_hbp
);