Rename Utils to Ia32Utils
This commit is contained in:
222
Sources/Ia32Utils.c
Normal file
222
Sources/Ia32Utils.c
Normal file
@@ -0,0 +1,222 @@
|
||||
/*!
|
||||
@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;
|
||||
}
|
||||
Reference in New Issue
Block a user