* same with xv6
[mascara-docs.git] / i386 / ucla / src / lab5 / kern / trap.c
blob84f728aa40957642c6b9fab794a774020d926087
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>
11 #include <kern/sched.h>
12 #include <kern/kclock.h>
13 #include <kern/picirq.h>
15 static struct Taskstate ts;
17 /* Interrupt descriptor table. (Must be built at run time because
18 * shifted function addresses can't be represented in relocation records.)
20 struct Gatedesc idt[256] = { { 0 } };
21 struct Pseudodesc idt_pd = {
22 sizeof(idt) - 1, (uint32_t) idt
26 static const char *trapname(int trapno)
28 static const char * const excnames[] = {
29 "Divide error",
30 "Debug",
31 "Non-Maskable Interrupt",
32 "Breakpoint",
33 "Overflow",
34 "BOUND Range Exceeded",
35 "Invalid Opcode",
36 "Device Not Available",
37 "Double Fault",
38 "Coprocessor Segment Overrun",
39 "Invalid TSS",
40 "Segment Not Present",
41 "Stack Fault",
42 "General Protection",
43 "Page Fault",
44 "(unknown trap)",
45 "x87 FPU Floating-Point Error",
46 "Alignment Check",
47 "Machine-Check",
48 "SIMD Floating-Point Exception"
51 if (trapno < (int) (sizeof(excnames)/sizeof(excnames[0])))
52 return excnames[trapno];
53 if (trapno == T_SYSCALL)
54 return "System call";
55 if (trapno >= IRQ_OFFSET && trapno < IRQ_OFFSET + 16)
56 return "Hardware Interrupt";
57 return "(unknown trap)";
61 void
62 idt_init(void)
64 extern struct Segdesc gdt[];
66 // LAB 2: Your code here.
68 // Set a gate for the system call interrupt.
69 // Hint: Must this gate be accessible from userlevel?
71 // LAB 3 (Exercise 4): Your code here.
73 // Setup a TSS so that we get the right stack
74 // when we trap to the kernel.
75 ts.ts_esp0 = KSTACKTOP;
76 ts.ts_ss0 = GD_KD;
78 // Initialize the TSS field of the gdt.
79 gdt[GD_TSS >> 3] = SEG16(STS_T32A, (uint32_t) (&ts),
80 sizeof(struct Taskstate), 0);
81 gdt[GD_TSS >> 3].sd_s = 0;
83 // Load the TSS
84 ltr(GD_TSS);
86 // Load the IDT
87 asm volatile("lidt idt_pd");
91 void
92 print_trapframe(struct Trapframe *tf, bool trap_just_happened)
94 cprintf("Trap frame at %p\n", tf);
95 print_regs(&tf->tf_regs);
96 cprintf(" es 0x----%04x\n", tf->tf_es);
97 cprintf(" ds 0x----%04x\n", tf->tf_ds);
98 cprintf(" trap 0x%08x %s", tf->tf_trapno, trapname(tf->tf_trapno));
99 // If this trap was a page fault that just happened
100 // (so %cr2 is meaningful), print the faulting linear address.
101 if (trap_just_happened && tf->tf_trapno == T_PGFLT)
102 cprintf(" [la 0x%08x]", rcr2());
103 cprintf("\n err 0x%08x", tf->tf_err);
104 // For page faults, print unparsed fault error code:
105 // U=fault occurred in user mode (K=kernel),
106 // WR=a write caused the fault (R=read),
107 // PR=a protection violation caused the fault (NP=page not present).
108 if (tf->tf_trapno == T_PGFLT)
109 cprintf(" [fault err %s,%s,%s]",
110 tf->tf_err & 4 ? "U" : "K",
111 tf->tf_err & 2 ? "W" : "R",
112 tf->tf_err & 1 ? "PR" : "NP");
113 cprintf("\n eip 0x%08x\n", tf->tf_eip);
114 cprintf(" cs 0x----%04x\n", tf->tf_cs);
115 cprintf(" flag 0x%08x\n", tf->tf_eflags);
116 cprintf(" esp 0x%08x\n", tf->tf_esp);
117 cprintf(" ss 0x----%04x\n", tf->tf_ss);
120 void
121 print_regs(struct PushRegs *regs)
123 cprintf(" edi 0x%08x\n", regs->reg_edi);
124 cprintf(" esi 0x%08x\n", regs->reg_esi);
125 cprintf(" ebp 0x%08x\n", regs->reg_ebp);
126 cprintf(" oesp 0x%08x\n", regs->reg_oesp);
127 cprintf(" ebx 0x%08x\n", regs->reg_ebx);
128 cprintf(" edx 0x%08x\n", regs->reg_edx);
129 cprintf(" ecx 0x%08x\n", regs->reg_ecx);
130 cprintf(" eax 0x%08x\n", regs->reg_eax);
133 static void
134 trap_dispatch(struct Trapframe *tf)
136 // Handle the breakpoint exception.
137 // LAB 2: Your code here.
139 // Handle page faults by calling page_fault_handler.
141 // LAB 3 (Exercise 3): Your code here.
143 // Handle system calls.
144 // Extract the system call number and arguments from 'tf',
145 // call 'syscall', and arrange for the return value to be passed
146 // back to the caller.
147 // LAB 3 (Exercise 4): Your code here.
149 // Handle clock interrupts.
150 // LAB 4: Your code here.
153 // Handle keyboard interrupts.
154 // LAB 5: Your code here.
156 // Handle spurious interrupts
157 // The hardware sometimes raises these because of noise on the
158 // IRQ line or other reasons. We don't care.
159 if (tf->tf_trapno == IRQ_OFFSET + IRQ_SPURIOUS) {
160 cprintf("Spurious interrupt on irq 7\n");
161 print_trapframe(tf, true);
162 return;
166 // Unexpected trap: The user process or the kernel has a bug.
167 print_trapframe(tf, true);
168 if (tf->tf_cs == GD_KT)
169 panic("unhandled trap in kernel");
170 else {
171 env_destroy(curenv);
172 return;
176 asmlinkage void
177 trap(struct Trapframe *tf)
179 // The environment may have set DF and some versions
180 // of GCC rely on DF being clear
181 asm volatile("cld" : : : "cc");
183 // Check that interrupts are disabled. If this assertion
184 // fails, DO NOT be tempted to fix it by inserting a "cli" in
185 // the interrupt path.
186 assert(!(read_eflags() & FL_IF));
188 if ((tf->tf_cs & 3) == 3) {
189 // Trapped from user mode.
190 // Copy trap frame (which is currently on the stack)
191 // into 'curenv->env_tf', so that running the environment
192 // will restart at the trap point.
193 assert(curenv);
194 curenv->env_tf = *tf;
195 // The trapframe on the stack should be ignored from here on.
196 tf = &curenv->env_tf;
199 // Dispatch based on what type of trap occurred
200 trap_dispatch(tf);
202 // If we made it to this point, then no other environment was
203 // scheduled, so we should return to the current environment
204 // if doing so makes sense.
205 if (curenv && curenv->env_status == ENV_RUNNABLE)
206 env_run(curenv);
207 else
208 sched_yield();
212 void
213 page_fault_handler(struct Trapframe *tf)
215 uint32_t fault_va;
217 // Read processor's CR2 register to find the faulting address
218 fault_va = rcr2();
220 // Page faults in the kernel should cause a panic.
221 // LAB 3 (Exercise 8): Your code here.
223 // If we get here, the page fault happened in user mode.
225 // Call the environment's page fault upcall, if one exists. Set up a
226 // page fault stack frame on the user exception stack (below
227 // UXSTACKTOP), then branch to curenv->env_pgfault_upcall.
229 // The page fault upcall might cause another page fault, in which case
230 // we branch to the page fault upcall recursively, pushing another
231 // page fault stack frame on top of the user exception stack.
233 // The trap handler needs one word of scratch space at the top of the
234 // trap-time stack in order to return. In the non-recursive case, we
235 // don't have to worry about this because the top of the regular user
236 // stack is free. In the recursive case, this means we have to leave
237 // an extra word between the current top of the exception stack and
238 // the new stack frame because the exception stack _is_ the trap-time
239 // stack.
241 // If there's no page fault upcall, the environment didn't allocate a
242 // page for its exception stack, the environment can't write to its
243 // exception stack page, or the exception stack overflows, then destroy
244 // the environment that caused the fault.
245 // The grade script assumes you will first check for the page fault
246 // upcall and print the "user fault va" message below if there is
247 // none.
249 // Note that when this function runs, 'tf == &curenv->env_tf'.
251 // LAB 4: Your code here.
253 // Destroy the environment that caused the fault.
254 cprintf("[%08x] user fault va %08x ip %08x\n",
255 curenv->env_id, fault_va, tf->tf_eip);
256 print_trapframe(tf, true);
257 env_destroy(curenv);