Bochs compatible SMP booting and enable_irqsave()
authorBarret Rhoden <brho@cs.berkeley.edu>
Fri, 3 Apr 2009 23:58:19 +0000 (16:58 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Fri, 3 Apr 2009 23:58:19 +0000 (16:58 -0700)
Bochs didn't like receiving a second SIPI when HLTed (or ever, I think).
This removes the second SIPI, which kvm and the corei7 don't need.  Also
adds some functionality to enable/disabling interrupts.

inc/atomic.h
inc/x86.h
kern/init.c
kern/testing.c

index 5d83a9b..0b30063 100644 (file)
@@ -48,7 +48,7 @@ static inline void spin_lock_irqsave(volatile uint32_t* lock)
 {
        uint32_t eflags;
        eflags = read_eflags();
-       disable_interrupts();
+       disable_irq();
        spin_lock(lock);
        if (eflags & FL_IF)
                *lock |= 0x80000000;
@@ -59,7 +59,7 @@ static inline void spin_unlock_irqsave(volatile uint32_t* lock)
 {
        if (*lock & 0x80000000) {
                *lock = 0;
-               enable_interrupts();
+               enable_irq();
        } else
                *lock = 0;
 }
index d683a5a..f8b4bec 100644 (file)
--- a/inc/x86.h
+++ b/inc/x86.h
@@ -2,6 +2,7 @@
 #define JOS_INC_X86_H
 
 #include <inc/types.h>
+#include <inc/mmu.h>
 
 /* Model Specific Registers */
 #define IA32_APIC_BASE                         0x1b
@@ -48,8 +49,11 @@ static __inline uint64_t read_msr(uint32_t reg) __attribute__((always_inline));
 static __inline void write_msr(uint32_t reg, uint64_t val) __attribute__((always_inline));
 static __inline uint32_t read_mmreg32(uint32_t reg) __attribute__((always_inline));
 static __inline void write_mmreg32(uint32_t reg, uint32_t val) __attribute__((always_inline));
-static __inline void enable_interrupts(void) __attribute__((always_inline));
-static __inline void disable_interrupts(void) __attribute__((always_inline));
+static __inline void enable_irq(void) __attribute__((always_inline));
+static __inline void disable_irq(void) __attribute__((always_inline));
+static __inline bool enable_irqsave(void) __attribute__((always_inline));
+static __inline void disable_irqsave(bool state) __attribute__((always_inline));
+static __inline void cpu_relax(void) __attribute__((always_inline));
 
 static __inline void
 breakpoint(void)
@@ -322,14 +326,39 @@ read_mmreg32(uint32_t reg)
 }
 
 static __inline void
-enable_interrupts(void) __attribute__((always_inline))
+enable_irq(void)
 {
        asm volatile("sti");
 }
 
 static __inline void
-disable_interrupts(void) __attribute__((always_inline))
+disable_irq(void)
 {
        asm volatile("cli");
 }
+
+static __inline bool
+enable_irqsave(void)
+{
+       // if interrupts are already on, return true
+       if (read_eflags() & FL_IF)
+               return 1;
+       enable_irq();
+       return 0;
+}
+
+static __inline void
+disable_irqsave(bool state)
+{
+       // if ints were already on, leave them on.
+       if (state)
+               return;
+       disable_irq();
+}
+
+static __inline void
+cpu_relax(void)
+{
+       asm volatile("pause");
+}
 #endif /* !JOS_INC_X86_H */
index 9044be5..541cd71 100644 (file)
@@ -55,6 +55,8 @@ void kernel_init(multiboot_info_t *mboot_info)
        // this returns when all other cores are done and ready to receive IPIs
        smp_boot();
 
+       test_ipi_sending();
+
        //ENV_CREATE(user_faultread);
        //ENV_CREATE(user_faultreadkernel);
        //ENV_CREATE(user_faultwrite);
@@ -97,17 +99,24 @@ void smp_boot(void)
 
        // Start the IPI process (INIT, wait, SIPI, wait, SIPI, wait)
        send_init_ipi();
-       enable_interrupts(); // LAPIC timer will fire, extINTs are blocked at LINT0 now
-       while (waiting); // gets released in smp_boot_handler
+       enable_irq(); // LAPIC timer will fire, extINTs are blocked at LINT0 now
+       while (waiting) // gets released in smp_boot_handler
+               cpu_relax();
+       // first SIPI
        waiting = 1;
-       send_startup_ipi(0x01); // first SIPI
+       send_startup_ipi(0x01);
        lapic_set_timer(0x00000fff, 0xf0, 0); // TODO - fix timing
-       while(waiting); // wait for the first SIPI to take effect
+       while(waiting) // wait for the first SIPI to take effect
+               cpu_relax();
+       /* //BOCHS does not like this second SIPI.
+       // second SIPI
        waiting = 1;
-       send_startup_ipi(0x01); // second SIPI
+       send_startup_ipi(0x01);
        lapic_set_timer(0x000fffff, 0xf0, 0); // TODO - fix timing
-       while(waiting); // wait for the second SIPI to take effect
-       disable_interrupts();
+       while(waiting) // wait for the second SIPI to take effect
+               cpu_relax();
+       */
+       disable_irq();
 
        // Each core will also increment smp_semaphore, and decrement when it is done, 
        // all in smp_entry.  It's purpose is to keep Core0 from competing for the 
index 6ca3c55..38ea855 100644 (file)
@@ -16,7 +16,9 @@ void test_ipi_sending(void)
 {
        extern isr_t interrupt_handlers[];
        uint32_t i, amount = 0x7ffffff0; // should calibrate this
+       bool state;
        register_interrupt_handler(interrupt_handlers, 0xf1, smp_hello_world_handler);
+       state = enable_irqsave();
        
        cprintf("\nCORE 0 sending broadcast\n");
        send_broadcast_ipi(0xf1);
@@ -64,6 +66,7 @@ void test_ipi_sending(void)
                asm volatile("nop;");
 
        cprintf("\nDone!\n");
+       disable_irqsave(state);
 }
 
 // Note this never returns and will muck with any other timer work
@@ -76,7 +79,7 @@ void test_pic_reception(void)
        cprintf("PIC2 Mask = 0x%04x\n", inb(PIC2_DATA));
        unmask_lapic_lvt(LAPIC_LVT_LINT0);
        cprintf("Core %d's LINT0: 0x%08x\n", lapic_get_id(), read_mmreg32(LAPIC_LVT_LINT0));
-       enable_interrupts();
+       enable_irq();
        while(1);
 }