From 189cc862893882b254316cb453cc8c0076f8815c Mon Sep 17 00:00:00 2001 From: Adam Williamson Date: Sat, 13 Sep 2014 11:27:40 -0700 Subject: [PATCH] add UEFI boot fixes from mfleming's 'urgent' branch (BKO #84241) --- kernel.spec | 7 + ...efi-fixup-got-in-all-boot-code-paths.patch | 227 ++++++++++++++++++ ...y-load-initrd-above-4g-on-second-try.patch | 79 ++++++ 3 files changed, 313 insertions(+) create mode 100644 x86-efi-fixup-got-in-all-boot-code-paths.patch create mode 100644 x86-efi-only-load-initrd-above-4g-on-second-try.patch diff --git a/kernel.spec b/kernel.spec index f6a602303..264e429f4 100644 --- a/kernel.spec +++ b/kernel.spec @@ -634,6 +634,11 @@ Patch31010: 0001-ACPI-temporary-dep-solution-for-battery-support.patch # Add SDIO ID for the V8P wireless adapter to ath6kl driver Patch31200: support-Dell-OEM-chipset-found-in-Venue-8-Pro-SDIO-I.patch +# UEFI boot fixes from Matt Fleming, fix +# https://bugzilla.kernel.org/show_bug.cgi?id=84241 +Patch31201: x86-efi-only-load-initrd-above-4g-on-second-try.patch +Patch21202: x86-efi-fixup-got-in-all-boot-code-paths.patch + # END OF AWB PATCH DEFINITIONS # END OF PATCH DEFINITIONS @@ -1376,6 +1381,8 @@ ApplyPatch kernel-arm64.patch -R # AWB (BAYTRAIL) PATCH APPLICATIONS ApplyPatch 0001-ACPI-temporary-dep-solution-for-battery-support.patch ApplyPatch support-Dell-OEM-chipset-found-in-Venue-8-Pro-SDIO-I.patch +ApplyPatch x86-efi-only-load-initrd-above-4g-on-second-try.patch +ApplyPatch x86-efi-fixup-got-in-all-boot-code-paths.patch # END OF AWB (BAYTRAIL) PATCH APPLICATIONS diff --git a/x86-efi-fixup-got-in-all-boot-code-paths.patch b/x86-efi-fixup-got-in-all-boot-code-paths.patch new file mode 100644 index 000000000..0c82266c3 --- /dev/null +++ b/x86-efi-fixup-got-in-all-boot-code-paths.patch @@ -0,0 +1,227 @@ +From 9cb0e394234d244fe5a97e743ec9dd7ddff7e64b Mon Sep 17 00:00:00 2001 +From: Matt Fleming +Date: Fri, 5 Sep 2014 14:52:26 +0100 +Subject: x86/efi: Fixup GOT in all boot code paths + +Maarten reported that his Macbook pro 8.2 stopped booting after commit +f23cf8bd5c1f49 ("efi/x86: efistub: Move shared dependencies to +"), 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 +Tested-by: Maarten Lankhorst +Cc: Ard Biesheuvel +Signed-off-by: Matt Fleming + +diff --git a/arch/x86/boot/compressed/head_32.S b/arch/x86/boot/compressed/head_32.S +index cbed140..d6b8aa4 100644 +--- a/arch/x86/boot/compressed/head_32.S ++++ b/arch/x86/boot/compressed/head_32.S +@@ -30,6 +30,33 @@ + #include + #include + ++/* ++ * 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 +diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S +index 2884e0c..50f69c7 100644 +--- a/arch/x86/boot/compressed/head_64.S ++++ b/arch/x86/boot/compressed/head_64.S +@@ -32,6 +32,33 @@ + #include + #include + ++/* ++ * 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 +-- +cgit v0.10.1 + + diff --git a/x86-efi-only-load-initrd-above-4g-on-second-try.patch b/x86-efi-only-load-initrd-above-4g-on-second-try.patch new file mode 100644 index 000000000..f977d8e22 --- /dev/null +++ b/x86-efi-only-load-initrd-above-4g-on-second-try.patch @@ -0,0 +1,79 @@ +From 47226ad4f4cfd1e91ded7f2ec42f83ff1c624663 Mon Sep 17 00:00:00 2001 +From: Yinghai Lu +Date: Wed, 3 Sep 2014 21:50:07 -0700 +Subject: x86/efi: Only load initrd above 4g on second try +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Mantas found that after commit 4bf7111f5016 ("x86/efi: Support initrd +loaded above 4G"), the kernel freezes at the earliest possible moment +when trying to boot via UEFI on Asus laptop. + +Revert to old way to load initrd under 4G on first try, second try will +use above 4G buffer when initrd is too big and does not fit under 4G. + +[ The cause of the freeze appears to be a firmware bug when reading + file data into buffers above 4GB, though the exact reason is unknown. + Mantas reports that the hang can be avoid if the file size is a + multiple of 512 bytes, but I've seen some ASUS firmware simply + corrupting the file data rather than freezing. + + Laszlo fixed an issue in the upstream EDK2 DiskIO code in Aug 2013 + which may possibly be related, commit 4e39b75e ("MdeModulePkg/DiskIoDxe: + fix source/destination pointer of overrun transfer"). + + Whatever the cause, it's unlikely that a fix will be forthcoming + from the vendor, hence the workaround - Matt ] + +Cc: Laszlo Ersek +Reported-by: Mantas Mikulėnas +Reported-by: Harald Hoyer +Tested-by: Anders Darander +Tested-by: Calvin Walton +Signed-off-by: Yinghai Lu +Signed-off-by: Matt Fleming + +diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c +index f277184..dca9842 100644 +--- a/arch/x86/boot/compressed/eboot.c ++++ b/arch/x86/boot/compressed/eboot.c +@@ -1032,7 +1032,6 @@ struct boot_params *make_boot_params(struct efi_config *c) + int i; + unsigned long ramdisk_addr; + unsigned long ramdisk_size; +- unsigned long initrd_addr_max; + + efi_early = c; + sys_table = (efi_system_table_t *)(unsigned long)efi_early->table; +@@ -1095,15 +1094,20 @@ struct boot_params *make_boot_params(struct efi_config *c) + + memset(sdt, 0, sizeof(*sdt)); + +- if (hdr->xloadflags & XLF_CAN_BE_LOADED_ABOVE_4G) +- initrd_addr_max = -1UL; +- else +- initrd_addr_max = hdr->initrd_addr_max; +- + status = handle_cmdline_files(sys_table, image, + (char *)(unsigned long)hdr->cmd_line_ptr, +- "initrd=", initrd_addr_max, ++ "initrd=", hdr->initrd_addr_max, + &ramdisk_addr, &ramdisk_size); ++ ++ if (status != EFI_SUCCESS && ++ hdr->xloadflags & XLF_CAN_BE_LOADED_ABOVE_4G) { ++ efi_printk(sys_table, "Trying to load files to higher address\n"); ++ status = handle_cmdline_files(sys_table, image, ++ (char *)(unsigned long)hdr->cmd_line_ptr, ++ "initrd=", -1UL, ++ &ramdisk_addr, &ramdisk_size); ++ } ++ + if (status != EFI_SUCCESS) + goto fail2; + hdr->ramdisk_image = ramdisk_addr & 0xffffffff; +-- +cgit v0.10.1 + +