disable_irqsave can be called first
authorBarret Rhoden <brho@cs.berkeley.edu>
Mon, 13 Apr 2009 23:27:15 +0000 (16:27 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Mon, 13 Apr 2009 23:27:15 +0000 (16:27 -0700)
enable and disable can be called with either first, with ints being the
same as they were at the beginning of the pair.  also allows for nesting
on the same state variable.  comes with a test and some macros for
printd and printk.

inc/stdio.h
inc/x86.h
kern/smp.c
kern/testing.c
kern/testing.h

index 9792bf9..a055fe2 100644 (file)
@@ -7,6 +7,14 @@
 #define NULL   ((void *) 0)
 #endif /* !NULL */
 
+#ifdef DEBUG
+#define printd(args...) cprintf(args)
+#else
+#define printd(args...) {}
+#endif
+
+#define printk(args...) cprintf(args)
+
 // lib/stdio.c
 void   cputchar(int c);
 int    getchar(void);
index 90f4cd3..2a9363c 100644 (file)
--- a/inc/x86.h
+++ b/inc/x86.h
@@ -70,8 +70,8 @@ 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_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 enable_irqsave(int8_t* state) __attribute__((always_inline));
+static __inline void disable_irqsave(int8_t* state) __attribute__((always_inline));
 static __inline void cpu_relax(void) __attribute__((always_inline));
 static __inline void wbinvd(void) __attribute__((always_inline));
 static __inline void clflush(uintptr_t* addr) __attribute__((always_inline));
@@ -358,23 +358,33 @@ disable_irq(void)
        asm volatile("cli");
 }
 
-static __inline bool
-enable_irqsave(void)
+static __inline void
+enable_irqsave(int8_t* state)
 {
-       // if interrupts are already on, return true
-       if (read_eflags() & FL_IF)
-               return 1;
-       enable_irq();
-       return 0;
+       // *state tracks the number of nested enables and disables
+       // initial value of state: 0 = first run / no favorite
+       // > 0 means more enabled calls have been made
+       // < 0 means more disabled calls have been made
+       // Mostly doing this so we can call disable_irqsave first if we want
+
+       // one side or another "gets a point" if interrupts were already the
+       // way it wanted to go.  o/w, state stays at 0.  if the state was not 0
+       // then, enabling/disabling isn't even an option.  just increment/decrement
+
+       // if enabling is winning or tied, make sure it's enabled
+       if ((*state == 0) && (!(read_eflags() & FL_IF)))
+               enable_irq();
+       else
+               (*state)++;
 }
 
 static __inline void
-disable_irqsave(bool state)
+disable_irqsave(int8_t* state)
 {
-       // if ints were already on, leave them on.
-       if (state)
-               return;
-       disable_irq();
+       if ((*state == 0) && (read_eflags() & FL_IF))
+               disable_irq();
+       else 
+               (*state)--;
 }
 
 static __inline void
index 7344b65..c9dc1c1 100644 (file)
@@ -185,13 +185,13 @@ static void smp_call_function(uint8_t type, uint8_t dest, isr_t handler, uint8_t
 {
        extern isr_t interrupt_handlers[];
        uint32_t i, amount = 0x7ffffff0; // should calibrate this!!  just remove it!
-       bool state;
+       int8_t state = 0;
 
        if (!vector)
                vector = 0xf1; //default value
        register_interrupt_handler(interrupt_handlers, vector, handler);
        // WRITE MEMORY BARRIER HERE
-       state = enable_irqsave();
+       enable_irqsave(&state);
        // Send the proper type of IPI.  I made up these numbers.
        switch (type) {
                case 1:
@@ -217,7 +217,7 @@ static void smp_call_function(uint8_t type, uint8_t dest, isr_t handler, uint8_t
        // maybe should think of some sort of completion notification mech
        for (i = 0; i < amount; i++)
                asm volatile("nop;");
-       disable_irqsave(state);
+       disable_irqsave(&state);
        // consider doing this, but we can't remove it before the receiver is done
        //register_interrupt_handler(interrupt_handlers, vector, 0);
        // we also will have issues if we call this function again too quickly
index 06510ce..eac436e 100644 (file)
@@ -17,9 +17,9 @@ void test_ipi_sending(void)
 {
        extern isr_t interrupt_handlers[];
        uint32_t i, amount = 0x7ffffff0; // should calibrate this
-       bool state;
+       int8_t state = 0;
        register_interrupt_handler(interrupt_handlers, 0xf1, test_hello_world_handler);
-       state = enable_irqsave();
+       enable_irqsave(&state);
        
        cprintf("\nCORE 0 sending broadcast\n");
        send_broadcast_ipi(0xf1);
@@ -67,7 +67,7 @@ void test_ipi_sending(void)
                asm volatile("nop;");
 
        cprintf("\nDone!\n");
-       disable_irqsave(state);
+       disable_irqsave(&state);
 }
 
 // Note this never returns and will muck with any other timer work
@@ -102,6 +102,102 @@ void test_barrier(void)
        smp_call_function_all(test_barrier_handler, 0);
 }
 
+void test_interrupts_irqsave(void)
+{
+       int8_t state = 0;
+       printd("Testing Nesting Enabling first, turning ints off:\n");
+       disable_irq();
+       printd("Interrupts are: %x\n", read_eflags() & FL_IF);
+       assert((read_eflags() & FL_IF) == 0);
+       printd("Enabling IRQSave\n");
+       enable_irqsave(&state);
+       printd("Interrupts are: %x\n", read_eflags() & FL_IF);
+       assert((read_eflags() & FL_IF) == 0x200);
+       printd("Enabling IRQSave Again\n");
+       enable_irqsave(&state);
+       printd("Interrupts are: %x\n", read_eflags() & FL_IF);
+       assert((read_eflags() & FL_IF) == 0x200);
+       printd("Disabling IRQSave Once\n");
+       disable_irqsave(&state);
+       printd("Interrupts are: %x\n", read_eflags() & FL_IF);
+       assert((read_eflags() & FL_IF) == 0x200);
+       printd("Disabling IRQSave Again\n");
+       disable_irqsave(&state);
+       printd("Interrupts are: %x\n", read_eflags() & FL_IF);
+       assert((read_eflags() & FL_IF) == 0);
+       printd("Done.  Should have been 0, 200, 200, 200, 0\n");        
+
+       printd("Testing Nesting Disabling first, turning ints on:\n");
+       state = 0;
+       enable_irq();
+       printd("Interrupts are: %x\n", read_eflags() & FL_IF);
+       assert((read_eflags() & FL_IF) == 0x200);
+       printd("Disabling IRQSave Once\n");
+       disable_irqsave(&state);
+       printd("Interrupts are: %x\n", read_eflags() & FL_IF);
+       assert((read_eflags() & FL_IF) == 0);
+       printd("Disabling IRQSave Again\n");
+       disable_irqsave(&state);
+       printd("Interrupts are: %x\n", read_eflags() & FL_IF);
+       assert((read_eflags() & FL_IF) == 0);
+       printd("Enabling IRQSave Once\n");
+       enable_irqsave(&state);
+       printd("Interrupts are: %x\n", read_eflags() & FL_IF);
+       assert((read_eflags() & FL_IF) == 0);
+       printd("Enabling IRQSave Again\n");
+       enable_irqsave(&state);
+       printd("Interrupts are: %x\n", read_eflags() & FL_IF);
+       assert((read_eflags() & FL_IF) == 0x200);
+       printd("Done.  Should have been 200, 0, 0, 0, 200 \n"); 
+
+       state = 0;
+       disable_irq();
+       printd("Ints are off, enabling then disabling.\n");
+       enable_irqsave(&state);
+       printd("Interrupts are: %x\n", read_eflags() & FL_IF);
+       assert((read_eflags() & FL_IF) == 0x200);
+       disable_irqsave(&state);
+       printd("Interrupts are: %x\n", read_eflags() & FL_IF);
+       assert((read_eflags() & FL_IF) == 0);
+       printd("Done.  Should have been 200, 0\n");     
+
+       state = 0;
+       enable_irq();
+       printd("Ints are on, enabling then disabling.\n");
+       enable_irqsave(&state);
+       printd("Interrupts are: %x\n", read_eflags() & FL_IF);
+       assert((read_eflags() & FL_IF) == 0x200);
+       disable_irqsave(&state);
+       printd("Interrupts are: %x\n", read_eflags() & FL_IF);
+       assert((read_eflags() & FL_IF) == 0x200);
+       printd("Done.  Should have been 200, 200\n");   
+
+       state = 0;
+       disable_irq();
+       printd("Ints are off, disabling then enabling.\n");
+       disable_irqsave(&state);
+       printd("Interrupts are: %x\n", read_eflags() & FL_IF);
+       assert((read_eflags() & FL_IF) == 0);
+       enable_irqsave(&state);
+       printd("Interrupts are: %x\n", read_eflags() & FL_IF);
+       assert((read_eflags() & FL_IF) == 0);
+       printd("Done.  Should have been 0, 0\n");       
+
+       state = 0;
+       enable_irq();
+       printd("Ints are on, disabling then enabling.\n");
+       disable_irqsave(&state);
+       printd("Interrupts are: %x\n", read_eflags() & FL_IF);
+       assert((read_eflags() & FL_IF) == 0);
+       enable_irqsave(&state);
+       printd("Interrupts are: %x\n", read_eflags() & FL_IF);
+       assert((read_eflags() & FL_IF) == 0x200);
+       printd("Done.  Should have been 0, 200\n");     
+
+       disable_irq();
+       cprintf("Passed enable_irqsave tests\n");
+}
+
 /* Helper Functions */
 
 void test_hello_world_handler(struct Trapframe *tf)
@@ -145,4 +241,3 @@ void test_barrier_handler(struct Trapframe *tf)
        // uncomment to see it fucked up
        //cprintf("Round 4: Core %d\n", lapic_get_id());
 }
-
index 941c22a..c9d6785 100644 (file)
@@ -14,11 +14,10 @@ void test_ipi_sending(void);
 void test_pic_reception(void);
 void test_print_info(void);
 void test_barrier(void);
+void test_interrupts_irqsave(void);
 
 void test_hello_world_handler(struct Trapframe *tf);
 void test_print_info_handler(struct Trapframe *tf);
 void test_barrier_handler(struct Trapframe *tf);
 
-
-
 #endif /* !ROS_INC_TESTING_H */