diff options
-rw-r--r-- | Documentation/arm/00-INDEX | 2 | ||||
-rw-r--r-- | Documentation/arm/uefi.txt | 64 | ||||
-rw-r--r-- | Documentation/arm64/booting.txt | 4 | ||||
-rw-r--r-- | Documentation/efi-stub.txt | 33 | ||||
-rw-r--r-- | arch/arm64/Kconfig | 16 | ||||
-rw-r--r-- | arch/arm64/include/asm/efi.h | 14 | ||||
-rw-r--r-- | arch/arm64/include/asm/mmu.h | 2 | ||||
-rw-r--r-- | arch/arm64/kernel/Makefile | 3 | ||||
-rw-r--r-- | arch/arm64/kernel/efi-entry.S | 109 | ||||
-rw-r--r-- | arch/arm64/kernel/efi-stub.c | 81 | ||||
-rw-r--r-- | arch/arm64/kernel/efi.c | 469 | ||||
-rw-r--r-- | arch/arm64/kernel/head.S | 112 | ||||
-rw-r--r-- | arch/arm64/kernel/setup.c | 5 | ||||
-rw-r--r-- | arch/arm64/mm/mmu.c | 65 | ||||
-rw-r--r-- | drivers/firmware/efi/Kconfig | 7 | ||||
-rw-r--r-- | drivers/firmware/efi/arm-stub.c | 278 | ||||
-rw-r--r-- | drivers/firmware/efi/efi.c | 79 | ||||
-rw-r--r-- | drivers/firmware/efi/fdt.c | 285 | ||||
-rw-r--r-- | include/linux/efi.h | 12 | ||||
-rw-r--r-- | lib/Makefile | 3 | ||||
-rw-r--r-- | lib/fdt_empty_tree.c | 2 |
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 |
47 | tcm.txt | 47 | tcm.txt |
48 | - ARM Tightly Coupled Memory | 48 | - ARM Tightly Coupled Memory |
49 | uefi.txt | ||
50 | - [U]EFI configuration and runtime services documentation | ||
49 | vlocks.txt | 51 | vlocks.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 @@ | |||
1 | UEFI, the Unified Extensible Firmware Interface, is a specification | ||
2 | governing the behaviours of compatible firmware interfaces. It is | ||
3 | maintained by the UEFI Forum - http://www.uefi.org/. | ||
4 | |||
5 | UEFI is an evolution of its predecessor 'EFI', so the terms EFI and | ||
6 | UEFI are used somewhat interchangeably in this document and associated | ||
7 | source code. As a rule, anything new uses 'UEFI', whereas 'EFI' refers | ||
8 | to legacy code or specifications. | ||
9 | |||
10 | UEFI support in Linux | ||
11 | ===================== | ||
12 | Booting on a platform with firmware compliant with the UEFI specification | ||
13 | makes 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 | |||
18 | For actually enabling [U]EFI support, enable: | ||
19 | - CONFIG_EFI=y | ||
20 | - CONFIG_EFI_VARS=y or m | ||
21 | |||
22 | The implementation depends on receiving information about the UEFI environment | ||
23 | in a Flattened Device Tree (FDT) - so is only available with CONFIG_OF. | ||
24 | |||
25 | UEFI stub | ||
26 | ========= | ||
27 | The "stub" is a feature that extends the Image/zImage into a valid UEFI | ||
28 | PE/COFF executable, including a loader application that makes it possible to | ||
29 | load the kernel directly from the UEFI shell, boot menu, or one of the | ||
30 | lightweight bootloaders like Gummiboot or rEFInd. | ||
31 | |||
32 | The kernel image built with stub support remains a valid kernel image for | ||
33 | booting in non-UEFI environments. | ||
34 | |||
35 | UEFI kernel support on ARM | ||
36 | ========================== | ||
37 | UEFI kernel support on the ARM architectures (arm and arm64) is only available | ||
38 | when boot is performed through the stub. | ||
39 | |||
40 | When booting in UEFI mode, the stub deletes any memory nodes from a provided DT. | ||
41 | Instead, the kernel reads the UEFI memory map. | ||
42 | |||
43 | The stub populates the FDT /chosen node with (and the kernel scans for) the | ||
44 | following parameters: | ||
45 | ________________________________________________________________________________ | ||
46 | Name | Size | Description | ||
47 | ================================================================================ | ||
48 | linux,uefi-system-table | 64-bit | Physical address of the UEFI System Table. | ||
49 | -------------------------------------------------------------------------------- | ||
50 | linux,uefi-mmap-start | 64-bit | Physical address of the UEFI memory map, | ||
51 | | | populated by the UEFI GetMemoryMap() call. | ||
52 | -------------------------------------------------------------------------------- | ||
53 | linux,uefi-mmap-size | 32-bit | Size in bytes of the UEFI memory map | ||
54 | | | pointed to in previous entry. | ||
55 | -------------------------------------------------------------------------------- | ||
56 | linux,uefi-mmap-desc-size | 32-bit | Size in bytes of each entry in the UEFI | ||
57 | | | memory map. | ||
58 | -------------------------------------------------------------------------------- | ||
59 | linux,uefi-mmap-desc-ver | 32-bit | Version of the mmap descriptor format. | ||
60 | -------------------------------------------------------------------------------- | ||
61 | linux,uefi-stub-kern-ver | string | Copy of linux_banner from build. | ||
62 | -------------------------------------------------------------------------------- | ||
63 | |||
64 | For 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: | |||
85 | Header notes: | 85 | Header 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 | ||
89 | The image must be placed at the specified offset (currently 0x80000) | 93 | The image must be placed at the specified offset (currently 0x80000) |
90 | from the start of the system RAM and called there. The start of the | 94 | from 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 | ||
4 | On the x86 platform, a bzImage can masquerade as a PE/COFF image, | 4 | On the x86 and ARM platforms, a kernel zImage/bzImage can masquerade |
5 | thereby convincing EFI firmware loaders to load it as an EFI | 5 | as a PE/COFF image, thereby convincing EFI firmware loaders to load |
6 | executable. The code that modifies the bzImage header, along with the | 6 | it as an EFI executable. The code that modifies the bzImage header, |
7 | EFI-specific entry point that the firmware loader jumps to are | 7 | along with the EFI-specific entry point that the firmware loader |
8 | collectively known as the "EFI boot stub", and live in | 8 | jumps to are collectively known as the "EFI boot stub", and live in |
9 | arch/x86/boot/header.S and arch/x86/boot/compressed/eboot.c, | 9 | arch/x86/boot/header.S and arch/x86/boot/compressed/eboot.c, |
10 | respectively. | 10 | respectively. For ARM the EFI stub is implemented in |
11 | arch/arm/boot/compressed/efi-header.S and | ||
12 | arch/arm/boot/compressed/efi-stub.c. EFI stub code that is shared | ||
13 | between architectures is in drivers/firmware/efi/efi-stub-helper.c. | ||
14 | |||
15 | For arm64, there is no compressed kernel support, so the Image itself | ||
16 | masquerades as a PE/COFF image and the EFI stub is linked into the | ||
17 | kernel. The arm64 EFI stub lives in arch/arm64/kernel/efi-entry.S | ||
18 | and arch/arm64/kernel/efi-stub.c. | ||
11 | 19 | ||
12 | By using the EFI boot stub it's possible to boot a Linux kernel | 20 | By using the EFI boot stub it's possible to boot a Linux kernel |
13 | without the use of a conventional EFI boot loader, such as grub or | 21 | without 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 | |||
23 | System Partition (ESP) and renamed with the extension ".efi". Without | 31 | System Partition (ESP) and renamed with the extension ".efi". Without |
24 | the extension the EFI firmware loader will refuse to execute it. It's | 32 | the extension the EFI firmware loader will refuse to execute it. It's |
25 | not possible to execute bzImage.efi from the usual Linux file systems | 33 | not possible to execute bzImage.efi from the usual Linux file systems |
26 | because EFI firmware doesn't have support for them. | 34 | because EFI firmware doesn't have support for them. For ARM the |
35 | arch/arm/boot/zImage should be copied to the system partition, and it | ||
36 | may not need to be renamed. Similarly for arm64, arch/arm64/boot/Image | ||
37 | should 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 | |||
63 | because the image we're executing is interpreted by the EFI shell, | 74 | because the image we're executing is interpreted by the EFI shell, |
64 | which understands relative paths, whereas the rest of the command line | 75 | which understands relative paths, whereas the rest of the command line |
65 | is passed to bzImage.efi. | 76 | is passed to bzImage.efi. |
77 | |||
78 | |||
79 | **** The "dtb=" option | ||
80 | |||
81 | For the ARM and arm64 architectures, we also need to be able to provide a | ||
82 | device tree to the kernel. This is done with the "dtb=" command line option, | ||
83 | and is processed in the same manner as the "initrd=" option that is | ||
84 | described 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 | ||
286 | config 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 | |||
286 | endmenu | 300 | endmenu |
287 | 301 | ||
288 | menu "Userspace binary formats" | 302 | menu "Userspace binary formats" |
@@ -334,6 +348,8 @@ source "net/Kconfig" | |||
334 | 348 | ||
335 | source "drivers/Kconfig" | 349 | source "drivers/Kconfig" |
336 | 350 | ||
351 | source "drivers/firmware/Kconfig" | ||
352 | |||
337 | source "fs/Kconfig" | 353 | source "fs/Kconfig" |
338 | 354 | ||
339 | source "arch/arm64/kvm/Kconfig" | 355 | source "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 | ||
7 | extern void efi_init(void); | ||
8 | extern 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); | |||
31 | extern void setup_mm_for_reboot(void); | 31 | extern void setup_mm_for_reboot(void); |
32 | extern void __iomem *early_io_map(phys_addr_t phys, unsigned long virt); | 32 | extern void __iomem *early_io_map(phys_addr_t phys, unsigned long virt); |
33 | extern void init_mem_pgprot(void); | 33 | extern void init_mem_pgprot(void); |
34 | /* create an identity mapping for memory (or io if map_io is true) */ | ||
35 | extern 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 | ||
5 | CPPFLAGS_vmlinux.lds := -DTEXT_OFFSET=$(TEXT_OFFSET) | 5 | CPPFLAGS_vmlinux.lds := -DTEXT_OFFSET=$(TEXT_OFFSET) |
6 | AFLAGS_head.o := -DTEXT_OFFSET=$(TEXT_OFFSET) | 6 | AFLAGS_head.o := -DTEXT_OFFSET=$(TEXT_OFFSET) |
7 | CFLAGS_efi-stub.o := -DTEXT_OFFSET=$(TEXT_OFFSET) \ | ||
8 | -I$(src)/../../../scripts/dtc/libfdt | ||
7 | 9 | ||
8 | # Object file lists. | 10 | # Object file lists. |
9 | arm64-obj-y := cputable.o debug-monitors.o entry.o irq.o fpsimd.o \ | 11 | arm64-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 | |||
21 | arm64-obj-$(CONFIG_ARM64_CPU_SUSPEND) += sleep.o suspend.o | 23 | arm64-obj-$(CONFIG_ARM64_CPU_SUSPEND) += sleep.o suspend.o |
22 | arm64-obj-$(CONFIG_JUMP_LABEL) += jump_label.o | 24 | arm64-obj-$(CONFIG_JUMP_LABEL) += jump_label.o |
23 | arm64-obj-$(CONFIG_KGDB) += kgdb.o | 25 | arm64-obj-$(CONFIG_KGDB) += kgdb.o |
26 | arm64-obj-$(CONFIG_EFI) += efi.o efi-stub.o efi-entry.o | ||
24 | 27 | ||
25 | obj-y += $(arm64-obj-y) vdso/ | 28 | obj-y += $(arm64-obj-y) vdso/ |
26 | obj-m += $(arm64-obj-m) | 29 | obj-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 | */ | ||
32 | ENTRY(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 | ||
90 | 1: | ||
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 | ||
96 | 2: | ||
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 | |||
104 | efi_load_fail: | ||
105 | mov x0, #EFI_LOAD_ERROR | ||
106 | ldp x29, x30, [sp], #32 | ||
107 | ret | ||
108 | |||
109 | ENDPROC(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 | |||
28 | static void efi_char16_printk(efi_system_table_t *sys_table_arg, | ||
29 | efi_char16_t *str); | ||
30 | |||
31 | static efi_status_t efi_open_volume(efi_system_table_t *sys_table, | ||
32 | void *__image, void **__fh); | ||
33 | static efi_status_t efi_file_close(void *handle); | ||
34 | |||
35 | static efi_status_t | ||
36 | efi_file_read(void *handle, unsigned long *size, void *addr); | ||
37 | |||
38 | static efi_status_t | ||
39 | efi_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 | |||
48 | static 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 | |||
28 | struct efi_memory_map memmap; | ||
29 | |||
30 | static efi_runtime_services_t *runtime; | ||
31 | |||
32 | static u64 efi_system_table; | ||
33 | |||
34 | static int uefi_debug __initdata; | ||
35 | static int __init uefi_debug_setup(char *str) | ||
36 | { | ||
37 | uefi_debug = 1; | ||
38 | |||
39 | return 0; | ||
40 | } | ||
41 | early_param("uefi_debug", uefi_debug_setup); | ||
42 | |||
43 | static 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 | |||
50 | static 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 | |||
71 | static 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 | |||
122 | static __initdata char memory_type_name[][32] = { | ||
123 | {"Reserved"}, | ||
124 | {"Loader Code"}, | ||
125 | {"Loader Data"}, | ||
126 | {"Boot Code"}, | ||
127 | {"Boot Data"}, | ||
128 | {"Runtime Code"}, | ||
129 | {"Runtime Data"}, | ||
130 | {"Conventional Memory"}, | ||
131 | {"Unusable Memory"}, | ||
132 | {"ACPI Reclaim Memory"}, | ||
133 | {"ACPI Memory NVS"}, | ||
134 | {"Memory Mapped I/O"}, | ||
135 | {"MMIO Port Space"}, | ||
136 | {"PAL Code"}, | ||
137 | }; | ||
138 | |||
139 | /* | ||
140 | * Return true for RAM regions we want to permanently reserve. | ||
141 | */ | ||
142 | static __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 | |||
157 | static __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 | |||
194 | static 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 | |||
205 | static 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 | |||
229 | static 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 | |||
310 | void __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(¶ms, 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 | |||
334 | void __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 | |||
343 | static 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 | */ | ||
379 | static 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 | } | ||
469 | early_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 | ||
112 | efi_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 | ||
141 | pe_header: | ||
142 | .ascii "PE" | ||
143 | .short 0 | ||
144 | coff_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 | ||
155 | optional_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 | |||
165 | extra_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 | ||
199 | section_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 | ||
125 | ENTRY(stext) | 237 | ENTRY(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 | ||
59 | unsigned int processor_id; | 61 | unsigned int processor_id; |
60 | EXPORT_SYMBOL(processor_id); | 62 | EXPORT_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 | ||
170 | static void __init alloc_init_pte(pmd_t *pmd, unsigned long addr, | 170 | static 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 | ||
188 | static void __init alloc_init_pmd(pud_t *pud, unsigned long addr, | 189 | static 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 | ||
222 | static void __init alloc_init_pud(pgd_t *pgd, unsigned long addr, | 236 | static 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 | */ |
239 | static void __init create_mapping(phys_addr_t phys, unsigned long virt, | 254 | static 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 | ||
271 | static 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 | |||
282 | void __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 | |||
263 | static void __init map_mem(void) | 292 | static 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 | ||
50 | config 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 | |||
50 | endmenu | 57 | endmenu |
51 | 58 | ||
52 | config UEFI_CPER | 59 | config 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 | |||
15 | static 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 | |||
39 | static 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 | } | ||
63 | static efi_status_t efi_file_close(void *handle) | ||
64 | { | ||
65 | efi_file_handle_t *fh = handle; | ||
66 | |||
67 | return fh->close(handle); | ||
68 | } | ||
69 | |||
70 | static efi_status_t | ||
71 | efi_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 | |||
79 | static efi_status_t | ||
80 | efi_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 | |||
106 | grow: | ||
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 | |||
132 | static 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 | */ | ||
148 | static 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 | */ | ||
161 | unsigned 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 | |||
270 | fail_free_cmdline: | ||
271 | efi_free(sys_table, cmdline_size, (unsigned long)cmdline_ptr); | ||
272 | |||
273 | fail_free_image: | ||
274 | efi_free(sys_table, image_size, *image_addr); | ||
275 | efi_free(sys_table, reserve_size, reserve_addr); | ||
276 | fail: | ||
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 | ||
25 | struct efi __read_mostly efi = { | 27 | struct 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 | |||
334 | static __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 | |||
347 | struct param_info { | ||
348 | int verbose; | ||
349 | void *params; | ||
350 | }; | ||
351 | |||
352 | static 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 | |||
390 | int __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 | |||
13 | static 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 | |||
157 | fdt_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 | |||
182 | efi_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 | |||
258 | fail_free_mmap: | ||
259 | sys_table->boottime->free_pool(memory_map); | ||
260 | |||
261 | fail_free_new_fdt: | ||
262 | efi_free(sys_table, new_fdt_size, *new_fdt_addr); | ||
263 | |||
264 | fail: | ||
265 | return EFI_LOAD_ERROR; | ||
266 | } | ||
267 | |||
268 | static 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 | |||
578 | typedef struct { | 581 | typedef 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 | ||
670 | struct efi_fdt_params { | ||
671 | u64 system_table; | ||
672 | u64 mmap; | ||
673 | u32 mmap_size; | ||
674 | u32 desc_size; | ||
675 | u32 desc_ver; | ||
676 | }; | ||
677 | |||
667 | typedef struct { | 678 | typedef 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, | |||
861 | extern void efi_get_time(struct timespec *now); | 872 | extern void efi_get_time(struct timespec *now); |
862 | extern int efi_set_rtc_mmss(const struct timespec *now); | 873 | extern int efi_set_rtc_mmss(const struct timespec *now); |
863 | extern void efi_reserve_boot_services(void); | 874 | extern void efi_reserve_boot_services(void); |
875 | extern int efi_get_fdt_params(struct efi_fdt_params *params, int verbose); | ||
864 | extern struct efi_memory_map memmap; | 876 | extern 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 | ||
149 | obj-$(CONFIG_STMP_DEVICE) += stmp_device.o | 149 | obj-$(CONFIG_STMP_DEVICE) += stmp_device.o |
150 | 150 | ||
151 | libfdt_files = fdt.o fdt_ro.o fdt_wip.o fdt_rw.o fdt_sw.o fdt_strerror.o | 151 | libfdt_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)) |
154 | lib-$(CONFIG_LIBFDT) += $(libfdt_files) | 155 | lib-$(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" | ||