2 * COPYRIGHT: See COPYING.ARM in the top level directory
3 * PROJECT: ReactOS UEFI Boot Manager
4 * FILE: boot/environ/app/bootmgr/bootmgr.c
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
;
36 /* FUNCTIONS *****************************************************************/
40 _In_ HANDLE BcdHandle
,
42 _In_ PBL_BCD_OPTION
*OptionList
47 ULONG ElementSize
, ElementCount
, i
, OptionsSize
;
49 PBCD_ELEMENT_HEADER Header
;
50 PBCD_ELEMENT BcdElements
;
51 PBL_BCD_OPTION Options
, Option
, PreviousOption
, DeviceOptions
;
52 PBCD_DEVICE_OPTION DeviceOption
;
56 /* Open the BCD object requested */
59 Status
= BcdOpenObject(BcdHandle
, ObjectId
, &ObjectHandle
);
60 if (!NT_SUCCESS(Status
))
65 /* Do the initial enumeration to get the size needed */
67 Status
= BcdEnumerateAndUnpackElements(BcdHandle
,
72 if (Status
!= STATUS_BUFFER_TOO_SMALL
)
74 /* If we got success, that doesn't make any sense */
75 if (NT_SUCCESS(Status
))
77 Status
= STATUS_INVALID_PARAMETER
;
84 /* Allocate a large-enough buffer */
85 BcdElements
= BlMmAllocateHeap(ElementSize
);
88 Status
= STATUS_NO_MEMORY
;
92 /* Now do the real enumeration to fill out the elements buffer */
93 Status
= BcdEnumerateAndUnpackElements(BcdHandle
,
98 if (!NT_SUCCESS(Status
))
103 /* Go through each BCD option to add the sizes up */
105 for (i
= 0; i
< ElementCount
; i
++)
107 OptionsSize
+= BcdElements
[i
].Header
->Size
+ sizeof(BL_BCD_OPTION
);
110 /* Allocate the required BCD option list */
111 Options
= BlMmAllocateHeap(OptionsSize
);
114 Status
= STATUS_NO_MEMORY
;
119 RtlZeroMemory(Options
, OptionsSize
);
121 /* Start going through each option */
122 PreviousOption
= NULL
;
124 EfiPrintf(L
"BCD Options found: %d\r\n", ElementCount
);
125 for (i
= 0; i
< ElementCount
; i
++)
127 /* Read the header and type */
128 Header
= BcdElements
[i
].Header
;
129 Type
.PackedValue
= Header
->Type
;
131 /* Check if this option isn't already present */
132 if (!MiscGetBootOption(Options
, Type
.PackedValue
))
134 /* It's a new option. Did we have an existing one? */
137 /* Link it to this new one */
138 PreviousOption
->NextEntryOffset
= (ULONG_PTR
)Option
-
142 /* Capture the type, size, data, and offset */
143 Option
->Type
= Type
.PackedValue
;
144 Option
->DataSize
= Header
->Size
;
145 RtlCopyMemory(Option
+ 1, BcdElements
[i
].Body
, Header
->Size
);
146 Option
->DataOffset
= sizeof(BL_BCD_OPTION
);
148 /* Check if this was a device */
149 if (Type
.Format
== BCD_TYPE_DEVICE
)
152 DeviceOption
= (PBCD_DEVICE_OPTION
)(Option
+ 1);
153 DeviceId
= DeviceOption
->AssociatedEntry
;
155 /* Look up the options for that GUID */
156 Status
= BmGetOptionList(BcdHandle
, &DeviceId
, &DeviceOptions
);
157 if (NT_SUCCESS(Status
))
159 /* Device data is after the device option */
160 DeviceData
= (PVOID
)((ULONG_PTR
)DeviceOption
+ Header
->Size
);
163 RtlCopyMemory(DeviceData
,
165 BlGetBootOptionListSize(DeviceOptions
));
167 /* Don't need this anymore */
168 BlMmFreeHeap(DeviceOptions
);
170 /* Write the offset of the device options */
171 Option
->ListOffset
= (ULONG_PTR
)DeviceData
-
176 /* Save the previous option and go to the next one */
177 PreviousOption
= Option
;
178 Option
= (PBL_BCD_OPTION
)((ULONG_PTR
)Option
+
179 BlGetBootOptionSize(Option
));
183 /* Return the pointer back, we've made it! */
184 *OptionList
= Options
;
185 Status
= STATUS_SUCCESS
;
188 /* Did we allocate a local buffer? Free it if so */
191 BlMmFreeHeap(BcdElements
);
194 /* Was the key open? Close it if so */
197 BiCloseKey(ObjectHandle
);
200 /* Return the option list parsing status */
205 BmpUpdateApplicationOptions (
206 _In_ HANDLE BcdHandle
210 PBL_BCD_OPTION Options
;
212 /* Get the boot option list */
213 Status
= BmGetOptionList(BcdHandle
, &BmApplicationIdentifier
, &Options
);
214 if (!NT_SUCCESS(Status
))
219 /* Append the options, free the local buffer, and return success */
220 BlAppendBootOptions(&BlpApplicationEntry
, Options
);
221 BlMmFreeHeap(Options
);
222 return STATUS_SUCCESS
;
226 BmpFwGetApplicationDirectoryPath (
227 _In_ PUNICODE_STRING ApplicationDirectoryPath
231 ULONG i
, AppPathLength
;
232 PWCHAR ApplicationPath
, PathCopy
;
234 /* Clear the incoming string */
235 ApplicationDirectoryPath
->Length
= 0;
236 ApplicationDirectoryPath
->MaximumLength
= 0;
237 ApplicationDirectoryPath
->Buffer
= 0;
239 /* Get the boot application path */
240 ApplicationPath
= NULL
;
241 Status
= BlGetBootOptionString(BlpApplicationEntry
.BcdData
,
242 BcdLibraryString_ApplicationPath
,
244 if (NT_SUCCESS(Status
))
246 /* Calculate the length of the application path */
247 for (i
= wcslen(ApplicationPath
) - 1; i
> 0; i
--)
249 /* Keep going until the path separator */
250 if (ApplicationPath
[i
] == OBJ_NAME_PATH_SEPARATOR
)
256 /* Check if we have space for one more character */
257 Status
= RtlULongAdd(i
, 1, &AppPathLength
);
258 if (NT_SUCCESS(Status
))
260 /* Check if it's safe to multiply by two */
261 Status
= RtlULongMult(AppPathLength
, sizeof(WCHAR
), &AppPathLength
);
262 if (NT_SUCCESS(Status
))
264 /* Allocate a copy for the string */
265 PathCopy
= BlMmAllocateHeap(AppPathLength
);
268 /* NULL-terminate it */
269 RtlCopyMemory(PathCopy
,
271 AppPathLength
- sizeof(UNICODE_NULL
));
272 PathCopy
[AppPathLength
] = UNICODE_NULL
;
274 /* Finally, initialize the outoing string */
275 RtlInitUnicodeString(ApplicationDirectoryPath
, PathCopy
);
279 /* No memory, fail */
280 Status
= STATUS_NO_MEMORY
;
286 /* Check if we had an application path */
289 /* No longer need this, free it */
290 BlMmFreeHeap(ApplicationPath
);
298 BmFwInitializeBootDirectoryPath (
305 UNICODE_STRING BcdPath
;
307 ULONG FileHandle
, DeviceHandle
;
309 /* Initialize everything for failure */
310 BcdPath
.MaximumLength
= 0;
311 BcdPath
.Buffer
= NULL
;
317 /* Try to open the boot device */
318 Status
= BlpDeviceOpen(BlpBootDevice
,
319 BL_DEVICE_READ_ACCESS
,
322 if (!NT_SUCCESS(Status
))
324 EfiPrintf(L
"Device open failed: %lx\r\n", Status
);
328 /* Get the directory path */
329 Status
= BmpFwGetApplicationDirectoryPath(&BcdPath
);
330 BcdDirectory
= BcdPath
.Buffer
;
331 if (!NT_SUCCESS(Status
))
336 /* Add the BCD file name to it */
337 FinalSize
= BcdPath
.MaximumLength
+ sizeof(L
"\\BCD") - sizeof(UNICODE_NULL
);
338 if (FinalSize
< BcdPath
.MaximumLength
)
343 /* Allocate space for the final path */
344 FinalPath
= BlMmAllocateHeap(FinalSize
);
351 RtlZeroMemory(FinalPath
, FinalSize
);
352 RtlCopyMemory(FinalPath
, BcdDirectory
, BcdPath
.MaximumLength
);
353 wcsncat(FinalPath
, L
"\\BCD", FinalSize
/ sizeof(WCHAR
));
355 /* Try to open the file */
356 Status
= BlFileOpen(DeviceHandle
,
360 if (!NT_SUCCESS(Status
))
362 BootDirectory
= BcdDirectory
;
366 /* Save the boot directory */
367 BootDirectory
= L
"\\EFI\\Boot"; /* Should be EFI\\ReactOS\\Boot */
370 /* Free all the allocations we made */
373 Status
= BlMmFreeHeap(BcdDirectory
);
377 Status
= BlMmFreeHeap(FinalPath
);
380 /* Close the BCD file */
381 if (FileHandle
!= -1)
383 Status
= BlFileClose(FileHandle
);
386 /* Close the boot device */
387 if (DeviceHandle
!= -1)
389 Status
= BlDeviceClose(DeviceHandle
);
392 /* Return back to the caller */
401 /* Don't yet handled boot.ini */
402 return STATUS_NOT_FOUND
;
406 BmpFatalErrorMessageFilter (
407 _In_ NTSTATUS ErrorStatus
,
408 _Out_ PULONG ErrorResourceId
413 /* Assume no message for now, check for known status message */
417 /* Convert each status to a resource ID */
418 case STATUS_UNEXPECTED_IO_ERROR
:
419 *ErrorResourceId
= 9017;
422 case STATUS_IMAGE_CHECKSUM_MISMATCH
:
423 *ErrorResourceId
= 9018;
425 case STATUS_INVALID_IMAGE_WIN_64
:
426 *ErrorResourceId
= 9016;
429 *ErrorResourceId
= 9019;
433 *ErrorResourceId
= 9013;
437 /* Return the type of message */
446 /* Check if a boot error is present */
447 if (BmpPackedBootError
.BootError
)
450 BlMmFreeHeap(BmpPackedBootError
.BootError
);
451 BmpPackedBootError
.BootError
= NULL
;
454 /* Zero out the packed buffer */
455 BmpPackedBootError
.Size
= 0;
456 BmpInternalBootError
= NULL
;
457 RtlZeroMemory(&BmpErrorBuffer
, sizeof(BmpErrorBuffer
));
462 _In_ ULONG ErrorCode
,
463 _In_ NTSTATUS ErrorStatus
,
464 _In_ ULONG ErrorMsgId
,
465 _In_ PWCHAR FileName
,
469 PWCHAR ErrorMsgString
;
471 /* Check if we already had an error */
472 if (BmpInternalBootError
)
478 /* Find the string for this error ID */
479 ErrorMsgString
= BlResourceFindMessage(ErrorMsgId
);
482 /* Fill out the error buffer */
483 BmpErrorBuffer
.Unknown1
= 0;
484 BmpErrorBuffer
.Unknown2
= 0;
485 BmpErrorBuffer
.ErrorString
= ErrorMsgString
;
486 BmpErrorBuffer
.FileName
= FileName
;
487 BmpErrorBuffer
.ErrorCode
= ErrorCode
;
488 BmpErrorBuffer
.ErrorStatus
= ErrorStatus
;
489 BmpErrorBuffer
.HelpMsgId
= HelpMsgId
;
490 BmpInternalBootError
= &BmpErrorBuffer
;
496 _In_ ULONG ErrorCode
,
497 _In_ ULONG_PTR Parameter1
,
498 _In_ ULONG_PTR Parameter2
,
499 _In_ ULONG_PTR Parameter3
,
500 _In_ ULONG_PTR Parameter4
503 PWCHAR FileName
, Buffer
;
504 NTSTATUS ErrorStatus
;
505 WCHAR FormatString
[256];
506 ULONG ErrorResourceId
, ErrorHelpId
;
507 BOOLEAN Restart
, NoError
;
509 /* Assume no buffer for now */
512 /* Check what error code is being raised */
515 /* Error reading the BCD */
516 case BL_FATAL_ERROR_BCD_READ
:
518 /* Check if we have a name for the BCD file */
521 /* Check if the name fits into our buffer */
522 FileName
= (PWCHAR
)Parameter1
;
523 if (wcslen(FileName
) < sizeof(BmpFileNameBuffer
))
525 /* Copy it in there */
526 Buffer
= BmpFileNameBuffer
;
527 wcsncpy(BmpFileNameBuffer
,
529 RTL_NUMBER_OF(BmpFileNameBuffer
));
533 /* If we don't have a buffer, use an empty one */
536 Buffer
= ParentFileName
;
539 /* The NTSTATUS code is in parameter 2*/
540 ErrorStatus
= (NTSTATUS
)Parameter2
;
542 /* Build the error string */
543 swprintf(FormatString
,
544 L
"\nAn error occurred (%08x) while attempting "
545 L
"to read the boot configuration data file %s\n",
549 /* Select the resource ID message */
550 ErrorResourceId
= 9002;
553 case BL_FATAL_ERROR_BCD_PARSE
:
555 /* File name isin parameter 1 */
556 FileName
= (PWCHAR
)Parameter1
;
558 /* The NTSTATUS code is in parameter 2*/
559 ErrorStatus
= (NTSTATUS
)Parameter2
;
561 /* Build the error string */
562 swprintf(FormatString
,
563 L
"\nThe boot configuration file %s is invalid (%08x).\n",
567 /* Select the resource ID message */
568 ErrorResourceId
= 9015;
571 case BL_FATAL_ERROR_GENERIC
:
573 /* The NTSTATUS code is in parameter 1*/
574 ErrorStatus
= (NTSTATUS
)Parameter1
;
576 /* Build the error string */
577 swprintf(FormatString
,
578 L
"\nThe boot manager experienced an error (%08x).\n",
581 /* Select the resource ID message */
582 ErrorResourceId
= 9005;
587 /* The rest is not yet handled */
588 EfiPrintf(L
"Unexpected fatal error: %lx\r\n", ErrorCode
);
593 /* Check if the BCD option for restart is set */
594 BlGetBootOptionBoolean(BlpApplicationEntry
.BcdData
,
595 BcdLibraryBoolean_RestartOnFailure
,
599 /* Yes, so no error should be shown since we'll auto-restart */
604 /* Check if the option for not showing errors is set in the BCD */
605 BlGetBootOptionBoolean(BlpApplicationEntry
.BcdData
,
606 BcdBootMgrBoolean_NoErrorDisplay
,
610 /* Do we want an error? */
613 /* Yep, print it and then raise an error */
614 BlStatusPrint(FormatString
);
615 BlStatusError(1, ErrorCode
, Parameter1
, Parameter2
, Parameter3
);
618 /* Get the help message ID */
619 ErrorHelpId
= BmpFatalErrorMessageFilter(ErrorStatus
, &ErrorResourceId
);
620 BmpErrorLog(ErrorCode
, ErrorStatus
, ErrorResourceId
, Buffer
, ErrorHelpId
);
625 _In_ PWCHAR FileName
,
626 _Out_ PWCHAR
* FullPath
630 ULONG BootDirLength
, PathLength
;
632 /* Compute the length of the directory, and add a NUL */
633 BootDirLength
= wcslen(BootDirectory
);
634 Status
= RtlULongAdd(BootDirLength
, 1, &BootDirLength
);
635 if (!NT_SUCCESS(Status
))
640 /* Add the length of the file, make sure it fits */
641 PathLength
= wcslen(FileName
);
642 Status
= RtlULongAdd(PathLength
, BootDirLength
, &PathLength
);
643 if (!NT_SUCCESS(Status
))
648 /* Convert to bytes */
649 Status
= RtlULongLongToULong(PathLength
* sizeof(WCHAR
), &PathLength
);
650 if (!NT_SUCCESS(Status
))
655 /* Allocate the full path */
656 *FullPath
= BlMmAllocateHeap(PathLength
);
659 /* Copy the directory followed by the file name */
660 wcsncpy(*FullPath
, BootDirectory
, PathLength
/ sizeof(WCHAR
));
661 wcsncat(*FullPath
, FileName
, PathLength
/ sizeof(WCHAR
));
665 /* Bail out since we have no memory */
666 Status
= STATUS_NO_MEMORY
;
670 /* Return to caller */
679 /* Check if boot.ini data needs to be freed */
682 EfiPrintf(L
"Not handled\r\n");
685 /* Dereference the hive and close the key */
686 BiDereferenceHive(Handle
);
696 PBL_DEVICE_DESCRIPTOR BcdDevice
;
697 PWCHAR BcdPath
, FullPath
, PathBuffer
;
699 ULONG PathLength
, FullSize
;
701 UNICODE_STRING BcdString
;
703 /* Initialize variables */
709 /* Check if a boot.ini file exists */
710 Status
= BmOpenBootIni();
711 if (NT_SUCCESS(Status
))
713 BmBootIniUsed
= TRUE
;
716 /* Check on which device the BCD is */
717 Status
= BlGetBootOptionDevice(BlpApplicationEntry
.BcdData
,
718 BcdBootMgrDevice_BcdDevice
,
721 if (!NT_SUCCESS(Status
))
723 /* It's not on a custom device, so it must be where we are */
724 Status
= BlGetBootOptionDevice(BlpApplicationEntry
.BcdData
,
725 BcdLibraryDevice_ApplicationDevice
,
728 if (!NT_SUCCESS(Status
))
730 /* This BCD option is required */
735 /* Next, check what file contains the BCD */
736 Status
= BlGetBootOptionString(BlpApplicationEntry
.BcdData
,
737 BcdBootMgrString_BcdFilePath
,
739 if (NT_SUCCESS(Status
))
741 /* We don't handle custom BCDs yet */
742 EfiPrintf(L
"Not handled: %s\r\n", BcdPath
);
743 Status
= STATUS_NOT_IMPLEMENTED
;
747 /* Now check if the BCD is on a remote share */
748 if (BcdDevice
->DeviceType
== UdpDevice
)
750 /* Nope. Nope. Nope */
751 EfiPrintf(L
"Not handled\r\n");
752 Status
= STATUS_NOT_IMPLEMENTED
;
756 /* Otherwise, compute the hardcoded path of the BCD */
757 Status
= BmpFwGetFullPath(L
"\\BCD", &FullPath
);
758 if (!NT_SUCCESS(Status
))
760 /* User the raw path */
761 PathBuffer
= BcdPath
;
765 /* Use the path we got */
766 PathBuffer
= FullPath
;
770 /* Check if we failed to get the BCD path */
771 if (!NT_SUCCESS(Status
))
776 /* Add a NUL to the path, make sure it'll fit */
777 PathLength
= wcslen(PathBuffer
);
778 Status
= RtlULongAdd(PathLength
, 1, &PathLength
);
779 if (!NT_SUCCESS(Status
))
784 /* Convert to bytes */
785 Status
= RtlULongLongToULong(PathLength
* sizeof(WCHAR
), &PathLength
);
786 if (!NT_SUCCESS(Status
))
791 /* Now add the size of the path to the device path, check if it fits */
792 Status
= RtlULongAdd(PathLength
, BcdDevice
->Size
, &FullSize
);
793 if (!NT_SUCCESS(Status
))
798 /* Allocate a final structure to hold both entities */
799 FinalBuffer
= BlMmAllocateHeap(FullSize
);
802 Status
= STATUS_NO_MEMORY
;
806 /* Copy the device path and file path into the final buffer */
807 RtlCopyMemory(FinalBuffer
, BcdDevice
, BcdDevice
->Size
);
808 RtlCopyMemory((PVOID
)((ULONG_PTR
)FinalBuffer
+ BcdDevice
->Size
),
812 /* Now tell the BCD engine to open the store */
813 BcdString
.Length
= FullSize
;
814 BcdString
.MaximumLength
= FullSize
;
815 BcdString
.Buffer
= FinalBuffer
;
816 Status
= BcdOpenStoreFromFile(&BcdString
, Handle
);
818 /* Free our final buffer */
819 BlMmFreeHeap(FinalBuffer
);
822 /* Did we allocate a device? */
826 BlMmFreeHeap(BcdDevice
);
829 /* Is this the failure path? */
830 if (!NT_SUCCESS(Status
))
832 /* Raise a fatal error */
833 BmFatalErrorEx(BL_FATAL_ERROR_BCD_READ
,
834 (ULONG_PTR
)PathBuffer
,
840 /* Did we get an allocated path? */
841 if ((PathBuffer
) && (HavePath
))
844 BlMmFreeHeap(PathBuffer
);
847 /* Return back to the caller */
851 typedef struct _BL_BSD_LOG_OBJECT
858 } BL_BSD_LOG_OBJECT
, *PBL_BSD_LOG_OBJECT
;
860 BL_BSD_LOG_OBJECT BsdpLogObject
;
861 BOOLEAN BsdpLogObjectInitialized
;
865 _In_ PBL_DEVICE_DESCRIPTOR LogDevice
,
872 /* Don't initialize twice */
873 if (BsdpLogObjectInitialized
)
878 /* Set invalid IDs for now */
879 BsdpLogObject
.DeviceId
= -1;
880 BsdpLogObject
.FileId
= -1;
882 /* Open the BSD device */
883 Status
= BlpDeviceOpen(LogDevice
,
884 BL_DEVICE_READ_ACCESS
| BL_DEVICE_WRITE_ACCESS
,
886 &BsdpLogObject
.DeviceId
);
887 if (!NT_SUCCESS(Status
))
889 /* Welp that didn't work */
893 /* Now open the BSD itself */
894 Status
= BlFileOpen(BsdpLogObject
.DeviceId
,
896 BL_FILE_READ_ACCESS
| BL_FILE_WRITE_ACCESS
,
897 &BsdpLogObject
.FileId
);
898 if (!NT_SUCCESS(Status
))
904 /* The BSD is open. Start doing stuff to it */
905 EfiPrintf(L
"Unimplemented BSD path\r\n");
906 Status
= STATUS_NOT_IMPLEMENTED
;
909 /* Close the BSD if we had it open */
910 if (BsdpLogObject
.FileId
!= -1)
912 BlFileClose(BsdpLogObject
.FileId
);
915 /* Close the device if we had it open */
916 if (BsdpLogObject
.DeviceId
!= -1)
918 BlDeviceClose(BsdpLogObject
.DeviceId
);
921 /* Set BSD object to its uninitialized state */
922 BsdpLogObjectInitialized
= FALSE
;
923 BsdpLogObject
.FileId
= 0;
924 BsdpLogObject
.DeviceId
= 0;
925 BsdpLogObject
.Flags
= 0;
926 BsdpLogObject
.Unknown
= 0;
927 BsdpLogObject
.Size
= 0;
931 BmpInitializeBootStatusDataLog (
936 PBL_DEVICE_DESCRIPTOR BsdDevice
;
941 /* Initialize locals */
946 /* Check if the BSD is stored in a custom device */
947 Status
= BlGetBootOptionDevice(BlpApplicationEntry
.BcdData
,
948 BcdLibraryDevice_BsdLogDevice
,
951 if (!NT_SUCCESS(Status
))
953 /* Nope, use the boot device */
954 BsdDevice
= BlpBootDevice
;
957 /* Check if the path is custom as well */
958 Status
= BlGetBootOptionString(BlpApplicationEntry
.BcdData
,
959 BcdLibraryString_BsdLogPath
,
961 if (!NT_SUCCESS(Status
))
963 /* Nope, use our default path */
964 Status
= BmpFwGetFullPath(L
"\\bootstat.dat", &BsdPath
);
965 if (!NT_SUCCESS(Status
))
970 /* Set preserve flag */
975 /* Set preserve flag */
979 /* Finally, check if the BSD should be preserved */
980 Status
= BlGetBootOptionBoolean(BlpApplicationEntry
.BcdData
,
981 BcdLibraryBoolean_PreserveBsdLog
,
983 if (!(NT_SUCCESS(Status
)) || !(PreserveBsd
))
985 /* We failed to read, or we were asked not to preserve it */
989 /* Initialize the log */
990 BlBsdInitializeLog(BsdDevice
, BsdPath
, Flags
);
992 /* Free the BSD device descriptor if we had one */
995 BlMmFreeHeap(BsdDevice
);
998 /* Free the BSD path if we had one */
999 if ((Flags
) && (BsdPath
))
1001 BlMmFreeHeap(BsdPath
);
1006 BmFwMemoryInitialize (
1011 PHYSICAL_ADDRESS PhysicalAddress
;
1012 BL_ADDRESS_RANGE AddressRange
;
1014 /* Select the range below 1MB */
1015 AddressRange
.Maximum
= 0xFFFFF;
1016 AddressRange
.Minimum
= 0;
1018 /* Allocate one reserved page with the "reserved" attribute */
1019 Status
= MmPapAllocatePhysicalPagesInRange(&PhysicalAddress
,
1020 BlApplicationReserved
,
1024 &MmMdlUnmappedAllocated
,
1026 BL_MM_REQUEST_DEFAULT_TYPE
);
1027 if (!NT_SUCCESS(Status
))
1029 /* Print a message on error, but keep going */
1030 BlStatusPrint(L
"BmFwMemoryInitialize: Failed to allocate a page below 1MB. Status: 0x%08x\r\n",
1036 BmpBgDisplayClearScreen (
1040 /* Not yet supported */
1041 return STATUS_NOT_IMPLEMENTED
;
1050 EfiPrintf(L
"XML: %s\r\n", XmlTag
);
1051 return STATUS_NOT_IMPLEMENTED
;
1056 _In_ PWCHAR Stylesheet
1059 /* Reset the cursor type */
1060 BlDisplaySetCursorType(0);
1062 /* Nope, not doing any XML stuff */
1063 return STATUS_SUCCESS
;
1067 BlImgQueryCodeIntegrityBootOptions (
1068 _In_ PBL_LOADED_APPLICATION_ENTRY ApplicationEntry
,
1069 _Out_ PBOOLEAN IntegrityChecksDisabled
,
1070 _Out_ PBOOLEAN TestSigningEnabled
1077 /* Check if /DISABLEINTEGRITYCHECKS is on */
1078 Status
= BlGetBootOptionBoolean(ApplicationEntry
->BcdData
,
1079 BcdLibraryBoolean_DisableIntegrityChecks
,
1081 *IntegrityChecksDisabled
= NT_SUCCESS(Status
) && (Value
);
1083 /* Check if /TESTSIGNING is on */
1084 Status
= BlGetBootOptionBoolean(ApplicationEntry
->BcdData
,
1085 BcdLibraryBoolean_AllowPrereleaseSignatures
,
1087 *TestSigningEnabled
= NT_SUCCESS(Status
) && (Value
);
1091 BmFwVerifySelfIntegrity (
1095 /* Check if we're booted by UEFI off the DVD directlry */
1096 if ((BlpBootDevice
->DeviceType
== LocalDevice
) &&
1097 (BlpBootDevice
->Local
.Type
== CdRomDevice
) &&
1098 (BlpApplicationFlags
& BL_APPLICATION_FLAG_CONVERTED_FROM_EFI
))
1100 /* Windows actually bypasses integrity checks in this case. Works for us */
1101 return STATUS_SUCCESS
;
1104 /* Our binaries aren't signed, so always return failure */
1109 BmFwRegisterRevocationList (
1114 BOOLEAN SecureBootEnabled
;
1116 /* Is SecureBoot enabled? */
1117 Status
= BlSecureBootIsEnabled(&SecureBootEnabled
);
1118 if ((NT_SUCCESS(Status
)) && (SecureBootEnabled
))
1120 EfiPrintf(L
"SB not implemented revok\r\n");
1121 return STATUS_NOT_IMPLEMENTED
;
1125 /* Nothing to do without SecureBoot */
1126 Status
= STATUS_SUCCESS
;
1129 /* Return revocation result back to caller */
1134 BmResumeFromHibernate (
1135 _Out_ PHANDLE BcdResumeHandle
1139 BOOLEAN AttemptResume
;
1141 /* Should we attempt to resume from hibernation? */
1142 Status
= BlGetBootOptionBoolean(BlpApplicationEntry
.BcdData
,
1143 BcdBootMgrBoolean_AttemptResume
,
1145 if (!NT_SUCCESS(Status
))
1147 /* Nope. Is automatic restart on crash enabled? */
1148 AttemptResume
= FALSE
;
1149 Status
= BlGetBootOptionBoolean(BlpApplicationEntry
.BcdData
,
1150 BcdOSLoaderBoolean_DisableCrashAutoReboot
,
1152 AttemptResume
= (NT_SUCCESS(Status
) && (AttemptResume
));
1155 /* Don't do anything if there's no need to resume anything */
1158 return STATUS_SUCCESS
;
1161 /* Not yet implemented */
1162 EfiPrintf(L
"Resume not supported\r\n");
1163 return STATUS_NOT_IMPLEMENTED
;
1167 BmpProcessBadMemory (
1171 EfiPrintf(L
"Bad page list persistence \r\n");
1172 return STATUS_NOT_IMPLEMENTED
;
1177 _In_ HANDLE BcdHandle
,
1178 _In_ PGUID ObjectId
,
1182 EfiPrintf(L
"Key BCD delete not yet implemented\r\n");
1183 return STATUS_NOT_IMPLEMENTED
;
1188 _In_ HANDLE BcdHandle
,
1189 _In_ PGUID SequenceList
,
1190 _In_ ULONG SequenceListCount
,
1192 _Out_ PBL_LOADED_APPLICATION_ENTRY
** BootSequence
,
1193 _Out_ PULONG SequenceCount
1196 EfiPrintf(L
"Fixed sequences not yet supported\r\n");
1198 *BootSequence
= NULL
;
1199 return STATUS_NOT_IMPLEMENTED
;
1203 BmpGetSelectedBootEntry (
1204 _In_ HANDLE BcdHandle
,
1205 _Out_ PBL_LOADED_APPLICATION_ENTRY
*SelectedBootEntry
,
1206 _Out_ PULONG EntryIndex
,
1207 _Out_ PBOOLEAN ExitBootManager
1210 EfiPrintf(L
"Boot selection not yet implemented\r\n");
1211 return STATUS_NOT_IMPLEMENTED
;
1215 BmpLaunchBootEntry (
1216 _In_ PBL_LOADED_APPLICATION_ENTRY BootEntry
,
1217 _Out_ PULONG EntryIndex
,
1219 _In_ BOOLEAN LaunchWinRe
1222 EfiPrintf(L
"Boot launch not yet implemented\r\n");
1223 return STATUS_NOT_IMPLEMENTED
;
1229 * The BmMain function implements the Windows Boot Application entrypoint for
1232 * @param BootParameters
1233 * Pointer to the Boot Application Parameter Block.
1235 * @return NT_SUCCESS if the image was loaded correctly, relevant error code
1241 _In_ PBOOT_APPLICATION_PARAMETER_BLOCK BootParameters
1244 NTSTATUS Status
, LibraryStatus
;
1245 BL_LIBRARY_PARAMETERS LibraryParameters
;
1246 PBL_RETURN_ARGUMENTS ReturnArguments
;
1247 PGUID AppIdentifier
;
1248 HANDLE BcdHandle
, ResumeBcdHandle
;
1249 PBL_BCD_OPTION EarlyOptions
;
1251 BOOLEAN XmlLoaded
, DisableIntegrity
, TestSigning
, PersistBootSequence
;
1252 BOOLEAN RebootOnError
, CustomActions
;
1254 PBL_LOADED_APPLICATION_ENTRY BootEntry
;
1256 ULONG SequenceListCount
;
1257 PBL_LOADED_APPLICATION_ENTRY
* BootSequence
;
1259 BOOLEAN ExitBootManager
;
1262 ULONG SequenceCount
;
1264 EfiPrintf(L
"ReactOS UEFI Boot Manager Initializing...\r\n");
1266 /* Reading the BCD can change this later on */
1267 RebootOnError
= FALSE
;
1269 /* Save the start/end-of-POST time */
1270 ApplicationStartTime
= __rdtsc();
1271 PostTime
= ApplicationStartTime
;
1273 /* Setup the boot library parameters for this application */
1274 BlSetupDefaultParameters(&LibraryParameters
);
1275 LibraryParameters
.TranslationType
= BlNone
;
1276 LibraryParameters
.LibraryFlags
= 0x400 | 0x8;
1277 LibraryParameters
.MinimumAllocationCount
= 16;
1278 LibraryParameters
.MinimumHeapSize
= 512 * 1024;
1280 /* Initialize the boot library */
1281 Status
= BlInitializeLibrary(BootParameters
, &LibraryParameters
);
1282 if (!NT_SUCCESS(Status
))
1284 /* Check for failure due to invalid application entry */
1285 if (Status
!= STATUS_INVALID_PARAMETER_9
)
1287 /* Specifically print out what happened */
1288 EfiPrintf(L
"BlInitializeLibrary failed 0x%x\r\n", Status
);
1291 /* Go to exit path */
1295 /* Get the application identifier */
1296 AppIdentifier
= BlGetApplicationIdentifier();
1299 /* None was given, so set our default one */
1300 AppIdentifier
= (PGUID
)&GUID_WINDOWS_BOOTMGR
;
1303 /* Save our identifier */
1304 BmApplicationIdentifier
= *AppIdentifier
;
1306 /* Initialize the file system to open a handle to our root boot directory */
1307 BmFwInitializeBootDirectoryPath();
1309 /* Load and initialize the boot configuration database (BCD) */
1310 Status
= BmOpenDataStore(&BcdHandle
);
1311 if (NT_SUCCESS(Status
))
1313 /* Copy the boot options */
1314 Status
= BlCopyBootOptions(BlpApplicationEntry
.BcdData
, &EarlyOptions
);
1315 if (NT_SUCCESS(Status
))
1318 Status
= BmpUpdateApplicationOptions(BcdHandle
);
1319 if (!NT_SUCCESS(Status
))
1321 /* Log a fatal error */
1322 BmFatalErrorEx(BL_FATAL_ERROR_BCD_PARSE
,
1323 (ULONG_PTR
)L
"\\BCD",
1332 /* Initialize the secure boot machine policy */
1333 Status
= BmSecureBootInitializeMachinePolicy();
1334 if (!NT_SUCCESS(Status
))
1336 BmFatalErrorEx(BL_FATAL_ERROR_SECURE_BOOT
, Status
, 0, 0, 0);
1340 /* Copy the library parameters and add the re-initialization flag */
1341 RtlCopyMemory(&LibraryParameters
,
1342 &BlpLibraryParameters
,
1343 sizeof(LibraryParameters
));
1344 LibraryParameters
.LibraryFlags
|= (BL_LIBRARY_FLAG_REINITIALIZE_ALL
|
1345 BL_LIBRARY_FLAG_REINITIALIZE
);
1347 /* Now that we've parsed the BCD, re-initialize the library */
1348 LibraryStatus
= BlInitializeLibrary(BootParameters
, &LibraryParameters
);
1349 if (!NT_SUCCESS(LibraryStatus
) && (NT_SUCCESS(Status
)))
1351 Status
= LibraryStatus
;
1354 /* Initialize firmware-specific memory regions */
1355 BmFwMemoryInitialize();
1357 /* Initialize the boot status data log (BSD) */
1358 BmpInitializeBootStatusDataLog();
1360 /* Find our XSL stylesheet */
1361 Stylesheet
= BlResourceFindHtml();
1364 /* Awe, no XML. This is actually fatal lol. Can't boot without XML. */
1365 Status
= STATUS_NOT_FOUND
;
1366 EfiPrintf(L
"BlResourceFindMessage failed 0x%x\r\n", STATUS_NOT_FOUND
);
1370 /* Initialize the XML Engine (as a side-effect, resets cursor) */
1371 Status
= BlXmiInitialize(Stylesheet
);
1372 if (!NT_SUCCESS(Status
))
1374 EfiPrintf(L
"\r\nBlXmiInitialize failed 0x%x\r\n", Status
);
1379 /* Check if there's an active bitmap visible */
1380 if (!BlDisplayValidOemBitmap())
1382 /* Nope, make the screen black using BGFX */
1383 if (!NT_SUCCESS(BmpBgDisplayClearScreen(0xFF000000)))
1385 /* BGFX isn't active, use standard display */
1386 BlDisplayClearScreen();
1391 /* Bitlocker will take over screen UI if enabled */
1392 FveDisplayScreen
= BmFveDisplayScreen
;
1395 /* Check if any bypass options are enabled */
1396 BlImgQueryCodeIntegrityBootOptions(&BlpApplicationEntry
,
1399 if (!DisableIntegrity
)
1401 /* Integrity checks are enabled, so validate our signature */
1402 Status
= BmFwVerifySelfIntegrity();
1403 if (!NT_SUCCESS(Status
))
1405 /* Signature invalid, fail boot */
1410 /* Write out the first XML tag */
1411 BlXmiWrite(L
"<bootmgr/>");
1413 /* Check for factory resset */
1414 BlSecureBootCheckForFactoryReset();
1416 /* Load the revocation list */
1417 Status
= BmFwRegisterRevocationList();
1418 if (!NT_SUCCESS(Status
))
1423 /* Register our custom progress routine */
1424 BlUtlRegisterProgressRoutine();
1426 /* Display state is not currently cached */
1427 BmDisplayStateCached
= FALSE
;
1429 /* Check if we need to resume from hibernate */
1430 Status
= BmResumeFromHibernate(&ResumeBcdHandle
);
1431 if (!NT_SUCCESS(Status
))
1436 #ifdef BL_NET_SUPPORT
1437 /* Register multicast printing routine */
1438 BlUtlRegisterMulticastRoutine();
1441 /* Check if restart on failure is enabled */
1442 BlGetBootOptionBoolean(BlpApplicationEntry
.BcdData
,
1443 BcdLibraryBoolean_RestartOnFailure
,
1446 /* Check if the boot sequence is persisted */
1447 Status
= BlGetBootOptionBoolean(BlpApplicationEntry
.BcdData
,
1448 BcdBootMgrBoolean_PersistBootSequence
,
1449 &PersistBootSequence
);
1450 if (!NT_SUCCESS(Status
))
1453 PersistBootSequence
= TRUE
;
1456 /* Check if there's custom actions to take */
1457 Status
= BlGetBootOptionBoolean(BlpApplicationEntry
.BcdData
,
1458 BcdBootMgrBoolean_ProcessCustomActionsFirst
,
1460 if ((NT_SUCCESS(Status
)) && (CustomActions
))
1462 /* We don't suppport this yet */
1463 EfiPrintf(L
"Not implemented\r\n");
1464 Status
= STATUS_NOT_IMPLEMENTED
;
1468 /* At last, enter the boot selection stage */
1472 SequenceList
= NULL
;
1473 BootSequence
= NULL
;
1477 /* We don't have a boot entry nor a sequence ID */
1481 /* Do we have a hardcoded boot sequence set? */
1482 if (!(BootSequence
) && !(GetEntry
))
1484 /* Not yet, read the BCD to see if one is there */
1485 Status
= BlGetBootOptionGuidList(BlpApplicationEntry
.BcdData
,
1486 BcdBootMgrObjectList_BootSequence
,
1488 &SequenceListCount
);
1489 if (NT_SUCCESS(Status
))
1491 /* A GUID list for the boot sequence is set. Extract it */
1492 Status
= BmGetBootSequence(BcdHandle
,
1498 if (NT_SUCCESS(Status
))
1500 /* Don't get stuck in a loop repeating this sequence */
1501 BlRemoveBootOption(BlpApplicationEntry
.BcdData
,
1502 BcdBootMgrObjectList_BootSequence
);
1504 /* But do check if we should persist it */
1505 if (PersistBootSequence
)
1507 /* Yes -- so go select an entry now */
1512 /* We shouldn't, so wipe it from the BCD too */
1513 Status
= BmPurgeOption(BcdHandle
,
1514 &BmApplicationIdentifier
,
1515 BcdBootMgrObjectList_BootSequence
);
1516 if (!NT_SUCCESS(Status
))
1518 /* Well that failed */
1526 /* No boot entry sequence for us */
1527 BootSequence
= NULL
;
1531 /* Do we have a sequence active, and are we still processing it? */
1532 if ((BootSequence
) && ((GetEntry
) || (SequenceId
< SequenceCount
)))
1534 /* Extract the next entry in the sequence */
1535 BootEntry
= BootSequence
[SequenceId
];
1536 BootSequence
[SequenceId
] = NULL
;
1538 /* Move to the next entry for next time */
1541 /* Unless there won't be a a next time? */
1542 if (SequenceId
== SequenceCount
)
1544 /* Clean up, it's the last entry */
1545 BlMmFreeHeap(BootSequence
);
1546 BootSequence
= NULL
;
1551 /* Get the selected boot entry from the user */
1552 ExitBootManager
= FALSE
;
1553 Status
= BmpGetSelectedBootEntry(BcdHandle
,
1557 if (!(NT_SUCCESS(Status
)) || (ExitBootManager
))
1559 /* Selection failed, or user wants to exit */
1564 /* Did we have a BCD open? */
1567 /* Close it, we'll be opening a new one */
1568 BmCloseDataStore(BcdHandle
);
1572 /* Launch the selected entry */
1573 Status
= BmpLaunchBootEntry(BootEntry
, &BootIndex
, 0, TRUE
);
1574 if (NT_SUCCESS(Status
))
1576 /* Boot worked, uncache display and process the bad memory list */
1577 BmDisplayStateCached
= FALSE
;
1578 BmpProcessBadMemory();
1582 /* Boot failed -- was it user driven? */
1583 if (Status
!= STATUS_CANCELLED
)
1585 /* Nope, remember that booting failed */
1590 /* Yes -- the display is still valid */
1591 BmDisplayStateCached
= TRUE
;
1594 /* Reopen the BCD */
1595 Status
= BmOpenDataStore(&BcdHandle
);
1596 if (!NT_SUCCESS(Status
))
1601 /* Put the BCD options back into our entry */
1602 BlReplaceBootOptions(&BlpApplicationEntry
, EarlyOptions
);
1604 /* Update our options one more time */
1605 Status
= BmpUpdateApplicationOptions(BcdHandle
);
1606 if (NT_SUCCESS(Status
))
1608 /* Boot was 100% OK */
1613 /* Did we have a boot entry? */
1616 /* We can destroy it now */
1617 BlDestroyBootEntry(BootEntry
);
1620 /* Is this the success path? */
1621 if (NT_SUCCESS(Status
))
1623 /* Did we actually boot something? */
1626 /* Bope, fail out */
1631 /* This is the failure path... should we reboot? */
1641 /* Check if we got here due to an internal error */
1642 if (BmpInternalBootError
)
1644 /* If XML is available, display the error */
1647 //BmDisplayDumpError(0, 0);
1651 /* Don't do a fatal error -- return back to firmware */
1656 /* Log a general fatal error once we're here */
1657 BmFatalErrorEx(BL_FATAL_ERROR_GENERIC
, Status
, 0, 0, 0);
1660 /* Check if we should reboot */
1661 if ((RebootOnError
) ||
1662 (BlpApplicationEntry
.Flags
& BL_APPLICATION_ENTRY_REBOOT_ON_ERROR
))
1664 /* Reboot the box */
1666 Status
= STATUS_SUCCESS
;
1670 /* Return back to the caller with the error argument encoded */
1671 ReturnArguments
= (PVOID
)((ULONG_PTR
)BootParameters
+ BootParameters
->ReturnArgumentsOffset
);
1672 ReturnArguments
->Version
= BL_RETURN_ARGUMENTS_VERSION
;
1673 ReturnArguments
->Status
= Status
;
1675 /* Tear down the boot library */
1679 /* Return back status */