x86: LAPIC vector masking
authorBarret Rhoden <brho@cs.berkeley.edu>
Mon, 17 Mar 2014 04:11:32 +0000 (21:11 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Sat, 29 Mar 2014 01:17:04 +0000 (18:17 -0700)
With another fake bus for IPIs (APIC messages), that can't be masked.

kern/arch/x86/apic.c
kern/arch/x86/apic.h
kern/arch/x86/io.h
kern/arch/x86/ioapic.c
kern/arch/x86/smp.c
kern/arch/x86/trap.c
kern/arch/x86/trap.h
kern/src/testing.c

index c997431..7250449 100644 (file)
@@ -62,8 +62,8 @@ void lapic_print_isr(void)
 static bool __lapic_get_isrr_bit(unsigned long base, uint8_t vector)
 {
        int which_reg = vector >> 5;    /* 32 bits per reg */
-       uint32_t *lapic_reg = (uint32_t*)(base + which_reg * 0x10);     /* offset 16 */
-       return (*lapic_reg & (1 << (vector % 32)) ? 1 : 0);
+       uintptr_t lapic_reg = base + which_reg * 0x10;  /* offset 16 */
+       return (read_mmreg32(lapic_reg) & (1 << (vector % 32)) ? 1 : 0);
 }
 
 bool lapic_get_isr_bit(uint8_t vector)
@@ -76,6 +76,28 @@ bool lapic_get_irr_bit(uint8_t vector)
        return __lapic_get_isrr_bit(LAPIC_IRR, vector);
 }
 
+void lapic_mask_irq(int apic_vector)
+{
+       uintptr_t mm_reg;
+       if (apic_vector < IdtLAPIC || IdtLAPIC + 4 < apic_vector) {
+               warn("Bad apic vector %d\n", apic_vector);
+               return;
+       }
+       mm_reg = LAPIC_BASE + (apic_vector - IdtLAPIC) * 0x10;
+       write_mmreg32(mm_reg, read_mmreg32(mm_reg) | LAPIC_LVT_MASK);
+}
+
+void lapic_unmask_irq(int apic_vector)
+{
+       uintptr_t mm_reg;
+       if (apic_vector < IdtLAPIC || IdtLAPIC + 4 < apic_vector) {
+               warn("Bad apic vector %d\n", apic_vector);
+               return;
+       }
+       mm_reg = LAPIC_BASE + (apic_vector - IdtLAPIC) * 0x10;
+       write_mmreg32(mm_reg, read_mmreg32(mm_reg) & ~LAPIC_LVT_MASK);
+}
+
 /* This works for any interrupt that goes through the LAPIC, but not things like
  * ExtInts.  To prevent abuse, we'll use it just for IPIs for now (which only
  * come via the APIC).
index e128d9e..cce9ebe 100644 (file)
 #define LAPIC_LOGICAL_ID                       (LAPIC_BASE + 0x0d0)
 // LAPIC Local Vector Table
 #define LAPIC_LVT_TIMER                                (LAPIC_BASE + 0x320)
+#define LAPIC_LVT_THERMAL                      (LAPIC_BASE + 0x330)
+#define LAPIC_LVT_PERFMON                      (LAPIC_BASE + 0x340)
 #define LAPIC_LVT_LINT0                                (LAPIC_BASE + 0x350)
 #define LAPIC_LVT_LINT1                                (LAPIC_BASE + 0x360)
 #define LAPIC_LVT_ERROR                                (LAPIC_BASE + 0x370)
-#define LAPIC_LVT_PERFMON                      (LAPIC_BASE + 0x340)
-#define LAPIC_LVT_THERMAL                      (LAPIC_BASE + 0x330)
 #define LAPIC_LVT_MASK                         0x00010000
 // LAPIC Timer
 #define LAPIC_TIMER_INIT                       (LAPIC_BASE + 0x380)
@@ -82,6 +82,8 @@ bool lapic_check_spurious(int trap_nr);
 bool lapic_get_isr_bit(uint8_t vector);
 bool lapic_get_irr_bit(uint8_t vector);
 void lapic_print_isr(void);
+void lapic_mask_irq(int apic_vector);
+void lapic_unmask_irq(int apic_vector);
 bool ipi_is_pending(uint8_t vector);
 void __lapic_set_timer(uint32_t ticks, uint8_t vec, bool periodic, uint8_t div);
 void lapic_set_timer(uint32_t usec, bool periodic);
index d8ba4c7..8e37911 100644 (file)
@@ -30,6 +30,7 @@ enum {
        BusVME, /* VMEbus */
        BusXPRESS,      /* Express System Bus */
        BusLAPIC,       /* Local APIC, fake type */
+       BusIPI, /* IPIs, fake type like the LAPIC */
 };
 
 #define MKBUS(t,b,d,f) (((t)<<24)|(((b)&0xFF)<<16)|(((d)&0x1F)<<11)|(((f)&0x07)<<8))
index ea0c23b..15bc2a6 100644 (file)
@@ -543,12 +543,21 @@ int bus_irq_setup(struct irq_handler *irq_h)
                         * method was 0.  we're not doing that (unless we have to). */
                        irq_h->check_spurious = lapic_check_spurious;
                        irq_h->eoi = lapic_send_eoi;
-                       irq_h->mask = 0;
-                       irq_h->unmask = 0;
+                       irq_h->mask = lapic_mask_irq;
+                       irq_h->unmask = lapic_unmask_irq;
                        irq_h->route_irq = 0;
                        irq_h->type = "lapic";
                        /* For the LAPIC, irq == vector */
                        return irq_h->dev_irq;
+               case BusIPI:
+                       /* similar to LAPIC, but we don't actually have LVT entries */
+                       irq_h->check_spurious = lapic_check_spurious;
+                       irq_h->eoi = lapic_send_eoi;
+                       irq_h->mask = 0;
+                       irq_h->unmask = 0;
+                       irq_h->route_irq = 0;
+                       irq_h->type = "IPI";
+                       return irq_h->dev_irq;
                case BusISA:
                        if (mpisabusno == -1)
                                panic("No ISA bus allocated");
index 5474f9b..d772eff 100644 (file)
@@ -120,7 +120,7 @@ static int smp_call_function(uint8_t type, uint32_t dest, isr_t handler,
         * We're waiting on RCU to do a nice unregister. */
        extern struct irq_handler *irq_handlers[];
        if (!irq_handlers[wrapper->vector]) {
-               register_irq(wrapper->vector, handler, data, MKBUS(BusLAPIC, 0, 0, 0));
+               register_irq(wrapper->vector, handler, data, MKBUS(BusIPI, 0, 0, 0));
        } else {
                /* we're replacing the old one.  hope it was ours, and the IRQ is firing
                 * concurrently (if it is, there's an smp_call bug)! */
index 43b8bc4..ab154d6 100644 (file)
@@ -189,10 +189,9 @@ void idt_init(void)
 
        /* register the generic timer_interrupt() handler for the per-core timers */
        register_irq(IdtLAPIC_TIMER, timer_interrupt, NULL,
-                        MKBUS(BusLAPIC, 0, 0, 0));
+                    MKBUS(BusLAPIC, 0, 0, 0));
        /* register the kernel message handler */
-       register_irq(I_KERNEL_MSG, handle_kmsg_ipi, NULL,
-                        MKBUS(BusLAPIC, 0, 0, 0));
+       register_irq(I_KERNEL_MSG, handle_kmsg_ipi, NULL, MKBUS(BusIPI, 0, 0, 0));
 }
 
 static void handle_fperr(struct hw_trapframe *hw_tf)
index fd9ce7a..78bdb38 100644 (file)
 
 /* 48-63 are LAPIC vectors */
 #define IdtLAPIC                               (IdtPIC + 16)
-#define IdtLAPIC_LINT0                 (IdtLAPIC + 0)
-#define IdtLAPIC_LINT1                 (IdtLAPIC + 1)
-#define IdtLAPIC_TIMER                 (IdtLAPIC + 2)
-#define IdtLAPIC_ERROR                 (IdtLAPIC + 3)
-#define IdtLAPIC_PCINT                 (IdtLAPIC + 4)
+#define IdtLAPIC_TIMER                 (IdtLAPIC + 0)
+#define IdtLAPIC_THERMAL               (IdtLAPIC + 1)
+#define IdtLAPIC_PCINT                 (IdtLAPIC + 2)
+#define IdtLAPIC_LINT0                 (IdtLAPIC + 3)
+#define IdtLAPIC_LINT1                 (IdtLAPIC + 4)
+#define IdtLAPIC_ERROR                 (IdtLAPIC + 5)
 /* Plan 9 apic note: the spurious vector number must have bits 3-0 0x0f
  * unless the Extended Spurious Vector Enable bit is set in the
  * HyperTransport Transaction Control register.  Plan 9 used 63 (0x3f), but
index 596698d..2851961 100644 (file)
@@ -52,7 +52,7 @@ void test_ipi_sending(void)
        int8_t state = 0;
 
        register_irq(I_TESTING, test_hello_world_handler, NULL,
-                        MKBUS(BusLAPIC, 0, 0, 0));
+                    MKBUS(BusIPI, 0, 0, 0));
        enable_irqsave(&state);
        cprintf("\nCORE 0 sending broadcast\n");
        send_broadcast_ipi(I_TESTING);
@@ -88,8 +88,8 @@ void test_ipi_sending(void)
 // Note this never returns and will muck with any other timer work
 void test_pic_reception(void)
 {
-       register_irq(0x20, test_hello_world_handler, NULL,
-                        MKBUS(BusLAPIC, 0, 0, 0));
+       register_irq(IdtPIC + IrqCLOCK, test_hello_world_handler, NULL,
+                    MKBUS(BusISA, 0, 0, 0));
        pit_set_timer(100,TIMER_RATEGEN); // totally arbitrary time
        pic_unmask_irq(0);
        cprintf("PIC1 Mask = 0x%04x\n", inb(PIC1_DATA));
@@ -102,8 +102,8 @@ void test_pic_reception(void)
 
 void test_ioapic_pit_reroute(void) 
 {
-       register_irq(0x20, test_hello_world_handler, NULL,
-                        MKBUS(BusLAPIC, 0, 0, 0));
+       register_irq(IdtPIC + IrqCLOCK, test_hello_world_handler, NULL,
+                    MKBUS(BusISA, 0, 0, 0));
 #ifdef CONFIG_ENABLE_MPTABLES
 #warning "not routing the irq"
        //ioapic_route_irq(0, 3);       
@@ -559,7 +559,7 @@ void test_smp_call_functions(void)
 void test_lapic_status_bit(void)
 {
        register_irq(I_TESTING, test_incrementer_handler, &a,
-                        MKBUS(BusLAPIC, 0, 0, 0));
+                    MKBUS(BusIPI, 0, 0, 0));
        #define NUM_IPI 100000
        atomic_set(&a,0);
        printk("IPIs received (should be 0): %d\n", a);
@@ -662,7 +662,7 @@ void test_pit(void)
        atomic_t waiting;
        atomic_init(&waiting, 1);
        register_irq(I_TESTING, test_waiting_handler, &waiting,
-                        MKBUS(BusLAPIC, 0, 0, 0));
+                    MKBUS(BusIPI, 0, 0, 0));
        while(atomic_read(&waiting))
                cpu_relax();
        cprintf("End now\n");