blob: 19239a9b7e29999bd52749fe3f89ed1aac322116 [file] [log] [blame]
Mark Salter3c7f2552014-04-15 22:47:52 -04001/*
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}