[BOOTMGFW]: Implement the final boot selection & launch loop.

[BOOTMLIB]: Implement a few more BCD option functions.
Minus a PE loader (BmpLaunchBootEntry) and some more BCD parsing (BmpGetSelectedBootEntry) with some glue in between, the UEFI Boot Manager is nearly done. Once it is, it will be time to implement the actual loader -- Winload.efi. The good news is that we'll have all of bootlib already good to go (with all its hacks). The bad news is that Winload will turn on paging, so all those unimplemented paths and UEFI mode switches will have to be made to work.

svn path=/trunk/; revision=70556
This commit is contained in:
Alex Ionescu 2016-01-09 05:39:18 +00:00
parent 5e7a5d0d57
commit 9701df346f
4 changed files with 362 additions and 47 deletions

View file

@ -1163,6 +1163,66 @@ BmResumeFromHibernate (
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
BmpProcessBadMemory (
VOID
)
{
EfiPrintf(L"Bad page list persistence \r\n");
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
BmPurgeOption (
_In_ HANDLE BcdHandle,
_In_ PGUID ObjectId,
_In_ ULONG Type
)
{
EfiPrintf(L"Key BCD delete not yet implemented\r\n");
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
BmGetBootSequence (
_In_ HANDLE BcdHandle,
_In_ PGUID SequenceList,
_In_ ULONG SequenceListCount,
_In_ ULONG Flags,
_Out_ PBL_LOADED_APPLICATION_ENTRY** BootSequence,
_Out_ PULONG SequenceCount
)
{
EfiPrintf(L"Fixed sequences not yet supported\r\n");
*SequenceCount = 0;
*BootSequence = NULL;
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
BmpGetSelectedBootEntry (
_In_ HANDLE BcdHandle,
_Out_ PBL_LOADED_APPLICATION_ENTRY *SelectedBootEntry,
_Out_ PULONG EntryIndex,
_Out_ PBOOLEAN ExitBootManager
)
{
EfiPrintf(L"Boot selection not yet implemented\r\n");
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
BmpLaunchBootEntry (
_In_ PBL_LOADED_APPLICATION_ENTRY BootEntry,
_Out_ PULONG EntryIndex,
_In_ ULONG Unknown,
_In_ BOOLEAN LaunchWinRe
)
{
EfiPrintf(L"Boot launch not yet implemented\r\n");
return STATUS_NOT_IMPLEMENTED;
}
/*++
* @name BmMain
*
@ -1189,12 +1249,18 @@ BmMain (
PBL_BCD_OPTION EarlyOptions;
PWCHAR Stylesheet;
BOOLEAN XmlLoaded, DisableIntegrity, TestSigning, PersistBootSequence;
BOOLEAN RebootOnError, CustomActions, ContinueLoop;
ULONG SequenceId, SequenceCount;
PGUID BootSequences;
//PBL_LOADED_APPLICATION_ENTRY* BootEntries;
//PBL_LOADED_APPLICATION_ENTRY BootEntry;
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 */
@ -1401,49 +1467,190 @@ BmMain (
/* At last, enter the boot selection stage */
SequenceId = 0;
do
GetEntry = FALSE;
BootFailed = FALSE;
SequenceList = NULL;
BootSequence = NULL;
SequenceCount = 0;
while (1)
{
ContinueLoop = FALSE;
/* We don't have a boot entry nor a sequence ID */
BootEntry = NULL;
BootOk = FALSE;
/* Get the list of boot sequences */
SequenceCount = 0;
Status = BlGetBootOptionGuidList(BlpApplicationEntry.BcdData,
BcdBootMgrObjectList_BootSequence,
&BootSequences,
&SequenceCount);
EfiPrintf(L"Count: %d\r\n", SequenceCount);
EfiStall(1000000);
if (!NT_SUCCESS(Status))
/* Do we have a hardcoded boot sequence set? */
if (!(BootSequence) && !(GetEntry))
{
//goto 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,
0x20000000,
&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))
{
continue;
/* 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;
}
if (RebootOnError)
/* Reopen the BCD */
Status = BmOpenDataStore(&BcdHandle);
if (!NT_SUCCESS(Status))
{
break;
}
SequenceId++;
} while (ContinueLoop);
/* Put the BCD options back into our entry */
BlReplaceBootOptions(&BlpApplicationEntry, EarlyOptions);
Failure:
/* Check if we got here due to an internal error */
if (BmpInternalBootError)
{
/* If XML is available, display the error */
if (XmlLoaded)
/* Update our options one more time */
Status = BmpUpdateApplicationOptions(BcdHandle);
if (NT_SUCCESS(Status))
{
//BmDisplayDumpError(0, 0);
//BmErrorPurge();
/* Boot was 100% OK */
BootOk = TRUE;
}
/* Don't do a fatal error -- return back to firmware */
goto Quickie;
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 */

View file

@ -1514,16 +1514,6 @@ BlUtlGetAcpiTable (
_In_ ULONG Signature
);
EFI_STATUS
EfiGetEfiStatusCode(
_In_ NTSTATUS Status
);
NTSTATUS
EfiGetNtStatusCode (
_In_ EFI_STATUS EfiStatus
);
NTSTATUS
BlUtlInitialize (
VOID
@ -1534,6 +1524,29 @@ BlUtlRegisterProgressRoutine (
VOID
);
NTSTATUS
BlGetApplicationBaseAndSize (
_Out_ PVOID* ImageBase,
_Out_ PULONG ImageSize
);
VOID
BlDestroyBootEntry (
_In_ PBL_LOADED_APPLICATION_ENTRY AppEntry
);
/* FIRMWARE UTILITY ROUTINES *************************************************/
EFI_STATUS
EfiGetEfiStatusCode(
_In_ NTSTATUS Status
);
NTSTATUS
EfiGetNtStatusCode (
_In_ EFI_STATUS EfiStatus
);
VOID
BlFwReboot (
VOID
@ -1559,11 +1572,7 @@ BlSecureBootCheckForFactoryReset (
VOID
);
NTSTATUS
BlGetApplicationBaseAndSize (
_Out_ PVOID* ImageBase,
_Out_ PULONG ImageSize
);
/* RESOURCE ROUTINES *********************************************************/
PWCHAR
BlResourceFindMessage (
@ -1716,6 +1725,18 @@ BlAppendBootOptions (
_In_ PBL_BCD_OPTION Options
);
VOID
BlRemoveBootOption (
_In_ PBL_BCD_OPTION List,
_In_ ULONG Type
);
NTSTATUS
BlReplaceBootOptions (
_In_ PBL_LOADED_APPLICATION_ENTRY AppEntry,
_In_ PBL_BCD_OPTION NewOptions
);
/* BOOT REGISTRY ROUTINES ****************************************************/
VOID

View file

@ -436,3 +436,18 @@ BlGetApplicationBaseAndSize (
*ImageSize = BlpApplicationParameters->ImageSize;
return STATUS_SUCCESS;
}
VOID
BlDestroyBootEntry (
_In_ PBL_LOADED_APPLICATION_ENTRY AppEntry
)
{
/* Check if we had allocated BCD options */
if (AppEntry->Flags & BL_APPLICATION_ENTRY_BCD_OPTIONS_INTERNAL)
{
BlMmFreeHeap(AppEntry->BcdData);
}
/* Free the entry itself */
BlMmFreeHeap(AppEntry);
}

View file

@ -645,3 +645,75 @@ BlAppendBootOptions (
return Status;
}
VOID
BlRemoveBootOption (
_In_ PBL_BCD_OPTION List,
_In_ ULONG Type
)
{
PBL_BCD_OPTION Option;
/* Keep going until the option is gone */
while (1)
{
/* Get the BCD option */
Option = MiscGetBootOption(List, Type);
if (!Option)
{
break;
}
/* Pretend it's empty */
Option->Empty = TRUE;
}
}
NTSTATUS
BlReplaceBootOptions (
_In_ PBL_LOADED_APPLICATION_ENTRY AppEntry,
_In_ PBL_BCD_OPTION NewOptions
)
{
NTSTATUS Status;
ULONG Size;
/* Make sure there's something to replace with */
if (!NewOptions)
{
return STATUS_INVALID_PARAMETER;
}
/* Check if we already had allocated internal options */
if (AppEntry->Flags & BL_APPLICATION_ENTRY_BCD_OPTIONS_INTERNAL)
{
/* Free them */
BlMmFreeHeap(AppEntry->BcdData);
}
/* Reset option flags */
AppEntry->Flags &= ~(BL_APPLICATION_ENTRY_BCD_OPTIONS_INTERNAL |
BL_APPLICATION_ENTRY_BCD_OPTIONS_EXTERNAL);
/* Reset the options and set success for now */
Status = STATUS_SUCCESS;
AppEntry->BcdData = NULL;
/* Get the size of the new list of options */
Size = BlGetBootOptionListSize(NewOptions);
/* Allocate a copy of the new list */
NewOptions = BlMmAllocateHeap(Size);
if (!NewOptions)
{
return STATUS_NO_MEMORY;
}
/* Copy it in */
RtlCopyMemory(NewOptions, NewOptions, Size);
/* Set it as the new set of options and return */
AppEntry->Flags |= BL_APPLICATION_ENTRY_BCD_OPTIONS_INTERNAL;
AppEntry->BcdData = NewOptions;
return Status;
}