This hardcodes the AP boot address to 0x11000 so that we do not need
to patch the ljmp absolute address in the code segment at runtime when flushing
the gdt.
This is safer so code segment remains read-only.
Also becomes easier to write 64 bit AP bringup.
---
i386/Makefrag.am | 3 +++
i386/i386/cpuboot.S | 41 +++++++++++++++++++----------------------
i386/i386/i386asm.sym | 3 +++
i386/i386/model_dep.h | 7 +++----
i386/i386/mp_desc.c | 13 ++++++-------
i386/i386at/biosmem.c | 7 +++----
i386/i386at/boothdr.S | 23 +++++++++--------------
i386/i386at/model_dep.c | 19 ++++---------------
i386/ldscript | 15 +++++++++++++++
x86_64/Makefrag.am | 2 ++
x86_64/boothdr.S | 22 +++++++++-------------
x86_64/ldscript | 15 +++++++++++++++
12 files changed, 91 insertions(+), 79 deletions(-)
diff --git a/i386/Makefrag.am b/i386/Makefrag.am
index 906ccc2d..f8792030 100644
--- a/i386/Makefrag.am
+++ b/i386/Makefrag.am
@@ -165,10 +165,13 @@ nodist_libkernel_a_SOURCES += \
# Architecture specialities.
#
+SIPI_AP_ADDR=0x11000
+
if PLATFORM_at
gnumach_LINKFLAGS += \
--defsym _START_MAP=$(_START_MAP) \
--defsym _START=_START_MAP+0xC0000000 \
+ --defsym SIPI_AP_ADDR=$(SIPI_AP_ADDR) \
-T '$(srcdir)'/i386/ldscript
endif
diff --git a/i386/i386/cpuboot.S b/i386/i386/cpuboot.S
index 76de8714..94280de6 100644
--- a/i386/i386/cpuboot.S
+++ b/i386/i386/cpuboot.S
@@ -34,7 +34,7 @@
#define GDT_DESCR_M32 4
#define GDT_TABLE_M32 (14*2)
-.data
+.section .data
.align 16
apboot_idt_ptr:
@@ -98,20 +98,24 @@ apboot_gdt:
/* boot GS = 0x68 */
.word 0xffff
apboot_percpu_low:
- .word 0
+ .word (-KERNELBASE) & 0xffff
apboot_percpu_med:
- .byte 0
+ .byte ((-KERNELBASE) >> 16) & 0xff
.byte ACC_PL_K | ACC_DATA_W | ACC_P
.byte ((SZ_32 | SZ_G) << 4) | 0xf
apboot_percpu_high:
- .byte 0
+ .byte ((-KERNELBASE) >> 24) & 0xff
/* Empty space for per-cpu gdt descriptor and gdt */
.space (NCPUS-1) * (GDT_DESCR_M32 + GDT_TABLE_M32) * 4, 0x0
-.globl apboot, apbootend, gdt_descr_tmp, apboot_jmp_offset
-.align 16
-.code16
+/* NOTE: apboot16 section is auto-loaded at runtime to just above 64k
+ * so it can be called as a SIPI vector. Relocations are thus computed simply.
+ */
+.section .apboot16.text,"ax",@progbits
+.globl apboot, apbootend
+.align 4096
+ .code16
apboot:
_apboot:
@@ -137,15 +141,14 @@ _apboot:
orl $CR0_SET_FLAGS, %eax
movl %eax, %cr0
- /* ljmpl with relocation from machine_init */
+ /* ljmpl with no relocation */
.byte 0x66
.byte 0xea
-apboot_jmp_offset:
- .long M(0f)
+ .long 0f
.word BOOT_CS
-0:
.code32
+0:
/* Protected mode! */
movw $BOOT_DS, %ax
movw %ax, %ds
@@ -153,13 +156,8 @@ apboot_jmp_offset:
movw %ax, %ss
lgdtl apboot_gdt_descr - KERNELBASE
- ljmpl $KERNEL_CS, $1f
+ ljmpl $KERNEL_CS, $(1f + KERNELBASE)
1:
- xorl %eax, %eax
- movw %ax, %ds
- movw %ax, %es
- movw %ax, %fs
- movw %ax, %gs
movw $KERNEL_DS, %ax
movw %ax, %ds
movw %ax, %es
@@ -213,14 +211,13 @@ apboot_jmp_offset:
/* Reload our copy of gdt */
lgdtl apboot_gdt_descr(%eax)
- ljmpl $KERNEL_CS, $2f
+ ljmpl $KERNEL_CS, $(2f + KERNELBASE)
2:
-
movw $PERCPU_DS, %ax
movw %ax, %gs
/* Load null Interrupt descriptor table */
- mov apboot_idt_ptr, %ebx
+ movl $apboot_idt_ptr, %ebx
lidt (%ebx)
/* Enable local apic in xAPIC mode */
@@ -245,7 +242,7 @@ apboot_jmp_offset:
popfl
/* Finish the cpu configuration */
- call EXT(cpu_ap_main)
+ call EXT(cpu_ap_main) - KERNELBASE
3:
/* NOT REACHED */
@@ -256,7 +253,7 @@ apboot_jmp_offset:
.word 0
gdt_descr_tmp:
.short 3*8-1
- .long M(gdt_tmp)
+ .long gdt_tmp
.align 16
gdt_tmp:
diff --git a/i386/i386/i386asm.sym b/i386/i386/i386asm.sym
index e1f5c6bb..d9c51f04 100644
--- a/i386/i386/i386asm.sym
+++ b/i386/i386/i386asm.sym
@@ -45,6 +45,7 @@
#include <i386/gdt.h>
#include <i386/ldt.h>
#include <i386/mp_desc.h>
+#include <i386/model_dep.h>
#include <i386/apic.h>
#include <i386/xen.h>
@@ -132,6 +133,8 @@ offset i386_tss tss ss0
offset machine_slot sub_type cpu_type
+expr SIPI_AP_ADDR
+expr SIPI_AP_LENGTH
expr I386_PGBYTES NBPG
expr VM_MIN_ADDRESS
expr VM_MAX_ADDRESS
diff --git a/i386/i386/model_dep.h b/i386/i386/model_dep.h
index 5369e288..62532215 100644
--- a/i386/i386/model_dep.h
+++ b/i386/i386/model_dep.h
@@ -28,10 +28,9 @@
#include <mach/std_types.h>
-/*
- * Address to hold AP boot code, held in ASM
- */
-extern phys_addr_t apboot_addr;
+/* Hardcoded AP boot code address */
+#define SIPI_AP_ADDR 0x11000
+#define SIPI_AP_LENGTH (0x20000 - SIPI_AP_ADDR)
/*
* Find devices. The system is alive.
diff --git a/i386/i386/mp_desc.c b/i386/i386/mp_desc.c
index e67aa767..b6778531 100644
--- a/i386/i386/mp_desc.c
+++ b/i386/i386/mp_desc.c
@@ -45,6 +45,7 @@
#include <i386at/int_init.h>
#include <i386/cpu.h>
#include <i386/smp.h>
+#include <i386/model_dep.h>
#include <i386at/model_dep.h>
#include <machine/ktss.h>
@@ -95,10 +96,11 @@ interrupt_stack_alloc(void)
}
#if NCPUS > 1
-phys_addr_t apboot_addr;
-extern void *apboot, *apbootend;
extern volatile ApicLocalUnit* lapic;
+/* This is needed to stop the linker dropping the .apboot16 section. */
+extern uint32_t *apboot;
+
/*
* Multiprocessor i386/i486 systems use a separate copy of the
* GDT, IDT, LDT, and kernel TSS per processor. The first three
@@ -282,13 +284,10 @@ start_other_cpus(void)
if (ncpus == 1)
return;
- //Copy cpu initialization assembly routine
- memcpy((void*) phystokv(apboot_addr), (void*) &apboot,
- (uint32_t)&apbootend - (uint32_t)&apboot);
-
unsigned cpu = cpu_number_slow();
assert (cpu == 0);
+ assert (phystokv(&apboot) != 0);
splhigh();
@@ -310,7 +309,7 @@ start_other_cpus(void)
machine_slot[cpu].running = FALSE;
}
- smp_startup_cpus(apic_get_current_cpu(), apboot_addr);
+ smp_startup_cpus(apic_get_current_cpu(), SIPI_AP_ADDR);
for (cpu = 1; cpu < ncpus; cpu++) {
printf("Waiting for AP %d\n", cpu);
diff --git a/i386/i386at/biosmem.c b/i386/i386at/biosmem.c
index 7cf7e171..e117a359 100644
--- a/i386/i386at/biosmem.c
+++ b/i386/i386at/biosmem.c
@@ -690,12 +690,11 @@ biosmem_bootstrap_common(void)
boot_panic(biosmem_panic_noseg_msg);
#if !defined(MACH_HYP) && NCPUS > 1
- /*
- * Grab an early page for AP boot code which needs to be below 1MB.
- */
assert (phys_start < 0x100000);
- apboot_addr = phys_start;
+ /* Grab an early page for multiboot header. */
phys_start += PAGE_SIZE;
+ /* Skip over AP boot code. */
+ phys_start += SIPI_AP_LENGTH;
#endif
biosmem_set_segment(VM_PAGE_SEG_DMA, phys_start, phys_end);
diff --git a/i386/i386at/boothdr.S b/i386/i386at/boothdr.S
index ff055746..69efdbdc 100644
--- a/i386/i386at/boothdr.S
+++ b/i386/i386at/boothdr.S
@@ -12,20 +12,10 @@
#endif /* __ELF__ */
#define MULTIBOOT_FLAGS MULTIBOOT_PAGE_ALIGN | MULTIBOOT_MEMORY_INFO |
MULTIBOOT_VIDEO_MODE | AOUT_KLUDGE
- /*
- * This section will be put first into .text. See also i386/ldscript.
- */
- .section .text.start,"ax"
-
- /* We should never be entered this way. */
- .globl start,_start
-start:
-_start:
- jmp boot_entry
-
- /* MultiBoot header - see multiboot.h. */
- P2ALIGN(2)
+ .section .multiboot,"ax",@progbits
+ .align 8
boot_hdr:
+ /* MultiBoot header - see multiboot.h. */
.long MULTIBOOT_MAGIC
.long MULTIBOOT_FLAGS
/*
@@ -51,7 +41,12 @@ boot_hdr:
.long 25
.long MULTIBOOT_VIDEO_PARAM_NO_PREFERENCE
-boot_entry:
+ .section .text,"ax",@progbits
+ .globl boot_start
+ .global _start
+boot_start:
+_start:
+ .code32
movl $percpu_array - KERNELBASE, %eax
movw %ax, boot_percpu_low - KERNELBASE
shr $16, %eax
diff --git a/i386/i386at/model_dep.c b/i386/i386at/model_dep.c
index e713cc8a..14518e3e 100644
--- a/i386/i386at/model_dep.c
+++ b/i386/i386at/model_dep.c
@@ -127,12 +127,6 @@ char *kernel_cmdline = "";
extern char version[];
-/* Realmode temporary GDT */
-extern struct pseudo_descriptor gdt_descr_tmp;
-
-/* Realmode relocated jmp */
-extern uint32_t apboot_jmp_offset;
-
/* If set, reboot the system on ctrl-alt-delete. */
boolean_t rebootflag = FALSE; /* exported to kdintr */
@@ -217,15 +211,6 @@ void machine_init(void)
pmap_unmap_page_zero();
#endif
-#if NCPUS > 1
- /*
- * Patch the realmode gdt with the correct offset and the first jmp to
- * protected mode with the correct target.
- */
- gdt_descr_tmp.linear_base += apboot_addr;
- apboot_jmp_offset += apboot_addr;
-#endif
-
#ifdef APIC
/*
* Initialize the HPET
@@ -390,6 +375,10 @@ i386at_init(void)
#ifdef MACH_HYP
biosmem_xen_bootstrap();
#else /* MACH_HYP */
+#if NCPUS > 1
+ /* Register one page for multiboot header plus the rest for AP boot
code */
+ biosmem_register_boot_data(SIPI_AP_ADDR - PAGE_SIZE, SIPI_AP_ADDR +
SIPI_AP_LENGTH, FALSE);
+#endif
register_boot_data((struct multiboot_raw_info *) &boot_info);
biosmem_bootstrap((struct multiboot_raw_info *) &boot_info);
#endif /* MACH_HYP */
diff --git a/i386/ldscript b/i386/ldscript
index ddbbf910..1335653a 100644
--- a/i386/ldscript
+++ b/i386/ldscript
@@ -11,6 +11,21 @@ SECTIONS
* be first in there. See also `i386/i386at/boothdr.S' and
* `gnumach_LINKFLAGS' in `i386/Makefrag.am'.
*/
+ . = SIPI_AP_ADDR - 1024;
+ .multiboot : AT(SIPI_AP_ADDR - 1024)
+ {
+ /* The MultiBoot header section */
+ KEEP (*(.multiboot))
+ }
+
+ . = SIPI_AP_ADDR;
+ .apboot16 : AT(SIPI_AP_ADDR)
+ {
+ /* A realmode section for starting APs */
+ KEEP (*(.apboot16.text))
+ KEEP (*(.apboot16.data))
+ } =0x90909090
+
. = _START;
.text :
AT (_START_MAP)
diff --git a/x86_64/Makefrag.am b/x86_64/Makefrag.am
index e0d4d2f9..1fc3bcfd 100644
--- a/x86_64/Makefrag.am
+++ b/x86_64/Makefrag.am
@@ -207,6 +207,7 @@ endif
#
KERNEL_MAP_BASE=0xffffffff80000000
+SIPI_AP_ADDR=0x11000
if PLATFORM_at
# For now simply keep all the kernel virtual space in the last 2G.
@@ -218,6 +219,7 @@ gnumach_LINKFLAGS += \
--defsym _START_MAP=$(_START_MAP) \
--defsym _START=$(_START_MAP) \
--defsym KERNEL_MAP_SHIFT=$(KERNEL_MAP_BASE) \
+ --defsym SIPI_AP_ADDR=$(SIPI_AP_ADDR) \
-z max-page-size=0x1000 \
-T '$(srcdir)'/x86_64/ldscript
diff --git a/x86_64/boothdr.S b/x86_64/boothdr.S
index abccec9a..88a77315 100644
--- a/x86_64/boothdr.S
+++ b/x86_64/boothdr.S
@@ -24,22 +24,14 @@
#include <i386/i386/msr.h>
#include <i386/i386/seg.h>
#include <i386/apic.h>
- /*
- * This section will be put first into .boot. See also x86_64/ldscript.
- */
- .section .boot.text,"ax"
- /* We should never be entered this way. */
- .globl boot_start
-boot_start:
- .code32
- jmp boot_entry
-
- /* MultiBoot header - see multiboot.h. */
#define MULTIBOOT_MAGIC 0x1BADB002
#define MULTIBOOT_FLAGS 0x00000003
- P2ALIGN(2)
+
+ .section .multiboot,"ax"
+ .align 8
boot_hdr:
+ /* MultiBoot header - see multiboot.h. */
.long MULTIBOOT_MAGIC
.long MULTIBOOT_FLAGS
/*
@@ -48,9 +40,13 @@ boot_hdr:
*/
.long - (MULTIBOOT_MAGIC+MULTIBOOT_FLAGS)
+ .section .boot.text,"ax"
+ .globl boot_start
.global _start
+boot_start:
_start:
-boot_entry:
+ .code32
+
/* Enable local apic in xAPIC mode */
xorl %eax, %eax
xorl %edx, %edx
diff --git a/x86_64/ldscript b/x86_64/ldscript
index 67703b4d..2e371cd0 100644
--- a/x86_64/ldscript
+++ b/x86_64/ldscript
@@ -12,6 +12,21 @@ SECTIONS
* `gnumach_LINKFLAGS' in `i386/Makefrag.am'.
*/
+ . = SIPI_AP_ADDR - 1024;
+ .multiboot : AT(SIPI_AP_ADDR - 1024)
+ {
+ /* The MultiBoot header section */
+ KEEP (*(.multiboot))
+ }
+
+ . = SIPI_AP_ADDR;
+ .apboot16 : AT(SIPI_AP_ADDR)
+ {
+ /* A realmode section for starting APs */
+ KEEP (*(.apboot16.text))
+ KEEP (*(.apboot16.data))
+ } =0x90909090
+
. = _START;
.boot : AT(_START_MAP)
{
--
2.45.2