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