399 lines
8.0 KiB
C
399 lines
8.0 KiB
C
/*!
|
|
@file EfiPlatform.c
|
|
|
|
@details Some of API in this module can be called from the host. See the
|
|
description of each API.
|
|
|
|
@brief EFI specific platform API.
|
|
|
|
@author Satoshi Tanda
|
|
|
|
@copyright Copyright (c) 2020 - , Satoshi Tanda. All rights reserved.
|
|
*/
|
|
#include "EfiPlatform.h"
|
|
#include <Guid/EventGroup.h>
|
|
#include <Library/DevicePathLib.h>
|
|
#include <Library/MemoryAllocationLib.h>
|
|
#include <Library/UefiBootServicesTableLib.h>
|
|
#include <Library/UefiRuntimeServicesTableLib.h>
|
|
#include <Pi/PiDxeCis.h>
|
|
#include <Protocol/MpService.h>
|
|
#include <Protocol/LoadedImage.h>
|
|
#include "EfiLogger.h"
|
|
#include "../../MiniVisor.h"
|
|
|
|
//
|
|
// Maps conversion between MV_STATUS and NTSTATUS.
|
|
//
|
|
typedef struct _STATUS_MAPPING
|
|
{
|
|
MV_STATUS MvStatus;
|
|
EFI_STATUS EfiStatus;
|
|
} STATUS_MAPPING;
|
|
|
|
static CONST STATUS_MAPPING k_StatusMapping[] =
|
|
{
|
|
{ MV_STATUS_SUCCESS, EFI_SUCCESS, },
|
|
{ MV_STATUS_UNSUCCESSFUL, EFI_ABORTED, },
|
|
{ MV_STATUS_ACCESS_DENIED, EFI_ACCESS_DENIED, },
|
|
{ MV_STATUS_INSUFFICIENT_RESOURCES, EFI_OUT_OF_RESOURCES, },
|
|
{ MV_STATUS_HV_OPERATION_FAILED, EFI_UNSUPPORTED, },
|
|
};
|
|
|
|
//
|
|
// The multi-processor protocol. Only available during the boot-time.
|
|
//
|
|
static EFI_MP_SERVICES_PROTOCOL* g_MpServices;
|
|
|
|
/*!
|
|
@brief Converts MV_STATUS to EFI_STATUS.
|
|
|
|
@param[in] Status - The MV_STATUS to convert from.
|
|
|
|
@return The converted EFI_STATUS.
|
|
*/
|
|
static
|
|
EFI_STATUS
|
|
ConvertMvToEfiStatus (
|
|
MV_STATUS Status
|
|
)
|
|
{
|
|
for (UINT32 i = 0; i < RTL_NUMBER_OF(k_StatusMapping); ++i)
|
|
{
|
|
if (Status == k_StatusMapping[i].MvStatus)
|
|
{
|
|
return k_StatusMapping[i].EfiStatus;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Update the mapping when this assert hits.
|
|
//
|
|
MV_ASSERT(FALSE);
|
|
return EFI_ABORTED;
|
|
}
|
|
|
|
/*!
|
|
@brief Converts EFI_STATUS to MV_STATUS.
|
|
|
|
@param[in] Status - The EFI_STATUS to convert from.
|
|
|
|
@return The converted MV_STATUS.
|
|
*/
|
|
static
|
|
MV_STATUS
|
|
ConvertEfiToMvStatus (
|
|
EFI_STATUS Status
|
|
)
|
|
{
|
|
for (UINT32 i = 0; i < RTL_NUMBER_OF(k_StatusMapping); ++i)
|
|
{
|
|
if (Status == k_StatusMapping[i].EfiStatus)
|
|
{
|
|
return k_StatusMapping[i].MvStatus;
|
|
}
|
|
}
|
|
return MV_STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
/*!
|
|
@brief Displays information about the current module.
|
|
|
|
@details Use of this API at the run-time is not allowed.
|
|
|
|
@return EFI_SUCCESS on success; otherwise, an appropriate error code.
|
|
*/
|
|
static
|
|
EFI_STATUS
|
|
PrintLoadedImageInformation (
|
|
)
|
|
{
|
|
EFI_STATUS status;
|
|
EFI_LOADED_IMAGE_PROTOCOL* loadedImageInfo;
|
|
CHAR16* devicePath;
|
|
|
|
devicePath = NULL;
|
|
|
|
status = gBS->OpenProtocol(gImageHandle,
|
|
&gEfiLoadedImageProtocolGuid,
|
|
(VOID**)&loadedImageInfo,
|
|
gImageHandle,
|
|
NULL,
|
|
EFI_OPEN_PROTOCOL_GET_PROTOCOL);
|
|
if (EFI_ERROR(status))
|
|
{
|
|
LOG_ERROR("OpenProtocol failed : %r", status);
|
|
goto Exit;
|
|
}
|
|
|
|
devicePath = ConvertDevicePathToText(loadedImageInfo->FilePath, TRUE, TRUE);
|
|
if (devicePath == NULL)
|
|
{
|
|
LOG_ERROR("ConvertDevicePathToText failed");
|
|
status = EFI_OUT_OF_RESOURCES;
|
|
goto Exit;
|
|
}
|
|
|
|
LOG_INFO("%s - %llx:%llx",
|
|
devicePath,
|
|
loadedImageInfo->ImageBase,
|
|
MV_ADD2PTR(loadedImageInfo->ImageBase, loadedImageInfo->ImageSize));
|
|
|
|
Exit:
|
|
if (devicePath != NULL)
|
|
{
|
|
FreePool(devicePath);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
/*!
|
|
@brief The platform specific module entry point.
|
|
|
|
@param[in] ImageHandle - The handle of this module.
|
|
|
|
@param[in] SystemTable - The boot service table pointer.
|
|
|
|
@return EFI_SUCCESS on success; otherwise, an appropriate error code.
|
|
*/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
DriverEntry (
|
|
EFI_HANDLE ImageHandle,
|
|
EFI_SYSTEM_TABLE* SystemTable
|
|
)
|
|
{
|
|
ASSERT(ImageHandle == gImageHandle);
|
|
ASSERT(SystemTable->BootServices == gBS);
|
|
|
|
return ConvertMvToEfiStatus(InitializeMiniVisor());
|
|
}
|
|
|
|
/*!
|
|
@brief The platform specific module unload callback.
|
|
|
|
@param[in] ImageHandle - The handle of this module.
|
|
|
|
@return Always EFI_SUCCESS.
|
|
*/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
DriverUnload (
|
|
EFI_HANDLE ImageHandle
|
|
)
|
|
{
|
|
CleanupMiniVisor();
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
MV_STATUS
|
|
InitializePlatform (
|
|
)
|
|
{
|
|
EFI_STATUS status;
|
|
BOOLEAN isLoggerInitialized;
|
|
|
|
status = InitializeLogger();
|
|
if (EFI_ERROR(status))
|
|
{
|
|
LOG_EARLY_ERROR("InitializeLogger failed : %r", status);
|
|
goto Exit;
|
|
}
|
|
isLoggerInitialized = TRUE;
|
|
|
|
PrintLoadedImageInformation();
|
|
|
|
//
|
|
// Locate the protocol for multi-processor handling. UEFI on a Hyper-V VM
|
|
// does not implement this and fails.
|
|
//
|
|
status = gBS->LocateProtocol(&gEfiMpServiceProtocolGuid,
|
|
NULL,
|
|
&g_MpServices);
|
|
if (EFI_ERROR(status))
|
|
{
|
|
LOG_ERROR("LocateProtocol failed : %r", status);
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
if (EFI_ERROR(status))
|
|
{
|
|
if (isLoggerInitialized != FALSE)
|
|
{
|
|
CleanupLogger();
|
|
}
|
|
}
|
|
return ConvertEfiToMvStatus(status);
|
|
}
|
|
|
|
VOID
|
|
CleanupPlatform (
|
|
)
|
|
{
|
|
CleanupLogger();
|
|
}
|
|
|
|
UINT32
|
|
GetActiveProcessorCount (
|
|
)
|
|
{
|
|
EFI_STATUS status;
|
|
UINTN numberOfProcessors;
|
|
UINTN numberOfEnabledProcessors;
|
|
|
|
status = g_MpServices->GetNumberOfProcessors(g_MpServices,
|
|
&numberOfProcessors,
|
|
&numberOfEnabledProcessors);
|
|
if (EFI_ERROR(status))
|
|
{
|
|
MV_PANIC();
|
|
}
|
|
|
|
return (UINT32)numberOfEnabledProcessors;
|
|
}
|
|
|
|
UINT32
|
|
GetCurrentProcessorNumber (
|
|
)
|
|
{
|
|
EFI_STATUS status;
|
|
UINTN processorNumber;
|
|
|
|
status = g_MpServices->WhoAmI(g_MpServices, &processorNumber);
|
|
if (EFI_ERROR(status))
|
|
{
|
|
MV_PANIC();
|
|
}
|
|
|
|
return (UINT32)processorNumber;
|
|
}
|
|
|
|
UINT64
|
|
GetPhysicalAddress (
|
|
VOID* VirualAddress
|
|
)
|
|
{
|
|
//
|
|
// Assume the current CR3 uses the identity mapping. This is the case during
|
|
// the boot time or execution of the host.
|
|
//
|
|
return (UINT64)VirualAddress;
|
|
}
|
|
|
|
VOID*
|
|
GetVirtualAddress (
|
|
UINT64 PhysicalAddress
|
|
)
|
|
{
|
|
//
|
|
// This function assume the current CR3 uses the identity mapping. This is
|
|
// the case during the boot time or execution of the host.
|
|
//
|
|
return (VOID*)PhysicalAddress;
|
|
}
|
|
|
|
VOID*
|
|
AllocateSystemMemory (
|
|
UINT64 PageCount
|
|
)
|
|
{
|
|
VOID* pages;
|
|
|
|
pages = AllocateRuntimePages(PageCount);
|
|
if (pages == NULL)
|
|
{
|
|
goto Exit;
|
|
}
|
|
ZeroMem(pages, PageCount * EFI_PAGE_SIZE);
|
|
|
|
Exit:
|
|
return pages;
|
|
}
|
|
|
|
VOID
|
|
FreeSystemMemory (
|
|
VOID* Pages,
|
|
UINT64 PageCount
|
|
)
|
|
{
|
|
FreePages(Pages, PageCount);
|
|
}
|
|
|
|
VOID*
|
|
ReserveVirtualAddress (
|
|
UINT64 PageCount
|
|
)
|
|
{
|
|
return AllocateSystemMemory(PageCount);
|
|
}
|
|
|
|
VOID
|
|
FreeReservedVirtualAddress (
|
|
VOID* BaseAddress,
|
|
UINT64 PageCount
|
|
)
|
|
{
|
|
FreeSystemMemory(BaseAddress, PageCount);
|
|
}
|
|
|
|
VOID
|
|
RunOnAllProcessors (
|
|
USER_PASSIVE_CALLBACK* Callback,
|
|
VOID* Context
|
|
)
|
|
{
|
|
EFI_STATUS status;
|
|
|
|
Callback(Context);
|
|
if (GetActiveProcessorCount() == 1)
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
status = g_MpServices->StartupAllAPs(g_MpServices,
|
|
Callback,
|
|
TRUE,
|
|
NULL,
|
|
0,
|
|
Context,
|
|
NULL);
|
|
if (EFI_ERROR(status))
|
|
{
|
|
MV_PANIC();
|
|
}
|
|
|
|
Exit:
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
InitializeSystemSpinLock (
|
|
SPIN_LOCK* SpinLock
|
|
)
|
|
{
|
|
(VOID)InitializeSpinLock(SpinLock);
|
|
}
|
|
|
|
UINT8
|
|
AcquireSystemSpinLock (
|
|
SPIN_LOCK* SpinLock
|
|
)
|
|
{
|
|
//
|
|
// This function does not raise TPL as it is not available at the run time.
|
|
//
|
|
(VOID)AcquireSpinLock(SpinLock);
|
|
return 0;
|
|
}
|
|
|
|
VOID
|
|
ReleaseSystemSpinLock (
|
|
SPIN_LOCK* SpinLock,
|
|
UINT8 PreviousContext
|
|
)
|
|
{
|
|
ASSERT(PreviousContext == 0);
|
|
(VOID)ReleaseSpinLock(SpinLock);
|
|
}
|