Added more SharC annotations
[akaros.git] / kern / arch / i386 / trap.c
index 708e1c1..37279ef 100644 (file)
@@ -1,5 +1,5 @@
 #ifdef __SHARC__
-#pragma nosharc
+//#pragma nosharc
 #endif
 
 #include <arch/mmu.h>
@@ -7,6 +7,7 @@
 #include <arch/arch.h>
 #include <arch/console.h>
 #include <arch/apic.h>
+#include <ros/common.h>
 #include <smp.h>
 #include <assert.h>
 #include <pmap.h>
 
 #include <syscall.h>
 
-taskstate_t ts;
+taskstate_t RO ts;
 
 /* Interrupt descriptor table.  (Must be built at run time because
  * shifted function addresses can't be represented in relocation records.)
  */
 // Aligned on an 8 byte boundary (SDM V3A 5-13)
-gatedesc_t __attribute__ ((aligned (8))) idt[256] = { { 0 } };
-pseudodesc_t idt_pd = {
+gatedesc_t __attribute__ ((aligned (8))) (RO idt)[256] = { { 0 } };
+pseudodesc_t RO idt_pd = {
        sizeof(idt) - 1, (uint32_t) idt
 };
 
@@ -32,12 +33,16 @@ pseudodesc_t idt_pd = {
  * of functions to be called when servicing an interrupt.  other cores
  * can set up their own later.
  */
-handler_t TP(void *) interrupt_handlers[NUM_INTERRUPT_HANDLERS];
+#ifdef __IVY__
+#pragma cilnoremove("iht_lock")
+#endif
+spinlock_t iht_lock;
+handler_t TP(TV(t)) LCKD(&iht_lock) (RO interrupt_handlers)[NUM_INTERRUPT_HANDLERS];
 
 static const char *NTS trapname(int trapno)
 {
     // zra: excnames is SREADONLY because Ivy doesn't trust const
-       static const char *NT const ( excnames)[] = {
+       static const char *NT const (RO excnames)[] = {
                "Divide error",
                "Debug",
                "Non-Maskable Interrupt",
@@ -71,20 +76,20 @@ static const char *NTS trapname(int trapno)
 void
 idt_init(void)
 {
-       extern segdesc_t gdt[];
+       extern segdesc_t (RO gdt)[];
 
        // This table is made in trapentry.S by each macro in that file.
        // It is layed out such that the ith entry is the ith's traphandler's
        // (uint32_t) trap addr, then (uint32_t) trap number
        struct trapinfo { uint32_t trapaddr; uint32_t trapnumber; };
-       extern struct trapinfo (BND(__this,trap_tbl_end) trap_tbl)[];
-       extern struct trapinfo (SNT trap_tbl_end)[];
+       extern struct trapinfo (BND(__this,trap_tbl_end) RO trap_tbl)[];
+       extern struct trapinfo (SNT RO trap_tbl_end)[];
        int i, trap_tbl_size = trap_tbl_end - trap_tbl;
        extern void ISR_default(void);
 
        // set all to default, to catch everything
        for(i = 0; i < 256; i++)
-               SETGATE(idt[i], 0, GD_KT, &ISR_default, 0);
+               ROSETGATE(idt[i], 0, GD_KT, &ISR_default, 0);
 
        // set all entries that have real trap handlers
        // we need to stop short of the last one, since the last is the default
@@ -93,24 +98,25 @@ idt_init(void)
        // if we set these to trap gates, be sure to handle the IRQs separately
        // and we might need to break our pretty tables
        for(i = 0; i < trap_tbl_size - 1; i++)
-               SETGATE(idt[trap_tbl[i].trapnumber], 0, GD_KT, trap_tbl[i].trapaddr, 0);
+               ROSETGATE(idt[trap_tbl[i].trapnumber], 0, GD_KT, trap_tbl[i].trapaddr, 0);
 
        // turn on syscall handling and other user-accessible ints
        // DPL 3 means this can be triggered by the int instruction
        // STS_TG32 sets the IDT type to a Trap Gate (interrupts enabled)
-       idt[T_SYSCALL].gd_dpl = 3;
-       idt[T_SYSCALL].gd_type = STS_TG32;
-       idt[T_BRKPT].gd_dpl = 3;
+       idt[T_SYSCALL].gd_dpl = SINIT(3);
+       idt[T_SYSCALL].gd_type = SINIT(STS_TG32);
+       idt[T_BRKPT].gd_dpl = SINIT(3);
 
        // Setup a TSS so that we get the right stack
        // when we trap to the kernel.
-       ts.ts_esp0 = KSTACKTOP;
-       ts.ts_ss0 = GD_KD;
+       ts.ts_esp0 = SINIT(KSTACKTOP);
+       ts.ts_ss0 = SINIT(GD_KD);
 
        // Initialize the TSS field of the gdt.
-       gdt[GD_TSS >> 3] = SEG16(STS_T32A, (uint32_t) (&ts),
-                                       sizeof(taskstate_t), 0);
-       gdt[GD_TSS >> 3].sd_s = 0;
+       SEG16ROINIT(gdt[GD_TSS >> 3],STS_T32A, (uint32_t)(&ts),sizeof(taskstate_t),0);
+       //gdt[GD_TSS >> 3] = (segdesc_t)SEG16(STS_T32A, (uint32_t) (&ts),
+       //                                 sizeof(taskstate_t), 0);
+       gdt[GD_TSS >> 3].sd_s = SINIT(0);
 
        // Load the TSS
        ltr(GD_TSS);
@@ -211,7 +217,7 @@ trap(trapframe_t *tf)
        //cprintf("Incoming TRAP frame at %p\n", tf);
 
        // TODO: do this once we know we are are not returning to the current
-       // context.  doing it now is safe.
+       // context.  doing it now is safe. (HSS)
        env_push_ancillary_state(current);
 
        if ((tf->tf_cs & ~3) != GD_UT && (tf->tf_cs & ~3) != GD_KT) {
@@ -248,10 +254,14 @@ irq_handler(trapframe_t *tf)
        //      cprintf("Incoming IRQ, ISR: %d on core %d\n", tf->tf_trapno, core_id());
        // merge this with alltraps?  other than the EOI... or do the same in all traps
 
-       extern handler_wrapper_t handler_wrappers[NUM_HANDLER_WRAPPERS];
+       // TODO: do this once we know we are are not returning to the current
+       // context.  doing it now is safe. (HSS)
+       env_push_ancillary_state(current);
+
+       extern handler_wrapper_t (RO handler_wrappers)[NUM_HANDLER_WRAPPERS];
 
        // determine the interrupt handler table to use.  for now, pick the global
-       handler_t TP(void *) * handler_tbl = interrupt_handlers;
+       handler_t TP(TV(t)) LCKD(&iht_lock) * handler_tbl = interrupt_handlers;
 
        if (handler_tbl[tf->tf_trapno].isr != 0)
                handler_tbl[tf->tf_trapno].isr(tf, handler_tbl[tf->tf_trapno].data);
@@ -273,7 +283,7 @@ irq_handler(trapframe_t *tf)
 
 void
 register_interrupt_handler(handler_t TP(TV(t)) table[],
-                           uint8_t int_num, poly_isr_t handler, void* data)
+                           uint8_t int_num, poly_isr_t handler, TV(t) data)
 {
        table[int_num].isr = handler;
        table[int_num].data = data;
@@ -343,7 +353,7 @@ void sysenter_init(void)
 void sysenter_callwrapper(struct Trapframe *tf)
 {
        current->env_tf = *tf;
-       
+
        // The trapframe on the stack should be ignored from here on.
        tf = &current->env_tf;
        tf->tf_regs.reg_eax = (intreg_t) syscall(current,
@@ -361,3 +371,68 @@ void sysenter_callwrapper(struct Trapframe *tf)
         */
        proc_startcore(current, tf);
 }
+
+uint32_t send_active_message(uint32_t dst, amr_t pc,
+                             TV(a0t) arg0, TV(a1t) arg1, TV(a2t) arg2)
+{
+       error_t retval = -EBUSY;
+       spin_lock_irqsave(&per_cpu_info[dst].amsg_lock);
+       size_t current_amsg = per_cpu_info[dst].amsg_current;
+       // If there's a PC there, then that means it's an outstanding message
+       FOR_CIRC_BUFFER(current_amsg, NUM_ACTIVE_MESSAGES, i) {
+               if (per_cpu_info[dst].active_msgs[i].pc)
+                       continue;
+               per_cpu_info[dst].active_msgs[i].pc = pc;
+               per_cpu_info[dst].active_msgs[i].arg0 = arg0;
+               per_cpu_info[dst].active_msgs[i].arg1 = arg1;
+               per_cpu_info[dst].active_msgs[i].arg2 = arg2;
+               per_cpu_info[dst].active_msgs[i].srcid = core_id();
+               retval = 0;
+               break;
+       }
+       spin_unlock_irqsave(&per_cpu_info[dst].amsg_lock);
+       // since we touched memory the other core will touch (the lock), we don't
+       // need an wmb_f()
+       if (!retval)
+               send_ipi(dst, 0, I_ACTIVE_MSG);
+       return retval;
+}
+
+/* Active message handler.  We don't want to block other AMs from coming in, so
+ * we'll copy out the message and let go of the lock.  This won't return until
+ * all pending AMs are executed.  If the PC is 0, then this was an extra IPI and
+ * we already handled the message (or someone is sending IPIs without loading
+ * the active message...)
+ * Note that all of this happens from interrupt context, and interrupts are
+ * currently disabled for this gate. */
+void __active_message(trapframe_t *tf)
+{
+       per_cpu_info_t RO*myinfo = &per_cpu_info[core_id()];
+       active_message_t amsg;
+
+       lapic_send_eoi();
+       while (1) { // will break out when we find an empty amsg
+               /* Get the message */
+               spin_lock_irqsave(&myinfo->amsg_lock);
+               if (myinfo->active_msgs[myinfo->amsg_current].pc) {
+                       amsg = myinfo->active_msgs[myinfo->amsg_current];
+                       myinfo->active_msgs[myinfo->amsg_current].pc = 0;
+                       myinfo->amsg_current = (myinfo->amsg_current + 1) %
+                                              NUM_ACTIVE_MESSAGES;
+               } else { // was no PC in the current active message, meaning we do nothing
+                       spin_unlock_irqsave(&myinfo->amsg_lock);
+                       return;
+               }
+               /* In case the function doesn't return (which is common: __startcore,
+                * __death, etc), there is a chance we could lose an amsg.  We can only
+                * have up to two interrupts outstanding, and if we never return, we
+                * never deal with any other amsgs.  This extra IPI hurts performance
+                * but is only necessary if there is another outstanding message in the
+                * buffer, but makes sure we never miss out on an amsg. */
+               if (myinfo->active_msgs[myinfo->amsg_current].pc)
+                       send_ipi(core_id(), 0, I_ACTIVE_MSG);
+               spin_unlock_irqsave(&myinfo->amsg_lock);
+               /* Execute the active message */
+               amsg.pc(tf, amsg.srcid, amsg.arg0, amsg.arg1, amsg.arg2);
+       }
+}