OpenCore  1.0.4
OpenCore Bootloader
Loading...
Searching...
No Matches
BootEntryManagement.c
Go to the documentation of this file.
1
7
8#include <Protocol/DevicePath.h>
9#include <Protocol/SimpleFileSystem.h>
10
12
13#include <Guid/AppleVariable.h>
14#include <Guid/FileInfo.h>
15#include <Guid/GlobalVariable.h>
16#include <Guid/Gpt.h>
17#include <Guid/OcVariable.h>
18
19#include <Library/BaseLib.h>
20#include <Library/BaseMemoryLib.h>
21#include <Library/DevicePathLib.h>
22#include <Library/MemoryAllocationLib.h>
27#include <Library/OcFileLib.h>
28#include <Library/OcStringLib.h>
30#include <Library/PrintLib.h>
31#include <Library/UefiBootServicesTableLib.h>
32#include <Library/UefiLib.h>
33#include <Library/UefiRuntimeServicesTableLib.h>
34
35/*
36 Expands DevicePath from short-form to full-form.
37 The only valid expansions are full Device Paths refering to a file or a
38 volume root. Latter type may be used with custom policies to determine a
39 bootable file.
40
41 @param[in] BootContext Context of filesystems.
42 @param[in] DevicePath The Device Path to expand.
43 @param[in] LazyScan Lazy filesystem scanning.
44 @param[out] FileSystem Resulting filesystem.
45 @param[out] IsRoot Whether DevicePath refers to the root of a volume.
46
47 @returns DevicePath expansion or NULL on failure.
48*/
49STATIC
50EFI_DEVICE_PATH_PROTOCOL *
52 IN OC_BOOT_CONTEXT *BootContext,
53 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
54 IN BOOLEAN LazyScan,
55 OUT OC_BOOT_FILESYSTEM **FileSystem,
56 OUT BOOLEAN *IsRoot
57 )
58{
59 EFI_STATUS Status;
60
61 EFI_DEVICE_PATH_PROTOCOL *FullDevicePath;
62 EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath;
63 EFI_DEVICE_PATH_PROTOCOL *PrevDevicePath;
64
65 EFI_HANDLE FileSystemHandle;
66 EFI_FILE_PROTOCOL *File;
67 EFI_FILE_INFO *FileInfo;
68 BOOLEAN IsRootPath;
69 BOOLEAN IsDirectory;
70
71 ASSERT (BootContext != NULL);
72 ASSERT (DevicePath != NULL);
73 ASSERT (FileSystem != NULL);
74 ASSERT (IsRoot != NULL);
75
76 //
77 // Iteratively expand the short-form Device Path to its possible full forms.
78 // A valid Device Path will either refer to a valid file or to a valid root
79 // volume.
80 //
81 PrevDevicePath = NULL;
82 IsDirectory = FALSE;
83 do {
84 FullDevicePath = OcGetNextLoadOptionDevicePath (
85 DevicePath,
86 PrevDevicePath
87 );
88
89 if (PrevDevicePath != NULL) {
90 FreePool (PrevDevicePath);
91 }
92
93 //
94 // When no more full representations can be built, the Device Path is
95 // not bootable.
96 //
97 if (FullDevicePath == NULL) {
98 DEBUG ((DEBUG_INFO, "OCB: Short-form DP could not be expanded\n"));
99 return NULL;
100 }
101
102 PrevDevicePath = FullDevicePath;
103
105 DEBUG_INFO,
106 "OCB: Expanded DP",
107 FullDevicePath
108 );
109
110 //
111 // Retrieve the filesystem handle.
112 //
113 RemainingDevicePath = FullDevicePath;
114 Status = gBS->LocateDevicePath (
116 &RemainingDevicePath,
117 &FileSystemHandle
118 );
119 if (EFI_ERROR (Status)) {
120 continue;
121 }
122
124 DEBUG_INFO,
125 "OCB: Expanded DP remainder",
126 RemainingDevicePath
127 );
128
129 //
130 // Check whether we are allowed to boot from this filesystem.
131 //
132 *FileSystem = InternalFileSystemForHandle (BootContext, FileSystemHandle, LazyScan, NULL);
133 if (*FileSystem == NULL) {
134 continue;
135 }
136
137 //
138 // Check whether the Device Path refers to a valid file handle.
139 //
141 FileSystemHandle,
142 RemainingDevicePath,
143 &File,
144 EFI_FILE_MODE_READ,
145 0
146 );
147 if (EFI_ERROR (Status)) {
148 continue;
149 }
150
151 //
152 // Retrieve file info to determine potentially bootable state.
153 //
154 FileInfo = OcGetFileInfo (
155 File,
157 sizeof (EFI_FILE_INFO),
158 NULL
159 );
160 //
161 // When File Info cannot be retrieved, assume the worst case but don't
162 // skip the Device Path expansion as it is valid.
163 //
164 IsDirectory = TRUE;
165 if (FileInfo != NULL) {
166 IsDirectory = (FileInfo->Attribute & EFI_FILE_DIRECTORY) != 0;
167 FreePool (FileInfo);
168 }
169
170 File->Close (File);
171
172 //
173 // Return only Device Paths that either refer to a file or a volume root.
174 // Root Device Paths may be expanded by custom policies (such as Apple Boot
175 // Policy) later.
176 //
177 IsRootPath = IsDevicePathEnd (RemainingDevicePath);
178 if (IsRootPath || !IsDirectory) {
179 ASSERT (FullDevicePath != NULL);
180 ASSERT (*FileSystem != NULL);
181
182 *IsRoot = IsDirectory;
183 return FullDevicePath;
184 }
185
186 //
187 // Request a new device path expansion.
188 //
189 } while (TRUE);
190}
191
200STATIC
203 IN OC_PICKER_CONTEXT *Context,
204 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
205 )
206{
207 EFI_STATUS Status;
208 CHAR8 *Visibility;
209 CHAR8 *VisibilityCommand;
210 CHAR8 *Walker;
211 UINTN IdentifierLength;
212
213 //
214 // Allow root location as well as leaf, because this is a non-Apple file which will
215 // get deleted at update if placed next to boot.efi in macOS.
216 // Leaf (next to bootloader) is recommended location for non-macOS.
217 //
219 DevicePath,
220 L".contentVisibility",
221 "visibility",
223 0,
224 (VOID **)&Visibility,
225 NULL,
226 TRUE,
227 TRUE
228 );
229
230 if (EFI_ERROR (Status)) {
231 return BootEntryNormal;
232 }
233
234 //
235 // Allow for terminating new line, but be strict about it -
236 // after removing this, things must match exactly.
237 //
238 Walker = AsciiStrStr (Visibility, "\r");
239 if (Walker != NULL) {
240 *Walker = '\0';
241 }
242
243 Walker = AsciiStrStr (Visibility, "\n");
244 if (Walker != NULL) {
245 *Walker = '\0';
246 }
247
248 Walker = AsciiStrStr (Visibility, ":");
249 if (Walker == NULL) {
250 VisibilityCommand = Visibility;
251 } else {
252 if (*(Context->InstanceIdentifier) == '\0') {
253 DEBUG ((DEBUG_INFO, "OCB: No InstanceIdentifier, ignoring qualified visibility\n"));
254 FreePool (Visibility);
255 return BootEntryNormal;
256 }
257
258 *Walker++ = '\0';
259 VisibilityCommand = Walker;
260 Walker = Visibility;
261
262 IdentifierLength = AsciiStrLen (Context->InstanceIdentifier);
263 Status = EFI_NOT_FOUND;
264 do {
265 if ( (AsciiStrnCmp (Walker, Context->InstanceIdentifier, IdentifierLength) == 0)
266 && ((Walker[IdentifierLength] == '\0') || (Walker[IdentifierLength] == ',')))
267 {
268 Status = EFI_SUCCESS;
269 break;
270 }
271
272 Walker = AsciiStrStr (Walker, ",");
273 if (Walker != NULL) {
274 ++Walker;
275 }
276 } while (Walker != NULL);
277
278 if (EFI_ERROR (Status)) {
279 DEBUG ((DEBUG_INFO, "OCB: \"%a\" not present in \"%a\" ignoring visibility\n", Context->InstanceIdentifier, Visibility));
280 FreePool (Visibility);
281 return BootEntryNormal;
282 }
283 }
284
285 if (AsciiStrCmp (VisibilityCommand, "Disabled") == 0) {
286 FreePool (Visibility);
287 return BootEntryDisabled;
288 }
289
290 if (AsciiStrCmp (VisibilityCommand, "Auxiliary") == 0) {
291 FreePool (Visibility);
292 return BootEntryAuxiliary;
293 }
294
295 DEBUG ((DEBUG_INFO, "OCB: Discovered unsupported visibility \"%a\"\n", VisibilityCommand));
296
297 FreePool (Visibility);
298 return BootEntryNormal;
299}
300
308STATIC
309VOID
311 IN OUT OC_BOOT_CONTEXT *BootContext,
312 IN OUT OC_BOOT_FILESYSTEM *FileSystem,
313 IN OC_BOOT_ENTRY *BootEntry
314 )
315{
316 CHAR16 *TextDevicePath;
317
318 DEBUG_CODE_BEGIN ();
319
320 if (BootEntry->DevicePath != NULL) {
321 TextDevicePath = ConvertDevicePathToText (BootEntry->DevicePath, FALSE, FALSE);
322 } else {
323 TextDevicePath = NULL;
324 }
325
326 DEBUG ((
327 DEBUG_INFO,
328 "OCB: Registering entry %s [%a] (T:%d|F:%d|G:%d|E:%d|B:%d) - %s\n",
329 BootEntry->Name,
330 BootEntry->Flavour,
331 BootEntry->Type,
332 BootEntry->IsFolder,
333 BootEntry->IsGeneric,
334 BootEntry->IsExternal,
335 BootEntry->IsBootEntryProtocol,
336 OC_HUMAN_STRING (TextDevicePath)
337 ));
338
339 if (TextDevicePath != NULL) {
340 FreePool (TextDevicePath);
341 }
342
343 DEBUG_CODE_END ();
344
345 //
346 // Register boot entry.
347 // Not using RecoveryFs is intended for correct order.
348 //
349 InsertTailList (&FileSystem->BootEntries, &BootEntry->Link);
350 ++BootContext->BootEntryCount;
351
352 //
353 // If no options were previously found and this entry type
354 // is allowed in this context then this is the default one.
355 //
356 if ( (BootContext->DefaultEntry == NULL)
357 && ((BootEntry->Type & OC_BOOT_EXTERNAL_TOOL) == 0)
358 && ( ((BootEntry->Type & OC_BOOT_SYSTEM) == 0)
359 || (BootContext->PickerContext->PickerCommand == OcPickerProtocolHotKey)
360 )
361 )
362 {
363 BootContext->DefaultEntry = BootEntry;
364 }
365
366 //
367 // For tools and system options we are done.
368 //
369 if ((BootEntry->Type & (OC_BOOT_EXTERNAL_TOOL | OC_BOOT_SYSTEM)) != 0) {
370 return;
371 }
372
373 //
374 // Set override picker commands.
375 //
376 if (BootContext->PickerContext->PickerCommand == OcPickerBootApple) {
377 if ( (BootContext->DefaultEntry->Type != OC_BOOT_APPLE_OS)
378 && (BootEntry->Type == OC_BOOT_APPLE_OS))
379 {
380 BootContext->DefaultEntry = BootEntry;
381 }
382 }
383}
384
396STATIC
397EFI_STATUS
399 IN OUT OC_BOOT_CONTEXT *BootContext,
400 IN OUT OC_BOOT_FILESYSTEM *FileSystem,
401 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
402 IN BOOLEAN RecoveryPart,
403 IN BOOLEAN Deduplicate
404 )
405{
406 EFI_STATUS Status;
407 OC_BOOT_ENTRY *BootEntry;
408 OC_BOOT_ENTRY_TYPE EntryType;
409 LIST_ENTRY *Link;
410 OC_BOOT_ENTRY *ExistingEntry;
411 CHAR16 *TextDevicePath;
412 INTERNAL_ENTRY_VISIBILITY Visibility;
413 BOOLEAN IsFolder;
414 BOOLEAN IsGeneric;
415 BOOLEAN IsReallocated;
416
417 EntryType = OcGetBootDevicePathType (DevicePath, &IsFolder, &IsGeneric);
418
419 if (IsFolder && (BootContext->PickerContext->DmgLoading == OcDmgLoadingDisabled)) {
420 DevicePath = AppendFileNameDevicePath (DevicePath, L"boot.efi");
421 IsFolder = FALSE;
422 IsReallocated = TRUE;
423 DEBUG ((DEBUG_INFO, "OCB: Switching DMG boot path to boot.efi due to policy\n"));
424 if (DevicePath == NULL) {
425 return EFI_OUT_OF_RESOURCES;
426 }
427 } else {
428 IsReallocated = FALSE;
429 }
430
431 DEBUG_CODE_BEGIN ();
432
433 TextDevicePath = ConvertDevicePathToText (DevicePath, FALSE, FALSE);
434
435 DEBUG ((
436 DEBUG_INFO,
437 "OCB: Adding entry type (T:%u|F:%d|G:%d) - %s\n",
438 EntryType,
439 IsFolder,
440 IsGeneric,
441 OC_HUMAN_STRING (TextDevicePath)
442 ));
443
444 if (TextDevicePath != NULL) {
445 FreePool (TextDevicePath);
446 }
447
448 DEBUG_CODE_END ();
449
450 //
451 // Mark self recovery presence.
452 //
453 if (!RecoveryPart && (EntryType == OC_BOOT_APPLE_RECOVERY)) {
454 FileSystem->HasSelfRecovery = TRUE;
455 }
456
457 //
458 // Do not add recoveries when not requested (e.g. can be HFS+ recovery).
459 //
460 if (BootContext->PickerContext->HideAuxiliary && (EntryType == OC_BOOT_APPLE_RECOVERY)) {
461 DEBUG ((DEBUG_INFO, "OCB: Discarding recovery entry due to auxiliary\n"));
462 if (IsReallocated) {
463 FreePool (DevicePath);
464 }
465
466 return EFI_UNSUPPORTED;
467 }
468
469 //
470 // Do not add Time Machine when not requested.
471 //
472 if (BootContext->PickerContext->HideAuxiliary && (EntryType == OC_BOOT_APPLE_TIME_MACHINE)) {
473 DEBUG ((DEBUG_INFO, "OCB: Discarding time machine entry due to auxiliary\n"));
474 if (IsReallocated) {
475 FreePool (DevicePath);
476 }
477
478 return EFI_UNSUPPORTED;
479 }
480
481 //
482 // Skip disabled entries, like OpenCore bootloader.
483 //
484 Visibility = ReadEntryVisibility (BootContext->PickerContext, DevicePath);
485 if (Visibility == BootEntryDisabled) {
486 DEBUG ((DEBUG_INFO, "OCB: Discarding disabled entry by visibility\n"));
487 if (IsReallocated) {
488 FreePool (DevicePath);
489 }
490
491 return EFI_UNSUPPORTED;
492 }
493
494 //
495 // Skip custom auxiliary entries.
496 //
497 if ((Visibility == BootEntryAuxiliary) && BootContext->PickerContext->HideAuxiliary) {
498 DEBUG ((DEBUG_INFO, "OCB: Discarding auxiliary entry by visibility\n"));
499 if (IsReallocated) {
500 FreePool (DevicePath);
501 }
502
503 return EFI_UNSUPPORTED;
504 }
505
506 //
507 // Skip duplicated entries, which may happen in BootOrder.
508 // For example, macOS during hibernation may leave Boot0082 in BootNext and Boot0080 in BootOrder,
509 // and they will have exactly the same boot entry.
510 //
511 if (Deduplicate) {
512 for (
513 Link = GetFirstNode (&FileSystem->BootEntries);
514 !IsNull (&FileSystem->BootEntries, Link);
515 Link = GetNextNode (&FileSystem->BootEntries, Link))
516 {
517 ExistingEntry = BASE_CR (Link, OC_BOOT_ENTRY, Link);
518 //
519 // All non-custom entries have DPs.
520 //
521 ASSERT (ExistingEntry->DevicePath != NULL);
522 if (IsDevicePathEqual (ExistingEntry->DevicePath, DevicePath)) {
523 DEBUG ((DEBUG_INFO, "OCB: Discarding already present DP\n"));
524 //
525 // We may have more than one macOS installation in APFS container.
526 // Boot policy returns them in a defined (constant) order, and we want
527 // to preserve this order regardless of the BootOrder.
528 //
529 // When an operating system is present in BootOrder it will be put to
530 // the front of FileSystem boot entries. As a result instead of:
531 // [OS1], [REC1], [OS2], [REC2] we may get [OS2], [OS1], [REC1], [REC2].
532 // The latter happens because after [REC1] discovered [OS1] is skipped
533 // due to being already present. The code below moves [OS2] to the end
534 // of list at [REC1] stage to fix the order.
535 //
536 // This change assumes that only one operating system from the container
537 // can be present as a boot option. For now this appears to be true.
538 //
539 RemoveEntryList (Link);
540 InsertTailList (&FileSystem->BootEntries, Link);
541 if (IsReallocated) {
542 FreePool (DevicePath);
543 }
544
545 return EFI_ALREADY_STARTED;
546 }
547 }
548 }
549
550 //
551 // Allocate, initialise, and describe boot entry.
552 //
553 BootEntry = AllocateZeroPool (sizeof (*BootEntry));
554 if (BootEntry == NULL) {
555 if (IsReallocated) {
556 FreePool (DevicePath);
557 }
558
559 return EFI_OUT_OF_RESOURCES;
560 }
561
562 BootEntry->DevicePath = DevicePath;
563 BootEntry->Type = EntryType;
564 BootEntry->IsFolder = IsFolder;
565 BootEntry->IsGeneric = IsGeneric;
566 BootEntry->IsExternal = RecoveryPart ? FileSystem->RecoveryFs->External : FileSystem->External;
567
568 Status = InternalDescribeBootEntry (BootContext, BootEntry);
569 if (EFI_ERROR (Status)) {
570 FreePool (BootEntry);
571 if (IsReallocated) {
572 FreePool (DevicePath);
573 }
574
575 return Status;
576 }
577
579 BootContext,
580 FileSystem,
581 BootEntry
582 );
583
584 return EFI_SUCCESS;
585}
586
592STATIC
593VOID
595 IN OC_BOOT_ENTRY *BootEntry
596 )
597{
598 if (BootEntry->DevicePath != NULL) {
599 FreePool (BootEntry->DevicePath);
600 BootEntry->DevicePath = NULL;
601 }
602
603 if (BootEntry->Id != NULL) {
604 FreePool (BootEntry->Id);
605 BootEntry->Id = NULL;
606 }
607
608 if (BootEntry->Name != NULL) {
609 FreePool (BootEntry->Name);
610 BootEntry->Name = NULL;
611 }
612
613 if (BootEntry->PathName != NULL) {
614 FreePool (BootEntry->PathName);
615 BootEntry->PathName = NULL;
616 }
617
618 if (BootEntry->LoadOptions != NULL) {
619 FreePool (BootEntry->LoadOptions);
620 BootEntry->LoadOptions = NULL;
621 BootEntry->LoadOptionsSize = 0;
622 }
623
624 if (BootEntry->Flavour != NULL) {
625 FreePool (BootEntry->Flavour);
626 BootEntry->Flavour = NULL;
627 }
628
629 FreePool (BootEntry);
630}
631
641EFI_STATUS
643 IN OUT OC_BOOT_CONTEXT *BootContext,
644 IN OUT OC_BOOT_FILESYSTEM *FileSystem,
645 IN OC_PICKER_ENTRY *CustomEntry,
646 IN BOOLEAN IsBootEntryProtocol
647 )
648{
649 EFI_STATUS Status;
650 OC_BOOT_ENTRY *BootEntry;
651 CHAR16 *PathName;
652 FILEPATH_DEVICE_PATH *FilePath;
653 CHAR8 *ContentFlavour;
654 CHAR16 *BootDirectoryName;
655 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFileSystem;
656 CONST EFI_PARTITION_ENTRY *PartitionEntry;
657
658 if (CustomEntry->Auxiliary && BootContext->PickerContext->HideAuxiliary) {
659 DEBUG ((
660 DEBUG_INFO,
661 "OCB: Not adding hidden auxiliary entry %a (%a|B:%d) -> %a\n",
662 CustomEntry->Name,
663 CustomEntry->Tool ? "tool" : "os",
664 IsBootEntryProtocol,
665 CustomEntry->Path
666 ));
667 return EFI_UNSUPPORTED;
668 }
669
670 //
671 // Allocate, initialise, and describe boot entry.
672 //
673 BootEntry = AllocateZeroPool (sizeof (*BootEntry));
674 if (BootEntry == NULL) {
675 return EFI_OUT_OF_RESOURCES;
676 }
677
678 BootEntry->IsExternal = FileSystem->External;
679 BootEntry->CustomRead = CustomEntry->CustomRead;
680 BootEntry->CustomFree = CustomEntry->CustomFree;
681
682 if (CustomEntry->Id != NULL) {
683 BootEntry->Id = AsciiStrCopyToUnicode (CustomEntry->Id, 0);
684 if (BootEntry->Id == NULL) {
685 FreeBootEntry (BootEntry);
686 return EFI_OUT_OF_RESOURCES;
687 }
688 }
689
690 ASSERT (CustomEntry->Name != NULL);
691 BootEntry->Name = AsciiStrCopyToUnicode (CustomEntry->Name, 0);
692 if (BootEntry->Name == NULL) {
693 FreeBootEntry (BootEntry);
694 return EFI_OUT_OF_RESOURCES;
695 }
696
697 if (!CustomEntry->UnmanagedBootAction && !CustomEntry->SystemAction && !CustomEntry->UnmanagedDevicePath) {
698 ASSERT (CustomEntry->Path != NULL);
699 PathName = AsciiStrCopyToUnicode (CustomEntry->Path, 0);
700 if (PathName == NULL) {
701 FreeBootEntry (BootEntry);
702 return EFI_OUT_OF_RESOURCES;
703 }
704 } else {
705 ASSERT (CustomEntry->Path == NULL);
706 PathName = NULL;
707 }
708
709 ASSERT (CustomEntry->Flavour != NULL);
710 BootEntry->Flavour = AllocateCopyPool (AsciiStrSize (CustomEntry->Flavour), CustomEntry->Flavour);
711 if (BootEntry->Flavour == NULL) {
712 FreeBootEntry (BootEntry);
713 return EFI_OUT_OF_RESOURCES;
714 }
715
716 DEBUG ((
717 DEBUG_INFO,
718 "OCB: Adding custom entry %s (%a|B:%d) -> %a\n",
719 BootEntry->Name,
720 CustomEntry->UnmanagedBootAction != NULL ? "unmanaged" : (CustomEntry->SystemAction != NULL ? "action" : (CustomEntry->Tool ? "tool" : "os")),
721 IsBootEntryProtocol,
722 CustomEntry->Path
723 ));
724
725 if (CustomEntry->UnmanagedBootAction) {
726 BootEntry->Type = OC_BOOT_UNMANAGED;
727 BootEntry->UnmanagedBootAction = CustomEntry->UnmanagedBootAction;
728 BootEntry->UnmanagedBootGetFinalDevicePath = CustomEntry->UnmanagedBootGetFinalDevicePath;
729 BootEntry->AudioBasePath = CustomEntry->AudioBasePath;
730 BootEntry->AudioBaseType = CustomEntry->AudioBaseType;
731 BootEntry->IsExternal = CustomEntry->External;
732 BootEntry->DevicePath = DuplicateDevicePath (CustomEntry->UnmanagedDevicePath);
733
734 if (BootEntry->DevicePath == NULL) {
735 FreeBootEntry (BootEntry);
736 return EFI_OUT_OF_RESOURCES;
737 }
738 } else if (CustomEntry->SystemAction) {
739 BootEntry->Type = OC_BOOT_SYSTEM;
740 BootEntry->SystemAction = CustomEntry->SystemAction;
741 BootEntry->AudioBasePath = CustomEntry->AudioBasePath;
742 BootEntry->AudioBaseType = CustomEntry->AudioBaseType;
743 } else if (CustomEntry->Tool) {
744 ASSERT (CustomEntry->CustomRead == NULL && CustomEntry->CustomFree == NULL);
745 BootEntry->Type = OC_BOOT_EXTERNAL_TOOL;
746 BootEntry->CustomRead = BootContext->PickerContext->CustomRead;
747 BootEntry->CustomFree = NULL;
749 BootEntry->PathName = PathName;
750 } else {
751 BootEntry->Type = OC_BOOT_EXTERNAL_OS;
752
753 //
754 // For boot entry protocol path is relative to device root,
755 // for user entry path is absolute device path.
756 //
757 if (IsBootEntryProtocol) {
758 if (CustomEntry->UnmanagedDevicePath) {
759 BootEntry->DevicePath = DuplicateDevicePath (CustomEntry->UnmanagedDevicePath);
760 } else {
762 BootEntry->DevicePath = FileDevicePath (FileSystem->Handle, PathName);
763 FreePool (PathName);
764 }
765 } else {
766 ASSERT (CustomEntry->UnmanagedDevicePath == NULL);
767 BootEntry->DevicePath = ConvertTextToDevicePath (PathName);
768 FreePool (PathName);
769 }
770
771 if (BootEntry->DevicePath == NULL) {
772 FreeBootEntry (BootEntry);
773 return EFI_OUT_OF_RESOURCES;
774 }
775
776 FilePath = (FILEPATH_DEVICE_PATH *)(
778 BootEntry->DevicePath,
779 MEDIA_DEVICE_PATH,
780 MEDIA_FILEPATH_DP
781 )
782 );
783 if (FilePath == NULL) {
784 if (BootEntry->CustomRead == NULL) {
785 DEBUG ((
786 DEBUG_WARN,
787 "OCB: Invalid device path, not adding entry %a\n",
788 CustomEntry->Name
789 ));
790 FreeBootEntry (BootEntry);
791 return EFI_UNSUPPORTED;
792 }
793 } else {
794 BootEntry->PathName = AllocateCopyPool (
796 FilePath->PathName
797 );
798 if (BootEntry->PathName == NULL) {
799 FreeBootEntry (BootEntry);
800 return EFI_OUT_OF_RESOURCES;
801 }
802 }
803
804 //
805 // NOTE: It is not currently necessary/useful to apply .contentDetails around here because:
806 // a) Entries have user-specified names already.
807 // b) OpenLinuxBoot needs to read the label file early, when allowed by picker attributes,
808 // so it can be used for pretty name with kernel version appended when required.
809 // If any future boot entry protocol drivers do want .contentDetails applied for them, we will need
810 // to pass back an entry flag indicating whether .contentDetails has already been applied or not.
811 //
812
813 //
814 // Try to get content flavour from file.
815 // If enabled and present, .contentFlavour always overrides flavour from boot entry protocol,
816 // but is only applied to Entries if they have flavour Auto.
817 //
818 if ( ((BootContext->PickerContext->PickerAttributes & OC_ATTR_USE_FLAVOUR_ICON) != 0)
819 && (IsBootEntryProtocol || (AsciiStrCmp (BootEntry->Flavour, OC_FLAVOUR_AUTO) == 0)))
820 {
822 BootEntry->DevicePath,
823 &BootDirectoryName,
824 &SimpleFileSystem
825 );
826
827 if (!EFI_ERROR (Status)) {
828 ContentFlavour = InternalGetContentFlavour (SimpleFileSystem, BootDirectoryName);
829
830 if (ContentFlavour != NULL) {
831 //
832 // 'Auto' read from file means do not override.
833 //
834 if (AsciiStrCmp (ContentFlavour, OC_FLAVOUR_AUTO) == 0) {
835 FreePool (ContentFlavour);
836 } else {
837 if (BootEntry->Flavour != NULL) {
838 FreePool (BootEntry->Flavour);
839 }
840
841 BootEntry->Flavour = ContentFlavour;
842 }
843 }
844
845 //
846 // There is no need for the additional flavour fixup from BootEntryInfo.c, since type
847 // OC_BOOT_EXTERNAL_OS does not need fixing up, and already determines our voiceover.
848 //
849
850 FreePool (BootDirectoryName);
851 }
852 }
853 }
854
855 BootEntry->LaunchInText = CustomEntry->TextMode;
856 BootEntry->ExposeDevicePath = CustomEntry->RealPath;
857 BootEntry->FullNvramAccess = CustomEntry->FullNvramAccess;
858
859 if ((BootEntry->UnmanagedBootAction != NULL) || (BootEntry->SystemAction != NULL) || (CustomEntry->CustomRead != NULL)) {
860 ASSERT (CustomEntry->Arguments == NULL);
861 } else {
862 ASSERT (CustomEntry->Arguments != NULL);
863 BootEntry->LoadOptionsSize = (UINT32)AsciiStrLen (CustomEntry->Arguments);
864 if (BootEntry->LoadOptionsSize > 0) {
865 BootEntry->LoadOptions = AllocateCopyPool (
866 BootEntry->LoadOptionsSize + 1,
867 CustomEntry->Arguments
868 );
869 if (BootEntry->LoadOptions == NULL) {
870 BootEntry->LoadOptionsSize = 0;
871 }
872 }
873 }
874
875 BootEntry->IsCustom = TRUE;
876 BootEntry->IsBootEntryProtocol = IsBootEntryProtocol;
877 if (IsBootEntryProtocol && (BootEntry->UnmanagedBootAction == NULL) && (BootEntry->SystemAction == NULL)) {
878 PartitionEntry = OcGetGptPartitionEntry (FileSystem->Handle);
879 if (PartitionEntry == NULL) {
880 CopyGuid (&BootEntry->UniquePartitionGUID, &gEfiPartTypeUnusedGuid);
881 } else {
882 CopyGuid (&BootEntry->UniquePartitionGUID, &PartitionEntry->UniquePartitionGUID);
883 }
884 }
885
887 BootContext,
888 FileSystem,
889 BootEntry
890 );
891
892 return EFI_SUCCESS;
893}
894
909STATIC
910EFI_STATUS
912 IN OUT OC_BOOT_CONTEXT *BootContext,
913 IN OUT OC_BOOT_FILESYSTEM *FileSystem,
914 IN CONST CHAR16 **PredefinedPaths,
915 IN UINTN NumPredefinedPaths,
916 IN BOOLEAN LazyScan,
917 IN BOOLEAN Deduplicate
918 )
919{
920 EFI_STATUS Status;
921 EFI_STATUS PrimaryStatus;
922 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFs;
923 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
924 EFI_DEVICE_PATH_PROTOCOL *DevicePathWalker;
925 EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
926 UINTN NewDevicePathSize;
927 EFI_DEVICE_PATH_PROTOCOL *HdDevicePath;
928 UINTN HdPrefixSize;
929 INTN CmpResult;
930 EFI_FILE_PROTOCOL *Root;
931 CHAR16 *RecoveryPath;
932 EFI_FILE_PROTOCOL *RecoveryRoot;
933 EFI_HANDLE RecoveryDeviceHandle;
934
935 //
936 // We need to ensure that blessed device paths are on the same filesystem.
937 // Read the prefix path.
938 //
939 Status = gBS->HandleProtocol (
940 FileSystem->Handle,
942 (VOID **)&HdDevicePath
943 );
944 if (EFI_ERROR (Status)) {
945 return EFI_UNSUPPORTED;
946 }
947
948 DebugPrintDevicePath (DEBUG_INFO, "OCB: Adding bless entry on disk", HdDevicePath);
949
950 HdPrefixSize = GetDevicePathSize (HdDevicePath) - END_DEVICE_PATH_LENGTH;
951
952 //
953 // Custom bless paths have the priority, try to look them up first.
954 //
955 if (BootContext->PickerContext->NumCustomBootPaths > 0) {
956 Status = gBS->HandleProtocol (
957 FileSystem->Handle,
959 (VOID **)&SimpleFs
960 );
961
962 if (!EFI_ERROR (Status)) {
963 Status = SimpleFs->OpenVolume (SimpleFs, &Root);
964 if (!EFI_ERROR (Status)) {
966 FileSystem->Handle,
967 Root,
968 (CONST CHAR16 **)BootContext->PickerContext->CustomBootPaths,
969 BootContext->PickerContext->NumCustomBootPaths,
970 &DevicePath,
971 NULL
972 );
973
974 Root->Close (Root);
975 }
976 }
977 } else {
978 Status = EFI_NOT_FOUND;
979 }
980
981 //
982 // On failure obtain normal bless paths.
983 //
984 if (EFI_ERROR (Status)) {
986 FileSystem->Handle,
987 PredefinedPaths,
988 NumPredefinedPaths,
989 &DevicePath
990 );
991 }
992
993 //
994 // If both custom and normal found nothing, then nothing is blessed.
995 //
996 if (EFI_ERROR (Status)) {
997 return Status;
998 }
999
1000 //
1001 // Since blessed paths can be multiple (e.g. when more than one macOS is present in the container).
1002 //
1003 Status = EFI_NOT_FOUND;
1004 DevicePathWalker = DevicePath;
1005 while (TRUE) {
1006 NewDevicePath = GetNextDevicePathInstance (&DevicePathWalker, &NewDevicePathSize);
1007 if (NewDevicePath == NULL) {
1008 break;
1009 }
1010
1011 //
1012 // Blessed path is obviously too short.
1013 //
1014 if (NewDevicePathSize - END_DEVICE_PATH_LENGTH < HdPrefixSize) {
1015 FreePool (NewDevicePath);
1016 continue;
1017 }
1018
1019 //
1020 // Blessed path does not prefix filesystem path.
1021 //
1022 CmpResult = CompareMem (
1023 NewDevicePath,
1024 HdDevicePath,
1025 HdPrefixSize
1026 );
1027 if (CmpResult != 0) {
1028 DEBUG ((
1029 DEBUG_INFO,
1030 "OCB: Skipping handle %p instance due to self trust violation\n",
1031 FileSystem->Handle
1032 ));
1033
1035 DEBUG_INFO,
1036 "OCB: Disk DP",
1037 HdDevicePath
1038 );
1040 DEBUG_INFO,
1041 "OCB: Instance DP",
1042 NewDevicePath
1043 );
1044
1045 FreePool (NewDevicePath);
1046 continue;
1047 }
1048
1049 //
1050 // Add blessed device path.
1051 //
1052 PrimaryStatus = AddBootEntryOnFileSystem (
1053 BootContext,
1054 FileSystem,
1055 NewDevicePath,
1056 FALSE,
1057 Deduplicate
1058 );
1059 //
1060 // Cannot free the failed device path now as it may have recovery.
1061 //
1062
1063 //
1064 // If the partition contains recovery on itself or recoveries are not requested,
1065 // proceed to next entry.
1066 //
1067 // First part means that APFS recovery is irrelevant, these recoveries are actually
1068 // on a different partition, but can only be pointed from Preboot.
1069 // This way we will show any 'com.apple.recovery.boot' recovery physically present
1070 // on the partition no more than once.
1071 //
1072 if (FileSystem->HasSelfRecovery || BootContext->PickerContext->HideAuxiliary) {
1073 if (EFI_ERROR (PrimaryStatus)) {
1074 FreePool (NewDevicePath);
1075 }
1076
1077 Status = PrimaryStatus;
1078 continue;
1079 }
1080
1081 //
1082 // Now add APFS recovery (from Recovery partition) right afterwards if present.
1083 //
1085 NewDevicePath,
1086 L"\\",
1087 PredefinedPaths,
1088 NumPredefinedPaths,
1089 &RecoveryPath,
1090 &RecoveryRoot,
1091 &RecoveryDeviceHandle
1092 );
1093
1094 //
1095 // Can free the failed primary device path now.
1096 //
1097 if (EFI_ERROR (PrimaryStatus)) {
1098 FreePool (NewDevicePath);
1099 }
1100
1101 if (EFI_ERROR (Status)) {
1102 DEBUG ((DEBUG_INFO, "OCB: APFS recovery is not present - %r\n", Status));
1103 continue;
1104 }
1105
1106 RecoveryRoot->Close (RecoveryRoot);
1107
1108 //
1109 // Obtain recovery file system and ensure scan policy if it was not done before.
1110 //
1111 if (FileSystem->RecoveryFs == NULL) {
1112 FileSystem->RecoveryFs = InternalFileSystemForHandle (BootContext, RecoveryDeviceHandle, LazyScan, NULL);
1113 }
1114
1115 //
1116 // If new recovery is not on the same volume or not allowed, then something went wrong, skip it.
1117 // This is technically also a performance optimisation allowing us not to lookup recovery fs every time.
1118 //
1119 if ((FileSystem->RecoveryFs == NULL) || (FileSystem->RecoveryFs->Handle != RecoveryDeviceHandle)) {
1120 FreePool (RecoveryPath);
1121 continue;
1122 }
1123
1124 NewDevicePath = FileDevicePath (RecoveryDeviceHandle, RecoveryPath);
1125 FreePool (RecoveryPath);
1126 if (NewDevicePath == NULL) {
1127 continue;
1128 }
1129
1130 //
1131 // Add blessed device path.
1132 //
1133 Status = AddBootEntryOnFileSystem (
1134 BootContext,
1135 FileSystem,
1136 NewDevicePath,
1137 TRUE,
1138 Deduplicate
1139 );
1140 if (EFI_ERROR (Status)) {
1141 FreePool (NewDevicePath);
1142 }
1143 }
1144
1145 FreePool (DevicePath);
1146
1147 return Status;
1148}
1149
1158STATIC
1159EFI_STATUS
1161 IN OUT OC_BOOT_CONTEXT *BootContext,
1162 IN OUT OC_BOOT_FILESYSTEM *FileSystem
1163 )
1164{
1165 EFI_STATUS Status;
1166 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
1167
1168 //
1169 // If there is already one recovery (it may not be registered due to HideAuxiliary)
1170 // or if there is HideAuxiliary, do not add recoveries at all.
1171 //
1172 if (FileSystem->HasSelfRecovery || BootContext->PickerContext->HideAuxiliary) {
1173 return EFI_UNSUPPORTED;
1174 }
1175
1177 FileSystem->Handle,
1178 &DevicePath,
1179 FALSE
1180 );
1181 if (EFI_ERROR (Status)) {
1182 return Status;
1183 }
1184
1185 //
1186 // Returned device path is always on the same partition, thus no scan check.
1187 //
1188 Status = AddBootEntryOnFileSystem (
1189 BootContext,
1190 FileSystem,
1191 DevicePath,
1192 FALSE,
1193 FALSE
1194 );
1195
1196 if (EFI_ERROR (Status)) {
1197 FreePool (DevicePath);
1198 }
1199
1200 return Status;
1201}
1202
1221STATIC
1222EFI_STATUS
1224 IN OUT OC_BOOT_CONTEXT *BootContext,
1225 IN UINT16 BootOption,
1226 IN BOOLEAN LazyScan,
1227 IN OUT OC_BOOT_FILESYSTEM *CustomFileSystem,
1228 OUT UINT32 *CustomIndex, OPTIONAL
1229 IN EFI_HANDLE *EntryProtocolHandles,
1230 IN UINTN EntryProtocolHandleCount,
1231 OUT EFI_GUID *EntryProtocolPartuuid, OPTIONAL
1232 OUT CHAR16 **EntryProtocolId OPTIONAL
1233 )
1234{
1235 EFI_STATUS Status;
1236 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
1237 EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath;
1238 EFI_DEVICE_PATH_PROTOCOL *ExpandedDevicePath;
1239 EFI_HANDLE FileSystemHandle;
1240 OC_BOOT_FILESYSTEM *FileSystem;
1241 UINTN DevicePathSize;
1242 CHAR16 *TextDevicePath;
1243 INTN NumPatchedNodes;
1244 BOOLEAN IsAppleLegacy;
1245 BOOLEAN IsAppleLegacyHandled;
1246 BOOLEAN IsRoot;
1247 EFI_LOAD_OPTION *LoadOption;
1248 UINTN LoadOptionSize;
1249 UINT32 Index;
1250 INTN CmpResult;
1251 UINTN NoHandles;
1252 EFI_HANDLE *Handles;
1253
1254 CONST EFI_PARTITION_ENTRY *PartitionEntry;
1255 CONST OC_CUSTOM_BOOT_DEVICE_PATH *CustomDevPath;
1256 CONST OC_ENTRY_PROTOCOL_DEVICE_PATH *EntryProtocolDevPath;
1257
1258 DEBUG ((DEBUG_INFO, "OCB: Building entry from Boot%04x\n", BootOption));
1259
1260 //
1261 // Obtain original device path.
1262 // Discard load options for security reasons.
1263 // Also discard boot name to avoid confusion.
1264 //
1265 LoadOption = OcGetBootOptionData (
1266 &LoadOptionSize,
1267 BootOption,
1268 BootContext->BootVariableGuid
1269 );
1270 if (LoadOption == NULL) {
1271 return EFI_NOT_FOUND;
1272 }
1273
1274 DevicePath = InternalGetBootOptionPath (
1275 LoadOption,
1276 LoadOptionSize
1277 );
1278 if (DevicePath == NULL) {
1279 FreePool (LoadOption);
1280 return EFI_NOT_FOUND;
1281 }
1282
1283 //
1284 // Re-use the Load Option buffer for the Device Path.
1285 //
1286 CopyMem (LoadOption, DevicePath, LoadOption->FilePathListLength);
1287 DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)LoadOption;
1288
1289 //
1290 // Get BootCamp device path stored in special variable.
1291 // BootCamp device path will point to disk instead of partition.
1292 //
1293 IsAppleLegacy = InternalIsAppleLegacyLoadApp (DevicePath);
1294 if (IsAppleLegacy) {
1295 FreePool (DevicePath);
1296 Status = GetVariable2 (
1299 (VOID **)&DevicePath,
1300 &DevicePathSize
1301 );
1302
1303 if (EFI_ERROR (Status) || !IsDevicePathValid (DevicePath, DevicePathSize)) {
1304 DEBUG ((DEBUG_INFO, "OCB: Legacy DP invalid - %r\n", Status));
1305 if (!EFI_ERROR (Status)) {
1306 FreePool (DevicePath);
1307 }
1308
1309 return EFI_NOT_FOUND;
1310 } else {
1311 DebugPrintDevicePath (DEBUG_INFO, "OCB: Solved legacy DP", DevicePath);
1312 }
1313 }
1314
1315 FileSystem = NULL;
1316 IsRoot = FALSE;
1317
1318 //
1319 // Fixup device path if necessary.
1320 // WARN: DevicePath must be allocated from pool as it may be reallocated.
1321 //
1322 NumPatchedNodes = OcFixAppleBootDevicePath (
1323 &DevicePath,
1324 &RemainingDevicePath
1325 );
1326 if (NumPatchedNodes > 0) {
1327 //
1328 // DevicePath size may be different on successful update.
1329 //
1330 DevicePathSize = GetDevicePathSize (DevicePath);
1331 DebugPrintDevicePath (DEBUG_INFO, "OCB: Fixed DP", DevicePath);
1332 }
1333
1334 //
1335 // Expand BootCamp device path to EFI partition device path.
1336 //
1337 IsAppleLegacyHandled = FALSE;
1338 if (IsAppleLegacy) {
1339 //
1340 // BootCampHD always refers to a full Device Path. Failure to patch
1341 // indicates an invalid Device Path.
1342 //
1343 if (NumPatchedNodes == -1) {
1344 DEBUG ((DEBUG_INFO, "OCB: Ignoring broken legacy DP\n"));
1345 FreePool (DevicePath);
1346 return EFI_NOT_FOUND;
1347 }
1348
1349 //
1350 // Attempt to handle detected legacy OS via Apple legacy interface.
1351 //
1352 RemainingDevicePath = DevicePath;
1354 DevicePath,
1355 &DevicePathSize,
1356 &FileSystemHandle
1357 );
1358
1359 //
1360 // Disk with MBR or hybrid MBR was detected.
1361 //
1362 if (DevicePath != NULL) {
1363 TextDevicePath = ConvertDevicePathToText (DevicePath, FALSE, FALSE);
1364 if (TextDevicePath != NULL) {
1365 //
1366 // Add entry from externally provided legacy interface.
1367 // Boot entry ID must be active partition Device Path.
1368 //
1370 BootContext,
1371 CustomFileSystem,
1372 EntryProtocolHandles,
1373 EntryProtocolHandleCount,
1374 TextDevicePath,
1375 TRUE,
1376 FALSE
1377 );
1378 if (!EFI_ERROR (Status)) {
1379 if (EntryProtocolId != NULL) {
1380 *EntryProtocolId = TextDevicePath;
1381 }
1382
1383 FileSystem = CustomFileSystem;
1384 IsAppleLegacyHandled = TRUE;
1385 } else {
1386 FreePool (TextDevicePath);
1387 }
1388 }
1389 }
1390
1391 if (!IsAppleLegacyHandled) {
1392 //
1393 // Boot option was set to Apple legacy interface incorrectly by macOS.
1394 // This will occur on Macs that normally boot Windows in legacy mode,
1395 // but have Windows installed in UEFI mode.
1396 //
1397 // Locate the ESP from the BootCampHD Device Path instead.
1398 //
1399 DevicePath = OcDiskFindSystemPartitionPath (
1400 RemainingDevicePath,
1401 &DevicePathSize,
1402 &FileSystemHandle
1403 );
1404
1405 //
1406 // Ensure that we are allowed to boot from this filesystem.
1407 //
1408 if (DevicePath != NULL) {
1409 FileSystem = InternalFileSystemForHandle (BootContext, FileSystemHandle, LazyScan, NULL);
1410 if (FileSystem == NULL) {
1411 DevicePath = NULL;
1412 }
1413 }
1414 }
1415
1416 FreePool (RemainingDevicePath);
1417
1418 //
1419 // This is obviously always a Root Device Path.
1420 //
1421 IsRoot = TRUE;
1422
1423 //
1424 // The Device Path returned by OcDiskFindSystemPartitionPath() is a pointer
1425 // to an installed protocol. Duplicate it so we own the memory.
1426 //
1427 if (DevicePath != NULL) {
1428 DevicePath = AllocateCopyPool (DevicePathSize, DevicePath);
1429 }
1430
1431 if (DevicePath == NULL) {
1432 return EFI_NOT_FOUND;
1433 }
1434
1435 //
1436 // The Device Path must be entirely locatable (and hence full-form) as
1437 // OcDiskFindSystemPartitionPath() guarantees to only return valid paths.
1438 //
1439 ASSERT (DevicePathSize > END_DEVICE_PATH_LENGTH);
1440 DevicePathSize -= END_DEVICE_PATH_LENGTH;
1441 RemainingDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)((UINTN)DevicePath + DevicePathSize);
1442 } else if (DevicePath == RemainingDevicePath) {
1443 //
1444 // OcFixAppleBootDevicePath() did not advance the Device Path node, hence
1445 // it cannot be located at all and may be a short-form Device Path.
1446 // DevicePath has not been changed no matter success or failure.
1447 //
1448 DEBUG ((DEBUG_INFO, "OCB: Assuming DP is short-form (prefix)\n"));
1449
1450 //
1451 // Expand and on failure fix the Device Path till both yields no new result.
1452 //
1453 do {
1454 //
1455 // Expand the short-form Device Path.
1456 //
1457 ExpandedDevicePath = ExpandShortFormBootPath (
1458 BootContext,
1459 DevicePath,
1460 LazyScan,
1461 &FileSystem,
1462 &IsRoot
1463 );
1464 if (ExpandedDevicePath != NULL) {
1465 break;
1466 }
1467
1468 //
1469 // If short-form expansion failed, try to fix the short-form and re-try.
1470 // WARN: DevicePath must be allocated from pool here.
1471 //
1472 NumPatchedNodes = OcFixAppleBootDevicePathNode (
1473 &DevicePath,
1474 &RemainingDevicePath,
1475 NULL,
1476 NULL
1477 );
1478 } while (NumPatchedNodes > 0);
1479
1480 Status = EFI_NOT_FOUND;
1481 if ((ExpandedDevicePath == NULL) && (CustomFileSystem != NULL)) {
1482 //
1483 // If non-standard device path, attempt to pre-construct a user config
1484 // custom entry found in BOOT#### so it can be set as default.
1485 //
1486 ASSERT (CustomIndex == NULL || *CustomIndex == MAX_UINT32);
1487
1488 CustomDevPath = InternalGetOcCustomDevPath (DevicePath);
1489
1490 if (CustomDevPath != NULL) {
1491 for (Index = 0; Index < BootContext->PickerContext->AllCustomEntryCount; ++Index) {
1492 CmpResult = MixedStrCmp (
1493 CustomDevPath->EntryName.PathName,
1494 BootContext->PickerContext->CustomEntries[Index].Name
1495 );
1496 if (CmpResult == 0) {
1497 if (CustomIndex != NULL) {
1498 *CustomIndex = Index;
1499 }
1500
1502 BootContext,
1503 CustomFileSystem,
1504 &BootContext->PickerContext->CustomEntries[Index],
1505 FALSE
1506 );
1507 break;
1508 }
1509 }
1510 } else {
1511 //
1512 // If still unknown device path, attempt to pre-construct an entry protocol
1513 // entry found in BOOT#### so it can be set as default.
1514 //
1515 ASSERT (EntryProtocolId == NULL || *EntryProtocolId == NULL);
1516 ASSERT ((EntryProtocolPartuuid == NULL) == (EntryProtocolId == NULL));
1517
1518 EntryProtocolDevPath = InternalGetOcEntryProtocolDevPath (DevicePath);
1519
1520 if (EntryProtocolDevPath != NULL) {
1521 //
1522 // Zero GUID can be non-file-based entry (e.g. from network boot),
1523 // or file-based entry on OVMF mounted drives where GPT GUIDs are
1524 // not available. Try non-file-based first.
1525 //
1526 if (CompareGuid (&gEfiPartTypeUnusedGuid, &EntryProtocolDevPath->Partuuid)) {
1528 BootContext,
1529 CustomFileSystem,
1530 EntryProtocolHandles,
1531 EntryProtocolHandleCount,
1532 EntryProtocolDevPath->EntryName.PathName,
1533 TRUE,
1534 FALSE
1535 );
1536 if (!EFI_ERROR (Status)) {
1537 if (EntryProtocolPartuuid != NULL) {
1538 CopyGuid (EntryProtocolPartuuid, &gEfiPartTypeUnusedGuid);
1539 }
1540
1541 if (EntryProtocolId != NULL) {
1542 *EntryProtocolId = AllocateCopyPool (StrSize (EntryProtocolDevPath->EntryName.PathName), EntryProtocolDevPath->EntryName.PathName);
1543 }
1544
1545 EntryProtocolDevPath = NULL;
1546 }
1547 }
1548 }
1549
1550 if (EntryProtocolDevPath != NULL) {
1551 //
1552 // Search for ID on matching device only.
1553 // Note that on, e.g., OVMF, devices do not have PartitionEntry, therefore
1554 // the first matching entry protocol ID on any filesystem will match.
1555 //
1556 NoHandles = 0;
1557 Status = gBS->LocateHandleBuffer (
1558 ByProtocol,
1560 NULL,
1561 &NoHandles,
1562 &Handles
1563 );
1564
1565 if (!EFI_ERROR (Status)) {
1566 for (Index = 0; Index < NoHandles; ++Index) {
1567 PartitionEntry = OcGetGptPartitionEntry (Handles[Index]);
1568
1569 if (CompareGuid (
1570 (PartitionEntry == NULL) ? &gEfiPartTypeUnusedGuid : &PartitionEntry->UniquePartitionGUID,
1571 &EntryProtocolDevPath->Partuuid
1572 )
1573 )
1574 {
1575 FileSystem = InternalFileSystemForHandle (BootContext, Handles[Index], TRUE, NULL);
1576 if (FileSystem == NULL) {
1577 continue;
1578 }
1579
1581 BootContext,
1582 FileSystem,
1583 EntryProtocolHandles,
1584 EntryProtocolHandleCount,
1585 EntryProtocolDevPath->EntryName.PathName,
1586 TRUE,
1587 FALSE
1588 );
1589
1590 if (!EFI_ERROR (Status)) {
1591 if (EntryProtocolPartuuid != NULL) {
1592 if (PartitionEntry == NULL) {
1593 CopyGuid (EntryProtocolPartuuid, &gEfiPartTypeUnusedGuid);
1594 } else {
1595 CopyGuid (EntryProtocolPartuuid, &PartitionEntry->UniquePartitionGUID);
1596 }
1597 }
1598
1599 if (EntryProtocolId != NULL) {
1600 *EntryProtocolId = AllocateCopyPool (StrSize (EntryProtocolDevPath->EntryName.PathName), EntryProtocolDevPath->EntryName.PathName);
1601 //
1602 // If NULL allocated, just continue as if we had not matched.
1603 //
1604 }
1605
1606 break;
1607 }
1608 }
1609 }
1610
1611 FreePool (Handles);
1612 }
1613 }
1614 }
1615 }
1616
1617 FreePool (DevicePath);
1618 DevicePath = ExpandedDevicePath;
1619
1620 if (DevicePath == NULL) {
1621 return Status;
1622 }
1623 } else if (NumPatchedNodes == -1) {
1624 //
1625 // OcFixAppleBootDevicePath() advanced the Device Path node and yet failed
1626 // to locate the path, it is invalid.
1627 //
1628 DEBUG ((DEBUG_INFO, "OCB: Ignoring broken normal DP\n"));
1629 FreePool (DevicePath);
1630 return EFI_NOT_FOUND;
1631 } else {
1632 //
1633 // OcFixAppleBootDevicePath() advanced the Device Path node and succeeded
1634 // to locate the path, but it may still be a shot-form Device Path (lacking
1635 // a suffix rather than prefix).
1636 //
1637 DEBUG ((DEBUG_INFO, "OCB: Assuming DP is full-form or lacks suffix\n"));
1638
1639 RemainingDevicePath = DevicePath;
1640 DevicePath = ExpandShortFormBootPath (
1641 BootContext,
1642 RemainingDevicePath,
1643 LazyScan,
1644 &FileSystem,
1645 &IsRoot
1646 );
1647
1648 FreePool (RemainingDevicePath);
1649
1650 if (DevicePath == NULL) {
1651 return EFI_NOT_FOUND;
1652 }
1653 }
1654
1655 //
1656 // If we reached here we have a filesystem and device path.
1657 //
1658 ASSERT (FileSystem != NULL);
1659 ASSERT (DevicePath != NULL);
1660
1661 //
1662 // We have a complete device path, just add this entry.
1663 //
1664 if (!IsRoot) {
1665 Status = AddBootEntryOnFileSystem (
1666 BootContext,
1667 FileSystem,
1668 DevicePath,
1669 FALSE,
1670 TRUE
1671 );
1672 } else {
1673 Status = EFI_UNSUPPORTED;
1674 }
1675
1676 if (EFI_ERROR (Status)) {
1677 FreePool (DevicePath);
1678 }
1679
1680 if (IsAppleLegacyHandled) {
1681 return EFI_SUCCESS;
1682 }
1683
1684 //
1685 // We may have a Boot#### entry pointing to macOS with full DP (up to boot.efi),
1686 // so IsRoot will be true. However, if this is APFS, we may still have:
1687 // - Recovery for this macOS.
1688 // - Another macOS installation.
1689 // We can only detect them with bless, so we invoke bless in deduplication mode.
1690 // We also detect only the Core Apple Boot Policy predefined booter paths to
1691 // avoid detection of e.g. generic booters (such as BOOTx64) to avoid
1692 // duplicates.
1693 //
1694 // The amount of paths depends on the kind of the entry.
1695 // - If this is a root entry (i.e. it points to the partition)
1696 // we invoke full bless, as it may be Windows entry created by legacy NVRAM script.
1697 // - If this is a full entry (i.e. it points to the bootloader)
1698 // we invoke partial bless, which ignores BOOTx64.efi.
1699 // Ignoring BOOTx64.efi is important as we may already have bootmgfw.efi as our entry,
1700 // and we do not want to see Windows added twice.
1701 //
1702 Status = AddBootEntryFromBless (
1703 BootContext,
1704 FileSystem,
1707 LazyScan,
1708 TRUE
1709 );
1710
1711 return Status;
1712}
1713
1724STATIC
1725EFI_STATUS
1727 IN OUT OC_BOOT_CONTEXT *BootContext,
1728 IN EFI_HANDLE FileSystemHandle,
1729 OUT OC_BOOT_FILESYSTEM **FileSystemEntry OPTIONAL
1730 )
1731{
1732 EFI_STATUS Status;
1733 EFI_STATUS TmpStatus;
1734 BOOLEAN IsExternal;
1735 BOOLEAN LoaderFs;
1736 OC_BOOT_FILESYSTEM *Entry;
1737 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
1738 CHAR16 *TextDevicePath;
1739
1740 Status = InternalCheckScanPolicy (
1741 FileSystemHandle,
1742 BootContext->PickerContext->ScanPolicy,
1743 &IsExternal
1744 );
1745
1746 LoaderFs = BootContext->PickerContext->LoaderHandle == FileSystemHandle;
1747
1748 DEBUG_CODE_BEGIN ();
1749
1750 TmpStatus = gBS->HandleProtocol (
1751 FileSystemHandle,
1753 (VOID **)&DevicePath
1754 );
1755 if (!EFI_ERROR (TmpStatus)) {
1756 TextDevicePath = ConvertDevicePathToText (DevicePath, FALSE, FALSE);
1757 } else {
1758 TextDevicePath = NULL;
1759 }
1760
1761 DEBUG ((
1762 DEBUG_INFO,
1763 "OCB: Adding fs %p (E:%d|L:%d|P:%r) - %s\n",
1764 FileSystemHandle,
1765 IsExternal,
1766 LoaderFs,
1767 Status,
1768 OC_HUMAN_STRING (TextDevicePath)
1769 ));
1770
1771 if (TextDevicePath != NULL) {
1772 FreePool (TextDevicePath);
1773 }
1774
1775 DEBUG_CODE_END ();
1776
1777 if (EFI_ERROR (Status)) {
1778 return Status;
1779 }
1780
1781 Entry = AllocatePool (sizeof (*Entry));
1782 if (Entry == NULL) {
1783 return EFI_OUT_OF_RESOURCES;
1784 }
1785
1786 Entry->Handle = FileSystemHandle;
1787 InitializeListHead (&Entry->BootEntries);
1788 Entry->RecoveryFs = NULL;
1789 Entry->External = IsExternal;
1790 Entry->LoaderFs = LoaderFs;
1791 Entry->HasSelfRecovery = FALSE;
1792 InsertTailList (&BootContext->FileSystems, &Entry->Link);
1793 ++BootContext->FileSystemCount;
1794
1795 if (FileSystemEntry != NULL) {
1796 *FileSystemEntry = Entry;
1797 }
1798
1799 return EFI_SUCCESS;
1800}
1801
1802STATIC
1805 IN OUT CONST OC_BOOT_CONTEXT *BootContext
1806 )
1807{
1808 OC_BOOT_FILESYSTEM *FileSystem;
1809
1810 FileSystem = AllocateZeroPool (sizeof (*FileSystem));
1811 if (FileSystem == NULL) {
1812 return NULL;
1813 }
1814
1815 FileSystem->Handle = OC_CUSTOM_FS_HANDLE;
1816 InitializeListHead (&FileSystem->BootEntries);
1817
1818 DEBUG ((
1819 DEBUG_INFO,
1820 "OCB: Adding fs %p for %u custom entries and BEP%a\n",
1822 BootContext->PickerContext->AllCustomEntryCount,
1823 BootContext->PickerContext->HideAuxiliary ? " (aux hidden)" : " (aux shown)"
1824 ));
1825
1826 return FileSystem;
1827}
1828
1829//
1830// @retval EFI_SUCCESS One or more entries added.
1831// @retval EFI_NOT_FOUND No entries added.
1832//
1833STATIC
1834EFI_STATUS
1836 IN OUT OC_BOOT_CONTEXT *BootContext,
1837 IN OUT OC_BOOT_FILESYSTEM *FileSystem,
1838 IN UINT32 PrecreatedCustomIndex
1839 )
1840{
1841 EFI_STATUS ReturnStatus;
1842 EFI_STATUS Status;
1843 UINTN Index;
1844
1845 ReturnStatus = EFI_NOT_FOUND;
1846
1847 for (Index = 0; Index < BootContext->PickerContext->AllCustomEntryCount; ++Index) {
1848 //
1849 // Skip the custom boot entry that has already been created.
1850 //
1851 if (Index == PrecreatedCustomIndex) {
1852 continue;
1853 }
1854
1856 BootContext,
1857 FileSystem,
1858 &BootContext->PickerContext->CustomEntries[Index],
1859 FALSE
1860 );
1861
1862 if (!EFI_ERROR (Status)) {
1863 ReturnStatus = EFI_SUCCESS;
1864 }
1865 }
1866
1867 return ReturnStatus;
1868}
1869
1870STATIC
1871VOID
1873 IN OUT OC_BOOT_CONTEXT *BootContext,
1874 IN OC_BOOT_FILESYSTEM *FileSystemEntry
1875 )
1876{
1877 LIST_ENTRY *Link;
1878 OC_BOOT_ENTRY *BootEntry;
1879
1880 RemoveEntryList (&FileSystemEntry->Link);
1881 --BootContext->FileSystemCount;
1882
1883 while (!IsListEmpty (&FileSystemEntry->BootEntries)) {
1884 Link = GetFirstNode (&FileSystemEntry->BootEntries);
1885 BootEntry = BASE_CR (Link, OC_BOOT_ENTRY, Link);
1886 RemoveEntryList (Link);
1887 FreeBootEntry (BootEntry);
1888 }
1889
1890 FreePool (FileSystemEntry);
1891}
1892
1895 IN OC_BOOT_CONTEXT *BootContext,
1896 IN EFI_HANDLE FileSystemHandle,
1897 IN BOOLEAN LazyScan,
1898 OUT BOOLEAN *AlreadySeen OPTIONAL
1899 )
1900{
1901 EFI_STATUS Status;
1902 LIST_ENTRY *Link;
1903 OC_BOOT_FILESYSTEM *FileSystem;
1904
1905 if (AlreadySeen != NULL) {
1906 *AlreadySeen = FALSE;
1907 }
1908
1909 for (
1910 Link = GetFirstNode (&BootContext->FileSystems);
1911 !IsNull (&BootContext->FileSystems, Link);
1912 Link = GetNextNode (&BootContext->FileSystems, Link))
1913 {
1914 FileSystem = BASE_CR (Link, OC_BOOT_FILESYSTEM, Link);
1915
1916 if (FileSystem->Handle == FileSystemHandle) {
1917 DEBUG ((DEBUG_INFO, "OCB: Matched fs %p%a\n", FileSystemHandle, LazyScan ? " (lazy)" : ""));
1918 if (AlreadySeen != NULL) {
1919 *AlreadySeen = TRUE;
1920 }
1921
1922 return FileSystem;
1923 }
1924 }
1925
1926 //
1927 // Lazily check filesystem scan policy and add it in case it is ok.
1928 //
1929 if (!LazyScan) {
1930 DEBUG ((DEBUG_INFO, "OCB: Restricted fs %p access\n", FileSystemHandle));
1931 return NULL;
1932 }
1933
1934 Status = AddFileSystemEntry (BootContext, FileSystemHandle, &FileSystem);
1935 if (!EFI_ERROR (Status)) {
1936 return FileSystem;
1937 }
1938
1939 return NULL;
1940}
1941
1942STATIC
1945 IN OC_PICKER_CONTEXT *Context,
1946 IN BOOLEAN Empty
1947 )
1948{
1949 OC_BOOT_CONTEXT *BootContext;
1950 EFI_STATUS Status;
1951 UINTN NoHandles;
1952 EFI_HANDLE *Handles;
1953 UINTN Index;
1954
1955 BootContext = AllocatePool (sizeof (*BootContext));
1956 if (BootContext == NULL) {
1957 return NULL;
1958 }
1959
1960 BootContext->BootEntryCount = 0;
1961 BootContext->FileSystemCount = 0;
1962 InitializeListHead (&BootContext->FileSystems);
1963 if (Context->CustomBootGuid) {
1965 } else {
1967 }
1968
1969 BootContext->DefaultEntry = NULL;
1970 BootContext->PickerContext = Context;
1971
1972 if (Empty) {
1973 return BootContext;
1974 }
1975
1976 Status = gBS->LocateHandleBuffer (
1977 ByProtocol,
1979 NULL,
1980 &NoHandles,
1981 &Handles
1982 );
1983 if (EFI_ERROR (Status)) {
1984 return BootContext;
1985 }
1986
1987 for (Index = 0; Index < NoHandles; ++Index) {
1989 BootContext,
1990 Handles[Index],
1991 NULL
1992 );
1993 }
1994
1995 FreePool (Handles);
1996 return BootContext;
1997}
1998
1999VOID
2001 IN OUT OC_BOOT_CONTEXT *Context
2002 )
2003{
2004 LIST_ENTRY *Link;
2005 OC_BOOT_FILESYSTEM *FileSystem;
2006
2007 while (!IsListEmpty (&Context->FileSystems)) {
2008 Link = GetFirstNode (&Context->FileSystems);
2009 FileSystem = BASE_CR (Link, OC_BOOT_FILESYSTEM, Link);
2010 FreeFileSystemEntry (Context, FileSystem);
2011 }
2012
2013 FreePool (Context);
2014}
2015
2016EFI_STATUS
2018 IN OUT OC_BOOT_CONTEXT *BootContext
2019 )
2020{
2021 LIST_ENTRY *FsLink;
2022 OC_BOOT_FILESYSTEM *FileSystem;
2023 LIST_ENTRY *EnLink;
2024 OC_BOOT_ENTRY *BootEntry;
2025 OC_BOOT_ENTRY *FirstRecovery;
2026 OC_BOOT_ENTRY *RecoveryInitiator;
2027 BOOLEAN UseInitiator;
2028
2029 FirstRecovery = NULL;
2030 UseInitiator = BootContext->PickerContext->RecoveryInitiator != NULL;
2031
2032 //
2033 // This could technically use AppleBootPolicy recovery getting function,
2034 // but it will do extra disk i/o and will not work with HFS+ recovery.
2035 //
2036 for (
2037 FsLink = GetFirstNode (&BootContext->FileSystems);
2038 !IsNull (&BootContext->FileSystems, FsLink);
2039 FsLink = GetNextNode (&BootContext->FileSystems, FsLink))
2040 {
2041 FileSystem = BASE_CR (FsLink, OC_BOOT_FILESYSTEM, Link);
2042
2043 RecoveryInitiator = NULL;
2044
2045 for (
2046 EnLink = GetFirstNode (&FileSystem->BootEntries);
2047 !IsNull (&FileSystem->BootEntries, EnLink);
2048 EnLink = GetNextNode (&FileSystem->BootEntries, EnLink))
2049 {
2050 BootEntry = BASE_CR (EnLink, OC_BOOT_ENTRY, Link);
2051
2052 //
2053 // Record first found recovery in case we find nothing.
2054 //
2055 if ((FirstRecovery == NULL) && (BootEntry->Type == OC_BOOT_APPLE_RECOVERY)) {
2056 FirstRecovery = BootEntry;
2057 ASSERT (BootEntry->DevicePath != NULL);
2058
2059 if (!UseInitiator) {
2060 DebugPrintDevicePath (DEBUG_INFO, "OCB: Using first recovery path", BootEntry->DevicePath);
2061 BootContext->DefaultEntry = FirstRecovery;
2062 return EFI_SUCCESS;
2063 } else {
2064 DebugPrintDevicePath (DEBUG_INFO, "OCB: Storing first recovery path", BootEntry->DevicePath);
2065 }
2066 }
2067
2068 if ((RecoveryInitiator != NULL) && (BootEntry->Type == OC_BOOT_APPLE_RECOVERY)) {
2069 DebugPrintDevicePath (DEBUG_INFO, "OCB: Using initiator recovery path", BootEntry->DevicePath);
2070 BootContext->DefaultEntry = BootEntry;
2071 return EFI_SUCCESS;
2072 }
2073
2074 if ( (BootEntry->Type == OC_BOOT_APPLE_OS)
2075 && UseInitiator
2077 BootContext->PickerContext->RecoveryInitiator,
2078 BootEntry->DevicePath
2079 ))
2080 {
2081 DebugPrintDevicePath (DEBUG_INFO, "OCB: Found initiator", BootEntry->DevicePath);
2082 RecoveryInitiator = BootEntry;
2083 }
2084 }
2085
2086 if (RecoveryInitiator != NULL) {
2087 if (FirstRecovery != NULL) {
2088 DEBUG ((DEBUG_INFO, "OCB: Using first recovery path for no initiator"));
2089 BootContext->DefaultEntry = FirstRecovery;
2090 return EFI_SUCCESS;
2091 }
2092
2093 DEBUG ((DEBUG_INFO, "OCB: Looking for any first recovery due to no initiator"));
2094 UseInitiator = FALSE;
2095 }
2096 }
2097
2098 return EFI_NOT_FOUND;
2099}
2100
2103 IN OC_PICKER_CONTEXT *Context
2104 )
2105{
2106 OC_BOOT_CONTEXT *BootContext;
2107 UINTN Index;
2108 LIST_ENTRY *Link;
2109 OC_BOOT_FILESYSTEM *FileSystem;
2110 OC_BOOT_FILESYSTEM *CustomFileSystem;
2111 OC_BOOT_FILESYSTEM *CustomFileSystemDefault;
2112 UINT32 DefaultCustomIndex;
2113 CHAR16 *DefaultEntryId;
2114 EFI_GUID DefaultEntryPartuuid;
2115 BOOLEAN IsDefaultEntryProtocolPartition;
2116 EFI_HANDLE *EntryProtocolHandles;
2117 UINTN EntryProtocolHandleCount;
2118 CONST EFI_PARTITION_ENTRY *PartitionEntry;
2119
2120 //
2121 // Obtain the list of filesystems filtered by scan policy.
2122 //
2123 BootContext = BuildFileSystemList (
2124 Context,
2125 FALSE
2126 );
2127 if (BootContext == NULL) {
2128 return NULL;
2129 }
2130
2131 DEBUG ((DEBUG_INFO, "OCB: Found %u potentially bootable filesystems\n", (UINT32)BootContext->FileSystemCount));
2132
2133 //
2134 // Locate loaded boot entry protocol drivers.
2135 //
2136 OcLocateBootEntryProtocolHandles (&EntryProtocolHandles, &EntryProtocolHandleCount);
2137
2138 //
2139 // Create primary boot options from BootOrder.
2140 //
2141 if (Context->BootOrder == NULL) {
2142 Context->BootOrder = InternalGetBootOrderForBooting (
2143 BootContext->BootVariableGuid,
2144 Context->BlacklistAppleUpdate,
2145 &Context->BootOrderCount,
2146 FALSE
2147 );
2148 }
2149
2150 CustomFileSystem = CreateFileSystemForCustom (BootContext);
2151
2152 //
2153 // Delay CustomFileSystem insertion to have custom entries at the end.
2154 //
2155
2156 DefaultCustomIndex = MAX_UINT32;
2157 DefaultEntryId = NULL;
2158
2159 if (Context->BootOrder != NULL) {
2160 CustomFileSystemDefault = CustomFileSystem;
2161
2162 for (Index = 0; Index < Context->BootOrderCount; ++Index) {
2164 BootContext,
2165 Context->BootOrder[Index],
2166 FALSE,
2167 CustomFileSystemDefault,
2168 &DefaultCustomIndex,
2169 EntryProtocolHandles,
2170 EntryProtocolHandleCount,
2171 &DefaultEntryPartuuid,
2172 &DefaultEntryId
2173 );
2174
2175 //
2176 // Pre-create at most one custom entry. Under normal circumstances, no
2177 // more than one should exist as a boot option anyway.
2178 //
2179 if ((DefaultCustomIndex != MAX_UINT32) || (DefaultEntryId != NULL)) {
2180 CustomFileSystemDefault = NULL;
2181 }
2182 }
2183 }
2184
2185 DEBUG ((DEBUG_INFO, "OCB: Processing blessed list\n"));
2186
2187 //
2188 // Create primary boot options on filesystems without options
2189 // and alternate boot options on all filesystems.
2190 //
2191 for (
2192 Link = GetFirstNode (&BootContext->FileSystems);
2193 !IsNull (&BootContext->FileSystems, Link);
2194 Link = GetNextNode (&BootContext->FileSystems, Link))
2195 {
2196 FileSystem = BASE_CR (Link, OC_BOOT_FILESYSTEM, Link);
2197
2198 PartitionEntry = OcGetGptPartitionEntry (FileSystem->Handle);
2199 IsDefaultEntryProtocolPartition = (
2200 (DefaultEntryId != NULL)
2201 && CompareGuid (
2202 &DefaultEntryPartuuid,
2203 (PartitionEntry == NULL) ? &gEfiPartTypeUnusedGuid : &PartitionEntry->UniquePartitionGUID
2204 )
2205 );
2206
2207 //
2208 // No entries, or only entry pre-created from boot entry protocol,
2209 // so process this directory with Apple Bless.
2210 //
2211 if (IsDefaultEntryProtocolPartition || IsListEmpty (&FileSystem->BootEntries)) {
2213 BootContext,
2214 FileSystem,
2217 FALSE,
2218 FALSE
2219 );
2220 }
2221
2222 //
2223 // Try boot entry protocol.
2224 // Entry protocol entries are added regardless of bless; e.g. user might well
2225 // have /loader/entries in ESP, in addition to normal blessed files.
2226 // Skip any entry already created from boot options.
2227 //
2229 BootContext,
2230 FileSystem,
2231 EntryProtocolHandles,
2232 EntryProtocolHandleCount,
2233 IsDefaultEntryProtocolPartition ? DefaultEntryId : NULL,
2234 FALSE,
2235 FALSE
2236 );
2237
2238 //
2239 // Record predefined recoveries.
2240 //
2241 AddBootEntryFromSelfRecovery (BootContext, FileSystem);
2242 }
2243
2244 if (CustomFileSystem != NULL) {
2245 //
2246 // Insert the custom file system last for entry order.
2247 //
2248 InsertTailList (&BootContext->FileSystems, &CustomFileSystem->Link);
2249 ++BootContext->FileSystemCount;
2250
2251 //
2252 // Build custom and system options.
2253 //
2254 AddFileSystemEntryForCustom (BootContext, CustomFileSystem, DefaultCustomIndex);
2255
2256 //
2257 // Boot entry protocol also supports custom and system entries.
2258 //
2260 BootContext,
2261 CustomFileSystem,
2262 EntryProtocolHandles,
2263 EntryProtocolHandleCount,
2264 DefaultEntryId,
2265 FALSE,
2266 FALSE
2267 );
2268 }
2269
2270 if (DefaultEntryId != NULL) {
2271 FreePool (DefaultEntryId);
2272 DefaultEntryId = NULL;
2273 }
2274
2275 OcFreeBootEntryProtocolHandles (&EntryProtocolHandles);
2276
2277 if (BootContext->BootEntryCount == 0) {
2278 OcFreeBootContext (BootContext);
2279 return NULL;
2280 }
2281
2282 //
2283 // Find recovery.
2284 //
2286 OcSetDefaultBootRecovery (BootContext);
2287 }
2288
2289 return BootContext;
2290}
2291
2294 IN OC_PICKER_CONTEXT *Context,
2295 IN BOOLEAN UseBootNextOnly
2296 )
2297{
2298 OC_BOOT_CONTEXT *BootContext;
2299 UINTN Index;
2300 OC_BOOT_FILESYSTEM *FileSystem;
2301 BOOLEAN AlreadySeen;
2302 EFI_STATUS Status;
2303 UINTN NoHandles;
2304 EFI_HANDLE *Handles;
2305 OC_BOOT_FILESYSTEM *CustomFileSystem;
2306 EFI_HANDLE *EntryProtocolHandles;
2307 UINTN EntryProtocolHandleCount;
2308
2309 //
2310 // Obtain empty list of filesystems.
2311 //
2312 BootContext = BuildFileSystemList (Context, TRUE);
2313 if (BootContext == NULL) {
2314 return NULL;
2315 }
2316
2317 CustomFileSystem = CreateFileSystemForCustom (BootContext);
2318 if (CustomFileSystem != NULL) {
2319 //
2320 // The entry order does not matter, UI will not be shown.
2321 //
2322 InsertTailList (&BootContext->FileSystems, &CustomFileSystem->Link);
2323 ++BootContext->FileSystemCount;
2324 }
2325
2326 DEBUG ((DEBUG_INFO, "OCB: Looking for default entry (%d:%a)\n", Context->PickerCommand, Context->HotKeyEntryId));
2327
2328 if (Context->PickerCommand != OcPickerProtocolHotKey) {
2329 //
2330 // Locate loaded boot entry protocol drivers.
2331 //
2332 OcLocateBootEntryProtocolHandles (&EntryProtocolHandles, &EntryProtocolHandleCount);
2333
2334 //
2335 // Create primary boot options from BootOrder.
2336 //
2337 if (Context->BootOrder == NULL) {
2338 Context->BootOrder = InternalGetBootOrderForBooting (
2339 BootContext->BootVariableGuid,
2340 Context->BlacklistAppleUpdate,
2341 &Context->BootOrderCount,
2342 UseBootNextOnly
2343 );
2344 }
2345
2346 if (Context->BootOrder != NULL) {
2347 for (Index = 0; Index < Context->BootOrderCount; ++Index) {
2348 //
2349 // Returned default entry values not required, as no other
2350 // entries will be created after a match here.
2351 //
2353 BootContext,
2354 Context->BootOrder[Index],
2355 TRUE,
2356 CustomFileSystem,
2357 NULL,
2358 EntryProtocolHandles,
2359 EntryProtocolHandleCount,
2360 NULL,
2361 NULL
2362 );
2363
2364 //
2365 // Return as long as we are good.
2366 //
2367 if (BootContext->DefaultEntry != NULL) {
2368 OcFreeBootEntryProtocolHandles (&EntryProtocolHandles);
2369 return BootContext;
2370 }
2371 }
2372 }
2373
2374 if (UseBootNextOnly) {
2375 OcFreeBootEntryProtocolHandles (&EntryProtocolHandles);
2376 OcFreeBootContext (BootContext);
2377 return NULL;
2378 }
2379
2380 //
2381 // Obtain filesystems and try processing those remaining.
2382 //
2383 NoHandles = 0;
2384 Status = gBS->LocateHandleBuffer (
2385 ByProtocol,
2387 NULL,
2388 &NoHandles,
2389 &Handles
2390 );
2391
2392 DEBUG ((DEBUG_INFO, "OCB: Processing %u blessed list - %r\n", (UINT32)NoHandles, Status));
2393
2394 if (!EFI_ERROR (Status)) {
2395 for (Index = 0; Index < NoHandles; ++Index) {
2396 //
2397 // If file system has been seen during BOOT#### entry processing then
2398 // bless has already been processed (and failed or we would not be here).
2399 //
2400 FileSystem = InternalFileSystemForHandle (BootContext, Handles[Index], TRUE, &AlreadySeen);
2401 if (FileSystem == NULL) {
2402 continue;
2403 }
2404
2405 if (!AlreadySeen) {
2407 BootContext,
2408 FileSystem,
2411 FALSE,
2412 FALSE
2413 );
2414 if (BootContext->DefaultEntry != NULL) {
2415 OcFreeBootEntryProtocolHandles (&EntryProtocolHandles);
2416 FreePool (Handles);
2417 return BootContext;
2418 }
2419 }
2420
2421 //
2422 // Try boot entry protocol. No need to deduplicate as won't reach
2423 // here if default entry from BOOT#### was successfully created.
2424 //
2426 BootContext,
2427 FileSystem,
2428 EntryProtocolHandles,
2429 EntryProtocolHandleCount,
2430 NULL,
2431 FALSE,
2432 FALSE
2433 );
2434 if (BootContext->DefaultEntry != NULL) {
2435 OcFreeBootEntryProtocolHandles (&EntryProtocolHandles);
2436 FreePool (Handles);
2437 return BootContext;
2438 }
2439
2440 AddBootEntryFromSelfRecovery (BootContext, FileSystem);
2441 if (BootContext->DefaultEntry != NULL) {
2442 OcFreeBootEntryProtocolHandles (&EntryProtocolHandles);
2443 FreePool (Handles);
2444 return BootContext;
2445 }
2446 }
2447
2448 FreePool (Handles);
2449 }
2450
2451 if (CustomFileSystem != NULL) {
2452 //
2453 // Build custom and system options. Do not try to deduplicate custom options
2454 // as the list is never shown.
2455 //
2456 AddFileSystemEntryForCustom (BootContext, CustomFileSystem, MAX_UINT32);
2457 if (BootContext->DefaultEntry != NULL) {
2458 OcFreeBootEntryProtocolHandles (&EntryProtocolHandles);
2459 return BootContext;
2460 }
2461
2462 //
2463 // Boot entry protocol for custom and system entries.
2464 //
2466 BootContext,
2467 CustomFileSystem,
2468 EntryProtocolHandles,
2469 EntryProtocolHandleCount,
2470 NULL,
2471 FALSE,
2472 FALSE
2473 );
2474 }
2475
2476 OcFreeBootEntryProtocolHandles (&EntryProtocolHandles);
2477 } else {
2478 //
2479 // Filter boot entry protocol entries from selected protocol instance only for hotkey entry.
2480 //
2482 BootContext,
2483 CustomFileSystem,
2484 &Context->HotKeyProtocolHandle,
2485 1,
2486 Context->HotKeyEntryId,
2487 TRUE,
2488 TRUE
2489 );
2490 if (EFI_ERROR (Status)) {
2491 DEBUG ((DEBUG_WARN, "OCB: Missing boot entry protocol entry for hotkey %a - %r\n", Context->HotKeyEntryId, Status));
2492 }
2493 }
2494
2495 if (BootContext->DefaultEntry == NULL) {
2496 OcFreeBootContext (BootContext);
2497 return NULL;
2498 }
2499
2500 ASSERT (BootContext->BootEntryCount > 0);
2501
2502 return BootContext;
2503}
2504
2507 IN OC_BOOT_CONTEXT *BootContext
2508 )
2509{
2510 OC_BOOT_ENTRY **Entries;
2511 UINT32 EntryIndex;
2512 LIST_ENTRY *FsLink;
2513 OC_BOOT_FILESYSTEM *FileSystem;
2514 LIST_ENTRY *EnLink;
2515 OC_BOOT_ENTRY *BootEntry;
2516
2517 Entries = AllocatePool (sizeof (*Entries) * BootContext->BootEntryCount);
2518 if (Entries == NULL) {
2519 return NULL;
2520 }
2521
2522 EntryIndex = 0;
2523 for (
2524 FsLink = GetFirstNode (&BootContext->FileSystems);
2525 !IsNull (&BootContext->FileSystems, FsLink);
2526 FsLink = GetNextNode (&BootContext->FileSystems, FsLink))
2527 {
2528 FileSystem = BASE_CR (FsLink, OC_BOOT_FILESYSTEM, Link);
2529
2530 for (
2531 EnLink = GetFirstNode (&FileSystem->BootEntries);
2532 !IsNull (&FileSystem->BootEntries, EnLink);
2533 EnLink = GetNextNode (&FileSystem->BootEntries, EnLink))
2534 {
2535 BootEntry = BASE_CR (EnLink, OC_BOOT_ENTRY, Link);
2536
2537 ASSERT (EntryIndex < BootContext->BootEntryCount);
2538 Entries[EntryIndex] = BootEntry;
2539 BootEntry->EntryIndex = ++EntryIndex;
2540 }
2541 }
2542
2543 ASSERT (EntryIndex == BootContext->BootEntryCount);
2544 ASSERT (BootContext->DefaultEntry == NULL || BootContext->DefaultEntry->EntryIndex > 0);
2545 return Entries;
2546}
2547
2548EFI_STATUS
2550 IN OC_PICKER_CONTEXT *Context,
2551 IN OC_BOOT_ENTRY *BootEntry,
2552 IN EFI_HANDLE ParentHandle
2553 )
2554{
2555 EFI_STATUS Status;
2556 EFI_HANDLE EntryHandle;
2557 INTERNAL_DMG_LOAD_CONTEXT DmgLoadContext;
2558 VOID *CustomFreeContext;
2559
2560 if ((BootEntry->Type & OC_BOOT_UNMANAGED) != 0) {
2561 ASSERT (BootEntry->UnmanagedBootAction != NULL);
2562 return BootEntry->UnmanagedBootAction (Context, BootEntry->DevicePath);
2563 }
2564
2565 if ((BootEntry->Type & OC_BOOT_SYSTEM) != 0) {
2566 ASSERT (BootEntry->SystemAction != NULL);
2567 return BootEntry->SystemAction (Context);
2568 }
2569
2570 Status = InternalLoadBootEntry (
2571 Context,
2572 BootEntry,
2573 ParentHandle,
2574 &EntryHandle,
2575 &DmgLoadContext,
2576 &CustomFreeContext
2577 );
2578 if (!EFI_ERROR (Status)) {
2579 //
2580 // This does nothing unless emulated NVRAM is present. A hack, basically, to allow us
2581 // to switch back to the normal macOS boot entry after booting a macOS Installer once,
2582 // because we have nothing available to correctly update the emulated NVRAM file while
2583 // the macOS installer is running and rebooting. This strategy is correct, often, and
2584 // better then the alternative (continuing to create an installer entry when it no longer
2585 // exists) in any event. See OpenVariableRuntimeDxe documentation for more details.
2586 //
2587 if (BootEntry->IsAppleInstaller) {
2589 }
2590
2591 Status = Context->StartImage (BootEntry, EntryHandle, NULL, NULL, BootEntry->LaunchInText);
2592 if (EFI_ERROR (Status)) {
2593 DEBUG ((DEBUG_WARN, "OCB: StartImage failed - %r\n", Status));
2594 //
2595 // Unload image.
2596 // Note: This is not needed on success, since this has already been done
2597 // and image handle is now invalid, if image was an application and it
2598 // exited successfully:
2599 // https://github.com/tianocore/edk2/blob/a3aab12c34dba35d1fd592f4939cb70617668f7e/MdeModulePkg/Core/Dxe/Image/Image.c#L1789-L1793
2600 //
2601 gBS->UnloadImage (EntryHandle);
2602 }
2603
2604 //
2605 // Unload dmg if any.
2606 //
2607 InternalUnloadDmg (&DmgLoadContext);
2608 //
2609 // Unload any entry protocol custom items.
2610 // For instance HTTP Boot natively supported RAM disk, on loading .iso or .img.
2611 //
2612 if (BootEntry->CustomFree != NULL) {
2613 BootEntry->CustomFree (CustomFreeContext);
2614 }
2615 } else {
2616 DEBUG ((DEBUG_WARN, "OCB: LoadImage failed - %r\n", Status));
2617 }
2618
2619 return Status;
2620}
EFI_GUID gAppleBootVariableGuid
#define APPLE_BOOT_CAMP_HD_VARIABLE_NAME
EFI_STATUS InternalGetRecoveryOsBooter(IN EFI_HANDLE Device, OUT EFI_DEVICE_PATH_PROTOCOL **FilePath, IN BOOLEAN Basic)
EFI_STATUS InternalDescribeBootEntry(IN OC_BOOT_CONTEXT *BootContext, IN OUT OC_BOOT_ENTRY *BootEntry)
CHAR8 * InternalGetContentFlavour(IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FileSystem, IN CONST CHAR16 *BootDirectoryName)
STATIC EFI_DEVICE_PATH_PROTOCOL * ExpandShortFormBootPath(IN OC_BOOT_CONTEXT *BootContext, IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, IN BOOLEAN LazyScan, OUT OC_BOOT_FILESYSTEM **FileSystem, OUT BOOLEAN *IsRoot)
EFI_STATUS OcSetDefaultBootRecovery(IN OUT OC_BOOT_CONTEXT *BootContext)
STATIC VOID FreeFileSystemEntry(IN OUT OC_BOOT_CONTEXT *BootContext, IN OC_BOOT_FILESYSTEM *FileSystemEntry)
OC_BOOT_FILESYSTEM * InternalFileSystemForHandle(IN OC_BOOT_CONTEXT *BootContext, IN EFI_HANDLE FileSystemHandle, IN BOOLEAN LazyScan, OUT BOOLEAN *AlreadySeen OPTIONAL)
STATIC VOID FreeBootEntry(IN OC_BOOT_ENTRY *BootEntry)
STATIC EFI_STATUS AddBootEntryOnFileSystem(IN OUT OC_BOOT_CONTEXT *BootContext, IN OUT OC_BOOT_FILESYSTEM *FileSystem, IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, IN BOOLEAN RecoveryPart, IN BOOLEAN Deduplicate)
OC_BOOT_CONTEXT * OcScanForBootEntries(IN OC_PICKER_CONTEXT *Context)
OC_BOOT_CONTEXT * OcScanForDefaultBootEntry(IN OC_PICKER_CONTEXT *Context, IN BOOLEAN UseBootNextOnly)
STATIC EFI_STATUS AddBootEntryFromBless(IN OUT OC_BOOT_CONTEXT *BootContext, IN OUT OC_BOOT_FILESYSTEM *FileSystem, IN CONST CHAR16 **PredefinedPaths, IN UINTN NumPredefinedPaths, IN BOOLEAN LazyScan, IN BOOLEAN Deduplicate)
STATIC EFI_STATUS AddBootEntryFromBootOption(IN OUT OC_BOOT_CONTEXT *BootContext, IN UINT16 BootOption, IN BOOLEAN LazyScan, IN OUT OC_BOOT_FILESYSTEM *CustomFileSystem, OUT UINT32 *CustomIndex, OPTIONAL IN EFI_HANDLE *EntryProtocolHandles, IN UINTN EntryProtocolHandleCount, OUT EFI_GUID *EntryProtocolPartuuid, OPTIONAL OUT CHAR16 **EntryProtocolId OPTIONAL)
STATIC OC_BOOT_CONTEXT * BuildFileSystemList(IN OC_PICKER_CONTEXT *Context, IN BOOLEAN Empty)
STATIC OC_BOOT_FILESYSTEM * CreateFileSystemForCustom(IN OUT CONST OC_BOOT_CONTEXT *BootContext)
STATIC EFI_STATUS AddBootEntryFromSelfRecovery(IN OUT OC_BOOT_CONTEXT *BootContext, IN OUT OC_BOOT_FILESYSTEM *FileSystem)
STATIC EFI_STATUS AddFileSystemEntryForCustom(IN OUT OC_BOOT_CONTEXT *BootContext, IN OUT OC_BOOT_FILESYSTEM *FileSystem, IN UINT32 PrecreatedCustomIndex)
EFI_STATUS InternalAddBootEntryFromCustomEntry(IN OUT OC_BOOT_CONTEXT *BootContext, IN OUT OC_BOOT_FILESYSTEM *FileSystem, IN OC_PICKER_ENTRY *CustomEntry, IN BOOLEAN IsBootEntryProtocol)
STATIC VOID RegisterBootOption(IN OUT OC_BOOT_CONTEXT *BootContext, IN OUT OC_BOOT_FILESYSTEM *FileSystem, IN OC_BOOT_ENTRY *BootEntry)
STATIC INTERNAL_ENTRY_VISIBILITY ReadEntryVisibility(IN OC_PICKER_CONTEXT *Context, IN EFI_DEVICE_PATH_PROTOCOL *DevicePath)
OC_BOOT_ENTRY ** OcEnumerateEntries(IN OC_BOOT_CONTEXT *BootContext)
STATIC EFI_STATUS AddFileSystemEntry(IN OUT OC_BOOT_CONTEXT *BootContext, IN EFI_HANDLE FileSystemHandle, OUT OC_BOOT_FILESYSTEM **FileSystemEntry OPTIONAL)
EFI_STATUS OcLoadBootEntry(IN OC_PICKER_CONTEXT *Context, IN OC_BOOT_ENTRY *BootEntry, IN EFI_HANDLE ParentHandle)
VOID OcFreeBootContext(IN OUT OC_BOOT_CONTEXT *Context)
#define OC_CUSTOM_FS_HANDLE
CONST OC_ENTRY_PROTOCOL_DEVICE_PATH * InternalGetOcEntryProtocolDevPath(IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath)
PACKED struct @90 OC_ENTRY_PROTOCOL_DEVICE_PATH
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)
INTERNAL_ENTRY_VISIBILITY
@ BootEntryAuxiliary
@ BootEntryDisabled
PACKED struct @89 OC_CUSTOM_BOOT_DEVICE_PATH
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)
BOOLEAN InternalIsAppleLegacyLoadApp(IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath)
CONST OC_CUSTOM_BOOT_DEVICE_PATH * InternalGetOcCustomDevPath(IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath)
EFI_STATUS InternalCheckScanPolicy(IN EFI_HANDLE Handle, IN UINT32 Policy, OUT BOOLEAN *External OPTIONAL)
VOID InternalUnloadDmg(IN INTERNAL_DMG_LOAD_CONTEXT *DmgLoadContext)
CONST CHAR16 * gAppleBootPolicyPredefinedPaths[]
CONST UINTN gAppleBootPolicyNumPredefinedPaths
EFI_STATUS OcGetBooterFromPredefinedPathList(IN EFI_HANDLE Device, IN EFI_FILE_PROTOCOL *Root, IN CONST CHAR16 **PredefinedPaths, IN UINTN NumPredefinedPaths, OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath OPTIONAL, IN CHAR16 *Prefix OPTIONAL)
EFI_STATUS OcBootPolicyGetBootFileEx(IN EFI_HANDLE Device, IN CONST CHAR16 **PredefinedPaths, IN UINTN NumPredefinedPaths, OUT EFI_DEVICE_PATH_PROTOCOL **FilePath)
EFI_STATUS OcBootPolicyDevicePathToDirPath(IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, OUT CHAR16 **BootPathName, OUT EFI_SIMPLE_FILE_SYSTEM_PROTOCOL **FileSystem)
EFI_STATUS OcBootPolicyGetApfsRecoveryFilePath(IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, IN CONST CHAR16 *PathName, IN CONST CHAR16 **PredefinedPaths, IN UINTN NumPredefinedPaths, OUT CHAR16 **FullPathName, OUT EFI_FILE_PROTOCOL **Root, OUT EFI_HANDLE *DeviceHandle)
CONST UINTN gAppleBootPolicyCoreNumPredefinedPaths
CHAR16 PathName[DMG_FILE_PATH_LEN]
DMG_FILEPATH_DEVICE_PATH FilePath
@ OcPickerBootAppleRecovery
@ OcPickerProtocolHotKey
@ OcPickerBootApple
VOID OcLocateBootEntryProtocolHandles(IN OUT EFI_HANDLE **EntryProtocolHandles, IN OUT UINTN *EntryProtocolHandleCount)
#define OC_BOOT_APPLE_TIME_MACHINE
#define OC_BOOT_EXTERNAL_TOOL
VOID OcFreeBootEntryProtocolHandles(EFI_HANDLE **EntryProtocolHandles)
#define OC_BOOT_EXTERNAL_OS
EFI_STATUS EFIAPI OcGetBootEntryFileFromDevicePath(IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, IN CONST CHAR16 *FileName, IN CONST CHAR8 *DebugFileType, IN UINT32 MaxFileSize, IN UINT32 MinFileSize, OUT VOID **FileData, OUT UINT32 *DataLength OPTIONAL, IN BOOLEAN SearchAtLeaf, IN BOOLEAN SearchAtRoot)
UINT32 OC_BOOT_ENTRY_TYPE
#define OC_ATTR_USE_FLAVOUR_ICON
OC_BOOT_ENTRY_TYPE OcGetBootDevicePathType(IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, OUT BOOLEAN *IsFolder OPTIONAL, OUT BOOLEAN *IsGeneric OPTIONAL)
@ OcDmgLoadingDisabled
#define OC_BOOT_APPLE_RECOVERY
#define OC_FLAVOUR_AUTO
#define OC_BOOT_APPLE_OS
#define OC_MAX_CONTENT_VISIBILITY_SIZE
#define OC_BOOT_UNMANAGED
EFI_STATUS OcAddEntriesFromBootEntryProtocol(IN OUT OC_BOOT_CONTEXT *BootContext, IN OUT OC_BOOT_FILESYSTEM *FileSystem, IN EFI_HANDLE *EntryProtocolHandles, IN UINTN EntryProtocolHandleCount, IN CONST VOID *DefaultEntryId, OPTIONAL IN BOOLEAN CreateDefault, IN BOOLEAN CreateForHotKey)
#define OC_BOOT_SYSTEM
EFI_BOOT_SERVICES * gBS
#define OC_HUMAN_STRING(TextDevicePath)
VOID DebugPrintDevicePath(IN UINTN ErrorLevel, IN CONST CHAR8 *Message, IN EFI_DEVICE_PATH_PROTOCOL *DevicePath OPTIONAL)
EFI_DEVICE_PATH_PROTOCOL * OcGetNextLoadOptionDevicePath(IN EFI_DEVICE_PATH_PROTOCOL *FilePath, IN EFI_DEVICE_PATH_PROTOCOL *FullPath)
INTN OcFixAppleBootDevicePath(IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath, OUT EFI_DEVICE_PATH_PROTOCOL **RemainingDevicePath)
UINTN OcFileDevicePathNameSize(IN CONST FILEPATH_DEVICE_PATH *FilePath)
INTN OcFixAppleBootDevicePathNode(IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath, IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNode, OUT APPLE_BOOT_DP_PATCH_CONTEXT *RestoreContext OPTIONAL, IN EFI_HANDLE ValidDevice OPTIONAL)
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)
EFI_DEVICE_PATH_PROTOCOL * OcDiskFindSystemPartitionPath(IN CONST EFI_DEVICE_PATH_PROTOCOL *DiskDevicePath, OUT UINTN *EspDevicePathSize, OUT EFI_HANDLE *EspDeviceHandle)
Definition DiskMisc.c:458
VOID * OcGetFileInfo(IN EFI_FILE_PROTOCOL *File, IN EFI_GUID *InformationType, IN UINTN MinFileInfoSize, OUT UINTN *RealFileInfoSize OPTIONAL)
Definition GetFileInfo.c:33
EFI_DEVICE_PATH_PROTOCOL * OcDiskFindActiveMbrPartitionPath(IN EFI_DEVICE_PATH_PROTOCOL *DiskDevicePath, OUT UINTN *PartitionDevicePathSize, OUT EFI_HANDLE *PartitionDeviceHandle)
Definition DiskMisc.c:1057
CONST EFI_PARTITION_ENTRY * OcGetGptPartitionEntry(IN EFI_HANDLE FsHandle)
Definition DiskMisc.c:732
EFI_STATUS EFIAPI OcOpenFileByRemainingDevicePath(IN EFI_HANDLE FileSystemHandle, IN CONST EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath, OUT EFI_FILE_PROTOCOL **File, IN UINT64 OpenMode, IN UINT64 Attributes)
Definition OpenFile.c:83
INTN MixedStrCmp(IN CONST CHAR16 *FirstString, IN CONST CHAR8 *SecondString)
VOID UnicodeUefiSlashes(IN OUT CHAR16 *String)
CHAR16 * AsciiStrCopyToUnicode(IN CONST CHAR8 *String, IN UINTN Length)
Definition OcAsciiLib.c:119
EFI_GUID gOcVendorVariableGuid
VOID EFIAPI OcSwitchToFallbackLegacyNvram(VOID)
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)
GUID *EFIAPI CopyGuid(OUT GUID *DestinationGuid, IN CONST GUID *SourceGuid)
EFI_GUID gEfiFileInfoGuid
EFI_GUID gEfiSimpleFileSystemProtocolGuid
EFI_GUID gEfiGlobalVariableGuid
EFI_GUID gEfiDevicePathProtocolGuid
#define ASSERT(x)
Definition coder.h:55
OC_BOOT_ENTRY * DefaultEntry
OC_PICKER_CONTEXT * PickerContext
OC_BOOT_SYSTEM_ACTION SystemAction
EFI_DEVICE_PATH_PROTOCOL * DevicePath
OC_CUSTOM_READ CustomRead
OC_BOOT_UNMANAGED_ACTION UnmanagedBootAction
OC_BOOT_ENTRY_TYPE Type
OC_CUSTOM_FREE CustomFree
OC_BOOT_UNMANAGED_GET_FINAL_DP UnmanagedBootGetFinalDevicePath
OC_BOOT_FILESYSTEM * RecoveryFs