breakpoint passed.
[mit-jos.git] / kern / trap.c
blob9c029fcb8c61c975162840a48adfe48db9a9d143
1 #include <inc/mmu.h>
2 #include <inc/x86.h>
3 #include <inc/assert.h>
5 #include <kern/pmap.h>
6 #include <kern/trap.h>
7 #include <kern/console.h>
8 #include <kern/monitor.h>
9 #include <kern/env.h>
10 #include <kern/syscall.h>
12 static struct Taskstate ts;
14 /* Interrupt descriptor table. (Must be built at run time because
15 * shifted function addresses can't be represented in relocation records.)
17 struct Gatedesc idt[256] = { { 0 } };
18 struct Pseudodesc idt_pd = {
19 sizeof(idt) - 1, (uint32_t) idt
23 static const char *trapname(int trapno)
25 static const char * const excnames[] = {
26 "Divide error",
27 "Debug",
28 "Non-Maskable Interrupt",
29 "Breakpoint",
30 "Overflow",
31 "BOUND Range Exceeded",
32 "Invalid Opcode",
33 "Device Not Available",
34 "Double Falt",
35 "Coprocessor Segment Overrun",
36 "Invalid TSS",
37 "Segment Not Present",
38 "Stack Fault",
39 "General Protection",
40 "Page Fault",
41 "(unknown trap)",
42 "x87 FPU Floating-Point Error",
43 "Alignment Check",
44 "Machine-Check",
45 "SIMD Floating-Point Exception"
48 if (trapno < sizeof(excnames)/sizeof(excnames[0]))
49 return excnames[trapno];
50 if (trapno == T_SYSCALL)
51 return "System call";
52 return "(unknown trap)";
56 void
57 idt_init(void)
59 extern struct Segdesc gdt[];
61 extern void divzero_entry();
62 extern void debug_entry();
63 extern void nmi_entry();
64 extern void brkpt_entry();
65 extern void oflow_entry();
66 extern void bound_entry();
67 extern void illop_entry();
68 extern void device_entry();
69 extern void dblflt_entry();
70 extern void tss_entry();
71 extern void segnp_entry();
72 extern void stack_entry();
73 extern void gpflt_entry();
74 extern void pgflt_entry();
75 extern void fperr_entry();
76 extern void align_entry();
77 extern void mchk_entry();
78 extern void simderr_entry();
80 // LAB 3: Your code here.
81 SETGATE(idt[T_DIVIDE], 1, GD_KT, divzero_entry, 0);
82 SETGATE(idt[T_DEBUG], 1, GD_KT, debug_entry, 0);
83 SETGATE(idt[T_NMI], 0, GD_KT, nmi_entry, 0);
84 SETGATE(idt[T_BRKPT], 1, GD_KT, brkpt_entry, 3);
85 SETGATE(idt[T_OFLOW], 1, GD_KT, oflow_entry, 0);
86 SETGATE(idt[T_BOUND], 1, GD_KT, bound_entry, 0);
87 SETGATE(idt[T_ILLOP], 1, GD_KT, illop_entry, 0);
88 SETGATE(idt[T_DEVICE], 1, GD_KT, device_entry, 0);
89 SETGATE(idt[T_DBLFLT], 1, GD_KT, dblflt_entry, 0);
90 SETGATE(idt[T_TSS], 1, GD_KT, tss_entry, 0);
91 SETGATE(idt[T_SEGNP], 1, GD_KT, segnp_entry, 0);
92 SETGATE(idt[T_STACK], 1, GD_KT, stack_entry, 0);
93 SETGATE(idt[T_GPFLT], 1, GD_KT, gpflt_entry, 0);
94 SETGATE(idt[T_PGFLT], 1, GD_KT, pgflt_entry, 0);
95 SETGATE(idt[T_FPERR], 1, GD_KT, fperr_entry, 0);
96 SETGATE(idt[T_ALIGN], 1, GD_KT, align_entry, 0);
97 SETGATE(idt[T_MCHK], 1, GD_KT, mchk_entry, 0);
98 SETGATE(idt[T_SIMDERR], 1, GD_KT, simderr_entry, 0);
100 // Setup a TSS so that we get the right stack
101 // when we trap to the kernel.
102 ts.ts_esp0 = KSTACKTOP;
103 ts.ts_ss0 = GD_KD;
105 // Initialize the TSS field of the gdt.
106 gdt[GD_TSS >> 3] = SEG16(STS_T32A, (uint32_t) (&ts),
107 sizeof(struct Taskstate), 0);
108 gdt[GD_TSS >> 3].sd_s = 0;
110 // Load the TSS
111 ltr(GD_TSS);
113 // Load the IDT
114 asm volatile("lidt idt_pd");
117 void
118 print_trapframe(struct Trapframe *tf)
120 cprintf("TRAP frame at %p\n", tf);
121 print_regs(&tf->tf_regs);
122 cprintf(" es 0x----%04x\n", tf->tf_es);
123 cprintf(" ds 0x----%04x\n", tf->tf_ds);
124 cprintf(" trap 0x%08x %s\n", tf->tf_trapno, trapname(tf->tf_trapno));
125 cprintf(" err 0x%08x\n", tf->tf_err);
126 cprintf(" eip 0x%08x\n", tf->tf_eip);
127 cprintf(" cs 0x----%04x\n", tf->tf_cs);
128 cprintf(" flag 0x%08x\n", tf->tf_eflags);
129 cprintf(" esp 0x%08x\n", tf->tf_esp);
130 cprintf(" ss 0x----%04x\n", tf->tf_ss);
133 void
134 print_regs(struct PushRegs *regs)
136 cprintf(" edi 0x%08x\n", regs->reg_edi);
137 cprintf(" esi 0x%08x\n", regs->reg_esi);
138 cprintf(" ebp 0x%08x\n", regs->reg_ebp);
139 cprintf(" oesp 0x%08x\n", regs->reg_oesp);
140 cprintf(" ebx 0x%08x\n", regs->reg_ebx);
141 cprintf(" edx 0x%08x\n", regs->reg_edx);
142 cprintf(" ecx 0x%08x\n", regs->reg_ecx);
143 cprintf(" eax 0x%08x\n", regs->reg_eax);
146 static void
147 trap_dispatch(struct Trapframe *tf)
149 // Handle processor exceptions.
150 // LAB 3: Your code here.
151 switch (tf->tf_trapno) {
152 case T_BRKPT:
153 print_trapframe(tf);
154 panic("enter breakpoint");
155 break;
156 case T_PGFLT:
157 page_fault_handler(tf);
158 break;
159 default:
160 break;
163 // Unexpected trap: The user process or the kernel has a bug.
164 print_trapframe(tf);
165 if (tf->tf_cs == GD_KT)
166 panic("unhandled trap in kernel");
167 else {
168 env_destroy(curenv);
169 return;
173 void
174 trap(struct Trapframe *tf)
176 cprintf("Incoming TRAP frame at %p\n", tf);
178 if ((tf->tf_cs & 3) == 3) {
179 // Trapped from user mode.
180 // Copy trap frame (which is currently on the stack)
181 // into 'curenv->env_tf', so that running the environment
182 // will restart at the trap point.
183 assert(curenv);
184 curenv->env_tf = *tf;
185 // The trapframe on the stack should be ignored from here on.
186 tf = &curenv->env_tf;
189 // Dispatch based on what type of trap occurred
190 trap_dispatch(tf);
192 // Return to the current environment, which should be runnable.
193 assert(curenv && curenv->env_status == ENV_RUNNABLE);
194 env_run(curenv);
198 void
199 page_fault_handler(struct Trapframe *tf)
201 uint32_t fault_va;
203 // Read processor's CR2 register to find the faulting address
204 fault_va = rcr2();
206 // Handle kernel-mode page faults.
208 // LAB 3: Your code here.
210 // We've already handled kernel-mode exceptions, so if we get here,
211 // the page fault happened in user mode.
213 // Call the environment's page fault upcall, if one exists. Set up a
214 // page fault stack frame on the user exception stack (below
215 // UXSTACKTOP), then branch to curenv->env_pgfault_upcall.
217 // The page fault upcall might cause another page fault, in which case
218 // we branch to the page fault upcall recursively, pushing another
219 // page fault stack frame on top of the user exception stack.
221 // The trap handler needs one word of scratch space at the top of the
222 // trap-time stack in order to return. In the non-recursive case, we
223 // don't have to worry about this because the top of the regular user
224 // stack is free. In the recursive case, this means we have to leave
225 // an extra word between the current top of the exception stack and
226 // the new stack frame because the exception stack _is_ the trap-time
227 // stack.
229 // If there's no page fault upcall, the environment didn't allocate a
230 // page for its exception stack, or the exception stack overflows,
231 // then destroy the environment that caused the fault.
233 // Hints:
234 // user_mem_assert() and env_run() are useful here.
235 // To change what the user environment runs, modify 'curenv->env_tf'
236 // (the 'tf' variable points at 'curenv->env_tf').
238 // LAB 4: Your code here.
240 // Destroy the environment that caused the fault.
241 cprintf("[%08x] user fault va %08x ip %08x\n",
242 curenv->env_id, fault_va, tf->tf_eip);
243 print_trapframe(tf);
244 env_destroy(curenv);