[BOOTLIB]: Separate out bcd.c into bcdopt.c, bootreg.c and bcd.c

[BOOTLIB]: Implement routines to enumerate subkeys and to read a key value.
[BOOTLIB]: Implement routines to parse, enumerate, and convert registry data into BCD elements, and to convert BCD elements into boot library BCD options.
[BOOTLIB/BOOTMGFW]: Lots of cleanups, mainly around the fact we now use ntintsafe.h instead of the manually self-inlined code from before, and from documenting additional flag values, and from using our newfound BCD powers.
[BOOTMGFW]: Implement BmGetOptionList, BmpUpdateApplicationOptions.
[BOOTMGFW]: Prepare for post-BCD library reinitialization. We correctly read the 3 BCD options so far in the hive.

svn path=/trunk/; revision=70492
This commit is contained in:
Alex Ionescu 2016-01-05 06:09:22 +00:00
parent bdc681e191
commit 6e87f8eab7
12 changed files with 3204 additions and 1113 deletions

View file

@ -12,6 +12,8 @@ list(APPEND BOOTLIB_SOURCE
lib/bootlib.c
lib/misc/debug.c
lib/misc/bcd.c
lib/misc/bcdopt.c
lib/misc/bootreg.c
lib/misc/util.c
lib/misc/image.c
lib/firmware/efi/firmware.c

View file

@ -31,8 +31,197 @@ BOOLEAN BmBootIniUsed;
WCHAR BmpFileNameBuffer[128];
PWCHAR ParentFileName = L"";
BOOLEAN BmDisplayStateCached;
/* FUNCTIONS *****************************************************************/
NTSTATUS
BmGetOptionList (
_In_ HANDLE BcdHandle,
_In_ PGUID ObjectId,
_In_ PBL_BCD_OPTION *OptionList
)
{
NTSTATUS Status;
HANDLE ObjectHandle;
ULONG ElementSize, ElementCount, i, OptionsSize;
BcdElementType Type;
PBCD_ELEMENT_HEADER Header;
PBCD_ELEMENT BcdElements;
PBL_BCD_OPTION Options, Option, PreviousOption, DeviceOptions;
PBCD_DEVICE_OPTION DeviceOption;
GUID DeviceId;
PVOID DeviceData;
/* Open the BCD object requested */
ObjectHandle = NULL;
BcdElements = NULL;
Status = BcdOpenObject(BcdHandle, ObjectId, &ObjectHandle);
if (!NT_SUCCESS(Status))
{
goto Quickie;
}
/* Do the initial enumeration to get the size needed */
ElementSize = 0;
Status = BcdEnumerateAndUnpackElements(BcdHandle,
ObjectHandle,
NULL,
&ElementSize,
&ElementCount);
if (Status != STATUS_BUFFER_TOO_SMALL)
{
/* If we got success, that doesn't make any sense */
if (NT_SUCCESS(Status))
{
Status = STATUS_INVALID_PARAMETER;
}
/* Bail out */
goto Quickie;
}
/* Allocate a large-enough buffer */
BcdElements = BlMmAllocateHeap(ElementSize);
if (!BcdElements)
{
Status = STATUS_NO_MEMORY;
goto Quickie;
}
/* Now do the real enumeration to fill out the elements buffer */
Status = BcdEnumerateAndUnpackElements(BcdHandle,
ObjectHandle,
BcdElements,
&ElementSize,
&ElementCount);
if (!NT_SUCCESS(Status))
{
goto Quickie;
}
/* Go through each BCD option to add the sizes up */
OptionsSize = 0;
for (i = 0; i < ElementCount; i++)
{
OptionsSize += BcdElements[i].Header->Size + sizeof(BL_BCD_OPTION);
}
/* Allocate the required BCD option list */
Options = BlMmAllocateHeap(OptionsSize);
if (!Options)
{
Status = STATUS_NO_MEMORY;
goto Quickie;
}
/* Zero it out */
RtlZeroMemory(Options, OptionsSize);
/* 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 */
Header = BcdElements[i].Header;
Type.PackedValue = Header->Type;
/* Check if this option isn't already present */
if (!MiscGetBootOption(Options, Type.PackedValue))
{
/* It's a new option. Did we have an existing one? */
if (PreviousOption)
{
/* Link it to this new one */
PreviousOption->NextEntryOffset = (ULONG_PTR)Option -
(ULONG_PTR)Options;
}
/* Capture the type, size, data, and offset */
Option->Type = Type.PackedValue;
Option->DataSize = Header->Size;
RtlCopyMemory(Option + 1, BcdElements[i].Body, Header->Size);
Option->DataOffset = sizeof(BL_BCD_OPTION);
/* Check if this was a device */
if (Type.Format == BCD_TYPE_DEVICE)
{
/* Grab its GUID */
DeviceOption = (PBCD_DEVICE_OPTION)(Option + 1);
DeviceId = DeviceOption->AssociatedEntry;
/* Look up the options for that GUID */
Status = BmGetOptionList(BcdHandle, &DeviceId, &DeviceOptions);
if (NT_SUCCESS(Status))
{
/* Device data is after the device option */
DeviceData = (PVOID)((ULONG_PTR)DeviceOption + Header->Size);
/* Copy it */
RtlCopyMemory(DeviceData,
DeviceOptions,
BlGetBootOptionListSize(DeviceOptions));
/* Don't need this anymore */
BlMmFreeHeap(DeviceOptions);
/* Write the offset of the device options */
Option->ListOffset = (ULONG_PTR)DeviceData -
(ULONG_PTR)Option;
}
}
/* Save the previous option and go to the next one */
PreviousOption = Option;
Option = (PBL_BCD_OPTION)((ULONG_PTR)Option +
BlGetBootOptionSize(Option));
}
}
/* Return the pointer back, we've made it! */
*OptionList = Options;
Status = STATUS_SUCCESS;
Quickie:
/* Did we allocate a local buffer? Free it if so */
if (BcdElements)
{
BlMmFreeHeap(BcdElements);
}
/* Was the key open? Close it if so */
if (ObjectHandle)
{
BiCloseKey(ObjectHandle);
}
/* Return the option list parsing status */
return Status;
}
NTSTATUS
BmpUpdateApplicationOptions (
_In_ HANDLE BcdHandle
)
{
NTSTATUS Status;
PBL_BCD_OPTION Options;
/* Get the boot option list */
Status = BmGetOptionList(BcdHandle, &BmApplicationIdentifier, &Options);
if (!NT_SUCCESS(Status))
{
return Status;
}
/* Append the options, free the local buffer, and return success */
BlAppendBootOptions(&BlpApplicationEntry, Options);
BlMmFreeHeap(Options);
return STATUS_SUCCESS;
}
NTSTATUS
BmpFwGetApplicationDirectoryPath (
_In_ PUNICODE_STRING ApplicationDirectoryPath
@ -65,39 +254,14 @@ BmpFwGetApplicationDirectoryPath (
}
/* Check if we have space for one more character */
AppPathLength = i + 1;
if (AppPathLength < i)
{
/* Nope, we'll overflow */
AppPathLength = -1;
Status = STATUS_INTEGER_OVERFLOW;
}
else
{
/* Go ahead */
Status = STATUS_SUCCESS;
}
/* No overflow? */
Status = RtlULongAdd(i, 1, &AppPathLength);
if (NT_SUCCESS(Status))
{
/* Check if it's safe to multiply by two */
if ((AppPathLength * sizeof(WCHAR)) > 0xFFFFFFFF)
{
/* Nope */
AppPathLength = -1;
Status = STATUS_INTEGER_OVERFLOW;
}
else
{
/* We're good, do the multiplication */
Status = STATUS_SUCCESS;
AppPathLength *= sizeof(WCHAR);
}
/* Allocate a copy for the string */
Status = RtlULongMult(AppPathLength, sizeof(WCHAR), &AppPathLength);
if (NT_SUCCESS(Status))
{
/* Allocate a copy for the string */
PathCopy = BlMmAllocateHeap(AppPathLength);
if (PathCopy)
{
@ -382,6 +546,38 @@ BmFatalErrorEx (
ErrorResourceId = 9002;
break;
case BL_FATAL_ERROR_BCD_PARSE:
/* File name isin parameter 1 */
FileName = (PWCHAR)Parameter1;
/* The NTSTATUS code is in parameter 2*/
ErrorStatus = (NTSTATUS)Parameter2;
/* Build the error string */
swprintf(FormatString,
L"\nThe boot configuration file %s is invalid (%08x).\n",
FileName,
ErrorStatus);
/* Select the resource ID message */
ErrorResourceId = 9015;
break;
case BL_FATAL_ERROR_GENERIC:
/* The NTSTATUS code is in parameter 1*/
ErrorStatus = (NTSTATUS)Parameter1;
/* Build the error string */
swprintf(FormatString,
L"\nThe boot manager experienced an error (%08x).\n",
ErrorStatus);
/* Select the resource ID message */
ErrorResourceId = 9005;
break;
default:
/* The rest is not yet handled */
@ -427,25 +623,11 @@ BmpFwGetFullPath (
)
{
NTSTATUS Status;
ULONG BootDirLength, BootDirLengthWithNul;
ULONG PathLength, FullPathLength;
ULONG BootDirLength, PathLength;
/* Compute the length of the directory, and add a NUL */
BootDirLength = wcslen(BootDirectory);
BootDirLengthWithNul = BootDirLength + 1;
if (BootDirLengthWithNul < BootDirLength)
{
/* This would overflow */
BootDirLengthWithNul = -1;
Status = STATUS_INTEGER_OVERFLOW;
}
else
{
/* We have space */
Status = STATUS_SUCCESS;
}
/* Fail on overflow */
Status = RtlULongAdd(BootDirLength, 1, &BootDirLength);
if (!NT_SUCCESS(Status))
{
goto Quickie;
@ -453,33 +635,26 @@ BmpFwGetFullPath (
/* Add the length of the file, make sure it fits */
PathLength = wcslen(FileName);
FullPathLength = PathLength + BootDirLength;
if (FullPathLength < PathLength)
Status = RtlULongAdd(PathLength, BootDirLength, &PathLength);
if (!NT_SUCCESS(Status))
{
/* Nope */
FullPathLength = -1;
Status = STATUS_INTEGER_OVERFLOW;
}
else
{
/* All good */
Status = STATUS_SUCCESS;
goto Quickie;
}
/* Fail on overflow */
/* Convert to bytes */
Status = RtlULongLongToULong(PathLength * sizeof(WCHAR), &PathLength);
if (!NT_SUCCESS(Status))
{
goto Quickie;
}
/* Allocate the full path */
FullPathLength = FullPathLength * sizeof(WCHAR);
*FullPath = BlMmAllocateHeap(FullPathLength);
*FullPath = BlMmAllocateHeap(PathLength);
if (*FullPath)
{
/* Copy the directory followed by the file name */
wcsncpy(*FullPath, BootDirectory, FullPathLength / sizeof(WCHAR));
wcsncat(*FullPath, FileName, FullPathLength / sizeof(WCHAR));
wcsncpy(*FullPath, BootDirectory, PathLength / sizeof(WCHAR));
wcsncat(*FullPath, FileName, PathLength / sizeof(WCHAR));
}
else
{
@ -492,6 +667,22 @@ Quickie:
return Status;
}
VOID
BmCloseDataStore (
_In_ HANDLE Handle
)
{
/* Check if boot.ini data needs to be freed */
if (BmBootIniUsed)
{
EfiPrintf(L"Not handled\r\n");
}
/* Dereference the hive and close the key */
BiDereferenceHive(Handle);
BiCloseKey(Handle);
}
NTSTATUS
BmOpenDataStore (
_Out_ PHANDLE Handle
@ -501,7 +692,7 @@ BmOpenDataStore (
PBL_DEVICE_DESCRIPTOR BcdDevice;
PWCHAR BcdPath, FullPath, PathBuffer;
BOOLEAN HavePath;
ULONG PathLength, PathLengthWithNul, FullSize;
ULONG PathLength, FullSize;
PVOID FinalBuffer;
UNICODE_STRING BcdString;
@ -544,7 +735,7 @@ BmOpenDataStore (
if (NT_SUCCESS(Status))
{
/* We don't handle custom BCDs yet */
EfiPrintf(L"Not handled\n");
EfiPrintf(L"Not handled: %s\r\n", BcdPath);
Status = STATUS_NOT_IMPLEMENTED;
goto Quickie;
}
@ -579,35 +770,22 @@ BmOpenDataStore (
}
/* Add a NUL to the path, make sure it'll fit */
Status = STATUS_SUCCESS;
PathLength = wcslen(PathBuffer);
PathLengthWithNul = PathLength + 1;
if (PathLengthWithNul < PathLength)
Status = RtlULongAdd(PathLength, 1, &PathLength);
if (!NT_SUCCESS(Status))
{
PathLengthWithNul = -1;
Status = STATUS_INTEGER_OVERFLOW;
goto Quickie;
}
/* Bail out if it doesn't fit */
/* Convert to bytes */
Status = RtlULongLongToULong(PathLength * sizeof(WCHAR), &PathLength);
if (!NT_SUCCESS(Status))
{
goto Quickie;
}
/* Now add the size of the path to the device path, check if it fits */
PathLengthWithNul = PathLengthWithNul * sizeof(WCHAR);
FullSize = PathLengthWithNul + BcdDevice->Size;
if (FullSize < BcdDevice->Size)
{
FullSize = -1;
Status = STATUS_INTEGER_OVERFLOW;
}
else
{
Status = STATUS_SUCCESS;
}
/* Bail out if it doesn't fit */
Status = RtlULongAdd(PathLength, BcdDevice->Size, &FullSize);
if (!NT_SUCCESS(Status))
{
goto Quickie;
@ -625,7 +803,7 @@ BmOpenDataStore (
RtlCopyMemory(FinalBuffer, BcdDevice, BcdDevice->Size);
RtlCopyMemory((PVOID)((ULONG_PTR)FinalBuffer + BcdDevice->Size),
PathBuffer,
PathLengthWithNul);
PathLength);
/* Now tell the BCD engine to open the store */
BcdString.Length = FullSize;
@ -648,7 +826,11 @@ Quickie:
if (!NT_SUCCESS(Status))
{
/* Raise a fatal error */
BmFatalErrorEx(1, (ULONG_PTR)PathBuffer, Status, 0, 0);
BmFatalErrorEx(BL_FATAL_ERROR_BCD_READ,
(ULONG_PTR)PathBuffer,
Status,
0,
0);
}
/* Did we get an allocated path? */
@ -680,12 +862,13 @@ BmMain (
_In_ PBOOT_APPLICATION_PARAMETER_BLOCK BootParameters
)
{
NTSTATUS Status;
NTSTATUS Status, LibraryStatus;
BL_LIBRARY_PARAMETERS LibraryParameters;
PBL_RETURN_ARGUMENTS ReturnArguments;
BOOLEAN RebootOnError;
PGUID AppIdentifier;
HANDLE BcdHandle;
PBL_BCD_OPTION EarlyOptions;
EfiPrintf(L"ReactOS UEFI Boot Manager Initializing...\n");
@ -734,12 +917,73 @@ BmMain (
/* Load and initialize the boot configuration database (BCD) */
Status = BmOpenDataStore(&BcdHandle);
EfiPrintf(L"BCD Open: %lx\r\n", Status);
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;
}
/* do more stuff!! */
EfiPrintf(L"We are A-OK!\r\n");
EfiPrintf(L"We are A-OKer!\r\n");
EfiStall(10000000);
//Failure:
/* Check if we got here due to an internal error */
if (BmpInternalBootError)
{
/* If XML is available, display the error */
#if 0
if (XmlLoaded)
{
BmDisplayDumpError(0, 0);
BmErrorPurge();
}
#endif
/* Don't do a fatal error -- return back to firmware */
goto Quickie;
}
/* Log a general fatal error once we're here */
BmFatalErrorEx(BL_FATAL_ERROR_GENERIC, Status, 0, 0, 0);
Quickie:
/* Check if we should reboot */
if ((RebootOnError) ||

View file

@ -49,7 +49,9 @@ typedef struct _BL_PACKED_BOOT_ERROR
ULONG Size;
} BL_PACKED_BOOT_ERROR, *PBL_PACKED_BOOT_ERROR;
#define BL_FATAL_ERROR_BCD_READ 0x01
#define BL_FATAL_ERROR_BCD_READ 0x01
#define BL_FATAL_ERROR_GENERIC 0x04
#define BL_FATAL_ERROR_BCD_PARSE 0x07
/* FUNCTIONS *****************************************************************/

View file

@ -11,6 +11,21 @@
/* ENUMERATIONS **************************************************************/
/* See https://msdn.microsoft.com/en-us/library/windows/desktop/aa964229(v=vs.85).aspx */
#define BCD_CLASS_LIBRARY 0x01
#define BCD_CLASS_APPLICATION 0x02
#define BCD_CLASS_DEVICE 0x03
#define BCD_CLASS_OEM 0x05
#define BCD_TYPE_DEVICE 0x01
#define BCD_TYPE_STRING 0x02
#define BCD_TYPE_OBJECT 0x03
#define BCD_TYPE_OBJECT_LIST 0x04
#define BCD_TYPE_INTEGER 0x05
#define BCD_TYPE_BOOLEAN 0x06
#define BCD_TYPE_INTEGER_LIST 0x07
typedef enum BcdLibraryElementTypes
{
BcdLibraryDevice_ApplicationDevice = 0x11000001,
@ -155,9 +170,43 @@ typedef enum BcdBootMgrElementTypes
BcdBootMgrBoolean_PersistBootSequence = 0x26000031
} BcdBootMgrElementTypes;
/* DATA STRUCTURES ***********************************************************/
typedef struct
{
union
{
ULONG PackedValue;
struct
{
ULONG SubType : 24;
ULONG Format : 4;
ULONG Class : 4;
};
};
} BcdElementType;
typedef struct _BCD_ELEMENT_HEADER
{
ULONG Version;
ULONG Type;
ULONG Size;
} BCD_ELEMENT_HEADER, *PBCD_ELEMENT_HEADER;
typedef struct _BCD_PACKED_ELEMENT
{
struct _BCD_PACKED_ELEMENT* NextEntry;
BcdElementType RootType;
BCD_ELEMENT_HEADER;
UCHAR Data[ANYSIZE_ARRAY];
} BCD_PACKED_ELEMENT, *PBCD_PACKED_ELEMENT;
typedef struct _BCD_ELEMENT
{
PBCD_ELEMENT_HEADER Header;
PUCHAR Body;
} BCD_ELEMENT, *PBCD_ELEMENT;
typedef struct _BCD_DEVICE_OPTION
{
GUID AssociatedEntry;
@ -172,4 +221,35 @@ BcdOpenStoreFromFile (
_In_ PHANDLE StoreHandle
);
#define BCD_ENUMERATE_FLAG_DEEP 0x04
#define BCD_ENUMERATE_FLAG_DEVICES 0x08
#define BCD_ENUMERATE_FLAG_IN_ORDER 0x10
NTSTATUS
BiEnumerateElements (
_In_ HANDLE BcdHandle,
_In_ HANDLE ObjectHandle,
_In_ ULONG RootElementType,
_In_ ULONG Flags,
_Out_opt_ PBCD_PACKED_ELEMENT Elements,
_Inout_ PULONG ElementSize,
_Out_ PULONG ElementCountNe
);
NTSTATUS
BcdOpenObject (
_In_ HANDLE BcdHandle,
_In_ PGUID ObjectId,
_Out_ PHANDLE ObjectHandle
);
NTSTATUS
BcdEnumerateAndUnpackElements (
_In_ HANDLE BcdHandle,
_In_ HANDLE ObjectHandle,
_Out_opt_ PBCD_ELEMENT Elements,
_Inout_ PULONG ElementSize,
_Out_ PULONG ElementCount
);
#endif

View file

@ -22,6 +22,9 @@
/* NDK Headers */
#include <ntndk.h>
/* NT SafeInt Header */
#include <ntintsafe.h>
/* UEFI Headers */
#include <Uefi.h>
#include <DevicePath.h>
@ -52,7 +55,9 @@
#define BL_FIRMWARE_DESCRIPTOR_VERSION 2
#define BL_APPLICATION_ENTRY_FLAG_NO_GUID 0x01
#define BL_APPLICATION_ENTRY_BCD_OPTIONS_INTERNAL 0x02
#define BL_APPLICATION_ENTRY_REBOOT_ON_ERROR 0x20
#define BL_APPLICATION_ENTRY_BCD_OPTIONS_EXTERNAL 0x80
#define BL_CONTEXT_PAGING_ON 1
#define BL_CONTEXT_INTERRUPTS_ON 2
@ -716,9 +721,9 @@ typedef struct _BL_LOCAL_DEVICE
typedef struct _BL_DEVICE_DESCRIPTOR
{
ULONG Size;
ULONG Flags;
DEVICE_TYPE DeviceType;
ULONG Flags;
ULONG Size;
ULONG Unknown;
union
{
@ -1424,7 +1429,18 @@ BlHtCreate (
_Out_ PULONG Id
);
/* BCD ROUTINES **************************************************************/
/* BCD OPTION ROUTINES *******************************************************/
PBL_BCD_OPTION
MiscGetBootOption (
_In_ PBL_BCD_OPTION List,
_In_ ULONG Type
);
ULONG
BlGetBootOptionListSize (
_In_ PBL_BCD_OPTION BcdOption
);
ULONG
BlGetBootOptionSize (
@ -1452,6 +1468,15 @@ BlGetBootOptionBoolean (
_Out_ PBOOLEAN Value
);
NTSTATUS
BlpGetBootOptionIntegerList (
_In_ PBL_BCD_OPTION List,
_In_ ULONG Type,
_Out_ PULONGLONG* Value,
_Out_ PULONGLONG Count,
_In_ BOOLEAN NoCopy
);
NTSTATUS
BlGetBootOptionDevice (
_In_ PBL_BCD_OPTION List,
@ -1460,6 +1485,68 @@ BlGetBootOptionDevice (
_In_opt_ PBL_BCD_OPTION* ExtraOptions
);
NTSTATUS
BlGetBootOptionGuidList (
_In_ PBL_BCD_OPTION List,
_In_ ULONG Type,
_Out_ PGUID *Value,
_In_ PULONG Count
);
NTSTATUS
BlCopyBootOptions (
_In_ PBL_BCD_OPTION OptionList,
_Out_ PBL_BCD_OPTION *CopiedOptions
);
NTSTATUS
BlAppendBootOptions (
_In_ PBL_LOADED_APPLICATION_ENTRY AppEntry,
_In_ PBL_BCD_OPTION Options
);
/* BOOT REGISTRY ROUTINES ****************************************************/
VOID
BiCloseKey (
_In_ HANDLE KeyHandle
);
NTSTATUS
BiOpenKey(
_In_ HANDLE ParentHandle,
_In_ PWCHAR KeyName,
_Out_ PHANDLE Handle
);
NTSTATUS
BiLoadHive (
_In_ PBL_FILE_PATH_DESCRIPTOR FilePath,
_Out_ PHANDLE HiveHandle
);
NTSTATUS
BiGetRegistryValue (
_In_ HANDLE KeyHandle,
_In_ PWCHAR ValueName,
_In_ PWCHAR KeyName,
_In_ ULONG Type,
_Out_ PVOID* Buffer,
_Out_ PULONG ValueLength
);
NTSTATUS
BiEnumerateSubKeys (
_In_ HANDLE KeyHandle,
_Out_ PWCHAR** SubKeyList,
_Out_ PULONG SubKeyCount
);
VOID
BiDereferenceHive (
_In_ HANDLE KeyHandle
);
/* CONTEXT ROUTINES **********************************************************/
VOID
@ -1561,6 +1648,16 @@ MmFwGetMemoryMap (
_In_ ULONG Flags
);
NTSTATUS
BlpMmInitializeConstraints (
VOID
);
NTSTATUS
BlMmRemoveBadMemory (
VOID
);
/* VIRTUAL MEMORY ROUTINES ***************************************************/
NTSTATUS

View file

@ -86,11 +86,15 @@ InitializeLibrary (
BlpApplicationParameters = BootAppParameters;
BlpLibraryParameters = *LibraryParameters;
/* Save the application entry flags */
if (AppEntry->Flags & 2)
/* Check if the caller sent us their internal BCD options */
if (AppEntry->Flags & BL_APPLICATION_ENTRY_BCD_OPTIONS_INTERNAL)
{
AppEntry->Flags = (AppEntry->Flags & ~0x2) | 0x80;
/* These are external to us now, as far as we are concerned */
AppEntry->Flags &= ~BL_APPLICATION_ENTRY_BCD_OPTIONS_INTERNAL;
AppEntry->Flags |= BL_APPLICATION_ENTRY_BCD_OPTIONS_EXTERNAL;
}
/* Save the application entry flags */
BlpApplicationEntry.Flags = AppEntry->Flags;
/* Copy the GUID and point to the options */
@ -363,15 +367,24 @@ BlInitializeLibrary(
BlpLibraryParameters = *LibraryParameters;
if (LibraryParameters->LibraryFlags & BL_LIBRARY_FLAG_REINITIALIZE_ALL)
{
#if 0
/* Initialize all the core modules again */
#ifdef BL_TPM_SUPPORT
/* Reinitialize the TPM security enclave as BCD hash changed */
BlpSiInitialize(1);
#endif
#ifdef BL_KD_SUPPORT
/* Reinitialize the boot debugger as BCD debug options changed */
BlBdInitialize();
#endif
/* Reparse the bad page list now that the BCD has been reloaded */
BlMmRemoveBadMemory();
/* Reparse the low/high physical address limits as well */
BlpMmInitializeConstraints();
/* Redraw the graphics console as needed */
BlpDisplayInitialize(LibraryParameters->LibraryFlags);
#if 0
BlpResourceInitialize();
#endif
}

View file

@ -43,7 +43,7 @@ DsppGraphicsDisabledByBcd (
VOID
)
{
//EarlyPrint(L"Disabling graphics\r\n");
EfiPrintf(L"Disabling graphics\r\n");
return FALSE;
}
@ -53,10 +53,10 @@ DsppInitialize (
)
{
BL_LIBRARY_PARAMETERS LibraryParameters = BlpLibraryParameters;
BOOLEAN NoGraphics;// , HighestMode;
BOOLEAN NoGraphics, HighestMode;
NTSTATUS Status;
PBL_DISPLAY_MODE DisplayMode;
//ULONG GraphicsResolution;
ULONGLONG GraphicsResolution;
PBL_GRAPHICS_CONSOLE GraphicsConsole;
PBL_TEXT_CONSOLE TextConsole, RemoteConsole;
@ -100,14 +100,9 @@ DsppInitialize (
DisplayMode = &ConsoleGraphicalResolutionList[0];
/* Check what resolution to use*/
#if 0
Status = BlGetBootOptionInteger(BlpApplicationEntry.BcdData,
BcdLibraryInteger_GraphicsResolution,
&GraphicsResolution);
#else
//GraphicsResolution = 0;
Status = STATUS_NOT_FOUND;
#endif
if (NT_SUCCESS(Status))
{
ConsoleGraphicalResolutionListFlags |= BL_DISPLAY_GRAPHICS_FORCED_VIDEO_MODE_FLAG;
@ -116,14 +111,9 @@ DsppInitialize (
}
/* Check if the highest mode should be forced */
#if 0
Status = BlGetBootOptionBoolean(BlpApplicationEntry.BcdData,
BcdLibraryBoolean_GraphicsForceHighestMode,
&HighestMode);
#else
//HighestMode = 0;
Status = STATUS_NOT_FOUND;
#endif
if (NT_SUCCESS(Status))
{
ConsoleGraphicalResolutionListFlags |= BL_DISPLAY_GRAPHICS_FORCED_HIGH_RES_MODE_FLAG;
@ -233,6 +223,7 @@ BlpDisplayInitialize (
{
/* This is a reset */
Status = STATUS_NOT_IMPLEMENTED;
EfiPrintf(L"Display reset not yet implemented\r\n");
#if 0
Status = DsppReinitialize(Flags);
if (NT_SUCCESS(Status))

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,647 @@
/*
* COPYRIGHT: See COPYING.ARM in the top level directory
* PROJECT: ReactOS UEFI Boot Library
* FILE: boot/environ/lib/misc/bcdopt.c
* PURPOSE: Boot Library BCD Option Parsing Routines
* PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include "bl.h"
#include <bcd.h>
/* FUNCTIONS *****************************************************************/
PBL_BCD_OPTION
MiscGetBootOption (
_In_ PBL_BCD_OPTION List,
_In_ ULONG Type
)
{
ULONG_PTR NextOption = 0, ListOption;
PBL_BCD_OPTION Option, FoundOption;
/* No options, bail out */
if (!List)
{
return NULL;
}
/* Loop while we find an option */
FoundOption = NULL;
do
{
/* Get the next option and see if it matches the type */
Option = (PBL_BCD_OPTION)((ULONG_PTR)List + NextOption);
if ((Option->Type == Type) && !(Option->Empty))
{
FoundOption = Option;
break;
}
/* Store the offset of the next option */
NextOption = Option->NextEntryOffset;
/* Failed to match. Check for list options */
ListOption = Option->ListOffset;
if (ListOption)
{
/* Try to get a match in the associated option */
Option = MiscGetBootOption((PBL_BCD_OPTION)((ULONG_PTR)Option +
ListOption),
Type);
if (Option)
{
/* Return it */
FoundOption = Option;
break;
}
}
} while (NextOption);
/* Return the option that was found, if any */
return FoundOption;
}
/*++
* @name BlGetBootOptionListSize
*
* The BlGetBootOptionListSize routine
*
* @param BcdOption
* UEFI Image Handle for the current loaded application.
*
* @return Size of the BCD option
*
*--*/
ULONG
BlGetBootOptionListSize (
_In_ PBL_BCD_OPTION BcdOption
)
{
ULONG Size = 0, NextOffset = 0;
PBL_BCD_OPTION NextOption;
/* Loop all the options*/
do
{
/* Move to the next one */
NextOption = (PBL_BCD_OPTION)((ULONG_PTR)BcdOption + NextOffset);
/* Compute the size of the next one */
Size += BlGetBootOptionSize(NextOption);
/* Update the offset */
NextOffset = NextOption->NextEntryOffset;
} while (NextOffset);
/* Return final computed size */
return Size;
}
/*++
* @name BlGetBootOptionSize
*
* The BlGetBootOptionSize routine
*
* @param BcdOption
* UEFI Image Handle for the current loaded application.
*
* @return Size of the BCD option
*
*--*/
ULONG
BlGetBootOptionSize (
_In_ PBL_BCD_OPTION BcdOption
)
{
ULONG Size, Offset;
/* Check if there's any data */
if (BcdOption->DataOffset)
{
/* Add the size of the data */
Size = BcdOption->DataOffset + BcdOption->DataSize;
}
else
{
/* No data, just the structure itself */
Size = sizeof(*BcdOption);
}
/* Any associated options? */
Offset = BcdOption->ListOffset;
if (Offset)
{
/* Go get those too */
Size += BlGetBootOptionListSize((PVOID)((ULONG_PTR)BcdOption + Offset));
}
/* Return the final size */
return Size;
}
NTSTATUS
BlGetBootOptionString (
_In_ PBL_BCD_OPTION List,
_In_ ULONG Type,
_Out_ PWCHAR* Value
)
{
NTSTATUS Status;
PBL_BCD_OPTION Option;
PWCHAR String, StringCopy;
ULONG StringLength;
BcdElementType ElementType;
//PGUID AppIdentifier;
/* Make sure this is a BCD_STRING */
ElementType.PackedValue = Type;
if (ElementType.Format != BCD_TYPE_STRING)
{
return STATUS_INVALID_PARAMETER;
}
/* Return the data */
Option = MiscGetBootOption(List, Type);
if (Option)
{
/* Extract the string */
String = (PWCHAR)((ULONG_PTR)Option + Option->DataOffset);
Status = STATUS_SUCCESS;
}
else
{
/* No string is present */
String = NULL;
Status = STATUS_NOT_FOUND;
}
/* Compute the data size */
StringLength = Option->DataSize / sizeof(WCHAR);
#ifdef _SECURE_BOOT_
/* Filter out SecureBoot Options */
AppIdentifier = BlGetApplicationIdentifier();
Status = BlpBootOptionCallbackString(AppIdentifier, Type, String, StringLength, &String, &StringLength);
#else
#endif
/* Make sure we have a valid, non-filtered string */
if (NT_SUCCESS(Status))
{
/* Check if we have space for one more character */
Status = RtlULongAdd(StringLength, 1, &StringLength);
if (NT_SUCCESS(Status))
{
/* Check if it's safe to multiply by two */
Status = RtlULongMult(StringLength, sizeof(WCHAR), &StringLength);
if (NT_SUCCESS(Status))
{
/* Allocate a copy for the string */
StringCopy = BlMmAllocateHeap(StringLength);
if (StringCopy)
{
/* NULL-terminate it */
RtlCopyMemory(StringCopy,
String,
StringLength - sizeof(UNICODE_NULL));
StringCopy[StringLength] = UNICODE_NULL;
*Value = StringCopy;
Status = STATUS_SUCCESS;
}
else
{
/* No memory, fail */
Status = STATUS_NO_MEMORY;
}
}
}
}
/* All done */
return Status;
}
NTSTATUS
BlGetBootOptionGuidList (
_In_ PBL_BCD_OPTION List,
_In_ ULONG Type,
_Out_ PGUID *Value,
_In_ PULONG Count
)
{
NTSTATUS Status;
PBL_BCD_OPTION Option;
PGUID GuidCopy, Guid;
ULONG GuidCount;
BcdElementType ElementType;
/* Make sure this is a BCD_TYPE_OBJECT_LIST */
ElementType.PackedValue = Type;
if (ElementType.Format != BCD_TYPE_OBJECT_LIST)
{
return STATUS_INVALID_PARAMETER;
}
/* Return the data */
Option = MiscGetBootOption(List, Type);
if (!Option)
{
/* Set failure if no data exists */
Status = STATUS_NOT_FOUND;
}
else
{
/* Get the GUIDs and allocate a copy for them */
Guid = (PGUID)((ULONG_PTR)Option + Option->DataOffset);
GuidCopy = BlMmAllocateHeap(Option->DataSize);
if (GuidCopy)
{
/* Copy the GUIDs */
RtlCopyMemory(GuidCopy, Guid, Option->DataSize);
/* Return the number of GUIDs and the start of the array */
GuidCount = Option->DataSize / sizeof(GUID);
*Value = GuidCopy;
*Count = GuidCount;
Status = STATUS_SUCCESS;
}
else
{
/* No memory for the copy */
Status = STATUS_NO_MEMORY;
}
}
/* All good */
return Status;
}
NTSTATUS
BlGetBootOptionDevice (
_In_ PBL_BCD_OPTION List,
_In_ ULONG Type,
_Out_ PBL_DEVICE_DESCRIPTOR* Value,
_In_opt_ PBL_BCD_OPTION* ExtraOptions
)
{
NTSTATUS Status;
PBL_BCD_OPTION Option, ListData, ListCopy, SecureListData;
PBCD_DEVICE_OPTION BcdDevice;
ULONG DeviceSize, ListOffset, ListSize;
PBL_DEVICE_DESCRIPTOR DeviceDescriptor, SecureDescriptor;
//PGUID AppIdentifier;
BcdElementType ElementType;
/* Make sure this is a BCD_TYPE_DEVICE */
ElementType.PackedValue = Type;
if (ElementType.Format != BCD_TYPE_DEVICE)
{
return STATUS_INVALID_PARAMETER;
}
/* Return the data */
Option = MiscGetBootOption(List, Type);
if (!Option)
{
/* Set failure if no data exists */
Status = STATUS_NOT_FOUND;
}
else
{
/* Otherwise, read the size of the BCD device encoded */
BcdDevice = (PBCD_DEVICE_OPTION)((ULONG_PTR)Option + Option->DataOffset);
DeviceSize = BcdDevice->DeviceDescriptor.Size;
/* Allocate a buffer to copy it into */
DeviceDescriptor = BlMmAllocateHeap(DeviceSize);
if (!DeviceDescriptor)
{
return STATUS_NO_MEMORY;
}
/* Copy it into that buffer */
RtlCopyMemory(DeviceDescriptor, &BcdDevice->DeviceDescriptor, DeviceSize);
Status = STATUS_SUCCESS;
}
/* Check if extra options were requested */
if (ExtraOptions)
{
/* See where they are */
ListOffset = Option->ListOffset;
if (ListOffset)
{
/* See how big they are */
ListData = (PBL_BCD_OPTION)((ULONG_PTR)Option + ListOffset);
ListSize = BlGetBootOptionListSize(ListData);
/* Allocate a buffer to hold them into */
ListCopy = BlMmAllocateHeap(ListSize);
if (!ListCopy)
{
Status = STATUS_NO_MEMORY;
goto Quickie;
}
/* Copy them in there */
RtlCopyMemory(ListCopy, ListData, ListSize);
}
}
#ifdef _SECURE_BOOT_
/* Filter out SecureBoot Options */
AppIdentifier = BlGetApplicationIdentifier();
if (BlpBootOptionCallbacks)
{
DeviceCallback = BlpBootOptionCallbacks->Device;
if (DeviceCallback)
{
Status = DeviceCallback(BlpBootOptionCallbackCookie,
Status,
0,
AppIdentifier,
Type,
&SecureDescriptor,
PtrOptionData);
}
}
#else
/* No secure boot, so the secure descriptors are the standard ones */
SecureDescriptor = DeviceDescriptor;
SecureListData = ListCopy;
#endif
/* Check if the data was read correctly */
if (NT_SUCCESS(Status))
{
/* Check if we had a new descriptor after filtering */
if (SecureDescriptor != DeviceDescriptor)
{
/* Yep -- if we had an old one, free it */
if (DeviceDescriptor)
{
BlMmFreeHeap(DeviceDescriptor);
}
}
/* Check if we had a new list after filtering */
if (SecureListData != ListCopy)
{
/* Yep -- if we had an old list, free it */
if (ListCopy)
{
BlMmFreeHeap(ListCopy);
}
}
/* Finally, check if the caller wanted extra options */
if (ExtraOptions)
{
/* Yep -- so pass the caller our copy */
*ExtraOptions = ListCopy;
ListCopy = NULL;
}
/* Caller always wants data back, so pass them our copy */
*Value = DeviceDescriptor;
DeviceDescriptor = NULL;
}
Quickie:
/* On the failure path, if these buffers are active, we should free them */
if (ListCopy)
{
BlMmFreeHeap(ListCopy);
}
if (DeviceDescriptor)
{
BlMmFreeHeap(DeviceDescriptor);
}
/* All done */
return Status;
}
NTSTATUS
BlGetBootOptionInteger (
_In_ PBL_BCD_OPTION List,
_In_ ULONG Type,
_Out_ PULONGLONG Value
)
{
NTSTATUS Status;
PBL_BCD_OPTION Option;
//PGUID AppIdentifier;
BcdElementType ElementType;
/* Make sure this is a BCD_TYPE_INTEGER */
ElementType.PackedValue = Type;
if (ElementType.Format != BCD_TYPE_INTEGER)
{
return STATUS_INVALID_PARAMETER;
}
/* Return the data */
Option = MiscGetBootOption(List, Type);
if (Option)
{
*Value = *(PULONGLONG)((ULONG_PTR)Option + Option->DataOffset);
}
#ifdef _SECURE_BOOT_
/* Filter out SecureBoot Options */
AppIdentifier = BlGetApplicationIdentifier();
Status = BlpBootOptionCallbackULongLong(AppIdentifier, Type, Value);
#else
/* Option found */
Status = Option ? STATUS_SUCCESS : STATUS_NOT_FOUND;
#endif
return Status;
}
NTSTATUS
BlGetBootOptionBoolean (
_In_ PBL_BCD_OPTION List,
_In_ ULONG Type,
_Out_ PBOOLEAN Value
)
{
NTSTATUS Status;
PBL_BCD_OPTION Option;
//PGUID AppIdentifier;
BcdElementType ElementType;
/* Make sure this is a BCD_TYPE_BOOLEAN */
ElementType.PackedValue = Type;
if (ElementType.Format != BCD_TYPE_BOOLEAN)
{
return STATUS_INVALID_PARAMETER;
}
/* Return the data */
Option = MiscGetBootOption(List, Type);
if (Option)
{
*Value = *(PBOOLEAN)((ULONG_PTR)Option + Option->DataOffset);
}
#ifdef _SECURE_BOOT_
/* Filter out SecureBoot Options */
AppIdentifier = BlGetApplicationIdentifier();
Status = BlpBootOptionCallbackBoolean(AppIdentifier, Type, Value);
#else
/* Option found */
Status = Option ? STATUS_SUCCESS : STATUS_NOT_FOUND;
#endif
return Status;
}
NTSTATUS
BlpGetBootOptionIntegerList (
_In_ PBL_BCD_OPTION List,
_In_ ULONG Type,
_Out_ PULONGLONG* Value,
_Out_ PULONGLONG Count,
_In_ BOOLEAN NoCopy
)
{
PBL_BCD_OPTION Option;
BcdElementType ElementType;
PULONGLONG ValueCopy;
/* Make sure this is a BCD_TYPE_INTEGER_LIST */
ElementType.PackedValue = Type;
if (ElementType.Format != BCD_TYPE_INTEGER_LIST)
{
return STATUS_INVALID_PARAMETER;
}
/* Return the data */
Option = MiscGetBootOption(List, Type);
if (!Option)
{
return STATUS_NOT_FOUND;
}
/* Check if a copy should be made of it */
if (NoCopy)
{
/* Nope, return the raw value */
*Value = (PULONGLONG)((ULONG_PTR)Option + Option->DataOffset);
}
else
{
/* Allocate a buffer for the copy */
ValueCopy = BlMmAllocateHeap(Option->DataSize);
if (!ValueCopy)
{
return STATUS_NO_MEMORY;
}
/* Copy the data in */
RtlCopyMemory(ValueCopy,
(PVOID)((ULONG_PTR)Option + Option->DataOffset),
Option->DataSize);
/* Return our copy */
*Value = ValueCopy;
}
/* Return count and success */
*Count = Option->DataSize / sizeof(ULONGLONG);
return STATUS_SUCCESS;
}
NTSTATUS
BlCopyBootOptions (
_In_ PBL_BCD_OPTION OptionList,
_Out_ PBL_BCD_OPTION *CopiedOptions
)
{
NTSTATUS Status;
ULONG OptionSize;
PBL_BCD_OPTION Options;
/* Assume no options */
Status = STATUS_SUCCESS;
*CopiedOptions = NULL;
/* Get the size of the list and allocate a copy for it */
OptionSize = BlGetBootOptionListSize(OptionList);
Options = BlMmAllocateHeap(OptionSize);
if (!Options)
{
return STATUS_NO_MEMORY;
}
/* Make the copy and return it to the caller */
RtlCopyMemory(Options, OptionList, OptionSize);
*CopiedOptions = Options;
return Status;
}
NTSTATUS
BlAppendBootOptions (
_In_ PBL_LOADED_APPLICATION_ENTRY AppEntry,
_In_ PBL_BCD_OPTION Options
)
{
ULONG OptionsSize, CurrentSize;
PBL_BCD_OPTION NewOptions, CurrentOptions, NextOption;
NTSTATUS Status;
ULONG CurrentOffset;
/* Get the current options */
CurrentOptions = AppEntry->BcdData;
/* Calculate the size of the current, and the appended options */
CurrentSize = BlGetBootOptionListSize(CurrentOptions);
OptionsSize = BlGetBootOptionListSize(Options);
/* Allocate a buffer for the concatenated (new) options */
NewOptions = BlMmAllocateHeap(CurrentSize + OptionsSize);
if (!NewOptions)
{
return STATUS_NO_MEMORY;
}
/* Copy the old options, and the ones to be added */
RtlCopyMemory(NewOptions, CurrentOptions, CurrentSize);
RtlCopyMemory(&NewOptions[OptionsSize], Options, OptionsSize);
/* We made it! */
Status = STATUS_SUCCESS;
/* Scan through to the last option in the list */
CurrentOffset = 0;
do
{
NextOption = (PBL_BCD_OPTION)((ULONG_PTR)NewOptions + CurrentOffset);
CurrentOffset = NextOption->NextEntryOffset;
} while (CurrentOffset);
/* Every other option now has to have its offset adjusted */
do
{
NextOption->NextEntryOffset += OptionsSize;
NextOption = (PBL_BCD_OPTION)((ULONG_PTR)NewOptions + NextOption->NextEntryOffset);
} while (NextOption->NextEntryOffset);
/* If we already had internal options, free them */
if (AppEntry->Flags & BL_APPLICATION_ENTRY_BCD_OPTIONS_INTERNAL)
{
BlMmFreeHeap(AppEntry->BcdData);
}
/* Write the new pointer */
AppEntry->BcdData = NewOptions;
/* Options are now internal, not external */
AppEntry->Flags &= ~BL_APPLICATION_ENTRY_BCD_OPTIONS_EXTERNAL;
AppEntry->Flags |= BL_APPLICATION_ENTRY_BCD_OPTIONS_INTERNAL;
return Status;
}

View file

@ -0,0 +1,889 @@
/*
* COPYRIGHT: See COPYING.ARM in the top level directory
* PROJECT: ReactOS UEFI Boot Library
* FILE: boot/environ/lib/misc/bootreg.c
* PURPOSE: Boot Library Boot Registry Wrapper for CMLIB
* PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include "bl.h"
#include <bcd.h>
/* DEFINITIONS ***************************************************************/
#define BI_FLUSH_HIVE 0x01
#define BI_HIVE_WRITEABLE 0x02
/* DATA STRUCTURES ***********************************************************/
typedef struct _BI_KEY_HIVE
{
PHBASE_BLOCK BaseBlock;
ULONG HiveSize;
PBL_FILE_PATH_DESCRIPTOR FilePath;
CMHIVE Hive;
LONG ReferenceCount;
ULONG Flags;
PCM_KEY_NODE RootNode;
} BI_KEY_HIVE, *PBI_KEY_HIVE;
typedef struct _BI_KEY_OBJECT
{
PBI_KEY_HIVE KeyHive;
PCM_KEY_NODE KeyNode;
HCELL_INDEX KeyCell;
PWCHAR KeyName;
} BI_KEY_OBJECT, *PBI_KEY_OBJECT;
/* GLOBALS *******************************************************************/
BOOLEAN BiHiveHashLibraryInitialized;
ULONGLONG HvSymcryptSeed;
/* FUNCTIONS *****************************************************************/
BOOLEAN
HvIsInPlaceBaseBlockValid (
_In_ PHBASE_BLOCK BaseBlock
)
{
ULONG HiveLength, HeaderSum;
BOOLEAN Valid;
/* Assume failure */
Valid = FALSE;
/* Check for incorrect signature, type, version, or format */
if ((BaseBlock->Signature == 'fger') &&
(BaseBlock->Type == 0) &&
(BaseBlock->Major <= 1) &&
(BaseBlock->Minor <= 5) &&
(BaseBlock->Minor >= 3) &&
(BaseBlock->Format == 1))
{
/* Check for invalid hive size */
HiveLength = BaseBlock->Length;
if (HiveLength)
{
/* Check for misaligned or too large hive size */
if (!(HiveLength & 0xFFF) && HiveLength <= 0x7FFFE000)
{
/* Check for invalid header checksum */
HeaderSum = HvpHiveHeaderChecksum(BaseBlock);
if (HeaderSum == BaseBlock->CheckSum)
{
/* All good */
Valid = TRUE;
}
}
}
}
/* Return validity */
return Valid;
}
PVOID
NTAPI
CmpAllocate (
_In_ SIZE_T Size,
_In_ BOOLEAN Paged,
_In_ ULONG Tag
)
{
UNREFERENCED_PARAMETER(Paged);
UNREFERENCED_PARAMETER(Tag);
/* Call the heap allocator */
return BlMmAllocateHeap(Size);
}
VOID
NTAPI
CmpFree (
_In_ PVOID Ptr,
_In_ ULONG Quota
)
{
UNREFERENCED_PARAMETER(Quota);
/* Call the heap allocator */
BlMmFreeHeap(Ptr);
}
VOID
BiDereferenceHive (
_In_ HANDLE KeyHandle
)
{
PBI_KEY_OBJECT KeyObject;
/* Get the key object */
KeyObject = (PBI_KEY_OBJECT)KeyHandle;
/* Drop a reference on the parent hive */
--KeyObject->KeyHive->ReferenceCount;
}
VOID
BiFlushHive (
_In_ HANDLE KeyHandle
)
{
/* Not yet implemented */
EfiPrintf(L"NO reg flush\r\n");
return;
}
VOID
BiCloseKey (
_In_ HANDLE KeyHandle
)
{
PBI_KEY_HIVE KeyHive;
PBI_KEY_OBJECT KeyObject;
/* Get the key object and hive */
KeyObject = (PBI_KEY_OBJECT)KeyHandle;
KeyHive = KeyObject->KeyHive;
/* Check if we have a hive, or name, or key node */
if ((KeyHive) || (KeyObject->KeyNode) || (KeyObject->KeyName))
{
/* Drop a reference, see if it's the last one */
BiDereferenceHive(KeyHandle);
if (!KeyHive->ReferenceCount)
{
/* Check if we should flush it */
if (KeyHive->Flags & BI_FLUSH_HIVE)
{
BiFlushHive(KeyHandle);
}
/* Unmap the hive */
//MmPapFreePages(KeyHive->ImageBase, 1);
EfiPrintf(L"Leaking hive memory\r\n");
/* Free the hive and hive path */
BlMmFreeHeap(KeyHive->FilePath);
BlMmFreeHeap(KeyHive);
}
/* Check if a key name is present */
if (KeyObject->KeyName)
{
/* Free it */
BlMmFreeHeap(KeyObject->KeyName);
}
}
/* Free the object */
BlMmFreeHeap(KeyObject);
}
NTSTATUS
BiOpenKey(
_In_ HANDLE ParentHandle,
_In_ PWCHAR KeyName,
_Out_ PHANDLE Handle
)
{
PBI_KEY_OBJECT ParentKey, NewKey;
PBI_KEY_HIVE ParentHive;
NTSTATUS Status;
ULONG NameLength, SubNameLength, NameBytes;
PWCHAR NameStart, NameBuffer;
UNICODE_STRING KeyString;
HCELL_INDEX KeyCell;
PHHIVE Hive;
PCM_KEY_NODE ParentNode;
/* Convert from a handle to our key object */
ParentKey = (PBI_KEY_OBJECT)ParentHandle;
/* Extract the hive and node information */
ParentHive = ParentKey->KeyHive;
ParentNode = ParentKey->KeyNode;
Hive = &ParentKey->KeyHive->Hive.Hive;
/* Initialize variables */
KeyCell = HCELL_NIL;
Status = STATUS_SUCCESS;
NameBuffer = NULL;
/* Loop as long as there's still portions of the key name in play */
NameLength = wcslen(KeyName);
while (NameLength)
{
/* Find the first path separator */
NameStart = wcschr(KeyName, OBJ_NAME_PATH_SEPARATOR);
if (NameStart)
{
/* Look only at the key before the separator */
SubNameLength = NameStart - KeyName;
++NameStart;
}
else
{
/* No path separator, this is the final leaf key */
SubNameLength = NameLength;
}
/* Free the name buffer from the previous pass if needed */
if (NameBuffer)
{
BlMmFreeHeap(NameBuffer);
}
/* Allocate a buffer to hold the name of this specific subkey only */
NameBytes = SubNameLength * sizeof(WCHAR);
NameBuffer = BlMmAllocateHeap(NameBytes + sizeof(UNICODE_NULL));
if (!NameBuffer)
{
Status = STATUS_NO_MEMORY;
goto Quickie;
}
/* Copy and null-terminate the name of the subkey */
RtlCopyMemory(NameBuffer, KeyName, NameBytes);
NameBuffer[SubNameLength] = UNICODE_NULL;
/* Convert it into a UNICODE_STRING and try to find it */
RtlInitUnicodeString(&KeyString, NameBuffer);
KeyCell = CmpFindSubKeyByName(Hive, ParentNode, &KeyString);
if (KeyCell == HCELL_NIL)
{
Status = STATUS_OBJECT_NAME_NOT_FOUND;
goto Quickie;
}
/* We found it -- get the key node out of it */
ParentNode = (PCM_KEY_NODE)HvGetCell(Hive, KeyCell);
if (!ParentNode)
{
Status = STATUS_REGISTRY_CORRUPT;
goto Quickie;
}
/* Update the key name to the next remaining path element */
KeyName = NameStart;
if (NameStart)
{
/* Update the length to the remainder of the path */
NameLength += -1 - SubNameLength;
}
else
{
/* There's nothing left, this was the leaf key */
NameLength = 0;
}
}
/* Allocate a key object */
NewKey = BlMmAllocateHeap(sizeof(*NewKey));
if (!NewKey)
{
/* Bail out if we had no memory for it */
Status = STATUS_NO_MEMORY;
goto Quickie;
}
/* Fill out the key object data */
NewKey->KeyNode = ParentNode;
NewKey->KeyHive = ParentHive;
NewKey->KeyName = NameBuffer;
NewKey->KeyCell = KeyCell;
/* Add a reference to the hive */
++ParentHive->ReferenceCount;
/* Return the object back to the caller */
*Handle = NewKey;
Quickie:
/* If we had a name buffer, free it */
if (NameBuffer)
{
BlMmFreeHeap(NameBuffer);
}
/* Return status of the open operation */
return Status;
}
NTSTATUS
BiInitializeAndValidateHive (
_In_ PBI_KEY_HIVE Hive
)
{
ULONG HiveSize;
NTSTATUS Status;
/* Make sure the hive is at least the size of a base block */
if (Hive->HiveSize < sizeof(HBASE_BLOCK))
{
return STATUS_REGISTRY_CORRUPT;
}
/* Make sure that the base block accurately describes the size of the hive */
HiveSize = Hive->BaseBlock->Length + sizeof(HBASE_BLOCK);
if ((HiveSize < sizeof(HBASE_BLOCK)) || (HiveSize > Hive->HiveSize))
{
return STATUS_REGISTRY_CORRUPT;
}
/* Initialize a flat memory hive */
RtlZeroMemory(&Hive->Hive, sizeof(Hive->Hive));
Status = HvInitialize(&Hive->Hive.Hive,
HINIT_FLAT,
0,
0,
Hive->BaseBlock,
CmpAllocate,
CmpFree,
NULL,
NULL,
NULL,
NULL,
0,
NULL);
if (NT_SUCCESS(Status))
{
/* Cleanup volatile/old data */
CmPrepareHive(&Hive->Hive.Hive); // CmCheckRegistry
Status = STATUS_SUCCESS;
}
/* Return the final status */
return Status;
}
NTSTATUS
BiLoadHive (
_In_ PBL_FILE_PATH_DESCRIPTOR FilePath,
_Out_ PHANDLE HiveHandle
)
{
ULONG DeviceId;
PHBASE_BLOCK BaseBlock, NewBaseBlock;
PBI_KEY_OBJECT KeyObject;
PBI_KEY_HIVE BcdHive;
PBL_DEVICE_DESCRIPTOR BcdDevice;
ULONG PathLength, DeviceLength, HiveSize, HiveLength, NewHiveSize;
PWCHAR HiveName, LogName;
BOOLEAN HaveWriteAccess;
NTSTATUS Status;
PVOID LogData;
PHHIVE Hive;
UNICODE_STRING KeyString;
PCM_KEY_NODE RootNode;
HCELL_INDEX CellIndex;
/* Initialize variables */
DeviceId = -1;
BaseBlock = NULL;
BcdHive = NULL;
KeyObject = NULL;
LogData = NULL;
LogName = NULL;
/* Initialize the crypto seed */
if (!BiHiveHashLibraryInitialized)
{
HvSymcryptSeed = 0x82EF4D887A4E55C5;
BiHiveHashLibraryInitialized = TRUE;
}
/* Extract and validate the input path */
BcdDevice = (PBL_DEVICE_DESCRIPTOR)&FilePath->Path;
PathLength = FilePath->Length;
DeviceLength = BcdDevice->Size;
HiveName = (PWCHAR)((ULONG_PTR)BcdDevice + BcdDevice->Size);
if (PathLength <= DeviceLength)
{
/* Doesn't make sense, bail out */
Status = STATUS_INVALID_PARAMETER;
goto Quickie;
}
/* Attempt to open the underlying device for RW access */
HaveWriteAccess = TRUE;
Status = BlpDeviceOpen(BcdDevice,
BL_DEVICE_READ_ACCESS | BL_DEVICE_WRITE_ACCESS,
0,
&DeviceId);
if (!NT_SUCCESS(Status))
{
/* Try for RO access instead */
HaveWriteAccess = FALSE;
Status = BlpDeviceOpen(BcdDevice, BL_DEVICE_READ_ACCESS, 0, &DeviceId);
if (!NT_SUCCESS(Status))
{
/* No access at all -- bail out */
goto Quickie;
}
}
/* Now try to load the hive on disk */
Status = BlImgLoadImageWithProgress2(DeviceId,
BlLoaderRegistry,
HiveName,
(PVOID*)&BaseBlock,
&HiveSize,
0,
FALSE,
NULL,
NULL);
if (!NT_SUCCESS(Status))
{
EfiPrintf(L"Hive read failure: % lx\r\n", Status);
goto Quickie;
}
/* Allocate a hive structure */
BcdHive = BlMmAllocateHeap(sizeof(*BcdHive));
if (!BcdHive)
{
Status = STATUS_NO_MEMORY;
goto Quickie;
}
/* Initialize it */
RtlZeroMemory(BcdHive, sizeof(*BcdHive));
BcdHive->BaseBlock = BaseBlock;
BcdHive->HiveSize = HiveSize;
if (HaveWriteAccess)
{
BcdHive->Flags |= BI_HIVE_WRITEABLE;
}
/* Make sure the hive was at least one bin long */
if (HiveSize < sizeof(*BaseBlock))
{
Status = STATUS_REGISTRY_CORRUPT;
goto Quickie;
}
/* Make sure the hive contents are at least one bin long */
HiveLength = BaseBlock->Length;
if (BaseBlock->Length < sizeof(*BaseBlock))
{
Status = STATUS_REGISTRY_CORRUPT;
goto Quickie;
}
/* Validate the initial bin (the base block) */
if (!HvIsInPlaceBaseBlockValid(BaseBlock))
{
EfiPrintf(L"Recovery not implemented\r\n");
Status = STATUS_REGISTRY_CORRUPT;
goto Quickie;
}
/* Check if there's log recovery that needs to happen */
if (BaseBlock->Sequence1 != BaseBlock->Sequence2)
{
EfiPrintf(L"Log fix not implemented: %lx %lx\r\n");
Status = STATUS_REGISTRY_CORRUPT;
goto Quickie;
}
/*
* Check if the whole hive doesn't fit in the buffer.
* Note: HiveLength does not include the size of the baseblock itself
*/
if (HiveSize < (HiveLength + sizeof(*BaseBlock)))
{
EfiPrintf(L"Need bigger hive buffer path\r\n");
/* Allocate a slightly bigger buffer */
NewHiveSize = HiveLength + sizeof(*BaseBlock);
Status = MmPapAllocatePagesInRange((PVOID*)&NewBaseBlock,
BlLoaderRegistry,
NewHiveSize >> PAGE_SHIFT,
0,
0,
NULL,
0);
if (!NT_SUCCESS(Status))
{
goto Quickie;
}
/* Copy the current data in there */
RtlCopyMemory(NewBaseBlock, BaseBlock, HiveSize);
/* Free the old data */
EfiPrintf(L"Leaking old hive buffer\r\n");
//MmPapFreePages(BaseBlock, 1);
/* Update our pointers */
BaseBlock = NewBaseBlock;
HiveSize = NewHiveSize;
BcdHive->BaseBlock = BaseBlock;
BcdHive->HiveSize = HiveSize;
}
/* Check if any log stuff needs to happen */
if (LogData)
{
EfiPrintf(L"Log fix not implemented: %lx %lx\r\n");
Status = STATUS_REGISTRY_CORRUPT;
goto Quickie;
}
/* Call Hv to setup the hive library */
Status = BiInitializeAndValidateHive(BcdHive);
if (!NT_SUCCESS(Status))
{
goto Quickie;
}
/* Now get the root node */
Hive = &BcdHive->Hive.Hive;
RootNode = (PCM_KEY_NODE)HvGetCell(Hive, Hive->BaseBlock->RootCell);
if (!RootNode)
{
Status = STATUS_OBJECT_NAME_NOT_FOUND;
goto Quickie;
}
/* Find the Objects subkey under it to see if it's a real BCD hive */
RtlInitUnicodeString(&KeyString, L"Objects");
CellIndex = CmpFindSubKeyByName(Hive, RootNode, &KeyString);
if (CellIndex == HCELL_NIL)
{
EfiPrintf(L"No OBJECTS subkey found!\r\n");
Status = STATUS_OBJECT_NAME_NOT_FOUND;
goto Quickie;
}
/* This is a valid BCD hive, store its root node here */
BcdHive->RootNode = RootNode;
/* Allocate a copy of the file path */
BcdHive->FilePath = BlMmAllocateHeap(FilePath->Length);
if (!BcdHive->FilePath)
{
Status = STATUS_NO_MEMORY;
goto Quickie;
}
/* Make a copy of it */
RtlCopyMemory(BcdHive->FilePath, FilePath, FilePath->Length);
/* Create a key object to describe the rot */
KeyObject = BlMmAllocateHeap(sizeof(*KeyObject));
if (!KeyObject)
{
Status = STATUS_NO_MEMORY;
goto Quickie;
}
/* Fill out the details */
KeyObject->KeyNode = RootNode;
KeyObject->KeyHive = BcdHive;
KeyObject->KeyName = NULL;
KeyObject->KeyCell = Hive->BaseBlock->RootCell;
/* One reference for the key object, plus one lifetime reference */
BcdHive->ReferenceCount = 2;
/* This is the hive handle */
*HiveHandle = KeyObject;
/* We're all good */
Status = STATUS_SUCCESS;
Quickie:
/* If we had a log name, free it */
if (LogName)
{
BlMmFreeHeap(LogName);
}
/* If we had logging data, free it */
if (LogData)
{
EfiPrintf(L"Leaking log buffer\r\n");
//MmPapFreePages(LogData, 1);
}
/* Check if this is the failure path */
if (!NT_SUCCESS(Status))
{
/* If we mapped the hive, free it */
if (BaseBlock)
{
EfiPrintf(L"Leaking base block on failure\r\n");
//MmPapFreePages(BaseBlock, 1u);
}
/* If we opened the device, close it */
if (DeviceId != -1)
{
BlDeviceClose(DeviceId);
}
/* Did we create a hive object? */
if (BcdHive)
{
/* Free the file path if we made a copy of it */
if (BcdHive->FilePath)
{
BlMmFreeHeap(BcdHive->FilePath);
}
/* Free the hive itself */
BlMmFreeHeap(BcdHive);
}
/* Finally, free the root key object if we created one */
if (KeyObject)
{
BlMmFreeHeap(KeyObject);
}
}
/* Return the final status */
return Status;
}
NTSTATUS
BiGetRegistryValue (
_In_ HANDLE KeyHandle,
_In_ PWCHAR ValueName,
_In_ PWCHAR KeyName,
_In_ ULONG Type,
_Out_ PVOID* Buffer,
_Out_ PULONG ValueLength
)
{
PCM_KEY_NODE KeyNode;
PHHIVE KeyHive;
UNICODE_STRING ValueString;
PBI_KEY_OBJECT KeyObject;
PCM_KEY_VALUE KeyValue;
PVOID ValueCopy;
ULONG Size;
HCELL_INDEX CellIndex;
PCELL_DATA ValueData;
/* Get the key object, node,and hive */
KeyObject = (PBI_KEY_OBJECT)KeyHandle;
KeyNode = KeyObject->KeyNode;
KeyHive = &KeyObject->KeyHive->Hive.Hive;
/* Find the value cell index in the list of values */
RtlInitUnicodeString(&ValueString, ValueName);
CmpFindNameInList(KeyHive,
&KeyNode->ValueList,
&ValueString,
NULL,
&CellIndex);
if (CellIndex == HCELL_NIL)
{
return STATUS_OBJECT_NAME_NOT_FOUND;
}
/* Get the cell data for it */
KeyValue = (PCM_KEY_VALUE)HvGetCell(KeyHive, CellIndex);
if (!KeyValue)
{
return STATUS_REGISTRY_CORRUPT;
}
/* Make sure the type matches */
if (KeyValue->Type != Type)
{
return STATUS_OBJECT_TYPE_MISMATCH;
}
/* Now get the data cell */
ValueData = CmpValueToData(KeyHive, KeyValue, &Size);
/* Make a copy of it */
ValueCopy = BlMmAllocateHeap(Size);
if (!ValueCopy)
{
return STATUS_NO_MEMORY;
}
/* Copy it in the buffer, and return it and its size */
RtlCopyMemory(ValueCopy, ValueData, Size);
*Buffer = ValueCopy;
*ValueLength = Size;
return STATUS_SUCCESS;
}
NTSTATUS
BiEnumerateSubKeys (
_In_ HANDLE KeyHandle,
_Out_ PWCHAR** SubKeyList,
_Out_ PULONG SubKeyCount
)
{
PCM_KEY_NODE KeyNode, Node;
PBI_KEY_OBJECT KeyObject;
ULONG KeyCount;
ULONG NameLength, NewTotalNameLength, FinalLength, TotalNameLength;
PHHIVE Hive;
PWCHAR KeyName, NameEnd;
HCELL_INDEX CellIndex;
PWCHAR* SubKeys;
NTSTATUS Status;
ULONG i;
/* Get the key object, node, and hive */
KeyObject = (PBI_KEY_OBJECT)KeyHandle;
KeyNode = KeyObject->KeyNode;
Hive = &KeyObject->KeyHive->Hive.Hive;
/* Assume it's empty */
*SubKeyList = 0;
*SubKeyCount = 0;
/* Initialize locals */
KeyCount = 0;
SubKeys = 0;
TotalNameLength = 0;
/* Find the first subkey cell index */
CellIndex = CmpFindSubKeyByNumber(Hive, KeyNode, KeyCount);
while (CellIndex != HCELL_NIL)
{
/* Move to the next one */
KeyCount++;
/* Get the cell data for it */
Node = (PCM_KEY_NODE)HvGetCell(Hive, CellIndex);
if (!Node)
{
return STATUS_REGISTRY_CORRUPT;
}
/* Check if the value is compressed */
if (Node->Flags & KEY_COMP_NAME)
{
/* Get the compressed name size */
NameLength = CmpCompressedNameSize(Node->Name, Node->NameLength);
}
else
{
/* Get the real size */
NameLength = Node->NameLength;
}
/* Add up the new length, protecting against overflow */
NewTotalNameLength = TotalNameLength + NameLength + sizeof(UNICODE_NULL);
if (NewTotalNameLength < TotalNameLength)
{
Status = STATUS_NAME_TOO_LONG;
goto Quickie;
}
/* We're good, use the new length */
TotalNameLength = NewTotalNameLength;
/* Find the next subkey cell index */
CellIndex = CmpFindSubKeyByNumber(Hive, KeyNode, KeyCount);
}
/* Were there no keys? We're done, if so */
if (!KeyCount)
{
return STATUS_SUCCESS;
}
/* Safely compute the size of the array needed */
Status = RtlULongLongToULong(sizeof(PWCHAR) * KeyCount, &FinalLength);
if (!NT_SUCCESS(Status))
{
goto Quickie;
}
/* Safely add that to the name length */
Status = RtlULongAdd(TotalNameLength, FinalLength, &FinalLength);
if (!NT_SUCCESS(Status))
{
goto Quickie;
}
/* Allocate an array big enough for the names and pointers */
SubKeys = BlMmAllocateHeap(FinalLength);
if (!SubKeys)
{
Status = STATUS_NO_MEMORY;
goto Quickie;
}
/* Go over each key again */
NameEnd = (PWCHAR)&SubKeys[KeyCount];
for (i = 0; i < KeyCount; i++)
{
/* Get the cell index for this subkey */
CellIndex = CmpFindSubKeyByNumber(Hive, KeyNode, i);
if (CellIndex == HCELL_NIL)
{
break;
}
/* Get the cell data for it */
Node = HvGetCell(Hive, CellIndex);
if (!Node)
{
Status = STATUS_REGISTRY_CORRUPT;
goto Quickie;
}
/* Check if the value is compressed */
KeyName = Node->Name;
if (Node->Flags & KEY_COMP_NAME)
{
/* Get the compressed name size */
NameLength = CmpCompressedNameSize(KeyName, Node->NameLength);
CmpCopyCompressedName(NameEnd, NameLength, KeyName, Node->NameLength);
}
else
{
/* Get the real size */
NameLength = Node->NameLength;
RtlCopyMemory(NameEnd, KeyName, NameLength);
}
/* Move the name buffer to the next spot, and NULL-terminate */
SubKeys[i] = NameEnd;
NameEnd += (NameLength / sizeof(WCHAR));
*NameEnd = UNICODE_NULL;
/* Keep going */
NameEnd++;
}
/* Check if the subkeys were empty */
if (i == 0)
{
/* They disappeared in the middle of enumeration */
Status = STATUS_OBJECT_NAME_NOT_FOUND;
goto Quickie;
}
/* Return the count and the array of names */
*SubKeyList = SubKeys;
*SubKeyCount = i;
SubKeys = NULL;
Status = STATUS_SUCCESS;
Quickie:
/* On the failure path, free the subkeys if any exist */
if (SubKeys)
{
BlMmFreeHeap(SubKeys);
}
/* All done, return the result */
return Status;
}

View file

@ -9,6 +9,7 @@
/* INCLUDES ******************************************************************/
#include "bl.h"
#include "bcd.h"
/* DATA VARIABLES ************************************************************/
@ -38,7 +39,35 @@ BlMmRemoveBadMemory (
VOID
)
{
/* FIXME: Read BCD option to see what bad memory to remove */
BOOLEAN AllowBad;
NTSTATUS Status;
PULONGLONG BadPages;
ULONGLONG BadPageCount;
/* First check if bad memory access is allowed */
AllowBad = FALSE;
Status = BlGetBootOptionBoolean(BlpApplicationEntry.BcdData,
BcdLibraryBoolean_AllowBadMemoryAccess,
&AllowBad);
if ((NT_SUCCESS(Status)) && (AllowBad))
{
/* No point checking the list if it is */
return STATUS_SUCCESS;
}
/* Otherwise, check if there's a persisted bad page list */
Status = BlpGetBootOptionIntegerList(BlpApplicationEntry.BcdData,
BcdLibraryIntegerList_BadMemoryList,
&BadPages,
&BadPageCount,
TRUE);
if (NT_SUCCESS(Status))
{
EfiPrintf(L"Persistent bad page list not supported\r\n");
return STATUS_NOT_IMPLEMENTED;
}
/* All done here */
return STATUS_SUCCESS;
}

View file

@ -9,7 +9,7 @@
/* INCLUDES ******************************************************************/
#include "bl.h"
#include "bcd.h"
typedef struct _BL_PA_REQUEST
{
@ -50,7 +50,30 @@ BlpMmInitializeConstraints (
VOID
)
{
/* FIXME: Read BCD option 'avoidlowmemory' and 'truncatememory' */
NTSTATUS Status;
ULONGLONG LowestAddressValid, HighestAddressValid;
/* Check for LOWMEM */
Status = BlGetBootOptionInteger(BlpApplicationEntry.BcdData,
BcdLibraryInteger_AvoidLowPhysicalMemory,
&LowestAddressValid);
if (NT_SUCCESS(Status))
{
EfiPrintf(L"/LOWMEM not supported\r\n");
return STATUS_NOT_IMPLEMENTED;
}
/* Check for MAXMEM */
Status = BlGetBootOptionInteger(BlpApplicationEntry.BcdData,
BcdLibraryInteger_TruncatePhysicalMemory,
&HighestAddressValid);
if (NT_SUCCESS(Status))
{
EfiPrintf(L"/MAXMEM not supported\r\n");
return STATUS_NOT_IMPLEMENTED;
}
/* Return back to the caller */
return STATUS_SUCCESS;
}