Abstract smp_wake from ACPI
authorJack Miller <jack@codezen.org>
Fri, 25 Mar 2016 05:54:34 +0000 (00:54 -0500)
committerJack Miller <jack@codezen.org>
Fri, 25 Mar 2016 21:59:18 +0000 (16:59 -0500)
asm/realmode.asm-bin
include/asm/realmode.h
include/page_alloc.h
include/smp.h [new file with mode: 0644]
kernel/acpi.c
kernel/apic.c
kernel/main.c
kernel/smp.c [new file with mode: 0644]
mm/page_alloc.c

index ddbf453..fbcb683 100644 (file)
 #include <memmap.h>
 
 #include <asm/gdt.h>
+#include <asm/realmode.h>
 
 /* Assumptions */
 
-#define REALMODE_PA 0x2000
 #define CODESEL_32  0x8
 #define DATASEL_32  0x10
 
index 50083ee..c5caf5b 100644 (file)
@@ -1,5 +1,8 @@
 #pragma once
 
+#define REALMODE_PA 0x2000
+
+#ifndef __ASSEMBLY__
 extern u64 realmode_bin;
 extern u64 end_realmode_bin;
 
@@ -14,3 +17,4 @@ struct rm_header {
 } __attribute__((packed));
 
 extern u64 GDTR_64;
+#endif
index fdba337..80b23a0 100644 (file)
@@ -1,14 +1,18 @@
-#ifndef PAGE_ALLOC_H
-#define PAGE_ALLOC_H
+#pragma once
 
 #include <grub.h>
 #include <types.h>
 
-u32 page_alloc_init (struct grub_info *info_phys, u64 end_structures);
+int page_alloc_init (struct grub_info *info_phys, u64 end_structures);
 
 u64 page_alloc_phys(u32 order);
 u64 page_alloc_free_phys(u64 phys);
 
 void *page_alloc(u32 order);
 void *page_alloc_to_virtual(u64 virtual, u32 order);
+
+#ifdef TEST_PAGE_ALLOC
+static void test_page_alloc(u64 max_pages);
+#else
+#define test_page_alloc(...)
 #endif
diff --git a/include/smp.h b/include/smp.h
new file mode 100644 (file)
index 0000000..adb6abd
--- /dev/null
@@ -0,0 +1,4 @@
+#pragma once
+
+int smp_prepare(void); 
+void smp_wake(u32 apic_id);
index b0c0900..e06dd14 100644 (file)
@@ -5,7 +5,7 @@
 #include <memmap.h>
 #include <map.h>
 #include <console.h>
-#include <apic.h>
+#include <smp.h>
 
 struct rsdp {
        char sig[8];
@@ -73,7 +73,6 @@ struct lapic_entry {
 void acpi_apic_handler(struct description_header *hdr, void *entry_ptr)
 {
        struct apic_entry *entry = entry_ptr;
-       int my_lapic = apic->get_id();
        int cpus = 0;
 
        u8 *intcons = (u8 *) (((u64) entry) + sizeof(struct apic_entry));
@@ -87,8 +86,7 @@ void acpi_apic_handler(struct description_header *hdr, void *entry_ptr)
                        struct lapic_entry *lapic = (void *) &intcons[cur_byte];
 
                        if (lapic->flags & LAPIC_FLAGS_ENABLED) {
-                               if (lapic->apic_id != my_lapic)
-                                       apic->wake_secondary(lapic->apic_id);
+                               smp_wake(lapic->apic_id);
                                cpus++;
                        }
                }
index 8ea7177..10284ab 100644 (file)
@@ -116,31 +116,10 @@ static void apic_eoi(void)
        apic->write(APIC_EOI, 0);
 }
 
-static struct rm_header *realboot = NULL;
-
-/* Yes, I know this is currently racy as fuck, it just doesn't matter yet */
-
-void secondary_start(void)
-{
-       printk("Here\n");
-       while(1) {}
-}
-
 static void apic_wake_secondary(u8 apic_id)
 {
        u32 lo;
 
-       if (!realboot) {
-               void *sp = page_alloc(1);
-               map_page(0x2000, 0x2000);
-               realboot = (void *) 0x2000;
-               memcpy(realboot, &realmode_bin, REALMODE_BIN_LEN);
-               realboot->gdtr = (VIRT_BASE + (u64) &GDTR_64);
-               realboot->cr3 = get_cr3();
-               realboot->sp = ((u64) sp + (2 * PAGE_SIZE));
-               realboot->kernel_entry = (u64) secondary_start;
-       }
-
        lo = ICRL_MT(MT_INIT) | ICRL_ASSERT | ICRL_TRIGGER_LEVEL;
 
        apic->write_icr(apic_id, lo);
index 4b07863..9ba875f 100644 (file)
@@ -7,6 +7,7 @@
 #include <cpuid.h>
 #include <vga.h>
 #include <acpi.h>
+#include <smp.h>
 
 void main (void *info_phys, unsigned long end_structures)
 {
@@ -24,6 +25,10 @@ void main (void *info_phys, unsigned long end_structures)
 
        apic_init();
 
+       /* Prepare the realmode landing zone */
+       smp_prepare();
+
+       /* ACPI init probes ACPI tables and generates smp_wake calls */
        acpi_init();
 
        asm ("sti" : : );
diff --git a/kernel/smp.c b/kernel/smp.c
new file mode 100644 (file)
index 0000000..3a1bd55
--- /dev/null
@@ -0,0 +1,48 @@
+/* vim: set ts=4 sw=4 sts=4 noet : */
+
+#include <console.h>
+#include <types.h>
+#include <page_alloc.h>
+#include <map.h>
+#include <memmap.h>
+#include <string.h>
+#include <apic.h>
+
+#include <asm/realmode.h>
+#include <asm/misc.h>
+
+static struct rm_header *realboot = NULL;
+
+/* Yes, I know this is currently racy as fuck, it just doesn't matter yet */
+
+void secondary_start(void)
+{
+       printk("Here\n");
+       while(1) {}
+}
+
+void smp_wake(u32 apic_id)
+{
+       int my_lapic = apic->get_id();
+       void *sp;
+
+       if (apic_id != my_lapic) {
+               sp = page_alloc(1);
+               realboot->sp = ((u64) sp + (2 * PAGE_SIZE));
+               apic->wake_secondary(apic_id);
+       }
+}
+
+int smp_prepare(void) 
+{
+       map_page(REALMODE_PA, REALMODE_PA);
+    realboot = (void *) REALMODE_PA;
+
+       memcpy(realboot, &realmode_bin, REALMODE_BIN_LEN);
+
+       realboot->gdtr = (VIRT_BASE + (u64) &GDTR_64);
+       realboot->cr3 = get_cr3();
+       realboot->kernel_entry = (u64) secondary_start;
+
+    return 0;
+}
index 4ce396d..b479264 100644 (file)
@@ -20,8 +20,7 @@
 #include <types.h>
 #include <vsalloc.h>
 #include <map.h>
-
-#define TEST_PAGE_ALLOC
+#include <page_alloc.h>
 
 struct page_block {
        u64 address;
@@ -477,160 +476,6 @@ void __reserve_region(u64 address, u64 pages)
  * structures.
  */
 
-#ifdef TEST_PAGE_ALLOC
-
-static inline void test_orders(struct page_block **head, u64 *orders)
-{
-       struct page_block *block;
-       int counter = 0;
-       int i = 0;
-
-       for(i = 0; i <= MAX_ORDER; i++) {
-               counter = 0;
-               for (block = head[i]; block; block = block->next)
-                       counter++;
-
-               if (counter != orders[i])
-                       while(1);
-       }
-
-}
-
-static inline void test_order_index(struct page_block *block, u32 index, u64 address, u32 nextnull)
-{
-       int i;
-
-       for (i = 0; i < index; i++)
-               block = block->next;
-
-       if(block->address != address)
-               while(1) {};
-       if(nextnull && block->next)
-               while(1) {};
-       if(!nextnull && !block->next)
-               while(1) {};
-}
-
-void test_page_alloc(u64 max_pages)
-{
-       struct page_block *upb_bak = unused_page_blocks;
-       int i;
-
-       u64 free_orders[MAX_ORDER + 1] = { 0 };
-       u64 used_orders[MAX_ORDER + 1] = { 0 };
-
-       test_orders(free_pages, free_orders);
-       test_orders(used_pages, used_orders);
-
-       /* Alloc 1GB of memory */
-
-       __init_free_region(0, (1 * 1024 * 1024 * 1024) >> PAGE_SHIFT);
-
-       /* Should create 128 blocks of 8M */
-       /* No allocations, obviously */
-
-       free_orders[MAX_ORDER] = 128;
-
-       test_orders(free_pages, free_orders);
-       test_orders(used_pages, used_orders);
-
-       test_order_index(free_pages[MAX_ORDER], 0, 0, 0);
-       test_order_index(free_pages[MAX_ORDER], 1, 0x800000, 0);
-       test_order_index(free_pages[MAX_ORDER], 2, 0x1000000, 0);
-
-       /* Reserve 0 - 4M, should split 1 8M block in 2 4M */
-       /* reserve_region won't record it on used_pages */
-
-       __reserve_region(0, 0x400);
-
-       free_orders[MAX_ORDER] = 127;
-       free_orders[MAX_ORDER - 1] = 1;
-
-       test_orders(free_pages, free_orders);
-       test_orders(used_pages, used_orders);
-
-       test_order_index(free_pages[MAX_ORDER], 0, 0x800000, 0);
-       test_order_index(free_pages[MAX_ORDER], 1, 0x1000000, 0);
-       test_order_index(free_pages[MAX_ORDER - 1], 0, 0x400000, 1);
-
-       /* Reserve 12M - 13M, should split the 8M - 16M
-        * block into 1 more 4M, 1 1M, and 1 2M block */
-
-       __reserve_region(0xc00000, 0x100);
-
-       free_orders[MAX_ORDER] = 126;
-       free_orders[MAX_ORDER - 1] = 2;
-       free_orders[MAX_ORDER - 2] = 1;
-       free_orders[MAX_ORDER - 3] = 1;
-
-       test_orders(free_pages, free_orders);
-       test_orders(used_pages, used_orders);
-
-       test_order_index(free_pages[MAX_ORDER], 0, 0x1000000, 0);
-       test_order_index(free_pages[MAX_ORDER], 1, 0x1800000, 0);
-       test_order_index(free_pages[MAX_ORDER - 1], 0, 0x400000, 0);
-       test_order_index(free_pages[MAX_ORDER - 1], 1, 0x800000, 1);
-
-       /* Now using page_alloc_phys should return the first two already
-        * split blocks
-        */
-
-       if(page_alloc_phys(MAX_ORDER - 1) != 0x400000)
-               while(1) {};
-
-       if(page_alloc_phys(MAX_ORDER - 1) != 0x800000)
-               while(1) {};
-
-       free_orders[MAX_ORDER - 1] = 0;
-       used_orders[MAX_ORDER - 1] = 2;
-
-       test_orders(free_pages, free_orders);
-       test_orders(used_pages, used_orders);
-
-       /* A third 4M alloc should split an 8M block and return its
-        * lower address
-        */
-
-       if(page_alloc_phys(MAX_ORDER - 1) != 0x1000000)
-               while(1) {};
-
-       free_orders[MAX_ORDER] -= 1;
-       free_orders[MAX_ORDER - 1] = 1;
-
-       used_orders[MAX_ORDER - 1] = 3;
-
-       test_orders(free_pages, free_orders);
-       test_orders(used_pages, used_orders);
-
-       test_order_index(free_pages[MAX_ORDER], 0, 0x1800000, 0);
-       test_order_index(free_pages[MAX_ORDER - 1], 0, 0x1400000, 1);
-
-       /* Now a free should properly reconstitute the 8M block */
-
-       page_alloc_free_phys(0x1000000);
-
-       free_orders[MAX_ORDER] += 1;
-       free_orders[MAX_ORDER - 1] = 0;
-
-       used_orders[MAX_ORDER - 1] = 2;
-
-       test_orders(free_pages, free_orders);
-       test_orders(used_pages, used_orders);
-
-       test_order_index(free_pages[MAX_ORDER], 0, 0x1000000, 0);
-
-       /* We're done, now reset our structures */
-
-       unused_page_blocks = upb_bak;
-       __init_unused_page_blocks(max_pages);
-
-       for (i = 0; i <= MAX_ORDER; i++) {
-               free_pages[i] = NULL;
-               used_pages[i] = NULL;
-       }
-}
-#endif
-
 struct grub_info *info = NULL;
 struct grub_mmap *mmap = NULL;
 
@@ -789,9 +634,7 @@ int page_alloc_init(struct grub_info *info_phys, u64 end_structures)
 
        __init_unused_page_blocks(max_pages);
 
-#ifdef TEST_PAGE_ALLOC
        test_page_alloc(max_pages);
-#endif
 
        /* Now put that reserved memory to use */
        __init_free_region(0, max_pages);
@@ -842,3 +685,156 @@ int page_alloc_init(struct grub_info *info_phys, u64 end_structures)
 
        return 0;
 }
+
+#ifdef TEST_PAGE_ALLOC
+static inline void test_orders(struct page_block **head, u64 *orders)
+{
+       struct page_block *block;
+       int counter = 0;
+       int i = 0;
+
+       for(i = 0; i <= MAX_ORDER; i++) {
+               counter = 0;
+               for (block = head[i]; block; block = block->next)
+                       counter++;
+
+               if (counter != orders[i])
+                       while(1);
+       }
+
+}
+
+static inline void test_order_index(struct page_block *block, u32 index, u64 address, u32 nextnull)
+{
+       int i;
+
+       for (i = 0; i < index; i++)
+               block = block->next;
+
+       if(block->address != address)
+               while(1) {};
+       if(nextnull && block->next)
+               while(1) {};
+       if(!nextnull && !block->next)
+               while(1) {};
+}
+
+static void test_page_alloc(u64 max_pages)
+{
+       struct page_block *upb_bak = unused_page_blocks;
+       int i;
+
+       u64 free_orders[MAX_ORDER + 1] = { 0 };
+       u64 used_orders[MAX_ORDER + 1] = { 0 };
+
+       test_orders(free_pages, free_orders);
+       test_orders(used_pages, used_orders);
+
+       /* Alloc 1GB of memory */
+
+       __init_free_region(0, (1 * 1024 * 1024 * 1024) >> PAGE_SHIFT);
+
+       /* Should create 128 blocks of 8M */
+       /* No allocations, obviously */
+
+       free_orders[MAX_ORDER] = 128;
+
+       test_orders(free_pages, free_orders);
+       test_orders(used_pages, used_orders);
+
+       test_order_index(free_pages[MAX_ORDER], 0, 0, 0);
+       test_order_index(free_pages[MAX_ORDER], 1, 0x800000, 0);
+       test_order_index(free_pages[MAX_ORDER], 2, 0x1000000, 0);
+
+       /* Reserve 0 - 4M, should split 1 8M block in 2 4M */
+       /* reserve_region won't record it on used_pages */
+
+       __reserve_region(0, 0x400);
+
+       free_orders[MAX_ORDER] = 127;
+       free_orders[MAX_ORDER - 1] = 1;
+
+       test_orders(free_pages, free_orders);
+       test_orders(used_pages, used_orders);
+
+       test_order_index(free_pages[MAX_ORDER], 0, 0x800000, 0);
+       test_order_index(free_pages[MAX_ORDER], 1, 0x1000000, 0);
+       test_order_index(free_pages[MAX_ORDER - 1], 0, 0x400000, 1);
+
+       /* Reserve 12M - 13M, should split the 8M - 16M
+        * block into 1 more 4M, 1 1M, and 1 2M block */
+
+       __reserve_region(0xc00000, 0x100);
+
+       free_orders[MAX_ORDER] = 126;
+       free_orders[MAX_ORDER - 1] = 2;
+       free_orders[MAX_ORDER - 2] = 1;
+       free_orders[MAX_ORDER - 3] = 1;
+
+       test_orders(free_pages, free_orders);
+       test_orders(used_pages, used_orders);
+
+       test_order_index(free_pages[MAX_ORDER], 0, 0x1000000, 0);
+       test_order_index(free_pages[MAX_ORDER], 1, 0x1800000, 0);
+       test_order_index(free_pages[MAX_ORDER - 1], 0, 0x400000, 0);
+       test_order_index(free_pages[MAX_ORDER - 1], 1, 0x800000, 1);
+
+       /* Now using page_alloc_phys should return the first two already
+        * split blocks
+        */
+
+       if(page_alloc_phys(MAX_ORDER - 1) != 0x400000)
+               while(1) {};
+
+       if(page_alloc_phys(MAX_ORDER - 1) != 0x800000)
+               while(1) {};
+
+       free_orders[MAX_ORDER - 1] = 0;
+       used_orders[MAX_ORDER - 1] = 2;
+
+       test_orders(free_pages, free_orders);
+       test_orders(used_pages, used_orders);
+
+       /* A third 4M alloc should split an 8M block and return its
+        * lower address
+        */
+
+       if(page_alloc_phys(MAX_ORDER - 1) != 0x1000000)
+               while(1) {};
+
+       free_orders[MAX_ORDER] -= 1;
+       free_orders[MAX_ORDER - 1] = 1;
+
+       used_orders[MAX_ORDER - 1] = 3;
+
+       test_orders(free_pages, free_orders);
+       test_orders(used_pages, used_orders);
+
+       test_order_index(free_pages[MAX_ORDER], 0, 0x1800000, 0);
+       test_order_index(free_pages[MAX_ORDER - 1], 0, 0x1400000, 1);
+
+       /* Now a free should properly reconstitute the 8M block */
+
+       page_alloc_free_phys(0x1000000);
+
+       free_orders[MAX_ORDER] += 1;
+       free_orders[MAX_ORDER - 1] = 0;
+
+       used_orders[MAX_ORDER - 1] = 2;
+
+       test_orders(free_pages, free_orders);
+       test_orders(used_pages, used_orders);
+
+       test_order_index(free_pages[MAX_ORDER], 0, 0x1000000, 0);
+
+       /* We're done, now reset our structures */
+
+       unused_page_blocks = upb_bak;
+       __init_unused_page_blocks(max_pages);
+
+       for (i = 0; i <= MAX_ORDER; i++) {
+               free_pages[i] = NULL;
+               used_pages[i] = NULL;
+       }
+}
+#endif