aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm64/include/asm/efi.h34
-rw-r--r--arch/arm64/kernel/efi.c230
-rw-r--r--arch/arm64/kernel/setup.c1
-rw-r--r--drivers/firmware/efi/libstub/arm-stub.c59
-rw-r--r--drivers/firmware/efi/libstub/efistub.h4
-rw-r--r--drivers/firmware/efi/libstub/fdt.c62
6 files changed, 282 insertions, 108 deletions
diff --git a/arch/arm64/include/asm/efi.h b/arch/arm64/include/asm/efi.h
index 71291253114f..effef3713c5a 100644
--- a/arch/arm64/include/asm/efi.h
+++ b/arch/arm64/include/asm/efi.h
@@ -7,28 +7,36 @@
7#ifdef CONFIG_EFI 7#ifdef CONFIG_EFI
8extern void efi_init(void); 8extern void efi_init(void);
9extern void efi_idmap_init(void); 9extern void efi_idmap_init(void);
10extern void efi_virtmap_init(void);
10#else 11#else
11#define efi_init() 12#define efi_init()
12#define efi_idmap_init() 13#define efi_idmap_init()
14#define efi_virtmap_init()
13#endif 15#endif
14 16
15#define efi_call_virt(f, ...) \ 17#define efi_call_virt(f, ...) \
16({ \ 18({ \
17 efi_##f##_t *__f = efi.systab->runtime->f; \ 19 efi_##f##_t *__f; \
18 efi_status_t __s; \ 20 efi_status_t __s; \
19 \ 21 \
20 kernel_neon_begin(); \ 22 kernel_neon_begin(); \
23 efi_virtmap_load(); \
24 __f = efi.systab->runtime->f; \
21 __s = __f(__VA_ARGS__); \ 25 __s = __f(__VA_ARGS__); \
26 efi_virtmap_unload(); \
22 kernel_neon_end(); \ 27 kernel_neon_end(); \
23 __s; \ 28 __s; \
24}) 29})
25 30
26#define __efi_call_virt(f, ...) \ 31#define __efi_call_virt(f, ...) \
27({ \ 32({ \
28 efi_##f##_t *__f = efi.systab->runtime->f; \ 33 efi_##f##_t *__f; \
29 \ 34 \
30 kernel_neon_begin(); \ 35 kernel_neon_begin(); \
36 efi_virtmap_load(); \
37 __f = efi.systab->runtime->f; \
31 __f(__VA_ARGS__); \ 38 __f(__VA_ARGS__); \
39 efi_virtmap_unload(); \
32 kernel_neon_end(); \ 40 kernel_neon_end(); \
33}) 41})
34 42
@@ -46,4 +54,26 @@ extern void efi_idmap_init(void);
46 54
47#define EFI_ALLOC_ALIGN SZ_64K 55#define EFI_ALLOC_ALIGN SZ_64K
48 56
57/*
58 * On ARM systems, virtually remapped UEFI runtime services are set up in three
59 * distinct stages:
60 * - The stub retrieves the final version of the memory map from UEFI, populates
61 * the virt_addr fields and calls the SetVirtualAddressMap() [SVAM] runtime
62 * service to communicate the new mapping to the firmware (Note that the new
63 * mapping is not live at this time)
64 * - During early boot, the page tables are allocated and populated based on the
65 * virt_addr fields in the memory map, but only if all descriptors with the
66 * EFI_MEMORY_RUNTIME attribute have a non-zero value for virt_addr. If this
67 * succeeds, the EFI_VIRTMAP flag is set to indicate that the virtual mappings
68 * have been installed successfully.
69 * - During an early initcall(), the UEFI Runtime Services are enabled and the
70 * EFI_RUNTIME_SERVICES bit set if some conditions are met, i.e., we need a
71 * non-early mapping of the UEFI system table, and we need to have the virtmap
72 * installed.
73 */
74#define EFI_VIRTMAP EFI_ARCH_1
75
76void efi_virtmap_load(void);
77void efi_virtmap_unload(void);
78
49#endif /* _ASM_EFI_H */ 79#endif /* _ASM_EFI_H */
diff --git a/arch/arm64/kernel/efi.c b/arch/arm64/kernel/efi.c
index 2bb4347d0edf..755e545144ea 100644
--- a/arch/arm64/kernel/efi.c
+++ b/arch/arm64/kernel/efi.c
@@ -11,25 +11,31 @@
11 * 11 *
12 */ 12 */
13 13
14#include <linux/atomic.h>
14#include <linux/dmi.h> 15#include <linux/dmi.h>
15#include <linux/efi.h> 16#include <linux/efi.h>
16#include <linux/export.h> 17#include <linux/export.h>
17#include <linux/memblock.h> 18#include <linux/memblock.h>
19#include <linux/mm_types.h>
18#include <linux/bootmem.h> 20#include <linux/bootmem.h>
19#include <linux/of.h> 21#include <linux/of.h>
20#include <linux/of_fdt.h> 22#include <linux/of_fdt.h>
23#include <linux/preempt.h>
24#include <linux/rbtree.h>
25#include <linux/rwsem.h>
21#include <linux/sched.h> 26#include <linux/sched.h>
22#include <linux/slab.h> 27#include <linux/slab.h>
28#include <linux/spinlock.h>
23 29
24#include <asm/cacheflush.h> 30#include <asm/cacheflush.h>
25#include <asm/efi.h> 31#include <asm/efi.h>
26#include <asm/tlbflush.h> 32#include <asm/tlbflush.h>
27#include <asm/mmu_context.h> 33#include <asm/mmu_context.h>
34#include <asm/mmu.h>
35#include <asm/pgtable.h>
28 36
29struct efi_memory_map memmap; 37struct efi_memory_map memmap;
30 38
31static efi_runtime_services_t *runtime;
32
33static u64 efi_system_table; 39static u64 efi_system_table;
34 40
35static int uefi_debug __initdata; 41static int uefi_debug __initdata;
@@ -69,9 +75,33 @@ static void __init efi_setup_idmap(void)
69 } 75 }
70} 76}
71 77
78/*
79 * Translate a EFI virtual address into a physical address: this is necessary,
80 * as some data members of the EFI system table are virtually remapped after
81 * SetVirtualAddressMap() has been called.
82 */
83static phys_addr_t efi_to_phys(unsigned long addr)
84{
85 efi_memory_desc_t *md;
86
87 for_each_efi_memory_desc(&memmap, md) {
88 if (!(md->attribute & EFI_MEMORY_RUNTIME))
89 continue;
90 if (md->virt_addr == 0)
91 /* no virtual mapping has been installed by the stub */
92 break;
93 if (md->virt_addr <= addr &&
94 (addr - md->virt_addr) < (md->num_pages << EFI_PAGE_SHIFT))
95 return md->phys_addr + addr - md->virt_addr;
96 }
97 return addr;
98}
99
72static int __init uefi_init(void) 100static int __init uefi_init(void)
73{ 101{
74 efi_char16_t *c16; 102 efi_char16_t *c16;
103 void *config_tables;
104 u64 table_size;
75 char vendor[100] = "unknown"; 105 char vendor[100] = "unknown";
76 int i, retval; 106 int i, retval;
77 107
@@ -99,7 +129,7 @@ static int __init uefi_init(void)
99 efi.systab->hdr.revision & 0xffff); 129 efi.systab->hdr.revision & 0xffff);
100 130
101 /* Show what we know for posterity */ 131 /* Show what we know for posterity */
102 c16 = early_memremap(efi.systab->fw_vendor, 132 c16 = early_memremap(efi_to_phys(efi.systab->fw_vendor),
103 sizeof(vendor)); 133 sizeof(vendor));
104 if (c16) { 134 if (c16) {
105 for (i = 0; i < (int) sizeof(vendor) - 1 && *c16; ++i) 135 for (i = 0; i < (int) sizeof(vendor) - 1 && *c16; ++i)
@@ -112,8 +142,14 @@ static int __init uefi_init(void)
112 efi.systab->hdr.revision >> 16, 142 efi.systab->hdr.revision >> 16,
113 efi.systab->hdr.revision & 0xffff, vendor); 143 efi.systab->hdr.revision & 0xffff, vendor);
114 144
115 retval = efi_config_init(NULL); 145 table_size = sizeof(efi_config_table_64_t) * efi.systab->nr_tables;
146 config_tables = early_memremap(efi_to_phys(efi.systab->tables),
147 table_size);
148
149 retval = efi_config_parse_tables(config_tables, efi.systab->nr_tables,
150 sizeof(efi_config_table_64_t), NULL);
116