aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2018-12-26 16:38:38 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2018-12-26 16:38:38 -0500
commit684019dd1f0092b4ffce4958c84aff0891deac83 (patch)
tree65977a5481527c26fe4a027badb9825b71ab9d35
parent792bf4d871dea8b69be2aaabdd320d7c6ed15985 (diff)
parent1debf0958fa27b7c469dbf22754929ec59a7c0e7 (diff)
Merge branch 'efi-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull EFI updates from Ingo Molnar: "The main changes in this cycle were: - Allocate the E820 buffer before doing the GetMemoryMap/ExitBootServices dance so we don't run out of space - Clear EFI boot services mappings when freeing the memory - Harden efivars against callers that invoke it on non-EFI boots - Reduce the number of memblock reservations resulting from extensive use of the new efi_mem_reserve_persistent() API - Other assorted fixes and cleanups" * 'efi-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86/efi: Don't unmap EFI boot services code/data regions for EFI_OLD_MEMMAP and EFI_MIXED_MODE efi: Reduce the amount of memblock reservations for persistent allocations efi: Permit multiple entries in persistent memreserve data structure efi/libstub: Disable some warnings for x86{,_64} x86/efi: Move efi_<reserve/free>_boot_services() to arch/x86 x86/efi: Unmap EFI boot services code/data regions from efi_pgd x86/mm/pageattr: Introduce helper function to unmap EFI boot services efi/fdt: Simplify the get_fdt() flow efi/fdt: Indentation fix firmware/efi: Add NULL pointer checks in efivars API functions
-rw-r--r--arch/x86/include/asm/efi.h2
-rw-r--r--arch/x86/include/asm/pgtable_types.h8
-rw-r--r--arch/x86/mm/pageattr.c40
-rw-r--r--arch/x86/platform/efi/efi.c2
-rw-r--r--arch/x86/platform/efi/quirks.c41
-rw-r--r--drivers/firmware/efi/efi.c54
-rw-r--r--drivers/firmware/efi/libstub/Makefile5
-rw-r--r--drivers/firmware/efi/libstub/arm-stub.c2
-rw-r--r--drivers/firmware/efi/libstub/fdt.c30
-rw-r--r--drivers/firmware/efi/vars.c99
-rw-r--r--include/linux/efi.h19
-rw-r--r--init/main.c4
12 files changed, 242 insertions, 64 deletions
diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h
index eea40d52ca78..d1e64ac80b9c 100644
--- a/arch/x86/include/asm/efi.h
+++ b/arch/x86/include/asm/efi.h
@@ -141,6 +141,8 @@ extern int __init efi_reuse_config(u64 tables, int nr_tables);
141extern void efi_delete_dummy_variable(void); 141extern void efi_delete_dummy_variable(void);
142extern void efi_switch_mm(struct mm_struct *mm); 142extern void efi_switch_mm(struct mm_struct *mm);
143extern void efi_recover_from_page_fault(unsigned long phys_addr); 143extern void efi_recover_from_page_fault(unsigned long phys_addr);
144extern void efi_free_boot_services(void);
145extern void efi_reserve_boot_services(void);
144 146
145struct efi_setup_data { 147struct efi_setup_data {
146 u64 fw_vendor; 148 u64 fw_vendor;
diff --git a/arch/x86/include/asm/pgtable_types.h b/arch/x86/include/asm/pgtable_types.h
index 106b7d0e2dae..d6ff0bbdb394 100644
--- a/arch/x86/include/asm/pgtable_types.h
+++ b/arch/x86/include/asm/pgtable_types.h
@@ -564,8 +564,12 @@ extern pte_t *lookup_address_in_pgd(pgd_t *pgd, unsigned long address,
564 unsigned int *level); 564 unsigned int *level);
565extern pmd_t *lookup_pmd_address(unsigned long address); 565extern pmd_t *lookup_pmd_address(unsigned long address);
566extern phys_addr_t slow_virt_to_phys(void *__address); 566extern phys_addr_t slow_virt_to_phys(void *__address);
567extern int kernel_map_pages_in_pgd(pgd_t *pgd, u64 pfn, unsigned long address, 567extern int __init kernel_map_pages_in_pgd(pgd_t *pgd, u64 pfn,
568 unsigned numpages, unsigned long page_flags); 568 unsigned long address,
569 unsigned numpages,
570 unsigned long page_flags);
571extern int __init kernel_unmap_pages_in_pgd(pgd_t *pgd, unsigned long address,
572 unsigned long numpages);
569#endif /* !__ASSEMBLY__ */ 573#endif /* !__ASSEMBLY__ */
570 574
571#endif /* _ASM_X86_PGTABLE_DEFS_H */ 575#endif /* _ASM_X86_PGTABLE_DEFS_H */
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c
index a1bcde35db4c..61bc7d1800d7 100644
--- a/arch/x86/mm/pageattr.c
+++ b/arch/x86/mm/pageattr.c
@@ -2346,8 +2346,8 @@ bool kernel_page_present(struct page *page)
2346 2346
2347#endif /* CONFIG_DEBUG_PAGEALLOC */ 2347#endif /* CONFIG_DEBUG_PAGEALLOC */
2348 2348
2349int kernel_map_pages_in_pgd(pgd_t *pgd, u64 pfn, unsigned long address, 2349int __init kernel_map_pages_in_pgd(pgd_t *pgd, u64 pfn, unsigned long address,
2350 unsigned numpages, unsigned long page_flags) 2350 unsigned numpages, unsigned long page_flags)
2351{ 2351{
2352 int retval = -EINVAL; 2352 int retval = -EINVAL;
2353 2353
@@ -2361,6 +2361,8 @@ int kernel_map_pages_in_pgd(pgd_t *pgd, u64 pfn, unsigned long address,
2361 .flags = 0, 2361 .flags = 0,
2362 }; 2362 };
2363 2363
2364 WARN_ONCE(num_online_cpus() > 1, "Don't call after initializing SMP");
2365
2364 if (!(__supported_pte_mask & _PAGE_NX)) 2366 if (!(__supported_pte_mask & _PAGE_NX))
2365 goto out; 2367 goto out;
2366 2368
@@ -2383,6 +2385,40 @@ out:
2383} 2385}
2384 2386
2385/* 2387/*
2388 * __flush_tlb_all() flushes mappings only on current CPU and hence this
2389 * function shouldn't be used in an SMP environment. Presently, it's used only
2390 * during boot (way before smp_init()) by EFI subsystem and hence is ok.
2391 */
2392int __init kernel_unmap_pages_in_pgd(pgd_t *pgd, unsigned long address,
2393 unsigned long numpages)
2394{
2395 int retval;
2396
2397 /*
2398 * The typical sequence for unmapping is to find a pte through
2399 * lookup_address_in_pgd() (ideally, it should never return NULL because
2400 * the address is already mapped) and change it's protections. As pfn is
2401 * the *target* of a mapping, it's not useful while unmapping.
2402 */
2403 struct cpa_data cpa = {
2404 .vaddr = &address,
2405 .pfn = 0,
2406 .pgd = pgd,
2407 .numpages = numpages,
2408 .mask_set = __pgprot(0),
2409 .mask_clr = __pgprot(_PAGE_PRESENT | _PAGE_RW),
2410 .flags = 0,
2411 };
2412
2413 WARN_ONCE(num_online_cpus() > 1, "Don't call after initializing SMP");
2414
2415 retval = __change_page_attr_set_clr(&cpa, 0);
2416 __flush_tlb_all();
2417
2418 return retval;
2419}
2420
2421/*
2386 * The testcases use internal knowledge of the implementation that shouldn't 2422 * The testcases use internal knowledge of the implementation that shouldn't
2387 * be exposed to the rest of the kernel. Include these directly here. 2423 * be exposed to the rest of the kernel. Include these directly here.
2388 */ 2424 */
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index 7ae939e353cd..e1cb01a22fa8 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -993,6 +993,8 @@ static void __init __efi_enter_virtual_mode(void)
993 panic("EFI call to SetVirtualAddressMap() failed!"); 993 panic("EFI call to SetVirtualAddressMap() failed!");
994 } 994 }
995 995
996 efi_free_boot_services();
997
996 /* 998 /*
997 * Now that EFI is in virtual mode, update the function 999 * Now that EFI is in virtual mode, update the function
998 * pointers in the runtime service table to the new virtual addresses. 1000 * pointers in the runtime service table to the new virtual addresses.
diff --git a/arch/x86/platform/efi/quirks.c b/arch/x86/platform/efi/quirks.c
index 95e77a667ba5..17456a1d3f04 100644
--- a/arch/x86/platform/efi/quirks.c
+++ b/arch/x86/platform/efi/quirks.c
@@ -369,6 +369,40 @@ void __init efi_reserve_boot_services(void)
369 } 369 }
370} 370}
371 371
372/*
373 * Apart from having VA mappings for EFI boot services code/data regions,
374 * (duplicate) 1:1 mappings were also created as a quirk for buggy firmware. So,
375 * unmap both 1:1 and VA mappings.
376 */
377static void __init efi_unmap_pages(efi_memory_desc_t *md)
378{
379 pgd_t *pgd = efi_mm.pgd;
380 u64 pa = md->phys_addr;
381 u64 va = md->virt_addr;
382
383 /*
384 * To Do: Remove this check after adding functionality to unmap EFI boot
385 * services code/data regions from direct mapping area because
386 * "efi=old_map" maps EFI regions in swapper_pg_dir.
387 */
388 if (efi_enabled(EFI_OLD_MEMMAP))
389 return;
390
391 /*
392 * EFI mixed mode has all RAM mapped to access arguments while making
393 * EFI runtime calls, hence don't unmap EFI boot services code/data
394 * regions.
395 */
396 if (!efi_is_native())
397 return;
398
399 if (kernel_unmap_pages_in_pgd(pgd, pa, md->num_pages))
400 pr_err("Failed to unmap 1:1 mapping for 0x%llx\n", pa);
401
402 if (kernel_unmap_pages_in_pgd(pgd, va, md->num_pages))
403 pr_err("Failed to unmap VA mapping for 0x%llx\n", va);
404}
405
372void __init efi_free_boot_services(void) 406void __init efi_free_boot_services(void)
373{ 407{
374 phys_addr_t new_phys, new_size; 408 phys_addr_t new_phys, new_size;
@@ -394,6 +428,13 @@ void __init efi_free_boot_services(void)
394 } 428 }
395 429
396 /* 430 /*
431 * Before calling set_virtual_address_map(), EFI boot services
432 * code/data regions were mapped as a quirk for buggy firmware.
433 * Unmap them from efi_pgd before freeing them up.
434 */
435 efi_unmap_pages(md);
436
437 /*
397 * Nasty quirk: if all sub-1MB memory is used for boot 438 * Nasty quirk: if all sub-1MB memory is used for boot
398 * services, we can get here without having allocated the 439 * services, we can get here without having allocated the
399 * real mode trampoline. It's too late to hand boot services 440 * real mode trampoline. It's too late to hand boot services
diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
index 415849bab233..4c46ff6f2242 100644
--- a/drivers/firmware/efi/efi.c
+++ b/drivers/firmware/efi/efi.c
@@ -602,21 +602,33 @@ int __init efi_apply_persistent_mem_reservations(void)
602 602
603 while (prsv) { 603 while (prsv) {
604 struct linux_efi_memreserve *rsv; 604 struct linux_efi_memreserve *rsv;
605 605 u8 *p;
606 /* reserve the entry itself */ 606 int i;
607 memblock_reserve(prsv, sizeof(*rsv)); 607
608 608 /*
609 rsv = early_memremap(prsv, sizeof(*rsv)); 609 * Just map a full page: that is what we will get
610 if (rsv == NULL) { 610 * anyway, and it permits us to map the entire entry
611 * before knowing its size.
612 */
613 p = early_memremap(ALIGN_DOWN(prsv, PAGE_SIZE),
614 PAGE_SIZE);
615 if (p == NULL) {
611 pr_err("Could not map UEFI memreserve entry!\n"); 616 pr_err("Could not map UEFI memreserve entry!\n");
612 return -ENOMEM; 617 return -ENOMEM;
613 } 618 }
614 619
615 if (rsv->size) 620 rsv = (void *)(p + prsv % PAGE_SIZE);
616 memblock_reserve(rsv->base, rsv->size); 621
622 /* reserve the entry itself */
623 memblock_reserve(prsv, EFI_MEMRESERVE_SIZE(rsv->size));
624
625 for (i = 0; i < atomic_read(&rsv->count); i++) {
626 memblock_reserve(rsv->entry[i].base,
627 rsv->entry[i].size);
628 }
617 629
618 prsv = rsv->next; 630 prsv = rsv->next;
619 early_memunmap(rsv, sizeof(*rsv)); 631 early_memunmap(p, PAGE_SIZE);
620 } 632 }
621 } 633 }
622 634
@@ -985,7 +997,8 @@ static int __init efi_memreserve_map_root(void)
985int __ref efi_mem_reserve_persistent(phys_addr_t addr, u64 size) 997int __ref efi_mem_reserve_persistent(phys_addr_t addr, u64 size)
986{ 998{
987 struct linux_efi_memreserve *rsv; 999 struct linux_efi_memreserve *rsv;
988 int rc; 1000 unsigned long prsv;
1001 int rc, index;
989 1002
990 if (efi_memreserve_root == (void *)ULONG_MAX) 1003 if (efi_memreserve_root == (void *)ULONG_MAX)
991 return -ENODEV; 1004 return -ENODEV;
@@ -996,12 +1009,27 @@ int __ref efi_mem_reserve_persistent(phys_addr_t addr, u64 size)
996 return rc; 1009 return rc;
997 } 1010 }
998 1011
999 rsv = kmalloc(sizeof(*rsv), GFP_ATOMIC); 1012 /* first try to find a slot in an existing linked list entry */
1013 for (prsv = efi_memreserve_root->next; prsv; prsv = rsv->next) {
1014 rsv = __va(prsv);
1015 index = atomic_fetch_add_unless(&rsv->count, 1, rsv->size);
1016 if (index < rsv->size) {
1017 rsv->entry[index].base = addr;
1018 rsv->entry[index].size = size;
1019
1020 return 0;
1021 }
1022 }
1023
1024 /* no slot found - allocate a new linked list entry */
1025 rsv = (struct linux_efi_memreserve *)__get_free_page(GFP_ATOMIC);
1000 if (!rsv) 1026 if (!rsv)
1001 return -ENOMEM; 1027 return -ENOMEM;
1002 1028
1003 rsv->base = addr; 1029 rsv->size = EFI_MEMRESERVE_COUNT(PAGE_SIZE);
1004 rsv->size = size; 1030 atomic_set(&rsv->count, 1);
1031 rsv->entry[0].base = addr;
1032 rsv->entry[0].size = size;
1005 1033
1006 spin_lock(&efi_mem_reserve_persistent_lock); 1034 spin_lock(&efi_mem_reserve_persistent_lock);
1007 rsv->next = efi_memreserve_root->next; 1035 rsv->next = efi_memreserve_root->next;
diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile
index c51627660dbb..d9845099635e 100644
--- a/drivers/firmware/efi/libstub/Makefile
+++ b/drivers/firmware/efi/libstub/Makefile
@@ -9,7 +9,10 @@ cflags-$(CONFIG_X86_32) := -march=i386
9cflags-$(CONFIG_X86_64) := -mcmodel=small 9cflags-$(CONFIG_X86_64) := -mcmodel=small
10cflags-$(CONFIG_X86) += -m$(BITS) -D__KERNEL__ -O2 \ 10cflags-$(CONFIG_X86) += -m$(BITS) -D__KERNEL__ -O2 \
11 -fPIC -fno-strict-aliasing -mno-red-zone \ 11 -fPIC -fno-strict-aliasing -mno-red-zone \
12 -mno-mmx -mno-sse -fshort-wchar 12 -mno-mmx -mno-sse -fshort-wchar \
13 -Wno-pointer-sign \
14 $(call cc-disable-warning, address-of-packed-member) \
15 $(call cc-disable-warning, gnu)
13 16
14# arm64 uses the full KBUILD_CFLAGS so it's necessary to explicitly 17# arm64 uses the full KBUILD_CFLAGS so it's necessary to explicitly
15# disable the stackleak plugin 18# disable the stackleak plugin
diff --git a/drivers/firmware/efi/libstub/arm-stub.c b/drivers/firmware/efi/libstub/arm-stub.c
index 6640942a1c0d..eee42d5e25ee 100644
--- a/drivers/firmware/efi/libstub/arm-stub.c
+++ b/drivers/firmware/efi/libstub/arm-stub.c
@@ -86,8 +86,8 @@ void install_memreserve_table(efi_system_table_t *sys_table_arg)
86 } 86 }
87 87
88 rsv->next = 0; 88 rsv->next = 0;
89 rsv->base = 0;
90 rsv->size = 0; 89 rsv->size = 0;
90 atomic_set(&rsv->count, 0);
91 91
92 status = efi_call_early(install_configuration_table, 92 status = efi_call_early(install_configuration_table,
93 &memreserve_table_guid, 93 &memreserve_table_guid,
diff --git a/drivers/firmware/efi/libstub/fdt.c b/drivers/firmware/efi/libstub/fdt.c
index 0c0d2312f4a8..0dc7b4987cc2 100644
--- a/drivers/firmware/efi/libstub/fdt.c
+++ b/drivers/firmware/efi/libstub/fdt.c
@@ -370,22 +370,24 @@ void *get_fdt(efi_system_table_t *sys_table, unsigned long *fdt_size)
370{ 370{
371 efi_guid_t fdt_guid = DEVICE_TREE_GUID; 371 efi_guid_t fdt_guid = DEVICE_TREE_GUID;
372 efi_config_table_t *tables; 372 efi_config_table_t *tables;
373 void *fdt;
374 int i; 373 int i;
375 374
376 tables = (efi_config_table_t *) sys_table->tables; 375 tables = (efi_config_table_t *)sys_table->tables;
377 fdt = NULL;
378 376
379 for (i = 0; i < sys_table->nr_tables; i++) 377 for (i = 0; i < sys_table->nr_tables; i++) {
380 if (efi_guidcmp(tables[i].guid, fdt_guid) == 0) { 378 void *fdt;
381 fdt = (void *) tables[i].table; 379
382 if (fdt_check_header(fdt) != 0) { 380 if (efi_guidcmp(tables[i].guid, fdt_guid) != 0)
383 pr_efi_err(sys_table, "Invalid header detected on UEFI supplied FDT, ignoring ...\n"); 381 continue;
384 return NULL; 382
385 } 383 fdt = (void *)tables[i].table;
386 *fdt_size = fdt_totalsize(fdt); 384 if (fdt_check_header(fdt) != 0) {
387 break; 385 pr_efi_err(sys_table, "Invalid header detected on UEFI supplied FDT, ignoring ...\n");
388 } 386 return NULL;
387 }
388 *fdt_size = fdt_totalsize(fdt);
389 return fdt;
390 }
389 391
390 return fdt; 392 return NULL;
391} 393}
diff --git a/drivers/firmware/efi/vars.c b/drivers/firmware/efi/vars.c
index 9336ffdf6e2c..fceaafd67ec6 100644
--- a/drivers/firmware/efi/vars.c
+++ b/drivers/firmware/efi/vars.c
@@ -318,7 +318,12 @@ EXPORT_SYMBOL_GPL(efivar_variable_is_removable);
318static efi_status_t 318static efi_status_t
319check_var_size(u32 attributes, unsigned long size) 319check_var_size(u32 attributes, unsigned long size)
320{ 320{
321 const struct efivar_operations *fops = __efivars->ops; 321 const struct efivar_operations *fops;
322
323 if (!__efivars)
324 return EFI_UNSUPPORTED;
325
326 fops = __efivars->ops;
322 327
323 if (!fops->query_variable_store) 328 if (!fops->query_variable_store)
324 return EFI_UNSUPPORTED; 329 return EFI_UNSUPPORTED;
@@ -329,7 +334,12 @@ check_var_size(u32 attributes, unsigned long size)
329static efi_status_t 334static efi_status_t
330check_var_size_nonblocking(u32 attributes, unsigned long size) 335check_var_size_nonblocking(u32 attributes, unsigned long size)
331{ 336{
332 const struct efivar_operations *fops = __efivars->ops; 337 const struct efivar_operations *fops;
338
339 if (!__efivars)
340 return EFI_UNSUPPORTED;
341
342 fops = __efivars->ops;
333 343
334 if (!fops->query_variable_store) 344 if (!fops->query_variable_store)
335 return EFI_UNSUPPORTED; 345 return EFI_UNSUPPORTED;
@@ -429,13 +439,18 @@ static void dup_variable_bug(efi_char16_t *str16, efi_guid_t *vendor_guid,
429int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *), 439int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *),
430 void *data, bool duplicates, struct list_head *head) 440 void *data, bool duplicates, struct list_head *head)
431{ 441{
432 const struct efivar_operations *ops = __efivars->ops; 442 const struct efivar_operations *ops;
433 unsigned long variable_name_size = 1024; 443 unsigned long variable_name_size = 1024;
434 efi_char16_t *variable_name; 444 efi_char16_t *variable_name;
435 efi_status_t status; 445 efi_status_t status;
436 efi_guid_t vendor_guid; 446 efi_guid_t vendor_guid;
437 int err = 0; 447 int err = 0;
438 448
449 if (!__efivars)
450 return -EFAULT;
451
452 ops = __efivars->ops;
453
439 variable_name = kzalloc(variable_name_size, GFP_KERNEL); 454 variable_name = kzalloc(variable_name_size, GFP_KERNEL);
440 if (!variable_name) { 455 if (!variable_name) {
441 printk(KERN_ERR "efivars: Memory allocation failed.\n"); 456 printk(KERN_ERR "efivars: Memory allocation failed.\n");
@@ -583,12 +598,14 @@ static void efivar_entry_list_del_unlock(struct efivar_entry *entry)
583 */ 598 */
584int __efivar_entry_delete(struct efivar_entry *entry) 599int __efivar_entry_delete(struct efivar_entry *entry)
585{ 600{
586 const struct efivar_operations *ops = __efivars->ops;
587 efi_status_t status; 601 efi_status_t status;
588 602
589 status = ops->set_variable(entry->var.VariableName, 603 if (!__efivars)
590 &entry->var.VendorGuid, 604 return -EINVAL;
591 0, 0, NULL); 605
606 status = __efivars->ops->set_variable(entry->var.VariableName,
607 &entry->var.VendorGuid,
608 0, 0, NULL);
592 609
593 return efi_status_to_err(status); 610 return efi_status_to_err(status);
594} 611}
@@ -607,12 +624,17 @@ EXPORT_SYMBOL_GPL(__efivar_entry_delete);
607 */ 624 */
608int efivar_entry_delete(struct efivar_entry *entry) 625int efivar_entry_delete(struct efivar_entry *entry)
609{ 626{
610 const struct efivar_operations *ops = __efivars->ops; 627 const struct efivar_operations *ops;
611 efi_status_t status; 628 efi_status_t status;
612 629
613 if (down_interruptible(&efivars_lock)) 630 if (down_interruptible(&efivars_lock))
614 return -EINTR; 631 return -EINTR;
615 632
633 if (!__efivars) {
634 up(&efivars_lock);
635 return -EINVAL;
636 }
637 ops = __efivars->ops;
616 status = ops->set_variable(entry->var.VariableName, 638 status = ops->set_variable(entry->var.VariableName,
617 &entry->var.VendorGuid, 639 &entry->var.VendorGuid,
618 0, 0, NULL); 640 0, 0, NULL);
@@ -650,13 +672,19 @@ EXPORT_SYMBOL_GPL(efivar_entry_delete);
650int efivar_entry_set(struct efivar_entry *entry, u32 attributes, 672int efivar_entry_set(struct efivar_entry *entry, u32 attributes,
651 unsigned long size, void *data, struct list_head *head) 673 unsigned long size, void *data, struct list_head *head)
652{ 674{
653 const struct efivar_operations *ops = __efivars->ops; 675 const struct efivar_operations *ops;
654 efi_status_t status; 676 efi_status_t status;
655 efi_char16_t *name = entry->var.VariableName; 677 efi_char16_t *name = entry->var.VariableName;
656 efi_guid_t vendor = entry->var.VendorGuid; 678 efi_guid_t vendor = entry->var.VendorGuid;
657 679
658 if (down_interruptible(&efivars_lock)) 680 if (down_interruptible(&efivars_lock))
659 return -EINTR; 681 return -EINTR;
682
683 if (!__efivars) {
684 up(&efivars_lock);
685 return -EINVAL;
686 }
687 ops = __efivars->ops;
660 if (head && efivar_entry_find(name, vendor, head, false)) { 688 if (head && efivar_entry_find(name, vendor, head, false)) {
661 up(&efivars_lock); 689 up(&efivars_lock);
662 return -EEXIST; 690 return -EEXIST;
@@ -687,12 +715,17 @@ static int
687efivar_entry_set_nonblocking(efi_char16_t *name, efi_guid_t vendor, 715efivar_entry_set_nonblocking(efi_char16_t *name, efi_guid_t vendor,
688 u32 attributes, unsigned long size, void *data) 716 u32 attributes, unsigned long size, void *data)
689{ 717{
690 const struct efivar_operations *ops = __efivars->ops; 718 const struct efivar_operations *ops;
691 efi_status_t status; 719 efi_status_t status;
692 720
693 if (down_trylock(&efivars_lock)) 721 if (down_trylock(&efivars_lock))
694 return -EBUSY; 722 return -EBUSY;
695 723
724 if (!__efivars) {
725 up(&efivars_lock);
726 return -EINVAL;
727 }
728
696 status = check_var_size_nonblocking(attributes, 729 status = check_var_size_nonblocking(attributes,
697 size + ucs2_strsize(name, 1024)); 730 size + ucs2_strsize(name, 1024));
698 if (status != EFI_SUCCESS) { 731 if (status != EFI_SUCCESS) {
@@ -700,6 +733,7 @@ efivar_entry_set_nonblocking(efi_char16_t *name, efi_guid_t vendor,
700 return -ENOSPC; 733 return -ENOSPC;
701 } 734 }
702 735
736 ops = __efivars->ops;
703 status = ops->set_variable_nonblocking(name, &vendor, attributes, 737 status = ops->set_variable_nonblocking(name, &vendor, attributes,
704 size, data); 738 size, data);
705 739
@@ -727,9 +761,13 @@ efivar_entry_set_nonblocking(efi_char16_t *name, efi_guid_t vendor,
727int efivar_entry_set_safe(efi_char16_t *name, efi_guid_t vendor, u32 attributes, 761int efivar_entry_set_safe(efi_char16_t *name, efi_guid_t vendor, u32 attributes,
728 bool block, unsigned long size, void *data) 762 bool block, unsigned long size, void *data)
729{ 763{
730 const struct efivar_operations *ops = __efivars->ops; 764 const struct efivar_operations *ops;
731 efi_status_t status; 765 efi_status_t status;
732 766
767 if (!__efivars)
768 return -EINVAL;
769
770 ops = __efivars->ops;
733 if (!ops->query_variable_store) 771 if (!ops->query_variable_store)
734 return -ENOSYS; 772 return -ENOSYS;
735 773
@@ -829,13 +867,18 @@ EXPORT_SYMBOL_GPL(efivar_entry_find);
829 */ 867 */
830int efivar_entry_size(struct efivar_entry *entry, unsigned long *size) 868int efivar_entry_size(struct efivar_entry *entry, unsigned long *size)
831{ 869{
832 const struct efivar_operations *ops = __efivars->ops; 870 const struct efivar_operations *ops;
833 efi_status_t status; 871 efi_status_t status;
834 872
835 *size = 0; 873 *size = 0;
836 874
837 if (down_interruptible(&efivars_lock)) 875 if (down_interruptible(&efivars_lock))
838 return -EINTR; 876 return -EINTR;
877 if (!__efivars) {
878 up(&efivars_lock);
879 return -EINVAL;
880 }
881 ops = __efivars->ops;
839 status = ops->get_variable(entry->var.VariableName, 882 status = ops->get_variable(entry->var.VariableName,
840 &entry->var.VendorGuid, NULL, size, NULL); 883 &entry->var.VendorGuid, NULL, size, NULL);
841 up(&efivars_lock); 884 up(&efivars_lock);
@@ -861,12 +904,14 @@ EXPORT_SYMBOL_GPL(efivar_entry_size);
861int __efivar_entry_get(struct efivar_entry *entry, u32 *attributes, 904int __efivar_entry_get(struct efivar_entry *entry, u32 *attributes,
862 unsigned long *size, void *data) 905 unsigned long *size, void *data)
863{ 906{
864 const struct efivar_operations *ops = __efivars->ops;
865 efi_status_t status; 907 efi_status_t status;
866 908
867 status = ops->get_variable(entry->var.VariableName, 909 if (!__efivars)
868 &entry->var.VendorGuid, 910 return -EINVAL;
869 attributes, size, data); 911
912 status = __efivars->ops->get_variable(entry->var.VariableName,
913 &entry->var.VendorGuid,
914 attributes, size, data);
870 915
871 return efi_status_to_err(status); 916 return efi_status_to_err(status);
872} 917}
@@ -882,14 +927,19 @@ EXPORT_SYMBOL_GPL(__efivar_entry_get);
882int efivar_entry_get(struct efivar_entry *entry, u32 *attributes, 927int efivar_entry_get(struct efivar_entry *entry, u32 *attributes,
883 unsigned long *size, void *data) 928 unsigned long *size, void *data)
884{ 929{
885 const struct efivar_operations *ops = __efivars->ops;
886 efi_status_t status; 930 efi_status_t status;
887 931
888 if (down_interruptible(&efivars_lock)) 932 if (down_interruptible(&efivars_lock))
889 return -EINTR; 933 return -EINTR;
890 status = ops->get_variable(entry->var.VariableName, 934
891 &entry->var.VendorGuid, 935 if (!__efivars) {
892 attributes, size, data); 936 up(&efivars_lock);
937 return -EINVAL;
938 }
939
940 status = __efivars->ops->get_variable(entry->var.VariableName,
941 &entry->var.VendorGuid,
942 attributes, size, data);
893 up(&efivars_lock); 943 up(&efivars_lock);
894 944
895 return efi_status_to_err(status); 945 return efi_status_to_err(status);
@@ -921,7 +971,7 @@ EXPORT_SYMBOL_GPL(efivar_entry_get);
921int efivar_entry_set_get_size(struct efivar_entry *entry, u32 attributes, 971int efivar_entry_set_get_size(struct efivar_entry *entry, u32 attributes,
922 unsigned long *size, void *data, bool *set) 972 unsigned long *size, void *data, bool *set)
923{ 973{
924 const struct efivar_operations *ops = __efivars->ops; 974 const struct efivar_operations *ops;
925 efi_char16_t *name = entry->var.VariableName; 975 efi_char16_t *name = entry->var.VariableName;
926 efi_guid_t *vendor = &entry->var.VendorGuid; 976 efi_guid_t *vendor = &entry->var.VendorGuid;
927 efi_status_t status; 977 efi_status_t status;
@@ -940,6 +990,11 @@ int efivar_entry_set_get_size(struct efivar_entry *entry, u32 attributes,
940 if (down_interruptible(&efivars_lock)) 990 if (down_interruptible(&efivars_lock))
941 return -EINTR; 991 return -EINTR;
942 992
993 if (!__efivars) {
994 err = -EINVAL;
995 goto out;
996 }
997
943 /* 998 /*
944 * Ensure that the available space hasn't shrunk below the safe level 999 * Ensure that the available space hasn't shrunk below the safe level
945 */ 1000 */
@@ -956,6 +1011,8 @@ int efivar_entry_set_get_size(struct efivar_entry *entry, u32 attributes,
956 } 1011 }
957 } 1012 }
958 1013
1014 ops = __efivars->ops;
1015
959 status = ops->set_variable(name, vendor, attributes, *size, data); 1016 status = ops->set_variable(name, vendor, attributes, *size, data);
960 if (status != EFI_SUCCESS) { 1017 if (status != EFI_SUCCESS) {
961 err = efi_status_to_err(status); 1018 err = efi_status_to_err(status);
diff --git a/include/linux/efi.h b/include/linux/efi.h
index 100ce4a4aff6..becd5d76a207 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -1000,13 +1000,11 @@ extern void efi_memmap_walk (efi_freemem_callback_t callback, void *arg);
1000extern void efi_gettimeofday (struct timespec64 *ts); 1000extern void efi_gettimeofday (struct timespec64 *ts);
1001extern void efi_enter_virtual_mode (void); /* switch EFI to virtual mode, if possible */ 1001extern void efi_enter_virtual_mode (void); /* switch EFI to virtual mode, if possible */
1002#ifdef CONFIG_X86 1002#ifdef CONFIG_X86
1003extern void efi_free_boot_services(void);
1004extern efi_status_t efi_query_variable_store(u32 attributes, 1003extern efi_status_t efi_query_variable_store(u32 attributes,
1005 unsigned long size, 1004 unsigned long size,
1006 bool nonblocking); 1005 bool nonblocking);
1007extern void efi_find_mirror(void); 1006extern void efi_find_mirror(void);
1008#else 1007#else
1009static inline void efi_free_boot_services(void) {}
1010 1008
1011static inline efi_status_t efi_query_variable_store(u32 attributes, 1009static inline efi_status_t efi_query_variable_store(u32 attributes,
1012 unsigned long size, 1010 unsigned long size,
@@ -1046,7 +1044,6 @@ extern void efi_mem_reserve(phys_addr_t addr, u64 size);
1046extern int efi_mem_reserve_persistent(phys_addr_t addr, u64 size); 1044extern int efi_mem_reserve_persistent(phys_addr_t addr, u64 size);
1047extern void efi_initialize_iomem_resources(struct resource *code_resource, 1045extern void efi_initialize_iomem_resources(struct resource *code_resource,
1048 struct resource *data_resource, struct resource *bss_resource); 1046 struct resource *data_resource, struct resource *bss_resource);
1049extern void efi_reserve_boot_services(void);
1050extern int efi_get_fdt_params(struct efi_fdt_params *params); 1047extern int efi_get_fdt_params(struct efi_fdt_params *params);
1051extern struct kobject *efi_kobj; 1048extern struct kobject *efi_kobj;
1052 1049
@@ -1715,9 +1712,19 @@ extern struct efi_runtime_work efi_rts_work;
1715extern struct workqueue_struct *efi_rts_wq; 1712extern struct workqueue_struct *efi_rts_wq;
1716 1713
1717struct linux_efi_memreserve { 1714struct linux_efi_memreserve {
1718 phys_addr_t next; 1715 int size; // allocated size of the array
1719 phys_addr_t base; 1716 atomic_t count; // number of entries used
1720 phys_addr_t size; 1717 phys_addr_t next; // pa of next struct instance
1718 struct {
1719 phys_addr_t base;
1720 phys_addr_t size;
1721 } entry[0];
1721}; 1722};
1722 1723
1724#define EFI_MEMRESERVE_SIZE(count) (sizeof(struct linux_efi_memreserve) + \
1725 (count) * sizeof(((struct linux_efi_memreserve *)0)->entry[0]))
1726
1727#define EFI_MEMRESERVE_COUNT(size) (((size) - sizeof(struct linux_efi_memreserve)) \
1728 / sizeof(((struct linux_efi_memreserve *)0)->entry[0]))
1729
1723#endif /* _LINUX_EFI_H */ 1730#endif /* _LINUX_EFI_H */
diff --git a/init/main.c b/init/main.c
index a45486330243..954d9b6c62c6 100644
--- a/init/main.c
+++ b/init/main.c
@@ -737,10 +737,6 @@ asmlinkage __visible void __init start_kernel(void)
737 arch_post_acpi_subsys_init(); 737 arch_post_acpi_subsys_init();
738 sfi_init_late(); 738 sfi_init_late();
739 739
740 if (efi_enabled(EFI_RUNTIME_SERVICES)) {
741 efi_free_boot_services();
742 }
743
744 /* Do the rest non-__init'ed, we're now alive */ 740 /* Do the rest non-__init'ed, we're now alive */
745 arch_call_rest_init(); 741 arch_call_rest_init();
746} 742}