2 * COPYRIGHT: See COPYING.ARM in the top level directory
3 * PROJECT: ReactOS UEFI Boot Manager
4 * FILE: boot/environ/app/bootmgr/bootmgr.cla
5 * PURPOSE: Boot Manager Entrypoint
6 * PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
9 /* INCLUDES ******************************************************************/
13 /* DATA VARIABLES ************************************************************/
15 DEFINE_GUID(GUID_WINDOWS_BOOTMGR
,
19 0xAC, 0xC1, 0xF3, 0x2B, 0x34, 0x4D, 0x47, 0x95);
21 ULONGLONG ApplicationStartTime
;
23 GUID BmApplicationIdentifier
;
26 BL_BOOT_ERROR BmpErrorBuffer
;
27 PBL_BOOT_ERROR BmpInternalBootError
;
28 BL_PACKED_BOOT_ERROR BmpPackedBootError
;
30 BOOLEAN BmBootIniUsed
;
31 WCHAR BmpFileNameBuffer
[128];
32 PWCHAR ParentFileName
= L
"";
34 BOOLEAN BmDisplayStateCached
;
35 PBL_LOADED_APPLICATION_ENTRY
* BmpFailedBootEntries
;
36 PBL_LOADED_APPLICATION_ENTRY BmpSelectedBootEntry
;
37 BOOLEAN BmBootEntryOverridePresent
;
38 BOOLEAN BmpDisplayBootMenu
;
40 /* FUNCTIONS *****************************************************************/
44 _In_ HANDLE BcdHandle
,
46 _In_ PBL_BCD_OPTION
*OptionList
51 ULONG ElementSize
, ElementCount
, i
, OptionsSize
;
53 PBCD_ELEMENT_HEADER Header
;
54 PBCD_ELEMENT BcdElements
;
55 PBL_BCD_OPTION Options
, Option
, PreviousOption
, DeviceOptions
;
56 PBCD_DEVICE_OPTION DeviceOption
;
60 /* Open the BCD object requested */
63 Status
= BcdOpenObject(BcdHandle
, ObjectId
, &ObjectHandle
);
64 if (!NT_SUCCESS(Status
))
69 /* Do the initial enumeration to get the size needed */
71 Status
= BcdEnumerateAndUnpackElements(BcdHandle
,
76 if (Status
!= STATUS_BUFFER_TOO_SMALL
)
78 /* If we got success, that doesn't make any sense */
79 if (NT_SUCCESS(Status
))
81 Status
= STATUS_INVALID_PARAMETER
;
88 /* Allocate a large-enough buffer */
89 BcdElements
= BlMmAllocateHeap(ElementSize
);
92 Status
= STATUS_NO_MEMORY
;
96 /* Now do the real enumeration to fill out the elements buffer */
97 Status
= BcdEnumerateAndUnpackElements(BcdHandle
,
102 if (!NT_SUCCESS(Status
))
107 /* Go through each BCD option to add the sizes up */
109 for (i
= 0; i
< ElementCount
; i
++)
111 OptionsSize
+= BcdElements
[i
].Header
->Size
+ sizeof(BL_BCD_OPTION
);
114 /* Allocate the required BCD option list */
115 Options
= BlMmAllocateHeap(OptionsSize
);
118 Status
= STATUS_NO_MEMORY
;
123 RtlZeroMemory(Options
, OptionsSize
);
125 /* Start going through each option */
126 PreviousOption
= NULL
;
128 for (i
= 0; i
< ElementCount
; i
++)
130 /* Read the header and type */
131 Header
= BcdElements
[i
].Header
;
132 Type
.PackedValue
= Header
->Type
;
134 /* Check if this option isn't already present */
135 if (!MiscGetBootOption(Options
, Type
.PackedValue
))
137 /* It's a new option. Did we have an existing one? */
140 /* Link it to this new one */
141 PreviousOption
->NextEntryOffset
= (ULONG_PTR
)Option
-
145 /* Capture the type, size, data, and offset */
146 Option
->Type
= Type
.PackedValue
;
147 Option
->DataSize
= Header
->Size
;
148 RtlCopyMemory(Option
+ 1, BcdElements
[i
].Body
, Header
->Size
);
149 Option
->DataOffset
= sizeof(BL_BCD_OPTION
);
151 /* Check if this was a device */
152 if (Type
.Format
== BCD_TYPE_DEVICE
)
155 DeviceOption
= (PBCD_DEVICE_OPTION
)(Option
+ 1);
156 DeviceId
= DeviceOption
->AssociatedEntry
;
158 /* Look up the options for that GUID */
159 Status
= BmGetOptionList(BcdHandle
, &DeviceId
, &DeviceOptions
);
160 if (NT_SUCCESS(Status
))
162 /* Device data is after the device option */
163 DeviceData
= (PVOID
)((ULONG_PTR
)DeviceOption
+ Header
->Size
);
166 RtlCopyMemory(DeviceData
,
168 BlGetBootOptionListSize(DeviceOptions
));
170 /* Don't need this anymore */
171 BlMmFreeHeap(DeviceOptions
);
173 /* Write the offset of the device options */
174 Option
->ListOffset
= (ULONG_PTR
)DeviceData
-
179 /* Save the previous option and go to the next one */
180 PreviousOption
= Option
;
181 Option
= (PBL_BCD_OPTION
)((ULONG_PTR
)Option
+
182 BlGetBootOptionSize(Option
));
186 /* Return the pointer back, we've made it! */
187 *OptionList
= Options
;
188 Status
= STATUS_SUCCESS
;
191 /* Did we allocate a local buffer? Free it if so */
194 BlMmFreeHeap(BcdElements
);
197 /* Was the key open? Close it if so */
200 BiCloseKey(ObjectHandle
);
203 /* Return the option list parsing status */
208 BmpUpdateApplicationOptions (
209 _In_ HANDLE BcdHandle
213 PBL_BCD_OPTION Options
;
215 /* Get the boot option list */
216 Status
= BmGetOptionList(BcdHandle
, &BmApplicationIdentifier
, &Options
);
217 if (!NT_SUCCESS(Status
))
222 /* Append the options, free the local buffer, and return success */
223 BlAppendBootOptions(&BlpApplicationEntry
, Options
);
224 BlMmFreeHeap(Options
);
225 return STATUS_SUCCESS
;
229 BmpFwGetApplicationDirectoryPath (
230 _In_ PUNICODE_STRING ApplicationDirectoryPath
234 ULONG i
, AppPathLength
;
235 PWCHAR ApplicationPath
, PathCopy
;
237 /* Clear the incoming string */
238 ApplicationDirectoryPath
->Length
= 0;
239 ApplicationDirectoryPath
->MaximumLength
= 0;
240 ApplicationDirectoryPath
->Buffer
= 0;
242 /* Get the boot application path */
243 ApplicationPath
= NULL
;
244 Status
= BlGetBootOptionString(BlpApplicationEntry
.BcdData
,
245 BcdLibraryString_ApplicationPath
,
247 if (NT_SUCCESS(Status
))
249 /* Calculate the length of the application path */
250 for (i
= wcslen(ApplicationPath
) - 1; i
> 0; i
--)
252 /* Keep going until the path separator */
253 if (ApplicationPath
[i
] == OBJ_NAME_PATH_SEPARATOR
)
259 /* Check if we have space for one more character */
260 Status
= RtlULongAdd(i
, 1, &AppPathLength
);
261 if (NT_SUCCESS(Status
))
263 /* Check if it's safe to multiply by two */
264 Status
= RtlULongMult(AppPathLength
, sizeof(WCHAR
), &AppPathLength
);
265 if (NT_SUCCESS(Status
))
267 /* Allocate a copy for the string */
268 PathCopy
= BlMmAllocateHeap(AppPathLength
);
271 /* NULL-terminate it */
272 RtlCopyMemory(PathCopy
,
274 AppPathLength
- sizeof(UNICODE_NULL
));
275 PathCopy
[AppPathLength
] = UNICODE_NULL
;
277 /* Finally, initialize the outoing string */
278 RtlInitUnicodeString(ApplicationDirectoryPath
, PathCopy
);
282 /* No memory, fail */
283 Status
= STATUS_NO_MEMORY
;
289 /* Check if we had an application path */
292 /* No longer need this, free it */
293 BlMmFreeHeap(ApplicationPath
);
301 BmFwInitializeBootDirectoryPath (
308 UNICODE_STRING BcdPath
;
310 ULONG FileHandle
, DeviceHandle
;
312 /* Initialize everything for failure */
313 BcdPath
.MaximumLength
= 0;
314 BcdPath
.Buffer
= NULL
;
320 /* Try to open the boot device */
321 Status
= BlpDeviceOpen(BlpBootDevice
,
322 BL_DEVICE_READ_ACCESS
,
325 if (!NT_SUCCESS(Status
))
327 EfiPrintf(L
"Device open failed: %lx\r\n", Status
);
331 /* Get the directory path */
332 Status
= BmpFwGetApplicationDirectoryPath(&BcdPath
);
333 BcdDirectory
= BcdPath
.Buffer
;
334 if (!NT_SUCCESS(Status
))
339 /* Add the BCD file name to it */
340 FinalSize
= BcdPath
.MaximumLength
+ sizeof(L
"\\BCD") - sizeof(UNICODE_NULL
);
341 if (FinalSize
< BcdPath
.MaximumLength
)
346 /* Allocate space for the final path */
347 FinalPath
= BlMmAllocateHeap(FinalSize
);
354 RtlZeroMemory(FinalPath
, FinalSize
);
355 RtlCopyMemory(FinalPath
, BcdDirectory
, BcdPath
.MaximumLength
);
356 wcsncat(FinalPath
, L
"\\BCD", FinalSize
/ sizeof(WCHAR
));
358 /* Try to open the file */
359 Status
= BlFileOpen(DeviceHandle
,
363 if (!NT_SUCCESS(Status
))
365 BootDirectory
= BcdDirectory
;
369 /* Save the boot directory */
370 BootDirectory
= L
"\\EFI\\Boot"; /* Should be EFI\\ReactOS\\Boot */
373 /* Free all the allocations we made */
376 Status
= BlMmFreeHeap(BcdDirectory
);
380 Status
= BlMmFreeHeap(FinalPath
);
383 /* Close the BCD file */
384 if (FileHandle
!= -1)
386 Status
= BlFileClose(FileHandle
);
389 /* Close the boot device */
390 if (DeviceHandle
!= -1)
392 Status
= BlDeviceClose(DeviceHandle
);
395 /* Return back to the caller */
404 /* Don't yet handled boot.ini */
405 return STATUS_NOT_FOUND
;
409 BmpFatalErrorMessageFilter (
410 _In_ NTSTATUS ErrorStatus
,
411 _Out_ PULONG ErrorResourceId
416 /* Assume no message for now, check for known status message */
420 /* Convert each status to a resource ID */
421 case STATUS_UNEXPECTED_IO_ERROR
:
422 *ErrorResourceId
= 9017;
425 case STATUS_IMAGE_CHECKSUM_MISMATCH
:
426 *ErrorResourceId
= 9018;
428 case STATUS_INVALID_IMAGE_WIN_64
:
429 *ErrorResourceId
= 9016;
432 *ErrorResourceId
= 9019;
436 *ErrorResourceId
= 9013;
440 /* Return the type of message */
449 /* Check if a boot error is present */
450 if (BmpPackedBootError
.BootError
)
453 BlMmFreeHeap(BmpPackedBootError
.BootError
);
454 BmpPackedBootError
.BootError
= NULL
;
457 /* Zero out the packed buffer */
458 BmpPackedBootError
.Size
= 0;
459 BmpInternalBootError
= NULL
;
460 RtlZeroMemory(&BmpErrorBuffer
, sizeof(BmpErrorBuffer
));
465 _In_ ULONG ErrorCode
,
466 _In_ NTSTATUS ErrorStatus
,
467 _In_ ULONG ErrorMsgId
,
468 _In_ PWCHAR FileName
,
472 PWCHAR ErrorMsgString
;
474 /* Check if we already had an error */
475 if (BmpInternalBootError
)
481 /* Find the string for this error ID */
482 ErrorMsgString
= BlResourceFindMessage(ErrorMsgId
);
485 /* Fill out the error buffer */
486 BmpErrorBuffer
.Unknown1
= 0;
487 BmpErrorBuffer
.Unknown2
= 0;
488 BmpErrorBuffer
.ErrorString
= ErrorMsgString
;
489 BmpErrorBuffer
.FileName
= FileName
;
490 BmpErrorBuffer
.ErrorCode
= ErrorCode
;
491 BmpErrorBuffer
.ErrorStatus
= ErrorStatus
;
492 BmpErrorBuffer
.HelpMsgId
= HelpMsgId
;
493 BmpInternalBootError
= &BmpErrorBuffer
;
499 _In_ ULONG ErrorCode
,
500 _In_ ULONG_PTR Parameter1
,
501 _In_ ULONG_PTR Parameter2
,
502 _In_ ULONG_PTR Parameter3
,
503 _In_ ULONG_PTR Parameter4
506 PWCHAR FileName
, Buffer
;
507 NTSTATUS ErrorStatus
;
508 WCHAR FormatString
[256];
509 ULONG ErrorResourceId
, ErrorHelpId
;
510 BOOLEAN Restart
, NoError
;
512 /* Assume no buffer for now */
515 /* Check what error code is being raised */
518 /* Error reading the BCD */
519 case BL_FATAL_ERROR_BCD_READ
:
521 /* Check if we have a name for the BCD file */
524 /* Check if the name fits into our buffer */
525 FileName
= (PWCHAR
)Parameter1
;
526 if (wcslen(FileName
) < sizeof(BmpFileNameBuffer
))
528 /* Copy it in there */
529 Buffer
= BmpFileNameBuffer
;
530 wcsncpy(BmpFileNameBuffer
,
532 RTL_NUMBER_OF(BmpFileNameBuffer
));
536 /* If we don't have a buffer, use an empty one */
539 Buffer
= ParentFileName
;
542 /* The NTSTATUS code is in parameter 2*/
543 ErrorStatus
= (NTSTATUS
)Parameter2
;
545 /* Build the error string */
546 swprintf(FormatString
,
547 L
"\nAn error occurred (%08x) while attempting "
548 L
"to read the boot configuration data file %s\n",
552 /* Select the resource ID message */
553 ErrorResourceId
= 9002;
556 case BL_FATAL_ERROR_BCD_ENTRIES
:
558 /* File name is in parameter 1 */
559 FileName
= (PWCHAR
)Parameter1
;
561 /* The NTSTATUS code is in parameter 2*/
562 ErrorStatus
= (NTSTATUS
)Parameter2
;
564 /* Build the error string */
565 swprintf(FormatString
,
566 L
"\nNo valid entries found in the boot configuration data file %s\n",
569 /* Select the resource ID message */
570 ErrorResourceId
= 9007;
573 case BL_FATAL_ERROR_BCD_PARSE
:
575 /* File name isin parameter 1 */
576 FileName
= (PWCHAR
)Parameter1
;
578 /* The NTSTATUS code is in parameter 2*/
579 ErrorStatus
= (NTSTATUS
)Parameter2
;
581 /* Build the error string */
582 swprintf(FormatString
,
583 L
"\nThe boot configuration file %s is invalid (%08x).\n",
587 /* Select the resource ID message */
588 ErrorResourceId
= 9015;
591 case BL_FATAL_ERROR_GENERIC
:
593 /* The NTSTATUS code is in parameter 1*/
594 ErrorStatus
= (NTSTATUS
)Parameter1
;
596 /* Build the error string */
597 swprintf(FormatString
,
598 L
"\nThe boot manager experienced an error (%08x).\n",
601 /* Select the resource ID message */
602 ErrorResourceId
= 9005;
607 /* The rest is not yet handled */
608 EfiPrintf(L
"Unexpected fatal error: %lx\r\n", ErrorCode
);
613 /* Check if the BCD option for restart is set */
614 BlGetBootOptionBoolean(BlpApplicationEntry
.BcdData
,
615 BcdLibraryBoolean_RestartOnFailure
,
619 /* Yes, so no error should be shown since we'll auto-restart */
624 /* Check if the option for not showing errors is set in the BCD */
625 BlGetBootOptionBoolean(BlpApplicationEntry
.BcdData
,
626 BcdBootMgrBoolean_NoErrorDisplay
,
630 /* Do we want an error? */
633 /* Yep, print it and then raise an error */
634 BlStatusPrint(FormatString
);
635 BlStatusError(1, ErrorCode
, Parameter1
, Parameter2
, Parameter3
);
638 /* Get the help message ID */
639 ErrorHelpId
= BmpFatalErrorMessageFilter(ErrorStatus
, &ErrorResourceId
);
640 BmpErrorLog(ErrorCode
, ErrorStatus
, ErrorResourceId
, Buffer
, ErrorHelpId
);
645 _In_ PWCHAR FileName
,
646 _Out_ PWCHAR
* FullPath
650 ULONG BootDirLength
, PathLength
;
652 /* Compute the length of the directory, and add a NUL */
653 BootDirLength
= wcslen(BootDirectory
);
654 Status
= RtlULongAdd(BootDirLength
, 1, &BootDirLength
);
655 if (!NT_SUCCESS(Status
))
660 /* Add the length of the file, make sure it fits */
661 PathLength
= wcslen(FileName
);
662 Status
= RtlULongAdd(PathLength
, BootDirLength
, &PathLength
);
663 if (!NT_SUCCESS(Status
))
668 /* Convert to bytes */
669 Status
= RtlULongLongToULong(PathLength
* sizeof(WCHAR
), &PathLength
);
670 if (!NT_SUCCESS(Status
))
675 /* Allocate the full path */
676 *FullPath
= BlMmAllocateHeap(PathLength
);
679 /* Copy the directory followed by the file name */
680 wcsncpy(*FullPath
, BootDirectory
, PathLength
/ sizeof(WCHAR
));
681 wcsncat(*FullPath
, FileName
, PathLength
/ sizeof(WCHAR
));
685 /* Bail out since we have no memory */
686 Status
= STATUS_NO_MEMORY
;
690 /* Return to caller */
699 /* Check if boot.ini data needs to be freed */
702 EfiPrintf(L
"Boot.ini not handled\r\n");
705 /* Dereference the hive and close the key */
706 BiDereferenceHive(Handle
);
716 PBL_DEVICE_DESCRIPTOR BcdDevice
;
717 PWCHAR BcdPath
, FullPath
, PathBuffer
;
719 ULONG PathLength
, FullSize
;
721 UNICODE_STRING BcdString
;
723 /* Initialize variables */
729 /* Check if a boot.ini file exists */
730 Status
= BmOpenBootIni();
731 if (NT_SUCCESS(Status
))
733 BmBootIniUsed
= TRUE
;
736 /* Check on which device the BCD is */
737 Status
= BlGetBootOptionDevice(BlpApplicationEntry
.BcdData
,
738 BcdBootMgrDevice_BcdDevice
,
741 if (!NT_SUCCESS(Status
))
743 /* It's not on a custom device, so it must be where we are */
744 Status
= BlGetBootOptionDevice(BlpApplicationEntry
.BcdData
,
745 BcdLibraryDevice_ApplicationDevice
,
748 if (!NT_SUCCESS(Status
))
750 /* This BCD option is required */
755 /* Next, check what file contains the BCD */
756 Status
= BlGetBootOptionString(BlpApplicationEntry
.BcdData
,
757 BcdBootMgrString_BcdFilePath
,
759 if (NT_SUCCESS(Status
))
761 /* We don't handle custom BCDs yet */
762 EfiPrintf(L
"Custom BCD Not handled: %s\r\n", BcdPath
);
763 Status
= STATUS_NOT_IMPLEMENTED
;
767 /* Now check if the BCD is on a remote share */
768 if (BcdDevice
->DeviceType
== UdpDevice
)
770 /* Nope. Nope. Nope */
771 EfiPrintf(L
"UDP device Not handled\r\n");
772 Status
= STATUS_NOT_IMPLEMENTED
;
776 /* Otherwise, compute the hardcoded path of the BCD */
777 Status
= BmpFwGetFullPath(L
"\\BCD", &FullPath
);
778 if (!NT_SUCCESS(Status
))
780 /* User the raw path */
781 PathBuffer
= BcdPath
;
785 /* Use the path we got */
786 PathBuffer
= FullPath
;
790 /* Check if we failed to get the BCD path */
791 if (!NT_SUCCESS(Status
))
796 /* Add a NUL to the path, make sure it'll fit */
797 PathLength
= wcslen(PathBuffer
);
798 Status
= RtlULongAdd(PathLength
, 1, &PathLength
);
799 if (!NT_SUCCESS(Status
))
804 /* Convert to bytes */
805 Status
= RtlULongLongToULong(PathLength
* sizeof(WCHAR
), &PathLength
);
806 if (!NT_SUCCESS(Status
))
811 /* Now add the size of the path to the device path, check if it fits */
812 Status
= RtlULongAdd(PathLength
, BcdDevice
->Size
, &FullSize
);
813 if (!NT_SUCCESS(Status
))
818 /* Allocate a final structure to hold both entities */
819 FinalBuffer
= BlMmAllocateHeap(FullSize
);
822 Status
= STATUS_NO_MEMORY
;
826 /* Copy the device path and file path into the final buffer */
827 RtlCopyMemory(FinalBuffer
, BcdDevice
, BcdDevice
->Size
);
828 RtlCopyMemory((PVOID
)((ULONG_PTR
)FinalBuffer
+ BcdDevice
->Size
),
832 /* Now tell the BCD engine to open the store */
833 BcdString
.Length
= FullSize
;
834 BcdString
.MaximumLength
= FullSize
;
835 BcdString
.Buffer
= FinalBuffer
;
836 Status
= BcdOpenStoreFromFile(&BcdString
, Handle
);
838 /* Free our final buffer */
839 BlMmFreeHeap(FinalBuffer
);
842 /* Did we allocate a device? */
846 BlMmFreeHeap(BcdDevice
);
849 /* Is this the failure path? */
850 if (!NT_SUCCESS(Status
))
852 /* Raise a fatal error */
853 BmFatalErrorEx(BL_FATAL_ERROR_BCD_READ
,
854 (ULONG_PTR
)PathBuffer
,
860 /* Did we get an allocated path? */
861 if ((PathBuffer
) && (HavePath
))
864 BlMmFreeHeap(PathBuffer
);
867 /* Return back to the caller */
871 typedef struct _BL_BSD_LOG_OBJECT
878 } BL_BSD_LOG_OBJECT
, *PBL_BSD_LOG_OBJECT
;
880 BL_BSD_LOG_OBJECT BsdpLogObject
;
881 BOOLEAN BsdpLogObjectInitialized
;
885 _In_ PBL_DEVICE_DESCRIPTOR LogDevice
,
892 /* Don't initialize twice */
893 if (BsdpLogObjectInitialized
)
898 /* Set invalid IDs for now */
899 BsdpLogObject
.DeviceId
= -1;
900 BsdpLogObject
.FileId
= -1;
902 /* Open the BSD device */
903 Status
= BlpDeviceOpen(LogDevice
,
904 BL_DEVICE_READ_ACCESS
| BL_DEVICE_WRITE_ACCESS
,
906 &BsdpLogObject
.DeviceId
);
907 if (!NT_SUCCESS(Status
))
909 /* Welp that didn't work */
913 /* Now open the BSD itself */
914 Status
= BlFileOpen(BsdpLogObject
.DeviceId
,
916 BL_FILE_READ_ACCESS
| BL_FILE_WRITE_ACCESS
,
917 &BsdpLogObject
.FileId
);
918 if (!NT_SUCCESS(Status
))
924 /* The BSD is open. Start doing stuff to it */
925 EfiPrintf(L
"Unimplemented BSD path\r\n");
926 Status
= STATUS_NOT_IMPLEMENTED
;
929 /* Close the BSD if we had it open */
930 if (BsdpLogObject
.FileId
!= -1)
932 BlFileClose(BsdpLogObject
.FileId
);
935 /* Close the device if we had it open */
936 if (BsdpLogObject
.DeviceId
!= -1)
938 BlDeviceClose(BsdpLogObject
.DeviceId
);
941 /* Set BSD object to its uninitialized state */
942 BsdpLogObjectInitialized
= FALSE
;
943 BsdpLogObject
.FileId
= 0;
944 BsdpLogObject
.DeviceId
= 0;
945 BsdpLogObject
.Flags
= 0;
946 BsdpLogObject
.Unknown
= 0;
947 BsdpLogObject
.Size
= 0;
951 BmpInitializeBootStatusDataLog (
956 PBL_DEVICE_DESCRIPTOR BsdDevice
;
961 /* Initialize locals */
966 /* Check if the BSD is stored in a custom device */
967 Status
= BlGetBootOptionDevice(BlpApplicationEntry
.BcdData
,
968 BcdLibraryDevice_BsdLogDevice
,
971 if (!NT_SUCCESS(Status
))
973 /* Nope, use the boot device */
974 BsdDevice
= BlpBootDevice
;
977 /* Check if the path is custom as well */
978 Status
= BlGetBootOptionString(BlpApplicationEntry
.BcdData
,
979 BcdLibraryString_BsdLogPath
,
981 if (!NT_SUCCESS(Status
))
983 /* Nope, use our default path */
984 Status
= BmpFwGetFullPath(L
"\\bootstat.dat", &BsdPath
);
985 if (!NT_SUCCESS(Status
))
990 /* Set preserve flag */
995 /* Set preserve flag */
999 /* Finally, check if the BSD should be preserved */
1000 Status
= BlGetBootOptionBoolean(BlpApplicationEntry
.BcdData
,
1001 BcdLibraryBoolean_PreserveBsdLog
,
1003 if (!(NT_SUCCESS(Status
)) || !(PreserveBsd
))
1005 /* We failed to read, or we were asked not to preserve it */
1009 /* Initialize the log */
1010 BlBsdInitializeLog(BsdDevice
, BsdPath
, Flags
);
1012 /* Free the BSD device descriptor if we had one */
1015 BlMmFreeHeap(BsdDevice
);
1018 /* Free the BSD path if we had one */
1019 if ((Flags
) && (BsdPath
))
1021 BlMmFreeHeap(BsdPath
);
1026 BmFwMemoryInitialize (
1031 PHYSICAL_ADDRESS PhysicalAddress
;
1032 BL_ADDRESS_RANGE AddressRange
;
1034 /* Select the range below 1MB */
1035 AddressRange
.Maximum
= 0xFFFFF;
1036 AddressRange
.Minimum
= 0;
1038 /* Allocate one reserved page with the "reserved" attribute */
1039 Status
= MmPapAllocatePhysicalPagesInRange(&PhysicalAddress
,
1040 BlApplicationReserved
,
1044 &MmMdlUnmappedAllocated
,
1046 BL_MM_REQUEST_DEFAULT_TYPE
);
1047 if (!NT_SUCCESS(Status
))
1049 /* Print a message on error, but keep going */
1050 BlStatusPrint(L
"BmFwMemoryInitialize: Failed to allocate a page below 1MB. Status: 0x%08x\r\n",
1056 BmpBgDisplayClearScreen (
1060 /* Not yet supported */
1061 return STATUS_NOT_IMPLEMENTED
;
1070 EfiPrintf(L
"XML: %s\r\n", XmlTag
);
1071 return STATUS_NOT_IMPLEMENTED
;
1076 _In_ PWCHAR Stylesheet
1079 /* Reset the cursor type */
1080 BlDisplaySetCursorType(0);
1082 /* Nope, not doing any XML stuff */
1083 return STATUS_SUCCESS
;
1087 BmFwVerifySelfIntegrity (
1091 /* Check if we're booted by UEFI off the DVD directlry */
1092 if ((BlpBootDevice
->DeviceType
== LocalDevice
) &&
1093 (BlpBootDevice
->Local
.Type
== CdRomDevice
) &&
1094 (BlpApplicationFlags
& BL_APPLICATION_FLAG_CONVERTED_FROM_EFI
))
1096 /* Windows actually bypasses integrity checks in this case. Works for us */
1097 return STATUS_SUCCESS
;
1100 /* Our binaries aren't signed, so always return failure */
1105 BmFwRegisterRevocationList (
1110 BOOLEAN SecureBootEnabled
;
1112 /* Is SecureBoot enabled? */
1113 Status
= BlSecureBootIsEnabled(&SecureBootEnabled
);
1114 if ((NT_SUCCESS(Status
)) && (SecureBootEnabled
))
1116 EfiPrintf(L
"SB not implemented revok\r\n");
1117 return STATUS_NOT_IMPLEMENTED
;
1121 /* Nothing to do without SecureBoot */
1122 Status
= STATUS_SUCCESS
;
1125 /* Return revocation result back to caller */
1130 BmResumeFromHibernate (
1131 _Out_ PHANDLE BcdResumeHandle
1135 BOOLEAN AttemptResume
;
1137 /* Should we attempt to resume from hibernation? */
1138 Status
= BlGetBootOptionBoolean(BlpApplicationEntry
.BcdData
,
1139 BcdBootMgrBoolean_AttemptResume
,
1141 if (!NT_SUCCESS(Status
))
1143 /* Nope. Is automatic restart on crash enabled? */
1144 AttemptResume
= FALSE
;
1145 Status
= BlGetBootOptionBoolean(BlpApplicationEntry
.BcdData
,
1146 BcdOSLoaderBoolean_DisableCrashAutoReboot
,
1148 AttemptResume
= (NT_SUCCESS(Status
) && (AttemptResume
));
1151 /* Don't do anything if there's no need to resume anything */
1154 return STATUS_SUCCESS
;
1157 /* Not yet implemented */
1158 EfiPrintf(L
"Resume not supported\r\n");
1159 return STATUS_NOT_IMPLEMENTED
;
1163 BmpProcessBadMemory (
1167 BL_PD_DATA_BLOB BadMemoryData
;
1170 /* Try to get the memory data from the memtest application */
1171 BadMemoryData
.BlobSize
= 0;
1172 BadMemoryData
.Data
= NULL
;
1173 BadMemoryData
.DataSize
= 0;
1174 Status
= BlPdQueryData(&BadMemoryGuid
, NULL
, &BadMemoryData
);
1175 if (Status
!= STATUS_BUFFER_TOO_SMALL
)
1177 /* No results, or some other error */
1181 /* Not yet implemented */
1182 EfiPrintf(L
"Bad page list persistence not implemented\r\n");
1183 return STATUS_NOT_IMPLEMENTED
;
1188 _In_ HANDLE BcdHandle
,
1189 _In_ PGUID ObjectId
,
1193 HANDLE ObjectHandle
;
1196 /* Open the object */
1197 Status
= BcdOpenObject(BcdHandle
, ObjectId
, &ObjectHandle
);
1198 if (NT_SUCCESS(Status
))
1200 /* Delete the element */
1201 BcdDeleteElement(ObjectHandle
, Type
);
1203 /* Close the object and set success */
1204 BiCloseKey(ObjectHandle
);
1205 Status
= STATUS_SUCCESS
;
1208 /* Return the result */
1213 BmGetEntryDescription (
1214 _In_ HANDLE BcdHandle
,
1215 _In_ PGUID ObjectId
,
1216 _Out_ PBCD_OBJECT_DESCRIPTION Description
1220 HANDLE ObjectHandle
;
1222 /* Open the BCD object */
1223 Status
= BcdOpenObject(BcdHandle
, ObjectId
, &ObjectHandle
);
1224 if (NT_SUCCESS(Status
))
1226 /* Make sure the caller passed this argument in */
1229 /* Fail otherwise */
1230 Status
= STATUS_INVALID_PARAMETER
;
1234 /* Query the description from the BCD interface */
1235 Status
= BiGetObjectDescription(ObjectHandle
, Description
);
1238 /* Close the object key */
1239 BiCloseKey(ObjectHandle
);
1242 /* Return the result back */
1247 BmpPopulateBootEntryList (
1248 _In_ HANDLE BcdHandle
,
1249 _In_ PGUID SequenceList
,
1251 _Out_ PBL_LOADED_APPLICATION_ENTRY
* BootSequence
,
1252 _Out_ PULONG SequenceCount
1256 ULONG BootIndex
, i
, OptionSize
;
1257 PBL_LOADED_APPLICATION_ENTRY BootEntry
;
1258 PBL_BCD_OPTION Options
;
1259 BCD_OBJECT_DESCRIPTION Description
;
1260 BcdObjectType ObjectType
;
1261 BOOLEAN HavePath
, IsWinPe
, SoftReboot
;
1264 /* Initialize locals */
1267 Status
= STATUS_NOT_FOUND
;
1269 /* Loop through every element in the sequence */
1270 for (i
= 0; i
< *SequenceCount
; i
++)
1272 /* Assume failure */
1275 /* Get the options for the sequence element */
1276 Status
= BmGetOptionList(BcdHandle
, SequenceList
, &Options
);
1277 if (!NT_SUCCESS(Status
))
1279 EfiPrintf(L
"option list failed: %lx\r\n", Status
);
1283 /* Make sure there's at least a path and description */
1284 if (!(MiscGetBootOption(Options
, BcdLibraryDevice_ApplicationDevice
)) ||
1285 !(MiscGetBootOption(Options
, BcdLibraryString_Description
)))
1287 Status
= STATUS_UNSUCCESSFUL
;
1288 EfiPrintf(L
"missing list failed: %lx\r\n", Status
);
1292 /* Get the size of the BCD options and allocate a large enough entry */
1293 OptionSize
= BlGetBootOptionListSize(Options
);
1294 BootEntry
= BlMmAllocateHeap(sizeof(*BootEntry
) + OptionSize
);
1297 Status
= STATUS_NO_MEMORY
;
1301 /* Save it as part of the sequence */
1302 BootSequence
[BootIndex
] = BootEntry
;
1304 /* Initialize it, and copy the BCD data */
1305 RtlZeroMemory(BootEntry
, sizeof(*BootEntry
));
1306 BootEntry
->Guid
= *SequenceList
;
1307 BootEntry
->BcdData
= (PBL_BCD_OPTION
)(BootEntry
+ 1);
1308 BootEntry
->Flags
= Flags
;
1309 RtlCopyMemory(BootEntry
->BcdData
, Options
, OptionSize
);
1311 /* Get the object descriptor to find out what kind of entry it is */
1312 Status
= BmGetEntryDescription(BcdHandle
,
1315 if (!NT_SUCCESS(Status
))
1317 EfiPrintf(L
"missing desc failed: %lx\r\n", Status
);
1321 /* Check if a path was given or not */
1322 HavePath
= MiscGetBootOption(Options
, BcdLibraryString_ApplicationPath
) ?
1325 /* Now select based on what type of object this is -- must be an app */
1326 ObjectType
.PackedValue
= Description
.Type
;
1327 if (ObjectType
.Application
.ObjectCode
== BCD_OBJECT_TYPE_APPLICATION
)
1329 /* Then select based on what kind of app it is */
1330 switch (ObjectType
.Application
.ApplicationCode
)
1332 /* Another boot manager */
1333 case BCD_APPLICATION_TYPE_BOOTMGR
:
1334 BootEntry
->Flags
|= BCD_APPLICATION_TYPE_BOOTMGR
;
1338 case BCD_APPLICATION_TYPE_OSLOADER
:
1339 BootEntry
->Flags
|= BL_APPLICATION_ENTRY_WINLOAD
;
1341 /* Do we have a path for it? */
1344 /* We'll try to make one up. Is this WinPE? */
1346 Status
= BlGetBootOptionBoolean(Options
,
1347 BcdOSLoaderBoolean_WinPEMode
,
1349 if (!(NT_SUCCESS(Status
)) && (Status
!= STATUS_NOT_FOUND
))
1354 /* Use the appropriate path for WinPE or local install */
1355 LoaderPath
= IsWinPe
?
1356 L
"\\Windows\\System32\\boot\\winload.efi" :
1357 L
"\\Windows\\System32\\winload.efi";
1359 /* Add the path to the boot entry */
1360 Status
= BlAppendBootOptionString(BootEntry
, LoaderPath
);
1361 if (!NT_SUCCESS(Status
))
1366 /* We have a path now */
1371 /* A hibernate-resume application */
1372 case BCD_APPLICATION_TYPE_RESUME
:
1373 BootEntry
->Flags
|= BL_APPLICATION_ENTRY_WINRESUME
;
1376 /* An older OS NTLDR */
1377 case BCD_APPLICATION_TYPE_NTLDR
:
1378 BootEntry
->Flags
|= BL_APPLICATION_ENTRY_NTLDR
;
1381 /* An older OS SETUPLDR */
1382 case BCD_APPLICATION_TYPE_SETUPLDR
:
1383 BootEntry
->Flags
|= BL_APPLICATION_ENTRY_SETUPLDR
;
1386 /* A 3rd party/Win9x boot sector */
1387 case BCD_APPLICATION_TYPE_BOOTSECTOR
:
1388 BootEntry
->Flags
|= BL_APPLICATION_ENTRY_BOOTSECTOR
;
1391 /* Something else entirely */
1397 /* We better have a path by now */
1400 Status
= STATUS_UNSUCCESSFUL
;
1404 /* Check if this is a real mode startup.com */
1405 if ((ObjectType
.Application
.ObjectCode
== BCD_OBJECT_TYPE_APPLICATION
) &&
1406 (ObjectType
.Application
.ImageCode
= BCD_IMAGE_TYPE_REAL_MODE
) &&
1407 (ObjectType
.Application
.ApplicationCode
== BCD_APPLICATION_TYPE_STARTUPCOM
))
1409 /* Check if PXE soft reboot will occur */
1410 Status
= BlGetBootOptionBoolean(Options
,
1411 BcdStartupBoolean_PxeSoftReboot
,
1413 if ((NT_SUCCESS(Status
)) && (SoftReboot
))
1415 /* Then it's a valid startup.com entry */
1416 BootEntry
->Flags
|= BL_APPLICATION_ENTRY_STARTUP
;
1421 /* All done with this entry -- did we have BCD options? */
1424 /* Free them, they're part of the entry now */
1425 BlMmFreeHeap(Options
);
1429 /* Did we fail anywhere? */
1430 if (!NT_SUCCESS(Status
))
1432 /* Yep -- did we fail with an active boot entry? */
1436 BlDestroyBootEntry(BootEntry
);
1437 BootSequence
[BootIndex
] = NULL
;
1442 /* It worked, so populate the next index now */
1446 /* And move to the next GUID in the sequence list */
1451 /* All done now -- did we have any BCD options? */
1455 BlMmFreeHeap(Options
);
1458 /* Return the status */
1464 _In_ HANDLE BcdHandle
,
1465 _In_ PGUID SequenceList
,
1466 _In_ ULONG SequenceListCount
,
1468 _Out_ PBL_LOADED_APPLICATION_ENTRY
** BootSequence
,
1469 _Out_ PULONG SequenceCount
1472 PBL_LOADED_APPLICATION_ENTRY
* Sequence
;
1476 /* Allocate the sequence list */
1477 Sequence
= BlMmAllocateHeap(SequenceListCount
* sizeof(*Sequence
));
1480 return STATUS_NO_MEMORY
;
1483 /* Populate the sequence list */
1484 Status
= BmpPopulateBootEntryList(BcdHandle
,
1489 if (!NT_SUCCESS(Status
))
1491 /* Free the list on failure */
1492 BlMmFreeHeap(Sequence
);
1496 /* Otherwise, set success and return the list and count */
1497 Status
= STATUS_SUCCESS
;
1498 *BootSequence
= Sequence
;
1499 *SequenceCount
= Count
;
1507 BmEnumerateBootEntries (
1508 _In_ HANDLE BcdHandle
,
1509 _Out_ PBL_LOADED_APPLICATION_ENTRY
**BootSequence
,
1510 _Out_ PULONG SequenceCount
1514 ULONG BootIndex
, BootIniCount
, BootEntryCount
, BcdCount
;
1515 PBL_LOADED_APPLICATION_ENTRY
* Sequence
;
1518 BOOLEAN UseDisplayList
;
1520 /* Initialize locals */
1523 /* First try to get the display list, if any */
1524 UseDisplayList
= TRUE
;
1525 Status
= BlGetBootOptionGuidList(BlpApplicationEntry
.BcdData
,
1526 BcdBootMgrObjectList_DisplayOrder
,
1529 if (!NT_SUCCESS(Status
))
1531 /* No list, get the default entry instead */
1532 Status
= BlGetBootOptionGuid(BlpApplicationEntry
.BcdData
,
1533 BcdBootMgrObject_DefaultObject
,
1535 if (NT_SUCCESS(Status
))
1537 /* Set the array to just our entry */
1538 UseDisplayList
= FALSE
;
1540 DisplayOrder
= &DefaultObject
;
1544 /* No default list either, return success but no entries */
1545 *BootSequence
= NULL
;
1547 Status
= STATUS_SUCCESS
;
1548 DisplayOrder
= NULL
;
1553 /* Check if boot.ini was used */
1557 /* Get the entries from it */
1558 EfiPrintf(L
"Boot.ini not supported\r\n");
1559 BootIniCount
= 0;//BmBootIniGetEntryCount();
1562 /* Allocate an array large enough for the combined boot entries */
1563 BootEntryCount
= BootIniCount
+ BcdCount
;
1564 Sequence
= BlMmAllocateHeap(BootEntryCount
* sizeof(*Sequence
));
1567 Status
= STATUS_NO_MEMORY
;
1572 RtlZeroMemory(Sequence
, BootEntryCount
* sizeof(*Sequence
));
1574 /* Check if we had BCD entries */
1577 /* Populate the list of bootable entries */
1578 Status
= BmpPopulateBootEntryList(BcdHandle
,
1580 BL_APPLICATION_ENTRY_DISPLAY_ORDER
,
1583 if (!NT_SUCCESS(Status
))
1590 /* Check if we had boot.ini entries */
1594 EfiPrintf(L
"Boot.ini not supported\r\n");
1597 /* Return success and the sequence + count populated */
1598 Status
= STATUS_SUCCESS
;
1599 *BootSequence
= Sequence
;
1600 *SequenceCount
= BootIniCount
+ BcdCount
;
1603 /* Check if we had allocated a GUID list */
1604 if ((UseDisplayList
) && (DisplayOrder
))
1607 BlMmFreeHeap(DisplayOrder
);
1610 /* Check if this is the failure path */
1611 if (!(NT_SUCCESS(Status
)) && (Sequence
))
1613 /* Loop the remaining boot entries */
1614 while (BootIndex
< BootEntryCount
)
1616 /* Check if it had been allocated */
1617 if (Sequence
[BootIndex
])
1620 BlMmFreeHeap(Sequence
[BootIndex
]);
1627 /* Free the whole sequence now */
1628 BlMmFreeHeap(Sequence
);
1631 /* All done, return the result */
1636 BmpGetDefaultBootEntry (
1637 _In_ PBL_LOADED_APPLICATION_ENTRY
* Sequence
,
1639 _Out_ PBL_LOADED_APPLICATION_ENTRY
* DefaultEntry
,
1640 _Out_ PULONG DefaultIndex
1647 /* Assume no default */
1648 *DefaultEntry
= *Sequence
;
1651 /* Nothing to do if there's just one entry */
1657 /* Get the default object, bail out if there isn't one */
1658 Status
= BlGetBootOptionGuid(BlpApplicationEntry
.BcdData
,
1659 BcdBootMgrObject_DefaultObject
,
1661 if (!(NT_SUCCESS(Status
)) || !(Count
))
1666 /* Scan the boot sequence */
1667 for (BootIndex
= 0; BootIndex
< Count
; BootIndex
++)
1669 /* Find one that matches the default */
1670 if (RtlEqualMemory(&Sequence
[BootIndex
]->Guid
,
1675 *DefaultEntry
= Sequence
[BootIndex
];
1676 *DefaultIndex
= BootIndex
;
1683 BmGetBootMenuPolicy (
1684 _In_ PBL_LOADED_APPLICATION_ENTRY BootEntry
1689 ULONGLONG BootMenuPolicy
;
1692 /* Check if EMS is enabled */
1693 Status
= BlGetBootOptionBoolean(BlpApplicationEntry
.BcdData
,
1694 BcdOSLoaderBoolean_EmsEnabled
,
1696 if ((NT_SUCCESS(Status
)) && (EmsEnabled
))
1699 return MenuPolicyLegacy
;
1702 /* Check what entry we are looking at */
1705 /* No entry, pick the selected one */
1706 BootEntry
= BmpSelectedBootEntry
;
1709 /* Do we still not have an entry? */
1713 return MenuPolicyStandard
;
1716 /* Check if this is an OS loader */
1718 if (BootEntry
->Flags
& BL_APPLICATION_ENTRY_WINLOAD
)
1720 /* Use the correct option ID */
1721 OptionId
= BcdOSLoaderInteger_BootMenuPolicy
;
1725 /* Check if this is an OS resumer */
1726 if (!(BootEntry
->Flags
& BL_APPLICATION_ENTRY_WINRESUME
))
1728 /* Nope, so no reason for a menu */
1729 return MenuPolicyLegacy
;
1732 /* Use the correct opetion ID */
1733 OptionId
= BcdResumeInteger_BootMenuPolicy
;
1736 /* Check the option ID for the boot menu policy */
1737 Status
= BlGetBootOptionInteger(BootEntry
->BcdData
,
1740 if (NT_SUCCESS(Status
))
1742 /* We have one, return it */
1743 return BootMenuPolicy
;
1746 /* No policy, so assume no menu */
1747 return MenuPolicyLegacy
;
1751 BmDisplayGetBootMenuStatus (
1752 _Out_ PL_MENU_STATUS MenuStatus
1755 /* For now, don't support key input at all */
1756 MenuStatus
->AsULong
= 0;
1757 MenuStatus
->OemKey
= UNICODE_NULL
;
1758 MenuStatus
->BootIndex
= -1;
1762 BmProcessCustomAction (
1763 _In_ HANDLE BcdHandle
,
1764 _In_ PWCHAR ActionKey
1767 EfiPrintf(L
"Custom actions not yet handled\r\n");
1768 return STATUS_NOT_IMPLEMENTED
;
1772 BmpProcessBootEntry (
1773 _In_ HANDLE BcdHandle
,
1774 _In_ PBL_LOADED_APPLICATION_ENTRY BootEntry
,
1775 _Out_ PBOOLEAN ExitBootManager
1778 BL_MENU_STATUS MenuStatus
;
1781 *ExitBootManager
= FALSE
;
1783 /* If the legacy menu must be shown, or if we have a boot entry */
1784 if ((BmGetBootMenuPolicy(BootEntry
) != MenuPolicyStandard
) || (BootEntry
))
1786 /* Check if any key has been presseed */
1787 BmDisplayGetBootMenuStatus(&MenuStatus
);
1788 if (MenuStatus
.AnyKey
)
1790 /* Was the exit key pressed? */
1791 if (MenuStatus
.Exit
)
1793 /* Don't display a menu, and exit */
1794 *ExitBootManager
= TRUE
;
1795 BmpDisplayBootMenu
= FALSE
;
1797 else if (MenuStatus
.OemKey
)
1799 /* Process the OEM key action */
1800 BmProcessCustomAction(BcdHandle
, &MenuStatus
.KeyValue
);
1804 /* Process other keys */
1805 EfiPrintf(L
"TODO\r\n");
1812 BmpGetSelectedBootEntry (
1813 _In_ HANDLE BcdHandle
,
1814 _Out_ PBL_LOADED_APPLICATION_ENTRY
* SelectedBootEntry
,
1815 _Out_ PULONG EntryIndex
,
1816 _Out_ PBOOLEAN ExitBootManager
1820 PBL_LOADED_APPLICATION_ENTRY
* Sequence
;
1821 PBL_LOADED_APPLICATION_ENTRY Entry
, SelectedEntry
;
1822 ULONG Count
, BootIndex
, SelectedIndex
;
1823 // BOOLEAN FoundFailedEntry;
1826 /* Initialize locals */
1830 SelectedEntry
= NULL
;
1832 /* Enumerate all the boot entries */
1833 Status
= BmEnumerateBootEntries(BcdHandle
, &Sequence
, &Count
);
1834 if (!NT_SUCCESS(Status
))
1836 /* Bail out if we failed */
1840 /* Check if there are no entries */
1843 /* This is fatal -- kill the system */
1844 Status
= STATUS_FILE_INVALID
;
1845 BmFatalErrorEx(BL_FATAL_ERROR_BCD_ENTRIES
, (ULONG_PTR
)L
"\\BCD", Status
, 0, 0);
1849 /* Check if we don't yet have an array of failed boot entries */
1850 if (!BmpFailedBootEntries
)
1853 BmpFailedBootEntries
= BlMmAllocateHeap(Count
);
1854 if (BmpFailedBootEntries
)
1857 RtlZeroMemory(BmpFailedBootEntries
, Count
);
1861 /* Check if we have a hardcoded boot override */
1862 if (BmBootEntryOverridePresent
)
1864 EfiPrintf(L
"Hard-coded boot override mode not supported\r\n");
1867 /* Log the OS count */
1868 //BlLogEtwWrite(BOOT_BOOTMGR_MULTI_OS_COUNT);
1870 /* Check if the display is already active and cached */
1871 if (!BmDisplayStateCached
)
1873 /* Check if we should display a boot menu */
1874 Status
= BlGetBootOptionBoolean(BlpApplicationEntry
.BcdData
,
1875 BcdBootMgrBoolean_DisplayBootMenu
,
1876 &BmpDisplayBootMenu
);
1877 if (!NT_SUCCESS(Status
))
1880 BmpDisplayBootMenu
= FALSE
;
1884 /* Check if there's only one entry to boot anyway */
1888 SelectedEntry
= *Sequence
;
1891 BmpProcessBootEntry(BcdHandle
, SelectedEntry
, ExitBootManager
);
1893 /* Check if we're not displaying a boot menu */
1894 if (!BmpDisplayBootMenu
)
1897 BmpDisplayBootMenu
= TRUE
;
1899 /* Return the entry and its index back */
1901 *SelectedBootEntry
= SelectedEntry
;
1902 Status
= STATUS_SUCCESS
;
1908 /* Get the default boot entry */
1909 BmpGetDefaultBootEntry(Sequence
, Count
, &SelectedEntry
, &SelectedIndex
);
1911 /* Check if we have a failed boot entry array allocated */
1912 //FoundFailedEntry = FALSE;
1913 if (BmpFailedBootEntries
)
1915 /* Check if the default entry failed to boot */
1916 if (BmpFailedBootEntries
[SelectedIndex
])
1918 /* Loop through the current boot sequence */
1919 for (SelectedIndex
= 0; SelectedIndex
< Count
; SelectedIndex
++)
1921 /* Check if there's no sequence for this index, or it failed */
1922 while (!(Sequence
[SelectedIndex
]) ||
1923 (BmpFailedBootEntries
[SelectedIndex
]))
1925 /* Remember that this is a failed entry */
1926 SelectedEntry
= Sequence
[SelectedIndex
];
1927 //FoundFailedEntry = TRUE;
1928 BmpDisplayBootMenu
= FALSE
;
1934 /* Check if the entry is an OS loader */
1935 if (SelectedEntry
->Flags
& BL_APPLICATION_ENTRY_WINLOAD
)
1938 EfiPrintf(L
"todo path\r\n");
1941 /* Check if there's no timeout */
1942 Status
= BlGetBootOptionInteger(BlpApplicationEntry
.BcdData
,
1943 BcdBootMgrInteger_Timeout
,
1945 if ((NT_SUCCESS(Status
) && !(Timeout
)))
1947 /* There isn't, so just process the default entry right away */
1948 BmpProcessBootEntry(BcdHandle
, SelectedEntry
, ExitBootManager
);
1950 /* Check if we're not displaying a boot menu */
1951 if (!BmpDisplayBootMenu
)
1954 BmpDisplayBootMenu
= TRUE
;
1956 /* Return the entry and its index back */
1958 *SelectedBootEntry
= SelectedEntry
;
1959 Status
= STATUS_SUCCESS
;
1963 /* Remove the timeout for this boot instance */
1964 BlRemoveBootOption(BlpApplicationEntry
.BcdData
,
1965 BcdBootMgrInteger_Timeout
);
1969 /* Here is where we display the menu and list of tools */
1970 EfiPrintf(L
"Tool selection not yet implemented\r\n");
1972 *SelectedBootEntry
= NULL
;
1975 /* We are done -- did we have a sequence? */
1978 /* Do we have any boot entries we parsed? */
1979 while (BootIndex
< Count
)
1981 /* Get the current boot entry */
1982 Entry
= Sequence
[BootIndex
];
1984 /* Did we fail, or is is not the selected one? */
1985 if ((Entry
) && ((Entry
!= SelectedEntry
) || !(NT_SUCCESS(Status
))))
1987 /* Destroy it, as it won't be needed */
1988 BlDestroyBootEntry(Entry
);
1990 else if (Entry
== SelectedEntry
)
1992 /* It's the selected one, return its index */
1993 *EntryIndex
= BootIndex
;
1996 /* Move to the next entry */
2000 /* Free the sequence of entries */
2001 BlMmFreeHeap(Sequence
);
2004 /* Return the selection result */
2009 BmLaunchRecoverySequence (
2010 _In_ PBL_LOADED_APPLICATION_ENTRY BootEntry
,
2011 _In_ ULONG LaunchCode
2015 PBL_LOADED_APPLICATION_ENTRY RecoveryEntry
;
2017 PGUID RecoverySequence
;
2018 ULONG Count
, i
, RecoveryIndex
, SequenceCount
;
2019 PBL_LOADED_APPLICATION_ENTRY
* Sequence
;
2021 /* Initialize locals */
2024 RecoverySequence
= NULL
;
2029 Status
= BmOpenDataStore(&BcdHandle
);
2030 if (!NT_SUCCESS(Status
))
2035 /* Get the recovery sequence list */
2036 Status
= BlGetBootOptionGuidList(BootEntry
->BcdData
,
2037 BcdLibraryObjectList_RecoverySequence
,
2040 if (!NT_SUCCESS(Status
))
2045 /* Get the sequence of boot entries out of it */
2046 Status
= BmGetBootSequence(BcdHandle
,
2049 BL_APPLICATION_ENTRY_RECOVERY
,
2052 if (!NT_SUCCESS(Status
))
2057 /* Was the BCD open? */
2061 BmCloseDataStore(BcdHandle
);
2064 /* Now go over every entry in the sequence */
2065 for (i
= 0; i
< Count
; ++i
)
2067 /* Check the code for this recovery launch */
2068 if (LaunchCode
== 2 || LaunchCode
== 5)
2070 /* Remove the override if there is one, and set it to 4 */
2071 BlRemoveBootOption(Sequence
[i
]->BcdData
, BcdLibraryInteger_DisplayMessageOverride
);
2072 BlAppendBootOptionInteger(Sequence
[i
],
2073 BcdLibraryInteger_DisplayMessageOverride
,
2076 else if (LaunchCode
== 3)
2078 /* Remove the override if there is one, and set it to 10 */
2079 BlRemoveBootOption(Sequence
[i
]->BcdData
, BcdLibraryInteger_DisplayMessageOverride
);
2080 BlAppendBootOptionInteger(Sequence
[i
],
2081 BcdLibraryInteger_DisplayMessageOverride
,
2085 /* Launch the boot entry for this part of the recovery sequence */
2086 Status
= BmpLaunchBootEntry(Sequence
[i
], NULL
, LaunchCode
, FALSE
);
2087 if (!NT_SUCCESS(Status
))
2094 /* Did we have a sequence of entries? */
2097 /* Loop through each one */
2098 for (RecoveryIndex
= 0; RecoveryIndex
< Count
; RecoveryIndex
++)
2100 /* Does this index have an allocated boot entry? */
2101 RecoveryEntry
= Sequence
[RecoveryIndex
];
2105 BlDestroyBootEntry(RecoveryEntry
);
2109 /* Free the sequence itself */
2110 BlMmFreeHeap(Sequence
);
2113 /* Was there a sequence list? */
2114 if (RecoverySequence
)
2117 BlMmFreeHeap(RecoverySequence
);
2120 /* Return back to caller */
2125 BmDisplayDumpError (
2126 _In_ PBL_LOADED_APPLICATION_ENTRY BootEntry
,
2127 _In_ ULONG LaunchCode
2132 BOOLEAN Restart
, NoError
;
2134 /* Assume we'll just reboot */
2137 /* Should we reboot? */
2138 Status
= BlGetBootOptionBoolean(BlpApplicationEntry
.BcdData
,
2139 BcdLibraryBoolean_RestartOnFailure
,
2141 if ((NT_SUCCESS(Status
)) && (Restart
))
2146 /* Should we not show errors, and thus, reboot? */
2147 Status
= BlGetBootOptionBoolean(BlpApplicationEntry
.BcdData
,
2148 BcdBootMgrBoolean_NoErrorDisplay
,
2150 if ((NT_SUCCESS(Status
)) && (NoError
))
2155 /* Is there an internal boot error? */
2156 if (BmpInternalBootError
)
2158 /* Return it -- but it's a pointer? */
2159 return (ULONG
)BmpInternalBootError
; // ???
2162 /* Otherwise, show the menu to see what to do */
2163 EfiPrintf(L
"Error menu not yet implemented\r\n");
2169 _In_ PBL_LOADED_APPLICATION_ENTRY BootEntry
2172 ULONG NextOffset
, DataOffset
, ListOffset
;
2173 PBL_BCD_OPTION Option
, ListOption
;
2174 BcdElementType ElementType
;
2175 PBCD_DEVICE_OPTION BcdDevice
;
2177 /* Starting at offset 0, loop every BCD option */
2181 /* Get the current option, and its offset */
2182 Option
= (PBL_BCD_OPTION
)((ULONG_PTR
)BootEntry
->BcdData
+ NextOffset
);
2183 NextOffset
= Option
->NextEntryOffset
;
2185 /* If it's empty, ignore it */
2191 /* If it's not a device option, ignore it */
2192 ElementType
.PackedValue
= Option
->Type
;
2193 if (ElementType
.Format
!= BCD_TYPE_DEVICE
)
2198 /* Get the data offset */
2199 DataOffset
= Option
->DataOffset
;
2201 /* Extract the device out of it */
2202 BcdDevice
= (PBCD_DEVICE_OPTION
)((ULONG_PTR
)BootEntry
->BcdData
+ DataOffset
);
2204 /* If the device is already fully specified, no need to build it */
2205 if (!(BcdDevice
->DeviceDescriptor
.Flags
& 1))
2210 /* Otherwise, check if there's any list options as well */
2212 ListOffset
= Option
->ListOffset
;
2213 if (Option
->ListOffset
)
2215 ListOption
= (PBL_BCD_OPTION
)((ULONG_PTR
)BootEntry
->BcdData
+ ListOffset
);
2218 /* And now call BlCreateDevice to build the full device descriptor */
2219 EfiPrintf(L
"Unspecified devices not yet supported: %p\r\n", ListOption
);
2220 return STATUS_NOT_SUPPORTED
;
2221 } while (NextOffset
!= 0);
2223 /* Devices created successfully */
2224 return STATUS_SUCCESS
;
2228 BmpTransferExecution (
2229 _In_ PBL_LOADED_APPLICATION_ENTRY BootEntry
,
2230 _Out_ PULONG LaunchCode
,
2231 _Out_ PBOOLEAN Recover
2236 PBL_DEVICE_DESCRIPTOR AppDevice
;
2237 BL_RETURN_ARGUMENTS ReturnArgs
;
2238 BOOLEAN AdvancedOptions
;
2241 /* Get the application path */
2242 Status
= BlGetBootOptionString(BootEntry
->BcdData
,
2243 BcdLibraryString_ApplicationPath
,
2245 if (!NT_SUCCESS(Status
))
2247 /* If we couldn't find one, set this to NULL */
2251 /* Check if this is a PXE startup.com */
2252 if (BootEntry
->Flags
& BL_APPLICATION_ENTRY_STARTUP
)
2255 /* Do soft reboot to launch it */
2256 Status
= BlNetSoftReboot(BootEntry
);
2258 EfiPrintf(L
"Net boot not supported\r\n");
2259 Status
= STATUS_NOT_SUPPORTED
;
2261 /* Nothing else for us to do */
2265 /* Loop as long as boot was not cancelled */
2268 /* Load the boot application */
2269 Status
= BlImgLoadBootApplication(BootEntry
, &AppHandle
);
2271 /* Did we not find it? */
2272 if (Status
== STATUS_NOT_FOUND
)
2274 /* Get the device for the boot application */
2275 Status
= BlGetBootOptionDevice(BootEntry
->BcdData
,
2276 BcdLibraryDevice_ApplicationDevice
,
2279 if (NT_SUCCESS(Status
))
2281 /* Force re-enumeration */
2282 Status
= BlFwEnumerateDevice(AppDevice
);
2285 /* Did re-enumeration work? */
2286 if (!NT_SUCCESS(Status
))
2288 /* Nope, raise a fatal error */
2289 BmFatalErrorEx(BL_FATAL_ERROR_APP_LOAD
,
2297 /* Yes, try booting it again */
2298 Status
= BlImgLoadBootApplication(BootEntry
, &AppHandle
);
2301 /* Was boot cancelled?*/
2302 if (Status
== STATUS_CANCELLED
)
2304 /* Should we display the menu, or is there no launch sequence? */
2305 if ((BmGetBootMenuPolicy(BootEntry
) != MenuPolicyStandard
) ||
2306 !(MiscGetBootOption(BootEntry
->BcdData
,
2307 BcdLibraryObjectList_RecoverySequence
)))
2309 /* Bail out, the menu will take care of it */
2313 /* No menu and there's a sequence, launch it */
2319 /* STATUS_FVE_LOCKED_VOLUME -- bitlocker volume is locked */
2320 if (Status
== 0xC0210000)
2322 /* Launch recovery mode */
2328 /* Was there some other error launching the boot application? */
2329 if (!NT_SUCCESS(Status
))
2331 /* Raise a fatal error */
2332 BmFatalErrorEx(BL_FATAL_ERROR_APP_LOAD
,
2340 /* Zero out the return arguments */
2341 RtlZeroMemory(&ReturnArgs
, sizeof(ReturnArgs
));
2343 /* Log to ETW this launch */
2344 //BmpLogApplicationLaunchEvent(&BootEntry->Guid, AppPath);
2346 /* Launch the boot application*/
2347 Status
= BlImgStartBootApplication(AppHandle
, &ReturnArgs
);
2349 #if BL_BITLOCKER_SUPPORT
2350 /* Bitlocker stuff */
2351 BlFveSecureBootCheckpointAppReturn(BootEntry
, &ReturnArgs
);
2354 /* Log in the boot status log the launch */
2355 //BlBsdLogEntry(1, 0x12, &BootEntry->Guid, 0x14);
2357 /* Unloac the boot application if we've returned */
2358 BlImgUnloadBootApplication(AppHandle
);
2360 /* Keep going unless STATUS_RESTART_BOOT_APPLICATION */
2361 } while (Status
!= 0xC0000453);
2363 /* We've come back. Assume we need to launch the recovery sequence */
2366 /* Why did we get back? */
2367 if (ReturnArgs
.Flags
& 1)
2369 /* Flag 1 -- should we display advanced options? */
2370 Status
= BlGetBootOptionBoolean(BootEntry
->BcdData
,
2371 BcdLibraryBoolean_DisplayAdvancedOptions
,
2373 if ((NT_SUCCESS(Status
)) && (AdvancedOptions
))
2375 /* Yes, so return with code 2 */
2380 /* No, return with code 1 */
2384 else if (ReturnArgs
.Flags
& 4)
2386 /* Flag 4 -- unkown */
2389 else if (ReturnArgs
.Flags
& 8)
2391 /* Flag 5 -- unkown */
2394 else if (ReturnArgs
.Flags
& 0x10)
2396 /* Flag 6 -- unkown */
2399 else if (ReturnArgs
.Flags
& 0x20)
2401 /* Flag 7 -- unkown */
2404 else if (ReturnArgs
.Flags
& BL_RETURN_ARGUMENTS_NO_PAE_FLAG
)
2406 /* PAE is not supported -- refuse to boot */
2408 BmFatalErrorEx(BL_FATAL_ERROR_NO_PAE
, Status
, 0, 0, 0);
2412 /* All done, did we have an application path? */
2416 BlMmFreeHeap(AppPath
);
2419 /* Back to the caller now */
2424 BmpLaunchBootEntry (
2425 _In_ PBL_LOADED_APPLICATION_ENTRY BootEntry
,
2426 _Out_ PULONG EntryIndex
,
2427 _In_ ULONG LaunchCode
,
2428 _In_ BOOLEAN LaunchWinRe
2434 BOOLEAN DoRecovery
, AutoRecovery
, DoSequence
, RestartOnFailure
;
2436 BOOLEAN AdvancedOneTime
, EditOneTime
;
2438 /* Check if this is the OS loader */
2439 if (BootEntry
->Flags
& BL_APPLICATION_ENTRY_WINLOAD
)
2441 /* Check if one-time advanced options should be shown */
2442 if (MiscGetBootOption(BootEntry
->BcdData
,
2443 BcdOSLoaderBoolean_AdvancedOptionsOneTime
))
2447 Status
= BmOpenDataStore(BcdHandle
);
2448 if (NT_SUCCESS(Status
))
2450 /* Delete the option from the BCD, so it doesn't happen again */
2451 ObjectId
= BootEntry
->Guid
;
2452 BmPurgeOption(BcdHandle
,
2454 BcdOSLoaderBoolean_AdvancedOptionsOneTime
);
2455 BmCloseDataStore(BcdHandle
);
2459 /* Check if one-time options editor should be shown */
2460 if (MiscGetBootOption(BootEntry
->BcdData
,
2461 BcdOSLoaderBoolean_OptionsEditOneTime
))
2465 Status
= BmOpenDataStore(BcdHandle
);
2466 if (NT_SUCCESS(Status
))
2468 /* Delete the option from the BCD, so it doesn't happen again */
2469 ObjectId
= BootEntry
->Guid
;
2470 BmPurgeOption(BcdHandle
,
2472 BcdOSLoaderBoolean_OptionsEditOneTime
);
2473 BmCloseDataStore(BcdHandle
);
2479 /* Disable recovery mode */
2482 /* Store globally which entry we are trying to boot */
2483 BmpSelectedBootEntry
= BootEntry
;
2485 /* Create any devices that aren't yet fully defined for this boot entry */
2486 Status
= BmpCreateDevices(BootEntry
);
2487 if (!NT_SUCCESS(Status
))
2489 /* That failed -- can we launch the recovery environment? */
2495 /* Yes, so return with the WinRe launch code */
2500 /* Is this an OS loader/ */
2501 if (BootEntry
->Flags
& BL_APPLICATION_ENTRY_WINLOAD
)
2503 /* Is the one-time advanced options menu option present? */
2504 Status
= BlGetBootOptionBoolean(BootEntry
->BcdData
,
2505 BcdOSLoaderBoolean_AdvancedOptionsOneTime
,
2507 if (NT_SUCCESS(Status
))
2509 /* Is it turned on? */
2510 if (AdvancedOneTime
)
2512 /* Set the option this once */
2513 BlAppendBootOptionBoolean(BootEntry
,
2514 BcdLibraryBoolean_DisplayAdvancedOptions
);
2518 /* It's not, so disable the option if active */
2519 BlRemoveBootOption(BootEntry
->BcdData
,
2520 BcdLibraryBoolean_DisplayAdvancedOptions
);
2523 /* Remove the one-time option. We've already purged it earlier */
2524 BlRemoveBootOption(BootEntry
->BcdData
,
2525 BcdOSLoaderBoolean_AdvancedOptionsOneTime
);
2528 /* Is the one-time options editor menu option present? */
2529 Status
= BlGetBootOptionBoolean(BootEntry
->BcdData
,
2530 BcdOSLoaderBoolean_OptionsEditOneTime
,
2532 if (NT_SUCCESS(Status
))
2534 /* Is it turned on? */
2537 /* Set the option this once */
2538 BlAppendBootOptionBoolean(BootEntry
,
2539 BcdLibraryBoolean_DisplayOptionsEdit
);
2543 /* It's not, so disable the option if active */
2544 BlRemoveBootOption(BootEntry
->BcdData
,
2545 BcdLibraryBoolean_DisplayOptionsEdit
);
2548 /* Remove the one-time option. We've already purged it earlier */
2549 BlRemoveBootOption(BootEntry
->BcdData
,
2550 BcdOSLoaderBoolean_OptionsEditOneTime
);
2554 /* BCD handling done, transfer execution to this entry */
2555 Status
= BmpTransferExecution(BootEntry
, &LaunchCode
, &DoRecovery
);
2561 /* Check if boot was successfull, or cancelled and we're not doing WinRE */
2562 if (((NT_SUCCESS(Status
)) || (Status
== STATUS_CANCELLED
)) && !(DoRecovery
))
2567 /* Boot failed -- are we doing recovery? */
2570 /* Nope, bail out */
2576 /* Get the recovery sequence */
2577 if (MiscGetBootOption(BootEntry
->BcdData
, BcdLibraryObjectList_RecoverySequence
))
2579 /* Check if the launch depends on auto-recovery being enabled or not */
2580 if ((LaunchCode
== 3) || (LaunchCode
== 5) || (LaunchCode
== 6))
2582 Status
= BlGetBootOptionBoolean(BootEntry
->BcdData
,
2583 BcdLibraryBoolean_AutoRecoveryEnabled
,
2585 if (NT_SUCCESS(Status
))
2587 /* Override the setting */
2588 DoRecovery
= AutoRecovery
;
2594 /* There's no recovery setting */
2598 /* Check if we should restart on failure */
2599 RestartOnFailure
= FALSE
;
2600 BlGetBootOptionBoolean(BlpApplicationEntry
.BcdData
,
2601 BcdLibraryBoolean_RestartOnFailure
,
2604 /* Do the sequence if recovery is on, unless we should restart instead */
2605 DoSequence
= RestartOnFailure
? FALSE
: DoRecovery
;
2608 /* Are we doing the recovery sequence? */
2611 /* Because of automatic recovery? */
2614 #if BL_BITLOCKER_SUPPORT
2615 /* Do bitlocker stuff */
2616 BlFveRegisterBootEntryForTrustedWimBoot(BootEntry
, TRUE
);
2620 /* Launch the recovery sequence*/
2621 Status
= BmLaunchRecoverySequence(BootEntry
, LaunchCode
);
2623 /* Was it launched automatically? */
2626 #if BL_BITLOCKER_SUPPORT
2627 /* Do bitlocker stuff */
2628 BlFveRegisterBootEntryForTrustedWimBoot(BootEntry
, FALSE
);
2631 /* No need to do this again */
2632 AutoRecovery
= FALSE
;
2635 /* Did the recovery sequence work? */
2636 if (NT_SUCCESS(Status
))
2639 return STATUS_SUCCESS
;
2642 /* Remove the sequence, don't do it again */
2643 BlRemoveBootOption(BootEntry
->BcdData
, BcdLibraryObjectList_RecoverySequence
);
2646 /* Recovery sequence also failed, show fatal error */
2647 if (!BmpInternalBootError
)
2649 BmFatalErrorEx(BL_FATAL_ERROR_GENERIC
, Status
, 0, 0, 0);
2652 /* Display the error menu */
2653 ErrorCode
= BmDisplayDumpError(BootEntry
, LaunchCode
);
2656 /* See what the user wants to do */
2664 /* Boot the next entry*/
2668 /* Cancel the boot*/
2669 return STATUS_CANCELLED
;
2672 /* Custom OEM recovery -- open the BCD */
2673 Status
= BmOpenDataStore(BcdHandle
);
2674 if (NT_SUCCESS(Status
))
2676 /* See what the custom sequence is */
2677 Status
= BmProcessCustomAction(BcdHandle
, NULL
);
2680 /* All done, close the BCD */
2683 BmCloseDataStore(BcdHandle
);
2687 case AdvancedOptions
:
2688 /* Show the advanced options next iteration */
2689 BlAppendBootOptionBoolean(BootEntry
, BcdOSLoaderBoolean_AdvancedOptionsOneTime
);
2693 /* Show the options editor next iteration */
2694 BlAppendBootOptionBoolean(BootEntry
, BcdOSLoaderBoolean_OptionsEditOneTime
);
2698 /* Try the recovery sequence next time*/
2704 /* Something unknown */
2705 return STATUS_CANCELLED
;
2709 /* We are booting the next OS, so return success as to not kill the boot */
2710 return STATUS_SUCCESS
;
2716 * The BmMain function implements the Windows Boot Application entrypoint for
2719 * @param BootParameters
2720 * Pointer to the Boot Application Parameter Block.
2722 * @return NT_SUCCESS if the image was loaded correctly, relevant error code
2728 _In_ PBOOT_APPLICATION_PARAMETER_BLOCK BootParameters
2731 NTSTATUS Status
, LibraryStatus
;
2732 BL_LIBRARY_PARAMETERS LibraryParameters
;
2733 PBL_RETURN_ARGUMENTS ReturnArguments
;
2734 PGUID AppIdentifier
;
2735 HANDLE BcdHandle
, ResumeBcdHandle
;
2736 PBL_BCD_OPTION EarlyOptions
;
2738 BOOLEAN XmlLoaded
, DisableIntegrity
, TestSigning
, PersistBootSequence
;
2739 BOOLEAN RebootOnError
, CustomActions
;
2741 PBL_LOADED_APPLICATION_ENTRY BootEntry
;
2743 ULONG SequenceListCount
;
2744 PBL_LOADED_APPLICATION_ENTRY
* BootSequence
;
2746 BOOLEAN ExitBootManager
;
2749 ULONG SequenceCount
;
2751 EfiPrintf(L
"ReactOS UEFI Boot Manager Initializing...\r\n");
2753 /* Reading the BCD can change this later on */
2754 RebootOnError
= FALSE
;
2756 /* Save the start/end-of-POST time */
2757 ApplicationStartTime
= __rdtsc();
2758 PostTime
= ApplicationStartTime
;
2760 /* Setup the boot library parameters for this application */
2761 BlSetupDefaultParameters(&LibraryParameters
);
2762 LibraryParameters
.TranslationType
= BlNone
;
2763 LibraryParameters
.LibraryFlags
= 0x400 | 0x8;
2764 LibraryParameters
.MinimumAllocationCount
= 16;
2765 LibraryParameters
.MinimumHeapSize
= 512 * 1024;
2767 /* Initialize the boot library */
2768 Status
= BlInitializeLibrary(BootParameters
, &LibraryParameters
);
2769 if (!NT_SUCCESS(Status
))
2771 /* Check for failure due to invalid application entry */
2772 if (Status
!= STATUS_INVALID_PARAMETER_9
)
2774 /* Specifically print out what happened */
2775 EfiPrintf(L
"BlInitializeLibrary failed 0x%x\r\n", Status
);
2778 /* Go to exit path */
2782 /* Get the application identifier */
2783 AppIdentifier
= BlGetApplicationIdentifier();
2786 /* None was given, so set our default one */
2787 AppIdentifier
= (PGUID
)&GUID_WINDOWS_BOOTMGR
;
2790 /* Save our identifier */
2791 BmApplicationIdentifier
= *AppIdentifier
;
2793 /* Initialize the file system to open a handle to our root boot directory */
2794 BmFwInitializeBootDirectoryPath();
2796 /* Load and initialize the boot configuration database (BCD) */
2797 Status
= BmOpenDataStore(&BcdHandle
);
2798 if (NT_SUCCESS(Status
))
2800 /* Copy the boot options */
2801 Status
= BlCopyBootOptions(BlpApplicationEntry
.BcdData
, &EarlyOptions
);
2802 if (NT_SUCCESS(Status
))
2805 Status
= BmpUpdateApplicationOptions(BcdHandle
);
2806 if (!NT_SUCCESS(Status
))
2808 /* Log a fatal error */
2809 BmFatalErrorEx(BL_FATAL_ERROR_BCD_PARSE
,
2810 (ULONG_PTR
)L
"\\BCD",
2819 /* Initialize the secure boot machine policy */
2820 Status
= BmSecureBootInitializeMachinePolicy();
2821 if (!NT_SUCCESS(Status
))
2823 BmFatalErrorEx(BL_FATAL_ERROR_SECURE_BOOT
, Status
, 0, 0, 0);
2827 /* Copy the library parameters and add the re-initialization flag */
2828 RtlCopyMemory(&LibraryParameters
,
2829 &BlpLibraryParameters
,
2830 sizeof(LibraryParameters
));
2831 LibraryParameters
.LibraryFlags
|= (BL_LIBRARY_FLAG_REINITIALIZE_ALL
|
2832 BL_LIBRARY_FLAG_REINITIALIZE
);
2834 /* Now that we've parsed the BCD, re-initialize the library */
2835 LibraryStatus
= BlInitializeLibrary(BootParameters
, &LibraryParameters
);
2836 if (!NT_SUCCESS(LibraryStatus
) && (NT_SUCCESS(Status
)))
2838 Status
= LibraryStatus
;
2841 /* Initialize firmware-specific memory regions */
2842 BmFwMemoryInitialize();
2844 /* Initialize the boot status data log (BSD) */
2845 BmpInitializeBootStatusDataLog();
2847 /* Find our XSL stylesheet */
2848 Stylesheet
= BlResourceFindHtml();
2851 /* Awe, no XML. This is actually fatal lol. Can't boot without XML. */
2852 Status
= STATUS_NOT_FOUND
;
2853 EfiPrintf(L
"BlResourceFindMessage failed 0x%x\r\n", STATUS_NOT_FOUND
);
2857 /* Initialize the XML Engine (as a side-effect, resets cursor) */
2858 Status
= BlXmiInitialize(Stylesheet
);
2859 if (!NT_SUCCESS(Status
))
2861 EfiPrintf(L
"\r\nBlXmiInitialize failed 0x%x\r\n", Status
);
2866 /* Check if there's an active bitmap visible */
2867 if (!BlDisplayValidOemBitmap())
2869 /* Nope, make the screen black using BGFX */
2870 if (!NT_SUCCESS(BmpBgDisplayClearScreen(0xFF000000)))
2872 /* BGFX isn't active, use standard display */
2873 BlDisplayClearScreen();
2878 /* Bitlocker will take over screen UI if enabled */
2879 FveDisplayScreen
= BmFveDisplayScreen
;
2882 /* Check if any bypass options are enabled */
2883 BlImgQueryCodeIntegrityBootOptions(&BlpApplicationEntry
,
2886 if (!DisableIntegrity
)
2888 /* Integrity checks are enabled, so validate our signature */
2889 Status
= BmFwVerifySelfIntegrity();
2890 if (!NT_SUCCESS(Status
))
2892 /* Signature invalid, fail boot */
2897 /* Write out the first XML tag */
2898 BlXmiWrite(L
"<bootmgr/>");
2900 /* Check for factory resset */
2901 BlSecureBootCheckForFactoryReset();
2903 /* Load the revocation list */
2904 Status
= BmFwRegisterRevocationList();
2905 if (!NT_SUCCESS(Status
))
2910 /* Register our custom progress routine */
2911 BlUtlRegisterProgressRoutine();
2913 /* Display state is not currently cached */
2914 BmDisplayStateCached
= FALSE
;
2916 /* Check if we need to resume from hibernate */
2917 Status
= BmResumeFromHibernate(&ResumeBcdHandle
);
2918 if (!NT_SUCCESS(Status
))
2923 #ifdef BL_NET_SUPPORT
2924 /* Register multicast printing routine */
2925 BlUtlRegisterMulticastRoutine();
2928 /* Check if restart on failure is enabled */
2929 BlGetBootOptionBoolean(BlpApplicationEntry
.BcdData
,
2930 BcdLibraryBoolean_RestartOnFailure
,
2933 /* Check if the boot sequence is persisted */
2934 Status
= BlGetBootOptionBoolean(BlpApplicationEntry
.BcdData
,
2935 BcdBootMgrBoolean_PersistBootSequence
,
2936 &PersistBootSequence
);
2937 if (!NT_SUCCESS(Status
))
2940 PersistBootSequence
= TRUE
;
2943 /* Check if there's custom actions to take */
2944 Status
= BlGetBootOptionBoolean(BlpApplicationEntry
.BcdData
,
2945 BcdBootMgrBoolean_ProcessCustomActionsFirst
,
2947 if ((NT_SUCCESS(Status
)) && (CustomActions
))
2949 /* We don't suppport this yet */
2950 EfiPrintf(L
"Not implemented\r\n");
2951 Status
= STATUS_NOT_IMPLEMENTED
;
2955 //BlResourceFindMessage(BM_MSG_TEST);
2957 /* At last, enter the boot selection stage */
2961 SequenceList
= NULL
;
2962 BootSequence
= NULL
;
2966 /* We don't have a boot entry nor a sequence ID */
2970 /* Do we have a hardcoded boot sequence set? */
2971 if (!(BootSequence
) && !(GetEntry
))
2973 /* Not yet, read the BCD to see if one is there */
2974 Status
= BlGetBootOptionGuidList(BlpApplicationEntry
.BcdData
,
2975 BcdBootMgrObjectList_BootSequence
,
2977 &SequenceListCount
);
2978 if (NT_SUCCESS(Status
))
2980 /* A GUID list for the boot sequence is set. Extract it */
2981 Status
= BmGetBootSequence(BcdHandle
,
2984 BL_APPLICATION_ENTRY_FIXED_SEQUENCE
,
2987 if (NT_SUCCESS(Status
))
2989 /* Don't get stuck in a loop repeating this sequence */
2990 BlRemoveBootOption(BlpApplicationEntry
.BcdData
,
2991 BcdBootMgrObjectList_BootSequence
);
2993 /* But do check if we should persist it */
2994 if (PersistBootSequence
)
2996 /* Yes -- so go select an entry now */
3001 /* We shouldn't, so wipe it from the BCD too */
3002 Status
= BmPurgeOption(BcdHandle
,
3003 &BmApplicationIdentifier
,
3004 BcdBootMgrObjectList_BootSequence
);
3005 if (!NT_SUCCESS(Status
))
3007 /* Well that failed */
3015 /* No boot entry sequence for us */
3016 BootSequence
= NULL
;
3020 /* Do we have a sequence active, and are we still processing it? */
3021 if ((BootSequence
) && ((GetEntry
) || (SequenceId
< SequenceCount
)))
3023 /* Extract the next entry in the sequence */
3024 BootEntry
= BootSequence
[SequenceId
];
3025 BootSequence
[SequenceId
] = NULL
;
3027 /* Move to the next entry for next time */
3030 /* Unless there won't be a a next time? */
3031 if (SequenceId
== SequenceCount
)
3033 /* Clean up, it's the last entry */
3034 BlMmFreeHeap(BootSequence
);
3035 BootSequence
= NULL
;
3040 /* Get the selected boot entry from the user */
3041 ExitBootManager
= FALSE
;
3042 Status
= BmpGetSelectedBootEntry(BcdHandle
,
3046 if (!(NT_SUCCESS(Status
)) || (ExitBootManager
))
3048 /* Selection failed, or user wants to exit */
3053 /* Did we have a BCD open? */
3056 /* Close it, we'll be opening a new one */
3057 BmCloseDataStore(BcdHandle
);
3061 /* Launch the selected entry */
3062 Status
= BmpLaunchBootEntry(BootEntry
, &BootIndex
, 0, TRUE
);
3063 if (NT_SUCCESS(Status
))
3065 /* Boot worked, uncache display and process the bad memory list */
3066 BmDisplayStateCached
= FALSE
;
3067 BmpProcessBadMemory();
3071 /* Boot failed -- was it user driven? */
3072 if (Status
!= STATUS_CANCELLED
)
3074 /* Nope, remember that booting failed */
3079 /* Yes -- the display is still valid */
3080 BmDisplayStateCached
= TRUE
;
3083 /* Reopen the BCD */
3084 Status
= BmOpenDataStore(&BcdHandle
);
3085 if (!NT_SUCCESS(Status
))
3090 /* Put the BCD options back into our entry */
3091 BlReplaceBootOptions(&BlpApplicationEntry
, EarlyOptions
);
3093 /* Update our options one more time */
3094 Status
= BmpUpdateApplicationOptions(BcdHandle
);
3095 if (NT_SUCCESS(Status
))
3097 /* Boot was 100% OK */
3102 /* Did we have a boot entry? */
3105 /* We can destroy it now */
3106 BlDestroyBootEntry(BootEntry
);
3109 /* Is this the success path? */
3110 if (NT_SUCCESS(Status
))
3112 /* Did we actually boot something? */
3115 /* Bope, fail out */
3120 /* This is the failure path... should we reboot? */
3130 /* Check if we got here due to an internal error */
3131 if (BmpInternalBootError
)
3133 /* If XML is available, display the error */
3136 //BmDisplayDumpError(0, 0);
3140 /* Don't do a fatal error -- return back to firmware */
3145 /* Log a general fatal error once we're here */
3146 BmFatalErrorEx(BL_FATAL_ERROR_GENERIC
, Status
, 0, 0, 0);
3149 /* Check if we should reboot */
3150 if ((RebootOnError
) ||
3151 (BlpApplicationEntry
.Flags
& BL_APPLICATION_ENTRY_REBOOT_ON_ERROR
))
3153 /* Reboot the box */
3155 Status
= STATUS_SUCCESS
;
3159 /* Return back to the caller with the error argument encoded */
3160 ReturnArguments
= (PVOID
)((ULONG_PTR
)BootParameters
+ BootParameters
->ReturnArgumentsOffset
);
3161 ReturnArguments
->Version
= BL_RETURN_ARGUMENTS_VERSION
;
3162 ReturnArguments
->Status
= Status
;
3164 /* Tear down the boot library */
3168 /* Return back status */