aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoy Franz <roy.franz@linaro.org>2015-09-23 23:17:54 -0400
committerard <ard.biesheuvel@linaro.org>2015-12-14 04:38:21 -0500
commit81a0bc39ea1960bbf8ece6a895d7cfd2d9efa28a (patch)
tree58f4c5c73cc4292b242dce2e0018511f9e18e39e
parentda58fb6571bf40e5b2287d6aa3bbca04965f5677 (diff)
ARM: add UEFI stub support
This patch adds EFI stub support for the ARM Linux kernel. The EFI stub operates similarly to the x86 and arm64 stubs: it is a shim between the EFI firmware and the normal zImage entry point, and sets up the environment that the zImage is expecting. This includes optionally loading the initrd and device tree from the system partition based on the kernel command line. Signed-off-by: Roy Franz <roy.franz@linaro.org> Tested-by: Ryan Harkin <ryan.harkin@linaro.org> Reviewed-by: Matt Fleming <matt@codeblueprint.co.uk> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
-rw-r--r--arch/arm/Kconfig19
-rw-r--r--arch/arm/boot/compressed/Makefile4
-rw-r--r--arch/arm/boot/compressed/efi-header.S130
-rw-r--r--arch/arm/boot/compressed/head.S54
-rw-r--r--arch/arm/boot/compressed/vmlinux.lds.S7
-rw-r--r--arch/arm/include/asm/efi.h23
-rw-r--r--drivers/firmware/efi/libstub/Makefile9
-rw-r--r--drivers/firmware/efi/libstub/arm-stub.c4
-rw-r--r--drivers/firmware/efi/libstub/arm32-stub.c85
9 files changed, 331 insertions, 4 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 446e49b56e6a..67f8303d513d 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -2041,6 +2041,25 @@ config AUTO_ZRELADDR
2041 0xf8000000. This assumes the zImage being placed in the first 128MB 2041 0xf8000000. This assumes the zImage being placed in the first 128MB
2042 from start of memory. 2042 from start of memory.
2043 2043
2044config EFI_STUB
2045 bool
2046
2047config EFI
2048 bool "UEFI runtime support"
2049 depends on OF && !CPU_BIG_ENDIAN && MMU && AUTO_ZRELADDR && !XIP_KERNEL
2050 select UCS2_STRING
2051 select EFI_PARAMS_FROM_FDT
2052 select EFI_STUB
2053 select EFI_ARMSTUB
2054 select EFI_RUNTIME_WRAPPERS
2055 ---help---
2056 This option provides support for runtime services provided
2057 by UEFI firmware (such as non-volatile variables, realtime
2058 clock, and platform reset). A UEFI stub is also provided to
2059 allow the kernel to be booted as an EFI application. This
2060 is only useful for kernels that may run on systems that have
2061 UEFI firmware.
2062
2044endmenu 2063endmenu
2045 2064
2046menu "CPU Power Management" 2065menu "CPU Power Management"
diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile
index 3f9a9ebc77c3..4c23a68a0917 100644
--- a/arch/arm/boot/compressed/Makefile
+++ b/arch/arm/boot/compressed/Makefile
@@ -167,9 +167,11 @@ if [ $(words $(ZRELADDR)) -gt 1 -a "$(CONFIG_AUTO_ZRELADDR)" = "" ]; then \
167 false; \ 167 false; \
168fi 168fi
169 169
170efi-obj-$(CONFIG_EFI_STUB) := $(objtree)/drivers/firmware/efi/libstub/lib.a
171
170$(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/$(HEAD) $(obj)/piggy.$(suffix_y).o \ 172$(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/$(HEAD) $(obj)/piggy.$(suffix_y).o \
171 $(addprefix $(obj)/, $(OBJS)) $(lib1funcs) $(ashldi3) \ 173 $(addprefix $(obj)/, $(OBJS)) $(lib1funcs) $(ashldi3) \
172 $(bswapsdi2) FORCE 174 $(bswapsdi2) $(efi-obj-y) FORCE
173 @$(check_for_multiple_zreladdr) 175 @$(check_for_multiple_zreladdr)
174 $(call if_changed,ld) 176 $(call if_changed,ld)
175 @$(check_for_bad_syms) 177 @$(check_for_bad_syms)
diff --git a/arch/arm/boot/compressed/efi-header.S b/arch/arm/boot/compressed/efi-header.S
new file mode 100644
index 000000000000..9d5dc4fda3c1
--- /dev/null
+++ b/arch/arm/boot/compressed/efi-header.S
@@ -0,0 +1,130 @@
1/*
2 * Copyright (C) 2013-2015 Linaro Ltd
3 * Authors: Roy Franz <roy.franz@linaro.org>
4 * Ard Biesheuvel <ard.biesheuvel@linaro.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
11 .macro __nop
12#ifdef CONFIG_EFI_STUB
13 @ This is almost but not quite a NOP, since it does clobber the
14 @ condition flags. But it is the best we can do for EFI, since
15 @ PE/COFF expects the magic string "MZ" at offset 0, while the
16 @ ARM/Linux boot protocol expects an executable instruction
17 @ there.
18 .inst 'M' | ('Z' << 8) | (0x1310 << 16) @ tstne r0, #0x4d000
19#else
20 mov r0, r0
21#endif
22 .endm
23
24 .macro __EFI_HEADER
25#ifdef CONFIG_EFI_STUB
26 b __efi_start
27
28 .set start_offset, __efi_start - start
29 .org start + 0x3c
30 @
31 @ The PE header can be anywhere in the file, but for
32 @ simplicity we keep it together with the MSDOS header
33 @ The offset to the PE/COFF header needs to be at offset
34 @ 0x3C in the MSDOS header.
35 @ The only 2 fields of the MSDOS header that are used are this
36 @ PE/COFF offset, and the "MZ" bytes at offset 0x0.
37 @
38 .long pe_header - start @ Offset to the PE header.
39
40pe_header:
41 .ascii "PE\0\0"
42
43coff_header:
44 .short 0x01c2 @ ARM or Thumb
45 .short 2 @ nr_sections
46 .long 0 @ TimeDateStamp
47 .long 0 @ PointerToSymbolTable
48 .long 1 @ NumberOfSymbols
49 .short section_table - optional_header
50 @ SizeOfOptionalHeader
51 .short 0x306 @ Characteristics.
52 @ IMAGE_FILE_32BIT_MACHINE |
53 @ IMAGE_FILE_DEBUG_STRIPPED |
54 @ IMAGE_FILE_EXECUTABLE_IMAGE |
55 @ IMAGE_FILE_LINE_NUMS_STRIPPED
56
57optional_header:
58 .short 0x10b @ PE32 format
59 .byte 0x02 @ MajorLinkerVersion
60 .byte 0x14 @ MinorLinkerVersion
61 .long _end - __efi_start @ SizeOfCode
62 .long 0 @ SizeOfInitializedData
63 .long 0 @ SizeOfUninitializedData
64 .long efi_stub_entry - start @ AddressOfEntryPoint
65 .long start_offset @ BaseOfCode
66 .long 0 @ data
67
68extra_header_fields:
69 .long 0 @ ImageBase
70 .long 0x200 @ SectionAlignment
71 .long 0x200 @ FileAlignment
72 .short 0 @ MajorOperatingSystemVersion
73 .short 0 @ MinorOperatingSystemVersion
74 .short 0 @ MajorImageVersion
75 .short 0 @ MinorImageVersion
76 .short 0 @ MajorSubsystemVersion
77 .short 0 @ MinorSubsystemVersion
78 .long 0 @ Win32VersionValue
79
80 .long _end - start @ SizeOfImage
81 .long start_offset @ SizeOfHeaders
82 .long 0 @ CheckSum
83 .short 0xa @ Subsystem (EFI application)
84 .short 0 @ DllCharacteristics
85 .long 0 @ SizeOfStackReserve
86 .long 0 @ SizeOfStackCommit
87 .long 0 @ SizeOfHeapReserve
88 .long 0 @ SizeOfHeapCommit
89 .long 0 @ LoaderFlags
90 .long 0x6 @ NumberOfRvaAndSizes
91
92 .quad 0 @ ExportTable
93 .quad 0 @ ImportTable
94 .quad 0 @ ResourceTable
95 .quad 0 @ ExceptionTable
96 .quad 0 @ CertificationTable
97 .quad 0 @ BaseRelocationTable
98
99section_table:
100 @
101 @ The EFI application loader requires a relocation section
102 @ because EFI applications must be relocatable. This is a
103 @ dummy section as far as we are concerned.
104 @
105 .ascii ".reloc\0\0"
106 .long 0 @ VirtualSize
107 .long 0 @ VirtualAddress
108 .long 0 @ SizeOfRawData
109 .long 0 @ PointerToRawData
110 .long 0 @ PointerToRelocations
111 .long 0 @ PointerToLineNumbers
112 .short 0 @ NumberOfRelocations
113 .short 0 @ NumberOfLineNumbers
114 .long 0x42100040 @ Characteristics
115
116 .ascii ".text\0\0\0"
117 .long _end - __efi_start @ VirtualSize
118 .long __efi_start @ VirtualAddress
119 .long _edata - __efi_start @ SizeOfRawData
120 .long __efi_start @ PointerToRawData
121 .long 0 @ PointerToRelocations
122 .long 0 @ PointerToLineNumbers
123 .short 0 @ NumberOfRelocations
124 .short 0 @ NumberOfLineNumbers
125 .long 0xe0500020 @ Characteristics
126
127 .align 9
128__efi_start:
129#endif
130 .endm
diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S
index 06e983f59980..af11c2f8f3b7 100644
--- a/arch/arm/boot/compressed/head.S
+++ b/arch/arm/boot/compressed/head.S
@@ -12,6 +12,8 @@
12#include <asm/assembler.h> 12#include <asm/assembler.h>
13#include <asm/v7m.h> 13#include <asm/v7m.h>
14 14
15#include "efi-header.S"
16
15 AR_CLASS( .arch armv7-a ) 17 AR_CLASS( .arch armv7-a )
16 M_CLASS( .arch armv7-m ) 18 M_CLASS( .arch armv7-m )
17 19
@@ -126,7 +128,7 @@
126start: 128start:
127 .type start,#function 129 .type start,#function
128 .rept 7 130 .rept 7
129 mov r0, r0 131 __nop
130 .endr 132 .endr
131 ARM( mov r0, r0 ) 133 ARM( mov r0, r0 )
132 ARM( b 1f ) 134 ARM( b 1f )
@@ -139,7 +141,8 @@ start:
139 .word 0x04030201 @ endianness flag 141 .word 0x04030201 @ endianness flag
140 142
141 THUMB( .thumb ) 143 THUMB( .thumb )
1421: 1441: __EFI_HEADER
145
143 ARM_BE8( setend be ) @ go BE8 if compiled for BE8 146 ARM_BE8( setend be ) @ go BE8 if compiled for BE8
144 AR_CLASS( mrs r9, cpsr ) 147 AR_CLASS( mrs r9, cpsr )
145#ifdef CONFIG_ARM_VIRT_EXT 148#ifdef CONFIG_ARM_VIRT_EXT
@@ -1353,6 +1356,53 @@ __enter_kernel:
1353 1356
1354reloc_code_end: 1357reloc_code_end:
1355 1358
1359#ifdef CONFIG_EFI_STUB
1360 .align 2
1361_start: .long start - .
1362
1363ENTRY(efi_stub_entry)
1364 @ allocate space on stack for passing current zImage address
1365 @ and for the EFI stub to return of new entry point of
1366 @ zImage, as EFI stub may copy the kernel. Pointer address
1367 @ is passed in r2. r0 and r1 are passed through from the
1368 @ EFI firmware to efi_entry
1369 adr ip, _start
1370 ldr r3, [ip]
1371 add r3, r3, ip
1372 stmfd sp!, {r3, lr}
1373 mov r2, sp @ pass zImage address in r2
1374 bl efi_entry
1375
1376 @ Check for error return from EFI stub. r0 has FDT address
1377 @ or error code.
1378 cmn r0, #1
1379 beq efi_load_fail
1380
1381 @ Preserve return value of efi_entry() in r4
1382 mov r4, r0
1383 bl cache_clean_flush
1384 bl cache_off
1385
1386 @ Set parameters for booting zImage according to boot protocol
1387 @ put FDT address in r2, it was returned by efi_entry()
1388 @ r1 is the machine type, and r0 needs to be 0
1389 mov r0, #0
1390 mov r1, #0xFFFFFFFF
1391 mov r2, r4
1392
1393 @ Branch to (possibly) relocated zImage that is in [sp]
1394 ldr lr, [sp]
1395 ldr ip, =start_offset
1396 add lr, lr, ip
1397 mov pc, lr @ no mode switch
1398
1399efi_load_fail:
1400 @ Return EFI_LOAD_ERROR to EFI firmware on error.
1401 ldr r0, =0x80000001
1402 ldmfd sp!, {ip, pc}
1403ENDPROC(efi_stub_entry)
1404#endif
1405
1356 .align 1406 .align
1357 .section ".stack", "aw", %nobits 1407 .section ".stack", "aw", %nobits
1358.L_user_stack: .space 4096 1408.L_user_stack: .space 4096
diff --git a/arch/arm/boot/compressed/vmlinux.lds.S b/arch/arm/boot/compressed/vmlinux.lds.S
index 2b60b843ac5e..81c493156ce8 100644
--- a/arch/arm/boot/compressed/vmlinux.lds.S
+++ b/arch/arm/boot/compressed/vmlinux.lds.S
@@ -48,6 +48,13 @@ SECTIONS
48 *(.rodata) 48 *(.rodata)
49 *(.rodata.*) 49 *(.rodata.*)
50 } 50 }
51 .data : {
52 /*
53 * The EFI stub always executes from RAM, and runs strictly before the
54 * decompressor, so we can make an exception for its r/w data, and keep it
55 */
56 *(.data.efistub)
57 }
51 .piggydata : { 58 .piggydata : {
52 *(.piggydata) 59 *(.piggydata)
53 } 60 }
diff --git a/arch/arm/include/asm/efi.h b/arch/arm/include/asm/efi.h
index c91e330616ad..e0eea72deb87 100644
--- a/arch/arm/include/asm/efi.h
+++ b/arch/arm/include/asm/efi.h
@@ -57,4 +57,27 @@ void efi_virtmap_unload(void);
57#define efi_init() 57#define efi_init()
58#endif /* CONFIG_EFI */ 58#endif /* CONFIG_EFI */
59 59
60/* arch specific definitions used by the stub code */
61
62#define efi_call_early(f, ...) sys_table_arg->boottime->f(__VA_ARGS__)
63
64/*
65 * A reasonable upper bound for the uncompressed kernel size is 32 MBytes,
66 * so we will reserve that amount of memory. We have no easy way to tell what
67 * the actuall size of code + data the uncompressed kernel will use.
68 * If this is insufficient, the decompressor will relocate itself out of the
69 * way before performing the decompression.
70 */
71#define MAX_UNCOMP_KERNEL_SIZE SZ_32M
72
73/*
74 * The kernel zImage should preferably be located between 32 MB and 128 MB
75 * from the base of DRAM. The min address leaves space for a maximal size
76 * uncompressed image, and the max address is due to how the zImage decompressor
77 * picks a destination address.
78 */
79#define ZIMAGE_OFFSET_LIMIT SZ_128M
80#define MIN_ZIMAGE_OFFSET MAX_UNCOMP_KERNEL_SIZE
81#define MAX_FDT_OFFSET ZIMAGE_OFFSET_LIMIT
82
60#endif /* _ASM_ARM_EFI_H */ 83#endif /* _ASM_ARM_EFI_H */
diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile
index 3c0467d3688c..8cf9ccbf42d5 100644
--- a/drivers/firmware/efi/libstub/Makefile
+++ b/drivers/firmware/efi/libstub/Makefile
@@ -34,6 +34,7 @@ $(obj)/lib-%.o: $(srctree)/lib/%.c FORCE
34lib-$(CONFIG_EFI_ARMSTUB) += arm-stub.o fdt.o string.o \ 34lib-$(CONFIG_EFI_ARMSTUB) += arm-stub.o fdt.o string.o \
35 $(patsubst %.c,lib-%.o,$(arm-deps)) 35 $(patsubst %.c,lib-%.o,$(arm-deps))
36 36
37lib-$(CONFIG_ARM) += arm32-stub.o
37lib-$(CONFIG_ARM64) += arm64-stub.o 38lib-$(CONFIG_ARM64) += arm64-stub.o
38CFLAGS_arm64-stub.o := -DTEXT_OFFSET=$(TEXT_OFFSET) 39CFLAGS_arm64-stub.o := -DTEXT_OFFSET=$(TEXT_OFFSET)
39 40
@@ -67,3 +68,11 @@ quiet_cmd_stubcopy = STUBCPY $@
67 $(OBJDUMP) -r $@ | grep $(STUBCOPY_RELOC-y) \ 68 $(OBJDUMP) -r $@ | grep $(STUBCOPY_RELOC-y) \
68 && (echo >&2 "$@: absolute symbol references not allowed in the EFI stub"; \ 69 && (echo >&2 "$@: absolute symbol references not allowed in the EFI stub"; \
69 rm -f $@; /bin/false); else /bin/false; fi 70 rm -f $@; /bin/false); else /bin/false; fi
71
72#
73# ARM discards the .data section because it disallows r/w data in the
74# decompressor. So move our .data to .data.efistub, which is preserved
75# explicitly by the decompressor linker script.
76#
77STUBCOPY_FLAGS-$(CONFIG_ARM) += --rename-section .data=.data.efistub
78STUBCOPY_RELOC-$(CONFIG_ARM) := R_ARM_ABS
diff --git a/drivers/firmware/efi/libstub/arm-stub.c b/drivers/firmware/efi/libstub/arm-stub.c
index 950c87f5d279..3397902e4040 100644
--- a/drivers/firmware/efi/libstub/arm-stub.c
+++ b/drivers/firmware/efi/libstub/arm-stub.c
@@ -303,8 +303,10 @@ fail:
303 * The value chosen is the largest non-zero power of 2 suitable for this purpose 303 * The value chosen is the largest non-zero power of 2 suitable for this purpose
304 * both on 32-bit and 64-bit ARM CPUs, to maximize the likelihood that it can 304 * both on 32-bit and 64-bit ARM CPUs, to maximize the likelihood that it can
305 * be mapped efficiently. 305 * be mapped efficiently.
306 * Since 32-bit ARM could potentially execute with a 1G/3G user/kernel split,
307 * map everything below 1 GB.
306 */ 308 */
307#define EFI_RT_VIRTUAL_BASE 0x40000000 309#define EFI_RT_VIRTUAL_BASE SZ_512M
308 310
309static int cmp_mem_desc(const void *l, const void *r) 311static int cmp_mem_desc(const void *l, const void *r)
310{ 312{
diff --git a/drivers/firmware/efi/libstub/arm32-stub.c b/drivers/firmware/efi/libstub/arm32-stub.c
new file mode 100644
index 000000000000..495ebd657e38
--- /dev/null
+++ b/drivers/firmware/efi/libstub/arm32-stub.c
@@ -0,0 +1,85 @@
1/*
2 * Copyright (C) 2013 Linaro Ltd; <roy.franz@linaro.org>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 */
9#include <linux/efi.h>
10#include <asm/efi.h>
11
12efi_status_t handle_kernel_image(efi_system_table_t *sys_table,
13 unsigned long *image_addr,
14 unsigned long *image_size,
15 unsigned long *reserve_addr,
16 unsigned long *reserve_size,
17 unsigned long dram_base,
18 efi_loaded_image_t *image)
19{
20 unsigned long nr_pages;
21 efi_status_t status;
22 /* Use alloc_addr to tranlsate between types */
23 efi_physical_addr_t alloc_addr;
24
25 /*
26 * Verify that the DRAM base address is compatible with the ARM
27 * boot protocol, which determines the base of DRAM by masking
28 * off the low 27 bits of the address at which the zImage is
29 * loaded. These assumptions are made by the decompressor,
30 * before any memory map is available.
31 */
32 dram_base = round_up(dram_base, SZ_128M);
33
34 /*
35 * Reserve memory for the uncompressed kernel image. This is
36 * all that prevents any future allocations from conflicting
37 * with the kernel. Since we can't tell from the compressed
38 * image how much DRAM the kernel actually uses (due to BSS
39 * size uncertainty) we allocate the maximum possible size.
40 * Do this very early, as prints can cause memory allocations
41 * that may conflict with this.
42 */
43 alloc_addr = dram_base;
44 *reserve_size = MAX_UNCOMP_KERNEL_SIZE;
45 nr_pages = round_up(*reserve_size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE;
46 status = sys_table->boottime->allocate_pages(EFI_ALLOCATE_ADDRESS,
47 EFI_LOADER_DATA,
48 nr_pages, &alloc_addr);
49 if (status != EFI_SUCCESS) {
50 *reserve_size = 0;
51 pr_efi_err(sys_table, "Unable to allocate memory for uncompressed kernel.\n");
52 return status;
53 }
54 *reserve_addr = alloc_addr;
55
56 /*
57 * Relocate the zImage, so that it appears in the lowest 128 MB
58 * memory window.
59 */
60 *image_size = image->image_size;
61 status = efi_relocate_kernel(sys_table, image_addr, *image_size,
62 *image_size,
63 dram_base + MAX_UNCOMP_KERNEL_SIZE, 0);
64 if (status != EFI_SUCCESS) {
65 pr_efi_err(sys_table, "Failed to relocate kernel.\n");
66 efi_free(sys_table, *reserve_size, *reserve_addr);
67 *reserve_size = 0;
68 return status;
69 }
70
71 /*
72 * Check to see if we were able to allocate memory low enough
73 * in memory. The kernel determines the base of DRAM from the
74 * address at which the zImage is loaded.
75 */
76 if (*image_addr + *image_size > dram_base + ZIMAGE_OFFSET_LIMIT) {
77 pr_efi_err(sys_table, "Failed to relocate kernel, no low memory available.\n");
78 efi_free(sys_table, *reserve_size, *reserve_addr);
79 *reserve_size = 0;
80 efi_free(sys_table, *image_size, *image_addr);
81 *image_size = 0;
82 return EFI_LOAD_ERROR;
83 }
84 return EFI_SUCCESS;
85}