Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b1994304 authored by Matt Fleming's avatar Matt Fleming Committed by H. Peter Anvin
Browse files

x86, efi: Add dedicated EFI stub entry point



The method used to work out whether we were booted by EFI firmware or
via a boot loader is broken. Because efi_main() is always executed
when booting from a boot loader we will dereference invalid pointers
either on the stack (CONFIG_X86_32) or contained in %rdx
(CONFIG_X86_64) when searching for an EFI System Table signature.

Instead of dereferencing these invalid system table pointers, add a
new entry point that is only used when booting from EFI firmware, when
we know the pointer arguments will be valid. With this change legacy
boot loaders will no longer execute efi_main(), but will instead skip
EFI stub initialisation completely.

[ hpa: Marking this for urgent/stable since it is a regression when
  the option is enabled; without the option the patch has no effect ]

Signed-off-by: default avatarMatt Fleming <matt.hfleming@intel.com>
Link: http://lkml.kernel.org/r/1334584744.26997.14.camel@mfleming-mobl1.ger.corp.intel.com


Reported-by: default avatarJordan Justen <jordan.l.justen@intel.com>
Signed-off-by: default avatarH. Peter Anvin <hpa@linux.intel.com>
Cc: <stable@vger.kernel.org> v3.3
parent d7de8649
Loading
Loading
Loading
Loading
+11 −3
Original line number Diff line number Diff line
@@ -33,6 +33,9 @@
	__HEAD
ENTRY(startup_32)
#ifdef CONFIG_EFI_STUB
	jmp	preferred_addr

	.balign	0x10
	/*
	 * We don't need the return address, so set up the stack so
	 * efi_main() can find its arugments.
@@ -41,12 +44,17 @@ ENTRY(startup_32)

	call	efi_main
	cmpl	$0, %eax
	je	preferred_addr
	movl	%eax, %esi
	call	1f
	jne	2f
1:
	/* EFI init failed, so hang. */
	hlt
	jmp	1b
2:
	call	3f
3:
	popl	%eax
	subl	$1b, %eax
	subl	$3b, %eax
	subl	BP_pref_address(%esi), %eax
	add	BP_code32_start(%esi), %eax
	leal	preferred_addr(%eax), %eax
+16 −6
Original line number Diff line number Diff line
@@ -200,18 +200,28 @@ ENTRY(startup_64)
	 * entire text+data+bss and hopefully all of memory.
	 */
#ifdef CONFIG_EFI_STUB
	pushq	%rsi
	/*
	 * The entry point for the PE/COFF executable is 0x210, so only
	 * legacy boot loaders will execute this jmp.
	 */
	jmp	preferred_addr

	.org 0x210
	mov	%rcx, %rdi
	mov	%rdx, %rsi
	call	efi_main
	popq	%rsi
	cmpq	$0,%rax
	je	preferred_addr
	movq	%rax,%rsi
	call	1f
	cmpq	$0,%rax
	jne	2f
1:
	/* EFI init failed, so hang. */
	hlt
	jmp	1b
2:
	call	3f
3:
	popq	%rax
	subq	$1b, %rax
	subq	$3b, %rax
	subq	BP_pref_address(%rsi), %rax
	add	BP_code32_start(%esi), %eax
	leaq	preferred_addr(%rax), %rax
+11 −4
Original line number Diff line number Diff line
@@ -205,8 +205,13 @@ int main(int argc, char ** argv)
	put_unaligned_le32(file_sz, &buf[pe_header + 0x50]);

#ifdef CONFIG_X86_32
	/* Address of entry point */
	put_unaligned_le32(i, &buf[pe_header + 0x28]);
	/*
	 * Address of entry point.
	 *
	 * The EFI stub entry point is +16 bytes from the start of
	 * the .text section.
	 */
	put_unaligned_le32(i + 16, &buf[pe_header + 0x28]);

	/* .text size */
	put_unaligned_le32(file_sz, &buf[pe_header + 0xb0]);
@@ -217,9 +222,11 @@ int main(int argc, char ** argv)
	/*
	 * Address of entry point. startup_32 is at the beginning and
	 * the 64-bit entry point (startup_64) is always 512 bytes
	 * after.
	 * after. The EFI stub entry point is 16 bytes after that, as
	 * the first instruction allows legacy loaders to jump over
	 * the EFI stub initialisation
	 */
	put_unaligned_le32(i + 512, &buf[pe_header + 0x28]);
	put_unaligned_le32(i + 528, &buf[pe_header + 0x28]);

	/* .text size */
	put_unaligned_le32(file_sz, &buf[pe_header + 0xc0]);