Windows系统下检测主板功能 VT-x/d 、SVM/IOMMU 开启状态

Windows系统下检测主板功能 VT-x/d 、SVM/IOMMU 开启状态

在 Windows 上检查虚拟化功能时,最容易犯的错误,是把 VT-x、VT-d、SVM 和 IOMMU 当成同一个开关。

它们其实分成两组:

CPU 平台 CPU 虚拟化 I/O 虚拟化
Intel VT-x / VMX VT-d / DMA Remapping
AMD AMD-V / SVM AMD-Vi / IOMMU

VT-x 和 SVM 负责让处理器高效运行虚拟机;VT-d 和 AMD IOMMU 负责限制、转换 PCIe 等设备发起的 DMA 内存访问。前者主要属于 CPU 执行能力,后者是处理器、芯片组、主板固件和操作系统共同提供的平台能力。

因此,可靠的检测不能只回答一个“开”或“关”,而应该区分:

  1. 硬件是否支持;
  2. BIOS/UEFI 是否已经开放给操作系统;
  3. Windows 是否已经在使用这项能力。

一、最快的图形界面检查

1. 用任务管理器检查 VT-x 或 SVM

按 Ctrl + Shift + Esc 打开任务管理器,进入:

性能 → CPU → 虚拟化

如果显示“已启用”,通常表示当前物理机的 Intel VT-x 或 AMD SVM 已在 BIOS/UEFI 中开启,并且 Windows 能够使用。

但任务管理器的“虚拟化”不代表 VT-d 或 AMD IOMMU。它主要回答的是 CPU 虚拟化扩展是否可用。

2. 用系统信息检查 IOMMU 的实际使用迹象

按 Win + R,运行:

msinfo32

在“系统摘要”中关注两项:

  • “固件中已启用虚拟化”:对应 VT-x 或 SVM;
  • “内核 DMA 保护”:与 VT-d/AMD IOMMU 的实际使用有关。

微软说明,Windows 的内核 DMA 保护利用系统 IOMMU 对外部 DMA 设备进行隔离,并可以在 msinfo32.exe 中检查状态。Microsoft Learn:Kernel DMA Protection

这里要特别注意:

“内核 DMA 保护 = 开启”是 Windows 正在利用 IOMMU 的强证据;但“关闭”不能单独证明 VT-d/IOMMU 一定在 BIOS 中关闭。

它还会受到平台拓扑、ACPI 标志、设备范围、驱动兼容性和 Windows 版本等条件影响。

二、用 PowerShell 检查 VT-x 或 SVM

以普通权限打开 PowerShell,运行:

$cpu = Get-CimInstance Win32_Processor
$computer = Get-CimInstance Win32_ComputerSystem

[pscustomobject]@{
    CPU名称                  = ($cpu.Name -join '; ')
    支持虚拟机监控扩展      = ($cpu.VMMonitorModeExtensions -contains $true)
    固件已开启CPU虚拟化     = ($cpu.VirtualizationFirmwareEnabled -contains $true)
    支持二级地址转换        = ($cpu.SecondLevelAddressTranslationExtensions -contains $true)
    已检测到Hypervisor      = [bool]$computer.HypervisorPresent
}

各字段的含义如下:

  • VMMonitorModeExtensions:CPU 是否支持 Intel VMX 或 AMD SVM;
  • VirtualizationFirmwareEnabled:固件是否已启用 CPU 虚拟化扩展;
  • SecondLevelAddressTranslationExtensions:是否支持 SLAT,也就是 Intel EPT 或 AMD NPT;
  • HypervisorPresent:Windows 当前是否检测到正在运行的 Hypervisor。

微软对 Win32_Processor.VirtualizationFirmwareEnabled 的定义就是“固件已启用虚拟化扩展”。这些属性从 Windows 8 / Windows Server 2012 起才受支持。Microsoft Learn:Win32_Processor

不要把 SecondLevelAddressTranslationExtensions 当成 VT-d。EPT/NPT 是 CPU 为虚拟机内存转换提供的 SLAT;VT-d/IOMMU 是设备 DMA 地址转换,两者不是同一功能。

三、systeminfo 为什么有时不给出四项结果

运行:

systeminfo

在输出底部通常能看到 Hyper-V 要求,包括“固件中已启用虚拟化”等信息。

如果 Hyper-V、VBS、内存完整性等组件已经启动,输出可能变成:

已检测到虚拟机监控程序。将不显示 Hyper-V 所需的功能。

这并不表示虚拟化被关闭。相反,在物理 Windows 主机上,Hypervisor 已经运行本身就是 CPU 虚拟化可用的强证据。微软也说明,已运行 Hyper-V 时,相关功能明细会被隐藏。Microsoft Learn:Hyper-V hardware requirements

如果当前 Windows 本身运行在虚拟机里,这个结论只能描述“来宾系统看到的虚拟 CPU”,不能据此判断物理宿主机 BIOS 的真实设置。

四、程序如何检测 VT-x 与 SVM

1. CPUID 只能先判断“硬件支持”

在 Intel 处理器上执行 CPUID(EAX=1)

ECX bit 5 = 1  → 支持 VMX,也就是 VT-x

Intel 的架构手册明确使用 CPUID.1:ECX.VMX[bit 5] 判断处理器是否支持 VMX。Intel 64 and IA-32 SDM,VMX support

在 AMD 处理器上执行 CPUID(EAX=0x80000001)

ECX bit 2 = 1  → 支持 SVM,也就是 AMD-V

AMD 将该能力记为 CPUID Fn8000_0001_ECX[SVM];固件还可以通过 SVM 禁用/锁定位阻止系统使用它。AMD64 Architecture Programmer’s Manual, Volume 2

所以,CPUID 位为 1 只代表处理器具有这项能力,不等于 BIOS 已经打开开关。

2. 用户态程序应让 Windows 判断“固件是否开放”

Windows 提供:

IsProcessorFeaturePresent(PF_VIRT_FIRMWARE_ENABLED)

其中 PF_VIRT_FIRMWARE_ENABLED 的值为 21。微软对它的定义是:虚拟化已经在固件中启用,并由操作系统提供。Microsoft Learn:IsProcessorFeaturePresent

一个简化的 C++ 检测片段如下:

#include <windows.h>
#include <intrin.h>
#include <array>
#include <cstring>
#include <string>

struct CpuVirtInfo {
    std::string vendor;
    bool vmxSupported = false;
    bool svmSupported = false;
    bool hypervisorPresent = false;
    bool enabledByFirmware = false;
};

CpuVirtInfo QueryCpuVirtualization() {
    CpuVirtInfo result;
    std::array<int, 4> cpu{};

    __cpuid(cpu.data(), 0);
    char vendor[13]{};
    std::memcpy(vendor,     &cpu[1], 4); // EBX
    std::memcpy(vendor + 4, &cpu[3], 4); // EDX
    std::memcpy(vendor + 8, &cpu[2], 4); // ECX
    result.vendor = vendor;

    __cpuid(cpu.data(), 1);
    result.vmxSupported = (cpu[2] & (1 << 5)) != 0;
    result.hypervisorPresent = (cpu[2] & (1U << 31)) != 0;

    __cpuid(cpu.data(), static_cast<int>(0x80000000U));
    if (static_cast<unsigned int>(cpu[0]) >= 0x80000001U) {
        __cpuid(cpu.data(), static_cast<int>(0x80000001U));
        result.svmSupported = (cpu[2] & (1 << 2)) != 0;
    }

    result.enabledByFirmware =
        IsProcessorFeaturePresent(PF_VIRT_FIRMWARE_ENABLED) != FALSE;
    return result;
}

推荐的判定顺序是:

  1. 先按 GenuineIntel 或 AuthenticAMD 区分厂商;
  2. 用对应 CPUID 位判断硬件是否支持;
  3. 用 PF_VIRT_FIRMWARE_ENABLED 判断固件是否已开放;
  4. 如果检测到正在运行的 Hypervisor,则单独报告,避免把被 Hypervisor 虚拟化或屏蔽后的 CPUID 误判成“不支持”。

五、程序如何检测 VT-d 与 AMD IOMMU

VT-d/AMD IOMMU 没有一个与 VirtualizationFirmwareEnabled 等价、适用于所有 Windows 版本的简单布尔属性。

通用用户态程序通常会枚举 ACPI 固件表:

  • Intel 平台查找 DMAR
  • AMD 平台查找 IVRS

Intel VT-d 固件通过 DMAR 表描述 DMA Remapping 硬件单元;AMD IOMMU 规范则定义了 IVRS,也就是 I/O Virtualization Reporting Structure。Intel VT-d Architecture SpecificationAMD IOMMU Specification

Windows 用户态可以调用:

EnumSystemFirmwareTables('ACPI', ...)

微软文档说明,使用 ACPI provider 时,返回的每个四字节标识都对应当前 ACPI 命名空间中的一个表签名。Microsoft Learn:EnumSystemFirmwareTables

如果只想快速检查表名,可以在完整 Windows 的 PowerShell 中运行下面的脚本:

Add-Type -TypeDefinition @'
using System;
using System.Runtime.InteropServices;

public static class NativeFirmware {
    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern uint EnumSystemFirmwareTables(
        uint provider, IntPtr buffer, uint size);
}
'@

# Windows API 中多字符常量 'ACPI' 对应 0x41435049
$acpi = [uint32]0x41435049
$size = [NativeFirmware]::EnumSystemFirmwareTables(
    $acpi, [IntPtr]::Zero, 0)

if ($size -eq 0) {
    throw '无法枚举 ACPI 固件表。'
}

$buffer = [Runtime.InteropServices.Marshal]::AllocHGlobal([int]$size)
try {
    $written = [NativeFirmware]::EnumSystemFirmwareTables(
        $acpi, $buffer, $size)
    if ($written -eq 0) {
        throw '读取 ACPI 固件表失败。'
    }

    $bytes = [byte[]]::new($written)
    [Runtime.InteropServices.Marshal]::Copy(
        $buffer, $bytes, 0, [int]$written)

    $tables = for ($i = 0; $i -le [int]$written - 4; $i += 4) {
        [Text.Encoding]::ASCII.GetString($bytes, $i, 4)
    }

    [pscustomobject]@{
        Intel_VTd_DMAR = $tables -contains 'DMAR'
        AMD_IOMMU_IVRS = $tables -contains 'IVRS'
        ACPI表数量     = $tables.Count
    }
}
finally {
    [Runtime.InteropServices.Marshal]::FreeHGlobal($buffer)
}

Intel_VTd_DMAR = True 表示检测到 DMAR;AMD_IOMMU_IVRS = True 表示检测到 IVRS。两项不能简单合并,因为应先根据 CPU 厂商选择对应的判断结果。

示例:

#include <windows.h>
#include <cstdint>
#include <cstring>
#include <string>
#include <vector>

constexpr DWORD Signature(char a, char b, char c, char d) {
    return (static_cast<DWORD>(a) << 24) |
           (static_cast<DWORD>(b) << 16) |
           (static_cast<DWORD>(c) << 8)  |
            static_cast<DWORD>(d);
}

bool HasAcpiTable(const char wanted[5]) {
    constexpr DWORD acpi = Signature('A', 'C', 'P', 'I');
    const UINT size = EnumSystemFirmwareTables(acpi, nullptr, 0);
    if (size == 0) return false;

    std::vector<std::uint8_t> buffer(size);
    const UINT written = EnumSystemFirmwareTables(
        acpi, buffer.data(), static_cast<DWORD>(buffer.size()));
    if (written == 0 || written > buffer.size()) return false;

    for (UINT offset = 0; offset + 4 <= written; offset += 4) {
        if (std::memcmp(buffer.data() + offset, wanted, 4) == 0)
            return true;
    }
    return false;
}

const bool intelVtdExposed = HasAcpiTable("DMAR");
const bool amdIommuExposed = HasAcpiTable("IVRS");

ACPI 表存在应该怎样描述

严谨的输出建议使用:

检测到 DMAR:固件已向 Windows 暴露 Intel DMA Remapping 信息    |       检测到 IVRS:固件已向 Windows 暴露 AMD IOMMU 信息

不要仅凭表名就声称“所有设备都已启用 DMA 重映射”。ACPI 表存在是非常强的固件暴露证据,但操作系统是否为所有设备建立重映射,还要看表内容、驱动、系统策略和当前启动环境。

如果还需要判断 Windows 是否正在将其用于安全防护,再结合 msinfo32 的“内核 DMA 保护”状态。

六、一个实用的判定矩阵

检测结果 推荐解释
CPUID 不支持,固件标志为否 CPU 不支持,或者当前虚拟环境屏蔽了该能力
CPUID 支持,固件标志为否 CPU 支持,但 BIOS/UEFI 可能未开启 VT-x/SVM
固件标志为是 VT-x/SVM 已由固件开放给 Windows
已检测到 Hypervisor 当前环境正在使用虚拟化;物理机上通常可视为已开启
Intel 平台存在 DMAR 固件已暴露 VT-d/DMA Remapping 信息
AMD 平台存在 IVRS 固件已暴露 AMD IOMMU 信息
内核 DMA 保护为开启 Windows 正在使用 IOMMU 提供相应 DMA 防护
内核 DMA 保护为关闭 不能单独断定 VT-d/IOMMU 已关闭

七、常见误区

误区 1:CPU 型号支持,就等于 BIOS 已开启

不对。CPUID 能证明“硬件有”,不能单独证明固件已经允许操作系统使用。

误区 2:任务管理器显示“虚拟化已启用”,所以 VT-d 也已启用

不对。任务管理器该字段主要对应 VT-x/SVM。

误区 3:SLAT 就是 IOMMU

不对。Intel EPT、AMD NPT 面向 CPU 的虚拟机内存转换;VT-d/AMD IOMMU 面向设备 DMA。

误区 4:内核 DMA 保护关闭,就说明 VT-d 关闭

不一定。Windows 的 DMA 防护还有额外的平台、ACPI、端口和驱动要求。

误区 5:直接读取 MSR 才是唯一可靠方法

Intel 的 IA32_FEATURE_CONTROL、AMD 的 VM_CR 等寄存器确实能提供更底层的信息,但用户态程序不能直接安全读取这些 MSR,通常需要签名内核驱动。普通检测工具优先组合 Windows 官方 API、CPUID、Hypervisor 状态和 ACPI 表即可,不应为了一个状态查询加载来源不明或存在漏洞的驱动。

八、Windows PE 下怎么检测

在精简 Windows PE 中,任务管理器、msinfo32、PowerShell 和 WMI/CIM 可能不存在。更适合的方案是编写原生 x64 程序,直接使用:

  • CPUID:判断 VMX/SVM 硬件能力;
  • IsProcessorFeaturePresent(PF_VIRT_FIRMWARE_ENABLED):查询 Windows 暴露的固件虚拟化状态;
  • EnumSystemFirmwareTables('ACPI'):查找 DMAR/IVRS;
  • CPUID.1:ECX[31]:辅助识别 Hypervisor 环境。

这组方法不依赖 WMI 或 .NET,适合完整 Windows 与 WinPE 共用。不过,在虚拟机里的 PE 仍然只能看到虚拟固件和虚拟 CPU,无法绕过 Hypervisor 查询物理宿主机 BIOS。

总结

Windows 下识别虚拟化状态,最稳妥的思路不是寻找一个万能字段,而是组合证据:

VT-x / SVM:CPU 厂商 + CPUID 支持位 + Windows 固件标志 + Hypervisor 状态
VT-d / IOMMU:CPU 厂商 + ACPI DMAR/IVRS + Windows 内核 DMA 保护状态

对于日常排查,先看任务管理器和 msinfo32;对于批量检测、WinPE 或硬件采集程序,再使用原生 Windows API、CPUID 和 ACPI 表。这样既能避免把“支持”误认为“开启”,也不会把 Windows 某项安全功能的关闭误判为 IOMMU 本身关闭。

参考资料

© 版权声明
THE END
喜欢就支持一下吧
点赞15 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容