[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
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
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
}
/* 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)
{
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 */
)
{
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;
/* Add the length of the file, make sure it fits */
PathLength = wcslen(FileName);
- FullPathLength = PathLength + BootDirLength;
- if (FullPathLength < PathLength)
- {
- /* Nope */
- FullPathLength = -1;
- Status = STATUS_INTEGER_OVERFLOW;
- }
- else
+ Status = RtlULongAdd(PathLength, BootDirLength, &PathLength);
+ if (!NT_SUCCESS(Status))
{
- /* 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
{
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
PBL_DEVICE_DESCRIPTOR BcdDevice;
PWCHAR BcdPath, FullPath, PathBuffer;
BOOLEAN HavePath;
- ULONG PathLength, PathLengthWithNul, FullSize;
+ ULONG PathLength, FullSize;
PVOID FinalBuffer;
UNICODE_STRING BcdString;
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;
}
}
/* 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;
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;
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? */
_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");
/* 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) ||
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 *****************************************************************/
/* 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,
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;
_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
/* NDK Headers */
#include <ntndk.h>
+/* NT SafeInt Header */
+#include <ntintsafe.h>
+
/* UEFI Headers */
#include <Uefi.h>
#include <DevicePath.h>
#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
typedef struct _BL_DEVICE_DESCRIPTOR
{
- ULONG Size;
- ULONG Flags;
DEVICE_TYPE DeviceType;
+ ULONG Flags;
+ ULONG Size;
ULONG Unknown;
union
{
_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 (
_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,
_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
_In_ ULONG Flags
);
+NTSTATUS
+BlpMmInitializeConstraints (
+ VOID
+ );
+
+NTSTATUS
+BlMmRemoveBadMemory (
+ VOID
+ );
+
/* VIRTUAL MEMORY ROUTINES ***************************************************/
NTSTATUS
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 */
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
}
VOID
)
{
- //EarlyPrint(L"Disabling graphics\r\n");
+ EfiPrintf(L"Disabling graphics\r\n");
return FALSE;
}
)
{
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;
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;
}
/* 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;
{
/* 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))
/* 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
+VOID
+BiNotifyEnumerationError (
+ _In_ HANDLE ObjectHandle,
+ _In_ PWCHAR ElementName,
+ _In_ NTSTATUS Status
)
{
- 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;
+ /* Stub for now */
+ UNREFERENCED_PARAMETER(ObjectHandle);
+ UNREFERENCED_PARAMETER(ElementName);
+ UNREFERENCED_PARAMETER(Status);
+ EfiPrintf(L"Error in BiNotify\r\n");
}
-/*++
- * @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
+BiConvertElementFormatToValueType (
+ _In_ ULONG Format
)
{
- ULONG Size, Offset;
-
- /* Check if there's any data */
- if (BcdOption->DataOffset)
- {
- /* Add the size of the data */
- Size = BcdOption->DataOffset + BcdOption->DataSize;
- }
- else
+ /* Strings and objects are strings */
+ if ((Format == BCD_TYPE_STRING) || (Format == BCD_TYPE_OBJECT))
{
- /* No data, just the structure itself */
- Size = sizeof(*BcdOption);
+ return REG_SZ;
}
- /* Any associated options? */
- Offset = BcdOption->ListOffset;
- if (Offset)
+ /* Object lists are arrays of strings */
+ if (Format == BCD_TYPE_OBJECT_LIST)
{
- /* Go get those too */
- Size += BlGetBootOptionListSize((PVOID)((ULONG_PTR)BcdOption + Offset));
+ return REG_MULTI_SZ;
}
- /* Return the final size */
- return Size;
+ /* Everything else is binary */
+ return REG_BINARY;
}
NTSTATUS
-BlGetBootOptionString (
- _In_ PBL_BCD_OPTION List,
- _In_ ULONG Type,
- _Out_ PWCHAR* Value
+BiConvertRegistryDataToElement (
+ _In_ HANDLE ObjectHandle,
+ _In_ PVOID Data,
+ _In_ ULONG DataLength,
+ _In_ BcdElementType ElementType,
+ _Out_ PVOID Element,
+ _Out_ PULONG ElementSize
)
{
NTSTATUS Status;
- PBL_BCD_OPTION Option;
- PWCHAR String, StringCopy;
- ULONG StringLength, CopyLength;
- //PGUID AppIdentifier;
+ ULONG Length, Size, ReturnedLength;
+ PBL_DEVICE_DESCRIPTOR Device;
+ BOOLEAN NullTerminate;
+ PBCD_DEVICE_OPTION BcdDevice, ElementDevice;
+ PWCHAR BcdString, ElementString;
+ PGUID ElementGuid; UNICODE_STRING GuidString;
+ PULONGLONG ElementInteger;
+ PUSHORT ElementWord; PBOOLEAN BcdBoolean;
- /* Make sure this is a BCD_STRING */
- if ((Type & 0xF000000) != 0x2000000)
- {
- return STATUS_INVALID_PARAMETER;
- }
+ /* Assume failure */
+ ReturnedLength = 0;
- /* Return the data */
- Option = MiscGetBootOption(List, Type);
- if (Option)
- {
- /* Extract the string */
- String = (PWCHAR)((ULONG_PTR)Option + Option->DataOffset);
- Status = STATUS_SUCCESS;
- }
- else
+ /* Check what type of format we are dealing with */
+ switch (ElementType.Format)
{
- /* No string is present */
- String = NULL;
- Status = STATUS_NOT_FOUND;
- }
+ /* Devices -- they are in a binary format */
+ case BCD_TYPE_DEVICE:
- /* 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
- /* Check if we have space for one more character */
- CopyLength = StringLength + 1;
- if (CopyLength < StringLength)
- {
- /* Nope, we'll overflow */
- CopyLength = -1;
- Status = STATUS_INTEGER_OVERFLOW;
- }
+ /* First, make sure it's at least big enough for an empty descriptor */
+ if (DataLength < FIELD_OFFSET(BCD_DEVICE_OPTION,
+ DeviceDescriptor.Unknown))
+ {
+ return STATUS_OBJECT_TYPE_MISMATCH;
+ }
- /* No overflow? */
- if (NT_SUCCESS(Status))
- {
- /* Check if it's safe to multiply by two */
- if ((CopyLength * sizeof(WCHAR)) > 0xFFFFFFFF)
- {
- /* Nope */
- CopyLength = -1;
- Status = STATUS_INTEGER_OVERFLOW;
- }
- else
- {
- /* We're good, do the multiplication */
- Status = STATUS_SUCCESS;
- CopyLength *= sizeof(WCHAR);
- }
+ /* Both the registry and BCD format are the same */
+ BcdDevice = (PBCD_DEVICE_OPTION)Data;
+ ElementDevice = (PBCD_DEVICE_OPTION)Element;
- /* Allocate a copy for the string */
- if (NT_SUCCESS(Status))
- {
- StringCopy = BlMmAllocateHeap(CopyLength);
- if (StringCopy)
+ /* Make sure the device fits in the registry data */
+ Device = &BcdDevice->DeviceDescriptor;
+ Size = Device->Size;
+ if ((Size + sizeof(BcdDevice->AssociatedEntry)) != DataLength)
{
- /* NULL-terminate it */
- RtlCopyMemory(StringCopy,
- String,
- CopyLength - sizeof(UNICODE_NULL));
- StringCopy[CopyLength] = UNICODE_NULL;
- *Value = StringCopy;
- Status = STATUS_SUCCESS;
+ return STATUS_OBJECT_TYPE_MISMATCH;
}
- else
+
+ /* Check if this is a locate device */
+ if (Device->DeviceType == LocateDevice)
{
- /* No memory, fail */
- Status = STATUS_NO_MEMORY;
+ EfiPrintf(L"Locates not yet supported\r\n");
+ return STATUS_NOT_SUPPORTED;
}
- }
- }
- /* All done */
- return Status;
-}
+ /* Make sure the caller's buffer can fit the device */
+ ReturnedLength = Size + sizeof(BcdDevice->AssociatedEntry);
+ if (ReturnedLength > *ElementSize)
+ {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ break;
+ }
-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;
-
- /* Make sure this is a BCD_DEVICE */
- if ((Type & 0xF000000) != 0x1000000)
- {
- return STATUS_INVALID_PARAMETER;
- }
+ /* It'll fit -- copy it in */
+ RtlCopyMemory(&ElementDevice->DeviceDescriptor, Device, Size);
+ ElementDevice->AssociatedEntry = BcdDevice->AssociatedEntry;
+ Status = STATUS_SUCCESS;
+ break;
- /* 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;
+ /* Strings -- they are stored as is */
+ case BCD_TYPE_STRING:
- /* Allocate a buffer to copy it into */
- DeviceDescriptor = BlMmAllocateHeap(DeviceSize);
- if (!DeviceDescriptor)
- {
- return STATUS_NO_MEMORY;
- }
+ /* Make sure the string isn't empty or misaligned */
+ if (!(DataLength) || (DataLength & 1))
+ {
+ return STATUS_OBJECT_TYPE_MISMATCH;
+ }
- /* Copy it into that buffer */
- RtlCopyMemory(DeviceDescriptor, &BcdDevice->DeviceDescriptor, DeviceSize);
- Status = STATUS_SUCCESS;
- }
+ /* Both the registry and BCD format are the same */
+ BcdString = (PWCHAR)Data;
+ ElementString = (PWCHAR)Element;
- /* 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);
+ /* We'll need as much data as the string has to offer */
+ ReturnedLength = DataLength;
- /* Allocate a buffer to hold them into */
- ListCopy = BlMmAllocateHeap(ListSize);
- if (!ListCopy)
+ /* If the string isn't NULL-terminated, do it now */
+ NullTerminate = FALSE;
+ if (BcdString[(DataLength / sizeof(WCHAR)) - 1] != UNICODE_NULL)
{
- Status = STATUS_NO_MEMORY;
- goto Quickie;
+ ReturnedLength += sizeof(UNICODE_NULL);
+ NullTerminate = TRUE;
}
- /* 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
+ /* Will we fit in the caller's buffer? */
+ if (ReturnedLength > *ElementSize)
+ {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ break;
+ }
- /* 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)
+ /* Yep -- copy it in, and NULL-terminate if needed */
+ RtlCopyMemory(Element, Data, DataLength);
+ if (NullTerminate)
{
- BlMmFreeHeap(DeviceDescriptor);
+ ElementString[DataLength / sizeof(WCHAR)] = UNICODE_NULL;
}
- }
- /* Check if we had a new list after filtering */
- if (SecureListData != ListCopy)
- {
- /* Yep -- if we had an old list, free it */
- if (ListCopy)
+ Status = STATUS_SUCCESS;
+ break;
+
+ /* Objects -- they are stored as GUID Strings */
+ case BCD_TYPE_OBJECT:
+
+ /* Registry data is a string, BCD data is a GUID */
+ BcdString = (PWCHAR)Data;
+ ElementGuid = (PGUID)Element;
+
+ /* We need a GUID-sized buffer, does the caller have one? */
+ ReturnedLength = sizeof(*ElementGuid);
+ if (*ElementSize < ReturnedLength)
{
- BlMmFreeHeap(ListCopy);
+ Status = STATUS_BUFFER_TOO_SMALL;
+ break;
}
- }
+
+ /* Yep, copy the GUID */
+ RtlInitUnicodeString(&GuidString, BcdString);
+ Status = RtlGUIDFromString(&GuidString, ElementGuid);
+ break;
- /* Finally, check if the caller wanted extra options */
- if (ExtraOptions)
- {
- /* Yep -- so pass the caller our copy */
- *ExtraOptions = ListCopy;
- ListCopy = NULL;
- }
+ /* Object Lists -- they are stored as arrays of GUID strings */
+ case BCD_TYPE_OBJECT_LIST:
- /* Caller always wants data back, so pass them our copy */
- *Value = DeviceDescriptor;
- DeviceDescriptor = NULL;
- }
+ /* Assume an empty list*/
+ ReturnedLength = 0;
+ Length = 0;
+ Status = STATUS_SUCCESS;
-Quickie:
- /* On the failure path, if these buffers are active, we should free them */
- if (ListCopy)
- {
- BlMmFreeHeap(ListCopy);
- }
- if (DeviceDescriptor)
- {
- BlMmFreeHeap(DeviceDescriptor);
- }
+ /* Registry data is an array of strings, BCD data is array of GUIDs */
+ BcdString = (PWCHAR)Data;
+ ElementGuid = (PGUID)Element;
- /* All done */
- return Status;
-}
+ /* Loop as long as the array still has strings */
+ while (*BcdString)
+ {
+ /* Don't read beyond the registry data */
+ if (Length >= DataLength)
+ {
+ break;
+ }
-NTSTATUS
-BlGetBootOptionInteger (
- _In_ PBL_BCD_OPTION List,
- _In_ ULONG Type,
- _Out_ PULONGLONG Value
- )
-{
- NTSTATUS Status;
- PBL_BCD_OPTION Option;
- //PGUID AppIdentifier;
+ /* One more GUID -- does the caller have space? */
+ ReturnedLength += sizeof(GUID);
+ if (ReturnedLength <= *ElementSize)
+ {
+ /* Convert and add it in */
+ RtlInitUnicodeString(&GuidString, BcdString);
+ Status = RtlGUIDFromString(&GuidString, ElementGuid);
+ if (!NT_SUCCESS(Status))
+ {
+ break;
+ }
+
+ /* Move to the next GUID in the caller's buffer */
+ ElementGuid++;
+ }
- /* Make sure this is a BCD_INTEGER */
- if ((Type & 0xF000000) != 0x5000000)
- {
- return STATUS_INVALID_PARAMETER;
- }
+ /* Move to the next string in the registry array */
+ Size = (wcslen(BcdString) * sizeof(WCHAR)) + sizeof(UNICODE_NULL);
+ Length += Size;
+ BcdString = (PWCHAR)((ULONG_PTR)BcdString + Length);
+ }
- /* Return the data */
- Option = MiscGetBootOption(List, Type);
- if (Option)
- {
- *Value = *(PULONGLONG)((ULONG_PTR)Option + Option->DataOffset);
- }
+ /* Check if we failed anywhere */
+ if (!NT_SUCCESS(Status))
+ {
+ break;
+ }
-#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;
-}
+ /* Check if we consumed more space than we have */
+ if (ReturnedLength > *ElementSize)
+ {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ }
-NTSTATUS
-BlGetBootOptionBoolean (
- _In_ PBL_BCD_OPTION List,
- _In_ ULONG Type,
- _Out_ PBOOLEAN Value
- )
-{
- NTSTATUS Status;
- PBL_BCD_OPTION Option;
- //PGUID AppIdentifier;
+ /* All good here */
+ break;
- /* Make sure this is a BCD_BOOLEAN */
- if ((Type & 0xF000000) != 0x6000000)
- {
- return STATUS_INVALID_PARAMETER;
- }
+ /* Integer -- stored as binary */
+ case BCD_TYPE_INTEGER:
- /* Return the data */
- Option = MiscGetBootOption(List, Type);
- if (Option)
- {
- *Value = *(PBOOLEAN)((ULONG_PTR)Option + Option->DataOffset);
- }
+ /* BCD data is a ULONGLONG, registry data is 8 bytes binary */
+ ElementInteger = (PULONGLONG)Element;
+ ReturnedLength = sizeof(*ElementInteger);
-#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;
-}
+ /* Make sure the registry data makes sense */
+ if (DataLength > ReturnedLength)
+ {
+ return STATUS_OBJECT_TYPE_MISMATCH;
+ }
-#define BI_FLUSH_HIVE 0x01
-#define BI_HIVE_WRITEABLE 0x02
+ /* Make sure the caller has space */
+ if (*ElementSize < ReturnedLength)
+ {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ break;
+ }
-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;
+ /* Write the integer result */
+ *ElementInteger = 0;
+ RtlCopyMemory(ElementInteger, Data, DataLength);
+ Status = STATUS_SUCCESS;
+ break;
-typedef struct _BI_KEY_OBJECT
-{
- PBI_KEY_HIVE KeyHive;
- PCM_KEY_NODE KeyNode;
- HCELL_INDEX KeyCell;
- PWCHAR KeyName;
-} BI_KEY_OBJECT, *PBI_KEY_OBJECT;
-
-PVOID
-NTAPI
-CmpAllocate (
- _In_ SIZE_T Size,
- _In_ BOOLEAN Paged,
- _In_ ULONG Tag
- )
-{
- UNREFERENCED_PARAMETER(Paged);
- UNREFERENCED_PARAMETER(Tag);
+ /* Boolean -- stored as binary */
+ case BCD_TYPE_BOOLEAN:
- /* Call the heap allocator */
- return BlMmAllocateHeap(Size);
-}
+ /* BCD data is a BOOLEAN, registry data is 2 bytes binary */
+ ElementWord = (PUSHORT)Element;
+ BcdBoolean = (PBOOLEAN)Data;
+ ReturnedLength = sizeof(ElementWord);
-VOID
-NTAPI
-CmpFree (
- _In_ PVOID Ptr,
- _In_ ULONG Quota
- )
-{
- UNREFERENCED_PARAMETER(Quota);
+ /* Make sure the registry data makes sense */
+ if (DataLength != sizeof(*BcdBoolean))
+ {
+ return STATUS_OBJECT_TYPE_MISMATCH;
+ }
- /* Call the heap allocator */
- BlMmFreeHeap(Ptr);
-}
+ /* Make sure the caller has space */
+ if (*ElementSize < ReturnedLength)
+ {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ break;
+ }
-FORCEINLINE
-VOID
-BiDereferenceHive (
- _In_ HANDLE KeyHandle
- )
-{
- PBI_KEY_OBJECT KeyObject;
+ /* Write the boolean result */
+ *ElementWord = 0;
+ *ElementWord = *BcdBoolean != 0;
+ Status = STATUS_SUCCESS;
+ break;
- /* Get the key object */
- KeyObject = (PBI_KEY_OBJECT)KeyHandle;
+ /* Integer list --stored as binary */
+ case BCD_TYPE_INTEGER_LIST:
- /* Drop a reference on the parent hive */
- --KeyObject->KeyHive->ReferenceCount;
-}
+ /* BCD Data is n ULONGLONGs, registry data is n*8 bytes binary */
+ ReturnedLength = DataLength;
+ if (!(DataLength) || (DataLength & 7))
+ {
+ return STATUS_OBJECT_TYPE_MISMATCH;
+ }
-VOID
-BiFlushHive (
- _In_ HANDLE KeyHandle
- )
-{
- /* Not yet implemented */
- EfiPrintf(L"NO reg flush\r\n");
- return;
-}
+ /* Make sure the caller has space */
+ if (*ElementSize < ReturnedLength)
+ {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ break;
+ }
-VOID
-BiCloseKey (
- _In_ HANDLE KeyHandle
- )
-{
- PBI_KEY_HIVE KeyHive;
- PBI_KEY_OBJECT KeyObject;
+ /* Write the integer list result */
+ RtlCopyMemory(Element, Data, DataLength);
+ Status = STATUS_SUCCESS;
+ break;
- /* Get the key object and hive */
- KeyObject = (PBI_KEY_OBJECT)KeyHandle;
- KeyHive = KeyObject->KeyHive;
+ /* Arbitrary data */
+ default:
- /* 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)
+ /* Registry data is copied binary as-is */
+ ReturnedLength = DataLength;
+
+ /* Make sure it's not empty */
+ if (!DataLength)
{
- BiFlushHive(KeyHandle);
+ return STATUS_OBJECT_TYPE_MISMATCH;
}
- /* Unmap the hive */
- //MmPapFreePages(KeyHive->ImageBase, 1);
- EfiPrintf(L"Leaking hive memory\r\n");
+ /* Make sure the caller has space */
+ if (*ElementSize < ReturnedLength)
+ {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ break;
+ }
- /* Free the hive and hive path */
- BlMmFreeHeap(KeyHive->FilePath);
- BlMmFreeHeap(KeyHive);
- }
+ /* Write the result */
+ RtlCopyMemory(Element, Data, DataLength);
+ Status = STATUS_SUCCESS;
+ break;
+ }
- /* Check if a key name is present */
- if (KeyObject->KeyName)
- {
- /* Free it */
- BlMmFreeHeap(KeyObject->KeyName);
- }
+ /* If we got here due to success or space issues, write the size */
+ if ((NT_SUCCESS(Status)) || (Status == STATUS_BUFFER_TOO_SMALL))
+ {
+ *ElementSize = ReturnedLength;
}
- /* Free the object */
- BlMmFreeHeap(KeyObject);
+ /* All done, return our conversion result */
+ return Status;
}
NTSTATUS
-BiOpenKey(
- _In_ HANDLE ParentHandle,
- _In_ PWCHAR KeyName,
- _Out_ PHANDLE Handle
+BiConvertBcdElements (
+ _In_ PBCD_PACKED_ELEMENT Elements,
+ _Out_opt_ PBCD_ELEMENT Buffer,
+ _Inout_ PULONG BufferSize,
+ _Inout_ PULONG ElementCount
)
{
- 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;
+ ULONG ElementSize, AlignedElementSize, AlignedDataSize;
+ PBCD_ELEMENT_HEADER Header;
+ PVOID Data;
+ BOOLEAN Exists;
+ ULONG i, j, Count;
- /* Convert from a handle to our key object */
- ParentKey = (PBI_KEY_OBJECT)ParentHandle;
+ /* Local variable to keep track of objects */
+ Count = 0;
- /* Extract the hive and node information */
- ParentHive = ParentKey->KeyHive;
- ParentNode = ParentKey->KeyNode;
- Hive = &ParentKey->KeyHive->Hive.Hive;
+ /* Safely compute the element bytes needed */
+ Status = RtlULongMult(*ElementCount, sizeof(BCD_ELEMENT), &ElementSize);
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
- /* Initialize variables */
- KeyCell = HCELL_NIL;
- Status = STATUS_SUCCESS;
- NameBuffer = NULL;
+ /* Safely align the element size */
+ Status = RtlULongAdd(ElementSize,
+ sizeof(ULONG) - 1,
+ &AlignedElementSize);
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+ AlignedElementSize = ALIGN_DOWN(AlignedElementSize, ULONG);
- /* Loop as long as there's still portions of the key name in play */
- NameLength = wcslen(KeyName);
- while (NameLength)
+ /* Do a safe version of Add2Ptr to figure out where the headers will start */
+ Status = RtlULongPtrAdd((ULONG_PTR)Buffer,
+ AlignedElementSize,
+ (PULONG_PTR)&Header);
+ if (!NT_SUCCESS(Status))
{
- /* 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;
- }
+ return Status;
+ }
- /* Free the name buffer from the previous pass if needed */
- if (NameBuffer)
- {
- BlMmFreeHeap(NameBuffer);
- }
+ /* Safely compute the header bytes needed */
+ Status = RtlULongMult(*ElementCount,
+ sizeof(BCD_ELEMENT_HEADER),
+ &ElementSize);
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
- /* 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;
- }
+ /* Safely align the header size */
+ Status = RtlULongAdd(ElementSize,
+ AlignedElementSize + sizeof(ULONG) - 1,
+ &AlignedElementSize);
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+ AlignedElementSize = ALIGN_DOWN(AlignedElementSize, ULONG);
- /* Copy and null-terminate the name of the subkey */
- RtlCopyMemory(NameBuffer, KeyName, NameBytes);
- NameBuffer[SubNameLength] = UNICODE_NULL;
+ /* Do a safe version of Add2Ptr */
+ Status = RtlULongPtrAdd((ULONG_PTR)Buffer,
+ AlignedElementSize,
+ (PULONG_PTR)&Data);
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
- /* Convert it into a UNICODE_STRING and try to find it */
- RtlInitUnicodeString(&KeyString, NameBuffer);
- KeyCell = CmpFindSubKeyByName(Hive, ParentNode, &KeyString);
- if (KeyCell == HCELL_NIL)
+ /* Iterate over every element */
+ for (i = 0; i < *ElementCount; i++)
+ {
+ /* Safely align the element size */
+ Status = RtlULongAdd(Elements->Size,
+ sizeof(ULONG) - 1,
+ &AlignedDataSize);
+ if (!NT_SUCCESS(Status))
{
- Status = STATUS_OBJECT_NAME_NOT_FOUND;
- goto Quickie;
+ break;
}
+ AlignedDataSize = ALIGN_DOWN(AlignedDataSize, ULONG);
- /* We found it -- get the key node out of it */
- ParentNode = (PCM_KEY_NODE)HvGetCell(Hive, KeyCell);
- if (!ParentNode)
+ /* Safely add the size of this data element */
+ Status = RtlULongAdd(AlignedElementSize,
+ AlignedDataSize,
+ &AlignedElementSize);
+ if (!NT_SUCCESS(Status))
{
- Status = STATUS_REGISTRY_CORRUPT;
- goto Quickie;
+ break;
}
- /* Update the key name to the next remaining path element */
- KeyName = NameStart;
- if (NameStart)
+ /* Do we have enough space left? */
+ if (*BufferSize >= AlignedElementSize)
{
- /* Update the length to the remainder of the path */
- NameLength += -1 - SubNameLength;
+ /* Check if our root is an inherited object */
+ Exists = FALSE;
+ if (Elements->RootType.PackedValue == BcdLibraryObjectList_InheritedObjects)
+ {
+ /* Yes, scan for us in the current buffer */
+ for (j = 0; j < Count; j++)
+ {
+ /* Do we already exist? */
+ while (Buffer[j].Header->Type == Elements->RootType.PackedValue)
+ {
+ /* Yep */
+ Exists = TRUE;
+ break;
+ }
+ }
+ }
+
+ /* Have we already found ourselves? */
+ if (!Exists)
+ {
+ /* Nope, one more entry */
+ ++Count;
+
+ /* Write out the unpacked object */
+ Buffer->Body = Data;
+ Buffer->Header = Header;
+
+ /* Fill out its header */
+ Header->Size = Elements->Size;
+ Header->Type = Elements->Type;
+ Header->Version = Elements->Version;
+
+ /* And copy the data */
+ RtlCopyMemory(Data, Elements->Data, Header->Size);
+
+ /* Move to the next unpacked object and header */
+ ++Buffer;
+ ++Header;
+
+ /* Move to the next data entry */
+ Data = (PVOID)((ULONG_PTR)Data + AlignedDataSize);
+ }
}
else
{
- /* There's nothing left, this was the leaf key */
- NameLength = 0;
+ /* Nope, set failure code, but keep going so we can return count */
+ Status = STATUS_BUFFER_TOO_SMALL;
}
+
+ /* Move to the next element entry */
+ Elements = Elements->NextEntry;
}
- /* Allocate a key object */
- NewKey = BlMmAllocateHeap(sizeof(*NewKey));
- if (!NewKey)
+ /* Return the new final buffer size and count */
+ *BufferSize = AlignedElementSize;
+ *ElementCount = Count;
+ return Status;
+}
+
+NTSTATUS
+BcdOpenObject (
+ _In_ HANDLE BcdHandle,
+ _In_ PGUID ObjectId,
+ _Out_ PHANDLE ObjectHandle
+ )
+{
+ NTSTATUS Status;
+ GUID LocalGuid;
+ UNICODE_STRING GuidString;
+ HANDLE RootObjectHandle;
+
+ /* Assume failure */
+ *ObjectHandle = NULL;
+
+ /* Initialize GUID string */
+ GuidString.Buffer = NULL;
+
+ /* Open the root "Objects" handle */
+ RootObjectHandle = NULL;
+ Status = BiOpenKey(BcdHandle, L"Objects", &RootObjectHandle);
+ if (!NT_SUCCESS(Status))
{
- /* 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;
+ /* Capture the object ID and convert it into a string */
+ LocalGuid = *ObjectId;
+ Status = RtlStringFromGUID(&LocalGuid, &GuidString);
+ if (!NT_SUCCESS(Status))
+ {
+ goto Quickie;
+ }
- /* Return the object back to the caller */
- *Handle = NewKey;
+ /* Now open the key containing this object ID */
+ Status = BiOpenKey(RootObjectHandle, GuidString.Buffer, ObjectHandle);
Quickie:
- /* If we had a name buffer, free it */
- if (NameBuffer)
+ /* Free the GUID string if we had one allocated */
+ if (GuidString.Buffer)
{
- BlMmFreeHeap(NameBuffer);
+ RtlFreeUnicodeString(&GuidString);
}
- /* Return status of the open operation */
+ /* Close the root handle if it was open */
+ if (RootObjectHandle)
+ {
+ BiCloseKey(RootObjectHandle);
+ }
+
+ /* Return the final status */
return Status;
}
-BOOLEAN BiHiveHashLibraryInitialized;
-ULONGLONG HvSymcryptSeed;
-
-BOOLEAN
-HvIsInPlaceBaseBlockValid (
- _In_ PHBASE_BLOCK BaseBlock
+NTSTATUS
+BiEnumerateSubElements (
+ _In_ HANDLE BcdHandle,
+ _In_ PVOID Object,
+ _In_ ULONG ElementType,
+ _In_ ULONG Flags,
+ _Out_opt_ PBCD_PACKED_ELEMENT* Elements,
+ _Inout_ PULONG ElementSize,
+ _Out_ PULONG ElementCount
)
{
- ULONG HiveLength, HeaderSum;
- BOOLEAN Valid;
+ NTSTATUS Status;
+ PBCD_PACKED_ELEMENT Element;
+ HANDLE ObjectHandle;
+ ULONG ParsedElements, RequiredSize;
+
+ /* Assume empty */
+ *ElementCount = 0;
+ RequiredSize = 0;
+ ParsedElements = 0;
+
+ /* Open the object */
+ Status = BcdOpenObject(BcdHandle, Object, &ObjectHandle);
+ if (!NT_SUCCESS(Status))
+ {
+ goto Quickie;
+ }
- /* 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))
+ /* Read the first entry, and the size available */
+ Element = *Elements;
+ RequiredSize = *ElementSize;
+
+ /* Enumerate the object into the element array */
+ Status = BiEnumerateElements(BcdHandle,
+ ObjectHandle,
+ ElementType,
+ Flags,
+ Element,
+ &RequiredSize,
+ &ParsedElements);
+
+ /* Close the handle and bail out if we couldn't enumerate */
+ BiCloseKey(ObjectHandle);
+ if (!NT_SUCCESS(Status))
+ {
+ goto Quickie;
+ }
+
+ /* Check if the and subelements were present */
+ if (ParsedElements)
{
- /* Check for invalid hive size */
- HiveLength = BaseBlock->Length;
- if (HiveLength)
+ /* Keep going until the last one */
+ while (Element->NextEntry)
{
- /* 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;
- }
- }
+ Element = Element->NextEntry;
}
+
+ /* Set the new buffer location to the last element */
+ *Elements = Element;
}
- /* Return validity */
- return Valid;
+Quickie:
+ /* Return the number of sub-elements and their size */
+ *ElementCount = ParsedElements;
+ *ElementSize = RequiredSize;
+ return Status;
}
NTSTATUS
-BiInitializeAndValidateHive (
- _In_ PBI_KEY_HIVE Hive
+BiEnumerateSubObjectElements (
+ _In_ HANDLE BcdHandle,
+ _Out_ PGUID SubObjectList,
+ _In_ ULONG SubObjectCount,
+ _In_ ULONG Flags,
+ _Out_opt_ PBCD_PACKED_ELEMENT Elements,
+ _Inout_ PULONG ElementSize,
+ _Out_ PULONG ElementCount
)
{
- ULONG HiveSize;
NTSTATUS Status;
+ ULONG SubElementCount, TotalSize, RequiredSize, CurrentSize, i;
+ PBCD_PACKED_ELEMENT PreviousElement;
+
+ /* Assume empty list */
+ *ElementCount = 0;
+ Status = STATUS_SUCCESS;
+
+ /* Initialize variables */
+ TotalSize = 0;
+ PreviousElement = NULL;
- /* Make sure the hive is at least the size of a base block */
- if (Hive->HiveSize < sizeof(HBASE_BLOCK))
+ /* Set the currently remaining size based on caller's input */
+ CurrentSize = *ElementSize;
+
+ /* Iterate over every subje object */
+ for (i = 0; i < SubObjectCount; i++)
{
- return STATUS_REGISTRY_CORRUPT;
+ /* Set the currently remaining buffer space */
+ RequiredSize = CurrentSize;
+
+ /* Enumerate the inherited sub elements */
+ Status = BiEnumerateSubElements(BcdHandle,
+ &SubObjectList[i],
+ BcdLibraryObjectList_InheritedObjects,
+ Flags,
+ &Elements,
+ &RequiredSize,
+ &SubElementCount);
+ if ((NT_SUCCESS(Status)) || (Status == STATUS_BUFFER_TOO_SMALL))
+ {
+ /* Safely add the length of the sub elements */
+ Status = RtlULongAdd(TotalSize, RequiredSize, &TotalSize);
+ if (!NT_SUCCESS(Status))
+ {
+ break;
+ }
+
+ /* Add the sub elements to the total */
+ *ElementCount += SubElementCount;
+
+ /* See if we have enough space*/
+ if (*ElementSize >= TotalSize)
+ {
+ /* Were there any subelements? */
+ if (SubElementCount)
+ {
+ /* Update to keep track of these new subelements */
+ CurrentSize = *ElementSize - TotalSize;
+
+ /* Link the subelements into the chain */
+ PreviousElement = Elements;
+ PreviousElement->NextEntry =
+ (PBCD_PACKED_ELEMENT)((ULONG_PTR)Elements + TotalSize);
+ Elements = PreviousElement->NextEntry;
+ }
+ }
+ else
+ {
+ /* We're out of space */
+ CurrentSize = 0;
+ }
+ }
+ else if ((Status != STATUS_NOT_FOUND) &&
+ (Status != STATUS_OBJECT_NAME_NOT_FOUND))
+ {
+ /* Some other fatal error, break out */
+ break;
+ }
+ else
+ {
+ /* The sub element was not found, print a warning but keep going */
+ BlStatusPrint(L"Ignoring missing BCD inherit object: {%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\n",
+ (&SubObjectList[i])->Data1,
+ (&SubObjectList[i])->Data2,
+ (&SubObjectList[i])->Data3,
+ (&SubObjectList[i])->Data4[0],
+ (&SubObjectList[i])->Data4[1],
+ (&SubObjectList[i])->Data4[2],
+ (&SubObjectList[i])->Data4[3],
+ (&SubObjectList[i])->Data4[4],
+ (&SubObjectList[i])->Data4[5],
+ (&SubObjectList[i])->Data4[6],
+ (&SubObjectList[i])->Data4[7],
+ (&SubObjectList[i])->Data4[8]);
+ Status = STATUS_SUCCESS;
+ }
}
- /* 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))
+ /* Terminate the last element, if one was left */
+ if (PreviousElement)
{
- return STATUS_REGISTRY_CORRUPT;
+ PreviousElement->NextEntry = NULL;
}
- /* 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))
+ /* Set failure code if we ran out of space */
+ if (*ElementSize < TotalSize)
{
- /* Cleanup volatile/old data */
- CmPrepareHive(&Hive->Hive.Hive); // CmCheckRegistry
- Status = STATUS_SUCCESS;
+ Status = STATUS_BUFFER_TOO_SMALL;
}
- /* Return the final status */
+ /* Return final length and status */
+ *ElementSize = TotalSize;
return Status;
}
NTSTATUS
-BiLoadHive (
- _In_ PBL_FILE_PATH_DESCRIPTOR FilePath,
- _Out_ PHANDLE HiveHandle
+BiEnumerateElements (
+ _In_ HANDLE BcdHandle,
+ _In_ HANDLE ObjectHandle,
+ _In_ ULONG RootElementType,
+ _In_ ULONG Flags,
+ _Out_opt_ PBCD_PACKED_ELEMENT Elements,
+ _Inout_ PULONG ElementSize,
+ _Out_ PULONG ElementCount
)
{
- 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;
+ HANDLE ElementsHandle, ElementHandle;
+ ULONG TotalLength, RegistryElementDataLength, RemainingLength;
NTSTATUS Status;
- PVOID LogData;
- PHHIVE Hive;
- UNICODE_STRING KeyString;
- PCM_KEY_NODE RootNode;
- HCELL_INDEX CellIndex;
+ ULONG i;
+ PVOID ElementData, SubObjectList, RegistryElementData;
+ BcdElementType ElementType;
+ PBCD_PACKED_ELEMENT PreviousElement;
+ ULONG SubElementCount, SubKeyCount, SubObjectCount, ElementDataLength;
+ PWCHAR ElementName;
+ PWCHAR* SubKeys;
- /* Initialize variables */
- DeviceId = -1;
- BaseBlock = NULL;
- BcdHive = NULL;
- KeyObject = NULL;
- LogData = NULL;
- LogName = NULL;
-
- /* Initialize the crypto seed */
- if (!BiHiveHashLibraryInitialized)
+ /* Assume failure */
+ *ElementCount = 0;
+
+ /* Initialize all locals that are checked at the end*/
+ SubKeys = NULL;
+ ElementsHandle = NULL;
+ ElementHandle = NULL;
+ ElementData = NULL;
+ RegistryElementData = NULL;
+ PreviousElement = NULL;
+ ElementName = NULL;
+ SubObjectList = NULL;
+ TotalLength = 0;
+ ElementDataLength = 0;
+ SubObjectCount = 0;
+ RemainingLength = 0;
+
+ /* Open the root object key's elements */
+ Status = BiOpenKey(ObjectHandle, L"Elements", &ElementsHandle);
+ if (!NT_SUCCESS(Status))
{
- HvSymcryptSeed = 0x82EF4D887A4E55C5;
- BiHiveHashLibraryInitialized = TRUE;
+ goto Quickie;
}
- /* 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)
+ /* Enumerate all elements */
+ Status = BiEnumerateSubKeys(ElementsHandle, &SubKeys, &SubKeyCount);
+ if (!NT_SUCCESS(Status))
{
- /* 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))
+ /* Iterate over each one */
+ for (i = 0; i < SubKeyCount; i++)
{
- /* Try for RO access instead */
- HaveWriteAccess = FALSE;
- Status = BlpDeviceOpen(BcdDevice, BL_DEVICE_READ_ACCESS, 0, &DeviceId);
+ /* Open the element */
+ ElementName = SubKeys[i];
+ Status = BiOpenKey(ElementsHandle, ElementName, &ElementHandle);
if (!NT_SUCCESS(Status))
{
- /* No access at all -- bail out */
- goto Quickie;
+ break;
}
- }
- /* 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;
- }
+ /* The name of the element is its data type */
+ ElementType.PackedValue = wcstoul(SubKeys[i], NULL, 16);
+ if (!(ElementType.PackedValue) || (ElementType.PackedValue == -1))
+ {
+ EfiPrintf(L"Value invald\r\n");
+ BiCloseKey(ElementHandle);
+ ElementHandle = 0;
+ continue;
+ }
- /* Initialize it */
- RtlZeroMemory(BcdHive, sizeof(*BcdHive));
- BcdHive->BaseBlock = BaseBlock;
- BcdHive->HiveSize = HiveSize;
- if (HaveWriteAccess)
- {
- BcdHive->Flags |= BI_HIVE_WRITEABLE;
- }
+ /* Read the appropriate registry value type for this element */
+ Status = BiGetRegistryValue(ElementHandle,
+ L"Element",
+ NULL,
+ BiConvertElementFormatToValueType(
+ ElementType.Format),
+ &RegistryElementData,
+ &RegistryElementDataLength);
+ if (!NT_SUCCESS(Status))
+ {
+ break;
+ }
- /* Make sure the hive was at least one bin long */
- if (HiveSize < sizeof(*BaseBlock))
- {
- Status = STATUS_REGISTRY_CORRUPT;
- goto Quickie;
- }
+ /* Now figure out how much space the converted element will need */
+ ElementDataLength = 0;
+ Status = BiConvertRegistryDataToElement(ObjectHandle,
+ RegistryElementData,
+ RegistryElementDataLength,
+ ElementType,
+ NULL,
+ &ElementDataLength);
+ if (Status != STATUS_BUFFER_TOO_SMALL)
+ {
+ break;
+ }
- /* 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;
- }
+ /* Allocate a buffer big enough for the converted element */
+ ElementData = BlMmAllocateHeap(ElementDataLength);
+ if (!ElementData)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
- /* Validate the initial bin (the base block) */
- if (!HvIsInPlaceBaseBlockValid(BaseBlock))
- {
- EfiPrintf(L"Recovery not implemented\r\n");
- Status = STATUS_REGISTRY_CORRUPT;
- goto Quickie;
- }
+ /* And actually convert it this time around */
+ Status = BiConvertRegistryDataToElement(ObjectHandle,
+ RegistryElementData,
+ RegistryElementDataLength,
+ ElementType,
+ ElementData,
+ &ElementDataLength);
+ if (!NT_SUCCESS(Status))
+ {
+ break;
+ }
- /* 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;
- }
+ /* Safely add space for the packed element header */
+ Status = RtlULongAdd(TotalLength,
+ FIELD_OFFSET(BCD_PACKED_ELEMENT, Data),
+ &TotalLength);
+ if (!NT_SUCCESS(Status))
+ {
+ break;
+ }
- /*
- * 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);
+ /* Safely add space for the data of the element itself */
+ Status = RtlULongAdd(TotalLength, ElementDataLength, &TotalLength);
if (!NT_SUCCESS(Status))
{
- goto Quickie;
+ break;
}
- /* Copy the current data in there */
- RtlCopyMemory(NewBaseBlock, BaseBlock, HiveSize);
+ /* One more element */
+ ++*ElementCount;
- /* Free the old data */
- EfiPrintf(L"Leaking old hive buffer\r\n");
- //MmPapFreePages(BaseBlock, 1);
+ /* See how much space we were given */
+ RemainingLength = *ElementSize;
+ if (RemainingLength >= TotalLength)
+ {
+ /* Set the next pointer */
+ Elements->NextEntry = (PBCD_PACKED_ELEMENT)((ULONG_PTR)Elements + TotalLength);
+
+ /* Fill this one out */
+ Elements->RootType.PackedValue = RootElementType;
+ Elements->Version = 1;
+ Elements->Type = ElementType.PackedValue;
+ Elements->Size = ElementDataLength;
+
+ /* Add the data */
+ RtlCopyMemory(Elements->Data, ElementData, ElementDataLength);
+ RemainingLength -= TotalLength;
+
+ /* Move to the next element on the next pass */
+ PreviousElement = Elements;
+ Elements = Elements->NextEntry;
+ }
+ else
+ {
+ /* We're out of space */
+ RemainingLength = 0;
+ }
- /* Update our pointers */
- BaseBlock = NewBaseBlock;
- HiveSize = NewHiveSize;
- BcdHive->BaseBlock = BaseBlock;
- BcdHive->HiveSize = HiveSize;
+ /* Are we enumerating devices, and is this a device? */
+ if ((Flags & BCD_ENUMERATE_FLAG_DEVICES) &&
+ (ElementType.Format == BCD_TYPE_DEVICE))
+ {
+ /* Yep, so go inside to enumerate it */
+ Status = BiEnumerateSubElements(BcdHandle,
+ ElementData,
+ ElementType.PackedValue,
+ Flags,
+ &Elements,
+ &ElementDataLength,
+ &SubElementCount);
+ if ((NT_SUCCESS(Status)) || (Status == STATUS_BUFFER_TOO_SMALL))
+ {
+ /* Safely add the length of the sub elements */
+ Status = RtlULongAdd(TotalLength,
+ ElementDataLength,
+ &TotalLength);
+ if (!NT_SUCCESS(Status))
+ {
+ break;
+ }
+
+ /* Add the sub elements to the total */
+ *ElementCount += SubElementCount;
+
+ /* See if we have enough space*/
+ if (*ElementSize >= TotalLength)
+ {
+ /* Were there any subelements? */
+ if (SubElementCount)
+ {
+ /* Update to keep track of these new subelements */
+ ElementDataLength = *ElementSize - TotalLength;
+
+ /* Link the subelements into the chain */
+ PreviousElement = Elements;
+ PreviousElement->NextEntry =
+ (PBCD_PACKED_ELEMENT)((ULONG_PTR)Elements +
+ TotalLength);
+ Elements = PreviousElement->NextEntry;
+ }
+ }
+ else
+ {
+ /* We're out of space */
+ ElementDataLength = 0;
+ }
+ }
+ else if ((Status != STATUS_NOT_FOUND) &&
+ (Status != STATUS_OBJECT_NAME_NOT_FOUND))
+ {
+ /* Fatal error trying to read the data, so fail */
+ break;
+ }
+ }
+ else if ((Flags & BCD_ENUMERATE_FLAG_DEEP) &&
+ (ElementType.PackedValue == BcdLibraryObjectList_InheritedObjects))
+ {
+ /* Inherited objects are requsted, so allocate a buffer for them */
+ SubObjectList = BlMmAllocateHeap(ElementDataLength);
+ if (!SubObjectList)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+
+ /* Copy the elements into the list. They are arrays of GUIDs */
+ RtlCopyMemory(SubObjectList, ElementData, ElementDataLength);
+ SubObjectCount = ElementDataLength / sizeof(GUID);
+ }
+
+ /* Free our local buffers */
+ BlMmFreeHeap(ElementData);
+ BlMmFreeHeap(RegistryElementData);
+ ElementData = NULL;
+ RegistryElementData = NULL;
+
+ /* Close the key */
+ BiCloseKey(ElementHandle);
+ ElementHandle = NULL;
+ ElementName = NULL;
}
- /* Check if any log stuff needs to happen */
- if (LogData)
+ /* Did we end up here with a sub object list after successful loop parsing? */
+ if ((i != 0) && (i == SubKeyCount) && (SubObjectList))
{
- EfiPrintf(L"Log fix not implemented: %lx %lx\r\n");
- Status = STATUS_REGISTRY_CORRUPT;
- goto Quickie;
+ /* We will actually enumerate it now, at the end */
+ Status = BiEnumerateSubObjectElements(BcdHandle,
+ SubObjectList,
+ SubObjectCount,
+ Flags,
+ Elements,
+ &RemainingLength,
+ &SubElementCount);
+ if ((NT_SUCCESS(Status)) || (Status == STATUS_BUFFER_TOO_SMALL))
+ {
+ /* Safely add the length of the sub elements */
+ Status = RtlULongAdd(TotalLength, RemainingLength, &TotalLength);
+ if ((NT_SUCCESS(Status)) && (SubElementCount))
+ {
+ /* Add the sub elements to the total */
+ *ElementCount += SubElementCount;
+
+ /* Don't touch PreviousElement anymore */
+ PreviousElement = NULL;
+ }
+ }
}
- /* Call Hv to setup the hive library */
- Status = BiInitializeAndValidateHive(BcdHive);
- if (!NT_SUCCESS(Status))
+Quickie:
+ /* Free the sub object list, if any */
+ if (SubObjectList)
{
- goto Quickie;
+ BlMmFreeHeap(SubObjectList);
}
- /* Now get the root node */
- Hive = &BcdHive->Hive.Hive;
- RootNode = (PCM_KEY_NODE)HvGetCell(Hive, Hive->BaseBlock->RootCell);
- if (!RootNode)
+ /* Free any local element data */
+ if (ElementData)
{
- Status = STATUS_OBJECT_NAME_NOT_FOUND;
- goto Quickie;
+ BlMmFreeHeap(ElementData);
}
- /* 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)
+ /* Free any local registry data */
+ if (RegistryElementData)
{
- EfiPrintf(L"No OBJECTS subkey found!\r\n");
- Status = STATUS_OBJECT_NAME_NOT_FOUND;
- goto Quickie;
+ BlMmFreeHeap(RegistryElementData);
}
- /* 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)
+ /* Close the handle if still opened */
+ if (ElementHandle)
{
- Status = STATUS_NO_MEMORY;
- goto Quickie;
+ BiCloseKey(ElementHandle);
}
- /* 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)
+ /* Terminate the last element, if any */
+ if (PreviousElement)
{
- Status = STATUS_NO_MEMORY;
- goto Quickie;
+ PreviousElement->NextEntry = NULL;
}
- /* 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)
+ /* Close the root handle if still opened */
+ if (ElementsHandle)
{
- BlMmFreeHeap(LogName);
+ BiCloseKey(ElementsHandle);
}
- /* If we had logging data, free it */
- if (LogData)
+ /* Set failure code if out of space */
+ if (*ElementSize < TotalLength)
{
- EfiPrintf(L"Leaking log buffer\r\n");
- //MmPapFreePages(LogData, 1);
+ Status = STATUS_BUFFER_TOO_SMALL;
}
- /* Check if this is the failure path */
- if (!NT_SUCCESS(Status))
+ /* Other errors will send a notification error */
+ if (!(NT_SUCCESS(Status)) && (Status != STATUS_BUFFER_TOO_SMALL))
{
- /* 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);
- }
+ BiNotifyEnumerationError(ObjectHandle, ElementName, Status);
+ }
- /* Finally, free the root key object if we created one */
- if (KeyObject)
- {
- BlMmFreeHeap(KeyObject);
- }
+ /* Finally free the subkeys array */
+ if (SubKeys)
+ {
+ BlMmFreeHeap(SubKeys);
}
- /* Return the final status */
+ /* And return the required, final length and status */
+ *ElementSize = TotalLength;
return Status;
}
return Status;
}
+NTSTATUS
+BcdEnumerateAndUnpackElements (
+ _In_ HANDLE BcdHandle,
+ _In_ HANDLE ObjectHandle,
+ _Out_opt_ PBCD_ELEMENT Elements,
+ _Inout_ PULONG ElementSize,
+ _Out_ PULONG ElementCount
+ )
+{
+ PVOID LocalElements;
+ NTSTATUS Status;
+ ULONG LocalElementCount, LocalElementSize;
+
+ /* Make sure required parameters are there */
+ if (!(ElementSize) || !(ElementCount) || ((Elements) && (!*ElementSize)))
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ /* Set initial count to zero */
+ *ElementCount = 0;
+
+ /* Do the initial enumeration to figure out the size required */
+ LocalElementSize = 0;
+ LocalElementCount = 0;
+ Status = BiEnumerateElements(BcdHandle,
+ ObjectHandle,
+ 0,
+ BCD_ENUMERATE_FLAG_IN_ORDER |
+ BCD_ENUMERATE_FLAG_DEVICES |
+ BCD_ENUMERATE_FLAG_DEEP,
+ NULL,
+ &LocalElementSize,
+ &LocalElementCount);
+ if (Status != STATUS_BUFFER_TOO_SMALL)
+ {
+ return Status;
+ }
+
+ /* Now allocate a buffer large enough to hold them */
+ LocalElements = BlMmAllocateHeap(LocalElementSize);
+ if (!LocalElements)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ /* Zero out the array and do the real enumeration this time around */
+ RtlZeroMemory(LocalElements, LocalElementSize);
+ Status = BiEnumerateElements(BcdHandle,
+ ObjectHandle,
+ 0,
+ BCD_ENUMERATE_FLAG_IN_ORDER |
+ BCD_ENUMERATE_FLAG_DEVICES |
+ BCD_ENUMERATE_FLAG_DEEP,
+ LocalElements,
+ &LocalElementSize,
+ &LocalElementCount);
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+
+ /* Now we know the real count */
+ *ElementCount = LocalElementCount;
+
+ /* Now unpack the data */
+ Status = BiConvertBcdElements(LocalElements,
+ Elements,
+ ElementSize,
+ &LocalElementCount);
+ if (NT_SUCCESS(Status))
+ {
+ /* Not all elements may have been converted */
+ *ElementCount = LocalElementCount;
+ }
+
+ /* Free the local (unpacked) buffer and return status */
+ BlMmFreeHeap(LocalElements);
+ return Status;
+}
+
NTSTATUS
BcdOpenStoreFromFile (
_In_ PUNICODE_STRING FileName,
- _In_ PHANDLE StoreHandle
+ _In_ PHANDLE BcdHandle
)
{
ULONG Length;
if (NT_SUCCESS(Status))
{
/* Return the handle on success */
- *StoreHandle = LocalHandle;
+ *BcdHandle = LocalHandle;
}
/* Free the descriptor and return the status */
--- /dev/null
+/*
+ * 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;
+}
+
--- /dev/null
+/*
+ * 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;
+}
+
/* INCLUDES ******************************************************************/
#include "bl.h"
+#include "bcd.h"
/* DATA VARIABLES ************************************************************/
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;
}
/* INCLUDES ******************************************************************/
#include "bl.h"
-
+#include "bcd.h"
typedef struct _BL_PA_REQUEST
{
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;
}