Here is the minimal backport.  I would like to see this one in -stable,
as there are ABI implications.

        -hpa

>From ae59d745c8f3b70efa046f056065922743ffad6e Mon Sep 17 00:00:00 2001
From: Matt Fleming <[email protected]>
Date: Sun, 15 Apr 2012 16:06:04 +0100
Subject: [PATCH] x86, efi: Add dedicated EFI stub entry point

[ upstream commit b1994304fc399f5d3a5368c81111d713490c4799 ]

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: Matt Fleming <[email protected]>
Link: http://lkml.kernel.org/r/[email protected]
Reported-by: Jordan Justen <[email protected]>
Signed-off-by: H. Peter Anvin <[email protected]>
Cc: <[email protected]> v3.3
---
 arch/x86/boot/compressed/head_32.S |   14 +++++++++++---
 arch/x86/boot/compressed/head_64.S |   22 ++++++++++++++++------
 arch/x86/boot/tools/build.c        |   15 +++++++++++----
 3 files changed, 38 insertions(+), 13 deletions(-)

diff --git a/arch/x86/boot/compressed/head_32.S b/arch/x86/boot/compressed/head_32.S
index a055993..c85e3ac 100644
--- a/arch/x86/boot/compressed/head_32.S
+++ b/arch/x86/boot/compressed/head_32.S
@@ -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
diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S
index 558d76c..87e03a1 100644
--- a/arch/x86/boot/compressed/head_64.S
+++ b/arch/x86/boot/compressed/head_64.S
@@ -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
diff --git a/arch/x86/boot/tools/build.c b/arch/x86/boot/tools/build.c
index 4e9bd6b..e4b18a6 100644
--- a/arch/x86/boot/tools/build.c
+++ b/arch/x86/boot/tools/build.c
@@ -209,8 +209,13 @@ int main(int argc, char ** argv)
 	*(unsigned int *)&buf[pe_header + 0x50] = file_sz;
 
 #ifdef CONFIG_X86_32
-	/* Address of entry point */
-	*(unsigned int *)&buf[pe_header + 0x28] = i;
+	/*
+	 * Address of entry point.
+	 *
+	 * The EFI stub entry point is +16 bytes from the start of
+	 * the .text section.
+	 */
+	*(unsigned int *)&buf[pe_header + 0x28] = i + 16;
 
 	/* .text size */
 	*(unsigned int *)&buf[pe_header + 0xb0] = file_sz;
@@ -221,9 +226,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
 	 */
-	*(unsigned int *)&buf[pe_header + 0x28] = i + 512;
+	*(unsigned int *)&buf[pe_header + 0x28] = i + 528;
 
 	/* .text size */
 	*(unsigned int *)&buf[pe_header + 0xc0] = file_sz;
-- 
1.7.6.5

Reply via email to