8cb59d91f0a1c932f3ea4f6fd45c1210a3ef42f8
[akaros.git] / kern / arch / i686 / trap.c
1 #ifdef __SHARC__
2 #pragma nosharc
3 #define SINIT(x) x
4 #endif
5
6 #include <arch/mmu.h>
7 #include <arch/x86.h>
8 #include <arch/arch.h>
9 #include <arch/console.h>
10 #include <arch/apic.h>
11 #include <ros/common.h>
12 #include <smp.h>
13 #include <assert.h>
14 #include <pmap.h>
15 #include <trap.h>
16 #include <monitor.h>
17 #include <process.h>
18 #include <mm.h>
19 #include <stdio.h>
20 #include <slab.h>
21 #include <syscall.h>
22 #include <kdebug.h>
23 #include <kmalloc.h>
24
25 taskstate_t RO ts;
26
27 /* Interrupt descriptor table.  (Must be built at run time because
28  * shifted function addresses can't be represented in relocation records.)
29  */
30 // Aligned on an 8 byte boundary (SDM V3A 5-13)
31 gatedesc_t __attribute__ ((aligned (8))) (RO idt)[256] = { { 0 } };
32 pseudodesc_t RO idt_pd = {
33         sizeof(idt) - 1, (uint32_t) idt
34 };
35
36 /* global handler table, used by core0 (for now).  allows the registration
37  * of functions to be called when servicing an interrupt.  other cores
38  * can set up their own later.
39  */
40 #ifdef __IVY__
41 #pragma cilnoremove("iht_lock")
42 #endif
43 spinlock_t iht_lock;
44 handler_t TP(TV(t)) LCKD(&iht_lock) (RO interrupt_handlers)[NUM_INTERRUPT_HANDLERS];
45
46 static const char *NTS trapname(int trapno)
47 {
48     // zra: excnames is SREADONLY because Ivy doesn't trust const
49         static const char *NT const (RO excnames)[] = {
50                 "Divide error",
51                 "Debug",
52                 "Non-Maskable Interrupt",
53                 "Breakpoint",
54                 "Overflow",
55                 "BOUND Range Exceeded",
56                 "Invalid Opcode",
57                 "Device Not Available",
58                 "Double Fault",
59                 "Coprocessor Segment Overrun",
60                 "Invalid TSS",
61                 "Segment Not Present",
62                 "Stack Fault",
63                 "General Protection",
64                 "Page Fault",
65                 "(unknown trap)",
66                 "x87 FPU Floating-Point Error",
67                 "Alignment Check",
68                 "Machine-Check",
69                 "SIMD Floating-Point Exception"
70         };
71
72         if (trapno < sizeof(excnames)/sizeof(excnames[0]))
73                 return excnames[trapno];
74         if (trapno == T_SYSCALL)
75                 return "System call";
76         return "(unknown trap)";
77 }
78
79 /* Set stacktop for the current core to be the stack the kernel will start on
80  * when trapping/interrupting from userspace.  Don't use this til after
81  * smp_percpu_init().  We can probably get the TSS by reading the task register
82  * and then the GDT.  Still, it's a pain. */
83 void set_stack_top(uintptr_t stacktop)
84 {
85         struct per_cpu_info *pcpu = &per_cpu_info[core_id()];
86         /* No need to reload the task register, this takes effect immediately */
87         pcpu->tss->ts_esp0 = stacktop;
88         /* Also need to make sure sysenters come in correctly */
89         write_msr(MSR_IA32_SYSENTER_ESP, stacktop);
90 }
91
92 /* Note the check implies we only are on a one page stack (or the first page) */
93 uintptr_t get_stack_top(void)
94 {
95         struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
96         uintptr_t stacktop;
97         /* so we can check this in interrupt handlers (before smp_boot()) */
98         if (!pcpui->tss)
99                 return ROUNDUP(read_esp(), PGSIZE);
100         stacktop = pcpui->tss->ts_esp0;
101         if (stacktop != ROUNDUP(read_esp(), PGSIZE))
102                 panic("Bad stacktop: %08p esp one is %08p\n", stacktop,
103                       ROUNDUP(read_esp(), PGSIZE));
104         return stacktop;
105 }
106
107 /* Starts running the current TF, just using ret. */
108 void pop_kernel_tf(struct trapframe *tf)
109 {
110         asm volatile ("movl %1,%%esp;           " /* move to future stack */
111                       "pushl %2;                " /* push cs */
112                       "movl %0,%%esp;           " /* move to TF */
113                       "addl $0x20,%%esp;        " /* move to tf_gs slot */
114                       "movl %1,(%%esp);         " /* write future esp */
115                       "subl $0x20,%%esp;        " /* move back to tf start */
116                       "popal;                   " /* restore regs */
117                       "popl %%esp;              " /* set stack ptr */
118                       "subl $0x4,%%esp;         " /* jump down past CS */
119                       "ret                      " /* return to the EIP */
120                       :
121                       : "g"(tf), "r"(tf->tf_esp), "r"(tf->tf_eip) : "memory");
122         panic("ret failed");                            /* mostly to placate your mom */
123 }
124
125 /* Sends a non-maskable interrupt; the handler will print a trapframe. */
126 void send_nmi(uint32_t os_coreid)
127 {
128         /* NMI / IPI for x86 are limited to 8 bits */
129         uint8_t hw_core = (uint8_t)get_hw_coreid(os_coreid);
130         __send_nmi(hw_core);
131 }
132
133 void idt_init(void)
134 {
135         extern segdesc_t (RO gdt)[];
136
137         // This table is made in trapentry.S by each macro in that file.
138         // It is layed out such that the ith entry is the ith's traphandler's
139         // (uint32_t) trap addr, then (uint32_t) trap number
140         struct trapinfo { uint32_t trapaddr; uint32_t trapnumber; };
141         extern struct trapinfo (BND(__this,trap_tbl_end) RO trap_tbl)[];
142         extern struct trapinfo (SNT RO trap_tbl_end)[];
143         int i, trap_tbl_size = trap_tbl_end - trap_tbl;
144         extern void ISR_default(void);
145
146         // set all to default, to catch everything
147         for(i = 0; i < 256; i++)
148                 ROSETGATE(idt[i], 0, GD_KT, &ISR_default, 0);
149
150         // set all entries that have real trap handlers
151         // we need to stop short of the last one, since the last is the default
152         // handler with a fake interrupt number (500) that is out of bounds of
153         // the idt[]
154         // if we set these to trap gates, be sure to handle the IRQs separately
155         // and we might need to break our pretty tables
156         for(i = 0; i < trap_tbl_size - 1; i++)
157                 ROSETGATE(idt[trap_tbl[i].trapnumber], 0, GD_KT, trap_tbl[i].trapaddr, 0);
158
159         // turn on syscall handling and other user-accessible ints
160         // DPL 3 means this can be triggered by the int instruction
161         // STS_TG32 sets the IDT type to a Interrupt Gate (interrupts disabled)
162         idt[T_SYSCALL].gd_dpl = SINIT(3);
163         idt[T_SYSCALL].gd_type = SINIT(STS_IG32);
164         idt[T_BRKPT].gd_dpl = SINIT(3);
165
166         /* Setup a TSS so that we get the right stack when we trap to the kernel. */
167         ts.ts_esp0 = (uintptr_t)bootstacktop;
168         ts.ts_ss0 = SINIT(GD_KD);
169 #ifdef __CONFIG_KTHREAD_POISON__
170         /* TODO: KTHR-STACK */
171         uintptr_t *poison = (uintptr_t*)ROUNDDOWN(bootstacktop - 1, PGSIZE);
172         *poison = 0xdeadbeef;
173 #endif /* __CONFIG_KTHREAD_POISON__ */
174
175         // Initialize the TSS field of the gdt.
176         SEG16ROINIT(gdt[GD_TSS >> 3],STS_T32A, (uint32_t)(&ts),sizeof(taskstate_t),0);
177         //gdt[GD_TSS >> 3] = (segdesc_t)SEG16(STS_T32A, (uint32_t) (&ts),
178         //                                 sizeof(taskstate_t), 0);
179         gdt[GD_TSS >> 3].sd_s = SINIT(0);
180
181         // Load the TSS
182         ltr(GD_TSS);
183
184         // Load the IDT
185         asm volatile("lidt idt_pd");
186
187         // This will go away when we start using the IOAPIC properly
188         pic_remap();
189         // set LINT0 to receive ExtINTs (KVM's default).  At reset they are 0x1000.
190         write_mmreg32(LAPIC_LVT_LINT0, 0x700);
191         // mask it to shut it up for now
192         mask_lapic_lvt(LAPIC_LVT_LINT0);
193         // and turn it on
194         lapic_enable();
195         /* register the generic timer_interrupt() handler for the per-core timers */
196         register_interrupt_handler(interrupt_handlers, LAPIC_TIMER_DEFAULT_VECTOR,
197                                    timer_interrupt, NULL);
198         /* register the kernel message handler */
199         register_interrupt_handler(interrupt_handlers, I_KERNEL_MSG,
200                                    handle_kmsg_ipi, NULL);
201 }
202
203 void
204 print_regs(push_regs_t *regs)
205 {
206         cprintf("  edi  0x%08x\n", regs->reg_edi);
207         cprintf("  esi  0x%08x\n", regs->reg_esi);
208         cprintf("  ebp  0x%08x\n", regs->reg_ebp);
209         cprintf("  oesp 0x%08x\n", regs->reg_oesp);
210         cprintf("  ebx  0x%08x\n", regs->reg_ebx);
211         cprintf("  edx  0x%08x\n", regs->reg_edx);
212         cprintf("  ecx  0x%08x\n", regs->reg_ecx);
213         cprintf("  eax  0x%08x\n", regs->reg_eax);
214 }
215
216 void
217 print_trapframe(trapframe_t *tf)
218 {
219         static spinlock_t ptf_lock = SPINLOCK_INITIALIZER_IRQSAVE;
220
221         spin_lock_irqsave(&ptf_lock);
222         printk("TRAP frame at %p on core %d\n", tf, core_id());
223         print_regs(&tf->tf_regs);
224         printk("  gs   0x----%04x\n", tf->tf_gs);
225         printk("  fs   0x----%04x\n", tf->tf_fs);
226         printk("  es   0x----%04x\n", tf->tf_es);
227         printk("  ds   0x----%04x\n", tf->tf_ds);
228         printk("  trap 0x%08x %s\n", tf->tf_trapno, trapname(tf->tf_trapno));
229         printk("  err  0x%08x\n", tf->tf_err);
230         printk("  eip  0x%08x\n", tf->tf_eip);
231         printk("  cs   0x----%04x\n", tf->tf_cs);
232         printk("  flag 0x%08x\n", tf->tf_eflags);
233         /* Prevents us from thinking these mean something for nested interrupts. */
234         if (tf->tf_cs != GD_KT) {
235                 printk("  esp  0x%08x\n", tf->tf_esp);
236                 printk("  ss   0x----%04x\n", tf->tf_ss);
237         }
238         spin_unlock_irqsave(&ptf_lock);
239 }
240
241 /* Certain traps want IRQs enabled, such as the syscall.  Others can't handle
242  * it, like the page fault handler.  Turn them on on a case-by-case basis. */
243 static void trap_dispatch(struct trapframe *tf)
244 {
245         // Handle processor exceptions.
246         switch(tf->tf_trapno) {
247                 case T_NMI:
248                         print_trapframe(tf);
249                         char *fn_name = get_fn_name(tf->tf_eip);
250                         printk("Core %d is at %08p (%s)\n", core_id(), tf->tf_eip, fn_name);
251                         kfree(fn_name);
252                         print_kmsgs(core_id());
253                         break;
254                 case T_BRKPT:
255                         enable_irq();
256                         monitor(tf);
257                         break;
258                 case T_PGFLT:
259                         page_fault_handler(tf);
260                         break;
261                 case T_SYSCALL:
262                         enable_irq();
263                         // check for userspace, for now
264                         assert(tf->tf_cs != GD_KT);
265                         /* Set up and run the async calls */
266                         prep_syscalls(current, (struct syscall*)tf->tf_regs.reg_eax,
267                                       tf->tf_regs.reg_edx);
268                         break;
269                 default:
270                         // Unexpected trap: The user process or the kernel has a bug.
271                         print_trapframe(tf);
272                         if (tf->tf_cs == GD_KT)
273                                 panic("Damn Damn!  Unhandled trap in the kernel!");
274                         else {
275                                 warn("Unexpected trap from userspace");
276                                 enable_irq();
277                                 proc_destroy(current);
278                         }
279         }
280         return;
281 }
282
283 void
284 env_push_ancillary_state(env_t* e)
285 {
286         // TODO: (HSS) handle silly state (don't really want this per-process)
287         // Here's where you'll save FP/MMX/XMM regs
288 }
289
290 void
291 env_pop_ancillary_state(env_t* e)
292 {
293         // Here's where you'll restore FP/MMX/XMM regs
294 }
295
296 /* Helper.  For now, this copies out the TF to pcpui.  Eventually, we should
297  * consider doing this in trapentry.S */
298 static void set_current_tf(struct per_cpu_info *pcpui, struct trapframe *tf)
299 {
300         assert(!irq_is_enabled());
301         assert(!pcpui->cur_tf);
302         pcpui->actual_tf = *tf;
303         pcpui->cur_tf = &pcpui->actual_tf;
304 }
305
306 /* If the interrupt interrupted a halt, we advance past it.  Made to work with
307  * x86's custom cpu_halt() in arch/arch.h.  Note this nearly never gets called.
308  * I needed to insert exactly one 'nop' in cpu_halt() (that isn't there now) to
309  * get the interrupt to trip on the hlt, o/w the hlt will execute before the
310  * interrupt arrives (even with a pending interrupt that should hit right after
311  * an interrupt_enable (sti)).  This was on the i7. */
312 static void abort_halt(struct trapframe *tf)
313 {
314         /* Don't care about user TFs.  Incidentally, dereferencing user EIPs is
315          * reading userspace memory, which can be dangerous.  It can page fault,
316          * like immediately after a fork (which doesn't populate the pages). */
317         if (!in_kernel(tf))
318                 return;
319         /* the halt instruction in 32 bit is 0xf4, and it's size is 1 byte */
320         if (*(uint8_t*)tf->tf_eip == 0xf4)
321                 tf->tf_eip += 1;
322 }
323
324 void trap(struct trapframe *tf)
325 {
326         struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
327         /* Copy out the TF for now */
328         if (!in_kernel(tf))
329                 set_current_tf(pcpui, tf);
330         else
331                 inc_ktrap_depth(pcpui);
332
333         printd("Incoming TRAP %d on core %d, TF at %p\n", tf->tf_trapno, core_id(),
334                tf);
335         if ((tf->tf_cs & ~3) != GD_UT && (tf->tf_cs & ~3) != GD_KT) {
336                 print_trapframe(tf);
337                 panic("Trapframe with invalid CS!");
338         }
339         trap_dispatch(tf);
340         /* Return to the current process, which should be runnable.  If we're the
341          * kernel, we should just return naturally.  Note that current and tf need
342          * to still be okay (might not be after blocking) */
343         if (in_kernel(tf)) {
344                 dec_ktrap_depth(pcpui);
345                 return;
346         }
347         proc_restartcore();
348         assert(0);
349 }
350
351 /* Tells us if an interrupt (trap_nr) came from the PIC or not */
352 static bool irq_from_pic(uint32_t trap_nr)
353 {
354         /* The 16 IRQs within the range [PIC1_OFFSET, PIC1_OFFSET + 15] came from
355          * the PIC.  [32-47] */
356         if (trap_nr < PIC1_OFFSET)
357                 return FALSE;
358         if (trap_nr > PIC1_OFFSET + 15)
359                 return FALSE;
360         return TRUE;
361 }
362
363 /* Helper: returns TRUE if the irq is spurious.  Pass in the trap_nr, not the
364  * IRQ number (trap_nr = PIC_OFFSET + irq) */
365 static bool check_spurious_irq(uint32_t trap_nr)
366 {
367 #ifndef __CONFIG_ENABLE_MPTABLES__              /* TODO: our proxy for using the PIC */
368         /* the PIC may send spurious irqs via one of the chips irq 7.  if the isr
369          * doesn't show that irq, then it was spurious, and we don't send an eoi.
370          * Check out http://wiki.osdev.org/8259_PIC#Spurious_IRQs */
371         if ((trap_nr == PIC1_SPURIOUS) && !(pic_get_isr() & PIC1_SPURIOUS)) {
372                 printk("Spurious PIC1 irq!\n"); /* want to know if this happens */
373                 return TRUE;
374         }
375         if ((trap_nr == PIC2_SPURIOUS) && !(pic_get_isr() & PIC2_SPURIOUS)) {
376                 printk("Spurious PIC2 irq!\n"); /* want to know if this happens */
377                 /* for the cascaded PIC, we *do* need to send an EOI to the master's
378                  * cascade irq (2). */
379                 pic_send_eoi(2);
380                 return TRUE;
381         }
382         /* At this point, we know the PIC didn't send a spurious IRQ */
383         if (irq_from_pic(trap_nr))
384                 return FALSE;
385 #endif
386         /* Either way (with or without a PIC), we need to check the LAPIC.
387          * FYI: lapic_spurious is 255 on qemu and 15 on the nehalem..  We actually
388          * can set bits 4-7, and P6s have 0-3 hardwired to 0.  YMMV.
389          *
390          * The SDM recommends not using the spurious vector for any other IRQs (LVT
391          * or IOAPIC RTE), since the handlers don't send an EOI.  However, our check
392          * here allows us to use the vector since we can tell the diff btw a
393          * spurious and a real IRQ. */
394         uint8_t lapic_spurious = read_mmreg32(LAPIC_SPURIOUS) & 0xff;
395         /* Note the lapic's vectors are not shifted by an offset. */
396         if ((trap_nr == lapic_spurious) && !lapic_get_isr_bit(lapic_spurious)) {
397                 printk("Spurious LAPIC irq %d, core %d!\n", lapic_spurious, core_id());
398                 lapic_print_isr();
399                 return TRUE;
400         }
401         return FALSE;
402 }
403
404 /* Helper, sends an end-of-interrupt for the trap_nr (not HW IRQ number). */
405 static void send_eoi(uint32_t trap_nr)
406 {
407 #ifndef __CONFIG_ENABLE_MPTABLES__              /* TODO: our proxy for using the PIC */
408         /* WARNING: this will break if the LAPIC requests vectors that overlap with
409          * the PIC's range. */
410         if (irq_from_pic(trap_nr))
411                 pic_send_eoi(trap_nr - PIC1_OFFSET);
412         else
413                 lapic_send_eoi();
414 #else
415         lapic_send_eoi();
416 #endif
417 }
418
419 /* Note IRQs are disabled unless explicitly turned on.
420  *
421  * In general, we should only get trapno's >= PIC1_OFFSET (32).  Anything else
422  * should be a trap.  Even if we don't use the PIC, that should be the standard.
423  * It is possible to get a spurious LAPIC IRQ with vector 15 (or similar), but
424  * the spurious check should catch that.
425  *
426  * Note that from hardware's perspective (PIC, etc), IRQs start from 0, but they
427  * are all mapped up at PIC1_OFFSET for the cpu / irq_handler. */
428 void irq_handler(struct trapframe *tf)
429 {
430         struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
431         /* Copy out the TF for now */
432         if (!in_kernel(tf))
433                 set_current_tf(pcpui, tf);
434         inc_irq_depth(pcpui);
435         /* Coupled with cpu_halt() and smp_idle() */
436         abort_halt(tf);
437         //if (core_id())
438                 printd("Incoming IRQ, ISR: %d on core %d\n", tf->tf_trapno, core_id());
439         if (check_spurious_irq(tf->tf_trapno))
440                 goto out_no_eoi;
441         /* Send the EOI.  This means the PIC/LAPIC can send us the same IRQ vector,
442          * and we'll handle it as soon as we reenable IRQs.  This does *not* mean
443          * the hardware device that triggered the IRQ had its IRQ reset.  This does
444          * mean we shouldn't enable irqs in a handler that isn't reentrant. */
445         assert(tf->tf_trapno >= 32);
446         send_eoi(tf->tf_trapno);
447
448         extern handler_wrapper_t (RO handler_wrappers)[NUM_HANDLER_WRAPPERS];
449         // determine the interrupt handler table to use.  for now, pick the global
450         handler_t TP(TV(t)) LCKD(&iht_lock) * handler_tbl = interrupt_handlers;
451         if (handler_tbl[tf->tf_trapno].isr != 0)
452                 handler_tbl[tf->tf_trapno].isr(tf, handler_tbl[tf->tf_trapno].data);
453         // if we're a general purpose IPI function call, down the cpu_list
454         if ((I_SMP_CALL0 <= tf->tf_trapno) && (tf->tf_trapno <= I_SMP_CALL_LAST))
455                 down_checklist(handler_wrappers[tf->tf_trapno & 0x0f].cpu_list);
456         /* Fall-through */
457 out_no_eoi:
458         dec_irq_depth(pcpui);
459         /* Return to the current process, which should be runnable.  If we're the
460          * kernel, we should just return naturally.  Note that current and tf need
461          * to still be okay (might not be after blocking) */
462         if (in_kernel(tf))
463                 return;
464         proc_restartcore();
465         assert(0);
466 }
467
468 void
469 register_interrupt_handler(handler_t TP(TV(t)) table[],
470                            uint8_t int_num, poly_isr_t handler, TV(t) data)
471 {
472         table[int_num].isr = handler;
473         table[int_num].data = data;
474 }
475
476 void page_fault_handler(struct trapframe *tf)
477 {
478         uint32_t fault_va = rcr2();
479         int prot = tf->tf_err & PF_ERROR_WRITE ? PROT_WRITE : PROT_READ;
480         int err;
481
482         /* TODO - handle kernel page faults */
483         if ((tf->tf_cs & 3) == 0) {
484                 print_trapframe(tf);
485                 panic("Page Fault in the Kernel at 0x%08x!", fault_va);
486                 /* if we want to do something like kill a process or other code, be
487                  * aware we are in a sort of irq-like context, meaning the main kernel
488                  * code we 'interrupted' could be holding locks - even irqsave locks.
489                  * Send yourself a kernel message to do this sort of work. */
490         }
491         /* safe to reenable after rcr2 */
492         enable_irq();
493         if ((err = handle_page_fault(current, fault_va, prot))) {
494                 /* Destroy the faulting process */
495                 printk("[%08x] user %s fault va %08x ip %08x on core %d with err %d\n",
496                        current->pid, prot & PROT_READ ? "READ" : "WRITE", fault_va,
497                        tf->tf_eip, core_id(), err);
498                 print_trapframe(tf);
499                 proc_destroy(current);
500         }
501 }
502
503 void sysenter_init(void)
504 {
505         write_msr(MSR_IA32_SYSENTER_CS, GD_KT);
506         write_msr(MSR_IA32_SYSENTER_ESP, ts.ts_esp0);
507         write_msr(MSR_IA32_SYSENTER_EIP, (uint32_t) &sysenter_handler);
508 }
509
510 /* This is called from sysenter's asm, with the tf on the kernel stack. */
511 void sysenter_callwrapper(struct trapframe *tf)
512 {
513         struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
514         assert(!in_kernel(tf));
515         set_current_tf(pcpui, tf);
516         /* Once we've set_current_tf, we can enable interrupts.  This used to be
517          * mandatory (we had immediate KMSGs that would muck with cur_tf).  Now it
518          * should only help for sanity/debugging. */
519         enable_irq();
520
521         /* Set up and run the async calls */
522         prep_syscalls(current, (struct syscall*)tf->tf_regs.reg_eax,
523                       tf->tf_regs.reg_esi);
524         /* If you use pcpui again, reread it, since you might have migrated */
525         proc_restartcore();
526 }
527
528 /* Declared in i686/arch.h */
529 void send_ipi(uint32_t os_coreid, uint8_t vector)
530 {
531         int hw_coreid = get_hw_coreid(os_coreid);
532         if (hw_coreid == -1) {
533                 warn("Unmapped OS coreid!\n");
534                 return;
535         }
536         __send_ipi(hw_coreid, vector);
537 }