Fixes x86 LAPIC_ISR/IRR reading
authorBarret Rhoden <brho@cs.berkeley.edu>
Mon, 9 Apr 2012 21:03:10 +0000 (14:03 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Mon, 9 Apr 2012 21:03:10 +0000 (14:03 -0700)
The ISR and IRR are not bitmaps, but are 8 32-bit registers spaced every
16 bytes in the LAPIC address space.  Thanks
http://forum.osdev.org/viewtopic.php?f=1&t=11670!

kern/arch/i686/apic.c
kern/arch/i686/apic.h
kern/arch/i686/trap.c

index 84245f5..8523c69 100644 (file)
@@ -88,6 +88,40 @@ uint16_t pic_get_isr(void)
        return __pic_get_irq_reg(PIC_READ_ISR);
 }
 
+/* Debugging helper.  Note the ISR/IRR are 32 bits at a time, spaced every 16
+ * bytes in the LAPIC address space. */
+void lapic_print_isr(void)
+{
+       printk("LAPIC ISR on core %d\n--------------\n", core_id());
+       for (int i = 7; i >= 0; i--)
+               printk("%3d-%3d: %08p\n", (i + 1) * 32 - 1, i * 32,
+                      *(uint32_t*)(LAPIC_ISR + i * 0x10));
+       printk("LAPIC IRR on core %d\n--------------\n", core_id());
+       for (int i = 7; i >= 0; i--)
+               printk("%3d-%3d: %08p\n", (i + 1) * 32 - 1, i * 32,
+                      *(uint32_t*)(LAPIC_IRR + i * 0x10));
+}
+
+/* Returns TRUE if the bit 'vector' is set in the LAPIC ISR or IRR (whatever you
+ * pass in.  These registers consist of 8, 32 byte registers spaced every 16
+ * bytes from the base in the LAPIC. */
+static bool __lapic_get_isrr_bit(uint32_t 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);
+}
+
+bool lapic_get_isr_bit(uint8_t vector)
+{
+       return __lapic_get_isrr_bit(LAPIC_ISR, vector);
+}
+
+bool lapic_get_irr_bit(uint8_t vector)
+{
+       return __lapic_get_isrr_bit(LAPIC_IRR, vector);
+}
+
 /* 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).
@@ -97,9 +131,7 @@ uint16_t pic_get_isr(void)
  * from the ISR. */
 bool ipi_is_pending(uint8_t vector)
 {
-       /* The ISR/IRR are 256 bits long.  We want to check if 'vector' is set. */
-       return GET_BITMASK_BIT((uint8_t*)LAPIC_ISR, vector) ||
-              GET_BITMASK_BIT((uint8_t*)LAPIC_IRR, vector);
+       return lapic_get_isr_bit(vector) || lapic_get_isr_bit(vector);
 }
 
 /*
index 4893490..46fa3d6 100644 (file)
 // IPI Interrupt Command Register
 #define LAPIC_IPI_ICR_LOWER                    (LAPIC_BASE + 0x300)
 #define LAPIC_IPI_ICR_UPPER                    (LAPIC_BASE + 0x310)
-// Interrupts being serviced (in-service) and pending (interrupt request reg)
-#define LAPIC_ISR                                      (LAPIC_BASE + 0x170)
-#define LAPIC_IRR                                      (LAPIC_BASE + 0x310)
+/* Interrupts being serviced (in-service) and pending (interrupt request reg).
+ * Note these registers are not normal bitmaps, but instead are 8 separate
+ * 32-bit registers, spaced/aligned on 16 byte boundaries in the LAPIC address
+ * space. */
+#define LAPIC_ISR                                      (LAPIC_BASE + 0x100)
+#define LAPIC_IRR                                      (LAPIC_BASE + 0x200)
 
 // PIT (Programmable Interval Timer)
 #define        TIMER_REG_CNTR0 0       /* timer 0 counter port */
@@ -110,6 +113,9 @@ void pic_unmask_irq(uint8_t irq);
 uint16_t pic_get_mask(void);
 uint16_t pic_get_irr(void);
 uint16_t pic_get_isr(void);
+bool lapic_get_isr_bit(uint8_t vector);
+bool lapic_get_irr_bit(uint8_t vector);
+void lapic_print_isr(void);
 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 a109856..2f330e2 100644 (file)
@@ -390,9 +390,9 @@ static bool check_spurious_irq(uint32_t trap_nr)
         * spurious and a real IRQ. */
        uint8_t lapic_spurious = read_mmreg32(LAPIC_SPURIOUS) & 0xff;
        /* Note the lapic's vectors are not shifted by an offset. */
-       if ((trap_nr == lapic_spurious) &&
-           !GET_BITMASK_BIT((uint8_t*)LAPIC_ISR, lapic_spurious)) {
-               printk("Spurious LAPIC irq %d!\n", lapic_spurious);
+       if ((trap_nr == lapic_spurious) && !lapic_get_isr_bit(lapic_spurious)) {
+               printk("Spurious LAPIC irq %d, core %d!\n", lapic_spurious, core_id());
+               lapic_print_isr();
                return TRUE;
        }
        return FALSE;