7 #include <arch/console.h>
20 /* Interrupt descriptor table. (Must be built at run time because
21 * shifted function addresses can't be represented in relocation records.)
23 // Aligned on an 8 byte boundary (SDM V3A 5-13)
24 gatedesc_t __attribute__ ((aligned (8))) idt[256] = { { 0 } };
25 pseudodesc_t idt_pd = {
26 sizeof(idt) - 1, (uint32_t) idt
29 /* global handler table, used by core0 (for now). allows the registration
30 * of functions to be called when servicing an interrupt. other cores
31 * can set up their own later.
33 handler_t interrupt_handlers[256];
35 static const char *NTS (IN_HANDLER trapname)(int trapno)
37 // zra: excnames is NORACE because Ivy doesn't trust const
38 static const char *NT const (NORACE excnames)[] = {
41 "Non-Maskable Interrupt",
44 "BOUND Range Exceeded",
46 "Device Not Available",
48 "Coprocessor Segment Overrun",
50 "Segment Not Present",
55 "x87 FPU Floating-Point Error",
58 "SIMD Floating-Point Exception"
61 if (trapno < sizeof(excnames)/sizeof(excnames[0]))
62 return excnames[trapno];
63 if (trapno == T_SYSCALL)
65 return "(unknown trap)";
72 extern segdesc_t gdt[];
74 // This table is made in trapentry.S by each macro in that file.
75 // It is layed out such that the ith entry is the ith's traphandler's
76 // (uint32_t) trap addr, then (uint32_t) trap number
77 struct trapinfo { uint32_t trapaddr; uint32_t trapnumber; };
78 extern struct trapinfo (BND(__this,trap_tbl_end) trap_tbl)[];
79 extern struct trapinfo (SNT trap_tbl_end)[];
80 int i, trap_tbl_size = trap_tbl_end - trap_tbl;
81 extern void ISR_default(void);
83 // set all to default, to catch everything
84 for(i = 0; i < 256; i++)
85 SETGATE(idt[i], 0, GD_KT, &ISR_default, 0);
87 // set all entries that have real trap handlers
88 // we need to stop short of the last one, since the last is the default
89 // handler with a fake interrupt number (500) that is out of bounds of
91 // if we set these to trap gates, be sure to handle the IRQs separately
92 // and we might need to break our pretty tables
93 for(i = 0; i < trap_tbl_size - 1; i++)
94 SETGATE(idt[trap_tbl[i].trapnumber], 0, GD_KT, trap_tbl[i].trapaddr, 0);
96 // turn on syscall handling and other user-accessible ints
97 // DPL 3 means this can be triggered by the int instruction
98 // STS_TG32 sets the IDT type to a Trap Gate (interrupts enabled)
99 idt[T_SYSCALL].gd_dpl = 3;
100 idt[T_SYSCALL].gd_type = STS_TG32;
101 idt[T_BRKPT].gd_dpl = 3;
103 // Setup a TSS so that we get the right stack
104 // when we trap to the kernel.
105 ts.ts_esp0 = KSTACKTOP;
108 // Initialize the TSS field of the gdt.
109 gdt[GD_TSS >> 3] = SEG16(STS_T32A, (uint32_t) (&ts),
110 sizeof(taskstate_t), 0);
111 gdt[GD_TSS >> 3].sd_s = 0;
117 asm volatile("lidt idt_pd");
119 // This will go away when we start using the IOAPIC properly
121 // set LINT0 to receive ExtINTs (KVM's default). At reset they are 0x1000.
122 write_mmreg32(LAPIC_LVT_LINT0, 0x700);
123 // mask it to shut it up for now
124 mask_lapic_lvt(LAPIC_LVT_LINT0);
130 (IN_HANDLER print_trapframe)(trapframe_t *tf)
132 cprintf("TRAP frame at %p on core %d\n", tf, coreid());
133 print_regs(&tf->tf_regs);
134 cprintf(" es 0x----%04x\n", tf->tf_es);
135 cprintf(" ds 0x----%04x\n", tf->tf_ds);
136 cprintf(" trap 0x%08x %s\n", tf->tf_trapno, trapname(tf->tf_trapno));
137 cprintf(" err 0x%08x\n", tf->tf_err);
138 cprintf(" eip 0x%08x\n", tf->tf_eip);
139 cprintf(" cs 0x----%04x\n", tf->tf_cs);
140 cprintf(" flag 0x%08x\n", tf->tf_eflags);
141 cprintf(" esp 0x%08x\n", tf->tf_esp);
142 cprintf(" ss 0x----%04x\n", tf->tf_ss);
146 (IN_HANDLER print_regs)(push_regs_t *regs)
148 cprintf(" edi 0x%08x\n", regs->reg_edi);
149 cprintf(" esi 0x%08x\n", regs->reg_esi);
150 cprintf(" ebp 0x%08x\n", regs->reg_ebp);
151 cprintf(" oesp 0x%08x\n", regs->reg_oesp);
152 cprintf(" ebx 0x%08x\n", regs->reg_ebx);
153 cprintf(" edx 0x%08x\n", regs->reg_edx);
154 cprintf(" ecx 0x%08x\n", regs->reg_ecx);
155 cprintf(" eax 0x%08x\n", regs->reg_eax);
159 (IN_HANDLER trap_dispatch)(trapframe_t *tf)
161 // Handle processor exceptions.
162 switch(tf->tf_trapno) {
169 page_fault_handler(tf);
172 // check for userspace, for now
173 assert(tf->tf_cs != GD_KT);
174 tf->tf_regs.reg_eax =
175 syscall(current, tf->tf_regs.reg_eax, tf->tf_regs.reg_edx,
176 tf->tf_regs.reg_ecx, tf->tf_regs.reg_ebx,
177 tf->tf_regs.reg_edi, tf->tf_regs.reg_esi);
178 proc_startcore(current, tf); // Note the comment in syscall.c
181 // Unexpected trap: The user process or the kernel has a bug.
183 if (tf->tf_cs == GD_KT)
184 panic("Damn Damn! Unhandled trap in the kernel!");
186 warn("Unexpected trap from userspace");
187 env_destroy(current);
195 (IN_HANDLER trap)(trapframe_t *tf)
197 //cprintf("Incoming TRAP frame at %p\n", tf);
199 if ((tf->tf_cs & ~3) != GD_UT && (tf->tf_cs & ~3) != GD_KT) {
201 panic("Trapframe with invalid CS!");
204 if ((tf->tf_cs & 3) == 3) {
205 // Trapped from user mode.
206 // TODO: this will change when an env has more than one context
207 // Copy trap frame (which is currently on the stack)
208 // into 'current->env_tf', so that running the environment
209 // will restart at the trap point.
211 current->env_tf = *tf;
212 // The trapframe on the stack should be ignored from here on.
213 tf = ¤t->env_tf;
216 // Dispatch based on what type of trap occurred
219 // should this be if == 3? Sort out later when we handle traps.
220 // so far we never get here
222 // Return to the current environment, which should be runnable.
223 proc_startcore(current, tf); // Note the comment in syscall.c
227 (IN_HANDLER irq_handler)(trapframe_t *tf)
230 // cprintf("Incoming IRQ, ISR: %d on core %d\n", tf->tf_trapno, coreid());
231 // merge this with alltraps? other than the EOI... or do the same in all traps
233 extern handler_wrapper_t handler_wrappers[NUM_HANDLER_WRAPPERS];
235 // determine the interrupt handler table to use. for now, pick the global
236 handler_t* handler_tbl = interrupt_handlers;
238 if (handler_tbl[tf->tf_trapno].isr != 0)
239 handler_tbl[tf->tf_trapno].isr(tf, handler_tbl[tf->tf_trapno].data);
240 // if we're a general purpose IPI function call, down the cpu_list
241 if ((0xf0 <= tf->tf_trapno) && (tf->tf_trapno < 0xf0 +NUM_HANDLER_WRAPPERS))
242 down_checklist(handler_wrappers[tf->tf_trapno & 0x0f].cpu_list);
244 // Send EOI. might want to do this in assembly, and possibly earlier
245 // This is set up to work with an old PIC for now
246 // Convention is that all IRQs between 32 and 47 are for the PIC.
247 // All others are LAPIC (timer, IPIs, perf, non-ExtINT LINTS, etc)
248 // For now, only 235-255 are available
249 assert(tf->tf_trapno >= 32); // slows us down, but we should never have this
250 if (tf->tf_trapno < 48)
251 pic_send_eoi(tf->tf_trapno - PIC1_OFFSET);
257 register_interrupt_handler(handler_t table[], uint8_t int_num, isr_t handler,
260 table[int_num].isr = handler;
261 table[int_num].data = data;
265 page_fault_handler(trapframe_t *tf)
269 // Read processor's CR2 register to find the faulting address
272 // Handle kernel-mode page faults.
274 // TODO - one day, we'll want to handle this.
275 if ((tf->tf_cs & 3) == 0) {
277 panic("Page Fault in the Kernel at 0x%08x!", fault_va);
280 // We've already handled kernel-mode exceptions, so if we get here,
281 // the page fault happened in user mode.
283 // Call the environment's page fault upcall, if one exists. Set up a
284 // page fault stack frame on the user exception stack (below
285 // UXSTACKTOP), then branch to current->env_pgfault_upcall.
287 // The page fault upcall might cause another page fault, in which case
288 // we branch to the page fault upcall recursively, pushing another
289 // page fault stack frame on top of the user exception stack.
291 // The trap handler needs one word of scratch space at the top of the
292 // trap-time stack in order to return. In the non-recursive case, we
293 // don't have to worry about this because the top of the regular user
294 // stack is free. In the recursive case, this means we have to leave
295 // an extra word between the current top of the exception stack and
296 // the new stack frame because the exception stack _is_ the trap-time
299 // If there's no page fault upcall, the environment didn't allocate a
300 // page for its exception stack, or the exception stack overflows,
301 // then destroy the environment that caused the fault.
304 // user_mem_assert() and env_run() are useful here.
305 // To change what the user environment runs, modify 'current->env_tf'
306 // (the 'tf' variable points at 'current->env_tf').
308 // LAB 4: Your code here.
310 // Destroy the environment that caused the fault.
311 cprintf("[%08x] user fault va %08x ip %08x from core %d\n",
312 current->env_id, fault_va, tf->tf_eip, coreid());
314 env_destroy(current);
317 void sysenter_init(void)
319 write_msr(MSR_IA32_SYSENTER_CS, GD_KT);
320 write_msr(MSR_IA32_SYSENTER_ESP, ts.ts_esp0);
321 write_msr(MSR_IA32_SYSENTER_EIP, (uint32_t) &sysenter_handler);