diff --git a/src/arch/x86/assembly_entry.S b/src/arch/x86/assembly_entry.S index 0d8307bb1f..31670c29b6 100644 --- a/src/arch/x86/assembly_entry.S +++ b/src/arch/x86/assembly_entry.S @@ -15,12 +15,22 @@ #define _STACK_TOP _ecar_stack #endif +#ifdef __x86_64__ +.code64 +#else +.code32 +#endif + .section ".text._start", "ax", @progbits .global _start _start: /* Migrate GDT to this text segment */ +#ifdef __x86_64__ + call gdt_init64 +#else call gdt_init +#endif /* reset stack pointer to CAR/EARLYRAM stack */ mov $_STACK_TOP, %esp diff --git a/src/arch/x86/gdt_init.S b/src/arch/x86/gdt_init.S index 7dd4b94933..1558ac62c8 100644 --- a/src/arch/x86/gdt_init.S +++ b/src/arch/x86/gdt_init.S @@ -20,7 +20,20 @@ gdtptr: .section ".text._gdt64_", "ax", @progbits .globl gdt_init64 gdt_init64: - lgdt gdtptr64 + /* Workaround a bug in the assembler. + * The following code doesn't work: + * lgdt gdtptr64 + * + * The assembler tries to save memory by using 32bit displacement addressing mode. + * Displacements are using signed integers. + * This is fine in protected mode, as the negative address points to the correct + * address > 2GiB, but in long mode this doesn't work at all. + * Tests showed that QEMU can gracefully handle it, but real CPUs can't. + * + * Use the movabs pseudo instruction to force using a 64bit absolute address. + */ + movabs $gdtptr64, %rax + lgdt (%rax) ret .previous