IDT set up
[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         // This table is made in trapentry.S by each macro in that file.
62         // It is layed out such that the ith entry is the ith's traphandler's
63         // (uint32_t) trap addr, then (uint32_t) trap number
64         struct trapinfo { uint32_t trapaddr; uint32_t trapnumber; };
65         extern struct trapinfo trap_tbl[];
66         extern struct trapinfo trap_tbl_end[];
67         int i, trap_tbl_size = trap_tbl_end - trap_tbl;
68         extern void ISR_default(void);
69
70         // set all to default, to catch everything
71         for(i = 0; i < 256; i++)
72                 SETGATE(idt[i], 1, GD_KT, &ISR_default, 3);
73         
74         // set all entries that have real trap handlers
75         // we need to stop short of the last one, since the last is the default
76         // handler with a fake interrupt number (500) that is out of bounds of
77         // the idt[]
78         for(i = 0; i < trap_tbl_size - 1; i++)
79                 SETGATE(idt[trap_tbl[i].trapnumber], 1, GD_KT, trap_tbl[i].trapaddr, 3);
80
81         // Setup a TSS so that we get the right stack
82         // when we trap to the kernel.
83         ts.ts_esp0 = KSTACKTOP;
84         ts.ts_ss0 = GD_KD;
85
86         // Initialize the TSS field of the gdt.
87         gdt[GD_TSS >> 3] = SEG16(STS_T32A, (uint32_t) (&ts),
88                                         sizeof(struct Taskstate), 0);
89         gdt[GD_TSS >> 3].sd_s = 0;
90
91         // Load the TSS
92         ltr(GD_TSS);
93
94         // Load the IDT
95         asm volatile("lidt idt_pd");
96 }
97
98 void
99 print_trapframe(struct Trapframe *tf)
100 {
101         cprintf("TRAP frame at %p\n", tf);
102         print_regs(&tf->tf_regs);
103         cprintf("  es   0x----%04x\n", tf->tf_es);
104         cprintf("  ds   0x----%04x\n", tf->tf_ds);
105         cprintf("  trap 0x%08x %s\n", tf->tf_trapno, trapname(tf->tf_trapno));
106         cprintf("  err  0x%08x\n", tf->tf_err);
107         cprintf("  eip  0x%08x\n", tf->tf_eip);
108         cprintf("  cs   0x----%04x\n", tf->tf_cs);
109         cprintf("  flag 0x%08x\n", tf->tf_eflags);
110         cprintf("  esp  0x%08x\n", tf->tf_esp);
111         cprintf("  ss   0x----%04x\n", tf->tf_ss);
112 }
113
114 void
115 print_regs(struct PushRegs *regs)
116 {
117         cprintf("  edi  0x%08x\n", regs->reg_edi);
118         cprintf("  esi  0x%08x\n", regs->reg_esi);
119         cprintf("  ebp  0x%08x\n", regs->reg_ebp);
120         cprintf("  oesp 0x%08x\n", regs->reg_oesp);
121         cprintf("  ebx  0x%08x\n", regs->reg_ebx);
122         cprintf("  edx  0x%08x\n", regs->reg_edx);
123         cprintf("  ecx  0x%08x\n", regs->reg_ecx);
124         cprintf("  eax  0x%08x\n", regs->reg_eax);
125 }
126
127 static void
128 trap_dispatch(struct Trapframe *tf)
129 {
130         // Handle processor exceptions.
131         // LAB 3: Your code here.
132         
133
134         // Unexpected trap: The user process or the kernel has a bug.
135         print_trapframe(tf);
136         if (tf->tf_cs == GD_KT)
137                 panic("unhandled trap in kernel");
138         else {
139                 env_destroy(curenv);
140                 return;
141         }
142 }
143
144 void
145 trap(struct Trapframe *tf)
146 {
147         cprintf("Incoming TRAP frame at %p\n", tf);
148
149         if ((tf->tf_cs & 3) == 3) {
150                 // Trapped from user mode.
151                 // Copy trap frame (which is currently on the stack)
152                 // into 'curenv->env_tf', so that running the environment
153                 // will restart at the trap point.
154                 assert(curenv);
155                 curenv->env_tf = *tf;
156                 // The trapframe on the stack should be ignored from here on.
157                 tf = &curenv->env_tf;
158         }
159         
160         // Dispatch based on what type of trap occurred
161         trap_dispatch(tf);
162
163         // should this be if == 3?  Sort out later when we handle traps.
164         // Return to the current environment, which should be runnable.
165         assert(curenv && curenv->env_status == ENV_RUNNABLE);
166         env_run(curenv);
167 }
168
169
170 void
171 page_fault_handler(struct Trapframe *tf)
172 {
173         uint32_t fault_va;
174
175         // Read processor's CR2 register to find the faulting address
176         fault_va = rcr2();
177
178         // Handle kernel-mode page faults.
179         
180         // LAB 3: Your code here.
181
182         // We've already handled kernel-mode exceptions, so if we get here,
183         // the page fault happened in user mode.
184
185         // Call the environment's page fault upcall, if one exists.  Set up a
186         // page fault stack frame on the user exception stack (below
187         // UXSTACKTOP), then branch to curenv->env_pgfault_upcall.
188         //
189         // The page fault upcall might cause another page fault, in which case
190         // we branch to the page fault upcall recursively, pushing another
191         // page fault stack frame on top of the user exception stack.
192         //
193         // The trap handler needs one word of scratch space at the top of the
194         // trap-time stack in order to return.  In the non-recursive case, we
195         // don't have to worry about this because the top of the regular user
196         // stack is free.  In the recursive case, this means we have to leave
197         // an extra word between the current top of the exception stack and
198         // the new stack frame because the exception stack _is_ the trap-time
199         // stack.
200         //
201         // If there's no page fault upcall, the environment didn't allocate a
202         // page for its exception stack, or the exception stack overflows,
203         // then destroy the environment that caused the fault.
204         //
205         // Hints:
206         //   user_mem_assert() and env_run() are useful here.
207         //   To change what the user environment runs, modify 'curenv->env_tf'
208         //   (the 'tf' variable points at 'curenv->env_tf').
209         
210         // LAB 4: Your code here.
211
212         // Destroy the environment that caused the fault.
213         cprintf("[%08x] user fault va %08x ip %08x\n",
214                 curenv->env_id, fault_va, tf->tf_eip);
215         print_trapframe(tf);
216         env_destroy(curenv);
217 }
218