diff options
-rw-r--r-- | arch/arm/boot/compressed/efi-header.S | 160 | ||||
-rw-r--r-- | arch/arm/boot/compressed/vmlinux.lds.S | 30 | ||||
-rw-r--r-- | arch/arm64/include/asm/efi.h | 3 | ||||
-rw-r--r-- | drivers/firmware/dcdbas.c | 2 | ||||
-rw-r--r-- | drivers/firmware/efi/arm-init.c | 8 | ||||
-rw-r--r-- | drivers/firmware/efi/efi.c | 2 | ||||
-rw-r--r-- | drivers/firmware/efi/esrt.c | 2 | ||||
-rw-r--r-- | drivers/firmware/efi/libstub/Makefile | 2 | ||||
-rw-r--r-- | drivers/firmware/efi/libstub/arm64-stub.c | 10 | ||||
-rw-r--r-- | drivers/firmware/efi/reboot.c | 12 | ||||
-rw-r--r-- | drivers/video/fbdev/efifb.c | 31 |
11 files changed, 158 insertions, 104 deletions
diff --git a/arch/arm/boot/compressed/efi-header.S b/arch/arm/boot/compressed/efi-header.S index a17ca8d78656..c94a88ae834d 100644 --- a/arch/arm/boot/compressed/efi-header.S +++ b/arch/arm/boot/compressed/efi-header.S @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013-2015 Linaro Ltd + * Copyright (C) 2013-2017 Linaro Ltd * Authors: Roy Franz <roy.franz@linaro.org> * Ard Biesheuvel <ard.biesheuvel@linaro.org> * @@ -8,6 +8,9 @@ * published by the Free Software Foundation. */ +#include <linux/pe.h> +#include <linux/sizes.h> + .macro __nop #ifdef CONFIG_EFI_STUB @ This is almost but not quite a NOP, since it does clobber the @@ -15,7 +18,7 @@ @ PE/COFF expects the magic string "MZ" at offset 0, while the @ ARM/Linux boot protocol expects an executable instruction @ there. - .inst 'M' | ('Z' << 8) | (0x1310 << 16) @ tstne r0, #0x4d000 + .inst MZ_MAGIC | (0x1310 << 16) @ tstne r0, #0x4d000 #else AR_CLASS( mov r0, r0 ) M_CLASS( nop.w ) @@ -34,96 +37,97 @@ @ The only 2 fields of the MSDOS header that are used are this @ PE/COFF offset, and the "MZ" bytes at offset 0x0. @ - .long pe_header - start @ Offset to the PE header. + .long pe_header - start @ Offset to the PE header. pe_header: - .ascii "PE\0\0" + .long PE_MAGIC coff_header: - .short 0x01c2 @ ARM or Thumb - .short 2 @ nr_sections - .long 0 @ TimeDateStamp - .long 0 @ PointerToSymbolTable - .long 1 @ NumberOfSymbols - .short section_table - optional_header - @ SizeOfOptionalHeader - .short 0x306 @ Characteristics. - @ IMAGE_FILE_32BIT_MACHINE | - @ IMAGE_FILE_DEBUG_STRIPPED | - @ IMAGE_FILE_EXECUTABLE_IMAGE | - @ IMAGE_FILE_LINE_NUMS_STRIPPED + .short IMAGE_FILE_MACHINE_THUMB @ Machine + .short section_count @ NumberOfSections + .long 0 @ TimeDateStamp + .long 0 @ PointerToSymbolTable + .long 0 @ NumberOfSymbols + .short section_table - optional_header @ SizeOfOptionalHeader + .short IMAGE_FILE_32BIT_MACHINE | \ + IMAGE_FILE_DEBUG_STRIPPED | \ + IMAGE_FILE_EXECUTABLE_IMAGE | \ + IMAGE_FILE_LINE_NUMS_STRIPPED @ Characteristics + +#define __pecoff_code_size (__pecoff_data_start - __efi_start) optional_header: - .short 0x10b @ PE32 format - .byte 0x02 @ MajorLinkerVersion - .byte 0x14 @ MinorLinkerVersion - .long _end - __efi_start @ SizeOfCode - .long 0 @ SizeOfInitializedData - .long 0 @ SizeOfUninitializedData - .long efi_stub_entry - start @ AddressOfEntryPoint - .long start_offset @ BaseOfCode - .long 0 @ data + .short PE_OPT_MAGIC_PE32 @ PE32 format + .byte 0x02 @ MajorLinkerVersion + .byte 0x14 @ MinorLinkerVersion + .long __pecoff_code_size @ SizeOfCode + .long __pecoff_data_size @ SizeOfInitializedData + .long 0 @ SizeOfUninitializedData + .long efi_stub_entry - start @ AddressOfEntryPoint + .long start_offset @ BaseOfCode + .long __pecoff_data_start - start @ BaseOfData extra_header_fields: - .long 0 @ ImageBase - .long 0x200 @ SectionAlignment - .long 0x200 @ FileAlignment - .short 0 @ MajorOperatingSystemVersion - .short 0 @ MinorOperatingSystemVersion - .short 0 @ MajorImageVersion - .short 0 @ MinorImageVersion - .short 0 @ MajorSubsystemVersion - .short 0 @ MinorSubsystemVersion - .long 0 @ Win32VersionValue + .long 0 @ ImageBase + .long SZ_4K @ SectionAlignment + .long SZ_512 @ FileAlignment + .short 0 @ MajorOsVersion + .short 0 @ MinorOsVersion + .short 0 @ MajorImageVersion + .short 0 @ MinorImageVersion + .short 0 @ MajorSubsystemVersion + .short 0 @ MinorSubsystemVersion + .long 0 @ Win32VersionValue - .long _end - start @ SizeOfImage - .long start_offset @ SizeOfHeaders - .long 0 @ CheckSum - .short 0xa @ Subsystem (EFI application) - .short 0 @ DllCharacteristics - .long 0 @ SizeOfStackReserve - .long 0 @ SizeOfStackCommit - .long 0 @ SizeOfHeapReserve - .long 0 @ SizeOfHeapCommit - .long 0 @ LoaderFlags - .long 0x6 @ NumberOfRvaAndSizes + .long __pecoff_end - start @ SizeOfImage + .long start_offset @ SizeOfHeaders + .long 0 @ CheckSum + .short IMAGE_SUBSYSTEM_EFI_APPLICATION @ Subsystem + .short 0 @ DllCharacteristics + .long 0 @ SizeOfStackReserve + .long 0 @ SizeOfStackCommit + .long 0 @ SizeOfHeapReserve + .long 0 @ SizeOfHeapCommit + .long 0 @ LoaderFlags + .long (section_table - .) / 8 @ NumberOfRvaAndSizes - .quad 0 @ ExportTable - .quad 0 @ ImportTable - .quad 0 @ ResourceTable - .quad 0 @ ExceptionTable - .quad 0 @ CertificationTable - .quad 0 @ BaseRelocationTable + .quad 0 @ ExportTable + .quad 0 @ ImportTable + .quad 0 @ ResourceTable + .quad 0 @ ExceptionTable + .quad 0 @ CertificationTable + .quad 0 @ BaseRelocationTable section_table: - @ - @ The EFI application loader requires a relocation section - @ because EFI applications must be relocatable. This is a - @ dummy section as far as we are concerned. - @ - .ascii ".reloc\0\0" - .long 0 @ VirtualSize - .long 0 @ VirtualAddress - .long 0 @ SizeOfRawData - .long 0 @ PointerToRawData - .long 0 @ PointerToRelocations - .long 0 @ PointerToLineNumbers - .short 0 @ NumberOfRelocations - .short 0 @ NumberOfLineNumbers - .long 0x42100040 @ Characteristics - .ascii ".text\0\0\0" - .long _end - __efi_start @ VirtualSize - .long __efi_start @ VirtualAddress - .long _edata - __efi_start @ SizeOfRawData - .long __efi_start @ PointerToRawData - .long 0 @ PointerToRelocations - .long 0 @ PointerToLineNumbers - .short 0 @ NumberOfRelocations - .short 0 @ NumberOfLineNumbers - .long 0xe0500020 @ Characteristics + .long __pecoff_code_size @ VirtualSize + .long __efi_start @ VirtualAddress + .long __pecoff_code_size @ SizeOfRawData + .long __efi_start @ PointerToRawData + .long 0 @ PointerToRelocations + .long 0 @ PointerToLineNumbers + .short 0 @ NumberOfRelocations + .short 0 @ NumberOfLineNumbers + .long IMAGE_SCN_CNT_CODE | \ + IMAGE_SCN_MEM_READ | \ + IMAGE_SCN_MEM_EXECUTE @ Characteristics + + .ascii ".data\0\0\0" + .long __pecoff_data_size @ VirtualSize + .long __pecoff_data_start - start @ VirtualAddress + .long __pecoff_data_rawsize @ SizeOfRawData + .long __pecoff_data_start - start @ PointerToRawData + .long 0 @ PointerToRelocations + .long 0 @ PointerToLineNumbers + .short 0 @ NumberOfRelocations + .short 0 @ NumberOfLineNumbers + .long IMAGE_SCN_CNT_INITIALIZED_DATA | \ + IMAGE_SCN_MEM_READ | \ + IMAGE_SCN_MEM_WRITE @ Characteristics + + .set section_count, (. - section_table) / 40 - .align 9 + .align 12 __efi_start: #endif .endm diff --git a/arch/arm/boot/compressed/vmlinux.lds.S b/arch/arm/boot/compressed/vmlinux.lds.S index 81c493156ce8..7a4c59154361 100644 --- a/arch/arm/boot/compressed/vmlinux.lds.S +++ b/arch/arm/boot/compressed/vmlinux.lds.S @@ -48,13 +48,6 @@ SECTIONS *(.rodata) *(.rodata.*) } - .data : { - /* - * The EFI stub always executes from RAM, and runs strictly before the - * decompressor, so we can make an exception for its r/w data, and keep it - */ - *(.data.efistub) - } .piggydata : { *(.piggydata) } @@ -70,6 +63,26 @@ SECTIONS /* ensure the zImage file size is always a multiple of 64 bits */ /* (without a dummy byte, ld just ignores the empty section) */ .pad : { BYTE(0); . = ALIGN(8); } + +#ifdef CONFIG_EFI_STUB + .data : ALIGN(4096) { + __pecoff_data_start = .; + /* + * The EFI stub always executes from RAM, and runs strictly before the + * decompressor, so we can make an exception for its r/w data, and keep it + */ + *(.data.efistub) + __pecoff_data_end = .; + + /* + * PE/COFF mandates a file size which is a multiple of 512 bytes if the + * section size equals or exceeds 4 KB + */ + . = ALIGN(512); + } + __pecoff_data_rawsize = . - ADDR(.data); +#endif + _edata = .; _magic_sig = ZIMAGE_MAGIC(0x016f2818); @@ -84,6 +97,9 @@ SECTIONS . = ALIGN(8); /* the stack must be 64-bit aligned */ .stack : { *(.stack) } + PROVIDE(__pecoff_data_size = ALIGN(512) - ADDR(.data)); + PROVIDE(__pecoff_end = ALIGN(512)); + .stab 0 : { *(.stab) } .stabstr 0 : { *(.stabstr) } .stab.excl 0 : { *(.stab.excl) } diff --git a/arch/arm64/include/asm/efi.h b/arch/arm64/include/asm/efi.h index 8f3043aba873..464ac850c5e2 100644 --- a/arch/arm64/include/asm/efi.h +++ b/arch/arm64/include/asm/efi.h @@ -81,6 +81,9 @@ static inline unsigned long efi_get_max_initrd_addr(unsigned long dram_base, #define alloc_screen_info(x...) &screen_info #define free_screen_info(x...) +/* redeclare as 'hidden' so the compiler will generate relative references */ +extern struct screen_info screen_info __attribute__((__visibility__("hidden"))); + static inline void efifb_setup_from_dmi(struct screen_info *si, const char *opt) { } diff --git a/drivers/firmware/dcdbas.c b/drivers/firmware/dcdbas.c index 2fe1a130189f..c16600f30611 100644 --- a/drivers/firmware/dcdbas.c +++ b/drivers/firmware/dcdbas.c @@ -534,7 +534,7 @@ static struct attribute *dcdbas_dev_attrs[] = { NULL }; -static struct attribute_group dcdbas_attr_group = { +static const struct attribute_group dcdbas_attr_group = { .attrs = dcdbas_dev_attrs, .bin_attrs = dcdbas_bin_attrs, }; diff --git a/drivers/firmware/efi/arm-init.c b/drivers/firmware/efi/arm-init.c index 1027d7b44358..80d1a885def5 100644 --- a/drivers/firmware/efi/arm-init.c +++ b/drivers/firmware/efi/arm-init.c @@ -145,6 +145,9 @@ static int __init uefi_init(void) sizeof(efi_config_table_t), arch_tables); + if (!retval) + efi.config_table = (unsigned long)efi.systab->tables; + early_memunmap(config_tables, table_size); out: early_memunmap(efi.systab, sizeof(efi_system_table_t)); @@ -159,6 +162,7 @@ static __init int is_usable_memory(efi_memory_desc_t *md) switch (md->type) { case EFI_LOADER_CODE: case EFI_LOADER_DATA: + case EFI_ACPI_RECLAIM_MEMORY: case EFI_BOOT_SERVICES_CODE: case EFI_BOOT_SERVICES_DATA: case EFI_CONVENTIONAL_MEMORY: @@ -211,6 +215,10 @@ static __init void reserve_regions(void) if (!is_usable_memory(md)) memblock_mark_nomap(paddr, size); + + /* keep ACPI reclaim memory intact for kexec etc. */ + if (md->type == EFI_ACPI_RECLAIM_MEMORY) + memblock_reserve(paddr, size); } } } diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index 69d4d130e055..a32e1460ade8 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -198,7 +198,7 @@ static umode_t efi_attr_is_visible(struct kobject *kobj, return attr->mode; } -static struct attribute_group efi_subsys_attr_group = { +static const struct attribute_group efi_subsys_attr_group = { .attrs = efi_subsys_attrs, .is_visible = efi_attr_is_visible, }; diff --git a/drivers/firmware/efi/esrt.c b/drivers/firmware/efi/esrt.c index 8554d7aec31c..bd7ed3c1148a 100644 --- a/drivers/firmware/efi/esrt.c +++ b/drivers/firmware/efi/esrt.c @@ -230,7 +230,7 @@ static umode_t esrt_attr_is_visible(struct kobject *kobj, return attr->mode; } -static struct attribute_group esrt_attr_group = { +static const struct attribute_group esrt_attr_group = { .attrs = esrt_attrs, .is_visible = esrt_attr_is_visible, }; diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile index 37e24f525162..cf81e6cf5ae8 100644 --- a/drivers/firmware/efi/libstub/Makefile +++ b/drivers/firmware/efi/libstub/Makefile @@ -10,7 +10,7 @@ cflags-$(CONFIG_X86) += -m$(BITS) -D__KERNEL__ -O2 \ -fPIC -fno-strict-aliasing -mno-red-zone \ -mno-mmx -mno-sse -cflags-$(CONFIG_ARM64) := $(subst -pg,,$(KBUILD_CFLAGS)) +cflags-$(CONFIG_ARM64) := $(subst -pg,,$(KBUILD_CFLAGS)) -fpie cflags-$(CONFIG_ARM) := $(subst -pg,,$(KBUILD_CFLAGS)) \ -fno-builtin -fpic -mno-single-pic-base diff --git a/drivers/firmware/efi/libstub/arm64-stub.c b/drivers/firmware/efi/libstub/arm64-stub.c index b4c2589d7c91..f7a6970e9abc 100644 --- a/drivers/firmware/efi/libstub/arm64-stub.c +++ b/drivers/firmware/efi/libstub/arm64-stub.c @@ -9,9 +9,17 @@ * published by the Free Software Foundation. * */ + +/* + * To prevent the compiler from emitting GOT-indirected (and thus absolute) + * references to the section markers, override their visibility as 'hidden' + */ +#pragma GCC visibility push(hidden) +#include <asm/sections.h> +#pragma GCC visibility pop + #include <linux/efi.h> #include <asm/efi.h> -#include <asm/sections.h> #include <asm/sysreg.h> #include "efistub.h" diff --git a/drivers/firmware/efi/reboot.c b/drivers/firmware/efi/reboot.c index 62ead9b9d871..7117e2d0c7f9 100644 --- a/drivers/firmware/efi/reboot.c +++ b/drivers/firmware/efi/reboot.c @@ -5,6 +5,8 @@ #include <linux/efi.h> #include <linux/reboot.h> +void (*orig_pm_power_off)(void); + int efi_reboot_quirk_mode = -1; void efi_reboot(enum reboot_mode reboot_mode, const char *__unused) @@ -51,6 +53,12 @@ bool __weak efi_poweroff_required(void) static void efi_power_off(void) { efi.reset_system(EFI_RESET_SHUTDOWN, EFI_SUCCESS, 0, NULL); + /* + * The above call should not return, if it does fall back to + * the original power off method (typically ACPI poweroff). + */ + if (orig_pm_power_off) + orig_pm_power_off(); } static int __init efi_shutdown_init(void) @@ -58,8 +66,10 @@ static int __init efi_shutdown_init(void) if (!efi_enabled(EFI_RUNTIME_SERVICES)) return -ENODEV; - if (efi_poweroff_required()) + if (efi_poweroff_required()) { + orig_pm_power_off = pm_power_off; pm_power_off = efi_power_off; + } return 0; } diff --git a/drivers/video/fbdev/efifb.c b/drivers/video/fbdev/efifb.c index 1e784adb89b1..3a010641f630 100644 --- a/drivers/video/fbdev/efifb.c +++ b/drivers/video/fbdev/efifb.c @@ -149,6 +149,10 @@ ATTRIBUTE_GROUPS(efifb); static bool pci_dev_disabled; /* FB base matches BAR of a disabled device */ +static struct pci_dev *efifb_pci_dev; /* dev with BAR covering the efifb */ +static struct resource *bar_resource; +static u64 bar_offset; + static int efifb_probe(struct platform_device *dev) { struct fb_info *info; @@ -203,6 +207,13 @@ static int efifb_probe(struct platform_device *dev) efifb_fix.smem_start |= ext_lfb_base; } + if (bar_resource && + bar_resource->start + bar_offset != efifb_fix.smem_start) { + dev_info(&efifb_pci_dev->dev, + "BAR has moved, updating efifb address\n"); + efifb_fix.smem_start = bar_resource->start + bar_offset; + } + efifb_defined.bits_per_pixel = screen_info.lfb_depth; efifb_defined.xres = screen_info.lfb_width; efifb_defined.yres = screen_info.lfb_height; @@ -370,15 +381,13 @@ static struct platform_driver efifb_driver = { builtin_platform_driver(efifb_driver); -#if defined(CONFIG_PCI) && !defined(CONFIG_X86) - -static bool pci_bar_found; /* did we find a BAR matching the efifb base? */ +#if defined(CONFIG_PCI) -static void claim_efifb_bar(struct pci_dev *dev, int idx) +static void record_efifb_bar_resource(struct pci_dev *dev, int idx, u64 offset) { u16 word; - pci_bar_found = true; + efifb_pci_dev = dev; pci_read_config_word(dev, PCI_COMMAND, &word); if (!(word & PCI_COMMAND_MEMORY)) { @@ -389,12 +398,8 @@ static void claim_efifb_bar(struct pci_dev *dev, int idx) return; } - if (pci_claim_resource(dev, idx)) { - pci_dev_disabled = true; - dev_err(&dev->dev, - "BAR %d: failed to claim resource for efifb!\n", idx); - return; - } + bar_resource = &dev->resource[idx]; + bar_offset = offset; dev_info(&dev->dev, "BAR %d: assigned to efifb\n", idx); } @@ -405,7 +410,7 @@ static void efifb_fixup_resources(struct pci_dev *dev) u64 size = screen_info.lfb_size; int i; - if (pci_bar_found || screen_info.orig_video_isVGA != VIDEO_TYPE_EFI) + if (efifb_pci_dev || screen_info.orig_video_isVGA != VIDEO_TYPE_EFI) return; if (screen_info.capabilities & VIDEO_CAPABILITY_64BIT_BASE) @@ -421,7 +426,7 @@ static void efifb_fixup_resources(struct pci_dev *dev) continue; if (res->start <= base && res->end >= base + size - 1) { - claim_efifb_bar(dev, i); + record_efifb_bar_resource(dev, i, base - res->start); break; } } |