2 * Copyright 2012-2013 Red Hat, Inc.
5 * See "COPYING" for license terms.
7 * Author(s): Peter Jones <pjones@redhat.com>
15 EFI_LOADED_IMAGE
*this_image
= NULL
;
18 get_fallback_verbose(void)
22 EFI_STATUS efi_status
;
24 static int state
= -1;
29 efi_status
= get_variable(L
"FALLBACK_VERBOSE",
30 &data
, &dataSize
, SHIM_LOCK_GUID
);
31 if (EFI_ERROR(efi_status
)) {
37 for (i
= 0; i
< dataSize
; i
++) {
49 #define VerbosePrintUnprefixed(fmt, ...) \
52 if (get_fallback_verbose()) \
53 ret_ = console_print((fmt), ##__VA_ARGS__); \
57 #define VerbosePrint(fmt, ...) \
58 ({ UINTN line_ = __LINE__; \
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 console_print(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 #ifdef DEBUG_FALLBACK
284 console_print(L
"nbootorder: %d\nBootOrder: ",
286 for (j
= 0 ; j
< nbootorder
; j
++)
287 console_print(L
"%04x ", bootorder
[j
]);
288 console_print(L
"\n");
294 return EFI_OUT_OF_RESOURCES
;
298 * AMI BIOS (e.g, Intel NUC5i3MYHE) may automatically hide and patch BootXXXX
299 * variables with ami_masked_device_path_guid. We can get the valid device path
300 * if just skipping it and its next end path.
303 static EFI_GUID ami_masked_device_path_guid
= {
304 0x99e275e7, 0x75a0, 0x4b37,
305 { 0xa2, 0xe6, 0xc5, 0x38, 0x5e, 0x6c, 0x0, 0xcb }
309 calc_masked_boot_option_size(unsigned int size
)
311 return size
+ sizeof(EFI_DEVICE_PATH
) +
312 sizeof(ami_masked_device_path_guid
) + sizeof(EFI_DEVICE_PATH
);
316 check_masked_boot_option(CHAR8
*candidate
, unsigned int candidate_size
,
317 CHAR8
*data
, unsigned int data_size
)
320 * The patched BootXXXX variables contain a hardware device path and
321 * an end path, preceding the real device path.
323 if (calc_masked_boot_option_size(data_size
) != candidate_size
)
326 CHAR8
*cursor
= candidate
;
328 /* Check whether the BootXXXX is patched */
329 cursor
+= sizeof(UINT32
) + sizeof(UINT16
);
330 cursor
+= StrSize((CHAR16
*)cursor
);
332 unsigned int min_valid_size
= cursor
- candidate
+ sizeof(EFI_DEVICE_PATH
);
334 if (candidate_size
<= min_valid_size
)
337 EFI_DEVICE_PATH
*dp
= (EFI_DEVICE_PATH
*)cursor
;
338 unsigned int node_size
= DevicePathNodeLength(dp
) - sizeof(EFI_DEVICE_PATH
);
340 min_valid_size
+= node_size
;
341 if (candidate_size
<= min_valid_size
||
342 DevicePathType(dp
) != HARDWARE_DEVICE_PATH
||
343 DevicePathSubType(dp
) != HW_VENDOR_DP
||
344 node_size
!= sizeof(ami_masked_device_path_guid
) ||
345 CompareGuid((EFI_GUID
*)(cursor
+ sizeof(EFI_DEVICE_PATH
)),
346 &ami_masked_device_path_guid
))
349 /* Check whether the patched guid is followed by an end path */
350 min_valid_size
+= sizeof(EFI_DEVICE_PATH
);
351 if (candidate_size
<= min_valid_size
)
354 dp
= NextDevicePathNode(dp
);
355 if (!IsDevicePathEnd(dp
))
359 * OK. We may really get a masked BootXXXX variable. The next
360 * step is to test whether it is hidden.
362 UINT32 attrs
= *(UINT32
*)candidate
;
363 #ifndef LOAD_OPTION_HIDDEN
364 # define LOAD_OPTION_HIDDEN 0x00000008
366 if (!(attrs
& LOAD_OPTION_HIDDEN
))
369 attrs
&= ~LOAD_OPTION_HIDDEN
;
371 /* Compare the field Attributes */
372 if (attrs
!= *(UINT32
*)data
)
375 /* Compare the field FilePathListLength */
376 data
+= sizeof(UINT32
);
377 candidate
+= sizeof(UINT32
);
378 if (calc_masked_boot_option_size(*(UINT16
*)data
) !=
379 *(UINT16
*)candidate
)
382 /* Compare the field Description */
383 data
+= sizeof(UINT16
);
384 candidate
+= sizeof(UINT16
);
385 if (CompareMem(candidate
, data
, cursor
- candidate
))
388 /* Compare the filed FilePathList */
389 cursor
= (CHAR8
*)NextDevicePathNode(dp
);
390 data
+= sizeof(UINT16
);
391 data
+= StrSize((CHAR16
*)data
);
393 return CompareMem(cursor
, data
, candidate_size
- min_valid_size
);
397 find_boot_option(EFI_DEVICE_PATH
*dp
, EFI_DEVICE_PATH
*fulldp
,
398 CHAR16
*filename
, CHAR16
*label
, CHAR16
*arguments
,
401 unsigned int size
= sizeof(UINT32
) + sizeof (UINT16
) +
402 StrLen(label
)*2 + 2 + DevicePathSize(dp
) +
403 StrLen(arguments
) * 2;
405 CHAR8
*data
= AllocateZeroPool(size
+ 2);
407 return EFI_OUT_OF_RESOURCES
;
408 CHAR8
*cursor
= data
;
409 *(UINT32
*)cursor
= LOAD_OPTION_ACTIVE
;
410 cursor
+= sizeof (UINT32
);
411 *(UINT16
*)cursor
= DevicePathSize(dp
);
412 cursor
+= sizeof (UINT16
);
413 StrCpy((CHAR16
*)cursor
, label
);
414 cursor
+= StrLen(label
)*2 + 2;
415 CopyMem(cursor
, dp
, DevicePathSize(dp
));
416 cursor
+= DevicePathSize(dp
);
417 StrCpy((CHAR16
*)cursor
, arguments
);
420 CHAR16 varname
[] = L
"Boot0000";
421 CHAR16 hexmap
[] = L
"0123456789ABCDEF";
422 EFI_STATUS efi_status
;
424 UINTN max_candidate_size
= calc_masked_boot_option_size(size
);
425 CHAR8
*candidate
= AllocateZeroPool(max_candidate_size
);
428 return EFI_OUT_OF_RESOURCES
;
431 for(i
= 0; i
< nbootorder
&& i
< 0x10000; i
++) {
432 varname
[4] = hexmap
[(bootorder
[i
] & 0xf000) >> 12];
433 varname
[5] = hexmap
[(bootorder
[i
] & 0x0f00) >> 8];
434 varname
[6] = hexmap
[(bootorder
[i
] & 0x00f0) >> 4];
435 varname
[7] = hexmap
[(bootorder
[i
] & 0x000f) >> 0];
437 UINTN candidate_size
= max_candidate_size
;
438 efi_status
= gRT
->GetVariable(varname
, &GV_GUID
, NULL
,
439 &candidate_size
, candidate
);
440 if (EFI_ERROR(efi_status
))
443 if (candidate_size
!= size
) {
444 if (check_masked_boot_option(candidate
, candidate_size
,
447 } else if (CompareMem(candidate
, data
, size
))
450 VerbosePrint(L
"Found boot entry \"%s\" with label \"%s\" "
451 L
"for file \"%s\"\n", varname
, label
, filename
);
453 /* at this point, we have duplicate data. */
454 if (!first_new_option
) {
455 first_new_option
= DuplicateDevicePath(fulldp
);
456 first_new_option_args
= arguments
;
457 first_new_option_size
= StrLen(arguments
) * sizeof (CHAR16
);
467 return EFI_NOT_FOUND
;
473 CHAR16
*oldbootorder
;
476 oldbootorder
= LibGetVariableAndSize(L
"BootOrder", &GV_GUID
, &size
);
478 nbootorder
= size
/ sizeof (CHAR16
);
479 bootorder
= oldbootorder
;
486 update_boot_order(void)
490 CHAR16
*newbootorder
= NULL
;
491 EFI_STATUS efi_status
;
493 size
= nbootorder
* sizeof(CHAR16
);
494 newbootorder
= AllocateZeroPool(size
);
496 return EFI_OUT_OF_RESOURCES
;
497 CopyMem(newbootorder
, bootorder
, size
);
499 VerbosePrint(L
"nbootorder: %d\nBootOrder: ", size
/ sizeof (CHAR16
));
501 for (j
= 0 ; j
< size
/ sizeof (CHAR16
); j
++)
502 VerbosePrintUnprefixed(L
"%04x ", newbootorder
[j
]);
503 console_print(L
"\n");
504 efi_status
= gRT
->GetVariable(L
"BootOrder", &GV_GUID
, NULL
, &len
, NULL
);
505 if (efi_status
== EFI_BUFFER_TOO_SMALL
)
506 LibDeleteVariable(L
"BootOrder", &GV_GUID
);
508 efi_status
= gRT
->SetVariable(L
"BootOrder", &GV_GUID
,
509 EFI_VARIABLE_NON_VOLATILE
|
510 EFI_VARIABLE_BOOTSERVICE_ACCESS
|
511 EFI_VARIABLE_RUNTIME_ACCESS
,
513 FreePool(newbootorder
);
518 add_to_boot_list(CHAR16
*dirname
, CHAR16
*filename
, CHAR16
*label
, CHAR16
*arguments
)
520 CHAR16
*fullpath
= NULL
;
522 EFI_STATUS efi_status
;
524 efi_status
= make_full_path(dirname
, filename
, &fullpath
, &pathlen
);
525 if (EFI_ERROR(efi_status
))
528 EFI_DEVICE_PATH
*full_device_path
= NULL
;
529 EFI_DEVICE_PATH
*dp
= NULL
;
532 full_device_path
= FileDevicePath(this_image
->DeviceHandle
, fullpath
);
533 if (!full_device_path
) {
534 efi_status
= EFI_OUT_OF_RESOURCES
;
537 dps
= DevicePathToStr(full_device_path
);
538 VerbosePrint(L
"file DP: %s\n", dps
);
541 efi_status
= FindSubDevicePath(full_device_path
,
542 MEDIA_DEVICE_PATH
, MEDIA_HARDDRIVE_DP
,
544 if (EFI_ERROR(efi_status
)) {
545 if (efi_status
== EFI_NOT_FOUND
) {
546 dp
= full_device_path
;
548 efi_status
= EFI_OUT_OF_RESOURCES
;
554 UINTN s
= DevicePathSize(dp
);
556 UINT8
*dpv
= (void *)dp
;
557 for (i
= 0; i
< s
; i
++) {
560 VerbosePrintUnprefixed(L
"\n");
563 VerbosePrintUnprefixed(L
"%02x ", dpv
[i
]);
565 VerbosePrintUnprefixed(L
"\n");
567 CHAR16
*dps
= DevicePathToStr(dp
);
568 VerbosePrint(L
"device path: \"%s\"\n", dps
);
573 efi_status
= find_boot_option(dp
, full_device_path
, fullpath
, label
,
575 if (EFI_ERROR(efi_status
)) {
576 add_boot_option(dp
, full_device_path
, fullpath
, label
,
578 } else if (option
!= 0) {
579 CHAR16
*newbootorder
;
580 newbootorder
= AllocateZeroPool(sizeof (CHAR16
) * nbootorder
);
582 return EFI_OUT_OF_RESOURCES
;
584 newbootorder
[0] = bootorder
[option
];
585 CopyMem(newbootorder
+ 1, bootorder
, sizeof (CHAR16
) * option
);
586 CopyMem(newbootorder
+ option
+ 1, bootorder
+ option
+ 1,
587 sizeof (CHAR16
) * (nbootorder
- option
- 1));
589 bootorder
= newbootorder
;
593 if (full_device_path
)
594 FreePool(full_device_path
);
595 if (dp
&& dp
!= full_device_path
)
603 populate_stanza(CHAR16
*dirname
, CHAR16
*filename
, CHAR16
*csv
)
606 VerbosePrint(L
"CSV data: \"%s\"\n", csv
);
608 UINTN comma0
= StrCSpn(csv
, L
",");
610 return EFI_INVALID_PARAMETER
;
611 file
[comma0
] = L
'\0';
612 VerbosePrint(L
"filename: \"%s\"\n", file
);
614 CHAR16
*label
= csv
+ comma0
+ 1;
615 UINTN comma1
= StrCSpn(label
, L
",");
617 return EFI_INVALID_PARAMETER
;
618 label
[comma1
] = L
'\0';
619 VerbosePrint(L
"label: \"%s\"\n", label
);
621 CHAR16
*arguments
= csv
+ comma0
+1 + comma1
+1;
622 UINTN comma2
= StrCSpn(arguments
, L
",");
623 arguments
[comma2
] = L
'\0';
624 /* This one is optional, so don't check if comma2 is 0 */
625 VerbosePrint(L
"arguments: \"%s\"\n", arguments
);
627 add_to_boot_list(dirname
, file
, label
, arguments
);
633 try_boot_csv(EFI_FILE_HANDLE fh
, CHAR16
*dirname
, CHAR16
*filename
)
635 CHAR16
*fullpath
= NULL
;
637 EFI_STATUS efi_status
;
639 efi_status
= make_full_path(dirname
, filename
, &fullpath
, &pathlen
);
640 if (EFI_ERROR(efi_status
))
643 VerbosePrint(L
"Found file \"%s\"\n", fullpath
);
647 efi_status
= read_file(fh
, fullpath
, &buffer
, &bs
);
648 if (EFI_ERROR(efi_status
)) {
649 console_print(L
"Could not read file \"%s\": %r\n",
650 fullpath
, efi_status
);
656 VerbosePrint(L
"File looks like:\n%s\n", buffer
);
658 CHAR16
*start
= buffer
;
659 /* The file may or may not start with the Unicode byte order marker.
660 * Sadness ensues. Since UEFI is defined as LE, I'm going to decree
661 * that these files must also be LE.
665 * But if we find the LE byte order marker, just skip it.
667 if (*start
== 0xfeff)
670 while (*start
== L
'\r' || *start
== L
'\n')
672 UINTN l
= StrCSpn(start
, L
"\r\n");
674 if (start
[l
] == L
'\0')
682 populate_stanza(dirname
, filename
, start
);
693 find_boot_csv(EFI_FILE_HANDLE fh
, CHAR16
*dirname
)
695 EFI_STATUS efi_status
;
699 /* The API here is "Call it once with bs=0, it fills in bs,
700 * then allocate a buffer and ask again to get it filled. */
701 efi_status
= fh
->GetInfo(fh
, &EFI_FILE_INFO_GUID
, &bs
, NULL
);
702 if (EFI_ERROR(efi_status
) && efi_status
!= EFI_BUFFER_TOO_SMALL
) {
703 console_print(L
"Could not get directory info for \\EFI\\%s\\: %r\n",
704 dirname
, efi_status
);
710 buffer
= AllocateZeroPool(bs
);
712 console_print(L
"Could not allocate memory\n");
713 return EFI_OUT_OF_RESOURCES
;
716 efi_status
= fh
->GetInfo(fh
, &EFI_FILE_INFO_GUID
, &bs
, buffer
);
717 /* This checks *either* the error from the first GetInfo, if it isn't
718 * the EFI_BUFFER_TOO_SMALL we're expecting, or the second GetInfo
719 * call in *any* case. */
720 if (EFI_ERROR(efi_status
)) {
721 console_print(L
"Could not get info for \"%s\": %r\n", dirname
,
728 EFI_FILE_INFO
*fi
= buffer
;
729 if (!(fi
->Attribute
& EFI_FILE_DIRECTORY
)) {
736 CHAR16
*bootcsv
=NULL
, *bootarchcsv
=NULL
;
741 efi_status
= fh
->Read(fh
, &bs
, NULL
);
742 if (EFI_ERROR(efi_status
) &&
743 efi_status
!= EFI_BUFFER_TOO_SMALL
) {
744 console_print(L
"Could not read \\EFI\\%s\\: %r\n",
745 dirname
, efi_status
);
748 /* If there's no data to read, don't try to allocate 0 bytes
749 * and read the data... */
753 buffer
= AllocateZeroPool(bs
);
755 console_print(L
"Could not allocate memory\n");
756 return EFI_OUT_OF_RESOURCES
;
759 efi_status
= fh
->Read(fh
, &bs
, buffer
);
760 if (EFI_ERROR(efi_status
)) {
761 console_print(L
"Could not read \\EFI\\%s\\: %r\n",
762 dirname
, efi_status
);
772 if (!bootcsv
&& !StrCaseCmp(fi
->FileName
, L
"boot.csv"))
773 bootcsv
= StrDuplicate(fi
->FileName
);
776 !StrCaseCmp(fi
->FileName
, L
"boot" EFI_ARCH L
".csv"))
777 bootarchcsv
= StrDuplicate(fi
->FileName
);
783 efi_status
= EFI_SUCCESS
;
786 efi_status
= fh
->Open(fh
, &fh2
, bootarchcsv
,
787 EFI_FILE_READ_ONLY
, 0);
788 if (EFI_ERROR(efi_status
) || fh2
== NULL
) {
789 console_print(L
"Couldn't open \\EFI\\%s\\%s: %r\n",
790 dirname
, bootarchcsv
, efi_status
);
792 efi_status
= try_boot_csv(fh2
, dirname
, bootarchcsv
);
794 if (EFI_ERROR(efi_status
))
795 console_print(L
"Could not process \\EFI\\%s\\%s: %r\n",
796 dirname
, bootarchcsv
, efi_status
);
799 if ((EFI_ERROR(efi_status
) || !bootarchcsv
) && bootcsv
) {
801 efi_status
= fh
->Open(fh
, &fh2
, bootcsv
,
802 EFI_FILE_READ_ONLY
, 0);
803 if (EFI_ERROR(efi_status
) || fh2
== NULL
) {
804 console_print(L
"Couldn't open \\EFI\\%s\\%s: %r\n",
805 dirname
, bootcsv
, efi_status
);
807 efi_status
= try_boot_csv(fh2
, dirname
, bootcsv
);
809 if (EFI_ERROR(efi_status
))
810 console_print(L
"Could not process \\EFI\\%s\\%s: %r\n",
811 dirname
, bootarchcsv
, efi_status
);
818 find_boot_options(EFI_HANDLE device
)
820 EFI_STATUS efi_status
;
821 EFI_FILE_IO_INTERFACE
*fio
= NULL
;
823 efi_status
= gBS
->HandleProtocol(device
, &FileSystemProtocol
,
825 if (EFI_ERROR(efi_status
)) {
826 console_print(L
"Couldn't find file system: %r\n", efi_status
);
830 /* EFI_FILE_HANDLE is a pointer to an EFI_FILE, and I have
831 * *no idea* what frees the memory allocated here. Hopefully
833 EFI_FILE_HANDLE fh
= NULL
;
834 efi_status
= fio
->OpenVolume(fio
, &fh
);
835 if (EFI_ERROR(efi_status
) || fh
== NULL
) {
836 console_print(L
"Couldn't open file system: %r\n", efi_status
);
840 EFI_FILE_HANDLE fh2
= NULL
;
841 efi_status
= fh
->Open(fh
, &fh2
, L
"EFI", EFI_FILE_READ_ONLY
, 0);
842 if (EFI_ERROR(efi_status
) || fh2
== NULL
) {
843 console_print(L
"Couldn't open EFI: %r\n", efi_status
);
847 efi_status
= fh2
->SetPosition(fh2
, 0);
848 if (EFI_ERROR(efi_status
)) {
849 console_print(L
"Couldn't set file position: %r\n", efi_status
);
859 efi_status
= fh2
->Read(fh2
, &bs
, NULL
);
860 if (EFI_ERROR(efi_status
) && efi_status
!= EFI_BUFFER_TOO_SMALL
) {
861 console_print(L
"Could not read \\EFI\\: %r\n", efi_status
);
867 buffer
= AllocateZeroPool(bs
);
869 console_print(L
"Could not allocate memory\n");
870 /* sure, this might work, why not? */
873 return EFI_OUT_OF_RESOURCES
;
876 efi_status
= fh2
->Read(fh2
, &bs
, buffer
);
877 if (EFI_ERROR(efi_status
)) {
886 EFI_FILE_INFO
*fi
= buffer
;
888 if (!(fi
->Attribute
& EFI_FILE_DIRECTORY
)) {
893 if (!StrCmp(fi
->FileName
, L
".") ||
894 !StrCmp(fi
->FileName
, L
"..") ||
895 !StrCaseCmp(fi
->FileName
, L
"BOOT")) {
900 VerbosePrint(L
"Found directory named \"%s\"\n", fi
->FileName
);
903 efi_status
= fh2
->Open(fh2
, &fh3
, fi
->FileName
,
904 EFI_FILE_READ_ONLY
, 0);
905 if (EFI_ERROR(efi_status
)) {
906 console_print(L
"%d Couldn't open %s: %r\n", __LINE__
,
907 fi
->FileName
, efi_status
);
913 efi_status
= find_boot_csv(fh3
, fi
->FileName
);
917 if (efi_status
== EFI_OUT_OF_RESOURCES
)
922 if (!EFI_ERROR(efi_status
) && nbootorder
> 0)
923 efi_status
= update_boot_order();
931 try_start_first_option(EFI_HANDLE parent_image_handle
)
933 EFI_STATUS efi_status
;
934 EFI_HANDLE image_handle
;
936 if (!first_new_option
) {
940 efi_status
= gBS
->LoadImage(0, parent_image_handle
, first_new_option
,
941 NULL
, 0, &image_handle
);
942 if (EFI_ERROR(efi_status
)) {
943 CHAR16
*dps
= DevicePathToStr(first_new_option
);
944 UINTN s
= DevicePathSize(first_new_option
);
946 UINT8
*dpv
= (void *)first_new_option
;
947 console_print(L
"LoadImage failed: %r\nDevice path: \"%s\"\n",
949 for (i
= 0; i
< s
; i
++) {
950 if (i
> 0 && i
% 16 == 0)
951 console_print(L
"\n");
952 console_print(L
"%02x ", dpv
[i
]);
954 console_print(L
"\n");
960 EFI_LOADED_IMAGE
*image
;
961 efi_status
= gBS
->HandleProtocol(image_handle
, &LoadedImageProtocol
,
963 if (!EFI_ERROR(efi_status
)) {
964 image
->LoadOptions
= first_new_option_args
;
965 image
->LoadOptionsSize
= first_new_option_size
;
968 efi_status
= gBS
->StartImage(image_handle
, NULL
, NULL
);
969 if (EFI_ERROR(efi_status
)) {
970 console_print(L
"StartImage failed: %r\n", efi_status
);
977 efi_main(EFI_HANDLE image
, EFI_SYSTEM_TABLE
*systab
);
980 __attribute__((__optimize__("0")))
985 EFI_STATUS efi_status
;
986 volatile register int x
= 0;
987 extern char _etext
, _edata
;
989 efi_status
= get_variable(L
"SHIM_DEBUG", &data
, &dataSize
,
991 if (EFI_ERROR(efi_status
)) {
1001 console_print(L
"add-symbol-file "DEBUGDIR
1002 L
"fb" EFI_ARCH L
".efi.debug %p -s .data %p\n",
1007 efi_main(EFI_HANDLE image
, EFI_SYSTEM_TABLE
*systab
)
1009 EFI_STATUS efi_status
;
1011 InitializeLib(image
, systab
);
1014 * if SHIM_DEBUG is set, wait for a debugger to attach.
1018 efi_status
= gBS
->HandleProtocol(image
, &LoadedImageProtocol
,
1019 (void *) &this_image
);
1020 if (EFI_ERROR(efi_status
)) {
1021 console_print(L
"Error: could not find loaded image: %r\n",
1026 console_print(L
"System BootOrder not found. Initializing defaults.\n");
1030 efi_status
= find_boot_options(this_image
->DeviceHandle
);
1031 if (EFI_ERROR(efi_status
)) {
1032 console_print(L
"Error: could not find boot options: %r\n",
1037 efi_status
= fallback_should_prefer_reset();
1038 if (EFI_ERROR(efi_status
)) {
1039 VerbosePrint(L
"tpm not present, starting the first image\n");
1040 try_start_first_option(image
);
1042 VerbosePrint(L
"tpm present, resetting system\n");
1045 console_print(L
"Reset System\n");
1047 if (get_fallback_verbose()) {
1048 console_print(L
"Verbose enabled, sleeping for half a second\n");
1052 gRT
->ResetSystem(EfiResetCold
, EFI_SUCCESS
, 0, NULL
);