aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
Diffstat (limited to 'arch')
-rw-r--r--arch/arm64/Kconfig16
-rw-r--r--arch/arm64/include/asm/efi.h14
-rw-r--r--arch/arm64/include/asm/mmu.h2
-rw-r--r--arch/arm64/kernel/Makefile3
-rw-r--r--arch/arm64/kernel/efi-entry.S109
-rw-r--r--arch/arm64/kernel/efi-stub.c81
-rw-r--r--arch/arm64/kernel/efi.c469
-rw-r--r--arch/arm64/kernel/head.S112
-rw-r--r--arch/arm64/kernel/setup.c5
-rw-r--r--arch/arm64/mm/mmu.c65
10 files changed, 858 insertions, 18 deletions
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index f5f63b715d91..e384ab9b3862 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -283,6 +283,20 @@ config CMDLINE_FORCE
283 This is useful if you cannot or don't want to change the 283 This is useful if you cannot or don't want to change the
284 command-line options your boot loader passes to the kernel. 284 command-line options your boot loader passes to the kernel.
285 285
286config EFI
287 bool "UEFI runtime support"
288 depends on OF && !CPU_BIG_ENDIAN
289 select LIBFDT
290 select UCS2_STRING
291 select EFI_PARAMS_FROM_FDT
292 default y
293 help
294 This option provides support for runtime services provided
295 by UEFI firmware (such as non-volatile variables, realtime
296 clock, and platform reset). A UEFI stub is also provided to
297 allow the kernel to be booted as an EFI application. This
298 is only useful on systems that have UEFI firmware.
299
286endmenu 300endmenu
287 301
288menu "Userspace binary formats" 302menu "Userspace binary formats"
@@ -334,6 +348,8 @@ source "net/Kconfig"
334 348
335source "drivers/Kconfig" 349source "drivers/Kconfig"
336 350
351source "drivers/firmware/Kconfig"
352
337source "fs/Kconfig" 353source "fs/Kconfig"
338 354
339source "arch/arm64/kvm/Kconfig" 355source "arch/arm64/kvm/Kconfig"
diff --git a/arch/arm64/include/asm/efi.h b/arch/arm64/include/asm/efi.h
new file mode 100644
index 000000000000..5a46c4e7f539
--- /dev/null
+++ b/arch/arm64/include/asm/efi.h
@@ -0,0 +1,14 @@
1#ifndef _ASM_EFI_H
2#define _ASM_EFI_H
3
4#include <asm/io.h>
5
6#ifdef CONFIG_EFI
7extern void efi_init(void);
8extern void efi_idmap_init(void);
9#else
10#define efi_init()
11#define efi_idmap_init()
12#endif
13
14#endif /* _ASM_EFI_H */
diff --git a/arch/arm64/include/asm/mmu.h b/arch/arm64/include/asm/mmu.h
index aff0292c8f4d..c2f006c48bdb 100644
--- a/arch/arm64/include/asm/mmu.h
+++ b/arch/arm64/include/asm/mmu.h
@@ -31,5 +31,7 @@ extern void paging_init(void);
31extern void setup_mm_for_reboot(void); 31extern void setup_mm_for_reboot(void);
32extern void __iomem *early_io_map(phys_addr_t phys, unsigned long virt); 32extern void __iomem *early_io_map(phys_addr_t phys, unsigned long virt);
33extern void init_mem_pgprot(void); 33extern void init_mem_pgprot(void);
34/* create an identity mapping for memory (or io if map_io is true) */
35extern void create_id_mapping(phys_addr_t addr, phys_addr_t size, int map_io);
34 36
35#endif 37#endif
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index 7a6fce5167e9..ba5e17a522d5 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -4,6 +4,8 @@
4 4
5CPPFLAGS_vmlinux.lds := -DTEXT_OFFSET=$(TEXT_OFFSET) 5CPPFLAGS_vmlinux.lds := -DTEXT_OFFSET=$(TEXT_OFFSET)
6AFLAGS_head.o := -DTEXT_OFFSET=$(TEXT_OFFSET) 6AFLAGS_head.o := -DTEXT_OFFSET=$(TEXT_OFFSET)
7CFLAGS_efi-stub.o := -DTEXT_OFFSET=$(TEXT_OFFSET) \
8 -I$(src)/../../../scripts/dtc/libfdt
7 9
8# Object file lists. 10# Object file lists.
9arm64-obj-y := cputable.o debug-monitors.o entry.o irq.o fpsimd.o \ 11arm64-obj-y := cputable.o debug-monitors.o entry.o irq.o fpsimd.o \
@@ -21,6 +23,7 @@ arm64-obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
21arm64-obj-$(CONFIG_ARM64_CPU_SUSPEND) += sleep.o suspend.o 23arm64-obj-$(CONFIG_ARM64_CPU_SUSPEND) += sleep.o suspend.o
22arm64-obj-$(CONFIG_JUMP_LABEL) += jump_label.o 24arm64-obj-$(CONFIG_JUMP_LABEL) += jump_label.o
23arm64-obj-$(CONFIG_KGDB) += kgdb.o 25arm64-obj-$(CONFIG_KGDB) += kgdb.o
26arm64-obj-$(CONFIG_EFI) += efi.o efi-stub.o efi-entry.o
24 27
25obj-y += $(arm64-obj-y) vdso/ 28obj-y += $(arm64-obj-y) vdso/
26obj-m += $(arm64-obj-m) 29obj-m += $(arm64-obj-m)
diff --git a/arch/arm64/kernel/efi-entry.S b/arch/arm64/kernel/efi-entry.S
new file mode 100644
index 000000000000..66716c9b9e5f
--- /dev/null
+++ b/arch/arm64/kernel/efi-entry.S
@@ -0,0 +1,109 @@
1/*
2 * EFI entry point.
3 *
4 * Copyright (C) 2013, 2014 Red Hat, Inc.
5 * Author: Mark Salter <msalter@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 */
12#include <linux/linkage.h>
13#include <linux/init.h>
14
15#include <asm/assembler.h>
16
17#define EFI_LOAD_ERROR 0x8000000000000001
18
19 __INIT
20
21 /*
22 * We arrive here from the EFI boot manager with:
23 *
24 * * CPU in little-endian mode
25 * * MMU on with identity-mapped RAM
26 * * Icache and Dcache on
27 *
28 * We will most likely be running from some place other than where
29 * we want to be. The kernel image wants to be placed at TEXT_OFFSET
30 * from start of RAM.
31 */
32ENTRY(efi_stub_entry)
33 /*
34 * Create a stack frame to save FP/LR with extra space
35 * for image_addr variable passed to efi_entry().
36 */
37 stp x29, x30, [sp, #-32]!
38
39 /*
40 * Call efi_entry to do the real work.
41 * x0 and x1 are already set up by firmware. Current runtime
42 * address of image is calculated and passed via *image_addr.
43 *
44 * unsigned long efi_entry(void *handle,
45 * efi_system_table_t *sys_table,
46 * unsigned long *image_addr) ;
47 */
48 adrp x8, _text
49 add x8, x8, #:lo12:_text
50 add x2, sp, 16
51 str x8, [x2]
52 bl efi_entry
53 cmn x0, #1
54 b.eq efi_load_fail
55
56 /*
57 * efi_entry() will have relocated the kernel image if necessary
58 * and we return here with device tree address in x0 and the kernel
59 * entry point stored at *image_addr. Save those values in registers
60 * which are callee preserved.
61 */
62 mov x20, x0 // DTB address
63 ldr x0, [sp, #16] // relocated _text address
64 mov x21, x0
65
66 /*
67 * Flush dcache covering current runtime addresses
68 * of kernel text/data. Then flush all of icache.
69 */
70 adrp x1, _text
71 add x1, x1, #:lo12:_text
72 adrp x2, _edata
73 add x2, x2, #:lo12:_edata
74 sub x1, x2, x1
75
76 bl __flush_dcache_area
77 ic ialluis
78
79 /* Turn off Dcache and MMU */
80 mrs x0, CurrentEL
81 cmp x0, #PSR_MODE_EL2t
82 ccmp x0, #PSR_MODE_EL2h, #0x4, ne
83 b.ne 1f
84 mrs x0, sctlr_el2
85 bic x0, x0, #1 << 0 // clear SCTLR.M
86 bic x0, x0, #1 << 2 // clear SCTLR.C
87 msr sctlr_el2, x0
88 isb
89 b 2f
901:
91 mrs x0, sctlr_el1
92 bic x0, x0, #1 << 0 // clear SCTLR.M
93 bic x0, x0, #1 << 2 // clear SCTLR.C
94 msr sctlr_el1, x0
95 isb
962:
97 /* Jump to kernel entry point */
98 mov x0, x20
99 mov x1, xzr
100 mov x2, xzr
101 mov x3, xzr
102 br x21
103
104efi_load_fail:
105 mov x0, #EFI_LOAD_ERROR
106 ldp x29, x30, [sp], #32
107 ret
108
109ENDPROC(efi_stub_entry)
diff --git a/arch/arm64/kernel/efi-stub.c b/arch/arm64/kernel/efi-stub.c
new file mode 100644
index 000000000000..60e98a639ac5
--- /dev/null
+++ b/arch/arm64/kernel/efi-stub.c
@@ -0,0 +1,81 @@
1/*
2 * Copyright (C) 2013, 2014 Linaro Ltd; <roy.franz@linaro.org>
3 *
4 * This file implements the EFI boot stub for the arm64 kernel.
5 * Adapted from ARM version by Mark Salter <msalter@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 */
12#include <linux/efi.h>
13#include <linux/libfdt.h>
14#include <asm/sections.h>
15#include <generated/compile.h>
16#include <generated/utsrelease.h>
17
18/*
19 * AArch64 requires the DTB to be 8-byte aligned in the first 512MiB from
20 * start of kernel and may not cross a 2MiB boundary. We set alignment to
21 * 2MiB so we know it won't cross a 2MiB boundary.
22 */
23#define EFI_FDT_ALIGN SZ_2M /* used by allocate_new_fdt_and_exit_boot() */
24#define MAX_FDT_OFFSET SZ_512M
25
26#define efi_call_early(f, ...) sys_table_arg->boottime->f(__VA_ARGS__)
27
28static void efi_char16_printk(efi_system_table_t *sys_table_arg,
29 efi_char16_t *str);
30
31static efi_status_t efi_open_volume(efi_system_table_t *sys_table,
32 void *__image, void **__fh);
33static efi_status_t efi_file_close(void *handle);
34
35static efi_status_t
36efi_file_read(void *handle, unsigned long *size, void *addr);
37
38static efi_status_t
39efi_file_size(efi_system_table_t *sys_table, void *__fh,
40 efi_char16_t *filename_16, void **handle, u64 *file_sz);
41
42/* Include shared EFI stub code */
43#include "../../../drivers/firmware/efi/efi-stub-helper.c"
44#include "../../../drivers/firmware/efi/fdt.c"
45#include "../../../drivers/firmware/efi/arm-stub.c"
46
47
48static efi_status_t handle_kernel_image(efi_system_table_t *sys_table,
49 unsigned long *image_addr,
50 unsigned long *image_size,
51 unsigned long *reserve_addr,
52 unsigned long *reserve_size,
53 unsigned long dram_base,
54 efi_loaded_image_t *image)
55{
56 efi_status_t status;
57 unsigned long kernel_size, kernel_memsize = 0;
58
59 /* Relocate the image, if required. */
60 kernel_size = _edata - _text;
61 if (*image_addr != (dram_base + TEXT_OFFSET)) {
62 kernel_memsize = kernel_size + (_end - _edata);
63 status = efi_relocate_kernel(sys_table, image_addr,
64 kernel_size, kernel_memsize,
65 dram_base + TEXT_OFFSET,
66 PAGE_SIZE);
67 if (status != EFI_SUCCESS) {
68 pr_efi_err(sys_table, "Failed to relocate kernel\n");
69 return status;
70 }
71 if (*image_addr != (dram_base + TEXT_OFFSET)) {
72 pr_efi_err(sys_table, "Failed to alloc kernel memory\n");
73 efi_free(sys_table, kernel_memsize, *image_addr);
74 return EFI_ERROR;
75 }
76 *image_size = kernel_memsize;
77 }
78
79
80 return EFI_SUCCESS;
81}
diff --git a/arch/arm64/kernel/efi.c b/arch/arm64/kernel/efi.c
new file mode 100644
index 000000000000..14db1f6e8d7f
--- /dev/null
+++ b/arch/arm64/kernel/efi.c
@@ -0,0 +1,469 @@
1/*
2 * Extensible Firmware Interface
3 *
4 * Based on Extensible Firmware Interface Specification version 2.4
5 *
6 * Copyright (C) 2013, 2014 Linaro Ltd.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
12 */
13
14#include <linux/efi.h>
15#include <linux/export.h>
16#include <linux/memblock.h>
17#include <linux/bootmem.h>
18#include <linux/of.h>
19#include <linux/of_fdt.h>
20#include <linux/sched.h>
21#include <linux/slab.h>
22
23#include <asm/cacheflush.h>
24#include <asm/efi.h>
25#include <asm/tlbflush.h>
26#include <asm/mmu_context.h>
27
28struct efi_memory_map memmap;
29
30static efi_runtime_services_t *runtime;
31
32static u64 efi_system_table;
33
34static int uefi_debug __initdata;
35static int __init uefi_debug_setup(char *str)
36{
37 uefi_debug = 1;
38
39 return 0;
40}
41early_param("uefi_debug", uefi_debug_setup);
42
43static int __init is_normal_ram(efi_memory_desc_t *md)
44{
45 if (md->attribute & EFI_MEMORY_WB)
46 return 1;
47 return 0;
48}
49
50static void __init efi_setup_idmap(void)
51{
52 struct memblock_region *r;
53 efi_memory_desc_t *md;
54 u64 paddr, npages, size;
55
56 for_each_memblock(memory, r)
57 create_id_mapping(r->base, r->size, 0);
58
59 /* map runtime io spaces */
60 for_each_efi_memory_desc(&memmap, md) {
61 if (!(md->attribute & EFI_MEMORY_RUNTIME) || is_normal_ram(md))
62 continue;
63 paddr = md->phys_addr;
64 npages = md->num_pages;
65 memrange_efi_to_native(&paddr, &npages);
66 size = npages << PAGE_SHIFT;
67 create_id_mapping(paddr, size, 1);
68 }
69}
70
71static int __init uefi_init(void)
72{
73 efi_char16_t *c16;
74 char vendor[100] = "unknown";
75 int i, retval;
76
77 efi.systab = early_memremap(efi_system_table,
78 sizeof(efi_system_table_t));
79 if (efi.systab == NULL) {
80 pr_warn("Unable to map EFI system table.\n");
81 return -ENOMEM;
82 }
83
84 set_bit(EFI_BOOT, &efi.flags);
85 set_bit(EFI_64BIT, &efi.flags);
86
87 /*
88 * Verify the EFI Table
89 */
90 if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) {
91 pr_err("System table signature incorrect\n");
92 return -EINVAL;
93 }
94 if ((efi.systab->hdr.revision >> 16) < 2)
95 pr_warn("Warning: EFI system table version %d.%02d, expected 2.00 or greater\n",
96 efi.systab->hdr.revision >> 16,
97 efi.systab->hdr.revision & 0xffff);
98
99 /* Show what we know for posterity */
100 c16 = early_memremap(efi.systab->fw_vendor,
101 sizeof(vendor));
102 if (c16) {
103 for (i = 0; i < (int) sizeof(vendor) - 1 && *c16; ++i)
104 vendor[i] = c16[i];
105 vendor[i] = '\0';
106 }
107
108 pr_info("EFI v%u.%.02u by %s\n",
109 efi.systab->hdr.revision >> 16,
110 efi.systab->hdr.revision & 0xffff, vendor);
111
112 retval = efi_config_init(NULL);
113 if (retval == 0)
114 set_bit(EFI_CONFIG_TABLES, &efi.flags);
115
116 early_memunmap(c16, sizeof(vendor));
117 early_memunmap(efi.systab, sizeof(efi_system_table_t));
118
119 return retval;
120}
121
122static __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/*
140 * Return true for RAM regions we want to permanently reserve.
141 */
142static __init int is_reserve_region(efi_memory_desc_t *md)
143{
144 if (!is_normal_ram(md))
145 return 0;
146
147 if (md->attribute & EFI_MEMORY_RUNTIME)
148 return 1;
149
150 if (md->type == EFI_ACPI_RECLAIM_MEMORY ||
151 md->type == EFI_RESERVED_TYPE)
152 return 1;
153
154 return 0;
155}
156
157static __init void reserve_regions(void)
158{
159 efi_memory_desc_t *md;
160 u64 paddr, npages, size;
161
162 if (uefi_debug)
163 pr_info("Processing EFI memory map:\n");
164
165 for_each_efi_memory_desc(&memmap, md) {
166 paddr = md->phys_addr;
167 npages = md->num_pages;
168
169 if (uefi_debug)
170 pr_info(" 0x%012llx-0x%012llx [%s]",
171 paddr, paddr + (npages << EFI_PAGE_SHIFT) - 1,
172 memory_type_name[md->type]);
173
174 memrange_efi_to_native(&paddr, &npages);
175 size = npages << PAGE_SHIFT;
176
177 if (is_normal_ram(md))
178 early_init_dt_add_memory_arch(paddr, size);
179
180 if (is_reserve_region(md) ||
181 md->type == EFI_BOOT_SERVICES_CODE ||
182 md->type == EFI_BOOT_SERVICES_DATA) {
183 memblock_reserve(paddr, size);
184 if (uefi_debug)
185 pr_cont("*");
186 }
187
188 if (uefi_debug)
189 pr_cont("\n");
190 }
191}
192
193
194static u64 __init free_one_region(u64 start, u64 end)
195{
196 u64 size = end - start;
197
198 if (uefi_debug)
199 pr_info(" EFI freeing: 0x%012llx-0x%012llx\n", start, end - 1);
200
201 free_bootmem_late(start, size);
202 return size;
203}
204
205static u64 __init free_region(u64 start, u64 end)
206{
207 u64 map_start, map_end, total = 0;
208
209 if (end <= start)
210 return total;
211
212 map_start = (u64)memmap.phys_map;
213 map_end = PAGE_ALIGN(map_start + (memmap.map_end - memmap.map));
214 map_start &= PAGE_MASK;
215
216 if (start < map_end && end > map_start) {
217 /* region overlaps UEFI memmap */
218 if (start < map_start)
219 total += free_one_region(start, map_start);
220
221 if (map_end < end)
222 total += free_one_region(map_end, end);
223 } else
224 total += free_one_region(start, end);
225
226 return total;
227}
228
229static void __init free_boot_services(void)
230{
231 u64 total_freed = 0;
232 u64 keep_end, free_start, free_end;
233 efi_memory_desc_t *md;
234
235 /*
236 * If kernel uses larger pages than UEFI, we have to be careful
237 * not to inadvertantly free memory we want to keep if there is
238 * overlap at the kernel page size alignment. We do not want to
239 * free is_reserve_region() memory nor the UEFI memmap itself.
240 *
241 * The memory map is sorted, so we keep track of the end of
242 * any previous region we want to keep, remember any region
243 * we want to free and defer freeing it until we encounter
244 * the next region we want to keep. This way, before freeing
245 * it, we can clip it as needed to avoid freeing memory we
246 * want to keep for UEFI.
247 */
248
249 keep_end = 0;
250 free_start = 0;
251
252 for_each_efi_memory_desc(&memmap, md) {
253 u64 paddr, npages, size;
254
255 if (is_reserve_region(md)) {
256 /*
257 * We don't want to free any memory from this region.
258 */
259 if (free_start) {
260 /* adjust free_end then free region */
261 if (free_end > md->phys_addr)
262 free_end -= PAGE_SIZE;
263 total_freed += free_region(free_start, free_end);
264 free_start = 0;
265 }
266 keep_end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT);
267 continue;
268 }
269
270 if (md->type != EFI_BOOT_SERVICES_CODE &&
271 md->type != EFI_BOOT_SERVICES_DATA) {
272 /* no need to free this region */
273 continue;
274 }
275
276 /*
277 * We want to free memory from this region.
278 */
279 paddr = md->phys_addr;
280 npages = md->num_pages;
281 memrange_efi_to_native(&paddr, &npages);
282 size = npages << PAGE_SHIFT;
283
284 if (free_start) {
285 if (paddr <= free_end)
286 free_end = paddr + size;
287 else {
288 total_freed += free_region(free_start, free_end);
289 free_start = paddr;
290 free_end = paddr + size;
291 }
292 } else {
293 free_start = paddr;
294 free_end = paddr + size;
295 }
296 if (free_start < keep_end) {
297 free_start += PAGE_SIZE;
298 if (free_start >= free_end)
299 free_start = 0;
300 }
301 }
302 if (free_start)
303 total_freed += free_region(free_start, free_end);
304
305 if (total_freed)
306 pr_info("Freed 0x%llx bytes of EFI boot services memory",
307 total_freed);
308}
309
310void __init efi_init(void)
311{
312 struct efi_fdt_params params;
313
314 /* Grab UEFI information placed in FDT by stub */
315 if (!efi_get_fdt_params(&params, uefi_debug))
316 return;
317
318 efi_system_table = params.system_table;
319
320 memblock_reserve(params.mmap & PAGE_MASK,
321 PAGE_ALIGN(params.mmap_size + (params.mmap & ~PAGE_MASK)));
322 memmap.phys_map = (void *)params.mmap;
323 memmap.map = early_memremap(params.mmap, params.mmap_size);
324 memmap.map_end = memmap.map + params.mmap_size;
325 memmap.desc_size = params.desc_size;
326 memmap.desc_version = params.desc_ver;
327
328 if (uefi_init() < 0)
329 return;
330
331 reserve_regions();
332}
333
334void __init efi_idmap_init(void)
335{
336 if (!efi_enabled(EFI_BOOT))
337 return;
338
339 /* boot time idmap_pg_dir is incomplete, so fill in missing parts */
340 efi_setup_idmap();
341}
342
343static int __init remap_region(efi_memory_desc_t *md, void **new)
344{
345 u64 paddr, vaddr, npages, size;
346
347 paddr = md->phys_addr;
348 npages = md->num_pages;
349 memrange_efi_to_native(&paddr, &npages);
350 size = npages << PAGE_SHIFT;
351
352 if (is_normal_ram(md))
353 vaddr = (__force u64)ioremap_cache(paddr, size);
354 else
355 vaddr = (__force u64)ioremap(paddr, size);
356
357 if (!vaddr) {
358 pr_err("Unable to remap 0x%llx pages @ %p\n",
359 npages, (void *)paddr);
360 return 0;
361 }
362
363 /* adjust for any rounding when EFI and system pagesize differs */
364 md->virt_addr = vaddr + (md->phys_addr - paddr);
365
366 if (uefi_debug)
367 pr_info(" EFI remap 0x%012llx => %p\n",
368 md->phys_addr, (void *)md->virt_addr);
369
370 memcpy(*new, md, memmap.desc_size);
371 *new += memmap.desc_size;
372
373 return 1;
374}
375
376/*
377 * Switch UEFI from an identity map to a kernel virtual map
378 */
379static int __init arm64_enter_virtual_mode(void)
380{
381 efi_memory_desc_t *md;
382 phys_addr_t virtmap_phys;
383 void *virtmap, *virt_md;
384 efi_status_t status;
385 u64 mapsize;
386 int count = 0;
387 unsigned long flags;
388
389 if (!efi_enabled(EFI_BOOT)) {
390 pr_info("EFI services will not be available.\n");
391 return -1;
392 }
393
394 pr_info("Remapping and enabling EFI services.\n");
395
396 /* replace early memmap mapping with permanent mapping */
397 mapsize = memmap.map_end - memmap.map;
398 early_memunmap(memmap.map, mapsize);
399 memmap.map = (__force void *)ioremap_cache((phys_addr_t)memmap.phys_map,
400 mapsize);
401 memmap.map_end = memmap.map + mapsize;
402
403 efi.memmap = &memmap;
404
405 /* Map the runtime regions */
406 virtmap = kmalloc(mapsize, GFP_KERNEL);
407 if (!virtmap) {
408 pr_err("Failed to allocate EFI virtual memmap\n");
409 return -1;
410 }
411 virtmap_phys = virt_to_phys(virtmap);
412 virt_md = virtmap;
413
414 for_each_efi_memory_desc(&memmap, md) {
415 if (!(md->attribute & EFI_MEMORY_RUNTIME))
416 continue;
417 if (remap_region(md, &virt_md))
418 ++count;
419 }
420
421 efi.systab = (__force void *)efi_lookup_mapped_addr(efi_system_table);
422 if (efi.systab)
423 set_bit(EFI_SYSTEM_TABLES, &efi.flags);
424
425 local_irq_save(flags);
426 cpu_switch_mm(idmap_pg_dir, &init_mm);
427
428 /* Call SetVirtualAddressMap with the physical address of the map */
429 runtime = efi.systab->runtime;
430 efi.set_virtual_address_map = runtime->set_virtual_address_map;
431
432 status = efi.set_virtual_address_map(count * memmap.desc_size,
433 memmap.desc_size,
434 memmap.desc_version,
435 (efi_memory_desc_t *)virtmap_phys);
436 cpu_set_reserved_ttbr0();
437 flush_tlb_all();
438 local_irq_restore(flags);
439
440 kfree(virtmap);
441
442 free_boot_services();
443
444 if (status != EFI_SUCCESS) {
445 pr_err("Failed to set EFI virtual address map! [%lx]\n",
446 status);
447 return -1;
448 }
449
450 /* Set up runtime services function pointers */
451 runtime = efi.systab->runtime;
452 efi.get_time = runtime->get_time;
453 efi.set_time = runtime->set_time;
454 efi.get_wakeup_time = runtime->get_wakeup_time;
455 efi.set_wakeup_time = runtime->set_wakeup_time;
456 efi.get_variable = runtime->get_variable;
457 efi.get_next_variable = runtime->get_next_variable;
458 efi.set_variable = runtime->set_variable;
459 efi.query_variable_info = runtime->query_variable_info;
460 efi.update_capsule = runtime->update_capsule;
461 efi.query_capsule_caps = runtime->query_capsule_caps;
462 efi.get_next_high_mono_count = runtime->get_next_high_mono_count;
463 efi.reset_system = runtime->reset_system;
464
465 set_bit(EFI_RUNTIME_SERVICES, &efi.flags);
466
467 return 0;
468}
469early_initcall(arm64_enter_virtual_mode);
diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
index 0fd565000772..738291b5be29 100644
--- a/arch/arm64/kernel/head.S
+++ b/arch/arm64/kernel/head.S
@@ -108,8 +108,18 @@
108 /* 108 /*
109 * DO NOT MODIFY. Image header expected by Linux boot-loaders. 109 * DO NOT MODIFY. Image header expected by Linux boot-loaders.
110 */ 110 */
111#ifdef CONFIG_EFI
112efi_head:
113 /*
114 * This add instruction has no meaningful effect except that
115 * its opcode forms the magic "MZ" signature required by UEFI.
116 */
117 add x13, x18, #0x16
118 b stext
119#else
111 b stext // branch to kernel start, magic 120 b stext // branch to kernel start, magic
112 .long 0 // reserved 121 .long 0 // reserved
122#endif
113 .quad TEXT_OFFSET // Image load offset from start of RAM 123 .quad TEXT_OFFSET // Image load offset from start of RAM
114 .quad 0 // reserved 124 .quad 0 // reserved
115 .quad 0 // reserved 125 .quad 0 // reserved
@@ -120,7 +130,109 @@
120 .byte 0x52 130 .byte 0x52
121 .byte 0x4d 131 .byte 0x4d
122 .byte 0x64 132 .byte 0x64
133#ifdef CONFIG_EFI
134 .long pe_header - efi_head // Offset to the PE header.
135#else
123 .word 0 // reserved 136 .word 0 // reserved
137#endif
138
139#ifdef CONFIG_EFI
140 .align 3
141pe_header:
142 .ascii "PE"
143 .short 0
144coff_header:
145 .short 0xaa64 // AArch64
146 .short 2 // nr_sections
147 .long 0 // TimeDateStamp
148 .long 0 // PointerToSymbolTable
149 .long 1 // NumberOfSymbols
150 .short section_table - optional_header // SizeOfOptionalHeader
151 .short 0x206 // Characteristics.
152 // IMAGE_FILE_DEBUG_STRIPPED |
153 // IMAGE_FILE_EXECUTABLE_IMAGE |
154 // IMAGE_FILE_LINE_NUMS_STRIPPED
155optional_header:
156 .short 0x20b // PE32+ format
157 .byte 0x02 // MajorLinkerVersion
158 .byte 0x14 // MinorLinkerVersion
159 .long _edata - stext // SizeOfCode
160 .long 0 // SizeOfInitializedData
161 .long 0 // SizeOfUninitializedData
162 .long efi_stub_entry - efi_head // AddressOfEntryPoint
163 .long stext - efi_head // BaseOfCode
164
165extra_header_fields:
166 .quad 0 // ImageBase
167 .long 0x20 // SectionAlignment
168 .long 0x8 // FileAlignment
169 .short 0 // MajorOperatingSystemVersion
170 .short 0 // MinorOperatingSystemVersion
171 .short 0 // MajorImageVersion
172 .short 0 // MinorImageVersion
173 .short 0 // MajorSubsystemVersion
174 .short 0 // MinorSubsystemVersion
175 .long 0 // Win32VersionValue
176
177 .long _edata - efi_head // SizeOfImage
178
179 // Everything before the kernel image is considered part of the header
180 .long stext - efi_head // SizeOfHeaders
181 .long 0 // CheckSum
182 .short 0xa // Subsystem (EFI application)
183 .short 0 // DllCharacteristics
184 .quad 0 // SizeOfStackReserve
185 .quad 0 // SizeOfStackCommit
186 .quad 0 // SizeOfHeapReserve
187 .quad 0 // SizeOfHeapCommit
188 .long 0 // LoaderFlags
189 .long 0x6 // NumberOfRvaAndSizes
190
191 .quad 0 // ExportTable
192 .quad 0 // ImportTable
193 .quad 0 // ResourceTable
194 .quad 0 // ExceptionTable
195 .quad 0 // CertificationTable
196 .quad 0 // BaseRelocationTable
197
198 // Section table
199section_table:
200
201 /*
202 * The EFI application loader requires a relocation section
203 * because EFI applications must be relocatable. This is a
204 * dummy section as far as we are concerned.
205 */
206 .ascii ".reloc"
207 .byte 0
208 .byte 0 // end of 0 padding of section name
209 .long 0
210 .long 0
211 .long 0 // SizeOfRawData
212 .long 0 // PointerToRawData
213 .long 0 // PointerToRelocations
214 .long 0 // PointerToLineNumbers
215 .short 0 // NumberOfRelocations
216 .short 0 // NumberOfLineNumbers
217 .long 0x42100040 // Characteristics (section flags)
218
219
220 .ascii ".text"
221 .byte 0
222 .byte 0
223 .byte 0 // end of 0 padding of section name
224 .long _edata - stext // VirtualSize
225 .long stext - efi_head // VirtualAddress
226 .long _edata - stext // SizeOfRawData
227 .long stext - efi_head // PointerToRawData
228
229 .long 0 // PointerToRelocations (0 for executables)
230 .long 0 // PointerToLineNumbers (0 for executables)
231 .short 0 // NumberOfRelocations (0 for executables)
232 .short 0 // NumberOfLineNumbers (0 for executables)
233 .long 0xe0500020 // Characteristics (section flags)
234 .align 5
235#endif
124 236
125ENTRY(stext) 237ENTRY(stext)
126 mov x21, x0 // x21=FDT 238 mov x21, x0 // x21=FDT
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
index 7ec784653b29..e578171b22ff 100644
--- a/arch/arm64/kernel/setup.c
+++ b/arch/arm64/kernel/setup.c
@@ -41,6 +41,7 @@
41#include <linux/memblock.h> 41#include <linux/memblock.h>
42#include <linux/of_fdt.h> 42#include <linux/of_fdt.h>
43#include <linux/of_platform.h> 43#include <linux/of_platform.h>
44#include <linux/efi.h>
44 45
45#include <asm/fixmap.h> 46#include <asm/fixmap.h>
46#include <asm/cputype.h> 47#include <asm/cputype.h>
@@ -55,6 +56,7 @@
55#include <asm/traps.h> 56#include <asm/traps.h>
56#include <asm/memblock.h> 57#include <asm/memblock.h>
57#include <asm/psci.h> 58#include <asm/psci.h>
59#include <asm/efi.h>
58 60
59unsigned int processor_id; 61unsigned int processor_id;
60EXPORT_SYMBOL(processor_id); 62EXPORT_SYMBOL(processor_id);
@@ -366,11 +368,14 @@ void __init setup_arch(char **cmdline_p)
366 368
367 parse_early_param(); 369 parse_early_param();
368 370
371 efi_init();
369 arm64_memblock_init(); 372 arm64_memblock_init();
370 373
371 paging_init(); 374 paging_init();
372 request_standard_resources(); 375 request_standard_resources();
373 376
377 efi_idmap_init();
378
374 unflatten_device_tree(); 379 unflatten_device_tree();
375 380
376 psci_init(); 381 psci_init();
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index 0a472c41a67f..4a829a210bb6 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -168,7 +168,8 @@ static void __init *early_alloc(unsigned long sz)
168} 168}
169 169
170static void __init alloc_init_pte(pmd_t *pmd, unsigned long addr, 170static void __init alloc_init_pte(pmd_t *pmd, unsigned long addr,
171 unsigned long end, unsigned long pfn) 171 unsigned long end, unsigned long pfn,
172 pgprot_t prot)
172{ 173{
173 pte_t *pte; 174 pte_t *pte;
174 175
@@ -180,16 +181,28 @@ static void __init alloc_init_pte(pmd_t *pmd, unsigned long addr,
180 181
181 pte = pte_offset_kernel(pmd, addr); 182 pte = pte_offset_kernel(pmd, addr);
182 do { 183 do {
183 set_pte(pte, pfn_pte(pfn, PAGE_KERNEL_EXEC)); 184 set_pte(pte, pfn_pte(pfn, prot));
184 pfn++; 185 pfn++;
185 } while (pte++, addr += PAGE_SIZE, addr != end); 186 } while (pte++, addr += PAGE_SIZE, addr != end);
186} 187}
187 188
188static void __init alloc_init_pmd(pud_t *pud, unsigned long addr, 189static void __init alloc_init_pmd(pud_t *pud, unsigned long addr,
189 unsigned long end, phys_addr_t phys) 190 unsigned long end, phys_addr_t phys,
191 int map_io)
190{ 192{
191 pmd_t *pmd; 193 pmd_t *pmd;
192 unsigned long next; 194 unsigned long next;
195 pmdval_t prot_sect;
196 pgprot_t prot_pte;
197
198 if (map_io) {
199 prot_sect = PMD_TYPE_SECT | PMD_SECT_AF |
200 PMD_ATTRINDX(MT_DEVICE_nGnRE);
201 prot_pte = __pgprot(PROT_DEVICE_nGnRE);
202 } else {
203 prot_sect = prot_sect_kernel;
204 prot_pte = PAGE_KERNEL_EXEC;
205 }
193 206
194 /* 207 /*
195 * Check for initial section mappings in the pgd/pud and remove them. 208 * Check for initial section mappings in the pgd/pud and remove them.
@@ -205,7 +218,7 @@ static void __init alloc_init_pmd(pud_t *pud, unsigned long addr,
205 /* try section mapping first */ 218 /* try section mapping first */
206 if (((addr | next | phys) & ~SECTION_MASK) == 0) { 219 if (((addr | next | phys) & ~SECTION_MASK) == 0) {
207 pmd_t old_pmd =*pmd; 220 pmd_t old_pmd =*pmd;
208 set_pmd(pmd, __pmd(phys | prot_sect_kernel)); 221 set_pmd(pmd, __pmd(phys | prot_sect));
209 /* 222 /*
210 * Check for previous table entries created during 223 * Check for previous table entries created during
211 * boot (__create_page_tables) and flush them. 224 * boot (__create_page_tables) and flush them.
@@ -213,21 +226,23 @@ static void __init alloc_init_pmd(pud_t *pud, unsigned long addr,
213 if (!pmd_none(old_pmd)) 226 if (!pmd_none(old_pmd))
214 flush_tlb_all(); 227 flush_tlb_all();
215 } else { 228 } else {
216 alloc_init_pte(pmd, addr, next, __phys_to_pfn(phys)); 229 alloc_init_pte(pmd, addr, next, __phys_to_pfn(phys),
230 prot_pte);
217 } 231 }
218 phys += next - addr; 232 phys += next - addr;
219 } while (pmd++, addr = next, addr != end); 233 } while (pmd++, addr = next, addr != end);
220} 234}
221 235
222static void __init alloc_init_pud(pgd_t *pgd, unsigned long addr, 236static void __init alloc_init_pud(pgd_t *pgd, unsigned long addr,
223 unsigned long end, unsigned long phys) 237 unsigned long end, unsigned long phys,
238 int map_io)
224{ 239{
225 pud_t *pud = pud_offset(pgd, addr); 240 pud_t *pud = pud_offset(pgd, addr);
226 unsigned long next; 241 unsigned long next;
227 242
228 do { 243 do {
229 next = pud_addr_end(addr, end); 244 next = pud_addr_end(addr, end);
230 alloc_init_pmd(pud, addr, next, phys); 245 alloc_init_pmd(pud, addr, next, phys, map_io);
231 phys += next - addr; 246 phys += next - addr;
232 } while (pud++, addr = next, addr != end); 247 } while (pud++, addr = next, addr != end);
233} 248}
@@ -236,30 +251,44 @@ static void __init alloc_init_pud(pgd_t *pgd, unsigned long addr,
236 * Create the page directory entries and any necessary page tables for the 251 * Create the page directory entries and any necessary page tables for the
237 * mapping specified by 'md'. 252 * mapping specified by 'md'.
238 */ 253 */
239static void __init create_mapping(phys_addr_t phys, unsigned long virt, 254static void __init __create_mapping(pgd_t *pgd, phys_addr_t phys,
240 phys_addr_t size) 255 unsigned long virt, phys_addr_t size,
256 int map_io)
241{ 257{
242 unsigned long addr, length, end, next; 258 unsigned long addr, length, end, next;
243 pgd_t *pgd;
244
245 if (virt < VMALLOC_START) {
246 pr_warning("BUG: not creating mapping for 0x%016llx at 0x%016lx - outside kernel range\n",
247 phys, virt);
248 return;
249 }
250 259
251 addr = virt & PAGE_MASK; 260 addr = virt & PAGE_MASK;
252 length = PAGE_ALIGN(size + (virt & ~PAGE_MASK)); 261 length = PAGE_ALIGN(size + (virt & ~PAGE_MASK));
253 262
254 pgd = pgd_offset_k(addr);
255 end = addr + length; 263 end = addr + length;
256 do { 264 do {
257 next = pgd_addr_end(addr, end); 265 next = pgd_addr_end(addr, end);
258 alloc_init_pud(pgd, addr, next, phys); 266 alloc_init_pud(pgd, addr, next, phys, map_io);
259 phys += next - addr; 267 phys += next - addr;
260 } while (pgd++, addr = next, addr != end); 268 } while (pgd++, addr = next, addr != end);
261} 269}
262 270
271static void __init create_mapping(phys_addr_t phys, unsigned long virt,
272 phys_addr_t size)
273{
274 if (virt < VMALLOC_START) {
275 pr_warn("BUG: not creating mapping for %pa at 0x%016lx - outside kernel range\n",
276 &phys, virt);
277 return;
278 }
279 __create_mapping(pgd_offset_k(virt & PAGE_MASK), phys, virt, size, 0);
280}
281
282void __init create_id_mapping(phys_addr_t addr, phys_addr_t size, int map_io)
283{
284 if ((addr >> PGDIR_SHIFT) >= ARRAY_SIZE(idmap_pg_dir)) {
285 pr_warn("BUG: not creating id mapping for %pa\n", &addr);
286 return;
287 }
288 __create_mapping(&idmap_pg_dir[pgd_index(addr)],
289 addr, addr, size, map_io);
290}
291
263static void __init map_mem(void) 292static void __init map_mem(void)
264{ 293{
265 struct memblock_region *reg; 294 struct memblock_region *reg;