Rudimentary breakpoint handling
[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, 0);
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, 0);
80
81         // turn on syscall handling and other user-accessible ints
82         // DPL 3 means this can be triggered by the int instruction
83         idt[T_SYSCALL].gd_dpl = 3;
84         idt[T_BRKPT].gd_dpl = 3;
85
86         // Setup a TSS so that we get the right stack
87         // when we trap to the kernel.
88         ts.ts_esp0 = KSTACKTOP;
89         ts.ts_ss0 = GD_KD;
90
91         // Initialize the TSS field of the gdt.
92         gdt[GD_TSS >> 3] = SEG16(STS_T32A, (uint32_t) (&ts),
93                                         sizeof(struct Taskstate), 0);
94         gdt[GD_TSS >> 3].sd_s = 0;
95
96         // Load the TSS
97         ltr(GD_TSS);
98
99         // Load the IDT
100         asm volatile("lidt idt_pd");
101 }
102
103 void
104 print_trapframe(struct Trapframe *tf)
105 {
106         cprintf("TRAP frame at %p\n", tf);
107         print_regs(&tf->tf_regs);
108         cprintf("  es   0x----%04x\n", tf->tf_es);
109         cprintf("  ds   0x----%04x\n", tf->tf_ds);
110         cprintf("  trap 0x%08x %s\n", tf->tf_trapno, trapname(tf->tf_trapno));
111         cprintf("  err  0x%08x\n", tf->tf_err);
112         cprintf("  eip  0x%08x\n", tf->tf_eip);
113         cprintf("  cs   0x----%04x\n", tf->tf_cs);
114         cprintf("  flag 0x%08x\n", tf->tf_eflags);
115         cprintf("  esp  0x%08x\n", tf->tf_esp);
116         cprintf("  ss   0x----%04x\n", tf->tf_ss);
117 }
118
119 void
120 print_regs(struct PushRegs *regs)
121 {
122         cprintf("  edi  0x%08x\n", regs->reg_edi);
123         cprintf("  esi  0x%08x\n", regs->reg_esi);
124         cprintf("  ebp  0x%08x\n", regs->reg_ebp);
125         cprintf("  oesp 0x%08x\n", regs->reg_oesp);
126         cprintf("  ebx  0x%08x\n", regs->reg_ebx);
127         cprintf("  edx  0x%08x\n", regs->reg_edx);
128         cprintf("  ecx  0x%08x\n", regs->reg_ecx);
129         cprintf("  eax  0x%08x\n", regs->reg_eax);
130 }
131
132 static void
133 trap_dispatch(struct Trapframe *tf)
134 {
135         // Handle processor exceptions.
136         
137         switch(tf->tf_trapno) {
138                 case (T_BRKPT):
139                         while (1)
140                                 monitor(tf);
141                         // never get to this
142                         assert(0);
143                 case (T_PGFLT):
144                         page_fault_handler(tf);
145                         break;
146                 default:
147                         break;
148         }
149
150         // Unexpected trap: The user process or the kernel has a bug.
151         print_trapframe(tf);
152         if (tf->tf_cs == GD_KT)
153                 panic("unhandled trap in kernel");
154         else {
155                 env_destroy(curenv);
156                 return;
157         }
158 }
159
160 void
161 trap(struct Trapframe *tf)
162 {
163         cprintf("Incoming TRAP frame at %p\n", tf);
164
165         if ((tf->tf_cs & ~3) != GD_UT && (tf->tf_cs & ~3) != GD_KT)
166                 panic("Trapframe with invalid CS!");
167
168         if ((tf->tf_cs & 3) == 3) {
169                 // Trapped from user mode.
170                 // Copy trap frame (which is currently on the stack)
171                 // into 'curenv->env_tf', so that running the environment
172                 // will restart at the trap point.
173                 assert(curenv);
174                 curenv->env_tf = *tf;
175                 // The trapframe on the stack should be ignored from here on.
176                 tf = &curenv->env_tf;
177         }
178         
179         // Dispatch based on what type of trap occurred
180         trap_dispatch(tf);
181
182         // should this be if == 3?  Sort out later when we handle traps.
183         // Return to the current environment, which should be runnable.
184         assert(curenv && curenv->env_status == ENV_RUNNABLE);
185         env_run(curenv);
186 }
187
188
189 void
190 page_fault_handler(struct Trapframe *tf)
191 {
192         uint32_t fault_va;
193
194         // Read processor's CR2 register to find the faulting address
195         fault_va = rcr2();
196
197         // Handle kernel-mode page faults.
198         
199         // LAB 3: Your code here.
200
201         // We've already handled kernel-mode exceptions, so if we get here,
202         // the page fault happened in user mode.
203
204         // Call the environment's page fault upcall, if one exists.  Set up a
205         // page fault stack frame on the user exception stack (below
206         // UXSTACKTOP), then branch to curenv->env_pgfault_upcall.
207         //
208         // The page fault upcall might cause another page fault, in which case
209         // we branch to the page fault upcall recursively, pushing another
210         // page fault stack frame on top of the user exception stack.
211         //
212         // The trap handler needs one word of scratch space at the top of the
213         // trap-time stack in order to return.  In the non-recursive case, we
214         // don't have to worry about this because the top of the regular user
215         // stack is free.  In the recursive case, this means we have to leave
216         // an extra word between the current top of the exception stack and
217         // the new stack frame because the exception stack _is_ the trap-time
218         // stack.
219         //
220         // If there's no page fault upcall, the environment didn't allocate a
221         // page for its exception stack, or the exception stack overflows,
222         // then destroy the environment that caused the fault.
223         //
224         // Hints:
225         //   user_mem_assert() and env_run() are useful here.
226         //   To change what the user environment runs, modify 'curenv->env_tf'
227         //   (the 'tf' variable points at 'curenv->env_tf').
228         
229         // LAB 4: Your code here.
230
231         // Destroy the environment that caused the fault.
232         cprintf("[%08x] user fault va %08x ip %08x\n",
233                 curenv->env_id, fault_va, tf->tf_eip);
234         print_trapframe(tf);
235         env_destroy(curenv);
236 }
237