之前也写过一个vt的框架,但是比较简单,写的比较乱迁移什么的比较麻烦,于是阅读下HyperPlatform的源码学习下。
本文只对主体框架分析。
vt的流程大概如下
1:检测是否支持VT。
2:vmxon。
3:vmclear.
4:vmptrload。
5:vmcs。
6:vmlaunch
7:vmclear
8:vmoff
VmInitialization
首先是关键的VMinit
检测vt是否已被占用
Use_decl_annotations_ static bool VmpIsHyperPlatformInstalled() {
PAGED_CODE()
int cpu_info[4] = {};
__cpuid(cpu_info, 1);
const CpuFeaturesEcx cpu_features = {static_cast<ULONG32>(cpu_info[2])};
if (!cpu_features.fields.not_used) {
return false;
}
__cpuid(cpu_info, kHyperVCpuidInterface);
return cpu_info[0] == 'PpyH';
}
检测是否支持VT
// Checks if the system supports virtualization
_Use_decl_annotations_ static bool VmpIsVmxAvailable() {
PAGED_CODE()
// See: DISCOVERING SUPPORT FOR VMX
// If CPUID.1:ECX.VMX[bit 5]=1, then VMX operation is supported.
int cpu_info[4] = {};
__cpuid(cpu_info, 1);
const CpuFeaturesEcx cpu_features = {static_cast<ULONG32>(cpu_info[2])};
if (!cpu_features.fields.vmx) {
HYPERPLATFORM_LOG_ERROR("VMX features are not supported.");
return false;
}
......
Ia32FeatureControlMsr vmx_feature_control = {
UtilReadMsr64(Msr::kIa32FeatureControl)};
if (!vmx_feature_control.fields.enable_vmxon) {
HYPERPLATFORM_LOG_ERROR("VMX features are not enabled.");
return false;
}
......
return true;
}
检查都通过后进入正题调用VmpStartVm
VmpStartVm
VmpInitializeVm
分配VMXON内存
processor_data->vmxon_region =
static_cast<VmControlStructure *>(ExAllocatePoolZero(
NonPagedPool, kVmxMaxVmcsSize, kHyperPlatformCommonPoolTag));
if (!processor_data->vmxon_region) {
VmpFreeProcessorData(processor_data);
return;
}
RtlZeroMemory(processor_data->vmxon_region, kVmxMaxVmcsSize);
分配VMCS内存
processor_data->vmcs_region =
static_cast<VmControlStructure *>(ExAllocatePoolZero(
NonPagedPool, kVmxMaxVmcsSize, kHyperPlatformCommonPoolTag));
if (!processor_data->vmcs_region) {
VmpFreeProcessorData(processor_data);
return;
}
RtlZeroMemory(processor_data->vmcs_region, kVmxMaxVmcsSize);
分配VMM stack内存
processor_data->vmm_stack_limit =
UtilAllocateContiguousMemory(KERNEL_STACK_SIZE);
if (!processor_data->vmm_stack_limit) {
VmpFreeProcessorData(processor_data);
return;
}
RtlZeroMemory(processor_data->vmm_stack_limit, KERNEL_STACK_SIZE);
VmpEnterVmxMode
对应VMXON,修正cr0和cr4寄存器的值,在上面申请的VMXON内存中写入版本号,然后执行vmxon。
_Use_decl_annotations_ static bool VmpEnterVmxMode(
ProcessorData *processor_data) {
PAGED_CODE()
// Apply FIXED bits
// See: VMX-FIXED BITS IN CR0
// IA32_VMX_CRx_FIXED0 IA32_VMX_CRx_FIXED1 Meaning
// Values 1 * bit of CRx is fixed to 1
// Values 0 1 bit of CRx is flexible
// Values * 0 bit of CRx is fixed to 0
const Cr0 cr0_fixed0 = {UtilReadMsr(Msr::kIa32VmxCr0Fixed0)};
const Cr0 cr0_fixed1 = {UtilReadMsr(Msr::kIa32VmxCr0Fixed1)};
Cr0 cr0 = {__readcr0()};
Cr0 cr0_original = cr0;
cr0.all &= cr0_fixed1.all;
cr0.all |= cr0_fixed0.all;
__writecr0(cr0.all);
HYPERPLATFORM_LOG_DEBUG("IA32_VMX_CR0_FIXED0 = %08Ix", cr0_fixed0.all);
HYPERPLATFORM_LOG_DEBUG("IA32_VMX_CR0_FIXED1 = %08Ix", cr0_fixed1.all);
HYPERPLATFORM_LOG_DEBUG("Original CR0 = %08Ix", cr0_original.all);
HYPERPLATFORM_LOG_DEBUG("Fixed CR0 = %08Ix", cr0.all);
// See: VMX-FIXED BITS IN CR4
const Cr4 cr4_fixed0 = {UtilReadMsr(Msr::kIa32VmxCr4Fixed0)};
const Cr4 cr4_fixed1 = {UtilReadMsr(Msr::kIa32VmxCr4Fixed1)};
Cr4 cr4 = {__readcr4()};
Cr4 cr4_original = cr4;
cr4.all &= cr4_fixed1.all;
cr4.all |= cr4_fixed0.all;
__writecr4(cr4.all);
HYPERPLATFORM_LOG_DEBUG("IA32_VMX_CR4_FIXED0 = %08Ix", cr4_fixed0.all);
HYPERPLATFORM_LOG_DEBUG("IA32_VMX_CR4_FIXED1 = %08Ix", cr4_fixed1.all);
HYPERPLATFORM_LOG_DEBUG("Original CR4 = %08Ix", cr4_original.all);
HYPERPLATFORM_LOG_DEBUG("Fixed CR4 = %08Ix", cr4.all);
// Write a VMCS revision identifier
const Ia32VmxBasicMsr vmx_basic_msr = {UtilReadMsr64(Msr::kIa32VmxBasic)};
processor_data->vmxon_region->revision_identifier =
vmx_basic_msr.fields.revision_identifier;
auto vmxon_region_pa = UtilPaFromVa(processor_data->vmxon_region);
if (__vmx_on(&vmxon_region_pa)) {
return false;
}
// See: Guidelines for Use of the INVVPID Instruction, and Guidelines for Use
// of the INVEPT Instruction
UtilInveptGlobal();
UtilInvvpidAllContext();
return true;
}
VmpInitializeVmcs
对应vmclear和vmptrload。向上面申请的VMCS内存区写入版本号,然后执行__vmx_vmclear和__vmx_vmptrld。
_Use_decl_annotations_ static bool VmpInitializeVmcs(
ProcessorData *processor_data) {
PAGED_CODE()
// Write a VMCS revision identifier
const Ia32VmxBasicMsr vmx_basic_msr = {UtilReadMsr64(Msr::kIa32VmxBasic)};
processor_data->vmcs_region->revision_identifier =
vmx_basic_msr.fields.revision_identifier;
auto vmcs_region_pa = UtilPaFromVa(processor_data->vmcs_region);
if (__vmx_vmclear(&vmcs_region_pa)) {
return false;
}
if (__vmx_vmptrld(&vmcs_region_pa)) {
return false;
}
// The launch state of current VMCS is "clear"
return true;
}
VmpSetupVmcs
对应VMCS。
标签:cr0,return,cr4,region,HyperPlatform,data,processor From: https://www.cnblogs.com/awesome-red/p/17114766.html