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: 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
This commit is contained in:
parent
d7de8649f3
commit
b1994304fc
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]);
|
||||
|
|
Loading…
Reference in a new issue