x86/efi: Fixup GOT in all boot code paths
Maarten reported that his Macbook pro 8.2 stopped booting after commit
f23cf8bd5c
("efi/x86: efistub: Move shared dependencies to
<asm/efi.h>"), the main feature of which is changing the visibility of
symbol 'efi_early' from local to global.
By making 'efi_early' global we end up requiring an entry in the Global
Offset Table. Unfortunately, while we do include code to fixup GOT
entries in the early boot code, it's only called after we've executed
the EFI boot stub.
What this amounts to is that references to 'efi_early' in the EFI boot
stub don't point to the correct place.
Since we've got multiple boot entry points we need to be prepared to
fixup the GOT in multiple places, while ensuring that we never do it
more than once, otherwise the GOT entries will still point to the wrong
place.
Reported-by: Maarten Lankhorst <maarten.lankhorst@canonical.com>
Tested-by: Maarten Lankhorst <maarten.lankhorst@canonical.com>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Matt Fleming <matt.fleming@intel.com>
This commit is contained in:
parent
47226ad4f4
commit
9cb0e39423
@ -30,6 +30,33 @@
|
||||
#include <asm/boot.h>
|
||||
#include <asm/asm-offsets.h>
|
||||
|
||||
/*
|
||||
* Adjust our own GOT
|
||||
*
|
||||
* The relocation base must be in %ebx
|
||||
*
|
||||
* It is safe to call this macro more than once, because in some of the
|
||||
* code paths multiple invocations are inevitable, e.g. via the efi*
|
||||
* entry points.
|
||||
*
|
||||
* Relocation is only performed the first time.
|
||||
*/
|
||||
.macro FIXUP_GOT
|
||||
cmpb $1, got_fixed(%ebx)
|
||||
je 2f
|
||||
|
||||
leal _got(%ebx), %edx
|
||||
leal _egot(%ebx), %ecx
|
||||
1:
|
||||
cmpl %ecx, %edx
|
||||
jae 2f
|
||||
addl %ebx, (%edx)
|
||||
addl $4, %edx
|
||||
jmp 1b
|
||||
2:
|
||||
movb $1, got_fixed(%ebx)
|
||||
.endm
|
||||
|
||||
__HEAD
|
||||
ENTRY(startup_32)
|
||||
#ifdef CONFIG_EFI_STUB
|
||||
@ -56,6 +83,9 @@ ENTRY(efi_pe_entry)
|
||||
add %esi, 88(%eax)
|
||||
pushl %eax
|
||||
|
||||
movl %esi, %ebx
|
||||
FIXUP_GOT
|
||||
|
||||
call make_boot_params
|
||||
cmpl $0, %eax
|
||||
je fail
|
||||
@ -81,6 +111,10 @@ ENTRY(efi32_stub_entry)
|
||||
leal efi32_config(%esi), %eax
|
||||
add %esi, 88(%eax)
|
||||
pushl %eax
|
||||
|
||||
movl %esi, %ebx
|
||||
FIXUP_GOT
|
||||
|
||||
2:
|
||||
call efi_main
|
||||
cmpl $0, %eax
|
||||
@ -190,19 +224,7 @@ relocated:
|
||||
shrl $2, %ecx
|
||||
rep stosl
|
||||
|
||||
/*
|
||||
* Adjust our own GOT
|
||||
*/
|
||||
leal _got(%ebx), %edx
|
||||
leal _egot(%ebx), %ecx
|
||||
1:
|
||||
cmpl %ecx, %edx
|
||||
jae 2f
|
||||
addl %ebx, (%edx)
|
||||
addl $4, %edx
|
||||
jmp 1b
|
||||
2:
|
||||
|
||||
FIXUP_GOT
|
||||
/*
|
||||
* Do the decompression, and jump to the new kernel..
|
||||
*/
|
||||
@ -225,8 +247,12 @@ relocated:
|
||||
xorl %ebx, %ebx
|
||||
jmp *%eax
|
||||
|
||||
#ifdef CONFIG_EFI_STUB
|
||||
.data
|
||||
/* Have we relocated the GOT? */
|
||||
got_fixed:
|
||||
.byte 0
|
||||
|
||||
#ifdef CONFIG_EFI_STUB
|
||||
efi32_config:
|
||||
.fill 11,8,0
|
||||
.long efi_call_phys
|
||||
|
@ -32,6 +32,33 @@
|
||||
#include <asm/processor-flags.h>
|
||||
#include <asm/asm-offsets.h>
|
||||
|
||||
/*
|
||||
* Adjust our own GOT
|
||||
*
|
||||
* The relocation base must be in %rbx
|
||||
*
|
||||
* It is safe to call this macro more than once, because in some of the
|
||||
* code paths multiple invocations are inevitable, e.g. via the efi*
|
||||
* entry points.
|
||||
*
|
||||
* Relocation is only performed the first time.
|
||||
*/
|
||||
.macro FIXUP_GOT
|
||||
cmpb $1, got_fixed(%rip)
|
||||
je 2f
|
||||
|
||||
leaq _got(%rip), %rdx
|
||||
leaq _egot(%rip), %rcx
|
||||
1:
|
||||
cmpq %rcx, %rdx
|
||||
jae 2f
|
||||
addq %rbx, (%rdx)
|
||||
addq $8, %rdx
|
||||
jmp 1b
|
||||
2:
|
||||
movb $1, got_fixed(%rip)
|
||||
.endm
|
||||
|
||||
__HEAD
|
||||
.code32
|
||||
ENTRY(startup_32)
|
||||
@ -252,10 +279,13 @@ ENTRY(efi_pe_entry)
|
||||
subq $1b, %rbp
|
||||
|
||||
/*
|
||||
* Relocate efi_config->call().
|
||||
* Relocate efi_config->call() and the GOT entries.
|
||||
*/
|
||||
addq %rbp, efi64_config+88(%rip)
|
||||
|
||||
movq %rbp, %rbx
|
||||
FIXUP_GOT
|
||||
|
||||
movq %rax, %rdi
|
||||
call make_boot_params
|
||||
cmpq $0,%rax
|
||||
@ -271,10 +301,13 @@ handover_entry:
|
||||
subq $1b, %rbp
|
||||
|
||||
/*
|
||||
* Relocate efi_config->call().
|
||||
* Relocate efi_config->call() and the GOT entries.
|
||||
*/
|
||||
movq efi_config(%rip), %rax
|
||||
addq %rbp, 88(%rax)
|
||||
|
||||
movq %rbp, %rbx
|
||||
FIXUP_GOT
|
||||
2:
|
||||
movq efi_config(%rip), %rdi
|
||||
call efi_main
|
||||
@ -385,19 +418,8 @@ relocated:
|
||||
shrq $3, %rcx
|
||||
rep stosq
|
||||
|
||||
/*
|
||||
* Adjust our own GOT
|
||||
*/
|
||||
leaq _got(%rip), %rdx
|
||||
leaq _egot(%rip), %rcx
|
||||
1:
|
||||
cmpq %rcx, %rdx
|
||||
jae 2f
|
||||
addq %rbx, (%rdx)
|
||||
addq $8, %rdx
|
||||
jmp 1b
|
||||
2:
|
||||
|
||||
FIXUP_GOT
|
||||
|
||||
/*
|
||||
* Do the decompression, and jump to the new kernel..
|
||||
*/
|
||||
@ -437,6 +459,10 @@ gdt:
|
||||
.quad 0x0000000000000000 /* TS continued */
|
||||
gdt_end:
|
||||
|
||||
/* Have we relocated the GOT? */
|
||||
got_fixed:
|
||||
.byte 0
|
||||
|
||||
#ifdef CONFIG_EFI_STUB
|
||||
efi_config:
|
||||
.quad 0
|
||||
|
Loading…
Reference in New Issue
Block a user