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(FALLBACK_VERBOSE_VAR_NAME
,
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
, *cursor
;
234 cursor
= data
= AllocateZeroPool(size
+ 2);
236 return EFI_OUT_OF_RESOURCES
;
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
);
248 VerbosePrint(L
"Creating boot entry \"%s\" with label \"%s\" "
249 L
"for file \"%s\"\n",
250 varname
, label
, filename
);
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
);
258 efi_status
= RT
->SetVariable(varname
, &GV_GUID
,
259 EFI_VARIABLE_NON_VOLATILE
|
260 EFI_VARIABLE_BOOTSERVICE_ACCESS
|
261 EFI_VARIABLE_RUNTIME_ACCESS
,
266 if (EFI_ERROR(efi_status
)) {
267 console_print(L
"Could not create variable: %r\n",
272 CHAR16
*newbootorder
= AllocateZeroPool(sizeof (CHAR16
)
275 return EFI_OUT_OF_RESOURCES
;
278 newbootorder
[0] = i
& 0xffff;
280 for (j
= 0; j
< nbootorder
; j
++)
281 newbootorder
[j
+1] = bootorder
[j
];
284 bootorder
= newbootorder
;
286 VerbosePrint(L
"nbootorder: %d\nBootOrder: ",
288 for (j
= 0 ; j
< nbootorder
; j
++)
289 VerbosePrintUnprefixed(L
"%04x ", bootorder
[j
]);
290 VerbosePrintUnprefixed(L
"\n");
295 return EFI_OUT_OF_RESOURCES
;
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.
304 static EFI_GUID ami_masked_device_path_guid
= {
305 0x99e275e7, 0x75a0, 0x4b37,
306 { 0xa2, 0xe6, 0xc5, 0x38, 0x5e, 0x6c, 0x0, 0xcb }
310 calc_masked_boot_option_size(unsigned int size
)
312 return size
+ sizeof(EFI_DEVICE_PATH
) +
313 sizeof(ami_masked_device_path_guid
) + sizeof(EFI_DEVICE_PATH
);
317 check_masked_boot_option(CHAR8
*candidate
, unsigned int candidate_size
,
318 CHAR8
*data
, unsigned int data_size
)
321 * The patched BootXXXX variables contain a hardware device path and
322 * an end path, preceding the real device path.
324 if (calc_masked_boot_option_size(data_size
) != candidate_size
)
327 CHAR8
*cursor
= candidate
;
329 /* Check whether the BootXXXX is patched */
330 cursor
+= sizeof(UINT32
) + sizeof(UINT16
);
331 cursor
+= StrSize((CHAR16
*)cursor
);
333 unsigned int min_valid_size
= cursor
- candidate
+ sizeof(EFI_DEVICE_PATH
);
335 if (candidate_size
<= min_valid_size
)
338 EFI_DEVICE_PATH
*dp
= (EFI_DEVICE_PATH
*)cursor
;
339 unsigned int node_size
= DevicePathNodeLength(dp
) - sizeof(EFI_DEVICE_PATH
);
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
))
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
)
355 dp
= NextDevicePathNode(dp
);
356 if (!IsDevicePathEnd(dp
))
360 * OK. We may really get a masked BootXXXX variable. The next
361 * step is to test whether it is hidden.
363 UINT32 attrs
= *(UINT32
*)candidate
;
364 #ifndef LOAD_OPTION_HIDDEN
365 # define LOAD_OPTION_HIDDEN 0x00000008
367 if (!(attrs
& LOAD_OPTION_HIDDEN
))
370 attrs
&= ~LOAD_OPTION_HIDDEN
;
372 /* Compare the field Attributes */
373 if (attrs
!= *(UINT32
*)data
)
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
)
383 /* Compare the field Description */
384 data
+= sizeof(UINT16
);
385 candidate
+= sizeof(UINT16
);
386 if (CompareMem(candidate
, data
, cursor
- candidate
))
389 /* Compare the filed FilePathList */
390 cursor
= (CHAR8
*)NextDevicePathNode(dp
);
391 data
+= sizeof(UINT16
);
392 data
+= StrSize((CHAR16
*)data
);
394 return CompareMem(cursor
, data
, candidate_size
- min_valid_size
);
398 find_boot_option(EFI_DEVICE_PATH
*dp
, EFI_DEVICE_PATH
*fulldp
,
399 CHAR16
*filename
, CHAR16
*label
, CHAR16
*arguments
,
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;
407 CHAR8
*data
= AllocateZeroPool(size
+ 2);
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
);
421 EFI_STATUS efi_status
;
422 EFI_GUID vendor_guid
= NullGuid
;
423 UINTN buffer_size
= 256 * sizeof(CHAR16
);
424 CHAR16
*varname
= AllocateZeroPool(buffer_size
);
426 return EFI_OUT_OF_RESOURCES
;
428 UINTN max_candidate_size
= calc_masked_boot_option_size(size
);
429 CHAR8
*candidate
= AllocateZeroPool(max_candidate_size
);
432 return EFI_OUT_OF_RESOURCES
;
436 UINTN varname_size
= buffer_size
;
437 efi_status
= RT
->GetNextVariableName(&varname_size
, varname
,
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",
443 varname
= ReallocatePool(varname
,
447 return EFI_OUT_OF_RESOURCES
;
448 buffer_size
= varname_size
;
452 if (efi_status
== EFI_DEVICE_ERROR
)
453 VerbosePrint(L
"The next variable name could not be retrieved due to a hardware error\n");
455 if (efi_status
== EFI_INVALID_PARAMETER
)
456 VerbosePrint(L
"Invalid parameter to GetNextVariableName: varname_size=%d, varname=%s\n",
457 varname_size
, varname
);
459 /* EFI_NOT_FOUND means we listed all variables */
460 VerbosePrint(L
"Checked all boot entries\n");
464 if (StrLen(varname
) != 8 || StrnCmp(varname
, L
"Boot", 4) ||
465 !isxdigit(varname
[4]) || !isxdigit(varname
[5]) ||
466 !isxdigit(varname
[6]) || !isxdigit(varname
[7]))
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
))
475 if (candidate_size
!= size
) {
476 if (check_masked_boot_option(candidate
, candidate_size
,
479 } else if (CompareMem(candidate
, data
, size
))
482 VerbosePrint(L
"Found boot entry \"%s\" with label \"%s\" "
483 L
"for file \"%s\"\n", varname
, label
, filename
);
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
);
492 *optnum
= xtoi(varname
+ 4);
506 CHAR16
*oldbootorder
;
509 oldbootorder
= LibGetVariableAndSize(L
"BootOrder", &GV_GUID
, &size
);
512 nbootorder
= size
/ sizeof (CHAR16
);
513 bootorder
= oldbootorder
;
515 VerbosePrint(L
"Original nbootorder: %d\nOriginal BootOrder: ",
517 for (i
= 0 ; i
< nbootorder
; i
++)
518 VerbosePrintUnprefixed(L
"%04x ", bootorder
[i
]);
519 VerbosePrintUnprefixed(L
"\n");
526 update_boot_order(void)
530 CHAR16
*newbootorder
= NULL
;
531 EFI_STATUS efi_status
;
533 size
= nbootorder
* sizeof(CHAR16
);
534 newbootorder
= AllocateZeroPool(size
);
536 return EFI_OUT_OF_RESOURCES
;
537 CopyMem(newbootorder
, bootorder
, size
);
539 VerbosePrint(L
"nbootorder: %d\nBootOrder: ", size
/ sizeof (CHAR16
));
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
);
548 efi_status
= RT
->SetVariable(L
"BootOrder", &GV_GUID
,
549 EFI_VARIABLE_NON_VOLATILE
|
550 EFI_VARIABLE_BOOTSERVICE_ACCESS
|
551 EFI_VARIABLE_RUNTIME_ACCESS
,
553 FreePool(newbootorder
);
558 add_to_boot_list(CHAR16
*dirname
, CHAR16
*filename
, CHAR16
*label
, CHAR16
*arguments
)
560 CHAR16
*fullpath
= NULL
;
562 EFI_STATUS efi_status
;
564 efi_status
= make_full_path(dirname
, filename
, &fullpath
, &pathlen
);
565 if (EFI_ERROR(efi_status
))
568 EFI_DEVICE_PATH
*full_device_path
= NULL
;
569 EFI_DEVICE_PATH
*dp
= NULL
;
572 full_device_path
= FileDevicePath(this_image
->DeviceHandle
, fullpath
);
573 if (!full_device_path
) {
574 efi_status
= EFI_OUT_OF_RESOURCES
;
577 dps
= DevicePathToStr(full_device_path
);
578 VerbosePrint(L
"file DP: %s\n", dps
);
581 efi_status
= FindSubDevicePath(full_device_path
,
582 MEDIA_DEVICE_PATH
, MEDIA_HARDDRIVE_DP
,
584 if (EFI_ERROR(efi_status
)) {
585 if (efi_status
== EFI_NOT_FOUND
) {
586 dp
= full_device_path
;
588 efi_status
= EFI_OUT_OF_RESOURCES
;
594 UINTN s
= DevicePathSize(dp
);
596 UINT8
*dpv
= (void *)dp
;
597 for (i
= 0; i
< s
; i
++) {
600 VerbosePrintUnprefixed(L
"\n");
603 VerbosePrintUnprefixed(L
"%02x ", dpv
[i
]);
605 VerbosePrintUnprefixed(L
"\n");
607 CHAR16
*dps
= DevicePathToStr(dp
);
608 VerbosePrint(L
"device path: \"%s\"\n", dps
);
613 efi_status
= find_boot_option(dp
, full_device_path
, fullpath
, label
,
615 if (EFI_ERROR(efi_status
)) {
616 add_boot_option(dp
, full_device_path
, fullpath
, label
,
622 CHAR16
*newbootorder
;
623 /* Search for the option in the current bootorder */
624 for (bootnum
= 0; bootnum
< nbootorder
; bootnum
++)
625 if (bootorder
[bootnum
] == option
)
627 if (bootnum
== nbootorder
) {
628 /* Option not found, prepend option and copy the rest */
629 newbootorder
= AllocateZeroPool(sizeof(CHAR16
)
632 efi_status
= EFI_OUT_OF_RESOURCES
;
635 newbootorder
[0] = option
;
636 CopyMem(newbootorder
+ 1, bootorder
,
637 sizeof(CHAR16
) * nbootorder
);
639 bootorder
= newbootorder
;
642 /* Option found, put first and slice the rest */
643 newbootorder
= AllocateZeroPool(
644 sizeof(CHAR16
) * nbootorder
);
646 efi_status
= EFI_OUT_OF_RESOURCES
;
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));
656 bootorder
= newbootorder
;
658 VerbosePrint(L
"New nbootorder: %d\nBootOrder: ",
660 for (int i
= 0 ; i
< nbootorder
; i
++)
661 VerbosePrintUnprefixed(L
"%04x ", bootorder
[i
]);
662 VerbosePrintUnprefixed(L
"\n");
665 if (full_device_path
)
666 FreePool(full_device_path
);
667 if (dp
&& dp
!= full_device_path
)
675 populate_stanza(CHAR16
*dirname
, CHAR16
*filename UNUSED
, CHAR16
*csv
)
678 VerbosePrint(L
"CSV data: \"%s\"\n", csv
);
680 UINTN comma0
= StrCSpn(csv
, L
",");
682 return EFI_INVALID_PARAMETER
;
683 file
[comma0
] = L
'\0';
684 VerbosePrint(L
"filename: \"%s\"\n", file
);
686 CHAR16
*label
= csv
+ comma0
+ 1;
687 UINTN comma1
= StrCSpn(label
, L
",");
689 return EFI_INVALID_PARAMETER
;
690 label
[comma1
] = L
'\0';
691 VerbosePrint(L
"label: \"%s\"\n", label
);
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
);
699 add_to_boot_list(dirname
, file
, label
, arguments
);
705 try_boot_csv(EFI_FILE_HANDLE fh
, CHAR16
*dirname
, CHAR16
*filename
)
707 CHAR16
*fullpath
= NULL
;
709 EFI_STATUS efi_status
;
711 efi_status
= make_full_path(dirname
, filename
, &fullpath
, &pathlen
);
712 if (EFI_ERROR(efi_status
))
715 VerbosePrint(L
"Found file \"%s\"\n", fullpath
);
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
);
728 VerbosePrint(L
"File looks like:\n%s\n", buffer
);
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.
737 * But if we find the LE byte order marker, just skip it.
739 if (*start
== 0xfeff)
742 while (*start
== L
'\r' || *start
== L
'\n')
744 UINTN l
= StrCSpn(start
, L
"\r\n");
746 if (start
[l
] == L
'\0')
754 populate_stanza(dirname
, filename
, start
);
765 find_boot_csv(EFI_FILE_HANDLE fh
, CHAR16
*dirname
)
767 EFI_STATUS efi_status
;
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
);
782 buffer
= AllocateZeroPool(bs
);
784 console_print(L
"Could not allocate memory\n");
785 return EFI_OUT_OF_RESOURCES
;
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
,
800 EFI_FILE_INFO
*fi
= buffer
;
801 if (!(fi
->Attribute
& EFI_FILE_DIRECTORY
)) {
808 CHAR16
*bootcsv
=NULL
, *bootarchcsv
=NULL
;
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
);
820 /* If there's no data to read, don't try to allocate 0 bytes
821 * and read the data... */
825 buffer
= AllocateZeroPool(bs
);
827 console_print(L
"Could not allocate memory\n");
828 return EFI_OUT_OF_RESOURCES
;
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
);
844 if (!bootcsv
&& !StrCaseCmp(fi
->FileName
, L
"boot.csv"))
845 bootcsv
= StrDuplicate(fi
->FileName
);
848 !StrCaseCmp(fi
->FileName
, L
"boot" EFI_ARCH L
".csv"))
849 bootarchcsv
= StrDuplicate(fi
->FileName
);
855 efi_status
= EFI_SUCCESS
;
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
);
864 efi_status
= try_boot_csv(fh2
, dirname
, bootarchcsv
);
866 if (EFI_ERROR(efi_status
))
867 console_print(L
"Could not process \\EFI\\%s\\%s: %r\n",
868 dirname
, bootarchcsv
, efi_status
);
871 if ((EFI_ERROR(efi_status
) || !bootarchcsv
) && bootcsv
) {
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
);
879 efi_status
= try_boot_csv(fh2
, dirname
, bootcsv
);
881 if (EFI_ERROR(efi_status
))
882 console_print(L
"Could not process \\EFI\\%s\\%s: %r\n",
883 dirname
, bootarchcsv
, efi_status
);
890 find_boot_options(EFI_HANDLE device
)
892 EFI_STATUS efi_status
;
893 EFI_FILE_IO_INTERFACE
*fio
= NULL
;
895 efi_status
= BS
->HandleProtocol(device
, &FileSystemProtocol
,
897 if (EFI_ERROR(efi_status
)) {
898 console_print(L
"Couldn't find file system: %r\n", efi_status
);
902 /* EFI_FILE_HANDLE is a pointer to an EFI_FILE, and I have
903 * *no idea* what frees the memory allocated here. Hopefully
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
);
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
);
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
);
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
);
939 buffer
= AllocateZeroPool(bs
);
941 console_print(L
"Could not allocate memory\n");
942 /* sure, this might work, why not? */
945 return EFI_OUT_OF_RESOURCES
;
948 efi_status
= fh2
->Read(fh2
, &bs
, buffer
);
949 if (EFI_ERROR(efi_status
)) {
958 EFI_FILE_INFO
*fi
= buffer
;
960 if (!(fi
->Attribute
& EFI_FILE_DIRECTORY
)) {
965 if (!StrCmp(fi
->FileName
, L
".") ||
966 !StrCmp(fi
->FileName
, L
"..") ||
967 !StrCaseCmp(fi
->FileName
, L
"BOOT")) {
972 VerbosePrint(L
"Found directory named \"%s\"\n", fi
->FileName
);
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
);
985 efi_status
= find_boot_csv(fh3
, fi
->FileName
);
989 if (efi_status
== EFI_OUT_OF_RESOURCES
)
994 if (!EFI_ERROR(efi_status
) && nbootorder
> 0)
995 efi_status
= update_boot_order();
1003 try_start_first_option(EFI_HANDLE parent_image_handle
)
1005 EFI_STATUS efi_status
;
1006 EFI_HANDLE image_handle
;
1008 if (get_fallback_verbose()) {
1009 unsigned long fallback_verbose_wait
= 500000; /* default to 0.5s */
1010 #ifdef FALLBACK_VERBOSE_WAIT
1011 fallback_verbose_wait
= FALLBACK_VERBOSE_WAIT
;
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 usleep(fallback_verbose_wait
);
1019 if (!first_new_option
) {
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
);
1029 UINT8
*dpv
= (void *)first_new_option
;
1030 console_print(L
"LoadImage failed: %r\nDevice path: \"%s\"\n",
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
]);
1037 console_print(L
"\n");
1043 EFI_LOADED_IMAGE
*image
;
1044 efi_status
= BS
->HandleProtocol(image_handle
, &LoadedImageProtocol
,
1046 if (!EFI_ERROR(efi_status
)) {
1047 image
->LoadOptions
= first_new_option_args
;
1048 image
->LoadOptionsSize
= first_new_option_size
;
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
);
1060 get_fallback_no_reboot(void)
1062 EFI_STATUS efi_status
;
1064 UINTN size
= sizeof(UINT32
);
1066 efi_status
= RT
->GetVariable(NO_REBOOT
, &SHIM_LOCK_GUID
,
1067 NULL
, &size
, &no_reboot
);
1068 if (!EFI_ERROR(efi_status
)) {
1074 #ifndef FALLBACK_NONINTERACTIVE
1076 set_fallback_no_reboot(void)
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
);
1089 draw_countdown(void)
1091 CHAR16
*title
= L
"Boot Option Restoration";
1092 CHAR16
*message
= L
"Press any key to stop system reset";
1095 timeout
= console_countdown(title
, message
, 5);
1101 get_user_choice(void)
1104 CHAR16
*title
[] = {L
"Boot Option Restored", NULL
};
1105 CHAR16
*menu_strings
[] = {
1108 L
"Always continue boot",
1113 choice
= console_select(title
, menu_strings
, 0);
1114 } while (choice
< 0 || choice
> 2);
1121 efi_main(EFI_HANDLE image
, EFI_SYSTEM_TABLE
*systab
);
1124 __attribute__((__optimize__("0")))
1129 EFI_STATUS efi_status
;
1130 register volatile int x
= 0;
1131 extern char _etext
, _edata
;
1133 efi_status
= get_variable(DEBUG_VAR_NAME
, &data
, &dataSize
,
1135 if (EFI_ERROR(efi_status
)) {
1145 console_print(L
"add-symbol-file "DEBUGDIR
1146 L
"fb" EFI_ARCH L
".efi.debug %p -s .data %p\n",
1151 efi_main(EFI_HANDLE image
, EFI_SYSTEM_TABLE
*systab
)
1153 EFI_STATUS efi_status
;
1155 InitializeLib(image
, systab
);
1158 * if SHIM_DEBUG is set, wait for a debugger to attach.
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",
1170 VerbosePrint(L
"System BootOrder not found. Initializing defaults.\n");
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",
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
);
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
);
1191 #ifndef FALLBACK_NONINTERACTIVE
1192 int timeout
= draw_countdown();
1196 int choice
= get_user_choice();
1199 } else if (choice
== 2) {
1200 efi_status
= set_fallback_no_reboot();
1201 if (EFI_ERROR(efi_status
))
1204 VerbosePrint(L
"tpm present, starting the first image\n");
1205 try_start_first_option(image
);
1208 VerbosePrint(L
"tpm present, resetting system\n");
1211 console_print(L
"Reset System\n");
1213 if (get_fallback_verbose()) {
1214 unsigned long fallback_verbose_wait
= 500000; /* default to 0.5s */
1215 #ifdef FALLBACK_VERBOSE_WAIT
1216 fallback_verbose_wait
= FALLBACK_VERBOSE_WAIT
;
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 usleep(fallback_verbose_wait
);
1224 RT
->ResetSystem(EfiResetCold
, EFI_SUCCESS
, 0, NULL
);