]> git.proxmox.com Git - efi-boot-shim.git/blob - fallback.c
8d89917a5cbc845d3c4b99580c77babbf45d4bf9
[efi-boot-shim.git] / fallback.c
1 // SPDX-License-Identifier: BSD-2-Clause-Patent
2 /*
3 * Copyright Red Hat, Inc.
4 * Copyright Peter Jones <pjones@redhat.com>
5 */
6 #include "shim.h"
7
8 #define NO_REBOOT L"FB_NO_REBOOT"
9
10 EFI_LOADED_IMAGE *this_image = NULL;
11
12 int
13 get_fallback_verbose(void)
14 {
15 #ifdef FALLBACK_VERBOSE
16 return 1;
17 #else
18 UINT8 *data = NULL;
19 UINTN dataSize = 0;
20 EFI_STATUS efi_status;
21 unsigned int i;
22 static int state = -1;
23
24 if (state != -1)
25 return state;
26
27 efi_status = get_variable(L"FALLBACK_VERBOSE",
28 &data, &dataSize, SHIM_LOCK_GUID);
29 if (EFI_ERROR(efi_status)) {
30 state = 0;
31 return state;
32 }
33
34 state = 0;
35 for (i = 0; i < dataSize; i++) {
36 if (data[i]) {
37 state = 1;
38 break;
39 }
40 }
41
42 if (data)
43 FreePool(data);
44 return state;
45 #endif
46 }
47
48 #define VerbosePrintUnprefixed(fmt, ...) \
49 ({ \
50 UINTN ret_ = 0; \
51 if (get_fallback_verbose()) \
52 ret_ = console_print((fmt), ##__VA_ARGS__); \
53 ret_; \
54 })
55
56 #define VerbosePrint(fmt, ...) \
57 ({ \
58 UINTN line_ = __LINE__ - 2; \
59 UINTN ret_ = 0; \
60 if (get_fallback_verbose()) { \
61 console_print(L"%a:%d: ", __func__, line_); \
62 ret_ = console_print((fmt), ##__VA_ARGS__); \
63 } \
64 ret_; \
65 })
66
67 static EFI_STATUS
68 FindSubDevicePath(EFI_DEVICE_PATH *In, UINT8 Type, UINT8 SubType,
69 EFI_DEVICE_PATH **Out)
70 {
71 EFI_DEVICE_PATH *dp = In;
72 if (!In || !Out)
73 return EFI_INVALID_PARAMETER;
74
75 CHAR16 *dps = DevicePathToStr(In);
76 VerbosePrint(L"input device path: \"%s\"\n", dps);
77 FreePool(dps);
78
79 for (dp = In; !IsDevicePathEnd(dp); dp = NextDevicePathNode(dp)) {
80 if (DevicePathType(dp) == Type &&
81 DevicePathSubType(dp) == SubType) {
82 dps = DevicePathToStr(dp);
83 VerbosePrint(L"sub-path (%hhd,%hhd): \"%s\"\n",
84 Type, SubType, dps);
85 FreePool(dps);
86
87 *Out = DuplicateDevicePath(dp);
88 if (!*Out)
89 return EFI_OUT_OF_RESOURCES;
90 return EFI_SUCCESS;
91 }
92 }
93 *Out = NULL;
94 return EFI_NOT_FOUND;
95 }
96
97 static EFI_STATUS
98 get_file_size(EFI_FILE_HANDLE fh, UINTN *retsize)
99 {
100 EFI_STATUS efi_status;
101 void *buffer = NULL;
102 UINTN bs = 0;
103
104 /* The API here is "Call it once with bs=0, it fills in bs,
105 * then allocate a buffer and ask again to get it filled. */
106 efi_status = fh->GetInfo(fh, &EFI_FILE_INFO_GUID, &bs, NULL);
107 if (EFI_ERROR(efi_status) && efi_status != EFI_BUFFER_TOO_SMALL)
108 return efi_status;
109 if (bs == 0)
110 return EFI_SUCCESS;
111
112 buffer = AllocateZeroPool(bs);
113 if (!buffer) {
114 console_print(L"Could not allocate memory\n");
115 return EFI_OUT_OF_RESOURCES;
116 }
117 efi_status = fh->GetInfo(fh, &EFI_FILE_INFO_GUID, &bs, buffer);
118 /* This checks *either* the error from the first GetInfo, if it isn't
119 * the EFI_BUFFER_TOO_SMALL we're expecting, or the second GetInfo
120 * call in *any* case. */
121 if (EFI_ERROR(efi_status)) {
122 console_print(L"Could not get file info: %r\n", efi_status);
123 if (buffer)
124 FreePool(buffer);
125 return efi_status;
126 }
127 EFI_FILE_INFO *fi = buffer;
128 *retsize = fi->FileSize;
129 FreePool(buffer);
130 return EFI_SUCCESS;
131 }
132
133 EFI_STATUS
134 read_file(EFI_FILE_HANDLE fh, CHAR16 *fullpath, CHAR16 **buffer, UINT64 *bs)
135 {
136 EFI_FILE_HANDLE fh2;
137 EFI_STATUS efi_status;
138
139 efi_status = fh->Open(fh, &fh2, fullpath, EFI_FILE_READ_ONLY, 0);
140 if (EFI_ERROR(efi_status)) {
141 console_print(L"Couldn't open \"%s\": %r\n", fullpath, efi_status);
142 return efi_status;
143 }
144
145 UINTN len = 0;
146 CHAR16 *b = NULL;
147 efi_status = get_file_size(fh2, &len);
148 if (EFI_ERROR(efi_status)) {
149 console_print(L"Could not get file size for \"%s\": %r\n",
150 fullpath, efi_status);
151 fh2->Close(fh2);
152 return efi_status;
153 }
154
155 if (len > 1024 * PAGE_SIZE) {
156 fh2->Close(fh2);
157 return EFI_BAD_BUFFER_SIZE;
158 }
159
160 b = AllocateZeroPool(len + 2);
161 if (!buffer) {
162 console_print(L"Could not allocate memory\n");
163 fh2->Close(fh2);
164 return EFI_OUT_OF_RESOURCES;
165 }
166
167 efi_status = fh->Read(fh, &len, b);
168 if (EFI_ERROR(efi_status)) {
169 FreePool(buffer);
170 fh2->Close(fh2);
171 console_print(L"Could not read file: %r\n", efi_status);
172 return efi_status;
173 }
174 *buffer = b;
175 *bs = len;
176 fh2->Close(fh2);
177 return EFI_SUCCESS;
178 }
179
180 EFI_STATUS
181 make_full_path(CHAR16 *dirname, CHAR16 *filename, CHAR16 **out, UINT64 *outlen)
182 {
183 UINT64 len;
184
185 len = StrLen(L"\\EFI\\") + StrLen(dirname)
186 + StrLen(L"\\") + StrLen(filename)
187 + 2;
188
189 CHAR16 *fullpath = AllocateZeroPool(len*sizeof(CHAR16));
190 if (!fullpath) {
191 console_print(L"Could not allocate memory\n");
192 return EFI_OUT_OF_RESOURCES;
193 }
194
195 StrCat(fullpath, L"\\EFI\\");
196 StrCat(fullpath, dirname);
197 StrCat(fullpath, L"\\");
198 StrCat(fullpath, filename);
199
200 *out = fullpath;
201 *outlen = len;
202 return EFI_SUCCESS;
203 }
204
205 CHAR16 *bootorder = NULL;
206 int nbootorder = 0;
207
208 EFI_DEVICE_PATH *first_new_option = NULL;
209 VOID *first_new_option_args = NULL;
210 UINTN first_new_option_size = 0;
211
212 EFI_STATUS
213 add_boot_option(EFI_DEVICE_PATH *hddp, EFI_DEVICE_PATH *fulldp,
214 CHAR16 *filename, CHAR16 *label, CHAR16 *arguments)
215 {
216 static int i = 0;
217 CHAR16 varname[] = L"Boot0000";
218 CHAR16 hexmap[] = L"0123456789ABCDEF";
219 EFI_STATUS efi_status;
220
221 for(; i <= 0xffff; i++) {
222 varname[4] = hexmap[(i & 0xf000) >> 12];
223 varname[5] = hexmap[(i & 0x0f00) >> 8];
224 varname[6] = hexmap[(i & 0x00f0) >> 4];
225 varname[7] = hexmap[(i & 0x000f) >> 0];
226
227 void *var = LibGetVariable(varname, &GV_GUID);
228 if (!var) {
229 int size = sizeof(UINT32) + sizeof (UINT16) +
230 StrLen(label)*2 + 2 + DevicePathSize(hddp) +
231 StrLen(arguments) * 2;
232
233 CHAR8 *data = AllocateZeroPool(size + 2);
234 CHAR8 *cursor = data;
235 *(UINT32 *)cursor = LOAD_OPTION_ACTIVE;
236 cursor += sizeof (UINT32);
237 *(UINT16 *)cursor = DevicePathSize(hddp);
238 cursor += sizeof (UINT16);
239 StrCpy((CHAR16 *)cursor, label);
240 cursor += StrLen(label)*2 + 2;
241 CopyMem(cursor, hddp, DevicePathSize(hddp));
242 cursor += DevicePathSize(hddp);
243 StrCpy((CHAR16 *)cursor, arguments);
244
245 VerbosePrint(L"Creating boot entry \"%s\" with label \"%s\" "
246 L"for file \"%s\"\n",
247 varname, label, filename);
248
249 if (!first_new_option) {
250 first_new_option = DuplicateDevicePath(fulldp);
251 first_new_option_args = arguments;
252 first_new_option_size = StrLen(arguments) * sizeof (CHAR16);
253 }
254
255 efi_status = gRT->SetVariable(varname, &GV_GUID,
256 EFI_VARIABLE_NON_VOLATILE |
257 EFI_VARIABLE_BOOTSERVICE_ACCESS |
258 EFI_VARIABLE_RUNTIME_ACCESS,
259 size, data);
260
261 FreePool(data);
262
263 if (EFI_ERROR(efi_status)) {
264 console_print(L"Could not create variable: %r\n",
265 efi_status);
266 return efi_status;
267 }
268
269 CHAR16 *newbootorder = AllocateZeroPool(sizeof (CHAR16)
270 * (nbootorder + 1));
271 if (!newbootorder)
272 return EFI_OUT_OF_RESOURCES;
273
274 int j = 0;
275 newbootorder[0] = i & 0xffff;
276 if (nbootorder) {
277 for (j = 0; j < nbootorder; j++)
278 newbootorder[j+1] = bootorder[j];
279 FreePool(bootorder);
280 }
281 bootorder = newbootorder;
282 nbootorder += 1;
283 VerbosePrint(L"nbootorder: %d\nBootOrder: ",
284 nbootorder);
285 for (j = 0 ; j < nbootorder ; j++)
286 VerbosePrintUnprefixed(L"%04x ", bootorder[j]);
287 VerbosePrintUnprefixed(L"\n");
288
289 return EFI_SUCCESS;
290 }
291 }
292 return EFI_OUT_OF_RESOURCES;
293 }
294
295 /*
296 * AMI BIOS (e.g, Intel NUC5i3MYHE) may automatically hide and patch BootXXXX
297 * variables with ami_masked_device_path_guid. We can get the valid device path
298 * if just skipping it and its next end path.
299 */
300
301 static EFI_GUID ami_masked_device_path_guid = {
302 0x99e275e7, 0x75a0, 0x4b37,
303 { 0xa2, 0xe6, 0xc5, 0x38, 0x5e, 0x6c, 0x0, 0xcb }
304 };
305
306 static unsigned int
307 calc_masked_boot_option_size(unsigned int size)
308 {
309 return size + sizeof(EFI_DEVICE_PATH) +
310 sizeof(ami_masked_device_path_guid) + sizeof(EFI_DEVICE_PATH);
311 }
312
313 static int
314 check_masked_boot_option(CHAR8 *candidate, unsigned int candidate_size,
315 CHAR8 *data, unsigned int data_size)
316 {
317 /*
318 * The patched BootXXXX variables contain a hardware device path and
319 * an end path, preceding the real device path.
320 */
321 if (calc_masked_boot_option_size(data_size) != candidate_size)
322 return 1;
323
324 CHAR8 *cursor = candidate;
325
326 /* Check whether the BootXXXX is patched */
327 cursor += sizeof(UINT32) + sizeof(UINT16);
328 cursor += StrSize((CHAR16 *)cursor);
329
330 unsigned int min_valid_size = cursor - candidate + sizeof(EFI_DEVICE_PATH);
331
332 if (candidate_size <= min_valid_size)
333 return 1;
334
335 EFI_DEVICE_PATH *dp = (EFI_DEVICE_PATH *)cursor;
336 unsigned int node_size = DevicePathNodeLength(dp) - sizeof(EFI_DEVICE_PATH);
337
338 min_valid_size += node_size;
339 if (candidate_size <= min_valid_size ||
340 DevicePathType(dp) != HARDWARE_DEVICE_PATH ||
341 DevicePathSubType(dp) != HW_VENDOR_DP ||
342 node_size != sizeof(ami_masked_device_path_guid) ||
343 CompareGuid((EFI_GUID *)(cursor + sizeof(EFI_DEVICE_PATH)),
344 &ami_masked_device_path_guid))
345 return 1;
346
347 /* Check whether the patched guid is followed by an end path */
348 min_valid_size += sizeof(EFI_DEVICE_PATH);
349 if (candidate_size <= min_valid_size)
350 return 1;
351
352 dp = NextDevicePathNode(dp);
353 if (!IsDevicePathEnd(dp))
354 return 1;
355
356 /*
357 * OK. We may really get a masked BootXXXX variable. The next
358 * step is to test whether it is hidden.
359 */
360 UINT32 attrs = *(UINT32 *)candidate;
361 #ifndef LOAD_OPTION_HIDDEN
362 # define LOAD_OPTION_HIDDEN 0x00000008
363 #endif
364 if (!(attrs & LOAD_OPTION_HIDDEN))
365 return 1;
366
367 attrs &= ~LOAD_OPTION_HIDDEN;
368
369 /* Compare the field Attributes */
370 if (attrs != *(UINT32 *)data)
371 return 1;
372
373 /* Compare the field FilePathListLength */
374 data += sizeof(UINT32);
375 candidate += sizeof(UINT32);
376 if (calc_masked_boot_option_size(*(UINT16 *)data) !=
377 *(UINT16 *)candidate)
378 return 1;
379
380 /* Compare the field Description */
381 data += sizeof(UINT16);
382 candidate += sizeof(UINT16);
383 if (CompareMem(candidate, data, cursor - candidate))
384 return 1;
385
386 /* Compare the filed FilePathList */
387 cursor = (CHAR8 *)NextDevicePathNode(dp);
388 data += sizeof(UINT16);
389 data += StrSize((CHAR16 *)data);
390
391 return CompareMem(cursor, data, candidate_size - min_valid_size);
392 }
393
394 EFI_STATUS
395 find_boot_option(EFI_DEVICE_PATH *dp, EFI_DEVICE_PATH *fulldp,
396 CHAR16 *filename, CHAR16 *label, CHAR16 *arguments,
397 UINT16 *optnum)
398 {
399 unsigned int label_size = StrLen(label)*2 + 2;
400 unsigned int size = sizeof(UINT32) + sizeof (UINT16) +
401 label_size + DevicePathSize(dp) +
402 StrLen(arguments) * 2;
403
404 CHAR8 *data = AllocateZeroPool(size + 2);
405 if (!data)
406 return EFI_OUT_OF_RESOURCES;
407 CHAR8 *cursor = data;
408 *(UINT32 *)cursor = LOAD_OPTION_ACTIVE;
409 cursor += sizeof (UINT32);
410 *(UINT16 *)cursor = DevicePathSize(dp);
411 cursor += sizeof (UINT16);
412 StrCpy((CHAR16 *)cursor, label);
413 cursor += label_size;
414 CopyMem(cursor, dp, DevicePathSize(dp));
415 cursor += DevicePathSize(dp);
416 StrCpy((CHAR16 *)cursor, arguments);
417
418 CHAR16 varname[256];
419 EFI_STATUS efi_status;
420 EFI_GUID vendor_guid = NullGuid;
421
422 UINTN max_candidate_size = calc_masked_boot_option_size(size);
423 CHAR8 *candidate = AllocateZeroPool(max_candidate_size);
424 if (!candidate) {
425 FreePool(data);
426 return EFI_OUT_OF_RESOURCES;
427 }
428
429 varname[0] = 0;
430 while (1) {
431 UINTN varname_size = sizeof(varname);
432 efi_status = gRT->GetNextVariableName(&varname_size, varname,
433 &vendor_guid);
434 if (EFI_ERROR(efi_status))
435 break;
436
437 if (StrLen(varname) != 8 || StrnCmp(varname, L"Boot", 4) ||
438 !isxdigit(varname[4]) || !isxdigit(varname[5]) ||
439 !isxdigit(varname[6]) || !isxdigit(varname[7]))
440 continue;
441
442 UINTN candidate_size = max_candidate_size;
443 efi_status = gRT->GetVariable(varname, &GV_GUID, NULL,
444 &candidate_size, candidate);
445 if (EFI_ERROR(efi_status))
446 continue;
447
448 if (candidate_size != size) {
449 if (check_masked_boot_option(candidate, candidate_size,
450 data, size))
451 continue;
452 } else if (CompareMem(candidate, data, size))
453 continue;
454
455 VerbosePrint(L"Found boot entry \"%s\" with label \"%s\" "
456 L"for file \"%s\"\n", varname, label, filename);
457
458 /* at this point, we have duplicate data. */
459 if (!first_new_option) {
460 first_new_option = DuplicateDevicePath(fulldp);
461 first_new_option_args = arguments;
462 first_new_option_size = StrLen(arguments) * sizeof (CHAR16);
463 }
464
465 *optnum = xtoi(varname + 4);
466 FreePool(candidate);
467 FreePool(data);
468 return EFI_SUCCESS;
469 }
470 FreePool(candidate);
471 FreePool(data);
472 return EFI_NOT_FOUND;
473 }
474
475 EFI_STATUS
476 set_boot_order(void)
477 {
478 CHAR16 *oldbootorder;
479 UINTN size;
480
481 oldbootorder = LibGetVariableAndSize(L"BootOrder", &GV_GUID, &size);
482 if (oldbootorder) {
483 int i;
484 nbootorder = size / sizeof (CHAR16);
485 bootorder = oldbootorder;
486
487 VerbosePrint(L"Original nbootorder: %d\nOriginal BootOrder: ",
488 nbootorder);
489 for (i = 0 ; i < nbootorder ; i++)
490 VerbosePrintUnprefixed(L"%04x ", bootorder[i]);
491 VerbosePrintUnprefixed(L"\n");
492 }
493 return EFI_SUCCESS;
494
495 }
496
497 EFI_STATUS
498 update_boot_order(void)
499 {
500 UINTN size;
501 UINTN len = 0;
502 CHAR16 *newbootorder = NULL;
503 EFI_STATUS efi_status;
504
505 size = nbootorder * sizeof(CHAR16);
506 newbootorder = AllocateZeroPool(size);
507 if (!newbootorder)
508 return EFI_OUT_OF_RESOURCES;
509 CopyMem(newbootorder, bootorder, size);
510
511 VerbosePrint(L"nbootorder: %d\nBootOrder: ", size / sizeof (CHAR16));
512 UINTN j;
513 for (j = 0 ; j < size / sizeof (CHAR16); j++)
514 VerbosePrintUnprefixed(L"%04x ", newbootorder[j]);
515 VerbosePrintUnprefixed(L"\n");
516 efi_status = gRT->GetVariable(L"BootOrder", &GV_GUID, NULL, &len, NULL);
517 if (efi_status == EFI_BUFFER_TOO_SMALL)
518 LibDeleteVariable(L"BootOrder", &GV_GUID);
519
520 efi_status = gRT->SetVariable(L"BootOrder", &GV_GUID,
521 EFI_VARIABLE_NON_VOLATILE |
522 EFI_VARIABLE_BOOTSERVICE_ACCESS |
523 EFI_VARIABLE_RUNTIME_ACCESS,
524 size, newbootorder);
525 FreePool(newbootorder);
526 return efi_status;
527 }
528
529 EFI_STATUS
530 add_to_boot_list(CHAR16 *dirname, CHAR16 *filename, CHAR16 *label, CHAR16 *arguments)
531 {
532 CHAR16 *fullpath = NULL;
533 UINT64 pathlen = 0;
534 EFI_STATUS efi_status;
535
536 efi_status = make_full_path(dirname, filename, &fullpath, &pathlen);
537 if (EFI_ERROR(efi_status))
538 return efi_status;
539
540 EFI_DEVICE_PATH *full_device_path = NULL;
541 EFI_DEVICE_PATH *dp = NULL;
542 CHAR16 *dps;
543
544 full_device_path = FileDevicePath(this_image->DeviceHandle, fullpath);
545 if (!full_device_path) {
546 efi_status = EFI_OUT_OF_RESOURCES;
547 goto err;
548 }
549 dps = DevicePathToStr(full_device_path);
550 VerbosePrint(L"file DP: %s\n", dps);
551 FreePool(dps);
552
553 efi_status = FindSubDevicePath(full_device_path,
554 MEDIA_DEVICE_PATH, MEDIA_HARDDRIVE_DP,
555 &dp);
556 if (EFI_ERROR(efi_status)) {
557 if (efi_status == EFI_NOT_FOUND) {
558 dp = full_device_path;
559 } else {
560 efi_status = EFI_OUT_OF_RESOURCES;
561 goto err;
562 }
563 }
564
565 {
566 UINTN s = DevicePathSize(dp);
567 UINTN i;
568 UINT8 *dpv = (void *)dp;
569 for (i = 0; i < s; i++) {
570 if (i % 16 == 0) {
571 if (i > 0)
572 VerbosePrintUnprefixed(L"\n");
573 VerbosePrint(L"");
574 }
575 VerbosePrintUnprefixed(L"%02x ", dpv[i]);
576 }
577 VerbosePrintUnprefixed(L"\n");
578
579 CHAR16 *dps = DevicePathToStr(dp);
580 VerbosePrint(L"device path: \"%s\"\n", dps);
581 FreePool(dps);
582 }
583
584 UINT16 option;
585 efi_status = find_boot_option(dp, full_device_path, fullpath, label,
586 arguments, &option);
587 if (EFI_ERROR(efi_status)) {
588 add_boot_option(dp, full_device_path, fullpath, label,
589 arguments);
590 } else if (option != 0) {
591 CHAR16 *newbootorder;
592 newbootorder = AllocateZeroPool(sizeof (CHAR16) * nbootorder);
593 if (!newbootorder)
594 return EFI_OUT_OF_RESOURCES;
595
596 newbootorder[0] = bootorder[option];
597 CopyMem(newbootorder + 1, bootorder, sizeof (CHAR16) * option);
598 CopyMem(newbootorder + option + 1, bootorder + option + 1,
599 sizeof (CHAR16) * (nbootorder - option - 1));
600 FreePool(bootorder);
601 bootorder = newbootorder;
602 }
603
604 err:
605 if (full_device_path)
606 FreePool(full_device_path);
607 if (dp && dp != full_device_path)
608 FreePool(dp);
609 if (fullpath)
610 FreePool(fullpath);
611 return efi_status;
612 }
613
614 EFI_STATUS
615 populate_stanza(CHAR16 *dirname, CHAR16 *filename UNUSED, CHAR16 *csv)
616 {
617 CHAR16 *file = csv;
618 VerbosePrint(L"CSV data: \"%s\"\n", csv);
619
620 UINTN comma0 = StrCSpn(csv, L",");
621 if (comma0 == 0)
622 return EFI_INVALID_PARAMETER;
623 file[comma0] = L'\0';
624 VerbosePrint(L"filename: \"%s\"\n", file);
625
626 CHAR16 *label = csv + comma0 + 1;
627 UINTN comma1 = StrCSpn(label, L",");
628 if (comma1 == 0)
629 return EFI_INVALID_PARAMETER;
630 label[comma1] = L'\0';
631 VerbosePrint(L"label: \"%s\"\n", label);
632
633 CHAR16 *arguments = csv + comma0 +1 + comma1 +1;
634 UINTN comma2 = StrCSpn(arguments, L",");
635 arguments[comma2] = L'\0';
636 /* This one is optional, so don't check if comma2 is 0 */
637 VerbosePrint(L"arguments: \"%s\"\n", arguments);
638
639 add_to_boot_list(dirname, file, label, arguments);
640
641 return EFI_SUCCESS;
642 }
643
644 EFI_STATUS
645 try_boot_csv(EFI_FILE_HANDLE fh, CHAR16 *dirname, CHAR16 *filename)
646 {
647 CHAR16 *fullpath = NULL;
648 UINT64 pathlen = 0;
649 EFI_STATUS efi_status;
650
651 efi_status = make_full_path(dirname, filename, &fullpath, &pathlen);
652 if (EFI_ERROR(efi_status))
653 return efi_status;
654
655 VerbosePrint(L"Found file \"%s\"\n", fullpath);
656
657 CHAR16 *buffer;
658 UINT64 bs;
659 efi_status = read_file(fh, fullpath, &buffer, &bs);
660 if (EFI_ERROR(efi_status)) {
661 console_print(L"Could not read file \"%s\": %r\n",
662 fullpath, efi_status);
663 FreePool(fullpath);
664 return efi_status;
665 }
666 FreePool(fullpath);
667
668 VerbosePrint(L"File looks like:\n%s\n", buffer);
669
670 CHAR16 *start = buffer;
671 /* The file may or may not start with the Unicode byte order marker.
672 * Sadness ensues. Since UEFI is defined as LE, I'm going to decree
673 * that these files must also be LE.
674 *
675 * IT IS THUS SO.
676 *
677 * But if we find the LE byte order marker, just skip it.
678 */
679 if (*start == 0xfeff)
680 start++;
681 while (*start) {
682 while (*start == L'\r' || *start == L'\n')
683 start++;
684 UINTN l = StrCSpn(start, L"\r\n");
685 if (l == 0) {
686 if (start[l] == L'\0')
687 break;
688 start++;
689 continue;
690 }
691 CHAR16 c = start[l];
692 start[l] = L'\0';
693
694 populate_stanza(dirname, filename, start);
695
696 start[l] = c;
697 start += l;
698 }
699
700 FreePool(buffer);
701 return EFI_SUCCESS;
702 }
703
704 EFI_STATUS
705 find_boot_csv(EFI_FILE_HANDLE fh, CHAR16 *dirname)
706 {
707 EFI_STATUS efi_status;
708 void *buffer = NULL;
709 UINTN bs = 0;
710
711 /* The API here is "Call it once with bs=0, it fills in bs,
712 * then allocate a buffer and ask again to get it filled. */
713 efi_status = fh->GetInfo(fh, &EFI_FILE_INFO_GUID, &bs, NULL);
714 if (EFI_ERROR(efi_status) && efi_status != EFI_BUFFER_TOO_SMALL) {
715 console_print(L"Could not get directory info for \\EFI\\%s\\: %r\n",
716 dirname, efi_status);
717 return efi_status;
718 }
719 if (bs == 0)
720 return EFI_SUCCESS;
721
722 buffer = AllocateZeroPool(bs);
723 if (!buffer) {
724 console_print(L"Could not allocate memory\n");
725 return EFI_OUT_OF_RESOURCES;
726 }
727
728 efi_status = fh->GetInfo(fh, &EFI_FILE_INFO_GUID, &bs, buffer);
729 /* This checks *either* the error from the first GetInfo, if it isn't
730 * the EFI_BUFFER_TOO_SMALL we're expecting, or the second GetInfo
731 * call in *any* case. */
732 if (EFI_ERROR(efi_status)) {
733 console_print(L"Could not get info for \"%s\": %r\n", dirname,
734 efi_status);
735 if (buffer)
736 FreePool(buffer);
737 return efi_status;
738 }
739
740 EFI_FILE_INFO *fi = buffer;
741 if (!(fi->Attribute & EFI_FILE_DIRECTORY)) {
742 FreePool(buffer);
743 return EFI_SUCCESS;
744 }
745 FreePool(buffer);
746 buffer = NULL;
747
748 CHAR16 *bootcsv=NULL, *bootarchcsv=NULL;
749
750 bs = 0;
751 do {
752 bs = 0;
753 efi_status = fh->Read(fh, &bs, NULL);
754 if (EFI_ERROR(efi_status) &&
755 efi_status != EFI_BUFFER_TOO_SMALL) {
756 console_print(L"Could not read \\EFI\\%s\\: %r\n",
757 dirname, efi_status);
758 return efi_status;
759 }
760 /* If there's no data to read, don't try to allocate 0 bytes
761 * and read the data... */
762 if (bs == 0)
763 break;
764
765 buffer = AllocateZeroPool(bs);
766 if (!buffer) {
767 console_print(L"Could not allocate memory\n");
768 return EFI_OUT_OF_RESOURCES;
769 }
770
771 efi_status = fh->Read(fh, &bs, buffer);
772 if (EFI_ERROR(efi_status)) {
773 console_print(L"Could not read \\EFI\\%s\\: %r\n",
774 dirname, efi_status);
775 FreePool(buffer);
776 return efi_status;
777 }
778
779 if (bs == 0)
780 break;
781
782 fi = buffer;
783
784 if (!bootcsv && !StrCaseCmp(fi->FileName, L"boot.csv"))
785 bootcsv = StrDuplicate(fi->FileName);
786
787 if (!bootarchcsv &&
788 !StrCaseCmp(fi->FileName, L"boot" EFI_ARCH L".csv"))
789 bootarchcsv = StrDuplicate(fi->FileName);
790
791 FreePool(buffer);
792 buffer = NULL;
793 } while (bs != 0);
794
795 efi_status = EFI_SUCCESS;
796 if (bootarchcsv) {
797 EFI_FILE_HANDLE fh2;
798 efi_status = fh->Open(fh, &fh2, bootarchcsv,
799 EFI_FILE_READ_ONLY, 0);
800 if (EFI_ERROR(efi_status) || fh2 == NULL) {
801 console_print(L"Couldn't open \\EFI\\%s\\%s: %r\n",
802 dirname, bootarchcsv, efi_status);
803 } else {
804 efi_status = try_boot_csv(fh2, dirname, bootarchcsv);
805 fh2->Close(fh2);
806 if (EFI_ERROR(efi_status))
807 console_print(L"Could not process \\EFI\\%s\\%s: %r\n",
808 dirname, bootarchcsv, efi_status);
809 }
810 }
811 if ((EFI_ERROR(efi_status) || !bootarchcsv) && bootcsv) {
812 EFI_FILE_HANDLE fh2;
813 efi_status = fh->Open(fh, &fh2, bootcsv,
814 EFI_FILE_READ_ONLY, 0);
815 if (EFI_ERROR(efi_status) || fh2 == NULL) {
816 console_print(L"Couldn't open \\EFI\\%s\\%s: %r\n",
817 dirname, bootcsv, efi_status);
818 } else {
819 efi_status = try_boot_csv(fh2, dirname, bootcsv);
820 fh2->Close(fh2);
821 if (EFI_ERROR(efi_status))
822 console_print(L"Could not process \\EFI\\%s\\%s: %r\n",
823 dirname, bootarchcsv, efi_status);
824 }
825 }
826 return EFI_SUCCESS;
827 }
828
829 EFI_STATUS
830 find_boot_options(EFI_HANDLE device)
831 {
832 EFI_STATUS efi_status;
833 EFI_FILE_IO_INTERFACE *fio = NULL;
834
835 efi_status = gBS->HandleProtocol(device, &FileSystemProtocol,
836 (void **) &fio);
837 if (EFI_ERROR(efi_status)) {
838 console_print(L"Couldn't find file system: %r\n", efi_status);
839 return efi_status;
840 }
841
842 /* EFI_FILE_HANDLE is a pointer to an EFI_FILE, and I have
843 * *no idea* what frees the memory allocated here. Hopefully
844 * Close() does. */
845 EFI_FILE_HANDLE fh = NULL;
846 efi_status = fio->OpenVolume(fio, &fh);
847 if (EFI_ERROR(efi_status) || fh == NULL) {
848 console_print(L"Couldn't open file system: %r\n", efi_status);
849 return efi_status;
850 }
851
852 EFI_FILE_HANDLE fh2 = NULL;
853 efi_status = fh->Open(fh, &fh2, L"EFI", EFI_FILE_READ_ONLY, 0);
854 if (EFI_ERROR(efi_status) || fh2 == NULL) {
855 console_print(L"Couldn't open EFI: %r\n", efi_status);
856 fh->Close(fh);
857 return efi_status;
858 }
859 efi_status = fh2->SetPosition(fh2, 0);
860 if (EFI_ERROR(efi_status)) {
861 console_print(L"Couldn't set file position: %r\n", efi_status);
862 fh2->Close(fh2);
863 fh->Close(fh);
864 return efi_status;
865 }
866
867 void *buffer;
868 UINTN bs;
869 do {
870 bs = 0;
871 efi_status = fh2->Read(fh2, &bs, NULL);
872 if (EFI_ERROR(efi_status) && efi_status != EFI_BUFFER_TOO_SMALL) {
873 console_print(L"Could not read \\EFI\\: %r\n", efi_status);
874 return efi_status;
875 }
876 if (bs == 0)
877 break;
878
879 buffer = AllocateZeroPool(bs);
880 if (!buffer) {
881 console_print(L"Could not allocate memory\n");
882 /* sure, this might work, why not? */
883 fh2->Close(fh2);
884 fh->Close(fh);
885 return EFI_OUT_OF_RESOURCES;
886 }
887
888 efi_status = fh2->Read(fh2, &bs, buffer);
889 if (EFI_ERROR(efi_status)) {
890 if (buffer) {
891 FreePool(buffer);
892 buffer = NULL;
893 }
894 fh2->Close(fh2);
895 fh->Close(fh);
896 return efi_status;
897 }
898 EFI_FILE_INFO *fi = buffer;
899
900 if (!(fi->Attribute & EFI_FILE_DIRECTORY)) {
901 FreePool(buffer);
902 buffer = NULL;
903 continue;
904 }
905 if (!StrCmp(fi->FileName, L".") ||
906 !StrCmp(fi->FileName, L"..") ||
907 !StrCaseCmp(fi->FileName, L"BOOT")) {
908 FreePool(buffer);
909 buffer = NULL;
910 continue;
911 }
912 VerbosePrint(L"Found directory named \"%s\"\n", fi->FileName);
913
914 EFI_FILE_HANDLE fh3;
915 efi_status = fh2->Open(fh2, &fh3, fi->FileName,
916 EFI_FILE_READ_ONLY, 0);
917 if (EFI_ERROR(efi_status)) {
918 console_print(L"%d Couldn't open %s: %r\n", __LINE__,
919 fi->FileName, efi_status);
920 FreePool(buffer);
921 buffer = NULL;
922 continue;
923 }
924
925 efi_status = find_boot_csv(fh3, fi->FileName);
926 fh3->Close(fh3);
927 FreePool(buffer);
928 buffer = NULL;
929 if (efi_status == EFI_OUT_OF_RESOURCES)
930 break;
931
932 } while (1);
933
934 if (!EFI_ERROR(efi_status) && nbootorder > 0)
935 efi_status = update_boot_order();
936
937 fh2->Close(fh2);
938 fh->Close(fh);
939 return efi_status;
940 }
941
942 static EFI_STATUS
943 try_start_first_option(EFI_HANDLE parent_image_handle)
944 {
945 EFI_STATUS efi_status;
946 EFI_HANDLE image_handle;
947
948 if (get_fallback_verbose()) {
949 int fallback_verbose_wait = 500000; /* default to 0.5s */
950 #ifdef FALLBACK_VERBOSE_WAIT
951 fallback_verbose_wait = FALLBACK_VERBOSE_WAIT;
952 #endif
953 console_print(L"Verbose enabled, sleeping for %d mseconds... "
954 L"Press the Pause key now to hold for longer.\n",
955 fallback_verbose_wait);
956 msleep(fallback_verbose_wait);
957 }
958
959 if (!first_new_option) {
960 return EFI_SUCCESS;
961 }
962
963 efi_status = gBS->LoadImage(0, parent_image_handle, first_new_option,
964 NULL, 0, &image_handle);
965 if (EFI_ERROR(efi_status)) {
966 CHAR16 *dps = DevicePathToStr(first_new_option);
967 UINTN s = DevicePathSize(first_new_option);
968 unsigned int i;
969 UINT8 *dpv = (void *)first_new_option;
970 console_print(L"LoadImage failed: %r\nDevice path: \"%s\"\n",
971 efi_status, dps);
972 for (i = 0; i < s; i++) {
973 if (i > 0 && i % 16 == 0)
974 console_print(L"\n");
975 console_print(L"%02x ", dpv[i]);
976 }
977 console_print(L"\n");
978
979 msleep(500000000);
980 return efi_status;
981 }
982
983 EFI_LOADED_IMAGE *image;
984 efi_status = gBS->HandleProtocol(image_handle, &LoadedImageProtocol,
985 (void *) &image);
986 if (!EFI_ERROR(efi_status)) {
987 image->LoadOptions = first_new_option_args;
988 image->LoadOptionsSize = first_new_option_size;
989 }
990
991 efi_status = gBS->StartImage(image_handle, NULL, NULL);
992 if (EFI_ERROR(efi_status)) {
993 console_print(L"StartImage failed: %r\n", efi_status);
994 msleep(500000000);
995 }
996 return efi_status;
997 }
998
999 static UINT32
1000 get_fallback_no_reboot(void)
1001 {
1002 EFI_STATUS efi_status;
1003 UINT32 no_reboot;
1004 UINTN size = sizeof(UINT32);
1005
1006 efi_status = gRT->GetVariable(NO_REBOOT, &SHIM_LOCK_GUID,
1007 NULL, &size, &no_reboot);
1008 if (!EFI_ERROR(efi_status)) {
1009 return no_reboot;
1010 }
1011 return 0;
1012 }
1013
1014 static EFI_STATUS
1015 set_fallback_no_reboot(void)
1016 {
1017 EFI_STATUS efi_status;
1018 UINT32 no_reboot = 1;
1019 efi_status = gRT->SetVariable(NO_REBOOT, &SHIM_LOCK_GUID,
1020 EFI_VARIABLE_NON_VOLATILE
1021 | EFI_VARIABLE_BOOTSERVICE_ACCESS
1022 | EFI_VARIABLE_RUNTIME_ACCESS,
1023 sizeof(UINT32), &no_reboot);
1024 return efi_status;
1025 }
1026
1027 static int
1028 draw_countdown(void)
1029 {
1030 CHAR16 *title = L"Boot Option Restoration";
1031 CHAR16 *message = L"Press any key to stop system reset";
1032 int timeout;
1033
1034 timeout = console_countdown(title, message, 5);
1035
1036 return timeout;
1037 }
1038
1039 static int
1040 get_user_choice(void)
1041 {
1042 int choice;
1043 CHAR16 *title[] = {L"Boot Option Restored", NULL};
1044 CHAR16 *menu_strings[] = {
1045 L"Reset system",
1046 L"Continue boot",
1047 L"Always continue boot",
1048 NULL
1049 };
1050
1051 do {
1052 choice = console_select(title, menu_strings, 0);
1053 } while (choice < 0 || choice > 2);
1054
1055 return choice;
1056 }
1057
1058 extern EFI_STATUS
1059 efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab);
1060
1061 static void
1062 __attribute__((__optimize__("0")))
1063 debug_hook(void)
1064 {
1065 UINT8 *data = NULL;
1066 UINTN dataSize = 0;
1067 EFI_STATUS efi_status;
1068 register volatile int x = 0;
1069 extern char _etext, _edata;
1070
1071 efi_status = get_variable(L"SHIM_DEBUG", &data, &dataSize,
1072 SHIM_LOCK_GUID);
1073 if (EFI_ERROR(efi_status)) {
1074 return;
1075 }
1076
1077 if (data)
1078 FreePool(data);
1079 if (x)
1080 return;
1081
1082 x = 1;
1083 console_print(L"add-symbol-file "DEBUGDIR
1084 L"fb" EFI_ARCH L".efi.debug %p -s .data %p\n",
1085 &_etext, &_edata);
1086 }
1087
1088 EFI_STATUS
1089 efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
1090 {
1091 EFI_STATUS efi_status;
1092
1093 InitializeLib(image, systab);
1094
1095 /*
1096 * if SHIM_DEBUG is set, wait for a debugger to attach.
1097 */
1098 debug_hook();
1099
1100 efi_status = gBS->HandleProtocol(image, &LoadedImageProtocol,
1101 (void *) &this_image);
1102 if (EFI_ERROR(efi_status)) {
1103 console_print(L"Error: could not find loaded image: %r\n",
1104 efi_status);
1105 return efi_status;
1106 }
1107
1108 VerbosePrint(L"System BootOrder not found. Initializing defaults.\n");
1109
1110 set_boot_order();
1111
1112 efi_status = find_boot_options(this_image->DeviceHandle);
1113 if (EFI_ERROR(efi_status)) {
1114 console_print(L"Error: could not find boot options: %r\n",
1115 efi_status);
1116 return efi_status;
1117 }
1118
1119 efi_status = fallback_should_prefer_reset();
1120 if (EFI_ERROR(efi_status)) {
1121 VerbosePrint(L"tpm not present, starting the first image\n");
1122 try_start_first_option(image);
1123 } else {
1124 if (get_fallback_no_reboot() == 1) {
1125 VerbosePrint(L"NO_REBOOT is set, starting the first image\n");
1126 try_start_first_option(image);
1127 }
1128
1129 int timeout = draw_countdown();
1130 if (timeout == 0)
1131 goto reset;
1132
1133 int choice = get_user_choice();
1134 if (choice == 0) {
1135 goto reset;
1136 } else if (choice == 2) {
1137 efi_status = set_fallback_no_reboot();
1138 if (EFI_ERROR(efi_status))
1139 goto reset;
1140 }
1141 VerbosePrint(L"tpm present, starting the first image\n");
1142 try_start_first_option(image);
1143 reset:
1144 VerbosePrint(L"tpm present, resetting system\n");
1145 }
1146
1147 console_print(L"Reset System\n");
1148
1149 if (get_fallback_verbose()) {
1150 int fallback_verbose_wait = 500000; /* default to 0.5s */
1151 #ifdef FALLBACK_VERBOSE_WAIT
1152 fallback_verbose_wait = FALLBACK_VERBOSE_WAIT;
1153 #endif
1154 console_print(L"Verbose enabled, sleeping for %d mseconds... "
1155 L"Press the Pause key now to hold for longer.\n",
1156 fallback_verbose_wait);
1157 msleep(fallback_verbose_wait);
1158 }
1159
1160 gRT->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL);
1161
1162 return EFI_SUCCESS;
1163 }