Proc refcnting wrappers
[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
23 taskstate_t RO ts;
24
25 /* Interrupt descriptor table.  (Must be built at run time because
26  * shifted function addresses can't be represented in relocation records.)
27  */
28 // Aligned on an 8 byte boundary (SDM V3A 5-13)
29 gatedesc_t __attribute__ ((aligned (8))) (RO idt)[256] = { { 0 } };
30 pseudodesc_t RO idt_pd = {
31         sizeof(idt) - 1, (uint32_t) idt
32 };
33
34 /* global handler table, used by core0 (for now).  allows the registration
35  * of functions to be called when servicing an interrupt.  other cores
36  * can set up their own later.
37  */
38 #ifdef __IVY__
39 #pragma cilnoremove("iht_lock")
40 #endif
41 spinlock_t iht_lock;
42 handler_t TP(TV(t)) LCKD(&iht_lock) (RO interrupt_handlers)[NUM_INTERRUPT_HANDLERS];
43
44 static const char *NTS trapname(int trapno)
45 {
46     // zra: excnames is SREADONLY because Ivy doesn't trust const
47         static const char *NT const (RO excnames)[] = {
48                 "Divide error",
49                 "Debug",
50                 "Non-Maskable Interrupt",
51                 "Breakpoint",
52                 "Overflow",
53                 "BOUND Range Exceeded",
54                 "Invalid Opcode",
55                 "Device Not Available",
56                 "Double Fault",
57                 "Coprocessor Segment Overrun",
58                 "Invalid TSS",
59                 "Segment Not Present",
60                 "Stack Fault",
61                 "General Protection",
62                 "Page Fault",
63                 "(unknown trap)",
64                 "x87 FPU Floating-Point Error",
65                 "Alignment Check",
66                 "Machine-Check",
67                 "SIMD Floating-Point Exception"
68         };
69
70         if (trapno < sizeof(excnames)/sizeof(excnames[0]))
71                 return excnames[trapno];
72         if (trapno == T_SYSCALL)
73                 return "System call";
74         return "(unknown trap)";
75 }
76
77 /* Set stacktop for the current core to be the stack the kernel will start on
78  * when trapping/interrupting from userspace.  Don't use this til after
79  * smp_percpu_init().  We can probably get the TSS by reading the task register
80  * and then the GDT.  Still, it's a pain. */
81 void set_stack_top(uintptr_t stacktop)
82 {
83         struct per_cpu_info *pcpu = &per_cpu_info[core_id()];
84         /* No need to reload the task register, this takes effect immediately */
85         pcpu->tss->ts_esp0 = stacktop;
86         /* Also need to make sure sysenters come in correctly */
87         write_msr(MSR_IA32_SYSENTER_ESP, stacktop);
88 }
89
90 /* Note the check implies we only are on a one page stack (or the first page) */
91 uintptr_t get_stack_top(void)
92 {
93         struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
94         uintptr_t stacktop;
95         /* so we can check this in interrupt handlers (before smp_boot()) */
96         if (!pcpui->tss)
97                 return ROUNDUP(read_esp(), PGSIZE);
98         stacktop = pcpui->tss->ts_esp0;
99         if (stacktop != ROUNDUP(read_esp(), PGSIZE))
100                 panic("Bad stacktop: %08p esp one is %08p\n", stacktop,
101                       ROUNDUP(read_esp(), PGSIZE));
102         return stacktop;
103 }
104
105 /* Starts running the current TF, just using ret. */
106 void pop_kernel_tf(struct trapframe *tf)
107 {
108         asm volatile ("movl %1,%%esp;           " /* move to future stack */
109                       "pushl %2;                " /* push cs */
110                       "movl %0,%%esp;           " /* move to TF */
111                       "addl $0x20,%%esp;        " /* move to tf_gs slot */
112                       "movl %1,(%%esp);         " /* write future esp */
113                       "subl $0x20,%%esp;        " /* move back to tf start */
114                       "popal;                   " /* restore regs */
115                       "popl %%esp;              " /* set stack ptr */
116                       "subl $0x4,%%esp;         " /* jump down past CS */
117                       "ret                      " /* return to the EIP */
118                       :
119                       : "g"(tf), "r"(tf->tf_esp), "r"(tf->tf_eip) : "memory");
120         panic("ret failed");                            /* mostly to placate your mom */
121 }
122
123 void idt_init(void)
124 {
125         extern segdesc_t (RO gdt)[];
126
127         // This table is made in trapentry.S by each macro in that file.
128         // It is layed out such that the ith entry is the ith's traphandler's
129         // (uint32_t) trap addr, then (uint32_t) trap number
130         struct trapinfo { uint32_t trapaddr; uint32_t trapnumber; };
131         extern struct trapinfo (BND(__this,trap_tbl_end) RO trap_tbl)[];
132         extern struct trapinfo (SNT RO trap_tbl_end)[];
133         int i, trap_tbl_size = trap_tbl_end - trap_tbl;
134         extern void ISR_default(void);
135
136         // set all to default, to catch everything
137         for(i = 0; i < 256; i++)
138                 ROSETGATE(idt[i], 0, GD_KT, &ISR_default, 0);
139
140         // set all entries that have real trap handlers
141         // we need to stop short of the last one, since the last is the default
142         // handler with a fake interrupt number (500) that is out of bounds of
143         // the idt[]
144         // if we set these to trap gates, be sure to handle the IRQs separately
145         // and we might need to break our pretty tables
146         for(i = 0; i < trap_tbl_size - 1; i++)
147                 ROSETGATE(idt[trap_tbl[i].trapnumber], 0, GD_KT, trap_tbl[i].trapaddr, 0);
148
149         // turn on syscall handling and other user-accessible ints
150         // DPL 3 means this can be triggered by the int instruction
151         // STS_TG32 sets the IDT type to a Trap Gate (interrupts enabled)
152         idt[T_SYSCALL].gd_dpl = SINIT(3);
153         idt[T_SYSCALL].gd_type = SINIT(STS_TG32);
154         idt[T_BRKPT].gd_dpl = SINIT(3);
155
156         /* Setup a TSS so that we get the right stack when we trap to the kernel.
157          * We need to use the KVA for stacktop, and not the memlayout virtual
158          * address, so we can free it later (and check for other bugs). */
159         pte_t *pte = pgdir_walk(boot_pgdir, (void*)KSTACKTOP - PGSIZE, 0);
160         uintptr_t stacktop_kva = (uintptr_t)ppn2kva(PTE2PPN(*pte)) + PGSIZE;
161         ts.ts_esp0 = stacktop_kva;
162         ts.ts_ss0 = SINIT(GD_KD);
163
164         // Initialize the TSS field of the gdt.
165         SEG16ROINIT(gdt[GD_TSS >> 3],STS_T32A, (uint32_t)(&ts),sizeof(taskstate_t),0);
166         //gdt[GD_TSS >> 3] = (segdesc_t)SEG16(STS_T32A, (uint32_t) (&ts),
167         //                                 sizeof(taskstate_t), 0);
168         gdt[GD_TSS >> 3].sd_s = SINIT(0);
169
170         // Load the TSS
171         ltr(GD_TSS);
172
173         // Load the IDT
174         asm volatile("lidt idt_pd");
175
176         // This will go away when we start using the IOAPIC properly
177         pic_remap();
178         // set LINT0 to receive ExtINTs (KVM's default).  At reset they are 0x1000.
179         write_mmreg32(LAPIC_LVT_LINT0, 0x700);
180         // mask it to shut it up for now
181         mask_lapic_lvt(LAPIC_LVT_LINT0);
182         // and turn it on
183         lapic_enable();
184         /* register the generic timer_interrupt() handler for the per-core timers */
185         register_interrupt_handler(interrupt_handlers, LAPIC_TIMER_DEFAULT_VECTOR,
186                                    timer_interrupt, NULL);
187 }
188
189 void
190 print_regs(push_regs_t *regs)
191 {
192         cprintf("  edi  0x%08x\n", regs->reg_edi);
193         cprintf("  esi  0x%08x\n", regs->reg_esi);
194         cprintf("  ebp  0x%08x\n", regs->reg_ebp);
195         cprintf("  oesp 0x%08x\n", regs->reg_oesp);
196         cprintf("  ebx  0x%08x\n", regs->reg_ebx);
197         cprintf("  edx  0x%08x\n", regs->reg_edx);
198         cprintf("  ecx  0x%08x\n", regs->reg_ecx);
199         cprintf("  eax  0x%08x\n", regs->reg_eax);
200 }
201
202 void
203 print_trapframe(trapframe_t *tf)
204 {
205         static spinlock_t ptf_lock;
206
207         spin_lock_irqsave(&ptf_lock);
208         printk("TRAP frame at %p on core %d\n", tf, core_id());
209         print_regs(&tf->tf_regs);
210         printk("  gs   0x----%04x\n", tf->tf_gs);
211         printk("  fs   0x----%04x\n", tf->tf_fs);
212         printk("  es   0x----%04x\n", tf->tf_es);
213         printk("  ds   0x----%04x\n", tf->tf_ds);
214         printk("  trap 0x%08x %s\n", tf->tf_trapno, trapname(tf->tf_trapno));
215         printk("  err  0x%08x\n", tf->tf_err);
216         printk("  eip  0x%08x\n", tf->tf_eip);
217         printk("  cs   0x----%04x\n", tf->tf_cs);
218         printk("  flag 0x%08x\n", tf->tf_eflags);
219         /* Prevents us from thinking these mean something for nested interrupts. */
220         if (tf->tf_cs != GD_KT) {
221                 printk("  esp  0x%08x\n", tf->tf_esp);
222                 printk("  ss   0x----%04x\n", tf->tf_ss);
223         }
224         spin_unlock_irqsave(&ptf_lock);
225 }
226
227 static void
228 trap_dispatch(trapframe_t *tf)
229 {
230         // Handle processor exceptions.
231         switch(tf->tf_trapno) {
232                 case T_BRKPT:
233                         monitor(tf);
234                         break;
235                 case T_PGFLT:
236                         page_fault_handler(tf);
237                         break;
238                 case T_SYSCALL:
239                         // check for userspace, for now
240                         assert(tf->tf_cs != GD_KT);
241                         /* Set up and run the async calls */
242                         prep_syscalls(current, (struct syscall*)tf->tf_regs.reg_eax,
243                                       tf->tf_regs.reg_edx);
244                         break;
245                 default:
246                         // Unexpected trap: The user process or the kernel has a bug.
247                         print_trapframe(tf);
248                         if (tf->tf_cs == GD_KT)
249                                 panic("Damn Damn!  Unhandled trap in the kernel!");
250                         else {
251                                 warn("Unexpected trap from userspace");
252                                 proc_incref(current, 1);
253                                 proc_destroy(current);
254                                 return;
255                         }
256         }
257         return;
258 }
259
260 void
261 env_push_ancillary_state(env_t* e)
262 {
263         // TODO: (HSS) handle silly state (don't really want this per-process)
264         // Here's where you'll save FP/MMX/XMM regs
265 }
266
267 void
268 env_pop_ancillary_state(env_t* e)
269 {
270         // Here's where you'll restore FP/MMX/XMM regs
271 }
272
273 /* Helper.  For now, this copies out the TF to pcpui, and sets the tf to use it.
274  * Eventually, we ought to do this in trapentry.S */
275 static void set_current_tf(struct per_cpu_info *pcpui, struct trapframe **tf)
276 {
277         pcpui->actual_tf = **tf;
278         pcpui->cur_tf = &pcpui->actual_tf;
279         *tf = &pcpui->actual_tf;
280 }
281
282 void trap(struct trapframe *tf)
283 {
284         struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
285         /* Copy out the TF for now, set tf to point to it.  */
286         if (!in_kernel(tf))
287                 set_current_tf(pcpui, &tf);
288
289         printd("Incoming TRAP %d on core %d, TF at %p\n", tf->tf_trapno, core_id(),
290                tf);
291         if ((tf->tf_cs & ~3) != GD_UT && (tf->tf_cs & ~3) != GD_KT) {
292                 print_trapframe(tf);
293                 panic("Trapframe with invalid CS!");
294         }
295         trap_dispatch(tf);
296         /* Return to the current process, which should be runnable.  If we're the
297          * kernel, we should just return naturally.  Note that current and tf need
298          * to still be okay (might not be after blocking) */
299         if (in_kernel(tf))
300                 return; /* TODO: think about this, might want a helper instead. */
301         proc_restartcore();
302         assert(0);
303 }
304
305 void irq_handler(struct trapframe *tf)
306 {
307         struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
308         /* Copy out the TF for now, set tf to point to it. */
309         if (!in_kernel(tf))
310                 set_current_tf(pcpui, &tf);
311
312         //if (core_id())
313                 printd("Incoming IRQ, ISR: %d on core %d\n", tf->tf_trapno, core_id());
314
315         extern handler_wrapper_t (RO handler_wrappers)[NUM_HANDLER_WRAPPERS];
316
317         // determine the interrupt handler table to use.  for now, pick the global
318         handler_t TP(TV(t)) LCKD(&iht_lock) * handler_tbl = interrupt_handlers;
319
320         if (handler_tbl[tf->tf_trapno].isr != 0)
321                 handler_tbl[tf->tf_trapno].isr(tf, handler_tbl[tf->tf_trapno].data);
322         // if we're a general purpose IPI function call, down the cpu_list
323         if ((I_SMP_CALL0 <= tf->tf_trapno) && (tf->tf_trapno <= I_SMP_CALL_LAST))
324                 down_checklist(handler_wrappers[tf->tf_trapno & 0x0f].cpu_list);
325
326         // Send EOI.  might want to do this in assembly, and possibly earlier
327         // This is set up to work with an old PIC for now
328         // Convention is that all IRQs between 32 and 47 are for the PIC.
329         // All others are LAPIC (timer, IPIs, perf, non-ExtINT LINTS, etc)
330         // For now, only 235-255 are available
331         assert(tf->tf_trapno >= 32); // slows us down, but we should never have this
332
333 #ifdef __CONFIG_ENABLE_MPTABLES__
334         /* TODO: this should be for any IOAPIC EOI, not just MPTABLES */
335         lapic_send_eoi();
336 #else
337         //Old PIC relatd code. Should be gone for good, but leaving it just incase.
338         if (tf->tf_trapno < 48)
339                 pic_send_eoi(tf->tf_trapno - PIC1_OFFSET);
340         else
341                 lapic_send_eoi();
342 #endif
343         /* Return to the current process, which should be runnable.  If we're the
344          * kernel, we should just return naturally.  Note that current and tf need
345          * to still be okay (might not be after blocking) */
346         if (in_kernel(tf))
347                 return; /* TODO: think about this, might want a helper instead. */
348         proc_restartcore();
349         assert(0);
350 }
351
352 void
353 register_interrupt_handler(handler_t TP(TV(t)) table[],
354                            uint8_t int_num, poly_isr_t handler, TV(t) data)
355 {
356         table[int_num].isr = handler;
357         table[int_num].data = data;
358 }
359
360 void page_fault_handler(struct trapframe *tf)
361 {
362         uint32_t fault_va = rcr2();
363         int prot = tf->tf_err & PF_ERROR_WRITE ? PROT_WRITE : PROT_READ;
364         int err;
365
366         /* TODO - handle kernel page faults */
367         if ((tf->tf_cs & 3) == 0) {
368                 print_trapframe(tf);
369                 panic("Page Fault in the Kernel at 0x%08x!", fault_va);
370         }
371         if ((err = handle_page_fault(current, fault_va, prot))) {
372                 /* Destroy the faulting process */
373                 printk("[%08x] user %s fault va %08x ip %08x on core %d with err %d\n",
374                        current->pid, prot & PROT_READ ? "READ" : "WRITE", fault_va,
375                        tf->tf_eip, core_id(), err);
376                 print_trapframe(tf);
377                 proc_incref(current, 1);
378                 proc_destroy(current);
379         }
380 }
381
382 void sysenter_init(void)
383 {
384         write_msr(MSR_IA32_SYSENTER_CS, GD_KT);
385         write_msr(MSR_IA32_SYSENTER_ESP, ts.ts_esp0);
386         write_msr(MSR_IA32_SYSENTER_EIP, (uint32_t) &sysenter_handler);
387 }
388
389 /* This is called from sysenter's asm, with the tf on the kernel stack. */
390 void sysenter_callwrapper(struct trapframe *tf)
391 {
392         struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
393         /* Copy out the TF for now, set tf to point to it. */
394         if (!in_kernel(tf))
395                 set_current_tf(pcpui, &tf);
396
397         if (in_kernel(tf))
398                 panic("sysenter from a kernel TF!!");
399         /* Set up and run the async calls */
400         prep_syscalls(current, (struct syscall*)tf->tf_regs.reg_eax,
401                       tf->tf_regs.reg_esi);
402         proc_restartcore();
403 }
404
405 struct kmem_cache *kernel_msg_cache;
406 void kernel_msg_init(void)
407 {
408         kernel_msg_cache = kmem_cache_create("kernel_msgs",
409                            sizeof(struct kernel_message), HW_CACHE_ALIGN, 0, 0, 0);
410 }
411
412 uint32_t send_kernel_message(uint32_t dst, amr_t pc, TV(a0t) arg0, TV(a1t) arg1,
413                              TV(a2t) arg2, int type)
414 {
415         kernel_message_t *k_msg;
416         assert(pc);
417         // note this will be freed on the destination core
418         k_msg = (kernel_message_t *CT(1))TC(kmem_cache_alloc(kernel_msg_cache, 0));
419         k_msg->srcid = core_id();
420         k_msg->pc = pc;
421         k_msg->arg0 = arg0;
422         k_msg->arg1 = arg1;
423         k_msg->arg2 = arg2;
424         switch (type) {
425                 case KMSG_IMMEDIATE:
426                         spin_lock_irqsave(&per_cpu_info[dst].immed_amsg_lock);
427                         STAILQ_INSERT_TAIL(&per_cpu_info[dst].immed_amsgs, k_msg, link);
428                         spin_unlock_irqsave(&per_cpu_info[dst].immed_amsg_lock);
429                         break;
430                 case KMSG_ROUTINE:
431                         spin_lock_irqsave(&per_cpu_info[dst].routine_amsg_lock);
432                         STAILQ_INSERT_TAIL(&per_cpu_info[dst].routine_amsgs, k_msg, link);
433                         spin_unlock_irqsave(&per_cpu_info[dst].routine_amsg_lock);
434                         break;
435                 default:
436                         panic("Unknown type of kernel message!");
437         }
438         /* since we touched memory the other core will touch (the lock), we don't
439          * need an wmb_f() */
440         /* if we're sending a routine message locally, we don't want/need an IPI */
441         if ((dst != k_msg->srcid) || (type == KMSG_IMMEDIATE))
442                 send_ipi(get_hw_coreid(dst), I_KERNEL_MSG);
443         return 0;
444 }
445
446 /* Helper function.  Returns 0 if the list was empty. */
447 static kernel_message_t *get_next_amsg(struct kernel_msg_list *list_head,
448                                        spinlock_t *list_lock)
449 {
450         kernel_message_t *k_msg;
451         spin_lock_irqsave(list_lock);
452         k_msg = STAILQ_FIRST(list_head);
453         if (k_msg)
454                 STAILQ_REMOVE_HEAD(list_head, link);
455         spin_unlock_irqsave(list_lock);
456         return k_msg;
457 }
458
459 /* Kernel message handler.  Extensive documentation is in
460  * Documentation/kernel_messages.txt.
461  *
462  * In general: this processes immediate messages, then routine messages.
463  * Routine messages might not return (__startcore, etc), so we need to be
464  * careful about a few things.
465  *
466  * Note that all of this happens from interrupt context, and interrupts are
467  * currently disabled for this gate.  Interrupts need to be disabled so that the
468  * self-ipi doesn't preempt the execution of this kernel message. */
469 void __kernel_message(struct trapframe *tf)
470 {
471         per_cpu_info_t *myinfo = &per_cpu_info[core_id()];
472         kernel_message_t msg_cp, *k_msg;
473
474         /* Copy out the TF for now, set tf to point to it. */
475         if (!in_kernel(tf))
476                 set_current_tf(myinfo, &tf);
477
478         lapic_send_eoi();
479         while (1) { // will break out when there are no more messages
480                 /* Try to get an immediate message.  Exec and free it. */
481                 k_msg = get_next_amsg(&myinfo->immed_amsgs, &myinfo->immed_amsg_lock);
482                 if (k_msg) {
483                         assert(k_msg->pc);
484                         k_msg->pc(tf, k_msg->srcid, k_msg->arg0, k_msg->arg1, k_msg->arg2);
485                         kmem_cache_free(kernel_msg_cache, (void*)k_msg);
486                 } else { // no immediate, might be a routine
487                         if (in_kernel(tf))
488                                 return; // don't execute routine msgs if we were in the kernel
489                         k_msg = get_next_amsg(&myinfo->routine_amsgs,
490                                               &myinfo->routine_amsg_lock);
491                         if (!k_msg) // no routines either
492                                 return;
493                         /* copy in, and then free, in case we don't return */
494                         msg_cp = *k_msg;
495                         kmem_cache_free(kernel_msg_cache, (void*)k_msg);
496                         /* make sure an IPI is pending if we have more work */
497                         /* techincally, we don't need to lock when checking */
498                         if (!STAILQ_EMPTY(&myinfo->routine_amsgs) &&
499                                !ipi_is_pending(I_KERNEL_MSG))
500                                 send_self_ipi(I_KERNEL_MSG);
501                         /* Execute the kernel message */
502                         assert(msg_cp.pc);
503                         /* TODO: when batching syscalls, this should be reread from cur_tf*/
504                         msg_cp.pc(tf, msg_cp.srcid, msg_cp.arg0, msg_cp.arg1, msg_cp.arg2);
505                 }
506         }
507 }
508
509 /* Runs any outstanding routine kernel messages from within the kernel.  Will
510  * make sure immediates still run first (or when they arrive, if processing a
511  * bunch of these messages).  This will disable interrupts, and restore them to
512  * whatever state you left them. */
513 void process_routine_kmsg(struct trapframe *tf)
514 {
515         per_cpu_info_t *myinfo = &per_cpu_info[core_id()];
516         kernel_message_t msg_cp, *k_msg;
517         int8_t irq_state = 0;
518
519         disable_irqsave(&irq_state);
520         /* If we were told what our TF was, use that.  o/w, go with current_tf. */
521         tf = tf ? tf : current_tf;
522         while (1) {
523                 /* normally, we want ints disabled, so we don't have an empty self-ipi
524                  * for every routine message. (imagine a long list of routines).  But we
525                  * do want immediates to run ahead of routines.  This enabling should
526                  * work (might not in some shitty VMs).  Also note we can receive an
527                  * extra self-ipi for routine messages before we turn off irqs again.
528                  * Not a big deal, since we will process it right away. 
529                  * TODO: consider calling __kernel_message() here. */
530                 if (!STAILQ_EMPTY(&myinfo->immed_amsgs)) {
531                         enable_irq();
532                         cpu_relax();
533                         disable_irq();
534                 }
535                 k_msg = get_next_amsg(&myinfo->routine_amsgs,
536                                       &myinfo->routine_amsg_lock);
537                 if (!k_msg) {
538                         enable_irqsave(&irq_state);
539                         return;
540                 }
541                 /* copy in, and then free, in case we don't return */
542                 msg_cp = *k_msg;
543                 kmem_cache_free(kernel_msg_cache, (void*)k_msg);
544                 /* make sure an IPI is pending if we have more work */
545                 if (!STAILQ_EMPTY(&myinfo->routine_amsgs) &&
546                        !ipi_is_pending(I_KERNEL_MSG))
547                         send_self_ipi(I_KERNEL_MSG);
548                 /* Execute the kernel message */
549                 assert(msg_cp.pc);
550                 msg_cp.pc(tf, msg_cp.srcid, msg_cp.arg0, msg_cp.arg1, msg_cp.arg2);
551         }
552 }