xref: /DragonStub/apps/helper.c (revision 823f04931913f01ee1fc0dc0c7876156ad150388)
1 #include "efidef.h"
2 #include <efi.h>
3 #include <efilib.h>
4 #include <lib.h>
5 #include <dragonstub/dragonstub.h>
6 
7 bool efi_nochunk;
8 bool efi_nokaslr = true;
9 // bool efi_nokaslr = !IS_ENABLED(CONFIG_RANDOMIZE_BASE);
10 bool efi_novamap = false;
11 
12 static bool efi_noinitrd;
13 static bool efi_nosoftreserve;
14 static bool efi_disable_pci_dma = false;
15 // static bool efi_disable_pci_dma = IS_ENABLED(CONFIG_EFI_DISABLE_PCI_DMA);
16 
17 enum efistub_event {
18 	EFISTUB_EVT_INITRD,
19 	EFISTUB_EVT_LOAD_OPTIONS,
20 	EFISTUB_EVT_COUNT,
21 };
22 
23 #define STR_WITH_SIZE(s) sizeof(s), s
24 
25 static const struct {
26 	u32 pcr_index;
27 	u32 event_id;
28 	u32 event_data_len;
29 	u8 event_data[52];
30 } events[] = {
31 	[EFISTUB_EVT_INITRD] = { 9, INITRD_EVENT_TAG_ID,
32 				 STR_WITH_SIZE("Linux initrd") },
33 	[EFISTUB_EVT_LOAD_OPTIONS] = { 9, LOAD_OPTIONS_EVENT_TAG_ID,
34 				       STR_WITH_SIZE(
35 					       "LOADED_IMAGE::LoadOptions") },
36 };
37 
38 static efi_status_t efi_measure_tagged_event(unsigned long load_addr,
39 					     unsigned long load_size,
40 					     enum efistub_event event)
41 {
42 	efi_guid_t tcg2_guid = EFI_TCG2_PROTOCOL_GUID;
43 	efi_tcg2_protocol_t *tcg2 = NULL;
44 	efi_status_t status;
45 
46 	efi_bs_call(LocateProtocol, &tcg2_guid, NULL, (void **)&tcg2);
47 	if (tcg2) {
48 		struct efi_measured_event {
49 			efi_tcg2_event_t event_data;
50 			efi_tcg2_tagged_event_t tagged_event;
51 			u8 tagged_event_data[];
52 		} * evt;
53 		int size = sizeof(*evt) + events[event].event_data_len;
54 
55 		status = efi_bs_call(AllocatePool, EfiLoaderData, size,
56 				     (void **)&evt);
57 		if (status != EFI_SUCCESS)
58 			goto fail;
59 
60 		evt->event_data = (struct efi_tcg2_event){
61 			.event_size = size,
62 			.event_header.header_size =
63 				sizeof(evt->event_data.event_header),
64 			.event_header.header_version =
65 				EFI_TCG2_EVENT_HEADER_VERSION,
66 			.event_header.pcr_index = events[event].pcr_index,
67 			.event_header.event_type = EV_EVENT_TAG,
68 		};
69 
70 		evt->tagged_event = (struct efi_tcg2_tagged_event){
71 			.tagged_event_id = events[event].event_id,
72 			.tagged_event_data_size = events[event].event_data_len,
73 		};
74 
75 		memcpy(evt->tagged_event_data, events[event].event_data,
76 		       events[event].event_data_len);
77 
78 		status = efi_call_proto(tcg2, hash_log_extend_event, 0,
79 					load_addr, load_size, &evt->event_data);
80 		efi_bs_call(FreePool, evt);
81 
82 		if (status != EFI_SUCCESS)
83 			goto fail;
84 		return EFI_SUCCESS;
85 	}
86 
87 	return EFI_UNSUPPORTED;
88 fail:
89 	efi_warn("Failed to measure data for event %d: 0x%lx\n", event, status);
90 	return status;
91 }
92 
93 /*
94  * At least some versions of Dell firmware pass the entire contents of the
95  * Boot#### variable, i.e. the EFI_LOAD_OPTION descriptor, rather than just the
96  * OptionalData field.
97  *
98  * Detect this case and extract OptionalData.
99  */
100 void efi_apply_loadoptions_quirk(const void **load_options,
101 				 u32 *load_options_size)
102 {
103 #ifndef CONFIG_X86
104 	return;
105 #else
106 	const efi_load_option_t *load_option = *load_options;
107 	efi_load_option_unpacked_t load_option_unpacked;
108 	if (!load_option)
109 		return;
110 	if (*load_options_size < sizeof(*load_option))
111 		return;
112 	if ((load_option->attributes & ~EFI_LOAD_OPTION_BOOT_MASK) != 0)
113 		return;
114 
115 	if (!efi_load_option_unpack(&load_option_unpacked, load_option,
116 				    *load_options_size))
117 		return;
118 
119 	efi_warn_once(FW_BUG "LoadOptions is an EFI_LOAD_OPTION descriptor\n");
120 	efi_warn_once(FW_BUG "Using OptionalData as a workaround\n");
121 
122 	*load_options = load_option_unpacked.optional_data;
123 	*load_options_size = load_option_unpacked.optional_data_size;
124 #endif
125 }
126 
127 /*
128  * Convert the unicode UEFI command line to ASCII to pass to kernel.
129  * Size of memory allocated return in *cmd_line_len.
130  * Returns NULL on error.
131  */
132 char *efi_convert_cmdline(EFI_LOADED_IMAGE *image, int *cmd_line_len)
133 {
134 	const efi_char16_t *options = efi_table_attr(image, LoadOptions);
135 	u32 options_size = efi_table_attr(image, LoadOptionsSize);
136 	int options_bytes = 0, safe_options_bytes = 0; /* UTF-8 bytes */
137 	unsigned long cmdline_addr = 0;
138 	const efi_char16_t *s2;
139 	bool in_quote = false;
140 	efi_status_t status;
141 	u32 options_chars;
142 
143 	if (options_size > 0)
144 		efi_measure_tagged_event((unsigned long)options, options_size,
145 					 EFISTUB_EVT_LOAD_OPTIONS);
146 
147 	efi_apply_loadoptions_quirk((const void **)&options, &options_size);
148 	options_chars = options_size / sizeof(efi_char16_t);
149 
150 	if (options) {
151 		s2 = options;
152 		while (options_bytes < COMMAND_LINE_SIZE && options_chars--) {
153 			efi_char16_t c = *s2++;
154 
155 			if (c < 0x80) {
156 				if (c == L'\0' || c == L'\n')
157 					break;
158 				if (c == L'"')
159 					in_quote = !in_quote;
160 				else if (!in_quote && isspace((char)c))
161 					safe_options_bytes = options_bytes;
162 
163 				options_bytes++;
164 				continue;
165 			}
166 
167 			/*
168 			 * Get the number of UTF-8 bytes corresponding to a
169 			 * UTF-16 character.
170 			 * The first part handles everything in the BMP.
171 			 */
172 			options_bytes += 2 + (c >= 0x800);
173 			/*
174 			 * Add one more byte for valid surrogate pairs. Invalid
175 			 * surrogates will be replaced with 0xfffd and take up
176 			 * only 3 bytes.
177 			 */
178 			if ((c & 0xfc00) == 0xd800) {
179 				/*
180 				 * If the very last word is a high surrogate,
181 				 * we must ignore it since we can't access the
182 				 * low surrogate.
183 				 */
184 				if (!options_chars) {
185 					options_bytes -= 3;
186 				} else if ((*s2 & 0xfc00) == 0xdc00) {
187 					options_bytes++;
188 					options_chars--;
189 					s2++;
190 				}
191 			}
192 		}
193 		if (options_bytes >= COMMAND_LINE_SIZE) {
194 			options_bytes = safe_options_bytes;
195 			efi_err("Command line is too long: truncated to %d bytes\n",
196 				options_bytes);
197 		}
198 	}
199 
200 	options_bytes++; /* NUL termination */
201 
202 	status = efi_bs_call(AllocatePool, EfiLoaderData, options_bytes,
203 			     (void **)&cmdline_addr);
204 	if (status != EFI_SUCCESS)
205 		return NULL;
206 
207 	snprintf((char *)cmdline_addr, options_bytes, "%.*ls",
208 		 options_bytes - 1, options);
209 
210 	*cmd_line_len = options_bytes;
211 	return (char *)cmdline_addr;
212 }
213 
214 /**
215  *	parse_option_str - Parse a string and check an option is set or not
216  *	@str: String to be parsed
217  *	@option: option name
218  *
219  *	This function parses a string containing a comma-separated list of
220  *	strings like a=b,c.
221  *
222  *	Return true if there's such option in the string, or return false.
223  */
224 bool parse_option_str(const char *str, const char *option)
225 {
226 	while (*str) {
227 		if (!strncmp(str, option, strlen(option))) {
228 			str += strlen(option);
229 			if (!*str || *str == ',')
230 				return true;
231 		}
232 
233 		while (*str && *str != ',')
234 			str++;
235 
236 		if (*str == ',')
237 			str++;
238 	}
239 
240 	return false;
241 }
242 
243 /**
244  * efi_parse_options() - Parse EFI command line options
245  * @cmdline:	kernel command line
246  *
247  * Parse the ASCII string @cmdline for EFI options, denoted by the efi=
248  * option, e.g. efi=nochunk.
249  *
250  * It should be noted that efi= is parsed in two very different
251  * environments, first in the early boot environment of the EFI boot
252  * stub, and subsequently during the kernel boot.
253  *
254  * Return:	status code
255  */
256 efi_status_t efi_parse_options(char const *cmdline)
257 {
258 	size_t len;
259 	efi_status_t status;
260 	char *str, *buf;
261 
262 	if (!cmdline)
263 		return EFI_SUCCESS;
264 
265 	len = strnlen(cmdline, COMMAND_LINE_SIZE - 1) + 1;
266 	status = efi_bs_call(AllocatePool, EfiLoaderData, len, (void **)&buf);
267 	if (status != EFI_SUCCESS)
268 		return status;
269 
270 	memcpy(buf, cmdline, len - 1);
271 	buf[len - 1] = '\0';
272 	str = skip_spaces(buf);
273 
274 	while (*str) {
275 		char *param, *val;
276 
277 		str = next_arg(str, &param, &val);
278 		if (!val && !strcmp(param, "--"))
279 			break;
280 
281 		if (!strcmp(param, "nokaslr")) {
282 			efi_nokaslr = true;
283 		} else if (!strcmp(param, "quiet")) {
284 			// efi_loglevel = CONSOLE_LOGLEVEL_QUIET;
285 		} else if (!strcmp(param, "noinitrd")) {
286 			efi_noinitrd = true;
287 		}
288 #ifdef CONFIG_X86_64
289 		else if (IS_ENABLED(CONFIG_X86_64) &&
290 			 !strcmp(param, "no5lvl")) {
291 			efi_no5lvl = true;
292 		}
293 #endif
294 		else if (!strcmp(param, "efi") && val) {
295 			efi_nochunk = parse_option_str(val, "nochunk");
296 			efi_novamap |= parse_option_str(val, "novamap");
297 
298 			// efi_nosoftreserve =
299 			// 	IS_ENABLED(CONFIG_EFI_SOFT_RESERVE) &&
300 			// 	parse_option_str(val, "nosoftreserve");
301 			efi_nosoftreserve = false;
302 
303 			if (parse_option_str(val, "disable_early_pci_dma"))
304 				efi_disable_pci_dma = true;
305 			if (parse_option_str(val, "no_disable_early_pci_dma"))
306 				efi_disable_pci_dma = false;
307 			if (parse_option_str(val, "debug")) {
308 				// efi_loglevel = CONSOLE_LOGLEVEL_DEBUG;
309 			}
310 		} else if (!strcmp(param, "video") && val &&
311 			   strstarts(val, "efifb:")) {
312 			// efi_parse_option_graphics(val + strlen("efifb:"));
313 		}
314 	}
315 	efi_bs_call(FreePool, buf);
316 	return EFI_SUCCESS;
317 }
318 
319 /**
320  * get_efi_config_table() - retrieve UEFI configuration table
321  * @guid:	GUID of the configuration table to be retrieved
322  * Return:	pointer to the configuration table or NULL
323  */
324 void *get_efi_config_table(efi_guid_t guid)
325 {
326 	efi_config_table_t *tables = efi_table_attr(ST, ConfigurationTable);
327 	int nr_tables = efi_table_attr(ST, NumberOfTableEntries);
328 	int i;
329 
330 	for (i = 0; i < nr_tables; i++) {
331 		efi_config_table_t *t = (void *)tables;
332 		// print_efi_guid(&t->VendorGuid);
333 		if (efi_guidcmp(t->VendorGuid, guid) == 0)
334 			return efi_table_attr(t, VendorTable);
335 
336 		tables++;
337 	}
338 	return NULL;
339 }
340 
341 /**
342  * efi_exit_boot_services() - Exit boot services
343  * @handle:	handle of the exiting image
344  * @priv:	argument to be passed to @priv_func
345  * @priv_func:	function to process the memory map before exiting boot services
346  *
347  * Handle calling ExitBootServices according to the requirements set out by the
348  * spec.  Obtains the current memory map, and returns that info after calling
349  * ExitBootServices.  The client must specify a function to perform any
350  * processing of the memory map data prior to ExitBootServices.  A client
351  * specific structure may be passed to the function via priv.  The client
352  * function may be called multiple times.
353  *
354  * Return:	status code
355  */
356 efi_status_t efi_exit_boot_services(void *handle, void *priv,
357 				    efi_exit_boot_map_processing priv_func)
358 {
359 	struct efi_boot_memmap *map;
360 	efi_status_t status;
361 
362 	if (efi_disable_pci_dma) {
363 		efi_todo("efi_exit_boot_services:: efi_disable_pci_dma: efi_pci_disable_bridge_busmaster");
364 		// efi_pci_disable_bridge_busmaster();
365 	}
366 
367 	status = efi_get_memory_map(&map, true);
368 	if (status != EFI_SUCCESS)
369 		return status;
370 	efi_debug("before priv_func\n");
371 	status = priv_func(map, priv);
372 	if (status != EFI_SUCCESS) {
373 
374 		efi_bs_call(FreePool, map);
375 		return status;
376 	}
377 
378 	efi_debug("before ExitBootServices, handle=%p, map_key=%p\n", handle, map->map_key);
379 
380 	status = efi_bs_call(ExitBootServices, handle, map->map_key);
381 
382 	efi_debug("after ExitBootServices, status: %d\n", status);
383 
384 	if (status == EFI_INVALID_PARAMETER) {
385 		/*
386 		 * The memory map changed between efi_get_memory_map() and
387 		 * exit_boot_services().  Per the UEFI Spec v2.6, Section 6.4:
388 		 * EFI_BOOT_SERVICES.ExitBootServices we need to get the
389 		 * updated map, and try again.  The spec implies one retry
390 		 * should be sufficent, which is confirmed against the EDK2
391 		 * implementation.  Per the spec, we can only invoke
392 		 * get_memory_map() and exit_boot_services() - we cannot alloc
393 		 * so efi_get_memory_map() cannot be used, and we must reuse
394 		 * the buffer.  For all practical purposes, the headroom in the
395 		 * buffer should account for any changes in the map so the call
396 		 * to get_memory_map() is expected to succeed here.
397 		 */
398 		map->map_size = map->buff_size;
399 		status = efi_bs_call(GetMemoryMap, &map->map_size, &map->map,
400 				     &map->map_key, &map->desc_size,
401 				     &map->desc_ver);
402 
403 		/* exit_boot_services() was called, thus cannot free */
404 		if (status != EFI_SUCCESS)
405 			return status;
406 
407 		status = priv_func(map, priv);
408 		/* exit_boot_services() was called, thus cannot free */
409 		if (status != EFI_SUCCESS)
410 			return status;
411 
412 		status = efi_bs_call(ExitBootServices, handle, map->map_key);
413 	}
414 
415 	return status;
416 }