diff --git a/kernel/arch/x86_64/entry.S b/kernel/arch/x86_64/entry.S index 9c4757b..64eabc3 100644 --- a/kernel/arch/x86_64/entry.S +++ b/kernel/arch/x86_64/entry.S @@ -163,6 +163,23 @@ gdt64_end: */ .global entry64uefi entry64uefi: + /* Enable SYSCALL/SYSRET. + * + * The 32-bit entry above sets EFER.SCE on its way into long mode. This path + * skips all of that, because firmware has already done the mode switch -- and + * with it skips the one bit that is not about paging. UEFI has no reason to + * set SCE and does not, so the kernel came up with SYSCALL disabled and the + * first sysretq back to user space raised #UD: "unexpected trap 6 ... rip + * " in pid 1, at zero ticks. It stayed hidden until this + * path first got far enough to run a user program. + * + * Read-modify-write: LME and LMA are already set by firmware and must stay. + */ + mov $MSR_EFER, %ecx + rdmsr + bts $0, %eax + wrmsr + lgdt (gdtr64 - mboot_header + mboot_load_addr) movq $(entry64low - mboot_header + mboot_load_addr), %rax pushq $8 /* the 64-bit code selector in gdt64 */