SMP MTRRs
authorBarret Rhoden <brho@cs.berkeley.edu>
Tue, 14 Apr 2009 07:32:44 +0000 (00:32 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Tue, 14 Apr 2009 07:32:44 +0000 (00:32 -0700)
Sets up the MTRRs the same (and hopefully correctly) across all cores.
Fixes up a couple minor details in the SMP booting and LAPIC ExtINT
setup.

inc/types.h
kern/apic.h
kern/pmap.c
kern/pmap.h
kern/smp.c
kern/smp_entry.S
kern/testing.c
kern/trap.c

index 4627178..60d6384 100644 (file)
@@ -69,4 +69,8 @@ typedef int32_t off_t;
 // Return the offset of 'member' relative to the beginning of a struct type
 #define offsetof(type, member)  ((size_t) (&((type*)0)->member))
 
+// Ivy currently can only handle 63 bits (OCaml thing), so use this to make
+// a uint64_t programatically
+#define UINT64(upper, lower) ( (((uint64_t)(upper)) << 32) | (lower) )
+
 #endif /* !JOS_INC_TYPES_H */
index 19c3c94..86c9880 100644 (file)
@@ -137,7 +137,7 @@ static inline void lapic_disable(void)
 static inline void lapic_wait_to_send(void)
 {
        while(read_mmreg32(LAPIC_IPI_ICR_LOWER) & 0x1000)
-               asm volatile("pause");
+               cpu_relax();
 }
 
 static inline void lapic_enable(void)
index 0638618..145a87a 100644 (file)
@@ -13,6 +13,7 @@
 #include <kern/kclock.h>
 #include <kern/env.h>
 #include <kern/apic.h>
+#include <kern/atomic.h>
 
 // These variables are set by i386_detect_memory()
 static physaddr_t maxpa;       // Maximum physical address
@@ -242,11 +243,16 @@ boot_map_segment(pde_t *pgdir, uintptr_t la, size_t size, physaddr_t pa, int per
 // could consider having an API to allow these to dynamically change
 // MTRRs are for physical, static ranges.  PAT are linear, more granular, and 
 // more dynamic
-void setup_default_mtrrs(void)
+void setup_default_mtrrs(barrier_t* smp_barrier)
 {
        // disable interrupts
-       //uint32_t state = enable_irqsave();    
-       // barrier
+       int8_t state = 0;
+       disable_irqsave(&state);
+       // barrier - if we're meant to do this for all cores, we'll be 
+       // passed a pointer to an initialized barrier
+       if (smp_barrier)
+               barrier_all(smp_barrier);
+       
        // disable caching      cr0: set CD and clear NW
        lcr0((rcr0() | CR0_CD) & ~CR0_NW);
        // flush caches
@@ -260,6 +266,7 @@ void setup_default_mtrrs(void)
        // MTRR for IO Holes (note these are 64 bit values we are writing)
        // 0x000a0000 - 0x000c0000 : VGA - WC 0x01
        write_msr(IA32_MTRR_PHYSBASE0, PTE_ADDR(VGAPHYSMEM) | 0x01);
+       // if we need to have a full 64bit val, use the UINT64 macro
        write_msr(IA32_MTRR_PHYSMASK0, 0x0000000ffffe0800);
        // 0x000c0000 - 0x00100000 : IO devices (and ROM BIOS) - UC 0x00
        write_msr(IA32_MTRR_PHYSBASE1, PTE_ADDR(DEVPHYSMEM) | 0x00);
@@ -284,8 +291,10 @@ void setup_default_mtrrs(void)
        // turn on caching
        lcr0(rcr0() & ~(CR0_CD | CR0_NW));
        // barrier
+       if (smp_barrier)
+               barrier_all(smp_barrier);
        // enable interrupts
-
+       enable_irqsave(&state);
 }
 
 
@@ -314,7 +323,7 @@ i386_vm_init(void)
                cprintf("PSE capability detected.\n");
 
        // set up mtrr's for core0.  other cores will do the same later
-       setup_default_mtrrs();
+       setup_default_mtrrs(0);
 
        /*
         * PSE status: 
index faab71b..37c61e3 100644 (file)
@@ -8,6 +8,9 @@
 
 #include <inc/memlayout.h>
 #include <inc/assert.h>
+
+#include <kern/atomic.h>
+
 struct Env;
 
 
@@ -61,6 +64,7 @@ void  page_remove(pde_t *pgdir, void *va);
 struct Page *page_lookup(pde_t *pgdir, void *va, pte_t **pte_store);
 void   page_decref(struct Page *pp);
 
+void setup_default_mtrrs(barrier_t* smp_barrier);
 void   tlb_invalidate(pde_t *pgdir, void *va);
 void tlb_flush_global(void);
 
index c9dc1c1..5ebd604 100644 (file)
 volatile uint32_t waiting = 1;
 volatile uint8_t num_cpus = 0xee;
 uintptr_t smp_stack_top;
+barrier_t generic_barrier;
 
 /* Breaks us out of the waiting loop in smp_boot */
 static void smp_boot_handler(struct Trapframe *tf)
 {
-       extern volatile uint32_t waiting;
        {HANDLER_ATOMIC atomic_dec(&waiting); }
 }
 
+static void smp_mtrr_handler(struct Trapframe *tf)
+{
+       setup_default_mtrrs(&generic_barrier);
+}
+
 void smp_boot(void)
 {
        struct Page* smp_stack;
@@ -101,6 +106,10 @@ void smp_boot(void)
        // Dealloc the temp shared stack
        page_decref(smp_stack);
 
+       // Set up all cores to use the proper MTRRs
+       init_barrier_all(&generic_barrier); // barrier used by smp_mtrr_handler
+       smp_call_function_all(smp_mtrr_handler, 0);
+
        // Should probably flush everyone's TLB at this point, to get rid of 
        // temp mappings that were removed.  TODO
 }
@@ -165,12 +174,13 @@ uint32_t smp_main(void)
        asm volatile("lidt idt_pd");
 
        // APIC setup
-       lapic_enable();
        // set LINT0 to receive ExtINTs (KVM's default).  At reset they are 0x1000.
        write_mmreg32(LAPIC_LVT_LINT0, 0x700); 
        // mask it to shut it up for now.  Doesn't seem to matter yet, since both
        // KVM and Bochs seem to only route the PIC to core0.
        mask_lapic_lvt(LAPIC_LVT_LINT0);
+       // and then turn it on
+       lapic_enable();
 
        // set a default logical id for now
        lapic_set_logid(lapic_get_id());
@@ -210,7 +220,7 @@ static void smp_call_function(uint8_t type, uint8_t dest, isr_t handler, uint8_t
                        send_ipi(dest, 1, vector);
                        break;
                default:
-                       //panic("Invalid type for cross-core function call!");
+                       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.
@@ -218,11 +228,16 @@ static void smp_call_function(uint8_t type, uint8_t dest, isr_t handler, uint8_t
        for (i = 0; i < amount; i++)
                asm volatile("nop;");
        disable_irqsave(&state);
+       // TODO
        // 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
 }
 
+// I'd rather have these functions take an arbitrary function and arguments...
+// Right now, I build a handler that just calls whatever I want, which is
+// another layer of indirection.  Might like some ability to specify if
+// we want to wait or not.
 void smp_call_function_self(isr_t handler, uint8_t vector)
 {
        smp_call_function(1, 0, handler, vector);
index 5ffe440..ec0e517 100644 (file)
@@ -83,8 +83,8 @@ here:
        lock decw       smp_semaphore - smp_entry + 0x1000  # show we are done
 
        sti                                             # turn on interrupts, and wait for an IPI
-       hlt                                             # hlts, else will just spin.
 spinwait:
+       hlt                                             # hlts, else will just spin.
        jmp             spinwait
 
        # Below here is just data, stored with the code text
index eac436e..3717593 100644 (file)
@@ -214,14 +214,22 @@ void test_print_info_handler(struct Trapframe *tf)
        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("MTRR Phys0 Base = 0x%016llx, Mask = 0x%016llx\n",
+               read_msr(0x200), read_msr(0x201));
+       cprintf("MTRR Phys1 Base = 0x%016llx, Mask = 0x%016llx\n",
+               read_msr(0x202), read_msr(0x203));
+       cprintf("MTRR Phys2 Base = 0x%016llx, Mask = 0x%016llx\n",
+               read_msr(0x204), read_msr(0x205));
+       cprintf("MTRR Phys3 Base = 0x%016llx, Mask = 0x%016llx\n",
+               read_msr(0x206), read_msr(0x207));
+       cprintf("MTRR Phys4 Base = 0x%016llx, Mask = 0x%016llx\n",
+               read_msr(0x208), read_msr(0x209));
+       cprintf("MTRR Phys5 Base = 0x%016llx, Mask = 0x%016llx\n",
+               read_msr(0x20a), read_msr(0x20b));
+       cprintf("MTRR Phys6 Base = 0x%016llx, Mask = 0x%016llx\n",
+               read_msr(0x20c), read_msr(0x20d));
+       cprintf("MTRR Phys7 Base = 0x%016llx, Mask = 0x%016llx\n",
+               read_msr(0x20e), read_msr(0x20f));
        cprintf("----------------------------\n");
        spin_unlock_irqsave(&print_info_lock);
 }
index 3e48cef..9c9d45e 100644 (file)
@@ -115,11 +115,12 @@ idt_init(void)
 
        // This will go away when we start using the IOAPIC properly
        pic_remap();
-       lapic_enable();
        // set LINT0 to receive ExtINTs (KVM's default).  At reset they are 0x1000.
        write_mmreg32(LAPIC_LVT_LINT0, 0x700); 
        // mask it to shut it up for now
        mask_lapic_lvt(LAPIC_LVT_LINT0);
+       // and turn it on
+       lapic_enable();
 }
 
 void
@@ -222,6 +223,10 @@ void
 void
 (IN_HANDLER irq_handler)(struct Trapframe *tf)
 {
+       //if (lapic_get_id())
+       //      cprintf("Incoming IRQ, ISR: %d on core %d\n", tf->tf_trapno, lapic_get_id());
+       // merge this with alltraps?  other than the EOI... or do the same in all traps
+
        // determine the interrupt handler table to use.  for now, pick the global
        isr_t* handler_table = interrupt_handlers;