summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/arch/x86/assembly_entry.S10
-rw-r--r--src/arch/x86/gdt_init.S15
2 files changed, 24 insertions, 1 deletions
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