Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+40 −14
Original line number Diff line number Diff line
@@ -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
+41 −15
Original line number Diff line number Diff line
@@ -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,18 +418,7 @@ 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