Started BlpMmDestroy(), MmMdDestroy(), MmPaDestroy(), EfiSetWatchdogTimer(), EfiOpenProtocol(), EfiConInExSetState(), and BlDestroyLibrary(). Completed BlpFwInitialize(). Improved InitializeLibrary().
537 lines
12 KiB
C
537 lines
12 KiB
C
/*++
|
|
|
|
Copyright (c) 2024, Quinn Stephens.
|
|
Provided under the BSD 3-Clause license.
|
|
|
|
Module Name:
|
|
|
|
efilib.c
|
|
|
|
Abstract:
|
|
|
|
Provides EFI utilities.
|
|
|
|
--*/
|
|
|
|
#include "efilib.h"
|
|
#include "mm.h"
|
|
|
|
EFI_GUID EfiSimpleTextInputExProtocol = EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID;
|
|
|
|
EFI_STATUS
|
|
EfiGetEfiStatusCode (
|
|
IN NTSTATUS Status
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Converts an NT status code into an EFI status code.
|
|
|
|
Arguments:
|
|
|
|
Status - The NT status code.
|
|
|
|
Return Value:
|
|
|
|
The EFI status code.
|
|
|
|
--*/
|
|
|
|
{
|
|
switch (Status) {
|
|
case STATUS_SUCCESS:
|
|
return EFI_SUCCESS;
|
|
case STATUS_DRIVER_UNABLE_TO_LOAD:
|
|
return EFI_LOAD_ERROR;
|
|
case STATUS_INVALID_PARAMETER:
|
|
return EFI_INVALID_PARAMETER;
|
|
case STATUS_NOT_SUPPORTED:
|
|
return EFI_UNSUPPORTED;
|
|
case STATUS_INVALID_BUFFER_SIZE:
|
|
return EFI_BAD_BUFFER_SIZE;
|
|
case STATUS_BUFFER_TOO_SMALL:
|
|
return EFI_BUFFER_TOO_SMALL;
|
|
case STATUS_IO_DEVICE_ERROR:
|
|
return EFI_DEVICE_ERROR;
|
|
case STATUS_MEDIA_WRITE_PROTECTED:
|
|
return EFI_WRITE_PROTECTED;
|
|
case STATUS_INSUFFICIENT_RESOURCES:
|
|
case STATUS_INSUFFICIENT_NVRAM_RESOURCES:
|
|
return EFI_OUT_OF_RESOURCES;
|
|
case STATUS_DISK_CORRUPT_ERROR:
|
|
return EFI_VOLUME_CORRUPTED;
|
|
case STATUS_DISK_FULL:
|
|
return EFI_VOLUME_FULL;
|
|
case STATUS_NO_MEDIA:
|
|
return EFI_NO_MEDIA;
|
|
case STATUS_MEDIA_CHANGED:
|
|
return EFI_MEDIA_CHANGED;
|
|
case STATUS_NOT_FOUND:
|
|
return EFI_NOT_FOUND;
|
|
case STATUS_ACCESS_DENIED:
|
|
return EFI_ACCESS_DENIED;
|
|
case STATUS_NO_MATCH:
|
|
return EFI_NO_MAPPING;
|
|
case STATUS_TIMEOUT:
|
|
return EFI_TIMEOUT;
|
|
case STATUS_DEVICE_NOT_READY:
|
|
return EFI_NOT_STARTED;
|
|
case STATUS_DEVICE_ALREADY_ATTACHED:
|
|
return EFI_ALREADY_STARTED;
|
|
case STATUS_REQUEST_ABORTED:
|
|
return EFI_ABORTED;
|
|
default:
|
|
return EFI_NO_MAPPING;
|
|
}
|
|
}
|
|
|
|
NTSTATUS
|
|
EfiGetNtStatusCode (
|
|
IN EFI_STATUS Status
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Converts an EFI status code into an NT status code.
|
|
|
|
Arguments:
|
|
|
|
Status - The EFI status code.
|
|
|
|
Return Value:
|
|
|
|
The NT status code.
|
|
|
|
--*/
|
|
|
|
{
|
|
switch (Status) {
|
|
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;
|
|
case EFI_BUFFER_TOO_SMALL:
|
|
return STATUS_BUFFER_TOO_SMALL;
|
|
case EFI_DEVICE_ERROR:
|
|
return STATUS_IO_DEVICE_ERROR;
|
|
case EFI_WRITE_PROTECTED:
|
|
return STATUS_MEDIA_WRITE_PROTECTED;
|
|
case EFI_OUT_OF_RESOURCES:
|
|
return STATUS_INSUFFICIENT_NVRAM_RESOURCES;
|
|
case EFI_VOLUME_CORRUPTED:
|
|
return STATUS_DISK_CORRUPT_ERROR;
|
|
case EFI_VOLUME_FULL:
|
|
return STATUS_DISK_FULL;
|
|
case EFI_NO_MEDIA:
|
|
return STATUS_NO_MEDIA;
|
|
case EFI_MEDIA_CHANGED:
|
|
return STATUS_MEDIA_CHANGED;
|
|
case EFI_NOT_FOUND:
|
|
case EFI_NOT_READY:
|
|
return STATUS_NOT_FOUND;
|
|
case EFI_ACCESS_DENIED:
|
|
case EFI_SECURITY_VIOLATION:
|
|
return STATUS_ACCESS_DENIED;
|
|
case EFI_NO_MAPPING:
|
|
return STATUS_NO_MATCH;
|
|
case EFI_TIMEOUT:
|
|
case EFI_NO_RESPONSE:
|
|
return STATUS_TIMEOUT;
|
|
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;
|
|
default:
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
}
|
|
|
|
NTSTATUS
|
|
EfiGetMemoryMap (
|
|
IN OUT UINTN *MemoryMapSize,
|
|
IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
|
|
IN OUT UINTN *MapKey,
|
|
IN OUT UINTN *DescriptorSize,
|
|
IN OUT UINT32 *DescriptorVersion
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Wrapper for EFI_BOOT_SERVICES.GetMemoryMap(). Gets the firmware memory map
|
|
and places it into a buffer.
|
|
|
|
Arguments:
|
|
|
|
MemoryMapSize - pointer to the size of the buffer.
|
|
|
|
MemoryMap - pointer to the buffer to store the memory map in.
|
|
|
|
MapKey - ponter to the memory map key.
|
|
|
|
DescriptorSize - pointer to the size of each memory map descriptor.
|
|
|
|
DescriptorVersion - pointer to the version of memory map descriptors.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if successful.
|
|
STATUS_INVALID_PARAMETER if MemoryMapSize and/or MemoryMap are invalid.
|
|
STATUS_BUFFER_TOO_SMALL if MemoryMapSize is too small.
|
|
|
|
--*/
|
|
|
|
{
|
|
EXECUTION_CONTEXT_TYPE ContextType;
|
|
EFI_STATUS EfiStatus;
|
|
|
|
ContextType = CurrentExecutionContext->Type;
|
|
if (ContextType != ExecutionContextFirmware) {
|
|
//
|
|
// TODO: Translate addresses here.
|
|
// Need MmArchTranslateVirtualAddress().
|
|
//
|
|
|
|
BlpArchSwitchContext(ExecutionContextFirmware);
|
|
}
|
|
|
|
EfiStatus = EfiBS->GetMemoryMap(
|
|
MemoryMapSize,
|
|
MemoryMap,
|
|
MapKey,
|
|
DescriptorSize,
|
|
DescriptorVersion
|
|
);
|
|
|
|
if (ContextType != ExecutionContextFirmware) {
|
|
BlpArchSwitchContext(ContextType);
|
|
}
|
|
|
|
return EfiGetNtStatusCode(EfiStatus);
|
|
}
|
|
|
|
NTSTATUS
|
|
EfiAllocatePages (
|
|
IN EFI_ALLOCATE_TYPE Type,
|
|
IN EFI_MEMORY_TYPE MemoryType,
|
|
IN UINTN Pages,
|
|
IN OUT EFI_PHYSICAL_ADDRESS *Memory
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Wrapper for EFI_BOOT_SERVICES.AllocatePages(). Allocates contiguous pages
|
|
of physical memory.
|
|
|
|
Arguments:
|
|
|
|
Type - the type of allocation.
|
|
|
|
MemoryType - the type of memory to allocate.
|
|
|
|
Pages - the number of pages to allocate.
|
|
|
|
Memory - pointer to a physical address of the allocation.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if successful.
|
|
STATUS_INVALID_PARAMETER if Type, MemoryType, and/or Memory are invalid.
|
|
STATUS_INSUFFICIENT_NVRAM_RESOURCES if the pages could not be allocated.
|
|
STATUS_NOT_FOUND if the pages could not be found.
|
|
|
|
--*/
|
|
|
|
{
|
|
EXECUTION_CONTEXT_TYPE ContextType;
|
|
EFI_STATUS EfiStatus;
|
|
|
|
ContextType = CurrentExecutionContext->Type;
|
|
if (ContextType != ExecutionContextFirmware) {
|
|
BlpArchSwitchContext(ExecutionContextFirmware);
|
|
}
|
|
|
|
EfiStatus = EfiBS->AllocatePages(
|
|
Type,
|
|
MemoryType,
|
|
Pages,
|
|
Memory
|
|
);
|
|
|
|
if (ContextType != ExecutionContextFirmware) {
|
|
BlpArchSwitchContext(ContextType);
|
|
}
|
|
|
|
return EfiGetNtStatusCode(EfiStatus);
|
|
}
|
|
|
|
NTSTATUS
|
|
EfiFreePages (
|
|
IN EFI_PHYSICAL_ADDRESS Memory,
|
|
IN UINTN Pages
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Wrapper for EFI_BOOT_SERVICES.FreePages(). Frees contiguous pages
|
|
of physical memory.
|
|
|
|
Arguments:
|
|
|
|
Memory - physical address of the pages to be freed.
|
|
|
|
Pages - the number of pages to free.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if successful.
|
|
STATUS_NOT_FOUND if the allocation was not found.
|
|
STATUS_INVALID_PARAMETER Memory and/or Pages are invalid.
|
|
|
|
--*/
|
|
|
|
{
|
|
EXECUTION_CONTEXT_TYPE ContextType;
|
|
EFI_STATUS EfiStatus;
|
|
|
|
ContextType = CurrentExecutionContext->Type;
|
|
if (ContextType != ExecutionContextFirmware) {
|
|
BlpArchSwitchContext(ExecutionContextFirmware);
|
|
}
|
|
|
|
EfiStatus = EfiBS->FreePages(
|
|
Memory,
|
|
Pages
|
|
);
|
|
|
|
if (ContextType != ExecutionContextFirmware) {
|
|
BlpArchSwitchContext(ContextType);
|
|
}
|
|
|
|
return EfiGetNtStatusCode(EfiStatus);
|
|
}
|
|
|
|
NTSTATUS
|
|
EfiSetWatchdogTimer (
|
|
IN UINTN Timeout,
|
|
IN UINT64 WatchdogCode,
|
|
IN UINTN DataSize,
|
|
IN CHAR16 *WatchdogData
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Wrapper for EFI_BOOT_SERVICES.SetWatchdogTimer().
|
|
Sets the watchdog timer.
|
|
|
|
Arguments:
|
|
|
|
Timeout - The number of seconds to set the timer to.
|
|
Setting this to 0 disables the timer.
|
|
|
|
WatchdogCode - The code to set when an event occurs.
|
|
|
|
DataSize - The size in bytes of WatchdogData.
|
|
|
|
WatchdogData - Optional pointer to a string containing
|
|
a description of the timer, possibly accompanied
|
|
by binary data.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if successful.
|
|
STATUS_INVALID_PARAMETER if WatchdogCode is invalid.
|
|
STATUS_NOT_SUPPORTED if there is no Watchdog timer.
|
|
STATUS_IO_DEVICE_ERROR if the timer could not be set.
|
|
|
|
--*/
|
|
|
|
{
|
|
EXECUTION_CONTEXT_TYPE ContextType;
|
|
EFI_STATUS EfiStatus;
|
|
|
|
if (Timeout != 0 && WatchdogCode <= 0xffff) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
ContextType = CurrentExecutionContext->Type;
|
|
if (ContextType != ExecutionContextFirmware) {
|
|
//
|
|
// TODO: Translate addresses here.
|
|
// Need MmArchTranslateVirtualAddress().
|
|
//
|
|
|
|
BlpArchSwitchContext(ExecutionContextFirmware);
|
|
}
|
|
|
|
EfiStatus = EfiBS->SetWatchdogTimer(
|
|
Timeout,
|
|
WatchdogCode,
|
|
DataSize,
|
|
WatchdogData
|
|
);
|
|
|
|
if (ContextType != ExecutionContextFirmware) {
|
|
BlpArchSwitchContext(ContextType);
|
|
}
|
|
|
|
return EfiGetNtStatusCode(EfiStatus);
|
|
}
|
|
|
|
NTSTATUS
|
|
EfiOpenProtocol (
|
|
IN EFI_HANDLE Handle,
|
|
IN EFI_GUID *Protocol,
|
|
IN OUT VOID **Interface
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Wrapper that uses either EFI_BOOT_SERVICES.OpenProtocol() or HandleProtocol().
|
|
Opens a handle to a protocol and finds its interface.
|
|
|
|
Arguments:
|
|
|
|
Handle - The handle to the protocol to open.
|
|
|
|
Protocol - The GUID of the protocol.
|
|
|
|
Intercce - Pointer that recieves the address of the interface.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if successful.
|
|
Error code on failure.
|
|
|
|
--*/
|
|
|
|
{
|
|
EXECUTION_CONTEXT_TYPE ContextType;
|
|
EFI_STATUS EfiStatus;
|
|
NTSTATUS Status;
|
|
|
|
if (MmTranslationType != TRANSLATION_TYPE_NONE) {
|
|
//
|
|
// TODO: Translate addresses.
|
|
// Need EfiVmOpenProtocol().
|
|
//
|
|
DebugPrint(L"EfiOpenProtocol(): Virtual address translation not supported\r\n");
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
ContextType = CurrentExecutionContext->Type;
|
|
if (ContextType != ExecutionContextFirmware) {
|
|
BlpArchSwitchContext(ExecutionContextFirmware);
|
|
}
|
|
|
|
//
|
|
// If supported, use OpenProtocol() (EFI 1.10+).
|
|
// It helps ensure the protocol is not uninstalled
|
|
// when still in use.
|
|
//
|
|
if (EfiST->Hdr.Revision >= EFI_MAKE_REVISION(1, 10)) {
|
|
EfiStatus = EfiBS->OpenProtocol(
|
|
Handle,
|
|
Protocol,
|
|
Interface,
|
|
EfiImageHandle,
|
|
NULL,
|
|
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
|
);
|
|
} else {
|
|
EfiStatus = EfiBS->HandleProtocol(
|
|
Handle,
|
|
Protocol,
|
|
Interface
|
|
);
|
|
}
|
|
|
|
if (ContextType != ExecutionContextFirmware) {
|
|
BlpArchSwitchContext(ContextType);
|
|
}
|
|
|
|
//
|
|
// Convert EFI status to NT status.
|
|
//
|
|
Status = EfiGetNtStatusCode(EfiStatus);
|
|
if (!NT_SUCCESS(Status)) {
|
|
*Interface = NULL;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
EfiConInExSetState (
|
|
IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *Protocol,
|
|
IN EFI_KEY_TOGGLE_STATE *KeyToggleState
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Wrapper around EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.SetState().
|
|
Sets an input protocol's state.
|
|
|
|
Arguments:
|
|
|
|
Protocol - The protocol to set the state of.
|
|
|
|
KeyToggle State - The state to set.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if successful.
|
|
STATUS_IO_DEVICE_ERROR if the state could not be set.
|
|
STATUS_UNSUPPORTED if State is not supported by the device.
|
|
|
|
--*/
|
|
|
|
{
|
|
EXECUTION_CONTEXT_TYPE ContextType;
|
|
EFI_STATUS EfiStatus;
|
|
|
|
ContextType = CurrentExecutionContext->Type;
|
|
if (ContextType != ExecutionContextFirmware) {
|
|
//
|
|
// TODO: Translate addresses here.
|
|
// Need MmArchTranslateVirtualAddress().
|
|
//
|
|
|
|
BlpArchSwitchContext(ExecutionContextFirmware);
|
|
}
|
|
|
|
EfiStatus = Protocol->SetState(
|
|
Protocol,
|
|
KeyToggleState
|
|
);
|
|
|
|
if (ContextType != ExecutionContextFirmware) {
|
|
BlpArchSwitchContext(ContextType);
|
|
}
|
|
|
|
return EfiGetNtStatusCode(EfiStatus);
|
|
}
|