Lab3 initial merge
[akaros.git] / kern / trap.c
1 #include <inc/mmu.h>
2 #include <inc/x86.h>
3 #include <inc/assert.h>
4
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
12 static struct Taskstate ts;
13
14 /* Interrupt descriptor table.  (Must be built at run time because
15  * shifted function addresses can't be represented in relocation records.)
16  */
17 struct Gatedesc idt[256] = { { 0 } };
18 struct Pseudodesc idt_pd = {
19         sizeof(idt) - 1, (uint32_t) idt
20 };
21
22
23 static const char *trapname(int trapno)
24 {
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"
46         };
47
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)";
53 }
54
55
56 void
57 idt_init(void)
58 {
59         extern struct Segdesc gdt[];
60         
61         // LAB 3: Your code here.
62
63         // Setup a TSS so that we get the right stack
64         // when we trap to the kernel.
65         ts.ts_esp0 = KSTACKTOP;
66         ts.ts_ss0 = GD_KD;
67
68         // Initialize the TSS field of the gdt.
69         gdt[GD_TSS >> 3] = SEG16(STS_T32A, (uint32_t) (&ts),
70                                         sizeof(struct Taskstate), 0);
71         gdt[GD_TSS >> 3].sd_s = 0;
72
73         // Load the TSS
74         ltr(GD_TSS);
75
76         // Load the IDT
77         asm volatile("lidt idt_pd");
78 }
79
80 void
81 print_trapframe(struct Trapframe *tf)
82 {
83         cprintf("TRAP frame at %p\n", tf);
84         print_regs(&tf->tf_regs);
85         cprintf("  es   0x----%04x\n", tf->tf_es);
86         cprintf("  ds   0x----%04x\n", tf->tf_ds);
87         cprintf("  trap 0x%08x %s\n", tf->tf_trapno, trapname(tf->tf_trapno));
88         cprintf("  err  0x%08x\n", tf->tf_err);
89         cprintf("  eip  0x%08x\n", tf->tf_eip);
90         cprintf("  cs   0x----%04x\n", tf->tf_cs);
91         cprintf("  flag 0x%08x\n", tf->tf_eflags);
92         cprintf("  esp  0x%08x\n", tf->tf_esp);
93         cprintf("  ss   0x----%04x\n", tf->tf_ss);
94 }
95
96 void
97 print_regs(struct PushRegs *regs)
98 {
99         cprintf("  edi  0x%08x\n", regs->reg_edi);
100         cprintf("  esi  0x%08x\n", regs->reg_esi);
101         cprintf("  ebp  0x%08x\n", regs->reg_ebp);
102         cprintf("  oesp 0x%08x\n", regs->reg_oesp);
103         cprintf("  ebx  0x%08x\n", regs->reg_ebx);
104         cprintf("  edx  0x%08x\n", regs->reg_edx);
105         cprintf("  ecx  0x%08x\n", regs->reg_ecx);
106         cprintf("  eax  0x%08x\n", regs->reg_eax);
107 }
108
109 static void
110 trap_dispatch(struct Trapframe *tf)
111 {
112         // Handle processor exceptions.
113         // LAB 3: Your code here.
114         
115
116         // Unexpected trap: The user process or the kernel has a bug.
117         print_trapframe(tf);
118         if (tf->tf_cs == GD_KT)
119                 panic("unhandled trap in kernel");
120         else {
121                 env_destroy(curenv);
122                 return;
123         }
124 }
125
126 void
127 trap(struct Trapframe *tf)
128 {
129         cprintf("Incoming TRAP frame at %p\n", tf);
130
131         if ((tf->tf_cs & 3) == 3) {
132                 // Trapped from user mode.
133                 // Copy trap frame (which is currently on the stack)
134                 // into 'curenv->env_tf', so that running the environment
135                 // will restart at the trap point.
136                 assert(curenv);
137                 curenv->env_tf = *tf;
138                 // The trapframe on the stack should be ignored from here on.
139                 tf = &curenv->env_tf;
140         }
141         
142         // Dispatch based on what type of trap occurred
143         trap_dispatch(tf);
144
145         // Return to the current environment, which should be runnable.
146         assert(curenv && curenv->env_status == ENV_RUNNABLE);
147         env_run(curenv);
148 }
149
150
151 void
152 page_fault_handler(struct Trapframe *tf)
153 {
154         uint32_t fault_va;
155
156         // Read processor's CR2 register to find the faulting address
157         fault_va = rcr2();
158
159         // Handle kernel-mode page faults.
160         
161         // LAB 3: Your code here.
162
163         // We've already handled kernel-mode exceptions, so if we get here,
164         // the page fault happened in user mode.
165
166         // Call the environment's page fault upcall, if one exists.  Set up a
167         // page fault stack frame on the user exception stack (below
168         // UXSTACKTOP), then branch to curenv->env_pgfault_upcall.
169         //
170         // The page fault upcall might cause another page fault, in which case
171         // we branch to the page fault upcall recursively, pushing another
172         // page fault stack frame on top of the user exception stack.
173         //
174         // The trap handler needs one word of scratch space at the top of the
175         // trap-time stack in order to return.  In the non-recursive case, we
176         // don't have to worry about this because the top of the regular user
177         // stack is free.  In the recursive case, this means we have to leave
178         // an extra word between the current top of the exception stack and
179         // the new stack frame because the exception stack _is_ the trap-time
180         // stack.
181         //
182         // If there's no page fault upcall, the environment didn't allocate a
183         // page for its exception stack, or the exception stack overflows,
184         // then destroy the environment that caused the fault.
185         //
186         // Hints:
187         //   user_mem_assert() and env_run() are useful here.
188         //   To change what the user environment runs, modify 'curenv->env_tf'
189         //   (the 'tf' variable points at 'curenv->env_tf').
190         
191         // LAB 4: Your code here.
192
193         // Destroy the environment that caused the fault.
194         cprintf("[%08x] user fault va %08x ip %08x\n",
195                 curenv->env_id, fault_va, tf->tf_eip);
196         print_trapframe(tf);
197         env_destroy(curenv);
198 }
199