官方全面叫做Deploy graphics devices using Discrete Device Assignment(使用离散设备分配部署图形设备)简称DDA 。
从 Windows Server 2016 开始,可以使用离散设备分配或DDA将整个PCIe设备传递到Hyper-V。这将允许从Hyper-V内部访问NVMe存储或图形卡等设备,同时能够利用设备本机驱动程序。一开始以为应该也挺简单的,但实际上还是踩了很多坑才最终弄好。

适用于:

Windows Server 2022、Microsoft Hyper-V Server 2016、Windows Server 2016、Windows Server 2019、Microsoft Hyper-V Server 2019 (Windows11应该也支持具体没测试)

步骤注意事项:

使用具有离散设备分配的设备有三个步骤:

为离散设备分配配置Hyper-V
从主机分区卸载设备
将设备分配到Hyper-V
所有命令都可以以管理员身份在 Windows PowerShell 控制台上的主机上执行。

关于Hyper-V方面请手动关闭虚拟机 设置-自动停止操作-强制关闭虚拟机。
如果存在还有检查点请手动全部删除 设置-检查点-关闭启动检查点。

如果你只有一张显卡可以直接跳转到完整示例查看完整代码。

参考文档:https://learn.microsoft.com/zh-cn/windows-server/virtualization/hyper-v/deploy/deploying-graphics-devices-using-dda

嵌套虚拟化

此办法用于虚拟化Hyper-V里面的虚拟机比如Windows11的安卓子系统,前提是需要物理机支持并且已经在bois开启了虚拟化。

参考资料:https://learn.microsoft.com/en-us/windows/wsl/troubleshooting#error-0x80370102-the-virtual-machine-could-not-be-started-because-a-required-feature-is-not-installed

Set-VMProcessor -VMName <VMName> -ExposeVirtualizationExtensions $true

 

完整示例

在此示例中,我们使用 PowerShell 配置名为“ddatest1”的虚拟机,使制造商NVIDIA提供的第一个GPU并将其分配到VM。

 

#设置需要直通的虚拟机名称
$vm = 	"ddatest1"
#将自动停止动作设置为关闭
Set-VM -Name $vm -AutomaticStopAction TurnOff
#在CPU上启用Write-Combining
Set-VM -GuestControlledCacheTypes $true -VMName $vm
#配置32位MMIO空间
Set-VM -LowMemoryMappedIoSpace 3Gb -VMName $vm
#配置大于32位MMIO空间
Set-VM -HighMemoryMappedIoSpace 33280Mb -VMName $vm

#查找位置路径并禁用设备
#枚举系统上的所有设备
$pnpdevs = Get-PnpDevice -presentOnly
#仅选择NVIDIA制造的显示设备
$gpudevs = $pnpdevs |where-object {$_.Class -like "Display" -and $_.Manufacturer -like "NVIDIA"}
#选择主机可以卸载的第一个设备的位置路径
$locationPath = ($gpudevs | Get-PnpDeviceProperty DEVPKEY_Device_LocationPaths).data[0]
#禁用设备
Disable-PnpDevice  -InstanceId $gpudevs[0].InstanceId

#从主机上卸载设备
Dismount-VMHostAssignableDevice -force -LocationPath $locationPath

#将设备分配给Hyper-V虚拟机
Add-VMAssignableDevice -LocationPath $locationPath -VMName $vm

 

步骤一获取设备路径:

设备路径在物理设备直通的过程中相当于设备的唯一描述符。下面的Powershell展示了如何获取名称以NVIDIA开头的设备的设备路径。

#获取所有名称以NVIDIA开头的设备

$pnpdevs = Get-PnpDevice -PresentOnly | Where-Object {$_.FriendlyName -like "NVIDIA*"}

#输出LocationPath

foreach ($pnpdev in $pnpdevs) {

$locationpath = ($pnpdev | get-pnpdeviceproperty DEVPKEY_Device_LocationPaths).data[0]

$pnpdev.FriendlyName + ": " + $locationpath

}

 

在我的机器上,可以得到下面的输出:

NVIDIA Tesla V100-SXM2-16GB: PCIROOT(0)#PCI(0300)#PCI(0000)#PCI(0C00)#PCI(0000)

NVIDIA Tesla V100-SXM2-16GB: PCIROOT(0)#PCI(0300)#PCI(0000)#PCI(0800)#PCI(0000)

NVIDIA Tesla V100-SXM2-16GB: PCIROOT(80)#PCI(0200)#PCI(0000)#PCI(0800)#PCI(0000)

NVIDIA Tesla V100-SXM2-16GB: PCIROOT(80)#PCI(0200)#PCI(0000)#PCI(0C00)#PCI(0000)

这个过程也可以通过设备管理器完成,如图所示:

步骤二:禁用设备

要被直通的物理设备将会被虚拟机独占使用,因此,操作系统需要确保宿主机没有其它应用在使用被直通的设备,因此在直通前禁用设备。

我们可以使用Disable-PnpDevice命令,通过设备的InstanceId来禁用设备。例如,在上文Powershell中获取$pnpdev对象后,继续执行:

disable-pnpdevice -InstanceId $pnpdev.InstanceId -Confirm:$false

这个过程同样可以通过设备管理器完成,如图所示:

步骤三:下线(Dismount)设备

这一步操作会将已经禁用的设备从操作系统中移除,使其变成可分配的状态。这一步只能通过Powershell完成。根据上面获得到的设备路径(Location Path),例如,”PCIROOT(0)#PCI(0300)#PCI(0000)#PCI(0C00)#PCI(0000)”,运行下面的命令:

Dismount-VmHostAssignableDevice -locationpath "PCIROOT(0)#PCI(0300)#PCI(0000)#PCI(0C00)#PCI(0000)" -force

这一步是最可能出现错误的。许多硬件上的不兼容都会在这个步骤报错。

成功执行此步操作后,宿主机上的设备管理器将无法查看到该设备。

步骤四:分配设备

假设前面的步骤都已完成,这个时候就已经可以将下线后的设备分配给虚拟机了。这一步依然只能通过Powershell完成。将GPU分配到名称为Test的虚拟机中的命令如下所示:

Add-VMAssignableDevice -LocationPath "PCIROOT(0)#PCI(0300)#PCI(0000)#PCI(0C00)#PCI(0000)" -VMName Test

如果到这一步依然没有任何错误,那么设备已经成功直通到了虚拟机上。你可以通过下面的Powershell检查:

Get-VMAssignableDevice -VMName Test

在我的机器上,可以得到下面的输出:

InstanceID : PCIP\VEN_10DE&DEV_1DB1&SUBSYS_121210DE&REV_A1\6&3D280D5&0&00600018

LocationPath : PCIROOT(0)#PCI(0300)#PCI(0000)#PCI(0C00)#PCI(0000)

ResourcePoolName : Primordial

Name : 虚拟 PCI Express 端口设置

Id : Microsoft:C3B8CA0E-F6DA-417C-B6D6-DD9D68F7D899\EAEE9BF9-B29B-4D2E-970B-325F02812E83

VMId : c3b8ca0e-f6da-417c-b6d6-dd9d68f7d899

VMName : Test

VMSnapshotId : 00000000-0000-0000-0000-000000000000

VMSnapshotName :

CimSession : CimSession: .

ComputerName : TRAIN

IsDeleted : False

VMCheckpointId : 00000000-0000-0000-0000-000000000000

VMCheckpointName :

GPU额外步骤一:合并缓存写入

对于GPU相比于一般的外部设备速度很快,这使得如果我们允许对CPU合并对GPU显存的写入操作以提升性能。以Test虚拟机为例,运行下面的Powershell:

Set-VM Test -GuestControlledCacheTypes $true

GPU额外步骤二:扩大内存映射IO空间(Memory Mapped IO Space)大小

GPU需要的MMIO空间通常较大,当一个虚拟机分配到的设备所需要的MMIO空间综合超过了Hyper-V为其默认提供的大小时,在虚拟机操作系统中就会提示“没有足够的系统资源”的错误。

你可以在设备管理器右键设备-属性中看到设备所需的MMIO空间,如图所示:

根据内存范围,我们可以算出一张V100所需的MMIO大小为16MB+16384MB+32MB,其中,32位地址空间内需求16MB,64位地址空间内需求16384MB+32MB=16416MB。目前一个新建的Hyper-V虚拟机默认只为32位和64位地址空间分别提供了128MB和512MB的MMIO空间大小,这导致V100直接分配到虚拟机中是无法使用的。

32位和64位地址空间的MMIO大小可以通过下面的Powershell来分别修改,以Test虚拟机为例:

Set-VM Test -LowMemoryMappedIoSpace 3Gb
Set-VM Test -HighMemoryMappedIoSpace 33280Mb

 

步骤五:驱动下载

以上步骤没问题后在nvidia官网下载对应驱动安装完成后重启就可以看到显卡了,ADM也是同理。
https://www.nvidia.cn/Download/index.aspx?lang=cn

删除设备并将其返回到主机

如果要将设备返回到其原始状态,则需要停止虚拟机并发出以下问题:

#从虚拟机中删除设备
Remove-VMAssignableDevice -LocationPath $locationPath -VMName VMName
#将设备装载回主机
Mount-VMHostAssignableDevice -LocationPath $locationPath

发表回复

后才能评论