OpenCore  1.0.4
OpenCore Bootloader
Loading...
Searching...
No Matches
DefaultEntryChoice.c
Go to the documentation of this file.
1
6#include <Uefi.h>
7#include <Library/OcMainLib.h>
9
10#include <Guid/AppleFile.h>
11#include <Guid/AppleVariable.h>
12#include <Guid/GlobalVariable.h>
13#include <Guid/Gpt.h>
14#include <Guid/OcVariable.h>
15
16#include <Protocol/DevicePath.h>
17#include <Protocol/LoadedImage.h>
19#include <Protocol/SimpleFileSystem.h>
20
21#include <Library/BaseMemoryLib.h>
22#include <Library/DebugLib.h>
23#include <Library/DevicePathLib.h>
24#include <Library/MemoryAllocationLib.h>
25#include <Library/PrintLib.h>
28#include <Library/OcFileLib.h>
29#include <Library/OcStringLib.h>
31#include <Library/UefiBootServicesTableLib.h>
32#include <Library/UefiLib.h>
33#include <Library/UefiRuntimeServicesTableLib.h>
34
39 {
40 {
41 HARDWARE_DEVICE_PATH,
42 HW_VENDOR_DP,
43 { sizeof (VENDOR_DEVICE_PATH), 0 }
44 },
46 },
47 {
48 MEDIA_DEVICE_PATH,
49 MEDIA_FILEPATH_DP,
50 { SIZE_OF_FILEPATH_DEVICE_PATH, 0 }
51 }
52};
53
58 {
59 {
60 HARDWARE_DEVICE_PATH,
61 HW_VENDOR_DP,
62 { sizeof (VENDOR_DEVICE_PATH) + sizeof (EFI_GUID), 0 }
63 },
65 },
66 EFI_PART_TYPE_UNUSED_GUID,
67 {
68 MEDIA_DEVICE_PATH,
69 MEDIA_FILEPATH_DP,
70 { SIZE_OF_FILEPATH_DEVICE_PATH, 0 }
71 }
72};
73
76 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath
77 )
78{
79 UINTN DevicePathSize;
80 INTN CmpResult;
81 CONST OC_CUSTOM_BOOT_DEVICE_PATH *CustomDevPath;
82
83 DevicePathSize = GetDevicePathSize (DevicePath);
84 if (DevicePathSize < SIZE_OF_OC_CUSTOM_BOOT_DEVICE_PATH) {
85 return NULL;
86 }
87
88 CmpResult = CompareMem (
89 DevicePath,
91 sizeof (mOcCustomBootDevPathTemplate.Header)
92 );
93 if (CmpResult != 0) {
94 return NULL;
95 }
96
97 CustomDevPath = (CONST OC_CUSTOM_BOOT_DEVICE_PATH *)DevicePath;
98 if ( (CustomDevPath->EntryName.Header.Type != MEDIA_DEVICE_PATH)
99 || (CustomDevPath->EntryName.Header.SubType != MEDIA_FILEPATH_DP))
100 {
101 return NULL;
102 }
103
104 return CustomDevPath;
105}
106
109 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath
110 )
111{
112 UINTN DevicePathSize;
113 INTN CmpResult;
114 CONST OC_ENTRY_PROTOCOL_DEVICE_PATH *EntryProtocolDevPath;
115
116 DevicePathSize = GetDevicePathSize (DevicePath);
117 if (DevicePathSize < SIZE_OF_OC_ENTRY_PROTOCOL_DEVICE_PATH) {
118 return NULL;
119 }
120
121 CmpResult = CompareMem (
122 DevicePath,
124 sizeof (mOcEntryProtocolDevPathTemplate.Header)
125 );
126 if (CmpResult != 0) {
127 return NULL;
128 }
129
130 EntryProtocolDevPath = (CONST OC_ENTRY_PROTOCOL_DEVICE_PATH *)DevicePath;
131 if ( (EntryProtocolDevPath->EntryName.Header.Type != MEDIA_DEVICE_PATH)
132 || (EntryProtocolDevPath->EntryName.Header.SubType != MEDIA_FILEPATH_DP))
133 {
134 return NULL;
135 }
136
137 return EntryProtocolDevPath;
138}
139
140EFI_DEVICE_PATH_PROTOCOL *
142 IN EFI_LOAD_OPTION *LoadOption,
143 IN UINTN LoadOptionSize
144 )
145{
146 UINT8 *LoadOptionPtr;
147
148 CHAR16 *Description;
149 UINTN DescriptionSize;
150 UINT16 FilePathListSize;
151 EFI_DEVICE_PATH_PROTOCOL *FilePathList;
152
153 FilePathListSize = LoadOption->FilePathListLength;
154
155 LoadOptionPtr = (UINT8 *)(LoadOption + 1);
156 LoadOptionSize -= sizeof (*LoadOption);
157
158 if (FilePathListSize > LoadOptionSize) {
159 return NULL;
160 }
161
162 LoadOptionSize -= FilePathListSize;
163
165 sizeof (*LoadOption) % BASE_ALIGNOF (CHAR16) == 0,
166 "The following accesses may be unaligned."
167 );
168
169 Description = (CHAR16 *)(VOID *)LoadOptionPtr;
170 DescriptionSize = StrnSizeS (Description, (LoadOptionSize / sizeof (CHAR16)));
171 if (DescriptionSize > LoadOptionSize) {
172 return NULL;
173 }
174
175 LoadOptionPtr += DescriptionSize;
176
177 FilePathList = (EFI_DEVICE_PATH_PROTOCOL *)LoadOptionPtr;
178 if (!IsDevicePathValid (FilePathList, FilePathListSize)) {
179 return NULL;
180 }
181
182 return FilePathList;
183}
184
185VOID
187 IN CONST UINT16 *BootOrder,
188 IN EFI_GUID *BootGuid,
189 IN UINTN BootOrderCount
190 )
191{
192 EFI_STATUS Status;
193 EFI_DEVICE_PATH_PROTOCOL *UefiDevicePath;
194 UINTN UefiDevicePathSize;
195 CHAR16 *DevicePathText;
196 UINTN Index;
197 INT32 Predefined;
198 EFI_LOAD_OPTION *LoadOption;
199 UINTN LoadOptionSize;
200
201 STATIC CONST CHAR16 *AppleDebugVariables[] = {
202 L"efi-boot-device-data",
203 L"efi-boot-next-data",
204 L"efi-backup-boot-device-data",
205 L"efi-apple-recovery-data"
206 };
207
208 STATIC CONST UINT16 ApplePredefinedVariables[] = {
209 0x80, 0x81, 0x82
210 };
211
212 for (Index = 0; Index < ARRAY_SIZE (AppleDebugVariables); ++Index) {
213 Status = GetVariable2 (
214 AppleDebugVariables[Index],
216 (VOID **)&UefiDevicePath,
217 &UefiDevicePathSize
218 );
219 if (!EFI_ERROR (Status) && IsDevicePathValid (UefiDevicePath, UefiDevicePathSize)) {
220 DevicePathText = ConvertDevicePathToText (UefiDevicePath, FALSE, FALSE);
221 if (DevicePathText != NULL) {
222 DEBUG ((DEBUG_INFO, "OCB: %s = %s\n", AppleDebugVariables[Index], DevicePathText));
223 FreePool (DevicePathText);
224 FreePool (UefiDevicePath);
225 continue;
226 }
227
228 FreePool (UefiDevicePath);
229 }
230
231 DEBUG ((DEBUG_INFO, "OCB: %s - %r\n", AppleDebugVariables[Index], Status));
232 }
233
234 DEBUG ((DEBUG_INFO, "OCB: Dumping BootOrder\n"));
235
236 for (Predefined = 0; Predefined < 2; ++Predefined) {
237 for (Index = 0; Index < BootOrderCount; ++Index) {
238 LoadOption = OcGetBootOptionData (
239 &LoadOptionSize,
240 BootOrder[Index],
241 BootGuid
242 );
243 if (LoadOption == NULL) {
244 continue;
245 }
246
247 UefiDevicePath = InternalGetBootOptionPath (LoadOption, LoadOptionSize);
248 if (UefiDevicePath == NULL) {
249 DEBUG ((
250 DEBUG_INFO,
251 "OCB: %u -> Boot%04x - failed to read\n",
252 (UINT32)Index,
253 BootOrder[Index]
254 ));
255 FreePool (LoadOption);
256 continue;
257 }
258
259 DevicePathText = ConvertDevicePathToText (UefiDevicePath, FALSE, FALSE);
260 DEBUG ((
261 DEBUG_INFO,
262 "OCB: %u -> Boot%04x = %s\n",
263 (UINT32)Index,
264 BootOrder[Index],
265 DevicePathText
266 ));
267 if (DevicePathText != NULL) {
268 FreePool (DevicePathText);
269 }
270
271 FreePool (LoadOption);
272 }
273
274 //
275 // Redo with predefined.
276 //
277 if (Predefined == 0) {
278 BootOrder = &ApplePredefinedVariables[0];
279 BootOrderCount = ARRAY_SIZE (ApplePredefinedVariables);
280 DEBUG ((DEBUG_INFO, "OCB: Parsing predefined list...\n"));
281 }
282 }
283}
284
285STATIC
286BOOLEAN
288 IN OUT OC_BOOT_ENTRY *BootEntry,
289 IN EFI_DEVICE_PATH_PROTOCOL *UefiDevicePath,
290 IN EFI_DEVICE_PATH_PROTOCOL *UefiRemainingDevicePath,
291 IN UINTN UefiDevicePathSize,
292 IN BOOLEAN IsBootNext
293 )
294{
295 INTN CmpResult;
296
297 UINTN RootDevicePathSize;
298
299 EFI_DEVICE_PATH_PROTOCOL *OcDevicePath;
300 EFI_DEVICE_PATH_PROTOCOL *OcRemainingDevicePath;
301
302 RootDevicePathSize = ((UINT8 *)UefiRemainingDevicePath - (UINT8 *)UefiDevicePath);
303
304 if ((BootEntry->DevicePath == NULL) || ((BootEntry->Type & OC_BOOT_SYSTEM) != 0)) {
305 return FALSE;
306 }
307
308 OcDevicePath = BootEntry->DevicePath;
309
310 if ((GetDevicePathSize (OcDevicePath) - END_DEVICE_PATH_LENGTH) < RootDevicePathSize) {
311 return FALSE;
312 }
313
314 CmpResult = CompareMem (OcDevicePath, UefiDevicePath, RootDevicePathSize);
315 if (CmpResult != 0) {
316 return FALSE;
317 }
318
319 //
320 // FIXME: Ensure that all the entries get properly filtered against any
321 // malicious sources. The drive itself should already be safe, but it is
322 // unclear whether a potentially safe device path can be transformed into
323 // an unsafe one.
324 //
325 OcRemainingDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)(
326 (UINT8 *)OcDevicePath + RootDevicePathSize
327 );
328 if (!IsBootNext) {
329 //
330 // For non-BootNext boot, the File Paths must match for the entries to be
331 // matched. Startup Disk however only stores the drive's Device Path
332 // excluding the booter path, which we treat as a match as well.
333 //
334 if ( !IsDevicePathEnd (UefiRemainingDevicePath)
335 && !IsDevicePathEqual (UefiRemainingDevicePath, OcRemainingDevicePath)
336 )
337 {
338 return FALSE;
339 }
340 } else {
341 //
342 // Only use the BootNext path when it has a file path.
343 //
344 if (!IsDevicePathEnd (UefiRemainingDevicePath)) {
345 //
346 // TODO: Investigate whether macOS adds BootNext entries that are not
347 // possibly located by bless.
348 //
349 FreePool (BootEntry->DevicePath);
350 BootEntry->DevicePath = AllocateCopyPool (
351 UefiDevicePathSize,
352 UefiDevicePath
353 );
354 }
355 }
356
357 return TRUE;
358}
359
360STATIC
361BOOLEAN
363 IN OUT OC_BOOT_ENTRY *BootEntry,
364 IN CONST OC_CUSTOM_BOOT_DEVICE_PATH *DevicePath
365 )
366{
367 INTN CmpResult;
368
369 if (!BootEntry->IsCustom || BootEntry->IsBootEntryProtocol) {
370 return FALSE;
371 }
372
373 CmpResult = StrCmp (BootEntry->Name, DevicePath->EntryName.PathName);
374 if (CmpResult != 0) {
375 return FALSE;
376 }
377
378 return TRUE;
379}
380
381STATIC
382BOOLEAN
384 IN OUT OC_BOOT_ENTRY *BootEntry,
385 IN CONST OC_ENTRY_PROTOCOL_DEVICE_PATH *DevicePath
386 )
387{
388 INTN CmpResult;
389
390 if (!BootEntry->IsCustom || !BootEntry->IsBootEntryProtocol || (BootEntry->Id == NULL)) {
391 return FALSE;
392 }
393
394 CmpResult = CompareMem (&BootEntry->UniquePartitionGUID, &DevicePath->Partuuid, sizeof (EFI_GUID));
395 if (CmpResult != 0) {
396 return FALSE;
397 }
398
399 CmpResult = StrCmp (BootEntry->Id, DevicePath->EntryName.PathName);
400 if (CmpResult != 0) {
401 return FALSE;
402 }
403
404 return TRUE;
405}
406
407STATIC
408VOID
410 IN EFI_GUID *BootVariableGuid,
411 IN BOOLEAN ClearApplePayload
412 )
413{
414 CHAR16 VariableName[32];
415 CHAR16 *BootNextName;
416 UINTN Index;
417
418 if (CompareGuid (BootVariableGuid, &gOcVendorVariableGuid)) {
420 } else {
421 BootNextName = EFI_BOOT_NEXT_VARIABLE_NAME;
422 }
423
424 //
425 // Next variable data specified by UEFI spec.
426 // For now we do not bother dropping the variable it points to.
427 //
428 gRT->SetVariable (
429 BootNextName,
430 BootVariableGuid,
431 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
432 0,
433 NULL
434 );
435
436 //
437 // Next variable string (in xml format) specified by Apple macOS.
438 //
439 gRT->SetVariable (
440 L"efi-boot-next",
442 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
443 0,
444 NULL
445 );
446
447 //
448 // Next variable blob (in DevicePath format) specified by Apple macOS.
449 //
450 gRT->SetVariable (
451 L"efi-boot-next-data",
453 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
454 0,
455 NULL
456 );
457
458 if (ClearApplePayload) {
459 for (Index = 0; Index <= 3; ++Index) {
460 UnicodeSPrint (
461 VariableName,
462 sizeof (VariableName),
463 L"efi-apple-payload%u%a",
464 (UINT32)Index,
465 "-data"
466 );
467
468 gRT->SetVariable (
469 VariableName,
471 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
472 0,
473 NULL
474 );
475
476 UnicodeSPrint (
477 VariableName,
478 sizeof (VariableName),
479 L"efi-apple-payload%u%a",
480 (UINT32)Index,
481 ""
482 );
483
484 gRT->SetVariable (
485 VariableName,
487 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
488 0,
489 NULL
490 );
491 }
492 }
493}
494
495STATIC
496BOOLEAN
498 IN EFI_GUID *BootVariableGuid
499 )
500{
501 EFI_STATUS Status;
502 UINT32 VariableAttributes;
503 UINT16 BootNext;
504 CHAR16 *BootNextName;
505 UINTN VariableSize;
506 OC_BOOT_ENTRY_TYPE EntryType;
507 EFI_DEVICE_PATH_PROTOCOL *UefiDevicePath;
508 EFI_LOAD_OPTION *LoadOption;
509 UINTN LoadOptionSize;
510
511 if (CompareGuid (BootVariableGuid, &gOcVendorVariableGuid)) {
513 } else {
514 BootNextName = EFI_BOOT_NEXT_VARIABLE_NAME;
515 }
516
517 VariableSize = sizeof (BootNext);
518 Status = gRT->GetVariable (
519 BootNextName,
520 BootVariableGuid,
521 &VariableAttributes,
522 &VariableSize,
523 &BootNext
524 );
525 if (EFI_ERROR (Status) || (VariableSize != sizeof (BootNext))) {
526 return FALSE;
527 }
528
529 LoadOption = OcGetBootOptionData (
530 &LoadOptionSize,
531 BootNext,
532 BootVariableGuid
533 );
534 if (LoadOption == NULL) {
535 return FALSE;
536 }
537
538 UefiDevicePath = InternalGetBootOptionPath (LoadOption, LoadOptionSize);
539 if (UefiDevicePath == NULL) {
540 FreePool (LoadOption);
541 return FALSE;
542 }
543
544 EntryType = OcGetBootDevicePathType (UefiDevicePath, NULL, NULL);
545 DEBUG ((DEBUG_INFO, "OCB: Found BootNext %04x of type %u\n", BootNext, EntryType));
546 FreePool (LoadOption);
547
548 return EntryType == OC_BOOT_APPLE_FW_UPDATE;
549}
550
551BOOLEAN
553 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath
554 )
555{
556 EFI_DEV_PATH_PTR FwVolDevPath;
557
558 ASSERT (DevicePath != NULL);
559
560 if ( (DevicePath->Type == HARDWARE_DEVICE_PATH)
561 && (DevicePath->SubType == HW_MEMMAP_DP))
562 {
563 FwVolDevPath.DevPath = NextDevicePathNode (DevicePath);
564 if ( (FwVolDevPath.DevPath->Type == MEDIA_DEVICE_PATH)
565 && (FwVolDevPath.DevPath->SubType == MEDIA_PIWG_FW_FILE_DP))
566 {
567 return CompareGuid (
568 &FwVolDevPath.FirmwareFile->FvFileName,
570 );
571 }
572 }
573
574 return FALSE;
575}
576
577UINT16 *
579 IN EFI_GUID *BootVariableGuid,
580 IN BOOLEAN WithBootNext,
581 OUT UINTN *BootOrderCount,
582 OUT BOOLEAN *Deduplicated OPTIONAL,
583 OUT BOOLEAN *HasBootNext OPTIONAL,
584 IN BOOLEAN UseBootNextOnly
585 )
586{
587 EFI_STATUS Status;
588 UINT32 VariableAttributes;
589 UINT16 BootNext;
590 CHAR16 *BootOrderName;
591 CHAR16 *BootNextName;
592 UINT16 *BootOrder;
593 UINTN VariableSize;
594 UINTN Index;
595 UINTN Index2;
596 BOOLEAN BootOrderChanged;
597
598 *BootOrderCount = 0;
599
600 if (Deduplicated != NULL) {
601 *Deduplicated = FALSE;
602 }
603
604 if (HasBootNext != NULL) {
605 *HasBootNext = FALSE;
606 }
607
608 if (CompareGuid (BootVariableGuid, &gOcVendorVariableGuid)) {
611 } else {
612 BootOrderName = EFI_BOOT_ORDER_VARIABLE_NAME;
613 BootNextName = EFI_BOOT_NEXT_VARIABLE_NAME;
614 }
615
616 //
617 // Precede variable with boot next.
618 //
619 if (WithBootNext) {
620 VariableSize = sizeof (BootNext);
621 Status = gRT->GetVariable (
622 BootNextName,
623 BootVariableGuid,
624 &VariableAttributes,
625 &VariableSize,
626 &BootNext
627 );
628 if (!EFI_ERROR (Status) && (VariableSize == sizeof (BootNext))) {
629 if (HasBootNext != NULL) {
630 *HasBootNext = TRUE;
631 }
632 } else {
633 WithBootNext = FALSE;
634 }
635 }
636
637 if (UseBootNextOnly) {
638 Status = EFI_ABORTED;
639 } else {
640 VariableSize = 0;
641 Status = gRT->GetVariable (
642 BootOrderName,
643 BootVariableGuid,
644 &VariableAttributes,
645 &VariableSize,
646 NULL
647 );
648
649 if (Status == EFI_BUFFER_TOO_SMALL) {
650 BootOrder = AllocatePool ((UINTN)WithBootNext * sizeof (BootNext) + VariableSize);
651 if (BootOrder == NULL) {
652 return NULL;
653 }
654
655 Status = gRT->GetVariable (
656 BootOrderName,
657 BootVariableGuid,
658 &VariableAttributes,
659 &VariableSize,
660 BootOrder + (UINTN)WithBootNext
661 );
662 if ( EFI_ERROR (Status)
663 || (VariableSize < sizeof (*BootOrder))
664 || (VariableSize % sizeof (*BootOrder) != 0))
665 {
666 FreePool (BootOrder);
667 Status = EFI_UNSUPPORTED;
668 }
669 } else if (!EFI_ERROR (Status)) {
670 Status = EFI_NOT_FOUND;
671 }
672 }
673
674 if (EFI_ERROR (Status)) {
675 if (WithBootNext) {
676 BootOrder = AllocateCopyPool (sizeof (BootNext), &BootNext);
677 if (BootOrder != NULL) {
678 *BootOrderCount = 1;
679 return BootOrder;
680 }
681 }
682
683 return NULL;
684 }
685
686 if (WithBootNext) {
687 BootOrder[0] = BootNext;
688 VariableSize += sizeof (*BootOrder);
689 }
690
691 BootOrderChanged = FALSE;
692
693 for (Index = 1; Index < VariableSize / sizeof (BootOrder[0]); ++Index) {
694 for (Index2 = 0; Index2 < Index; ++Index2) {
695 if (BootOrder[Index] == BootOrder[Index2]) {
696 //
697 // Found duplicate.
698 //
699 BootOrderChanged = TRUE;
700 CopyMem (
701 &BootOrder[Index],
702 &BootOrder[Index + 1],
703 VariableSize - sizeof (BootOrder[0]) * (Index + 1)
704 );
705 VariableSize -= sizeof (BootOrder[0]);
706 --Index;
707 break;
708 }
709 }
710 }
711
712 *BootOrderCount = VariableSize / sizeof (*BootOrder);
713 if (Deduplicated != NULL) {
714 *Deduplicated = BootOrderChanged;
715 }
716
717 return BootOrder;
718}
719
720UINT16 *
722 IN EFI_GUID *BootVariableGuid,
723 IN BOOLEAN BlacklistAppleUpdate,
724 OUT UINTN *BootOrderCount,
725 IN BOOLEAN UseBootNextOnly
726 )
727{
728 UINT16 *BootOrder;
729 BOOLEAN HasFwBootNext;
730 BOOLEAN HasBootNext;
731
732 //
733 // Precede variable with boot next unless we were forced to ignore it.
734 //
735 if (BlacklistAppleUpdate) {
736 HasFwBootNext = InternalHasFirmwareUpdateAsNext (BootVariableGuid);
737 } else {
738 HasFwBootNext = FALSE;
739 }
740
741 BootOrder = OcGetBootOrder (
742 BootVariableGuid,
743 HasFwBootNext == FALSE,
744 BootOrderCount,
745 NULL,
746 &HasBootNext,
747 UseBootNextOnly
748 );
749 if (BootOrder == NULL) {
750 DEBUG ((DEBUG_INFO, "OCB: BootOrder/BootNext are not present or unsupported %u %u\n", HasFwBootNext, UseBootNextOnly));
751 return NULL;
752 }
753
754 DEBUG_CODE_BEGIN ();
755 DEBUG ((
756 DEBUG_INFO,
757 "OCB: Found %u BootOrder entries with BootNext %a\n",
758 (UINT32)*BootOrderCount,
759 UseBootNextOnly ? "only" : (HasBootNext ? "included" : "excluded")
760 ));
761 InternalDebugBootEnvironment (BootOrder, BootVariableGuid, *BootOrderCount);
762 DEBUG_CODE_END ();
763
764 if (HasFwBootNext || HasBootNext) {
765 InternalClearNextVariables (BootVariableGuid, HasFwBootNext);
766 }
767
768 return BootOrder;
769}
770
771EFI_STATUS
773 IN OC_PICKER_CONTEXT *Context,
774 IN OC_BOOT_ENTRY *Entry
775 )
776{
777 EFI_STATUS Status;
778 EFI_DEVICE_PATH *BootOptionDevicePath;
779 EFI_DEVICE_PATH *BootOptionRemainingDevicePath;
780 EFI_HANDLE DeviceHandle;
781 BOOLEAN MatchedEntry;
782 BOOLEAN IsOverflow;
783 BOOLEAN IsAsciiOptionName;
784 EFI_GUID *BootVariableGuid;
785 CHAR16 *BootOrderName;
786 CHAR16 *BootVariableName;
787 CHAR16 *LoadOptionId;
788 VOID *LoadOptionName;
789 CHAR8 *FirstFlavourEnd;
790 UINT16 *BootOrder;
791 UINT16 *NewBootOrder;
792 UINT16 BootTmp;
793 UINT16 EntryIdLength;
794 UINTN BootOrderCount;
795 UINTN BootChosenIndex;
796 UINTN Index;
797 UINTN DevicePathSize;
798 UINTN UnmanagedBootDevPathSize;
799 UINTN LoadOptionSize;
800 UINTN LoadOptionIdSize;
801 UINTN LoadOptionNameSize;
802 UINTN LoadOptionNameLen;
803 UINTN CopiedLength;
804 EFI_LOAD_OPTION *LoadOption;
805
806 CONST OC_CUSTOM_BOOT_DEVICE_PATH *CustomDevPath;
807 CONST OC_ENTRY_PROTOCOL_DEVICE_PATH *EntryProtocolDevPath;
808 EFI_DEVICE_PATH_PROTOCOL *UnmanagedBootDevPath;
809 VENDOR_DEVICE_PATH *DestCustomDevPath;
810 FILEPATH_DEVICE_PATH *DestCustomEntryName;
811 EFI_DEVICE_PATH_PROTOCOL *DestCustomEndNode;
812
813 //
814 // Do not allow when prohibited.
815 //
816 if (!Context->AllowSetDefault) {
817 return EFI_SECURITY_VIOLATION;
818 }
819
820 //
821 // Ignore entries without device paths.
822 //
823 if (Entry->DevicePath == NULL) {
824 return EFI_INVALID_PARAMETER;
825 }
826
827 //
828 // Get final device path for unmanaged boot entries.
829 //
830 UnmanagedBootDevPath = NULL;
831 if ((Entry->Type == OC_BOOT_UNMANAGED) && (Entry->UnmanagedBootGetFinalDevicePath != NULL)) {
832 UnmanagedBootDevPath = Entry->DevicePath;
833 Status = Entry->UnmanagedBootGetFinalDevicePath (Context, &UnmanagedBootDevPath);
834 if (EFI_ERROR (Status)) {
835 UnmanagedBootDevPath = NULL;
836 } else {
837 UnmanagedBootDevPathSize = GetDevicePathSize (UnmanagedBootDevPath);
838 }
839 }
840
841 if (Context->CustomBootGuid) {
842 BootVariableGuid = &gOcVendorVariableGuid;
844 BootVariableName = OC_VENDOR_BOOT_VARIABLE_PREFIX L"0080";
845 } else {
846 BootVariableGuid = &gEfiGlobalVariableGuid;
847 BootOrderName = EFI_BOOT_ORDER_VARIABLE_NAME;
848 BootVariableName = L"Boot0080";
849 }
850
851 BootOrder = OcGetBootOrder (
852 BootVariableGuid,
853 FALSE,
854 &BootOrderCount,
855 NULL,
856 NULL,
857 FALSE
858 );
859
860 MatchedEntry = FALSE;
861 BootChosenIndex = BootOrderCount;
862 for (Index = 0; Index < BootOrderCount; ++Index) {
863 if (BootOrder[Index] == 0x80) {
864 BootChosenIndex = Index;
865 }
866
867 if (MatchedEntry) {
868 if (BootChosenIndex != BootOrderCount) {
869 break;
870 }
871
872 continue;
873 }
874
875 LoadOption = OcGetBootOptionData (
876 &LoadOptionSize,
877 BootOrder[Index],
878 BootVariableGuid
879 );
880 if (LoadOption == NULL) {
881 continue;
882 }
883
884 BootOptionDevicePath = InternalGetBootOptionPath (
885 LoadOption,
886 LoadOptionSize
887 );
888 if (BootOptionDevicePath == NULL) {
889 FreePool (LoadOption);
890 continue;
891 }
892
893 if (UnmanagedBootDevPath != NULL) {
894 DevicePathSize = GetDevicePathSize (BootOptionDevicePath);
895 if (DevicePathSize >= UnmanagedBootDevPathSize) {
896 MatchedEntry = CompareMem (BootOptionDevicePath, UnmanagedBootDevPath, UnmanagedBootDevPathSize) == 0;
897 }
898 } else {
899 BootOptionRemainingDevicePath = BootOptionDevicePath;
900 Status = gBS->LocateDevicePath (
902 &BootOptionRemainingDevicePath,
903 &DeviceHandle
904 );
905
906 if (!EFI_ERROR (Status)) {
908 Entry,
909 BootOptionDevicePath,
910 BootOptionRemainingDevicePath,
911 LoadOption->FilePathListLength,
912 FALSE
913 );
914 } else {
915 CustomDevPath = InternalGetOcCustomDevPath (BootOptionDevicePath);
916 if (CustomDevPath != NULL) {
918 Entry,
919 CustomDevPath
920 );
921 } else {
922 EntryProtocolDevPath = InternalGetOcEntryProtocolDevPath (BootOptionDevicePath);
923 if (EntryProtocolDevPath != NULL) {
925 Entry,
926 EntryProtocolDevPath
927 );
928 }
929 }
930 }
931 }
932
933 FreePool (LoadOption);
934 }
935
936 if (!MatchedEntry) {
937 //
938 // Write to Boot0080
939 //
940 ASSERT (Entry->Name != NULL);
941 IsAsciiOptionName = FALSE;
942 if (Entry->Id == NULL) {
943 //
944 // Re-use user defined entry name as stored id.
945 //
946 LoadOptionName = Entry->Name;
947 LoadOptionNameSize = StrSize (Entry->Name);
948
949 LoadOptionId = LoadOptionName;
950 LoadOptionIdSize = LoadOptionNameSize;
951 } else {
952 //
953 // Re-use first part of flavour as option name if available, it is more human
954 // readable than entry id, but is not version specific, unlike entry name.
955 //
956 LoadOptionId = Entry->Id;
957 LoadOptionIdSize = StrSize (Entry->Id);
958
959 if ((Entry->Flavour != NULL) && (Entry->Flavour[0] != '\0') && (Entry->Flavour[0] != ':')) {
960 FirstFlavourEnd = OcAsciiStrChr (Entry->Flavour, ':');
961 if (FirstFlavourEnd != NULL) {
962 LoadOptionNameLen = FirstFlavourEnd - Entry->Flavour;
963 } else {
964 LoadOptionNameLen = AsciiStrLen (Entry->Flavour);
965 }
966
967 IsAsciiOptionName = TRUE;
968 LoadOptionNameSize = (LoadOptionNameLen + 1) * sizeof (CHAR16) / sizeof (CHAR8);
969 LoadOptionName = Entry->Flavour;
970 } else {
971 LoadOptionName = LoadOptionId;
972 LoadOptionNameSize = LoadOptionIdSize;
973 }
974 }
975
976 if (UnmanagedBootDevPath != NULL) {
977 DevicePathSize = UnmanagedBootDevPathSize;
978 } else if (!Entry->IsCustom) {
979 DevicePathSize = GetDevicePathSize (Entry->DevicePath);
980 } else {
982 + (Entry->IsBootEntryProtocol ? sizeof (EFI_GUID) : 0)
983 + LoadOptionIdSize
984 + sizeof (EFI_DEVICE_PATH_PROTOCOL);
985
986 if (LoadOptionIdSize > MAX_UINT16) {
987 IsOverflow = TRUE;
988 } else {
989 IsOverflow = BaseOverflowAddU16 (SIZE_OF_FILEPATH_DEVICE_PATH, (UINT16)LoadOptionIdSize, &EntryIdLength);
990 }
991
992 if (IsOverflow) {
993 DEBUG ((DEBUG_ERROR, "OCB: Overflowing option id size (%u)\n", LoadOptionIdSize));
994 if (BootOrder != NULL) {
995 FreePool (BootOrder);
996 }
997
998 return EFI_INVALID_PARAMETER;
999 }
1000 }
1001
1002 LoadOptionSize = sizeof (EFI_LOAD_OPTION) + LoadOptionNameSize + DevicePathSize;
1003
1004 LoadOption = AllocatePool (LoadOptionSize);
1005 if (LoadOption == NULL) {
1006 DEBUG ((DEBUG_INFO, "OCB: Failed to allocate default option (%u)\n", (UINT32)LoadOptionSize));
1007 if (BootOrder != NULL) {
1008 FreePool (BootOrder);
1009 }
1010
1011 return EFI_OUT_OF_RESOURCES;
1012 }
1013
1014 LoadOption->Attributes = LOAD_OPTION_ACTIVE | LOAD_OPTION_CATEGORY_BOOT;
1015 LoadOption->FilePathListLength = (UINT16)DevicePathSize;
1016 if (IsAsciiOptionName) {
1017 Status = AsciiStrnToUnicodeStrS (LoadOptionName, LoadOptionNameLen, (CHAR16 *)(LoadOption + 1), LoadOptionNameSize / sizeof (CHAR16), &CopiedLength);
1018 ASSERT_EFI_ERROR (Status);
1019 ASSERT (CopiedLength == LoadOptionNameLen);
1020 } else {
1021 CopyMem (LoadOption + 1, LoadOptionName, LoadOptionNameSize);
1022 }
1023
1024 if (UnmanagedBootDevPath != NULL) {
1025 CopyMem ((UINT8 *)(LoadOption + 1) + LoadOptionNameSize, UnmanagedBootDevPath, DevicePathSize);
1026 } else if (!Entry->IsCustom) {
1027 CopyMem ((UINT8 *)(LoadOption + 1) + LoadOptionNameSize, Entry->DevicePath, DevicePathSize);
1028 } else {
1029 DestCustomDevPath = (VENDOR_DEVICE_PATH *)(
1030 (UINT8 *)(LoadOption + 1) + LoadOptionNameSize
1031 );
1032 if (Entry->IsBootEntryProtocol) {
1033 CopyMem (
1034 DestCustomDevPath,
1037 );
1038 CopyMem (
1039 DestCustomDevPath + 1,
1040 &Entry->UniquePartitionGUID,
1041 sizeof (EFI_GUID)
1042 );
1043 DestCustomEntryName = (FILEPATH_DEVICE_PATH *)(
1044 (UINT8 *)(DestCustomDevPath + 1) +
1045 sizeof (EFI_GUID)
1046 );
1047 } else {
1048 CopyMem (
1049 DestCustomDevPath,
1052 );
1053 DestCustomEntryName = (FILEPATH_DEVICE_PATH *)(
1054 (UINT8 *)(DestCustomDevPath + 1)
1055 );
1056 }
1057
1058 CopyMem (
1059 DestCustomEntryName->PathName,
1060 LoadOptionId,
1061 LoadOptionIdSize
1062 );
1063
1064 DestCustomEntryName->Header.Length[0] = (UINT8)EntryIdLength;
1065 DestCustomEntryName->Header.Length[1] = (UINT8)(EntryIdLength >> 8);
1066
1067 DestCustomEndNode = (EFI_DEVICE_PATH_PROTOCOL *)(
1068 (UINT8 *)DestCustomEntryName + EntryIdLength
1069 );
1070 SetDevicePathEndNode (DestCustomEndNode);
1071
1072 ASSERT (GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *)DestCustomDevPath) == DevicePathSize);
1073 }
1074
1075 Status = gRT->SetVariable (
1076 BootVariableName,
1077 BootVariableGuid,
1078 EFI_VARIABLE_BOOTSERVICE_ACCESS
1079 | EFI_VARIABLE_RUNTIME_ACCESS
1080 | EFI_VARIABLE_NON_VOLATILE,
1081 LoadOptionSize,
1082 LoadOption
1083 );
1084
1085 FreePool (LoadOption);
1086
1087 if (UnmanagedBootDevPath != NULL) {
1088 FreePool (UnmanagedBootDevPath);
1089 UnmanagedBootDevPath = NULL;
1090 }
1091
1092 if (EFI_ERROR (Status)) {
1093 DEBUG ((
1094 DEBUG_INFO,
1095 "OCB: Failed to set default entry Boot0080 - %r\n",
1096 Status
1097 ));
1098 if (BootOrder != NULL) {
1099 FreePool (BootOrder);
1100 }
1101
1102 return Status;
1103 }
1104 } else {
1105 DEBUG ((DEBUG_INFO, "OCB: Matched default entry in BootOrder\n"));
1106 BootChosenIndex = Index;
1107 }
1108
1109 //
1110 // Update BootOrder to contain new option.
1111 //
1112 if (BootChosenIndex != BootOrderCount) {
1113 BootTmp = BootOrder[0];
1114 BootOrder[0] = BootOrder[BootChosenIndex];
1115 BootOrder[BootChosenIndex] = BootTmp;
1116 NewBootOrder = BootOrder;
1117
1118 DEBUG ((
1119 DEBUG_INFO,
1120 "OCB: Found default entry in BootOrder, reordering %X <-> %X\n",
1121 NewBootOrder[0],
1122 NewBootOrder[BootChosenIndex]
1123 ));
1124 } else {
1125 DEBUG ((
1126 DEBUG_INFO,
1127 "OCB: Adding default entry Boot0080 to BootOrder\n"
1128 ));
1129
1130 NewBootOrder = AllocatePool ((BootOrderCount + 1) * sizeof (*BootOrder));
1131 if (NewBootOrder == NULL) {
1132 if (BootOrder != NULL) {
1133 FreePool (BootOrder);
1134 }
1135
1136 return EFI_OUT_OF_RESOURCES;
1137 }
1138
1139 NewBootOrder[0] = 0x80;
1140 CopyMem (&NewBootOrder[1], &BootOrder[0], BootOrderCount * sizeof (*BootOrder));
1141
1142 if (BootOrder != NULL) {
1143 FreePool (BootOrder);
1144 }
1145
1146 ++BootOrderCount;
1147 }
1148
1149 Status = gRT->SetVariable (
1150 BootOrderName,
1151 BootVariableGuid,
1152 EFI_VARIABLE_BOOTSERVICE_ACCESS
1153 | EFI_VARIABLE_RUNTIME_ACCESS
1154 | EFI_VARIABLE_NON_VOLATILE,
1155 BootOrderCount * sizeof (*BootOrder),
1156 NewBootOrder
1157 );
1158
1159 FreePool (NewBootOrder);
1160
1161 if (EFI_ERROR (Status)) {
1162 DEBUG ((
1163 DEBUG_INFO,
1164 "OCB: Failed to set default BootOrder - %r\n",
1165 Status
1166 ));
1167 }
1168
1170
1171 return Status;
1172}
1173
1174/*
1175 Retrieves the Bootstrap Load Option data, matching it from BootOrder by
1176 finding a path ending with MatchSuffix.
1177
1178 @param[out] LoadOptionSize The size, in bytes, of the Load Option data.
1179 @param[out] BootOption The index of the Boot Option.
1180 @param[out] LoadPath Pointer into the Load Option data to the
1181 Device Path.
1182 @param[in] BootOptions The list of Boot Option indices to match.
1183 @param[in] NumBootOptions The number of elements in BootOptions.
1184 @param[in] MatchSuffix The file Device Path suffix of a matching option.
1185 @param[in] MatchSuffixLen The length, in characters, of MatchSuffix.
1186*/
1187EFI_LOAD_OPTION *
1189 OUT UINTN *LoadOptionSize,
1190 OUT UINT16 *BootOption,
1191 OUT EFI_DEVICE_PATH_PROTOCOL **LoadPath,
1192 IN UINT16 *BootOptions,
1193 IN UINTN NumBootOptions,
1194 IN CONST CHAR16 *MatchSuffix,
1195 IN UINTN MatchSuffixLen
1196 )
1197{
1198 UINTN BootOptionIndex;
1199 EFI_LOAD_OPTION *CurrLoadOption;
1200 EFI_DEVICE_PATH_PROTOCOL *CurrDevicePath;
1201 BOOLEAN IsBooptstrap;
1202
1203 //
1204 // Check all boot options for trailing "\Bootstrap\Bootstrap.efi".
1205 //
1206 for (BootOptionIndex = 0; BootOptionIndex < NumBootOptions; ++BootOptionIndex) {
1207 CurrLoadOption = OcGetBootOptionData (
1208 LoadOptionSize,
1209 BootOptions[BootOptionIndex],
1211 );
1212 if (CurrLoadOption == NULL) {
1213 continue;
1214 }
1215
1216 CurrDevicePath = InternalGetBootOptionPath (
1217 CurrLoadOption,
1218 *LoadOptionSize
1219 );
1220 if (CurrDevicePath == NULL) {
1221 FreePool (CurrDevicePath);
1222 continue;
1223 }
1224
1225 IsBooptstrap = OcDevicePathHasFilePathSuffix (
1226 CurrDevicePath,
1227 MatchSuffix,
1228 MatchSuffixLen
1229 );
1230 if (IsBooptstrap) {
1231 break;
1232 }
1233
1234 FreePool (CurrLoadOption);
1235 }
1236
1237 if (BootOptionIndex == NumBootOptions) {
1238 return NULL;
1239 }
1240
1241 *LoadPath = CurrDevicePath;
1242 *BootOption = BootOptions[BootOptionIndex];
1243 return CurrLoadOption;
1244}
1245
1246STATIC
1247EFI_STATUS
1249 IN CONST CHAR16 *OptionName,
1250 IN EFI_HANDLE DeviceHandle,
1251 IN CONST CHAR16 *FilePath,
1252 IN BOOLEAN ShortForm,
1253 IN CONST CHAR16 *MatchSuffix,
1254 IN UINTN MatchSuffixLen
1255 )
1256{
1257 EFI_STATUS Status;
1258 EFI_LOAD_OPTION *Option;
1259 UINTN OptionNameSize;
1260 UINTN ReferencePathSize;
1261 UINTN OptionSize;
1262 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
1263 EFI_DEVICE_PATH_PROTOCOL *CurrDevicePath;
1264 UINTN Index;
1265 UINT16 *BootOrder;
1266 UINTN BootOrderSize;
1267 UINT32 BootOrderAttributes;
1268 BOOLEAN CurrOptionExists;
1269 BOOLEAN CurrOptionValid;
1270 EFI_DEVICE_PATH_PROTOCOL *ShortFormPath;
1271 EFI_DEVICE_PATH_PROTOCOL *ReferencePath;
1272 CHAR16 BootOptionVariable[L_STR_LEN (L"Boot####") + 1];
1273 UINT16 BootOptionIndex;
1274 UINTN OrderIndex;
1275
1276 Status = gBS->HandleProtocol (
1277 DeviceHandle,
1279 (VOID **)&DevicePath
1280 );
1281 if (EFI_ERROR (Status)) {
1282 DEBUG ((DEBUG_INFO, "OCB: Failed to obtain device path for boot option - %r\n", Status));
1283 return Status;
1284 }
1285
1286 DevicePath = AppendFileNameDevicePath (DevicePath, (CHAR16 *)FilePath);
1287 if (DevicePath == NULL) {
1288 DEBUG ((DEBUG_INFO, "OCB: Failed to append %s loader path for boot option - %r\n", FilePath));
1289 return EFI_OUT_OF_RESOURCES;
1290 }
1291
1292 ReferencePath = DevicePath;
1293
1294 if (ShortForm) {
1295 ShortFormPath = FindDevicePathNodeWithType (
1296 DevicePath,
1297 MEDIA_DEVICE_PATH,
1298 MEDIA_HARDDRIVE_DP
1299 );
1300 if (ShortFormPath != NULL) {
1301 ReferencePath = ShortFormPath;
1302 }
1303 }
1304
1305 CurrOptionValid = FALSE;
1306 CurrOptionExists = FALSE;
1307
1308 BootOrderSize = 0;
1309 Status = gRT->GetVariable (
1310 EFI_BOOT_ORDER_VARIABLE_NAME,
1312 &BootOrderAttributes,
1313 &BootOrderSize,
1314 NULL
1315 );
1316
1317 DEBUG ((
1318 DEBUG_INFO,
1319 "OCB: Have existing order of size %u - %r\n",
1320 (UINT32)BootOrderSize,
1321 Status
1322 ));
1323
1324 BootOrder = NULL;
1325
1326 if ((Status == EFI_BUFFER_TOO_SMALL) && (BootOrderSize > 0) && (BootOrderSize % sizeof (UINT16) == 0)) {
1327 BootOrder = AllocateZeroPool (BootOrderSize + sizeof (UINT16));
1328 if (BootOrder == NULL) {
1329 DEBUG ((DEBUG_INFO, "OCB: Failed to allocate boot order\n"));
1330 return EFI_OUT_OF_RESOURCES;
1331 }
1332
1333 Status = gRT->GetVariable (
1334 EFI_BOOT_ORDER_VARIABLE_NAME,
1336 &BootOrderAttributes,
1337 &BootOrderSize,
1338 (VOID *)(BootOrder + 1)
1339 );
1340
1341 if (EFI_ERROR (Status) || (BootOrderSize == 0) || (BootOrderSize % sizeof (UINT16) != 0)) {
1342 DEBUG ((DEBUG_INFO, "OCB: Failed to obtain boot order %u - %r\n", (UINT32)BootOrderSize, Status));
1343 FreePool (BootOrder);
1344 return EFI_OUT_OF_RESOURCES;
1345 }
1346
1348 &OptionSize,
1349 &BootOptionIndex,
1350 &CurrDevicePath,
1351 &BootOrder[1],
1352 BootOrderSize / sizeof (*BootOrder),
1353 MatchSuffix,
1354 MatchSuffixLen
1355 );
1356 CurrOptionExists = Option != NULL;
1357 if (CurrOptionExists) {
1358 CurrOptionValid = IsDevicePathEqual (ReferencePath, CurrDevicePath);
1359 FreePool (Option);
1360 }
1361 } else {
1362 BootOrderSize = 0;
1363 }
1364
1365 DEBUG ((
1366 DEBUG_INFO,
1367 "OCB: %a existing option at Boot%04x, %a\n",
1368 CurrOptionExists ? "Have" : "No",
1369 BootOrder != NULL ? BootOrder[1] : 0,
1370 CurrOptionValid ? "valid" : "invalid"
1371 ));
1372
1373 if (!CurrOptionValid) {
1374 //
1375 // Locate a free boot option index when no Bootstrap entry could be found.
1376 //
1377 if (!CurrOptionExists) {
1378 //
1379 // High magic numbers cause entry purging on e.g. HP 15-ab237ne, InsydeH2O.
1380 //
1381 // Find the lowest unused Boot#### index. In the absolutely unrealistic case
1382 // that all entries are occupied, always overwrite BootFFFF.
1383 //
1384 // Boot0000 is reserved on ASUS boards and is treated like a deleted entry.
1385 // Setting Boot0000 will essentially cause entries to duplicate and eventual
1386 // BIOS brick as ASUS boards simply zero removed boot entries instead of
1387 // shrinking BootOrder size. Reproduced on ASUS ROG STRIX Z370-F GAMING.
1388 //
1389 for (BootOptionIndex = 1; BootOptionIndex < 0xFFFF; ++BootOptionIndex) {
1390 for (OrderIndex = 0; OrderIndex < BootOrderSize / sizeof (*BootOrder); ++OrderIndex) {
1391 if (BootOrder[OrderIndex + 1] == BootOptionIndex) {
1392 break;
1393 }
1394 }
1395
1396 if (OrderIndex == BootOrderSize / sizeof (*BootOrder)) {
1397 break;
1398 }
1399 }
1400 }
1401
1402 UnicodeSPrint (
1403 BootOptionVariable,
1404 sizeof (BootOptionVariable),
1405 L"Boot%04x",
1406 BootOptionIndex
1407 );
1408
1409 OptionNameSize = StrSize (OptionName);
1410 ReferencePathSize = GetDevicePathSize (ReferencePath);
1411 OptionSize = sizeof (EFI_LOAD_OPTION) + OptionNameSize + ReferencePathSize;
1412
1413 DEBUG ((DEBUG_INFO, "OCB: Creating boot option %s of %u bytes\n", OptionName, (UINT32)OptionSize));
1414
1415 Option = AllocatePool (OptionSize);
1416 if (Option == NULL) {
1417 DEBUG ((DEBUG_INFO, "OCB: Failed to allocate boot option (%u)\n", (UINT32)OptionSize));
1418 FreePool (DevicePath);
1419 return EFI_OUT_OF_RESOURCES;
1420 }
1421
1422 Option->Attributes = LOAD_OPTION_ACTIVE | LOAD_OPTION_CATEGORY_BOOT;
1423 Option->FilePathListLength = (UINT16)ReferencePathSize;
1424 CopyMem (Option + 1, OptionName, OptionNameSize);
1425 CopyMem ((UINT8 *)(Option + 1) + OptionNameSize, ReferencePath, ReferencePathSize);
1426
1427 Status = gRT->SetVariable (
1428 BootOptionVariable,
1430 EFI_VARIABLE_BOOTSERVICE_ACCESS
1431 | EFI_VARIABLE_RUNTIME_ACCESS
1432 | EFI_VARIABLE_NON_VOLATILE,
1433 OptionSize,
1434 Option
1435 );
1436
1437 FreePool (Option);
1438 FreePool (DevicePath);
1439
1440 if (EFI_ERROR (Status)) {
1441 DEBUG ((DEBUG_INFO, "OCB: Failed to store boot option - %r\n", Status));
1442 return Status;
1443 }
1444 }
1445
1446 if (BootOrderSize != 0) {
1447 if (BootOrder[1] == BootOptionIndex) {
1448 DEBUG ((DEBUG_INFO, "OCB: Boot order has first option as the default option\n"));
1449 FreePool (BootOrder);
1450 return EFI_SUCCESS;
1451 }
1452
1453 BootOrder[0] = BootOptionIndex;
1454
1455 Index = 1;
1456 while (Index <= BootOrderSize / sizeof (UINT16)) {
1457 if (BootOrder[Index] == BootOptionIndex) {
1458 DEBUG ((DEBUG_INFO, "OCB: Moving boot option to the front from %u position\n", (UINT32)Index));
1459 CopyMem (
1460 &BootOrder[Index],
1461 &BootOrder[Index + 1],
1462 BootOrderSize - Index * sizeof (UINT16)
1463 );
1464 BootOrderSize -= sizeof (UINT16);
1465 } else {
1466 ++Index;
1467 }
1468 }
1469
1470 Status = gRT->SetVariable (
1471 EFI_BOOT_ORDER_VARIABLE_NAME,
1473 EFI_VARIABLE_BOOTSERVICE_ACCESS
1474 | EFI_VARIABLE_RUNTIME_ACCESS
1475 | EFI_VARIABLE_NON_VOLATILE,
1476 BootOrderSize + sizeof (UINT16),
1477 BootOrder
1478 );
1479
1480 FreePool (BootOrder);
1481 } else {
1482 Status = gRT->SetVariable (
1483 EFI_BOOT_ORDER_VARIABLE_NAME,
1485 EFI_VARIABLE_BOOTSERVICE_ACCESS
1486 | EFI_VARIABLE_RUNTIME_ACCESS
1487 | EFI_VARIABLE_NON_VOLATILE,
1488 sizeof (UINT16),
1489 &BootOptionIndex
1490 );
1491 }
1492
1493 DEBUG ((DEBUG_INFO, "OCB: Wrote new boot order with boot option - %r\n", Status));
1494 return EFI_SUCCESS;
1495}
1496
1497EFI_STATUS
1499 IN CONST CHAR16 *OptionName,
1500 IN EFI_HANDLE DeviceHandle,
1501 IN CONST CHAR16 *FilePath,
1502 IN BOOLEAN ShortForm,
1503 IN CONST CHAR16 *MatchSuffix,
1504 IN UINTN MatchSuffixLen
1505 )
1506{
1507 EFI_STATUS Status;
1509
1510 FwRuntime = OcDisableNvramProtection ();
1511
1513 OptionName,
1514 DeviceHandle,
1515 FilePath,
1516 ShortForm,
1517 MatchSuffix,
1518 MatchSuffixLen
1519 );
1520
1521 OcRestoreNvramProtection (FwRuntime);
1522
1523 return Status;
1524}
1525
1526EFI_STATUS
1528 IN OC_PICKER_CONTEXT *Context,
1529 IN OC_BOOT_ENTRY *BootEntry,
1530 IN EFI_HANDLE ParentHandle,
1531 OUT EFI_HANDLE *EntryHandle,
1532 OUT INTERNAL_DMG_LOAD_CONTEXT *DmgLoadContext,
1533 OUT VOID **CustomFreeContext
1534 )
1535{
1536 EFI_STATUS Status;
1537 EFI_STATUS OptionalStatus;
1538 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
1539 EFI_HANDLE StorageHandle;
1540 EFI_DEVICE_PATH_PROTOCOL *StoragePath;
1541 CHAR16 *UnicodeDevicePath;
1542 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
1543 VOID *EntryData;
1544 UINT32 EntryDataSize;
1545 CONST CHAR8 *Args;
1546 OC_APPLE_DISK_IMAGE_PRELOAD_CONTEXT DmgPreloadContext;
1547
1548 ASSERT (BootEntry != NULL);
1549 //
1550 // System entries are not loaded but called directly.
1551 //
1552 ASSERT ((BootEntry->Type & OC_BOOT_UNMANAGED) == 0);
1553 ASSERT ((BootEntry->Type & OC_BOOT_SYSTEM) == 0);
1554 ASSERT (Context != NULL);
1555 ASSERT (DmgLoadContext != NULL);
1556
1557 //
1558 // TODO: support Apple loaded image, policy, and dmg boot.
1559 //
1560
1561 ZeroMem (DmgLoadContext, sizeof (*DmgLoadContext));
1562
1563 EntryData = NULL;
1564 EntryDataSize = 0;
1565 StorageHandle = NULL;
1566 StoragePath = NULL;
1567 *CustomFreeContext = NULL;
1568 ZeroMem (&DmgPreloadContext, sizeof (DmgPreloadContext));
1569
1570 //
1571 // CustomRead must be set for external tools, but may also be set for boot
1572 // entry protocol entries.
1573 //
1574 ASSERT (BootEntry->Type != OC_BOOT_EXTERNAL_TOOL || BootEntry->CustomRead != NULL);
1575
1576 if (BootEntry->CustomRead != NULL) {
1577 Status = BootEntry->CustomRead (
1578 Context->StorageContext,
1579 BootEntry,
1580 &EntryData,
1581 &EntryDataSize,
1582 &DevicePath,
1583 &StorageHandle,
1584 &StoragePath,
1585 Context->DmgLoading,
1586 &DmgPreloadContext,
1587 CustomFreeContext
1588 );
1589
1590 if (EFI_ERROR (Status)) {
1591 DEBUG ((DEBUG_WARN, "OCB: Custom read failed - %r\n", Status));
1592 return Status;
1593 }
1594 }
1595
1596 if ( (DmgPreloadContext.DmgFile != NULL)
1597 || (DmgPreloadContext.DmgContext != NULL)
1598 || BootEntry->IsFolder)
1599 {
1600 if (Context->DmgLoading == OcDmgLoadingDisabled) {
1601 return EFI_SECURITY_VIOLATION;
1602 }
1603
1604 DmgLoadContext->DevicePath = BootEntry->DevicePath;
1605 DevicePath = InternalLoadDmg (
1606 DmgLoadContext,
1607 Context->DmgLoading,
1608 &DmgPreloadContext
1609 );
1610 if (DevicePath == NULL) {
1611 return EFI_UNSUPPORTED;
1612 }
1613 } else if (BootEntry->CustomRead == NULL) {
1614 DevicePath = BootEntry->DevicePath;
1615 }
1616
1617 DEBUG_CODE_BEGIN ();
1618 ASSERT (DevicePath != NULL);
1619 UnicodeDevicePath = ConvertDevicePathToText (DevicePath, FALSE, FALSE);
1620 DEBUG ((
1621 DEBUG_INFO,
1622 "OCB: Perform boot %s to dp %s (%p/%u)\n",
1623 BootEntry->Name,
1624 UnicodeDevicePath != NULL ? UnicodeDevicePath : L"<null>",
1625 EntryData,
1626 EntryDataSize
1627 ));
1628 if (UnicodeDevicePath != NULL) {
1629 FreePool (UnicodeDevicePath);
1630 }
1631
1632 DEBUG_CODE_END ();
1633
1634 Status = gBS->LoadImage (
1635 FALSE,
1636 ParentHandle,
1637 DevicePath,
1638 EntryData,
1639 EntryDataSize,
1640 EntryHandle
1641 );
1642
1643 if (EntryData != NULL) {
1644 FreePool (EntryData);
1645 }
1646
1647 if (!EFI_ERROR (Status)) {
1648 OptionalStatus = gBS->HandleProtocol (
1649 *EntryHandle,
1651 (VOID **)&LoadedImage
1652 );
1653 if (!EFI_ERROR (OptionalStatus)) {
1654 DEBUG ((
1655 DEBUG_INFO,
1656 "OCB: Matching <%a>/%p[%u] args on type %u\n",
1657 Context->AppleBootArgs,
1658 BootEntry->LoadOptions,
1659 BootEntry->LoadOptionsSize,
1660 BootEntry->Type
1661 ));
1662
1663 LoadedImage->LoadOptionsSize = 0;
1664 LoadedImage->LoadOptions = NULL;
1665
1666 if ((BootEntry->LoadOptions == NULL) && ((BootEntry->Type & OC_BOOT_APPLE_ANY) != 0)) {
1667 Args = Context->AppleBootArgs;
1668 } else {
1669 Args = BootEntry->LoadOptions;
1670 }
1671
1672 //
1673 // This only correctly passes on args which are a NUL terminated ASCII string.
1674 //
1675 if ((Args != NULL) && (Args[0] != '\0')) {
1677 LoadedImage,
1678 &Args,
1679 1,
1680 TRUE
1681 );
1682 DEBUG ((
1683 DEBUG_INFO,
1684 "OCB: Args <%s>\n",
1685 LoadedImage->LoadOptions
1686 ));
1687 }
1688
1689 if ((BootEntry->Type == OC_BOOT_EXTERNAL_OS) || (BootEntry->Type == OC_BOOT_EXTERNAL_TOOL)) {
1690 DEBUG ((
1691 DEBUG_INFO,
1692 "OCB: Custom (%u) DeviceHandle %p FilePath %p\n",
1693 BootEntry->Type,
1694 LoadedImage->DeviceHandle,
1695 LoadedImage->FilePath
1696 ));
1697
1698 //
1699 // Some fragile firmware fail to properly set LoadedImage file source
1700 // fields to our custom device path, so we fix it up here.
1701 // REF: https://github.com/acidanthera/bugtracker/issues/712
1702 //
1703 if ((LoadedImage->DeviceHandle == NULL) && (StorageHandle != NULL)) {
1704 if (LoadedImage->FilePath != NULL) {
1705 FreePool (LoadedImage->FilePath);
1706 }
1707
1708 LoadedImage->DeviceHandle = StorageHandle;
1709 LoadedImage->FilePath = StoragePath;
1710 }
1711 }
1712 }
1713 } else {
1714 InternalUnloadDmg (DmgLoadContext);
1715 if (BootEntry->CustomFree != NULL) {
1716 BootEntry->CustomFree (*CustomFreeContext);
1717 }
1718 }
1719
1720 return Status;
1721}
EFI_GUID gAppleLegacyLoadAppFileGuid
#define ARRAY_SIZE(Array)
Definition AppleMacEfi.h:34
EFI_GUID gAppleBootVariableGuid
#define SIZE_OF_OC_ENTRY_PROTOCOL_DEVICE_PATH
#define OC_ENTRY_PROTOCOL_DEVICE_PATH_GUID
EFI_DEVICE_PATH_PROTOCOL * InternalLoadDmg(IN OUT INTERNAL_DMG_LOAD_CONTEXT *Context, IN OC_DMG_LOADING_SUPPORT DmgLoading, IN OC_APPLE_DISK_IMAGE_PRELOAD_CONTEXT *DmgPreloadContext)
PACKED struct @90 OC_ENTRY_PROTOCOL_DEVICE_PATH
PACKED struct @89 OC_CUSTOM_BOOT_DEVICE_PATH
PACKED struct @92 OC_ENTRY_PROTOCOL_DEVICE_PATH_DECL
#define SIZE_OF_OC_CUSTOM_BOOT_DEVICE_PATH
#define OC_CUSTOM_BOOT_DEVICE_PATH_GUID
PACKED struct @91 OC_CUSTOM_BOOT_DEVICE_PATH_DECL
VOID InternalUnloadDmg(IN INTERNAL_DMG_LOAD_CONTEXT *DmgLoadContext)
EFI_STATUS OcRegisterBootstrapBootOption(IN CONST CHAR16 *OptionName, IN EFI_HANDLE DeviceHandle, IN CONST CHAR16 *FilePath, IN BOOLEAN ShortForm, IN CONST CHAR16 *MatchSuffix, IN UINTN MatchSuffixLen)
STATIC BOOLEAN InternalMatchCustomBootEntryByDevicePath(IN OUT OC_BOOT_ENTRY *BootEntry, IN CONST OC_CUSTOM_BOOT_DEVICE_PATH *DevicePath)
STATIC BOOLEAN InternalHasFirmwareUpdateAsNext(IN EFI_GUID *BootVariableGuid)
CONST OC_ENTRY_PROTOCOL_DEVICE_PATH * InternalGetOcEntryProtocolDevPath(IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath)
STATIC CONST OC_ENTRY_PROTOCOL_DEVICE_PATH_DECL mOcEntryProtocolDevPathTemplate
EFI_STATUS InternalLoadBootEntry(IN OC_PICKER_CONTEXT *Context, IN OC_BOOT_ENTRY *BootEntry, IN EFI_HANDLE ParentHandle, OUT EFI_HANDLE *EntryHandle, OUT INTERNAL_DMG_LOAD_CONTEXT *DmgLoadContext, OUT VOID **CustomFreeContext)
STATIC VOID InternalClearNextVariables(IN EFI_GUID *BootVariableGuid, IN BOOLEAN ClearApplePayload)
EFI_STATUS OcSetDefaultBootEntry(IN OC_PICKER_CONTEXT *Context, IN OC_BOOT_ENTRY *Entry)
STATIC BOOLEAN InternalMatchEntryProtocolEntryByDevicePath(IN OUT OC_BOOT_ENTRY *BootEntry, IN CONST OC_ENTRY_PROTOCOL_DEVICE_PATH *DevicePath)
STATIC EFI_STATUS InternalRegisterBootstrapBootOption(IN CONST CHAR16 *OptionName, IN EFI_HANDLE DeviceHandle, IN CONST CHAR16 *FilePath, IN BOOLEAN ShortForm, IN CONST CHAR16 *MatchSuffix, IN UINTN MatchSuffixLen)
UINT16 * InternalGetBootOrderForBooting(IN EFI_GUID *BootVariableGuid, IN BOOLEAN BlacklistAppleUpdate, OUT UINTN *BootOrderCount, IN BOOLEAN UseBootNextOnly)
EFI_DEVICE_PATH_PROTOCOL * InternalGetBootOptionPath(IN EFI_LOAD_OPTION *LoadOption, IN UINTN LoadOptionSize)
STATIC CONST OC_CUSTOM_BOOT_DEVICE_PATH_DECL mOcCustomBootDevPathTemplate
VOID InternalDebugBootEnvironment(IN CONST UINT16 *BootOrder, IN EFI_GUID *BootGuid, IN UINTN BootOrderCount)
UINT16 * OcGetBootOrder(IN EFI_GUID *BootVariableGuid, IN BOOLEAN WithBootNext, OUT UINTN *BootOrderCount, OUT BOOLEAN *Deduplicated OPTIONAL, OUT BOOLEAN *HasBootNext OPTIONAL, IN BOOLEAN UseBootNextOnly)
BOOLEAN InternalIsAppleLegacyLoadApp(IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath)
CONST OC_CUSTOM_BOOT_DEVICE_PATH * InternalGetOcCustomDevPath(IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath)
EFI_LOAD_OPTION * InternalGetBoostrapOptionData(OUT UINTN *LoadOptionSize, OUT UINT16 *BootOption, OUT EFI_DEVICE_PATH_PROTOCOL **LoadPath, IN UINT16 *BootOptions, IN UINTN NumBootOptions, IN CONST CHAR16 *MatchSuffix, IN UINTN MatchSuffixLen)
STATIC BOOLEAN InternalMatchBootEntryByDevicePath(IN OUT OC_BOOT_ENTRY *BootEntry, IN EFI_DEVICE_PATH_PROTOCOL *UefiDevicePath, IN EFI_DEVICE_PATH_PROTOCOL *UefiRemainingDevicePath, IN UINTN UefiDevicePathSize, IN BOOLEAN IsBootNext)
DMG_FILEPATH_DEVICE_PATH FilePath
STATIC_ASSERT(BYTES_PER_PIXEL==sizeof(UINT32), "Non 4-byte pixels are unsupported!")
#define OC_BOOT_APPLE_ANY
#define OC_BOOT_EXTERNAL_TOOL
#define OC_BOOT_EXTERNAL_OS
UINT32 OC_BOOT_ENTRY_TYPE
OC_BOOT_ENTRY_TYPE OcGetBootDevicePathType(IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, OUT BOOLEAN *IsFolder OPTIONAL, OUT BOOLEAN *IsGeneric OPTIONAL)
@ OcDmgLoadingDisabled
BOOLEAN OcAppendArgumentsToLoadedImage(IN OUT EFI_LOADED_IMAGE_PROTOCOL *LoadedImage, IN CONST CHAR8 **Arguments, IN UINT32 ArgumentCount, IN BOOLEAN Replace)
#define OC_BOOT_APPLE_FW_UPDATE
#define OC_BOOT_UNMANAGED
#define OC_BOOT_SYSTEM
EFI_BOOT_SERVICES * gBS
BOOLEAN OcDevicePathHasFilePathSuffix(IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, IN CONST CHAR16 *Suffix, IN UINTN SuffixLen)
EFI_DEVICE_PATH_PROTOCOL * FindDevicePathNodeWithType(IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, IN UINT8 Type, IN UINT8 SubType OPTIONAL)
EFI_DEVICE_PATH_PROTOCOL * AppendFileNameDevicePath(IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, IN CHAR16 *FileName)
BOOLEAN EFIAPI IsDevicePathEqual(IN EFI_DEVICE_PATH_PROTOCOL *DevicePath1, IN EFI_DEVICE_PATH_PROTOCOL *DevicePath2)
#define L_STR_LEN(String)
Definition OcStringLib.h:26
CHAR8 *EFIAPI OcAsciiStrChr(IN CONST CHAR8 *String, IN CHAR8 Char)
Definition OcAsciiLib.c:369
EFI_GUID gOcVendorVariableGuid
#define OC_VENDOR_BOOT_NEXT_VARIABLE_NAME
Definition OcVariable.h:95
#define OC_VENDOR_BOOT_ORDER_VARIABLE_NAME
Definition OcVariable.h:90
#define OC_VENDOR_BOOT_VARIABLE_PREFIX
Definition OcVariable.h:85
VOID EFIAPI OcSaveLegacyNvram(VOID)
OC_FIRMWARE_RUNTIME_PROTOCOL * OcDisableNvramProtection(VOID)
VOID OcRestoreNvramProtection(IN OC_FIRMWARE_RUNTIME_PROTOCOL *FwRuntime)
EFI_LOAD_OPTION * OcGetBootOptionData(OUT UINTN *OptionSize, IN UINT16 BootOption, IN CONST EFI_GUID *BootGuid)
INTN EFIAPI CompareMem(IN CONST VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
BOOLEAN EFIAPI CompareGuid(IN CONST GUID *Guid1, IN CONST GUID *Guid2)
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
EFI_RUNTIME_SERVICES * gRT
EFI_GUID gEfiSimpleFileSystemProtocolGuid
EFI_GUID gEfiGlobalVariableGuid
EFI_GUID gEfiLoadedImageProtocolGuid
EFI_GUID gEfiDevicePathProtocolGuid
#define ASSERT(x)
Definition coder.h:55
OC_APPLE_DISK_IMAGE_CONTEXT * DmgContext