Commit 9cb0e394 authored by Matt Fleming's avatar Matt Fleming

x86/efi: Fixup GOT in all boot code paths

Maarten reported that his Macbook pro 8.2 stopped booting after commit
f23cf8bd ("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: default avatarMaarten Lankhorst <maarten.lankhorst@canonical.com>
Tested-by: default avatarMaarten Lankhorst <maarten.lankhorst@canonical.com>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: default avatarMatt Fleming <matt.fleming@intel.com>
parent 47226ad4
...@@ -30,6 +30,33 @@ ...@@ -30,6 +30,33 @@
#include <asm/boot.h> #include <asm/boot.h>
#include <asm/asm-offsets.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 __HEAD
ENTRY(startup_32) ENTRY(startup_32)
#ifdef CONFIG_EFI_STUB #ifdef CONFIG_EFI_STUB
...@@ -56,6 +83,9 @@ ENTRY(efi_pe_entry) ...@@ -56,6 +83,9 @@ ENTRY(efi_pe_entry)
add %esi, 88(%eax) add %esi, 88(%eax)
pushl %eax pushl %eax
movl %esi, %ebx
FIXUP_GOT
call make_boot_params call make_boot_params
cmpl $0, %eax cmpl $0, %eax
je fail je fail
...@@ -81,6 +111,10 @@ ENTRY(efi32_stub_entry) ...@@ -81,6 +111,10 @@ ENTRY(efi32_stub_entry)
leal efi32_config(%esi), %eax leal efi32_config(%esi), %eax
add %esi, 88(%eax) add %esi, 88(%eax)
pushl %eax pushl %eax
movl %esi, %ebx
FIXUP_GOT
2: 2:
call efi_main call efi_main
cmpl $0, %eax cmpl $0, %eax
...@@ -190,19 +224,7 @@ relocated: ...@@ -190,19 +224,7 @@ relocated:
shrl $2, %ecx shrl $2, %ecx
rep stosl rep stosl
/* FIXUP_GOT
* 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:
/* /*
* Do the decompression, and jump to the new kernel.. * Do the decompression, and jump to the new kernel..
*/ */
...@@ -225,8 +247,12 @@ relocated: ...@@ -225,8 +247,12 @@ relocated:
xorl %ebx, %ebx xorl %ebx, %ebx
jmp *%eax jmp *%eax
#ifdef CONFIG_EFI_STUB
.data .data
/* Have we relocated the GOT? */
got_fixed:
.byte 0
#ifdef CONFIG_EFI_STUB
efi32_config: efi32_config:
.fill 11,8,0 .fill 11,8,0
.long efi_call_phys .long efi_call_phys
......
...@@ -32,6 +32,33 @@ ...@@ -32,6 +32,33 @@
#include <asm/processor-flags.h> #include <asm/processor-flags.h>
#include <asm/asm-offsets.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 __HEAD
.code32 .code32
ENTRY(startup_32) ENTRY(startup_32)
...@@ -252,10 +279,13 @@ ENTRY(efi_pe_entry) ...@@ -252,10 +279,13 @@ ENTRY(efi_pe_entry)
subq $1b, %rbp subq $1b, %rbp
/* /*
* Relocate efi_config->call(). * Relocate efi_config->call() and the GOT entries.
*/ */
addq %rbp, efi64_config+88(%rip) addq %rbp, efi64_config+88(%rip)
movq %rbp, %rbx
FIXUP_GOT
movq %rax, %rdi movq %rax, %rdi
call make_boot_params call make_boot_params
cmpq $0,%rax cmpq $0,%rax
...@@ -271,10 +301,13 @@ handover_entry: ...@@ -271,10 +301,13 @@ handover_entry:
subq $1b, %rbp subq $1b, %rbp
/* /*
* Relocate efi_config->call(). * Relocate efi_config->call() and the GOT entries.
*/ */
movq efi_config(%rip), %rax movq efi_config(%rip), %rax
addq %rbp, 88(%rax) addq %rbp, 88(%rax)
movq %rbp, %rbx
FIXUP_GOT
2: 2:
movq efi_config(%rip), %rdi movq efi_config(%rip), %rdi
call efi_main call efi_main
...@@ -385,19 +418,8 @@ relocated: ...@@ -385,19 +418,8 @@ relocated:
shrq $3, %rcx shrq $3, %rcx
rep stosq rep stosq
/* FIXUP_GOT
* 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:
/* /*
* Do the decompression, and jump to the new kernel.. * Do the decompression, and jump to the new kernel..
*/ */
...@@ -437,6 +459,10 @@ gdt: ...@@ -437,6 +459,10 @@ gdt:
.quad 0x0000000000000000 /* TS continued */ .quad 0x0000000000000000 /* TS continued */
gdt_end: gdt_end:
/* Have we relocated the GOT? */
got_fixed:
.byte 0
#ifdef CONFIG_EFI_STUB #ifdef CONFIG_EFI_STUB
efi_config: efi_config:
.quad 0 .quad 0
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment