mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-16 12:46:55 +07:00
efi/x86: Don't depend on firmware GDT layout
When booting in mixed mode, the firmware's GDT is still installed at handover entry in efi32_stub_entry. We save the GDTR for later use in __efi64_thunk but we are assuming that descriptor 2 (__KERNEL_CS) is a valid 32-bit code segment descriptor and that descriptor 3 (__KERNEL_DS/__BOOT_DS) is a valid data segment descriptor. This happens to be true for OVMF (it actually uses descriptor 1 for data segments, but descriptor 3 is also setup as data), but we shouldn't depend on this being the case. Fix this by saving the code and data selectors in addition to the GDTR in efi32_stub_entry, and restoring them in __efi64_thunk before calling the firmware. The UEFI specification guarantees that selectors will be flat, so using the DS selector for all the segment registers should be enough. We also need to install our own GDT before initializing segment registers in startup_32, so move the GDT load up to the beginning of the function. [ardb: mention mixed mode in the commit log] Signed-off-by: Arvind Sankar <nivedita@alum.mit.edu> Link: https://lore.kernel.org/r/20200202171353.3736319-3-nivedita@alum.mit.edu Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
This commit is contained in:
parent
67a6af7ad1
commit
90ff226281
@ -54,11 +54,16 @@ SYM_FUNC_START(__efi64_thunk)
|
||||
* Switch to gdt with 32-bit segments. This is the firmware GDT
|
||||
* that was installed when the kernel started executing. This
|
||||
* pointer was saved at the EFI stub entry point in head_64.S.
|
||||
*
|
||||
* Pass the saved DS selector to the 32-bit code, and use far return to
|
||||
* restore the saved CS selector.
|
||||
*/
|
||||
leaq efi32_boot_gdt(%rip), %rax
|
||||
lgdt (%rax)
|
||||
|
||||
pushq $__KERNEL_CS
|
||||
movzwl efi32_boot_ds(%rip), %edx
|
||||
movzwq efi32_boot_cs(%rip), %rax
|
||||
pushq %rax
|
||||
leaq efi_enter32(%rip), %rax
|
||||
pushq %rax
|
||||
lretq
|
||||
@ -73,6 +78,10 @@ SYM_FUNC_START(__efi64_thunk)
|
||||
movl %ebx, %es
|
||||
pop %rbx
|
||||
movl %ebx, %ds
|
||||
/* Clear out 32-bit selector from FS and GS */
|
||||
xorl %ebx, %ebx
|
||||
movl %ebx, %fs
|
||||
movl %ebx, %gs
|
||||
|
||||
/*
|
||||
* Convert 32-bit status code into 64-bit.
|
||||
@ -92,10 +101,12 @@ SYM_FUNC_END(__efi64_thunk)
|
||||
* The stack should represent the 32-bit calling convention.
|
||||
*/
|
||||
SYM_FUNC_START_LOCAL(efi_enter32)
|
||||
movl $__KERNEL_DS, %eax
|
||||
movl %eax, %ds
|
||||
movl %eax, %es
|
||||
movl %eax, %ss
|
||||
/* Load firmware selector into data and stack segment registers */
|
||||
movl %edx, %ds
|
||||
movl %edx, %es
|
||||
movl %edx, %fs
|
||||
movl %edx, %gs
|
||||
movl %edx, %ss
|
||||
|
||||
/* Reload pgtables */
|
||||
movl %cr3, %eax
|
||||
@ -157,6 +168,14 @@ SYM_DATA_START(efi32_boot_gdt)
|
||||
.quad 0
|
||||
SYM_DATA_END(efi32_boot_gdt)
|
||||
|
||||
SYM_DATA_START(efi32_boot_cs)
|
||||
.word 0
|
||||
SYM_DATA_END(efi32_boot_cs)
|
||||
|
||||
SYM_DATA_START(efi32_boot_ds)
|
||||
.word 0
|
||||
SYM_DATA_END(efi32_boot_ds)
|
||||
|
||||
SYM_DATA_START(efi_gdt64)
|
||||
.word efi_gdt64_end - efi_gdt64
|
||||
.long 0 /* Filled out by user */
|
||||
|
@ -54,10 +54,6 @@ SYM_FUNC_START(startup_32)
|
||||
*/
|
||||
cld
|
||||
cli
|
||||
movl $(__BOOT_DS), %eax
|
||||
movl %eax, %ds
|
||||
movl %eax, %es
|
||||
movl %eax, %ss
|
||||
|
||||
/*
|
||||
* Calculate the delta between where we were compiled to run
|
||||
@ -72,10 +68,20 @@ SYM_FUNC_START(startup_32)
|
||||
1: popl %ebp
|
||||
subl $1b, %ebp
|
||||
|
||||
/* Load new GDT with the 64bit segments using 32bit descriptor */
|
||||
addl %ebp, gdt+2(%ebp)
|
||||
lgdt gdt(%ebp)
|
||||
|
||||
/* Load segment registers with our descriptors */
|
||||
movl $__BOOT_DS, %eax
|
||||
movl %eax, %ds
|
||||
movl %eax, %es
|
||||
movl %eax, %fs
|
||||
movl %eax, %gs
|
||||
movl %eax, %ss
|
||||
|
||||
/* setup a stack and make sure cpu supports long mode. */
|
||||
movl $boot_stack_end, %eax
|
||||
addl %ebp, %eax
|
||||
movl %eax, %esp
|
||||
leal boot_stack_end(%ebp), %esp
|
||||
|
||||
call verify_cpu
|
||||
testl %eax, %eax
|
||||
@ -112,10 +118,6 @@ SYM_FUNC_START(startup_32)
|
||||
* Prepare for entering 64 bit mode
|
||||
*/
|
||||
|
||||
/* Load new GDT with the 64bit segments using 32bit descriptor */
|
||||
addl %ebp, gdt+2(%ebp)
|
||||
lgdt gdt(%ebp)
|
||||
|
||||
/* Enable PAE mode */
|
||||
movl %cr4, %eax
|
||||
orl $X86_CR4_PAE, %eax
|
||||
@ -232,9 +234,13 @@ SYM_FUNC_START(efi32_stub_entry)
|
||||
|
||||
movl %ecx, efi32_boot_args(%ebp)
|
||||
movl %edx, efi32_boot_args+4(%ebp)
|
||||
sgdtl efi32_boot_gdt(%ebp)
|
||||
movb $0, efi_is64(%ebp)
|
||||
|
||||
/* Save firmware GDTR and code/data selectors */
|
||||
sgdtl efi32_boot_gdt(%ebp)
|
||||
movw %cs, efi32_boot_cs(%ebp)
|
||||
movw %ds, efi32_boot_ds(%ebp)
|
||||
|
||||
/* Disable paging */
|
||||
movl %cr0, %eax
|
||||
btrl $X86_CR0_PG_BIT, %eax
|
||||
|
Loading…
Reference in New Issue
Block a user