/* INCLUDES ******************************************************************/
#include "bl.h"
+#include <bcd.h>
/* FUNCTIONS *****************************************************************/
)
{
ULONG_PTR NextOption = 0, ListOption;
- PBL_BCD_OPTION Option;
+ PBL_BCD_OPTION Option, FoundOption;
/* No options, bail out */
if (!List)
}
/* Loop while we find an option */
- while (TRUE)
+ 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;
}
Option = MiscGetBootOption((PBL_BCD_OPTION)((ULONG_PTR)Option +
ListOption),
Type);
-
- /* Found one, return it */
if (Option)
{
- return 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);
}
- /* We found the option, return it */
- return Option;
+ /* 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
{
/* 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 */
AppIdentifier = BlGetApplicationIdentifier();
Status = BlpBootOptionCallbackString(AppIdentifier, Type, String, StringLength, &String, &StringLength);
#else
- Status = STATUS_SUCCESS;
#endif
-
/* Check if we have space for one more character */
CopyLength = StringLength + 1;
if (CopyLength < StringLength)
CopyLength = -1;
Status = STATUS_INTEGER_OVERFLOW;
}
- else
- {
- /* Go ahead */
- Status = STATUS_SUCCESS;
- }
/* No overflow? */
if (NT_SUCCESS(Status))
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;
+
+ /* Make sure this is a BCD_DEVICE */
+ if ((Type & 0xF000000) != 0x1000000)
+ {
+ 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,
return Status;
}
-/*++
- * @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
+#define BI_FLUSH_HIVE 0x01
+
+typedef struct _BI_KEY_HIVE
+{
+ PVOID ImageBase;
+ PBL_FILE_PATH_DESCRIPTOR FilePath;
+ CMHIVE Hive;
+ LONG ReferenceCount;
+ ULONG Flags;
+} 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;
+
+PVOID
+NTAPI
+CmpAllocate (
+ _In_ SIZE_T Size,
+ _In_ BOOLEAN Paged,
+ _In_ ULONG Tag
)
{
- ULONG Size = 0, NextOffset = 0;
- PBL_BCD_OPTION NextOption;
+ UNREFERENCED_PARAMETER(Paged);
+ UNREFERENCED_PARAMETER(Tag);
- /* Loop all the options*/
- do
+ /* 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);
+}
+
+FORCEINLINE
+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))
{
- /* Move to the next one */
- NextOption = (PBL_BCD_OPTION)((ULONG_PTR)BcdOption + NextOffset);
+ /* 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);
+ }
- /* Compute the size of the next one */
- Size += BlGetBootOptionSize(NextOption);
+ /* Unmap the hive */
+ //MmPapFreePages(KeyHive->ImageBase, 1);
+ EfiPrintf(L"Leaking hive memory\r\n");
- /* Update the offset */
- NextOffset = NextOption->NextEntryOffset;
- } while (NextOffset != 0);
+ /* Free the hive and hive path */
+ BlMmFreeHeap(KeyHive->FilePath);
+ BlMmFreeHeap(KeyHive);
+ }
- /* Return final computed size */
- return Size;
+ /* Check if a key name is present */
+ if (KeyObject->KeyName)
+ {
+ /* Free it */
+ BlMmFreeHeap(KeyObject->KeyName);
+ }
+ }
+
+ /* Free the object */
+ BlMmFreeHeap(KeyObject);
}
-/*++
- * @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
+NTSTATUS
+BiOpenKey(
+ _In_ HANDLE ParentHandle,
+ _In_ PWCHAR KeyName,
+ _Out_ PHANDLE Handle
)
{
- ULONG Size, Offset;
+ 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;
- /* Check if there's any data */
- if (BcdOption->DataOffset != 0)
+ /* Loop as long as there's still portions of the key name in play */
+ NameLength = wcslen(KeyName);
+ while (NameLength)
{
- /* Add the size of the data */
- Size = BcdOption->DataOffset + BcdOption->DataSize;
+ /* 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)Hive->GetCellRoutine(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
+BiLoadHive (
+ _In_ PBL_FILE_PATH_DESCRIPTOR FilePath,
+ _Out_ PHANDLE HiveHandle
+ )
+{
+ /* This is TODO */
+ EfiPrintf(L"Loading a hive is not yet implemented\r\n");
+ *HiveHandle = NULL;
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS
+BiAddStoreFromFile (
+ _In_ PBL_FILE_PATH_DESCRIPTOR FilePath,
+ _Out_ PHANDLE StoreHandle
+ )
+{
+ NTSTATUS Status;
+ HANDLE HiveHandle, KeyHandle;
+
+ /* Load the specified hive */
+ Status = BiLoadHive(FilePath, &HiveHandle);
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+
+ /* Open the description key to make sure this is really a BCD */
+ Status = BiOpenKey(HiveHandle, L"Description", &KeyHandle);
+ if (NT_SUCCESS(Status))
+ {
+ /* It is -- close the key as we don't need it */
+ BiCloseKey(KeyHandle);
+ *StoreHandle = HiveHandle;
}
else
{
- /* No data, just the structure itself */
- Size = sizeof(*BcdOption);
+ /* Failure, drop a reference on the hive and close the key */
+ BiDereferenceHive(HiveHandle);
+ BiCloseKey(HiveHandle);
}
- /* Any associated options? */
- Offset = BcdOption->ListOffset;
- if (Offset != 0)
+ /* Return the status */
+ return Status;
+}
+
+NTSTATUS
+BcdOpenStoreFromFile (
+ _In_ PUNICODE_STRING FileName,
+ _In_ PHANDLE StoreHandle
+ )
+{
+ ULONG Length;
+ PBL_FILE_PATH_DESCRIPTOR FilePath;
+ NTSTATUS Status;
+ HANDLE LocalHandle;
+
+ /* Assume failure */
+ LocalHandle = NULL;
+ EfiPrintf(L"Opening BCD store: %wZ\n", FileName);
+
+ /* Allocate a path descriptor */
+ Length = FileName->Length + sizeof(*FilePath);
+ FilePath = BlMmAllocateHeap(Length);
+ if (!FilePath)
{
- /* Go get those too */
- Size += BlGetBootOptionListSize((PVOID)((ULONG_PTR)BcdOption + Offset));
+ return STATUS_NO_MEMORY;
}
- /* Return the final size */
- return Size;
+ /* Initialize it */
+ FilePath->Version = 1;
+ FilePath->PathType = InternalPath;
+ FilePath->Length = Length;
+
+ /* Copy the name and NULL-terminate it */
+ RtlCopyMemory(FilePath->Path, FileName->Buffer, Length);
+ FilePath->Path[Length / sizeof(WCHAR)] = UNICODE_NULL;
+
+ /* Open the BCD */
+ Status = BiAddStoreFromFile(FilePath, &LocalHandle);
+ if (NT_SUCCESS(Status))
+ {
+ /* Return the handle on success */
+ *StoreHandle = LocalHandle;
+ }
+
+ /* Free the descriptor and return the status */
+ BlMmFreeHeap(FilePath);
+ return Status;
}
+