entry: enable SYSCALL on the UEFI hand-off path
The 32-bit entry sets EFER.SCE on its way into long mode. entry64uefi skips that bootstrap entirely, because firmware has already done the mode switch -- and with it skipped the one bit in there that is not about paging. UEFI has no reason to set SCE and does not, so the kernel came up with SYSCALL disabled. Nothing noticed until the UEFI path first got far enough to run a user program, at which point the first sysretq raised #UD: "unexpected trap 6 ... rip <syscall_trapret>" in pid 1, at zero ticks. Read-modify-write, because LME and LMA are already set by firmware and have to stay. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
b768f5ded9
commit
e4df779048
1 changed files with 17 additions and 0 deletions
|
|
@ -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
|
||||
* <syscall_trapret>" 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 */
|
||||
|
|
|
|||
Loading…
Reference in a new issue