SMP function call helpers
authorBarret Rhoden <brho@cs.berkeley.edu>
Thu, 9 Apr 2009 04:45:43 +0000 (21:45 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Thu, 9 Apr 2009 04:45:43 +0000 (21:45 -0700)
Creates helpers to call functions across all cores or a subset of cores,
mostly just registration and IPI sending.  Needs work, esp with knowing
when to proceed (esp when overwriting the IDT), and some wmb() love.

kern/Makefrag
kern/init.c
kern/monitor.c
kern/smp.c [new file with mode: 0644]
kern/smp.h [new file with mode: 0644]
kern/testing.c
kern/testing.h

index 03e5317..18c0937 100644 (file)
@@ -32,6 +32,7 @@ KERN_SRCFILES :=      kern/entry.S \
                        kern/apic.c \
                        kern/testing.c \
                        kern/atomic.c \
+                       kern/smp.c \
                        lib/printfmt.c \
                        lib/readline.c \
                        lib/string.c
@@ -94,12 +95,12 @@ $(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
+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
 
index 2bbb88b..033ac53 100644 (file)
@@ -55,9 +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_barrier();
        test_ipi_sending();
 
        //ENV_CREATE(user_faultread);
@@ -108,7 +108,7 @@ void smp_boot(void)
        // first SIPI
        waiting = 1;
        send_startup_ipi(0x01);
-       lapic_set_timer(0x0000ffff, 0xf0, 0); // TODO - fix timing
+       lapic_set_timer(0x000fffff, 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 7fa7cdf..644794d 100644 (file)
@@ -18,6 +18,8 @@
 #include <kern/kdebug.h>
 #include <kern/pmap.h>
 #include <kern/apic.h>
+#include <kern/smp.h>
+#include <kern/testing.h>
 
 #define CMDBUF_SIZE    80      // enough for one VGA text line
 
@@ -174,7 +176,7 @@ int mon_showmapping(int argc, char **argv, struct Trapframe *tf)
 
 int mon_setmapperm(int argc, char **argv, struct Trapframe *tf)
 {
-       if (argc < 2) {
+       if (argc < 3) {
                cprintf("Sets VIRT_ADDR's mapping's permissions to PERMS (in hex)\n");
                cprintf("Only affects the lowest level PTE.  To adjust the PDE, do the math.\n");
                cprintf("Be careful with this around UVPT, VPT, and friends.\n");
@@ -210,8 +212,14 @@ int mon_setmapperm(int argc, char **argv, struct Trapframe *tf)
 int mon_cpuinfo(int argc, char **argv, struct Trapframe *tf)
 {
        extern uint8_t num_cpus;
+
        cprintf("Number of CPUs detected: %d\n", num_cpus);     
-       cprintf("Current CPU's LAPIC ID: 0x%08x\n", lapic_get_id());
+       cprintf("Calling CPU's LAPIC ID: 0x%08x\n", lapic_get_id());
+       if (argc < 2)
+               smp_call_function_self(test_print_info_handler, 0);
+       else
+               smp_call_function_single(strtol(argv[1], 0, 16),
+                                        test_print_info_handler, 0);
        return 0;
 }
 
diff --git a/kern/smp.c b/kern/smp.c
new file mode 100644 (file)
index 0000000..2e783b1
--- /dev/null
@@ -0,0 +1,67 @@
+#ifdef __DEPUTY__
+#pragma nodeputy
+#endif
+
+#include <kern/smp.h>
+#include <kern/apic.h>
+
+// as far as completion mechs go, we might want a bit mask that every sender 
+// has to toggle.  or a more general barrier that works on a queue / LL, 
+// instead of everyone.  TODO!
+static void smp_call_function(uint8_t type, uint8_t dest, isr_t handler, uint8_t vector)
+{
+       extern isr_t interrupt_handlers[];
+       uint32_t i, amount = 0x7ffffff0; // should calibrate this!!  just remove it!
+       bool state;
+
+       if (!vector)
+               vector = 0xf1; //default value
+       register_interrupt_handler(interrupt_handlers, vector, handler);
+       // WRITE MEMORY BARRIER HERE
+       state = enable_irqsave();
+       // Send the proper type of IPI.  I made up these numbers.
+       switch (type) {
+               case 1:
+                       send_self_ipi(vector);
+                       break;
+               case 2:
+                       send_broadcast_ipi(vector);
+                       break;
+               case 3:
+                       send_all_others_ipi(vector);
+                       break;
+               case 4: // physical mode
+                       send_ipi(dest, 0, vector);
+                       break;
+               case 5: // logical mode
+                       send_ipi(dest, 1, vector);
+                       break;
+               default:
+                       //panic("Invalid type for cross-core function call!");
+       }
+       // 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);
+       // 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
+}
+
+void smp_call_function_self(isr_t handler, uint8_t vector)
+{
+       smp_call_function(1, 0, handler, vector);
+}
+
+void smp_call_function_all(isr_t handler, uint8_t vector)
+{
+       smp_call_function(2, 0, handler, vector);
+}
+
+void smp_call_function_single(uint8_t dest, isr_t handler, uint8_t vector)
+{
+       smp_call_function(4, dest, handler, vector);
+}
+
diff --git a/kern/smp.h b/kern/smp.h
new file mode 100644 (file)
index 0000000..724896e
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef ROS_INC_SMP_H
+#define ROS_INC_SMP_H
+
+/* SMP related functions */
+
+#include <inc/types.h>
+
+#include <kern/trap.h>
+
+void smp_call_function_self(isr_t handler, uint8_t vector);
+void smp_call_function_all(isr_t handler, uint8_t vector);
+void smp_call_function_single(uint8_t dest, isr_t handler, uint8_t vector);
+
+#endif /* !ROS_INC_SMP_H */
index 1e57fb3..06510ce 100644 (file)
 #include <kern/trap.h>
 #include <kern/apic.h>
 #include <kern/atomic.h>
+#include <kern/smp.h>
 
 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);
+       register_interrupt_handler(interrupt_handlers, 0xf1, test_hello_world_handler);
        state = enable_irqsave();
        
        cprintf("\nCORE 0 sending broadcast\n");
@@ -72,7 +73,7 @@ void test_ipi_sending(void)
 // Note this never returns and will muck with any other timer work
 void test_pic_reception(void)
 {
-       register_interrupt_handler(interrupt_handlers, 0x20, smp_hello_world_handler);
+       register_interrupt_handler(interrupt_handlers, 0x20, test_hello_world_handler);
        pit_set_timer(1000, 1); // totally arbitrary time
        pic_unmask_irq(0);
        cprintf("PIC1 Mask = 0x%04x\n", inb(PIC1_DATA));
@@ -83,12 +84,10 @@ 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);
+       smp_call_function_all(test_print_info_handler, 0);
        cprintf("\nDone!\n");
 }
        
@@ -100,33 +99,12 @@ void test_barrier(void)
        cprintf("Core 0 initializing barrier\n");
        init_barrier_all(&test_cpu_array);
        cprintf("Core 0 asking all cores to print ids, barrier, rinse, repeat\n");
-       all_cores_call(smp_barrier_test_handler, 0);
+       smp_call_function_all(test_barrier_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)
+void test_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);
@@ -134,17 +112,25 @@ void smp_hello_world_handler(struct Trapframe *tf)
 
 uint32_t print_info_lock = 0;
 
-void smp_print_info_handler(struct Trapframe *tf)
+void test_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("MTRR Phys0 Base = 0x%08x, Mask = 0x%08x\n", read_msr(0x200), read_msr(0x201));
+       cprintf("MTRR Phys1 Base = 0x%08x, Mask = 0x%08x\n", read_msr(0x202), read_msr(0x203));
+       cprintf("MTRR Phys2 Base = 0x%08x, Mask = 0x%08x\n", read_msr(0x204), read_msr(0x205));
+       cprintf("MTRR Phys3 Base = 0x%08x, Mask = 0x%08x\n", read_msr(0x206), read_msr(0x207));
+       cprintf("MTRR Phys4 Base = 0x%08x, Mask = 0x%08x\n", read_msr(0x208), read_msr(0x209));
+       cprintf("MTRR Phys5 Base = 0x%08x, Mask = 0x%08x\n", read_msr(0x20a), read_msr(0x20b));
+       cprintf("MTRR Phys6 Base = 0x%08x, Mask = 0x%08x\n", read_msr(0x20c), read_msr(0x20d));
+       cprintf("MTRR Phys7 Base = 0x%08x, Mask = 0x%08x\n", read_msr(0x20e), read_msr(0x20f));
        cprintf("----------------------------\n");
        spin_unlock_irqsave(&print_info_lock);
 }
 
-void smp_barrier_test_handler(struct Trapframe *tf)
+void test_barrier_handler(struct Trapframe *tf)
 {
        cprintf("Round 1: Core %d\n", lapic_get_id());
        barrier_all(&test_cpu_array);
index 59736fa..941c22a 100644 (file)
@@ -15,9 +15,9 @@ 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);
+void test_hello_world_handler(struct Trapframe *tf);
+void test_print_info_handler(struct Trapframe *tf);
+void test_barrier_handler(struct Trapframe *tf);