/*
* COPYRIGHT: See COPYING.ARM in the top level directory
* PROJECT: ReactOS UEFI Boot Manager
- * FILE: boot/environ/app/bootmgr/bootmgr.c
+ * FILE: boot/environ/app/bootmgr/bootmgr.cla
* PURPOSE: Boot Manager Entrypoint
* PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
*/
PWCHAR ParentFileName = L"";
BOOLEAN BmDisplayStateCached;
+PBL_LOADED_APPLICATION_ENTRY* BmpFailedBootEntries;
+PBL_LOADED_APPLICATION_ENTRY BmpSelectedBootEntry;
+BOOLEAN BmBootEntryOverridePresent;
+BOOLEAN BmpDisplayBootMenu;
/* FUNCTIONS *****************************************************************/
/* Start going through each option */
PreviousOption = NULL;
Option = Options;
- EfiPrintf(L"BCD Options found: %d\r\n", ElementCount);
for (i = 0; i < ElementCount; i++)
{
/* Read the header and type */
DeviceHandle = -1;
/* Try to open the boot device */
- Status = BlpDeviceOpen(BlpBootDevice, 1u, 0, &DeviceHandle);
+ Status = BlpDeviceOpen(BlpBootDevice,
+ BL_DEVICE_READ_ACCESS,
+ 0,
+ &DeviceHandle);
if (!NT_SUCCESS(Status))
{
EfiPrintf(L"Device open failed: %lx\r\n", Status);
BcdDirectory = BcdPath.Buffer;
if (!NT_SUCCESS(Status))
{
- EfiPrintf(L"path failed: %lx\n", Status);
goto Quickie;
}
wcsncat(FinalPath, L"\\BCD", FinalSize / sizeof(WCHAR));
/* Try to open the file */
- EfiPrintf(L"Opening: %s\r\n", FinalPath);
- Status = BlFileOpen(DeviceHandle, FinalPath, 1, &FileHandle);
+ Status = BlFileOpen(DeviceHandle,
+ FinalPath,
+ BL_FILE_READ_ACCESS,
+ &FileHandle);
if (!NT_SUCCESS(Status))
{
BootDirectory = BcdDirectory;
ErrorResourceId = 9002;
break;
+ case BL_FATAL_ERROR_BCD_ENTRIES:
+
+ /* File name is in parameter 1 */
+ FileName = (PWCHAR)Parameter1;
+
+ /* The NTSTATUS code is in parameter 2*/
+ ErrorStatus = (NTSTATUS)Parameter2;
+
+ /* Build the error string */
+ swprintf(FormatString,
+ L"\nNo valid entries found in the boot configuration data file %s\n",
+ FileName);
+
+ /* Select the resource ID message */
+ ErrorResourceId = 9007;
+ break;
+
case BL_FATAL_ERROR_BCD_PARSE:
/* File name isin parameter 1 */
default:
/* The rest is not yet handled */
- EfiPrintf(L"Unexpected fatal error: %lx\n", ErrorCode);
+ EfiPrintf(L"Unexpected fatal error: %lx\r\n", ErrorCode);
while (1);
break;
}
/* Check if boot.ini data needs to be freed */
if (BmBootIniUsed)
{
- EfiPrintf(L"Not handled\r\n");
+ EfiPrintf(L"Boot.ini not handled\r\n");
}
/* Dereference the hive and close the key */
if (NT_SUCCESS(Status))
{
/* We don't handle custom BCDs yet */
- EfiPrintf(L"Not handled: %s\r\n", BcdPath);
+ EfiPrintf(L"Custom BCD Not handled: %s\r\n", BcdPath);
Status = STATUS_NOT_IMPLEMENTED;
goto Quickie;
}
if (BcdDevice->DeviceType == UdpDevice)
{
/* Nope. Nope. Nope */
- EfiPrintf(L"Not handled\n");
+ EfiPrintf(L"UDP device Not handled\r\n");
Status = STATUS_NOT_IMPLEMENTED;
goto Quickie;
}
/* The BSD is open. Start doing stuff to it */
EfiPrintf(L"Unimplemented BSD path\r\n");
- Status = STATUS_NOT_IMPLEMENTED;
+ Status = STATUS_NOT_IMPLEMENTED;
FailurePath:
/* Close the BSD if we had it open */
}
}
+NTSTATUS
+BmpBgDisplayClearScreen (
+ _In_ ULONG Color
+ )
+{
+ /* Not yet supported */
+ return STATUS_NOT_IMPLEMENTED;
+}
-/*++
- * @name BmMain
- *
- * The BmMain function implements the Windows Boot Application entrypoint for
- * the Boot Manager.
- *
- * @param BootParameters
- * Pointer to the Boot Application Parameter Block.
- *
- * @return NT_SUCCESS if the image was loaded correctly, relevant error code
- * otherwise.
- *
- *--*/
NTSTATUS
-BmMain (
- _In_ PBOOT_APPLICATION_PARAMETER_BLOCK BootParameters
+BlXmiWrite (
+ _In_ PWCHAR XmlTag
)
{
- NTSTATUS Status, LibraryStatus;
- BL_LIBRARY_PARAMETERS LibraryParameters;
- PBL_RETURN_ARGUMENTS ReturnArguments;
- BOOLEAN RebootOnError;
- PGUID AppIdentifier;
- HANDLE BcdHandle;
- PBL_BCD_OPTION EarlyOptions;
- PWCHAR Stylesheet;
+ /* Sigh */
+ EfiPrintf(L"XML: %s\r\n", XmlTag);
+ return STATUS_NOT_IMPLEMENTED;
+}
- EfiPrintf(L"ReactOS UEFI Boot Manager Initializing...\n");
+NTSTATUS
+BlXmiInitialize (
+ _In_ PWCHAR Stylesheet
+ )
+{
+ /* Reset the cursor type */
+ BlDisplaySetCursorType(0);
- /* Reading the BCD can change this later on */
- RebootOnError = FALSE;
+ /* Nope, not doing any XML stuff */
+ return STATUS_SUCCESS;
+}
- /* Save the start/end-of-POST time */
- ApplicationStartTime = __rdtsc();
- PostTime = ApplicationStartTime;
+NTSTATUS
+BmFwVerifySelfIntegrity (
+ VOID
+ )
+{
+ /* Check if we're booted by UEFI off the DVD directlry */
+ if ((BlpBootDevice->DeviceType == LocalDevice) &&
+ (BlpBootDevice->Local.Type == CdRomDevice) &&
+ (BlpApplicationFlags & BL_APPLICATION_FLAG_CONVERTED_FROM_EFI))
+ {
+ /* Windows actually bypasses integrity checks in this case. Works for us */
+ return STATUS_SUCCESS;
+ }
- /* Setup the boot library parameters for this application */
- BlSetupDefaultParameters(&LibraryParameters);
- LibraryParameters.TranslationType = BlNone;
- LibraryParameters.LibraryFlags = 0x400 | 0x8;
- LibraryParameters.MinimumAllocationCount = 16;
- LibraryParameters.MinimumHeapSize = 512 * 1024;
+ /* Our binaries aren't signed, so always return failure */
+ return 0xC0000428;
+}
- /* Initialize the boot library */
- Status = BlInitializeLibrary(BootParameters, &LibraryParameters);
- if (!NT_SUCCESS(Status))
- {
- /* Check for failure due to invalid application entry */
- if (Status != STATUS_INVALID_PARAMETER_9)
- {
- /* Specifically print out what happened */
- EfiPrintf(L"BlInitializeLibrary failed 0x%x\r\n", Status);
- }
+NTSTATUS
+BmFwRegisterRevocationList (
+ VOID
+ )
+{
+ NTSTATUS Status;
+ BOOLEAN SecureBootEnabled;
- /* Go to exit path */
- goto Quickie;
+ /* Is SecureBoot enabled? */
+ Status = BlSecureBootIsEnabled(&SecureBootEnabled);
+ if ((NT_SUCCESS(Status)) && (SecureBootEnabled))
+ {
+ EfiPrintf(L"SB not implemented revok\r\n");
+ return STATUS_NOT_IMPLEMENTED;
}
-
- /* Get the application identifier */
- AppIdentifier = BlGetApplicationIdentifier();
- if (!AppIdentifier)
+ else
{
- /* None was given, so set our default one */
- AppIdentifier = (PGUID)&GUID_WINDOWS_BOOTMGR;
+ /* Nothing to do without SecureBoot */
+ Status = STATUS_SUCCESS;
}
- /* Save our identifier */
- BmApplicationIdentifier = *AppIdentifier;
+ /* Return revocation result back to caller */
+ return Status;
+}
- /* Initialize the file system to open a handle to our root boot directory */
- BmFwInitializeBootDirectoryPath();
+NTSTATUS
+BmResumeFromHibernate (
+ _Out_ PHANDLE BcdResumeHandle
+ )
+{
+ NTSTATUS Status;
+ BOOLEAN AttemptResume;
- /* Load and initialize the boot configuration database (BCD) */
- Status = BmOpenDataStore(&BcdHandle);
- if (NT_SUCCESS(Status))
+ /* Should we attempt to resume from hibernation? */
+ Status = BlGetBootOptionBoolean(BlpApplicationEntry.BcdData,
+ BcdBootMgrBoolean_AttemptResume,
+ &AttemptResume);
+ if (!NT_SUCCESS(Status))
{
- /* Copy the boot options */
- Status = BlCopyBootOptions(BlpApplicationEntry.BcdData, &EarlyOptions);
- if (NT_SUCCESS(Status))
- {
- /* Update them */
- Status = BmpUpdateApplicationOptions(BcdHandle);
- if (!NT_SUCCESS(Status))
- {
- /* Log a fatal error */
- BmFatalErrorEx(BL_FATAL_ERROR_BCD_PARSE,
- (ULONG_PTR)L"\\BCD",
- Status,
- 0,
- 0);
- }
- }
+ /* Nope. Is automatic restart on crash enabled? */
+ AttemptResume = FALSE;
+ Status = BlGetBootOptionBoolean(BlpApplicationEntry.BcdData,
+ BcdOSLoaderBoolean_DisableCrashAutoReboot,
+ &AttemptResume);
+ AttemptResume = (NT_SUCCESS(Status) && (AttemptResume));
}
-#ifdef _SECURE_BOOT
- /* Initialize the secure boot machine policy */
- Status = BmSecureBootInitializeMachinePolicy();
- if (!NT_SUCCESS(Status))
+ /* Don't do anything if there's no need to resume anything */
+ if (!AttemptResume)
{
- BmFatalErrorEx(BL_FATAL_ERROR_SECURE_BOOT, Status, 0, 0, 0);
+ return STATUS_SUCCESS;
}
-#endif
- /* Copy the library parameters and add the re-initialization flag */
- RtlCopyMemory(&LibraryParameters,
- &BlpLibraryParameters,
- sizeof(LibraryParameters));
- LibraryParameters.LibraryFlags |= (BL_LIBRARY_FLAG_REINITIALIZE_ALL |
- BL_LIBRARY_FLAG_REINITIALIZE);
+ /* Not yet implemented */
+ EfiPrintf(L"Resume not supported\r\n");
+ return STATUS_NOT_IMPLEMENTED;
+}
- /* Now that we've parsed the BCD, re-initialize the library */
- LibraryStatus = BlInitializeLibrary(BootParameters, &LibraryParameters);
- if (!NT_SUCCESS(LibraryStatus) && (NT_SUCCESS(Status)))
+NTSTATUS
+BmpProcessBadMemory (
+ VOID
+ )
+{
+ BL_PD_DATA_BLOB BadMemoryData;
+ NTSTATUS Status;
+
+ /* Try to get the memory data from the memtest application */
+ BadMemoryData.BlobSize = 0;
+ BadMemoryData.Data = NULL;
+ BadMemoryData.DataSize = 0;
+ Status = BlPdQueryData(&BadMemoryGuid, NULL, &BadMemoryData);
+ if (Status != STATUS_BUFFER_TOO_SMALL)
{
- Status = LibraryStatus;
+ /* No results, or some other error */
+ return Status;
}
- /* Initialize firmware-specific memory regions */
- //BmFwMemoryInitialize();
+ /* Not yet implemented */
+ EfiPrintf(L"Bad page list persistence not implemented\r\n");
+ return STATUS_NOT_IMPLEMENTED;
+}
- /* Initialize the boot status data log (BSD) */
- BmpInitializeBootStatusDataLog();
+NTSTATUS
+BmPurgeOption (
+ _In_ HANDLE BcdHandle,
+ _In_ PGUID ObjectId,
+ _In_ ULONG Type
+ )
+{
+ HANDLE ObjectHandle;
+ NTSTATUS Status;
- /* Find our XSL stylesheet */
- Stylesheet = BlResourceFindHtml();
- if (!Stylesheet)
+ /* Open the object */
+ Status = BcdOpenObject(BcdHandle, ObjectId, &ObjectHandle);
+ if (NT_SUCCESS(Status))
{
- /* Awe, no XML. This is actually fatal lol. Can't boot without XML. */
- Status = STATUS_NOT_FOUND;
- EfiPrintf(L"BlResourceFindMessage failed 0x%x\r\n", STATUS_NOT_FOUND);
- goto Quickie;
+ /* Delete the element */
+ BcdDeleteElement(ObjectHandle, Type);
+
+ /* Close the object and set success */
+ BiCloseKey(ObjectHandle);
+ Status = STATUS_SUCCESS;
}
- /* do more stuff!! */
- EfiPrintf(BlResourceFindMessage(BM_MSG_TEST));
- EfiPrintf(Stylesheet);
- EfiStall(10000000);
+ /* Return the result */
+ return Status;
+}
-//Failure:
- /* Check if we got here due to an internal error */
- if (BmpInternalBootError)
+NTSTATUS
+BmGetEntryDescription (
+ _In_ HANDLE BcdHandle,
+ _In_ PGUID ObjectId,
+ _Out_ PBCD_OBJECT_DESCRIPTION Description
+ )
+{
+ NTSTATUS Status;
+ HANDLE ObjectHandle;
+
+ /* Open the BCD object */
+ Status = BcdOpenObject(BcdHandle, ObjectId, &ObjectHandle);
+ if (NT_SUCCESS(Status))
{
- /* If XML is available, display the error */
-#if 0
- if (XmlLoaded)
+ /* Make sure the caller passed this argument in */
+ if (!Description)
{
- BmDisplayDumpError(0, 0);
- BmErrorPurge();
+ /* Fail otherwise */
+ Status = STATUS_INVALID_PARAMETER;
+ }
+ else
+ {
+ /* Query the description from the BCD interface */
+ Status = BiGetObjectDescription(ObjectHandle, Description);
}
-#endif
- /* Don't do a fatal error -- return back to firmware */
- goto Quickie;
+ /* Close the object key */
+ BiCloseKey(ObjectHandle);
+ }
+
+ /* Return the result back */
+ return Status;
+}
+
+NTSTATUS
+BmpPopulateBootEntryList (
+ _In_ HANDLE BcdHandle,
+ _In_ PGUID SequenceList,
+ _In_ ULONG Flags,
+ _Out_ PBL_LOADED_APPLICATION_ENTRY* BootSequence,
+ _Out_ PULONG SequenceCount
+ )
+{
+ NTSTATUS Status;
+ ULONG BootIndex, i, OptionSize;
+ PBL_LOADED_APPLICATION_ENTRY BootEntry;
+ PBL_BCD_OPTION Options;
+ BCD_OBJECT_DESCRIPTION Description;
+ BcdObjectType ObjectType;
+ BOOLEAN HavePath, IsWinPe, SoftReboot;
+ PWCHAR LoaderPath;
+
+ /* Initialize locals */
+ Options = NULL;
+ BootIndex = 0;
+ Status = STATUS_NOT_FOUND;
+
+ /* Loop through every element in the sequence */
+ for (i = 0; i < *SequenceCount; i++)
+ {
+ /* Assume failure */
+ BootEntry = NULL;
+
+ /* Get the options for the sequence element */
+ Status = BmGetOptionList(BcdHandle, SequenceList, &Options);
+ if (!NT_SUCCESS(Status))
+ {
+ EfiPrintf(L"option list failed: %lx\r\n", Status);
+ goto LoopQuickie;
+ }
+
+ /* Make sure there's at least a path and description */
+ if (!(MiscGetBootOption(Options, BcdLibraryDevice_ApplicationDevice)) ||
+ !(MiscGetBootOption(Options, BcdLibraryString_Description)))
+ {
+ Status = STATUS_UNSUCCESSFUL;
+ EfiPrintf(L"missing list failed: %lx\r\n", Status);
+ goto LoopQuickie;
+ }
+
+ /* Get the size of the BCD options and allocate a large enough entry */
+ OptionSize = BlGetBootOptionListSize(Options);
+ BootEntry = BlMmAllocateHeap(sizeof(*BootEntry) + OptionSize);
+ if (!BootEntry)
+ {
+ Status = STATUS_NO_MEMORY;
+ goto Quickie;
+ }
+
+ /* Save it as part of the sequence */
+ BootSequence[BootIndex] = BootEntry;
+
+ /* Initialize it, and copy the BCD data */
+ RtlZeroMemory(BootEntry, sizeof(*BootEntry));
+ BootEntry->Guid = *SequenceList;
+ BootEntry->BcdData = (PBL_BCD_OPTION)(BootEntry + 1);
+ BootEntry->Flags = Flags;
+ RtlCopyMemory(BootEntry->BcdData, Options, OptionSize);
+
+ /* Get the object descriptor to find out what kind of entry it is */
+ Status = BmGetEntryDescription(BcdHandle,
+ &BootEntry->Guid,
+ &Description);
+ if (!NT_SUCCESS(Status))
+ {
+ EfiPrintf(L"missing desc failed: %lx\r\n", Status);
+ goto LoopQuickie;
+ }
+
+ /* Check if a path was given or not */
+ HavePath = MiscGetBootOption(Options, BcdLibraryString_ApplicationPath) ?
+ TRUE : FALSE;
+
+ /* Now select based on what type of object this is -- must be an app */
+ ObjectType.PackedValue = Description.Type;
+ if (ObjectType.Application.ObjectCode == BCD_OBJECT_TYPE_APPLICATION)
+ {
+ /* Then select based on what kind of app it is */
+ switch (ObjectType.Application.ApplicationCode)
+ {
+ /* Another boot manager */
+ case BCD_APPLICATION_TYPE_BOOTMGR:
+ BootEntry->Flags |= BCD_APPLICATION_TYPE_BOOTMGR;
+ break;
+
+ /* An OS loader */
+ case BCD_APPLICATION_TYPE_OSLOADER:
+ BootEntry->Flags |= BL_APPLICATION_ENTRY_WINLOAD;
+
+ /* Do we have a path for it? */
+ if (!HavePath)
+ {
+ /* We'll try to make one up. Is this WinPE? */
+ IsWinPe = FALSE;
+ Status = BlGetBootOptionBoolean(Options,
+ BcdOSLoaderBoolean_WinPEMode,
+ &IsWinPe);
+ if (!(NT_SUCCESS(Status)) && (Status != STATUS_NOT_FOUND))
+ {
+ goto Quickie;
+ }
+
+ /* Use the appropriate path for WinPE or local install */
+ LoaderPath = IsWinPe ?
+ L"\\Windows\\System32\\boot\\winload.efi" :
+ L"\\Windows\\System32\\winload.efi";
+
+ /* Add the path to the boot entry */
+ Status = BlAppendBootOptionString(BootEntry, LoaderPath);
+ if (!NT_SUCCESS(Status))
+ {
+ goto Quickie;
+ }
+
+ /* We have a path now */
+ HavePath = TRUE;
+ }
+ break;
+
+ /* A hibernate-resume application */
+ case BCD_APPLICATION_TYPE_RESUME:
+ BootEntry->Flags |= BL_APPLICATION_ENTRY_WINRESUME;
+ break;
+
+ /* An older OS NTLDR */
+ case BCD_APPLICATION_TYPE_NTLDR:
+ BootEntry->Flags |= BL_APPLICATION_ENTRY_NTLDR;
+ break;
+
+ /* An older OS SETUPLDR */
+ case BCD_APPLICATION_TYPE_SETUPLDR:
+ BootEntry->Flags |= BL_APPLICATION_ENTRY_SETUPLDR;
+ break;
+
+ /* A 3rd party/Win9x boot sector */
+ case BCD_APPLICATION_TYPE_BOOTSECTOR:
+ BootEntry->Flags |= BL_APPLICATION_ENTRY_BOOTSECTOR;
+ break;
+
+ /* Something else entirely */
+ default:
+ break;
+ }
+ }
+
+ /* We better have a path by now */
+ if (!HavePath)
+ {
+ Status = STATUS_UNSUCCESSFUL;
+ goto LoopQuickie;
+ }
+
+ /* Check if this is a real mode startup.com */
+ if ((ObjectType.Application.ObjectCode == BCD_OBJECT_TYPE_APPLICATION) &&
+ (ObjectType.Application.ImageCode = BCD_IMAGE_TYPE_REAL_MODE) &&
+ (ObjectType.Application.ApplicationCode == BCD_APPLICATION_TYPE_STARTUPCOM))
+ {
+ /* Check if PXE soft reboot will occur */
+ Status = BlGetBootOptionBoolean(Options,
+ BcdStartupBoolean_PxeSoftReboot,
+ &SoftReboot);
+ if ((NT_SUCCESS(Status)) && (SoftReboot))
+ {
+ /* Then it's a valid startup.com entry */
+ BootEntry->Flags |= BL_APPLICATION_ENTRY_STARTUP;
+ }
+ }
+
+LoopQuickie:
+ /* All done with this entry -- did we have BCD options? */
+ if (Options)
+ {
+ /* Free them, they're part of the entry now */
+ BlMmFreeHeap(Options);
+ Options = NULL;
+ }
+
+ /* Did we fail anywhere? */
+ if (!NT_SUCCESS(Status))
+ {
+ /* Yep -- did we fail with an active boot entry? */
+ if (BootEntry)
+ {
+ /* Destroy it */
+ BlDestroyBootEntry(BootEntry);
+ BootSequence[BootIndex] = NULL;
+ }
+ }
+ else
+ {
+ /* It worked, so populate the next index now */
+ BootIndex++;
+ }
+
+ /* And move to the next GUID in the sequence list */
+ SequenceList++;
+ }
+
+Quickie:
+ /* All done now -- did we have any BCD options? */
+ if (Options)
+ {
+ /* Free them */
+ BlMmFreeHeap(Options);
+ }
+
+ /* Return the status */
+ return Status;
+}
+
+NTSTATUS
+BmGetBootSequence (
+ _In_ HANDLE BcdHandle,
+ _In_ PGUID SequenceList,
+ _In_ ULONG SequenceListCount,
+ _In_ ULONG Flags,
+ _Out_ PBL_LOADED_APPLICATION_ENTRY** BootSequence,
+ _Out_ PULONG SequenceCount
+ )
+{
+ PBL_LOADED_APPLICATION_ENTRY* Sequence;
+ ULONG Count;
+ NTSTATUS Status;
+
+ /* Allocate the sequence list */
+ Sequence = BlMmAllocateHeap(SequenceListCount * sizeof(*Sequence));
+ if (!Sequence)
+ {
+ return STATUS_NO_MEMORY;
+ }
+
+ /* Populate the sequence list */
+ Status = BmpPopulateBootEntryList(BcdHandle,
+ SequenceList,
+ Flags,
+ Sequence,
+ &Count);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Free the list on failure */
+ BlMmFreeHeap(Sequence);
+ }
+ else
+ {
+ /* Otherwise, set success and return the list and count */
+ Status = STATUS_SUCCESS;
+ *BootSequence = Sequence;
+ *SequenceCount = Count;
+ }
+
+ /* All done */
+ return Status;
+}
+
+NTSTATUS
+BmEnumerateBootEntries (
+ _In_ HANDLE BcdHandle,
+ _Out_ PBL_LOADED_APPLICATION_ENTRY **BootSequence,
+ _Out_ PULONG SequenceCount
+ )
+{
+ NTSTATUS Status;
+ ULONG BootIndex, BootIniCount, BootEntryCount, BcdCount;
+ PBL_LOADED_APPLICATION_ENTRY* Sequence;
+ PGUID DisplayOrder;
+ GUID DefaultObject;
+ BOOLEAN UseDisplayList;
+
+ /* Initialize locals */
+ BootIndex = 0;
+
+ /* First try to get the display list, if any */
+ UseDisplayList = TRUE;
+ Status = BlGetBootOptionGuidList(BlpApplicationEntry.BcdData,
+ BcdBootMgrObjectList_DisplayOrder,
+ &DisplayOrder,
+ &BcdCount);
+ if (!NT_SUCCESS(Status))
+ {
+ /* No list, get the default entry instead */
+ Status = BlGetBootOptionGuid(BlpApplicationEntry.BcdData,
+ BcdBootMgrObject_DefaultObject,
+ &DefaultObject);
+ if (NT_SUCCESS(Status))
+ {
+ /* Set the array to just our entry */
+ UseDisplayList = FALSE;
+ BcdCount = 1;
+ DisplayOrder = &DefaultObject;
+ }
+ else
+ {
+ /* No default list either, return success but no entries */
+ *BootSequence = NULL;
+ *SequenceCount = 0;
+ Status = STATUS_SUCCESS;
+ DisplayOrder = NULL;
+ goto Quickie;
+ }
+ }
+
+ /* Check if boot.ini was used */
+ BootIniCount = 0;
+ if (BmBootIniUsed)
+ {
+ /* Get the entries from it */
+ EfiPrintf(L"Boot.ini not supported\r\n");
+ BootIniCount = 0;//BmBootIniGetEntryCount();
+ }
+
+ /* Allocate an array large enough for the combined boot entries */
+ BootEntryCount = BootIniCount + BcdCount;
+ Sequence = BlMmAllocateHeap(BootEntryCount * sizeof(*Sequence));
+ if (!Sequence)
+ {
+ Status = STATUS_NO_MEMORY;
+ goto Quickie;
+ }
+
+ /* Zero it out */
+ RtlZeroMemory(Sequence, BootEntryCount * sizeof(*Sequence));
+
+ /* Check if we had BCD entries */
+ if (BcdCount)
+ {
+ /* Populate the list of bootable entries */
+ Status = BmpPopulateBootEntryList(BcdHandle,
+ DisplayOrder,
+ BL_APPLICATION_ENTRY_DISPLAY_ORDER,
+ Sequence,
+ &BcdCount);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Bail out */
+ goto Quickie;
+ }
+ }
+
+ /* Check if we had boot.ini entries */
+ if (BootIniCount)
+ {
+ /* TODO */
+ EfiPrintf(L"Boot.ini not supported\r\n");
+ }
+
+ /* Return success and the sequence + count populated */
+ Status = STATUS_SUCCESS;
+ *BootSequence = Sequence;
+ *SequenceCount = BootIniCount + BcdCount;
+
+Quickie:
+ /* Check if we had allocated a GUID list */
+ if ((UseDisplayList) && (DisplayOrder))
+ {
+ /* Free it */
+ BlMmFreeHeap(DisplayOrder);
+ }
+
+ /* Check if this is the failure path */
+ if (!(NT_SUCCESS(Status)) && (Sequence))
+ {
+ /* Loop the remaining boot entries */
+ while (BootIndex < BootEntryCount)
+ {
+ /* Check if it had been allocated */
+ if (Sequence[BootIndex])
+ {
+ /* Free it */
+ BlMmFreeHeap(Sequence[BootIndex]);
+ }
+
+ /* Next*/
+ BootIndex++;
+ }
+
+ /* Free the whole sequence now */
+ BlMmFreeHeap(Sequence);
+ }
+
+ /* All done, return the result */
+ return Status;
+}
+
+VOID
+BmpGetDefaultBootEntry (
+ _In_ PBL_LOADED_APPLICATION_ENTRY* Sequence,
+ _In_ ULONG Count,
+ _Out_ PBL_LOADED_APPLICATION_ENTRY* DefaultEntry,
+ _Out_ PULONG DefaultIndex
+ )
+{
+ GUID DefaultObject;
+ NTSTATUS Status;
+ ULONG BootIndex;
+
+ /* Assume no default */
+ *DefaultEntry = *Sequence;
+ *DefaultIndex = 0;
+
+ /* Nothing to do if there's just one entry */
+ if (Count == 1)
+ {
+ return;
+ }
+
+ /* Get the default object, bail out if there isn't one */
+ Status = BlGetBootOptionGuid(BlpApplicationEntry.BcdData,
+ BcdBootMgrObject_DefaultObject,
+ &DefaultObject);
+ if (!(NT_SUCCESS(Status)) || !(Count))
+ {
+ return;
+ }
+
+ /* Scan the boot sequence */
+ for (BootIndex = 0; BootIndex < Count; BootIndex++)
+ {
+ /* Find one that matches the default */
+ if (RtlEqualMemory(&Sequence[BootIndex]->Guid,
+ &DefaultObject,
+ sizeof(GUID)))
+ {
+ /* Return it */
+ *DefaultEntry = Sequence[BootIndex];
+ *DefaultIndex = BootIndex;
+ return;
+ }
+ }
+}
+
+BL_MENU_POLICY
+BmGetBootMenuPolicy (
+ _In_ PBL_LOADED_APPLICATION_ENTRY BootEntry
+ )
+{
+ NTSTATUS Status;
+ BOOLEAN EmsEnabled;
+ ULONGLONG BootMenuPolicy;
+ ULONG OptionId;
+
+ /* Check if EMS is enabled */
+ Status = BlGetBootOptionBoolean(BlpApplicationEntry.BcdData,
+ BcdOSLoaderBoolean_EmsEnabled,
+ &EmsEnabled);
+ if ((NT_SUCCESS(Status)) && (EmsEnabled))
+ {
+ /* No boot menu */
+ return MenuPolicyLegacy;
+ }
+
+ /* Check what entry we are looking at */
+ if (!BootEntry)
+ {
+ /* No entry, pick the selected one */
+ BootEntry = BmpSelectedBootEntry;
+ }
+
+ /* Do we still not have an entry? */
+ if (!BootEntry)
+ {
+ /* Show the menu */
+ return MenuPolicyStandard;
+ }
+
+ /* Check if this is an OS loader */
+ BootMenuPolicy = 0;
+ if (BootEntry->Flags & BL_APPLICATION_ENTRY_WINLOAD)
+ {
+ /* Use the correct option ID */
+ OptionId = BcdOSLoaderInteger_BootMenuPolicy;
+ }
+ else
+ {
+ /* Check if this is an OS resumer */
+ if (!(BootEntry->Flags & BL_APPLICATION_ENTRY_WINRESUME))
+ {
+ /* Nope, so no reason for a menu */
+ return MenuPolicyLegacy;
+ }
+
+ /* Use the correct opetion ID */
+ OptionId = BcdResumeInteger_BootMenuPolicy;
+ }
+
+ /* Check the option ID for the boot menu policy */
+ Status = BlGetBootOptionInteger(BootEntry->BcdData,
+ OptionId,
+ &BootMenuPolicy);
+ if (NT_SUCCESS(Status))
+ {
+ /* We have one, return it */
+ return BootMenuPolicy;
+ }
+
+ /* No policy, so assume no menu */
+ return MenuPolicyLegacy;
+}
+
+VOID
+BmDisplayGetBootMenuStatus (
+ _Out_ PL_MENU_STATUS MenuStatus
+ )
+{
+ /* For now, don't support key input at all */
+ MenuStatus->AsULong = 0;
+ MenuStatus->OemKey = UNICODE_NULL;
+ MenuStatus->BootIndex = -1;
+}
+
+NTSTATUS
+BmProcessCustomAction (
+ _In_ HANDLE BcdHandle,
+ _In_ PWCHAR ActionKey
+ )
+{
+ EfiPrintf(L"Custom actions not yet handled\r\n");
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+VOID
+BmpProcessBootEntry (
+ _In_ HANDLE BcdHandle,
+ _In_ PBL_LOADED_APPLICATION_ENTRY BootEntry,
+ _Out_ PBOOLEAN ExitBootManager
+ )
+{
+ BL_MENU_STATUS MenuStatus;
+
+ /* Don't exit */
+ *ExitBootManager = FALSE;
+
+ /* If the legacy menu must be shown, or if we have a boot entry */
+ if ((BmGetBootMenuPolicy(BootEntry) != MenuPolicyStandard) || (BootEntry))
+ {
+ /* Check if any key has been presseed */
+ BmDisplayGetBootMenuStatus(&MenuStatus);
+ if (MenuStatus.AnyKey)
+ {
+ /* Was the exit key pressed? */
+ if (MenuStatus.Exit)
+ {
+ /* Don't display a menu, and exit */
+ *ExitBootManager = TRUE;
+ BmpDisplayBootMenu = FALSE;
+ }
+ else if (MenuStatus.OemKey)
+ {
+ /* Process the OEM key action */
+ BmProcessCustomAction(BcdHandle, &MenuStatus.KeyValue);
+ }
+ else
+ {
+ /* Process other keys */
+ EfiPrintf(L"TODO\r\n");
+ }
+ }
+ }
+}
+
+NTSTATUS
+BmpGetSelectedBootEntry (
+ _In_ HANDLE BcdHandle,
+ _Out_ PBL_LOADED_APPLICATION_ENTRY* SelectedBootEntry,
+ _Out_ PULONG EntryIndex,
+ _Out_ PBOOLEAN ExitBootManager
+ )
+{
+ NTSTATUS Status;
+ PBL_LOADED_APPLICATION_ENTRY* Sequence;
+ PBL_LOADED_APPLICATION_ENTRY Entry, SelectedEntry;
+ ULONG Count, BootIndex, SelectedIndex;
+ // BOOLEAN FoundFailedEntry;
+ ULONGLONG Timeout;
+
+ /* Initialize locals */
+ BootIndex = 0;
+ Count = 0;
+ Sequence = NULL;
+ SelectedEntry = NULL;
+
+ /* Enumerate all the boot entries */
+ Status = BmEnumerateBootEntries(BcdHandle, &Sequence, &Count);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Bail out if we failed */
+ goto Quickie;
+ }
+
+ /* Check if there are no entries */
+ if (!Count)
+ {
+ /* This is fatal -- kill the system */
+ Status = STATUS_FILE_INVALID;
+ BmFatalErrorEx(BL_FATAL_ERROR_BCD_ENTRIES, (ULONG_PTR)L"\\BCD", Status, 0, 0);
+ goto Quickie;
+ }
+
+ /* Check if we don't yet have an array of failed boot entries */
+ if (!BmpFailedBootEntries)
+ {
+ /* Allocate it */
+ BmpFailedBootEntries = BlMmAllocateHeap(Count);
+ if (BmpFailedBootEntries)
+ {
+ /* Zero it out */
+ RtlZeroMemory(BmpFailedBootEntries, Count);
+ }
+ }
+
+ /* Check if we have a hardcoded boot override */
+ if (BmBootEntryOverridePresent)
+ {
+ EfiPrintf(L"Hard-coded boot override mode not supported\r\n");
+ }
+
+ /* Log the OS count */
+ //BlLogEtwWrite(BOOT_BOOTMGR_MULTI_OS_COUNT);
+
+ /* Check if the display is already active and cached */
+ if (!BmDisplayStateCached)
+ {
+ /* Check if we should display a boot menu */
+ Status = BlGetBootOptionBoolean(BlpApplicationEntry.BcdData,
+ BcdBootMgrBoolean_DisplayBootMenu,
+ &BmpDisplayBootMenu);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Assume not */
+ BmpDisplayBootMenu = FALSE;
+ }
+ }
+
+ /* Check if there's only one entry to boot anyway */
+ if (Count == 1)
+ {
+ /* Read it */
+ SelectedEntry = *Sequence;
+
+ /* Process it */
+ BmpProcessBootEntry(BcdHandle, SelectedEntry, ExitBootManager);
+
+ /* Check if we're not displaying a boot menu */
+ if (!BmpDisplayBootMenu)
+ {
+ /* Now we are */
+ BmpDisplayBootMenu = TRUE;
+
+ /* Return the entry and its index back */
+ *EntryIndex = 0;
+ *SelectedBootEntry = SelectedEntry;
+ Status = STATUS_SUCCESS;
+ goto Quickie;
+ }
+ }
+ else
+ {
+ /* Get the default boot entry */
+ BmpGetDefaultBootEntry(Sequence, Count, &SelectedEntry, &SelectedIndex);
+
+ /* Check if we have a failed boot entry array allocated */
+ //FoundFailedEntry = FALSE;
+ if (BmpFailedBootEntries)
+ {
+ /* Check if the default entry failed to boot */
+ if (BmpFailedBootEntries[SelectedIndex])
+ {
+ /* Loop through the current boot sequence */
+ for (SelectedIndex = 0; SelectedIndex < Count; SelectedIndex++)
+ {
+ /* Check if there's no sequence for this index, or it failed */
+ while (!(Sequence[SelectedIndex]) ||
+ (BmpFailedBootEntries[SelectedIndex]))
+ {
+ /* Remember that this is a failed entry */
+ SelectedEntry = Sequence[SelectedIndex];
+ //FoundFailedEntry = TRUE;
+ BmpDisplayBootMenu = FALSE;
+ }
+ }
+ }
+ }
+
+ /* Check if the entry is an OS loader */
+ if (SelectedEntry->Flags & BL_APPLICATION_ENTRY_WINLOAD)
+ {
+ // todo
+ EfiPrintf(L"todo path\r\n");
+ }
+
+ /* Check if there's no timeout */
+ Status = BlGetBootOptionInteger(BlpApplicationEntry.BcdData,
+ BcdBootMgrInteger_Timeout,
+ &Timeout);
+ if ((NT_SUCCESS(Status) && !(Timeout)))
+ {
+ /* There isn't, so just process the default entry right away */
+ BmpProcessBootEntry(BcdHandle, SelectedEntry, ExitBootManager);
+
+ /* Check if we're not displaying a boot menu */
+ if (!BmpDisplayBootMenu)
+ {
+ /* Now we are */
+ BmpDisplayBootMenu = TRUE;
+
+ /* Return the entry and its index back */
+ *EntryIndex = 0;
+ *SelectedBootEntry = SelectedEntry;
+ Status = STATUS_SUCCESS;
+ goto Quickie;
+ }
+
+ /* Remove the timeout for this boot instance */
+ BlRemoveBootOption(BlpApplicationEntry.BcdData,
+ BcdBootMgrInteger_Timeout);
+ }
+ }
+
+ /* Here is where we display the menu and list of tools */
+ EfiPrintf(L"Tool selection not yet implemented\r\n");
+ EfiStall(10000000);
+ *SelectedBootEntry = NULL;
+
+Quickie:
+ /* We are done -- did we have a sequence? */
+ if (Sequence)
+ {
+ /* Do we have any boot entries we parsed? */
+ while (BootIndex < Count)
+ {
+ /* Get the current boot entry */
+ Entry = Sequence[BootIndex];
+
+ /* Did we fail, or is is not the selected one? */
+ if ((Entry) && ((Entry != SelectedEntry) || !(NT_SUCCESS(Status))))
+ {
+ /* Destroy it, as it won't be needed */
+ BlDestroyBootEntry(Entry);
+ }
+ else if (Entry == SelectedEntry)
+ {
+ /* It's the selected one, return its index */
+ *EntryIndex = BootIndex;
+ }
+
+ /* Move to the next entry */
+ BootIndex++;
+ }
+
+ /* Free the sequence of entries */
+ BlMmFreeHeap(Sequence);
+ }
+
+ /* Return the selection result */
+ return Status;
+}
+
+NTSTATUS
+BmLaunchRecoverySequence (
+ _In_ PBL_LOADED_APPLICATION_ENTRY BootEntry,
+ _In_ ULONG LaunchCode
+ )
+{
+ NTSTATUS Status;
+ PBL_LOADED_APPLICATION_ENTRY RecoveryEntry;
+ HANDLE BcdHandle;
+ PGUID RecoverySequence;
+ ULONG Count, i, RecoveryIndex, SequenceCount;
+ PBL_LOADED_APPLICATION_ENTRY* Sequence;
+
+ /* Initialize locals */
+ RecoveryIndex = 0;
+ Sequence = NULL;
+ RecoverySequence = NULL;
+ Count = 0;
+ BcdHandle = NULL;
+
+ /* Open the BCD*/
+ Status = BmOpenDataStore(&BcdHandle);
+ if (!NT_SUCCESS(Status))
+ {
+ goto Quickie;
+ }
+
+ /* Get the recovery sequence list */
+ Status = BlGetBootOptionGuidList(BootEntry->BcdData,
+ BcdLibraryObjectList_RecoverySequence,
+ &RecoverySequence,
+ &SequenceCount);
+ if (!NT_SUCCESS(Status))
+ {
+ goto Quickie;
+ }
+
+ /* Get the sequence of boot entries out of it */
+ Status = BmGetBootSequence(BcdHandle,
+ RecoverySequence,
+ SequenceCount,
+ BL_APPLICATION_ENTRY_RECOVERY,
+ &Sequence,
+ &Count);
+ if (!NT_SUCCESS(Status))
+ {
+ goto Quickie;
+ }
+
+ /* Was the BCD open? */
+ if (BcdHandle)
+ {
+ /* Close it */
+ BmCloseDataStore(BcdHandle);
+ }
+
+ /* Now go over every entry in the sequence */
+ for (i = 0; i < Count; ++i)
+ {
+ /* Check the code for this recovery launch */
+ if (LaunchCode == 2 || LaunchCode == 5)
+ {
+ /* Remove the override if there is one, and set it to 4 */
+ BlRemoveBootOption(Sequence[i]->BcdData, BcdLibraryInteger_DisplayMessageOverride);
+ BlAppendBootOptionInteger(Sequence[i],
+ BcdLibraryInteger_DisplayMessageOverride,
+ 4);
+ }
+ else if (LaunchCode == 3)
+ {
+ /* Remove the override if there is one, and set it to 10 */
+ BlRemoveBootOption(Sequence[i]->BcdData, BcdLibraryInteger_DisplayMessageOverride);
+ BlAppendBootOptionInteger(Sequence[i],
+ BcdLibraryInteger_DisplayMessageOverride,
+ 10);
+ }
+
+ /* Launch the boot entry for this part of the recovery sequence */
+ Status = BmpLaunchBootEntry(Sequence[i], NULL, LaunchCode, FALSE);
+ if (!NT_SUCCESS(Status))
+ {
+ break;
+ }
+ }
+
+Quickie:
+ /* Did we have a sequence of entries? */
+ if (Sequence)
+ {
+ /* Loop through each one */
+ for (RecoveryIndex = 0; RecoveryIndex < Count; RecoveryIndex++)
+ {
+ /* Does this index have an allocated boot entry? */
+ RecoveryEntry = Sequence[RecoveryIndex];
+ if (RecoveryEntry)
+ {
+ /* Destroy it */
+ BlDestroyBootEntry(RecoveryEntry);
+ }
+ }
+
+ /* Free the sequence itself */
+ BlMmFreeHeap(Sequence);
+ }
+
+ /* Was there a sequence list? */
+ if (RecoverySequence)
+ {
+ /* Free it */
+ BlMmFreeHeap(RecoverySequence);
+ }
+
+ /* Return back to caller */
+ return Status;
+}
+
+ULONG
+BmDisplayDumpError (
+ _In_ PBL_LOADED_APPLICATION_ENTRY BootEntry,
+ _In_ ULONG LaunchCode
+ )
+{
+ ULONG BootError;
+ NTSTATUS Status;
+ BOOLEAN Restart, NoError;
+
+ /* Assume we'll just reboot */
+ BootError = Reboot;
+
+ /* Should we reboot? */
+ Status = BlGetBootOptionBoolean(BlpApplicationEntry.BcdData,
+ BcdLibraryBoolean_RestartOnFailure,
+ &Restart);
+ if ((NT_SUCCESS(Status)) && (Restart))
+ {
+ return BootError;
+ }
+
+ /* Should we not show errors, and thus, reboot? */
+ Status = BlGetBootOptionBoolean(BlpApplicationEntry.BcdData,
+ BcdBootMgrBoolean_NoErrorDisplay,
+ &NoError);
+ if ((NT_SUCCESS(Status)) && (NoError))
+ {
+ return BootError;
+ }
+
+ /* Is there an internal boot error? */
+ if (BmpInternalBootError)
+ {
+ /* Return it -- but it's a pointer? */
+ return (ULONG)BmpInternalBootError; // ???
+ }
+
+ /* Otherwise, show the menu to see what to do */
+ EfiPrintf(L"Error menu not yet implemented\r\n");
+ return BootError;
+}
+
+NTSTATUS
+BmpCreateDevices (
+ _In_ PBL_LOADED_APPLICATION_ENTRY BootEntry
+ )
+{
+ ULONG NextOffset, DataOffset, ListOffset;
+ PBL_BCD_OPTION Option, ListOption;
+ BcdElementType ElementType;
+ PBCD_DEVICE_OPTION BcdDevice;
+
+ /* Starting at offset 0, loop every BCD option */
+ NextOffset = 0;
+ do
+ {
+ /* Get the current option, and its offset */
+ Option = (PBL_BCD_OPTION)((ULONG_PTR)BootEntry->BcdData + NextOffset);
+ NextOffset = Option->NextEntryOffset;
+
+ /* If it's empty, ignore it */
+ if (Option->Empty)
+ {
+ continue;
+ }
+
+ /* If it's not a device option, ignore it */
+ ElementType.PackedValue = Option->Type;
+ if (ElementType.Format != BCD_TYPE_DEVICE)
+ {
+ continue;
+ }
+
+ /* Get the data offset */
+ DataOffset = Option->DataOffset;
+
+ /* Extract the device out of it */
+ BcdDevice = (PBCD_DEVICE_OPTION)((ULONG_PTR)BootEntry->BcdData + DataOffset);
+
+ /* If the device is already fully specified, no need to build it */
+ if (!(BcdDevice->DeviceDescriptor.Flags & 1))
+ {
+ continue;
+ }
+
+ /* Otherwise, check if there's any list options as well */
+ ListOption = NULL;
+ ListOffset = Option->ListOffset;
+ if (Option->ListOffset)
+ {
+ ListOption = (PBL_BCD_OPTION)((ULONG_PTR)BootEntry->BcdData + ListOffset);
+ }
+
+ /* And now call BlCreateDevice to build the full device descriptor */
+ EfiPrintf(L"Unspecified devices not yet supported: %p\r\n", ListOption);
+ return STATUS_NOT_SUPPORTED;
+ } while (NextOffset != 0);
+
+ /* Devices created successfully */
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+BmpTransferExecution (
+ _In_ PBL_LOADED_APPLICATION_ENTRY BootEntry,
+ _Out_ PULONG LaunchCode,
+ _Out_ PBOOLEAN Recover
+ )
+{
+ PWCHAR AppPath;
+ NTSTATUS Status;
+ PBL_DEVICE_DESCRIPTOR AppDevice;
+ BL_RETURN_ARGUMENTS ReturnArgs;
+ BOOLEAN AdvancedOptions;
+ ULONG AppHandle;
+
+ /* Get the application path */
+ Status = BlGetBootOptionString(BootEntry->BcdData,
+ BcdLibraryString_ApplicationPath,
+ &AppPath);
+ if (!NT_SUCCESS(Status))
+ {
+ /* If we couldn't find one, set this to NULL */
+ AppPath = NULL;
+ }
+
+ /* Check if this is a PXE startup.com */
+ if (BootEntry->Flags & BL_APPLICATION_ENTRY_STARTUP)
+ {
+#if BL_NET_SUPPORT
+ /* Do soft reboot to launch it */
+ Status = BlNetSoftReboot(BootEntry);
+#else
+ EfiPrintf(L"Net boot not supported\r\n");
+ Status = STATUS_NOT_SUPPORTED;
+#endif
+ /* Nothing else for us to do */
+ goto Quickie;
+ }
+
+ /* Loop as long as boot was not cancelled */
+ do
+ {
+ /* Load the boot application */
+ Status = BlImgLoadBootApplication(BootEntry, &AppHandle);
+
+ /* Did we not find it? */
+ if (Status == STATUS_NOT_FOUND)
+ {
+ /* Get the device for the boot application */
+ Status = BlGetBootOptionDevice(BootEntry->BcdData,
+ BcdLibraryDevice_ApplicationDevice,
+ &AppDevice,
+ NULL);
+ if (NT_SUCCESS(Status))
+ {
+ /* Force re-enumeration */
+ Status = BlFwEnumerateDevice(AppDevice);
+ }
+
+ /* Did re-enumeration work? */
+ if (!NT_SUCCESS(Status))
+ {
+ /* Nope, raise a fatal error */
+ BmFatalErrorEx(BL_FATAL_ERROR_APP_LOAD,
+ (ULONG_PTR)AppPath,
+ Status,
+ 0,
+ 0);
+ goto Quickie;
+ }
+
+ /* Yes, try booting it again */
+ Status = BlImgLoadBootApplication(BootEntry, &AppHandle);
+ }
+
+ /* Was boot cancelled?*/
+ if (Status == STATUS_CANCELLED)
+ {
+ /* Should we display the menu, or is there no launch sequence? */
+ if ((BmGetBootMenuPolicy(BootEntry) != MenuPolicyStandard) ||
+ !(MiscGetBootOption(BootEntry->BcdData,
+ BcdLibraryObjectList_RecoverySequence)))
+ {
+ /* Bail out, the menu will take care of it */
+ goto Quickie;
+ }
+
+ /* No menu and there's a sequence, launch it */
+ *LaunchCode = 4;
+ *Recover = TRUE;
+ goto Quickie;
+ }
+
+ /* STATUS_FVE_LOCKED_VOLUME -- bitlocker volume is locked */
+ if (Status == 0xC0210000)
+ {
+ /* Launch recovery mode */
+ *LaunchCode = 4;
+ *Recover = TRUE;
+ goto Quickie;
+ }
+
+ /* Was there some other error launching the boot application? */
+ if (!NT_SUCCESS(Status))
+ {
+ /* Raise a fatal error */
+ BmFatalErrorEx(BL_FATAL_ERROR_APP_LOAD,
+ (ULONG_PTR)AppPath,
+ Status,
+ 0,
+ 0);
+ goto Quickie;
+ }
+
+ /* Zero out the return arguments */
+ RtlZeroMemory(&ReturnArgs, sizeof(ReturnArgs));
+
+ /* Log to ETW this launch */
+ //BmpLogApplicationLaunchEvent(&BootEntry->Guid, AppPath);
+
+ /* Launch the boot application*/
+ Status = BlImgStartBootApplication(AppHandle, &ReturnArgs);
+
+#if BL_BITLOCKER_SUPPORT
+ /* Bitlocker stuff */
+ BlFveSecureBootCheckpointAppReturn(BootEntry, &ReturnArgs);
+#endif
+
+ /* Log in the boot status log the launch */
+ //BlBsdLogEntry(1, 0x12, &BootEntry->Guid, 0x14);
+
+ /* Unloac the boot application if we've returned */
+ BlImgUnloadBootApplication(AppHandle);
+
+ /* Keep going unless STATUS_RESTART_BOOT_APPLICATION */
+ } while (Status != 0xC0000453);
+
+ /* We've come back. Assume we need to launch the recovery sequence */
+ *Recover = TRUE;
+
+ /* Why did we get back? */
+ if (ReturnArgs.Flags & 1)
+ {
+ /* Flag 1 -- should we display advanced options? */
+ Status = BlGetBootOptionBoolean(BootEntry->BcdData,
+ BcdLibraryBoolean_DisplayAdvancedOptions,
+ &AdvancedOptions);
+ if ((NT_SUCCESS(Status)) && (AdvancedOptions))
+ {
+ /* Yes, so return with code 2 */
+ *LaunchCode = 2;
+ }
+ else
+ {
+ /* No, return with code 1 */
+ *LaunchCode = 1;
+ }
+ }
+ else if (ReturnArgs.Flags & 4)
+ {
+ /* Flag 4 -- unkown */
+ *LaunchCode = 1;
+ }
+ else if (ReturnArgs.Flags & 8)
+ {
+ /* Flag 5 -- unkown */
+ *LaunchCode = 5;
+ }
+ else if (ReturnArgs.Flags & 0x10)
+ {
+ /* Flag 6 -- unkown */
+ *LaunchCode = 6;
+ }
+ else if (ReturnArgs.Flags & 0x20)
+ {
+ /* Flag 7 -- unkown */
+ *LaunchCode = 7;
+ }
+ else if (ReturnArgs.Flags & BL_RETURN_ARGUMENTS_NO_PAE_FLAG)
+ {
+ /* PAE is not supported -- refuse to boot */
+ *Recover = FALSE;
+ BmFatalErrorEx(BL_FATAL_ERROR_NO_PAE, Status, 0, 0, 0);
+ }
+
+Quickie:
+ /* All done, did we have an application path? */
+ if (AppPath)
+ {
+ /* Free it */
+ BlMmFreeHeap(AppPath);
+ }
+
+ /* Back to the caller now */
+ return Status;
+}
+
+NTSTATUS
+BmpLaunchBootEntry (
+ _In_ PBL_LOADED_APPLICATION_ENTRY BootEntry,
+ _Out_ PULONG EntryIndex,
+ _In_ ULONG LaunchCode,
+ _In_ BOOLEAN LaunchWinRe
+ )
+{
+ HANDLE BcdHandle;
+ NTSTATUS Status;
+ GUID ObjectId;
+ BOOLEAN DoRecovery, AutoRecovery, DoSequence, RestartOnFailure;
+ ULONG ErrorCode;
+ BOOLEAN AdvancedOneTime, EditOneTime;
+
+ /* Check if this is the OS loader */
+ if (BootEntry->Flags & BL_APPLICATION_ENTRY_WINLOAD)
+ {
+ /* Check if one-time advanced options should be shown */
+ if (MiscGetBootOption(BootEntry->BcdData,
+ BcdOSLoaderBoolean_AdvancedOptionsOneTime))
+ {
+ /* Open the BCD */
+ BcdHandle = NULL;
+ Status = BmOpenDataStore(BcdHandle);
+ if (NT_SUCCESS(Status))
+ {
+ /* Delete the option from the BCD, so it doesn't happen again */
+ ObjectId = BootEntry->Guid;
+ BmPurgeOption(BcdHandle,
+ &ObjectId,
+ BcdOSLoaderBoolean_AdvancedOptionsOneTime);
+ BmCloseDataStore(BcdHandle);
+ }
+ }
+
+ /* Check if one-time options editor should be shown */
+ if (MiscGetBootOption(BootEntry->BcdData,
+ BcdOSLoaderBoolean_OptionsEditOneTime))
+ {
+ /* Open the BCD */
+ BcdHandle = NULL;
+ Status = BmOpenDataStore(BcdHandle);
+ if (NT_SUCCESS(Status))
+ {
+ /* Delete the option from the BCD, so it doesn't happen again */
+ ObjectId = BootEntry->Guid;
+ BmPurgeOption(BcdHandle,
+ &ObjectId,
+ BcdOSLoaderBoolean_OptionsEditOneTime);
+ BmCloseDataStore(BcdHandle);
+ }
+ }
+ }
+
+TryAgain:
+ /* Disable recovery mode */
+ DoRecovery = FALSE;
+
+ /* Store globally which entry we are trying to boot */
+ BmpSelectedBootEntry = BootEntry;
+
+ /* Create any devices that aren't yet fully defined for this boot entry */
+ Status = BmpCreateDevices(BootEntry);
+ if (!NT_SUCCESS(Status))
+ {
+ /* That failed -- can we launch the recovery environment? */
+ if (!LaunchWinRe)
+ {
+ return Status;
+ }
+
+ /* Yes, so return with the WinRe launch code */
+ LaunchCode = 2;
+ goto Quickie;
+ }
+
+ /* Is this an OS loader/ */
+ if (BootEntry->Flags & BL_APPLICATION_ENTRY_WINLOAD)
+ {
+ /* Is the one-time advanced options menu option present? */
+ Status = BlGetBootOptionBoolean(BootEntry->BcdData,
+ BcdOSLoaderBoolean_AdvancedOptionsOneTime,
+ &AdvancedOneTime);
+ if (NT_SUCCESS(Status))
+ {
+ /* Is it turned on? */
+ if (AdvancedOneTime)
+ {
+ /* Set the option this once */
+ BlAppendBootOptionBoolean(BootEntry,
+ BcdLibraryBoolean_DisplayAdvancedOptions);
+ }
+ else
+ {
+ /* It's not, so disable the option if active */
+ BlRemoveBootOption(BootEntry->BcdData,
+ BcdLibraryBoolean_DisplayAdvancedOptions);
+ }
+
+ /* Remove the one-time option. We've already purged it earlier */
+ BlRemoveBootOption(BootEntry->BcdData,
+ BcdOSLoaderBoolean_AdvancedOptionsOneTime);
+ }
+
+ /* Is the one-time options editor menu option present? */
+ Status = BlGetBootOptionBoolean(BootEntry->BcdData,
+ BcdOSLoaderBoolean_OptionsEditOneTime,
+ &EditOneTime);
+ if (NT_SUCCESS(Status))
+ {
+ /* Is it turned on? */
+ if (EditOneTime)
+ {
+ /* Set the option this once */
+ BlAppendBootOptionBoolean(BootEntry,
+ BcdLibraryBoolean_DisplayOptionsEdit);
+ }
+ else
+ {
+ /* It's not, so disable the option if active */
+ BlRemoveBootOption(BootEntry->BcdData,
+ BcdLibraryBoolean_DisplayOptionsEdit);
+ }
+
+ /* Remove the one-time option. We've already purged it earlier */
+ BlRemoveBootOption(BootEntry->BcdData,
+ BcdOSLoaderBoolean_OptionsEditOneTime);
+ }
+ }
+
+ /* BCD handling done, transfer execution to this entry */
+ Status = BmpTransferExecution(BootEntry, &LaunchCode, &DoRecovery);
+ if (!LaunchWinRe)
+ {
+ return Status;
+ }
+
+ /* Check if boot was successfull, or cancelled and we're not doing WinRE */
+ if (((NT_SUCCESS(Status)) || (Status == STATUS_CANCELLED)) && !(DoRecovery))
+ {
+ return Status;
+ }
+
+ /* Boot failed -- are we doing recovery? */
+ if (!DoRecovery)
+ {
+ /* Nope, bail out */
+ LaunchCode = 2;
+ goto Quickie;
+ }
+
+Quickie:
+ /* Get the recovery sequence */
+ if (MiscGetBootOption(BootEntry->BcdData, BcdLibraryObjectList_RecoverySequence))
+ {
+ /* Check if the launch depends on auto-recovery being enabled or not */
+ if ((LaunchCode == 3) || (LaunchCode == 5) || (LaunchCode == 6))
+ {
+ Status = BlGetBootOptionBoolean(BootEntry->BcdData,
+ BcdLibraryBoolean_AutoRecoveryEnabled,
+ &AutoRecovery);
+ if (NT_SUCCESS(Status))
+ {
+ /* Override the setting */
+ DoRecovery = AutoRecovery;
+ }
+ }
+ }
+ else
+ {
+ /* There's no recovery setting */
+ DoRecovery = FALSE;
+ }
+
+ /* Check if we should restart on failure */
+ RestartOnFailure = FALSE;
+ BlGetBootOptionBoolean(BlpApplicationEntry.BcdData,
+ BcdLibraryBoolean_RestartOnFailure,
+ &RestartOnFailure);
+
+ /* Do the sequence if recovery is on, unless we should restart instead */
+ DoSequence = RestartOnFailure ? FALSE : DoRecovery;
+ while (1)
+ {
+ /* Are we doing the recovery sequence? */
+ if (DoSequence)
+ {
+ /* Because of automatic recovery? */
+ if (AutoRecovery)
+ {
+#if BL_BITLOCKER_SUPPORT
+ /* Do bitlocker stuff */
+ BlFveRegisterBootEntryForTrustedWimBoot(BootEntry, TRUE);
+#endif
+ }
+
+ /* Launch the recovery sequence*/
+ Status = BmLaunchRecoverySequence(BootEntry, LaunchCode);
+
+ /* Was it launched automatically? */
+ if (AutoRecovery)
+ {
+#if BL_BITLOCKER_SUPPORT
+ /* Do bitlocker stuff */
+ BlFveRegisterBootEntryForTrustedWimBoot(BootEntry, FALSE);
+#endif
+
+ /* No need to do this again */
+ AutoRecovery = FALSE;
+ }
+
+ /* Did the recovery sequence work? */
+ if (NT_SUCCESS(Status))
+ {
+ /* All good */
+ return STATUS_SUCCESS;
+ }
+
+ /* Remove the sequence, don't do it again */
+ BlRemoveBootOption(BootEntry->BcdData, BcdLibraryObjectList_RecoverySequence);
+ }
+
+ /* Recovery sequence also failed, show fatal error */
+ if (!BmpInternalBootError)
+ {
+ BmFatalErrorEx(BL_FATAL_ERROR_GENERIC, Status, 0, 0, 0);
+ }
+
+ /* Display the error menu */
+ ErrorCode = BmDisplayDumpError(BootEntry, LaunchCode);
+ BmErrorPurge();
+
+ /* See what the user wants to do */
+ switch (ErrorCode)
+ {
+ case TryAgain:
+ /* Try again */
+ goto TryAgain;
+
+ case NextOs:
+ /* Boot the next entry*/
+ break;
+
+ case OsSelection:
+ /* Cancel the boot*/
+ return STATUS_CANCELLED;
+
+ case RecoverOem:
+ /* Custom OEM recovery -- open the BCD */
+ Status = BmOpenDataStore(BcdHandle);
+ if (NT_SUCCESS(Status))
+ {
+ /* See what the custom sequence is */
+ Status = BmProcessCustomAction(BcdHandle, NULL);
+ }
+
+ /* All done, close the BCD */
+ if (BcdHandle)
+ {
+ BmCloseDataStore(BcdHandle);
+ }
+ return Status;
+
+ case AdvancedOptions:
+ /* Show the advanced options next iteration */
+ BlAppendBootOptionBoolean(BootEntry, BcdOSLoaderBoolean_AdvancedOptionsOneTime);
+ goto TryAgain;
+
+ case BootOptions:
+ /* Show the options editor next iteration */
+ BlAppendBootOptionBoolean(BootEntry, BcdOSLoaderBoolean_OptionsEditOneTime);
+ goto TryAgain;
+
+ case Recover:
+ /* Try the recovery sequence next time*/
+ DoSequence = TRUE;
+ LaunchCode = 1;
+ goto TryAgain;
+
+ default:
+ /* Something unknown */
+ return STATUS_CANCELLED;
+ }
+ }
+
+ /* We are booting the next OS, so return success as to not kill the boot */
+ return STATUS_SUCCESS;
+}
+
+/*++
+ * @name BmMain
+ *
+ * The BmMain function implements the Windows Boot Application entrypoint for
+ * the Boot Manager.
+ *
+ * @param BootParameters
+ * Pointer to the Boot Application Parameter Block.
+ *
+ * @return NT_SUCCESS if the image was loaded correctly, relevant error code
+ * otherwise.
+ *
+ *--*/
+NTSTATUS
+BmMain (
+ _In_ PBOOT_APPLICATION_PARAMETER_BLOCK BootParameters
+ )
+{
+ NTSTATUS Status, LibraryStatus;
+ BL_LIBRARY_PARAMETERS LibraryParameters;
+ PBL_RETURN_ARGUMENTS ReturnArguments;
+ PGUID AppIdentifier;
+ HANDLE BcdHandle, ResumeBcdHandle;
+ PBL_BCD_OPTION EarlyOptions;
+ PWCHAR Stylesheet;
+ BOOLEAN XmlLoaded, DisableIntegrity, TestSigning, PersistBootSequence;
+ BOOLEAN RebootOnError, CustomActions;
+ ULONG SequenceId;
+ PBL_LOADED_APPLICATION_ENTRY BootEntry;
+ PGUID SequenceList;
+ ULONG SequenceListCount;
+ PBL_LOADED_APPLICATION_ENTRY* BootSequence;
+ ULONG BootIndex;
+ BOOLEAN ExitBootManager;
+ BOOLEAN BootFailed;
+ BOOLEAN BootOk;
+ ULONG SequenceCount;
+ BOOLEAN GetEntry;
+ EfiPrintf(L"ReactOS UEFI Boot Manager Initializing...\r\n");
+
+ /* Reading the BCD can change this later on */
+ RebootOnError = FALSE;
+
+ /* Save the start/end-of-POST time */
+ ApplicationStartTime = __rdtsc();
+ PostTime = ApplicationStartTime;
+
+ /* Setup the boot library parameters for this application */
+ BlSetupDefaultParameters(&LibraryParameters);
+ LibraryParameters.TranslationType = BlNone;
+ LibraryParameters.LibraryFlags = 0x400 | 0x8;
+ LibraryParameters.MinimumAllocationCount = 16;
+ LibraryParameters.MinimumHeapSize = 512 * 1024;
+
+ /* Initialize the boot library */
+ Status = BlInitializeLibrary(BootParameters, &LibraryParameters);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Check for failure due to invalid application entry */
+ if (Status != STATUS_INVALID_PARAMETER_9)
+ {
+ /* Specifically print out what happened */
+ EfiPrintf(L"BlInitializeLibrary failed 0x%x\r\n", Status);
+ }
+
+ /* Go to exit path */
+ goto Quickie;
+ }
+
+ /* Get the application identifier */
+ AppIdentifier = BlGetApplicationIdentifier();
+ if (!AppIdentifier)
+ {
+ /* None was given, so set our default one */
+ AppIdentifier = (PGUID)&GUID_WINDOWS_BOOTMGR;
+ }
+
+ /* Save our identifier */
+ BmApplicationIdentifier = *AppIdentifier;
+
+ /* Initialize the file system to open a handle to our root boot directory */
+ BmFwInitializeBootDirectoryPath();
+
+ /* Load and initialize the boot configuration database (BCD) */
+ Status = BmOpenDataStore(&BcdHandle);
+ if (NT_SUCCESS(Status))
+ {
+ /* Copy the boot options */
+ Status = BlCopyBootOptions(BlpApplicationEntry.BcdData, &EarlyOptions);
+ if (NT_SUCCESS(Status))
+ {
+ /* Update them */
+ Status = BmpUpdateApplicationOptions(BcdHandle);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Log a fatal error */
+ BmFatalErrorEx(BL_FATAL_ERROR_BCD_PARSE,
+ (ULONG_PTR)L"\\BCD",
+ Status,
+ 0,
+ 0);
+ }
+ }
+ }
+
+#ifdef _SECURE_BOOT
+ /* Initialize the secure boot machine policy */
+ Status = BmSecureBootInitializeMachinePolicy();
+ if (!NT_SUCCESS(Status))
+ {
+ BmFatalErrorEx(BL_FATAL_ERROR_SECURE_BOOT, Status, 0, 0, 0);
+ }
+#endif
+
+ /* Copy the library parameters and add the re-initialization flag */
+ RtlCopyMemory(&LibraryParameters,
+ &BlpLibraryParameters,
+ sizeof(LibraryParameters));
+ LibraryParameters.LibraryFlags |= (BL_LIBRARY_FLAG_REINITIALIZE_ALL |
+ BL_LIBRARY_FLAG_REINITIALIZE);
+
+ /* Now that we've parsed the BCD, re-initialize the library */
+ LibraryStatus = BlInitializeLibrary(BootParameters, &LibraryParameters);
+ if (!NT_SUCCESS(LibraryStatus) && (NT_SUCCESS(Status)))
+ {
+ Status = LibraryStatus;
+ }
+
+ /* Initialize firmware-specific memory regions */
+ BmFwMemoryInitialize();
+
+ /* Initialize the boot status data log (BSD) */
+ BmpInitializeBootStatusDataLog();
+
+ /* Find our XSL stylesheet */
+ Stylesheet = BlResourceFindHtml();
+ if (!Stylesheet)
+ {
+ /* Awe, no XML. This is actually fatal lol. Can't boot without XML. */
+ Status = STATUS_NOT_FOUND;
+ EfiPrintf(L"BlResourceFindMessage failed 0x%x\r\n", STATUS_NOT_FOUND);
+ goto Quickie;
+ }
+
+ /* Initialize the XML Engine (as a side-effect, resets cursor) */
+ Status = BlXmiInitialize(Stylesheet);
+ if (!NT_SUCCESS(Status))
+ {
+ EfiPrintf(L"\r\nBlXmiInitialize failed 0x%x\r\n", Status);
+ goto Failure;
+ }
+ XmlLoaded = TRUE;
+ EfiStall(100000000);
+ /* Check if there's an active bitmap visible */
+ if (!BlDisplayValidOemBitmap())
+ {
+ /* Nope, make the screen black using BGFX */
+ if (!NT_SUCCESS(BmpBgDisplayClearScreen(0xFF000000)))
+ {
+ /* BGFX isn't active, use standard display */
+ BlDisplayClearScreen();
+ }
+ }
+
+#ifdef _BIT_LOCKER_
+ /* Bitlocker will take over screen UI if enabled */
+ FveDisplayScreen = BmFveDisplayScreen;
+#endif
+
+ /* Check if any bypass options are enabled */
+ BlImgQueryCodeIntegrityBootOptions(&BlpApplicationEntry,
+ &DisableIntegrity,
+ &TestSigning);
+ if (!DisableIntegrity)
+ {
+ /* Integrity checks are enabled, so validate our signature */
+ Status = BmFwVerifySelfIntegrity();
+ if (!NT_SUCCESS(Status))
+ {
+ /* Signature invalid, fail boot */
+ goto Failure;
+ }
+ }
+
+ /* Write out the first XML tag */
+ BlXmiWrite(L"<bootmgr/>");
+
+ /* Check for factory resset */
+ BlSecureBootCheckForFactoryReset();
+
+ /* Load the revocation list */
+ Status = BmFwRegisterRevocationList();
+ if (!NT_SUCCESS(Status))
+ {
+ goto Failure;
+ }
+
+ /* Register our custom progress routine */
+ BlUtlRegisterProgressRoutine();
+
+ /* Display state is not currently cached */
+ BmDisplayStateCached = FALSE;
+
+ /* Check if we need to resume from hibernate */
+ Status = BmResumeFromHibernate(&ResumeBcdHandle);
+ if (!NT_SUCCESS(Status))
+ {
+ goto Failure;
+ }
+
+#ifdef BL_NET_SUPPORT
+ /* Register multicast printing routine */
+ BlUtlRegisterMulticastRoutine();
+#endif
+
+ /* Check if restart on failure is enabled */
+ BlGetBootOptionBoolean(BlpApplicationEntry.BcdData,
+ BcdLibraryBoolean_RestartOnFailure,
+ &RebootOnError);
+
+ /* Check if the boot sequence is persisted */
+ Status = BlGetBootOptionBoolean(BlpApplicationEntry.BcdData,
+ BcdBootMgrBoolean_PersistBootSequence,
+ &PersistBootSequence);
+ if (!NT_SUCCESS(Status))
+ {
+ /* It usually is */
+ PersistBootSequence = TRUE;
+ }
+
+ /* Check if there's custom actions to take */
+ Status = BlGetBootOptionBoolean(BlpApplicationEntry.BcdData,
+ BcdBootMgrBoolean_ProcessCustomActionsFirst,
+ &CustomActions);
+ if ((NT_SUCCESS(Status)) && (CustomActions))
+ {
+ /* We don't suppport this yet */
+ EfiPrintf(L"Not implemented\r\n");
+ Status = STATUS_NOT_IMPLEMENTED;
+ goto Failure;
+ }
+
+ //BlResourceFindMessage(BM_MSG_TEST);
+
+ /* At last, enter the boot selection stage */
+ SequenceId = 0;
+ GetEntry = FALSE;
+ BootFailed = FALSE;
+ SequenceList = NULL;
+ BootSequence = NULL;
+ SequenceCount = 0;
+ while (1)
+ {
+ /* We don't have a boot entry nor a sequence ID */
+ BootEntry = NULL;
+ BootOk = FALSE;
+
+ /* Do we have a hardcoded boot sequence set? */
+ if (!(BootSequence) && !(GetEntry))
+ {
+ /* Not yet, read the BCD to see if one is there */
+ Status = BlGetBootOptionGuidList(BlpApplicationEntry.BcdData,
+ BcdBootMgrObjectList_BootSequence,
+ &SequenceList,
+ &SequenceListCount);
+ if (NT_SUCCESS(Status))
+ {
+ /* A GUID list for the boot sequence is set. Extract it */
+ Status = BmGetBootSequence(BcdHandle,
+ SequenceList,
+ SequenceListCount,
+ BL_APPLICATION_ENTRY_FIXED_SEQUENCE,
+ &BootSequence,
+ &SequenceCount);
+ if (NT_SUCCESS(Status))
+ {
+ /* Don't get stuck in a loop repeating this sequence */
+ BlRemoveBootOption(BlpApplicationEntry.BcdData,
+ BcdBootMgrObjectList_BootSequence);
+
+ /* But do check if we should persist it */
+ if (PersistBootSequence)
+ {
+ /* Yes -- so go select an entry now */
+ GetEntry = TRUE;
+ }
+ else
+ {
+ /* We shouldn't, so wipe it from the BCD too */
+ Status = BmPurgeOption(BcdHandle,
+ &BmApplicationIdentifier,
+ BcdBootMgrObjectList_BootSequence);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Well that failed */
+ goto LoopQuickie;
+ }
+ }
+ }
+ }
+ else
+ {
+ /* No boot entry sequence for us */
+ BootSequence = NULL;
+ }
+ }
+
+ /* Do we have a sequence active, and are we still processing it? */
+ if ((BootSequence) && ((GetEntry) || (SequenceId < SequenceCount)))
+ {
+ /* Extract the next entry in the sequence */
+ BootEntry = BootSequence[SequenceId];
+ BootSequence[SequenceId] = NULL;
+
+ /* Move to the next entry for next time */
+ SequenceId++;
+
+ /* Unless there won't be a a next time? */
+ if (SequenceId == SequenceCount)
+ {
+ /* Clean up, it's the last entry */
+ BlMmFreeHeap(BootSequence);
+ BootSequence = NULL;
+ }
+ }
+ else
+ {
+ /* Get the selected boot entry from the user */
+ ExitBootManager = FALSE;
+ Status = BmpGetSelectedBootEntry(BcdHandle,
+ &BootEntry,
+ &BootIndex,
+ &ExitBootManager);
+ if (!(NT_SUCCESS(Status)) || (ExitBootManager))
+ {
+ /* Selection failed, or user wants to exit */
+ goto LoopQuickie;
+ }
+ }
+
+ /* Did we have a BCD open? */
+ if (BcdHandle)
+ {
+ /* Close it, we'll be opening a new one */
+ BmCloseDataStore(BcdHandle);
+ BcdHandle = NULL;
+ }
+
+ /* Launch the selected entry */
+ Status = BmpLaunchBootEntry(BootEntry, &BootIndex, 0, TRUE);
+ if (NT_SUCCESS(Status))
+ {
+ /* Boot worked, uncache display and process the bad memory list */
+ BmDisplayStateCached = FALSE;
+ BmpProcessBadMemory();
+ }
+ else
+ {
+ /* Boot failed -- was it user driven? */
+ if (Status != STATUS_CANCELLED)
+ {
+ /* Nope, remember that booting failed */
+ BootFailed = TRUE;
+ goto LoopQuickie;
+ }
+
+ /* Yes -- the display is still valid */
+ BmDisplayStateCached = TRUE;
+ }
+
+ /* Reopen the BCD */
+ Status = BmOpenDataStore(&BcdHandle);
+ if (!NT_SUCCESS(Status))
+ {
+ break;
+ }
+
+ /* Put the BCD options back into our entry */
+ BlReplaceBootOptions(&BlpApplicationEntry, EarlyOptions);
+
+ /* Update our options one more time */
+ Status = BmpUpdateApplicationOptions(BcdHandle);
+ if (NT_SUCCESS(Status))
+ {
+ /* Boot was 100% OK */
+ BootOk = TRUE;
+ }
+
+LoopQuickie:
+ /* Did we have a boot entry? */
+ if (BootEntry)
+ {
+ /* We can destroy it now */
+ BlDestroyBootEntry(BootEntry);
+ }
+
+ /* Is this the success path? */
+ if (NT_SUCCESS(Status))
+ {
+ /* Did we actually boot something? */
+ if (!BootOk)
+ {
+ /* Bope, fail out */
+ break;
+ }
+ }
+
+ /* This is the failure path... should we reboot? */
+ if (RebootOnError)
+ {
+ break;
+ }
+ };
+
+Failure:
+ if (!BootFailed)
+ {
+ /* Check if we got here due to an internal error */
+ if (BmpInternalBootError)
+ {
+ /* If XML is available, display the error */
+ if (XmlLoaded)
+ {
+ //BmDisplayDumpError(0, 0);
+ //BmErrorPurge();
+ }
+
+ /* Don't do a fatal error -- return back to firmware */
+ goto Quickie;
+ }
}
/* Log a general fatal error once we're here */
ReturnArguments->Version = BL_RETURN_ARGUMENTS_VERSION;
ReturnArguments->Status = Status;
- /* Tear down the boot library*/
+ /* Tear down the boot library */
BlDestroyLibrary();
}