[BOOTLIB]: Separate out bcd.c into bcdopt.c, bootreg.c and bcd.c
authorAlex Ionescu <aionescu@gmail.com>
Tue, 5 Jan 2016 06:09:22 +0000 (06:09 +0000)
committerAlex Ionescu <aionescu@gmail.com>
Tue, 5 Jan 2016 06:09:22 +0000 (06:09 +0000)
[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

12 files changed:
reactos/boot/environ/CMakeLists.txt
reactos/boot/environ/app/bootmgr/bootmgr.c
reactos/boot/environ/app/bootmgr/bootmgr.h
reactos/boot/environ/include/bcd.h
reactos/boot/environ/include/bl.h
reactos/boot/environ/lib/bootlib.c
reactos/boot/environ/lib/io/display/display.c
reactos/boot/environ/lib/misc/bcd.c
reactos/boot/environ/lib/misc/bcdopt.c [new file with mode: 0644]
reactos/boot/environ/lib/misc/bootreg.c [new file with mode: 0644]
reactos/boot/environ/lib/mm/mm.c
reactos/boot/environ/lib/mm/pagealloc.c

index b790ab3..e7dc32b 100644 (file)
@@ -12,6 +12,8 @@ list(APPEND BOOTLIB_SOURCE
      lib/bootlib.c
      lib/misc/debug.c
      lib/misc/bcd.c
+     lib/misc/bcdopt.c
+     lib/misc/bootreg.c
      lib/misc/util.c
      lib/misc/image.c
      lib/firmware/efi/firmware.c
index bf1e305..2e80c18 100644 (file)
@@ -31,8 +31,197 @@ BOOLEAN BmBootIniUsed;
 WCHAR BmpFileNameBuffer[128];
 PWCHAR ParentFileName = L"";
 
+BOOLEAN BmDisplayStateCached;
+
 /* FUNCTIONS *****************************************************************/
 
+NTSTATUS
+BmGetOptionList (
+    _In_ HANDLE BcdHandle,
+    _In_ PGUID ObjectId,
+    _In_ PBL_BCD_OPTION *OptionList
+    )
+{
+    NTSTATUS Status;
+    HANDLE ObjectHandle;
+    ULONG ElementSize, ElementCount, i, OptionsSize;
+    BcdElementType Type;
+    PBCD_ELEMENT_HEADER Header;
+    PBCD_ELEMENT BcdElements;
+    PBL_BCD_OPTION Options, Option, PreviousOption, DeviceOptions;
+    PBCD_DEVICE_OPTION DeviceOption;
+    GUID DeviceId;
+    PVOID DeviceData;
+
+    /* Open the BCD object requested */
+    ObjectHandle = NULL;
+    BcdElements = NULL;
+    Status = BcdOpenObject(BcdHandle, ObjectId, &ObjectHandle);
+    if (!NT_SUCCESS(Status))
+    {
+        goto Quickie;
+    }
+
+    /* Do the initial enumeration to get the size needed */
+    ElementSize = 0;
+    Status = BcdEnumerateAndUnpackElements(BcdHandle,
+                                           ObjectHandle,
+                                           NULL,
+                                           &ElementSize,
+                                           &ElementCount);
+    if (Status != STATUS_BUFFER_TOO_SMALL)
+    {
+        /* If we got success, that doesn't make any sense */
+        if (NT_SUCCESS(Status))
+        {
+            Status = STATUS_INVALID_PARAMETER;
+        }
+
+        /* Bail out */
+        goto Quickie;
+    }
+
+    /* Allocate a large-enough buffer */
+    BcdElements = BlMmAllocateHeap(ElementSize);
+    if (!BcdElements)
+    {
+        Status = STATUS_NO_MEMORY;
+        goto Quickie;
+    }
+
+    /* Now do the real enumeration to fill out the elements buffer */
+    Status = BcdEnumerateAndUnpackElements(BcdHandle,
+                                           ObjectHandle,
+                                           BcdElements,
+                                           &ElementSize,
+                                           &ElementCount);
+    if (!NT_SUCCESS(Status))
+    {
+        goto Quickie;
+    }
+
+    /* Go through each BCD option to add the sizes up */
+    OptionsSize = 0;
+    for (i = 0; i < ElementCount; i++)
+    {
+        OptionsSize += BcdElements[i].Header->Size + sizeof(BL_BCD_OPTION);
+    }
+
+    /* Allocate the required BCD option list */
+    Options = BlMmAllocateHeap(OptionsSize);
+    if (!Options)
+    {
+        Status = STATUS_NO_MEMORY;
+        goto Quickie;
+    }
+
+    /* Zero it out */
+    RtlZeroMemory(Options, OptionsSize);
+
+    /* Start going through each option */
+    PreviousOption = NULL;
+    Option = Options;
+    EfiPrintf(L"BCD Options found: %d\r\n", ElementCount);
+    for (i = 0; i < ElementCount; i++)
+    {
+        /* Read the header and type */
+        Header = BcdElements[i].Header;
+        Type.PackedValue = Header->Type;
+
+        /* Check if this option isn't already present */
+        if (!MiscGetBootOption(Options, Type.PackedValue))
+        {
+            /* It's a new option. Did we have an existing one? */
+            if (PreviousOption)
+            {
+                /* Link it to this new one */
+                PreviousOption->NextEntryOffset = (ULONG_PTR)Option -
+                                                  (ULONG_PTR)Options;
+            }
+
+            /* Capture the type, size, data, and offset */
+            Option->Type = Type.PackedValue;
+            Option->DataSize = Header->Size;
+            RtlCopyMemory(Option + 1, BcdElements[i].Body, Header->Size);
+            Option->DataOffset = sizeof(BL_BCD_OPTION);
+
+            /* Check if this was a device */
+            if (Type.Format == BCD_TYPE_DEVICE)
+            {
+                /* Grab its GUID */
+                DeviceOption = (PBCD_DEVICE_OPTION)(Option + 1);
+                DeviceId = DeviceOption->AssociatedEntry;
+
+                /* Look up the options for that GUID */
+                Status = BmGetOptionList(BcdHandle, &DeviceId, &DeviceOptions);
+                if (NT_SUCCESS(Status))
+                {
+                    /* Device data is after the device option */
+                    DeviceData = (PVOID)((ULONG_PTR)DeviceOption + Header->Size);
+
+                    /* Copy it */
+                    RtlCopyMemory(DeviceData,
+                                  DeviceOptions,
+                                  BlGetBootOptionListSize(DeviceOptions));
+
+                    /* Don't need this anymore */
+                    BlMmFreeHeap(DeviceOptions);
+
+                    /* Write the offset of the device options */
+                    Option->ListOffset = (ULONG_PTR)DeviceData -
+                                         (ULONG_PTR)Option;
+                }
+            }
+
+            /* Save the previous option and go to the next one */
+            PreviousOption = Option;
+            Option = (PBL_BCD_OPTION)((ULONG_PTR)Option +
+                                      BlGetBootOptionSize(Option));
+        }
+    }
+
+    /* Return the pointer back, we've made it! */
+    *OptionList = Options;
+    Status = STATUS_SUCCESS;
+
+Quickie:
+    /* Did we allocate a local buffer? Free it if so */
+    if (BcdElements)
+    {
+        BlMmFreeHeap(BcdElements);
+    }
+
+    /* Was the key open? Close it if so */
+    if (ObjectHandle)
+    {
+        BiCloseKey(ObjectHandle);
+    }
+
+    /* Return the option list parsing status */
+    return Status;
+}
+
+NTSTATUS
+BmpUpdateApplicationOptions (
+    _In_ HANDLE BcdHandle
+    )
+{
+    NTSTATUS Status;
+    PBL_BCD_OPTION Options;
+
+    /* Get the boot option list */
+    Status = BmGetOptionList(BcdHandle, &BmApplicationIdentifier, &Options);
+    if (!NT_SUCCESS(Status))
+    {
+        return Status;
+    }
+
+    /* Append the options, free the local buffer, and return success */
+    BlAppendBootOptions(&BlpApplicationEntry, Options);
+    BlMmFreeHeap(Options);
+    return STATUS_SUCCESS;
+}
+
 NTSTATUS
 BmpFwGetApplicationDirectoryPath (
     _In_ PUNICODE_STRING ApplicationDirectoryPath
@@ -65,39 +254,14 @@ BmpFwGetApplicationDirectoryPath (
         }
 
         /* Check if we have space for one more character */
-        AppPathLength = i + 1;
-        if (AppPathLength < i)
-        {
-            /* Nope, we'll overflow */
-            AppPathLength = -1;
-            Status = STATUS_INTEGER_OVERFLOW;
-        }
-        else
-        {
-            /* Go ahead */
-            Status = STATUS_SUCCESS;
-        }
-
-        /* No overflow? */
+        Status = RtlULongAdd(i, 1, &AppPathLength);
         if (NT_SUCCESS(Status))
         {
             /* Check if it's safe to multiply by two */
-            if ((AppPathLength * sizeof(WCHAR)) > 0xFFFFFFFF)
-            {
-                /* Nope */
-                AppPathLength = -1;
-                Status = STATUS_INTEGER_OVERFLOW;
-            }
-            else
-            {
-                /* We're good, do the multiplication */
-                Status = STATUS_SUCCESS;
-                AppPathLength *= sizeof(WCHAR);
-            }
-
-            /* Allocate a copy for the string */
+            Status = RtlULongMult(AppPathLength, sizeof(WCHAR), &AppPathLength);
             if (NT_SUCCESS(Status))
             {
+                /* Allocate a copy for the string */
                 PathCopy = BlMmAllocateHeap(AppPathLength);
                 if (PathCopy)
                 {
@@ -382,6 +546,38 @@ BmFatalErrorEx (
             ErrorResourceId = 9002;
             break;
 
+        case BL_FATAL_ERROR_BCD_PARSE:
+
+            /* File name isin parameter 1 */
+            FileName = (PWCHAR)Parameter1;
+
+            /* The NTSTATUS code is in parameter 2*/
+            ErrorStatus = (NTSTATUS)Parameter2;
+
+            /* Build the error string */
+            swprintf(FormatString,
+                     L"\nThe boot configuration file %s is invalid (%08x).\n",
+                     FileName,
+                     ErrorStatus);
+
+            /* Select the resource ID message */
+            ErrorResourceId = 9015;
+            break;
+
+        case BL_FATAL_ERROR_GENERIC:
+
+            /* The NTSTATUS code is in parameter 1*/
+            ErrorStatus = (NTSTATUS)Parameter1;
+
+            /* Build the error string */
+            swprintf(FormatString,
+                     L"\nThe boot manager experienced an error (%08x).\n",
+                     ErrorStatus);
+
+            /* Select the resource ID message */
+            ErrorResourceId = 9005;
+            break;
+
         default:
 
             /* The rest is not yet handled */
@@ -427,25 +623,11 @@ BmpFwGetFullPath (
     )
 {
     NTSTATUS Status;
-    ULONG BootDirLength, BootDirLengthWithNul;
-    ULONG PathLength, FullPathLength;
+    ULONG BootDirLength, PathLength;
 
     /* Compute the length of the directory, and add a NUL */
     BootDirLength = wcslen(BootDirectory);
-    BootDirLengthWithNul = BootDirLength + 1;
-    if (BootDirLengthWithNul < BootDirLength)
-    {
-        /* This would overflow */
-        BootDirLengthWithNul = -1;
-        Status = STATUS_INTEGER_OVERFLOW;
-    }
-    else
-    {
-        /* We have space */
-        Status = STATUS_SUCCESS;
-    }
-
-    /* Fail on overflow */
+    Status = RtlULongAdd(BootDirLength, 1, &BootDirLength);
     if (!NT_SUCCESS(Status))
     {
         goto Quickie;
@@ -453,33 +635,26 @@ BmpFwGetFullPath (
 
     /* Add the length of the file, make sure it fits */
     PathLength = wcslen(FileName);
-    FullPathLength = PathLength + BootDirLength;
-    if (FullPathLength < PathLength)
-    {
-        /* 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
     {
@@ -492,6 +667,22 @@ Quickie:
     return Status;
 }
 
+VOID
+BmCloseDataStore (
+    _In_ HANDLE Handle
+    )
+{
+    /* Check if boot.ini data needs to be freed */
+    if (BmBootIniUsed)
+    {
+        EfiPrintf(L"Not handled\r\n");
+    }
+
+    /* Dereference the hive and close the key */
+    BiDereferenceHive(Handle);
+    BiCloseKey(Handle);
+}
+
 NTSTATUS
 BmOpenDataStore (
     _Out_ PHANDLE Handle
@@ -501,7 +692,7 @@ BmOpenDataStore (
     PBL_DEVICE_DESCRIPTOR BcdDevice;
     PWCHAR BcdPath, FullPath, PathBuffer;
     BOOLEAN HavePath;
-    ULONG PathLength, PathLengthWithNul, FullSize;
+    ULONG PathLength, FullSize;
     PVOID FinalBuffer;
     UNICODE_STRING BcdString;
 
@@ -544,7 +735,7 @@ BmOpenDataStore (
     if (NT_SUCCESS(Status))
     {
         /* We don't handle custom BCDs yet */
-        EfiPrintf(L"Not handled\n");
+        EfiPrintf(L"Not handled: %s\r\n", BcdPath);
         Status = STATUS_NOT_IMPLEMENTED;
         goto Quickie;
     }
@@ -579,35 +770,22 @@ BmOpenDataStore (
     }
 
     /* Add a NUL to the path, make sure it'll fit */
-    Status = STATUS_SUCCESS;
     PathLength = wcslen(PathBuffer);
-    PathLengthWithNul = PathLength + 1;
-    if (PathLengthWithNul < PathLength)
+    Status = RtlULongAdd(PathLength, 1, &PathLength);
+    if (!NT_SUCCESS(Status))
     {
-        PathLengthWithNul = -1;
-        Status = STATUS_INTEGER_OVERFLOW;
+        goto Quickie;
     }
 
-    /* Bail out if it doesn't fit */
+    /* Convert to bytes */
+    Status = RtlULongLongToULong(PathLength * sizeof(WCHAR), &PathLength);
     if (!NT_SUCCESS(Status))
     {
         goto Quickie;
     }
 
     /* Now add the size of the path to the device path, check if it fits */
-    PathLengthWithNul = PathLengthWithNul * sizeof(WCHAR);
-    FullSize = PathLengthWithNul + BcdDevice->Size;
-    if (FullSize < BcdDevice->Size)
-    {
-        FullSize = -1;
-        Status = STATUS_INTEGER_OVERFLOW;
-    }
-    else
-    {
-        Status = STATUS_SUCCESS;
-    }
-
-    /* Bail out if it doesn't fit */
+    Status = RtlULongAdd(PathLength, BcdDevice->Size, &FullSize);
     if (!NT_SUCCESS(Status))
     {
         goto Quickie;
@@ -625,7 +803,7 @@ BmOpenDataStore (
     RtlCopyMemory(FinalBuffer, BcdDevice, BcdDevice->Size);
     RtlCopyMemory((PVOID)((ULONG_PTR)FinalBuffer + BcdDevice->Size),
                   PathBuffer,
-                  PathLengthWithNul);
+                  PathLength);
 
     /* Now tell the BCD engine to open the store */
     BcdString.Length = FullSize;
@@ -648,7 +826,11 @@ Quickie:
     if (!NT_SUCCESS(Status))
     {
         /* Raise a fatal error */
-        BmFatalErrorEx(1, (ULONG_PTR)PathBuffer, Status, 0, 0);
+        BmFatalErrorEx(BL_FATAL_ERROR_BCD_READ,
+                       (ULONG_PTR)PathBuffer,
+                       Status,
+                       0,
+                       0);
     }
 
     /* Did we get an allocated path? */
@@ -680,12 +862,13 @@ BmMain (
     _In_ PBOOT_APPLICATION_PARAMETER_BLOCK BootParameters
     )
 {
-    NTSTATUS Status;
+    NTSTATUS Status, LibraryStatus;
     BL_LIBRARY_PARAMETERS LibraryParameters;
     PBL_RETURN_ARGUMENTS ReturnArguments;
     BOOLEAN RebootOnError;
     PGUID AppIdentifier;
     HANDLE BcdHandle;
+    PBL_BCD_OPTION EarlyOptions;
 
     EfiPrintf(L"ReactOS UEFI Boot Manager Initializing...\n");
 
@@ -734,12 +917,73 @@ BmMain (
 
     /* Load and initialize the boot configuration database (BCD) */
     Status = BmOpenDataStore(&BcdHandle);
-    EfiPrintf(L"BCD Open: %lx\r\n", Status);
+    if (NT_SUCCESS(Status))
+    {
+        /* Copy the boot options */
+        Status = BlCopyBootOptions(BlpApplicationEntry.BcdData, &EarlyOptions);
+        if (NT_SUCCESS(Status))
+        {
+            /* Update them */
+            Status = BmpUpdateApplicationOptions(BcdHandle);
+            if (!NT_SUCCESS(Status))
+            {
+                /* Log a fatal error */
+                BmFatalErrorEx(BL_FATAL_ERROR_BCD_PARSE,
+                               (ULONG_PTR)L"\\BCD",
+                               Status,
+                               0,
+                               0);
+            }
+        }
+    }
+
+#ifdef _SECURE_BOOT
+    /* Initialize the secure boot machine policy */
+    Status = BmSecureBootInitializeMachinePolicy();
+    if (!NT_SUCCESS(Status))
+    {
+        BmFatalErrorEx(BL_FATAL_ERROR_SECURE_BOOT, Status, 0, 0, 0);
+    }
+#endif
+
+    /* Copy the library parameters and add the re-initialization flag */
+    RtlCopyMemory(&LibraryParameters,
+                  &BlpLibraryParameters, 
+                  sizeof(LibraryParameters));
+    LibraryParameters.LibraryFlags |= (BL_LIBRARY_FLAG_REINITIALIZE_ALL |
+                                       BL_LIBRARY_FLAG_REINITIALIZE);
+
+    /* Now that we've parsed the BCD, re-initialize the library */
+    LibraryStatus = BlInitializeLibrary(BootParameters, &LibraryParameters);
+    if (!NT_SUCCESS(LibraryStatus) && (NT_SUCCESS(Status)))
+    {
+        Status = LibraryStatus;
+    }
 
     /* do more stuff!! */
-    EfiPrintf(L"We are A-OK!\r\n");
+    EfiPrintf(L"We are A-OKer!\r\n");
     EfiStall(10000000);
 
+//Failure:
+    /* Check if we got here due to an internal error */
+    if (BmpInternalBootError)
+    {
+        /* If XML is available, display the error */
+#if 0
+        if (XmlLoaded)
+        {
+            BmDisplayDumpError(0, 0);
+            BmErrorPurge();
+        }
+#endif
+
+        /* Don't do a fatal error -- return back to firmware */
+        goto Quickie;
+    }
+
+    /* Log a general fatal error once we're here */
+    BmFatalErrorEx(BL_FATAL_ERROR_GENERIC, Status, 0, 0, 0);
+
 Quickie:
     /* Check if we should reboot */
     if ((RebootOnError) ||
index 76dea63..3d10382 100644 (file)
@@ -49,7 +49,9 @@ typedef struct _BL_PACKED_BOOT_ERROR
     ULONG Size;
 } BL_PACKED_BOOT_ERROR, *PBL_PACKED_BOOT_ERROR;
 
-#define BL_FATAL_ERROR_BCD_READ 0x01
+#define BL_FATAL_ERROR_BCD_READ     0x01
+#define BL_FATAL_ERROR_GENERIC      0x04
+#define BL_FATAL_ERROR_BCD_PARSE    0x07
 
 /* FUNCTIONS *****************************************************************/
 
index f08e6ea..ccd9be0 100644 (file)
 
 /* ENUMERATIONS **************************************************************/
 
+/* See https://msdn.microsoft.com/en-us/library/windows/desktop/aa964229(v=vs.85).aspx */
+
+#define BCD_CLASS_LIBRARY       0x01
+#define BCD_CLASS_APPLICATION   0x02
+#define BCD_CLASS_DEVICE        0x03
+#define BCD_CLASS_OEM           0x05
+
+#define BCD_TYPE_DEVICE         0x01
+#define BCD_TYPE_STRING         0x02
+#define BCD_TYPE_OBJECT         0x03
+#define BCD_TYPE_OBJECT_LIST    0x04
+#define BCD_TYPE_INTEGER        0x05
+#define BCD_TYPE_BOOLEAN        0x06
+#define BCD_TYPE_INTEGER_LIST   0x07
+
 typedef enum BcdLibraryElementTypes
 {
     BcdLibraryDevice_ApplicationDevice = 0x11000001,
@@ -155,9 +170,43 @@ typedef enum BcdBootMgrElementTypes
     BcdBootMgrBoolean_PersistBootSequence = 0x26000031
 } BcdBootMgrElementTypes;
 
-
 /* DATA STRUCTURES ***********************************************************/
 
+typedef struct
+{
+    union
+    {
+        ULONG  PackedValue;
+        struct
+        {
+            ULONG SubType : 24;
+            ULONG Format : 4;
+            ULONG Class : 4;
+        };
+    };
+} BcdElementType;
+
+typedef struct _BCD_ELEMENT_HEADER
+{
+    ULONG Version;
+    ULONG Type;
+    ULONG Size;
+} BCD_ELEMENT_HEADER, *PBCD_ELEMENT_HEADER;
+
+typedef struct _BCD_PACKED_ELEMENT
+{
+    struct _BCD_PACKED_ELEMENT* NextEntry;
+    BcdElementType RootType;
+    BCD_ELEMENT_HEADER;
+    UCHAR Data[ANYSIZE_ARRAY];
+} BCD_PACKED_ELEMENT, *PBCD_PACKED_ELEMENT;
+
+typedef struct _BCD_ELEMENT
+{
+    PBCD_ELEMENT_HEADER Header;
+    PUCHAR Body;
+} BCD_ELEMENT, *PBCD_ELEMENT;
+
 typedef struct _BCD_DEVICE_OPTION
 {
     GUID AssociatedEntry;
@@ -172,4 +221,35 @@ BcdOpenStoreFromFile (
     _In_ PHANDLE StoreHandle
     );
 
+#define BCD_ENUMERATE_FLAG_DEEP         0x04
+#define BCD_ENUMERATE_FLAG_DEVICES      0x08
+#define BCD_ENUMERATE_FLAG_IN_ORDER     0x10
+
+NTSTATUS
+BiEnumerateElements (
+    _In_ HANDLE BcdHandle,
+    _In_ HANDLE ObjectHandle,
+    _In_ ULONG RootElementType,
+    _In_ ULONG Flags,
+    _Out_opt_ PBCD_PACKED_ELEMENT Elements,
+    _Inout_ PULONG ElementSize,
+    _Out_ PULONG ElementCountNe
+    );
+
+NTSTATUS
+BcdOpenObject (
+    _In_ HANDLE BcdHandle,
+    _In_ PGUID ObjectId,
+    _Out_ PHANDLE ObjectHandle
+    );
+
+NTSTATUS
+BcdEnumerateAndUnpackElements (
+    _In_ HANDLE BcdHandle,
+    _In_ HANDLE ObjectHandle,
+    _Out_opt_ PBCD_ELEMENT Elements,
+    _Inout_ PULONG ElementSize,
+    _Out_ PULONG ElementCount
+    );
+
 #endif
index aa4a608..d5572cb 100644 (file)
@@ -22,6 +22,9 @@
 /* NDK Headers */
 #include <ntndk.h>
 
+/* NT SafeInt Header */
+#include <ntintsafe.h>
+
 /* UEFI Headers */
 #include <Uefi.h>
 #include <DevicePath.h>
@@ -52,7 +55,9 @@
 #define BL_FIRMWARE_DESCRIPTOR_VERSION                  2
 
 #define BL_APPLICATION_ENTRY_FLAG_NO_GUID               0x01
+#define BL_APPLICATION_ENTRY_BCD_OPTIONS_INTERNAL       0x02
 #define BL_APPLICATION_ENTRY_REBOOT_ON_ERROR            0x20
+#define BL_APPLICATION_ENTRY_BCD_OPTIONS_EXTERNAL       0x80
 
 #define BL_CONTEXT_PAGING_ON                            1
 #define BL_CONTEXT_INTERRUPTS_ON                        2
@@ -716,9 +721,9 @@ typedef struct _BL_LOCAL_DEVICE
 
 typedef struct _BL_DEVICE_DESCRIPTOR
 {
-    ULONG Size;
-    ULONG Flags;
     DEVICE_TYPE DeviceType;
+    ULONG Flags;
+    ULONG Size;
     ULONG Unknown;
     union
     {
@@ -1424,7 +1429,18 @@ BlHtCreate (
     _Out_ PULONG Id
     );
 
-/* BCD ROUTINES **************************************************************/
+/* BCD OPTION ROUTINES *******************************************************/
+
+PBL_BCD_OPTION
+MiscGetBootOption (
+    _In_ PBL_BCD_OPTION List,
+    _In_ ULONG Type
+    );
+
+ULONG
+BlGetBootOptionListSize (
+    _In_ PBL_BCD_OPTION BcdOption
+    );
 
 ULONG
 BlGetBootOptionSize (
@@ -1452,6 +1468,15 @@ BlGetBootOptionBoolean (
     _Out_ PBOOLEAN Value
     );
 
+NTSTATUS
+BlpGetBootOptionIntegerList (
+    _In_ PBL_BCD_OPTION List,
+    _In_ ULONG Type,
+    _Out_ PULONGLONG* Value,
+    _Out_ PULONGLONG Count,
+    _In_ BOOLEAN NoCopy
+    );
+
 NTSTATUS
 BlGetBootOptionDevice (
     _In_ PBL_BCD_OPTION List,
@@ -1460,6 +1485,68 @@ BlGetBootOptionDevice (
     _In_opt_ PBL_BCD_OPTION* ExtraOptions
     );
 
+NTSTATUS
+BlGetBootOptionGuidList (
+    _In_ PBL_BCD_OPTION List,
+    _In_ ULONG Type,
+    _Out_ PGUID *Value,
+    _In_ PULONG Count
+    );
+
+NTSTATUS
+BlCopyBootOptions (
+    _In_ PBL_BCD_OPTION OptionList,
+    _Out_ PBL_BCD_OPTION *CopiedOptions
+    );
+
+NTSTATUS
+BlAppendBootOptions (
+    _In_ PBL_LOADED_APPLICATION_ENTRY AppEntry,
+    _In_ PBL_BCD_OPTION Options
+    );
+
+/* BOOT REGISTRY ROUTINES ****************************************************/
+
+VOID
+BiCloseKey (
+    _In_ HANDLE KeyHandle
+    );
+
+NTSTATUS
+BiOpenKey(
+    _In_ HANDLE ParentHandle,
+    _In_ PWCHAR KeyName,
+    _Out_ PHANDLE Handle
+    );
+
+NTSTATUS
+BiLoadHive (
+    _In_ PBL_FILE_PATH_DESCRIPTOR FilePath,
+    _Out_ PHANDLE HiveHandle
+    );
+
+NTSTATUS
+BiGetRegistryValue (
+    _In_ HANDLE KeyHandle,
+    _In_ PWCHAR ValueName,
+    _In_ PWCHAR KeyName,
+    _In_ ULONG Type,
+    _Out_ PVOID* Buffer,
+    _Out_ PULONG ValueLength
+    );
+
+NTSTATUS
+BiEnumerateSubKeys (
+    _In_ HANDLE KeyHandle,
+    _Out_ PWCHAR** SubKeyList,
+    _Out_ PULONG SubKeyCount
+    );
+
+VOID
+BiDereferenceHive (
+    _In_ HANDLE KeyHandle
+    );
+
 /* CONTEXT ROUTINES **********************************************************/
 
 VOID
@@ -1561,6 +1648,16 @@ MmFwGetMemoryMap (
     _In_ ULONG Flags
     );
 
+NTSTATUS
+BlpMmInitializeConstraints (
+    VOID
+    );
+
+NTSTATUS
+BlMmRemoveBadMemory (
+    VOID
+    );
+
 /* VIRTUAL MEMORY ROUTINES ***************************************************/
 
 NTSTATUS
index 43ef213..5e9a6be 100644 (file)
@@ -86,11 +86,15 @@ InitializeLibrary (
     BlpApplicationParameters = BootAppParameters;
     BlpLibraryParameters = *LibraryParameters;
 
-    /* Save the application entry flags */
-    if (AppEntry->Flags & 2)
+    /* Check if the caller sent us their internal BCD options */
+    if (AppEntry->Flags & BL_APPLICATION_ENTRY_BCD_OPTIONS_INTERNAL)
     {
-        AppEntry->Flags = (AppEntry->Flags & ~0x2) | 0x80;
+        /* These are external to us now, as far as we are concerned */
+        AppEntry->Flags &= ~BL_APPLICATION_ENTRY_BCD_OPTIONS_INTERNAL;
+        AppEntry->Flags |= BL_APPLICATION_ENTRY_BCD_OPTIONS_EXTERNAL;
     }
+
+    /* Save the application entry flags */
     BlpApplicationEntry.Flags = AppEntry->Flags;
 
     /* Copy the GUID and point to the options */
@@ -363,15 +367,24 @@ BlInitializeLibrary(
         BlpLibraryParameters = *LibraryParameters;
         if (LibraryParameters->LibraryFlags & BL_LIBRARY_FLAG_REINITIALIZE_ALL)
         {
-#if 0
-            /* Initialize all the core modules again */
+#ifdef BL_TPM_SUPPORT
+            /* Reinitialize the TPM security enclave as BCD hash changed */
             BlpSiInitialize(1);
+#endif
+#ifdef BL_KD_SUPPORT
+            /* Reinitialize the boot debugger as BCD debug options changed */
             BlBdInitialize();
+#endif
+
+            /* Reparse the bad page list now that the BCD has been reloaded */
             BlMmRemoveBadMemory();
+
+            /* Reparse the low/high physical address limits as well */
             BlpMmInitializeConstraints();
 
             /* Redraw the graphics console as needed */
             BlpDisplayInitialize(LibraryParameters->LibraryFlags);
+#if 0
             BlpResourceInitialize();
 #endif
         }
index 21e80fc..33620d4 100644 (file)
@@ -43,7 +43,7 @@ DsppGraphicsDisabledByBcd (
     VOID
     )
 {
-    //EarlyPrint(L"Disabling graphics\r\n");
+    EfiPrintf(L"Disabling graphics\r\n");
     return FALSE;
 }
 
@@ -53,10 +53,10 @@ DsppInitialize (
     )
 {
     BL_LIBRARY_PARAMETERS LibraryParameters = BlpLibraryParameters;
-    BOOLEAN NoGraphics;// , HighestMode;
+    BOOLEAN NoGraphics, HighestMode;
     NTSTATUS Status;
     PBL_DISPLAY_MODE DisplayMode;
-    //ULONG GraphicsResolution;
+    ULONGLONG GraphicsResolution;
     PBL_GRAPHICS_CONSOLE GraphicsConsole;
     PBL_TEXT_CONSOLE TextConsole, RemoteConsole;
 
@@ -100,14 +100,9 @@ DsppInitialize (
         DisplayMode = &ConsoleGraphicalResolutionList[0];
 
         /* Check what resolution to use*/
-#if 0
         Status = BlGetBootOptionInteger(BlpApplicationEntry.BcdData,
                                         BcdLibraryInteger_GraphicsResolution,
                                         &GraphicsResolution);
-#else
-        //GraphicsResolution = 0;
-        Status = STATUS_NOT_FOUND;
-#endif
         if (NT_SUCCESS(Status))
         {
             ConsoleGraphicalResolutionListFlags |= BL_DISPLAY_GRAPHICS_FORCED_VIDEO_MODE_FLAG;
@@ -116,14 +111,9 @@ DsppInitialize (
         }
 
         /* Check if the highest mode should be forced */
-#if 0
         Status = BlGetBootOptionBoolean(BlpApplicationEntry.BcdData,
                                         BcdLibraryBoolean_GraphicsForceHighestMode,
                                         &HighestMode);
-#else
-        //HighestMode = 0;
-        Status = STATUS_NOT_FOUND;
-#endif
         if (NT_SUCCESS(Status))
         {
             ConsoleGraphicalResolutionListFlags |= BL_DISPLAY_GRAPHICS_FORCED_HIGH_RES_MODE_FLAG;
@@ -233,6 +223,7 @@ BlpDisplayInitialize (
     {
         /* This is a reset */
         Status = STATUS_NOT_IMPLEMENTED;
+        EfiPrintf(L"Display reset not yet implemented\r\n");
 #if 0
         Status = DsppReinitialize(Flags);
         if (NT_SUCCESS(Status))
index cb88bdb..31c76c5 100644 (file)
 
 /* 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;
 }
 
@@ -1119,10 +1112,91 @@ BiAddStoreFromFile (
     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;
@@ -1155,7 +1229,7 @@ BcdOpenStoreFromFile (
     if (NT_SUCCESS(Status))
     {
         /* Return the handle on success */
-        *StoreHandle = LocalHandle;
+        *BcdHandle = LocalHandle;
     }
 
     /* Free the descriptor and return the status */
diff --git a/reactos/boot/environ/lib/misc/bcdopt.c b/reactos/boot/environ/lib/misc/bcdopt.c
new file mode 100644 (file)
index 0000000..5a8ce22
--- /dev/null
@@ -0,0 +1,647 @@
+/*
+ * COPYRIGHT:       See COPYING.ARM in the top level directory
+ * PROJECT:         ReactOS UEFI Boot Library
+ * FILE:            boot/environ/lib/misc/bcdopt.c
+ * PURPOSE:         Boot Library BCD Option Parsing Routines
+ * PROGRAMMER:      Alex Ionescu (alex.ionescu@reactos.org)
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include "bl.h"
+#include <bcd.h>
+
+/* FUNCTIONS *****************************************************************/
+
+PBL_BCD_OPTION
+MiscGetBootOption (
+    _In_ PBL_BCD_OPTION List,
+    _In_ ULONG Type
+    )
+{
+    ULONG_PTR NextOption = 0, ListOption;
+    PBL_BCD_OPTION Option, FoundOption;
+
+    /* No options, bail out */
+    if (!List)
+    {
+        return NULL;
+    }
+
+    /* Loop while we find an option */
+    FoundOption = NULL;
+    do
+    {
+        /* Get the next option and see if it matches the type */
+        Option = (PBL_BCD_OPTION)((ULONG_PTR)List + NextOption);
+        if ((Option->Type == Type) && !(Option->Empty))
+        {
+            FoundOption = Option;
+            break;
+        }
+
+        /* Store the offset of the next option */
+        NextOption = Option->NextEntryOffset;
+
+        /* Failed to match. Check for list options */
+        ListOption = Option->ListOffset;
+        if (ListOption)
+        {
+            /* Try to get a match in the associated option */
+            Option = MiscGetBootOption((PBL_BCD_OPTION)((ULONG_PTR)Option +
+                                       ListOption),
+                                       Type);
+            if (Option)
+            {
+                /* Return it */
+                FoundOption = Option;
+                break;
+            }
+        }
+    } while (NextOption);
+
+    /* Return the option that was found, if any */
+    return FoundOption;
+}
+
+/*++
+ * @name BlGetBootOptionListSize
+ *
+ *     The BlGetBootOptionListSize routine
+ *
+ * @param  BcdOption
+ *         UEFI Image Handle for the current loaded application.
+ *
+ * @return Size of the BCD option
+ *
+ *--*/
+ULONG
+BlGetBootOptionListSize (
+    _In_ PBL_BCD_OPTION BcdOption
+    )
+{
+    ULONG Size = 0, NextOffset = 0;
+    PBL_BCD_OPTION NextOption;
+
+    /* Loop all the options*/
+    do
+    {
+        /* Move to the next one */
+        NextOption = (PBL_BCD_OPTION)((ULONG_PTR)BcdOption + NextOffset);
+
+        /* Compute the size of the next one */
+        Size += BlGetBootOptionSize(NextOption);
+
+        /* Update the offset */
+        NextOffset = NextOption->NextEntryOffset;
+    } while (NextOffset);
+
+    /* Return final computed size */
+    return Size;
+}
+
+/*++
+ * @name BlGetBootOptionSize
+ *
+ *     The BlGetBootOptionSize routine
+ *
+ * @param  BcdOption
+ *         UEFI Image Handle for the current loaded application.
+ *
+ * @return Size of the BCD option
+ *
+ *--*/
+ULONG
+BlGetBootOptionSize (
+    _In_ PBL_BCD_OPTION BcdOption
+    )
+{
+    ULONG Size, Offset;
+
+    /* Check if there's any data */
+    if (BcdOption->DataOffset)
+    {
+        /* Add the size of the data */
+        Size = BcdOption->DataOffset + BcdOption->DataSize;
+    }
+    else
+    {
+        /* No data, just the structure itself */
+        Size = sizeof(*BcdOption);
+    }
+
+    /* Any associated options? */
+    Offset = BcdOption->ListOffset;
+    if (Offset)
+    {
+        /* Go get those too */
+        Size += BlGetBootOptionListSize((PVOID)((ULONG_PTR)BcdOption + Offset));
+    }
+
+    /* Return the final size */
+    return Size;
+}
+
+NTSTATUS
+BlGetBootOptionString (
+    _In_ PBL_BCD_OPTION List,
+    _In_ ULONG Type,
+    _Out_ PWCHAR* Value
+    )
+{
+    NTSTATUS Status;
+    PBL_BCD_OPTION Option;
+    PWCHAR String, StringCopy;
+    ULONG StringLength;
+    BcdElementType ElementType;
+    //PGUID AppIdentifier;
+
+    /* Make sure this is a BCD_STRING */
+    ElementType.PackedValue = Type;
+    if (ElementType.Format != BCD_TYPE_STRING)
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    /* Return the data */
+    Option = MiscGetBootOption(List, Type);
+    if (Option)
+    {
+        /* Extract the string */
+        String = (PWCHAR)((ULONG_PTR)Option + Option->DataOffset);
+        Status = STATUS_SUCCESS;
+    }
+    else
+    {
+        /* No string is present */
+        String = NULL;
+        Status = STATUS_NOT_FOUND;
+    }
+
+    /* Compute the data size */
+    StringLength = Option->DataSize / sizeof(WCHAR);
+
+#ifdef _SECURE_BOOT_
+    /* Filter out SecureBoot Options */
+    AppIdentifier = BlGetApplicationIdentifier();
+    Status = BlpBootOptionCallbackString(AppIdentifier, Type, String, StringLength, &String, &StringLength);
+#else
+#endif
+
+    /* Make sure we have a valid, non-filtered string */
+    if (NT_SUCCESS(Status))
+    {
+        /* Check if we have space for one more character */
+        Status = RtlULongAdd(StringLength, 1, &StringLength);
+        if (NT_SUCCESS(Status))
+        {
+            /* Check if it's safe to multiply by two */
+            Status = RtlULongMult(StringLength, sizeof(WCHAR), &StringLength);
+            if (NT_SUCCESS(Status))
+            {
+                /* Allocate a copy for the string */
+                StringCopy = BlMmAllocateHeap(StringLength);
+                if (StringCopy)
+                {
+                    /* NULL-terminate it */
+                    RtlCopyMemory(StringCopy,
+                                  String,
+                                  StringLength - sizeof(UNICODE_NULL));
+                    StringCopy[StringLength] = UNICODE_NULL;
+                    *Value = StringCopy;
+                    Status = STATUS_SUCCESS;
+                }
+                else
+                {
+                    /* No memory, fail */
+                    Status = STATUS_NO_MEMORY;
+                }
+            }
+        }
+    }
+
+    /* All done */
+    return Status;
+}
+
+NTSTATUS
+BlGetBootOptionGuidList (
+    _In_ PBL_BCD_OPTION List,
+    _In_ ULONG Type,
+    _Out_ PGUID *Value,
+    _In_ PULONG Count
+    )
+{
+    NTSTATUS Status;
+    PBL_BCD_OPTION Option;
+    PGUID GuidCopy, Guid;
+    ULONG GuidCount;
+    BcdElementType ElementType;
+
+    /* Make sure this is a BCD_TYPE_OBJECT_LIST */
+    ElementType.PackedValue = Type;
+    if (ElementType.Format != BCD_TYPE_OBJECT_LIST)
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    /* Return the data */
+    Option = MiscGetBootOption(List, Type);
+    if (!Option)
+    {
+        /* Set failure if no data exists */
+        Status = STATUS_NOT_FOUND;
+    }
+    else
+    {
+        /* Get the GUIDs and allocate a copy for them */
+        Guid = (PGUID)((ULONG_PTR)Option + Option->DataOffset);
+        GuidCopy = BlMmAllocateHeap(Option->DataSize);
+        if (GuidCopy)
+        {
+            /* Copy the GUIDs */
+            RtlCopyMemory(GuidCopy, Guid, Option->DataSize);
+
+            /* Return the number of GUIDs and the start of the array */
+            GuidCount = Option->DataSize / sizeof(GUID);
+            *Value = GuidCopy;
+            *Count = GuidCount;
+            Status = STATUS_SUCCESS;
+        }
+        else
+        {
+            /* No memory for the copy */
+            Status = STATUS_NO_MEMORY;
+        }
+    }
+
+    /* All good */
+    return Status;
+}
+
+NTSTATUS
+BlGetBootOptionDevice (
+    _In_ PBL_BCD_OPTION List,
+    _In_ ULONG Type,
+    _Out_ PBL_DEVICE_DESCRIPTOR* Value,
+    _In_opt_ PBL_BCD_OPTION* ExtraOptions
+    )
+{
+    NTSTATUS Status;
+    PBL_BCD_OPTION Option, ListData, ListCopy, SecureListData;
+    PBCD_DEVICE_OPTION BcdDevice;
+    ULONG DeviceSize, ListOffset, ListSize;
+    PBL_DEVICE_DESCRIPTOR DeviceDescriptor, SecureDescriptor;
+    //PGUID AppIdentifier;
+    BcdElementType ElementType;
+
+    /* Make sure this is a BCD_TYPE_DEVICE */
+    ElementType.PackedValue = Type;
+    if (ElementType.Format != BCD_TYPE_DEVICE)
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    /* Return the data */
+    Option = MiscGetBootOption(List, Type);
+    if (!Option)
+    {
+        /* Set failure if no data exists */
+        Status = STATUS_NOT_FOUND;
+    }
+    else
+    {
+        /* Otherwise, read the size of the BCD device encoded */
+        BcdDevice = (PBCD_DEVICE_OPTION)((ULONG_PTR)Option + Option->DataOffset);
+        DeviceSize = BcdDevice->DeviceDescriptor.Size;
+
+        /* Allocate a buffer to copy it into */
+        DeviceDescriptor = BlMmAllocateHeap(DeviceSize);
+        if (!DeviceDescriptor)
+        {
+            return STATUS_NO_MEMORY;
+        }
+
+        /* Copy it into that buffer */
+        RtlCopyMemory(DeviceDescriptor, &BcdDevice->DeviceDescriptor, DeviceSize);
+        Status = STATUS_SUCCESS;
+    }
+
+    /* Check if extra options were requested */
+    if (ExtraOptions)
+    {
+        /* See where they are */
+        ListOffset = Option->ListOffset;
+        if (ListOffset)
+        {
+            /* See how big they are */
+            ListData = (PBL_BCD_OPTION)((ULONG_PTR)Option + ListOffset);
+            ListSize = BlGetBootOptionListSize(ListData);
+
+            /* Allocate a buffer to hold them into */
+            ListCopy = BlMmAllocateHeap(ListSize);
+            if (!ListCopy)
+            {
+                Status = STATUS_NO_MEMORY;
+                goto Quickie;
+            }
+
+            /* Copy them in there */
+            RtlCopyMemory(ListCopy, ListData, ListSize);
+        }
+    }
+
+#ifdef _SECURE_BOOT_
+    /* Filter out SecureBoot Options */
+    AppIdentifier = BlGetApplicationIdentifier();
+    if (BlpBootOptionCallbacks)
+    {
+        DeviceCallback = BlpBootOptionCallbacks->Device;
+        if (DeviceCallback)
+        {
+            Status = DeviceCallback(BlpBootOptionCallbackCookie,
+                                    Status,
+                                    0,
+                                    AppIdentifier,
+                                    Type,
+                                    &SecureDescriptor,
+                                    PtrOptionData);
+        }
+    }
+#else
+    /* No secure boot, so the secure descriptors are the standard ones */
+    SecureDescriptor = DeviceDescriptor;
+    SecureListData = ListCopy;
+#endif
+
+    /* Check if the data was read correctly */
+    if (NT_SUCCESS(Status))
+    {
+        /* Check if we had a new descriptor after filtering */
+        if (SecureDescriptor != DeviceDescriptor)
+        {
+            /* Yep -- if we had an old one, free it */
+            if (DeviceDescriptor)
+            {
+                BlMmFreeHeap(DeviceDescriptor);
+            }
+        }
+
+        /* Check if we had a new list after filtering */
+        if (SecureListData != ListCopy)
+        {
+            /* Yep -- if we had an old list, free it */
+            if (ListCopy)
+            {
+                BlMmFreeHeap(ListCopy);
+            }
+        }
+
+        /* Finally, check if the caller wanted extra options */
+        if (ExtraOptions)
+        {
+            /* Yep -- so pass the caller our copy */
+            *ExtraOptions = ListCopy;
+            ListCopy = NULL;
+        }
+
+        /* Caller always wants data back, so pass them our copy */
+        *Value = DeviceDescriptor;
+        DeviceDescriptor = NULL;
+    }
+
+Quickie:
+    /* On the failure path, if these buffers are active, we should free them */
+    if (ListCopy)
+    {
+        BlMmFreeHeap(ListCopy);
+    }
+    if (DeviceDescriptor)
+    {
+        BlMmFreeHeap(DeviceDescriptor);
+    }
+
+    /* All done */
+    return Status;
+}
+
+NTSTATUS
+BlGetBootOptionInteger (
+    _In_ PBL_BCD_OPTION List,
+    _In_ ULONG Type,
+    _Out_ PULONGLONG Value
+    )
+{
+    NTSTATUS Status;
+    PBL_BCD_OPTION Option;
+    //PGUID AppIdentifier;
+    BcdElementType ElementType;
+
+    /* Make sure this is a BCD_TYPE_INTEGER */
+    ElementType.PackedValue = Type;
+    if (ElementType.Format != BCD_TYPE_INTEGER)
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    /* Return the data */
+    Option = MiscGetBootOption(List, Type);
+    if (Option)
+    {
+        *Value = *(PULONGLONG)((ULONG_PTR)Option + Option->DataOffset);
+    }
+
+#ifdef _SECURE_BOOT_
+    /* Filter out SecureBoot Options */
+    AppIdentifier = BlGetApplicationIdentifier();
+    Status = BlpBootOptionCallbackULongLong(AppIdentifier, Type, Value);
+#else
+    /* Option found */
+    Status = Option ? STATUS_SUCCESS : STATUS_NOT_FOUND;
+#endif
+    return Status;
+}
+
+NTSTATUS
+BlGetBootOptionBoolean (
+    _In_ PBL_BCD_OPTION List,
+    _In_ ULONG Type,
+    _Out_ PBOOLEAN Value
+    )
+{
+    NTSTATUS Status;
+    PBL_BCD_OPTION Option;
+    //PGUID AppIdentifier;
+    BcdElementType ElementType;
+
+    /* Make sure this is a BCD_TYPE_BOOLEAN */
+    ElementType.PackedValue = Type;
+    if (ElementType.Format != BCD_TYPE_BOOLEAN)
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    /* Return the data */
+    Option = MiscGetBootOption(List, Type);
+    if (Option)
+    {
+        *Value = *(PBOOLEAN)((ULONG_PTR)Option + Option->DataOffset);
+    }
+
+#ifdef _SECURE_BOOT_
+    /* Filter out SecureBoot Options */
+    AppIdentifier = BlGetApplicationIdentifier();
+    Status = BlpBootOptionCallbackBoolean(AppIdentifier, Type, Value);
+#else
+    /* Option found */
+    Status = Option ? STATUS_SUCCESS : STATUS_NOT_FOUND;
+#endif
+    return Status;
+}
+
+NTSTATUS
+BlpGetBootOptionIntegerList (
+    _In_ PBL_BCD_OPTION List,
+    _In_ ULONG Type,
+    _Out_ PULONGLONG* Value,
+    _Out_ PULONGLONG Count,
+    _In_ BOOLEAN NoCopy
+    )
+{
+    PBL_BCD_OPTION Option;
+    BcdElementType ElementType;
+    PULONGLONG ValueCopy;
+
+    /* Make sure this is a BCD_TYPE_INTEGER_LIST */
+    ElementType.PackedValue = Type;
+    if (ElementType.Format != BCD_TYPE_INTEGER_LIST)
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    /* Return the data */
+    Option = MiscGetBootOption(List, Type);
+    if (!Option)
+    {
+        return STATUS_NOT_FOUND;
+    }
+
+    /* Check if a copy should be made of it */
+    if (NoCopy)
+    {
+        /* Nope, return the raw value */
+        *Value = (PULONGLONG)((ULONG_PTR)Option + Option->DataOffset);
+    }
+    else
+    {
+        /* Allocate a buffer for the copy */
+        ValueCopy = BlMmAllocateHeap(Option->DataSize);
+        if (!ValueCopy)
+        {
+            return STATUS_NO_MEMORY;
+        }
+
+        /* Copy the data in */
+        RtlCopyMemory(ValueCopy,
+                      (PVOID)((ULONG_PTR)Option + Option->DataOffset),
+                      Option->DataSize);
+
+        /* Return our copy */
+        *Value = ValueCopy;
+    }
+
+    /* Return count and success */
+    *Count = Option->DataSize / sizeof(ULONGLONG);
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+BlCopyBootOptions (
+    _In_ PBL_BCD_OPTION OptionList,
+    _Out_ PBL_BCD_OPTION *CopiedOptions
+    )
+{
+    NTSTATUS Status;
+    ULONG OptionSize;
+    PBL_BCD_OPTION Options;
+
+    /* Assume no options */
+    Status = STATUS_SUCCESS;
+    *CopiedOptions = NULL;
+
+    /* Get the size of the list and allocate a copy for it */
+    OptionSize = BlGetBootOptionListSize(OptionList);
+    Options = BlMmAllocateHeap(OptionSize);
+    if (!Options)
+    {
+        return STATUS_NO_MEMORY;
+    }
+
+    /* Make the copy and return it to the caller */
+    RtlCopyMemory(Options, OptionList, OptionSize);
+    *CopiedOptions = Options;
+    return Status;
+}
+
+NTSTATUS
+BlAppendBootOptions (
+    _In_ PBL_LOADED_APPLICATION_ENTRY AppEntry,
+    _In_ PBL_BCD_OPTION Options
+    )
+{
+    ULONG OptionsSize, CurrentSize;
+    PBL_BCD_OPTION NewOptions, CurrentOptions, NextOption;
+    NTSTATUS Status;
+    ULONG CurrentOffset;
+
+    /* Get the current options */
+    CurrentOptions = AppEntry->BcdData;
+
+    /* Calculate the size of the current, and the appended options */
+    CurrentSize = BlGetBootOptionListSize(CurrentOptions);
+    OptionsSize = BlGetBootOptionListSize(Options);
+
+    /* Allocate a buffer for the concatenated (new) options */
+    NewOptions = BlMmAllocateHeap(CurrentSize + OptionsSize);
+    if (!NewOptions)
+    {
+        return STATUS_NO_MEMORY;
+    }
+
+    /* Copy the old options, and the ones to be added */
+    RtlCopyMemory(NewOptions, CurrentOptions, CurrentSize);
+    RtlCopyMemory(&NewOptions[OptionsSize], Options, OptionsSize);
+
+    /* We made it! */
+    Status = STATUS_SUCCESS;
+
+    /* Scan through to the last option in the list */
+    CurrentOffset = 0;
+    do
+    {
+        NextOption = (PBL_BCD_OPTION)((ULONG_PTR)NewOptions + CurrentOffset);
+        CurrentOffset = NextOption->NextEntryOffset;
+    } while (CurrentOffset);
+
+    /* Every other option now has to have its offset adjusted */
+    do
+    {
+        NextOption->NextEntryOffset += OptionsSize;
+        NextOption = (PBL_BCD_OPTION)((ULONG_PTR)NewOptions + NextOption->NextEntryOffset);
+    } while (NextOption->NextEntryOffset);
+
+    /* If we already had internal options, free them */
+    if (AppEntry->Flags & BL_APPLICATION_ENTRY_BCD_OPTIONS_INTERNAL)
+    {
+        BlMmFreeHeap(AppEntry->BcdData);
+    }
+
+    /* Write the new pointer */
+    AppEntry->BcdData = NewOptions;
+
+    /* Options are now internal, not external */
+    AppEntry->Flags &= ~BL_APPLICATION_ENTRY_BCD_OPTIONS_EXTERNAL;
+    AppEntry->Flags |= BL_APPLICATION_ENTRY_BCD_OPTIONS_INTERNAL;
+    return Status;
+}
+
diff --git a/reactos/boot/environ/lib/misc/bootreg.c b/reactos/boot/environ/lib/misc/bootreg.c
new file mode 100644 (file)
index 0000000..278ca1c
--- /dev/null
@@ -0,0 +1,889 @@
+/*
+ * COPYRIGHT:       See COPYING.ARM in the top level directory
+ * PROJECT:         ReactOS UEFI Boot Library
+ * FILE:            boot/environ/lib/misc/bootreg.c
+ * PURPOSE:         Boot Library Boot Registry Wrapper for CMLIB
+ * PROGRAMMER:      Alex Ionescu (alex.ionescu@reactos.org)
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include "bl.h"
+#include <bcd.h>
+
+/* DEFINITIONS ***************************************************************/
+
+#define BI_FLUSH_HIVE       0x01
+#define BI_HIVE_WRITEABLE   0x02
+
+/* DATA STRUCTURES ***********************************************************/
+
+typedef struct _BI_KEY_HIVE
+{
+    PHBASE_BLOCK BaseBlock;
+    ULONG HiveSize;
+    PBL_FILE_PATH_DESCRIPTOR FilePath;
+    CMHIVE Hive;
+    LONG ReferenceCount;
+    ULONG Flags;
+    PCM_KEY_NODE RootNode;
+} BI_KEY_HIVE, *PBI_KEY_HIVE;
+
+typedef struct _BI_KEY_OBJECT
+{
+    PBI_KEY_HIVE KeyHive;
+    PCM_KEY_NODE KeyNode;
+    HCELL_INDEX KeyCell;
+    PWCHAR KeyName;
+} BI_KEY_OBJECT, *PBI_KEY_OBJECT;
+
+/* GLOBALS *******************************************************************/
+
+BOOLEAN BiHiveHashLibraryInitialized;
+ULONGLONG HvSymcryptSeed;
+
+/* FUNCTIONS *****************************************************************/
+
+BOOLEAN
+HvIsInPlaceBaseBlockValid (
+    _In_ PHBASE_BLOCK BaseBlock
+    )
+{
+    ULONG HiveLength, HeaderSum;
+    BOOLEAN Valid;
+
+    /* Assume failure */
+    Valid = FALSE;
+
+    /* Check for incorrect signature, type, version, or format */
+    if ((BaseBlock->Signature == 'fger') &&
+        (BaseBlock->Type == 0) &&
+        (BaseBlock->Major <= 1) &&
+        (BaseBlock->Minor <= 5) &&
+        (BaseBlock->Minor >= 3) &&
+        (BaseBlock->Format == 1))
+    {
+        /* Check for invalid hive size */
+        HiveLength = BaseBlock->Length;
+        if (HiveLength)
+        {
+            /* Check for misaligned or too large hive size */
+            if (!(HiveLength & 0xFFF) && HiveLength <= 0x7FFFE000)
+            {
+                /* Check for invalid header checksum */
+                HeaderSum = HvpHiveHeaderChecksum(BaseBlock);
+                if (HeaderSum == BaseBlock->CheckSum)
+                {
+                    /* All good */
+                    Valid = TRUE;
+                }
+            }
+        }
+    }
+
+    /* Return validity */
+    return Valid;
+}
+
+PVOID
+NTAPI
+CmpAllocate (
+    _In_ SIZE_T Size,
+    _In_ BOOLEAN Paged,
+    _In_ ULONG Tag
+    )
+{
+    UNREFERENCED_PARAMETER(Paged);
+    UNREFERENCED_PARAMETER(Tag);
+
+    /* Call the heap allocator */
+    return BlMmAllocateHeap(Size);
+}
+
+VOID
+NTAPI
+CmpFree (
+    _In_ PVOID Ptr,
+    _In_ ULONG Quota
+    )
+{
+    UNREFERENCED_PARAMETER(Quota);
+
+    /* Call the heap allocator */
+    BlMmFreeHeap(Ptr);
+}
+
+VOID
+BiDereferenceHive (
+    _In_ HANDLE KeyHandle
+    )
+{
+    PBI_KEY_OBJECT KeyObject;
+
+    /* Get the key object */
+    KeyObject = (PBI_KEY_OBJECT)KeyHandle;
+
+    /* Drop a reference on the parent hive */
+    --KeyObject->KeyHive->ReferenceCount;
+}
+
+VOID
+BiFlushHive (
+    _In_ HANDLE KeyHandle
+    )
+{
+    /* Not yet implemented */
+    EfiPrintf(L"NO reg flush\r\n");
+    return;
+}
+
+VOID
+BiCloseKey (
+    _In_ HANDLE KeyHandle
+    )
+{
+    PBI_KEY_HIVE KeyHive;
+    PBI_KEY_OBJECT KeyObject;
+
+    /* Get the key object and hive */
+    KeyObject = (PBI_KEY_OBJECT)KeyHandle;
+    KeyHive = KeyObject->KeyHive;
+
+    /* Check if we have a hive, or name, or key node */
+    if ((KeyHive) || (KeyObject->KeyNode) || (KeyObject->KeyName))
+    {
+        /* Drop a reference, see if it's the last one */
+        BiDereferenceHive(KeyHandle);
+        if (!KeyHive->ReferenceCount)
+        {
+            /* Check if we should flush it */
+            if (KeyHive->Flags & BI_FLUSH_HIVE)
+            {
+                BiFlushHive(KeyHandle);
+            }
+
+            /* Unmap the hive */
+            //MmPapFreePages(KeyHive->ImageBase, 1);
+            EfiPrintf(L"Leaking hive memory\r\n");
+
+            /* Free the hive and hive path */
+            BlMmFreeHeap(KeyHive->FilePath);
+            BlMmFreeHeap(KeyHive);
+        }
+
+        /* Check if a key name is present */
+        if (KeyObject->KeyName)
+        {
+            /* Free it */
+            BlMmFreeHeap(KeyObject->KeyName);
+        }
+    }
+
+    /* Free the object */
+    BlMmFreeHeap(KeyObject);
+}
+
+NTSTATUS
+BiOpenKey(
+    _In_ HANDLE ParentHandle,
+    _In_ PWCHAR KeyName,
+    _Out_ PHANDLE Handle
+    )
+{
+    PBI_KEY_OBJECT ParentKey, NewKey;
+    PBI_KEY_HIVE ParentHive;
+    NTSTATUS Status;
+    ULONG NameLength, SubNameLength, NameBytes;
+    PWCHAR NameStart, NameBuffer;
+    UNICODE_STRING KeyString;
+    HCELL_INDEX KeyCell;
+    PHHIVE Hive;
+    PCM_KEY_NODE ParentNode;
+
+    /* Convert from a handle to our key object */
+    ParentKey = (PBI_KEY_OBJECT)ParentHandle;
+
+    /* Extract the hive and node information */
+    ParentHive = ParentKey->KeyHive;
+    ParentNode = ParentKey->KeyNode;
+    Hive = &ParentKey->KeyHive->Hive.Hive;
+
+    /* Initialize variables */
+    KeyCell = HCELL_NIL;
+    Status = STATUS_SUCCESS;
+    NameBuffer = NULL;
+
+    /* Loop as long as there's still portions of the key name in play */
+    NameLength = wcslen(KeyName);
+    while (NameLength)
+    {
+        /* Find the first path separator */
+        NameStart = wcschr(KeyName, OBJ_NAME_PATH_SEPARATOR);
+        if (NameStart)
+        {
+            /* Look only at the key before the separator */
+            SubNameLength = NameStart - KeyName;
+            ++NameStart;
+        }
+        else
+        {
+            /* No path separator, this is the final leaf key */
+            SubNameLength = NameLength;
+        }
+
+        /* Free the name buffer from the previous pass if needed */
+        if (NameBuffer)
+        {
+            BlMmFreeHeap(NameBuffer);
+        }
+
+        /* Allocate a buffer to hold the name of this specific subkey only */
+        NameBytes = SubNameLength * sizeof(WCHAR);
+        NameBuffer = BlMmAllocateHeap(NameBytes + sizeof(UNICODE_NULL));
+        if (!NameBuffer)
+        {
+            Status = STATUS_NO_MEMORY;
+            goto Quickie;
+        }
+
+        /* Copy and null-terminate the name of the subkey */
+        RtlCopyMemory(NameBuffer, KeyName, NameBytes);
+        NameBuffer[SubNameLength] = UNICODE_NULL;
+
+        /* Convert it into a UNICODE_STRING and try to find it */
+        RtlInitUnicodeString(&KeyString, NameBuffer);
+        KeyCell = CmpFindSubKeyByName(Hive, ParentNode, &KeyString);
+        if (KeyCell == HCELL_NIL)
+        {
+            Status = STATUS_OBJECT_NAME_NOT_FOUND;
+            goto Quickie;
+        }
+
+        /* We found it -- get the key node out of it */
+        ParentNode = (PCM_KEY_NODE)HvGetCell(Hive, KeyCell);
+        if (!ParentNode)
+        {
+            Status = STATUS_REGISTRY_CORRUPT;
+            goto Quickie;
+        }
+
+        /* Update the key name to the next remaining path element */
+        KeyName = NameStart;
+        if (NameStart)
+        {
+            /* Update the length to the remainder of the path */
+            NameLength += -1 - SubNameLength;
+        }
+        else
+        {
+            /* There's nothing left, this was the leaf key */
+            NameLength = 0;
+        }
+    }
+
+    /* Allocate a key object */
+    NewKey = BlMmAllocateHeap(sizeof(*NewKey));
+    if (!NewKey)
+    {
+        /* Bail out if we had no memory for it */
+        Status = STATUS_NO_MEMORY;
+        goto Quickie;
+    }
+
+    /* Fill out the key object data */
+    NewKey->KeyNode = ParentNode;
+    NewKey->KeyHive = ParentHive;
+    NewKey->KeyName = NameBuffer;
+    NewKey->KeyCell = KeyCell;
+
+    /* Add a reference to the hive */
+    ++ParentHive->ReferenceCount;
+
+    /* Return the object back to the caller */
+    *Handle = NewKey;
+
+Quickie:
+    /* If we had a name buffer, free it */
+    if (NameBuffer)
+    {
+        BlMmFreeHeap(NameBuffer);
+    }
+
+    /* Return status of the open operation */
+    return Status;
+}
+
+NTSTATUS
+BiInitializeAndValidateHive (
+    _In_ PBI_KEY_HIVE Hive
+    )
+{
+    ULONG HiveSize;
+    NTSTATUS Status;
+
+    /* Make sure the hive is at least the size of a base block */
+    if (Hive->HiveSize < sizeof(HBASE_BLOCK))
+    {
+        return STATUS_REGISTRY_CORRUPT;
+    }
+
+    /* Make sure that the base block accurately describes the size of the hive */
+    HiveSize = Hive->BaseBlock->Length + sizeof(HBASE_BLOCK);
+    if ((HiveSize < sizeof(HBASE_BLOCK)) || (HiveSize > Hive->HiveSize))
+    {
+        return STATUS_REGISTRY_CORRUPT;
+    }
+
+    /* Initialize a flat memory hive */
+    RtlZeroMemory(&Hive->Hive, sizeof(Hive->Hive));
+    Status = HvInitialize(&Hive->Hive.Hive,
+                          HINIT_FLAT,
+                          0,
+                          0,
+                          Hive->BaseBlock,
+                          CmpAllocate,
+                          CmpFree,
+                          NULL,
+                          NULL,
+                          NULL,
+                          NULL,
+                          0,
+                          NULL);
+    if (NT_SUCCESS(Status))
+    {
+        /* Cleanup volatile/old data */
+        CmPrepareHive(&Hive->Hive.Hive); // CmCheckRegistry 
+        Status = STATUS_SUCCESS;
+    }
+
+    /* Return the final status */
+    return Status;
+}
+
+NTSTATUS
+BiLoadHive (
+    _In_ PBL_FILE_PATH_DESCRIPTOR FilePath,
+    _Out_ PHANDLE HiveHandle
+    )
+{
+    ULONG DeviceId;
+    PHBASE_BLOCK BaseBlock, NewBaseBlock;
+    PBI_KEY_OBJECT KeyObject;
+    PBI_KEY_HIVE BcdHive;
+    PBL_DEVICE_DESCRIPTOR BcdDevice;
+    ULONG PathLength, DeviceLength, HiveSize, HiveLength, NewHiveSize;
+    PWCHAR HiveName, LogName;
+    BOOLEAN HaveWriteAccess;
+    NTSTATUS Status;
+    PVOID LogData;
+    PHHIVE Hive;
+    UNICODE_STRING KeyString;
+    PCM_KEY_NODE RootNode;
+    HCELL_INDEX CellIndex;
+
+    /* Initialize variables */
+    DeviceId = -1;
+    BaseBlock = NULL;
+    BcdHive = NULL;
+    KeyObject = NULL;
+    LogData = NULL;
+    LogName = NULL;
+
+    /* Initialize the crypto seed */
+    if (!BiHiveHashLibraryInitialized)
+    {
+        HvSymcryptSeed = 0x82EF4D887A4E55C5;
+        BiHiveHashLibraryInitialized = TRUE;
+    }
+
+    /* Extract and validate the input path */
+    BcdDevice = (PBL_DEVICE_DESCRIPTOR)&FilePath->Path;
+    PathLength = FilePath->Length;
+    DeviceLength = BcdDevice->Size;
+    HiveName = (PWCHAR)((ULONG_PTR)BcdDevice + BcdDevice->Size);
+    if (PathLength <= DeviceLength)
+    {
+        /* Doesn't make sense, bail out */
+        Status = STATUS_INVALID_PARAMETER;
+        goto Quickie;
+    }
+
+    /* Attempt to open the underlying device for RW access */
+    HaveWriteAccess = TRUE;
+    Status = BlpDeviceOpen(BcdDevice,
+                           BL_DEVICE_READ_ACCESS | BL_DEVICE_WRITE_ACCESS,
+                           0,
+                           &DeviceId);
+    if (!NT_SUCCESS(Status))
+    {
+        /* Try for RO access instead */
+        HaveWriteAccess = FALSE;
+        Status = BlpDeviceOpen(BcdDevice, BL_DEVICE_READ_ACCESS, 0, &DeviceId);
+        if (!NT_SUCCESS(Status))
+        {
+            /* No access at all -- bail out */
+            goto Quickie;
+        }
+    }
+
+    /* Now try to load the hive on disk */
+    Status = BlImgLoadImageWithProgress2(DeviceId,
+                                         BlLoaderRegistry,
+                                         HiveName,
+                                         (PVOID*)&BaseBlock,
+                                         &HiveSize,
+                                         0,
+                                         FALSE,
+                                         NULL,
+                                         NULL);
+    if (!NT_SUCCESS(Status))
+    {
+        EfiPrintf(L"Hive read failure: % lx\r\n", Status);
+        goto Quickie;
+    }
+
+    /* Allocate a hive structure */
+    BcdHive = BlMmAllocateHeap(sizeof(*BcdHive));
+    if (!BcdHive)
+    {
+        Status = STATUS_NO_MEMORY;
+        goto Quickie;
+    }
+
+    /* Initialize it */
+    RtlZeroMemory(BcdHive, sizeof(*BcdHive));
+    BcdHive->BaseBlock = BaseBlock;
+    BcdHive->HiveSize = HiveSize;
+    if (HaveWriteAccess)
+    {
+        BcdHive->Flags |= BI_HIVE_WRITEABLE;
+    }
+
+    /* Make sure the hive was at least one bin long */
+    if (HiveSize < sizeof(*BaseBlock))
+    {
+        Status = STATUS_REGISTRY_CORRUPT;
+        goto Quickie;
+    }
+
+    /* Make sure the hive contents are at least one bin long */
+    HiveLength = BaseBlock->Length;
+    if (BaseBlock->Length < sizeof(*BaseBlock))
+    {
+        Status = STATUS_REGISTRY_CORRUPT;
+        goto Quickie;
+    }
+
+    /* Validate the initial bin (the base block) */
+    if (!HvIsInPlaceBaseBlockValid(BaseBlock))
+    {
+        EfiPrintf(L"Recovery not implemented\r\n");
+        Status = STATUS_REGISTRY_CORRUPT;
+        goto Quickie;
+    }
+
+    /* Check if there's log recovery that needs to happen */
+    if (BaseBlock->Sequence1 != BaseBlock->Sequence2)
+    {
+        EfiPrintf(L"Log fix not implemented: %lx %lx\r\n");
+        Status = STATUS_REGISTRY_CORRUPT;
+        goto Quickie;
+    }
+
+    /*
+     * Check if the whole hive doesn't fit in the buffer.
+     * Note: HiveLength does not include the size of the baseblock itself
+     */
+    if (HiveSize < (HiveLength + sizeof(*BaseBlock)))
+    {
+        EfiPrintf(L"Need bigger hive buffer path\r\n");
+
+        /* Allocate a slightly bigger buffer */
+        NewHiveSize = HiveLength + sizeof(*BaseBlock);
+        Status = MmPapAllocatePagesInRange((PVOID*)&NewBaseBlock,
+                                           BlLoaderRegistry,
+                                           NewHiveSize >> PAGE_SHIFT,
+                                           0,
+                                           0,
+                                           NULL,
+                                           0);
+        if (!NT_SUCCESS(Status))
+        {
+            goto Quickie;
+        }
+
+        /* Copy the current data in there */
+        RtlCopyMemory(NewBaseBlock, BaseBlock, HiveSize);
+
+        /* Free the old data */
+        EfiPrintf(L"Leaking old hive buffer\r\n");
+        //MmPapFreePages(BaseBlock, 1);
+
+        /* Update our pointers */
+        BaseBlock = NewBaseBlock;
+        HiveSize = NewHiveSize;
+        BcdHive->BaseBlock = BaseBlock;
+        BcdHive->HiveSize = HiveSize;
+    }
+
+    /* Check if any log stuff needs to happen */
+    if (LogData)
+    {
+        EfiPrintf(L"Log fix not implemented: %lx %lx\r\n");
+        Status = STATUS_REGISTRY_CORRUPT;
+        goto Quickie;
+    }
+
+    /* Call Hv to setup the hive library */
+    Status = BiInitializeAndValidateHive(BcdHive);
+    if (!NT_SUCCESS(Status))
+    {
+        goto Quickie;
+    }
+
+    /* Now get the root node */
+    Hive = &BcdHive->Hive.Hive;
+    RootNode = (PCM_KEY_NODE)HvGetCell(Hive, Hive->BaseBlock->RootCell);
+    if (!RootNode)
+    {
+        Status = STATUS_OBJECT_NAME_NOT_FOUND;
+        goto Quickie;
+    }
+
+    /* Find the Objects subkey under it to see if it's a real BCD hive */
+    RtlInitUnicodeString(&KeyString, L"Objects");
+    CellIndex = CmpFindSubKeyByName(Hive, RootNode, &KeyString);
+    if (CellIndex == HCELL_NIL)
+    {
+        EfiPrintf(L"No OBJECTS subkey found!\r\n");
+        Status = STATUS_OBJECT_NAME_NOT_FOUND;
+        goto Quickie;
+    }
+
+    /* This is a valid BCD hive, store its root node here */
+    BcdHive->RootNode = RootNode;
+
+    /* Allocate a copy of the file path */
+    BcdHive->FilePath = BlMmAllocateHeap(FilePath->Length);
+    if (!BcdHive->FilePath)
+    {
+        Status = STATUS_NO_MEMORY;
+        goto Quickie;
+    }
+
+    /* Make a copy of it */
+    RtlCopyMemory(BcdHive->FilePath, FilePath, FilePath->Length);
+
+    /* Create a key object to describe the rot */
+    KeyObject = BlMmAllocateHeap(sizeof(*KeyObject));
+    if (!KeyObject)
+    {
+        Status = STATUS_NO_MEMORY;
+        goto Quickie;
+    }
+
+    /* Fill out the details */
+    KeyObject->KeyNode = RootNode;
+    KeyObject->KeyHive = BcdHive;
+    KeyObject->KeyName = NULL;
+    KeyObject->KeyCell = Hive->BaseBlock->RootCell;
+
+    /* One reference for the key object, plus one lifetime reference */
+    BcdHive->ReferenceCount = 2;
+
+    /* This is the hive handle */
+    *HiveHandle  = KeyObject;
+
+    /* We're all good */
+    Status = STATUS_SUCCESS;
+
+Quickie:
+    /* If we had a log name, free it */
+    if (LogName)
+    {
+        BlMmFreeHeap(LogName);
+    }
+
+    /* If we had logging data, free it */
+    if (LogData)
+    {
+        EfiPrintf(L"Leaking log buffer\r\n");
+        //MmPapFreePages(LogData, 1);
+    }
+
+    /* Check if this is the failure path */
+    if (!NT_SUCCESS(Status))
+    {
+        /* If we mapped the hive, free it */
+        if (BaseBlock)
+        {
+            EfiPrintf(L"Leaking base block on failure\r\n");
+            //MmPapFreePages(BaseBlock, 1u);
+        }
+
+        /* If we opened the device, close it */
+        if (DeviceId != -1)
+        {
+            BlDeviceClose(DeviceId);
+        }
+
+        /* Did we create a hive object? */
+        if (BcdHive)
+        {
+            /* Free the file path if we made a copy of it */
+            if (BcdHive->FilePath)
+            {
+                BlMmFreeHeap(BcdHive->FilePath);
+            }
+
+            /* Free the hive itself */
+            BlMmFreeHeap(BcdHive);
+        }
+
+        /* Finally, free the root key object if we created one */
+        if (KeyObject)
+        {
+            BlMmFreeHeap(KeyObject);
+        }
+    }
+
+    /* Return the final status */
+    return Status;
+}
+
+NTSTATUS
+BiGetRegistryValue (
+    _In_ HANDLE KeyHandle,
+    _In_ PWCHAR ValueName,
+    _In_ PWCHAR KeyName,
+    _In_ ULONG Type,
+    _Out_ PVOID* Buffer,
+    _Out_ PULONG ValueLength
+    )
+{
+    PCM_KEY_NODE KeyNode;
+    PHHIVE KeyHive;
+    UNICODE_STRING ValueString;
+    PBI_KEY_OBJECT KeyObject;
+    PCM_KEY_VALUE KeyValue;
+    PVOID ValueCopy;
+    ULONG Size;
+    HCELL_INDEX CellIndex;
+    PCELL_DATA ValueData;
+
+    /* Get the key object, node,and hive */
+    KeyObject = (PBI_KEY_OBJECT)KeyHandle;
+    KeyNode = KeyObject->KeyNode;
+    KeyHive = &KeyObject->KeyHive->Hive.Hive;
+
+    /* Find the value cell index in the list of values */
+    RtlInitUnicodeString(&ValueString, ValueName);
+    CmpFindNameInList(KeyHive,
+                      &KeyNode->ValueList,
+                      &ValueString,
+                      NULL,
+                      &CellIndex);
+    if (CellIndex == HCELL_NIL)
+    {
+        return STATUS_OBJECT_NAME_NOT_FOUND;
+    }
+
+    /* Get the cell data for it */
+    KeyValue = (PCM_KEY_VALUE)HvGetCell(KeyHive, CellIndex);
+    if (!KeyValue)
+    {
+        return STATUS_REGISTRY_CORRUPT;
+    }
+
+    /* Make sure the type matches */
+    if (KeyValue->Type != Type)
+    {
+        return STATUS_OBJECT_TYPE_MISMATCH;
+    }
+
+    /* Now get the data cell */
+    ValueData = CmpValueToData(KeyHive, KeyValue, &Size);
+
+    /* Make a copy of it */
+    ValueCopy = BlMmAllocateHeap(Size);
+    if (!ValueCopy)
+    {
+        return STATUS_NO_MEMORY;
+    }
+
+    /* Copy it in the buffer, and return it and its size */
+    RtlCopyMemory(ValueCopy, ValueData, Size);
+    *Buffer = ValueCopy;
+    *ValueLength = Size;
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+BiEnumerateSubKeys (
+    _In_ HANDLE KeyHandle,
+    _Out_ PWCHAR** SubKeyList,
+    _Out_ PULONG SubKeyCount
+    )
+{
+    PCM_KEY_NODE KeyNode, Node;
+    PBI_KEY_OBJECT KeyObject;
+    ULONG KeyCount;
+    ULONG NameLength, NewTotalNameLength, FinalLength, TotalNameLength;
+    PHHIVE Hive;
+    PWCHAR KeyName, NameEnd;
+    HCELL_INDEX CellIndex;
+    PWCHAR* SubKeys;
+    NTSTATUS Status;
+    ULONG i;
+
+    /* Get the key object, node, and hive */
+    KeyObject = (PBI_KEY_OBJECT)KeyHandle;
+    KeyNode = KeyObject->KeyNode;
+    Hive = &KeyObject->KeyHive->Hive.Hive;
+
+    /* Assume it's empty */
+    *SubKeyList = 0;
+    *SubKeyCount = 0;
+
+    /* Initialize locals */
+    KeyCount = 0;
+    SubKeys = 0;
+    TotalNameLength = 0;
+
+    /* Find the first subkey cell index */
+    CellIndex = CmpFindSubKeyByNumber(Hive, KeyNode, KeyCount);
+    while (CellIndex != HCELL_NIL)
+    {
+        /* Move to the next one */
+        KeyCount++;
+
+        /* Get the cell data for it */
+        Node = (PCM_KEY_NODE)HvGetCell(Hive, CellIndex);
+        if (!Node)
+        {
+            return STATUS_REGISTRY_CORRUPT;
+        }
+
+        /* Check if the value is compressed */
+        if (Node->Flags & KEY_COMP_NAME)
+        {
+            /* Get the compressed name size */
+            NameLength = CmpCompressedNameSize(Node->Name, Node->NameLength);
+        }
+        else
+        {
+            /* Get the real size */
+            NameLength = Node->NameLength;
+        }
+
+        /* Add up the new length, protecting against overflow */
+        NewTotalNameLength = TotalNameLength + NameLength + sizeof(UNICODE_NULL);
+        if (NewTotalNameLength < TotalNameLength)
+        {
+            Status = STATUS_NAME_TOO_LONG;
+            goto Quickie;
+        }
+
+        /* We're good, use the new length */
+        TotalNameLength = NewTotalNameLength;
+
+        /* Find the next subkey cell index */
+        CellIndex = CmpFindSubKeyByNumber(Hive, KeyNode, KeyCount);
+    }
+
+    /* Were there no keys? We're done, if so */
+    if (!KeyCount)
+    {
+        return STATUS_SUCCESS;
+    }
+
+    /* Safely compute the size of the array needed */
+    Status = RtlULongLongToULong(sizeof(PWCHAR) * KeyCount, &FinalLength);
+    if (!NT_SUCCESS(Status))
+    {
+        goto Quickie;
+    }
+
+    /* Safely add that to the name length */
+    Status = RtlULongAdd(TotalNameLength, FinalLength, &FinalLength);
+    if (!NT_SUCCESS(Status))
+    {
+        goto Quickie;
+    }
+
+    /* Allocate an array big enough for the names and pointers */
+    SubKeys = BlMmAllocateHeap(FinalLength);
+    if (!SubKeys)
+    {
+        Status = STATUS_NO_MEMORY;
+        goto Quickie;
+    }
+
+    /* Go over each key again */
+    NameEnd = (PWCHAR)&SubKeys[KeyCount];
+    for (i = 0; i < KeyCount; i++)
+    {
+        /* Get the cell index for this subkey */
+        CellIndex = CmpFindSubKeyByNumber(Hive, KeyNode, i);
+        if (CellIndex == HCELL_NIL)
+        {
+            break;
+        }
+
+        /* Get the cell data for it */
+        Node = HvGetCell(Hive, CellIndex);
+        if (!Node)
+        {
+            Status = STATUS_REGISTRY_CORRUPT;
+            goto Quickie;
+        }
+
+        /* Check if the value is compressed */
+        KeyName = Node->Name;
+        if (Node->Flags & KEY_COMP_NAME)
+        {
+            /* Get the compressed name size */
+            NameLength = CmpCompressedNameSize(KeyName, Node->NameLength);
+            CmpCopyCompressedName(NameEnd, NameLength, KeyName, Node->NameLength);
+        }
+        else
+        {
+            /* Get the real size */
+            NameLength = Node->NameLength;
+            RtlCopyMemory(NameEnd, KeyName, NameLength);
+        }
+
+        /* Move the name buffer to the next spot, and NULL-terminate */
+        SubKeys[i] = NameEnd;
+        NameEnd += (NameLength / sizeof(WCHAR));
+        *NameEnd = UNICODE_NULL;
+
+        /* Keep going */
+        NameEnd++;
+    }
+
+    /* Check if the subkeys were empty */
+    if (i == 0)
+    {
+        /* They disappeared in the middle of enumeration */
+        Status = STATUS_OBJECT_NAME_NOT_FOUND;
+        goto Quickie;
+    }
+
+    /* Return the count and the array of names */
+    *SubKeyList = SubKeys;
+    *SubKeyCount = i;
+    SubKeys = NULL;
+    Status = STATUS_SUCCESS;
+
+Quickie:
+    /* On the failure path, free the subkeys if any exist */
+    if (SubKeys)
+    {
+        BlMmFreeHeap(SubKeys);
+    }
+
+    /* All done, return the result */
+    return Status;
+}
+
index d7519fc..bc679a1 100644 (file)
@@ -9,6 +9,7 @@
 /* INCLUDES ******************************************************************/
 
 #include "bl.h"
+#include "bcd.h"
 
 /* DATA VARIABLES ************************************************************/
 
@@ -38,7 +39,35 @@ BlMmRemoveBadMemory (
     VOID
     )
 {
-    /* FIXME: Read BCD option to see what bad memory to remove */
+    BOOLEAN AllowBad;
+    NTSTATUS Status;
+    PULONGLONG BadPages;
+    ULONGLONG BadPageCount;
+
+    /* First check if bad memory access is allowed */
+    AllowBad = FALSE;
+    Status = BlGetBootOptionBoolean(BlpApplicationEntry.BcdData,
+                                    BcdLibraryBoolean_AllowBadMemoryAccess,
+                                    &AllowBad);
+    if ((NT_SUCCESS(Status)) && (AllowBad))
+    {
+        /* No point checking the list if it is */
+        return STATUS_SUCCESS;
+    }
+
+    /* Otherwise, check if there's a persisted bad page list */
+    Status = BlpGetBootOptionIntegerList(BlpApplicationEntry.BcdData,
+                                         BcdLibraryIntegerList_BadMemoryList,
+                                         &BadPages,
+                                         &BadPageCount,
+                                         TRUE);
+    if (NT_SUCCESS(Status))
+    {
+        EfiPrintf(L"Persistent bad page list not supported\r\n");
+        return STATUS_NOT_IMPLEMENTED;
+    }
+
+    /* All done here */
     return STATUS_SUCCESS;
 }
 
index 55314c1..2b682a1 100644 (file)
@@ -9,7 +9,7 @@
 /* INCLUDES ******************************************************************/
 
 #include "bl.h"
-
+#include "bcd.h"
 
 typedef struct _BL_PA_REQUEST
 {
@@ -50,7 +50,30 @@ BlpMmInitializeConstraints (
     VOID
     )
 {
-    /* FIXME: Read BCD option 'avoidlowmemory' and 'truncatememory' */
+    NTSTATUS Status;
+    ULONGLONG LowestAddressValid, HighestAddressValid;
+
+    /* Check for LOWMEM */
+    Status = BlGetBootOptionInteger(BlpApplicationEntry.BcdData,
+                                    BcdLibraryInteger_AvoidLowPhysicalMemory,
+                                    &LowestAddressValid);
+    if (NT_SUCCESS(Status))
+    {
+        EfiPrintf(L"/LOWMEM not supported\r\n");
+        return STATUS_NOT_IMPLEMENTED;
+    }
+
+    /* Check for MAXMEM */
+    Status = BlGetBootOptionInteger(BlpApplicationEntry.BcdData,
+                                    BcdLibraryInteger_TruncatePhysicalMemory,
+                                    &HighestAddressValid);
+    if (NT_SUCCESS(Status))
+    {
+        EfiPrintf(L"/MAXMEM not supported\r\n");
+        return STATUS_NOT_IMPLEMENTED;
+    }
+
+    /* Return back to the caller */
     return STATUS_SUCCESS;
 }