Emulate IA32_BIOS_SIGN_ID read
This commit is contained in:
@@ -47,6 +47,12 @@ typedef struct _INITIAL_HYPERVISOR_STACK
|
||||
/*!
|
||||
@brief Handles VM-exit due to execution of the RDMSR and WRMSR instruction.
|
||||
|
||||
@details Accessing MSR can results in #GP(0) that would have been handled by
|
||||
the guest. However, in this context, this results in host exception leading
|
||||
to the panic (See HandleHostException). For graceful handling, the handler
|
||||
can check the exception is #GP(0) caused by RDMSR or WRMSR, and if this
|
||||
is the case, inject it to the guest.
|
||||
|
||||
@param[in,out] GuestContext - A pointer to the guest context.
|
||||
|
||||
@param[in] OperationType - The type of the operation.
|
||||
@@ -64,18 +70,35 @@ HandleMsrAccess (
|
||||
msr = (IA32_MSR_ADDRESS)GuestContext->StackBasedRegisters->Rcx;
|
||||
if (OperationType == OperationRead)
|
||||
{
|
||||
//
|
||||
// Performs the same read on behalf of the guest.
|
||||
//
|
||||
value = __readmsr(msr);
|
||||
switch (msr)
|
||||
{
|
||||
case IA32_BIOS_SIGN_ID:
|
||||
//
|
||||
// Linux reads this MSR during boot and may attempt to update BIOS
|
||||
// microcode. Returning the greater value than the value the kernel
|
||||
// wishes prevent it from attempt to update microcode. APs will enter
|
||||
// infinite INIT-SIPI loop if this is not done.
|
||||
//
|
||||
// "The VMM may wish to prevent a guest from loading a microcode
|
||||
// update (...). To prevent microcode update loading, the VMM may
|
||||
// return a microcode update signature value greater than the value
|
||||
// of IA32_BIOS_SIGN_ID MSR. A well behaved guest will not attempt
|
||||
// to load an older microcode update."
|
||||
// See: 32.4.2 Late Load of Microcode Updates
|
||||
//
|
||||
value = MAXUINT64;
|
||||
break;
|
||||
|
||||
default:
|
||||
value = __readmsr(msr);
|
||||
break;
|
||||
}
|
||||
|
||||
GuestContext->StackBasedRegisters->Rax = value & MAXUINT32;
|
||||
GuestContext->StackBasedRegisters->Rdx = (value >> 32) & MAXUINT32;
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// Performs the same write on behalf of the guest.
|
||||
//
|
||||
value = (GuestContext->StackBasedRegisters->Rax & MAXUINT32) |
|
||||
((GuestContext->StackBasedRegisters->Rdx & MAXUINT32) << 32);
|
||||
__writemsr(msr, value);
|
||||
|
||||
@@ -22,6 +22,10 @@
|
||||
#include "ia32-doc/out/ia32.h"
|
||||
#pragma warning(pop)
|
||||
|
||||
#if !defined(CHAR_BIT)
|
||||
#define CHAR_BIT (8)
|
||||
#endif
|
||||
|
||||
//
|
||||
// The entry count within an EPT page table.
|
||||
//
|
||||
@@ -137,3 +141,25 @@ typedef struct _TASK_STATE_SEGMENT_64
|
||||
} TASK_STATE_SEGMENT_64;
|
||||
C_ASSERT(sizeof(TASK_STATE_SEGMENT_64) == 104);
|
||||
#pragma pack(pop)
|
||||
|
||||
//
|
||||
// The page-aligned, 4KB size region used as a MSR bitmap. The MSR bitmap is
|
||||
// used to indicate which MSR should cause VM-exit on RDMSR and WRMSR. Each
|
||||
// bit in this 4KB region represents ON or OFF of VM-exit, where 0 indicates
|
||||
// not to trigger, and 1 indicates to trigger VM-exit. This hypervisor does
|
||||
// not intend to handle MSR accesses and so, all bits are left as 0. It is
|
||||
// important that this bitmap governs VM-exit behavior only for certain sets
|
||||
// of MSRs. An access to any MSR that is not governed by this bitmap still
|
||||
// causes VM-exit unconditionally. For this reason, this hypervisor still
|
||||
// has RDMSR and WRMSR handling logic.
|
||||
//
|
||||
// See: 24.6.9 MSR-Bitmap Address
|
||||
//
|
||||
typedef struct _MSR_BITMAPS
|
||||
{
|
||||
UINT8 ReadBitmapLow[1024];
|
||||
UINT8 ReadBitmapHigh[1024];
|
||||
UINT8 WriteBitmapLow[1024];
|
||||
UINT8 WriteBitmapHigh[1024];
|
||||
} MSR_BITMAPS;
|
||||
C_ASSERT(sizeof(MSR_BITMAPS) == PAGE_SIZE);
|
||||
|
||||
@@ -14,10 +14,6 @@
|
||||
#include "Platform/EFI/EfiBitmap.h"
|
||||
#endif
|
||||
|
||||
#if !defined(CHAR_BIT)
|
||||
#define CHAR_BIT (8)
|
||||
#endif
|
||||
|
||||
typedef struct _MEMORY_MANAGER_CONTEXT
|
||||
{
|
||||
//
|
||||
|
||||
@@ -149,19 +149,9 @@ typedef struct _SHARED_PROCESSOR_CONTEXT
|
||||
UINT32 NumberOfContexts;
|
||||
|
||||
//
|
||||
// The page-aligned, 4KB size region used as a MSR bitmap. The MSR bitmap is
|
||||
// used to indicate which MSR should cause VM-exit on RDMSR and WRMSR. Each
|
||||
// bit in this 4KB region represents ON or OFF of VM-exit, where 0 indicates
|
||||
// not to trigger, and 1 indicates to trigger VM-exit. This hypervisor does
|
||||
// not intend to handle MSR accesses and so, all bits are left as 0. It is
|
||||
// important that this bitmap governs VM-exit behavior only for certain sets
|
||||
// of MSRs. An access to any MSR that is not governed by this bitmap still
|
||||
// causes VM-exit unconditionally. For this reason, this hypervisor still
|
||||
// has RDMSR and WRMSR handling logic.
|
||||
// The MSR bitmap used across all processors.
|
||||
//
|
||||
// See: 24.6.9 MSR-Bitmap Address
|
||||
//
|
||||
DECLSPEC_ALIGN(PAGE_SIZE) VOID* MsrBitmap;
|
||||
DECLSPEC_ALIGN(PAGE_SIZE) MSR_BITMAPS MsrBitmaps;
|
||||
|
||||
//
|
||||
// An array of PER_PROCESSOR_CONTEXTs. Each context is associated with and
|
||||
@@ -918,7 +908,7 @@ SetupVmcs (
|
||||
VmxWrite(VMCS_CTRL_VIRTUAL_PROCESSOR_IDENTIFIER, 1);
|
||||
|
||||
/* 64-Bit Control Fields */
|
||||
VmxWrite(VMCS_CTRL_MSR_BITMAP_ADDRESS, GetPhysicalAddress(&VpContexts->MsrBitmap));
|
||||
VmxWrite(VMCS_CTRL_MSR_BITMAP_ADDRESS, GetPhysicalAddress(&VpContexts->MsrBitmaps));
|
||||
VmxWrite(VMCS_CTRL_EPT_POINTER, VpContext->EptContext.EptPointer.Flags);
|
||||
|
||||
/* 32-Bit Control Fields */
|
||||
@@ -1165,9 +1155,36 @@ Exit:
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Enables hypervisor on the all processors.
|
||||
@brief Initializes the MSR bitmaps.
|
||||
|
||||
@return MV_STATUS_SUCCESS on success; otherwise, an appropriate error code.
|
||||
@details This function clears the bitmaps to avoid VM-exits that do not require
|
||||
manual handling. The MSR that requires manual handling for MiniVisor is
|
||||
IA32_BIOS_SIGN_ID to prevent the guest from attempting update BIOS
|
||||
microcode. See HandleMsrAccess for more details.
|
||||
|
||||
@param[out] Bitmaps - The pointer to the MSR bitmaps to initialize.
|
||||
*/
|
||||
MV_SECTION_PAGED
|
||||
static
|
||||
VOID
|
||||
InitializeMsrBitmaps (
|
||||
_Out_ MSR_BITMAPS* Bitmaps
|
||||
)
|
||||
{
|
||||
static CONST UINT64 biosSignatureByteOffset = (IA32_BIOS_SIGN_ID / CHAR_BIT);
|
||||
static CONST UINT64 biosSignatureBitMask = (1ull << (IA32_BIOS_SIGN_ID % CHAR_BIT));
|
||||
|
||||
PAGED_CODE()
|
||||
|
||||
RtlZeroMemory(Bitmaps, sizeof(*Bitmaps));
|
||||
|
||||
Bitmaps->ReadBitmapLow[biosSignatureByteOffset] |= biosSignatureBitMask;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Enables hypervisor on the all processors.
|
||||
|
||||
@return MV_STATUS_SUCCESS on success; otherwise, an appropriate error code.
|
||||
*/
|
||||
MV_SECTION_PAGED
|
||||
static
|
||||
@@ -1211,6 +1228,7 @@ EnableHypervisorOnAllProcessors (
|
||||
goto Exit;
|
||||
}
|
||||
vpContexts->NumberOfContexts = numberOfProcessors;
|
||||
InitializeMsrBitmaps(&vpContexts->MsrBitmaps);
|
||||
|
||||
//
|
||||
// Start virtualizing processors one-by-one. This is done by changing
|
||||
|
||||
Reference in New Issue
Block a user