检测CPU是否具备VT的功能,并开启

本文详细介绍了如何通过CPUID和RDMSR指令检查及启用IntelVT-x技术。首先,通过CPUID的EFLAGSID标志检测支持,然后读取IA32_FEATURE_CONTROLMSR以检查VMX锁定位。接着,确保CR4的VMXE位已开启,最后调整CR0和CR4的设置以符合VMX操作的要求。这是在系统层面启用虚拟化技术的关键步骤。
摘要由CSDN通过智能技术生成

1.cpuid 指令:

EFLAGS寄存器中的ID标志(位21)表示对CPUID指令的支持。如果一个软件程序可以设置和清除这个标志,那么执行该程序的处理器支持CPUID指令。这条指令在非64位模式和64位模式下操作相同。

CPUID在EAX、EBX、ECX和EDX寄存器中返回处理器识别和特征信息。

__cpuid 函数在 #include <intrin.h>

intel提供了非常方便的头文件

传入数组,功能号为1

就能得到相关的信息,我们这里只关注返回后,ecx的第5个位,这里为了简单就做了下与操作。(后面如果有深入VT的额外课程,会使用其他功能号的位,intel手册上cpuid指令有祥细的说明,可将这些定义为结构体,注释起来方便使用,一劳永逸)

返回值是真就代表支持VMX.

2.__rdmsr 指令 -- 从特定型号寄存器读取

cpu 有很多特殊寄存器 统称为MSR

MSR_IA32_FEATURE_CONTROL -- 地址是0x3A.(手册上第四卷有祥细的说明)

指令同样也在intel提供的头文件里。

第0位说明:

锁定位(R/WO):(1 = 锁定)。设置后,锁定此 MSR 不被写入;写入此位将导致GP(0)。

注意:一旦设置了锁定位,就无法修改此寄存器的内容。

因此,在配置对英特尔虚拟化技术的支持之后,以及在将控制权转移到选项 ROM 或操作系统之前,必须设置锁定位。因此,一旦设置了锁定位,当 PWRGOOD 未取消断言时,整个IA32_FEATURE_CONTROL内容将在整个 RESET 中保留。

结构体我已经定义好了(一劳永逸)。我们这里要检查锁定位是否为0,为0的话VMXON会失败,这个地方可在BIOS设置开启,大家型号可能不一样,网上查一下自己的bios怎么开启叭~。

返回值是真表示可以开启VMX。

设置CR4:

在系统软件可以进入 VMX 操作之前,它通过设置 CR4 启用 VMX。VMXE[位 13] = 1。然后通过执行 VMXON 指令进入 VMX 操作。如果未开启此位,VMXON 会导致无效操作码异常(#UD)。一旦进入 VMX 操作,就无法清除 CR4.VMXE(请参见第 23.8 节)。系统软件通过执行 VMXOFF 指令离开 VMX 操作。执行 VMXOFF 后,可以在 VMX 操作之外清除 VMXE。

这一步只是检查VMXE是否已经开启,未对它进行设置,如果未开启的话,就由我们来开启。

下面修正CR4,CR0设置会开启VMXE。

修正CR0,CR4:

VMX 操作对处理器操作施加了限制。具体如下:

* 在 VMX 操作中,处理器可能会将 CR0 和 CR4 中的某些位固定为特定值,而不支持其他值。如果这些位中的任何一个包含不受支持的值,则 VMXON 将失败(请参见第 30 章中的“VMXON-Enter VMX 操作”)。在 VMX 操作(包括 VMX 根操作)中使用任何 CLTS、LMSW 或 MOV CR 指令时,尝试将这些位之一设置为不受支持的值会导致常规保护异常。VM Entry或 VM Exit无法将这些位中的任何一个设置为不受支持的值。软件应参考 VMX 功能 MSR IA32_VMX_CR0_FIXED0和IA32_VMX_CR0_FIXED1,以确定如何修复 CR0 中的位(请参阅附录 A.7)。对于 CR4,软件应参考 VMX 功能 MSR IA32_VMX_CR4_FIXED0和IA32_VMX_CR4_FIXED1(请参阅附录 A.8)。

IA32_VMX_CR0_FIXED0MSR(索引 486H)和 IA32_VMX_CR0_FIXED1 MSR(索引487H)指示如何在 VMX 操作中设置 CR0 中的位。它们报告 CR0 中允许在 VMX 操作中分别为 0 和 1 的位。如果位 X 在IA32_VMX_CR0_FIXED0中为 1,则CR0 的位在 VMX 操作中固定为 1。同样,如果位 X 在 IA32_VMX_CR0_FIXED1 中为0,则 CR0 位在 VMX 操作中固定为 0。总是这样,如果位 X 是 1 IA32_VMX_CR0_FIXED0,那么该位也是 1 IA32_VMX_CR0_FIXED1;如果位 X 在IA32_VMX_CR0_FIXED1中为 0,则该位在IA32_VMX_CR0_FIXED0中也是 0。因此,CR0 中的每个位要么固定为 0(两个 MSR 中的值均为 0),要么固定为 1(两个 MSR 中的值均为 1),要么灵活(IA32_VMX_CR0_FIXED0 为 0,IA32_VMX_CR0_FIXED1中为 1)。

How to 理解?

也就是说 CR0_FIXED0 中的任意一位是1,CR0的该位就必须是1,CR0_FIXED1 中的任意一位是0,CR0的该位就必须是0

不关心CR0_FIXED0 中的0值的位,不关心CR0_FIXED1 中的1值的位。

组合起来就是以下:

CR0_FIXED0=486H,CR0_FIXED1=487H。

CR4也同样需要一份这样的代码,CR4_FIXED0=488H,CR4_FIXED1=489H。

每个CPU核都有自己CR0,CR4哦,所以每个核都要设置。

以上我们已经检查并开启了VMX。进入下一节。

#include <ntifs.h>
#include <intrin.h>

#define CPUID_ECX_VMX_ABILITY 5
#define MSR_IA32_FEATURE_CONTROL 0x3A

#define MSR_IA32_VMX_CR0_FIXED0    0x486
#define MSR_IA32_VMX_CR0_FIXED1    0x487
#define MSR_IA32_VMX_CR4_FIXED0    0x488
#define MSR_IA32_VMX_CR4_FIXED1    0x489

#pragma pack(1)
typedef union {

    struct {
        ULONG  Lock : 1;                            //bit-0            Lock bit (0 = unlocked, 1 = locked). When set to '1' further writes to this MSR are blocked.
        ULONG  EnableVmxInsideSmx : 1;                //bit-1            Enable VMX in SMX operation.
        ULONG  EnableVmxOutsideSmx : 1;                //bit-2            Enable VMX outside SMX operation.
        ULONG  Reserved1 : 5;                        //bit-3:7        Reserved
        ULONG  SenterLocalFunctionEnables : 7;        //bit-8:14        SENTER Local Function Enables: When set, each bit in the field represents an enable control for a corresponding SENTER function.
        ULONG  SenterGlobalEnable : 1;                //bit-15        SENTER Global Enable: Must be set to ‘1’ to enable operation of GETSEC[SENTER].
        ULONG  Reserved2 : 1;                        //bit-16        Reserved
        ULONG  SgxLaunchControlEnable : 1;            //bit-17        SGX Launch Control Enable: Must be set to ‘1’ to enable runtime re-configuration of SGX Launch Control via the IA32_SGXLEPUBKEYHASHn MSR.
        ULONG  SgxEnable : 1;                        //bit-18        SGX Global Enable: Must be set to ‘1’ to enable Intel SGX leaf functions.
        ULONG  Reserved3 : 1;                        //bit-19        Reserved
        ULONG  LmceOn : 1;                            //bit-20        LMCE On: When set, system software can program the MSRs associated with LMCE to configure delivery of some machine check exceptions to a single logical processor.
        ULONG  Reserved4 : 11;                        //bit-21:31        Reserved
        ULONG  Reserved5 : 32;                        //bit-32:64        Reserved
    } Bits;
    LARGE_INTEGER  value;
} MSR_IA32_FEATURE_CONTROL_REGISTER, * PMSR_IA32_FEATURE_CONTROL_REGISTER;

typedef union {
    struct {
        ULONG  PE : 1;           ///< Protection Enable.
        ULONG  MP : 1;           ///< Monitor Coprocessor.
        ULONG  EM : 1;           ///< Emulation.
        ULONG  TS : 1;           ///< Task Switched.
        ULONG  ET : 1;           ///< Extension Type.
        ULONG  NE : 1;           ///< Numeric Error.
        ULONG  Reserved_0 : 10;  ///< Reserved.
        ULONG  WP : 1;           ///< Write Protect.
        ULONG  Reserved_1 : 1;   ///< Reserved.
        ULONG  AM : 1;           ///< Alignment Mask.
        ULONG  Reserved_2 : 10;  ///< Reserved.
        ULONG  NW : 1;           ///< Mot Write-through.
        ULONG  CD : 1;           ///< Cache Disable.
        ULONG  PG : 1;           ///< Paging.
    } Bits;
    LARGE_INTEGER value;
} IA32_CR0, * PCR0;
typedef union {
    struct {
        ULONG64 VME : 1;                //Bit-0
        ULONG64 PVI : 1;                //Bit-1
        ULONG64 TSD : 1;                //Bit-2
        ULONG64 DE : 1;                    //Bit-3
        ULONG64 PSE : 1;                //Bit-4
        ULONG64 PAE : 1;                //Bit-5
        ULONG64 MCE : 1;                //Bit-6
        ULONG64 PGE : 1;                //Bit-7
        ULONG64 PCE : 1;                //Bit-8
        ULONG64 OSFXSR : 1;                //Bit-9
        ULONG64 OSXMMEXCPT : 1;            //Bit-10
        ULONG64 UMIP : 1;                //Bit-11
        ULONG64 LA57 : 1;                //Bit-12
        ULONG64 VMXE : 1;                //Bit-13
        ULONG64 SMXE : 1;                //Bit-14
        ULONG64 NOP_15 : 1;                //Bit-15
        ULONG64 FSGSBASE : 1;            //Bit-16
        ULONG64 PCIDE : 1;                //Bit-17
        ULONG64 OSXSAVE : 1;            //Bit-18
        ULONG64 KL : 1;                    //Bit-19
        ULONG64 SMEP : 1;                //Bit-20
        ULONG64 SMAP : 1;                //Bit-21
        ULONG64 PKE : 1;                //Bit-22
        ULONG64 CET : 1;                //Bit-23
        ULONG64 PKS : 1;                //Bit-24
        ULONG64 NOP_25_31 : 7;            //These are zero
        ULONG64 Reserved_64 : 32;
    }Bits;
    LARGE_INTEGER value;
}IA32_CR4, * PCR4;
#pragma pack()

IA32_CR0 SaveCr0[10] = { 0 };
IA32_CR4 SaveCr4[10] = { 0 };

ULONG64 CheckCPUID() {
    int ctx[4] = { 0 };//顺序:eax,ebx,ecx,edx
    __cpuid(ctx, 1);

    return ctx[2] & CPUID_ECX_VMX_ABILITY;    //Bit-5
}

ULONG64 SetCr0(ULONG64 IndexCpu) {
    IA32_CR0 uCr0 = { 0 };
    uCr0.value.QuadPart = __readcr0();

    SaveCr0[IndexCpu].value.QuadPart = uCr0.value.QuadPart;

    uCr0.value.QuadPart |= __readmsr(MSR_IA32_VMX_CR0_FIXED0);
    uCr0.value.QuadPart &= __readmsr(MSR_IA32_VMX_CR0_FIXED1);

    __writecr0(uCr0.value.QuadPart);
    return TRUE;
}
ULONG64 SetCr4(ULONG64 IndexCpu) {
    IA32_CR4 uCr4 = { 0 };
    uCr4.value.QuadPart = __readcr4();

    SaveCr4[IndexCpu].value.QuadPart = uCr4.value.QuadPart;

    uCr4.value.QuadPart |= __readmsr(MSR_IA32_VMX_CR4_FIXED0);
    uCr4.value.QuadPart &= __readmsr(MSR_IA32_VMX_CR4_FIXED1);

    __writecr4(uCr4.value.QuadPart);
    return TRUE;
}

ULONG64 CheckMsr() {
    MSR_IA32_FEATURE_CONTROL_REGISTER msr = { 0 };
    msr.value.QuadPart = __readmsr(MSR_IA32_FEATURE_CONTROL);

    return msr.Bits.Lock;
}

VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
{
    for (ULONG CpuIndex = 0; CpuIndex < KeNumberProcessors; CpuIndex++)
    {
        KeSetSystemAffinityThread((KAFFINITY)(1 << CpuIndex));
        __writecr0(SaveCr0[CpuIndex].value.QuadPart);
        __writecr4(SaveCr4[CpuIndex].value.QuadPart);
        KdPrint(("CPU:[%d],关闭VMX\n", CpuIndex));
        KeRevertToUserAffinityThread();
    }
    ULONG64 Cr4 = __readcr4();
    KdPrint(("卸载驱动,当前CR4.VMEX=%I64X,1==打开,0==关闭\n", ((IA32_CR4*)&Cr4)->Bits.VMXE));
}
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING RegisterPath)
{
    if (CheckCPUID() == FALSE) {
        KdPrint(("CPU不支持\n"));
    }
    if (CheckMsr() == FALSE) {
        KdPrint(("BIOS未开启VMX\n"));
    }
    for (ULONG CpuIndex = 0; CpuIndex < KeNumberProcessors; CpuIndex++)
    {
        KeSetSystemAffinityThread((KAFFINITY)(1 << CpuIndex));
        SetCr0(CpuIndex);
        SetCr4(CpuIndex);
        KdPrint(("CPU:[%d],开启VMX\n", CpuIndex));
        KeRevertToUserAffinityThread();
    }
    ULONG64 Cr4 = __readcr4();
    KdPrint(("加载驱动,当前CR4.VMEX=%I64X,1==打开,0==关闭\n", ((IA32_CR4*)&Cr4)->Bits.VMXE));

    pDriverObject->DriverUnload = DriverUnload;
    return STATUS_SUCCESS;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小烟囱

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值