diff mbox series

[v2,02/16] x86/compressed: efi-mixed: move 32-bit entrypoint code into .text section

Message ID 20220921145422.437618-3-ardb@kernel.org
State New
Headers show
Series x86: head_64.S spring cleaning | expand

Commit Message

Ard Biesheuvel Sept. 21, 2022, 2:54 p.m. UTC
Move the code that stores the arguments passed to the EFI entrypoint
into the .text section, so that it can be moved into a separate
compilation unit in a subsequent patch.

Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
 arch/x86/boot/compressed/head_64.S | 34 ++++++++++++--------
 1 file changed, 20 insertions(+), 14 deletions(-)

Comments

Borislav Petkov Oct. 6, 2022, 10:42 a.m. UTC | #1
On Wed, Sep 21, 2022 at 04:54:08PM +0200, Ard Biesheuvel wrote:
> Move the code that stores the arguments passed to the EFI entrypoint
> into the .text section, so that it can be moved into a separate
> compilation unit in a subsequent patch.
> 
> Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
> ---
>  arch/x86/boot/compressed/head_64.S | 34 ++++++++++++--------
>  1 file changed, 20 insertions(+), 14 deletions(-)
> 
> diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S
> index d33f060900d2..1ba2fc2357e6 100644
> --- a/arch/x86/boot/compressed/head_64.S
> +++ b/arch/x86/boot/compressed/head_64.S
> @@ -303,24 +303,28 @@ SYM_FUNC_START(efi32_stub_entry)
>  	popl	%ecx
>  	popl	%edx
>  	popl	%esi
> +	jmp	efi32_entry
> +SYM_FUNC_END(efi32_stub_entry)
>  
> +	.text
> +SYM_FUNC_START_LOCAL(efi32_entry)
>  	call	1f
> -1:	pop	%ebp
> -	subl	$ rva(1b), %ebp
> -
> -	movl	%esi, rva(efi32_boot_args+8)(%ebp)
> -SYM_INNER_LABEL(efi32_pe_stub_entry, SYM_L_LOCAL)
> -	movl	%ecx, rva(efi32_boot_args)(%ebp)
> -	movl	%edx, rva(efi32_boot_args+4)(%ebp)
> -	movb	$0, rva(efi_is64)(%ebp)
> +1:	pop	%ebx

I'm guessing according to the EFI mixed mode calling convention, %ebx is
not a live register which gets overwritten here...?

Looking at efi32_pe_entry() from where this is called, %ebx looks live.

What am I missing?
Ard Biesheuvel Oct. 6, 2022, 10:56 a.m. UTC | #2
On Thu, 6 Oct 2022 at 12:42, Borislav Petkov <bp@alien8.de> wrote:
>
> On Wed, Sep 21, 2022 at 04:54:08PM +0200, Ard Biesheuvel wrote:
> > Move the code that stores the arguments passed to the EFI entrypoint
> > into the .text section, so that it can be moved into a separate
> > compilation unit in a subsequent patch.
> >
> > Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
> > ---
> >  arch/x86/boot/compressed/head_64.S | 34 ++++++++++++--------
> >  1 file changed, 20 insertions(+), 14 deletions(-)
> >
> > diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S
> > index d33f060900d2..1ba2fc2357e6 100644
> > --- a/arch/x86/boot/compressed/head_64.S
> > +++ b/arch/x86/boot/compressed/head_64.S
> > @@ -303,24 +303,28 @@ SYM_FUNC_START(efi32_stub_entry)
> >       popl    %ecx
> >       popl    %edx
> >       popl    %esi
> > +     jmp     efi32_entry
> > +SYM_FUNC_END(efi32_stub_entry)
> >
> > +     .text
> > +SYM_FUNC_START_LOCAL(efi32_entry)
> >       call    1f
> > -1:   pop     %ebp
> > -     subl    $ rva(1b), %ebp
> > -
> > -     movl    %esi, rva(efi32_boot_args+8)(%ebp)
> > -SYM_INNER_LABEL(efi32_pe_stub_entry, SYM_L_LOCAL)
> > -     movl    %ecx, rva(efi32_boot_args)(%ebp)
> > -     movl    %edx, rva(efi32_boot_args+4)(%ebp)
> > -     movb    $0, rva(efi_is64)(%ebp)
> > +1:   pop     %ebx
>
> I'm guessing according to the EFI mixed mode calling convention, %ebx is
> not a live register which gets overwritten here...?
>
> Looking at efi32_pe_entry() from where this is called, %ebx looks live.
>
> What am I missing?
>

efi32_pe_entry() preserves and restores the caller's value of %ebx,
because from there, we might actually return control to the firmware.
The value it keeps in %ebx itself is not live when it jumps to
efi32_entry - it stores its value into image_offset, which is reloaded
from memory at a later point.

efi32_stub_entry() is the 'EFI handover protocol' entry point, which
cannot return to the firmware (and we discard the return address
already) so %ebx can be clobbered.
Borislav Petkov Oct. 6, 2022, 11:13 a.m. UTC | #3
On Thu, Oct 06, 2022 at 12:56:09PM +0200, Ard Biesheuvel wrote:
> efi32_pe_entry() preserves and restores the caller's value of %ebx,
> because from there, we might actually return control to the firmware.
> The value it keeps in %ebx itself is not live when it jumps to
> efi32_entry - it stores its value into image_offset, which is reloaded
> from memory at a later point.

Hmm, might be prudent to have a comment there because it is using %ebx a
couple of insns before the JMP:

        subl    %esi, %ebx
		      ^^^^
        movl    %ebx, rva(image_offset)(%ebp)   // save image_offset

<--- I think you mean that after this, %ebx is not needed anymore?

        xorl    %esi, %esi
        jmp     efi32_entry

2:      popl    %edi                            // restore callee-save registers
        popl    %ebx

and this restores its original value ofc.

> efi32_stub_entry() is the 'EFI handover protocol' entry point, which
> cannot return to the firmware (and we discard the return address
> already) so %ebx can be clobbered.

That info would be good to have in a comment above it.

Thx.
Ard Biesheuvel Oct. 6, 2022, 11:19 a.m. UTC | #4
On Thu, 6 Oct 2022 at 13:13, Borislav Petkov <bp@alien8.de> wrote:
>
> On Thu, Oct 06, 2022 at 12:56:09PM +0200, Ard Biesheuvel wrote:
> > efi32_pe_entry() preserves and restores the caller's value of %ebx,
> > because from there, we might actually return control to the firmware.
> > The value it keeps in %ebx itself is not live when it jumps to
> > efi32_entry - it stores its value into image_offset, which is reloaded
> > from memory at a later point.
>
> Hmm, might be prudent to have a comment there because it is using %ebx a
> couple of insns before the JMP:
>
>         subl    %esi, %ebx
>                       ^^^^
>         movl    %ebx, rva(image_offset)(%ebp)   // save image_offset
>
> <--- I think you mean that after this, %ebx is not needed anymore?
>

Exactly.

>         xorl    %esi, %esi
>         jmp     efi32_entry
>
> 2:      popl    %edi                            // restore callee-save registers
>         popl    %ebx
>
> and this restores its original value ofc.
>
> > efi32_stub_entry() is the 'EFI handover protocol' entry point, which
> > cannot return to the firmware (and we discard the return address
> > already) so %ebx can be clobbered.
>
> That info would be good to have in a comment above it.
>

Fair enough.
Ard Biesheuvel Oct. 6, 2022, 12:27 p.m. UTC | #5
On Thu, 6 Oct 2022 at 13:19, Ard Biesheuvel <ardb@kernel.org> wrote:
>
> On Thu, 6 Oct 2022 at 13:13, Borislav Petkov <bp@alien8.de> wrote:
> >
> > On Thu, Oct 06, 2022 at 12:56:09PM +0200, Ard Biesheuvel wrote:
> > > efi32_pe_entry() preserves and restores the caller's value of %ebx,
> > > because from there, we might actually return control to the firmware.
> > > The value it keeps in %ebx itself is not live when it jumps to
> > > efi32_entry - it stores its value into image_offset, which is reloaded
> > > from memory at a later point.
> >
> > Hmm, might be prudent to have a comment there because it is using %ebx a
> > couple of insns before the JMP:
> >
> >         subl    %esi, %ebx
> >                       ^^^^
> >         movl    %ebx, rva(image_offset)(%ebp)   // save image_offset
> >
> > <--- I think you mean that after this, %ebx is not needed anymore?
> >
>
> Exactly.
>
> >         xorl    %esi, %esi
> >         jmp     efi32_entry
> >
> > 2:      popl    %edi                            // restore callee-save registers
> >         popl    %ebx
> >
> > and this restores its original value ofc.
> >
> > > efi32_stub_entry() is the 'EFI handover protocol' entry point, which
> > > cannot return to the firmware (and we discard the return address
> > > already) so %ebx can be clobbered.
> >
> > That info would be good to have in a comment above it.
> >
>
> Fair enough.

I'll add the below in the next revision

--- a/arch/x86/boot/compressed/head_64.S
+++ b/arch/x86/boot/compressed/head_64.S
@@ -307,6 +307,19 @@ SYM_FUNC_START(efi32_stub_entry)
 SYM_FUNC_END(efi32_stub_entry)

        .text
+/*
+ * This is the common EFI stub entry point for mixed mode.
+ *
+ * Arguments:  %ecx    image handle
+ *             %edx    EFI system table pointer
+ *             %esi    struct bootparams pointer (or NULL when not using
+ *                     the EFI handover protocol)
+ *
+ * Since this is the point of no return for ordinary execution, no registers
+ * are considered live except for the function parameters. [Note that the EFI
+ * stub may still exit and return to the firmware using the Exit() EFI boot
+ * service.]
+ */
 SYM_FUNC_START_LOCAL(efi32_entry)
        call    1f
 1:     pop     %ebx
@@ -837,7 +850,8 @@ SYM_FUNC_START(efi32_pe_entry)
        subl    %esi, %ebx
        movl    %ebx, rva(image_offset)(%ebp)   // save image_offset
        xorl    %esi, %esi
-       jmp     efi32_entry
+       jmp     efi32_entry                     // pass %ecx, %edx, %esi
+                                               // no other registers
remain live

 2:     popl    %edi                            // restore callee-save registers
        popl    %ebx
Borislav Petkov Oct. 7, 2022, 8:56 a.m. UTC | #6
On Thu, Oct 06, 2022 at 02:27:54PM +0200, Ard Biesheuvel wrote:
> I'll add the below in the next revision

LGTM.

Thx.
diff mbox series

Patch

diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S
index d33f060900d2..1ba2fc2357e6 100644
--- a/arch/x86/boot/compressed/head_64.S
+++ b/arch/x86/boot/compressed/head_64.S
@@ -303,24 +303,28 @@  SYM_FUNC_START(efi32_stub_entry)
 	popl	%ecx
 	popl	%edx
 	popl	%esi
+	jmp	efi32_entry
+SYM_FUNC_END(efi32_stub_entry)
 
+	.text
+SYM_FUNC_START_LOCAL(efi32_entry)
 	call	1f
-1:	pop	%ebp
-	subl	$ rva(1b), %ebp
-
-	movl	%esi, rva(efi32_boot_args+8)(%ebp)
-SYM_INNER_LABEL(efi32_pe_stub_entry, SYM_L_LOCAL)
-	movl	%ecx, rva(efi32_boot_args)(%ebp)
-	movl	%edx, rva(efi32_boot_args+4)(%ebp)
-	movb	$0, rva(efi_is64)(%ebp)
+1:	pop	%ebx
 
 	/* Save firmware GDTR and code/data selectors */
-	sgdtl	rva(efi32_boot_gdt)(%ebp)
-	movw	%cs, rva(efi32_boot_cs)(%ebp)
-	movw	%ds, rva(efi32_boot_ds)(%ebp)
+	sgdtl	(efi32_boot_gdt - 1b)(%ebx)
+	movw	%cs, (efi32_boot_cs - 1b)(%ebx)
+	movw	%ds, (efi32_boot_ds - 1b)(%ebx)
 
 	/* Store firmware IDT descriptor */
-	sidtl	rva(efi32_boot_idt)(%ebp)
+	sidtl	(efi32_boot_idt - 1b)(%ebx)
+
+	/* Store boot arguments */
+	leal	(efi32_boot_args - 1b)(%ebx), %ebx
+	movl	%ecx, 0(%ebx)
+	movl	%edx, 4(%ebx)
+	movl	%esi, 8(%ebx)
+	movb	$0x0, 12(%ebx)          // efi_is64
 
 	/* Disable paging */
 	movl	%cr0, %eax
@@ -328,7 +332,8 @@  SYM_INNER_LABEL(efi32_pe_stub_entry, SYM_L_LOCAL)
 	movl	%eax, %cr0
 
 	jmp	startup_32
-SYM_FUNC_END(efi32_stub_entry)
+SYM_FUNC_END(efi32_entry)
+	__HEAD
 #endif
 
 	.code64
@@ -831,7 +836,8 @@  SYM_FUNC_START(efi32_pe_entry)
 	 */
 	subl	%esi, %ebx
 	movl	%ebx, rva(image_offset)(%ebp)	// save image_offset
-	jmp	efi32_pe_stub_entry
+	xorl	%esi, %esi
+	jmp	efi32_entry
 
 2:	popl	%edi				// restore callee-save registers
 	popl	%ebx