]> git.proxmox.com Git - efi-boot-shim.git/blob - fallback.c
Start packaging updates for the new 15.51 upstream release
[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 (!b) {
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(b);
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, *cursor;
234 cursor = data = AllocateZeroPool(size + 2);
235 if (!data)
236 return EFI_OUT_OF_RESOURCES;
237
238 *(UINT32 *)cursor = LOAD_OPTION_ACTIVE;
239 cursor += sizeof (UINT32);
240 *(UINT16 *)cursor = DevicePathSize(hddp);
241 cursor += sizeof (UINT16);
242 StrCpy((CHAR16 *)cursor, label);
243 cursor += StrLen(label)*2 + 2;
244 CopyMem(cursor, hddp, DevicePathSize(hddp));
245 cursor += DevicePathSize(hddp);
246 StrCpy((CHAR16 *)cursor, arguments);
247
248 VerbosePrint(L"Creating boot entry \"%s\" with label \"%s\" "
249 L"for file \"%s\"\n",
250 varname, label, filename);
251
252 if (!first_new_option) {
253 first_new_option = DuplicateDevicePath(fulldp);
254 first_new_option_args = StrDuplicate(arguments);
255 first_new_option_size = StrLen(arguments) * sizeof (CHAR16);
256 }
257
258 efi_status = RT->SetVariable(varname, &GV_GUID,
259 EFI_VARIABLE_NON_VOLATILE |
260 EFI_VARIABLE_BOOTSERVICE_ACCESS |
261 EFI_VARIABLE_RUNTIME_ACCESS,
262 size, data);
263
264 FreePool(data);
265
266 if (EFI_ERROR(efi_status)) {
267 console_print(L"Could not create variable: %r\n",
268 efi_status);
269 return efi_status;
270 }
271
272 CHAR16 *newbootorder = AllocateZeroPool(sizeof (CHAR16)
273 * (nbootorder + 1));
274 if (!newbootorder)
275 return EFI_OUT_OF_RESOURCES;
276
277 int j = 0;
278 newbootorder[0] = i & 0xffff;
279 if (nbootorder) {
280 for (j = 0; j < nbootorder; j++)
281 newbootorder[j+1] = bootorder[j];
282 FreePool(bootorder);
283 }
284 bootorder = newbootorder;
285 nbootorder += 1;
286 VerbosePrint(L"nbootorder: %d\nBootOrder: ",
287 nbootorder);
288 for (j = 0 ; j < nbootorder ; j++)
289 VerbosePrintUnprefixed(L"%04x ", bootorder[j]);
290 VerbosePrintUnprefixed(L"\n");
291
292 return EFI_SUCCESS;
293 }
294 }
295 return EFI_OUT_OF_RESOURCES;
296 }
297
298 /*
299 * AMI BIOS (e.g, Intel NUC5i3MYHE) may automatically hide and patch BootXXXX
300 * variables with ami_masked_device_path_guid. We can get the valid device path
301 * if just skipping it and its next end path.
302 */
303
304 static EFI_GUID ami_masked_device_path_guid = {
305 0x99e275e7, 0x75a0, 0x4b37,
306 { 0xa2, 0xe6, 0xc5, 0x38, 0x5e, 0x6c, 0x0, 0xcb }
307 };
308
309 static unsigned int
310 calc_masked_boot_option_size(unsigned int size)
311 {
312 return size + sizeof(EFI_DEVICE_PATH) +
313 sizeof(ami_masked_device_path_guid) + sizeof(EFI_DEVICE_PATH);
314 }
315
316 static int
317 check_masked_boot_option(CHAR8 *candidate, unsigned int candidate_size,
318 CHAR8 *data, unsigned int data_size)
319 {
320 /*
321 * The patched BootXXXX variables contain a hardware device path and
322 * an end path, preceding the real device path.
323 */
324 if (calc_masked_boot_option_size(data_size) != candidate_size)
325 return 1;
326
327 CHAR8 *cursor = candidate;
328
329 /* Check whether the BootXXXX is patched */
330 cursor += sizeof(UINT32) + sizeof(UINT16);
331 cursor += StrSize((CHAR16 *)cursor);
332
333 unsigned int min_valid_size = cursor - candidate + sizeof(EFI_DEVICE_PATH);
334
335 if (candidate_size <= min_valid_size)
336 return 1;
337
338 EFI_DEVICE_PATH *dp = (EFI_DEVICE_PATH *)cursor;
339 unsigned int node_size = DevicePathNodeLength(dp) - sizeof(EFI_DEVICE_PATH);
340
341 min_valid_size += node_size;
342 if (candidate_size <= min_valid_size ||
343 DevicePathType(dp) != HARDWARE_DEVICE_PATH ||
344 DevicePathSubType(dp) != HW_VENDOR_DP ||
345 node_size != sizeof(ami_masked_device_path_guid) ||
346 CompareGuid((EFI_GUID *)(cursor + sizeof(EFI_DEVICE_PATH)),
347 &ami_masked_device_path_guid))
348 return 1;
349
350 /* Check whether the patched guid is followed by an end path */
351 min_valid_size += sizeof(EFI_DEVICE_PATH);
352 if (candidate_size <= min_valid_size)
353 return 1;
354
355 dp = NextDevicePathNode(dp);
356 if (!IsDevicePathEnd(dp))
357 return 1;
358
359 /*
360 * OK. We may really get a masked BootXXXX variable. The next
361 * step is to test whether it is hidden.
362 */
363 UINT32 attrs = *(UINT32 *)candidate;
364 #ifndef LOAD_OPTION_HIDDEN
365 # define LOAD_OPTION_HIDDEN 0x00000008
366 #endif
367 if (!(attrs & LOAD_OPTION_HIDDEN))
368 return 1;
369
370 attrs &= ~LOAD_OPTION_HIDDEN;
371
372 /* Compare the field Attributes */
373 if (attrs != *(UINT32 *)data)
374 return 1;
375
376 /* Compare the field FilePathListLength */
377 data += sizeof(UINT32);
378 candidate += sizeof(UINT32);
379 if (calc_masked_boot_option_size(*(UINT16 *)data) !=
380 *(UINT16 *)candidate)
381 return 1;
382
383 /* Compare the field Description */
384 data += sizeof(UINT16);
385 candidate += sizeof(UINT16);
386 if (CompareMem(candidate, data, cursor - candidate))
387 return 1;
388
389 /* Compare the filed FilePathList */
390 cursor = (CHAR8 *)NextDevicePathNode(dp);
391 data += sizeof(UINT16);
392 data += StrSize((CHAR16 *)data);
393
394 return CompareMem(cursor, data, candidate_size - min_valid_size);
395 }
396
397 EFI_STATUS
398 find_boot_option(EFI_DEVICE_PATH *dp, EFI_DEVICE_PATH *fulldp,
399 CHAR16 *filename, CHAR16 *label, CHAR16 *arguments,
400 UINT16 *optnum)
401 {
402 unsigned int label_size = StrLen(label)*2 + 2;
403 unsigned int size = sizeof(UINT32) + sizeof (UINT16) +
404 label_size + DevicePathSize(dp) +
405 StrLen(arguments) * 2;
406
407 CHAR8 *data = AllocateZeroPool(size + 2);
408 if (!data)
409 return EFI_OUT_OF_RESOURCES;
410 CHAR8 *cursor = data;
411 *(UINT32 *)cursor = LOAD_OPTION_ACTIVE;
412 cursor += sizeof (UINT32);
413 *(UINT16 *)cursor = DevicePathSize(dp);
414 cursor += sizeof (UINT16);
415 StrCpy((CHAR16 *)cursor, label);
416 cursor += label_size;
417 CopyMem(cursor, dp, DevicePathSize(dp));
418 cursor += DevicePathSize(dp);
419 StrCpy((CHAR16 *)cursor, arguments);
420
421 EFI_STATUS efi_status;
422 EFI_GUID vendor_guid = NullGuid;
423 UINTN buffer_size = 256 * sizeof(CHAR16);
424 CHAR16 *varname = AllocateZeroPool(buffer_size);
425 if (!varname)
426 return EFI_OUT_OF_RESOURCES;
427
428 UINTN max_candidate_size = calc_masked_boot_option_size(size);
429 CHAR8 *candidate = AllocateZeroPool(max_candidate_size);
430 if (!candidate) {
431 FreePool(data);
432 return EFI_OUT_OF_RESOURCES;
433 }
434
435 while (1) {
436 UINTN varname_size = buffer_size;
437 efi_status = RT->GetNextVariableName(&varname_size, varname,
438 &vendor_guid);
439 if (EFI_ERROR(efi_status)) {
440 if (efi_status == EFI_BUFFER_TOO_SMALL) {
441 VerbosePrint(L"Buffer too small for next variable name, re-allocating it to be %d bytes and retrying\n",
442 varname_size);
443 varname = ReallocatePool(varname,
444 buffer_size,
445 varname_size);
446 if (!varname)
447 return EFI_OUT_OF_RESOURCES;
448 buffer_size = varname_size;
449 continue;
450 }
451
452 if (efi_status == EFI_DEVICE_ERROR)
453 VerbosePrint(L"The next variable name could not be retrieved due to a hardware error\n");
454
455 if (efi_status == EFI_INVALID_PARAMETER)
456 VerbosePrint(L"Invalid parameter to GetNextVariableName: varname_size=%d, varname=%s\n",
457 varname_size, varname);
458
459 /* EFI_NOT_FOUND means we listed all variables */
460 VerbosePrint(L"Checked all boot entries\n");
461 break;
462 }
463
464 if (StrLen(varname) != 8 || StrnCmp(varname, L"Boot", 4) ||
465 !isxdigit(varname[4]) || !isxdigit(varname[5]) ||
466 !isxdigit(varname[6]) || !isxdigit(varname[7]))
467 continue;
468
469 UINTN candidate_size = max_candidate_size;
470 efi_status = RT->GetVariable(varname, &GV_GUID, NULL,
471 &candidate_size, candidate);
472 if (EFI_ERROR(efi_status))
473 continue;
474
475 if (candidate_size != size) {
476 if (check_masked_boot_option(candidate, candidate_size,
477 data, size))
478 continue;
479 } else if (CompareMem(candidate, data, size))
480 continue;
481
482 VerbosePrint(L"Found boot entry \"%s\" with label \"%s\" "
483 L"for file \"%s\"\n", varname, label, filename);
484
485 /* at this point, we have duplicate data. */
486 if (!first_new_option) {
487 first_new_option = DuplicateDevicePath(fulldp);
488 first_new_option_args = StrDuplicate(arguments);
489 first_new_option_size = StrLen(arguments) * sizeof (CHAR16);
490 }
491
492 *optnum = xtoi(varname + 4);
493 FreePool(candidate);
494 FreePool(data);
495 return EFI_SUCCESS;
496 }
497 FreePool(candidate);
498 FreePool(data);
499 FreePool(varname);
500 return efi_status;
501 }
502
503 EFI_STATUS
504 set_boot_order(void)
505 {
506 CHAR16 *oldbootorder;
507 UINTN size;
508
509 oldbootorder = LibGetVariableAndSize(L"BootOrder", &GV_GUID, &size);
510 if (oldbootorder) {
511 int i;
512 nbootorder = size / sizeof (CHAR16);
513 bootorder = oldbootorder;
514
515 VerbosePrint(L"Original nbootorder: %d\nOriginal BootOrder: ",
516 nbootorder);
517 for (i = 0 ; i < nbootorder ; i++)
518 VerbosePrintUnprefixed(L"%04x ", bootorder[i]);
519 VerbosePrintUnprefixed(L"\n");
520 }
521 return EFI_SUCCESS;
522
523 }
524
525 EFI_STATUS
526 update_boot_order(void)
527 {
528 UINTN size;
529 UINTN len = 0;
530 CHAR16 *newbootorder = NULL;
531 EFI_STATUS efi_status;
532
533 size = nbootorder * sizeof(CHAR16);
534 newbootorder = AllocateZeroPool(size);
535 if (!newbootorder)
536 return EFI_OUT_OF_RESOURCES;
537 CopyMem(newbootorder, bootorder, size);
538
539 VerbosePrint(L"nbootorder: %d\nBootOrder: ", size / sizeof (CHAR16));
540 UINTN j;
541 for (j = 0 ; j < size / sizeof (CHAR16); j++)
542 VerbosePrintUnprefixed(L"%04x ", newbootorder[j]);
543 VerbosePrintUnprefixed(L"\n");
544 efi_status = RT->GetVariable(L"BootOrder", &GV_GUID, NULL, &len, NULL);
545 if (efi_status == EFI_BUFFER_TOO_SMALL)
546 LibDeleteVariable(L"BootOrder", &GV_GUID);
547
548 efi_status = RT->SetVariable(L"BootOrder", &GV_GUID,
549 EFI_VARIABLE_NON_VOLATILE |
550 EFI_VARIABLE_BOOTSERVICE_ACCESS |
551 EFI_VARIABLE_RUNTIME_ACCESS,
552 size, newbootorder);
553 FreePool(newbootorder);
554 return efi_status;
555 }
556
557 EFI_STATUS
558 add_to_boot_list(CHAR16 *dirname, CHAR16 *filename, CHAR16 *label, CHAR16 *arguments)
559 {
560 CHAR16 *fullpath = NULL;
561 UINT64 pathlen = 0;
562 EFI_STATUS efi_status;
563
564 efi_status = make_full_path(dirname, filename, &fullpath, &pathlen);
565 if (EFI_ERROR(efi_status))
566 return efi_status;
567
568 EFI_DEVICE_PATH *full_device_path = NULL;
569 EFI_DEVICE_PATH *dp = NULL;
570 CHAR16 *dps;
571
572 full_device_path = FileDevicePath(this_image->DeviceHandle, fullpath);
573 if (!full_device_path) {
574 efi_status = EFI_OUT_OF_RESOURCES;
575 goto done;
576 }
577 dps = DevicePathToStr(full_device_path);
578 VerbosePrint(L"file DP: %s\n", dps);
579 FreePool(dps);
580
581 efi_status = FindSubDevicePath(full_device_path,
582 MEDIA_DEVICE_PATH, MEDIA_HARDDRIVE_DP,
583 &dp);
584 if (EFI_ERROR(efi_status)) {
585 if (efi_status == EFI_NOT_FOUND) {
586 dp = full_device_path;
587 } else {
588 efi_status = EFI_OUT_OF_RESOURCES;
589 goto done;
590 }
591 }
592
593 {
594 UINTN s = DevicePathSize(dp);
595 UINTN i;
596 UINT8 *dpv = (void *)dp;
597 for (i = 0; i < s; i++) {
598 if (i % 16 == 0) {
599 if (i > 0)
600 VerbosePrintUnprefixed(L"\n");
601 VerbosePrint(L"");
602 }
603 VerbosePrintUnprefixed(L"%02x ", dpv[i]);
604 }
605 VerbosePrintUnprefixed(L"\n");
606
607 CHAR16 *dps = DevicePathToStr(dp);
608 VerbosePrint(L"device path: \"%s\"\n", dps);
609 FreePool(dps);
610 }
611
612 UINT16 option;
613 efi_status = find_boot_option(dp, full_device_path, fullpath, label,
614 arguments, &option);
615 if (EFI_ERROR(efi_status)) {
616 add_boot_option(dp, full_device_path, fullpath, label,
617 arguments);
618 goto done;
619 }
620
621 UINT16 bootnum;
622 CHAR16 *newbootorder;
623 /* Search for the option in the current bootorder */
624 for (bootnum = 0; bootnum < nbootorder; bootnum++)
625 if (bootorder[bootnum] == option)
626 break;
627 if (bootnum == nbootorder) {
628 /* Option not found, prepend option and copy the rest */
629 newbootorder = AllocateZeroPool(sizeof(CHAR16)
630 * (nbootorder + 1));
631 if (!newbootorder) {
632 efi_status = EFI_OUT_OF_RESOURCES;
633 goto done;
634 }
635 newbootorder[0] = option;
636 CopyMem(newbootorder + 1, bootorder,
637 sizeof(CHAR16) * nbootorder);
638 FreePool(bootorder);
639 bootorder = newbootorder;
640 nbootorder += 1;
641 } else {
642 /* Option found, put first and slice the rest */
643 newbootorder = AllocateZeroPool(
644 sizeof(CHAR16) * nbootorder);
645 if (!newbootorder) {
646 efi_status = EFI_OUT_OF_RESOURCES;
647 goto done;
648 }
649 newbootorder[0] = option;
650 CopyMem(newbootorder + 1, bootorder,
651 sizeof(CHAR16) * bootnum);
652 CopyMem(newbootorder + 1 + bootnum,
653 bootorder + bootnum + 1,
654 sizeof(CHAR16) * (nbootorder - bootnum - 1));
655 FreePool(bootorder);
656 bootorder = newbootorder;
657 }
658 VerbosePrint(L"New nbootorder: %d\nBootOrder: ",
659 nbootorder);
660 for (int i = 0 ; i < nbootorder ; i++)
661 VerbosePrintUnprefixed(L"%04x ", bootorder[i]);
662 VerbosePrintUnprefixed(L"\n");
663
664 done:
665 if (full_device_path)
666 FreePool(full_device_path);
667 if (dp && dp != full_device_path)
668 FreePool(dp);
669 if (fullpath)
670 FreePool(fullpath);
671 return efi_status;
672 }
673
674 EFI_STATUS
675 populate_stanza(CHAR16 *dirname, CHAR16 *filename UNUSED, CHAR16 *csv)
676 {
677 CHAR16 *file = csv;
678 VerbosePrint(L"CSV data: \"%s\"\n", csv);
679
680 UINTN comma0 = StrCSpn(csv, L",");
681 if (comma0 == 0)
682 return EFI_INVALID_PARAMETER;
683 file[comma0] = L'\0';
684 VerbosePrint(L"filename: \"%s\"\n", file);
685
686 CHAR16 *label = csv + comma0 + 1;
687 UINTN comma1 = StrCSpn(label, L",");
688 if (comma1 == 0)
689 return EFI_INVALID_PARAMETER;
690 label[comma1] = L'\0';
691 VerbosePrint(L"label: \"%s\"\n", label);
692
693 CHAR16 *arguments = csv + comma0 +1 + comma1 +1;
694 UINTN comma2 = StrCSpn(arguments, L",");
695 arguments[comma2] = L'\0';
696 /* This one is optional, so don't check if comma2 is 0 */
697 VerbosePrint(L"arguments: \"%s\"\n", arguments);
698
699 add_to_boot_list(dirname, file, label, arguments);
700
701 return EFI_SUCCESS;
702 }
703
704 EFI_STATUS
705 try_boot_csv(EFI_FILE_HANDLE fh, CHAR16 *dirname, CHAR16 *filename)
706 {
707 CHAR16 *fullpath = NULL;
708 UINT64 pathlen = 0;
709 EFI_STATUS efi_status;
710
711 efi_status = make_full_path(dirname, filename, &fullpath, &pathlen);
712 if (EFI_ERROR(efi_status))
713 return efi_status;
714
715 VerbosePrint(L"Found file \"%s\"\n", fullpath);
716
717 CHAR16 *buffer;
718 UINT64 bs;
719 efi_status = read_file(fh, fullpath, &buffer, &bs);
720 if (EFI_ERROR(efi_status)) {
721 console_print(L"Could not read file \"%s\": %r\n",
722 fullpath, efi_status);
723 FreePool(fullpath);
724 return efi_status;
725 }
726 FreePool(fullpath);
727
728 VerbosePrint(L"File looks like:\n%s\n", buffer);
729
730 CHAR16 *start = buffer;
731 /* The file may or may not start with the Unicode byte order marker.
732 * Sadness ensues. Since UEFI is defined as LE, I'm going to decree
733 * that these files must also be LE.
734 *
735 * IT IS THUS SO.
736 *
737 * But if we find the LE byte order marker, just skip it.
738 */
739 if (*start == 0xfeff)
740 start++;
741 while (*start) {
742 while (*start == L'\r' || *start == L'\n')
743 start++;
744 UINTN l = StrCSpn(start, L"\r\n");
745 if (l == 0) {
746 if (start[l] == L'\0')
747 break;
748 start++;
749 continue;
750 }
751 CHAR16 c = start[l];
752 start[l] = L'\0';
753
754 populate_stanza(dirname, filename, start);
755
756 start[l] = c;
757 start += l;
758 }
759
760 FreePool(buffer);
761 return EFI_SUCCESS;
762 }
763
764 EFI_STATUS
765 find_boot_csv(EFI_FILE_HANDLE fh, CHAR16 *dirname)
766 {
767 EFI_STATUS efi_status;
768 void *buffer = NULL;
769 UINTN bs = 0;
770
771 /* The API here is "Call it once with bs=0, it fills in bs,
772 * then allocate a buffer and ask again to get it filled. */
773 efi_status = fh->GetInfo(fh, &EFI_FILE_INFO_GUID, &bs, NULL);
774 if (EFI_ERROR(efi_status) && efi_status != EFI_BUFFER_TOO_SMALL) {
775 console_print(L"Could not get directory info for \\EFI\\%s\\: %r\n",
776 dirname, efi_status);
777 return efi_status;
778 }
779 if (bs == 0)
780 return EFI_SUCCESS;
781
782 buffer = AllocateZeroPool(bs);
783 if (!buffer) {
784 console_print(L"Could not allocate memory\n");
785 return EFI_OUT_OF_RESOURCES;
786 }
787
788 efi_status = fh->GetInfo(fh, &EFI_FILE_INFO_GUID, &bs, buffer);
789 /* This checks *either* the error from the first GetInfo, if it isn't
790 * the EFI_BUFFER_TOO_SMALL we're expecting, or the second GetInfo
791 * call in *any* case. */
792 if (EFI_ERROR(efi_status)) {
793 console_print(L"Could not get info for \"%s\": %r\n", dirname,
794 efi_status);
795 if (buffer)
796 FreePool(buffer);
797 return efi_status;
798 }
799
800 EFI_FILE_INFO *fi = buffer;
801 if (!(fi->Attribute & EFI_FILE_DIRECTORY)) {
802 FreePool(buffer);
803 return EFI_SUCCESS;
804 }
805 FreePool(buffer);
806 buffer = NULL;
807
808 CHAR16 *bootcsv=NULL, *bootarchcsv=NULL;
809
810 bs = 0;
811 do {
812 bs = 0;
813 efi_status = fh->Read(fh, &bs, NULL);
814 if (EFI_ERROR(efi_status) &&
815 efi_status != EFI_BUFFER_TOO_SMALL) {
816 console_print(L"Could not read \\EFI\\%s\\: %r\n",
817 dirname, efi_status);
818 return efi_status;
819 }
820 /* If there's no data to read, don't try to allocate 0 bytes
821 * and read the data... */
822 if (bs == 0)
823 break;
824
825 buffer = AllocateZeroPool(bs);
826 if (!buffer) {
827 console_print(L"Could not allocate memory\n");
828 return EFI_OUT_OF_RESOURCES;
829 }
830
831 efi_status = fh->Read(fh, &bs, buffer);
832 if (EFI_ERROR(efi_status)) {
833 console_print(L"Could not read \\EFI\\%s\\: %r\n",
834 dirname, efi_status);
835 FreePool(buffer);
836 return efi_status;
837 }
838
839 if (bs == 0)
840 break;
841
842 fi = buffer;
843
844 if (!bootcsv && !StrCaseCmp(fi->FileName, L"boot.csv"))
845 bootcsv = StrDuplicate(fi->FileName);
846
847 if (!bootarchcsv &&
848 !StrCaseCmp(fi->FileName, L"boot" EFI_ARCH L".csv"))
849 bootarchcsv = StrDuplicate(fi->FileName);
850
851 FreePool(buffer);
852 buffer = NULL;
853 } while (bs != 0);
854
855 efi_status = EFI_SUCCESS;
856 if (bootarchcsv) {
857 EFI_FILE_HANDLE fh2;
858 efi_status = fh->Open(fh, &fh2, bootarchcsv,
859 EFI_FILE_READ_ONLY, 0);
860 if (EFI_ERROR(efi_status) || fh2 == NULL) {
861 console_print(L"Couldn't open \\EFI\\%s\\%s: %r\n",
862 dirname, bootarchcsv, efi_status);
863 } else {
864 efi_status = try_boot_csv(fh2, dirname, bootarchcsv);
865 fh2->Close(fh2);
866 if (EFI_ERROR(efi_status))
867 console_print(L"Could not process \\EFI\\%s\\%s: %r\n",
868 dirname, bootarchcsv, efi_status);
869 }
870 }
871 if ((EFI_ERROR(efi_status) || !bootarchcsv) && bootcsv) {
872 EFI_FILE_HANDLE fh2;
873 efi_status = fh->Open(fh, &fh2, bootcsv,
874 EFI_FILE_READ_ONLY, 0);
875 if (EFI_ERROR(efi_status) || fh2 == NULL) {
876 console_print(L"Couldn't open \\EFI\\%s\\%s: %r\n",
877 dirname, bootcsv, efi_status);
878 } else {
879 efi_status = try_boot_csv(fh2, dirname, bootcsv);
880 fh2->Close(fh2);
881 if (EFI_ERROR(efi_status))
882 console_print(L"Could not process \\EFI\\%s\\%s: %r\n",
883 dirname, bootarchcsv, efi_status);
884 }
885 }
886 return EFI_SUCCESS;
887 }
888
889 EFI_STATUS
890 find_boot_options(EFI_HANDLE device)
891 {
892 EFI_STATUS efi_status;
893 EFI_FILE_IO_INTERFACE *fio = NULL;
894
895 efi_status = BS->HandleProtocol(device, &FileSystemProtocol,
896 (void **) &fio);
897 if (EFI_ERROR(efi_status)) {
898 console_print(L"Couldn't find file system: %r\n", efi_status);
899 return efi_status;
900 }
901
902 /* EFI_FILE_HANDLE is a pointer to an EFI_FILE, and I have
903 * *no idea* what frees the memory allocated here. Hopefully
904 * Close() does. */
905 EFI_FILE_HANDLE fh = NULL;
906 efi_status = fio->OpenVolume(fio, &fh);
907 if (EFI_ERROR(efi_status) || fh == NULL) {
908 console_print(L"Couldn't open file system: %r\n", efi_status);
909 return efi_status;
910 }
911
912 EFI_FILE_HANDLE fh2 = NULL;
913 efi_status = fh->Open(fh, &fh2, L"EFI", EFI_FILE_READ_ONLY, 0);
914 if (EFI_ERROR(efi_status) || fh2 == NULL) {
915 console_print(L"Couldn't open EFI: %r\n", efi_status);
916 fh->Close(fh);
917 return efi_status;
918 }
919 efi_status = fh2->SetPosition(fh2, 0);
920 if (EFI_ERROR(efi_status)) {
921 console_print(L"Couldn't set file position: %r\n", efi_status);
922 fh2->Close(fh2);
923 fh->Close(fh);
924 return efi_status;
925 }
926
927 void *buffer;
928 UINTN bs;
929 do {
930 bs = 0;
931 efi_status = fh2->Read(fh2, &bs, NULL);
932 if (EFI_ERROR(efi_status) && efi_status != EFI_BUFFER_TOO_SMALL) {
933 console_print(L"Could not read \\EFI\\: %r\n", efi_status);
934 return efi_status;
935 }
936 if (bs == 0)
937 break;
938
939 buffer = AllocateZeroPool(bs);
940 if (!buffer) {
941 console_print(L"Could not allocate memory\n");
942 /* sure, this might work, why not? */
943 fh2->Close(fh2);
944 fh->Close(fh);
945 return EFI_OUT_OF_RESOURCES;
946 }
947
948 efi_status = fh2->Read(fh2, &bs, buffer);
949 if (EFI_ERROR(efi_status)) {
950 if (buffer) {
951 FreePool(buffer);
952 buffer = NULL;
953 }
954 fh2->Close(fh2);
955 fh->Close(fh);
956 return efi_status;
957 }
958 EFI_FILE_INFO *fi = buffer;
959
960 if (!(fi->Attribute & EFI_FILE_DIRECTORY)) {
961 FreePool(buffer);
962 buffer = NULL;
963 continue;
964 }
965 if (!StrCmp(fi->FileName, L".") ||
966 !StrCmp(fi->FileName, L"..") ||
967 !StrCaseCmp(fi->FileName, L"BOOT")) {
968 FreePool(buffer);
969 buffer = NULL;
970 continue;
971 }
972 VerbosePrint(L"Found directory named \"%s\"\n", fi->FileName);
973
974 EFI_FILE_HANDLE fh3;
975 efi_status = fh2->Open(fh2, &fh3, fi->FileName,
976 EFI_FILE_READ_ONLY, 0);
977 if (EFI_ERROR(efi_status)) {
978 console_print(L"%d Couldn't open %s: %r\n", __LINE__,
979 fi->FileName, efi_status);
980 FreePool(buffer);
981 buffer = NULL;
982 continue;
983 }
984
985 efi_status = find_boot_csv(fh3, fi->FileName);
986 fh3->Close(fh3);
987 FreePool(buffer);
988 buffer = NULL;
989 if (efi_status == EFI_OUT_OF_RESOURCES)
990 break;
991
992 } while (1);
993
994 if (!EFI_ERROR(efi_status) && nbootorder > 0)
995 efi_status = update_boot_order();
996
997 fh2->Close(fh2);
998 fh->Close(fh);
999 return efi_status;
1000 }
1001
1002 static EFI_STATUS
1003 try_start_first_option(EFI_HANDLE parent_image_handle)
1004 {
1005 EFI_STATUS efi_status;
1006 EFI_HANDLE image_handle;
1007
1008 if (get_fallback_verbose()) {
1009 int fallback_verbose_wait = 500000; /* default to 0.5s */
1010 #ifdef FALLBACK_VERBOSE_WAIT
1011 fallback_verbose_wait = FALLBACK_VERBOSE_WAIT;
1012 #endif
1013 console_print(L"Verbose enabled, sleeping for %d mseconds... "
1014 L"Press the Pause key now to hold for longer.\n",
1015 fallback_verbose_wait);
1016 msleep(fallback_verbose_wait);
1017 }
1018
1019 if (!first_new_option) {
1020 return EFI_SUCCESS;
1021 }
1022
1023 efi_status = BS->LoadImage(0, parent_image_handle, first_new_option,
1024 NULL, 0, &image_handle);
1025 if (EFI_ERROR(efi_status)) {
1026 CHAR16 *dps = DevicePathToStr(first_new_option);
1027 UINTN s = DevicePathSize(first_new_option);
1028 unsigned int i;
1029 UINT8 *dpv = (void *)first_new_option;
1030 console_print(L"LoadImage failed: %r\nDevice path: \"%s\"\n",
1031 efi_status, dps);
1032 for (i = 0; i < s; i++) {
1033 if (i > 0 && i % 16 == 0)
1034 console_print(L"\n");
1035 console_print(L"%02x ", dpv[i]);
1036 }
1037 console_print(L"\n");
1038
1039 msleep(500000000);
1040 return efi_status;
1041 }
1042
1043 EFI_LOADED_IMAGE *image;
1044 efi_status = BS->HandleProtocol(image_handle, &LoadedImageProtocol,
1045 (void *) &image);
1046 if (!EFI_ERROR(efi_status)) {
1047 image->LoadOptions = first_new_option_args;
1048 image->LoadOptionsSize = first_new_option_size;
1049 }
1050
1051 efi_status = BS->StartImage(image_handle, NULL, NULL);
1052 if (EFI_ERROR(efi_status)) {
1053 console_print(L"StartImage failed: %r\n", efi_status);
1054 msleep(500000000);
1055 }
1056 return efi_status;
1057 }
1058
1059 static UINT32
1060 get_fallback_no_reboot(void)
1061 {
1062 EFI_STATUS efi_status;
1063 UINT32 no_reboot;
1064 UINTN size = sizeof(UINT32);
1065
1066 efi_status = RT->GetVariable(NO_REBOOT, &SHIM_LOCK_GUID,
1067 NULL, &size, &no_reboot);
1068 if (!EFI_ERROR(efi_status)) {
1069 return no_reboot;
1070 }
1071 return 0;
1072 }
1073
1074 #ifndef FALLBACK_NONINTERACTIVE
1075 static EFI_STATUS
1076 set_fallback_no_reboot(void)
1077 {
1078 EFI_STATUS efi_status;
1079 UINT32 no_reboot = 1;
1080 efi_status = RT->SetVariable(NO_REBOOT, &SHIM_LOCK_GUID,
1081 EFI_VARIABLE_NON_VOLATILE |
1082 EFI_VARIABLE_BOOTSERVICE_ACCESS |
1083 EFI_VARIABLE_RUNTIME_ACCESS,
1084 sizeof(UINT32), &no_reboot);
1085 return efi_status;
1086 }
1087
1088 static int
1089 draw_countdown(void)
1090 {
1091 CHAR16 *title = L"Boot Option Restoration";
1092 CHAR16 *message = L"Press any key to stop system reset";
1093 int timeout;
1094
1095 timeout = console_countdown(title, message, 5);
1096
1097 return timeout;
1098 }
1099
1100 static int
1101 get_user_choice(void)
1102 {
1103 int choice;
1104 CHAR16 *title[] = {L"Boot Option Restored", NULL};
1105 CHAR16 *menu_strings[] = {
1106 L"Reset system",
1107 L"Continue boot",
1108 L"Always continue boot",
1109 NULL
1110 };
1111
1112 do {
1113 choice = console_select(title, menu_strings, 0);
1114 } while (choice < 0 || choice > 2);
1115
1116 return choice;
1117 }
1118 #endif
1119
1120 extern EFI_STATUS
1121 efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab);
1122
1123 static void
1124 __attribute__((__optimize__("0")))
1125 debug_hook(void)
1126 {
1127 UINT8 *data = NULL;
1128 UINTN dataSize = 0;
1129 EFI_STATUS efi_status;
1130 register volatile int x = 0;
1131 extern char _etext, _edata;
1132
1133 efi_status = get_variable(L"SHIM_DEBUG", &data, &dataSize,
1134 SHIM_LOCK_GUID);
1135 if (EFI_ERROR(efi_status)) {
1136 return;
1137 }
1138
1139 if (data)
1140 FreePool(data);
1141 if (x)
1142 return;
1143
1144 x = 1;
1145 console_print(L"add-symbol-file "DEBUGDIR
1146 L"fb" EFI_ARCH L".efi.debug %p -s .data %p\n",
1147 &_etext, &_edata);
1148 }
1149
1150 EFI_STATUS
1151 efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
1152 {
1153 EFI_STATUS efi_status;
1154
1155 InitializeLib(image, systab);
1156
1157 /*
1158 * if SHIM_DEBUG is set, wait for a debugger to attach.
1159 */
1160 debug_hook();
1161
1162 efi_status = BS->HandleProtocol(image, &LoadedImageProtocol,
1163 (void *) &this_image);
1164 if (EFI_ERROR(efi_status)) {
1165 console_print(L"Error: could not find loaded image: %r\n",
1166 efi_status);
1167 return efi_status;
1168 }
1169
1170 VerbosePrint(L"System BootOrder not found. Initializing defaults.\n");
1171
1172 set_boot_order();
1173
1174 efi_status = find_boot_options(this_image->DeviceHandle);
1175 if (EFI_ERROR(efi_status)) {
1176 console_print(L"Error: could not find boot options: %r\n",
1177 efi_status);
1178 return efi_status;
1179 }
1180
1181 efi_status = fallback_should_prefer_reset();
1182 if (EFI_ERROR(efi_status)) {
1183 VerbosePrint(L"tpm not present, starting the first image\n");
1184 try_start_first_option(image);
1185 } else {
1186 if (get_fallback_no_reboot() == 1) {
1187 VerbosePrint(L"NO_REBOOT is set, starting the first image\n");
1188 try_start_first_option(image);
1189 }
1190
1191 #ifndef FALLBACK_NONINTERACTIVE
1192 int timeout = draw_countdown();
1193 if (timeout == 0)
1194 goto reset;
1195
1196 int choice = get_user_choice();
1197 if (choice == 0) {
1198 goto reset;
1199 } else if (choice == 2) {
1200 efi_status = set_fallback_no_reboot();
1201 if (EFI_ERROR(efi_status))
1202 goto reset;
1203 }
1204 VerbosePrint(L"tpm present, starting the first image\n");
1205 try_start_first_option(image);
1206 reset:
1207 #endif
1208 VerbosePrint(L"tpm present, resetting system\n");
1209 }
1210
1211 console_print(L"Reset System\n");
1212
1213 if (get_fallback_verbose()) {
1214 int fallback_verbose_wait = 500000; /* default to 0.5s */
1215 #ifdef FALLBACK_VERBOSE_WAIT
1216 fallback_verbose_wait = FALLBACK_VERBOSE_WAIT;
1217 #endif
1218 console_print(L"Verbose enabled, sleeping for %d mseconds... "
1219 L"Press the Pause key now to hold for longer.\n",
1220 fallback_verbose_wait);
1221 msleep(fallback_verbose_wait);
1222 }
1223
1224 RT->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL);
1225
1226 return EFI_SUCCESS;
1227 }