x86/decompressor: Don't rely on upper 32 bits of GPRs being preserved
[ Upstream commit264b82fdb4
] The 4-to-5 level mode switch trampoline disables long mode and paging in order to be able to flick the LA57 bit. According to section 3.4.1.1 of the x86 architecture manual [0], 64-bit GPRs might not retain the upper 32 bits of their contents across such a mode switch. Given that RBP, RBX and RSI are live at this point, preserve them on the stack, along with the return address that might be above 4G as well. [0] Intel® 64 and IA-32 Architectures Software Developer’s Manual, Volume 1: Basic Architecture "Because the upper 32 bits of 64-bit general-purpose registers are undefined in 32-bit modes, the upper 32 bits of any general-purpose register are not preserved when switching from 64-bit mode to a 32-bit mode (to protected mode or compatibility mode). Software must not depend on these bits to maintain a value after a 64-bit to 32-bit mode switch." Fixes:194a9749c7
("x86/boot/compressed/64: Handle 5-level paging boot if kernel is above 4G") Signed-off-by: Ard Biesheuvel <ardb@kernel.org> Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de> Link: https://lore.kernel.org/r/20230807162720.545787-2-ardb@kernel.org Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
be361e5ec4
commit
1d9a735d4e
|
@ -485,11 +485,25 @@ SYM_CODE_START(startup_64)
|
||||||
/* Save the trampoline address in RCX */
|
/* Save the trampoline address in RCX */
|
||||||
movq %rax, %rcx
|
movq %rax, %rcx
|
||||||
|
|
||||||
|
/* Set up 32-bit addressable stack */
|
||||||
|
leaq TRAMPOLINE_32BIT_STACK_END(%rcx), %rsp
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Load the address of trampoline_return() into RDI.
|
* Preserve live 64-bit registers on the stack: this is necessary
|
||||||
* It will be used by the trampoline to return to the main code.
|
* because the architecture does not guarantee that GPRs will retain
|
||||||
|
* their full 64-bit values across a 32-bit mode switch.
|
||||||
|
*/
|
||||||
|
pushq %rbp
|
||||||
|
pushq %rbx
|
||||||
|
pushq %rsi
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Push the 64-bit address of trampoline_return() onto the new stack.
|
||||||
|
* It will be used by the trampoline to return to the main code. Due to
|
||||||
|
* the 32-bit mode switch, it cannot be kept it in a register either.
|
||||||
*/
|
*/
|
||||||
leaq trampoline_return(%rip), %rdi
|
leaq trampoline_return(%rip), %rdi
|
||||||
|
pushq %rdi
|
||||||
|
|
||||||
/* Switch to compatibility mode (CS.L = 0 CS.D = 1) via far return */
|
/* Switch to compatibility mode (CS.L = 0 CS.D = 1) via far return */
|
||||||
pushq $__KERNEL32_CS
|
pushq $__KERNEL32_CS
|
||||||
|
@ -497,6 +511,11 @@ SYM_CODE_START(startup_64)
|
||||||
pushq %rax
|
pushq %rax
|
||||||
lretq
|
lretq
|
||||||
trampoline_return:
|
trampoline_return:
|
||||||
|
/* Restore live 64-bit registers */
|
||||||
|
popq %rsi
|
||||||
|
popq %rbx
|
||||||
|
popq %rbp
|
||||||
|
|
||||||
/* Restore the stack, the 32-bit trampoline uses its own stack */
|
/* Restore the stack, the 32-bit trampoline uses its own stack */
|
||||||
leaq rva(boot_stack_end)(%rbx), %rsp
|
leaq rva(boot_stack_end)(%rbx), %rsp
|
||||||
|
|
||||||
|
@ -606,7 +625,7 @@ SYM_FUNC_END(.Lrelocated)
|
||||||
/*
|
/*
|
||||||
* This is the 32-bit trampoline that will be copied over to low memory.
|
* This is the 32-bit trampoline that will be copied over to low memory.
|
||||||
*
|
*
|
||||||
* RDI contains the return address (might be above 4G).
|
* Return address is at the top of the stack (might be above 4G).
|
||||||
* ECX contains the base address of the trampoline memory.
|
* ECX contains the base address of the trampoline memory.
|
||||||
* Non zero RDX means trampoline needs to enable 5-level paging.
|
* Non zero RDX means trampoline needs to enable 5-level paging.
|
||||||
*/
|
*/
|
||||||
|
@ -616,9 +635,6 @@ SYM_CODE_START(trampoline_32bit_src)
|
||||||
movl %eax, %ds
|
movl %eax, %ds
|
||||||
movl %eax, %ss
|
movl %eax, %ss
|
||||||
|
|
||||||
/* Set up new stack */
|
|
||||||
leal TRAMPOLINE_32BIT_STACK_END(%ecx), %esp
|
|
||||||
|
|
||||||
/* Disable paging */
|
/* Disable paging */
|
||||||
movl %cr0, %eax
|
movl %cr0, %eax
|
||||||
btrl $X86_CR0_PG_BIT, %eax
|
btrl $X86_CR0_PG_BIT, %eax
|
||||||
|
@ -695,7 +711,7 @@ SYM_CODE_END(trampoline_32bit_src)
|
||||||
.code64
|
.code64
|
||||||
SYM_FUNC_START_LOCAL_NOALIGN(.Lpaging_enabled)
|
SYM_FUNC_START_LOCAL_NOALIGN(.Lpaging_enabled)
|
||||||
/* Return from the trampoline */
|
/* Return from the trampoline */
|
||||||
jmp *%rdi
|
retq
|
||||||
SYM_FUNC_END(.Lpaging_enabled)
|
SYM_FUNC_END(.Lpaging_enabled)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Reference in New Issue