--- /dev/null
+/*
+ * COPYRIGHT: See COPYING.ARM in the top level directory
+ * PROJECT: ReactOS UEFI Boot Library
+ * FILE: boot/environ/lib/firmware/efi/firmware.c
+ * PURPOSE: Boot Library Firmware Initialization for EFI
+ * PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
+ */
+
+/* INCLUDES ******************************************************************/
+
+#include "bl.h"
+
+/* DATA VARIABLES ************************************************************/
+
+PBL_FIRMWARE_DESCRIPTOR EfiFirmwareParameters;
+BL_FIRMWARE_DESCRIPTOR EfiFirmwareData;
+EFI_HANDLE EfiImageHandle;
+EFI_SYSTEM_TABLE* EfiSystemTable;
+
+EFI_SYSTEM_TABLE *EfiST;
+EFI_BOOT_SERVICES *EfiBS;
+EFI_RUNTIME_SERVICES *EfiRT;
+EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *EfiConOut;
+EFI_SIMPLE_TEXT_INPUT_PROTOCOL *EfiConIn;
+EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *EfiConInEx;
+PHYSICAL_ADDRESS EfiRsdt;
+
+EFI_GUID EfiGraphicsOutputProtocol = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
+EFI_GUID EfiUgaDrawProtocol = EFI_UGA_DRAW_PROTOCOL_GUID;
+EFI_GUID EfiLoadedImageProtocol = EFI_LOADED_IMAGE_PROTOCOL_GUID;
+EFI_GUID EfiDevicePathProtocol = EFI_DEVICE_PATH_PROTOCOL_GUID;
+EFI_GUID EfiSimpleTextInputExProtocol = EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID;
+EFI_GUID EfiBlockIoProtocol = EFI_BLOCK_IO_PROTOCOL_GUID;
+EFI_GUID EfiRootAcpiTableGuid = EFI_ACPI_20_TABLE_GUID;
+EFI_GUID EfiRootAcpiTable10Guid = EFI_ACPI_TABLE_GUID;
+EFI_GUID EfiGlobalVariable = EFI_GLOBAL_VARIABLE;
+EFI_GUID BlpEfiSecureBootPrivateNamespace = { 0x77FA9ABD , 0x0359, 0x4D32, { 0xBD, 0x60, 0x28, 0xF4, 0xE7, 0x8F, 0x78, 0x4B } };
+
+WCHAR BlScratchBuffer[8192];
+
+BOOLEAN BlpFirmwareChecked;
+BOOLEAN BlpFirmwareEnabled;
+
+/* FUNCTIONS *****************************************************************/
+
+EFI_DEVICE_PATH *
+EfiIsDevicePathParent (
+ _In_ EFI_DEVICE_PATH *DevicePath1,
+ _In_ EFI_DEVICE_PATH *DevicePath2
+ )
+{
+ EFI_DEVICE_PATH* CurrentPath1;
+ EFI_DEVICE_PATH* CurrentPath2;
+ USHORT Length1, Length2;
+
+ /* Start with the current nodes */
+ CurrentPath1 = DevicePath1;
+ CurrentPath2 = DevicePath2;
+
+ /* Loop each element of the device path */
+ while (!(IsDevicePathEndType(CurrentPath1)) &&
+ !(IsDevicePathEndType(CurrentPath2)))
+ {
+ /* Check if the element has a different length */
+ Length1 = DevicePathNodeLength(CurrentPath1);
+ Length2 = DevicePathNodeLength(CurrentPath2);
+ if (Length1 != Length2)
+ {
+ /* Then they're not related */
+ return NULL;
+ }
+
+ /* Check if the rest of the element data matches */
+ if (RtlCompareMemory(CurrentPath1, CurrentPath2, Length1) != Length1)
+ {
+ /* Nope, not related */
+ return NULL;
+ }
+
+ /* Move to the next element */
+ CurrentPath1 = NextDevicePathNode(CurrentPath1);
+ CurrentPath2 = NextDevicePathNode(CurrentPath2);
+ }
+
+ /* If the last element in path 1 is empty, then path 2 is the child (deeper) */
+ if (!IsDevicePathEndType(CurrentPath1))
+ {
+ return DevicePath2;
+ }
+
+ /* If the last element in path 2 is empty, then path 1 is the child (deeper) */
+ if (!IsDevicePathEndType(CurrentPath2))
+ {
+ return DevicePath1;
+ }
+
+ /* They're both the end, so they're identical, so there's no parent */
+ return NULL;
+}
+
+EFI_DEVICE_PATH*
+EfiGetLeafNode (
+ _In_ EFI_DEVICE_PATH *DevicePath
+ )
+{
+ EFI_DEVICE_PATH *NextDevicePath;
+
+ /* Make sure we're not already at the end */
+ if (!IsDevicePathEndType(DevicePath))
+ {
+ /* Grab the next node element, and keep going until the end */
+ for (NextDevicePath = NextDevicePathNode(DevicePath);
+ !IsDevicePathEndType(NextDevicePath);
+ NextDevicePath = NextDevicePathNode(NextDevicePath))
+ {
+ /* Save the current node we're at */
+ DevicePath = NextDevicePath;
+ }
+ }
+
+ /* This now contains the deepest (leaf) node */
+ return DevicePath;
+}
+
+VOID
+EfiPrintf (
+ _In_ PWCHAR Format,
+ ...
+ )
+{
+ va_list args;
+ va_start(args, Format);
+
+ /* Capture the buffer in our scratch pad, and NULL-terminate */
+ vsnwprintf(BlScratchBuffer, RTL_NUMBER_OF(BlScratchBuffer) - 1, Format, args);
+ BlScratchBuffer[RTL_NUMBER_OF(BlScratchBuffer) - 1] = UNICODE_NULL;
+
+ /* Check which mode we're in */
+ if (CurrentExecutionContext->Mode == BlRealMode)
+ {
+ /* Call EFI directly */
+ EfiConOut->OutputString(EfiConOut, BlScratchBuffer);
+ }
+ else
+ {
+ /* Switch to real mode */
+ BlpArchSwitchContext(BlRealMode);
+
+ /* Call EFI directly */
+ if (EfiConOut != NULL)
+ {
+ EfiConOut->OutputString(EfiConOut, BlScratchBuffer);
+ }
+
+ /* Switch back to protected mode */
+ BlpArchSwitchContext(BlProtectedMode);
+ }
+
+ /* All done */
+ va_end(args);
+}
+
+BOOLEAN EfiProtHashTableInitialized;
+ULONG EfiProtHashTableId;
+
+typedef struct _BL_EFI_PROTOCOL
+{
+ LIST_ENTRY ListEntry;
+ EFI_GUID* Protocol;
+ PVOID Interface;
+ LONG ReferenceCount;
+ BOOLEAN AddressMapped;
+} BL_EFI_PROTOCOL, *PBL_EFI_PROTOCOL;
+
+NTSTATUS
+EfiVmOpenProtocol (
+ _In_ EFI_HANDLE Handle,
+ _In_ EFI_GUID* Protocol,
+ _Outptr_ PVOID* Interface
+ )
+{
+ BOOLEAN AddressMapped;
+ PLIST_ENTRY HashList, NextEntry;
+ PHYSICAL_ADDRESS InterfaceAddress, TranslatedAddress;
+ NTSTATUS Status;
+ BL_HASH_ENTRY HashEntry;
+ PBL_HASH_VALUE HashValue;
+ PBL_EFI_PROTOCOL EfiProtocol;
+ BL_ARCH_MODE OldMode;
+ EFI_STATUS EfiStatus;
+ PVOID InterfaceVa;
+
+ /* Initialize failure paths */
+ AddressMapped = FALSE;
+ HashList = NULL;
+ InterfaceAddress.QuadPart = 0;
+
+ /* Have we initialized the protocol table yet? */
+ if (!EfiProtHashTableInitialized)
+ {
+ /* Nope -- create the hash table */
+ Status = BlHtCreate(0, NULL, NULL, &EfiProtHashTableId);
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+
+ /* Remember for next time */
+ EfiProtHashTableInitialized = TRUE;
+ }
+
+ /* Check if we already have a list of protocols for this handle */
+ HashEntry.Flags = BL_HT_VALUE_IS_INLINE;
+ HashEntry.Size = sizeof(Handle);
+ HashEntry.Value = Handle;
+ Status = BlHtLookup(EfiProtHashTableId, &HashEntry, &HashValue);
+ if (NT_SUCCESS(Status))
+ {
+ /* We do -- the hash value is the list itself */
+ HashList = (PLIST_ENTRY)HashValue->Data;
+ NextEntry = HashList->Flink;
+
+ /* Iterate over it */
+ while (NextEntry != HashList)
+ {
+ /* Get each protocol in the list, checking for a match */
+ EfiProtocol = CONTAINING_RECORD(NextEntry,
+ BL_EFI_PROTOCOL,
+ ListEntry);
+ if (EfiProtocol->Protocol == Protocol)
+ {
+ /* Match found -- add a reference and return it */
+ EfiProtocol->ReferenceCount++;
+ *Interface = EfiProtocol->Interface;
+ return STATUS_SUCCESS;
+ }
+
+ /* Try the next entry */
+ NextEntry = NextEntry->Flink;
+ }
+ }
+
+ /* Switch to real mode for firmware call */
+ OldMode = CurrentExecutionContext->Mode;
+ if (OldMode != BlRealMode)
+ {
+ BlpArchSwitchContext(BlRealMode);
+ }
+
+ /* Check if this is EFI 1.02 */
+ if (EfiST->Hdr.Revision == EFI_1_02_SYSTEM_TABLE_REVISION)
+ {
+ /* Use the old call */
+ EfiStatus = EfiBS->HandleProtocol(Handle,
+ Protocol,
+ (PVOID*)&InterfaceAddress);
+ }
+ else
+ {
+ /* Use the EFI 2.00 API instead */
+ EfiStatus = EfiBS->OpenProtocol(Handle,
+ Protocol,
+ (PVOID*)&InterfaceAddress,
+ EfiImageHandle,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+ }
+
+ /* Switch back to protected mode if needed */
+ if (OldMode != BlRealMode)
+ {
+ BlpArchSwitchContext(OldMode);
+ }
+
+ /* Check the result, and bail out on failure */
+ Status = EfiGetNtStatusCode(EfiStatus);
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+
+ /* Check what address the interface lives at, and translate it */
+ InterfaceVa = (PVOID)InterfaceAddress.LowPart;
+ if (BlMmTranslateVirtualAddress(InterfaceVa, &TranslatedAddress))
+ {
+ /* We expect firmware to be 1:1 mapped, fail if not */
+ if (InterfaceAddress.QuadPart != TranslatedAddress.QuadPart)
+ {
+ return STATUS_NOT_SUPPORTED;
+ }
+ }
+ else
+ {
+ /* Create a virtual (1:1) mapping for the interface */
+ Status = BlMmMapPhysicalAddressEx(&InterfaceVa,
+ BlMemoryFixed,
+ PAGE_SIZE,
+ InterfaceAddress);
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+
+ /* Remember for cleanup */
+ AddressMapped = TRUE;
+ }
+
+ /* The caller now has the interface */
+ *Interface = InterfaceVa;
+
+ /* Did we already have some protocols on this handle? */
+ if (!HashList)
+ {
+ /* Nope, this is the first time -- so allocate the list */
+ HashList = BlMmAllocateHeap(sizeof(*HashList));
+ if (!HashList)
+ {
+ Status = STATUS_NO_MEMORY;
+ goto Quickie;
+ }
+
+ /* Initialize it */
+ InitializeListHead(HashList);
+
+ /* And then store it in the hash table for this handle */
+ Status = BlHtStore(EfiProtHashTableId,
+ &HashEntry,
+ HashList,
+ sizeof(*HashList));
+ if (!NT_SUCCESS(Status))
+ {
+ BlMmFreeHeap(HashList);
+ goto Quickie;
+ }
+ }
+
+ /* Finally, allocate a protocol tracker structure */
+ EfiProtocol = BlMmAllocateHeap(sizeof(*EfiProtocol));
+ if (!EfiProtocol)
+ {
+ Status = STATUS_NO_MEMORY;
+ goto Quickie;
+ }
+
+ /* And store this information in case the protocol is needed again */
+ EfiProtocol->Protocol = Protocol;
+ EfiProtocol->Interface = *Interface;
+ EfiProtocol->ReferenceCount = 1;
+ EfiProtocol->AddressMapped = AddressMapped;
+ InsertTailList(HashList, &EfiProtocol->ListEntry);
+
+ /* Passthru to success case */
+ AddressMapped = FALSE;
+
+Quickie:
+ /* Failure path -- did we map anything ?*/
+ if (AddressMapped)
+ {
+ /* Get rid of it */
+ BlMmUnmapVirtualAddressEx(InterfaceVa, PAGE_SIZE);
+ *Interface = NULL;
+ }
+
+ /* Return the failure */
+ return Status;
+}
+
+NTSTATUS
+EfiOpenProtocol (
+ _In_ EFI_HANDLE Handle,
+ _In_ EFI_GUID *Protocol,
+ _Outptr_ PVOID* Interface
+ )
+{
+ EFI_STATUS EfiStatus;
+ NTSTATUS Status;
+ BL_ARCH_MODE OldMode;
+
+ /* Are we using virtual memory/ */
+ if (MmTranslationType != BlNone)
+ {
+ /* We need complex tracking to make this work */
+ Status = EfiVmOpenProtocol(Handle, Protocol, Interface);
+ }
+ else
+ {
+ /* Are we in protected mode? */
+ OldMode = CurrentExecutionContext->Mode;
+ if (OldMode != BlRealMode)
+ {
+ /* Switch to real mode */
+ BlpArchSwitchContext(BlRealMode);
+ }
+
+ /* Are we on legacy 1.02? */
+ if (EfiST->FirmwareRevision == EFI_1_02_SYSTEM_TABLE_REVISION)
+ {
+ /* Make the legacy call */
+ EfiStatus = EfiBS->HandleProtocol(Handle, Protocol, Interface);
+ }
+ else
+ {
+ /* Use the UEFI version */
+ EfiStatus = EfiBS->OpenProtocol(Handle,
+ Protocol,
+ Interface,
+ EfiImageHandle,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+
+ /* Switch back to protected mode if we came from there */
+ if (OldMode != BlRealMode)
+ {
+ BlpArchSwitchContext(OldMode);
+ }
+ }
+
+ /* Convert the error to an NTSTATUS */
+ Status = EfiGetNtStatusCode(EfiStatus);
+ }
+
+ /* Clear the interface on failure, and return the status */
+ if (!NT_SUCCESS(Status))
+ {
+ *Interface = NULL;
+ }
+
+ return Status;
+}
+
+NTSTATUS
+EfiVmpCloseProtocol (
+ _In_ EFI_HANDLE Handle,
+ _In_ EFI_GUID* Protocol
+ )
+{
+ EFI_STATUS EfiStatus;
+ BL_ARCH_MODE OldMode;
+
+ /* Are we in protected mode? */
+ OldMode = CurrentExecutionContext->Mode;
+ if (OldMode != BlRealMode)
+ {
+ /* Switch to real mode */
+ BlpArchSwitchContext(BlRealMode);
+ }
+
+ /* Are we on legacy 1.02? */
+ if (EfiST->FirmwareRevision == EFI_1_02_SYSTEM_TABLE_REVISION)
+ {
+ /* Nothing to close */
+ EfiStatus = EFI_SUCCESS;
+ }
+ else
+ {
+ /* Use the UEFI version */
+ EfiStatus = EfiBS->CloseProtocol(Handle,
+ Protocol,
+ EfiImageHandle,
+ NULL);
+
+ /* Normalize not found as success */
+ if (EfiStatus == EFI_NOT_FOUND)
+ {
+ EfiStatus = EFI_SUCCESS;
+ }
+ }
+
+ /* Switch back to protected mode if we came from there */
+ if (OldMode != BlRealMode)
+ {
+ BlpArchSwitchContext(OldMode);
+ }
+
+ /* Convert to NT status */
+ return EfiGetNtStatusCode(EfiStatus);
+}
+
+NTSTATUS
+EfiVmpFreeInterfaceEntry (
+ _In_ EFI_HANDLE Handle,
+ _In_ PBL_EFI_PROTOCOL EfiProtocol
+ )
+{
+ NTSTATUS Status;
+ BL_HASH_ENTRY HashEntry;
+
+ /* Assume success */
+ Status = STATUS_SUCCESS;
+
+ /* Is this the last protocol on this handle? */
+ if (IsListEmpty(&EfiProtocol->ListEntry))
+ {
+ /* Delete the hash table entry for this handle */
+ HashEntry.Value = Handle;
+ HashEntry.Size = sizeof(Handle);
+ HashEntry.Flags = BL_HT_VALUE_IS_INLINE;
+ Status = BlHtDelete(EfiProtHashTableId, &HashEntry);
+
+ /* This will free the list head itself */
+ BlMmFreeHeap(EfiProtocol->ListEntry.Flink);
+ }
+ else
+ {
+ /* Simply remove this entry */
+ RemoveEntryList(&EfiProtocol->ListEntry);
+ }
+
+ /* Had we virtually mapped this protocol? */
+ if (EfiProtocol->AddressMapped)
+ {
+ /* Unmap it */
+ BlMmUnmapVirtualAddressEx(EfiProtocol->Interface, PAGE_SIZE);
+ }
+
+ /* Free the protocol entry, and return */
+ BlMmFreeHeap(EfiProtocol);
+ return Status;
+}
+
+NTSTATUS
+EfiVmCloseProtocol (
+ _In_ EFI_HANDLE Handle,
+ _In_ EFI_GUID* Protocol
+ )
+{
+ BL_HASH_ENTRY HashEntry;
+ PLIST_ENTRY ListHead, NextEntry;
+ NTSTATUS Status, CloseStatus;
+ PBL_HASH_VALUE HashValue;
+ PBL_EFI_PROTOCOL EfiProtocol;
+
+ /* Lookup the list entry for this handle */
+ HashEntry.Size = sizeof(Handle);
+ HashEntry.Flags = BL_HT_VALUE_IS_INLINE;
+ HashEntry.Value = Handle;
+ Status = BlHtLookup(EfiProtHashTableId, &HashEntry, &HashValue);
+ if (!NT_SUCCESS(Status))
+ {
+ /* This handle was never used for any protocols */
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ /* Iterate through the list of opened protocols */
+ ListHead = (PLIST_ENTRY)HashValue->Data;
+ NextEntry = ListHead->Flink;
+ while (NextEntry != ListHead)
+ {
+ /* Get this protocol entry and check for a match */
+ EfiProtocol = CONTAINING_RECORD(NextEntry, BL_EFI_PROTOCOL, ListEntry);
+ if (EfiProtocol->Protocol == Protocol)
+ {
+ /* Drop a reference -- was it the last one? */
+ if (EfiProtocol->ReferenceCount-- == 1)
+ {
+ /* Yep -- free this entry */
+ Status = EfiVmpFreeInterfaceEntry(Handle, EfiProtocol);
+
+ /* Call firmware to close the protocol */
+ CloseStatus = EfiVmpCloseProtocol(Handle, Protocol);
+ if (!NT_SUCCESS(CloseStatus))
+ {
+ /* Override free status if close was a failure */
+ Status = CloseStatus;
+ }
+
+ /* Return final status */
+ return Status;
+ }
+ }
+
+ /* Next entry */
+ NextEntry = NextEntry->Flink;
+ }
+
+ /* This protocol was never opened */
+ return STATUS_INVALID_PARAMETER;
+}
+
+NTSTATUS
+EfiCloseProtocol (
+ _In_ EFI_HANDLE Handle,
+ _In_ EFI_GUID *Protocol
+ )
+{
+ EFI_STATUS EfiStatus;
+ NTSTATUS Status;
+ BL_ARCH_MODE OldMode;
+
+ /* Are we using virtual memory/ */
+ if (MmTranslationType != BlNone)
+ {
+ /* We need complex tracking to make this work */
+ Status = EfiVmCloseProtocol(Handle, Protocol);
+ }
+ else
+ {
+ /* Are we on legacy 1.02? */
+ if (EfiST->FirmwareRevision == EFI_1_02_SYSTEM_TABLE_REVISION)
+ {
+ /* Nothing to close */
+ EfiStatus = EFI_SUCCESS;
+ }
+ else
+ {
+ /* Are we in protected mode? */
+ OldMode = CurrentExecutionContext->Mode;
+ if (OldMode != BlRealMode)
+ {
+ /* Switch to real mode */
+ BlpArchSwitchContext(BlRealMode);
+ }
+
+ /* Use the UEFI version */
+ EfiStatus = EfiBS->CloseProtocol(Handle, Protocol, EfiImageHandle, NULL);
+
+ /* Switch back to protected mode if we came from there */
+ if (OldMode != BlRealMode)
+ {
+ BlpArchSwitchContext(OldMode);
+ }
+
+ /* Normalize not found as success */
+ if (EfiStatus == EFI_NOT_FOUND)
+ {
+ EfiStatus = EFI_SUCCESS;
+ }
+ }
+
+ /* Convert the error to an NTSTATUS */
+ Status = EfiGetNtStatusCode(EfiStatus);
+ }
+
+ /* All done */
+ return Status;
+}
+
+NTSTATUS
+EfiGetVariable (
+ _In_ PWCHAR VariableName,
+ _In_ EFI_GUID* VendorGuid,
+ _Out_opt_ PULONG Attributes,
+ _Inout_ PULONG DataSize,
+ _Out_ PVOID Data
+ )
+{
+ EFI_STATUS EfiStatus;
+ NTSTATUS Status;
+ BL_ARCH_MODE OldMode;
+ ULONG LocalAttributes;
+
+ /* Are we in protected mode? */
+ OldMode = CurrentExecutionContext->Mode;
+ if (OldMode != BlRealMode)
+ {
+ /* FIXME: Not yet implemented */
+ EfiPrintf(L"getvar vm path\r\n");
+ EfiStall(10000000);
+ return STATUS_NOT_IMPLEMENTED;
+ }
+
+ /* Call the runtime API */
+ EfiStatus = EfiRT->GetVariable(VariableName,
+ VendorGuid,
+ (UINT32*)&LocalAttributes,
+ (UINTN*)DataSize,
+ Data);
+
+ /* Switch back to protected mode if we came from there */
+ if (OldMode != BlRealMode)
+ {
+ BlpArchSwitchContext(OldMode);
+ }
+
+ /* Return attributes back to the caller if asked to */
+ if (Attributes)
+ {
+ *Attributes = LocalAttributes;
+ }
+
+ /* Convert the error to an NTSTATUS and return it */
+ Status = EfiGetNtStatusCode(EfiStatus);
+ return Status;
+}
+
+NTSTATUS
+BlpSecureBootEFIIsEnabled (
+ VOID
+ )
+{
+ NTSTATUS Status;
+ BOOLEAN SetupMode, SecureBoot;
+ ULONG DataSize;
+
+ /* Assume setup mode enabled, and no secure boot */
+ SecureBoot = FALSE;
+ SetupMode = TRUE;
+
+ /* Get the SetupMode variable */
+ DataSize = sizeof(SetupMode);
+ Status = EfiGetVariable(L"SetupMode",
+ &EfiGlobalVariable,
+ NULL,
+ &DataSize,
+ &SetupMode);
+ if (NT_SUCCESS(Status))
+ {
+ /* If it worked, get the SecureBoot variable */
+ DataSize = sizeof(SecureBoot);
+ Status = EfiGetVariable(L"SecureBoot",
+ &EfiGlobalVariable,
+ NULL,
+ &DataSize,
+ &SecureBoot);
+ if (NT_SUCCESS(Status))
+ {
+ /* In setup mode or without secureboot turned on, return failure */
+ if ((SecureBoot != TRUE) || (SetupMode))
+ {
+ Status = STATUS_INVALID_SIGNATURE;
+ }
+
+ // BlpSbdiStateFlags |= 8u;
+ }
+ }
+
+ /* Return secureboot status */
+ return Status;
+}
+
+NTSTATUS
+BlSecureBootIsEnabled (
+ _Out_ PBOOLEAN SecureBootEnabled
+ )
+{
+ NTSTATUS Status;
+
+ /* Have we checked before ? */
+ if (!BlpFirmwareChecked)
+ {
+ /* First time checking */
+ Status = BlpSecureBootEFIIsEnabled();
+ if NT_SUCCESS(Status)
+ {
+ /* Yep, it's on */
+ BlpFirmwareEnabled = TRUE;
+ }
+
+ /* Don't check again */
+ BlpFirmwareChecked = TRUE;
+ }
+
+ /* Return the firmware result */
+ *SecureBootEnabled = BlpFirmwareEnabled;
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+BlSecureBootCheckForFactoryReset (
+ VOID
+ )
+{
+ BOOLEAN SecureBootEnabled;
+ NTSTATUS Status;
+ ULONG DataSize;
+
+ /* Initialize locals */
+ DataSize = 0;
+ SecureBootEnabled = FALSE;
+
+ /* Check if secureboot is enabled */
+ Status = BlSecureBootIsEnabled(&SecureBootEnabled);
+ if (!(NT_SUCCESS(Status)) || !(SecureBootEnabled))
+ {
+ /* It's not. Check if there's a revocation list */
+ Status = EfiGetVariable(L"RevocationList",
+ &BlpEfiSecureBootPrivateNamespace,
+ NULL,
+ &DataSize,
+ NULL);
+ if ((NT_SUCCESS(Status)) || (Status == STATUS_BUFFER_TOO_SMALL))
+ {
+ /* We don't support this yet */
+ EfiPrintf(L"Not yet supported\r\n");
+ Status = STATUS_NOT_IMPLEMENTED;
+ }
+ }
+
+ /* Return back to the caller */
+ return Status;
+}
+
+NTSTATUS
+EfiConInReset (
+ VOID
+ )
+{
+ BL_ARCH_MODE OldMode;
+ EFI_STATUS EfiStatus;
+
+ /* Are we in protected mode? */
+ OldMode = CurrentExecutionContext->Mode;
+ if (OldMode != BlRealMode)
+ {
+ /* FIXME: Not yet implemented */
+ EfiPrintf(L"coninreset vm path\r\n");
+ EfiStall(10000000);
+ return STATUS_NOT_IMPLEMENTED;
+ }
+
+ /* Make the EFI call */
+ EfiStatus = EfiConIn->Reset(EfiConIn, FALSE);
+
+ /* Switch back to protected mode if we came from there */
+ if (OldMode != BlRealMode)
+ {
+ BlpArchSwitchContext(OldMode);
+ }
+
+ /* Convert the error to an NTSTATUS */
+ return EfiGetNtStatusCode(EfiStatus);
+}
+
+NTSTATUS
+EfiConInExReset (
+ VOID
+ )
+{
+ BL_ARCH_MODE OldMode;
+ EFI_STATUS EfiStatus;
+
+ /* Are we in protected mode? */
+ OldMode = CurrentExecutionContext->Mode;
+ if (OldMode != BlRealMode)
+ {
+ /* FIXME: Not yet implemented */
+ EfiPrintf(L"conreset vm path\r\n");
+ EfiStall(10000000);
+ return STATUS_NOT_IMPLEMENTED;
+ }
+
+ /* Make the EFI call */
+ EfiStatus = EfiConInEx->Reset(EfiConInEx, FALSE);
+
+ /* Switch back to protected mode if we came from there */
+ if (OldMode != BlRealMode)
+ {
+ BlpArchSwitchContext(OldMode);
+ }
+
+ /* Convert the error to an NTSTATUS */
+ return EfiGetNtStatusCode(EfiStatus);
+}
+
+NTSTATUS
+EfiConInExSetState (
+ _In_ EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *ConInEx,
+ _In_ EFI_KEY_TOGGLE_STATE* KeyToggleState
+ )
+{
+ BL_ARCH_MODE OldMode;
+ EFI_STATUS EfiStatus;
+ PHYSICAL_ADDRESS ConInExPhys, KeyTogglePhys;
+
+ /* Are we in protected mode? */
+ OldMode = CurrentExecutionContext->Mode;
+ if (OldMode != BlRealMode)
+ {
+ /* Translate pointers from virtual to physical */
+ BlMmTranslateVirtualAddress(ConInEx, &ConInExPhys);
+ ConInEx = (EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL*)ConInExPhys.LowPart;
+ BlMmTranslateVirtualAddress(KeyToggleState, &KeyTogglePhys);
+ KeyToggleState = (EFI_KEY_TOGGLE_STATE*)KeyTogglePhys.LowPart;
+
+ /* Switch to real mode */
+ BlpArchSwitchContext(BlRealMode);
+ }
+
+ /* Make the EFI call */
+ EfiStatus = ConInEx->SetState(ConInEx, KeyToggleState);
+
+ /* Switch back to protected mode if we came from there */
+ if (OldMode != BlRealMode)
+ {
+ BlpArchSwitchContext(OldMode);
+ }
+
+ /* Convert the error to an NTSTATUS */
+ return EfiGetNtStatusCode(EfiStatus);
+}
+
+NTSTATUS
+EfiSetWatchdogTimer (
+ VOID
+ )
+{
+ BL_ARCH_MODE OldMode;
+ EFI_STATUS EfiStatus;
+
+ /* Are we in protected mode? */
+ OldMode = CurrentExecutionContext->Mode;
+ if (OldMode != BlRealMode)
+ {
+ /* Switch to real mode */
+ BlpArchSwitchContext(BlRealMode);
+ }
+
+ /* Make the EFI call */
+ EfiStatus = EfiBS->SetWatchdogTimer(0, 0, 0, NULL);
+
+ /* Switch back to protected mode if we came from there */
+ if (OldMode != BlRealMode)
+ {
+ BlpArchSwitchContext(OldMode);
+ }
+
+ /* Convert the error to an NTSTATUS */
+ return EfiGetNtStatusCode(EfiStatus);
+}
+
+NTSTATUS
+EfiGetMemoryMap (
+ _Out_ UINTN* MemoryMapSize,
+ _Inout_ EFI_MEMORY_DESCRIPTOR *MemoryMap,
+ _Out_ UINTN* MapKey,
+ _Out_ UINTN* DescriptorSize,
+ _Out_ UINTN* DescriptorVersion
+ )
+{
+ BL_ARCH_MODE OldMode;
+ EFI_STATUS EfiStatus;
+ PHYSICAL_ADDRESS MemoryMapSizePhysical, MemoryMapPhysical, MapKeyPhysical;
+ PHYSICAL_ADDRESS DescriptorSizePhysical, DescriptorVersionPhysical;
+
+ /* Are we in protected mode? */
+ OldMode = CurrentExecutionContext->Mode;
+ if (OldMode != BlRealMode)
+ {
+ /* Convert all of the addresses to physical */
+ BlMmTranslateVirtualAddress(MemoryMapSize, &MemoryMapSizePhysical);
+ MemoryMapSize = (UINTN*)MemoryMapSizePhysical.LowPart;
+ BlMmTranslateVirtualAddress(MemoryMap, &MemoryMapPhysical);
+ MemoryMap = (EFI_MEMORY_DESCRIPTOR*)MemoryMapPhysical.LowPart;
+ BlMmTranslateVirtualAddress(MapKey, &MapKeyPhysical);
+ MapKey = (UINTN*)MapKeyPhysical.LowPart;
+ BlMmTranslateVirtualAddress(DescriptorSize, &DescriptorSizePhysical);
+ DescriptorSize = (UINTN*)DescriptorSizePhysical.LowPart;
+ BlMmTranslateVirtualAddress(DescriptorVersion, &DescriptorVersionPhysical);
+ DescriptorVersion = (UINTN*)DescriptorVersionPhysical.LowPart;
+
+ /* Switch to real mode */
+ BlpArchSwitchContext(BlRealMode);
+ }
+
+ /* Make the EFI call */
+ EfiStatus = EfiBS->GetMemoryMap(MemoryMapSize,
+ MemoryMap,
+ MapKey,
+ DescriptorSize,
+ DescriptorVersion);
+
+ /* Switch back to protected mode if we came from there */
+ if (OldMode != BlRealMode)
+ {
+ BlpArchSwitchContext(OldMode);
+ }
+
+ /* Convert the error to an NTSTATUS */
+ return EfiGetNtStatusCode(EfiStatus);
+}
+
+NTSTATUS
+EfiFreePages (
+ _In_ ULONG Pages,
+ _In_ EFI_PHYSICAL_ADDRESS PhysicalAddress
+ )
+{
+ BL_ARCH_MODE OldMode;
+ EFI_STATUS EfiStatus;
+
+ /* Are we in protected mode? */
+ OldMode = CurrentExecutionContext->Mode;
+ if (OldMode != BlRealMode)
+ {
+ /* Switch to real mode */
+ BlpArchSwitchContext(BlRealMode);
+ }
+
+ /* Make the EFI call */
+ EfiStatus = EfiBS->FreePages(PhysicalAddress, Pages);
+
+ /* Switch back to protected mode if we came from there */
+ if (OldMode != BlRealMode)
+ {
+ BlpArchSwitchContext(OldMode);
+ }
+
+ /* Convert the error to an NTSTATUS */
+ return EfiGetNtStatusCode(EfiStatus);
+}
+
+NTSTATUS
+EfiStall (
+ _In_ ULONG StallTime
+ )
+{
+ BL_ARCH_MODE OldMode;
+ EFI_STATUS EfiStatus;
+
+ /* Are we in protected mode? */
+ OldMode = CurrentExecutionContext->Mode;
+ if (OldMode != BlRealMode)
+ {
+ /* Switch to real mode */
+ BlpArchSwitchContext(BlRealMode);
+ }
+
+ /* Make the EFI call */
+ EfiStatus = EfiBS->Stall(StallTime);
+
+ /* Switch back to protected mode if we came from there */
+ if (OldMode != BlRealMode)
+ {
+ BlpArchSwitchContext(OldMode);
+ }
+
+ /* Convert the error to an NTSTATUS */
+ return EfiGetNtStatusCode(EfiStatus);
+}
+
+NTSTATUS
+EfiConOutQueryMode (
+ _In_ SIMPLE_TEXT_OUTPUT_INTERFACE *TextInterface,
+ _In_ ULONG Mode,
+ _In_ UINTN* Columns,
+ _In_ UINTN* Rows
+ )
+{
+ BL_ARCH_MODE OldMode;
+ EFI_STATUS EfiStatus;
+
+ /* Are we in protected mode? */
+ OldMode = CurrentExecutionContext->Mode;
+ if (OldMode != BlRealMode)
+ {
+ /* FIXME: Not yet implemented */
+ EfiPrintf(L"conqmode vm path\r\n");
+ EfiStall(10000000);
+ return STATUS_NOT_IMPLEMENTED;
+ }
+
+ /* Make the EFI call */
+ EfiStatus = TextInterface->QueryMode(TextInterface, Mode, Columns, Rows);
+
+ /* Switch back to protected mode if we came from there */
+ if (OldMode != BlRealMode)
+ {
+ BlpArchSwitchContext(OldMode);
+ }
+
+ /* Convert the error to an NTSTATUS */
+ return EfiGetNtStatusCode(EfiStatus);
+}
+
+NTSTATUS
+EfiConOutSetMode (
+ _In_ SIMPLE_TEXT_OUTPUT_INTERFACE *TextInterface,
+ _In_ ULONG Mode
+ )
+{
+ BL_ARCH_MODE OldMode;
+ EFI_STATUS EfiStatus;
+
+ /* Are we in protected mode? */
+ OldMode = CurrentExecutionContext->Mode;
+ if (OldMode != BlRealMode)
+ {
+ /* FIXME: Not yet implemented */
+ EfiPrintf(L"setmode vm path\r\n");
+ EfiStall(10000000);
+ return STATUS_NOT_IMPLEMENTED;
+ }
+
+ /* Make the EFI call */
+ EfiStatus = TextInterface->SetMode(TextInterface, Mode);
+
+ /* Switch back to protected mode if we came from there */
+ if (OldMode != BlRealMode)
+ {
+ BlpArchSwitchContext(OldMode);
+ }
+
+ /* Convert the error to an NTSTATUS */
+ return EfiGetNtStatusCode(EfiStatus);
+}
+
+NTSTATUS
+EfiConOutSetAttribute (
+ _In_ SIMPLE_TEXT_OUTPUT_INTERFACE *TextInterface,
+ _In_ ULONG Attribute
+ )
+{
+ BL_ARCH_MODE OldMode;
+ EFI_STATUS EfiStatus;
+
+ /* Are we in protected mode? */
+ OldMode = CurrentExecutionContext->Mode;
+ if (OldMode != BlRealMode)
+ {
+ /* FIXME: Not yet implemented */
+ EfiPrintf(L"sattr vm path\r\n");
+ EfiStall(10000000);
+ return STATUS_NOT_IMPLEMENTED;
+ }
+
+ /* Make the EFI call */
+ EfiStatus = TextInterface->SetAttribute(TextInterface, Attribute);
+
+ /* Switch back to protected mode if we came from there */
+ if (OldMode != BlRealMode)
+ {
+ BlpArchSwitchContext(OldMode);
+ }
+
+ /* Convert the error to an NTSTATUS */
+ return EfiGetNtStatusCode(EfiStatus);
+}
+
+NTSTATUS
+EfiConOutSetCursorPosition (
+ _In_ SIMPLE_TEXT_OUTPUT_INTERFACE *TextInterface,
+ _In_ ULONG Column,
+ _In_ ULONG Row
+ )
+{
+ BL_ARCH_MODE OldMode;
+ EFI_STATUS EfiStatus;
+
+ /* Are we in protected mode? */
+ OldMode = CurrentExecutionContext->Mode;
+ if (OldMode != BlRealMode)
+ {
+ /* FIXME: Not yet implemented */
+ EfiPrintf(L"setcursor vm path\r\n");
+ EfiStall(10000000);
+ return STATUS_NOT_IMPLEMENTED;
+ }
+
+ /* Make the EFI call */
+ EfiStatus = TextInterface->SetCursorPosition(TextInterface, Column, Row);
+
+ /* Switch back to protected mode if we came from there */
+ if (OldMode != BlRealMode)
+ {
+ BlpArchSwitchContext(OldMode);
+ }
+
+ /* Convert the error to an NTSTATUS */
+ return EfiGetNtStatusCode(EfiStatus);
+}
+
+NTSTATUS
+EfiConOutEnableCursor (
+ _In_ SIMPLE_TEXT_OUTPUT_INTERFACE *TextInterface,
+ _In_ BOOLEAN Visible
+ )
+{
+ BL_ARCH_MODE OldMode;
+ EFI_STATUS EfiStatus;
+
+ /* Are we in protected mode? */
+ OldMode = CurrentExecutionContext->Mode;
+ if (OldMode != BlRealMode)
+ {
+ /* FIXME: Not yet implemented */
+ EfiPrintf(L"enablecurso vm path\r\n");
+ EfiStall(10000000);
+ return STATUS_NOT_IMPLEMENTED;
+ }
+
+ /* Make the EFI call */
+ EfiStatus = TextInterface->EnableCursor(TextInterface, Visible);
+
+ /* Switch back to protected mode if we came from there */
+ if (OldMode != BlRealMode)
+ {
+ BlpArchSwitchContext(OldMode);
+ }
+
+ /* Convert the error to an NTSTATUS */
+ return EfiGetNtStatusCode(EfiStatus);
+}
+
+NTSTATUS
+EfiConOutOutputString (
+ _In_ SIMPLE_TEXT_OUTPUT_INTERFACE *TextInterface,
+ _In_ PWCHAR String
+ )
+{
+ BL_ARCH_MODE OldMode;
+ EFI_STATUS EfiStatus;
+
+ /* Are we in protected mode? */
+ OldMode = CurrentExecutionContext->Mode;
+ if (OldMode != BlRealMode)
+ {
+ /* FIXME: Not yet implemented */
+ EfiPrintf(L"output string vm path\r\n");
+ EfiStall(10000000);
+ return STATUS_NOT_IMPLEMENTED;
+ }
+
+ /* Make the EFI call */
+ EfiStatus = TextInterface->OutputString(TextInterface, String);
+
+ /* Switch back to protected mode if we came from there */
+ if (OldMode != BlRealMode)
+ {
+ BlpArchSwitchContext(OldMode);
+ }
+
+ /* Convert the error to an NTSTATUS */
+ return EfiGetNtStatusCode(EfiStatus);
+}
+
+VOID
+EfiConOutReadCurrentMode (
+ _In_ SIMPLE_TEXT_OUTPUT_INTERFACE *TextInterface,
+ _Out_ EFI_SIMPLE_TEXT_OUTPUT_MODE* Mode
+ )
+{
+ BL_ARCH_MODE OldMode;
+
+ /* Are we in protected mode? */
+ OldMode = CurrentExecutionContext->Mode;
+ if (OldMode != BlRealMode)
+ {
+ /* FIXME: Not yet implemented */
+ EfiPrintf(L"readmode vm path\r\n");
+ EfiStall(10000000);
+ return;
+ }
+
+ /* Make the EFI call */
+ RtlCopyMemory(Mode, TextInterface->Mode, sizeof(*Mode));
+
+ /* Switch back to protected mode if we came from there */
+ if (OldMode != BlRealMode)
+ {
+ BlpArchSwitchContext(OldMode);
+ }
+}
+
+VOID
+EfiGopGetFrameBuffer (
+ _In_ EFI_GRAPHICS_OUTPUT_PROTOCOL *GopInterface,
+ _Out_ PHYSICAL_ADDRESS* FrameBuffer,
+ _Out_ UINTN *FrameBufferSize
+ )
+{
+ BL_ARCH_MODE OldMode;
+ PHYSICAL_ADDRESS GopInterfacePhys, FrameBufferPhys, FrameBufferSizePhys;
+
+ /* Are we in protected mode? */
+ OldMode = CurrentExecutionContext->Mode;
+ if (OldMode != BlRealMode)
+ {
+ /* Translate pointer to physical */
+ BlMmTranslateVirtualAddress(GopInterface, &GopInterfacePhys);
+ GopInterface = (PVOID)GopInterfacePhys.LowPart;
+
+ /* Translate pointer to physical */
+ BlMmTranslateVirtualAddress(FrameBuffer, &FrameBufferPhys);
+ FrameBuffer = (PVOID)FrameBufferPhys.LowPart;
+
+ /* Translate pointer to physical */
+ BlMmTranslateVirtualAddress(FrameBufferSize, &FrameBufferSizePhys);
+ FrameBufferSize = (PVOID)FrameBufferSizePhys.LowPart;
+
+ /* Switch to real mode */
+ BlpArchSwitchContext(BlRealMode);
+ }
+
+ /* Make the EFI call */
+ FrameBuffer->QuadPart = GopInterface->Mode->FrameBufferBase;
+ *FrameBufferSize = GopInterface->Mode->FrameBufferSize;
+
+ /* Switch back to protected mode if we came from there */
+ if (OldMode != BlRealMode)
+ {
+ BlpArchSwitchContext(OldMode);
+ }
+}
+
+NTSTATUS
+EfiGopGetCurrentMode (
+ _In_ EFI_GRAPHICS_OUTPUT_PROTOCOL *GopInterface,
+ _Out_ UINTN* Mode,
+ _Out_ EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Information
+ )
+{
+ BL_ARCH_MODE OldMode;
+ PHYSICAL_ADDRESS GopInterfacePhys, ModePhys, InformationPhys;
+
+ /* Are we in protected mode? */
+ OldMode = CurrentExecutionContext->Mode;
+ if (OldMode != BlRealMode)
+ {
+ /* Translate pointer to physical */
+ if (!BlMmTranslateVirtualAddress(GopInterface, &GopInterfacePhys))
+ {
+ return STATUS_UNSUCCESSFUL;
+ }
+ GopInterface = (PVOID)GopInterfacePhys.LowPart;
+
+ /* Translate pointer to physical */
+ if (!BlMmTranslateVirtualAddress(Mode, &ModePhys))
+ {
+ return STATUS_UNSUCCESSFUL;
+ }
+ Mode = (PVOID)ModePhys.LowPart;
+
+ /* Translate pointer to physical */
+ if (!BlMmTranslateVirtualAddress(Information, &InformationPhys))
+ {
+ return STATUS_UNSUCCESSFUL;
+ }
+ Information = (PVOID)InformationPhys.LowPart;
+
+ /* Switch to real mode */
+ BlpArchSwitchContext(BlRealMode);
+ }
+
+ /* Make the EFI call */
+ *Mode = GopInterface->Mode->Mode;
+ RtlCopyMemory(Information, GopInterface->Mode->Info, sizeof(*Information));
+
+ /* Switch back to protected mode if we came from there */
+ if (OldMode != BlRealMode)
+ {
+ BlpArchSwitchContext(OldMode);
+ }
+
+ /* Return back */
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+EfiGopSetMode (
+ _In_ EFI_GRAPHICS_OUTPUT_PROTOCOL *GopInterface,
+ _In_ ULONG Mode
+ )
+{
+ BL_ARCH_MODE OldMode;
+ EFI_STATUS EfiStatus;
+ BOOLEAN ModeChanged;
+ NTSTATUS Status;
+
+ /* Are we in protected mode? */
+ OldMode = CurrentExecutionContext->Mode;
+ if (OldMode != BlRealMode)
+ {
+ /* FIXME: Not yet implemented */
+ EfiPrintf(L"gopsmode vm path\r\n");
+ EfiStall(10000000);
+ return STATUS_NOT_IMPLEMENTED;
+ }
+
+ /* Make the EFI call */
+ if (Mode == GopInterface->Mode->Mode)
+ {
+ EfiStatus = EFI_SUCCESS;
+ ModeChanged = FALSE;
+ }
+ {
+ EfiStatus = GopInterface->SetMode(GopInterface, Mode);
+ ModeChanged = TRUE;
+ }
+
+ /* Switch back to protected mode if we came from there */
+ if (OldMode != BlRealMode)
+ {
+ BlpArchSwitchContext(OldMode);
+ }
+
+ /* Print out to the debugger if the mode was changed */
+ Status = EfiGetNtStatusCode(EfiStatus);
+ if ((ModeChanged) && (NT_SUCCESS(Status)))
+ {
+ /* FIXME @TODO: Should be BlStatusPrint */
+ EfiPrintf(L"Console video mode set to 0x%x\r\n", Mode);
+ }
+
+ /* Convert the error to an NTSTATUS */
+ return Status;
+}
+
+NTSTATUS
+EfiLocateHandleBuffer (
+ _In_ EFI_LOCATE_SEARCH_TYPE SearchType,
+ _In_ EFI_GUID *Protocol,
+ _Inout_ PULONG HandleCount,
+ _Inout_ EFI_HANDLE** Buffer
+ )
+{
+ BL_ARCH_MODE OldMode;
+ EFI_STATUS EfiStatus;
+ UINTN BufferSize;
+ PVOID InputBuffer;
+ BOOLEAN TranslateResult;
+ PHYSICAL_ADDRESS BufferPhys;
+
+ /* Bail out if we're missing parameters */
+ if (!(Buffer) || !(HandleCount))
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ /* Check if a buffer was passed in*/
+ InputBuffer = *Buffer;
+ if (InputBuffer)
+ {
+ /* Then we should already have a buffer size*/
+ BufferSize = sizeof(EFI_HANDLE) * *HandleCount;
+ }
+ else
+ {
+ /* Then no buffer size exists */
+ BufferSize = 0;
+ }
+
+ /* Are we in protected mode? */
+ OldMode = CurrentExecutionContext->Mode;
+ if (OldMode != BlRealMode)
+ {
+ /* Translate the input buffer from virtual to physical */
+ TranslateResult = BlMmTranslateVirtualAddress(InputBuffer, &BufferPhys);
+ InputBuffer = TranslateResult ? (PVOID)BufferPhys.LowPart : NULL;
+
+ /* Switch to real mode */
+ BlpArchSwitchContext(BlRealMode);
+ }
+
+ /* Try the first time */
+ EfiStatus = EfiBS->LocateHandle(SearchType,
+ Protocol,
+ NULL,
+ &BufferSize,
+ InputBuffer);
+
+ /* Switch back to protected mode if we came from there */
+ if (OldMode != BlRealMode)
+ {
+ BlpArchSwitchContext(OldMode);
+ }
+
+ /* Check result of first search */
+ if (EfiStatus == EFI_BUFFER_TOO_SMALL)
+ {
+ /* Did we have an existing buffer? */
+ if (*Buffer)
+ {
+ /* Free it */
+ BlMmFreeHeap(*Buffer);
+ }
+
+ /* Allocate a new one */
+ InputBuffer = BlMmAllocateHeap(BufferSize);
+ *Buffer = InputBuffer;
+ if (!InputBuffer)
+ {
+ /* No space, fail */
+ return STATUS_NO_MEMORY;
+ }
+
+ if (OldMode != BlRealMode)
+ {
+ /* Translate the input buffer from virtual to physical */
+ TranslateResult = BlMmTranslateVirtualAddress(InputBuffer,
+ &BufferPhys);
+ InputBuffer = TranslateResult ? (PVOID)BufferPhys.LowPart : NULL;
+
+ /* Switch to real mode */
+ BlpArchSwitchContext(BlRealMode);
+ }
+
+ /* Try again */
+ EfiStatus = EfiBS->LocateHandle(SearchType,
+ Protocol,
+ NULL,
+ &BufferSize,
+ InputBuffer);
+
+ /* Switch back to protected mode if we came from there */
+ if (OldMode != BlRealMode)
+ {
+ BlpArchSwitchContext(OldMode);
+ }
+ }
+
+ /* Return the number of handles */
+ *HandleCount = BufferSize / sizeof(EFI_HANDLE);
+
+ /* Convert the error to an NTSTATUS */
+ return EfiGetNtStatusCode(EfiStatus);
+}
+
+VOID
+EfiResetSystem (
+ _In_ EFI_RESET_TYPE ResetType
+ )
+{
+ BL_ARCH_MODE OldMode;
+
+ /* Are we in protected mode? */
+ OldMode = CurrentExecutionContext->Mode;
+ if (OldMode != BlRealMode)
+ {
+ /* FIXME: Not yet implemented */
+ EfiPrintf(L"reset vm path\r\n");
+ EfiStall(10000000);
+ return;
+ }
+
+ /* Call the EFI runtime */
+ EfiRT->ResetSystem(ResetType, EFI_SUCCESS, 0, NULL);
+}
+
+NTSTATUS
+EfiConnectController (
+ _In_ EFI_HANDLE ControllerHandle
+ )
+{
+ BL_ARCH_MODE OldMode;
+ EFI_STATUS EfiStatus;
+
+ /* Is this EFI 1.02? */
+ if (EfiST->Hdr.Revision == EFI_1_02_SYSTEM_TABLE_REVISION)
+ {
+ /* This function didn't exist back then */
+ return STATUS_NOT_SUPPORTED;
+ }
+
+ /* Are we in protected mode? */
+ OldMode = CurrentExecutionContext->Mode;
+ if (OldMode != BlRealMode)
+ {
+ /* FIXME: Not yet implemented */
+ EfiPrintf(L"connectctrl vm path\r\n");
+ EfiStall(10000000);
+ return STATUS_NOT_IMPLEMENTED;
+ }
+
+ /* Make the EFI call */
+ EfiStatus = EfiBS->ConnectController(ControllerHandle, NULL, NULL, TRUE);
+
+ /* Switch back to protected mode if we came from there */
+ if (OldMode != BlRealMode)
+ {
+ BlpArchSwitchContext(OldMode);
+ }
+
+ /* Convert the error to an NTSTATUS */
+ return EfiGetNtStatusCode(EfiStatus);
+}
+
+NTSTATUS
+EfiAllocatePages (
+ _In_ ULONG Type,
+ _In_ ULONG Pages,
+ _Inout_ EFI_PHYSICAL_ADDRESS* Memory
+ )
+{
+ BL_ARCH_MODE OldMode;
+ EFI_STATUS EfiStatus;
+ PHYSICAL_ADDRESS MemoryPhysical;
+
+ /* Are we in protected mode? */
+ OldMode = CurrentExecutionContext->Mode;
+ if (OldMode != BlRealMode)
+ {
+ /* Translate output address */
+ BlMmTranslateVirtualAddress(Memory, &MemoryPhysical);
+ Memory = (EFI_PHYSICAL_ADDRESS*)MemoryPhysical.LowPart;
+
+ /* Switch to real mode */
+ BlpArchSwitchContext(BlRealMode);
+ }
+
+ /* Make the EFI call */
+ EfiStatus = EfiBS->AllocatePages(Type, EfiLoaderData, Pages, Memory);
+
+ /* Switch back to protected mode if we came from there */
+ if (OldMode != BlRealMode)
+ {
+ BlpArchSwitchContext(OldMode);
+ }
+
+ /* Convert the error to an NTSTATUS */
+ return EfiGetNtStatusCode(EfiStatus);
+}
+
+NTSTATUS
+EfipGetSystemTable (
+ _In_ EFI_GUID *TableGuid,
+ _Out_ PPHYSICAL_ADDRESS TableAddress
+ )
+{
+ ULONG i;
+ NTSTATUS Status;
+
+ /* Assume failure */
+ Status = STATUS_NOT_FOUND;
+
+ /* Loop through the configuration tables */
+ for (i = 0; i < EfiST->NumberOfTableEntries; i++)
+ {
+ /* Check if this one matches the one we want */
+ if (RtlEqualMemory(&EfiST->ConfigurationTable[i].VendorGuid,
+ TableGuid,
+ sizeof(*TableGuid)))
+ {
+ /* Return its address */
+ TableAddress->QuadPart = (ULONG_PTR)EfiST->ConfigurationTable[i].VendorTable;
+ Status = STATUS_SUCCESS;
+ break;
+ }
+ }
+
+ /* Return the search result */
+ return Status;
+}
+
+NTSTATUS
+EfipGetRsdt (
+ _Out_ PPHYSICAL_ADDRESS FoundRsdt
+ )
+{
+ NTSTATUS Status;
+ ULONG Length;
+ PHYSICAL_ADDRESS RsdpAddress, Rsdt;
+ PRSDP Rsdp;
+
+ /* Assume failure */
+ Length = 0;
+ Rsdp = NULL;
+
+ /* Check if we already know it */
+ if (EfiRsdt.QuadPart)
+ {
+ /* Return it */
+ *FoundRsdt = EfiRsdt;
+ return STATUS_SUCCESS;
+ }
+
+ /* Otherwise, look for the ACPI 2.0 RSDP (XSDT really) */
+ Status = EfipGetSystemTable(&EfiRootAcpiTableGuid, &RsdpAddress);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Didn't fint it, look for the ACPI 1.0 RSDP (RSDT really) */
+ Status = EfipGetSystemTable(&EfiRootAcpiTable10Guid, &RsdpAddress);
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+ }
+
+ /* Map it */
+ Length = sizeof(*Rsdp);
+ Status = BlMmMapPhysicalAddressEx((PVOID*)&Rsdp,
+ 0,
+ Length,
+ RsdpAddress);
+ if (NT_SUCCESS(Status))
+ {
+ /* Check the revision (anything >= 2.0 is XSDT) */
+ if (Rsdp->Revision)
+ {
+ /* Check if the table is bigger than just its header */
+ if (Rsdp->Length > Length)
+ {
+ /* Capture the real length */
+ Length = Rsdp->Length;
+
+ /* Unmap our header mapping */
+ BlMmUnmapVirtualAddressEx(Rsdp, sizeof(*Rsdp));
+
+ /* And map the whole thing now */
+ Status = BlMmMapPhysicalAddressEx((PVOID*)&Rsdp,
+ 0,
+ Length,
+ RsdpAddress);
+ if (!NT_SUCCESS(Status))
+ {
+ return Status;
+ }
+ }
+
+ /* Read the XSDT address from the table*/
+ Rsdt = Rsdp->XsdtAddress;
+ }
+ else
+ {
+ /* ACPI 1.0 so just read the RSDT */
+ Rsdt.QuadPart = Rsdp->RsdtAddress;
+ }
+
+ /* Save it for later */
+ EfiRsdt = Rsdt;
+
+ /* And return it back */
+ *FoundRsdt = Rsdt;
+ }
+
+ /* Check if we had mapped the RSDP */
+ if (Rsdp)
+ {
+ /* Unmap it */
+ BlMmUnmapVirtualAddressEx(Rsdp, Length);
+ }
+
+ /* Return search result back to caller */
+ return Status;
+}
+
+BL_MEMORY_ATTR
+MmFwpGetOsAttributeType (
+ _In_ ULONGLONG Attribute
+ )
+{
+ BL_MEMORY_ATTR OsAttribute = 0;
+
+ if (Attribute & EFI_MEMORY_UC)
+ {
+ OsAttribute = BlMemoryUncached;
+ }
+
+ if (Attribute & EFI_MEMORY_WC)
+ {
+ OsAttribute |= BlMemoryWriteCombined;
+ }
+
+ if (Attribute & EFI_MEMORY_WT)
+ {
+ OsAttribute |= BlMemoryWriteThrough;
+ }
+
+ if (Attribute & EFI_MEMORY_WB)
+ {
+ OsAttribute |= BlMemoryWriteBack;
+ }
+
+ if (Attribute & EFI_MEMORY_UCE)
+ {
+ OsAttribute |= BlMemoryUncachedExported;
+ }
+
+ if (Attribute & EFI_MEMORY_WP)
+ {
+ OsAttribute |= BlMemoryWriteProtected;
+ }
+
+ if (Attribute & EFI_MEMORY_RP)
+ {
+ OsAttribute |= BlMemoryReadProtected;
+ }
+
+ if (Attribute & EFI_MEMORY_XP)
+ {
+ OsAttribute |= BlMemoryExecuteProtected;
+ }
+
+ if (Attribute & EFI_MEMORY_RUNTIME)
+ {
+ OsAttribute |= BlMemoryRuntime;
+ }
+
+ return OsAttribute;
+}
+
+BL_MEMORY_TYPE
+MmFwpGetOsMemoryType (
+ _In_ EFI_MEMORY_TYPE MemoryType
+ )
+{
+ BL_MEMORY_TYPE OsType;
+
+ switch (MemoryType)
+ {
+ case EfiLoaderCode:
+ case EfiLoaderData:
+ OsType = BlLoaderMemory;
+ break;
+
+ case EfiBootServicesCode:
+ case EfiBootServicesData:
+ OsType = BlEfiBootMemory;
+ break;
+
+ case EfiRuntimeServicesCode:
+ OsType = BlEfiRuntimeCodeMemory;
+ break;
+
+ case EfiRuntimeServicesData:
+ OsType = BlEfiRuntimeDataMemory;
+ break;
+
+ case EfiConventionalMemory:
+ OsType = BlConventionalMemory;
+ break;
+
+ case EfiUnusableMemory:
+ OsType = BlUnusableMemory;
+ break;
+
+ case EfiACPIReclaimMemory:
+ OsType = BlAcpiReclaimMemory;
+ break;
+
+ case EfiACPIMemoryNVS:
+ OsType = BlAcpiNvsMemory;
+ break;
+
+ case EfiMemoryMappedIO:
+ OsType = BlDeviceIoMemory;
+ break;
+
+ case EfiMemoryMappedIOPortSpace:
+ OsType = BlDevicePortMemory;
+ break;
+
+ case EfiPalCode:
+ OsType = BlPalMemory;
+ break;
+
+ default:
+ OsType = BlReservedMemory;
+ break;
+ }
+
+ return OsType;
+}
+
+NTSTATUS
+MmFwGetMemoryMap (
+ _Out_ PBL_MEMORY_DESCRIPTOR_LIST MemoryMap,
+ _In_ ULONG Flags
+ )
+{
+ BL_LIBRARY_PARAMETERS LibraryParameters = BlpLibraryParameters;
+ BOOLEAN UseEfiBuffer, HaveRamDisk;
+ NTSTATUS Status;
+ ULONGLONG Pages, StartPage, EndPage, EfiBufferPage;
+ UINTN EfiMemoryMapSize, MapKey, DescriptorSize, DescriptorVersion;
+ EFI_PHYSICAL_ADDRESS EfiBuffer = 0;
+ EFI_MEMORY_DESCRIPTOR* EfiMemoryMap;
+ EFI_STATUS EfiStatus;
+ BL_ARCH_MODE OldMode;
+ EFI_MEMORY_DESCRIPTOR EfiDescriptor;
+ BL_MEMORY_TYPE MemoryType;
+ PBL_MEMORY_DESCRIPTOR Descriptor;
+ BL_MEMORY_ATTR Attribute;
+ PVOID LibraryBuffer;
+
+ /* Initialize EFI memory map attributes */
+ EfiMemoryMapSize = MapKey = DescriptorSize = DescriptorVersion = 0;
+ LibraryBuffer = NULL;
+
+ /* Increment the nesting depth */
+ MmDescriptorCallTreeCount++;
+
+ /* Determine if we should use EFI or our own allocator at this point */
+ UseEfiBuffer = Flags & BL_MM_FLAG_USE_FIRMWARE_FOR_MEMORY_MAP_BUFFERS;
+ if (!(LibraryParameters.LibraryFlags & BL_LIBRARY_FLAG_INITIALIZATION_COMPLETED))
+ {
+ UseEfiBuffer = TRUE;
+ }
+
+ /* Bail out if we don't have a list to use */
+ if (MemoryMap == NULL)
+ {
+ Status = STATUS_INVALID_PARAMETER;
+ goto Quickie;
+ }
+
+ /* Free the current descriptor list */
+ MmMdFreeList(MemoryMap);
+
+ /* Call into EFI to get the size of the memory map */
+ Status = EfiGetMemoryMap(&EfiMemoryMapSize,
+ NULL,
+ &MapKey,
+ &DescriptorSize,
+ &DescriptorVersion);
+ if (Status != STATUS_BUFFER_TOO_SMALL)
+ {
+ /* This should've failed because our buffer was too small, nothing else */
+ if (NT_SUCCESS(Status))
+ {
+ Status = STATUS_UNSUCCESSFUL;
+ }
+ goto Quickie;
+ }
+
+ /* Add 4 more descriptors just in case things changed */
+ EfiMemoryMapSize += (4 * DescriptorSize);
+ Pages = BYTES_TO_PAGES(EfiMemoryMapSize);
+
+ /* Should we use EFI to grab memory? */
+ if (UseEfiBuffer)
+ {
+ /* Yes -- request one more page to align up correctly */
+ Pages++;
+
+ /* Grab the required pages */
+ Status = EfiAllocatePages(AllocateAnyPages,
+ Pages,
+ &EfiBuffer);
+ if (!NT_SUCCESS(Status))
+ {
+ EfiPrintf(L"EFI allocation failed: %lx\r\n", Status);
+ goto Quickie;
+ }
+
+ /* Free the pages for now */
+ Status = EfiFreePages(Pages, EfiBuffer);
+ if (!NT_SUCCESS(Status))
+ {
+ EfiBuffer = 0;
+ goto Quickie;
+ }
+
+ /* Now round to the actual buffer size, removing the extra page */
+ EfiBuffer = ROUND_TO_PAGES(EfiBuffer);
+ Pages--;
+ Status = EfiAllocatePages(AllocateAddress,
+ Pages,
+ &EfiBuffer);
+ if (!NT_SUCCESS(Status))
+ {
+ EfiBuffer = 0;
+ goto Quickie;
+ }
+
+ /* Get the final aligned size and proper buffer */
+ EfiMemoryMapSize = EFI_PAGES_TO_SIZE(Pages);
+ EfiMemoryMap = (EFI_MEMORY_DESCRIPTOR*)(ULONG_PTR)EfiBuffer;
+
+ /* Switch to real mode if not already in it */
+ OldMode = CurrentExecutionContext->Mode;
+ if (OldMode != BlRealMode)
+ {
+ BlpArchSwitchContext(BlRealMode);
+ }
+
+ /* Call EFI to get the memory map */
+ EfiStatus = EfiBS->GetMemoryMap(&EfiMemoryMapSize,
+ EfiMemoryMap,
+ &MapKey,
+ &DescriptorSize,
+ &DescriptorVersion);
+
+ /* Switch back into the previous mode */
+ if (OldMode != BlRealMode)
+ {
+ BlpArchSwitchContext(OldMode);
+ }
+
+ /* Convert the result code */
+ Status = EfiGetNtStatusCode(EfiStatus);
+ }
+ else
+ {
+ /* Round the map to pages */
+ Pages = BYTES_TO_PAGES(EfiMemoryMapSize);
+
+ /* Allocate a large enough buffer */
+ Status = MmPapAllocatePagesInRange(&LibraryBuffer,
+ BlLoaderData,
+ Pages,
+ 0,
+ 0,
+ 0,
+ 0);
+ if (!NT_SUCCESS(Status))
+ {
+ EfiPrintf(L"Failed to allocate mapped VM for EFI map: %lx\r\n", Status);
+ goto Quickie;
+ }
+
+ /* Call EFI to get the memory map */
+ EfiMemoryMap = LibraryBuffer;
+ Status = EfiGetMemoryMap(&EfiMemoryMapSize,
+ LibraryBuffer,
+ &MapKey,
+ &DescriptorSize,
+ &DescriptorVersion);
+ }
+
+ /* So far so good? */
+ if (!NT_SUCCESS(Status))
+ {
+ EfiPrintf(L"Failed to get EFI memory map: %lx\r\n", Status);
+ goto Quickie;
+ }
+
+ /* Did we get correct data from firmware? */
+ if (((EfiMemoryMapSize % DescriptorSize)) ||
+ (DescriptorSize < sizeof(EFI_MEMORY_DESCRIPTOR)))
+ {
+ EfiPrintf(L"Incorrect descriptor size\r\n");
+ Status = STATUS_UNSUCCESSFUL;
+ goto Quickie;
+ }
+
+ /* Did we boot from a RAM disk? */
+ if ((BlpBootDevice->DeviceType == LocalDevice) &&
+ (BlpBootDevice->Local.Type == RamDiskDevice))
+ {
+ /* We don't handle this yet */
+ EfiPrintf(L"RAM boot not supported\r\n");
+ Status = STATUS_NOT_IMPLEMENTED;
+ goto Quickie;
+ }
+ else
+ {
+ /* We didn't, so there won't be any need to find the memory descriptor */
+ HaveRamDisk = FALSE;
+ }
+
+ /* Loop the EFI memory map */
+#if 0
+ EfiPrintf(L"UEFI MEMORY MAP\r\n\r\n");
+ EfiPrintf(L"TYPE START END ATTRIBUTES\r\n");
+ EfiPrintf(L"===============================================================\r\n");
+#endif
+ while (EfiMemoryMapSize != 0)
+ {
+ /* Check if this is an EFI buffer, but we're not in real mode */
+ if ((UseEfiBuffer) && (OldMode != BlRealMode))
+ {
+ BlpArchSwitchContext(BlRealMode);
+ }
+
+ /* Capture it so we can go back to protected mode (if possible) */
+ EfiDescriptor = *EfiMemoryMap;
+
+ /* Go back to protected mode, if we had switched */
+ if ((UseEfiBuffer) && (OldMode != BlRealMode))
+ {
+ BlpArchSwitchContext(OldMode);
+ }
+
+ /* Convert to OS memory type */
+ MemoryType = MmFwpGetOsMemoryType(EfiDescriptor.Type);
+
+ /* Round up or round down depending on where the memory is coming from */
+ if (MemoryType == BlConventionalMemory)
+ {
+ StartPage = BYTES_TO_PAGES(EfiDescriptor.PhysicalStart);
+ }
+ else
+ {
+ StartPage = EfiDescriptor.PhysicalStart >> PAGE_SHIFT;
+ }
+
+ /* Calculate the ending page */
+ EndPage = StartPage + EfiDescriptor.NumberOfPages;
+
+ /* If after rounding, we ended up with 0 pages, skip this */
+ if (StartPage == EndPage)
+ {
+ goto LoopAgain;
+ }
+#if 0
+ EfiPrintf(L"%08X 0x%016I64X-0x%016I64X 0x%I64X\r\n",
+ MemoryType,
+ StartPage << PAGE_SHIFT,
+ EndPage << PAGE_SHIFT,
+ EfiDescriptor.Attribute);
+#endif
+ /* Check for any range of memory below 1MB */
+ if (StartPage < 0x100)
+ {
+ /* Does this range actually contain NULL? */
+ if (StartPage == 0)
+ {
+ /* Manually create a reserved descriptof for this page */
+ Attribute = MmFwpGetOsAttributeType(EfiDescriptor.Attribute);
+ Descriptor = MmMdInitByteGranularDescriptor(Attribute,
+ BlReservedMemory,
+ 0,
+ 0,
+ 1);
+ if (!Descriptor)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+
+ /* Add this descriptor into the list */
+ Status = MmMdAddDescriptorToList(MemoryMap,
+ Descriptor,
+ BL_MM_ADD_DESCRIPTOR_TRUNCATE_FLAG);
+ if (!NT_SUCCESS(Status))
+ {
+ EfiPrintf(L"Failed to add zero page descriptor: %lx\r\n", Status);
+ break;
+ }
+
+ /* Now handle the rest of the range, unless this was it */
+ StartPage = 1;
+ if (EndPage == 1)
+ {
+ goto LoopAgain;
+ }
+ }
+
+ /* Does the range go beyond 1MB? */
+ if (EndPage > 0x100)
+ {
+ /* Then create the descriptor for everything up until the megabyte */
+ Attribute = MmFwpGetOsAttributeType(EfiDescriptor.Attribute);
+ Descriptor = MmMdInitByteGranularDescriptor(Attribute,
+ MemoryType,
+ StartPage,
+ 0,
+ 0x100 - StartPage);
+ if (!Descriptor)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+
+ /* Check if this region is currently free RAM */
+ if (Descriptor->Type == BlConventionalMemory)
+ {
+ /* Set the appropriate flag on the descriptor */
+ Descriptor->Flags |= BlMemoryBelow1MB;
+ }
+
+ /* Add this descriptor into the list */
+ Status = MmMdAddDescriptorToList(MemoryMap,
+ Descriptor,
+ BL_MM_ADD_DESCRIPTOR_TRUNCATE_FLAG);
+ if (!NT_SUCCESS(Status))
+ {
+ EfiPrintf(L"Failed to add 1MB descriptor: %lx\r\n", Status);
+ break;
+ }
+
+ /* Now handle the rest of the range above 1MB */
+ StartPage = 0x100;
+ }
+ }
+
+ /* Check if we loaded from a RAM disk */
+ if (HaveRamDisk)
+ {
+ /* We don't handle this yet */
+ EfiPrintf(L"RAM boot not supported\r\n");
+ Status = STATUS_NOT_IMPLEMENTED;
+ goto Quickie;
+ }
+
+ /* Create a descriptor for the current range */
+ Attribute = MmFwpGetOsAttributeType(EfiDescriptor.Attribute);
+ Descriptor = MmMdInitByteGranularDescriptor(Attribute,
+ MemoryType,
+ StartPage,
+ 0,
+ EndPage - StartPage);
+ if (!Descriptor)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+
+ /* Check if this region is currently free RAM below 1MB */
+ if ((Descriptor->Type == BlConventionalMemory) && (EndPage <= 0x100))
+ {
+ /* Set the appropriate flag on the descriptor */
+ Descriptor->Flags |= BlMemoryBelow1MB;
+ }
+
+ /* Add the descriptor to the list, requesting coalescing as asked */
+ Status = MmMdAddDescriptorToList(MemoryMap,
+ Descriptor,
+ BL_MM_ADD_DESCRIPTOR_TRUNCATE_FLAG |
+ ((Flags & BL_MM_FLAG_REQUEST_COALESCING) ?
+ BL_MM_ADD_DESCRIPTOR_COALESCE_FLAG : 0));
+ if (!NT_SUCCESS(Status))
+ {
+ EfiPrintf(L"Failed to add full descriptor: %lx\r\n", Status);
+ break;
+ }
+
+LoopAgain:
+ /* Consume this descriptor, and move to the next one */
+ EfiMemoryMapSize -= DescriptorSize;
+ EfiMemoryMap = (PVOID)((ULONG_PTR)EfiMemoryMap + DescriptorSize);
+ }
+
+ /* Check if we are using the local UEFI buffer */
+ if (!UseEfiBuffer)
+ {
+ goto Quickie;
+ }
+
+ /* Free the EFI buffer */
+ Status = EfiFreePages(Pages, EfiBuffer);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Keep the pages marked 'in use' and fake success */
+ Status = STATUS_SUCCESS;
+ goto Quickie;
+ }
+
+ /* Get the base page of the EFI buffer */
+ EfiBufferPage = EfiBuffer >> PAGE_SHIFT;
+ Pages = (EfiBufferPage + Pages) - EfiBufferPage;
+
+ /* Don't try freeing below */
+ EfiBuffer = 0;
+
+ /* Find the current descriptor for the allocation */
+ Descriptor = MmMdFindDescriptorFromMdl(MemoryMap,
+ BL_MM_REMOVE_PHYSICAL_REGION_FLAG,
+ EfiBufferPage);
+ if (!Descriptor)
+ {
+ Status = STATUS_UNSUCCESSFUL;
+ goto Quickie;
+ }
+
+ /* Convert it to a free descriptor */
+ Descriptor = MmMdInitByteGranularDescriptor(Descriptor->Flags,
+ BlConventionalMemory,
+ EfiBufferPage,
+ 0,
+ Pages);
+ if (!Descriptor)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto Quickie;
+ }
+
+ /* Remove the region from the memory map */
+ Status = MmMdRemoveRegionFromMdlEx(MemoryMap,
+ BL_MM_REMOVE_PHYSICAL_REGION_FLAG,
+ EfiBufferPage,
+ Pages,
+ NULL);
+ if (!NT_SUCCESS(Status))
+ {
+ MmMdFreeDescriptor(Descriptor);
+ goto Quickie;
+ }
+
+ /* Add it back as free memory */
+ Status = MmMdAddDescriptorToList(MemoryMap,
+ Descriptor,
+ BL_MM_ADD_DESCRIPTOR_COALESCE_FLAG);
+
+Quickie:
+ /* Free the EFI buffer, if we had one */
+ if (EfiBuffer != 0)
+ {
+ EfiFreePages(Pages, EfiBuffer);
+ }
+
+ /* Free the library-allocated buffer, if we had one */
+ if (LibraryBuffer != 0)
+ {
+ MmPapFreePages(LibraryBuffer, BL_MM_INCLUDE_MAPPED_ALLOCATED);
+ }
+
+ /* On failure, free the memory map if one was passed in */
+ if (!NT_SUCCESS(Status) && (MemoryMap != NULL))
+ {
+ MmMdFreeList(MemoryMap);
+ }
+
+ /* Decrement the nesting depth and return */
+ MmDescriptorCallTreeCount--;
+ return Status;
+}
+
+NTSTATUS
+BlpFwInitialize (
+ _In_ ULONG Phase,
+ _In_ PBL_FIRMWARE_DESCRIPTOR FirmwareData
+ )
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ EFI_KEY_TOGGLE_STATE KeyToggleState;
+
+ /* Check if we have valid firmware data */
+ if (!(FirmwareData) || !(FirmwareData->Version))
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ /* Check which boot phase we're in */
+ if (Phase != 0)
+ {
+ /* Memory manager is ready, open the extended input protocol */
+ Status = EfiOpenProtocol(EfiST->ConsoleInHandle,
+ &EfiSimpleTextInputExProtocol,
+ (PVOID*)&EfiConInEx);
+ if (NT_SUCCESS(Status))
+ {
+ /* Set the initial key toggle state */
+ KeyToggleState = EFI_TOGGLE_STATE_VALID | 40;
+ EfiConInExSetState(EfiConInEx, &KeyToggleState);
+ }
+
+ /* Setup the watchdog timer */
+ EfiSetWatchdogTimer();
+ }
+ else
+ {
+ /* Make a copy of the parameters */
+ EfiFirmwareParameters = &EfiFirmwareData;
+
+ /* Check which version we received */
+ if (FirmwareData->Version == 1)
+ {
+ /* FIXME: Not supported */
+ Status = STATUS_NOT_SUPPORTED;
+ }
+ else if (FirmwareData->Version >= BL_FIRMWARE_DESCRIPTOR_VERSION)
+ {
+ /* Version 2 -- save the data */
+ EfiFirmwareData = *FirmwareData;
+ EfiSystemTable = FirmwareData->SystemTable;
+ EfiImageHandle = FirmwareData->ImageHandle;
+
+ /* Set the EDK-II style variables as well */
+ EfiST = EfiSystemTable;
+ EfiBS = EfiSystemTable->BootServices;
+ EfiRT = EfiSystemTable->RuntimeServices;
+ EfiConOut = EfiSystemTable->ConOut;
+ EfiConIn = EfiSystemTable->ConIn;
+ EfiConInEx = NULL;
+ }
+ else
+ {
+ /* Unknown version */
+ Status = STATUS_NOT_SUPPORTED;
+ }
+ }
+
+ /* Return the initialization state */
+ return Status;
+}
+
+NTSTATUS
+BlFwGetParameters (
+ _In_ PBL_FIRMWARE_DESCRIPTOR Parameters
+ )
+{
+ /* Make sure we got an argument */
+ if (!Parameters)
+ {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ /* Copy the static data */
+ *Parameters = *EfiFirmwareParameters;
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+BlFwEnumerateDevice (
+ _In_ PBL_DEVICE_DESCRIPTOR Device
+ )
+{
+ NTSTATUS Status;
+ ULONG PathProtocols, BlockProtocols;
+ EFI_HANDLE* PathArray;
+ EFI_HANDLE* BlockArray;
+
+ /* Initialize locals */
+ BlockArray = NULL;
+ PathArray = NULL;
+ PathProtocols = 0;
+ BlockProtocols = 0;
+
+ /* Enumeration only makes sense on disks or partitions */
+ if ((Device->DeviceType != DiskDevice) &&
+ (Device->DeviceType != LegacyPartitionDevice) &&
+ (Device->DeviceType != PartitionDevice))
+ {
+ return STATUS_NOT_SUPPORTED;
+ }
+
+ /* Enumerate the list of device paths */
+ Status = EfiLocateHandleBuffer(ByProtocol,
+ &EfiDevicePathProtocol,
+ &PathProtocols,
+ &PathArray);
+ if (NT_SUCCESS(Status))
+ {
+ /* Loop through each one */
+ Status = STATUS_NOT_FOUND;
+ while (PathProtocols)
+ {
+ /* Attempt to connect the driver for this device epath */
+ Status = EfiConnectController(PathArray[--PathProtocols]);
+ if (NT_SUCCESS(Status))
+ {
+ /* Now enumerate any block I/O devices the driver added */
+ Status = EfiLocateHandleBuffer(ByProtocol,
+ &EfiBlockIoProtocol,
+ &BlockProtocols,
+ &BlockArray);
+ if (!NT_SUCCESS(Status))
+ {
+ break;
+ }
+
+ /* Loop through each one */
+ while (BlockProtocols)
+ {
+ /* Check if one of the new devices is the one we want */
+ Status = BlockIoEfiCompareDevice(Device,
+ BlockArray[--BlockProtocols]);
+ if (NT_SUCCESS(Status))
+ {
+ /* Yep, all done */
+ goto Quickie;
+ }
+ }
+
+ /* Move on to the next device path */
+ BlMmFreeHeap(BlockArray);
+ BlockArray = NULL;
+ }
+ }
+ }
+
+Quickie:
+ /* We're done -- free the array of device path protocols, if any */
+ if (PathArray)
+ {
+ BlMmFreeHeap(PathArray);
+ }
+
+ /* We're done -- free the array of block I/O protocols, if any */
+ if (BlockArray)
+ {
+ BlMmFreeHeap(BlockArray);
+ }
+
+ /* Return if we found the device or not */
+ return Status;
+}
+
+/*++
+ * @name EfiGetEfiStatusCode
+ *
+ * The EfiGetEfiStatusCode routine converts an NT Status to an EFI status.
+ *
+ * @param Status
+ * NT Status code to be converted.
+ *
+ * @remark Only certain, specific NT status codes are converted to EFI codes.
+ *
+ * @return The corresponding EFI Status code, EFI_NO_MAPPING otherwise.
+ *
+ *--*/
+EFI_STATUS
+EfiGetEfiStatusCode(
+ _In_ NTSTATUS Status
+ )
+{
+ switch (Status)
+ {
+ case STATUS_NOT_SUPPORTED:
+ return EFI_UNSUPPORTED;
+ case STATUS_DISK_FULL:
+ return EFI_VOLUME_FULL;
+ case STATUS_INSUFFICIENT_RESOURCES:
+ return EFI_OUT_OF_RESOURCES;
+ case STATUS_MEDIA_WRITE_PROTECTED:
+ return EFI_WRITE_PROTECTED;
+ case STATUS_DEVICE_NOT_READY:
+ return EFI_NOT_STARTED;
+ case STATUS_DEVICE_ALREADY_ATTACHED:
+ return EFI_ALREADY_STARTED;
+ case STATUS_MEDIA_CHANGED:
+ return EFI_MEDIA_CHANGED;
+ case STATUS_INVALID_PARAMETER:
+ return EFI_INVALID_PARAMETER;
+ case STATUS_ACCESS_DENIED:
+ return EFI_ACCESS_DENIED;
+ case STATUS_BUFFER_TOO_SMALL:
+ return EFI_BUFFER_TOO_SMALL;
+ case STATUS_DISK_CORRUPT_ERROR:
+ return EFI_VOLUME_CORRUPTED;
+ case STATUS_REQUEST_ABORTED:
+ return EFI_ABORTED;
+ case STATUS_NO_MEDIA:
+ return EFI_NO_MEDIA;
+ case STATUS_IO_DEVICE_ERROR:
+ return EFI_DEVICE_ERROR;
+ case STATUS_INVALID_BUFFER_SIZE:
+ return EFI_BAD_BUFFER_SIZE;
+ case STATUS_NOT_FOUND:
+ return EFI_NOT_FOUND;
+ case STATUS_DRIVER_UNABLE_TO_LOAD:
+ return EFI_LOAD_ERROR;
+ case STATUS_NO_MATCH:
+ return EFI_NO_MAPPING;
+ case STATUS_SUCCESS:
+ return EFI_SUCCESS;
+ case STATUS_TIMEOUT:
+ return EFI_TIMEOUT;
+ default:
+ return EFI_NO_MAPPING;
+ }
+}
+
+/*++
+ * @name EfiGetNtStatusCode
+ *
+ * The EfiGetNtStatusCode routine converts an EFI Status to an NT status.
+ *
+ * @param EfiStatus
+ * EFI Status code to be converted.
+ *
+ * @remark Only certain, specific EFI status codes are converted to NT codes.
+ *
+ * @return The corresponding NT Status code, STATUS_UNSUCCESSFUL otherwise.
+ *
+ *--*/
+NTSTATUS
+EfiGetNtStatusCode (
+ _In_ EFI_STATUS EfiStatus
+ )
+{
+ switch (EfiStatus)
+ {
+ case EFI_NOT_READY:
+ case EFI_NOT_FOUND:
+ return STATUS_NOT_FOUND;
+ case EFI_NO_MEDIA:
+ return STATUS_NO_MEDIA;
+ case EFI_MEDIA_CHANGED:
+ return STATUS_MEDIA_CHANGED;
+ case EFI_ACCESS_DENIED:
+ case EFI_SECURITY_VIOLATION:
+ return STATUS_ACCESS_DENIED;
+ case EFI_TIMEOUT:
+ case EFI_NO_RESPONSE:
+ return STATUS_TIMEOUT;
+ case EFI_NO_MAPPING:
+ return STATUS_NO_MATCH;
+ case EFI_NOT_STARTED:
+ return STATUS_DEVICE_NOT_READY;
+ case EFI_ALREADY_STARTED:
+ return STATUS_DEVICE_ALREADY_ATTACHED;
+ case EFI_ABORTED:
+ return STATUS_REQUEST_ABORTED;
+ case EFI_VOLUME_FULL:
+ return STATUS_DISK_FULL;
+ case EFI_DEVICE_ERROR:
+ return STATUS_IO_DEVICE_ERROR;
+ case EFI_WRITE_PROTECTED:
+ return STATUS_MEDIA_WRITE_PROTECTED;
+ /* @FIXME: ReactOS Headers don't yet have this */
+ //case EFI_OUT_OF_RESOURCES:
+ //return STATUS_INSUFFICIENT_NVRAM_RESOURCES;
+ case EFI_VOLUME_CORRUPTED:
+ return STATUS_DISK_CORRUPT_ERROR;
+ case EFI_BUFFER_TOO_SMALL:
+ return STATUS_BUFFER_TOO_SMALL;
+ case EFI_SUCCESS:
+ return STATUS_SUCCESS;
+ case EFI_LOAD_ERROR:
+ return STATUS_DRIVER_UNABLE_TO_LOAD;
+ case EFI_INVALID_PARAMETER:
+ return STATUS_INVALID_PARAMETER;
+ case EFI_UNSUPPORTED:
+ return STATUS_NOT_SUPPORTED;
+ case EFI_BAD_BUFFER_SIZE:
+ return STATUS_INVALID_BUFFER_SIZE;
+ default:
+ return STATUS_UNSUCCESSFUL;
+ }
+}