223 lines
6.2 KiB
C
223 lines
6.2 KiB
C
/*!
|
|
@file Ia32Utils.c
|
|
|
|
@brief Utility functions that could be used by both the host and non-host.
|
|
|
|
@author Satoshi Tanda
|
|
|
|
@copyright Copyright (c) 2020 - , Satoshi Tanda. All rights reserved.
|
|
*/
|
|
#include "Ia32Utils.h"
|
|
#include "Asm.h"
|
|
#include "Logger.h"
|
|
|
|
_Use_decl_annotations_
|
|
UINT64
|
|
ComputeAddressFromIndexes (
|
|
UINT32 Pml4Index,
|
|
UINT32 PdptIndex,
|
|
UINT32 PdIndex,
|
|
UINT32 PtIndex
|
|
)
|
|
{
|
|
ADDRESS_TRANSLATION_HELPER helper;
|
|
|
|
helper.AsUInt64 = 0;
|
|
helper.AsIndex.Pml4 = Pml4Index;
|
|
helper.AsIndex.Pdpt = PdptIndex;
|
|
helper.AsIndex.Pd = PdIndex;
|
|
helper.AsIndex.Pt = PtIndex;
|
|
return helper.AsUInt64;
|
|
}
|
|
|
|
UINT32
|
|
GetSegmentAccessRight (
|
|
_In_ UINT16 SegmentSelector
|
|
)
|
|
{
|
|
SEGMENT_SELECTOR segmentSelector;
|
|
UINT32 nativeAccessRight;
|
|
VMX_SEGMENT_ACCESS_RIGHTS accessRight;
|
|
|
|
segmentSelector.Flags = SegmentSelector;
|
|
|
|
//
|
|
// "In general, a segment register is unusable if it has been loaded with a
|
|
// null selector."
|
|
// See: 24.4.1 Guest Register State
|
|
//
|
|
if ((segmentSelector.Table == 0) &&
|
|
(segmentSelector.Index == 0))
|
|
{
|
|
accessRight.Flags = 0;
|
|
accessRight.Unusable = TRUE;
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// Convert the native access right to the format for VMX. Those two formats
|
|
// are almost identical except that first 8 bits of the native format does
|
|
// not exist in the VMX format, and that few fields are undefined in the
|
|
// native format but reserved to be zero in the VMX format.
|
|
//
|
|
nativeAccessRight = AsmLoadAccessRightsByte(SegmentSelector);
|
|
MV_ASSERT(nativeAccessRight);
|
|
accessRight.Flags = (nativeAccessRight >> 8);
|
|
accessRight.Reserved1 = 0;
|
|
accessRight.Reserved2 = 0;
|
|
accessRight.Unusable = FALSE;
|
|
|
|
Exit:
|
|
return accessRight.Flags;
|
|
}
|
|
|
|
/*!
|
|
@brief Returns the segment descriptor corresponds to the SegmentSelector.
|
|
|
|
@param[in] DescriptorTableBase - The address of the base of the descriptor
|
|
table.
|
|
|
|
@param[in] SegmentSelector - The segment selector value.
|
|
|
|
@return The segment descriptor corresponds to the SegmentSelector.
|
|
*/
|
|
static
|
|
SEGMENT_DESCRIPTOR_32*
|
|
GetSegmentDescriptor (
|
|
_In_ UINT64 DescriptorTableBase,
|
|
_In_ UINT16 SegmentSelector
|
|
)
|
|
{
|
|
SEGMENT_SELECTOR segmentSelector;
|
|
SEGMENT_DESCRIPTOR_32* segmentDescriptors;
|
|
|
|
//
|
|
// "Selects one of 8192 descriptors in the GDT or LDT. The processor multiplies
|
|
// the index value by 8 (the number of bytes in a segment descriptor) and
|
|
// adds the result to the base address of the GDT or LDT (from the GDTR or
|
|
// LDTR register, respectively)."
|
|
// See: 3.4.2 Segment Selectors
|
|
//
|
|
segmentSelector.Flags = SegmentSelector;
|
|
segmentDescriptors = (SEGMENT_DESCRIPTOR_32*)DescriptorTableBase;
|
|
return &segmentDescriptors[segmentSelector.Index];
|
|
}
|
|
|
|
/*!
|
|
@brief Returns the base address of SegmentDescriptor.
|
|
|
|
@param[in] SegmentDescriptor - The segment descriptor from which retrieve
|
|
the base address.
|
|
|
|
@return The base address of SegmentDescriptor.
|
|
*/
|
|
static
|
|
UINT64
|
|
GetSegmentBaseByDescriptor (
|
|
_In_ CONST SEGMENT_DESCRIPTOR_32* SegmentDescriptor
|
|
)
|
|
{
|
|
UINT64 segmentBase;
|
|
UINT64 baseHigh, baseMiddle, baseLow;
|
|
|
|
baseHigh = ((UINT64)SegmentDescriptor->BaseAddressHigh) << (6 * 4);
|
|
baseMiddle = ((UINT64)SegmentDescriptor->BaseAddressMiddle) << (4 * 4);
|
|
baseLow = SegmentDescriptor->BaseAddressLow;
|
|
segmentBase = (baseHigh | baseMiddle | baseLow) & MAXUINT32;
|
|
|
|
//
|
|
// Few system descriptors are expanded to 16 bytes on x64. For practical
|
|
// reasons, we only detect TSS descriptors (that is the System field is
|
|
// cleared, and the Type field has either one of specific values).
|
|
//
|
|
// See: 3.5.2 Segment Descriptor Tables in IA-32e Mode
|
|
//
|
|
if ((SegmentDescriptor->System == 0) &&
|
|
((SegmentDescriptor->Type == SEGMENT_DESCRIPTOR_TYPE_TSS_AVAILABLE) ||
|
|
(SegmentDescriptor->Type == SEGMENT_DESCRIPTOR_TYPE_TSS_BUSY)))
|
|
{
|
|
CONST SEGMENT_DESCRIPTOR_64* descriptor64;
|
|
|
|
descriptor64 = (CONST SEGMENT_DESCRIPTOR_64*)SegmentDescriptor;
|
|
segmentBase |= ((UINT64)descriptor64->BaseAddressUpper << 32);
|
|
}
|
|
return segmentBase;
|
|
}
|
|
|
|
UINT64
|
|
GetSegmentBase (
|
|
_In_ UINT64 DescriptorTableBase,
|
|
_In_ UINT16 SegmentSelector
|
|
)
|
|
{
|
|
UINT64 segmentBase;
|
|
SEGMENT_SELECTOR segmentSelector;
|
|
|
|
segmentSelector.Flags = SegmentSelector;
|
|
|
|
if ((segmentSelector.Table == 0) &&
|
|
(segmentSelector.Index == 0))
|
|
{
|
|
//
|
|
// The null segment selectors technically does not point to a valid
|
|
// segment descriptor, hence no valid base address either. We return
|
|
// 0 for convenience, however.
|
|
//
|
|
// "The first entry of the GDT is not used by the processor. A segment
|
|
// selector that points to this entry of the GDT (that is, a segment
|
|
// selector with an index of 0 and the TI flag set to 0) is used as a
|
|
// "null segment selector."".
|
|
// 3.4.2 Segment Selectors
|
|
//
|
|
segmentBase = 0;
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// For practical reasons, we do not support LDT. This will not be an issue
|
|
// as we are running as a SYSTEM which will not use LDT.
|
|
//
|
|
// "Specifies the descriptor table to use: clearing this flag selects the GDT;
|
|
// setting this flag selects the current LDT."
|
|
// See: 3.4.2 Segment Selectors
|
|
//
|
|
MV_ASSERT(segmentSelector.Table == 0);
|
|
segmentBase = GetSegmentBaseByDescriptor(GetSegmentDescriptor(DescriptorTableBase,
|
|
SegmentSelector));
|
|
|
|
Exit:
|
|
return segmentBase;
|
|
}
|
|
|
|
_Use_decl_annotations_
|
|
CR0
|
|
AdjustCr0 (
|
|
CR0 Cr0
|
|
)
|
|
{
|
|
CR0 newCr0, fixed0Cr0, fixed1Cr0;
|
|
|
|
newCr0 = Cr0;
|
|
fixed0Cr0.Flags = __readmsr(IA32_VMX_CR0_FIXED0);
|
|
fixed1Cr0.Flags = __readmsr(IA32_VMX_CR0_FIXED1);
|
|
newCr0.Flags &= fixed1Cr0.Flags;
|
|
newCr0.Flags |= fixed0Cr0.Flags;
|
|
return newCr0;
|
|
}
|
|
|
|
_Use_decl_annotations_
|
|
CR4
|
|
AdjustCr4 (
|
|
CR4 Cr4
|
|
)
|
|
{
|
|
CR4 newCr4, fixed0Cr4, fixed1Cr4;
|
|
|
|
newCr4 = Cr4;
|
|
fixed0Cr4.Flags = __readmsr(IA32_VMX_CR4_FIXED0);
|
|
fixed1Cr4.Flags = __readmsr(IA32_VMX_CR4_FIXED1);
|
|
newCr4.Flags &= fixed1Cr4.Flags;
|
|
newCr4.Flags |= fixed0Cr4.Flags;
|
|
return newCr4;
|
|
}
|