primitive barrier and testing helpers
authorBarret Rhoden <brho@cs.berkeley.edu>
Wed, 8 Apr 2009 18:43:04 +0000 (11:43 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Wed, 8 Apr 2009 18:43:04 +0000 (11:43 -0700)
added a barrier, needs to be init'd.  moved the atomics to kern/, and
added some more testing infrastructure.

inc/atomic.h [deleted file]
inc/x86.h
kern/Makefrag
kern/atomic.c [new file with mode: 0644]
kern/atomic.h [new file with mode: 0644]
kern/init.c
kern/printf.c
kern/testing.c
kern/testing.h

diff --git a/inc/atomic.h b/inc/atomic.h
deleted file mode 100644 (file)
index 0b30063..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-#ifndef ROS_INC_ATOMIC_H
-#define ROS_INC_ATOMIC_H
-
-#include <inc/types.h>
-#include <inc/mmu.h>
-#include <inc/x86.h>
-
-/* //linux style atomic ops
-typedef struct {uint32_t real_num;} atomic_t;
-#define atomic_read(atom) ((atom)->real_num)
-#define atomic_set(atom, val) (((atom)->real_num) = (val))
-#define atomic_init(i) {(i)}
-//and the atomic incs, etc take an atomic_t ptr, deref inside
-*/
-
-static inline void spin_lock(volatile uint32_t* lock);
-static inline void spin_unlock(volatile uint32_t* lock);
-static inline void spin_lock_irqsave(volatile uint32_t* lock);
-static inline void spin_unlock_irqsave(volatile uint32_t* lock);
-static inline void atomic_inc(volatile uint32_t* number);
-static inline void atomic_dec(volatile uint32_t* number);
-
-
-static inline void spin_lock(volatile uint32_t* lock)
-{
-       asm volatile(
-                       "1:                       "
-                       "       cmpb $0, %0;          "
-                       "       je 2f;                "
-                       "       pause;                "
-                       "       jmp 1b;               "
-                       "2:                       " 
-                       "       movb $1, %%al;        "
-                       "       xchgb %%al, %0;       "
-                       "       cmpb $0, %%al;        "
-                       "       jne 1b;               "
-               : : "m"(*lock) : "eax", "cc");
-}
-
-static inline void spin_unlock(volatile uint32_t* lock)
-{
-       *lock = 0;
-}
-
-// If ints are enabled, disable them and note it in the top bit of the lock
-// There is an assumption about releasing locks in order here...
-static inline void spin_lock_irqsave(volatile uint32_t* lock)
-{
-       uint32_t eflags;
-       eflags = read_eflags();
-       disable_irq();
-       spin_lock(lock);
-       if (eflags & FL_IF)
-               *lock |= 0x80000000;
-}
-
-// if the top bit of the lock is set, then re-enable interrupts
-static inline void spin_unlock_irqsave(volatile uint32_t* lock)
-{
-       if (*lock & 0x80000000) {
-               *lock = 0;
-               enable_irq();
-       } else
-               *lock = 0;
-}
-
-// need to do this with pointers and deref.  %0 needs to be the memory address
-static inline void atomic_inc(volatile uint32_t* number)
-{
-       asm volatile("lock incl %0" : "=m"(*number) : : "cc");
-}
-
-static inline void atomic_dec(volatile uint32_t* number)
-{
-       asm volatile("lock decl %0" : "=m"(*number) : : "cc");
-}
-#endif /* !ROS_INC_ATOMIC_H */
index f8b4bec..36cc6b0 100644 (file)
--- a/inc/x86.h
+++ b/inc/x86.h
@@ -14,6 +14,9 @@
 /* CPUID */
 #define CPUID_PSE_SUPPORT                      0x00000008
 
+/* Arch Constants */
+#define MAX_NUM_CPUS                           255
+
 static __inline void breakpoint(void) __attribute__((always_inline));
 static __inline uint8_t inb(int port) __attribute__((always_inline));
 static __inline void insb(int port, void *addr, int cnt) __attribute__((always_inline));
index d63fc54..03e5317 100644 (file)
@@ -31,6 +31,7 @@ KERN_SRCFILES :=      kern/entry.S \
                        kern/kdebug.c \
                        kern/apic.c \
                        kern/testing.c \
+                       kern/atomic.c \
                        lib/printfmt.c \
                        lib/readline.c \
                        lib/string.c
@@ -93,6 +94,13 @@ $(OBJDIR)/kern/bochs.img: $(OBJDIR)/kern/kernel $(OBJDIR)/boot/boot
 
 all: $(OBJDIR)/kern/bochs.img
 
+#usb: all 
+#      $(V)echo "Copying to /dev/sdb4"
+#      $(V)mount /dev/sdb4
+#      $(V)cp $(OBJDIR)/kern/kernel /mnt/pornstick/texas
+#      $(V)sync
+#      $(V)umount /mnt/pornstick
+
 grub: $(OBJDIR)/jos-grub
 
 $(OBJDIR)/jos-grub: $(OBJDIR)/kern/kernel
diff --git a/kern/atomic.c b/kern/atomic.c
new file mode 100644 (file)
index 0000000..59f0bf3
--- /dev/null
@@ -0,0 +1,28 @@
+#include <kern/atomic.h>
+#include <kern/apic.h>
+
+// byte per cpu, as mentioned below
+void init_barrier(barrier_t cpu_array)
+{
+       extern uint8_t num_cpus;
+       uint8_t i;
+       for(i = 0; i < num_cpus; i++)
+               cpu_array[i] = 1;
+}
+
+// primitive barrier function.  all cores call this.
+// should change this to use bits and lock bit ops.
+// currently uses a byte per core, and assumes it was 
+// initialized by a core such that up num_cpus entries
+// are all 1
+void barrier(barrier_t cpu_array)
+{
+       extern uint8_t num_cpus;
+       uint8_t i;
+
+       cpu_array[lapic_get_id()] = 0;
+       for(i = 0; i < num_cpus; i++) {
+               while(cpu_array[i]) 
+                       cpu_relax();
+       }
+}
diff --git a/kern/atomic.h b/kern/atomic.h
new file mode 100644 (file)
index 0000000..61472bd
--- /dev/null
@@ -0,0 +1,81 @@
+#ifndef ROS_INC_ATOMIC_H
+#define ROS_INC_ATOMIC_H
+
+#include <inc/types.h>
+#include <inc/mmu.h>
+#include <inc/x86.h>
+
+/* //linux style atomic ops
+typedef struct {uint32_t real_num;} atomic_t;
+#define atomic_read(atom) ((atom)->real_num)
+#define atomic_set(atom, val) (((atom)->real_num) = (val))
+#define atomic_init(i) {(i)}
+//and the atomic incs, etc take an atomic_t ptr, deref inside
+*/
+
+static inline void spin_lock(volatile uint32_t* lock);
+static inline void spin_unlock(volatile uint32_t* lock);
+static inline void spin_lock_irqsave(volatile uint32_t* lock);
+static inline void spin_unlock_irqsave(volatile uint32_t* lock);
+static inline void atomic_inc(volatile uint32_t* number);
+static inline void atomic_dec(volatile uint32_t* number);
+
+
+typedef volatile uint8_t barrier_t[MAX_NUM_CPUS];
+void init_barrier(barrier_t COUNT(MAX_NUM_CPUS) cpu_array);
+void barrier(barrier_t COUNT(MAX_NUM_CPUS) cpu_array);
+
+static inline void spin_lock(volatile uint32_t* lock)
+{
+       asm volatile(
+                       "1:                       "
+                       "       cmpb $0, %0;          "
+                       "       je 2f;                "
+                       "       pause;                "
+                       "       jmp 1b;               "
+                       "2:                       " 
+                       "       movb $1, %%al;        "
+                       "       xchgb %%al, %0;       "
+                       "       cmpb $0, %%al;        "
+                       "       jne 1b;               "
+               : : "m"(*lock) : "eax", "cc");
+}
+
+static inline void spin_unlock(volatile uint32_t* lock)
+{
+       *lock = 0;
+}
+
+// If ints are enabled, disable them and note it in the top bit of the lock
+// There is an assumption about releasing locks in order here...
+static inline void spin_lock_irqsave(volatile uint32_t* lock)
+{
+       uint32_t eflags;
+       eflags = read_eflags();
+       disable_irq();
+       spin_lock(lock);
+       if (eflags & FL_IF)
+               *lock |= 0x80000000;
+}
+
+// if the top bit of the lock is set, then re-enable interrupts
+static inline void spin_unlock_irqsave(volatile uint32_t* lock)
+{
+       if (*lock & 0x80000000) {
+               *lock = 0;
+               enable_irq();
+       } else
+               *lock = 0;
+}
+
+// need to do this with pointers and deref.  %0 needs to be the memory address
+static inline void atomic_inc(volatile uint32_t* number)
+{
+       asm volatile("lock incl %0" : "=m"(*number) : : "cc");
+}
+
+static inline void atomic_dec(volatile uint32_t* number)
+{
+       asm volatile("lock decl %0" : "=m"(*number) : : "cc");
+}
+#endif /* !ROS_INC_ATOMIC_H */
index 541cd71..2bbb88b 100644 (file)
@@ -10,7 +10,6 @@
 #include <inc/multiboot.h>
 #include <inc/stab.h>
 #include <inc/x86.h>
-#include <inc/atomic.h>
 
 #include <kern/monitor.h>
 #include <kern/console.h>
@@ -20,6 +19,7 @@
 #include <kern/trap.h>
 #include <kern/apic.h>
 #include <kern/testing.h>
+#include <kern/atomic.h>
 
 volatile uint32_t waiting = 1;
 volatile uint8_t num_cpus = 0xee;
@@ -55,6 +55,9 @@ void kernel_init(multiboot_info_t *mboot_info)
        // this returns when all other cores are done and ready to receive IPIs
        smp_boot();
 
+       test_barrier();
+       panic("Don't Panic");
+       test_print_info();
        test_ipi_sending();
 
        //ENV_CREATE(user_faultread);
@@ -105,7 +108,7 @@ void smp_boot(void)
        // first SIPI
        waiting = 1;
        send_startup_ipi(0x01);
-       lapic_set_timer(0x00000fff, 0xf0, 0); // TODO - fix timing
+       lapic_set_timer(0x0000ffff, 0xf0, 0); // TODO - fix timing
        while(waiting) // wait for the first SIPI to take effect
                cpu_relax();
        /* //BOCHS does not like this second SIPI.
index 7b815c7..d1c3efe 100644 (file)
@@ -4,7 +4,8 @@
 #include <inc/types.h>
 #include <inc/stdio.h>
 #include <inc/stdarg.h>
-#include <inc/atomic.h>
+
+#include <kern/atomic.h>
 
 uint32_t output_lock = 0;
 
index 38ea855..e6f8d5c 100644 (file)
@@ -4,13 +4,13 @@
 
 #include <inc/mmu.h>
 #include <inc/x86.h>
-#include <inc/atomic.h>
 #include <inc/stdio.h>
 #include <inc/assert.h>
 
 #include <kern/testing.h>
 #include <kern/trap.h>
 #include <kern/apic.h>
+#include <kern/atomic.h>
 
 void test_ipi_sending(void)
 {
@@ -83,9 +83,75 @@ void test_pic_reception(void)
        while(1);
 }
 
+static void all_cores_call(isr_t handler, uint8_t vector);
+
+void test_print_info(void)
+{
+       cprintf("\nCORE 0 asking all cores to print info:\n");
+       all_cores_call(smp_print_info_handler, 0);
+       cprintf("\nDone!\n");
+}
+       
+
+barrier_t test_cpu_array;
+
+void test_barrier(void)
+{
+       cprintf("Core 0 initializing barrier\n");
+       init_barrier(test_cpu_array);
+       cprintf("Core 0 asking all cores to print ids, barrier, rinse, repeat\n");
+       all_cores_call(smp_barrier_test_handler, 0);
+}
+
+/* Helper Functions */
+
+// should probably find a new home for this, or something that does the same
+// function more generally
+static void all_cores_call(isr_t handler, uint8_t vector)
+{
+       extern isr_t interrupt_handlers[];
+       uint32_t i, amount = 0x7ffffff0; // should calibrate this!!
+       bool state;
+
+       if (!vector)
+               vector = 0xf1; //default value
+       register_interrupt_handler(interrupt_handlers, vector, handler);
+       state = enable_irqsave();
+       send_broadcast_ipi(vector);
+       // wait some arbitrary amount til we think all the cores could be done.
+       // very wonky without an idea of how long the function takes.
+       // maybe should think of some sort of completion notification mech
+       for (i = 0; i < amount; i++)
+               asm volatile("nop;");
+       disable_irqsave(state);
+}
+
 void smp_hello_world_handler(struct Trapframe *tf)
 {
        cprintf("Incoming IRQ, ISR: %d on core %d with tf at 0x%08x\n", 
                tf->tf_trapno, lapic_get_id(), tf);
 }
 
+uint32_t print_info_lock = 0;
+
+void smp_print_info_handler(struct Trapframe *tf)
+{
+       spin_lock_irqsave(&print_info_lock);
+       cprintf("----------------------------\n");
+       cprintf("This is Core %d\n", lapic_get_id());
+       cprintf("MTRR_DEF_TYPE = 0x%08x\n", read_msr(IA32_MTRR_DEF_TYPE));
+       cprintf("----------------------------\n");
+       spin_unlock_irqsave(&print_info_lock);
+}
+
+void smp_barrier_test_handler(struct Trapframe *tf)
+{
+       cprintf("Round 1: Core %d\n", lapic_get_id());
+       barrier(test_cpu_array);
+       cprintf("Round 2: Core %d\n", lapic_get_id());
+       // note that if we barrier again, we'll need to reinit it first
+       // uncomment these two to see the barrier not work
+       //barrier(test_cpu_array);
+       //cprintf("Round 3: Core %d\n", lapic_get_id());
+}
+
index a9bd7a8..59736fa 100644 (file)
 
 void test_ipi_sending(void);
 void test_pic_reception(void);
+void test_print_info(void);
+void test_barrier(void);
 
 void smp_hello_world_handler(struct Trapframe *tf);
+void smp_print_info_handler(struct Trapframe *tf);
+void smp_barrier_test_handler(struct Trapframe *tf);