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 <matt.hfleming@intel.com>
Link: http://lkml.kernel.org/r/1334584744.26997.14.camel@mfleming-mobl1.ger.corp.intel.com
Reported-by: Jordan Justen <jordan.l.justen@intel.com>
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
Cc: <stable@vger.kernel.org> v3.3
__HEAD
ENTRY(startup_32)
#ifdef CONFIG_EFI_STUB
__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.
/*
* We don't need the return address, so set up the stack so
* efi_main() can find its arugments.
call efi_main
cmpl $0, %eax
call efi_main
cmpl $0, %eax
+ /* EFI init failed, so hang. */
+ hlt
+ jmp 1b
+2:
+ call 3f
+3:
subl BP_pref_address(%esi), %eax
add BP_code32_start(%esi), %eax
leal preferred_addr(%eax), %eax
subl BP_pref_address(%esi), %eax
add BP_code32_start(%esi), %eax
leal preferred_addr(%eax), %eax
* entire text+data+bss and hopefully all of memory.
*/
#ifdef CONFIG_EFI_STUB
* entire text+data+bss and hopefully all of memory.
*/
#ifdef CONFIG_EFI_STUB
+ /*
+ * 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
mov %rcx, %rdi
mov %rdx, %rsi
call efi_main
- popq %rsi
- cmpq $0,%rax
- je preferred_addr
+ /* EFI init failed, so hang. */
+ hlt
+ jmp 1b
+2:
+ call 3f
+3:
subq BP_pref_address(%rsi), %rax
add BP_code32_start(%esi), %eax
leaq preferred_addr(%rax), %rax
subq BP_pref_address(%rsi), %rax
add BP_code32_start(%esi), %eax
leaq preferred_addr(%rax), %rax
put_unaligned_le32(file_sz, &buf[pe_header + 0x50]);
#ifdef CONFIG_X86_32
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]);
/* .text size */
put_unaligned_le32(file_sz, &buf[pe_header + 0xb0]);
/*
* Address of entry point. startup_32 is at the beginning and
* the 64-bit entry point (startup_64) is always 512 bytes
/*
* Address of entry point. startup_32 is at the beginning and
* the 64-bit entry point (startup_64) is always 512 bytes
+ * 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]);
/* .text size */
put_unaligned_le32(file_sz, &buf[pe_header + 0xc0]);