timer works in bochs and on physical machine. need global definition for bochs...
[akaros.git] / kern / smp.c
index 7344b65..99b714f 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)
+static void smp_boot_handler(trapframe_t *tf)
 {
-       extern volatile uint32_t waiting;
        {HANDLER_ATOMIC atomic_dec(&waiting); }
 }
 
+static void smp_mtrr_handler(trapframe_t *tf)
+{
+       setup_default_mtrrs(&generic_barrier);
+}
+
 void smp_boot(void)
 {
-       struct Page* smp_stack;
+       page_t *smp_stack;
        extern isr_t interrupt_handlers[];
        // NEED TO GRAB A LOWMEM FREE PAGE FOR AP BOOTUP CODE
        // page1 (2nd page) is reserved, hardcoded in pmap.c
@@ -58,7 +63,7 @@ void smp_boot(void)
        // first SIPI
        waiting = 1;
        send_startup_ipi(0x01);
-       lapic_set_timer(0x002fffff, 0xf0, 0); // TODO - fix timing
+       lapic_set_timer(SMP_BOOT_TIMEOUT, 0xf0, 0); // TODO - fix timing
        while(waiting) // wait for the first SIPI to take effect
                cpu_relax();
        /* //BOCHS does not like this second SIPI.
@@ -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(&generic_barrier, num_cpus); // 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
 }
@@ -125,7 +134,7 @@ uint32_t smp_main(void)
        */
        
        // Get a per-core kernel stack
-       struct Page* my_stack;
+       page_t *my_stack;
        if (page_alloc(&my_stack))
                panic("Unable to alloc a per-core stack!");
        memset(page2kva(my_stack), 0, PGSIZE);
@@ -133,30 +142,30 @@ uint32_t smp_main(void)
        // Set up a gdt / gdt_pd for this core, stored at the top of the stack
        // This is necessary, eagle-eyed readers know why
        // GDT should be 4-byte aligned.  TS isn't aligned.  Not sure if it matters.
-       struct Pseudodesc* my_gdt_pd = page2kva(my_stack) + PGSIZE - 
-               sizeof(struct Pseudodesc) - sizeof(struct Segdesc)*SEG_COUNT;
-       struct Segdesc* my_gdt = page2kva(my_stack) + PGSIZE - 
-               sizeof(struct Segdesc)*SEG_COUNT;
+       pseudodesc_t *my_gdt_pd = page2kva(my_stack) + PGSIZE - 
+               sizeof(pseudodesc_t) - sizeof(segdesc_t)*SEG_COUNT;
+       segdesc_t *my_gdt = page2kva(my_stack) + PGSIZE - 
+               sizeof(segdesc_t)*SEG_COUNT;
        // TS also needs to be permanent
-       struct Taskstate* my_ts = page2kva(my_stack) + PGSIZE - 
-               sizeof(struct Pseudodesc) - sizeof(struct Segdesc)*SEG_COUNT - 
-               sizeof(struct Taskstate);
+       taskstate_t *my_ts = page2kva(my_stack) + PGSIZE - 
+               sizeof(pseudodesc_t) - sizeof(segdesc_t)*SEG_COUNT - 
+               sizeof(taskstate_t);
        // Usable portion of the KSTACK grows down from here
        // Won't actually start using this stack til our first interrupt
        // (issues with changing the stack pointer and then trying to "return")
        uintptr_t my_stack_top = (uintptr_t)my_ts;
 
        // Build and load the gdt / gdt_pd
-       memcpy(my_gdt, gdt, sizeof(struct Segdesc)*SEG_COUNT);
-       *my_gdt_pd = (struct Pseudodesc) { 
-               sizeof(struct Segdesc)*SEG_COUNT - 1, (uintptr_t) my_gdt };
+       memcpy(my_gdt, gdt, sizeof(segdesc_t)*SEG_COUNT);
+       *my_gdt_pd = (pseudodesc_t) { 
+               sizeof(segdesc_t)*SEG_COUNT - 1, (uintptr_t) my_gdt };
        asm volatile("lgdt %0" : : "m"(*my_gdt_pd));
 
        // Need to set the TSS so we know where to trap on this core
        my_ts->ts_esp0 = my_stack_top;
        my_ts->ts_ss0 = GD_KD;
        // Initialize the TSS field of my_gdt.
-       my_gdt[GD_TSS >> 3] = SEG16(STS_T32A, (uint32_t) (my_ts), sizeof(struct Taskstate), 0);
+       my_gdt[GD_TSS >> 3] = SEG16(STS_T32A, (uint32_t) (my_ts), sizeof(taskstate_t), 0);
        my_gdt[GD_TSS >> 3].sd_s = 0;
        // Load the TSS
        ltr(GD_TSS);
@@ -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());
@@ -184,14 +194,14 @@ uint32_t smp_main(void)
 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;
+       uint32_t i, amount = SMP_CALL_FUNCTION_TIMEOUT; // should calibrate this!!  just remove it!
+       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:
@@ -210,19 +220,24 @@ 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.
        // 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);
+       // 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);