Skip to content

Commit e8972a7

Browse files
ardbiesheuvelbp3tk0v
authored andcommitted
x86/decompressor: Call trampoline as a normal function
Move the long return to switch to 32-bit mode into the trampoline code so it can be called as an ordinary function. This will allow it to be called directly from C code in a subsequent patch. While at it, reorganize the code somewhat to keep the prologue and epilogue of the function together, making the code a bit easier to follow. Also, given that the trampoline is now entered in 64-bit mode, a simple RIP-relative reference can be used to take the address of the exit point. Signed-off-by: Ard Biesheuvel <[email protected]> Signed-off-by: Borislav Petkov (AMD) <[email protected]> Acked-by: Kirill A. Shutemov <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 00c6b09 commit e8972a7

File tree

2 files changed

+36
-45
lines changed

2 files changed

+36
-45
lines changed

arch/x86/boot/compressed/head_64.S

Lines changed: 35 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -447,39 +447,8 @@ SYM_CODE_START(startup_64)
447447
/* Save the trampoline address in RCX */
448448
movq %rax, %rcx
449449

450-
/* Set up 32-bit addressable stack */
451-
leaq TRAMPOLINE_32BIT_STACK_END(%rcx), %rsp
452-
453-
/*
454-
* Preserve live 64-bit registers on the stack: this is necessary
455-
* because the architecture does not guarantee that GPRs will retain
456-
* their full 64-bit values across a 32-bit mode switch.
457-
*/
458-
pushq %r15
459-
pushq %rbp
460-
pushq %rbx
461-
462-
/*
463-
* Push the 64-bit address of trampoline_return() onto the new stack.
464-
* It will be used by the trampoline to return to the main code. Due to
465-
* the 32-bit mode switch, it cannot be kept it in a register either.
466-
*/
467-
leaq trampoline_return(%rip), %rdi
468-
pushq %rdi
469-
470-
/* Switch to compatibility mode (CS.L = 0 CS.D = 1) via far return */
471-
pushq $__KERNEL32_CS
472450
leaq TRAMPOLINE_32BIT_CODE_OFFSET(%rax), %rax
473-
pushq %rax
474-
lretq
475-
trampoline_return:
476-
/* Restore live 64-bit registers */
477-
popq %rbx
478-
popq %rbp
479-
popq %r15
480-
481-
/* Restore the stack, the 32-bit trampoline uses its own stack */
482-
leaq rva(boot_stack_end)(%rbx), %rsp
451+
call *%rax
483452

484453
/*
485454
* cleanup_trampoline() would restore trampoline memory.
@@ -561,7 +530,6 @@ SYM_FUNC_START_LOCAL_NOALIGN(.Lrelocated)
561530
jmp *%rax
562531
SYM_FUNC_END(.Lrelocated)
563532

564-
.code32
565533
/*
566534
* This is the 32-bit trampoline that will be copied over to low memory.
567535
*
@@ -570,6 +538,39 @@ SYM_FUNC_END(.Lrelocated)
570538
* Non zero RDX means trampoline needs to enable 5-level paging.
571539
*/
572540
SYM_CODE_START(trampoline_32bit_src)
541+
/*
542+
* Preserve live 64-bit registers on the stack: this is necessary
543+
* because the architecture does not guarantee that GPRs will retain
544+
* their full 64-bit values across a 32-bit mode switch.
545+
*/
546+
pushq %r15
547+
pushq %rbp
548+
pushq %rbx
549+
550+
/* Set up 32-bit addressable stack and push the old RSP value */
551+
leaq (TRAMPOLINE_32BIT_STACK_END - 8)(%rcx), %rbx
552+
movq %rsp, (%rbx)
553+
movq %rbx, %rsp
554+
555+
/* Take the address of the trampoline exit code */
556+
leaq .Lret(%rip), %rbx
557+
558+
/* Switch to compatibility mode (CS.L = 0 CS.D = 1) via far return */
559+
pushq $__KERNEL32_CS
560+
leaq 0f(%rip), %rax
561+
pushq %rax
562+
lretq
563+
564+
.Lret:
565+
/* Restore the preserved 64-bit registers */
566+
movq (%rsp), %rsp
567+
popq %rbx
568+
popq %rbp
569+
popq %r15
570+
retq
571+
572+
.code32
573+
0:
573574
/* Set up data and stack segments */
574575
movl $__KERNEL_DS, %eax
575576
movl %eax, %ds
@@ -633,12 +634,9 @@ SYM_CODE_START(trampoline_32bit_src)
633634
1:
634635
movl %eax, %cr4
635636

636-
/* Calculate address of paging_enabled() once we are executing in the trampoline */
637-
leal .Lpaging_enabled - trampoline_32bit_src + TRAMPOLINE_32BIT_CODE_OFFSET(%ecx), %eax
638-
639637
/* Prepare the stack for far return to Long Mode */
640638
pushl $__KERNEL_CS
641-
pushl %eax
639+
pushl %ebx
642640

643641
/* Enable paging again. */
644642
movl %cr0, %eax
@@ -648,20 +646,13 @@ SYM_CODE_START(trampoline_32bit_src)
648646
lret
649647
SYM_CODE_END(trampoline_32bit_src)
650648

651-
.code64
652-
SYM_FUNC_START_LOCAL_NOALIGN(.Lpaging_enabled)
653-
/* Return from the trampoline */
654-
retq
655-
SYM_FUNC_END(.Lpaging_enabled)
656-
657649
/*
658650
* The trampoline code has a size limit.
659651
* Make sure we fail to compile if the trampoline code grows
660652
* beyond TRAMPOLINE_32BIT_CODE_SIZE bytes.
661653
*/
662654
.org trampoline_32bit_src + TRAMPOLINE_32BIT_CODE_SIZE
663655

664-
.code32
665656
SYM_FUNC_START_LOCAL_NOALIGN(.Lno_longmode)
666657
/* This isn't an x86-64 CPU, so hang intentionally, we cannot continue */
667658
1:

arch/x86/boot/compressed/pgtable.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
#define TRAMPOLINE_32BIT_PGTABLE_OFFSET 0
77

88
#define TRAMPOLINE_32BIT_CODE_OFFSET PAGE_SIZE
9-
#define TRAMPOLINE_32BIT_CODE_SIZE 0x80
9+
#define TRAMPOLINE_32BIT_CODE_SIZE 0xA0
1010

1111
#define TRAMPOLINE_32BIT_STACK_END TRAMPOLINE_32BIT_SIZE
1212

0 commit comments

Comments
 (0)