1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright 2020, Heinrich Schuchardt <xypron.glpk@gmx.de>
4  *
5  * initrddump.efi saves the initial RAM disk provided via the
6  * EFI_LOAD_FILE2_PROTOCOL.
7  *
8  * Specifying 'nocolor' as load option data suppresses colored output and
9  * clearing of the screen.
10  */
11 
12 #include <efi_api.h>
13 #include <efi_load_initrd.h>
14 
15 #define BUFFER_SIZE 64
16 #define ESC 0x17
17 
18 #define efi_size_in_pages(size) (((size) + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT)
19 
20 static struct efi_system_table *systable;
21 static struct efi_boot_services *bs;
22 static struct efi_simple_text_output_protocol *cerr;
23 static struct efi_simple_text_output_protocol *cout;
24 static struct efi_simple_text_input_protocol *cin;
25 static const efi_guid_t loaded_image_guid = EFI_LOADED_IMAGE_PROTOCOL_GUID;
26 static const efi_guid_t guid_simple_file_system_protocol =
27 					EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID;
28 static const efi_guid_t load_file2_guid = EFI_LOAD_FILE2_PROTOCOL_GUID;
29 static efi_handle_t handle;
30 static bool nocolor;
31 
32 /*
33  * Device path defined by Linux to identify the handle providing the
34  * EFI_LOAD_FILE2_PROTOCOL used for loading the initial ramdisk.
35  */
36 static const struct efi_lo_dp_prefix initrd_dp = {
37 	.vendor = {
38 		{
39 		   DEVICE_PATH_TYPE_MEDIA_DEVICE,
40 		   DEVICE_PATH_SUB_TYPE_VENDOR_PATH,
41 		   sizeof(initrd_dp.vendor),
42 		},
43 		EFI_INITRD_MEDIA_GUID,
44 	},
45 	.end = {
46 		DEVICE_PATH_TYPE_END,
47 		DEVICE_PATH_SUB_TYPE_END,
48 		sizeof(initrd_dp.end),
49 	}
50 };
51 
52 /**
53  * color() - set foreground color
54  *
55  * @color:	foreground color
56  */
color(u8 color)57 static void color(u8 color)
58 {
59 	if (!nocolor)
60 		cout->set_attribute(cout, color | EFI_BACKGROUND_BLACK);
61 }
62 
63 /**
64  * print() - print string
65  *
66  * @string:	text
67  */
print(u16 * string)68 static void print(u16 *string)
69 {
70 	cout->output_string(cout, string);
71 }
72 
73 /**
74  * cls() - clear screen
75  */
cls(void)76 static void cls(void)
77 {
78 	if (nocolor)
79 		print(u"\r\n");
80 	else
81 		cout->clear_screen(cout);
82 }
83 
84 /**
85  * error() - print error string
86  *
87  * @string:	error text
88  */
error(u16 * string)89 static void error(u16 *string)
90 {
91 	color(EFI_LIGHTRED);
92 	print(string);
93 	color(EFI_LIGHTBLUE);
94 }
95 
96 /*
97  * printx() - print hexadecimal number
98  *
99  * @val:	value to print;
100  * @prec:	minimum number of digits to print
101  */
printx(u64 val,u32 prec)102 static void printx(u64 val, u32 prec)
103 {
104 	int i;
105 	u16 c;
106 	u16 buf[16];
107 	u16 *pos = buf;
108 
109 	for (i = 2 * sizeof(val) - 1; i >= 0; --i) {
110 		c = (val >> (4 * i)) & 0x0f;
111 		if (c || pos != buf || !i || i < prec) {
112 			c += '0';
113 			if (c > '9')
114 				c += 'a' - '9' - 1;
115 			*pos++ = c;
116 		}
117 	}
118 	*pos = 0;
119 	print(buf);
120 }
121 
122 /**
123  * efi_drain_input() - drain console input
124  */
efi_drain_input(void)125 static void efi_drain_input(void)
126 {
127 	cin->reset(cin, true);
128 }
129 
130 /**
131  * efi_input_yn() - get answer to yes/no question
132  *
133  * Return:
134  * y or Y
135  *     EFI_SUCCESS
136  * n or N
137  *     EFI_ACCESS_DENIED
138  * ESC
139  *     EFI_ABORTED
140  */
efi_input_yn(void)141 static efi_status_t efi_input_yn(void)
142 {
143 	struct efi_input_key key = {0};
144 	efi_uintn_t index;
145 	efi_status_t ret;
146 
147 	for (;;) {
148 		ret = bs->wait_for_event(1, &cin->wait_for_key, &index);
149 		if (ret != EFI_SUCCESS)
150 			continue;
151 		ret = cin->read_key_stroke(cin, &key);
152 		if (ret != EFI_SUCCESS)
153 			continue;
154 		switch (key.scan_code) {
155 		case 0x17: /* Escape */
156 			return EFI_ABORTED;
157 		default:
158 			break;
159 		}
160 		/* Convert to lower case */
161 		switch (key.unicode_char | 0x20) {
162 		case 'y':
163 			return EFI_SUCCESS;
164 		case 'n':
165 			return EFI_ACCESS_DENIED;
166 		default:
167 			break;
168 		}
169 	}
170 }
171 
172 /**
173  * efi_input() - read string from console
174  *
175  * @buffer:		input buffer
176  * @buffer_size:	buffer size
177  * Return:		status code
178  */
efi_input(u16 * buffer,efi_uintn_t buffer_size)179 static efi_status_t efi_input(u16 *buffer, efi_uintn_t buffer_size)
180 {
181 	struct efi_input_key key = {0};
182 	efi_uintn_t index;
183 	efi_uintn_t pos = 0;
184 	u16 outbuf[2] = u" ";
185 	efi_status_t ret;
186 
187 	*buffer = 0;
188 	for (;;) {
189 		ret = bs->wait_for_event(1, &cin->wait_for_key, &index);
190 		if (ret != EFI_SUCCESS)
191 			continue;
192 		ret = cin->read_key_stroke(cin, &key);
193 		if (ret != EFI_SUCCESS)
194 			continue;
195 		switch (key.scan_code) {
196 		case 0x17: /* Escape */
197 			print(u"\r\nAborted\r\n");
198 			return EFI_ABORTED;
199 		default:
200 			break;
201 		}
202 		switch (key.unicode_char) {
203 		case 0x08: /* Backspace */
204 			if (pos) {
205 				buffer[pos--] = 0;
206 				print(u"\b \b");
207 			}
208 			break;
209 		case 0x0a: /* Linefeed */
210 		case 0x0d: /* Carriage return */
211 			print(u"\r\n");
212 			return EFI_SUCCESS;
213 		default:
214 			break;
215 		}
216 		/* Ignore surrogate codes */
217 		if (key.unicode_char >= 0xD800 && key.unicode_char <= 0xDBFF)
218 			continue;
219 		if (key.unicode_char >= 0x20 &&
220 		    pos < buffer_size - 1) {
221 			*outbuf = key.unicode_char;
222 			buffer[pos++] = key.unicode_char;
223 			buffer[pos] = 0;
224 			print(outbuf);
225 		}
226 	}
227 }
228 
229 /**
230  * skip_whitespace() - skip over leading whitespace
231  *
232  * @pos:	UTF-16 string
233  * Return:	pointer to first non-whitespace
234  */
skip_whitespace(u16 * pos)235 static u16 *skip_whitespace(u16 *pos)
236 {
237 	for (; *pos && *pos <= 0x20; ++pos)
238 		;
239 	return pos;
240 }
241 
242 /**
243  * starts_with() - check if @string starts with @keyword
244  *
245  * @string:	string to search for keyword
246  * @keyword:	keyword to be searched
247  * Return:	true if @string starts with the keyword
248  */
starts_with(u16 * string,u16 * keyword)249 static bool starts_with(u16 *string, u16 *keyword)
250 {
251 	if (!string || !keyword)
252 		return false;
253 
254 	for (; *keyword; ++string, ++keyword) {
255 		if (*string != *keyword)
256 			return false;
257 	}
258 	return true;
259 }
260 
261 /**
262  * do_help() - print help
263  */
do_help(void)264 static void do_help(void)
265 {
266 	error(u"load          - show length and CRC32 of initial RAM disk\r\n");
267 	error(u"save <initrd> - save initial RAM disk to file\r\n");
268 	error(u"exit          - exit the shell\r\n");
269 }
270 
271 /**
272  * get_initrd() - read initial RAM disk via EFI_LOAD_FILE2_PROTOCOL
273  *
274  * @initrd:		on return buffer with initial RAM disk
275  * @initrd_size:	size of initial RAM disk
276  * Return:		status code
277  */
get_initrd(void ** initrd,efi_uintn_t * initrd_size)278 static efi_status_t get_initrd(void **initrd, efi_uintn_t *initrd_size)
279 {
280 	struct efi_device_path *dp = (struct efi_device_path *)&initrd_dp;
281 	struct efi_load_file_protocol *load_file2_prot;
282 	u64 buffer;
283 	efi_handle_t handle;
284 	efi_status_t ret;
285 
286 	*initrd = NULL;
287 	*initrd_size = 0;
288 	ret = bs->locate_device_path(&load_file2_guid, &dp, &handle);
289 	if (ret != EFI_SUCCESS) {
290 		error(u"Load File2 protocol not found\r\n");
291 		return ret;
292 	}
293 	ret = bs->open_protocol(handle, &load_file2_guid,
294 				(void **)&load_file2_prot, NULL, NULL,
295 				EFI_OPEN_PROTOCOL_GET_PROTOCOL);
296 	ret = load_file2_prot->load_file(load_file2_prot, dp, false,
297 					 initrd_size, NULL);
298 	if (ret != EFI_BUFFER_TOO_SMALL) {
299 		error(u"Load File2 protocol does not provide file length\r\n");
300 		return EFI_LOAD_ERROR;
301 	}
302 	ret = bs->allocate_pages(EFI_ALLOCATE_ANY_PAGES, EFI_LOADER_DATA,
303 				 efi_size_in_pages(*initrd_size), &buffer);
304 	if (ret != EFI_SUCCESS) {
305 		error(u"Out of memory\r\n");
306 		return ret;
307 	}
308 	*initrd = (void *)(uintptr_t)buffer;
309 	ret = load_file2_prot->load_file(load_file2_prot, dp, false,
310 					 initrd_size, *initrd);
311 	if (ret != EFI_SUCCESS) {
312 		error(u"Load File2 protocol failed to provide file\r\n");
313 		bs->free_pages(buffer, efi_size_in_pages(*initrd_size));
314 		return EFI_LOAD_ERROR;
315 	}
316 	return ret;
317 }
318 
319 /**
320  * do_load() - load initial RAM disk and display CRC32 and length
321  *
322  * @filename:	file name
323  * Return:	status code
324  */
do_load(void)325 static efi_status_t do_load(void)
326 {
327 	void *initrd;
328 	efi_uintn_t initrd_size;
329 	u32 crc32;
330 	efi_uintn_t ret;
331 
332 	ret =  get_initrd(&initrd, &initrd_size);
333 	if (ret != EFI_SUCCESS)
334 		return ret;
335 	print(u"length: 0x");
336 	printx(initrd_size, 1);
337 	print(u"\r\n");
338 
339 	ret = bs->calculate_crc32(initrd, initrd_size, &crc32);
340 	if (ret != EFI_SUCCESS) {
341 		error(u"Calculating CRC32 failed\r\n");
342 		return EFI_LOAD_ERROR;
343 	}
344 	print(u"crc32: 0x");
345 	printx(crc32, 8);
346 	print(u"\r\n");
347 
348 	return EFI_SUCCESS;
349 }
350 
351 /**
352  * do_save() - save initial RAM disk
353  *
354  * @filename:	file name
355  * Return:	status code
356  */
do_save(u16 * filename)357 static efi_status_t do_save(u16 *filename)
358 {
359 	struct efi_loaded_image *loaded_image;
360 	struct efi_simple_file_system_protocol *file_system;
361 	struct efi_file_handle *root, *file;
362 	void *initrd;
363 	efi_uintn_t initrd_size;
364 	efi_uintn_t ret;
365 
366 	ret = get_initrd(&initrd, &initrd_size);
367 	if (ret != EFI_SUCCESS)
368 		return ret;
369 
370 	filename = skip_whitespace(filename);
371 
372 	ret = bs->open_protocol(handle, &loaded_image_guid,
373 				(void **)&loaded_image, NULL, NULL,
374 				EFI_OPEN_PROTOCOL_GET_PROTOCOL);
375 	if (ret != EFI_SUCCESS) {
376 		error(u"Loaded image protocol not found\r\n");
377 		goto out;
378 	}
379 
380 	/* Open the simple file system protocol */
381 	ret = bs->open_protocol(loaded_image->device_handle,
382 				&guid_simple_file_system_protocol,
383 				(void **)&file_system, NULL, NULL,
384 				EFI_OPEN_PROTOCOL_GET_PROTOCOL);
385 	if (ret != EFI_SUCCESS) {
386 		error(u"Failed to open simple file system protocol\r\n");
387 		goto out;
388 	}
389 
390 	/* Open volume */
391 	ret = file_system->open_volume(file_system, &root);
392 	if (ret != EFI_SUCCESS) {
393 		error(u"Failed to open volume\r\n");
394 		goto out;
395 	}
396 	/* Check if file already exists */
397 	ret = root->open(root, &file, filename, EFI_FILE_MODE_READ, 0);
398 	if (ret == EFI_SUCCESS) {
399 		file->close(file);
400 		efi_drain_input();
401 		print(u"Overwrite existing file (y/n)? ");
402 		ret = efi_input_yn();
403 		print(u"\r\n");
404 		if (ret != EFI_SUCCESS) {
405 			root->close(root);
406 			error(u"Aborted by user\r\n");
407 			goto out;
408 		}
409 	}
410 
411 	/* Create file */
412 	ret = root->open(root, &file, filename,
413 			 EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE |
414 			 EFI_FILE_MODE_CREATE, EFI_FILE_ARCHIVE);
415 	if (ret == EFI_SUCCESS) {
416 		/* Write file */
417 		ret = file->write(file, &initrd_size, initrd);
418 		if (ret != EFI_SUCCESS) {
419 			error(u"Failed to write file\r\n");
420 		} else {
421 			print(filename);
422 			print(u" written\r\n");
423 		}
424 		file->close(file);
425 	} else {
426 		error(u"Failed to open file\r\n");
427 	}
428 	root->close(root);
429 
430 out:
431 	if (initrd)
432 		bs->free_pages((uintptr_t)initrd,
433 			       efi_size_in_pages(initrd_size));
434 	return ret;
435 }
436 
437 /**
438  * get_load_options() - get load options
439  *
440  * Return:	load options or NULL
441  */
get_load_options(void)442 static u16 *get_load_options(void)
443 {
444 	efi_status_t ret;
445 	struct efi_loaded_image *loaded_image;
446 
447 	ret = bs->open_protocol(handle, &loaded_image_guid,
448 				(void **)&loaded_image, NULL, NULL,
449 				EFI_OPEN_PROTOCOL_GET_PROTOCOL);
450 	if (ret != EFI_SUCCESS) {
451 		error(u"Loaded image protocol not found\r\n");
452 		return NULL;
453 	}
454 
455 	if (!loaded_image->load_options_size || !loaded_image->load_options)
456 		return NULL;
457 
458 	return loaded_image->load_options;
459 }
460 
461 /**
462  * efi_main() - entry point of the EFI application.
463  *
464  * @handle:	handle of the loaded image
465  * @systab:	system table
466  * Return:	status code
467  */
efi_main(efi_handle_t image_handle,struct efi_system_table * systab)468 efi_status_t EFIAPI efi_main(efi_handle_t image_handle,
469 			     struct efi_system_table *systab)
470 {
471 	u16 *load_options;
472 
473 	handle = image_handle;
474 	systable = systab;
475 	cerr = systable->std_err;
476 	cout = systable->con_out;
477 	cin = systable->con_in;
478 	bs = systable->boottime;
479 	load_options = get_load_options();
480 
481 	if (starts_with(load_options, u"nocolor"))
482 		nocolor = true;
483 
484 	color(EFI_WHITE);
485 	cls();
486 	print(u"INITRD Dump\r\n===========\r\n\r\n");
487 	color(EFI_LIGHTBLUE);
488 
489 	for (;;) {
490 		u16 command[BUFFER_SIZE];
491 		u16 *pos;
492 		efi_uintn_t ret;
493 
494 		efi_drain_input();
495 		print(u"=> ");
496 		ret = efi_input(command, sizeof(command));
497 		if (ret == EFI_ABORTED)
498 			break;
499 		pos = skip_whitespace(command);
500 		if (starts_with(pos, u"exit"))
501 			break;
502 		else if (starts_with(pos, u"load"))
503 			do_load();
504 		else if (starts_with(pos, u"save "))
505 			do_save(pos + 5);
506 		else
507 			do_help();
508 	}
509 
510 	color(EFI_LIGHTGRAY);
511 	cls();
512 
513 	return EFI_SUCCESS;
514 }
515