d5f567cb8d7283854428b28037d6aaeefffadb38
[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 Trap Gate (interrupts enabled)
162         idt[T_SYSCALL].gd_dpl = SINIT(3);
163         idt[T_SYSCALL].gd_type = SINIT(STS_TG32);
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          * We need to use the KVA for stacktop, and not the memlayout virtual
168          * address, so we can free it later (and check for other bugs). */
169         pte_t *pte = pgdir_walk(boot_pgdir, (void*)KSTACKTOP - PGSIZE, 0);
170         uintptr_t stacktop_kva = (uintptr_t)ppn2kva(PTE2PPN(*pte)) + PGSIZE;
171         ts.ts_esp0 = stacktop_kva;
172         ts.ts_ss0 = SINIT(GD_KD);
173 #ifdef __CONFIG_KTHREAD_POISON__
174         /* TODO: KTHR-STACK */
175         uintptr_t *poison = (uintptr_t*)ROUNDDOWN(stacktop_kva - 1, PGSIZE);
176         *poison = 0xdeadbeef;
177 #endif /* __CONFIG_KTHREAD_POISON__ */
178
179         // Initialize the TSS field of the gdt.
180         SEG16ROINIT(gdt[GD_TSS >> 3],STS_T32A, (uint32_t)(&ts),sizeof(taskstate_t),0);
181         //gdt[GD_TSS >> 3] = (segdesc_t)SEG16(STS_T32A, (uint32_t) (&ts),
182         //                                 sizeof(taskstate_t), 0);
183         gdt[GD_TSS >> 3].sd_s = SINIT(0);
184
185         // Load the TSS
186         ltr(GD_TSS);
187
188         // Load the IDT
189         asm volatile("lidt idt_pd");
190
191         // This will go away when we start using the IOAPIC properly
192         pic_remap();
193         // set LINT0 to receive ExtINTs (KVM's default).  At reset they are 0x1000.
194         write_mmreg32(LAPIC_LVT_LINT0, 0x700);
195         // mask it to shut it up for now
196         mask_lapic_lvt(LAPIC_LVT_LINT0);
197         // and turn it on
198         lapic_enable();
199         /* register the generic timer_interrupt() handler for the per-core timers */
200         register_interrupt_handler(interrupt_handlers, LAPIC_TIMER_DEFAULT_VECTOR,
201                                    timer_interrupt, NULL);
202 }
203
204 void
205 print_regs(push_regs_t *regs)
206 {
207         cprintf("  edi  0x%08x\n", regs->reg_edi);
208         cprintf("  esi  0x%08x\n", regs->reg_esi);
209         cprintf("  ebp  0x%08x\n", regs->reg_ebp);
210         cprintf("  oesp 0x%08x\n", regs->reg_oesp);
211         cprintf("  ebx  0x%08x\n", regs->reg_ebx);
212         cprintf("  edx  0x%08x\n", regs->reg_edx);
213         cprintf("  ecx  0x%08x\n", regs->reg_ecx);
214         cprintf("  eax  0x%08x\n", regs->reg_eax);
215 }
216
217 void
218 print_trapframe(trapframe_t *tf)
219 {
220         static spinlock_t ptf_lock;
221
222         spin_lock_irqsave(&ptf_lock);
223         printk("TRAP frame at %p on core %d\n", tf, core_id());
224         print_regs(&tf->tf_regs);
225         printk("  gs   0x----%04x\n", tf->tf_gs);
226         printk("  fs   0x----%04x\n", tf->tf_fs);
227         printk("  es   0x----%04x\n", tf->tf_es);
228         printk("  ds   0x----%04x\n", tf->tf_ds);
229         printk("  trap 0x%08x %s\n", tf->tf_trapno, trapname(tf->tf_trapno));
230         printk("  err  0x%08x\n", tf->tf_err);
231         printk("  eip  0x%08x\n", tf->tf_eip);
232         printk("  cs   0x----%04x\n", tf->tf_cs);
233         printk("  flag 0x%08x\n", tf->tf_eflags);
234         /* Prevents us from thinking these mean something for nested interrupts. */
235         if (tf->tf_cs != GD_KT) {
236                 printk("  esp  0x%08x\n", tf->tf_esp);
237                 printk("  ss   0x----%04x\n", tf->tf_ss);
238         }
239         spin_unlock_irqsave(&ptf_lock);
240 }
241
242 static void trap_dispatch(struct trapframe *tf)
243 {
244         // Handle processor exceptions.
245         switch(tf->tf_trapno) {
246                 case T_NMI:
247                         print_trapframe(tf);
248                         char *fn_name = get_fn_name(tf->tf_eip);
249                         printk("Core %d is at %08p (%s)\n", core_id(), tf->tf_eip, fn_name);
250                         kfree(fn_name);
251                         break;
252                 case T_BRKPT:
253                         monitor(tf);
254                         break;
255                 case T_PGFLT:
256                         page_fault_handler(tf);
257                         break;
258                 case T_SYSCALL:
259                         // check for userspace, for now
260                         assert(tf->tf_cs != GD_KT);
261                         /* Set up and run the async calls */
262                         prep_syscalls(current, (struct syscall*)tf->tf_regs.reg_eax,
263                                       tf->tf_regs.reg_edx);
264                         break;
265                 default:
266                         // Unexpected trap: The user process or the kernel has a bug.
267                         print_trapframe(tf);
268                         if (tf->tf_cs == GD_KT)
269                                 panic("Damn Damn!  Unhandled trap in the kernel!");
270                         else {
271                                 warn("Unexpected trap from userspace");
272                                 proc_incref(current, 1);
273                                 proc_destroy(current);
274                                 assert(0);
275                                 return;
276                         }
277         }
278         return;
279 }
280
281 void
282 env_push_ancillary_state(env_t* e)
283 {
284         // TODO: (HSS) handle silly state (don't really want this per-process)
285         // Here's where you'll save FP/MMX/XMM regs
286 }
287
288 void
289 env_pop_ancillary_state(env_t* e)
290 {
291         // Here's where you'll restore FP/MMX/XMM regs
292 }
293
294 /* Helper.  For now, this copies out the TF to pcpui, and sets the tf to use it.
295  * Eventually, we ought to do this in trapentry.S */
296 static void set_current_tf(struct per_cpu_info *pcpui, struct trapframe **tf)
297 {
298         pcpui->actual_tf = **tf;
299         pcpui->cur_tf = &pcpui->actual_tf;
300         *tf = &pcpui->actual_tf;
301 }
302
303 void trap(struct trapframe *tf)
304 {
305         struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
306         /* Copy out the TF for now, set tf to point to it.  */
307         if (!in_kernel(tf))
308                 set_current_tf(pcpui, &tf);
309
310         printd("Incoming TRAP %d on core %d, TF at %p\n", tf->tf_trapno, core_id(),
311                tf);
312         if ((tf->tf_cs & ~3) != GD_UT && (tf->tf_cs & ~3) != GD_KT) {
313                 print_trapframe(tf);
314                 panic("Trapframe with invalid CS!");
315         }
316         trap_dispatch(tf);
317         /* Return to the current process, which should be runnable.  If we're the
318          * kernel, we should just return naturally.  Note that current and tf need
319          * to still be okay (might not be after blocking) */
320         if (in_kernel(tf))
321                 return; /* TODO: think about this, might want a helper instead. */
322         proc_restartcore();
323         assert(0);
324 }
325
326 void irq_handler(struct trapframe *tf)
327 {
328         struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
329         /* Copy out the TF for now, set tf to point to it. */
330         if (!in_kernel(tf))
331                 set_current_tf(pcpui, &tf);
332
333         //if (core_id())
334                 printd("Incoming IRQ, ISR: %d on core %d\n", tf->tf_trapno, core_id());
335
336         extern handler_wrapper_t (RO handler_wrappers)[NUM_HANDLER_WRAPPERS];
337
338         // determine the interrupt handler table to use.  for now, pick the global
339         handler_t TP(TV(t)) LCKD(&iht_lock) * handler_tbl = interrupt_handlers;
340
341         if (handler_tbl[tf->tf_trapno].isr != 0)
342                 handler_tbl[tf->tf_trapno].isr(tf, handler_tbl[tf->tf_trapno].data);
343         // if we're a general purpose IPI function call, down the cpu_list
344         if ((I_SMP_CALL0 <= tf->tf_trapno) && (tf->tf_trapno <= I_SMP_CALL_LAST))
345                 down_checklist(handler_wrappers[tf->tf_trapno & 0x0f].cpu_list);
346
347         // Send EOI.  might want to do this in assembly, and possibly earlier
348         // This is set up to work with an old PIC for now
349         // Convention is that all IRQs between 32 and 47 are for the PIC.
350         // All others are LAPIC (timer, IPIs, perf, non-ExtINT LINTS, etc)
351         // For now, only 235-255 are available
352         assert(tf->tf_trapno >= 32); // slows us down, but we should never have this
353
354 #ifdef __CONFIG_ENABLE_MPTABLES__
355         /* TODO: this should be for any IOAPIC EOI, not just MPTABLES */
356         lapic_send_eoi();
357 #else
358         //Old PIC relatd code. Should be gone for good, but leaving it just incase.
359         if (tf->tf_trapno < 48)
360                 pic_send_eoi(tf->tf_trapno - PIC1_OFFSET);
361         else
362                 lapic_send_eoi();
363 #endif
364         /* Return to the current process, which should be runnable.  If we're the
365          * kernel, we should just return naturally.  Note that current and tf need
366          * to still be okay (might not be after blocking) */
367         if (in_kernel(tf))
368                 return; /* TODO: think about this, might want a helper instead. */
369         proc_restartcore();
370         assert(0);
371 }
372
373 void
374 register_interrupt_handler(handler_t TP(TV(t)) table[],
375                            uint8_t int_num, poly_isr_t handler, TV(t) data)
376 {
377         table[int_num].isr = handler;
378         table[int_num].data = data;
379 }
380
381 void page_fault_handler(struct trapframe *tf)
382 {
383         uint32_t fault_va = rcr2();
384         int prot = tf->tf_err & PF_ERROR_WRITE ? PROT_WRITE : PROT_READ;
385         int err;
386
387         /* TODO - handle kernel page faults */
388         if ((tf->tf_cs & 3) == 0) {
389                 print_trapframe(tf);
390                 panic("Page Fault in the Kernel at 0x%08x!", fault_va);
391         }
392         if ((err = handle_page_fault(current, fault_va, prot))) {
393                 /* Destroy the faulting process */
394                 printk("[%08x] user %s fault va %08x ip %08x on core %d with err %d\n",
395                        current->pid, prot & PROT_READ ? "READ" : "WRITE", fault_va,
396                        tf->tf_eip, core_id(), err);
397                 print_trapframe(tf);
398                 proc_incref(current, 1);
399                 proc_destroy(current);
400                 assert(0);
401         }
402 }
403
404 void sysenter_init(void)
405 {
406         write_msr(MSR_IA32_SYSENTER_CS, GD_KT);
407         write_msr(MSR_IA32_SYSENTER_ESP, ts.ts_esp0);
408         write_msr(MSR_IA32_SYSENTER_EIP, (uint32_t) &sysenter_handler);
409 }
410
411 /* This is called from sysenter's asm, with the tf on the kernel stack. */
412 void sysenter_callwrapper(struct trapframe *tf)
413 {
414         struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
415         /* Copy out the TF for now, set tf to point to it. */
416         if (!in_kernel(tf))
417                 set_current_tf(pcpui, &tf);
418
419         if (in_kernel(tf))
420                 panic("sysenter from a kernel TF!!");
421         /* Set up and run the async calls */
422         prep_syscalls(current, (struct syscall*)tf->tf_regs.reg_eax,
423                       tf->tf_regs.reg_esi);
424         /* If you use pcpui again, reread it, since you might have migrated */
425         proc_restartcore();
426 }
427
428 struct kmem_cache *kernel_msg_cache;
429 void kernel_msg_init(void)
430 {
431         kernel_msg_cache = kmem_cache_create("kernel_msgs",
432                            sizeof(struct kernel_message), HW_CACHE_ALIGN, 0, 0, 0);
433 }
434
435 uint32_t send_kernel_message(uint32_t dst, amr_t pc, TV(a0t) arg0, TV(a1t) arg1,
436                              TV(a2t) arg2, int type)
437 {
438         kernel_message_t *k_msg;
439         assert(pc);
440         // note this will be freed on the destination core
441         k_msg = (kernel_message_t *CT(1))TC(kmem_cache_alloc(kernel_msg_cache, 0));
442         k_msg->srcid = core_id();
443         k_msg->dstid = dst;
444         k_msg->pc = pc;
445         k_msg->arg0 = arg0;
446         k_msg->arg1 = arg1;
447         k_msg->arg2 = arg2;
448         switch (type) {
449                 case KMSG_IMMEDIATE:
450                         spin_lock_irqsave(&per_cpu_info[dst].immed_amsg_lock);
451                         STAILQ_INSERT_TAIL(&per_cpu_info[dst].immed_amsgs, k_msg, link);
452                         spin_unlock_irqsave(&per_cpu_info[dst].immed_amsg_lock);
453                         break;
454                 case KMSG_ROUTINE:
455                         spin_lock_irqsave(&per_cpu_info[dst].routine_amsg_lock);
456                         STAILQ_INSERT_TAIL(&per_cpu_info[dst].routine_amsgs, k_msg, link);
457                         spin_unlock_irqsave(&per_cpu_info[dst].routine_amsg_lock);
458                         break;
459                 default:
460                         panic("Unknown type of kernel message!");
461         }
462         /* since we touched memory the other core will touch (the lock), we don't
463          * need an wmb_f() */
464         /* if we're sending a routine message locally, we don't want/need an IPI */
465         if ((dst != k_msg->srcid) || (type == KMSG_IMMEDIATE))
466                 send_ipi(get_hw_coreid(dst), I_KERNEL_MSG);
467         return 0;
468 }
469
470 /* Helper function.  Returns 0 if the list was empty. */
471 static kernel_message_t *get_next_amsg(struct kernel_msg_list *list_head,
472                                        spinlock_t *list_lock)
473 {
474         kernel_message_t *k_msg;
475         spin_lock_irqsave(list_lock);
476         k_msg = STAILQ_FIRST(list_head);
477         if (k_msg)
478                 STAILQ_REMOVE_HEAD(list_head, link);
479         spin_unlock_irqsave(list_lock);
480         return k_msg;
481 }
482
483 /* Kernel message handler.  Extensive documentation is in
484  * Documentation/kernel_messages.txt.
485  *
486  * In general: this processes immediate messages, then routine messages.
487  * Routine messages might not return (__startcore, etc), so we need to be
488  * careful about a few things.
489  *
490  * Note that all of this happens from interrupt context, and interrupts are
491  * currently disabled for this gate.  Interrupts need to be disabled so that the
492  * self-ipi doesn't preempt the execution of this kernel message. */
493 void __kernel_message(struct trapframe *tf)
494 {
495         per_cpu_info_t *myinfo = &per_cpu_info[core_id()];
496         kernel_message_t msg_cp, *k_msg;
497
498         /* Copy out the TF for now, set tf to point to it. */
499         if (!in_kernel(tf))
500                 set_current_tf(myinfo, &tf);
501
502         lapic_send_eoi();
503         while (1) { // will break out when there are no more messages
504                 /* Try to get an immediate message.  Exec and free it. */
505                 k_msg = get_next_amsg(&myinfo->immed_amsgs, &myinfo->immed_amsg_lock);
506                 if (k_msg) {
507                         assert(k_msg->pc);
508                         k_msg->pc(tf, k_msg->srcid, k_msg->arg0, k_msg->arg1, k_msg->arg2);
509                         kmem_cache_free(kernel_msg_cache, (void*)k_msg);
510                 } else { // no immediate, might be a routine
511                         if (in_kernel(tf))
512                                 return; // don't execute routine msgs if we were in the kernel
513                         k_msg = get_next_amsg(&myinfo->routine_amsgs,
514                                               &myinfo->routine_amsg_lock);
515                         if (!k_msg) // no routines either
516                                 return;
517                         /* copy in, and then free, in case we don't return */
518                         msg_cp = *k_msg;
519                         kmem_cache_free(kernel_msg_cache, (void*)k_msg);
520                         /* make sure an IPI is pending if we have more work */
521                         /* techincally, we don't need to lock when checking */
522                         if (!STAILQ_EMPTY(&myinfo->routine_amsgs) &&
523                                !ipi_is_pending(I_KERNEL_MSG))
524                                 send_self_ipi(I_KERNEL_MSG);
525                         /* Execute the kernel message */
526                         assert(msg_cp.pc);
527                         assert(msg_cp.dstid == core_id());
528                         /* TODO: when batching syscalls, this should be reread from cur_tf*/
529                         msg_cp.pc(tf, msg_cp.srcid, msg_cp.arg0, msg_cp.arg1, msg_cp.arg2);
530                 }
531         }
532         /* TODO: should this proc_restartcore, like the irq/trap paths?  Or at least
533          * take some things from __proc_startcore() (since we don't want to re-run
534          * kmsgs). */
535 }
536
537 /* Runs any outstanding routine kernel messages from within the kernel.  Will
538  * make sure immediates still run first (or when they arrive, if processing a
539  * bunch of these messages).  This will disable interrupts, and restore them to
540  * whatever state you left them. */
541 void process_routine_kmsg(struct trapframe *tf)
542 {
543         per_cpu_info_t *myinfo = &per_cpu_info[core_id()];
544         kernel_message_t msg_cp, *k_msg;
545         int8_t irq_state = 0;
546
547         disable_irqsave(&irq_state);
548         /* If we were told what our TF was, use that.  o/w, go with current_tf. */
549         tf = tf ? tf : current_tf;
550         while (1) {
551                 /* normally, we want ints disabled, so we don't have an empty self-ipi
552                  * for every routine message. (imagine a long list of routines).  But we
553                  * do want immediates to run ahead of routines.  This enabling should
554                  * work (might not in some shitty VMs).  Also note we can receive an
555                  * extra self-ipi for routine messages before we turn off irqs again.
556                  * Not a big deal, since we will process it right away. 
557                  * TODO: consider calling __kernel_message() here. */
558                 if (!STAILQ_EMPTY(&myinfo->immed_amsgs)) {
559                         enable_irq();
560                         cpu_relax();
561                         disable_irq();
562                 }
563                 k_msg = get_next_amsg(&myinfo->routine_amsgs,
564                                       &myinfo->routine_amsg_lock);
565                 if (!k_msg) {
566                         enable_irqsave(&irq_state);
567                         return;
568                 }
569                 /* copy in, and then free, in case we don't return */
570                 msg_cp = *k_msg;
571                 kmem_cache_free(kernel_msg_cache, (void*)k_msg);
572                 /* make sure an IPI is pending if we have more work */
573                 if (!STAILQ_EMPTY(&myinfo->routine_amsgs) &&
574                        !ipi_is_pending(I_KERNEL_MSG))
575                         send_self_ipi(I_KERNEL_MSG);
576                 /* Execute the kernel message */
577                 assert(msg_cp.pc);
578                 assert(msg_cp.dstid == core_id());
579                 msg_cp.pc(tf, msg_cp.srcid, msg_cp.arg0, msg_cp.arg1, msg_cp.arg2);
580         }
581 }