Patrick Rudolph has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/81371?usp=email )
Change subject: [WIP]arch/x86: Support x86_64 kernel entry ......................................................................
[WIP]arch/x86: Support x86_64 kernel entry
- Call payload in long mode when necessary. - Detect long mode in linux trampoline and call 64-bit kernel entry point. - Modify x86 code to run in long and protected mode
TODO: Use different approach? - Detect x86_64 support in cbfstool? - Detect long mode at trampoline entry and duplicate code?
Change-Id: Ia5e28bc61e759d14140b44ca738a03d4fdff7fdc Signed-off-by: Patrick Rudolph patrick.rudolph@9elements.com --- M payloads/Kconfig M src/arch/x86/boot.c M util/cbfstool/linux_trampoline.S M util/cbfstool/linux_trampoline.c 4 files changed, 113 insertions(+), 37 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/71/81371/1
diff --git a/payloads/Kconfig b/payloads/Kconfig index ec1d40c..d3fa580 100644 --- a/payloads/Kconfig +++ b/payloads/Kconfig @@ -92,6 +92,17 @@ coreboot can compress them using the LZ4 algorithm. endchoice
+config PAYLOAD_ELF_X86_32 + bool "Payload is an x86_32 executable" + depends on PAYLOAD_FILE + depends on ARCH_X86 + depends on USE_EXP_X86_64_SUPPORT + default n + help + Select this option if you have a payload image (an ELF file) + which coreboot should run in 32-bits (protected mode). + When false the payload is run in 64-bits (long mode). + config PAYLOAD_OPTIONS string "Additional cbfstool options" if PAYLOAD_FLAT_BINARY default "" diff --git a/src/arch/x86/boot.c b/src/arch/x86/boot.c index 90af84f..130a0dd 100644 --- a/src/arch/x86/boot.c +++ b/src/arch/x86/boot.c @@ -21,7 +21,7 @@
void arch_prog_run(struct prog *prog) { -#if ENV_RAMSTAGE && ENV_X86_64 +#if ENV_RAMSTAGE && ENV_X86_64 && CONFIG(PAYLOAD_ELF_X86_32) const uint32_t arg = pointer_to_uint32_safe(prog_entry_arg(prog)); const uint32_t entry = pointer_to_uint32_safe(prog_entry(prog));
diff --git a/util/cbfstool/linux_trampoline.S b/util/cbfstool/linux_trampoline.S index 6a62ff0..c9369e8 100644 --- a/util/cbfstool/linux_trampoline.S +++ b/util/cbfstool/linux_trampoline.S @@ -17,8 +17,10 @@
#define ACPI_RSDP_ADDR 0x70 #define E820_NR_OFFSET 0x1e8 +#define LINUX_CODE64_START 0x200 #define PROTOCOL_VERSION 0x206 -#define LINUX_ENTRY_OFFSET 0x214 +#define LINUX_CODE32_START 0x214 +#define XLOADFLAGS 0x236 #define E820_OFFSET 0x2d0
.trampoline_start: @@ -66,7 +68,8 @@ * the year 2005 (Linux 2.6.11) to hold up to 128 entries. * Assume 128 entries when the boot protocol version is 2.04+. */ -cmpw $0x0204, (LINUX_PARAM_LOC + PROTOCOL_VERSION) +mov $(LINUX_PARAM_LOC + PROTOCOL_VERSION), %edi +cmpw $0x0204, (%edi) jge .e820big /* protocol version >= 2.04 can handle 128 entries of 5 dwords */ cmp $(32 * 5), %eax /* linux wants at most 32 entries of 5 dwords */ jng 1f @@ -81,15 +84,18 @@ mov %eax, %esi mov $5, %edi div %edi -mov %eax, (LINUX_PARAM_LOC + E820_NR_OFFSET) +mov $(LINUX_PARAM_LOC + E820_NR_OFFSET), %edi +mov %eax, (%edi) mov %esi, %eax xchg %eax, %ecx lea 8(%ebx), %esi /* e820 data source */ mov $(LINUX_PARAM_LOC + E820_OFFSET), %edi rep movsl xchg %eax, %ecx + /* e820 and LB_TAG_MEMORY type don't fully match: remap unknown type to 2, reserved memory */ -mov (LINUX_PARAM_LOC + E820_NR_OFFSET), %eax +mov $(LINUX_PARAM_LOC + E820_NR_OFFSET), %edi +mov (%edi), %eax mov $(LINUX_PARAM_LOC + E820_OFFSET), %edi .test_e820_entry: cmp $0, %eax @@ -99,7 +105,7 @@ /* Fixup the type to 2, reserved memory */ mov $2, 16(%edi) .next_e820_entry: -dec %eax +sub $1, %eax add $20, %edi jmp .test_e820_entry
@@ -108,16 +114,18 @@ jne .testFramebuffer
mov 8(%ebx), %eax -mov %eax, (LINUX_PARAM_LOC + ACPI_RSDP_ADDR) +mov $(LINUX_PARAM_LOC + ACPI_RSDP_ADDR), %edi +mov %eax, (%edi) mov 12(%ebx), %eax -mov %eax, (LINUX_PARAM_LOC + ACPI_RSDP_ADDR + 4) +mov %eax, 4(%edi) jmp .endScan
.testFramebuffer: cmp $CB_TAG_FRAMEBUFFER, (%ebx) jne .endScan
-cmpw $0x020f, (LINUX_PARAM_LOC + PROTOCOL_VERSION) +mov $(LINUX_PARAM_LOC + PROTOCOL_VERSION), %edi +cmpw $0x020f, (%edi) jge .framebufferSetup /* protocol version >= 2.15 can handle 64-bit address */ cmpl $0, 0x0c(%ebx) /* check if upper 32-bit of framebuffer address are 0 */ jne .endScan @@ -146,7 +154,7 @@ mov 0x1b(%ebx, %esi, 2), %ax rol %ax /* Order is reversed for Linux, hence swap. */ mov %ax, 0x24(%edi, %esi, 2) -dec %esi +sub $1, %esi jnz 1b
#define VIDEO_CAPABILITY_64BIT_BASE (1 << 1) @@ -157,11 +165,13 @@
.endScan: add 4(%ebx), %ebx -dec %ecx +sub $1, %ecx jnz .tableScan
/* Setup basic code and data segment selectors for Linux ** +** Keep in sync with arch/x86/include/arch/ram_segs.h! +** ** Flat code segment descriptor: ** selector: 0x10 ** base : 0x00000000 @@ -174,22 +184,71 @@ ** limit : 0xFFFFFFFF ** type : data, read/write ** +** Flat x64 code segment descriptor: +** selector: 0x48 +** base : 0x00000000 +** limit : 0xFFFFFFFF +** type : data, read/write +** ** Use TRAMPOLINE_ENTRY_LOC as a scratchpad. */ mov $TRAMPOLINE_ENTRY_LOC, %eax -movl $0x0000ffff, 16(%eax) // Set up the 2 new descriptors +movl $0x0000ffff, 16(%eax) // Set up the 3 new descriptors movl $0x00cf9b00, 20(%eax) movl $0x0000ffff, 24(%eax) movl $0x00cf9300, 28(%eax) -movb $0x2b, 0(%eax) // Set the size +movl $0x0000ffff, 72(%eax) +movl $0x00af9b00, 76(%eax) + +movb $0x4f, 0(%eax) // Set the size movl %eax, 2(%eax) // Set pointer to new GDT lgdt (%eax) // Load it
/* finally: jump to kernel */ mov $LINUX_PARAM_LOC, %esi -jmp *(LINUX_PARAM_LOC + LINUX_ENTRY_OFFSET) +mov $(LINUX_PARAM_LOC + LINUX_CODE64_START), %eax +jmp *(%eax)
+/* Check if CPU supports long mode */ +mov $0x80000001, %eax +cpuid +btl $29, %edx +jnc .long_mode_check_done + +/* Paging enabled? */ +mov %cr0, %eax +btl $31, %eax +jnc .long_mode_check_done + +/* Long mode enabled? */ +mov $0xC0000080, %ecx +rdmsr +btl $8, %eax +jnc .long_mode_check_done + +/* protocol version >= 2.12 provides xloadflags */ +mov $(LINUX_PARAM_LOC + PROTOCOL_VERSION), %edi +cmpw $0x020c, (%edi) +jl .long_mode_check_done + +/* XLF_KERNEL_64 bit set? */ +mov $(LINUX_PARAM_LOC + XLOADFLAGS), %edi +btl $0, (%edi) +jnc .long_mode_check_done + +/* finally: jump to kernel */ +mov $LINUX_PARAM_LOC, %esi +mov $(LINUX_PARAM_LOC + LINUX_CODE64_START), %eax +jmp *(%eax) + +.long_mode_check_done: + +/* finally: jump to kernel */ +mov $LINUX_PARAM_LOC, %esi +mov $(LINUX_PARAM_LOC + LINUX_CODE32_START), %eax +jmp *(%eax) + 2: hlt jmp 2b diff --git a/util/cbfstool/linux_trampoline.c b/util/cbfstool/linux_trampoline.c index 13c0edb..f245a6a 100644 --- a/util/cbfstool/linux_trampoline.c +++ b/util/cbfstool/linux_trampoline.c @@ -3,27 +3,33 @@ unsigned char trampoline[] = { 0xfc, 0x31, 0xd2, 0xb9, 0x00, 0x00, 0x00, 0x00, 0xbb, 0x00, 0x00, 0x01, 0x00, 0x01, 0xcb, 0x8b, 0x01, 0x3d, 0x4c, 0x42, 0x49, 0x4f, 0x74, 0x07, 0x83, 0xc1, 0x10, 0x39, 0xcb, 0x75, 0xe9, 0x39, - 0xcb, 0x0f, 0x84, 0x47, 0x01, 0x00, 0x00, 0x8b, 0x59, 0x04, 0x01, 0xcb, 0x8b, 0x49, 0x14, 0x83, - 0x3b, 0x11, 0x75, 0x05, 0x8b, 0x4b, 0x08, 0xeb, 0xcf, 0x83, 0x3b, 0x01, 0x75, 0x70, 0x8b, 0x43, - 0x04, 0x83, 0xe8, 0x08, 0xc1, 0xe8, 0x02, 0x66, 0x81, 0x3d, 0x06, 0x02, 0x09, 0x00, 0x04, 0x02, - 0x7d, 0x0e, 0x3d, 0xa0, 0x00, 0x00, 0x00, 0x7e, 0x13, 0xb8, 0xa0, 0x00, 0x00, 0x00, 0xeb, 0x0c, - 0x3d, 0x80, 0x02, 0x00, 0x00, 0x7e, 0x05, 0xb8, 0x80, 0x02, 0x00, 0x00, 0x89, 0xc6, 0xbf, 0x05, - 0x00, 0x00, 0x00, 0xf7, 0xf7, 0xa3, 0xe8, 0x01, 0x09, 0x00, 0x89, 0xf0, 0x91, 0x8d, 0x73, 0x08, - 0xbf, 0xd0, 0x02, 0x09, 0x00, 0xf3, 0xa5, 0x91, 0xa1, 0xe8, 0x01, 0x09, 0x00, 0xbf, 0xd0, 0x02, - 0x09, 0x00, 0x83, 0xf8, 0x00, 0x0f, 0x84, 0x94, 0x00, 0x00, 0x00, 0x83, 0x7f, 0x10, 0x0c, 0x7e, - 0x07, 0xc7, 0x47, 0x10, 0x02, 0x00, 0x00, 0x00, 0x48, 0x83, 0xc7, 0x14, 0xeb, 0xe4, 0x83, 0x3b, - 0x43, 0x75, 0x12, 0x8b, 0x43, 0x08, 0xa3, 0x70, 0x00, 0x09, 0x00, 0x8b, 0x43, 0x0c, 0xa3, 0x74, - 0x00, 0x09, 0x00, 0xeb, 0x6a, 0x83, 0x3b, 0x12, 0x75, 0x65, 0x66, 0x81, 0x3d, 0x06, 0x02, 0x09, - 0x00, 0x0f, 0x02, 0x7d, 0x06, 0x83, 0x7b, 0x0c, 0x00, 0x75, 0x54, 0xbf, 0x00, 0x00, 0x09, 0x00, - 0x8b, 0x43, 0x08, 0x89, 0x47, 0x18, 0x8b, 0x43, 0x0c, 0x89, 0x47, 0x3a, 0x8b, 0x43, 0x10, 0x66, - 0x89, 0x47, 0x12, 0x8b, 0x43, 0x14, 0x66, 0x89, 0x47, 0x14, 0x8b, 0x53, 0x18, 0x66, 0x89, 0x57, - 0x24, 0xf7, 0xe2, 0x89, 0x47, 0x1c, 0x66, 0x0f, 0xb6, 0x43, 0x1c, 0x66, 0x89, 0x47, 0x16, 0xbe, - 0x04, 0x00, 0x00, 0x00, 0x66, 0x8b, 0x44, 0x73, 0x1b, 0x66, 0xd1, 0xc0, 0x66, 0x89, 0x44, 0x77, - 0x24, 0x4e, 0x75, 0xf0, 0xc7, 0x47, 0x36, 0x02, 0x00, 0x00, 0x00, 0xc6, 0x47, 0x0f, 0x70, 0x03, - 0x5b, 0x04, 0x49, 0x0f, 0x85, 0xf6, 0xfe, 0xff, 0xff, 0xb8, 0x00, 0x00, 0x04, 0x00, 0xc7, 0x40, - 0x10, 0xff, 0xff, 0x00, 0x00, 0xc7, 0x40, 0x14, 0x00, 0x9b, 0xcf, 0x00, 0xc7, 0x40, 0x18, 0xff, - 0xff, 0x00, 0x00, 0xc7, 0x40, 0x1c, 0x00, 0x93, 0xcf, 0x00, 0xc6, 0x00, 0x2b, 0x89, 0x40, 0x02, - 0x0f, 0x01, 0x10, 0xbe, 0x00, 0x00, 0x09, 0x00, 0xff, 0x25, 0x14, 0x02, 0x09, 0x00, 0xf4, 0xeb, - 0xfd + 0xcb, 0x0f, 0x84, 0xb4, 0x01, 0x00, 0x00, 0x8b, 0x59, 0x04, 0x01, 0xcb, 0x8b, 0x49, 0x14, 0x83, + 0x3b, 0x11, 0x75, 0x05, 0x8b, 0x4b, 0x08, 0xeb, 0xcf, 0x83, 0x3b, 0x01, 0x75, 0x77, 0x8b, 0x43, + 0x04, 0x83, 0xe8, 0x08, 0xc1, 0xe8, 0x02, 0xbf, 0x06, 0x02, 0x09, 0x00, 0x66, 0x81, 0x3f, 0x04, + 0x02, 0x7d, 0x0e, 0x3d, 0xa0, 0x00, 0x00, 0x00, 0x7e, 0x13, 0xb8, 0xa0, 0x00, 0x00, 0x00, 0xeb, + 0x0c, 0x3d, 0x80, 0x02, 0x00, 0x00, 0x7e, 0x05, 0xb8, 0x80, 0x02, 0x00, 0x00, 0x89, 0xc6, 0xbf, + 0x05, 0x00, 0x00, 0x00, 0xf7, 0xf7, 0xbf, 0xe8, 0x01, 0x09, 0x00, 0x89, 0x07, 0x89, 0xf0, 0x91, + 0x8d, 0x73, 0x08, 0xbf, 0xd0, 0x02, 0x09, 0x00, 0xf3, 0xa5, 0x91, 0xbf, 0xe8, 0x01, 0x09, 0x00, + 0x8b, 0x07, 0xbf, 0xd0, 0x02, 0x09, 0x00, 0x83, 0xf8, 0x00, 0x0f, 0x84, 0x99, 0x00, 0x00, 0x00, + 0x83, 0x7f, 0x10, 0x0c, 0x7e, 0x07, 0xc7, 0x47, 0x10, 0x02, 0x00, 0x00, 0x00, 0x83, 0xe8, 0x01, + 0x83, 0xc7, 0x14, 0xeb, 0xe2, 0x83, 0x3b, 0x43, 0x75, 0x12, 0x8b, 0x43, 0x08, 0xbf, 0x70, 0x00, + 0x09, 0x00, 0x89, 0x07, 0x8b, 0x43, 0x0c, 0x89, 0x47, 0x04, 0xeb, 0x6d, 0x83, 0x3b, 0x12, 0x75, + 0x68, 0xbf, 0x06, 0x02, 0x09, 0x00, 0x66, 0x81, 0x3f, 0x0f, 0x02, 0x7d, 0x06, 0x83, 0x7b, 0x0c, + 0x00, 0x75, 0x56, 0xbf, 0x00, 0x00, 0x09, 0x00, 0x8b, 0x43, 0x08, 0x89, 0x47, 0x18, 0x8b, 0x43, + 0x0c, 0x89, 0x47, 0x3a, 0x8b, 0x43, 0x10, 0x66, 0x89, 0x47, 0x12, 0x8b, 0x43, 0x14, 0x66, 0x89, + 0x47, 0x14, 0x8b, 0x53, 0x18, 0x66, 0x89, 0x57, 0x24, 0xf7, 0xe2, 0x89, 0x47, 0x1c, 0x66, 0x0f, + 0xb6, 0x43, 0x1c, 0x66, 0x89, 0x47, 0x16, 0xbe, 0x04, 0x00, 0x00, 0x00, 0x66, 0x8b, 0x44, 0x73, + 0x1b, 0x66, 0xd1, 0xc0, 0x66, 0x89, 0x44, 0x77, 0x24, 0x83, 0xee, 0x01, 0x75, 0xee, 0xc7, 0x47, + 0x36, 0x02, 0x00, 0x00, 0x00, 0xc6, 0x47, 0x0f, 0x70, 0x03, 0x5b, 0x04, 0x83, 0xe9, 0x01, 0x0f, + 0x85, 0xea, 0xfe, 0xff, 0xff, 0xb8, 0x00, 0x00, 0x04, 0x00, 0xc7, 0x40, 0x10, 0xff, 0xff, 0x00, + 0x00, 0xc7, 0x40, 0x14, 0x00, 0x9b, 0xcf, 0x00, 0xc7, 0x40, 0x18, 0xff, 0xff, 0x00, 0x00, 0xc7, + 0x40, 0x1c, 0x00, 0x93, 0xcf, 0x00, 0xc7, 0x40, 0x48, 0xff, 0xff, 0x00, 0x00, 0xc7, 0x40, 0x4c, + 0x00, 0x9b, 0xaf, 0x00, 0xc6, 0x00, 0x4f, 0x89, 0x40, 0x02, 0x0f, 0x01, 0x10, 0xbe, 0x00, 0x00, + 0x09, 0x00, 0xb8, 0x00, 0x02, 0x09, 0x00, 0xff, 0x20, 0xb8, 0x01, 0x00, 0x00, 0x80, 0x0f, 0xa2, + 0x0f, 0xba, 0xe2, 0x1d, 0x73, 0x39, 0x0f, 0x20, 0xc0, 0x0f, 0xba, 0xe0, 0x1f, 0x73, 0x30, 0xb9, + 0x80, 0x00, 0x00, 0xc0, 0x0f, 0x32, 0x0f, 0xba, 0xe0, 0x08, 0x73, 0x23, 0xbf, 0x06, 0x02, 0x09, + 0x00, 0x66, 0x81, 0x3f, 0x0c, 0x02, 0x7c, 0x17, 0xbf, 0x36, 0x02, 0x09, 0x00, 0x0f, 0xba, 0x27, + 0x00, 0x73, 0x0c, 0xbe, 0x00, 0x00, 0x09, 0x00, 0xb8, 0x00, 0x02, 0x09, 0x00, 0xff, 0x20, 0xbe, + 0x00, 0x00, 0x09, 0x00, 0xb8, 0x14, 0x02, 0x09, 0x00, 0xff, 0x20, 0xf4, 0xeb, 0xfd }; -unsigned int trampoline_len = 369; +unsigned int trampoline_len = 478;