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.
|
@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,out] GuestContext - A pointer to the guest context.
|
||||||
|
|
||||||
@param[in] OperationType - The type of the operation.
|
@param[in] OperationType - The type of the operation.
|
||||||
@@ -64,18 +70,35 @@ HandleMsrAccess (
|
|||||||
msr = (IA32_MSR_ADDRESS)GuestContext->StackBasedRegisters->Rcx;
|
msr = (IA32_MSR_ADDRESS)GuestContext->StackBasedRegisters->Rcx;
|
||||||
if (OperationType == OperationRead)
|
if (OperationType == OperationRead)
|
||||||
{
|
{
|
||||||
//
|
switch (msr)
|
||||||
// Performs the same read on behalf of the guest.
|
{
|
||||||
//
|
case IA32_BIOS_SIGN_ID:
|
||||||
value = __readmsr(msr);
|
//
|
||||||
|
// 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->Rax = value & MAXUINT32;
|
||||||
GuestContext->StackBasedRegisters->Rdx = (value >> 32) & MAXUINT32;
|
GuestContext->StackBasedRegisters->Rdx = (value >> 32) & MAXUINT32;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//
|
|
||||||
// Performs the same write on behalf of the guest.
|
|
||||||
//
|
|
||||||
value = (GuestContext->StackBasedRegisters->Rax & MAXUINT32) |
|
value = (GuestContext->StackBasedRegisters->Rax & MAXUINT32) |
|
||||||
((GuestContext->StackBasedRegisters->Rdx & MAXUINT32) << 32);
|
((GuestContext->StackBasedRegisters->Rdx & MAXUINT32) << 32);
|
||||||
__writemsr(msr, value);
|
__writemsr(msr, value);
|
||||||
|
|||||||
@@ -22,6 +22,10 @@
|
|||||||
#include "ia32-doc/out/ia32.h"
|
#include "ia32-doc/out/ia32.h"
|
||||||
#pragma warning(pop)
|
#pragma warning(pop)
|
||||||
|
|
||||||
|
#if !defined(CHAR_BIT)
|
||||||
|
#define CHAR_BIT (8)
|
||||||
|
#endif
|
||||||
|
|
||||||
//
|
//
|
||||||
// The entry count within an EPT page table.
|
// The entry count within an EPT page table.
|
||||||
//
|
//
|
||||||
@@ -137,3 +141,25 @@ typedef struct _TASK_STATE_SEGMENT_64
|
|||||||
} TASK_STATE_SEGMENT_64;
|
} TASK_STATE_SEGMENT_64;
|
||||||
C_ASSERT(sizeof(TASK_STATE_SEGMENT_64) == 104);
|
C_ASSERT(sizeof(TASK_STATE_SEGMENT_64) == 104);
|
||||||
#pragma pack(pop)
|
#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"
|
#include "Platform/EFI/EfiBitmap.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(CHAR_BIT)
|
|
||||||
#define CHAR_BIT (8)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef struct _MEMORY_MANAGER_CONTEXT
|
typedef struct _MEMORY_MANAGER_CONTEXT
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -149,19 +149,9 @@ typedef struct _SHARED_PROCESSOR_CONTEXT
|
|||||||
UINT32 NumberOfContexts;
|
UINT32 NumberOfContexts;
|
||||||
|
|
||||||
//
|
//
|
||||||
// The page-aligned, 4KB size region used as a MSR bitmap. The MSR bitmap is
|
// The MSR bitmap used across all processors.
|
||||||
// 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
|
DECLSPEC_ALIGN(PAGE_SIZE) MSR_BITMAPS MsrBitmaps;
|
||||||
//
|
|
||||||
DECLSPEC_ALIGN(PAGE_SIZE) VOID* MsrBitmap;
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// An array of PER_PROCESSOR_CONTEXTs. Each context is associated with and
|
// An array of PER_PROCESSOR_CONTEXTs. Each context is associated with and
|
||||||
@@ -918,7 +908,7 @@ SetupVmcs (
|
|||||||
VmxWrite(VMCS_CTRL_VIRTUAL_PROCESSOR_IDENTIFIER, 1);
|
VmxWrite(VMCS_CTRL_VIRTUAL_PROCESSOR_IDENTIFIER, 1);
|
||||||
|
|
||||||
/* 64-Bit Control Fields */
|
/* 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);
|
VmxWrite(VMCS_CTRL_EPT_POINTER, VpContext->EptContext.EptPointer.Flags);
|
||||||
|
|
||||||
/* 32-Bit Control Fields */
|
/* 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
|
MV_SECTION_PAGED
|
||||||
static
|
static
|
||||||
@@ -1211,6 +1228,7 @@ EnableHypervisorOnAllProcessors (
|
|||||||
goto Exit;
|
goto Exit;
|
||||||
}
|
}
|
||||||
vpContexts->NumberOfContexts = numberOfProcessors;
|
vpContexts->NumberOfContexts = numberOfProcessors;
|
||||||
|
InitializeMsrBitmaps(&vpContexts->MsrBitmaps);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Start virtualizing processors one-by-one. This is done by changing
|
// Start virtualizing processors one-by-one. This is done by changing
|
||||||
|
|||||||
Reference in New Issue
Block a user