Derive CPU stack address in realmode stub
authorJack Miller <jack@codezen.org>
Wed, 6 Apr 2016 05:51:53 +0000 (00:51 -0500)
committerJack Miller <jack@codezen.org>
Wed, 6 Apr 2016 05:51:53 +0000 (00:51 -0500)
This resolves a potential race condition where the boot thread writes
another stack value before the awakened thread reads it. All of the
other realmode header values are constant for all threads.

asm/realmode.asm-bin
include/apic.h
include/asm/realmode.h
kernel/apic.c
kernel/smp.c

index fbcb683..1a25899 100644 (file)
@@ -26,6 +26,7 @@
  */
 
 #include <memmap.h>
+#include <apic.h>
 
 #include <asm/gdt.h>
 #include <asm/realmode.h>
@@ -44,8 +45,6 @@ crthree:
     DD 0
 gdtr:
     DQ 0
-stackpointer:
-    DQ 0
 kernel_entry:
     DQ 0
 
@@ -68,6 +67,23 @@ host_local_gdt:
     mov fs, ax
     mov gs, ax
 
+    /* While we're in 32 bit pmode, grab our APIC ID */
+
+    /* NOTE: The APIC is still in xapic mode, so the lower 8 bits
+     * of the ID are in the high 8 bits of the register, but if I 
+     * understand the docs, the full 32 bit value is indeed in place.
+     * Needs testing with > 256 IDs.
+     */
+
+    mov ecx, MSR_IA32_APIC_BASE
+    rdmsr
+
+    and eax, BASE_ADDR_MASK
+    add eax, MMIO_OFFSET(APIC_ID)
+
+    mov edi, [eax]
+    rol edi, 8
+
     /* This init is taken from head.asm */
 
     /* PAE */
@@ -110,9 +126,15 @@ kernel_gdt:
     mov fs, ax
     mov gs, ax
 
-    /* Grab our stack pointer, and get into C */
+    mov rcx, KERNEL_STACK_VIRTUAL
+
+    mov rax, rdi
+    mov rdx, STACK_V_SIZE
+    mul rdx
 
-    mov rsp, [stackpointer]
+    or rcx, rax
+    add rcx, (STACK_SIZE - 8)
+    mov rsp, rcx
 
     jmp [kernel_entry]
 
index 1bc562b..1ff6f97 100644 (file)
@@ -1,13 +1,67 @@
 /* vim: set ts=4 sw=4 sts=4 et : */
 #pragma once
 
+#define CPUID_X2APIC   (1 << 21)
+#define CPUID_LAPIC            (1 << 9)
+
+#define MSR_IA32_APIC_BASE                     0x1B
+#define     BASE_ADDR_MASK          (~0xFFF)
+#define                XAPIC_ENABLE                    (1 << 11)
+#define                XAPIC_EXTD                              (1 << 10)
+
+#define APIC_ID                                                0x2
+#define                ID(x)                                   ((x) >> 24)
+
+#define APIC_EOI                                       0xb
+
+#define APIC_SVR                                       0xf
+#define                SVR_APIC_EN                             (1 << 8)
+
+#define APIC_ESR                                       0x28
+
+#define APIC_ICRL                                      0x30
+#define                ICRL_DSH(x)                             ((x & 0x3) << 18)
+#define                        DSH_ALL_EX_SELF         0x3
+#define                        DSH_ALL_IN_SELF         0x2
+#define                ICRL_MT(x)                              ((x & 0x7) << 8)
+#define                        MT_INIT                         0x5
+#define                        MT_STARTUP                      0x6
+#define                ICRL_VEC(x)                             (x & 0xFF)
+#define                ICRL_DM                                 (1 << 11)
+#define                ICRL_BUSY                               (1 << 12)
+#define                ICRL_ASSERT                             (1 << 14)
+#define                ICRL_TRIGGER_LEVEL              (1 << 15)
+#define APIC_ICRH                                      0x31
+#define                ICRH_DEST(x)                    ((x & 0xFF) << 24)
+#define APIC_LVT_TIMER                         0x32
+#define                LVT_TIMER_PERIODIC              (1 << 17)
+#define                LVT_VECTOR(x)                   (x & 0xff)
+#define                LVT_MASKED                              (1 << 16)
+
+#define APIC_LVT3                                      0x37
+#define        APIC_TIMER_INIT_CT                      0x38
+#define APIC_TIMER_CUR_CT                      0x39
+#define APIC_TIMER_DIV                         0x3e
+
+/*
+ * X2APIC uses MSRs, offset from the base register
+ *
+ * XAPIC uses MMIO, offset is based on 16 byte indexes into the region
+ */
+
+#define MSR_X2APIC_BASE                                0x800
+#define MSR_OFFSET(x)                          (MSR_X2APIC_BASE | (x))
+#define MMIO_OFFSET(x)                         ((x) << 4)
+
+#ifndef __ASSEMBLY__
+
 struct apic {
     void (*init) (void);
     void (*eoi) (void);
     void (*wake_secondary) (u8 apic_id);
     void (*start_timer) (void);
-     u8(*get_id) (void);
-     u32(*read) (u32 offset);
+     u32 (*get_id) (void);
+     u32 (*read) (u32 offset);
     void (*write) (u32 offset, u32 val);
     void (*write_icr) (u32 dest, u32 val);
     void (*wait) (void);
@@ -22,3 +76,5 @@ static inline void disable_pic(void)
 int apic_init(void);
 
 struct apic *apic;
+
+#endif
index 31090b4..8c92851 100644 (file)
@@ -12,7 +12,6 @@ struct rm_header {
     u8 jmp[2];                  /* Two bytes for the jump over data */
     u32 cr3;
     u64 gdtr;
-    u64 sp;
     u64 kernel_entry;
 } __attribute__ ((packed));
 
index 75c767b..755b6fd 100644 (file)
 #include <asm/mmio.h>
 #include <asm/msr.h>
 
-#define CPUID_X2APIC   (1 << 21)
-#define CPUID_LAPIC            (1 << 9)
-
-#define MSR_IA32_APIC_BASE                     0x1B
-#define                XAPIC_ENABLE                    (1 << 11)
-#define                XAPIC_EXTD                              (1 << 10)
-
-#define APIC_ID                                                0x2
-#define                ID(x)                                   ((x) >> 24)
-
-#define APIC_EOI                                       0xb
-
-#define APIC_SVR                                       0xf
-#define                SVR_APIC_EN                             (1 << 8)
-
-#define APIC_ESR                                       0x28
-
-#define APIC_ICRL                                      0x30
-#define                ICRL_DSH(x)                             ((x & 0x3) << 18)
-#define                        DSH_ALL_EX_SELF         0x3
-#define                        DSH_ALL_IN_SELF         0x2
-#define                ICRL_MT(x)                              ((x & 0x7) << 8)
-#define                        MT_INIT                         0x5
-#define                        MT_STARTUP                      0x6
-#define                ICRL_VEC(x)                             (x & 0xFF)
-#define                ICRL_DM                                 (1 << 11)
-#define                ICRL_BUSY                               (1 << 12)
-#define                ICRL_ASSERT                             (1 << 14)
-#define                ICRL_TRIGGER_LEVEL              (1 << 15)
-#define APIC_ICRH                                      0x31
-#define                ICRH_DEST(x)                    ((x & 0xFF) << 24)
-#define APIC_LVT_TIMER                         0x32
-#define                LVT_TIMER_PERIODIC              (1 << 17)
-#define                LVT_VECTOR(x)                   (x & 0xff)
-#define                LVT_MASKED                              (1 << 16)
-
-#define APIC_LVT3                                      0x37
-#define        APIC_TIMER_INIT_CT                      0x38
-#define APIC_TIMER_CUR_CT                      0x39
-#define APIC_TIMER_DIV                         0x3e
-
-/* 
- * X2APIC uses MSRs, offset from the base register
- *
- * XAPIC uses MMIO, offset is based on 16 byte indexes into the region
- */
-
-#define MSR_X2APIC_BASE                                0x800
-#define MSR_OFFSET(x)                          (MSR_X2APIC_BASE | (x))
-#define MMIO_OFFSET(x)                         ((x) << 4)
-
 static volatile u64 *mmio_mem = NULL;
 
 static void apic_init_common(void)
@@ -181,7 +130,7 @@ static void xapic_write_icr(u32 dest, u32 val)
     apic->write(APIC_ICRL, val);
 }
 
-static u8 xapic_get_id(void)
+static u32 xapic_get_id(void)
 {
     return ID(apic->read(APIC_ID));
 }
@@ -231,7 +180,7 @@ static void x2apic_write_icr(u32 dest, u32 val)
     wrmsr(MSR_OFFSET(APIC_ICRL), ((u64) dest << 32) | val);
 }
 
-static u8 x2apic_get_id(void)
+static u32 x2apic_get_id(void)
 {
     return apic->read(APIC_ID);
 }
index 2462847..7446121 100644 (file)
@@ -29,7 +29,6 @@ void smp_wake(u32 apic_id)
 
         page_alloc_to_virtual(STACK_ADDR_CPU(apic_id), STACK_PAGES_ORDER);
 
-        realboot->sp = STACK_TOP_CPU(apic_id);
         apic->wake_secondary(apic_id);
     }
 }