diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-10-23 17:45:09 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-10-23 17:45:09 -0400 |
| commit | 8c81f48e16fbe103e682d7ee7b2f16d065c42954 (patch) | |
| tree | 1eac3abf36ed9330b3d5f9e550d1ccbc0c174f9b | |
| parent | 5de551e0eeddf470928e9fee59825a3645641bc7 (diff) | |
| parent | 75b128573b275d5a5a7210b98c4b8cb3b39c12e7 (diff) | |
Merge branch 'x86-efi-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 EFI updates from Peter Anvin:
"This patchset falls under the "maintainers that grovel" clause in the
v3.18-rc1 announcement. We had intended to push it late in the merge
window since we got it into the -tip tree relatively late.
Many of these are relatively simple things, but there are a couple of
key bits, especially Ard's and Matt's patches"
* 'x86-efi-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (24 commits)
rtc: Disable EFI rtc for x86
efi: rtc-efi: Export platform:rtc-efi as module alias
efi: Delete the in_nmi() conditional runtime locking
efi: Provide a non-blocking SetVariable() operation
x86/efi: Adding efi_printks on memory allocationa and pci.reads
x86/efi: Mark initialization code as such
x86/efi: Update comment regarding required phys mapped EFI services
x86/efi: Unexport add_efi_memmap variable
x86/efi: Remove unused efi_call* macros
efi: Resolve some shadow warnings
arm64: efi: Format EFI memory type & attrs with efi_md_typeattr_format()
ia64: efi: Format EFI memory type & attrs with efi_md_typeattr_format()
x86: efi: Format EFI memory type & attrs with efi_md_typeattr_format()
efi: Introduce efi_md_typeattr_format()
efi: Add macro for EFI_MEMORY_UCE memory attribute
x86/efi: Clear EFI_RUNTIME_SERVICES if failing to enter virtual mode
arm64/efi: Do not enter virtual mode if booting with efi=noruntime or noefi
arm64/efi: uefi_init error handling fix
efi: Add kernel param efi=noruntime
lib: Add a generic cmdline parse function parse_option_str
...
| -rw-r--r-- | Documentation/kernel-parameters.txt | 8 | ||||
| -rw-r--r-- | arch/arm64/kernel/efi.c | 44 | ||||
| -rw-r--r-- | arch/ia64/kernel/efi.c | 6 | ||||
| -rw-r--r-- | arch/x86/boot/compressed/eboot.c | 32 | ||||
| -rw-r--r-- | arch/x86/include/asm/efi.h | 31 | ||||
| -rw-r--r-- | arch/x86/platform/efi/efi-bgrt.c | 36 | ||||
| -rw-r--r-- | arch/x86/platform/efi/efi.c | 52 | ||||
| -rw-r--r-- | arch/x86/platform/efi/efi_32.c | 12 | ||||
| -rw-r--r-- | arch/x86/platform/efi/efi_64.c | 6 | ||||
| -rw-r--r-- | arch/x86/platform/efi/efi_stub_32.S | 4 | ||||
| -rw-r--r-- | drivers/firmware/efi/efi.c | 79 | ||||
| -rw-r--r-- | drivers/firmware/efi/libstub/arm-stub.c | 4 | ||||
| -rw-r--r-- | drivers/firmware/efi/libstub/efi-stub-helper.c | 62 | ||||
| -rw-r--r-- | drivers/firmware/efi/runtime-wrappers.c | 164 | ||||
| -rw-r--r-- | drivers/firmware/efi/vars.c | 61 | ||||
| -rw-r--r-- | drivers/rtc/Kconfig | 2 | ||||
| -rw-r--r-- | drivers/rtc/rtc-efi.c | 1 | ||||
| -rw-r--r-- | include/linux/efi.h | 17 | ||||
| -rw-r--r-- | include/linux/kernel.h | 1 | ||||
| -rw-r--r-- | lib/cmdline.c | 29 |
20 files changed, 528 insertions, 123 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 988160a4ad31..74339c57b914 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt | |||
| @@ -1015,10 +1015,14 @@ bytes respectively. Such letter suffixes can also be entirely omitted. | |||
| 1015 | Format: {"off" | "on" | "skip[mbr]"} | 1015 | Format: {"off" | "on" | "skip[mbr]"} |
| 1016 | 1016 | ||
| 1017 | efi= [EFI] | 1017 | efi= [EFI] |
| 1018 | Format: { "old_map" } | 1018 | Format: { "old_map", "nochunk", "noruntime" } |
| 1019 | old_map [X86-64]: switch to the old ioremap-based EFI | 1019 | old_map [X86-64]: switch to the old ioremap-based EFI |
| 1020 | runtime services mapping. 32-bit still uses this one by | 1020 | runtime services mapping. 32-bit still uses this one by |
| 1021 | default. | 1021 | default. |
| 1022 | nochunk: disable reading files in "chunks" in the EFI | ||
| 1023 | boot stub, as chunking can cause problems with some | ||
| 1024 | firmware implementations. | ||
| 1025 | noruntime : disable EFI runtime services support | ||
| 1022 | 1026 | ||
| 1023 | efi_no_storage_paranoia [EFI; X86] | 1027 | efi_no_storage_paranoia [EFI; X86] |
| 1024 | Using this parameter you can use more than 50% of | 1028 | Using this parameter you can use more than 50% of |
| @@ -2232,7 +2236,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted. | |||
| 2232 | 2236 | ||
| 2233 | nodsp [SH] Disable hardware DSP at boot time. | 2237 | nodsp [SH] Disable hardware DSP at boot time. |
| 2234 | 2238 | ||
| 2235 | noefi [X86] Disable EFI runtime services support. | 2239 | noefi Disable EFI runtime services support. |
| 2236 | 2240 | ||
| 2237 | noexec [IA-64] | 2241 | noexec [IA-64] |
| 2238 | 2242 | ||
diff --git a/arch/arm64/kernel/efi.c b/arch/arm64/kernel/efi.c index 03aaa99e1ea0..95c49ebc660d 100644 --- a/arch/arm64/kernel/efi.c +++ b/arch/arm64/kernel/efi.c | |||
| @@ -89,7 +89,8 @@ static int __init uefi_init(void) | |||
| 89 | */ | 89 | */ |
| 90 | if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) { | 90 | if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) { |
| 91 | pr_err("System table signature incorrect\n"); | 91 | pr_err("System table signature incorrect\n"); |
| 92 | return -EINVAL; | 92 | retval = -EINVAL; |
| 93 | goto out; | ||
| 93 | } | 94 | } |
| 94 | if ((efi.systab->hdr.revision >> 16) < 2) | 95 | if ((efi.systab->hdr.revision >> 16) < 2) |
| 95 | pr_warn("Warning: EFI system table version %d.%02d, expected 2.00 or greater\n", | 96 | pr_warn("Warning: EFI system table version %d.%02d, expected 2.00 or greater\n", |
| @@ -103,6 +104,7 @@ static int __init uefi_init(void) | |||
| 103 | for (i = 0; i < (int) sizeof(vendor) - 1 && *c16; ++i) | 104 | for (i = 0; i < (int) sizeof(vendor) - 1 && *c16; ++i) |
| 104 | vendor[i] = c16[i]; | 105 | vendor[i] = c16[i]; |
| 105 | vendor[i] = '\0'; | 106 | vendor[i] = '\0'; |
| 107 | early_memunmap(c16, sizeof(vendor)); | ||
| 106 | } | 108 | } |
| 107 | 109 | ||
| 108 | pr_info("EFI v%u.%.02u by %s\n", | 110 | pr_info("EFI v%u.%.02u by %s\n", |
| @@ -113,29 +115,11 @@ static int __init uefi_init(void) | |||
| 113 | if (retval == 0) | 115 | if (retval == 0) |
| 114 | set_bit(EFI_CONFIG_TABLES, &efi.flags); | 116 | set_bit(EFI_CONFIG_TABLES, &efi.flags); |
| 115 | 117 | ||
| 116 | early_memunmap(c16, sizeof(vendor)); | 118 | out: |
| 117 | early_memunmap(efi.systab, sizeof(efi_system_table_t)); | 119 | early_memunmap(efi.systab, sizeof(efi_system_table_t)); |
| 118 | |||
| 119 | return retval; | 120 | return retval; |
| 120 | } | 121 | } |
| 121 | 122 | ||
| 122 | static __initdata char memory_type_name[][32] = { | ||
| 123 | {"Reserved"}, | ||
| 124 | {"Loader Code"}, | ||
| 125 | {"Loader Data"}, | ||
| 126 | {"Boot Code"}, | ||
| 127 | {"Boot Data"}, | ||
| 128 | {"Runtime Code"}, | ||
| 129 | {"Runtime Data"}, | ||
| 130 | {"Conventional Memory"}, | ||
| 131 | {"Unusable Memory"}, | ||
| 132 | {"ACPI Reclaim Memory"}, | ||
| 133 | {"ACPI Memory NVS"}, | ||
| 134 | {"Memory Mapped I/O"}, | ||
| 135 | {"MMIO Port Space"}, | ||
| 136 | {"PAL Code"}, | ||
| 137 | }; | ||
| 138 | |||
| 139 | /* | 123 | /* |
| 140 | * Return true for RAM regions we want to permanently reserve. | 124 | * Return true for RAM regions we want to permanently reserve. |
| 141 | */ | 125 | */ |
| @@ -166,10 +150,13 @@ static __init void reserve_regions(void) | |||
| 166 | paddr = md->phys_addr; | 150 | paddr = md->phys_addr; |
| 167 | npages = md->num_pages; | 151 | npages = md->num_pages; |
| 168 | 152 | ||
| 169 | if (uefi_debug) | 153 | if (uefi_debug) { |
| 170 | pr_info(" 0x%012llx-0x%012llx [%s]", | 154 | char buf[64]; |
| 155 | |||
| 156 | pr_info(" 0x%012llx-0x%012llx %s", | ||
| 171 | paddr, paddr + (npages << EFI_PAGE_SHIFT) - 1, | 157 | paddr, paddr + (npages << EFI_PAGE_SHIFT) - 1, |
| 172 | memory_type_name[md->type]); | 158 | efi_md_typeattr_format(buf, sizeof(buf), md)); |
| 159 | } | ||
| 173 | 160 | ||
| 174 | memrange_efi_to_native(&paddr, &npages); | 161 | memrange_efi_to_native(&paddr, &npages); |
| 175 | size = npages << PAGE_SHIFT; | 162 | size = npages << PAGE_SHIFT; |
| @@ -393,11 +380,16 @@ static int __init arm64_enter_virtual_mode(void) | |||
| 393 | return -1; | 380 | return -1; |
| 394 | } | 381 | } |
| 395 | 382 | ||
| 396 | pr_info("Remapping and enabling EFI services.\n"); | ||
| 397 | |||
| 398 | /* replace early memmap mapping with permanent mapping */ | ||
| 399 | mapsize = memmap.map_end - memmap.map; | 383 | mapsize = memmap.map_end - memmap.map; |
| 400 | early_memunmap(memmap.map, mapsize); | 384 | early_memunmap(memmap.map, mapsize); |
| 385 | |||
| 386 | if (efi_runtime_disabled()) { | ||
| 387 | pr_info("EFI runtime services will be disabled.\n"); | ||
| 388 | return -1; | ||
| 389 | } | ||
| 390 | |||
| 391 | pr_info("Remapping and enabling EFI services.\n"); | ||
| 392 | /* replace early memmap mapping with permanent mapping */ | ||
| 401 | memmap.map = (__force void *)ioremap_cache((phys_addr_t)memmap.phys_map, | 393 | memmap.map = (__force void *)ioremap_cache((phys_addr_t)memmap.phys_map, |
| 402 | mapsize); | 394 | mapsize); |
| 403 | memmap.map_end = memmap.map + mapsize; | 395 | memmap.map_end = memmap.map + mapsize; |
diff --git a/arch/ia64/kernel/efi.c b/arch/ia64/kernel/efi.c index 741b99c1a0b1..c52d7540dc05 100644 --- a/arch/ia64/kernel/efi.c +++ b/arch/ia64/kernel/efi.c | |||
| @@ -568,6 +568,7 @@ efi_init (void) | |||
| 568 | { | 568 | { |
| 569 | const char *unit; | 569 | const char *unit; |
| 570 | unsigned long size; | 570 | unsigned long size; |
| 571 | char buf[64]; | ||
| 571 | 572 | ||
| 572 | md = p; | 573 | md = p; |
| 573 | size = md->num_pages << EFI_PAGE_SHIFT; | 574 | size = md->num_pages << EFI_PAGE_SHIFT; |
| @@ -586,9 +587,10 @@ efi_init (void) | |||
| 586 | unit = "KB"; | 587 | unit = "KB"; |
| 587 | } | 588 | } |
| 588 | 589 | ||
| 589 | printk("mem%02d: type=%2u, attr=0x%016lx, " | 590 | printk("mem%02d: %s " |
| 590 | "range=[0x%016lx-0x%016lx) (%4lu%s)\n", | 591 | "range=[0x%016lx-0x%016lx) (%4lu%s)\n", |
| 591 | i, md->type, md->attribute, md->phys_addr, | 592 | i, efi_md_typeattr_format(buf, sizeof(buf), md), |
| 593 | md->phys_addr, | ||
| 592 | md->phys_addr + efi_md_size(md), size, unit); | 594 | md->phys_addr + efi_md_size(md), size, unit); |
| 593 | } | 595 | } |
| 594 | } | 596 | } |
diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c index de8eebd6f67c..1acf605a646d 100644 --- a/arch/x86/boot/compressed/eboot.c +++ b/arch/x86/boot/compressed/eboot.c | |||
| @@ -330,8 +330,10 @@ __setup_efi_pci32(efi_pci_io_protocol_32 *pci, struct pci_setup_rom **__rom) | |||
| 330 | size = pci->romsize + sizeof(*rom); | 330 | size = pci->romsize + sizeof(*rom); |
| 331 | 331 | ||
| 332 | status = efi_call_early(allocate_pool, EFI_LOADER_DATA, size, &rom); | 332 | status = efi_call_early(allocate_pool, EFI_LOADER_DATA, size, &rom); |
| 333 | if (status != EFI_SUCCESS) | 333 | if (status != EFI_SUCCESS) { |
| 334 | efi_printk(sys_table, "Failed to alloc mem for rom\n"); | ||
| 334 | return status; | 335 | return status; |
| 336 | } | ||
| 335 | 337 | ||
| 336 | memset(rom, 0, sizeof(*rom)); | 338 | memset(rom, 0, sizeof(*rom)); |
| 337 | 339 | ||
| @@ -344,14 +346,18 @@ __setup_efi_pci32(efi_pci_io_protocol_32 *pci, struct pci_setup_rom **__rom) | |||
| 344 | status = efi_early->call(pci->pci.read, pci, EfiPciIoWidthUint16, | 346 | status = efi_early->call(pci->pci.read, pci, EfiPciIoWidthUint16, |
| 345 | PCI_VENDOR_ID, 1, &(rom->vendor)); | 347 | PCI_VENDOR_ID, 1, &(rom->vendor)); |
| 346 | 348 | ||
| 347 | if (status != EFI_SUCCESS) | 349 | if (status != EFI_SUCCESS) { |
| 350 | efi_printk(sys_table, "Failed to read rom->vendor\n"); | ||
| 348 | goto free_struct; | 351 | goto free_struct; |
| 352 | } | ||
| 349 | 353 | ||
| 350 | status = efi_early->call(pci->pci.read, pci, EfiPciIoWidthUint16, | 354 | status = efi_early->call(pci->pci.read, pci, EfiPciIoWidthUint16, |
| 351 | PCI_DEVICE_ID, 1, &(rom->devid)); | 355 | PCI_DEVICE_ID, 1, &(rom->devid)); |
| 352 | 356 | ||
| 353 | if (status != EFI_SUCCESS) | 357 | if (status != EFI_SUCCESS) { |
| 358 | efi_printk(sys_table, "Failed to read rom->devid\n"); | ||
| 354 | goto free_struct; | 359 | goto free_struct; |
| 360 | } | ||
| 355 | 361 | ||
| 356 | status = efi_early->call(pci->get_location, pci, &(rom->segment), | 362 | status = efi_early->call(pci->get_location, pci, &(rom->segment), |
| 357 | &(rom->bus), &(rom->device), &(rom->function)); | 363 | &(rom->bus), &(rom->device), &(rom->function)); |
| @@ -432,8 +438,10 @@ __setup_efi_pci64(efi_pci_io_protocol_64 *pci, struct pci_setup_rom **__rom) | |||
| 432 | size = pci->romsize + sizeof(*rom); | 438 | size = pci->romsize + sizeof(*rom); |
| 433 | 439 | ||
| 434 | status = efi_call_early(allocate_pool, EFI_LOADER_DATA, size, &rom); | 440 | status = efi_call_early(allocate_pool, EFI_LOADER_DATA, size, &rom); |
| 435 | if (status != EFI_SUCCESS) | 441 | if (status != EFI_SUCCESS) { |
| 442 | efi_printk(sys_table, "Failed to alloc mem for rom\n"); | ||
| 436 | return status; | 443 | return status; |
| 444 | } | ||
| 437 | 445 | ||
| 438 | rom->data.type = SETUP_PCI; | 446 | rom->data.type = SETUP_PCI; |
| 439 | rom->data.len = size - sizeof(struct setup_data); | 447 | rom->data.len = size - sizeof(struct setup_data); |
| @@ -444,14 +452,18 @@ __setup_efi_pci64(efi_pci_io_protocol_64 *pci, struct pci_setup_rom **__rom) | |||
| 444 | status = efi_early->call(pci->pci.read, pci, EfiPciIoWidthUint16, | 452 | status = efi_early->call(pci->pci.read, pci, EfiPciIoWidthUint16, |
| 445 | PCI_VENDOR_ID, 1, &(rom->vendor)); | 453 | PCI_VENDOR_ID, 1, &(rom->vendor)); |
| 446 | 454 | ||
| 447 | if (status != EFI_SUCCESS) | 455 | if (status != EFI_SUCCESS) { |
| 456 | efi_printk(sys_table, "Failed to read rom->vendor\n"); | ||
| 448 | goto free_struct; | 457 | goto free_struct; |
| 458 | } | ||
| 449 | 459 | ||
| 450 | status = efi_early->call(pci->pci.read, pci, EfiPciIoWidthUint16, | 460 | status = efi_early->call(pci->pci.read, pci, EfiPciIoWidthUint16, |
| 451 | PCI_DEVICE_ID, 1, &(rom->devid)); | 461 | PCI_DEVICE_ID, 1, &(rom->devid)); |
| 452 | 462 | ||
| 453 | if (status != EFI_SUCCESS) | 463 | if (status != EFI_SUCCESS) { |
| 464 | efi_printk(sys_table, "Failed to read rom->devid\n"); | ||
| 454 | goto free_struct; | 465 | goto free_struct; |
| 466 | } | ||
| 455 | 467 | ||
| 456 | status = efi_early->call(pci->get_location, pci, &(rom->segment), | 468 | status = efi_early->call(pci->get_location, pci, &(rom->segment), |
| 457 | &(rom->bus), &(rom->device), &(rom->function)); | 469 | &(rom->bus), &(rom->device), &(rom->function)); |
| @@ -538,8 +550,10 @@ static void setup_efi_pci(struct boot_params *params) | |||
| 538 | EFI_LOADER_DATA, | 550 | EFI_LOADER_DATA, |
| 539 | size, (void **)&pci_handle); | 551 | size, (void **)&pci_handle); |
| 540 | 552 | ||
| 541 | if (status != EFI_SUCCESS) | 553 | if (status != EFI_SUCCESS) { |
| 554 | efi_printk(sys_table, "Failed to alloc mem for pci_handle\n"); | ||
| 542 | return; | 555 | return; |
| 556 | } | ||
| 543 | 557 | ||
| 544 | status = efi_call_early(locate_handle, | 558 | status = efi_call_early(locate_handle, |
| 545 | EFI_LOCATE_BY_PROTOCOL, &pci_proto, | 559 | EFI_LOCATE_BY_PROTOCOL, &pci_proto, |
| @@ -1105,6 +1119,10 @@ struct boot_params *make_boot_params(struct efi_config *c) | |||
| 1105 | 1119 | ||
| 1106 | memset(sdt, 0, sizeof(*sdt)); | 1120 | memset(sdt, 0, sizeof(*sdt)); |
| 1107 | 1121 | ||
| 1122 | status = efi_parse_options(cmdline_ptr); | ||
| 1123 | if (status != EFI_SUCCESS) | ||
| 1124 | goto fail2; | ||
| 1125 | |||
| 1108 | status = handle_cmdline_files(sys_table, image, | 1126 | status = handle_cmdline_files(sys_table, image, |
| 1109 | (char *)(unsigned long)hdr->cmd_line_ptr, | 1127 | (char *)(unsigned long)hdr->cmd_line_ptr, |
| 1110 | "initrd=", hdr->initrd_addr_max, | 1128 | "initrd=", hdr->initrd_addr_max, |
diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h index 0ec241ede5a2..9b11757975d0 100644 --- a/arch/x86/include/asm/efi.h +++ b/arch/x86/include/asm/efi.h | |||
| @@ -81,24 +81,23 @@ extern u64 asmlinkage efi_call(void *fp, ...); | |||
| 81 | */ | 81 | */ |
| 82 | #define __efi_call_virt(f, args...) efi_call_virt(f, args) | 82 | #define __efi_call_virt(f, args...) efi_call_virt(f, args) |
| 83 | 83 | ||
| 84 | extern void __iomem *efi_ioremap(unsigned long addr, unsigned long size, | 84 | extern void __iomem *__init efi_ioremap(unsigned long addr, unsigned long size, |
| 85 | u32 type, u64 attribute); | 85 | u32 type, u64 attribute); |
| 86 | 86 | ||
| 87 | #endif /* CONFIG_X86_32 */ | 87 | #endif /* CONFIG_X86_32 */ |
| 88 | 88 | ||
| 89 | extern int add_efi_memmap; | ||
| 90 | extern struct efi_scratch efi_scratch; | 89 | extern struct efi_scratch efi_scratch; |
| 91 | extern void efi_set_executable(efi_memory_desc_t *md, bool executable); | 90 | extern void __init efi_set_executable(efi_memory_desc_t *md, bool executable); |
| 92 | extern int efi_memblock_x86_reserve_range(void); | 91 | extern int __init efi_memblock_x86_reserve_range(void); |
| 93 | extern void efi_call_phys_prelog(void); | 92 | extern void __init efi_call_phys_prolog(void); |
| 94 | extern void efi_call_phys_epilog(void); | 93 | extern void __init efi_call_phys_epilog(void); |
| 95 | extern void efi_unmap_memmap(void); | 94 | extern void __init efi_unmap_memmap(void); |
| 96 | extern void efi_memory_uc(u64 addr, unsigned long size); | 95 | extern void __init efi_memory_uc(u64 addr, unsigned long size); |
| 97 | extern void __init efi_map_region(efi_memory_desc_t *md); | 96 | extern void __init efi_map_region(efi_memory_desc_t *md); |
| 98 | extern void __init efi_map_region_fixed(efi_memory_desc_t *md); | 97 | extern void __init efi_map_region_fixed(efi_memory_desc_t *md); |
| 99 | extern void efi_sync_low_kernel_mappings(void); | 98 | extern void efi_sync_low_kernel_mappings(void); |
| 100 | extern int efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages); | 99 | extern int __init efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages); |
| 101 | extern void efi_cleanup_page_tables(unsigned long pa_memmap, unsigned num_pages); | 100 | extern void __init efi_cleanup_page_tables(unsigned long pa_memmap, unsigned num_pages); |
| 102 | extern void __init old_map_region(efi_memory_desc_t *md); | 101 | extern void __init old_map_region(efi_memory_desc_t *md); |
| 103 | extern void __init runtime_code_page_mkexec(void); | 102 | extern void __init runtime_code_page_mkexec(void); |
| 104 | extern void __init efi_runtime_mkexec(void); | 103 | extern void __init efi_runtime_mkexec(void); |
| @@ -162,16 +161,6 @@ static inline efi_status_t efi_thunk_set_virtual_address_map( | |||
| 162 | extern bool efi_reboot_required(void); | 161 | extern bool efi_reboot_required(void); |
| 163 | 162 | ||
| 164 | #else | 163 | #else |
| 165 | /* | ||
| 166 | * IF EFI is not configured, have the EFI calls return -ENOSYS. | ||
| 167 | */ | ||
| 168 | #define efi_call0(_f) (-ENOSYS) | ||
| 169 | #define efi_call1(_f, _a1) (-ENOSYS) | ||
| 170 | #define efi_call2(_f, _a1, _a2) (-ENOSYS) | ||
| 171 | #define efi_call3(_f, _a1, _a2, _a3) (-ENOSYS) | ||
| 172 | #define efi_call4(_f, _a1, _a2, _a3, _a4) (-ENOSYS) | ||
| 173 | #define efi_call5(_f, _a1, _a2, _a3, _a4, _a5) (-ENOSYS) | ||
| 174 | #define efi_call6(_f, _a1, _a2, _a3, _a4, _a5, _a6) (-ENOSYS) | ||
| 175 | static inline void parse_efi_setup(u64 phys_addr, u32 data_len) {} | 164 | static inline void parse_efi_setup(u64 phys_addr, u32 data_len) {} |
| 176 | static inline bool efi_reboot_required(void) | 165 | static inline bool efi_reboot_required(void) |
| 177 | { | 166 | { |
diff --git a/arch/x86/platform/efi/efi-bgrt.c b/arch/x86/platform/efi/efi-bgrt.c index f15103dff4b4..d143d216d52b 100644 --- a/arch/x86/platform/efi/efi-bgrt.c +++ b/arch/x86/platform/efi/efi-bgrt.c | |||
| @@ -40,20 +40,40 @@ void __init efi_bgrt_init(void) | |||
| 40 | if (ACPI_FAILURE(status)) | 40 | if (ACPI_FAILURE(status)) |
| 41 | return; | 41 | return; |
| 42 | 42 | ||
| 43 | if (bgrt_tab->header.length < sizeof(*bgrt_tab)) | 43 | if (bgrt_tab->header.length < sizeof(*bgrt_tab)) { |
| 44 | pr_err("Ignoring BGRT: invalid length %u (expected %zu)\n", | ||
| 45 | bgrt_tab->header.length, sizeof(*bgrt_tab)); | ||
| 44 | return; | 46 | return; |
| 45 | if (bgrt_tab->version != 1 || bgrt_tab->status != 1) | 47 | } |
| 48 | if (bgrt_tab->version != 1) { | ||
| 49 | pr_err("Ignoring BGRT: invalid version %u (expected 1)\n", | ||
| 50 | bgrt_tab->version); | ||
| 51 | return; | ||
| 52 | } | ||
| 53 | if (bgrt_tab->status != 1) { | ||
| 54 | pr_err("Ignoring BGRT: invalid status %u (expected 1)\n", | ||
| 55 | bgrt_tab->status); | ||
| 56 | return; | ||
| 57 | } | ||
| 58 | if (bgrt_tab->image_type != 0) { | ||
| 59 | pr_err("Ignoring BGRT: invalid image type %u (expected 0)\n", | ||
| 60 | bgrt_tab->image_type); | ||
| 46 | return; | 61 | return; |
| 47 | if (bgrt_tab->image_type != 0 || !bgrt_tab->image_address) | 62 | } |
| 63 | if (!bgrt_tab->image_address) { | ||
| 64 | pr_err("Ignoring BGRT: null image address\n"); | ||
| 48 | return; | 65 | return; |
| 66 | } | ||
| 49 | 67 | ||
| 50 | image = efi_lookup_mapped_addr(bgrt_tab->image_address); | 68 | image = efi_lookup_mapped_addr(bgrt_tab->image_address); |
| 51 | if (!image) { | 69 | if (!image) { |
| 52 | image = early_memremap(bgrt_tab->image_address, | 70 | image = early_memremap(bgrt_tab->image_address, |
| 53 | sizeof(bmp_header)); | 71 | sizeof(bmp_header)); |
| 54 | ioremapped = true; | 72 | ioremapped = true; |
| 55 | if (!image) | 73 | if (!image) { |
| 74 | pr_err("Ignoring BGRT: failed to map image header memory\n"); | ||
| 56 | return; | 75 | return; |
| 76 | } | ||
| 57 | } | 77 | } |
| 58 | 78 | ||
| 59 | memcpy_fromio(&bmp_header, image, sizeof(bmp_header)); | 79 | memcpy_fromio(&bmp_header, image, sizeof(bmp_header)); |
| @@ -61,14 +81,18 @@ void __init efi_bgrt_init(void) | |||
| 61 | early_iounmap(image, sizeof(bmp_header)); | 81 | early_iounmap(image, sizeof(bmp_header)); |
| 62 | bgrt_image_size = bmp_header.size; | 82 | bgrt_image_size = bmp_header.size; |
| 63 | 83 | ||
| 64 | bgrt_image = kmalloc(bgrt_image_size, GFP_KERNEL); | 84 | bgrt_image = kmalloc(bgrt_image_size, GFP_KERNEL | __GFP_NOWARN); |
| 65 | if (!bgrt_image) | 85 | if (!bgrt_image) { |
| 86 | pr_err("Ignoring BGRT: failed to allocate memory for image (wanted %zu bytes)\n", | ||
| 87 | bgrt_image_size); | ||
| 66 | return; | 88 | return; |
| 89 | } | ||
| 67 | 90 | ||
| 68 | if (ioremapped) { | 91 | if (ioremapped) { |
| 69 | image = early_memremap(bgrt_tab->image_address, | 92 | image = early_memremap(bgrt_tab->image_address, |
| 70 | bmp_header.size); | 93 | bmp_header.size); |
| 71 | if (!image) { | 94 | if (!image) { |
| 95 | pr_err("Ignoring BGRT: failed to map image memory\n"); | ||
| 72 | kfree(bgrt_image); | 96 | kfree(bgrt_image); |
| 73 | bgrt_image = NULL; | 97 | bgrt_image = NULL; |
| 74 | return; | 98 | return; |
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c index 850da94fef30..dbc8627a5cdf 100644 --- a/arch/x86/platform/efi/efi.c +++ b/arch/x86/platform/efi/efi.c | |||
| @@ -70,17 +70,7 @@ static efi_config_table_type_t arch_tables[] __initdata = { | |||
| 70 | 70 | ||
| 71 | u64 efi_setup; /* efi setup_data physical address */ | 71 | u64 efi_setup; /* efi setup_data physical address */ |
| 72 | 72 | ||
| 73 | static bool disable_runtime __initdata = false; | 73 | static int add_efi_memmap __initdata; |
| 74 | static int __init setup_noefi(char *arg) | ||
| 75 | { | ||
| 76 | disable_runtime = true; | ||
| 77 | return 0; | ||
| 78 | } | ||
| 79 | early_param("noefi", setup_noefi); | ||
| 80 | |||
| 81 | int add_efi_memmap; | ||
| 82 | EXPORT_SYMBOL(add_efi_memmap); | ||
| 83 | |||
| 84 | static int __init setup_add_efi_memmap(char *arg) | 74 | static int __init setup_add_efi_memmap(char *arg) |
| 85 | { | 75 | { |
| 86 | add_efi_memmap = 1; | 76 | add_efi_memmap = 1; |
| @@ -96,7 +86,7 @@ static efi_status_t __init phys_efi_set_virtual_address_map( | |||
| 96 | { | 86 | { |
| 97 | efi_status_t status; | 87 | efi_status_t status; |
| 98 | 88 | ||
| 99 | efi_call_phys_prelog(); | 89 | efi_call_phys_prolog(); |
| 100 | status = efi_call_phys(efi_phys.set_virtual_address_map, | 90 | status = efi_call_phys(efi_phys.set_virtual_address_map, |
| 101 | memory_map_size, descriptor_size, | 91 | memory_map_size, descriptor_size, |
| 102 | descriptor_version, virtual_map); | 92 | descriptor_version, virtual_map); |
| @@ -210,9 +200,12 @@ static void __init print_efi_memmap(void) | |||
| 210 | for (p = memmap.map, i = 0; | 200 | for (p = memmap.map, i = 0; |
| 211 | p < memmap.map_end; | 201 | p < memmap.map_end; |
| 212 | p += memmap.desc_size, i++) { | 202 | p += memmap.desc_size, i++) { |
| 203 | char buf[64]; | ||
| 204 | |||
| 213 | md = p; | 205 | md = p; |
| 214 | pr_info("mem%02u: type=%u, attr=0x%llx, range=[0x%016llx-0x%016llx) (%lluMB)\n", | 206 | pr_info("mem%02u: %s range=[0x%016llx-0x%016llx) (%lluMB)\n", |
| 215 | i, md->type, md->attribute, md->phys_addr, | 207 | i, efi_md_typeattr_format(buf, sizeof(buf), md), |
| 208 | md->phys_addr, | ||
| 216 | md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT), | 209 | md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT), |
| 217 | (md->num_pages >> (20 - EFI_PAGE_SHIFT))); | 210 | (md->num_pages >> (20 - EFI_PAGE_SHIFT))); |
| 218 | } | 211 | } |
| @@ -344,9 +337,9 @@ static int __init efi_runtime_init32(void) | |||
| 344 | } | 337 | } |
| 345 | 338 | ||
| 346 | /* | 339 | /* |
| 347 | * We will only need *early* access to the following two | 340 | * We will only need *early* access to the SetVirtualAddressMap |
| 348 | * EFI runtime services before set_virtual_address_map | 341 | * EFI runtime service. All other runtime services will be called |
| 349 | * is invoked. | 342 | * via the virtual mapping. |
| 350 | */ | 343 | */ |
| 351 | efi_phys.set_virtual_address_map = | 344 | efi_phys.set_virtual_address_map = |
| 352 | (efi_set_virtual_address_map_t *) | 345 | (efi_set_virtual_address_map_t *) |
| @@ -368,9 +361,9 @@ static int __init efi_runtime_init64(void) | |||
| 368 | } | 361 | } |
| 369 | 362 | ||
| 370 | /* | 363 | /* |
| 371 | * We will only need *early* access to the following two | 364 | * We will only need *early* access to the SetVirtualAddressMap |
| 372 | * EFI runtime services before set_virtual_address_map | 365 | * EFI runtime service. All other runtime services will be called |
| 373 | * is invoked. | 366 | * via the virtual mapping. |
| 374 | */ | 367 | */ |
| 375 | efi_phys.set_virtual_address_map = | 368 | efi_phys.set_virtual_address_map = |
| 376 | (efi_set_virtual_address_map_t *) | 369 | (efi_set_virtual_address_map_t *) |
| @@ -492,7 +485,7 @@ void __init efi_init(void) | |||
| 492 | if (!efi_runtime_supported()) | 485 | if (!efi_runtime_supported()) |
| 493 | pr_info("No EFI runtime due to 32/64-bit mismatch with kernel\n"); | 486 | pr_info("No EFI runtime due to 32/64-bit mismatch with kernel\n"); |
| 494 | else { | 487 | else { |
| 495 | if (disable_runtime || efi_runtime_init()) | 488 | if (efi_runtime_disabled() || efi_runtime_init()) |
| 496 | return; | 489 | return; |
| 497 | } | 490 | } |
| 498 | if (efi_memmap_init()) | 491 | if (efi_memmap_init()) |
| @@ -537,7 +530,7 @@ void __init runtime_code_page_mkexec(void) | |||
| 537 | } | 530 | } |
| 538 | } | 531 | } |
| 539 | 532 | ||
| 540 | void efi_memory_uc(u64 addr, unsigned long size) | 533 | void __init efi_memory_uc(u64 addr, unsigned long size) |
| 541 | { | 534 | { |
| 542 | unsigned long page_shift = 1UL << EFI_PAGE_SHIFT; | 535 | unsigned long page_shift = 1UL << EFI_PAGE_SHIFT; |
| 543 | u64 npages; | 536 | u64 npages; |
| @@ -732,6 +725,7 @@ static void __init kexec_enter_virtual_mode(void) | |||
| 732 | */ | 725 | */ |
| 733 | if (!efi_is_native()) { | 726 | if (!efi_is_native()) { |
| 734 | efi_unmap_memmap(); | 727 | efi_unmap_memmap(); |
| 728 | clear_bit(EFI_RUNTIME_SERVICES, &efi.flags); | ||
| 735 | return; | 729 | return; |
| 736 | } | 730 | } |
| 737 | 731 | ||
| @@ -805,6 +799,7 @@ static void __init __efi_enter_virtual_mode(void) | |||
| 805 | new_memmap = efi_map_regions(&count, &pg_shift); | 799 | new_memmap = efi_map_regions(&count, &pg_shift); |
| 806 | if (!new_memmap) { | 800 | if (!new_memmap) { |
| 807 | pr_err("Error reallocating memory, EFI runtime non-functional!\n"); | 801 | pr_err("Error reallocating memory, EFI runtime non-functional!\n"); |
| 802 | clear_bit(EFI_RUNTIME_SERVICES, &efi.flags); | ||
| 808 | return; | 803 | return; |
| 809 | } | 804 | } |
| 810 | 805 | ||
| @@ -812,8 +807,10 @@ static void __init __efi_enter_virtual_mode(void) | |||
| 812 | 807 | ||
| 813 | BUG_ON(!efi.systab); | 808 | BUG_ON(!efi.systab); |
| 814 | 809 | ||
| 815 | if (efi_setup_page_tables(__pa(new_memmap), 1 << pg_shift)) | 810 | if (efi_setup_page_tables(__pa(new_memmap), 1 << pg_shift)) { |
| 811 | clear_bit(EFI_RUNTIME_SERVICES, &efi.flags); | ||
| 816 | return; | 812 | return; |
| 813 | } | ||
| 817 | 814 | ||
| 818 | efi_sync_low_kernel_mappings(); | 815 | efi_sync_low_kernel_mappings(); |
| 819 | efi_dump_pagetable(); | 816 | efi_dump_pagetable(); |
| @@ -938,14 +935,11 @@ u64 efi_mem_attributes(unsigned long phys_addr) | |||
| 938 | return 0; | 935 | return 0; |
| 939 | } | 936 | } |
| 940 | 937 | ||
| 941 | static int __init parse_efi_cmdline(char *str) | 938 | static int __init arch_parse_efi_cmdline(char *str) |
| 942 | { | 939 | { |
| 943 | if (*str == '=') | 940 | if (parse_option_str(str, "old_map")) |
| 944 | str++; | ||
| 945 | |||
| 946 | if (!strncmp(str, "old_map", 7)) | ||
| 947 | set_bit(EFI_OLD_MEMMAP, &efi.flags); | 941 | set_bit(EFI_OLD_MEMMAP, &efi.flags); |
| 948 | 942 | ||
| 949 | return 0; | 943 | return 0; |
| 950 | } | 944 | } |
| 951 | early_param("efi", parse_efi_cmdline); | 945 | early_param("efi", arch_parse_efi_cmdline); |
diff --git a/arch/x86/platform/efi/efi_32.c b/arch/x86/platform/efi/efi_32.c index 9ee3491e31fb..40e7cda52936 100644 --- a/arch/x86/platform/efi/efi_32.c +++ b/arch/x86/platform/efi/efi_32.c | |||
| @@ -33,7 +33,7 @@ | |||
| 33 | 33 | ||
| 34 | /* | 34 | /* |
| 35 | * To make EFI call EFI runtime service in physical addressing mode we need | 35 | * To make EFI call EFI runtime service in physical addressing mode we need |
| 36 | * prelog/epilog before/after the invocation to disable interrupt, to | 36 | * prolog/epilog before/after the invocation to disable interrupt, to |
| 37 | * claim EFI runtime service handler exclusively and to duplicate a memory in | 37 | * claim EFI runtime service handler exclusively and to duplicate a memory in |
| 38 | * low memory space say 0 - 3G. | 38 | * low memory space say 0 - 3G. |
| 39 | */ | 39 | */ |
| @@ -41,11 +41,13 @@ static unsigned long efi_rt_eflags; | |||
| 41 | 41 | ||
| 42 | void efi_sync_low_kernel_mappings(void) {} | 42 | void efi_sync_low_kernel_mappings(void) {} |
| 43 | void __init efi_dump_pagetable(void) {} | 43 | void __init efi_dump_pagetable(void) {} |
| 44 | int efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages) | 44 | int __init efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages) |
| 45 | { | 45 | { |
| 46 | return 0; | 46 | return 0; |
| 47 | } | 47 | } |
| 48 | void efi_cleanup_page_tables(unsigned long pa_memmap, unsigned num_pages) {} | 48 | void __init efi_cleanup_page_tables(unsigned long pa_memmap, unsigned num_pages) |
| 49 | { | ||
| 50 | } | ||
| 49 | 51 | ||
| 50 | void __init efi_map_region(efi_memory_desc_t *md) | 52 | void __init efi_map_region(efi_memory_desc_t *md) |
| 51 | { | 53 | { |
| @@ -55,7 +57,7 @@ void __init efi_map_region(efi_memory_desc_t *md) | |||
| 55 | void __init efi_map_region_fixed(efi_memory_desc_t *md) {} | 57 | void __init efi_map_region_fixed(efi_memory_desc_t *md) {} |
| 56 | void __init parse_efi_setup(u64 phys_addr, u32 data_len) {} | 58 | void __init parse_efi_setup(u64 phys_addr, u32 data_len) {} |
| 57 | 59 | ||
| 58 | void efi_call_phys_prelog(void) | 60 | void __init efi_call_phys_prolog(void) |
| 59 | { | 61 | { |
| 60 | struct desc_ptr gdt_descr; | 62 | struct desc_ptr gdt_descr; |
| 61 | 63 | ||
| @@ -69,7 +71,7 @@ void efi_call_phys_prelog(void) | |||
| 69 | load_gdt(&gdt_descr); | 71 | load_gdt(&gdt_descr); |
| 70 | } | 72 | } |
| 71 | 73 | ||
| 72 | void efi_call_phys_epilog(void) | 74 | void __init efi_call_phys_epilog(void) |
| 73 | { | 75 | { |
| 74 | struct desc_ptr gdt_descr; | 76 | struct desc_ptr gdt_descr; |
| 75 | 77 | ||
diff --git a/arch/x86/platform/efi/efi_64.c b/arch/x86/platform/efi/efi_64.c index 290d397e1dd9..35aecb6042fb 100644 --- a/arch/x86/platform/efi/efi_64.c +++ b/arch/x86/platform/efi/efi_64.c | |||
| @@ -79,7 +79,7 @@ static void __init early_code_mapping_set_exec(int executable) | |||
| 79 | } | 79 | } |
| 80 | } | 80 | } |
| 81 | 81 | ||
| 82 | void __init efi_call_phys_prelog(void) | 82 | void __init efi_call_phys_prolog(void) |
| 83 | { | 83 | { |
| 84 | unsigned long vaddress; | 84 | unsigned long vaddress; |
| 85 | int pgd; | 85 | int pgd; |
| @@ -139,7 +139,7 @@ void efi_sync_low_kernel_mappings(void) | |||
| 139 | sizeof(pgd_t) * num_pgds); | 139 | sizeof(pgd_t) * num_pgds); |
| 140 | } | 140 | } |
| 141 | 141 | ||
| 142 | int efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages) | 142 | int __init efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages) |
| 143 | { | 143 | { |
| 144 | unsigned long text; | 144 | unsigned long text; |
| 145 | struct page *page; | 145 | struct page *page; |
| @@ -192,7 +192,7 @@ int efi_setup_page_tables(unsigned long pa_memmap, unsigned num_pages) | |||
| 192 | return 0; | 192 | return 0; |
| 193 | } | 193 | } |
| 194 | 194 | ||
| 195 | void efi_cleanup_page_tables(unsigned long pa_memmap, unsigned num_pages) | 195 | void __init efi_cleanup_page_tables(unsigned long pa_memmap, unsigned num_pages) |
| 196 | { | 196 | { |
| 197 | pgd_t *pgd = (pgd_t *)__va(real_mode_header->trampoline_pgd); | 197 | pgd_t *pgd = (pgd_t *)__va(real_mode_header->trampoline_pgd); |
| 198 | 198 | ||
diff --git a/arch/x86/platform/efi/efi_stub_32.S b/arch/x86/platform/efi/efi_stub_32.S index fbe66e626c09..040192b50d02 100644 --- a/arch/x86/platform/efi/efi_stub_32.S +++ b/arch/x86/platform/efi/efi_stub_32.S | |||
| @@ -27,13 +27,13 @@ ENTRY(efi_call_phys) | |||
| 27 | * set to 0x0010, DS and SS have been set to 0x0018. In EFI, I found | 27 | * set to 0x0010, DS and SS have been set to 0x0018. In EFI, I found |
| 28 | * the values of these registers are the same. And, the corresponding | 28 | * the values of these registers are the same. And, the corresponding |
| 29 | * GDT entries are identical. So I will do nothing about segment reg | 29 | * GDT entries are identical. So I will do nothing about segment reg |
| 30 | * and GDT, but change GDT base register in prelog and epilog. | 30 | * and GDT, but change GDT base register in prolog and epilog. |
| 31 | */ | 31 | */ |
| 32 | 32 | ||
| 33 | /* | 33 | /* |
| 34 | * 1. Now I am running with EIP = <physical address> + PAGE_OFFSET. | 34 | * 1. Now I am running with EIP = <physical address> + PAGE_OFFSET. |
| 35 | * But to make it smoothly switch from virtual mode to flat mode. | 35 | * But to make it smoothly switch from virtual mode to flat mode. |
| 36 | * The mapping of lower virtual memory has been created in prelog and | 36 | * The mapping of lower virtual memory has been created in prolog and |
| 37 | * epilog. | 37 | * epilog. |
| 38 | */ | 38 | */ |
| 39 | movl $1f, %edx | 39 | movl $1f, %edx |
diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index 64ecbb501c50..8590099ac148 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c | |||
| @@ -41,6 +41,28 @@ struct efi __read_mostly efi = { | |||
| 41 | }; | 41 | }; |
| 42 | EXPORT_SYMBOL(efi); | 42 | EXPORT_SYMBOL(efi); |
| 43 | 43 | ||
| 44 | static bool disable_runtime; | ||
| 45 | static int __init setup_noefi(char *arg) | ||
| 46 | { | ||
| 47 | disable_runtime = true; | ||
| 48 | return 0; | ||
| 49 | } | ||
| 50 | early_param("noefi", setup_noefi); | ||
| 51 | |||
| 52 | bool efi_runtime_disabled(void) | ||
| 53 | { | ||
| 54 | return disable_runtime; | ||
| 55 | } | ||
| 56 | |||
| 57 | static int __init parse_efi_cmdline(char *str) | ||
| 58 | { | ||
| 59 | if (parse_option_str(str, "noruntime")) | ||
| 60 | disable_runtime = true; | ||
| 61 | |||
| 62 | return 0; | ||
| 63 | } | ||
| 64 | early_param("efi", parse_efi_cmdline); | ||
| 65 | |||
| 44 | static struct kobject *efi_kobj; | 66 | static struct kobject *efi_kobj; |
| 45 | static struct kobject *efivars_kobj; | 67 | static struct kobject *efivars_kobj; |
| 46 | 68 | ||
| @@ -423,3 +445,60 @@ int __init efi_get_fdt_params(struct efi_fdt_params *params, int verbose) | |||
| 423 | return ret; | 445 | return ret; |
| 424 | } | 446 | } |
| 425 | #endif /* CONFIG_EFI_PARAMS_FROM_FDT */ | 447 | #endif /* CONFIG_EFI_PARAMS_FROM_FDT */ |
| 448 | |||
| 449 | static __initdata char memory_type_name[][20] = { | ||
| 450 | "Reserved", | ||
| 451 | "Loader Code", | ||
| 452 | "Loader Data", | ||
| 453 | "Boot Code", | ||
| 454 | "Boot Data", | ||
| 455 | "Runtime Code", | ||
| 456 | "Runtime Data", | ||
| 457 | "Conventional Memory", | ||
| 458 | "Unusable Memory", | ||
| 459 | "ACPI Reclaim Memory", | ||
| 460 | "ACPI Memory NVS", | ||
| 461 | "Memory Mapped I/O", | ||
| 462 | "MMIO Port Space", | ||
| 463 | "PAL Code" | ||
| 464 | }; | ||
| 465 | |||
| 466 | char * __init efi_md_typeattr_format(char *buf, size_t size, | ||
| 467 | const efi_memory_desc_t *md) | ||
| 468 | { | ||
| 469 | char *pos; | ||
| 470 | int type_len; | ||
| 471 | u64 attr; | ||
| 472 | |||
| 473 | pos = buf; | ||
| 474 | if (md->type >= ARRAY_SIZE(memory_type_name)) | ||
| 475 | type_len = snprintf(pos, size, "[type=%u", md->type); | ||
| 476 | else | ||
| 477 | type_len = snprintf(pos, size, "[%-*s", | ||
| 478 | (int)(sizeof(memory_type_name[0]) - 1), | ||
| 479 | memory_type_name[md->type]); | ||
| 480 | if (type_len >= size) | ||
| 481 | return buf; | ||
| 482 | |||
| 483 | pos += type_len; | ||
| 484 | size -= type_len; | ||
| 485 | |||
| 486 | attr = md->attribute; | ||
| 487 | if (attr & ~(EFI_MEMORY_UC | EFI_MEMORY_WC | EFI_MEMORY_WT | | ||
| 488 | EFI_MEMORY_WB | EFI_MEMORY_UCE | EFI_MEMORY_WP | | ||
| 489 | EFI_MEMORY_RP | EFI_MEMORY_XP | EFI_MEMORY_RUNTIME)) | ||
| 490 | snprintf(pos, size, "|attr=0x%016llx]", | ||
| 491 | (unsigned long long)attr); | ||
| 492 | else | ||
| 493 | snprintf(pos, size, "|%3s|%2s|%2s|%2s|%3s|%2s|%2s|%2s|%2s]", | ||
| 494 | attr & EFI_MEMORY_RUNTIME ? "RUN" : "", | ||
| 495 | attr & EFI_MEMORY_XP ? "XP" : "", | ||
| 496 | attr & EFI_MEMORY_RP ? "RP" : "", | ||
| 497 | attr & EFI_MEMORY_WP ? "WP" : "", | ||
| 498 | attr & EFI_MEMORY_UCE ? "UCE" : "", | ||
| 499 | attr & EFI_MEMORY_WB ? "WB" : "", | ||
| 500 | attr & EFI_MEMORY_WT ? "WT" : "", | ||
| 501 | attr & EFI_MEMORY_WC ? "WC" : "", | ||
| 502 | attr & EFI_MEMORY_UC ? "UC" : ""); | ||
| 503 | return buf; | ||
| 504 | } | ||
diff --git a/drivers/firmware/efi/libstub/arm-stub.c b/drivers/firmware/efi/libstub/arm-stub.c index 480339b6b110..75ee05964cbc 100644 --- a/drivers/firmware/efi/libstub/arm-stub.c +++ b/drivers/firmware/efi/libstub/arm-stub.c | |||
| @@ -226,6 +226,10 @@ unsigned long __init efi_entry(void *handle, efi_system_table_t *sys_table, | |||
| 226 | goto fail_free_image; | 226 | goto fail_free_image; |
| 227 | } | 227 | } |
| 228 | 228 | ||
| 229 | status = efi_parse_options(cmdline_ptr); | ||
| 230 | if (status != EFI_SUCCESS) | ||
| 231 | pr_efi_err(sys_table, "Failed to parse EFI cmdline options\n"); | ||
| 232 | |||
| 229 | /* | 233 | /* |
| 230 | * Unauthenticated device tree data is a security hazard, so | 234 | * Unauthenticated device tree data is a security hazard, so |
| 231 | * ignore 'dtb=' unless UEFI Secure Boot is disabled. | 235 | * ignore 'dtb=' unless UEFI Secure Boot is disabled. |
diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c index 32d5cca30f49..a920fec8fe88 100644 --- a/drivers/firmware/efi/libstub/efi-stub-helper.c +++ b/drivers/firmware/efi/libstub/efi-stub-helper.c | |||
| @@ -15,8 +15,23 @@ | |||
| 15 | 15 | ||
| 16 | #include "efistub.h" | 16 | #include "efistub.h" |
| 17 | 17 | ||
| 18 | /* | ||
| 19 | * Some firmware implementations have problems reading files in one go. | ||
| 20 | * A read chunk size of 1MB seems to work for most platforms. | ||
| 21 | * | ||
| 22 | * Unfortunately, reading files in chunks triggers *other* bugs on some | ||
| 23 | * platforms, so we provide a way to disable this workaround, which can | ||
| 24 | * be done by passing "efi=nochunk" on the EFI boot stub command line. | ||
| 25 | * | ||
| 26 | * If you experience issues with initrd images being corrupt it's worth | ||
| 27 | * trying efi=nochunk, but chunking is enabled by default because there | ||
| 28 | * are far more machines that require the workaround than those that | ||
| 29 | * break with it enabled. | ||
| 30 | */ | ||
| 18 | #define EFI_READ_CHUNK_SIZE (1024 * 1024) | 31 | #define EFI_READ_CHUNK_SIZE (1024 * 1024) |
| 19 | 32 | ||
| 33 | static unsigned long __chunk_size = EFI_READ_CHUNK_SIZE; | ||
| 34 | |||
| 20 | struct file_info { | 35 | struct file_info { |
| 21 | efi_file_handle_t *handle; | 36 | efi_file_handle_t *handle; |
| 22 | u64 size; | 37 | u64 size; |
| @@ -281,6 +296,49 @@ void efi_free(efi_system_table_t *sys_table_arg, unsigned long size, | |||
| 281 | efi_call_early(free_pages, addr, nr_pages); | 296 | efi_call_early(free_pages, addr, nr_pages); |
| 282 | } | 297 | } |
| 283 | 298 | ||
| 299 | /* | ||
| 300 | * Parse the ASCII string 'cmdline' for EFI options, denoted by the efi= | ||
| 301 | * option, e.g. efi=nochunk. | ||
| 302 | * | ||
| 303 | * It should be noted that efi= is parsed in two very different | ||
| 304 | * environments, first in the early boot environment of the EFI boot | ||
| 305 | * stub, and subsequently during the kernel boot. | ||
| 306 | */ | ||
| 307 | efi_status_t efi_parse_options(char *cmdline) | ||
| 308 | { | ||
| 309 | char *str; | ||
| 310 | |||
| 311 | /* | ||
| 312 | * If no EFI parameters were specified on the cmdline we've got | ||
| 313 | * nothing to do. | ||
| 314 | */ | ||
| 315 | str = strstr(cmdline, "efi="); | ||
| 316 | if (!str) | ||
| 317 | return EFI_SUCCESS; | ||
| 318 | |||
| 319 | /* Skip ahead to first argument */ | ||
| 320 | str += strlen("efi="); | ||
| 321 | |||
| 322 | /* | ||
| 323 | * Remember, because efi= is also used by the kernel we need to | ||
| 324 | * skip over arguments we don't understand. | ||
| 325 | */ | ||
| 326 | while (*str) { | ||
| 327 | if (!strncmp(str, "nochunk", 7)) { | ||
| 328 | str += strlen("nochunk"); | ||
| 329 | __chunk_size = -1UL; | ||
| 330 | } | ||
| 331 | |||
| 332 | /* Group words together, delimited by "," */ | ||
| 333 | while (*str && *str != ',') | ||
| 334 | str++; | ||
| 335 | |||
| 336 | if (*str == ',') | ||
| 337 | str++; | ||
| 338 | } | ||
| 339 | |||
| 340 | return EFI_SUCCESS; | ||
| 341 | } | ||
| 284 | 342 | ||
| 285 | /* | 343 | /* |
| 286 | * Check the cmdline for a LILO-style file= arguments. | 344 | * Check the cmdline for a LILO-style file= arguments. |
| @@ -423,8 +481,8 @@ efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg, | |||
| 423 | size = files[j].size; | 481 | size = files[j].size; |
| 424 | while (size) { | 482 | while (size) { |
| 425 | unsigned long chunksize; | 483 | unsigned long chunksize; |
| 426 | if (size > EFI_READ_CHUNK_SIZE) | 484 | if (size > __chunk_size) |
| 427 | chunksize = EFI_READ_CHUNK_SIZE; | 485 | chunksize = __chunk_size; |
| 428 | else | 486 | else |
| 429 | chunksize = size; | 487 | chunksize = size; |
| 430 | 488 | ||
diff --git a/drivers/firmware/efi/runtime-wrappers.c b/drivers/firmware/efi/runtime-wrappers.c index 10daa4bbb258..228bbf910461 100644 --- a/drivers/firmware/efi/runtime-wrappers.c +++ b/drivers/firmware/efi/runtime-wrappers.c | |||
| @@ -14,11 +14,80 @@ | |||
| 14 | * This file is released under the GPLv2. | 14 | * This file is released under the GPLv2. |
| 15 | */ | 15 | */ |
| 16 | 16 | ||
| 17 | #include <linux/bug.h> | ||
| 17 | #include <linux/efi.h> | 18 | #include <linux/efi.h> |
| 18 | #include <linux/spinlock.h> /* spinlock_t */ | 19 | #include <linux/mutex.h> |
| 20 | #include <linux/spinlock.h> | ||
| 19 | #include <asm/efi.h> | 21 | #include <asm/efi.h> |
| 20 | 22 | ||
| 21 | /* | 23 | /* |
| 24 | * According to section 7.1 of the UEFI spec, Runtime Services are not fully | ||
| 25 | * reentrant, and there are particular combinations of calls that need to be | ||
| 26 | * serialized. (source: UEFI Specification v2.4A) | ||
| 27 | * | ||
| 28 | * Table 31. Rules for Reentry Into Runtime Services | ||
| 29 | * +------------------------------------+-------------------------------+ | ||
| 30 | * | If previous call is busy in | Forbidden to call | | ||
| 31 | * +------------------------------------+-------------------------------+ | ||
| 32 | * | Any | SetVirtualAddressMap() | | ||
| 33 | * +------------------------------------+-------------------------------+ | ||
| 34 | * | ConvertPointer() | ConvertPointer() | | ||
| 35 | * +------------------------------------+-------------------------------+ | ||
| 36 | * | SetVariable() | ResetSystem() | | ||
| 37 | * | UpdateCapsule() | | | ||
| 38 | * | SetTime() | | | ||
| 39 | * | SetWakeupTime() | | | ||
| 40 | * | GetNextHighMonotonicCount() | | | ||
| 41 | * +------------------------------------+-------------------------------+ | ||
| 42 | * | GetVariable() | GetVariable() | | ||
| 43 | * | GetNextVariableName() | GetNextVariableName() | | ||
| 44 | * | SetVariable() | SetVariable() | | ||
| 45 | * | QueryVariableInfo() | QueryVariableInfo() | | ||
| 46 | * | UpdateCapsule() | UpdateCapsule() | | ||
| 47 | * | QueryCapsuleCapabilities() | QueryCapsuleCapabilities() | | ||
| 48 | * | GetNextHighMonotonicCount() | GetNextHighMonotonicCount() | | ||
| 49 | * +------------------------------------+-------------------------------+ | ||
| 50 | * | GetTime() | GetTime() | | ||
| 51 | * | SetTime() | SetTime() | | ||
| 52 | * | GetWakeupTime() | GetWakeupTime() | | ||
| 53 | * | SetWakeupTime() | SetWakeupTime() | | ||
| 54 | * +------------------------------------+-------------------------------+ | ||
| 55 | * | ||
| 56 | * Due to the fact that the EFI pstore may write to the variable store in | ||
| 57 | * interrupt context, we need to use a spinlock for at least the groups that | ||
| 58 | * contain SetVariable() and QueryVariableInfo(). That leaves little else, as | ||
| 59 | * none of the remaining functions are actually ever called at runtime. | ||
| 60 | * So let's just use a single spinlock to serialize all Runtime Services calls. | ||
| 61 | */ | ||
| 62 | static DEFINE_SPINLOCK(efi_runtime_lock); | ||
| 63 | |||
| 64 | /* | ||
| 65 | * Some runtime services calls can be reentrant under NMI, even if the table | ||
| 66 | * above says they are not. (source: UEFI Specification v2.4A) | ||
| 67 | * | ||
| 68 | * Table 32. Functions that may be called after Machine Check, INIT and NMI | ||
| 69 | * +----------------------------+------------------------------------------+ | ||
| 70 | * | Function | Called after Machine Check, INIT and NMI | | ||
| 71 | * +----------------------------+------------------------------------------+ | ||
| 72 | * | GetTime() | Yes, even if previously busy. | | ||
| 73 | * | GetVariable() | Yes, even if previously busy | | ||
| 74 | * | GetNextVariableName() | Yes, even if previously busy | | ||
| 75 | * | QueryVariableInfo() | Yes, even if previously busy | | ||
| 76 | * | SetVariable() | Yes, even if previously busy | | ||
| 77 | * | UpdateCapsule() | Yes, even if previously busy | | ||
| 78 | * | QueryCapsuleCapabilities() | Yes, even if previously busy | | ||
| 79 | * | ResetSystem() | Yes, even if previously busy | | ||
| 80 | * +----------------------------+------------------------------------------+ | ||
| 81 | * | ||
| 82 | * In order to prevent deadlocks under NMI, the wrappers for these functions | ||
| 83 | * may only grab the efi_runtime_lock or rtc_lock spinlocks if !efi_in_nmi(). | ||
| 84 | * However, not all of the services listed are reachable through NMI code paths, | ||
| 85 | * so the the special handling as suggested by the UEFI spec is only implemented | ||
| 86 | * for QueryVariableInfo() and SetVariable(), as these can be reached in NMI | ||
| 87 | * context through efi_pstore_write(). | ||
| 88 | */ | ||
| 89 | |||
| 90 | /* | ||
| 22 | * As per commit ef68c8f87ed1 ("x86: Serialize EFI time accesses on rtc_lock"), | 91 | * As per commit ef68c8f87ed1 ("x86: Serialize EFI time accesses on rtc_lock"), |
| 23 | * the EFI specification requires that callers of the time related runtime | 92 | * the EFI specification requires that callers of the time related runtime |
| 24 | * functions serialize with other CMOS accesses in the kernel, as the EFI time | 93 | * functions serialize with other CMOS accesses in the kernel, as the EFI time |
| @@ -32,7 +101,9 @@ static efi_status_t virt_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc) | |||
| 32 | efi_status_t status; | 101 | efi_status_t status; |
| 33 | 102 | ||
| 34 | spin_lock_irqsave(&rtc_lock, flags); | 103 | spin_lock_irqsave(&rtc_lock, flags); |
| 104 | spin_lock(&efi_runtime_lock); | ||
| 35 | status = efi_call_virt(get_time, tm, tc); | 105 | status = efi_call_virt(get_time, tm, tc); |
| 106 | spin_unlock(&efi_runtime_lock); | ||
| 36 | spin_unlock_irqrestore(&rtc_lock, flags); | 107 | spin_unlock_irqrestore(&rtc_lock, flags); |
| 37 | return status; | 108 | return status; |
| 38 | } | 109 | } |
| @@ -43,7 +114,9 @@ static efi_status_t virt_efi_set_time(efi_time_t *tm) | |||
| 43 | efi_status_t status; | 114 | efi_status_t status; |
| 44 | 115 | ||
| 45 | spin_lock_irqsave(&rtc_lock, flags); | 116 | spin_lock_irqsave(&rtc_lock, flags); |
| 117 | spin_lock(&efi_runtime_lock); | ||
| 46 | status = efi_call_virt(set_time, tm); | 118 | status = efi_call_virt(set_time, tm); |
| 119 | spin_unlock(&efi_runtime_lock); | ||
| 47 | spin_unlock_irqrestore(&rtc_lock, flags); | 120 | spin_unlock_irqrestore(&rtc_lock, flags); |
| 48 | return status; | 121 | return status; |
| 49 | } | 122 | } |
| @@ -56,7 +129,9 @@ static efi_status_t virt_efi_get_wakeup_time(efi_bool_t *enabled, | |||
| 56 | efi_status_t status; | 129 | efi_status_t status; |
| 57 | 130 | ||
| 58 | spin_lock_irqsave(&rtc_lock, flags); | 131 | spin_lock_irqsave(&rtc_lock, flags); |
| 132 | spin_lock(&efi_runtime_lock); | ||
| 59 | status = efi_call_virt(get_wakeup_time, enabled, pending, tm); | 133 | status = efi_call_virt(get_wakeup_time, enabled, pending, tm); |
| 134 | spin_unlock(&efi_runtime_lock); | ||
| 60 | spin_unlock_irqrestore(&rtc_lock, flags); | 135 | spin_unlock_irqrestore(&rtc_lock, flags); |
| 61 | return status; | 136 | return status; |
| 62 | } | 137 | } |
| @@ -67,7 +142,9 @@ static efi_status_t virt_efi_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm) | |||
| 67 | efi_status_t status; | 142 | efi_status_t status; |
| 68 | 143 | ||
| 69 | spin_lock_irqsave(&rtc_lock, flags); | 144 | spin_lock_irqsave(&rtc_lock, flags); |
| 145 | spin_lock(&efi_runtime_lock); | ||
| 70 | status = efi_call_virt(set_wakeup_time, enabled, tm); | 146 | status = efi_call_virt(set_wakeup_time, enabled, tm); |
| 147 | spin_unlock(&efi_runtime_lock); | ||
| 71 | spin_unlock_irqrestore(&rtc_lock, flags); | 148 | spin_unlock_irqrestore(&rtc_lock, flags); |
| 72 | return status; | 149 | return status; |
| 73 | } | 150 | } |
| @@ -78,14 +155,27 @@ static efi_status_t virt_efi_get_variable(efi_char16_t *name, | |||
| 78 | unsigned long *data_size, | 155 | unsigned long *data_size, |
| 79 | void *data) | 156 | void *data) |
| 80 | { | 157 | { |
| 81 | return efi_call_virt(get_variable, name, vendor, attr, data_size, data); | 158 | unsigned long flags; |
| 159 | efi_status_t status; | ||
| 160 | |||
| 161 | spin_lock_irqsave(&efi_runtime_lock, flags); | ||
| 162 | status = efi_call_virt(get_variable, name, vendor, attr, data_size, | ||
| 163 | data); | ||
| 164 | spin_unlock_irqrestore(&efi_runtime_lock, flags); | ||
| 165 | return status; | ||
| 82 | } | 166 | } |
| 83 | 167 | ||
| 84 | static efi_status_t virt_efi_get_next_variable(unsigned long *name_size, | 168 | static efi_status_t virt_efi_get_next_variable(unsigned long *name_size, |
| 85 | efi_char16_t *name, | 169 | efi_char16_t *name, |
| 86 | efi_guid_t *vendor) | 170 | efi_guid_t *vendor) |
| 87 | { | 171 | { |
| 88 | return efi_call_virt(get_next_variable, name_size, name, vendor); | 172 | unsigned long flags; |
| 173 | efi_status_t status; | ||
| 174 | |||
| 175 | spin_lock_irqsave(&efi_runtime_lock, flags); | ||
| 176 | status = efi_call_virt(get_next_variable, name_size, name, vendor); | ||
| 177 | spin_unlock_irqrestore(&efi_runtime_lock, flags); | ||
| 178 | return status; | ||
| 89 | } | 179 | } |
| 90 | 180 | ||
| 91 | static efi_status_t virt_efi_set_variable(efi_char16_t *name, | 181 | static efi_status_t virt_efi_set_variable(efi_char16_t *name, |
| @@ -94,24 +184,61 @@ static efi_status_t virt_efi_set_variable(efi_char16_t *name, | |||
| 94 | unsigned long data_size, | 184 | unsigned long data_size, |
| 95 | void *data) | 185 | void *data) |
| 96 | { | 186 | { |
| 97 | return efi_call_virt(set_variable, name, vendor, attr, data_size, data); | 187 | unsigned long flags; |
| 188 | efi_status_t status; | ||
| 189 | |||
| 190 | spin_lock_irqsave(&efi_runtime_lock, flags); | ||
| 191 | status = efi_call_virt(set_variable, name, vendor, attr, data_size, | ||
| 192 | data); | ||
| 193 | spin_unlock_irqrestore(&efi_runtime_lock, flags); | ||
| 194 | return status; | ||
| 98 | } | 195 | } |
| 99 | 196 | ||
| 197 | static efi_status_t | ||
| 198 | virt_efi_set_variable_nonblocking(efi_char16_t *name, efi_guid_t *vendor, | ||
| 199 | u32 attr, unsigned long data_size, | ||
| 200 | void *data) | ||
| 201 | { | ||
| 202 | unsigned long flags; | ||
| 203 | efi_status_t status; | ||
| 204 | |||
| 205 | if (!spin_trylock_irqsave(&efi_runtime_lock, flags)) | ||
| 206 | return EFI_NOT_READY; | ||
| 207 | |||
| 208 | status = efi_call_virt(set_variable, name, vendor, attr, data_size, | ||
| 209 | data); | ||
| 210 | spin_unlock_irqrestore(&efi_runtime_lock, flags); | ||
| 211 | return status; | ||
| 212 | } | ||
| 213 | |||
| 214 | |||
| 100 | static efi_status_t virt_efi_query_variable_info(u32 attr, | 215 | static efi_status_t virt_efi_query_variable_info(u32 attr, |
| 101 | u64 *storage_space, | 216 | u64 *storage_space, |
| 102 | u64 *remaining_space, | 217 | u64 *remaining_space, |
| 103 | u64 *max_variable_size) | 218 | u64 *max_variable_size) |
| 104 | { | 219 | { |
| 220 | unsigned long flags; | ||
| 221 | efi_status_t status; | ||
| 222 | |||
| 105 | if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) | 223 | if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) |
| 106 | return EFI_UNSUPPORTED; | 224 | return EFI_UNSUPPORTED; |
| 107 | 225 | ||
| 108 | return efi_call_virt(query_variable_info, attr, storage_space, | 226 | spin_lock_irqsave(&efi_runtime_lock, flags); |
| 109 | remaining_space, max_variable_size); | 227 | status = efi_call_virt(query_variable_info, attr, storage_space, |
| 228 | remaining_space, max_variable_size); | ||
| 229 | spin_unlock_irqrestore(&efi_runtime_lock, flags); | ||
| 230 | return status; | ||
| 110 | } | 231 | } |
| 111 | 232 | ||
| 112 | static efi_status_t virt_efi_get_next_high_mono_count(u32 *count) | 233 | static efi_status_t virt_efi_get_next_high_mono_count(u32 *count) |
| 113 | { | 234 | { |
| 114 | return efi_call_virt(get_next_high_mono_count, count); | 235 | unsigned long flags; |
| 236 | efi_status_t status; | ||
| 237 | |||
| 238 | spin_lock_irqsave(&efi_runtime_lock, flags); | ||
| 239 | status = efi_call_virt(get_next_high_mono_count, count); | ||
| 240 | spin_unlock_irqrestore(&efi_runtime_lock, flags); | ||
| 241 | return status; | ||
| 115 | } | 242 | } |
| 116 | 243 | ||
| 117 | static void virt_efi_reset_system(int reset_type, | 244 | static void virt_efi_reset_system(int reset_type, |
| @@ -119,17 +246,27 @@ static void virt_efi_reset_system(int reset_type, | |||
| 119 | unsigned long data_size, | 246 | unsigned long data_size, |
| 120 | efi_char16_t *data) | 247 | efi_char16_t *data) |
| 121 | { | 248 | { |
| 249 | unsigned long flags; | ||
| 250 | |||
| 251 | spin_lock_irqsave(&efi_runtime_lock, flags); | ||
| 122 | __efi_call_virt(reset_system, reset_type, status, data_size, data); | 252 | __efi_call_virt(reset_system, reset_type, status, data_size, data); |
| 253 | spin_unlock_irqrestore(&efi_runtime_lock, flags); | ||
| 123 | } | 254 | } |
| 124 | 255 | ||
| 125 | static efi_status_t virt_efi_update_capsule(efi_capsule_header_t **capsules, | 256 | static efi_status_t virt_efi_update_capsule(efi_capsule_header_t **capsules, |
| 126 | unsigned long count, | 257 | unsigned long count, |
| 127 | unsigned long sg_list) | 258 | unsigned long sg_list) |
| 128 | { | 259 | { |
| 260 | unsigned long flags; | ||
| 261 | efi_status_t status; | ||
| 262 | |||
| 129 | if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) | 263 | if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) |
| 130 | return EFI_UNSUPPORTED; | 264 | return EFI_UNSUPPORTED; |
| 131 | 265 | ||
| 132 | return efi_call_virt(update_capsule, capsules, count, sg_list); | 266 | spin_lock_irqsave(&efi_runtime_lock, flags); |
| 267 | status = efi_call_virt(update_capsule, capsules, count, sg_list); | ||
| 268 | spin_unlock_irqrestore(&efi_runtime_lock, flags); | ||
| 269 | return status; | ||
| 133 | } | 270 | } |
| 134 | 271 | ||
| 135 | static efi_status_t virt_efi_query_capsule_caps(efi_capsule_header_t **capsules, | 272 | static efi_status_t virt_efi_query_capsule_caps(efi_capsule_header_t **capsules, |
| @@ -137,11 +274,17 @@ static efi_status_t virt_efi_query_capsule_caps(efi_capsule_header_t **capsules, | |||
| 137 | u64 *max_size, | 274 | u64 *max_size, |
| 138 | int *reset_type) | 275 | int *reset_type) |
| 139 | { | 276 | { |
| 277 | unsigned long flags; | ||
| 278 | efi_status_t status; | ||
| 279 | |||
| 140 | if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) | 280 | if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) |
| 141 | return EFI_UNSUPPORTED; | 281 | return EFI_UNSUPPORTED; |
| 142 | 282 | ||
| 143 | return efi_call_virt(query_capsule_caps, capsules, count, max_size, | 283 | spin_lock_irqsave(&efi_runtime_lock, flags); |
| 144 | reset_type); | 284 | status = efi_call_virt(query_capsule_caps, capsules, count, max_size, |
| 285 | reset_type); | ||
| 286 | spin_unlock_irqrestore(&efi_runtime_lock, flags); | ||
| 287 | return status; | ||
| 145 | } | 288 | } |
| 146 | 289 | ||
| 147 | void efi_native_runtime_setup(void) | 290 | void efi_native_runtime_setup(void) |
| @@ -153,6 +296,7 @@ void efi_native_runtime_setup(void) | |||
| 153 | efi.get_variable = virt_efi_get_variable; | 296 | efi.get_variable = virt_efi_get_variable; |
| 154 | efi.get_next_variable = virt_efi_get_next_variable; | 297 | efi.get_next_variable = virt_efi_get_next_variable; |
| 155 | efi.set_variable = virt_efi_set_variable; | 298 | efi.set_variable = virt_efi_set_variable; |
| 299 | efi.set_variable_nonblocking = virt_efi_set_variable_nonblocking; | ||
| 156 | efi.get_next_high_mono_count = virt_efi_get_next_high_mono_count; | 300 | efi.get_next_high_mono_count = virt_efi_get_next_high_mono_count; |
| 157 | efi.reset_system = virt_efi_reset_system; | 301 | efi.reset_system = virt_efi_reset_system; |
| 158 | efi.query_variable_info = virt_efi_query_variable_info; | 302 | efi.query_variable_info = virt_efi_query_variable_info; |
diff --git a/drivers/firmware/efi/vars.c b/drivers/firmware/efi/vars.c index 5abe943e3404..70a0fb10517f 100644 --- a/drivers/firmware/efi/vars.c +++ b/drivers/firmware/efi/vars.c | |||
| @@ -321,11 +321,11 @@ static unsigned long var_name_strnsize(efi_char16_t *variable_name, | |||
| 321 | * Print a warning when duplicate EFI variables are encountered and | 321 | * Print a warning when duplicate EFI variables are encountered and |
| 322 | * disable the sysfs workqueue since the firmware is buggy. | 322 | * disable the sysfs workqueue since the firmware is buggy. |
| 323 | */ | 323 | */ |
| 324 | static void dup_variable_bug(efi_char16_t *s16, efi_guid_t *vendor_guid, | 324 | static void dup_variable_bug(efi_char16_t *str16, efi_guid_t *vendor_guid, |
| 325 | unsigned long len16) | 325 | unsigned long len16) |
| 326 | { | 326 | { |
| 327 | size_t i, len8 = len16 / sizeof(efi_char16_t); | 327 | size_t i, len8 = len16 / sizeof(efi_char16_t); |
| 328 | char *s8; | 328 | char *str8; |
| 329 | 329 | ||
| 330 | /* | 330 | /* |
| 331 | * Disable the workqueue since the algorithm it uses for | 331 | * Disable the workqueue since the algorithm it uses for |
| @@ -334,16 +334,16 @@ static void dup_variable_bug(efi_char16_t *s16, efi_guid_t *vendor_guid, | |||
| 334 | */ | 334 | */ |
| 335 | efivar_wq_enabled = false; | 335 | efivar_wq_enabled = false; |
| 336 | 336 | ||
| 337 | s8 = kzalloc(len8, GFP_KERNEL); | 337 | str8 = kzalloc(len8, GFP_KERNEL); |
| 338 | if (!s8) | 338 | if (!str8) |
| 339 | return; | 339 | return; |
| 340 | 340 | ||
| 341 | for (i = 0; i < len8; i++) | 341 | for (i = 0; i < len8; i++) |
| 342 | s8[i] = s16[i]; | 342 | str8[i] = str16[i]; |
| 343 | 343 | ||
| 344 | printk(KERN_WARNING "efivars: duplicate variable: %s-%pUl\n", | 344 | printk(KERN_WARNING "efivars: duplicate variable: %s-%pUl\n", |
| 345 | s8, vendor_guid); | 345 | str8, vendor_guid); |
| 346 | kfree(s8); | 346 | kfree(str8); |
| 347 | } | 347 | } |
| 348 | 348 | ||
| 349 | /** | 349 | /** |
| @@ -595,6 +595,39 @@ int efivar_entry_set(struct efivar_entry *entry, u32 attributes, | |||
| 595 | } | 595 | } |
| 596 | EXPORT_SYMBOL_GPL(efivar_entry_set); | 596 | EXPORT_SYMBOL_GPL(efivar_entry_set); |
| 597 | 597 | ||
| 598 | /* | ||
| 599 | * efivar_entry_set_nonblocking - call set_variable_nonblocking() | ||
| 600 | * | ||
| 601 | * This function is guaranteed to not block and is suitable for calling | ||
| 602 | * from crash/panic handlers. | ||
| 603 | * | ||
| 604 | * Crucially, this function will not block if it cannot acquire | ||
| 605 | * __efivars->lock. Instead, it returns -EBUSY. | ||
| 606 | */ | ||
| 607 | static int | ||
| 608 | efivar_entry_set_nonblocking(efi_char16_t *name, efi_guid_t vendor, | ||
| 609 | u32 attributes, unsigned long size, void *data) | ||
| 610 | { | ||
| 611 | const struct efivar_operations *ops = __efivars->ops; | ||
| 612 | unsigned long flags; | ||
| 613 | efi_status_t status; | ||
| 614 | |||
| 615 | if (!spin_trylock_irqsave(&__efivars->lock, flags)) | ||
| 616 | return -EBUSY; | ||
| 617 | |||
| 618 | status = check_var_size(attributes, size + ucs2_strsize(name, 1024)); | ||
| 619 | if (status != EFI_SUCCESS) { | ||
| 620 | spin_unlock_irqrestore(&__efivars->lock, flags); | ||
| 621 | return -ENOSPC; | ||
| 622 | } | ||
| 623 | |||
| 624 | status = ops->set_variable_nonblocking(name, &vendor, attributes, | ||
| 625 | size, data); | ||
| 626 | |||
| 627 | spin_unlock_irqrestore(&__efivars->lock, flags); | ||
| 628 | return efi_status_to_err(status); | ||
| 629 | } | ||
| 630 | |||
| 598 | /** | 631 | /** |
| 599 | * efivar_entry_set_safe - call set_variable() if enough space in firmware | 632 | * efivar_entry_set_safe - call set_variable() if enough space in firmware |
| 600 | * @name: buffer containing the variable name | 633 | * @name: buffer containing the variable name |
| @@ -622,6 +655,20 @@ int efivar_entry_set_safe(efi_char16_t *name, efi_guid_t vendor, u32 attributes, | |||
| 622 | if (!ops->query_variable_store) | 655 | if (!ops->query_variable_store) |
| 623 | return -ENOSYS; | 656 | return -ENOSYS; |
| 624 | 657 | ||
| 658 | /* | ||
| 659 | * If the EFI variable backend provides a non-blocking | ||
| 660 | * ->set_variable() operation and we're in a context where we | ||
| 661 | * cannot block, then we need to use it to avoid live-locks, | ||
| 662 | * since the implication is that the regular ->set_variable() | ||
| 663 | * will block. | ||
| 664 | * | ||
| 665 | * If no ->set_variable_nonblocking() is provided then | ||
| 666 | * ->set_variable() is assumed to be non-blocking. | ||
| 667 | */ | ||
| 668 | if (!block && ops->set_variable_nonblocking) | ||
| 669 | return efivar_entry_set_nonblocking(name, vendor, attributes, | ||
| 670 | size, data); | ||
| 671 | |||
| 625 | if (!block) { | 672 | if (!block) { |
| 626 | if (!spin_trylock_irqsave(&__efivars->lock, flags)) | 673 | if (!spin_trylock_irqsave(&__efivars->lock, flags)) |
| 627 | return -EBUSY; | 674 | return -EBUSY; |
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 8cd0beebdc3f..94ae1798d48a 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig | |||
| @@ -830,7 +830,7 @@ config RTC_DRV_DA9063 | |||
| 830 | 830 | ||
| 831 | config RTC_DRV_EFI | 831 | config RTC_DRV_EFI |
| 832 | tristate "EFI RTC" | 832 | tristate "EFI RTC" |
| 833 | depends on EFI | 833 | depends on EFI && !X86 |
| 834 | help | 834 | help |
| 835 | If you say yes here you will get support for the EFI | 835 | If you say yes here you will get support for the EFI |
| 836 | Real Time Clock. | 836 | Real Time Clock. |
diff --git a/drivers/rtc/rtc-efi.c b/drivers/rtc/rtc-efi.c index c384fec6d173..53b589dc34eb 100644 --- a/drivers/rtc/rtc-efi.c +++ b/drivers/rtc/rtc-efi.c | |||
| @@ -236,3 +236,4 @@ MODULE_ALIAS("platform:rtc-efi"); | |||
| 236 | MODULE_AUTHOR("dann frazier <dannf@hp.com>"); | 236 | MODULE_AUTHOR("dann frazier <dannf@hp.com>"); |
| 237 | MODULE_LICENSE("GPL"); | 237 | MODULE_LICENSE("GPL"); |
| 238 | MODULE_DESCRIPTION("EFI RTC driver"); | 238 | MODULE_DESCRIPTION("EFI RTC driver"); |
| 239 | MODULE_ALIAS("platform:rtc-efi"); | ||
diff --git a/include/linux/efi.h b/include/linux/efi.h index 45cb4ffdea62..0949f9c7e872 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h | |||
| @@ -92,6 +92,7 @@ typedef struct { | |||
| 92 | #define EFI_MEMORY_WC ((u64)0x0000000000000002ULL) /* write-coalescing */ | 92 | #define EFI_MEMORY_WC ((u64)0x0000000000000002ULL) /* write-coalescing */ |
| 93 | #define EFI_MEMORY_WT ((u64)0x0000000000000004ULL) /* write-through */ | 93 | #define EFI_MEMORY_WT ((u64)0x0000000000000004ULL) /* write-through */ |
| 94 | #define EFI_MEMORY_WB ((u64)0x0000000000000008ULL) /* write-back */ | 94 | #define EFI_MEMORY_WB ((u64)0x0000000000000008ULL) /* write-back */ |
| 95 | #define EFI_MEMORY_UCE ((u64)0x0000000000000010ULL) /* uncached, exported */ | ||
| 95 | #define EFI_MEMORY_WP ((u64)0x0000000000001000ULL) /* write-protect */ | 96 | #define EFI_MEMORY_WP ((u64)0x0000000000001000ULL) /* write-protect */ |
| 96 | #define EFI_MEMORY_RP ((u64)0x0000000000002000ULL) /* read-protect */ | 97 | #define EFI_MEMORY_RP ((u64)0x0000000000002000ULL) /* read-protect */ |
| 97 | #define EFI_MEMORY_XP ((u64)0x0000000000004000ULL) /* execute-protect */ | 98 | #define EFI_MEMORY_XP ((u64)0x0000000000004000ULL) /* execute-protect */ |
| @@ -502,6 +503,10 @@ typedef efi_status_t efi_get_next_variable_t (unsigned long *name_size, efi_char | |||
| 502 | typedef efi_status_t efi_set_variable_t (efi_char16_t *name, efi_guid_t *vendor, | 503 | typedef efi_status_t efi_set_variable_t (efi_char16_t *name, efi_guid_t *vendor, |
| 503 | u32 attr, unsigned long data_size, | 504 | u32 attr, unsigned long data_size, |
| 504 | void *data); | 505 | void *data); |
| 506 | typedef efi_status_t | ||
| 507 | efi_set_variable_nonblocking_t(efi_char16_t *name, efi_guid_t *vendor, | ||
| 508 | u32 attr, unsigned long data_size, void *data); | ||
| 509 | |||
| 505 | typedef efi_status_t efi_get_next_high_mono_count_t (u32 *count); | 510 | typedef efi_status_t efi_get_next_high_mono_count_t (u32 *count); |
| 506 | typedef void efi_reset_system_t (int reset_type, efi_status_t status, | 511 | typedef void efi_reset_system_t (int reset_type, efi_status_t status, |
| 507 | unsigned long data_size, efi_char16_t *data); | 512 | unsigned long data_size, efi_char16_t *data); |
| @@ -821,6 +826,7 @@ extern struct efi { | |||
| 821 | efi_get_variable_t *get_variable; | 826 | efi_get_variable_t *get_variable; |
| 822 | efi_get_next_variable_t *get_next_variable; | 827 | efi_get_next_variable_t *get_next_variable; |
| 823 | efi_set_variable_t *set_variable; | 828 | efi_set_variable_t *set_variable; |
| 829 | efi_set_variable_nonblocking_t *set_variable_nonblocking; | ||
| 824 | efi_query_variable_info_t *query_variable_info; | 830 | efi_query_variable_info_t *query_variable_info; |
| 825 | efi_update_capsule_t *update_capsule; | 831 | efi_update_capsule_t *update_capsule; |
| 826 | efi_query_capsule_caps_t *query_capsule_caps; | 832 | efi_query_capsule_caps_t *query_capsule_caps; |
| @@ -886,6 +892,13 @@ extern bool efi_poweroff_required(void); | |||
| 886 | (md) <= (efi_memory_desc_t *)((m)->map_end - (m)->desc_size); \ | 892 | (md) <= (efi_memory_desc_t *)((m)->map_end - (m)->desc_size); \ |
| 887 | (md) = (void *)(md) + (m)->desc_size) | 893 | (md) = (void *)(md) + (m)->desc_size) |
| 888 | 894 | ||
| 895 | /* | ||
| 896 | * Format an EFI memory descriptor's type and attributes to a user-provided | ||
| 897 | * character buffer, as per snprintf(), and return the buffer. | ||
| 898 | */ | ||
| 899 | char * __init efi_md_typeattr_format(char *buf, size_t size, | ||
| 900 | const efi_memory_desc_t *md); | ||
| 901 | |||
| 889 | /** | 902 | /** |
| 890 | * efi_range_is_wc - check the WC bit on an address range | 903 | * efi_range_is_wc - check the WC bit on an address range |
| 891 | * @start: starting kvirt address | 904 | * @start: starting kvirt address |
| @@ -1034,6 +1047,7 @@ struct efivar_operations { | |||
| 1034 | efi_get_variable_t *get_variable; | 1047 | efi_get_variable_t *get_variable; |
| 1035 | efi_get_next_variable_t *get_next_variable; | 1048 | efi_get_next_variable_t *get_next_variable; |
| 1036 | efi_set_variable_t *set_variable; | 1049 | efi_set_variable_t *set_variable; |
| 1050 | efi_set_variable_nonblocking_t *set_variable_nonblocking; | ||
| 1037 | efi_query_variable_store_t *query_variable_store; | 1051 | efi_query_variable_store_t *query_variable_store; |
| 1038 | }; | 1052 | }; |
| 1039 | 1053 | ||
| @@ -1227,4 +1241,7 @@ efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg, | |||
| 1227 | unsigned long *load_addr, | 1241 | unsigned long *load_addr, |
| 1228 | unsigned long *load_size); | 1242 | unsigned long *load_size); |
| 1229 | 1243 | ||
| 1244 | efi_status_t efi_parse_options(char *cmdline); | ||
| 1245 | |||
| 1246 | bool efi_runtime_disabled(void); | ||
| 1230 | #endif /* _LINUX_EFI_H */ | 1247 | #endif /* _LINUX_EFI_H */ |
diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 40728cf1c452..3d770f5564b8 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h | |||
| @@ -403,6 +403,7 @@ int vsscanf(const char *, const char *, va_list); | |||
| 403 | extern int get_option(char **str, int *pint); | 403 | extern int get_option(char **str, int *pint); |
| 404 | extern char *get_options(const char *str, int nints, int *ints); | 404 | extern char *get_options(const char *str, int nints, int *ints); |
| 405 | extern unsigned long long memparse(const char *ptr, char **retptr); | 405 | extern unsigned long long memparse(const char *ptr, char **retptr); |
| 406 | extern bool parse_option_str(const char *str, const char *option); | ||
| 406 | 407 | ||
| 407 | extern int core_kernel_text(unsigned long addr); | 408 | extern int core_kernel_text(unsigned long addr); |
| 408 | extern int core_kernel_data(unsigned long addr); | 409 | extern int core_kernel_data(unsigned long addr); |
diff --git a/lib/cmdline.c b/lib/cmdline.c index 76a712e6e20e..8f13cf73c2ec 100644 --- a/lib/cmdline.c +++ b/lib/cmdline.c | |||
| @@ -160,3 +160,32 @@ unsigned long long memparse(const char *ptr, char **retptr) | |||
| 160 | return ret; | 160 | return ret; |
| 161 | } | 161 | } |
| 162 | EXPORT_SYMBOL(memparse); | 162 | EXPORT_SYMBOL(memparse); |
| 163 | |||
| 164 | /** | ||
| 165 | * parse_option_str - Parse a string and check an option is set or not | ||
| 166 | * @str: String to be parsed | ||
| 167 | * @option: option name | ||
| 168 | * | ||
| 169 | * This function parses a string containing a comma-separated list of | ||
| 170 | * strings like a=b,c. | ||
| 171 | * | ||
| 172 | * Return true if there's such option in the string, or return false. | ||
| 173 | */ | ||
| 174 | bool parse_option_str(const char *str, const char *option) | ||
| 175 | { | ||
| 176 | while (*str) { | ||
| 177 | if (!strncmp(str, option, strlen(option))) { | ||
| 178 | str += strlen(option); | ||
| 179 | if (!*str || *str == ',') | ||
| 180 | return true; | ||
| 181 | } | ||
| 182 | |||
| 183 | while (*str && *str != ',') | ||
| 184 | str++; | ||
| 185 | |||
| 186 | if (*str == ',') | ||
| 187 | str++; | ||
| 188 | } | ||
| 189 | |||
| 190 | return false; | ||
| 191 | } | ||
