blob: 953b264d9d4502d3366bb97486d5347dc3e19ddb [file] [log] [blame]
Heinrich Schuchardt12083ba2020-11-04 22:00:48 +01001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright 2020, Heinrich Schuchardt <xypron.glpk@gmx.de>
4 *
5 * dtbdump.efi saves the device tree provided as a configuration table
6 * to a file.
7 */
8
9#include <common.h>
10#include <efi_api.h>
Heinrich Schuchardt45910792020-12-13 19:13:57 +010011#include <efi_dt_fixup.h>
Heinrich Schuchardt12083ba2020-11-04 22:00:48 +010012
13#define BUFFER_SIZE 64
14#define ESC 0x17
Heinrich Schuchardt45910792020-12-13 19:13:57 +010015
16#define efi_size_in_pages(size) ((size + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT)
Heinrich Schuchardt12083ba2020-11-04 22:00:48 +010017
18static struct efi_simple_text_output_protocol *cerr;
19static struct efi_simple_text_output_protocol *cout;
20static struct efi_simple_text_input_protocol *cin;
21static struct efi_boot_services *bs;
22static const efi_guid_t fdt_guid = EFI_FDT_GUID;
23static const efi_guid_t loaded_image_guid = EFI_LOADED_IMAGE_PROTOCOL_GUID;
24static const efi_guid_t guid_simple_file_system_protocol =
25 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID;
Heinrich Schuchardt45910792020-12-13 19:13:57 +010026static efi_handle_t handle;
27static struct efi_system_table *systable;
28static const efi_guid_t efi_dt_fixup_protocol_guid = EFI_DT_FIXUP_PROTOCOL_GUID;
29static const efi_guid_t efi_file_info_guid = EFI_FILE_INFO_GUID;
30
31/**
Heinrich Schuchardt9d4c19e2021-01-19 10:06:00 +010032 * print() - print string
33 *
34 * @string: text
35 */
36static void print(u16 *string)
37{
38 cout->output_string(cout, string);
39}
40
41/**
Heinrich Schuchardt45910792020-12-13 19:13:57 +010042 * error() - print error string
43 *
44 * @string: error text
45 */
46static void error(u16 *string)
47{
48 cout->set_attribute(cout, EFI_LIGHTRED | EFI_BACKGROUND_BLACK);
Heinrich Schuchardt9d4c19e2021-01-19 10:06:00 +010049 print(string);
Heinrich Schuchardt45910792020-12-13 19:13:57 +010050 cout->set_attribute(cout, EFI_LIGHTBLUE | EFI_BACKGROUND_BLACK);
51}
Heinrich Schuchardt12083ba2020-11-04 22:00:48 +010052
53/**
Heinrich Schuchardt2e88aad2021-01-17 05:13:21 +010054 * efi_input_yn() - get answer to yes/no question
55 *
56 * Return:
57 * y or Y
58 * EFI_SUCCESS
59 * n or N
60 * EFI_ACCESS_DENIED
61 * ESC
62 * EFI_ABORTED
63 */
64static efi_status_t efi_input_yn(void)
65{
66 struct efi_input_key key = {0};
67 efi_uintn_t index;
68 efi_status_t ret;
69
70 /* Drain the console input */
71 ret = cin->reset(cin, true);
72 for (;;) {
73 ret = bs->wait_for_event(1, &cin->wait_for_key, &index);
74 if (ret != EFI_SUCCESS)
75 continue;
76 ret = cin->read_key_stroke(cin, &key);
77 if (ret != EFI_SUCCESS)
78 continue;
79 switch (key.scan_code) {
80 case 0x17: /* Escape */
81 return EFI_ABORTED;
82 default:
83 break;
84 }
85 /* Convert to lower case */
86 switch (key.unicode_char | 0x20) {
87 case 'y':
88 return EFI_SUCCESS;
89 case 'n':
90 return EFI_ACCESS_DENIED;
91 default:
92 break;
93 }
94 }
95}
96
97/**
98 * efi_input() - read string from console
Heinrich Schuchardt12083ba2020-11-04 22:00:48 +010099 *
100 * @buffer: input buffer
101 * @buffer_size: buffer size
102 * Return: status code
103 */
104static efi_status_t efi_input(u16 *buffer, efi_uintn_t buffer_size)
105{
106 struct efi_input_key key = {0};
107 efi_uintn_t index;
108 efi_uintn_t pos = 0;
109 u16 outbuf[2] = L" ";
110 efi_status_t ret;
111
112 /* Drain the console input */
113 ret = cin->reset(cin, true);
Heinrich Schuchardt45910792020-12-13 19:13:57 +0100114 *buffer = 0;
Heinrich Schuchardt12083ba2020-11-04 22:00:48 +0100115 for (;;) {
116 ret = bs->wait_for_event(1, &cin->wait_for_key, &index);
117 if (ret != EFI_SUCCESS)
118 continue;
119 ret = cin->read_key_stroke(cin, &key);
120 if (ret != EFI_SUCCESS)
121 continue;
122 switch (key.scan_code) {
123 case 0x17: /* Escape */
Heinrich Schuchardt9d4c19e2021-01-19 10:06:00 +0100124 print(L"\r\nAborted\r\n");
Heinrich Schuchardt12083ba2020-11-04 22:00:48 +0100125 return EFI_ABORTED;
126 default:
127 break;
128 }
129 switch (key.unicode_char) {
130 case 0x08: /* Backspace */
131 if (pos) {
132 buffer[pos--] = 0;
Heinrich Schuchardt9d4c19e2021-01-19 10:06:00 +0100133 print(L"\b \b");
Heinrich Schuchardt12083ba2020-11-04 22:00:48 +0100134 }
135 break;
136 case 0x0a: /* Linefeed */
137 case 0x0d: /* Carriage return */
Heinrich Schuchardt9d4c19e2021-01-19 10:06:00 +0100138 print(L"\r\n");
Heinrich Schuchardt12083ba2020-11-04 22:00:48 +0100139 return EFI_SUCCESS;
140 default:
141 break;
142 }
143 /* Ignore surrogate codes */
144 if (key.unicode_char >= 0xD800 && key.unicode_char <= 0xDBFF)
145 continue;
146 if (key.unicode_char >= 0x20 &&
147 pos < buffer_size - 1) {
148 *outbuf = key.unicode_char;
149 buffer[pos++] = key.unicode_char;
Heinrich Schuchardt45910792020-12-13 19:13:57 +0100150 buffer[pos] = 0;
Heinrich Schuchardt9d4c19e2021-01-19 10:06:00 +0100151 print(outbuf);
Heinrich Schuchardt12083ba2020-11-04 22:00:48 +0100152 }
153 }
154}
155
156/*
157 * Convert FDT value to host endianness.
158 *
159 * @val FDT value
160 * @return converted value
161 */
162static u32 f2h(fdt32_t val)
163{
164 char *buf = (char *)&val;
165 char i;
166
167 /* Swap the bytes */
168 i = buf[0]; buf[0] = buf[3]; buf[3] = i;
169 i = buf[1]; buf[1] = buf[2]; buf[2] = i;
170 return *(u32 *)buf;
171}
172
173/**
174 * get_dtb() - get device tree
175 *
176 * @systable: system table
177 * Return: device tree or NULL
178 */
179void *get_dtb(struct efi_system_table *systable)
180{
181 void *dtb = NULL;
182 efi_uintn_t i;
183
184 for (i = 0; i < systable->nr_tables; ++i) {
185 if (!memcmp(&systable->tables[i].guid, &fdt_guid,
186 sizeof(efi_guid_t))) {
187 dtb = systable->tables[i].table;
188 break;
189 }
190 }
191 return dtb;
192}
193
194/**
Heinrich Schuchardt45910792020-12-13 19:13:57 +0100195 * skip_whitespace() - skip over leading whitespace
Heinrich Schuchardt12083ba2020-11-04 22:00:48 +0100196 *
Heinrich Schuchardt45910792020-12-13 19:13:57 +0100197 * @pos: UTF-16 string
198 * Return: pointer to first non-whitespace
Heinrich Schuchardt12083ba2020-11-04 22:00:48 +0100199 */
Heinrich Schuchardt45910792020-12-13 19:13:57 +0100200u16 *skip_whitespace(u16 *pos)
Heinrich Schuchardt12083ba2020-11-04 22:00:48 +0100201{
Heinrich Schuchardt45910792020-12-13 19:13:57 +0100202 for (; *pos && *pos <= 0x20; ++pos)
203 ;
204 return pos;
205}
206
207/**
208 * starts_with() - check if @string starts with @keyword
209 *
210 * @string: string to search for keyword
211 * @keyword: keyword to be searched
212 * Return: true fi @string starts with the keyword
213 */
214bool starts_with(u16 *string, u16 *keyword)
215{
216 for (; *keyword; ++string, ++keyword) {
217 if (*string != *keyword)
218 return false;
219 }
220 return true;
221}
222
223/**
224 * do_help() - print help
225 */
226void do_help(void)
227{
Heinrich Schuchardt9d4c19e2021-01-19 10:06:00 +0100228 error(L"load <dtb> - load device-tree from file\r\n");
229 error(L"save <dtb> - save device-tree to file\r\n");
230 error(L"exit - exit the shell\r\n");
Heinrich Schuchardt45910792020-12-13 19:13:57 +0100231}
232
233/**
234 * do_load() - load and install device-tree
235 *
236 * @filename: file name
237 * Return: status code
238 */
239efi_status_t do_load(u16 *filename)
240{
241 struct efi_dt_fixup_protocol *dt_fixup_prot;
Heinrich Schuchardt12083ba2020-11-04 22:00:48 +0100242 struct efi_loaded_image *loaded_image;
243 struct efi_simple_file_system_protocol *file_system;
Heinrich Schuchardt45910792020-12-13 19:13:57 +0100244 struct efi_file_handle *root = NULL, *file = NULL;
245 u64 addr = 0;
246 struct efi_file_info *info;
Heinrich Schuchardt12083ba2020-11-04 22:00:48 +0100247 struct fdt_header *dtb;
Heinrich Schuchardt45910792020-12-13 19:13:57 +0100248 efi_uintn_t buffer_size;
249 efi_uintn_t pages;
250 efi_status_t ret, ret2;
Heinrich Schuchardt12083ba2020-11-04 22:00:48 +0100251
Heinrich Schuchardt45910792020-12-13 19:13:57 +0100252 ret = bs->locate_protocol(&efi_dt_fixup_protocol_guid, NULL,
253 (void **)&dt_fixup_prot);
254 if (ret != EFI_SUCCESS) {
Heinrich Schuchardt9d4c19e2021-01-19 10:06:00 +0100255 error(L"Device-tree fix-up protocol not found\r\n");
Heinrich Schuchardt45910792020-12-13 19:13:57 +0100256 return ret;
257 }
Heinrich Schuchardt12083ba2020-11-04 22:00:48 +0100258
Heinrich Schuchardt45910792020-12-13 19:13:57 +0100259 filename = skip_whitespace(filename);
260
261 ret = bs->open_protocol(handle, &loaded_image_guid,
262 (void **)&loaded_image, NULL, NULL,
263 EFI_OPEN_PROTOCOL_GET_PROTOCOL);
264 if (ret != EFI_SUCCESS) {
Heinrich Schuchardt9d4c19e2021-01-19 10:06:00 +0100265 error(L"Loaded image protocol not found\r\n");
Heinrich Schuchardt45910792020-12-13 19:13:57 +0100266 return ret;
267 }
268 /* Open the simple file system protocol */
269 ret = bs->open_protocol(loaded_image->device_handle,
270 &guid_simple_file_system_protocol,
271 (void **)&file_system, NULL, NULL,
272 EFI_OPEN_PROTOCOL_GET_PROTOCOL);
273 if (ret != EFI_SUCCESS) {
Heinrich Schuchardt9d4c19e2021-01-19 10:06:00 +0100274 error(L"Failed to open simple file system protocol\r\n");
Heinrich Schuchardt45910792020-12-13 19:13:57 +0100275 goto out;
276 }
277
278 /* Open volume */
279 ret = file_system->open_volume(file_system, &root);
280 if (ret != EFI_SUCCESS) {
Heinrich Schuchardt9d4c19e2021-01-19 10:06:00 +0100281 error(L"Failed to open volume\r\n");
Heinrich Schuchardt45910792020-12-13 19:13:57 +0100282 goto out;
283 }
284
285 /* Open file */
286 ret = root->open(root, &file, filename, EFI_FILE_MODE_READ, 0);
287 if (ret != EFI_SUCCESS) {
Heinrich Schuchardt9d4c19e2021-01-19 10:06:00 +0100288 error(L"File not found\r\n");
Heinrich Schuchardt45910792020-12-13 19:13:57 +0100289 goto out;
290 }
291 /* Get file size */
292 buffer_size = 0;
293 ret = file->getinfo(file, &efi_file_info_guid, &buffer_size, NULL);
294 if (ret != EFI_BUFFER_TOO_SMALL) {
Heinrich Schuchardt9d4c19e2021-01-19 10:06:00 +0100295 error(L"Can't get file info size\r\n");
Heinrich Schuchardt45910792020-12-13 19:13:57 +0100296 goto out;
297 }
298 ret = bs->allocate_pool(EFI_LOADER_DATA, buffer_size, (void **)&info);
299 if (ret != EFI_SUCCESS) {
Heinrich Schuchardt9d4c19e2021-01-19 10:06:00 +0100300 error(L"Out of memory\r\n");
Heinrich Schuchardt45910792020-12-13 19:13:57 +0100301 goto out;
302 }
303 ret = file->getinfo(file, &efi_file_info_guid, &buffer_size, info);
304 if (ret != EFI_SUCCESS) {
Heinrich Schuchardt9d4c19e2021-01-19 10:06:00 +0100305 error(L"Can't get file info\r\n");
Heinrich Schuchardt45910792020-12-13 19:13:57 +0100306 goto out;
307 }
308 buffer_size = info->file_size;
309 pages = efi_size_in_pages(buffer_size);
310 ret = bs->free_pool(info);
311 if (ret != EFI_SUCCESS)
Heinrich Schuchardt9d4c19e2021-01-19 10:06:00 +0100312 error(L"Can't free memory pool\r\n");
Heinrich Schuchardt45910792020-12-13 19:13:57 +0100313 /* Read file */
314 ret = bs->allocate_pages(EFI_ALLOCATE_ANY_PAGES,
315 EFI_ACPI_RECLAIM_MEMORY,
316 pages, &addr);
317 if (ret != EFI_SUCCESS) {
Heinrich Schuchardt9d4c19e2021-01-19 10:06:00 +0100318 error(L"Out of memory\r\n");
Heinrich Schuchardt45910792020-12-13 19:13:57 +0100319 goto out;
320 }
321 dtb = (struct fdt_header *)(uintptr_t)addr;
322 ret = file->read(file, &buffer_size, dtb);
323 if (ret != EFI_SUCCESS) {
Heinrich Schuchardt9d4c19e2021-01-19 10:06:00 +0100324 error(L"Can't read file\r\n");
Heinrich Schuchardt45910792020-12-13 19:13:57 +0100325 goto out;
326 }
327 /* Fixup file, expecting EFI_BUFFER_TOO_SMALL */
328 ret = dt_fixup_prot->fixup(dt_fixup_prot, dtb, &buffer_size,
329 EFI_DT_APPLY_FIXUPS | EFI_DT_RESERVE_MEMORY |
330 EFI_DT_INSTALL_TABLE);
331 if (ret == EFI_BUFFER_TOO_SMALL) {
332 /* Read file into larger buffer */
333 ret = bs->free_pages(addr, pages);
334 if (ret != EFI_SUCCESS)
Heinrich Schuchardt9d4c19e2021-01-19 10:06:00 +0100335 error(L"Can't free memory pages\r\n");
Heinrich Schuchardt45910792020-12-13 19:13:57 +0100336 pages = efi_size_in_pages(buffer_size);
337 ret = bs->allocate_pages(EFI_ALLOCATE_ANY_PAGES,
338 EFI_ACPI_RECLAIM_MEMORY,
339 pages, &addr);
340 if (ret != EFI_SUCCESS) {
Heinrich Schuchardt9d4c19e2021-01-19 10:06:00 +0100341 error(L"Out of memory\r\n");
Heinrich Schuchardt45910792020-12-13 19:13:57 +0100342 goto out;
343 }
344 dtb = (struct fdt_header *)(uintptr_t)addr;
345 ret = file->setpos(file, 0);
346 if (ret != EFI_SUCCESS) {
Heinrich Schuchardt9d4c19e2021-01-19 10:06:00 +0100347 error(L"Can't position file\r\n");
Heinrich Schuchardt45910792020-12-13 19:13:57 +0100348 goto out;
349 }
350 ret = file->read(file, &buffer_size, dtb);
351 if (ret != EFI_SUCCESS) {
Heinrich Schuchardt9d4c19e2021-01-19 10:06:00 +0100352 error(L"Can't read file\r\n");
Heinrich Schuchardt45910792020-12-13 19:13:57 +0100353 goto out;
354 }
355 buffer_size = pages << EFI_PAGE_SHIFT;
356 ret = dt_fixup_prot->fixup(
357 dt_fixup_prot, dtb, &buffer_size,
358 EFI_DT_APPLY_FIXUPS | EFI_DT_RESERVE_MEMORY |
359 EFI_DT_INSTALL_TABLE);
360 }
361 if (ret == EFI_SUCCESS)
Heinrich Schuchardt9d4c19e2021-01-19 10:06:00 +0100362 print(L"device-tree installed\r\n");
Heinrich Schuchardt45910792020-12-13 19:13:57 +0100363 else
Heinrich Schuchardt9d4c19e2021-01-19 10:06:00 +0100364 error(L"Device-tree fix-up failed\r\n");
Heinrich Schuchardt45910792020-12-13 19:13:57 +0100365out:
366 if (addr) {
367 ret2 = bs->free_pages(addr, pages);
368 if (ret2 != EFI_SUCCESS)
Heinrich Schuchardt9d4c19e2021-01-19 10:06:00 +0100369 error(L"Can't free memory pages\r\n");
Heinrich Schuchardt45910792020-12-13 19:13:57 +0100370 }
371 if (file) {
372 ret2 = file->close(file);
373 if (ret2 != EFI_SUCCESS)
Heinrich Schuchardt9d4c19e2021-01-19 10:06:00 +0100374 error(L"Can't close file\r\n");
Heinrich Schuchardt45910792020-12-13 19:13:57 +0100375 }
376 if (root) {
377 ret2 = root->close(root);
378 if (ret2 != EFI_SUCCESS)
Heinrich Schuchardt9d4c19e2021-01-19 10:06:00 +0100379 error(L"Can't close volume\r\n");
Heinrich Schuchardt45910792020-12-13 19:13:57 +0100380 }
381 return ret;
382}
383
384/**
385 * do_save() - save current device-tree
386 *
387 * @filename: file name
388 * Return: status code
389 */
390efi_status_t do_save(u16 *filename)
391{
392 struct efi_loaded_image *loaded_image;
393 struct efi_simple_file_system_protocol *file_system;
394 efi_uintn_t dtb_size;
395 struct efi_file_handle *root, *file;
396 struct fdt_header *dtb;
397 efi_uintn_t ret;
Heinrich Schuchardt12083ba2020-11-04 22:00:48 +0100398
399 dtb = get_dtb(systable);
400 if (!dtb) {
Heinrich Schuchardt9d4c19e2021-01-19 10:06:00 +0100401 error(L"DTB not found\r\n");
Heinrich Schuchardt12083ba2020-11-04 22:00:48 +0100402 return EFI_NOT_FOUND;
403 }
404 if (f2h(dtb->magic) != FDT_MAGIC) {
Heinrich Schuchardt9d4c19e2021-01-19 10:06:00 +0100405 error(L"Wrong device tree magic\r\n");
Heinrich Schuchardt12083ba2020-11-04 22:00:48 +0100406 return EFI_NOT_FOUND;
407 }
408 dtb_size = f2h(dtb->totalsize);
409
Heinrich Schuchardt45910792020-12-13 19:13:57 +0100410 filename = skip_whitespace(filename);
Heinrich Schuchardt12083ba2020-11-04 22:00:48 +0100411
412 ret = bs->open_protocol(handle, &loaded_image_guid,
413 (void **)&loaded_image, NULL, NULL,
414 EFI_OPEN_PROTOCOL_GET_PROTOCOL);
415 if (ret != EFI_SUCCESS) {
Heinrich Schuchardt9d4c19e2021-01-19 10:06:00 +0100416 error(L"Loaded image protocol not found\r\n");
Heinrich Schuchardt12083ba2020-11-04 22:00:48 +0100417 return ret;
418 }
419
420 /* Open the simple file system protocol */
421 ret = bs->open_protocol(loaded_image->device_handle,
422 &guid_simple_file_system_protocol,
423 (void **)&file_system, NULL, NULL,
424 EFI_OPEN_PROTOCOL_GET_PROTOCOL);
425 if (ret != EFI_SUCCESS) {
Heinrich Schuchardt9d4c19e2021-01-19 10:06:00 +0100426 error(L"Failed to open simple file system protocol\r\n");
Heinrich Schuchardt12083ba2020-11-04 22:00:48 +0100427 return ret;
428 }
429
430 /* Open volume */
431 ret = file_system->open_volume(file_system, &root);
432 if (ret != EFI_SUCCESS) {
Heinrich Schuchardt9d4c19e2021-01-19 10:06:00 +0100433 error(L"Failed to open volume\r\n");
Heinrich Schuchardt12083ba2020-11-04 22:00:48 +0100434 return ret;
435 }
Heinrich Schuchardt2e88aad2021-01-17 05:13:21 +0100436 /* Check if file already exists */
437 ret = root->open(root, &file, filename, EFI_FILE_MODE_READ, 0);
438 if (ret == EFI_SUCCESS) {
439 file->close(file);
Heinrich Schuchardt9d4c19e2021-01-19 10:06:00 +0100440 print(L"Overwrite existing file (y/n)? ");
Heinrich Schuchardt2e88aad2021-01-17 05:13:21 +0100441 ret = efi_input_yn();
Heinrich Schuchardt9d4c19e2021-01-19 10:06:00 +0100442 print(L"\r\n");
Heinrich Schuchardt2e88aad2021-01-17 05:13:21 +0100443 if (ret != EFI_SUCCESS) {
444 root->close(root);
Heinrich Schuchardt9d4c19e2021-01-19 10:06:00 +0100445 error(L"Aborted by user\r\n");
Heinrich Schuchardt2e88aad2021-01-17 05:13:21 +0100446 return ret;
447 }
448 }
449
Heinrich Schuchardt12083ba2020-11-04 22:00:48 +0100450 /* Create file */
451 ret = root->open(root, &file, filename,
452 EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE |
453 EFI_FILE_MODE_CREATE, EFI_FILE_ARCHIVE);
454 if (ret == EFI_SUCCESS) {
455 /* Write file */
456 ret = file->write(file, &dtb_size, dtb);
457 if (ret != EFI_SUCCESS)
Heinrich Schuchardt9d4c19e2021-01-19 10:06:00 +0100458 error(L"Failed to write file\r\n");
Heinrich Schuchardt12083ba2020-11-04 22:00:48 +0100459 file->close(file);
460 } else {
Heinrich Schuchardt9d4c19e2021-01-19 10:06:00 +0100461 error(L"Failed to open file\r\n");
Heinrich Schuchardt12083ba2020-11-04 22:00:48 +0100462 }
463 root->close(root);
464
465 if (ret == EFI_SUCCESS) {
Heinrich Schuchardt9d4c19e2021-01-19 10:06:00 +0100466 print(filename);
467 print(L" written\r\n");
Heinrich Schuchardt12083ba2020-11-04 22:00:48 +0100468 }
469
470 return ret;
471}
Heinrich Schuchardt45910792020-12-13 19:13:57 +0100472
473/**
474 * efi_main() - entry point of the EFI application.
475 *
476 * @handle: handle of the loaded image
477 * @systab: system table
478 * @return: status code
479 */
480efi_status_t EFIAPI efi_main(efi_handle_t image_handle,
481 struct efi_system_table *systab)
482{
483 handle = image_handle;
484 systable = systab;
485 cerr = systable->std_err;
486 cout = systable->con_out;
487 cin = systable->con_in;
488 bs = systable->boottime;
489
490 cout->set_attribute(cout, EFI_LIGHTBLUE | EFI_BACKGROUND_BLACK);
491 cout->clear_screen(cout);
492 cout->set_attribute(cout, EFI_WHITE | EFI_BACKGROUND_BLACK);
Heinrich Schuchardt9d4c19e2021-01-19 10:06:00 +0100493 print(L"DTB Dump\r\n========\r\n\r\n");
Heinrich Schuchardt45910792020-12-13 19:13:57 +0100494 cout->set_attribute(cout, EFI_LIGHTBLUE | EFI_BACKGROUND_BLACK);
495
496 for (;;) {
497 u16 command[BUFFER_SIZE];
498 u16 *pos;
499 efi_uintn_t ret;
500
Heinrich Schuchardt9d4c19e2021-01-19 10:06:00 +0100501 print(L"=> ");
Heinrich Schuchardt45910792020-12-13 19:13:57 +0100502 ret = efi_input(command, sizeof(command));
503 if (ret == EFI_ABORTED)
504 break;
505 pos = skip_whitespace(command);
506 if (starts_with(pos, L"exit"))
507 break;
508 else if (starts_with(pos, L"load "))
509 do_load(pos + 5);
510 else if (starts_with(pos, L"save "))
511 do_save(pos + 5);
512 else
513 do_help();
514 }
515
516 cout->set_attribute(cout, EFI_LIGHTGRAY | EFI_BACKGROUND_BLACK);
517 cout->clear_screen(cout);
518 return EFI_SUCCESS;
519}