1 // SPDX-License-Identifier: BSD-2-Clause-Patent
3 * Copyright Red Hat, Inc.
4 * Copyright Peter Jones <pjones@redhat.com>
8 #define NO_REBOOT L"FB_NO_REBOOT"
10 EFI_LOADED_IMAGE
*this_image
= NULL
;
13 get_fallback_verbose(void)
15 #ifdef FALLBACK_VERBOSE
20 EFI_STATUS efi_status
;
22 static int state
= -1;
27 efi_status
= get_variable(L
"FALLBACK_VERBOSE",
28 &data
, &dataSize
, SHIM_LOCK_GUID
);
29 if (EFI_ERROR(efi_status
)) {
35 for (i
= 0; i
< dataSize
; i
++) {
48 #define VerbosePrintUnprefixed(fmt, ...) \
51 if (get_fallback_verbose()) \
52 ret_ = console_print((fmt), ##__VA_ARGS__); \
56 #define VerbosePrint(fmt, ...) \
58 UINTN line_ = __LINE__ - 2; \
60 if (get_fallback_verbose()) { \
61 console_print(L"%a:%d: ", __func__, line_); \
62 ret_ = console_print((fmt), ##__VA_ARGS__); \
68 FindSubDevicePath(EFI_DEVICE_PATH
*In
, UINT8 Type
, UINT8 SubType
,
69 EFI_DEVICE_PATH
**Out
)
71 EFI_DEVICE_PATH
*dp
= In
;
73 return EFI_INVALID_PARAMETER
;
75 CHAR16
*dps
= DevicePathToStr(In
);
76 VerbosePrint(L
"input device path: \"%s\"\n", dps
);
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",
87 *Out
= DuplicateDevicePath(dp
);
89 return EFI_OUT_OF_RESOURCES
;
98 get_file_size(EFI_FILE_HANDLE fh
, UINTN
*retsize
)
100 EFI_STATUS efi_status
;
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
)
112 buffer
= AllocateZeroPool(bs
);
114 console_print(L
"Could not allocate memory\n");
115 return EFI_OUT_OF_RESOURCES
;
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
);
127 EFI_FILE_INFO
*fi
= buffer
;
128 *retsize
= fi
->FileSize
;
134 read_file(EFI_FILE_HANDLE fh
, CHAR16
*fullpath
, CHAR16
**buffer
, UINT64
*bs
)
137 EFI_STATUS efi_status
;
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
);
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
);
155 if (len
> 1024 * PAGE_SIZE
) {
157 return EFI_BAD_BUFFER_SIZE
;
160 b
= AllocateZeroPool(len
+ 2);
162 console_print(L
"Could not allocate memory\n");
164 return EFI_OUT_OF_RESOURCES
;
167 efi_status
= fh
->Read(fh
, &len
, b
);
168 if (EFI_ERROR(efi_status
)) {
171 console_print(L
"Could not read file: %r\n", efi_status
);
181 make_full_path(CHAR16
*dirname
, CHAR16
*filename
, CHAR16
**out
, UINT64
*outlen
)
185 len
= StrLen(L
"\\EFI\\") + StrLen(dirname
)
186 + StrLen(L
"\\") + StrLen(filename
)
189 CHAR16
*fullpath
= AllocateZeroPool(len
*sizeof(CHAR16
));
191 console_print(L
"Could not allocate memory\n");
192 return EFI_OUT_OF_RESOURCES
;
195 StrCat(fullpath
, L
"\\EFI\\");
196 StrCat(fullpath
, dirname
);
197 StrCat(fullpath
, L
"\\");
198 StrCat(fullpath
, filename
);
205 CHAR16
*bootorder
= NULL
;
208 EFI_DEVICE_PATH
*first_new_option
= NULL
;
209 VOID
*first_new_option_args
= NULL
;
210 UINTN first_new_option_size
= 0;
213 add_boot_option(EFI_DEVICE_PATH
*hddp
, EFI_DEVICE_PATH
*fulldp
,
214 CHAR16
*filename
, CHAR16
*label
, CHAR16
*arguments
)
217 CHAR16 varname
[] = L
"Boot0000";
218 CHAR16 hexmap
[] = L
"0123456789ABCDEF";
219 EFI_STATUS efi_status
;
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];
227 void *var
= LibGetVariable(varname
, &GV_GUID
);
229 int size
= sizeof(UINT32
) + sizeof (UINT16
) +
230 StrLen(label
)*2 + 2 + DevicePathSize(hddp
) +
231 StrLen(arguments
) * 2;
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
);
245 VerbosePrint(L
"Creating boot entry \"%s\" with label \"%s\" "
246 L
"for file \"%s\"\n",
247 varname
, label
, filename
);
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
);
255 efi_status
= gRT
->SetVariable(varname
, &GV_GUID
,
256 EFI_VARIABLE_NON_VOLATILE
|
257 EFI_VARIABLE_BOOTSERVICE_ACCESS
|
258 EFI_VARIABLE_RUNTIME_ACCESS
,
263 if (EFI_ERROR(efi_status
)) {
264 console_print(L
"Could not create variable: %r\n",
269 CHAR16
*newbootorder
= AllocateZeroPool(sizeof (CHAR16
)
272 return EFI_OUT_OF_RESOURCES
;
275 newbootorder
[0] = i
& 0xffff;
277 for (j
= 0; j
< nbootorder
; j
++)
278 newbootorder
[j
+1] = bootorder
[j
];
281 bootorder
= newbootorder
;
283 VerbosePrint(L
"nbootorder: %d\nBootOrder: ",
285 for (j
= 0 ; j
< nbootorder
; j
++)
286 VerbosePrintUnprefixed(L
"%04x ", bootorder
[j
]);
287 VerbosePrintUnprefixed(L
"\n");
292 return EFI_OUT_OF_RESOURCES
;
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.
301 static EFI_GUID ami_masked_device_path_guid
= {
302 0x99e275e7, 0x75a0, 0x4b37,
303 { 0xa2, 0xe6, 0xc5, 0x38, 0x5e, 0x6c, 0x0, 0xcb }
307 calc_masked_boot_option_size(unsigned int size
)
309 return size
+ sizeof(EFI_DEVICE_PATH
) +
310 sizeof(ami_masked_device_path_guid
) + sizeof(EFI_DEVICE_PATH
);
314 check_masked_boot_option(CHAR8
*candidate
, unsigned int candidate_size
,
315 CHAR8
*data
, unsigned int data_size
)
318 * The patched BootXXXX variables contain a hardware device path and
319 * an end path, preceding the real device path.
321 if (calc_masked_boot_option_size(data_size
) != candidate_size
)
324 CHAR8
*cursor
= candidate
;
326 /* Check whether the BootXXXX is patched */
327 cursor
+= sizeof(UINT32
) + sizeof(UINT16
);
328 cursor
+= StrSize((CHAR16
*)cursor
);
330 unsigned int min_valid_size
= cursor
- candidate
+ sizeof(EFI_DEVICE_PATH
);
332 if (candidate_size
<= min_valid_size
)
335 EFI_DEVICE_PATH
*dp
= (EFI_DEVICE_PATH
*)cursor
;
336 unsigned int node_size
= DevicePathNodeLength(dp
) - sizeof(EFI_DEVICE_PATH
);
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
))
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
)
352 dp
= NextDevicePathNode(dp
);
353 if (!IsDevicePathEnd(dp
))
357 * OK. We may really get a masked BootXXXX variable. The next
358 * step is to test whether it is hidden.
360 UINT32 attrs
= *(UINT32
*)candidate
;
361 #ifndef LOAD_OPTION_HIDDEN
362 # define LOAD_OPTION_HIDDEN 0x00000008
364 if (!(attrs
& LOAD_OPTION_HIDDEN
))
367 attrs
&= ~LOAD_OPTION_HIDDEN
;
369 /* Compare the field Attributes */
370 if (attrs
!= *(UINT32
*)data
)
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
)
380 /* Compare the field Description */
381 data
+= sizeof(UINT16
);
382 candidate
+= sizeof(UINT16
);
383 if (CompareMem(candidate
, data
, cursor
- candidate
))
386 /* Compare the filed FilePathList */
387 cursor
= (CHAR8
*)NextDevicePathNode(dp
);
388 data
+= sizeof(UINT16
);
389 data
+= StrSize((CHAR16
*)data
);
391 return CompareMem(cursor
, data
, candidate_size
- min_valid_size
);
395 find_boot_option(EFI_DEVICE_PATH
*dp
, EFI_DEVICE_PATH
*fulldp
,
396 CHAR16
*filename
, CHAR16
*label
, CHAR16
*arguments
,
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;
404 CHAR8
*data
= AllocateZeroPool(size
+ 2);
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
);
419 EFI_STATUS efi_status
;
420 EFI_GUID vendor_guid
= NullGuid
;
422 UINTN max_candidate_size
= calc_masked_boot_option_size(size
);
423 CHAR8
*candidate
= AllocateZeroPool(max_candidate_size
);
426 return EFI_OUT_OF_RESOURCES
;
431 UINTN varname_size
= sizeof(varname
);
432 efi_status
= gRT
->GetNextVariableName(&varname_size
, varname
,
434 if (EFI_ERROR(efi_status
))
437 if (StrLen(varname
) != 8 || StrnCmp(varname
, L
"Boot", 4) ||
438 !isxdigit(varname
[4]) || !isxdigit(varname
[5]) ||
439 !isxdigit(varname
[6]) || !isxdigit(varname
[7]))
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
))
448 if (candidate_size
!= size
) {
449 if (check_masked_boot_option(candidate
, candidate_size
,
452 } else if (CompareMem(candidate
, data
, size
))
455 VerbosePrint(L
"Found boot entry \"%s\" with label \"%s\" "
456 L
"for file \"%s\"\n", varname
, label
, filename
);
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
);
465 *optnum
= xtoi(varname
+ 4);
472 return EFI_NOT_FOUND
;
478 CHAR16
*oldbootorder
;
481 oldbootorder
= LibGetVariableAndSize(L
"BootOrder", &GV_GUID
, &size
);
484 nbootorder
= size
/ sizeof (CHAR16
);
485 bootorder
= oldbootorder
;
487 VerbosePrint(L
"Original nbootorder: %d\nOriginal BootOrder: ",
489 for (i
= 0 ; i
< nbootorder
; i
++)
490 VerbosePrintUnprefixed(L
"%04x ", bootorder
[i
]);
491 VerbosePrintUnprefixed(L
"\n");
498 update_boot_order(void)
502 CHAR16
*newbootorder
= NULL
;
503 EFI_STATUS efi_status
;
505 size
= nbootorder
* sizeof(CHAR16
);
506 newbootorder
= AllocateZeroPool(size
);
508 return EFI_OUT_OF_RESOURCES
;
509 CopyMem(newbootorder
, bootorder
, size
);
511 VerbosePrint(L
"nbootorder: %d\nBootOrder: ", size
/ sizeof (CHAR16
));
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
);
520 efi_status
= gRT
->SetVariable(L
"BootOrder", &GV_GUID
,
521 EFI_VARIABLE_NON_VOLATILE
|
522 EFI_VARIABLE_BOOTSERVICE_ACCESS
|
523 EFI_VARIABLE_RUNTIME_ACCESS
,
525 FreePool(newbootorder
);
530 add_to_boot_list(CHAR16
*dirname
, CHAR16
*filename
, CHAR16
*label
, CHAR16
*arguments
)
532 CHAR16
*fullpath
= NULL
;
534 EFI_STATUS efi_status
;
536 efi_status
= make_full_path(dirname
, filename
, &fullpath
, &pathlen
);
537 if (EFI_ERROR(efi_status
))
540 EFI_DEVICE_PATH
*full_device_path
= NULL
;
541 EFI_DEVICE_PATH
*dp
= NULL
;
544 full_device_path
= FileDevicePath(this_image
->DeviceHandle
, fullpath
);
545 if (!full_device_path
) {
546 efi_status
= EFI_OUT_OF_RESOURCES
;
549 dps
= DevicePathToStr(full_device_path
);
550 VerbosePrint(L
"file DP: %s\n", dps
);
553 efi_status
= FindSubDevicePath(full_device_path
,
554 MEDIA_DEVICE_PATH
, MEDIA_HARDDRIVE_DP
,
556 if (EFI_ERROR(efi_status
)) {
557 if (efi_status
== EFI_NOT_FOUND
) {
558 dp
= full_device_path
;
560 efi_status
= EFI_OUT_OF_RESOURCES
;
566 UINTN s
= DevicePathSize(dp
);
568 UINT8
*dpv
= (void *)dp
;
569 for (i
= 0; i
< s
; i
++) {
572 VerbosePrintUnprefixed(L
"\n");
575 VerbosePrintUnprefixed(L
"%02x ", dpv
[i
]);
577 VerbosePrintUnprefixed(L
"\n");
579 CHAR16
*dps
= DevicePathToStr(dp
);
580 VerbosePrint(L
"device path: \"%s\"\n", dps
);
585 efi_status
= find_boot_option(dp
, full_device_path
, fullpath
, label
,
587 if (EFI_ERROR(efi_status
)) {
588 add_boot_option(dp
, full_device_path
, fullpath
, label
,
590 } else if (option
!= 0) {
591 CHAR16
*newbootorder
;
592 newbootorder
= AllocateZeroPool(sizeof (CHAR16
) * nbootorder
);
594 return EFI_OUT_OF_RESOURCES
;
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));
601 bootorder
= newbootorder
;
605 if (full_device_path
)
606 FreePool(full_device_path
);
607 if (dp
&& dp
!= full_device_path
)
615 populate_stanza(CHAR16
*dirname
, CHAR16
*filename UNUSED
, CHAR16
*csv
)
618 VerbosePrint(L
"CSV data: \"%s\"\n", csv
);
620 UINTN comma0
= StrCSpn(csv
, L
",");
622 return EFI_INVALID_PARAMETER
;
623 file
[comma0
] = L
'\0';
624 VerbosePrint(L
"filename: \"%s\"\n", file
);
626 CHAR16
*label
= csv
+ comma0
+ 1;
627 UINTN comma1
= StrCSpn(label
, L
",");
629 return EFI_INVALID_PARAMETER
;
630 label
[comma1
] = L
'\0';
631 VerbosePrint(L
"label: \"%s\"\n", label
);
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
);
639 add_to_boot_list(dirname
, file
, label
, arguments
);
645 try_boot_csv(EFI_FILE_HANDLE fh
, CHAR16
*dirname
, CHAR16
*filename
)
647 CHAR16
*fullpath
= NULL
;
649 EFI_STATUS efi_status
;
651 efi_status
= make_full_path(dirname
, filename
, &fullpath
, &pathlen
);
652 if (EFI_ERROR(efi_status
))
655 VerbosePrint(L
"Found file \"%s\"\n", fullpath
);
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
);
668 VerbosePrint(L
"File looks like:\n%s\n", buffer
);
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.
677 * But if we find the LE byte order marker, just skip it.
679 if (*start
== 0xfeff)
682 while (*start
== L
'\r' || *start
== L
'\n')
684 UINTN l
= StrCSpn(start
, L
"\r\n");
686 if (start
[l
] == L
'\0')
694 populate_stanza(dirname
, filename
, start
);
705 find_boot_csv(EFI_FILE_HANDLE fh
, CHAR16
*dirname
)
707 EFI_STATUS efi_status
;
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
);
722 buffer
= AllocateZeroPool(bs
);
724 console_print(L
"Could not allocate memory\n");
725 return EFI_OUT_OF_RESOURCES
;
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
,
740 EFI_FILE_INFO
*fi
= buffer
;
741 if (!(fi
->Attribute
& EFI_FILE_DIRECTORY
)) {
748 CHAR16
*bootcsv
=NULL
, *bootarchcsv
=NULL
;
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
);
760 /* If there's no data to read, don't try to allocate 0 bytes
761 * and read the data... */
765 buffer
= AllocateZeroPool(bs
);
767 console_print(L
"Could not allocate memory\n");
768 return EFI_OUT_OF_RESOURCES
;
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
);
784 if (!bootcsv
&& !StrCaseCmp(fi
->FileName
, L
"boot.csv"))
785 bootcsv
= StrDuplicate(fi
->FileName
);
788 !StrCaseCmp(fi
->FileName
, L
"boot" EFI_ARCH L
".csv"))
789 bootarchcsv
= StrDuplicate(fi
->FileName
);
795 efi_status
= EFI_SUCCESS
;
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
);
804 efi_status
= try_boot_csv(fh2
, dirname
, bootarchcsv
);
806 if (EFI_ERROR(efi_status
))
807 console_print(L
"Could not process \\EFI\\%s\\%s: %r\n",
808 dirname
, bootarchcsv
, efi_status
);
811 if ((EFI_ERROR(efi_status
) || !bootarchcsv
) && bootcsv
) {
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
);
819 efi_status
= try_boot_csv(fh2
, dirname
, bootcsv
);
821 if (EFI_ERROR(efi_status
))
822 console_print(L
"Could not process \\EFI\\%s\\%s: %r\n",
823 dirname
, bootarchcsv
, efi_status
);
830 find_boot_options(EFI_HANDLE device
)
832 EFI_STATUS efi_status
;
833 EFI_FILE_IO_INTERFACE
*fio
= NULL
;
835 efi_status
= gBS
->HandleProtocol(device
, &FileSystemProtocol
,
837 if (EFI_ERROR(efi_status
)) {
838 console_print(L
"Couldn't find file system: %r\n", efi_status
);
842 /* EFI_FILE_HANDLE is a pointer to an EFI_FILE, and I have
843 * *no idea* what frees the memory allocated here. Hopefully
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
);
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
);
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
);
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
);
879 buffer
= AllocateZeroPool(bs
);
881 console_print(L
"Could not allocate memory\n");
882 /* sure, this might work, why not? */
885 return EFI_OUT_OF_RESOURCES
;
888 efi_status
= fh2
->Read(fh2
, &bs
, buffer
);
889 if (EFI_ERROR(efi_status
)) {
898 EFI_FILE_INFO
*fi
= buffer
;
900 if (!(fi
->Attribute
& EFI_FILE_DIRECTORY
)) {
905 if (!StrCmp(fi
->FileName
, L
".") ||
906 !StrCmp(fi
->FileName
, L
"..") ||
907 !StrCaseCmp(fi
->FileName
, L
"BOOT")) {
912 VerbosePrint(L
"Found directory named \"%s\"\n", fi
->FileName
);
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
);
925 efi_status
= find_boot_csv(fh3
, fi
->FileName
);
929 if (efi_status
== EFI_OUT_OF_RESOURCES
)
934 if (!EFI_ERROR(efi_status
) && nbootorder
> 0)
935 efi_status
= update_boot_order();
943 try_start_first_option(EFI_HANDLE parent_image_handle
)
945 EFI_STATUS efi_status
;
946 EFI_HANDLE image_handle
;
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
;
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
);
959 if (!first_new_option
) {
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
);
969 UINT8
*dpv
= (void *)first_new_option
;
970 console_print(L
"LoadImage failed: %r\nDevice path: \"%s\"\n",
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
]);
977 console_print(L
"\n");
983 EFI_LOADED_IMAGE
*image
;
984 efi_status
= gBS
->HandleProtocol(image_handle
, &LoadedImageProtocol
,
986 if (!EFI_ERROR(efi_status
)) {
987 image
->LoadOptions
= first_new_option_args
;
988 image
->LoadOptionsSize
= first_new_option_size
;
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
);
1000 get_fallback_no_reboot(void)
1002 EFI_STATUS efi_status
;
1004 UINTN size
= sizeof(UINT32
);
1006 efi_status
= gRT
->GetVariable(NO_REBOOT
, &SHIM_LOCK_GUID
,
1007 NULL
, &size
, &no_reboot
);
1008 if (!EFI_ERROR(efi_status
)) {
1015 set_fallback_no_reboot(void)
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
);
1028 draw_countdown(void)
1030 CHAR16
*title
= L
"Boot Option Restoration";
1031 CHAR16
*message
= L
"Press any key to stop system reset";
1034 timeout
= console_countdown(title
, message
, 5);
1040 get_user_choice(void)
1043 CHAR16
*title
[] = {L
"Boot Option Restored", NULL
};
1044 CHAR16
*menu_strings
[] = {
1047 L
"Always continue boot",
1052 choice
= console_select(title
, menu_strings
, 0);
1053 } while (choice
< 0 || choice
> 2);
1059 efi_main(EFI_HANDLE image
, EFI_SYSTEM_TABLE
*systab
);
1062 __attribute__((__optimize__("0")))
1067 EFI_STATUS efi_status
;
1068 register volatile int x
= 0;
1069 extern char _etext
, _edata
;
1071 efi_status
= get_variable(L
"SHIM_DEBUG", &data
, &dataSize
,
1073 if (EFI_ERROR(efi_status
)) {
1083 console_print(L
"add-symbol-file "DEBUGDIR
1084 L
"fb" EFI_ARCH L
".efi.debug %p -s .data %p\n",
1089 efi_main(EFI_HANDLE image
, EFI_SYSTEM_TABLE
*systab
)
1091 EFI_STATUS efi_status
;
1093 InitializeLib(image
, systab
);
1096 * if SHIM_DEBUG is set, wait for a debugger to attach.
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",
1108 VerbosePrint(L
"System BootOrder not found. Initializing defaults.\n");
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",
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
);
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
);
1129 int timeout
= draw_countdown();
1133 int choice
= get_user_choice();
1136 } else if (choice
== 2) {
1137 efi_status
= set_fallback_no_reboot();
1138 if (EFI_ERROR(efi_status
))
1141 VerbosePrint(L
"tpm present, starting the first image\n");
1142 try_start_first_option(image
);
1144 VerbosePrint(L
"tpm present, resetting system\n");
1147 console_print(L
"Reset System\n");
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
;
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
);
1160 gRT
->ResetSystem(EfiResetCold
, EFI_SUCCESS
, 0, NULL
);