Publish the files
This commit is contained in:
105
Sources/Platform/EFI/EfiAsm.asm
Normal file
105
Sources/Platform/EFI/EfiAsm.asm
Normal file
@@ -0,0 +1,105 @@
|
||||
;
|
||||
; @file EfiAsm.asm
|
||||
;
|
||||
; @brief EFI specific MASM-written functions.
|
||||
;
|
||||
; @author Satoshi Tanda
|
||||
;
|
||||
; @copyright Copyright (c) 2020 - , Satoshi Tanda. All rights reserved.
|
||||
;
|
||||
include AsmCommon.inc
|
||||
.code
|
||||
|
||||
extern HandleHostException : proc
|
||||
|
||||
;
|
||||
; The index to track an interrupt number for generating AsmDefaultExceptionHandlers.
|
||||
;
|
||||
Index = 0
|
||||
|
||||
;
|
||||
; Generates the default exception handler code for the given interrupt/exception
|
||||
; number. The generated code assumes that the interrupt/exception does not push
|
||||
; error code.
|
||||
;
|
||||
; Index is incremented whenever this macro is used.
|
||||
;
|
||||
INTERRUPT_HANDLER macro InterruptNumber
|
||||
push 0 ; Push dummy error code for consistent stack layout.
|
||||
push InterruptNumber
|
||||
jmp AsmCommonExceptionHandler
|
||||
Index = Index + 1
|
||||
endm
|
||||
|
||||
;
|
||||
; Generates the default exception handler code for the given interrupt/exception
|
||||
; number. The generated code assumes that the interrupt/exception pushes error code.
|
||||
;
|
||||
; Index is incremented whenever this macro is used.
|
||||
;
|
||||
INTERRUPT_HANDLER_WITH_CODE macro InterruptNumber
|
||||
nop ; Error code is expected to be pushed by the processor.
|
||||
nop
|
||||
push InterruptNumber
|
||||
jmp AsmCommonExceptionHandler
|
||||
Index = Index + 1
|
||||
endm
|
||||
|
||||
;
|
||||
; @brief The default host exception handlers.
|
||||
;
|
||||
; @details This is the function containing actually 256 stub functions generated
|
||||
; with the INTERRUPT_HANDLER and INTERRUPT_HANDLER_WITH_CODE macros. Each function
|
||||
; works as a hendler of the corresponding interrupt/exception in the host.
|
||||
;
|
||||
AsmDefaultExceptionHandlers proc
|
||||
repeat 8
|
||||
INTERRUPT_HANDLER Index ; INT0-7
|
||||
endm
|
||||
|
||||
INTERRUPT_HANDLER_WITH_CODE Index ; INT8
|
||||
INTERRUPT_HANDLER Index ; INT9
|
||||
|
||||
repeat 5
|
||||
INTERRUPT_HANDLER_WITH_CODE Index ; INT10-14
|
||||
endm
|
||||
|
||||
repeat 2
|
||||
INTERRUPT_HANDLER Index ; INT15-16
|
||||
endm
|
||||
|
||||
INTERRUPT_HANDLER_WITH_CODE Index ; INT17
|
||||
|
||||
repeat 238
|
||||
INTERRUPT_HANDLER Index ; INT18-255
|
||||
endm
|
||||
AsmDefaultExceptionHandlers endp
|
||||
|
||||
;
|
||||
; @brief The common logic for the exception handlers.
|
||||
;
|
||||
; @details This function pushes register values into the stack and calls the
|
||||
; high-level handler written in C.
|
||||
;
|
||||
AsmCommonExceptionHandler proc
|
||||
PUSHAQ
|
||||
mov rcx, rsp
|
||||
sub rsp, 20h
|
||||
call HandleHostException
|
||||
add rsp, 20h
|
||||
POPAQ
|
||||
add rsp, 10h ; Remove the error code and interrupt number.
|
||||
iretq
|
||||
AsmCommonExceptionHandler endp
|
||||
|
||||
;
|
||||
; @brief The NMI handler for the host.
|
||||
;
|
||||
; @details This implementation is incomplete. When NMI occurs while the host is
|
||||
; executed, it should be injected to the guest.
|
||||
;
|
||||
AsmNmiExceptionHandler proc
|
||||
iretq
|
||||
AsmNmiExceptionHandler endp
|
||||
|
||||
end
|
||||
27
Sources/Platform/EFI/EfiAsm.h
Normal file
27
Sources/Platform/EFI/EfiAsm.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/*!
|
||||
@file EfiAsm.h
|
||||
|
||||
@brief EFI specific MASM-written functions.
|
||||
|
||||
@author Satoshi Tanda
|
||||
|
||||
@copyright Copyright (c) 2020 - , Satoshi Tanda. All rights reserved.
|
||||
*/
|
||||
#pragma once
|
||||
#include "EfiCommon.h"
|
||||
|
||||
/*!
|
||||
@brief The array of the default host exception handlers.
|
||||
*/
|
||||
VOID
|
||||
AsmDefaultExceptionHandlers (
|
||||
VOID
|
||||
);
|
||||
|
||||
/*!
|
||||
@brief The host NMI handler.
|
||||
*/
|
||||
VOID
|
||||
AsmNmiExceptionHandler (
|
||||
VOID
|
||||
);
|
||||
98
Sources/Platform/EFI/EfiBitmap.c
Normal file
98
Sources/Platform/EFI/EfiBitmap.c
Normal file
@@ -0,0 +1,98 @@
|
||||
/*!
|
||||
@file EfiBitmap.c
|
||||
|
||||
@brief EFI specific implementation of bitmap algorithm.
|
||||
|
||||
@details Implementation of algorithm is good enough for the current use of
|
||||
those API but is incomplete and broken, for example, bits are NEVER
|
||||
reused once they are set, even after they are "cleared".
|
||||
|
||||
For complete implementation, one can copy ReactOS's implementation if
|
||||
licensing the project under GPL is acceptable. hvpp by wbenny has its own
|
||||
implementation of bitmap but is actually influenced by ReactOS
|
||||
implementation and such should be treated as GPL.
|
||||
|
||||
@author Satoshi Tanda
|
||||
|
||||
@copyright Copyright (c) 2020 - , Satoshi Tanda. All rights reserved.
|
||||
*/
|
||||
#include "EfiBitmap.h"
|
||||
|
||||
VOID
|
||||
RtlInitializeBitMap (
|
||||
RTL_BITMAP* BitMapHeader,
|
||||
UINT32* BitMapBuffer,
|
||||
UINT32 SizeOfBitMap
|
||||
)
|
||||
{
|
||||
BitMapHeader->SizeOfBitMap = SizeOfBitMap;
|
||||
BitMapHeader->Buffer = BitMapBuffer;
|
||||
BitMapHeader->NextAvailableBitIndex = 0;
|
||||
BitMapHeader->SetBitCount = 0;
|
||||
}
|
||||
|
||||
UINT32
|
||||
RtlFindClearBitsAndSet (
|
||||
RTL_BITMAP* BitMapHeader,
|
||||
UINT32 NumberToFind,
|
||||
UINT32 HintIndex
|
||||
)
|
||||
{
|
||||
UINT32 clearBitIndex;
|
||||
|
||||
//
|
||||
// Return error if the bitmap does not have enough bits after the current
|
||||
// index. In other words, it never search from the index 0 because implementation
|
||||
// never clears bits.
|
||||
//
|
||||
if (BitMapHeader->NextAvailableBitIndex + NumberToFind > BitMapHeader->SizeOfBitMap)
|
||||
{
|
||||
clearBitIndex = MAXUINT32;
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
//
|
||||
// "Find" clear bits, which is just using bits from the current position.
|
||||
//
|
||||
clearBitIndex = BitMapHeader->NextAvailableBitIndex;
|
||||
|
||||
//
|
||||
// "Set" requested bits, which is just moving the index further.
|
||||
//
|
||||
BitMapHeader->SetBitCount += NumberToFind;
|
||||
BitMapHeader->NextAvailableBitIndex += NumberToFind;
|
||||
|
||||
Exit:
|
||||
return clearBitIndex;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
RtlAreBitsClear (
|
||||
RTL_BITMAP* BitMapHeader,
|
||||
UINT32 StartingIndex,
|
||||
UINT32 Length
|
||||
)
|
||||
{
|
||||
//
|
||||
// This implementation support checking only whether an entire bitmap is
|
||||
// cleared.
|
||||
//
|
||||
ASSERT(StartingIndex == 0);
|
||||
ASSERT(Length == BitMapHeader->SizeOfBitMap);
|
||||
|
||||
return (BitMapHeader->SetBitCount == 0);
|
||||
}
|
||||
|
||||
VOID
|
||||
RtlClearBits (
|
||||
RTL_BITMAP* BitMapHeader,
|
||||
UINT32 StartingIndex,
|
||||
UINT32 NumberToClear
|
||||
)
|
||||
{
|
||||
//
|
||||
// This implementation only change this counter, and never actually clear
|
||||
// bits and let them to be re-set.
|
||||
//
|
||||
BitMapHeader->SetBitCount -= NumberToClear;
|
||||
}
|
||||
96
Sources/Platform/EFI/EfiBitmap.h
Normal file
96
Sources/Platform/EFI/EfiBitmap.h
Normal file
@@ -0,0 +1,96 @@
|
||||
/*!
|
||||
@file EfiBitmap.h
|
||||
|
||||
@brief EFI specific implementation of bitmap algorithm.
|
||||
|
||||
@author Satoshi Tanda
|
||||
|
||||
@copyright Copyright (c) 2020 - , Satoshi Tanda. All rights reserved.
|
||||
*/
|
||||
#pragma once
|
||||
#include "EfiCommon.h"
|
||||
|
||||
typedef struct _RTL_BITMAP
|
||||
{
|
||||
UINT32 SizeOfBitMap; // Number of bits in bit map
|
||||
UINT32* Buffer; // Pointer to the bit map itself
|
||||
UINT32 NextAvailableBitIndex; // Index of the next cleared bit
|
||||
UINT32 SetBitCount; // Number of bits currently set
|
||||
} RTL_BITMAP;
|
||||
|
||||
/*!
|
||||
@brief Initializes the header of a bitmap variable.
|
||||
|
||||
@param[out] BitMapHeader - The pointer to the bitmap variable to initialize.
|
||||
|
||||
@param[in] BitMapBuffer - The pointer to caller-allocated memory for the bitmap
|
||||
itself.
|
||||
|
||||
@param[in] SizeOfBitMap - The number of bits in the bitmap.
|
||||
*/
|
||||
VOID
|
||||
RtlInitializeBitMap (
|
||||
RTL_BITMAP* BitMapHeader,
|
||||
UINT32* BitMapBuffer,
|
||||
UINT32 SizeOfBitMap
|
||||
);
|
||||
|
||||
/*!
|
||||
@brief Searches for a range of clear bits of a requested size within a bitmap
|
||||
and sets all bits in the range when it has been located.
|
||||
|
||||
@param[out] BitMapHeader - The pointer to the RTL_BITMAP structure that
|
||||
describes the bitmap.
|
||||
|
||||
@param[in] NumberToFind - How many contiguous clear bits will satisfy this
|
||||
request.
|
||||
|
||||
@param[in] HintIndex - Unused.
|
||||
|
||||
@return The zero-based starting bit index for a clear bit range of the
|
||||
requested size that it set, or it returns 0xFFFFFFFF if it cannot find
|
||||
such a range within the given bitmap variable.
|
||||
*/
|
||||
UINT32
|
||||
RtlFindClearBitsAndSet (
|
||||
RTL_BITMAP* BitMapHeader,
|
||||
UINT32 NumberToFind,
|
||||
UINT32 HintIndex
|
||||
);
|
||||
|
||||
/*!
|
||||
@brief Determines whether a given range of bits within a bitmap variable is
|
||||
clear.
|
||||
|
||||
@param[in] BitMapHeader - The pointer to the RTL_BITMAP structure that
|
||||
describes the bitmap.
|
||||
|
||||
@param[in] StartingIndex - The start of the bit range to be tested.
|
||||
|
||||
@param[in] Length - How many bits to test.
|
||||
|
||||
@return Whether a given range of bits within a bitmap variable is clear.
|
||||
*/
|
||||
BOOLEAN
|
||||
RtlAreBitsClear (
|
||||
RTL_BITMAP* BitMapHeader,
|
||||
UINT32 StartingIndex,
|
||||
UINT32 Length
|
||||
);
|
||||
|
||||
/*!
|
||||
@brief Sets all bits in the specified range of bits in the bitmap to zero.
|
||||
|
||||
@param[out] BitMapHeader - The pointer to the RTL_BITMAP structure that
|
||||
describes the bitmap.
|
||||
|
||||
@param[in] StartingIndex - Unused.
|
||||
|
||||
@param[in] NumberToClear - How many bits to clear.
|
||||
*/
|
||||
VOID
|
||||
RtlClearBits (
|
||||
RTL_BITMAP* BitMapHeader,
|
||||
UINT32 StartingIndex,
|
||||
UINT32 NumberToClear
|
||||
);
|
||||
135
Sources/Platform/EFI/EfiCommon.h
Normal file
135
Sources/Platform/EFI/EfiCommon.h
Normal file
@@ -0,0 +1,135 @@
|
||||
/*!
|
||||
@file EfiCommon.h
|
||||
|
||||
@brief EFI specific implementation of common things across the project.
|
||||
|
||||
@author Satoshi Tanda
|
||||
|
||||
@copyright Copyright (c) 2020 - , Satoshi Tanda. All rights reserved.
|
||||
*/
|
||||
#pragma once
|
||||
#include <Uefi.h>
|
||||
#include <Library/UefiLib.h>
|
||||
#include <Library/DebugLib.h>
|
||||
#include <Library/BaseMemoryLib.h>
|
||||
|
||||
//
|
||||
// "structure was padded due to alignment specifier"
|
||||
//
|
||||
#pragma warning(disable: 4324)
|
||||
|
||||
|
||||
/*!
|
||||
@brief Freezes execution of the processor by entering infinite busy loop.
|
||||
*/
|
||||
#define MV_PANIC() do { CpuDeadLoop(); } while (TRUE)
|
||||
#define MV_DEBUG_BREAK()
|
||||
#define MV_SECTION_INIT
|
||||
#define MV_SECTION_PAGED
|
||||
#define MV_ASSERT(x) ASSERT(x)
|
||||
#if !defined(MDEPKG_NDEBUG)
|
||||
#define MV_VERIFY(x) ASSERT(x)
|
||||
#else
|
||||
#define MV_VERIFY(x) (x)
|
||||
#endif
|
||||
#define MV_MAX(x, y) MAX((x), (y))
|
||||
#define MV_MIN(x, y) MIN((x), (y))
|
||||
|
||||
//
|
||||
// MSVC compatibility type definitions.
|
||||
//
|
||||
typedef CHAR8 CHAR;
|
||||
typedef CHAR16 WCHAR;
|
||||
|
||||
//
|
||||
// MSVC intrinsics.
|
||||
//
|
||||
unsigned __int64 __readcr0(void);
|
||||
unsigned __int64 __readcr2(void);
|
||||
unsigned __int64 __readcr3(void);
|
||||
unsigned __int64 __readcr4(void);
|
||||
unsigned __int64 __readdr(unsigned int);
|
||||
unsigned __int64 __readeflags(void);
|
||||
unsigned __int64 __readmsr(unsigned long);
|
||||
unsigned char __vmx_on(unsigned __int64 *);
|
||||
unsigned char __vmx_vmclear(unsigned __int64 *);
|
||||
unsigned char __vmx_vmlaunch(void);
|
||||
unsigned char __vmx_vmptrld(unsigned __int64 *);
|
||||
unsigned char __vmx_vmread(unsigned __int64, unsigned __int64 *);
|
||||
unsigned char __vmx_vmresume(void);
|
||||
unsigned char __vmx_vmwrite(unsigned __int64, unsigned __int64);
|
||||
unsigned long __segmentlimit(unsigned long);
|
||||
void __cpuid(int[4], int);
|
||||
void __cpuidex(int[4], int, int);
|
||||
void __invlpg(void *);
|
||||
void __lidt(void *);
|
||||
void __sidt(void *);
|
||||
void __stosq(unsigned __int64 *, unsigned __int64, unsigned __int64);
|
||||
void __vmx_off(void);
|
||||
void __vmx_vmptrst(unsigned __int64 *);
|
||||
void __writecr0(unsigned __int64);
|
||||
void __writecr2(unsigned __int64);
|
||||
void __writecr3(unsigned __int64);
|
||||
void __writecr4(unsigned __int64);
|
||||
void __writedr(unsigned int, unsigned __int64);
|
||||
void __writemsr(unsigned long, unsigned __int64);
|
||||
void _lgdt(void *);
|
||||
void _sgdt(void *);
|
||||
|
||||
//
|
||||
// MSVC compatibility macro definitions.
|
||||
//
|
||||
#define __drv_aliasesMem
|
||||
#define __drv_allocatesMem(x)
|
||||
#define __drv_freesMem(x)
|
||||
#define _Acquires_lock_(x)
|
||||
#define _In_
|
||||
#define _In_opt_
|
||||
#define _In_range_(x, y)
|
||||
#define _In_reads_bytes_(x)
|
||||
#define _Inout_
|
||||
#define _IRQL_raises_(x)
|
||||
#define _IRQL_requires_max_(x)
|
||||
#define _IRQL_restores_
|
||||
#define _IRQL_saves_
|
||||
#define _Must_inspect_result_
|
||||
#define _Out_
|
||||
#define _Out_opt_
|
||||
#define _Out_writes_bytes_(x)
|
||||
#define _Post_maybenull_
|
||||
#define _Post_writable_byte_size_(x)
|
||||
#define _Pre_notnull_
|
||||
#define _Printf_format_string_
|
||||
#define _Releases_lock_(x)
|
||||
#define _Requires_lock_held_(x)
|
||||
#define _Requires_lock_not_held_(x)
|
||||
#define _Return_type_success_(x)
|
||||
#define _Success_(x)
|
||||
#define _Use_decl_annotations_
|
||||
#define _When_(x, y)
|
||||
|
||||
#define ANSI_NULL ((CHAR)0)
|
||||
#define ANYSIZE_ARRAY (1)
|
||||
#define ARGUMENT_PRESENT(x) ((x) != NULL)
|
||||
#define BooleanFlagOn(F,SF) ((BOOLEAN)(((F) & (SF)) != 0))
|
||||
#define BYTES_TO_PAGES(x) EFI_SIZE_TO_PAGES(x)
|
||||
#define C_ASSERT(x) STATIC_ASSERT(x, #x)
|
||||
#define ClearFlag(_F,_SF) ((_F) &= ~(_SF))
|
||||
#define DBG_UNREFERENCED_PARAMETER(x)
|
||||
#define DECLSPEC_ALIGN(x) __declspec(align(x))
|
||||
#define FlagOn(_F,_SF) ((_F) & (_SF))
|
||||
#define KERNEL_STACK_SIZE (0x6000)
|
||||
#define MAXUINT16 MAX_UINT16
|
||||
#define MAXUINT32 MAX_UINT32
|
||||
#define MAXUINT64 MAX_UINT64
|
||||
#define MAXUINT8 MAX_UINT8
|
||||
#define NOTHING
|
||||
#define PAGE_ALIGN(Va) ((VOID*)((UINT64)(Va) & ~(PAGE_SIZE - 1)))
|
||||
#define PAGE_SIZE EFI_PAGE_SIZE
|
||||
#define PAGED_CODE()
|
||||
#define RTL_NUMBER_OF(x) ARRAY_SIZE(x)
|
||||
#define RtlCopyMemory CopyMem
|
||||
#define RtlZeroMemory ZeroMem
|
||||
#define SetFlag(_F,_SF) ((_F) |= (_SF))
|
||||
#define strcmp(x, y) AsciiStrCmp((x), (y))
|
||||
#define UNREFERENCED_PARAMETER(x)
|
||||
330
Sources/Platform/EFI/EfiHostInitialization.c
Normal file
330
Sources/Platform/EFI/EfiHostInitialization.c
Normal file
@@ -0,0 +1,330 @@
|
||||
/*!
|
||||
@file EfiHostInitialization.c
|
||||
|
||||
@brief EFI specific implementation of host environment initialization.
|
||||
|
||||
@details On EFI, the host uses its own paging structures (CR3) and interrupt
|
||||
descriptor table (IDT).
|
||||
|
||||
Its own paging structures is preferable and the most straightforward
|
||||
approach to void impact from the physical mode to the virtual mode
|
||||
transition happens during OS startup time. After this transition (ie,
|
||||
SetVirtualAddressMap is called from a boot loader), the paging structures
|
||||
that is used at the physical mode and the host would be using it becomes
|
||||
invalid, as nothing runs on the physical mode anymore. This results in
|
||||
crash (triple fault) when VM-exit occurs. One solution could be to
|
||||
subscribe the SetVirtualAddressMap event and notify the host to switch
|
||||
to the new CR3 for the virtual mode, but this has to be done for all
|
||||
logical processors requiring some inter processor calls. The MP protocol
|
||||
could do the job but is no longer available at the moment of the transition
|
||||
notification because the system is already switched from the boot time to
|
||||
the run time.
|
||||
|
||||
Its own interrupt descriptor table is required for the same reason. After
|
||||
transitioning to the virtual mode, the existing IDT becomes invalid. One
|
||||
might think the host IDT is not relevant as interrupts are disabled. The
|
||||
fact is that NMI still occurs while the host is running, and also, having
|
||||
basic diagnose handlers are useful in case of access violation, for example.
|
||||
|
||||
@author Satoshi Tanda
|
||||
|
||||
@copyright Copyright (c) 2020 - , Satoshi Tanda. All rights reserved.
|
||||
*/
|
||||
#include "EfiHostInitialization.h"
|
||||
#include "EfiAsm.h"
|
||||
#include "EfiPlatform.h"
|
||||
#include "../../Utils.h"
|
||||
|
||||
//
|
||||
// The format of the IDT.
|
||||
//
|
||||
typedef struct _INTERRUPT_GATE_DESCRIPTOR
|
||||
{
|
||||
UINT16 Offset15To0 : 16;
|
||||
UINT16 SegmentSelector : 16;
|
||||
UINT8 Reserved0;
|
||||
UINT8 GateType;
|
||||
UINT16 Offset31To16;
|
||||
UINT32 Offset63To32;
|
||||
UINT32 Reserved1;
|
||||
} INTERRUPT_GATE_DESCRIPTOR;
|
||||
C_ASSERT(sizeof(INTERRUPT_GATE_DESCRIPTOR) == 16);
|
||||
|
||||
//
|
||||
// Collections of paging structures. Only the single PDPT is accommodated to
|
||||
// handle only up to 512GB of physical memory.
|
||||
//
|
||||
typedef struct _PAGING_STRUCTURES
|
||||
{
|
||||
//
|
||||
// There is only one PML4, unless 5-level page mapping is enabled.
|
||||
//
|
||||
DECLSPEC_ALIGN(PAGE_SIZE) PML4E_64 Pml4[PML4_ENTRY_COUNT];
|
||||
|
||||
//
|
||||
// Only one PDPT is used for PML4[0]. This covers 512GB of the physical memory
|
||||
// range and is sufficient for our purpose.
|
||||
//
|
||||
DECLSPEC_ALIGN(PAGE_SIZE) PDPTE_64 Pdpt[1][PDPT_ENTRY_COUNT];
|
||||
|
||||
//
|
||||
// PDs are assigned for each PDPT entry, meaning that 512 (PDPTEs) multiplied
|
||||
// by the PDT entry count.
|
||||
//
|
||||
DECLSPEC_ALIGN(PAGE_SIZE) PDE_2MB_64 Pdt[1][PDPT_ENTRY_COUNT][PDT_ENTRY_COUNT];
|
||||
} PAGING_STRUCTURES;
|
||||
|
||||
//
|
||||
// Paging related.
|
||||
//
|
||||
static PAGING_STRUCTURES g_HostPagingStructures;
|
||||
static CR3 g_HostCr3;
|
||||
|
||||
//
|
||||
// IDT related.
|
||||
//
|
||||
static INTERRUPT_GATE_DESCRIPTOR g_HostIdt[IDT_ENTRY_COUNT];
|
||||
static IDTR g_HostIdtr;
|
||||
|
||||
/*!
|
||||
@brief Initializes the host paging structures.
|
||||
|
||||
@details This function fills out the statically allocated paging structures
|
||||
and builds the identity mapping. All translation is done with 2MB pages
|
||||
since not 4KB granularity configuration is not needed.
|
||||
|
||||
The identity mapping works because when the host is loaded, the EFI system
|
||||
also uses the identity mapping, meaning that it is essentially making a
|
||||
clone of existing paging structures.
|
||||
|
||||
Note that page protections are all writable and executable. One may drop
|
||||
the executable attribute for outside the range of the .text section of
|
||||
this module and drop writable for the same range to be W^X.
|
||||
*/
|
||||
static
|
||||
VOID
|
||||
InitializeHostPagingStructures (
|
||||
)
|
||||
{
|
||||
PML4E_64* pml4;
|
||||
PDPTE_64* pdpt;
|
||||
PDE_2MB_64* pdt;
|
||||
UINT32 pml4Index;
|
||||
|
||||
pml4Index = 0;
|
||||
pml4 = g_HostPagingStructures.Pml4;
|
||||
pdpt = g_HostPagingStructures.Pdpt[pml4Index];
|
||||
|
||||
//
|
||||
// Fill out PML4, PDPT, PDT.
|
||||
//
|
||||
pml4[0].Present = TRUE;
|
||||
pml4[0].Write = TRUE;
|
||||
pml4[0].PageFrameNumber = GetPhysicalAddress(pdpt) >> PAGE_SHIFT;
|
||||
|
||||
for (UINT32 pdptIndex = 0; pdptIndex < PDPT_ENTRY_COUNT; ++pdptIndex)
|
||||
{
|
||||
pdt = g_HostPagingStructures.Pdt[pml4Index][pdptIndex];
|
||||
|
||||
pdpt[pdptIndex].Present = TRUE;
|
||||
pdpt[pdptIndex].Write = TRUE;
|
||||
pdpt[pdptIndex].PageFrameNumber = GetPhysicalAddress(pdt) >> PAGE_SHIFT;
|
||||
|
||||
for (UINT32 pdIndex = 0; pdIndex < PDT_ENTRY_COUNT; ++pdIndex)
|
||||
{
|
||||
UINT64 physicalAddress;
|
||||
|
||||
physicalAddress = ComputeAddressFromIndexes(pml4Index,
|
||||
pdptIndex,
|
||||
pdIndex,
|
||||
0);
|
||||
pdt[pdIndex].Present = TRUE;
|
||||
pdt[pdIndex].Write = TRUE;
|
||||
pdt[pdIndex].LargePage = TRUE;
|
||||
pdt[pdIndex].PageFrameNumber = physicalAddress >> PAGE_SHIFT_2BM;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Then initialize the CR3 to point to the PML4.
|
||||
//
|
||||
g_HostCr3.AddressOfPageDirectory = GetPhysicalAddress(pml4) >> PAGE_SHIFT;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Initializes the host IDT.
|
||||
|
||||
@details This function fills out the IDT with AsmDefaultExceptionHandlers[N]
|
||||
where N is the interrupt number, updates IDT[2] with AsmNmiExceptionHandler,
|
||||
and initializes IDTR to point to the IDT.
|
||||
|
||||
AsmDefaultExceptionHandlers is the array of stub functions to transfer
|
||||
execution to the main common logic in AsmCommonExceptionHandler.
|
||||
*/
|
||||
static
|
||||
VOID
|
||||
InitializeHostIdt (
|
||||
)
|
||||
{
|
||||
UINT64 handlerBase;
|
||||
|
||||
//
|
||||
// Get the beginning of the AsmDefaultExceptionHandlers to index.
|
||||
//
|
||||
handlerBase = (UINT64)&AsmDefaultExceptionHandlers;
|
||||
|
||||
//
|
||||
// Fill out all IDT entries.
|
||||
//
|
||||
for (UINT32 i = 0; i < IDT_ENTRY_COUNT; ++i)
|
||||
{
|
||||
static const UINT64 sizeOfHandlerTill0x7f = 9;
|
||||
static const UINT64 sizeOfHandlerFrom0x80 = 12;
|
||||
UINT64 sizeOfHandler;
|
||||
UINT64 handlerAddress;
|
||||
|
||||
//
|
||||
// Compute the address of AsmDefaultExceptionHandlers[i]. Each stub
|
||||
// function is 9 bytes up to 0x7f, and 12 bytes after that.
|
||||
//
|
||||
if (i < 0x80)
|
||||
{
|
||||
sizeOfHandler = sizeOfHandlerTill0x7f;
|
||||
}
|
||||
else
|
||||
{
|
||||
sizeOfHandler = sizeOfHandlerFrom0x80;
|
||||
}
|
||||
handlerAddress = (handlerBase + i * sizeOfHandler);
|
||||
|
||||
//
|
||||
// Fill out the IDT entry. The type is 32-bit Interrupt gate: 0x8E
|
||||
// P=1, DPL=00b, S=0, type=1110b => type_attr=1000_1110b=0x8E)
|
||||
//
|
||||
g_HostIdt[i].Offset15To0 = (UINT16)handlerAddress;
|
||||
g_HostIdt[i].Offset31To16 = (UINT16)(handlerAddress >> 16);
|
||||
g_HostIdt[i].Offset63To32 = (UINT32)(handlerAddress >> 32);
|
||||
g_HostIdt[i].SegmentSelector = AsmReadCs();
|
||||
g_HostIdt[i].GateType = 0x8E;
|
||||
}
|
||||
|
||||
//
|
||||
// Interrupt 0x2 is NMI. This needs special handling.
|
||||
//
|
||||
g_HostIdt[2].Offset15To0 = (UINT16)((UINT64)&AsmNmiExceptionHandler);
|
||||
g_HostIdt[2].Offset31To16 = (UINT16)((UINT64)&AsmNmiExceptionHandler >> 16);
|
||||
g_HostIdt[2].Offset63To32 = (UINT32)((UINT64)&AsmNmiExceptionHandler >> 32);
|
||||
|
||||
//
|
||||
// Finally initialize the IDTR to point to the IDT.
|
||||
//
|
||||
g_HostIdtr.Limit = sizeof(g_HostIdt) - 1;
|
||||
g_HostIdtr.BaseAddress = (UINT64)(&g_HostIdt[0]);
|
||||
}
|
||||
|
||||
VOID
|
||||
InitializeHostEnvironment (
|
||||
)
|
||||
{
|
||||
InitializeHostPagingStructures();
|
||||
InitializeHostIdt();
|
||||
}
|
||||
|
||||
CR3
|
||||
GetHostCr3 (
|
||||
)
|
||||
{
|
||||
return g_HostCr3;
|
||||
}
|
||||
|
||||
CONST IDTR*
|
||||
GetHostIdtr (
|
||||
)
|
||||
{
|
||||
return &g_HostIdtr;
|
||||
}
|
||||
|
||||
VOID
|
||||
InitializeGdt (
|
||||
TASK_STATE_SEGMENT_64* NewTss,
|
||||
SEGMENT_DESCRIPTOR_64* NewGdt,
|
||||
UINT64 NewGdtSize,
|
||||
GDTR* OriginalGdtr
|
||||
)
|
||||
{
|
||||
GDTR newGdtr;
|
||||
SEGMENT_SELECTOR taskRegister;
|
||||
SEGMENT_DESCRIPTOR_64 tssDescriptor;
|
||||
SEGMENT_DESCRIPTOR_64* tssDescriptorInGdt;
|
||||
UINT64 tssAddress;
|
||||
SEGMENT_DESCRIPTOR_32* newGdt32;
|
||||
|
||||
//
|
||||
// Get the current GDTR.
|
||||
//
|
||||
_sgdt(&newGdtr);
|
||||
*OriginalGdtr = newGdtr;
|
||||
|
||||
//
|
||||
// Copy contents of the existing GDT to the new GDT in the processor context.
|
||||
//
|
||||
RtlCopyMemory(NewGdt, (VOID*)newGdtr.BaseAddress, newGdtr.Limit);
|
||||
|
||||
//
|
||||
// Set up TR pointing to the entry going to be added below in the GDT. Divide
|
||||
// by the size of SEGMENT_DESCRIPTOR_32 because the limit field is in bytes
|
||||
// while the index is index in the entry count.
|
||||
//
|
||||
taskRegister.Flags = 0;
|
||||
taskRegister.Index = (newGdtr.Limit + 1ull) / sizeof(SEGMENT_DESCRIPTOR_32);
|
||||
|
||||
//
|
||||
// Update the GDTR. Change the base to the new location and increase the
|
||||
// limit to add one more entry for TR. Make sure we have enough space
|
||||
// in the processor context to copy the contents of GDT.
|
||||
//
|
||||
newGdtr.BaseAddress = (UINT64)NewGdt;
|
||||
newGdtr.Limit += sizeof(SEGMENT_DESCRIPTOR_64);
|
||||
MV_ASSERT(newGdtr.Limit < NewGdtSize);
|
||||
|
||||
//
|
||||
// At this point, the TR points to uninitialized entry in the GDT. Set up
|
||||
// the Task State Segment Descriptor to be written to GDT.
|
||||
//
|
||||
tssAddress = (UINT64)NewTss;
|
||||
RtlZeroMemory(&tssDescriptor, sizeof(tssDescriptor));
|
||||
tssDescriptor.SegmentLimitLow = sizeof(*NewTss) - 1;
|
||||
tssDescriptor.BaseAddressLow = (tssAddress & MAXUINT16);
|
||||
tssDescriptor.BaseAddressMiddle = ((tssAddress >> 16) & MAXUINT8);
|
||||
tssDescriptor.BaseAddressHigh = ((tssAddress >> 24) & MAXUINT8);
|
||||
tssDescriptor.BaseAddressUpper = ((tssAddress >> 32) & MAXUINT32);
|
||||
tssDescriptor.Type = SEGMENT_DESCRIPTOR_TYPE_TSS_AVAILABLE;
|
||||
tssDescriptor.Present = TRUE;
|
||||
|
||||
//
|
||||
// Update the GDT by writing entry for TSS, which is pointed by the TR.
|
||||
//
|
||||
newGdt32 = (SEGMENT_DESCRIPTOR_32*)NewGdt;
|
||||
tssDescriptorInGdt = (SEGMENT_DESCRIPTOR_64*)(&newGdt32[taskRegister.Index]);
|
||||
*tssDescriptorInGdt = tssDescriptor;
|
||||
|
||||
//
|
||||
// Finally, update the GDTR and TR of the current processor. The VT-x
|
||||
// requires the guest task segment register to be configured correctly
|
||||
// and the UEFI platform typically does not (ie, TR being zero). Update TR
|
||||
// to point to the task segment just set up.
|
||||
//
|
||||
// See: 26.3.1.2 Checks on Guest Segment Registers
|
||||
//
|
||||
_lgdt(&newGdtr);
|
||||
AsmWriteTr(taskRegister.Flags);
|
||||
}
|
||||
|
||||
VOID
|
||||
CleanupGdt (
|
||||
CONST GDTR* OriginalGdtr
|
||||
)
|
||||
{
|
||||
MV_ASSERT(OriginalGdtr->BaseAddress != 0);
|
||||
_lgdt((VOID*)OriginalGdtr);
|
||||
}
|
||||
11
Sources/Platform/EFI/EfiHostInitialization.h
Normal file
11
Sources/Platform/EFI/EfiHostInitialization.h
Normal file
@@ -0,0 +1,11 @@
|
||||
/*!
|
||||
@file EfiHostInitialization.h
|
||||
|
||||
@brief EFI specific implementation of host environment initialization.
|
||||
|
||||
@author Satoshi Tanda
|
||||
|
||||
@copyright Copyright (c) 2020 - , Satoshi Tanda. All rights reserved.
|
||||
*/
|
||||
#pragma once
|
||||
#include "../../HostInitialization.h"
|
||||
151
Sources/Platform/EFI/EfiLogger.c
Normal file
151
Sources/Platform/EFI/EfiLogger.c
Normal file
@@ -0,0 +1,151 @@
|
||||
/*!
|
||||
@file EfiLogger.c
|
||||
|
||||
@brief EFI specific implementation of the logger.
|
||||
|
||||
@details Logging becomes no-op at the runtime when UefiDebugLibConOut is used,
|
||||
ie, -D DEBUG_ON_SERIAL_PORT is not set. See use of mPostEBS in
|
||||
edk2/MdePkg/Library/UefiDebugLibConOut/DebugLib.c for this behavior.
|
||||
|
||||
@author Satoshi Tanda
|
||||
|
||||
@copyright Copyright (c) 2020 - , Satoshi Tanda. All rights reserved.
|
||||
*/
|
||||
#include "EfiLogger.h"
|
||||
#include <Guid/EventGroup.h>
|
||||
#include <Library/UefiBootServicesTableLib.h>
|
||||
#include <Library/PrintLib.h>
|
||||
|
||||
//
|
||||
// The event handle for ExitBootServices event subscription.
|
||||
//
|
||||
static EFI_EVENT g_EfiExitBootServicesEvent;
|
||||
|
||||
//
|
||||
// FALSE during boot time. Once the system is transition to the run time, any
|
||||
// EFI API that depends on boot services directly or indirectly cannot be called.
|
||||
// The most significant implication is the console output cannot be used anymore.
|
||||
//
|
||||
static BOOLEAN g_AtRuntime;
|
||||
|
||||
/*!
|
||||
@brief Handles the ExitBootServices notification.
|
||||
|
||||
@details The solo purpose of this handler is to report the end of console
|
||||
debug output.
|
||||
|
||||
@param[in] Event - Unused.
|
||||
|
||||
@param[in] Context - Unused.
|
||||
*/
|
||||
static
|
||||
VOID
|
||||
EFIAPI
|
||||
ExitBootServicesHandler (
|
||||
EFI_EVENT Event,
|
||||
VOID* Context
|
||||
)
|
||||
{
|
||||
LOG_INFO("ExitBootServices was called. Ending console logging if used.");
|
||||
gBS->CloseEvent(g_EfiExitBootServicesEvent);
|
||||
g_AtRuntime = TRUE;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Registers ExitBootServices notification.
|
||||
|
||||
@return EFI_SUCCESS on success; otherwise, an appropriate error code.
|
||||
*/
|
||||
static
|
||||
EFI_STATUS
|
||||
RegisterNotification (
|
||||
)
|
||||
{
|
||||
EFI_STATUS status;
|
||||
|
||||
status = gBS->CreateEventEx(EVT_NOTIFY_SIGNAL,
|
||||
TPL_NOTIFY,
|
||||
ExitBootServicesHandler,
|
||||
NULL,
|
||||
&gEfiEventExitBootServicesGuid,
|
||||
&g_EfiExitBootServicesEvent);
|
||||
if (EFI_ERROR(status))
|
||||
{
|
||||
LOG_ERROR("CreateEventEx failed : %r", status);
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
Exit:
|
||||
return status;
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
InitializeLogger (
|
||||
)
|
||||
{
|
||||
EFI_STATUS status;
|
||||
|
||||
status = RegisterNotification();
|
||||
if (EFI_ERROR(status))
|
||||
{
|
||||
LOG_ERROR("RegisterNotifications failed : %r", status);
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
Exit:
|
||||
return status;
|
||||
}
|
||||
|
||||
VOID
|
||||
CleanupLogger (
|
||||
)
|
||||
{
|
||||
if (g_AtRuntime == FALSE)
|
||||
{
|
||||
gBS->CloseEvent(g_EfiExitBootServicesEvent);
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
LogMessage (
|
||||
LOG_LEVEL Level,
|
||||
CONST CHAR* FunctionName,
|
||||
CONST CHAR* Format,
|
||||
...
|
||||
)
|
||||
{
|
||||
//
|
||||
// Mapping from LOG_LEVEL to the EFI log level.
|
||||
//
|
||||
static CONST UINT64 debugLevelMapping[] =
|
||||
{
|
||||
0,
|
||||
DEBUG_ERROR,
|
||||
DEBUG_WARN,
|
||||
DEBUG_INFO,
|
||||
DEBUG_VERBOSE,
|
||||
};
|
||||
C_ASSERT(RTL_NUMBER_OF(debugLevelMapping) == LogLevelReserved);
|
||||
|
||||
VA_LIST args;
|
||||
CHAR8 message[400];
|
||||
|
||||
VA_START(args, Format);
|
||||
(VOID)AsciiVSPrint(message, sizeof(message), Format, args);
|
||||
VA_END(args);
|
||||
|
||||
DebugPrint(debugLevelMapping[Level], "%a: %a\n", FunctionName, message);
|
||||
}
|
||||
|
||||
VOID
|
||||
LogEarlyErrorMessage (
|
||||
CONST CHAR* Format,
|
||||
...
|
||||
)
|
||||
{
|
||||
VA_LIST args;
|
||||
|
||||
VA_START(args, Format);
|
||||
(VOID)DebugVPrint(DEBUG_ERROR, Format, args);
|
||||
VA_END(args);
|
||||
}
|
||||
26
Sources/Platform/EFI/EfiLogger.h
Normal file
26
Sources/Platform/EFI/EfiLogger.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/*!
|
||||
@file EfiLogger.h
|
||||
|
||||
@brief EFI specific implementation of the logger.
|
||||
|
||||
@author Satoshi Tanda
|
||||
|
||||
@copyright Copyright (c) 2020 - , Satoshi Tanda. All rights reserved.
|
||||
*/
|
||||
#include "../../Logger.h"
|
||||
|
||||
/*!
|
||||
@brief Initializes the global logger.
|
||||
|
||||
@return EFI_SUCCESS on success; otherwise, an appropriate error code.
|
||||
*/
|
||||
EFI_STATUS
|
||||
InitializeLogger (
|
||||
);
|
||||
|
||||
/*!
|
||||
@brief Clean up the logger.
|
||||
*/
|
||||
VOID
|
||||
CleanupLogger (
|
||||
);
|
||||
398
Sources/Platform/EFI/EfiPlatform.c
Normal file
398
Sources/Platform/EFI/EfiPlatform.c
Normal file
@@ -0,0 +1,398 @@
|
||||
/*!
|
||||
@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);
|
||||
}
|
||||
11
Sources/Platform/EFI/EfiPlatform.h
Normal file
11
Sources/Platform/EFI/EfiPlatform.h
Normal file
@@ -0,0 +1,11 @@
|
||||
/*!
|
||||
@file EfiPlatform.h
|
||||
|
||||
@brief EFI specific platform API.
|
||||
|
||||
@author Satoshi Tanda
|
||||
|
||||
@copyright Copyright (c) 2020 - , Satoshi Tanda. All rights reserved.
|
||||
*/
|
||||
#pragma once
|
||||
#include "../../Platform.h"
|
||||
Reference in New Issue
Block a user