[HIVEBCD]: Fix wrong element type for application device element.

[BOOTMGR]: Implement boot sequence population. We correctly detect our winload.efi entry in the BCD hive.
[BOOTMGR]: Document more application entry flags.
[BOOTLIB]: Document and implement BCD object description parsing. Based off BCD Reference Guide / Geoff Chappel's website.
[BOOTLIB]: Add support for appending a boot option to an entry.

svn path=/trunk/; revision=70614
This commit is contained in:
Alex Ionescu 2016-01-18 16:54:44 +00:00
parent f3c6cefe6f
commit 12f04d8cb1
7 changed files with 439 additions and 14 deletions

View file

@ -22,7 +22,7 @@ BCD,"BCD00000000\Objects\{9dea862c-5cdd-4e70-acc1-f32b344d4795}\Elements\2500000
; ReactOS Boot Loader
;
BCD,"BCD00000000\Objects\{7619dcc9-fafe-11d9-b411-000476eba25f}\Description","Type",0x00010001,0x10200003 ; identifier={winload}
BCD,"BCD00000000\Objects\{7619dcc9-fafe-11d9-b411-000476eba25f}\Elements\11000011","Element",0x1,\ ; device=boot
BCD,"BCD00000000\Objects\{7619dcc9-fafe-11d9-b411-000476eba25f}\Elements\11000001","Element",0x1,\ ; device=boot
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\
05,00,00,00,\
00,00,00,00,\
@ -45,7 +45,7 @@ BCD,"BCD00000000\Objects\{7619dcc9-fafe-11d9-b411-000476eba25f}\Elements\260000b
; ReactOS Memory Tester
;
BCD,"BCD00000000\Objects\{b2721d73-1db4-4c62-bf78-c548a880142d}\Description","Type",0x00010001,0x10200005 ; identifier={memdiag}
BCD,"BCD00000000\Objects\{b2721d73-1db4-4c62-bf78-c548a880142d}\Elements\11000011","Element",0x1,\ ; device=boot
BCD,"BCD00000000\Objects\{b2721d73-1db4-4c62-bf78-c548a880142d}\Elements\11000001","Element",0x1,\ ; device=boot
00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\
05,00,00,00,\
00,00,00,00,\

View file

@ -121,7 +121,6 @@ BmGetOptionList (
/* 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 */
@ -1230,6 +1229,40 @@ BmPurgeOption (
return Status;
}
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))
{
/* Make sure the caller passed this argument in */
if (!Description)
{
/* Fail otherwise */
Status = STATUS_INVALID_PARAMETER;
}
else
{
/* Query the description from the BCD interface */
Status = BiGetObjectDescription(ObjectHandle, Description);
}
/* Close the object key */
BiCloseKey(ObjectHandle);
}
/* Return the result back */
return Status;
}
NTSTATUS
BmpPopulateBootEntryList (
_In_ HANDLE BcdHandle,
@ -1239,10 +1272,211 @@ BmpPopulateBootEntryList (
_Out_ PULONG SequenceCount
)
{
EfiPrintf(L"Boot population not yet supported\r\n");
*SequenceCount = 0;
*BootSequence = NULL;
return STATUS_NOT_IMPLEMENTED;
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
@ -1363,7 +1597,7 @@ BmEnumerateBootEntries (
/* Populate the list of bootable entries */
Status = BmpPopulateBootEntryList(BcdHandle,
DisplayOrder,
0x800000,
BL_APPLICATION_ENTRY_DISPLAY_ORDER,
Sequence,
&BcdCount);
if (!NT_SUCCESS(Status))
@ -1454,7 +1688,8 @@ BmpGetSelectedBootEntry (
goto Quickie;
}
EfiPrintf(L"Boot selection not yet implemented\r\n");
EfiPrintf(L"Boot selection not yet implemented. %d entries found\r\n", Count);
EfiStall(10000000);
*SelectedBootEntry = NULL;
Quickie:
@ -1772,7 +2007,7 @@ BmMain (
Status = BmGetBootSequence(BcdHandle,
SequenceList,
SequenceListCount,
0x20000000,
BL_APPLICATION_ENTRY_FIXED_SEQUENCE,
&BootSequence,
&SequenceCount);
if (NT_SUCCESS(Status))

View file

@ -26,6 +26,25 @@
#define BCD_TYPE_BOOLEAN 0x06
#define BCD_TYPE_INTEGER_LIST 0x07
#define BCD_IMAGE_TYPE_FIRMWARE 0x01
#define BCD_IMAGE_TYPE_BOOT_APP 0x02
#define BCD_IMAGE_TYPE_NTLDR 0x03
#define BCD_IMAGE_TYPE_REAL_MODE 0x04
#define BCD_APPLICATION_TYPE_FWBOOTMGR 0x01
#define BCD_APPLICATION_TYPE_BOOTMGR 0x02
#define BCD_APPLICATION_TYPE_OSLOADER 0x03
#define BCD_APPLICATION_TYPE_RESUME 0x04
#define BCD_APPLICATION_TYPE_MEMDIAG 0x05
#define BCD_APPLICATION_TYPE_NTLDR 0x06
#define BCD_APPLICATION_TYPE_SETUPLDR 0x07
#define BCD_APPLICATION_TYPE_BOOTSECTOR 0x08
#define BCD_APPLICATION_TYPE_STARTUPCOM 0x09
#define BCD_OBJECT_TYPE_APPLICATION 0x01
#define BCD_OBJECT_TYPE_INHEREIT 0x02
#define BCD_OBJECT_TYPE_DEVICE 0x03
typedef enum BcdLibraryElementTypes
{
BcdLibraryDevice_ApplicationDevice = 0x11000001,
@ -172,13 +191,20 @@ typedef enum BcdBootMgrElementTypes
BcdBootMgrBoolean_PersistBootSequence = 0x26000031
} BcdBootMgrElementTypes;
/* Undocumented */
typedef enum BcdStartupElementTypes
{
BcdStartupBoolean_PxeSoftReboot = 0x26000001,
BcdStartupString_PxeApplicationName = 0x22000002,
} BcdStartupElementTypes;
/* DATA STRUCTURES ***********************************************************/
typedef struct
{
union
{
ULONG PackedValue;
ULONG PackedValue;
struct
{
ULONG SubType : 24;
@ -188,6 +214,36 @@ typedef struct
};
} BcdElementType;
typedef struct
{
union
{
ULONG PackedValue;
union
{
struct
{
ULONG ApplicationCode : 20;
ULONG ImageCode : 4;
ULONG Reserved : 4;
ULONG ObjectCode : 4;
} Application;
struct
{
ULONG Value : 20;
ULONG ClassCode : 4;
ULONG Reserved : 4;
ULONG ObjectCode : 4;
} Inherit;
struct
{
ULONG Reserved:28;
ULONG ObjectCode : 4;
} Device;
};
};
} BcdObjectType;
typedef struct _BCD_ELEMENT_HEADER
{
ULONG Version;
@ -215,6 +271,12 @@ typedef struct _BCD_DEVICE_OPTION
BL_DEVICE_DESCRIPTOR DeviceDescriptor;
} BCD_DEVICE_OPTION, *PBCD_DEVICE_OPTION;
typedef struct _BCD_OBJECT_DESCRIPTION
{
ULONG Valid;
ULONG Type;
} BCD_OBJECT_DESCRIPTION, *PBCD_OBJECT_DESCRIPTION;;
/* FUNCTIONS ******************************************************************/
NTSTATUS
@ -260,4 +322,10 @@ BcdEnumerateAndUnpackElements (
_Out_ PULONG ElementCount
);
NTSTATUS
BiGetObjectDescription (
_In_ HANDLE ObjectHandle,
_Out_ PBCD_OBJECT_DESCRIPTION Description
);
#endif

View file

@ -66,8 +66,17 @@ DEFINE_GUID(BadMemoryGuid, 0x54B8275B, 0xD431, 0x473F, 0xAC, 0xFB, 0xE5, 0x36, 0
#define BL_APPLICATION_ENTRY_FLAG_NO_GUID 0x01
#define BL_APPLICATION_ENTRY_BCD_OPTIONS_INTERNAL 0x02
#define BL_APPLICATION_ENTRY_WINLOAD 0x04
#define BL_APPLICATION_ENTRY_STARTUP 0x08
#define BL_APPLICATION_ENTRY_REBOOT_ON_ERROR 0x20
#define BL_APPLICATION_ENTRY_NTLDR 0x40
#define BL_APPLICATION_ENTRY_BCD_OPTIONS_EXTERNAL 0x80
#define BL_APPLICATION_ENTRY_WINRESUME 0x100
#define BL_APPLICATION_ENTRY_SETUPLDR 0x200
#define BL_APPLICATION_ENTRY_BOOTSECTOR 0x400
#define BL_APPLICATION_ENTRY_BOOTMGR 0x1000
#define BL_APPLICATION_ENTRY_DISPLAY_ORDER 0x800000
#define BL_APPLICATION_ENTRY_FIXED_SEQUENCE 0x20000000
#define BL_CONTEXT_PAGING_ON 1
#define BL_CONTEXT_INTERRUPTS_ON 2
@ -1742,6 +1751,12 @@ BlCopyBootOptions (
_Out_ PBL_BCD_OPTION *CopiedOptions
);
NTSTATUS
BlAppendBootOptionString (
_In_ PBL_LOADED_APPLICATION_ENTRY AppEntry,
_In_ PWCHAR OptionString
);
NTSTATUS
BlAppendBootOptions (
_In_ PBL_LOADED_APPLICATION_ENTRY AppEntry,
@ -1784,7 +1799,6 @@ NTSTATUS
BiGetRegistryValue (
_In_ HANDLE KeyHandle,
_In_ PWCHAR ValueName,
_In_ PWCHAR KeyName,
_In_ ULONG Type,
_Out_ PVOID* Buffer,
_Out_ PULONG ValueLength

View file

@ -881,7 +881,6 @@ BiEnumerateElements (
/* Read the appropriate registry value type for this element */
Status = BiGetRegistryValue(ElementHandle,
L"Element",
NULL,
BiConvertElementFormatToValueType(
ElementType.Format),
&RegistryElementData,
@ -1176,6 +1175,69 @@ BiAddStoreFromFile (
return Status;
}
NTSTATUS
BiGetObjectDescription (
_In_ HANDLE ObjectHandle,
_Out_ PBCD_OBJECT_DESCRIPTION Description
)
{
NTSTATUS Status;
HANDLE DescriptionHandle;
PULONG Data;
ULONG Length;
/* Initialize locals */
Data = NULL;
DescriptionHandle = NULL;
/* Open the description key */
Status = BiOpenKey(ObjectHandle, L"Description", &DescriptionHandle);
if (NT_SUCCESS(Status))
{
/* It exists */
Description->Valid = TRUE;
/* Read the type */
Length = 0;
Status = BiGetRegistryValue(DescriptionHandle,
L"Type",
REG_DWORD,
(PVOID*)&Data,
&Length);
if (NT_SUCCESS(Status))
{
/* Make sure it's the length we expected it to be */
if (Length == sizeof(Data))
{
/* Return the type that is stored there */
Description->Type = *Data;
}
else
{
/* Invalid type value */
Status = STATUS_OBJECT_TYPE_MISMATCH;
}
}
}
/* Did we have a handle open? */
if (DescriptionHandle)
{
/* Close it */
BiCloseKey(DescriptionHandle);
}
/* Did we have data allocated? */
if (Data)
{
/* Free it */
BlMmFreeHeap(Data);
}
/* Return back to caller */
return Status;
}
NTSTATUS
BcdEnumerateAndUnpackElements (
_In_ HANDLE BcdHandle,

View file

@ -621,6 +621,53 @@ BlCopyBootOptions (
return Status;
}
NTSTATUS
BlAppendBootOptionString (
_In_ PBL_LOADED_APPLICATION_ENTRY AppEntry,
_In_ PWCHAR OptionString
)
{
NTSTATUS Status;
ULONG StringSize;
PBL_BCD_OPTION Option;
/* Get the length in bytes */
Status = RtlULongLongToULong(wcslen(OptionString) * sizeof(WCHAR),
&StringSize);
if (!NT_SUCCESS(Status))
{
return Status;
}
/* Add a NULL-terminator */
Status = RtlULongAdd(StringSize, sizeof(UNICODE_NULL), &StringSize);
if (!NT_SUCCESS(Status))
{
return Status;
}
/* Allocate space for the entry */
Option = BlMmAllocateHeap(sizeof(*Option) + StringSize);
if (!Option)
{
return STATUS_NO_MEMORY;
}
/* Initialize it and copy the string value */
RtlZeroMemory(Option, sizeof(*Option) + StringSize);
Option->DataSize = StringSize;
Option->Type = BcdLibraryString_ApplicationPath;
Option->DataOffset = sizeof(*Option);
wcsncpy((PWCHAR)Option + 1, OptionString, StringSize / sizeof(WCHAR));
/* Append it */
Status = BlAppendBootOptions(AppEntry, Option);
/* We're all done, free our initial option */
BlMmFreeHeap(Option);
return Status;
}
NTSTATUS
BlAppendBootOptions (
_In_ PBL_LOADED_APPLICATION_ENTRY AppEntry,

View file

@ -655,7 +655,6 @@ NTSTATUS
BiGetRegistryValue (
_In_ HANDLE KeyHandle,
_In_ PWCHAR ValueName,
_In_ PWCHAR KeyName,
_In_ ULONG Type,
_Out_ PVOID* Buffer,
_Out_ PULONG ValueLength