aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/arm/00-INDEX2
-rw-r--r--Documentation/arm/uefi.txt64
-rw-r--r--Documentation/arm64/booting.txt4
-rw-r--r--Documentation/efi-stub.txt33
-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
-rw-r--r--drivers/firmware/efi/Kconfig7
-rw-r--r--drivers/firmware/efi/arm-stub.c278
-rw-r--r--drivers/firmware/efi/efi.c79
-rw-r--r--drivers/firmware/efi/fdt.c285
-rw-r--r--include/linux/efi.h12
-rw-r--r--lib/Makefile3
-rw-r--r--lib/fdt_empty_tree.c2
21 files changed, 1619 insertions, 26 deletions
diff --git a/Documentation/arm/00-INDEX b/Documentation/arm/00-INDEX
index a94090cc785d..3b08bc2b04cf 100644
--- a/Documentation/arm/00-INDEX
+++ b/Documentation/arm/00-INDEX
@@ -46,5 +46,7 @@ swp_emulation
46 - SWP/SWPB emulation handler/logging description 46 - SWP/SWPB emulation handler/logging description
47tcm.txt 47tcm.txt
48 - ARM Tightly Coupled Memory 48 - ARM Tightly Coupled Memory
49uefi.txt
50 - [U]EFI configuration and runtime services documentation
49vlocks.txt 51vlocks.txt
50 - Voting locks, low-level mechanism relying on memory system atomic writes. 52 - Voting locks, low-level mechanism relying on memory system atomic writes.
diff --git a/Documentation/arm/uefi.txt b/Documentation/arm/uefi.txt
new file mode 100644
index 000000000000..d60030a1b909
--- /dev/null
+++ b/Documentation/arm/uefi.txt
@@ -0,0 +1,64 @@
1UEFI, the Unified Extensible Firmware Interface, is a specification
2governing the behaviours of compatible firmware interfaces. It is
3maintained by the UEFI Forum - http://www.uefi.org/.
4
5UEFI is an evolution of its predecessor 'EFI', so the terms EFI and
6UEFI are used somewhat interchangeably in this document and associated
7source code. As a rule, anything new uses 'UEFI', whereas 'EFI' refers
8to legacy code or specifications.
9
10UEFI support in Linux
11=====================
12Booting on a platform with firmware compliant with the UEFI specification
13makes it possible for the kernel to support additional features:
14- UEFI Runtime Services
15- Retrieving various configuration information through the standardised
16 interface of UEFI configuration tables. (ACPI, SMBIOS, ...)
17
18For actually enabling [U]EFI support, enable:
19- CONFIG_EFI=y
20- CONFIG_EFI_VARS=y or m
21
22The implementation depends on receiving information about the UEFI environment
23in a Flattened Device Tree (FDT) - so is only available with CONFIG_OF.
24
25UEFI stub
26=========
27The "stub" is a feature that extends the Image/zImage into a valid UEFI
28PE/COFF executable, including a loader application that makes it possible to
29load the kernel directly from the UEFI shell, boot menu, or one of the
30lightweight bootloaders like Gummiboot or rEFInd.
31
32The kernel image built with stub support remains a valid kernel image for
33booting in non-UEFI environments.
34
35UEFI kernel support on ARM
36==========================
37UEFI kernel support on the ARM architectures (arm and arm64) is only available
38when boot is performed through the stub.
39
40When booting in UEFI mode, the stub deletes any memory nodes from a provided DT.
41Instead, the kernel reads the UEFI memory map.
42
43The stub populates the FDT /chosen node with (and the kernel scans for) the
44following parameters:
45________________________________________________________________________________
46Name | Size | Description
47================================================================================
48linux,uefi-system-table | 64-bit | Physical address of the UEFI System Table.
49--------------------------------------------------------------------------------
50linux,uefi-mmap-start | 64-bit | Physical address of the UEFI memory map,
51 | | populated by the UEFI GetMemoryMap() call.
52--------------------------------------------------------------------------------
53linux,uefi-mmap-size | 32-bit | Size in bytes of the UEFI memory map
54 | | pointed to in previous entry.
55--------------------------------------------------------------------------------
56linux,uefi-mmap-desc-size | 32-bit | Size in bytes of each entry in the UEFI
57 | | memory map.
58--------------------------------------------------------------------------------
59linux,uefi-mmap-desc-ver | 32-bit | Version of the mmap descriptor format.
60--------------------------------------------------------------------------------
61linux,uefi-stub-kern-ver | string | Copy of linux_banner from build.
62--------------------------------------------------------------------------------
63
64For verbose debug messages, specify 'uefi_debug' on the kernel command line.
diff --git a/Documentation/arm64/booting.txt b/Documentation/arm64/booting.txt
index beb754e87c65..37fc4f632176 100644
--- a/Documentation/arm64/booting.txt
+++ b/Documentation/arm64/booting.txt
@@ -85,6 +85,10 @@ The decompressed kernel image contains a 64-byte header as follows:
85Header notes: 85Header notes:
86 86
87- code0/code1 are responsible for branching to stext. 87- code0/code1 are responsible for branching to stext.
88- when booting through EFI, code0/code1 are initially skipped.
89 res5 is an offset to the PE header and the PE header has the EFI
90 entry point (efi_stub_entry). When the stub has done its work, it
91 jumps to code0 to resume the normal boot process.
88 92
89The image must be placed at the specified offset (currently 0x80000) 93The image must be placed at the specified offset (currently 0x80000)
90from the start of the system RAM and called there. The start of the 94from the start of the system RAM and called there. The start of the
diff --git a/Documentation/efi-stub.txt b/Documentation/efi-stub.txt
index c628788d5b47..7747024d3bb7 100644
--- a/Documentation/efi-stub.txt
+++ b/Documentation/efi-stub.txt
@@ -1,13 +1,21 @@
1 The EFI Boot Stub 1 The EFI Boot Stub
2 --------------------------- 2 ---------------------------
3 3
4On the x86 platform, a bzImage can masquerade as a PE/COFF image, 4On the x86 and ARM platforms, a kernel zImage/bzImage can masquerade
5thereby convincing EFI firmware loaders to load it as an EFI 5as a PE/COFF image, thereby convincing EFI firmware loaders to load
6executable. The code that modifies the bzImage header, along with the 6it as an EFI executable. The code that modifies the bzImage header,
7EFI-specific entry point that the firmware loader jumps to are 7along with the EFI-specific entry point that the firmware loader
8collectively known as the "EFI boot stub", and live in 8jumps to are collectively known as the "EFI boot stub", and live in
9arch/x86/boot/header.S and arch/x86/boot/compressed/eboot.c, 9arch/x86/boot/header.S and arch/x86/boot/compressed/eboot.c,
10respectively. 10respectively. For ARM the EFI stub is implemented in
11arch/arm/boot/compressed/efi-header.S and
12arch/arm/boot/compressed/efi-stub.c. EFI stub code that is shared
13between architectures is in drivers/firmware/efi/efi-stub-helper.c.
14
15For arm64, there is no compressed kernel support, so the Image itself
16masquerades as a PE/COFF image and the EFI stub is linked into the
17kernel. The arm64 EFI stub lives in arch/arm64/kernel/efi-entry.S
18and arch/arm64/kernel/efi-stub.c.
11 19
12By using the EFI boot stub it's possible to boot a Linux kernel 20By using the EFI boot stub it's possible to boot a Linux kernel
13without the use of a conventional EFI boot loader, such as grub or 21without the use of a conventional EFI boot loader, such as grub or
@@ -23,7 +31,10 @@ The bzImage located in arch/x86/boot/bzImage must be copied to the EFI
23System Partition (ESP) and renamed with the extension ".efi". Without 31System Partition (ESP) and renamed with the extension ".efi". Without
24the extension the EFI firmware loader will refuse to execute it. It's 32the extension the EFI firmware loader will refuse to execute it. It's
25not possible to execute bzImage.efi from the usual Linux file systems 33not possible to execute bzImage.efi from the usual Linux file systems
26because EFI firmware doesn't have support for them. 34because EFI firmware doesn't have support for them. For ARM the
35arch/arm/boot/zImage should be copied to the system partition, and it
36may not need to be renamed. Similarly for arm64, arch/arm64/boot/Image
37should be copied but not necessarily renamed.
27 38
28 39
29**** Passing kernel parameters from the EFI shell 40**** Passing kernel parameters from the EFI shell
@@ -63,3 +74,11 @@ Notice how bzImage.efi can be specified with a relative path. That's
63because the image we're executing is interpreted by the EFI shell, 74because the image we're executing is interpreted by the EFI shell,
64which understands relative paths, whereas the rest of the command line 75which understands relative paths, whereas the rest of the command line
65is passed to bzImage.efi. 76is passed to bzImage.efi.
77
78
79**** The "dtb=" option
80
81For the ARM and arm64 architectures, we also need to be able to provide a
82device tree to the kernel. This is done with the "dtb=" command line option,
83and is processed in the same manner as the "initrd=" option that is
84described above.
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;
diff --git a/drivers/firmware/efi/Kconfig b/drivers/firmware/efi/Kconfig
index 1e75f48b61f8..d420ae2d3413 100644
--- a/drivers/firmware/efi/Kconfig
+++ b/drivers/firmware/efi/Kconfig
@@ -47,6 +47,13 @@ config EFI_RUNTIME_MAP
47 47
48 See also Documentation/ABI/testing/sysfs-firmware-efi-runtime-map. 48 See also Documentation/ABI/testing/sysfs-firmware-efi-runtime-map.
49 49
50config EFI_PARAMS_FROM_FDT
51 bool
52 help
53 Select this config option from the architecture Kconfig if
54 the EFI runtime support gets system table address, memory
55 map address, and other parameters from the device tree.
56
50endmenu 57endmenu
51 58
52config UEFI_CPER 59config UEFI_CPER
diff --git a/drivers/firmware/efi/arm-stub.c b/drivers/firmware/efi/arm-stub.c
new file mode 100644
index 000000000000..41114ce03b01
--- /dev/null
+++ b/drivers/firmware/efi/arm-stub.c
@@ -0,0 +1,278 @@
1/*
2 * EFI stub implementation that is shared by arm and arm64 architectures.
3 * This should be #included by the EFI stub implementation files.
4 *
5 * Copyright (C) 2013,2014 Linaro Limited
6 * Roy Franz <roy.franz@linaro.org
7 * Copyright (C) 2013 Red Hat, Inc.
8 * Mark Salter <msalter@redhat.com>
9 *
10 * This file is part of the Linux kernel, and is made available under the
11 * terms of the GNU General Public License version 2.
12 *
13 */
14
15static int __init efi_secureboot_enabled(efi_system_table_t *sys_table_arg)
16{
17 static efi_guid_t const var_guid __initconst = EFI_GLOBAL_VARIABLE_GUID;
18 static efi_char16_t const var_name[] __initconst = {
19 'S', 'e', 'c', 'u', 'r', 'e', 'B', 'o', 'o', 't', 0 };
20
21 efi_get_variable_t *f_getvar = sys_table_arg->runtime->get_variable;
22 unsigned long size = sizeof(u8);
23 efi_status_t status;
24 u8 val;
25
26 status = f_getvar((efi_char16_t *)var_name, (efi_guid_t *)&var_guid,
27 NULL, &size, &val);
28
29 switch (status) {
30 case EFI_SUCCESS:
31 return val;
32 case EFI_NOT_FOUND:
33 return 0;
34 default:
35 return 1;
36 }
37}
38
39static efi_status_t efi_open_volume(efi_system_table_t *sys_table_arg,
40 void *__image, void **__fh)
41{
42 efi_file_io_interface_t *io;
43 efi_loaded_image_t *image = __image;
44 efi_file_handle_t *fh;
45 efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID;
46 efi_status_t status;
47 void *handle = (void *)(unsigned long)image->device_handle;
48
49 status = sys_table_arg->boottime->handle_protocol(handle,
50 &fs_proto, (void **)&io);
51 if (status != EFI_SUCCESS) {
52 efi_printk(sys_table_arg, "Failed to handle fs_proto\n");
53 return status;
54 }
55
56 status = io->open_volume(io, &fh);
57 if (status != EFI_SUCCESS)
58 efi_printk(sys_table_arg, "Failed to open volume\n");
59
60 *__fh = fh;
61 return status;
62}
63static efi_status_t efi_file_close(void *handle)
64{
65 efi_file_handle_t *fh = handle;
66
67 return fh->close(handle);
68}
69
70static efi_status_t
71efi_file_read(void *handle, unsigned long *size, void *addr)
72{
73 efi_file_handle_t *fh = handle;
74
75 return fh->read(handle, size, addr);
76}
77
78
79static efi_status_t
80efi_file_size(efi_system_table_t *sys_table_arg, void *__fh,
81 efi_char16_t *filename_16, void **handle, u64 *file_sz)
82{
83 efi_file_handle_t *h, *fh = __fh;
84 efi_file_info_t *info;
85 efi_status_t status;
86 efi_guid_t info_guid = EFI_FILE_INFO_ID;
87 unsigned long info_sz;
88
89 status = fh->open(fh, &h, filename_16, EFI_FILE_MODE_READ, (u64)0);
90 if (status != EFI_SUCCESS) {
91 efi_printk(sys_table_arg, "Failed to open file: ");
92 efi_char16_printk(sys_table_arg, filename_16);
93 efi_printk(sys_table_arg, "\n");
94 return status;
95 }
96
97 *handle = h;
98
99 info_sz = 0;
100 status = h->get_info(h, &info_guid, &info_sz, NULL);
101 if (status != EFI_BUFFER_TOO_SMALL) {
102 efi_printk(sys_table_arg, "Failed to get file info size\n");
103 return status;
104 }
105
106grow:
107 status = sys_table_arg->boottime->allocate_pool(EFI_LOADER_DATA,
108 info_sz, (void **)&info);
109 if (status != EFI_SUCCESS) {
110 efi_printk(sys_table_arg, "Failed to alloc mem for file info\n");
111 return status;
112 }
113
114 status = h->get_info(h, &info_guid, &info_sz,
115 info);
116 if (status == EFI_BUFFER_TOO_SMALL) {
117 sys_table_arg->boottime->free_pool(info);
118 goto grow;
119 }
120
121 *file_sz = info->file_size;
122 sys_table_arg->boottime->free_pool(info);
123
124 if (status != EFI_SUCCESS)
125 efi_printk(sys_table_arg, "Failed to get initrd info\n");
126
127 return status;
128}
129
130
131
132static void efi_char16_printk(efi_system_table_t *sys_table_arg,
133 efi_char16_t *str)
134{
135 struct efi_simple_text_output_protocol *out;
136
137 out = (struct efi_simple_text_output_protocol *)sys_table_arg->con_out;
138 out->output_string(out, str);
139}
140
141
142/*
143 * This function handles the architcture specific differences between arm and
144 * arm64 regarding where the kernel image must be loaded and any memory that
145 * must be reserved. On failure it is required to free all
146 * all allocations it has made.
147 */
148static efi_status_t handle_kernel_image(efi_system_table_t *sys_table,
149 unsigned long *image_addr,
150 unsigned long *image_size,
151 unsigned long *reserve_addr,
152 unsigned long *reserve_size,
153 unsigned long dram_base,
154 efi_loaded_image_t *image);
155/*
156 * EFI entry point for the arm/arm64 EFI stubs. This is the entrypoint
157 * that is described in the PE/COFF header. Most of the code is the same
158 * for both archictectures, with the arch-specific code provided in the
159 * handle_kernel_image() function.
160 */
161unsigned long __init efi_entry(void *handle, efi_system_table_t *sys_table,
162 unsigned long *image_addr)
163{
164 efi_loaded_image_t *image;
165 efi_status_t status;
166 unsigned long image_size = 0;
167 unsigned long dram_base;
168 /* addr/point and size pairs for memory management*/
169 unsigned long initrd_addr;
170 u64 initrd_size = 0;
171 unsigned long fdt_addr = 0; /* Original DTB */
172 u64 fdt_size = 0; /* We don't get size from configuration table */
173 char *cmdline_ptr = NULL;
174 int cmdline_size = 0;
175 unsigned long new_fdt_addr;
176 efi_guid_t loaded_image_proto = LOADED_IMAGE_PROTOCOL_GUID;
177 unsigned long reserve_addr = 0;
178 unsigned long reserve_size = 0;
179
180 /* Check if we were booted by the EFI firmware */
181 if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
182 goto fail;
183
184 pr_efi(sys_table, "Booting Linux Kernel...\n");
185
186 /*
187 * Get a handle to the loaded image protocol. This is used to get
188 * information about the running image, such as size and the command
189 * line.
190 */
191 status = sys_table->boottime->handle_protocol(handle,
192 &loaded_image_proto, (void *)&image);
193 if (status != EFI_SUCCESS) {
194 pr_efi_err(sys_table, "Failed to get loaded image protocol\n");
195 goto fail;
196 }
197
198 dram_base = get_dram_base(sys_table);
199 if (dram_base == EFI_ERROR) {
200 pr_efi_err(sys_table, "Failed to find DRAM base\n");
201 goto fail;
202 }
203 status = handle_kernel_image(sys_table, image_addr, &image_size,
204 &reserve_addr,
205 &reserve_size,
206 dram_base, image);
207 if (status != EFI_SUCCESS) {
208 pr_efi_err(sys_table, "Failed to relocate kernel\n");
209 goto fail;
210 }
211
212 /*
213 * Get the command line from EFI, using the LOADED_IMAGE
214 * protocol. We are going to copy the command line into the
215 * device tree, so this can be allocated anywhere.
216 */
217 cmdline_ptr = efi_convert_cmdline(sys_table, image, &cmdline_size);
218 if (!cmdline_ptr) {
219 pr_efi_err(sys_table, "getting command line via LOADED_IMAGE_PROTOCOL\n");
220 goto fail_free_image;
221 }
222
223 /*
224 * Unauthenticated device tree data is a security hazard, so
225 * ignore 'dtb=' unless UEFI Secure Boot is disabled.
226 */
227 if (efi_secureboot_enabled(sys_table)) {
228 pr_efi(sys_table, "UEFI Secure Boot is enabled.\n");
229 } else {
230 status = handle_cmdline_files(sys_table, image, cmdline_ptr,
231 "dtb=",
232 ~0UL, (unsigned long *)&fdt_addr,
233 (unsigned long *)&fdt_size);
234
235 if (status != EFI_SUCCESS) {
236 pr_efi_err(sys_table, "Failed to load device tree!\n");
237 goto fail_free_cmdline;
238 }
239 }
240 if (!fdt_addr)
241 /* Look for a device tree configuration table entry. */
242 fdt_addr = (uintptr_t)get_fdt(sys_table);
243
244 status = handle_cmdline_files(sys_table, image, cmdline_ptr,
245 "initrd=", dram_base + SZ_512M,
246 (unsigned long *)&initrd_addr,
247 (unsigned long *)&initrd_size);
248 if (status != EFI_SUCCESS)
249 pr_efi_err(sys_table, "Failed initrd from command line!\n");
250
251 new_fdt_addr = fdt_addr;
252 status = allocate_new_fdt_and_exit_boot(sys_table, handle,
253 &new_fdt_addr, dram_base + MAX_FDT_OFFSET,
254 initrd_addr, initrd_size, cmdline_ptr,
255 fdt_addr, fdt_size);
256
257 /*
258 * If all went well, we need to return the FDT address to the
259 * calling function so it can be passed to kernel as part of
260 * the kernel boot protocol.
261 */
262 if (status == EFI_SUCCESS)
263 return new_fdt_addr;
264
265 pr_efi_err(sys_table, "Failed to update FDT and exit boot services\n");
266
267 efi_free(sys_table, initrd_size, initrd_addr);
268 efi_free(sys_table, fdt_size, fdt_addr);
269
270fail_free_cmdline:
271 efi_free(sys_table, cmdline_size, (unsigned long)cmdline_ptr);
272
273fail_free_image:
274 efi_free(sys_table, image_size, *image_addr);
275 efi_free(sys_table, reserve_size, reserve_addr);
276fail:
277 return EFI_ERROR;
278}
diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
index af20f1712337..cd36deb619fa 100644
--- a/drivers/firmware/efi/efi.c
+++ b/drivers/firmware/efi/efi.c
@@ -20,6 +20,8 @@
20#include <linux/init.h> 20#include <linux/init.h>
21#include <linux/device.h> 21#include <linux/device.h>
22#include <linux/efi.h> 22#include <linux/efi.h>
23#include <linux/of.h>
24#include <linux/of_fdt.h>
23#include <linux/io.h> 25#include <linux/io.h>
24 26
25struct efi __read_mostly efi = { 27struct efi __read_mostly efi = {
@@ -318,3 +320,80 @@ int __init efi_config_init(efi_config_table_type_t *arch_tables)
318 320
319 return 0; 321 return 0;
320} 322}
323
324#ifdef CONFIG_EFI_PARAMS_FROM_FDT
325
326#define UEFI_PARAM(name, prop, field) \
327 { \
328 { name }, \
329 { prop }, \
330 offsetof(struct efi_fdt_params, field), \
331 FIELD_SIZEOF(struct efi_fdt_params, field) \
332 }
333
334static __initdata struct {
335 const char name[32];
336 const char propname[32];
337 int offset;
338 int size;
339} dt_params[] = {
340 UEFI_PARAM("System Table", "linux,uefi-system-table", system_table),
341 UEFI_PARAM("MemMap Address", "linux,uefi-mmap-start", mmap),
342 UEFI_PARAM("MemMap Size", "linux,uefi-mmap-size", mmap_size),
343 UEFI_PARAM("MemMap Desc. Size", "linux,uefi-mmap-desc-size", desc_size),
344 UEFI_PARAM("MemMap Desc. Version", "linux,uefi-mmap-desc-ver", desc_ver)
345};
346
347struct param_info {
348 int verbose;
349 void *params;
350};
351
352static int __init fdt_find_uefi_params(unsigned long node, const char *uname,
353 int depth, void *data)
354{
355 struct param_info *info = data;
356 void *prop, *dest;
357 unsigned long len;
358 u64 val;
359 int i;
360
361 if (depth != 1 ||
362 (strcmp(uname, "chosen") != 0 && strcmp(uname, "chosen@0") != 0))
363 return 0;
364
365 pr_info("Getting parameters from FDT:\n");
366
367 for (i = 0; i < ARRAY_SIZE(dt_params); i++) {
368 prop = of_get_flat_dt_prop(node, dt_params[i].propname, &len);
369 if (!prop) {
370 pr_err("Can't find %s in device tree!\n",
371 dt_params[i].name);
372 return 0;
373 }
374 dest = info->params + dt_params[i].offset;
375
376 val = of_read_number(prop, len / sizeof(u32));
377
378 if (dt_params[i].size == sizeof(u32))
379 *(u32 *)dest = val;
380 else
381 *(u64 *)dest = val;
382
383 if (info->verbose)
384 pr_info(" %s: 0x%0*llx\n", dt_params[i].name,
385 dt_params[i].size * 2, val);
386 }
387 return 1;
388}
389
390int __init efi_get_fdt_params(struct efi_fdt_params *params, int verbose)
391{
392 struct param_info info;
393
394 info.verbose = verbose;
395 info.params = params;
396
397 return of_scan_flat_dt(fdt_find_uefi_params, &info);
398}
399#endif /* CONFIG_EFI_PARAMS_FROM_FDT */
diff --git a/drivers/firmware/efi/fdt.c b/drivers/firmware/efi/fdt.c
new file mode 100644
index 000000000000..5c6a8e8a9580
--- /dev/null
+++ b/drivers/firmware/efi/fdt.c
@@ -0,0 +1,285 @@
1/*
2 * FDT related Helper functions used by the EFI stub on multiple
3 * architectures. This should be #included by the EFI stub
4 * implementation files.
5 *
6 * Copyright 2013 Linaro Limited; author Roy Franz
7 *
8 * This file is part of the Linux kernel, and is made available
9 * under the terms of the GNU General Public License version 2.
10 *
11 */
12
13static efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt,
14 unsigned long orig_fdt_size,
15 void *fdt, int new_fdt_size, char *cmdline_ptr,
16 u64 initrd_addr, u64 initrd_size,
17 efi_memory_desc_t *memory_map,
18 unsigned long map_size, unsigned long desc_size,
19 u32 desc_ver)
20{
21 int node, prev;
22 int status;
23 u32 fdt_val32;
24 u64 fdt_val64;
25
26 /*
27 * Copy definition of linux_banner here. Since this code is
28 * built as part of the decompressor for ARM v7, pulling
29 * in version.c where linux_banner is defined for the
30 * kernel brings other kernel dependencies with it.
31 */
32 const char linux_banner[] =
33 "Linux version " UTS_RELEASE " (" LINUX_COMPILE_BY "@"
34 LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") " UTS_VERSION "\n";
35
36 /* Do some checks on provided FDT, if it exists*/
37 if (orig_fdt) {
38 if (fdt_check_header(orig_fdt)) {
39 pr_efi_err(sys_table, "Device Tree header not valid!\n");
40 return EFI_LOAD_ERROR;
41 }
42 /*
43 * We don't get the size of the FDT if we get if from a
44 * configuration table.
45 */
46 if (orig_fdt_size && fdt_totalsize(orig_fdt) > orig_fdt_size) {
47 pr_efi_err(sys_table, "Truncated device tree! foo!\n");
48 return EFI_LOAD_ERROR;
49 }
50 }
51
52 if (orig_fdt)
53 status = fdt_open_into(orig_fdt, fdt, new_fdt_size);
54 else
55 status = fdt_create_empty_tree(fdt, new_fdt_size);
56
57 if (status != 0)
58 goto fdt_set_fail;
59
60 /*
61 * Delete any memory nodes present. We must delete nodes which
62 * early_init_dt_scan_memory may try to use.
63 */
64 prev = 0;
65 for (;;) {
66 const char *type, *name;
67 int len;
68
69 node = fdt_next_node(fdt, prev, NULL);
70 if (node < 0)
71 break;
72
73 type = fdt_getprop(fdt, node, "device_type", &len);
74 if (type && strncmp(type, "memory", len) == 0) {
75 fdt_del_node(fdt, node);
76 continue;
77 }
78
79 prev = node;
80 }
81
82 node = fdt_subnode_offset(fdt, 0, "chosen");
83 if (node < 0) {
84 node = fdt_add_subnode(fdt, 0, "chosen");
85 if (node < 0) {
86 status = node; /* node is error code when negative */
87 goto fdt_set_fail;
88 }
89 }
90
91 if ((cmdline_ptr != NULL) && (strlen(cmdline_ptr) > 0)) {
92 status = fdt_setprop(fdt, node, "bootargs", cmdline_ptr,
93 strlen(cmdline_ptr) + 1);
94 if (status)
95 goto fdt_set_fail;
96 }
97
98 /* Set initrd address/end in device tree, if present */
99 if (initrd_size != 0) {
100 u64 initrd_image_end;
101 u64 initrd_image_start = cpu_to_fdt64(initrd_addr);
102
103 status = fdt_setprop(fdt, node, "linux,initrd-start",
104 &initrd_image_start, sizeof(u64));
105 if (status)
106 goto fdt_set_fail;
107 initrd_image_end = cpu_to_fdt64(initrd_addr + initrd_size);
108 status = fdt_setprop(fdt, node, "linux,initrd-end",
109 &initrd_image_end, sizeof(u64));
110 if (status)
111 goto fdt_set_fail;
112 }
113
114 /* Add FDT entries for EFI runtime services in chosen node. */
115 node = fdt_subnode_offset(fdt, 0, "chosen");
116 fdt_val64 = cpu_to_fdt64((u64)(unsigned long)sys_table);
117 status = fdt_setprop(fdt, node, "linux,uefi-system-table",
118 &fdt_val64, sizeof(fdt_val64));
119 if (status)
120 goto fdt_set_fail;
121
122 fdt_val64 = cpu_to_fdt64((u64)(unsigned long)memory_map);
123 status = fdt_setprop(fdt, node, "linux,uefi-mmap-start",
124 &fdt_val64, sizeof(fdt_val64));
125 if (status)
126 goto fdt_set_fail;
127
128 fdt_val32 = cpu_to_fdt32(map_size);
129 status = fdt_setprop(fdt, node, "linux,uefi-mmap-size",
130 &fdt_val32, sizeof(fdt_val32));
131 if (status)
132 goto fdt_set_fail;
133
134 fdt_val32 = cpu_to_fdt32(desc_size);
135 status = fdt_setprop(fdt, node, "linux,uefi-mmap-desc-size",
136 &fdt_val32, sizeof(fdt_val32));
137 if (status)
138 goto fdt_set_fail;
139
140 fdt_val32 = cpu_to_fdt32(desc_ver);
141 status = fdt_setprop(fdt, node, "linux,uefi-mmap-desc-ver",
142 &fdt_val32, sizeof(fdt_val32));
143 if (status)
144 goto fdt_set_fail;
145
146 /*
147 * Add kernel version banner so stub/kernel match can be
148 * verified.
149 */
150 status = fdt_setprop_string(fdt, node, "linux,uefi-stub-kern-ver",
151 linux_banner);
152 if (status)
153 goto fdt_set_fail;
154
155 return EFI_SUCCESS;
156
157fdt_set_fail:
158 if (status == -FDT_ERR_NOSPACE)
159 return EFI_BUFFER_TOO_SMALL;
160
161 return EFI_LOAD_ERROR;
162}
163
164#ifndef EFI_FDT_ALIGN
165#define EFI_FDT_ALIGN EFI_PAGE_SIZE
166#endif
167
168/*
169 * Allocate memory for a new FDT, then add EFI, commandline, and
170 * initrd related fields to the FDT. This routine increases the
171 * FDT allocation size until the allocated memory is large
172 * enough. EFI allocations are in EFI_PAGE_SIZE granules,
173 * which are fixed at 4K bytes, so in most cases the first
174 * allocation should succeed.
175 * EFI boot services are exited at the end of this function.
176 * There must be no allocations between the get_memory_map()
177 * call and the exit_boot_services() call, so the exiting of
178 * boot services is very tightly tied to the creation of the FDT
179 * with the final memory map in it.
180 */
181
182efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table,
183 void *handle,
184 unsigned long *new_fdt_addr,
185 unsigned long max_addr,
186 u64 initrd_addr, u64 initrd_size,
187 char *cmdline_ptr,
188 unsigned long fdt_addr,
189 unsigned long fdt_size)
190{
191 unsigned long map_size, desc_size;
192 u32 desc_ver;
193 unsigned long mmap_key;
194 efi_memory_desc_t *memory_map;
195 unsigned long new_fdt_size;
196 efi_status_t status;
197
198 /*
199 * Estimate size of new FDT, and allocate memory for it. We
200 * will allocate a bigger buffer if this ends up being too
201 * small, so a rough guess is OK here.
202 */
203 new_fdt_size = fdt_size + EFI_PAGE_SIZE;
204 while (1) {
205 status = efi_high_alloc(sys_table, new_fdt_size, EFI_FDT_ALIGN,
206 new_fdt_addr, max_addr);
207 if (status != EFI_SUCCESS) {
208 pr_efi_err(sys_table, "Unable to allocate memory for new device tree.\n");
209 goto fail;
210 }
211
212 /*
213 * Now that we have done our final memory allocation (and free)
214 * we can get the memory map key needed for
215 * exit_boot_services().
216 */
217 status = efi_get_memory_map(sys_table, &memory_map, &map_size,
218 &desc_size, &desc_ver, &mmap_key);
219 if (status != EFI_SUCCESS)
220 goto fail_free_new_fdt;
221
222 status = update_fdt(sys_table,
223 (void *)fdt_addr, fdt_size,
224 (void *)*new_fdt_addr, new_fdt_size,
225 cmdline_ptr, initrd_addr, initrd_size,
226 memory_map, map_size, desc_size, desc_ver);
227
228 /* Succeeding the first time is the expected case. */
229 if (status == EFI_SUCCESS)
230 break;
231
232 if (status == EFI_BUFFER_TOO_SMALL) {
233 /*
234 * We need to allocate more space for the new
235 * device tree, so free existing buffer that is
236 * too small. Also free memory map, as we will need
237 * to get new one that reflects the free/alloc we do
238 * on the device tree buffer.
239 */
240 efi_free(sys_table, new_fdt_size, *new_fdt_addr);
241 sys_table->boottime->free_pool(memory_map);
242 new_fdt_size += EFI_PAGE_SIZE;
243 } else {
244 pr_efi_err(sys_table, "Unable to constuct new device tree.\n");
245 goto fail_free_mmap;
246 }
247 }
248
249 /* Now we are ready to exit_boot_services.*/
250 status = sys_table->boottime->exit_boot_services(handle, mmap_key);
251
252
253 if (status == EFI_SUCCESS)
254 return status;
255
256 pr_efi_err(sys_table, "Exit boot services failed.\n");
257
258fail_free_mmap:
259 sys_table->boottime->free_pool(memory_map);
260
261fail_free_new_fdt:
262 efi_free(sys_table, new_fdt_size, *new_fdt_addr);
263
264fail:
265 return EFI_LOAD_ERROR;
266}
267
268static void *get_fdt(efi_system_table_t *sys_table)
269{
270 efi_guid_t fdt_guid = DEVICE_TREE_GUID;
271 efi_config_table_t *tables;
272 void *fdt;
273 int i;
274
275 tables = (efi_config_table_t *) sys_table->tables;
276 fdt = NULL;
277
278 for (i = 0; i < sys_table->nr_tables; i++)
279 if (efi_guidcmp(tables[i].guid, fdt_guid) == 0) {
280 fdt = (void *) tables[i].table;
281 break;
282 }
283
284 return fdt;
285}
diff --git a/include/linux/efi.h b/include/linux/efi.h
index 6a4d8e27d1d7..41bbf8ba4ba8 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -575,6 +575,9 @@ typedef efi_status_t efi_query_variable_store_t(u32 attributes, unsigned long si
575#define EFI_FILE_SYSTEM_GUID \ 575#define EFI_FILE_SYSTEM_GUID \
576 EFI_GUID( 0x964e5b22, 0x6459, 0x11d2, 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b ) 576 EFI_GUID( 0x964e5b22, 0x6459, 0x11d2, 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b )
577 577
578#define DEVICE_TREE_GUID \
579 EFI_GUID( 0xb1b621d5, 0xf19c, 0x41a5, 0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0 )
580
578typedef struct { 581typedef struct {
579 efi_guid_t guid; 582 efi_guid_t guid;
580 u64 table; 583 u64 table;
@@ -664,6 +667,14 @@ struct efi_memory_map {
664 unsigned long desc_size; 667 unsigned long desc_size;
665}; 668};
666 669
670struct efi_fdt_params {
671 u64 system_table;
672 u64 mmap;
673 u32 mmap_size;
674 u32 desc_size;
675 u32 desc_ver;
676};
677
667typedef struct { 678typedef struct {
668 u32 revision; 679 u32 revision;
669 u32 parent_handle; 680 u32 parent_handle;
@@ -861,6 +872,7 @@ extern void efi_initialize_iomem_resources(struct resource *code_resource,
861extern void efi_get_time(struct timespec *now); 872extern void efi_get_time(struct timespec *now);
862extern int efi_set_rtc_mmss(const struct timespec *now); 873extern int efi_set_rtc_mmss(const struct timespec *now);
863extern void efi_reserve_boot_services(void); 874extern void efi_reserve_boot_services(void);
875extern int efi_get_fdt_params(struct efi_fdt_params *params, int verbose);
864extern struct efi_memory_map memmap; 876extern struct efi_memory_map memmap;
865 877
866/* Iterate through an efi_memory_map */ 878/* Iterate through an efi_memory_map */
diff --git a/lib/Makefile b/lib/Makefile
index 0cd7b68e1382..74a32dc49a93 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -148,7 +148,8 @@ obj-$(CONFIG_GENERIC_NET_UTILS) += net_utils.o
148 148
149obj-$(CONFIG_STMP_DEVICE) += stmp_device.o 149obj-$(CONFIG_STMP_DEVICE) += stmp_device.o
150 150
151libfdt_files = fdt.o fdt_ro.o fdt_wip.o fdt_rw.o fdt_sw.o fdt_strerror.o 151libfdt_files = fdt.o fdt_ro.o fdt_wip.o fdt_rw.o fdt_sw.o fdt_strerror.o \
152 fdt_empty_tree.o
152$(foreach file, $(libfdt_files), \ 153$(foreach file, $(libfdt_files), \
153 $(eval CFLAGS_$(file) = -I$(src)/../scripts/dtc/libfdt)) 154 $(eval CFLAGS_$(file) = -I$(src)/../scripts/dtc/libfdt))
154lib-$(CONFIG_LIBFDT) += $(libfdt_files) 155lib-$(CONFIG_LIBFDT) += $(libfdt_files)
diff --git a/lib/fdt_empty_tree.c b/lib/fdt_empty_tree.c
new file mode 100644
index 000000000000..5d30c58150ad
--- /dev/null
+++ b/lib/fdt_empty_tree.c
@@ -0,0 +1,2 @@
1#include <linux/libfdt_env.h>
2#include "../scripts/dtc/libfdt/fdt_empty_tree.c"