Spinlock and SMP booting
authorBarret Rhoden <brho@cs.berkeley.edu>
Tue, 24 Mar 2009 06:48:34 +0000 (23:48 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Tue, 24 Mar 2009 06:48:34 +0000 (23:48 -0700)
Added spin_lock and some initial other atomic ops.  Used them to hack up
a way for core0 to wait a bit (timer), then wait for the other cores to
finish their smp_main()s.

inc/atomic.h [new file with mode: 0644]
kern/init.c
kern/smp_entry.S

diff --git a/inc/atomic.h b/inc/atomic.h
new file mode 100644 (file)
index 0000000..de60d1d
--- /dev/null
@@ -0,0 +1,51 @@
+#ifndef ROS_INC_ATOMIC_H
+#define ROS_INC_ATOMIC_H
+
+#include <inc/types.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 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(
+                       "spinlock:                "
+                       "       testb $0,%0;          "
+                       "       je getlock;           "
+                       "       pause;                "
+                       "       jmp spinlock;         "
+                       "getlock:                 " 
+                       "       movb $1, %%al;        "
+                       "       xchgb %%al, %0;       "
+                       "       test $0, %%al;        "
+                       "       jne spinlock;         "
+               : : "m"(*lock) : "eax", "cc");
+}
+
+static inline void spin_unlock(volatile uint32_t* lock)
+{
+       *lock = 0;
+}
+
+// need to do this with pointers and deref.  not totally sure why
+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 23aded6..f3fec1b 100644 (file)
@@ -10,6 +10,7 @@
 #include <inc/multiboot.h>
 #include <inc/stab.h>
 #include <inc/x86.h>
+#include <inc/atomic.h>
 
 #include <kern/monitor.h>
 #include <kern/console.h>
@@ -19,7 +20,7 @@
 #include <kern/trap.h>
 #include <kern/apic.h>
 
-volatile bool waiting = 1;
+volatile uint32_t waiting = 1;
 volatile uint8_t num_cpus = 0xee;
 uintptr_t smp_stack_top;
 volatile bool smp_boot_lock = 0;
@@ -99,17 +100,22 @@ void smp_boot(void)
        send_init_ipi();
        asm volatile("sti"); // LAPIC timer will fire, extINTs are blocked at LINT0 now
        while (waiting); // gets released in smp_boot_handler
-       send_startup_ipi(0x01);
+
+       // Since we don't know how many CPUs are out there (need to parse tables)
+       // we'll wait for a little bit, using the timer as above.  each core will
+       // also increment waiting, and decrement when it is done, all in smp_entry.
+       // core0 uses the timer for its decrement to signal "waiting a while".  
+       // Replace this shit when we parse the ACPI/MP tables
+       waiting = 1;
+       send_startup_ipi(0x01); // can also send another one if all don't report in
+       lapic_set_timer(0x0000ffff, 0xf0, 0);
+       while(waiting); // want other cores to do stuff for now
+
        // Deregister smp_boot_handler
        register_interrupt_handler(interrupt_handlers, 0xf0, 0);
-
-       // replace this with something that checks to see if smp_entrys are done
-       while(1); // want other cores to do stuff for now
-       
        // Remove the mapping of the page used by the trampoline
        page_remove(boot_pgdir, (void*)0x00001000);
        // It had a refcount of 2 earlier, so we need to dec once more to free it
-       // TODO - double check that
        page_decref(pa2page(0x00001000));
        // Dealloc the temp shared stack
        page_decref(smp_stack);
@@ -118,8 +124,8 @@ void smp_boot(void)
 /* Breaks us out of the waiting loop in smp_boot */
 void smp_boot_handler(struct Trapframe *tf)
 {
-       extern volatile bool waiting;
-       {HANDLER_ATOMIC waiting = 0; }
+       extern volatile uint32_t waiting;
+       {HANDLER_ATOMIC atomic_dec(&waiting); }
 }
 
 /* 
index a82fbd7..fea2a15 100644 (file)
@@ -72,10 +72,12 @@ spin_start:                                 # grab lock for smp_main
        test    %eax, %eax
        jne             spin_start
 
-       addl    $0x1, num_cpus
+       incl    num_cpus
+       lock incl       waiting
        movl    (smp_stack_top), %esp
        movl    $0, %ebp                # so backtrace works
        call    smp_main
+       lock decl       waiting
        movl    $0, smp_boot_lock       # release lock
 
        hlt                                             # hlts, and PC advances to the spinwait