1 /*
2 * EFI-related functions to set up and run test cases in EFI
3 *
4 * Copyright (c) 2021, SUSE, Varad Gautam <varad.gautam@suse.com>
5 * Copyright (c) 2021, Google Inc, Zixuan Wang <zixuanwang@google.com>
6 *
7 * SPDX-License-Identifier: LGPL-2.0-or-later
8 */
9 #include <libcflat.h>
10 #include <argv.h>
11 #include <ctype.h>
12 #include <stdlib.h>
13 #include <asm/setup.h>
14 #include "efi.h"
15
16 /* From each arch */
17 extern char *initrd;
18 extern u32 initrd_size;
19
20 /* From lib/argv.c */
21 extern int __argc, __envc;
22 extern char *__argv[100];
23 extern char *__environ[200];
24
25 extern char _text;
26
27 extern int main(int argc, char **argv, char **envp);
28
29 efi_system_table_t *efi_system_table = NULL;
30
31 #ifdef __riscv
32 #define RISCV_EFI_BOOT_PROTOCOL_GUID EFI_GUID(0xccd15fec, 0x6f73, 0x4eec, 0x83, 0x95, 0x3e, 0x69, 0xe4, 0xb9, 0x40, 0xbf)
33
34 unsigned long boot_hartid;
35
36 struct riscv_efi_boot_protocol {
37 u64 revision;
38 efi_status_t (*get_boot_hartid)(struct riscv_efi_boot_protocol *,
39 unsigned long *boot_hartid);
40 };
41
efi_get_boot_hartid(void)42 static efi_status_t efi_get_boot_hartid(void)
43 {
44 efi_guid_t boot_protocol_guid = RISCV_EFI_BOOT_PROTOCOL_GUID;
45 struct riscv_efi_boot_protocol *boot_protocol;
46 efi_status_t status;
47
48 status = efi_bs_call(locate_protocol, &boot_protocol_guid, NULL,
49 (void **)&boot_protocol);
50 if (status != EFI_SUCCESS)
51 return status;
52 return efi_call_proto(boot_protocol, get_boot_hartid, &boot_hartid);
53 }
54 #endif
55
efi_free_pool(void * ptr)56 static void efi_free_pool(void *ptr)
57 {
58 efi_bs_call(free_pool, ptr);
59 }
60
efi_get_memory_map(struct efi_boot_memmap * map)61 efi_status_t efi_get_memory_map(struct efi_boot_memmap *map)
62 {
63 efi_memory_desc_t *m = NULL;
64 efi_status_t status;
65 unsigned long key = 0, map_size = 0, desc_size = 0;
66 u32 desc_ver;
67
68 status = efi_bs_call(get_memory_map, &map_size,
69 NULL, &key, &desc_size, &desc_ver);
70 if (status != EFI_BUFFER_TOO_SMALL || map_size == 0)
71 goto out;
72
73 /*
74 * Pad map_size with additional descriptors so we don't need to
75 * retry.
76 */
77 map_size += 4 * desc_size;
78 *map->buff_size = map_size;
79 status = efi_bs_call(allocate_pool, EFI_LOADER_DATA,
80 map_size, (void **)&m);
81 if (status != EFI_SUCCESS)
82 goto out;
83
84 /* Get the map. */
85 status = efi_bs_call(get_memory_map, &map_size,
86 m, &key, &desc_size, &desc_ver);
87 if (status != EFI_SUCCESS) {
88 efi_free_pool(m);
89 goto out;
90 }
91
92 *map->desc_ver = desc_ver;
93 *map->desc_size = desc_size;
94 *map->map_size = map_size;
95 *map->key_ptr = key;
96 out:
97 *map->map = m;
98 return status;
99 }
100
efi_exit_boot_services(void * handle,struct efi_boot_memmap * map)101 efi_status_t efi_exit_boot_services(void *handle, struct efi_boot_memmap *map)
102 {
103 return efi_bs_call(exit_boot_services, handle, *map->key_ptr);
104 }
105
efi_get_system_config_table(efi_guid_t table_guid,void ** table)106 efi_status_t efi_get_system_config_table(efi_guid_t table_guid, void **table)
107 {
108 size_t i;
109 efi_config_table_t *tables;
110
111 tables = (efi_config_table_t *)efi_system_table->tables;
112 for (i = 0; i < efi_system_table->nr_tables; i++) {
113 if (!memcmp(&table_guid, &tables[i].guid, sizeof(efi_guid_t))) {
114 *table = tables[i].table;
115 return EFI_SUCCESS;
116 }
117 }
118 return EFI_NOT_FOUND;
119 }
120
efi_exit(efi_status_t code)121 static void efi_exit(efi_status_t code)
122 {
123 exit(code);
124
125 /*
126 * Fallback to UEFI reset_system() service, in case testdev is
127 * missing and exit() does not properly exit.
128 */
129 efi_rs_call(reset_system, EFI_RESET_SHUTDOWN, code, 0, NULL);
130 }
131
132 /* Adapted from drivers/firmware/efi/libstub/efi-stub.c */
efi_convert_cmdline(struct efi_loaded_image_64 * image,int * cmd_line_len)133 static char *efi_convert_cmdline(struct efi_loaded_image_64 *image, int *cmd_line_len)
134 {
135 const u16 *s2;
136 unsigned long cmdline_addr = 0;
137 int options_chars = image->load_options_size;
138 const u16 *options = image->load_options;
139 int options_bytes = 0, safe_options_bytes = 0; /* UTF-8 bytes */
140 bool in_quote = false;
141 efi_status_t status;
142 const int COMMAND_LINE_SIZE = 2048;
143
144 if (options) {
145 s2 = options;
146 while (options_bytes < COMMAND_LINE_SIZE && options_chars--) {
147 u16 c = *s2++;
148
149 if (c < 0x80) {
150 if (c == L'\0' || c == L'\n')
151 break;
152 if (c == L'"')
153 in_quote = !in_quote;
154 else if (!in_quote && isspace((char)c))
155 safe_options_bytes = options_bytes;
156
157 options_bytes++;
158 continue;
159 }
160
161 /*
162 * Get the number of UTF-8 bytes corresponding to a
163 * UTF-16 character.
164 * The first part handles everything in the BMP.
165 */
166 options_bytes += 2 + (c >= 0x800);
167 /*
168 * Add one more byte for valid surrogate pairs. Invalid
169 * surrogates will be replaced with 0xfffd and take up
170 * only 3 bytes.
171 */
172 if ((c & 0xfc00) == 0xd800) {
173 /*
174 * If the very last word is a high surrogate,
175 * we must ignore it since we can't access the
176 * low surrogate.
177 */
178 if (!options_chars) {
179 options_bytes -= 3;
180 } else if ((*s2 & 0xfc00) == 0xdc00) {
181 options_bytes++;
182 options_chars--;
183 s2++;
184 }
185 }
186 }
187 if (options_bytes >= COMMAND_LINE_SIZE) {
188 options_bytes = safe_options_bytes;
189 printf("Command line is too long: truncated to %d bytes\n",
190 options_bytes);
191 }
192 }
193
194 options_bytes++; /* NUL termination */
195
196 status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, options_bytes, (void **)&cmdline_addr);
197 if (status != EFI_SUCCESS)
198 return NULL;
199
200 snprintf((char *)cmdline_addr, options_bytes, "%.*ls", options_bytes - 1, options);
201
202 *cmd_line_len = options_bytes;
203 return (char *)cmdline_addr;
204 }
205
206 #if defined(__aarch64__) || defined(__riscv)
207 #include "libfdt/libfdt.h"
208 /*
209 * Open the file and read it into a buffer.
210 */
efi_load_image(efi_handle_t handle,struct efi_loaded_image_64 * image,void ** data,int * datasize,efi_char16_t * path_name)211 static void efi_load_image(efi_handle_t handle, struct efi_loaded_image_64 *image, void **data,
212 int *datasize, efi_char16_t *path_name)
213 {
214 uint64_t buffer_size = sizeof(efi_file_info_t);
215 efi_file_info_t *file_info;
216 efi_file_io_interface_t *io_if;
217 efi_file_t *root, *file;
218 efi_status_t status;
219 efi_guid_t file_system_proto_guid = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID;
220 efi_guid_t file_info_guid = EFI_FILE_INFO_ID;
221
222 /* Open the device */
223 status = efi_bs_call(handle_protocol, image->device_handle, &file_system_proto_guid,
224 (void **)&io_if);
225 if (status != EFI_SUCCESS)
226 return;
227
228 status = io_if->open_volume(io_if, &root);
229 if (status != EFI_SUCCESS)
230 return;
231
232 /* And then open the file */
233 status = root->open(root, &file, path_name, EFI_FILE_MODE_READ, 0);
234 if (status != EFI_SUCCESS) {
235 printf("Failed to open %ls - %lx\n", path_name, status);
236 assert(status == EFI_SUCCESS);
237 }
238
239 /* Find the file size in order to allocate the buffer */
240 status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, buffer_size, (void **)&file_info);
241 if (status != EFI_SUCCESS)
242 return;
243
244 status = file->get_info(file, &file_info_guid, &buffer_size, file_info);
245 if (status == EFI_BUFFER_TOO_SMALL) {
246 efi_free_pool(file_info);
247 status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, buffer_size, (void **)&file_info);
248 assert(file_info);
249 status = file->get_info(file, &file_info_guid, &buffer_size, file_info);
250 }
251 assert(status == EFI_SUCCESS);
252
253 buffer_size = file_info->file_size;
254
255 efi_free_pool(file_info);
256
257 status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, buffer_size, (void **)data);
258 assert(*data);
259 /* Perform the actual read */
260 status = file->read(file, &buffer_size, *data);
261 if (status == EFI_BUFFER_TOO_SMALL) {
262 efi_free_pool(*data);
263 status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, buffer_size, (void **)data);
264 status = file->read(file, &buffer_size, *data);
265 }
266 assert(status == EFI_SUCCESS);
267
268 *datasize = buffer_size;
269 }
270
efi_grow_buffer(efi_status_t * status,void ** buffer,uint64_t buffer_size)271 static int efi_grow_buffer(efi_status_t *status, void **buffer, uint64_t buffer_size)
272 {
273 int try_again;
274
275 if (!*buffer && buffer_size) {
276 *status = EFI_BUFFER_TOO_SMALL;
277 }
278
279 try_again = 0;
280 if (*status == EFI_BUFFER_TOO_SMALL) {
281 if (*buffer)
282 efi_free_pool(*buffer);
283
284 efi_bs_call(allocate_pool, EFI_LOADER_DATA, buffer_size, buffer);
285 if (*buffer) {
286 try_again = 1;
287 } else {
288 *status = EFI_OUT_OF_RESOURCES;
289 }
290 }
291
292 if (!try_again && EFI_ERROR(*status) && *buffer) {
293 efi_free_pool(*buffer);
294 *buffer = NULL;
295 }
296
297 return try_again;
298 }
299
efi_get_var(efi_handle_t handle,struct efi_loaded_image_64 * image,efi_char16_t * var)300 static void* efi_get_var(efi_handle_t handle, struct efi_loaded_image_64 *image, efi_char16_t *var)
301 {
302 efi_status_t status = EFI_SUCCESS;
303 void *val = NULL;
304 uint64_t val_size = 100;
305 efi_guid_t efi_var_guid = EFI_VAR_GUID;
306
307 while (efi_grow_buffer(&status, &val, val_size + sizeof(efi_char16_t)))
308 status = efi_rs_call(get_variable, var, &efi_var_guid, NULL, &val_size, val);
309
310 if (val)
311 ((efi_char16_t *)val)[val_size / sizeof(efi_char16_t)] = L'\0';
312
313 return val;
314 }
315
efi_get_fdt(efi_handle_t handle,struct efi_loaded_image_64 * image)316 static void *efi_get_fdt(efi_handle_t handle, struct efi_loaded_image_64 *image)
317 {
318 efi_char16_t var[] = ENV_VARNAME_DTBFILE;
319 efi_char16_t *val;
320 void *fdt = NULL;
321 int fdtsize = 0;
322
323 val = efi_get_var(handle, image, var);
324 if (val) {
325 efi_load_image(handle, image, &fdt, &fdtsize, val);
326 if (fdtsize == 0)
327 return NULL;
328 } else if (efi_get_system_config_table(DEVICE_TREE_GUID, &fdt) != EFI_SUCCESS) {
329 return NULL;
330 }
331
332 return fdt_check_header(fdt) == 0 ? fdt : NULL;
333 }
334 #else
efi_get_fdt(efi_handle_t handle,struct efi_loaded_image_64 * image)335 static void *efi_get_fdt(efi_handle_t handle, struct efi_loaded_image_64 *image)
336 {
337 return NULL;
338 }
339 #endif
340
341 static const struct {
342 struct efi_vendor_dev_path vendor;
343 struct efi_generic_dev_path end;
344 } __packed initrd_dev_path = {
345 {
346 {
347 EFI_DEV_MEDIA,
348 EFI_DEV_MEDIA_VENDOR,
349 sizeof(struct efi_vendor_dev_path),
350 },
351 LINUX_EFI_INITRD_MEDIA_GUID
352 }, {
353 EFI_DEV_END_PATH,
354 EFI_DEV_END_ENTIRE,
355 sizeof(struct efi_generic_dev_path)
356 }
357 };
358
efi_load_initrd(void)359 static void efi_load_initrd(void)
360 {
361 efi_guid_t lf2_proto_guid = EFI_LOAD_FILE2_PROTOCOL_GUID;
362 efi_device_path_protocol_t *dp;
363 efi_load_file2_protocol_t *lf2;
364 efi_handle_t handle;
365 efi_status_t status;
366 unsigned long file_size = 0;
367
368 initrd = NULL;
369 initrd_size = 0;
370
371 dp = (efi_device_path_protocol_t *)&initrd_dev_path;
372 status = efi_bs_call(locate_device_path, &lf2_proto_guid, &dp, &handle);
373 if (status != EFI_SUCCESS)
374 return;
375
376 status = efi_bs_call(handle_protocol, handle, &lf2_proto_guid, (void **)&lf2);
377 assert(status == EFI_SUCCESS);
378
379 status = efi_call_proto(lf2, load_file, dp, false, &file_size, NULL);
380 assert(status == EFI_BUFFER_TOO_SMALL);
381
382 status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, file_size, (void **)&initrd);
383 assert(status == EFI_SUCCESS);
384
385 status = efi_call_proto(lf2, load_file, dp, false, &file_size, (void *)initrd);
386 assert(status == EFI_SUCCESS);
387
388 initrd_size = (u32)file_size;
389
390 /*
391 * UEFI appends initrd=initrd to the command line when an initrd is present.
392 * Remove it in order to avoid confusing unit tests.
393 */
394 if (!strcmp(__argv[__argc - 1], "initrd=initrd")) {
395 __argv[__argc - 1] = NULL;
396 __argc -= 1;
397 }
398 }
399
efi_main(efi_handle_t handle,efi_system_table_t * sys_tab)400 efi_status_t efi_main(efi_handle_t handle, efi_system_table_t *sys_tab)
401 {
402 int ret;
403 efi_status_t status;
404 efi_bootinfo_t efi_bootinfo;
405
406 efi_system_table = sys_tab;
407
408 /* Memory map struct values */
409 efi_memory_desc_t *map;
410 unsigned long map_size, desc_size, key, buff_size;
411 u32 desc_ver;
412
413 /* Helper variables needed to get the cmdline */
414 struct efi_loaded_image_64 *image;
415 efi_guid_t loaded_image_proto = LOADED_IMAGE_PROTOCOL_GUID;
416 char *cmdline_ptr = NULL;
417 int cmdline_size = 0;
418
419 /*
420 * Get a handle to the loaded image protocol. This is used to get
421 * information about the running image, such as size and the command
422 * line.
423 */
424 status = efi_bs_call(handle_protocol, handle, &loaded_image_proto, (void *)&image);
425 if (status != EFI_SUCCESS) {
426 printf("Failed to get loaded image protocol\n");
427 goto efi_main_error;
428 }
429
430 cmdline_ptr = efi_convert_cmdline(image, &cmdline_size);
431 if (!cmdline_ptr) {
432 printf("getting command line via LOADED_IMAGE_PROTOCOL\n");
433 status = EFI_OUT_OF_RESOURCES;
434 goto efi_main_error;
435 }
436 setup_args(cmdline_ptr);
437
438 efi_load_initrd();
439
440 efi_bootinfo.fdt = efi_get_fdt(handle, image);
441 /* Set up efi_bootinfo */
442 efi_bootinfo.mem_map.map = ↦
443 efi_bootinfo.mem_map.map_size = &map_size;
444 efi_bootinfo.mem_map.desc_size = &desc_size;
445 efi_bootinfo.mem_map.desc_ver = &desc_ver;
446 efi_bootinfo.mem_map.key_ptr = &key;
447 efi_bootinfo.mem_map.buff_size = &buff_size;
448
449 #ifdef __riscv
450 status = efi_get_boot_hartid();
451 if (status != EFI_SUCCESS) {
452 printf("Failed to get boot haritd\n");
453 goto efi_main_error;
454 }
455 #endif
456
457 status = EFI_INVALID_PARAMETER;
458 while (status == EFI_INVALID_PARAMETER) {
459 status = efi_get_memory_map(&efi_bootinfo.mem_map);
460 if (status != EFI_SUCCESS) {
461 printf("Failed to get memory map\n");
462 goto efi_main_error;
463 }
464 /*
465 * Exit EFI boot services, let kvm-unit-tests take full
466 * control of the guest.
467 */
468 status = efi_exit_boot_services(handle, &efi_bootinfo.mem_map);
469 if (status == EFI_INVALID_PARAMETER)
470 efi_free_pool(*efi_bootinfo.mem_map.map);
471 }
472
473 if (status != EFI_SUCCESS) {
474 printf("Failed to exit boot services\n");
475 goto efi_main_error;
476 }
477
478 /* Set up arch-specific resources */
479 status = setup_efi(&efi_bootinfo);
480 if (status != EFI_SUCCESS) {
481 printf("Failed to set up arch-specific resources\n");
482 goto efi_main_error;
483 }
484
485 printf("Address of image is: 0x%lx\n", (unsigned long)&_text);
486
487 /* Run the test case */
488 ret = main(__argc, __argv, __environ);
489
490 /* Shutdown the guest VM */
491 efi_exit(ret);
492
493 /* Unreachable */
494 return EFI_UNSUPPORTED;
495
496 efi_main_error:
497 /* Shutdown the guest with error EFI status */
498 efi_exit(status);
499
500 /* Unreachable */
501 return EFI_UNSUPPORTED;
502 }
503