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 | } | ||