All of lore.kernel.org
 help / color / mirror / Atom feed
From: Tom Lendacky <thomas.lendacky@amd.com>
To: Ard Biesheuvel <ardb@kernel.org>, linux-efi@vger.kernel.org
Cc: linux-kernel@vger.kernel.org, Evgeniy Baskov <baskov@ispras.ru>,
	Borislav Petkov <bp@alien8.de>, Andy Lutomirski <luto@kernel.org>,
	Dave Hansen <dave.hansen@linux.intel.com>,
	Ingo Molnar <mingo@redhat.com>,
	Peter Zijlstra <peterz@infradead.org>,
	Thomas Gleixner <tglx@linutronix.de>,
	Alexey Khoroshilov <khoroshilov@ispras.ru>,
	Peter Jones <pjones@redhat.com>,
	Gerd Hoffmann <kraxel@redhat.com>, Dave Young <dyoung@redhat.com>,
	Mario Limonciello <mario.limonciello@amd.com>,
	Kees Cook <keescook@chromium.org>,
	"Kirill A . Shutemov" <kirill.shutemov@linux.intel.com>,
	Linus Torvalds <torvalds@linux-foundation.org>
Subject: Re: [PATCH v2 05/20] x86: decompressor: Avoid the need for a stack in the 32-bit trampoline
Date: Wed, 17 May 2023 17:40:30 -0500	[thread overview]
Message-ID: <6f858998-bb56-689b-76a7-0952d73f5ab8@amd.com> (raw)
In-Reply-To: <20230508070330.582131-6-ardb@kernel.org>

On 5/8/23 02:03, Ard Biesheuvel wrote:
> The 32-bit trampoline no longer uses the stack for anything except
> performing a long return back to long mode. Currently, this stack is
> allocated in the same page that carries the trampoline code, which means
> this page must be mapped writable and executable, and the stack is
> therefore executable as well.
> 
> So let's do a long jump instead: that way, we can pre-calculate the
> return address and poke it into the code before we call it. In a later
> patch, we will take advantage of this by removing writable permissions
> (and adding executable ones) explicitly when booting via the EFI stub.
> 
> Not playing with the stack pointer also makes it more straight-forward
> to call the trampoline code as an ordinary 64-bit function from C code.
> 
> Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
> ---
>   arch/x86/boot/compressed/head_64.S    | 34 ++++----------------
>   arch/x86/boot/compressed/pgtable.h    |  6 ++--
>   arch/x86/boot/compressed/pgtable_64.c | 12 ++++++-
>   3 files changed, 21 insertions(+), 31 deletions(-)
> 
> diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S
> index b1f8a867777120bb..3b5fc851737ffc39 100644
> --- a/arch/x86/boot/compressed/head_64.S
> +++ b/arch/x86/boot/compressed/head_64.S
> @@ -460,9 +460,6 @@ SYM_CODE_START(startup_64)
>   	leaq	TRAMPOLINE_32BIT_CODE_OFFSET(%rax), %rax
>   	call	*%rax
>   
> -	/* Restore the stack, the 32-bit trampoline uses its own stack */
> -	leaq	rva(boot_stack_end)(%rbx), %rsp
> -
>   	/*
>   	 * cleanup_trampoline() would restore trampoline memory.
>   	 *
> @@ -563,24 +560,17 @@ SYM_FUNC_END(.Lrelocated)
>    * EDI contains the base address of the trampoline memory.
>    * Non-zero ESI means trampoline needs to enable 5-level paging.
>    */
> +	.section ".rodata", "a", @progbits
>   SYM_CODE_START(trampoline_32bit_src)
> -	popq	%r8
>   	/* Switch to compatibility mode (CS.L = 0 CS.D = 1) via far return */
>   	pushq	$__KERNEL32_CS
>   	leaq	0f(%rip), %rax
>   	pushq	%rax
>   	lretq
> +.Lret:	retq

Maybe just add a comment above this to explain that this is a target of 
the long jump below to get back into long mode and be able to return 
without setting up a new stack for the 32-bit code.

And then a corresponding comment on the long jump itself. I think it would 
make it easier to understand what is going on in this part of the code.

Thanks,
Tom

>   
>   	.code32
> -0:	/* Set up data and stack segments */
> -	movl	$__KERNEL_DS, %eax
> -	movl	%eax, %ds
> -	movl	%eax, %ss
> -
> -	/* Set up new stack */
> -	leal	TRAMPOLINE_32BIT_STACK_END(%edi), %esp
> -
> -	/* Disable paging */
> +0:	/* Disable paging */
>   	movl	%cr0, %eax
>   	btrl	$X86_CR0_PG_BIT, %eax
>   	movl	%eax, %cr0
> @@ -634,26 +624,16 @@ SYM_CODE_START(trampoline_32bit_src)
>   1:
>   	movl	%eax, %cr4
>   
> -	/* Calculate address of paging_enabled() once we are executing in the trampoline */
> -	leal	.Lpaging_enabled - trampoline_32bit_src + TRAMPOLINE_32BIT_CODE_OFFSET(%edi), %eax
> -
> -	/* Prepare the stack for far return to Long Mode */
> -	pushl	$__KERNEL_CS
> -	pushl	%eax
> -
>   	/* Enable paging again. */
>   	movl	%cr0, %eax
>   	btsl	$X86_CR0_PG_BIT, %eax
>   	movl	%eax, %cr0
>   
> -	lret
> +.Ljmp:	ljmpl	$__KERNEL_CS, $(.Lret - trampoline_32bit_src)
>   SYM_CODE_END(trampoline_32bit_src)
>   
> -	.code64
> -SYM_FUNC_START_LOCAL_NOALIGN(.Lpaging_enabled)
> -	/* Return from the trampoline */
> -	jmp	*%r8
> -SYM_FUNC_END(.Lpaging_enabled)
> +/* keep this right after trampoline_32bit_src() so we can infer its size */
> +SYM_DATA(trampoline_ljmp_imm_offset, .word  .Ljmp + 1 - trampoline_32bit_src)
>   
>   	/*
>            * The trampoline code has a size limit.
> @@ -662,7 +642,7 @@ SYM_FUNC_END(.Lpaging_enabled)
>   	 */
>   	.org	trampoline_32bit_src + TRAMPOLINE_32BIT_CODE_SIZE
>   
> -	.code32
> +	.text
>   SYM_FUNC_START_LOCAL_NOALIGN(.Lno_longmode)
>   	/* This isn't an x86-64 CPU, so hang intentionally, we cannot continue */
>   1:
> diff --git a/arch/x86/boot/compressed/pgtable.h b/arch/x86/boot/compressed/pgtable.h
> index 4e8cef135226bcbb..131488f50af55d0a 100644
> --- a/arch/x86/boot/compressed/pgtable.h
> +++ b/arch/x86/boot/compressed/pgtable.h
> @@ -6,9 +6,7 @@
>   #define TRAMPOLINE_32BIT_PGTABLE_OFFSET	0
>   
>   #define TRAMPOLINE_32BIT_CODE_OFFSET	PAGE_SIZE
> -#define TRAMPOLINE_32BIT_CODE_SIZE	0xA0
> -
> -#define TRAMPOLINE_32BIT_STACK_END	TRAMPOLINE_32BIT_SIZE
> +#define TRAMPOLINE_32BIT_CODE_SIZE	0x80
>   
>   #ifndef __ASSEMBLER__
>   
> @@ -16,5 +14,7 @@ extern unsigned long *trampoline_32bit;
>   
>   extern void trampoline_32bit_src(void *trampoline, bool enable_5lvl);
>   
> +extern const u16 trampoline_ljmp_imm_offset;
> +
>   #endif /* __ASSEMBLER__ */
>   #endif /* BOOT_COMPRESSED_PAGETABLE_H */
> diff --git a/arch/x86/boot/compressed/pgtable_64.c b/arch/x86/boot/compressed/pgtable_64.c
> index 2ac12ff4111bf8c0..09fc18180929fab3 100644
> --- a/arch/x86/boot/compressed/pgtable_64.c
> +++ b/arch/x86/boot/compressed/pgtable_64.c
> @@ -109,6 +109,7 @@ static unsigned long find_trampoline_placement(void)
>   struct paging_config paging_prepare(void *rmode)
>   {
>   	struct paging_config paging_config = {};
> +	void *tramp_code;
>   
>   	/* Initialize boot_params. Required for cmdline_find_option_bool(). */
>   	boot_params = rmode;
> @@ -143,9 +144,18 @@ struct paging_config paging_prepare(void *rmode)
>   	memset(trampoline_32bit, 0, TRAMPOLINE_32BIT_SIZE);
>   
>   	/* Copy trampoline code in place */
> -	memcpy(trampoline_32bit + TRAMPOLINE_32BIT_CODE_OFFSET / sizeof(unsigned long),
> +	tramp_code = memcpy(trampoline_32bit +
> +			TRAMPOLINE_32BIT_CODE_OFFSET / sizeof(unsigned long),
>   			&trampoline_32bit_src, TRAMPOLINE_32BIT_CODE_SIZE);
>   
> +	/*
> +	 * Avoid the need for a stack in the 32-bit trampoline code, by using
> +	 * LJMP rather than LRET to return back to long mode. LJMP takes an
> +	 * immediate absolute address, so we have to adjust that based on the
> +	 * placement of the trampoline.
> +	 */
> +	*(u32 *)(tramp_code + trampoline_ljmp_imm_offset) += (unsigned long)tramp_code;
> +
>   	/*
>   	 * The code below prepares page table in trampoline memory.
>   	 *

  parent reply	other threads:[~2023-05-17 22:40 UTC|newest]

Thread overview: 42+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-05-08  7:03 [PATCH v2 00/20] efi/x86: Avoid bare metal decompressor during EFI boot Ard Biesheuvel
2023-05-08  7:03 ` [PATCH v2 01/20] x86: decompressor: Use proper sequence to take the address of the GOT Ard Biesheuvel
2023-05-17 17:31   ` Borislav Petkov
2023-05-17 17:39     ` Ard Biesheuvel
2023-05-08  7:03 ` [PATCH v2 02/20] x86: decompressor: Store boot_params pointer in callee save register Ard Biesheuvel
2023-05-08  7:03 ` [PATCH v2 03/20] x86: decompressor: Call trampoline as a normal function Ard Biesheuvel
2023-05-15 13:59   ` Kirill A. Shutemov
2023-05-08  7:03 ` [PATCH v2 04/20] x86: decompressor: Use standard calling convention for trampoline Ard Biesheuvel
2023-05-15 14:00   ` Kirill A. Shutemov
2023-05-08  7:03 ` [PATCH v2 05/20] x86: decompressor: Avoid the need for a stack in the 32-bit trampoline Ard Biesheuvel
2023-05-15 14:03   ` Kirill A. Shutemov
2023-05-17 22:40   ` Tom Lendacky [this message]
2023-05-18 14:55     ` Ard Biesheuvel
2023-05-08  7:03 ` [PATCH v2 06/20] x86: decompressor: Call trampoline directly from C code Ard Biesheuvel
2023-05-15 14:05   ` Kirill A. Shutemov
2023-05-08  7:03 ` [PATCH v2 07/20] x86: decompressor: Only call the trampoline when changing paging levels Ard Biesheuvel
2023-05-15 14:07   ` Kirill A. Shutemov
2023-05-08  7:03 ` [PATCH v2 08/20] x86: decompressor: Merge trampoline cleanup with switching code Ard Biesheuvel
     [not found]   ` <20230515140955.d4adbstv6gtnshp2@box.shutemov.name>
2023-05-16 17:50     ` Ard Biesheuvel
2023-05-08  7:03 ` [PATCH v2 09/20] x86: efistub: Perform 4/5 level paging switch from the stub Ard Biesheuvel
2023-05-15 14:14   ` Kirill A. Shutemov
2023-05-16 17:53     ` Ard Biesheuvel
2023-05-08  7:03 ` [PATCH v2 10/20] x86: efistub: Prefer EFI memory attributes protocol over DXE services Ard Biesheuvel
2023-05-08  7:03 ` [PATCH v2 11/20] decompress: Use 8 byte alignment Ard Biesheuvel
2023-05-08  7:03 ` [PATCH v2 12/20] x86: decompressor: Move global symbol references to C code Ard Biesheuvel
2023-05-08  7:03 ` [PATCH v2 13/20] x86: decompressor: Factor out kernel decompression and relocation Ard Biesheuvel
2023-05-08  7:03 ` [PATCH v2 14/20] x86: head_64: Store boot_params pointer in callee-preserved register Ard Biesheuvel
2023-05-08  7:03 ` [PATCH v2 15/20] x86: head_64: Switch to kernel CS before enabling memory encryption Ard Biesheuvel
2023-05-17 18:54   ` Tom Lendacky
2023-05-08  7:03 ` [PATCH v2 16/20] efi: libstub: Add limit argument to efi_random_alloc() Ard Biesheuvel
2023-05-08  7:03 ` [PATCH v2 17/20] x86: efistub: Check SEV/SNP support while running in the firmware Ard Biesheuvel
2023-05-18 20:16   ` Tom Lendacky
2023-05-18 22:27     ` Ard Biesheuvel
2023-05-19 14:04       ` Tom Lendacky
2023-05-22 12:48         ` Joerg Roedel
2023-05-22 13:07           ` Ard Biesheuvel
2023-05-22 13:35             ` Joerg Roedel
2023-05-08  7:03 ` [PATCH v2 18/20] x86: efistub: Avoid legacy decompressor when doing EFI boot Ard Biesheuvel
2023-05-18 20:48   ` Tom Lendacky
2023-05-18 22:33     ` Ard Biesheuvel
2023-05-08  7:03 ` [PATCH v2 19/20] x86: efistub: Clear BSS in EFI handover protocol entrypoint Ard Biesheuvel
2023-05-08  7:03 ` [PATCH v2 20/20] x86: decompressor: Avoid magic offsets for EFI handover entrypoint Ard Biesheuvel

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=6f858998-bb56-689b-76a7-0952d73f5ab8@amd.com \
    --to=thomas.lendacky@amd.com \
    --cc=ardb@kernel.org \
    --cc=baskov@ispras.ru \
    --cc=bp@alien8.de \
    --cc=dave.hansen@linux.intel.com \
    --cc=dyoung@redhat.com \
    --cc=keescook@chromium.org \
    --cc=khoroshilov@ispras.ru \
    --cc=kirill.shutemov@linux.intel.com \
    --cc=kraxel@redhat.com \
    --cc=linux-efi@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=luto@kernel.org \
    --cc=mario.limonciello@amd.com \
    --cc=mingo@redhat.com \
    --cc=peterz@infradead.org \
    --cc=pjones@redhat.com \
    --cc=tglx@linutronix.de \
    --cc=torvalds@linux-foundation.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.