aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Salter <msalter@redhat.com>2014-04-15 22:47:52 -0400
committerMatt Fleming <matt.fleming@intel.com>2014-04-30 14:57:04 -0400
commit3c7f255039a2ad6ee1e3890505caf0d029b22e29 (patch)
tree30fdbf23554e3a4aaf7ebd082f96aa71ec6a54c5
parente1977464e8403b4d7ed23d6bdb3358e78b311aa0 (diff)
arm64: efi: add EFI stub
This patch adds PE/COFF header fields to the start of the kernel Image so that it appears as an EFI application to UEFI firmware. An EFI stub is included to allow direct booting of the kernel Image. Signed-off-by: Mark Salter <msalter@redhat.com> [Add support in PE/COFF header for signed images] Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> Signed-off-by: Leif Lindholm <leif.lindholm@linaro.org> Acked-by: Catalin Marinas <catalin.marinas@arm.com> Signed-off-by: Matt Fleming <matt.fleming@intel.com>
-rw-r--r--arch/arm64/Kconfig5
-rw-r--r--arch/arm64/kernel/Makefile4
-rw-r--r--arch/arm64/kernel/efi-entry.S109
-rw-r--r--arch/arm64/kernel/efi-stub.c81
-rw-r--r--arch/arm64/kernel/head.S112
-rw-r--r--drivers/firmware/efi/arm-stub.c247
6 files changed, 555 insertions, 3 deletions
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 82e21de5db3b..6c71f122638d 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -290,8 +290,9 @@ config EFI
290 help 290 help
291 This option provides support for runtime services provided 291 This option provides support for runtime services provided
292 by UEFI firmware (such as non-volatile variables, realtime 292 by UEFI firmware (such as non-volatile variables, realtime
293 clock, and platform reset). This is only useful on systems 293 clock, and platform reset). A UEFI stub is also provided to
294 that have UEFI firmware. 294 allow the kernel to be booted as an EFI application. This
295 is only useful on systems that have UEFI firmware.
295 296
296endmenu 297endmenu
297 298
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index f57ccd755886..db63a0a25810 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -4,6 +4,8 @@
4 4
5CPPFLAGS_vmlinux.lds := -DTEXT_OFFSET=$(TEXT_OFFSET) 5CPPFLAGS_vmlinux.lds := -DTEXT_OFFSET=$(TEXT_OFFSET)
6AFLAGS_head.o := -DTEXT_OFFSET=$(TEXT_OFFSET) 6AFLAGS_head.o := -DTEXT_OFFSET=$(TEXT_OFFSET)
7CFLAGS_efi-stub.o := -DTEXT_OFFSET=$(TEXT_OFFSET) \
8 -I$(src)/../../../scripts/dtc/libfdt
7 9
8# Object file lists. 10# Object file lists.
9arm64-obj-y := cputable.o debug-monitors.o entry.o irq.o fpsimd.o \ 11arm64-obj-y := cputable.o debug-monitors.o entry.o irq.o fpsimd.o \
@@ -22,7 +24,7 @@ arm64-obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
22arm64-obj-$(CONFIG_ARM64_CPU_SUSPEND) += sleep.o suspend.o 24arm64-obj-$(CONFIG_ARM64_CPU_SUSPEND) += sleep.o suspend.o
23arm64-obj-$(CONFIG_JUMP_LABEL) += jump_label.o 25arm64-obj-$(CONFIG_JUMP_LABEL) += jump_label.o
24arm64-obj-$(CONFIG_KGDB) += kgdb.o 26arm64-obj-$(CONFIG_KGDB) += kgdb.o
25arm64-obj-$(CONFIG_EFI) += efi.o 27arm64-obj-$(CONFIG_EFI) += efi.o efi-stub.o efi-entry.o
26 28
27obj-y += $(arm64-obj-y) vdso/ 29obj-y += $(arm64-obj-y) vdso/
28obj-m += $(arm64-obj-m) 30obj-m += $(arm64-obj-m)
diff --git a/arch/arm64/kernel/efi-entry.S b/arch/arm64/kernel/efi-entry.S
new file mode 100644
index 000000000000..66716c9b9e5f
--- /dev/null
+++ b/arch/arm64/kernel/efi-entry.S
@@ -0,0 +1,109 @@
1/*
2 * EFI entry point.
3 *
4 * Copyright (C) 2013, 2014 Red Hat, Inc.
5 * Author: Mark Salter <msalter@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 */
12#include <linux/linkage.h>
13#include <linux/init.h>
14
15#include <asm/assembler.h>
16
17#define EFI_LOAD_ERROR 0x8000000000000001
18
19 __INIT
20
21 /*
22 * We arrive here from the EFI boot manager with:
23 *
24 * * CPU in little-endian mode
25 * * MMU on with identity-mapped RAM
26 * * Icache and Dcache on
27 *
28 * We will most likely be running from some place other than where
29 * we want to be. The kernel image wants to be placed at TEXT_OFFSET
30 * from start of RAM.
31 */
32ENTRY(efi_stub_entry)
33 /*
34 * Create a stack frame to save FP/LR with extra space
35 * for image_addr variable passed to efi_entry().
36 */
37 stp x29, x30, [sp, #-32]!
38
39 /*
40 * Call efi_entry to do the real work.
41 * x0 and x1 are already set up by firmware. Current runtime
42 * address of image is calculated and passed via *image_addr.
43 *
44 * unsigned long efi_entry(void *handle,
45 * efi_system_table_t *sys_table,
46 * unsigned long *image_addr) ;
47 */
48 adrp x8, _text
49 add x8, x8, #:lo12:_text
50 add x2, sp, 16
51 str x8, [x2]
52 bl efi_entry
53 cmn x0, #1
54 b.eq efi_load_fail
55
56 /*
57 * efi_entry() will have relocated the kernel image if necessary
58 * and we return here with device tree address in x0 and the kernel
59 * entry point stored at *image_addr. Save those values in registers
60 * which are callee preserved.
61 */
62 mov x20, x0 // DTB address
63 ldr x0, [sp, #16] // relocated _text address
64 mov x21, x0
65
66 /*
67 * Flush dcache covering current runtime addresses
68 * of kernel text/data. Then flush all of icache.
69 */
70 adrp x1, _text
71 add x1, x1, #:lo12:_text
72 adrp x2, _edata
73 add x2, x2, #:lo12:_edata
74 sub x1, x2, x1
75
76 bl __flush_dcache_area
77 ic ialluis
78
79 /* Turn off Dcache and MMU */
80 mrs x0, CurrentEL
81 cmp x0, #PSR_MODE_EL2t
82 ccmp x0, #PSR_MODE_EL2h, #0x4, ne
83 b.ne 1f
84 mrs x0, sctlr_el2
85 bic x0, x0, #1 << 0 // clear SCTLR.M
86 bic x0, x0, #1 << 2 // clear SCTLR.C
87 msr sctlr_el2, x0
88 isb
89 b 2f
901:
91 mrs x0, sctlr_el1
92 bic x0, x0, #1 << 0 // clear SCTLR.M
93 bic x0, x0, #1 << 2 // clear SCTLR.C
94 msr sctlr_el1, x0
95 isb
962:
97 /* Jump to kernel entry point */
98 mov x0, x20
99 mov x1, xzr
100 mov x2, xzr
101 mov x3, xzr
102 br x21
103
104efi_load_fail:
105 mov x0, #EFI_LOAD_ERROR
106 ldp x29, x30, [sp], #32
107 ret
108
109ENDPROC(efi_stub_entry)
diff --git a/arch/arm64/kernel/efi-stub.c b/arch/arm64/kernel/efi-stub.c
new file mode 100644
index 000000000000..60e98a639ac5
--- /dev/null
+++ b/arch/arm64/kernel/efi-stub.c
@@ -0,0 +1,81 @@
1/*
2 * Copyright (C) 2013, 2014 Linaro Ltd; <roy.franz@linaro.org>
3 *
4 * This file implements the EFI boot stub for the arm64 kernel.
5 * Adapted from ARM version by Mark Salter <msalter@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 */
12#include <linux/efi.h>
13#include <linux/libfdt.h>
14#include <asm/sections.h>
15#include <generated/compile.h>
16#include <generated/utsrelease.h>
17
18/*
19 * AArch64 requires the DTB to be 8-byte aligned in the first 512MiB from
20 * start of kernel and may not cross a 2MiB boundary. We set alignment to
21 * 2MiB so we know it won't cross a 2MiB boundary.
22 */
23#define EFI_FDT_ALIGN SZ_2M /* used by allocate_new_fdt_and_exit_boot() */
24#define MAX_FDT_OFFSET SZ_512M
25
26#define efi_call_early(f, ...) sys_table_arg->boottime->f(__VA_ARGS__)
27
28static void efi_char16_printk(efi_system_table_t *sys_table_arg,
29 efi_char16_t *str);
30
31static efi_status_t efi_open_volume(efi_system_table_t *sys_table,
32 void *__image, void **__fh);
33static efi_status_t efi_file_close(void *handle);
34
35static efi_status_t
36efi_file_read(void *handle, unsigned long *size, void *addr);
37
38static efi_status_t
39efi_file_size(efi_system_table_t *sys_table, void *__fh,
40 efi_char16_t *filename_16, void **handle, u64 *file_sz);
41
42/* Include shared EFI stub code */
43#include "../../../drivers/firmware/efi/efi-stub-helper.c"
44#include "../../../drivers/firmware/efi/fdt.c"
45#include "../../../drivers/firmware/efi/arm-stub.c"
46
47
48static efi_status_t handle_kernel_image(efi_system_table_t *sys_table,
49 unsigned long *image_addr,
50 unsigned long *image_size,
51 unsigned long *reserve_addr,
52 unsigned long *reserve_size,
53 unsigned long dram_base,
54 efi_loaded_image_t *image)
55{
56 efi_status_t status;
57 unsigned long kernel_size, kernel_memsize = 0;
58
59 /* Relocate the image, if required. */
60 kernel_size = _edata - _text;
61 if (*image_addr != (dram_base + TEXT_OFFSET)) {
62 kernel_memsize = kernel_size + (_end - _edata);
63 status = efi_relocate_kernel(sys_table, image_addr,
64 kernel_size, kernel_memsize,
65 dram_base + TEXT_OFFSET,
66 PAGE_SIZE);
67 if (status != EFI_SUCCESS) {
68 pr_efi_err(sys_table, "Failed to relocate kernel\n");
69 return status;
70 }
71 if (*image_addr != (dram_base + TEXT_OFFSET)) {
72 pr_efi_err(sys_table, "Failed to alloc kernel memory\n");
73 efi_free(sys_table, kernel_memsize, *image_addr);
74 return EFI_ERROR;
75 }
76 *image_size = kernel_memsize;
77 }
78
79
80 return EFI_SUCCESS;
81}
diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
index 0fd565000772..738291b5be29 100644
--- a/arch/arm64/kernel/head.S
+++ b/arch/arm64/kernel/head.S
@@ -108,8 +108,18 @@
108 /* 108 /*
109 * DO NOT MODIFY. Image header expected by Linux boot-loaders. 109 * DO NOT MODIFY. Image header expected by Linux boot-loaders.
110 */ 110 */
111#ifdef CONFIG_EFI
112efi_head:
113 /*
114 * This add instruction has no meaningful effect except that
115 * its opcode forms the magic "MZ" signature required by UEFI.
116 */
117 add x13, x18, #0x16
118 b stext
119#else
111 b stext // branch to kernel start, magic 120 b stext // branch to kernel start, magic
112 .long 0 // reserved 121 .long 0 // reserved
122#endif
113 .quad TEXT_OFFSET // Image load offset from start of RAM 123 .quad TEXT_OFFSET // Image load offset from start of RAM
114 .quad 0 // reserved 124 .quad 0 // reserved
115 .quad 0 // reserved 125 .quad 0 // reserved
@@ -120,7 +130,109 @@
120 .byte 0x52 130 .byte 0x52
121 .byte 0x4d 131 .byte 0x4d
122 .byte 0x64 132 .byte 0x64
133#ifdef CONFIG_EFI
134 .long pe_header - efi_head // Offset to the PE header.
135#else
123 .word 0 // reserved 136 .word 0 // reserved
137#endif
138
139#ifdef CONFIG_EFI
140 .align 3
141pe_header:
142 .ascii "PE"
143 .short 0
144coff_header:
145 .short 0xaa64 // AArch64
146 .short 2 // nr_sections
147 .long 0 // TimeDateStamp
148 .long 0 // PointerToSymbolTable
149 .long 1 // NumberOfSymbols
150 .short section_table - optional_header // SizeOfOptionalHeader
151 .short 0x206 // Characteristics.
152 // IMAGE_FILE_DEBUG_STRIPPED |
153 // IMAGE_FILE_EXECUTABLE_IMAGE |
154 // IMAGE_FILE_LINE_NUMS_STRIPPED
155optional_header:
156 .short 0x20b // PE32+ format
157 .byte 0x02 // MajorLinkerVersion
158 .byte 0x14 // MinorLinkerVersion
159 .long _edata - stext // SizeOfCode
160 .long 0 // SizeOfInitializedData
161 .long 0 // SizeOfUninitializedData
162 .long efi_stub_entry - efi_head // AddressOfEntryPoint
163 .long stext - efi_head // BaseOfCode
164
165extra_header_fields:
166 .quad 0 // ImageBase
167 .long 0x20 // SectionAlignment
168 .long 0x8 // FileAlignment
169 .short 0 // MajorOperatingSystemVersion
170 .short 0 // MinorOperatingSystemVersion
171 .short 0 // MajorImageVersion
172 .short 0 // MinorImageVersion
173 .short 0 // MajorSubsystemVersion
174 .short 0 // MinorSubsystemVersion
175 .long 0 // Win32VersionValue
176
177 .long _edata - efi_head // SizeOfImage
178
179 // Everything before the kernel image is considered part of the header
180 .long stext - efi_head // SizeOfHeaders
181 .long 0 // CheckSum
182 .short 0xa // Subsystem (EFI application)
183 .short 0 // DllCharacteristics
184 .quad 0 // SizeOfStackReserve
185 .quad 0 // SizeOfStackCommit
186 .quad 0 // SizeOfHeapReserve
187 .quad 0 // SizeOfHeapCommit
188 .long 0 // LoaderFlags
189 .long 0x6 // NumberOfRvaAndSizes
190
191 .quad 0 // ExportTable
192 .quad 0 // ImportTable
193 .quad 0 // ResourceTable
194 .quad 0 // ExceptionTable
195 .quad 0 // CertificationTable
196 .quad 0 // BaseRelocationTable
197
198 // Section table
199section_table:
200
201 /*
202 * The EFI application loader requires a relocation section
203 * because EFI applications must be relocatable. This is a
204 * dummy section as far as we are concerned.
205 */
206 .ascii ".reloc"
207 .byte 0
208 .byte 0 // end of 0 padding of section name
209 .long 0
210 .long 0
211 .long 0 // SizeOfRawData
212 .long 0 // PointerToRawData
213 .long 0 // PointerToRelocations
214 .long 0 // PointerToLineNumbers
215 .short 0 // NumberOfRelocations
216 .short 0 // NumberOfLineNumbers
217 .long 0x42100040 // Characteristics (section flags)
218
219
220 .ascii ".text"
221 .byte 0
222 .byte 0
223 .byte 0 // end of 0 padding of section name
224 .long _edata - stext // VirtualSize
225 .long stext - efi_head // VirtualAddress
226 .long _edata - stext // SizeOfRawData
227 .long stext - efi_head // PointerToRawData
228
229 .long 0 // PointerToRelocations (0 for executables)
230 .long 0 // PointerToLineNumbers (0 for executables)
231 .short 0 // NumberOfRelocations (0 for executables)
232 .short 0 // NumberOfLineNumbers (0 for executables)
233 .long 0xe0500020 // Characteristics (section flags)
234 .align 5
235#endif
124 236
125ENTRY(stext) 237ENTRY(stext)
126 mov x21, x0 // x21=FDT 238 mov x21, x0 // x21=FDT
diff --git a/drivers/firmware/efi/arm-stub.c b/drivers/firmware/efi/arm-stub.c
new file mode 100644
index 000000000000..19239a9b7e29
--- /dev/null
+++ b/drivers/firmware/efi/arm-stub.c
@@ -0,0 +1,247 @@
1/*
2 * EFI stub implementation that is shared by arm and arm64 architectures.
3 * This should be #included by the EFI stub implementation files.
4 *
5 * Copyright (C) 2013,2014 Linaro Limited
6 * Roy Franz <roy.franz@linaro.org
7 * Copyright (C) 2013 Red Hat, Inc.
8 * Mark Salter <msalter@redhat.com>
9 *
10 * This file is part of the Linux kernel, and is made available under the
11 * terms of the GNU General Public License version 2.
12 *
13 */
14
15static efi_status_t efi_open_volume(efi_system_table_t *sys_table_arg,
16 void *__image, void **__fh)
17{
18 efi_file_io_interface_t *io;
19 efi_loaded_image_t *image = __image;
20 efi_file_handle_t *fh;
21 efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID;
22 efi_status_t status;
23 void *handle = (void *)(unsigned long)image->device_handle;
24
25 status = sys_table_arg->boottime->handle_protocol(handle,
26 &fs_proto, (void **)&io);
27 if (status != EFI_SUCCESS) {
28 efi_printk(sys_table_arg, "Failed to handle fs_proto\n");
29 return status;
30 }
31
32 status = io->open_volume(io, &fh);
33 if (status != EFI_SUCCESS)
34 efi_printk(sys_table_arg, "Failed to open volume\n");
35
36 *__fh = fh;
37 return status;
38}
39static efi_status_t efi_file_close(void *handle)
40{
41 efi_file_handle_t *fh = handle;
42
43 return fh->close(handle);
44}
45
46static efi_status_t
47efi_file_read(void *handle, unsigned long *size, void *addr)
48{
49 efi_file_handle_t *fh = handle;
50
51 return fh->read(handle, size, addr);
52}
53
54
55static efi_status_t
56efi_file_size(efi_system_table_t *sys_table_arg, void *__fh,
57 efi_char16_t *filename_16, void **handle, u64 *file_sz)
58{
59 efi_file_handle_t *h, *fh = __fh;
60 efi_file_info_t *info;
61 efi_status_t status;
62 efi_guid_t info_guid = EFI_FILE_INFO_ID;
63 unsigned long info_sz;
64
65 status = fh->open(fh, &h, filename_16, EFI_FILE_MODE_READ, (u64)0);
66 if (status != EFI_SUCCESS) {
67 efi_printk(sys_table_arg, "Failed to open file: ");
68 efi_char16_printk(sys_table_arg, filename_16);
69 efi_printk(sys_table_arg, "\n");
70 return status;
71 }
72
73 *handle = h;
74
75 info_sz = 0;
76 status = h->get_info(h, &info_guid, &info_sz, NULL);
77 if (status != EFI_BUFFER_TOO_SMALL) {
78 efi_printk(sys_table_arg, "Failed to get file info size\n");
79 return status;
80 }
81
82grow:
83 status = sys_table_arg->boottime->allocate_pool(EFI_LOADER_DATA,
84 info_sz, (void **)&info);
85 if (status != EFI_SUCCESS) {
86 efi_printk(sys_table_arg, "Failed to alloc mem for file info\n");
87 return status;
88 }
89
90 status = h->get_info(h, &info_guid, &info_sz,
91 info);
92 if (status == EFI_BUFFER_TOO_SMALL) {
93 sys_table_arg->boottime->free_pool(info);
94 goto grow;
95 }
96
97 *file_sz = info->file_size;
98 sys_table_arg->boottime->free_pool(info);
99
100 if (status != EFI_SUCCESS)
101 efi_printk(sys_table_arg, "Failed to get initrd info\n");
102
103 return status;
104}
105
106
107
108static void efi_char16_printk(efi_system_table_t *sys_table_arg,
109 efi_char16_t *str)
110{
111 struct efi_simple_text_output_protocol *out;
112
113 out = (struct efi_simple_text_output_protocol *)sys_table_arg->con_out;
114 out->output_string(out, str);
115}
116
117
118/*
119 * This function handles the architcture specific differences between arm and
120 * arm64 regarding where the kernel image must be loaded and any memory that
121 * must be reserved. On failure it is required to free all
122 * all allocations it has made.
123 */
124static efi_status_t handle_kernel_image(efi_system_table_t *sys_table,
125 unsigned long *image_addr,
126 unsigned long *image_size,
127 unsigned long *reserve_addr,
128 unsigned long *reserve_size,
129 unsigned long dram_base,
130 efi_loaded_image_t *image);
131/*
132 * EFI entry point for the arm/arm64 EFI stubs. This is the entrypoint
133 * that is described in the PE/COFF header. Most of the code is the same
134 * for both archictectures, with the arch-specific code provided in the
135 * handle_kernel_image() function.
136 */
137unsigned long __init efi_entry(void *handle, efi_system_table_t *sys_table,
138 unsigned long *image_addr)
139{
140 efi_loaded_image_t *image;
141 efi_status_t status;
142 unsigned long image_size = 0;
143 unsigned long dram_base;
144 /* addr/point and size pairs for memory management*/
145 unsigned long initrd_addr;
146 u64 initrd_size = 0;
147 unsigned long fdt_addr; /* Original DTB */
148 u64 fdt_size = 0; /* We don't get size from configuration table */
149 char *cmdline_ptr = NULL;
150 int cmdline_size = 0;
151 unsigned long new_fdt_addr;
152 efi_guid_t loaded_image_proto = LOADED_IMAGE_PROTOCOL_GUID;
153 unsigned long reserve_addr = 0;
154 unsigned long reserve_size = 0;
155
156 /* Check if we were booted by the EFI firmware */
157 if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
158 goto fail;
159
160 pr_efi(sys_table, "Booting Linux Kernel...\n");
161
162 /*
163 * Get a handle to the loaded image protocol. This is used to get
164 * information about the running image, such as size and the command
165 * line.
166 */
167 status = sys_table->boottime->handle_protocol(handle,
168 &loaded_image_proto, (void *)&image);
169 if (status != EFI_SUCCESS) {
170 pr_efi_err(sys_table, "Failed to get loaded image protocol\n");
171 goto fail;
172 }
173
174 dram_base = get_dram_base(sys_table);
175 if (dram_base == EFI_ERROR) {
176 pr_efi_err(sys_table, "Failed to find DRAM base\n");
177 goto fail;
178 }
179 status = handle_kernel_image(sys_table, image_addr, &image_size,
180 &reserve_addr,
181 &reserve_size,
182 dram_base, image);
183 if (status != EFI_SUCCESS) {
184 pr_efi_err(sys_table, "Failed to relocate kernel\n");
185 goto fail;
186 }
187
188 /*
189 * Get the command line from EFI, using the LOADED_IMAGE
190 * protocol. We are going to copy the command line into the
191 * device tree, so this can be allocated anywhere.
192 */
193 cmdline_ptr = efi_convert_cmdline(sys_table, image, &cmdline_size);
194 if (!cmdline_ptr) {
195 pr_efi_err(sys_table, "getting command line via LOADED_IMAGE_PROTOCOL\n");
196 goto fail_free_image;
197 }
198
199 /* Load a device tree from the configuration table, if present. */
200 fdt_addr = (uintptr_t)get_fdt(sys_table);
201 if (!fdt_addr) {
202 status = handle_cmdline_files(sys_table, image, cmdline_ptr,
203 "dtb=",
204 ~0UL, (unsigned long *)&fdt_addr,
205 (unsigned long *)&fdt_size);
206
207 if (status != EFI_SUCCESS) {
208 pr_efi_err(sys_table, "Failed to load device tree!\n");
209 goto fail_free_cmdline;
210 }
211 }
212
213 status = handle_cmdline_files(sys_table, image, cmdline_ptr,
214 "initrd=", dram_base + SZ_512M,
215 (unsigned long *)&initrd_addr,
216 (unsigned long *)&initrd_size);
217 if (status != EFI_SUCCESS)
218 pr_efi_err(sys_table, "Failed initrd from command line!\n");
219
220 new_fdt_addr = fdt_addr;
221 status = allocate_new_fdt_and_exit_boot(sys_table, handle,
222 &new_fdt_addr, dram_base + MAX_FDT_OFFSET,
223 initrd_addr, initrd_size, cmdline_ptr,
224 fdt_addr, fdt_size);
225
226 /*
227 * If all went well, we need to return the FDT address to the
228 * calling function so it can be passed to kernel as part of
229 * the kernel boot protocol.
230 */
231 if (status == EFI_SUCCESS)
232 return new_fdt_addr;
233
234 pr_efi_err(sys_table, "Failed to update FDT and exit boot services\n");
235
236 efi_free(sys_table, initrd_size, initrd_addr);
237 efi_free(sys_table, fdt_size, fdt_addr);
238
239fail_free_cmdline:
240 efi_free(sys_table, cmdline_size, (unsigned long)cmdline_ptr);
241
242fail_free_image:
243 efi_free(sys_table, image_size, *image_addr);
244 efi_free(sys_table, reserve_size, reserve_addr);
245fail:
246 return EFI_ERROR;
247}