arch/x86_64: Terrible, awful hackery to bootstrap entry
Because of a historical misunderstanding, by default the ACRN hypervisor wants to load Zephyr at address 0x1000 and enter the binary at that same address. This entry point corresponds to the __start symbol of the build they were given, which is a 1-cpu non-SMP configuration. Unfortunately, when we build with CONFIG_MP_NUM_CPUS=1, the code in locore.S #if's out the 16 bit entry point for the auxiliary CPUs at the start of the section. So in the build ACRN received, the start address happened to be 0x7000, the same address we need to launch the AP processors from. That's right: under ACRN, the SAME ADDRESS used to enter the OS in 32 bit mode needs to be used later to boot CPUs running in 16 bit real mode! The solution, such as it is, is to put a 32 bit jump at the entry address which hops to the 32 bit OS entry code, and then scribble NOP instructions over that jump once we get there so that the next time we reach that address (in real mode) we fall through to the correct entry. This patch should be considered a temporary workaround. While it works on all x86 hardware, it's not really needed. A much better solution would be to eliminate the locore linker region entirely (which causes other headaches) and enter the Zephyr binary in a 32 bit address somewhere in the contiguous high memory area. All that locore is needed for is the 16 bit bootstrap code for SMP processors, which is ~6 instructions and can be copied in from the kernel at runtime. Signed-off-by: Andy Ross <andrew.j.ross@intel.com>
This commit is contained in:
parent
d6a3679c97
commit
5e9c583c24
1 changed files with 45 additions and 8 deletions
|
@ -78,15 +78,41 @@
|
|||
movq %rax, %cr0
|
||||
.endm
|
||||
|
||||
/* The .locore section begins the page-aligned initialization region
|
||||
* of low memory. The first address is used as the architectural
|
||||
* entry point for auxiliary CPUs being brought up (in real mode!)
|
||||
* via a startup IPI. It's is ALSO used by some loaders (well,
|
||||
* ACRN...) who hard-coded the address by inspecting _start on a
|
||||
* non-SMP build.
|
||||
*
|
||||
* === OUTRAGEOUS HACK FOLLOWS ===
|
||||
*
|
||||
* Therefore it needs to start at OS entry with a 32 bit jump to the
|
||||
* 32 bit entry point, and gets clobbered later (see the beginning of
|
||||
* __start32) with NOP bytes such that the next CPU will fall through
|
||||
* to the 16 bit SMP entry.
|
||||
*
|
||||
* We write out the JMP followed by 8 NOPs for simplicity. No i386
|
||||
* JMP encodes with more than 8 bytes, so we can come back later and
|
||||
* scribble over it with 8 0x90 bytes (which is the 1-byte NOP) and be
|
||||
* sure to get all of it without overwriting anything.
|
||||
*/
|
||||
.section .locore,"ax"
|
||||
.code32
|
||||
.globl __start
|
||||
__start:
|
||||
jmp __start32
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
|
||||
#if CONFIG_MP_NUM_CPUS > 1
|
||||
|
||||
/*
|
||||
* APs are sent here on startup, in real mode. This
|
||||
* is first because we want it on a page boundary.
|
||||
*/
|
||||
|
||||
.code16
|
||||
.global x86_ap_start
|
||||
x86_ap_start:
|
||||
|
@ -133,14 +159,25 @@ unknown_loapic_id:
|
|||
#endif /* CONFIG_MP_NUM_CPUS > 1 */
|
||||
|
||||
.code32
|
||||
.globl __start
|
||||
__start:
|
||||
.globl __start32
|
||||
__start32:
|
||||
/*
|
||||
* kernel execution begins here in 32-bit mode, with flat-mode
|
||||
* descriptors in all segment registers, interrupts disabled.
|
||||
* first, let common code do things like detect multiboot info.
|
||||
*/
|
||||
|
||||
/* See note above, re: OUTRAGEOUS HACK */
|
||||
movl $__start, %ebp
|
||||
movb $0x90, 0(%ebp)
|
||||
movb $0x90, 1(%ebp)
|
||||
movb $0x90, 2(%ebp)
|
||||
movb $0x90, 3(%ebp)
|
||||
movb $0x90, 4(%ebp)
|
||||
movb $0x90, 5(%ebp)
|
||||
movb $0x90, 6(%ebp)
|
||||
movb $0x90, 7(%ebp)
|
||||
wbinvd
|
||||
|
||||
lgdt gdt48
|
||||
lidt idt48
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue