Skip to content

此方法目前仅测试了ArchLinux 7.0.3内核的GPU-Pv方法,可以简单尝试 #199

@Micro-ATP

Description

@Micro-ATP

旧方法:#67 不适用新内核,只能用旧内核,此方法现在可以适用于7.0.3内核,但是可能也只适用于7.0.x的内核,因为我只提取了7.0.x版本的组件。

Arch Linux Hyper-V 虚拟机部署 NVIDIA GPU-PV 完整教程

目标:让 Hyper-V 里的 Arch Linux 虚拟机 使用 Windows 宿主机的 NVIDIA GPU-PV,实现 /dev/dxgnvidia-smi、CUDA/NVML 正常工作。
本教程基于实际跑通环境整理:Arch Linux 7.0.3-arch1-1、NVIDIA RTX 4070 Ti SUPER、Windows Hyper-V、NVIDIA Windows 驱动 591.86、CUDA 显示 13.1


0. 总体原理

Hyper-V GPU-PV 不是传统 PCIe 直通,也不是在 Linux VM 里安装普通 nvidia 内核驱动。

整个方案由三部分组成:

Windows 宿主机:
  给虚拟机挂载 GpuPartitionAdapter

Arch Linux VM 内核侧:
  编译并加载 dxgkrnl 模块,生成 /dev/dxg

Arch Linux VM 用户态:
  使用 WSL GPU-PV runtime + 本机 NVIDIA DriverStore 里的用户态驱动库

最终成功标准:

lsmod | grep dxg
ls -l /dev/dxg
nvidia-smi

应看到:

dxgkrnl 已加载
/dev/dxg 存在
nvidia-smi 正常显示 NVIDIA GPU
CUDA Version 正常

1. 环境要求

1.1 Windows 宿主机

需要:

Windows 10/11,支持 Hyper-V
Hyper-V 已启用
NVIDIA Windows 驱动已安装
GPU 支持 GPU-PV
管理员 PowerShell

建议先确认 WSL/GPU 能在宿主机环境正常工作,但本教程的 WSL runtime 文件不要求每个用户本机额外提取。

1.2 Arch Linux VM

本教程实际跑通内核:

7.0.3-arch1-1

虚拟机建议:

Generation 2 VM
Secure Boot 关闭
Dynamic Memory 关闭
Checkpoint 关闭

2. Windows 宿主机配置 GPU-PV

以下命令都在 管理员 PowerShell 执行。

2.1 设置虚拟机名称

Arch-test 改成你自己的 Hyper-V 虚拟机名称:

$vm = "Arch-test"

2.2 关闭虚拟机

添加 GPU-PV adapter 必须在虚拟机关机状态下执行。

Stop-VM -Name $vm -Force
Get-VM -Name $vm | Select-Object Name, State

确认:

State : Off

2.3 关闭 Secure Boot、动态内存和检查点

Set-VMFirmware -VMName $vm -EnableSecureBoot Off
Set-VMMemory -VMName $vm -DynamicMemoryEnabled $false
Set-VM -VMName $vm -CheckpointType Disabled

检查:

Get-VMFirmware -VMName $vm | Select-Object VMName, SecureBoot
Get-VMMemory -VMName $vm | Select-Object VMName, DynamicMemoryEnabled
Get-VM -Name $vm | Select-Object Name, CheckpointType

期望结果:

SecureBoot           Off
DynamicMemoryEnabled False
CheckpointType       Disabled

2.4 查看可 GPU-PV 的 GPU

Get-VMHostPartitionableGpu | Format-List *

如果机器同时有 AMD 核显和 NVIDIA 独显,通常会看到:

VEN_1002 = AMD
VEN_10DE = NVIDIA

本教程用于 NVIDIA CUDA,所以选择 VEN_10DE

2.5 给 VM 绑定 NVIDIA GPU-PV adapter

Remove-VMGpuPartitionAdapter -VMName $vm -ErrorAction SilentlyContinue

$nvidiaGpu = Get-VMHostPartitionableGpu |
    Where-Object { $_.Name -like "*VEN_10DE*" } |
    Select-Object -First 1

$nvidiaGpu.Name

Add-VMGpuPartitionAdapter -VMName $vm -InstancePath $nvidiaGpu.Name

检查:

Get-VMGpuPartitionAdapter -VMName $vm | Select-Object VMName, InstancePath

InstancePath 应包含:

VEN_10DE

2.6 设置 GPU-PV 分区参数和 MMIO

Set-VMGpuPartitionAdapter -VMName $vm `
  -MinPartitionVRAM 1 `
  -MaxPartitionVRAM 1000000000 `
  -OptimalPartitionVRAM 1000000000 `
  -MinPartitionEncode 1 `
  -MaxPartitionEncode 18446744073709551615 `
  -OptimalPartitionEncode 18446744073709551615 `
  -MinPartitionDecode 1 `
  -MaxPartitionDecode 1000000000 `
  -OptimalPartitionDecode 1000000000 `
  -MinPartitionCompute 1 `
  -MaxPartitionCompute 1000000000 `
  -OptimalPartitionCompute 1000000000

Set-VM -GuestControlledCacheTypes $true -VMName $vm
Set-VM -LowMemoryMappedIoSpace 1GB -VMName $vm
Set-VM -HighMemoryMappedIoSpace 32GB -VMName $vm

检查:

Get-VMGpuPartitionAdapter -VMName $vm | Format-List VMName,InstancePath,*Partition*

2.7 启动虚拟机

Start-VM -Name $vm
Get-VM -Name $vm | Select-Object Name, State

3. Arch Linux VM 安装编译依赖

进入 Arch Linux VM 后执行:

uname -r

本教程示例:

7.0.3-arch1-1

安装依赖:

sudo pacman -Syu
sudo pacman -S --needed base-devel git dkms linux-headers linux-api-headers pahole curl

检查内核和 headers 是否匹配:

uname -r
pacman -Q linux linux-headers dkms
test -d /usr/lib/modules/$(uname -r)/build && echo "headers OK" || echo "headers MISSING"

期望:

headers OK

如果 linuxlinux-headers 版本不一致,先重启到新内核后再继续。


4. 编译并修补 dxgkrnl DKMS

4.1 下载 Arch 版 dxgkrnl DKMS 包

mkdir -p ~/build
cd ~/build

git clone https://github.com/ssxwcz/dxgkrnl-dkms-git.git
cd dxgkrnl-dkms-git

makepkg -si

在 Arch 7.0.3-arch1-1 上,首次 DKMS 编译可能失败,这是预期内情况。后面需要手动修补源码。

4.2 设置源码变量

DXG_SRC=$(ls -d /usr/src/dxgkrnl-* | sort | tail -n1)
DXG_VER=${DXG_SRC##*/dxgkrnl-}

echo "$DXG_SRC"
echo "$DXG_VER"

示例:

/usr/src/dxgkrnl-a07f9ea
a07f9ea

4.3 修补 Makefile include 路径

如果遇到:

fatal error: uapi/misc/d3dkmthk.h: No such file or directory

执行:

sudo cp "$DXG_SRC/Makefile" "$DXG_SRC/Makefile.bak"

grep -q 'ccflags-y.*$(src)/include' "$DXG_SRC/Makefile" || \
  echo 'ccflags-y += -I$(src)/include' | sudo tee -a "$DXG_SRC/Makefile"

4.4 修补 __get_task_comm

如果遇到:

implicit declaration of function ‘__get_task_comm’

执行:

sudo cp "$DXG_SRC/dxgvmbus.c" "$DXG_SRC/dxgvmbus.c.bak"

sudo sed -i \
  's/__get_task_comm(s, WIN_MAX_PATH, current);/get_task_comm(s, current);/' \
  "$DXG_SRC/dxgvmbus.c"

确认:

grep -n "get_task_comm" "$DXG_SRC/dxgvmbus.c"

应看到:

get_task_comm(s, current);

4.5 修补 dma_fence API 变化

Arch 7.0.3 上可能遇到:

__dma_fence_is_later 参数不兼容
const struct dma_fence_ops 没有 fence_value_str
const struct dma_fence_ops 没有 timeline_value_str

执行:

sudo cp "$DXG_SRC/dxgsyncfile.c" "$DXG_SRC/dxgsyncfile.c.bak"

sudo perl -0pi -e \
  's/return __dma_fence_is_later\(syncpoint->fence_value,\s*fence->seqno,\s*fence->ops\);/return __dma_fence_is_later(fence, syncpoint->fence_value, fence->seqno);/s' \
  "$DXG_SRC/dxgsyncfile.c"

sudo sed -i '/\.fence_value_str = dxgdmafence_value_str,/d' "$DXG_SRC/dxgsyncfile.c"
sudo sed -i '/\.timeline_value_str = dxgdmafence_timeline_value_str,/d' "$DXG_SRC/dxgsyncfile.c"

确认:

sed -n '440,485p' "$DXG_SRC/dxgsyncfile.c"

关键行应变成:

return __dma_fence_is_later(fence, syncpoint->fence_value, fence->seqno);

4.6 重新安装 DKMS 模块

sudo dkms remove dxgkrnl/"$DXG_VER" -k "$(uname -r)" --force || true
sudo dkms install dxgkrnl/"$DXG_VER" -k "$(uname -r)"

成功时应看到:

Building module(s)... done.
Installing /usr/lib/modules/.../updates/dkms/dxgkrnl.ko.zst
Running depmod... done.

4.7 加载 dxgkrnl

sudo modprobe dxgkrnl
lsmod | grep dxg
ls -l /dev/dxg

期望看到:

dxgkrnl ...
crw-rw-rw- ... /dev/dxg

设置开机自动加载:

echo dxgkrnl | sudo tee /etc/modules-load.d/dxgkrnl.conf

可查看日志:

sudo dmesg | grep -Ei "dxg|vmbus|hyperv" | tail -120

只要看到类似:

hv_vmbus: registering driver dxgkrnl

就说明内核侧基本正常。


5. 下载 WSL GPU-PV Runtime 资源

本教程不要求用户自己安装或升级 WSL 来提取 runtime 文件。直接下载已经整理好的 WSL GPU-PV runtime 包:

https://github.com/Micro-ATP/wsl-gpupv-runtime/releases/download/7.0.3/wsl-gpupv-runtime.tar

该包包含:

metadata
ProgramFiles-WSL-lib
System32-lxss-lib

不包含:

NVIDIA DriverStore
C:\Windows\System32\DriverStore\FileRepository\nv_dispi.inf_amd64_xxxxx

NVIDIA DriverStore 必须从用户自己的 Windows 宿主机提取。

5.1 在 Arch VM 中下载并解压

mkdir -p ~/wsl-gpupv-runtime
cd ~/wsl-gpupv-runtime

curl -L -o wsl-gpupv-runtime.tar \
  "https://github.com/Micro-ATP/wsl-gpupv-runtime/releases/download/7.0.3/wsl-gpupv-runtime.tar"

tar -xf wsl-gpupv-runtime.tar

检查目录结构:

find . -maxdepth 2 -type d | sort

应看到:

./metadata
./ProgramFiles-WSL-lib
./System32-lxss-lib

如果 tar 包解压后多了一层 wsl-gpupv-runtime/ 目录,则后续路径按实际情况调整。

5.2 安装 WSL runtime 到 /usr/lib/wsl/lib

sudo rm -rf /usr/lib/wsl/lib
sudo mkdir -p /usr/lib/wsl/lib

sudo cp -a ~/wsl-gpupv-runtime/ProgramFiles-WSL-lib/. /usr/lib/wsl/lib/
sudo cp -a ~/wsl-gpupv-runtime/System32-lxss-lib/. /usr/lib/wsl/lib/

sudo chown -R root:root /usr/lib/wsl
sudo chmod -R 755 /usr/lib/wsl/lib

创建软链接:

cd /usr/lib/wsl/lib

sudo ln -sf libd3d12core.so libD3D12Core.so
sudo ln -sf libcuda.so libcuda.so.1
sudo ln -sf libnvidia-ml.so.1 libnvidia-ml.so

检查:

ls -lah /usr/lib/wsl/lib | grep -E "libd3d12|libdxcore|libcuda|libnvidia-ml|nvidia-smi"

6. 从本机 Windows 提取 NVIDIA DriverStore

WSL runtime 包不能替代 NVIDIA DriverStore。NVIDIA 驱动文件必须和用户自己的 GPU 型号、Windows NVIDIA 驱动版本匹配。

以下命令在 Windows 管理员 PowerShell 执行。

6.1 设置 SSH 目标

将用户名和 IP 改成自己的 Arch VM:

$user = "atp"
$ip = "10.0.0.100"

6.2 找到 NVIDIA DriverStore 目录

Get-CimInstance Win32_VideoController |
  Select-Object Name, AdapterCompatibility, InstalledDisplayDrivers |
  Format-List

然后自动提取 NVIDIA 路径:

$nvDriverFiles = (Get-CimInstance Win32_VideoController |
  Where-Object { $_.AdapterCompatibility -match "NVIDIA" }).InstalledDisplayDrivers

if (-not $nvDriverFiles) {
    throw "没有找到 NVIDIA 显卡驱动"
}

$nvDriverDir = ($nvDriverFiles -split "," |
  Select-Object -First 1 |
  Split-Path -Parent)

$nvDriverLeaf = Split-Path $nvDriverDir -Leaf

$nvDriverDir
$nvDriverLeaf

路径类似:

C:\Windows\System32\DriverStore\FileRepository\nv_dispi.inf_amd64_xxxxx

6.3 打包并复制到 Arch VM

直接 scp -r DriverStore 目录可能失败,推荐先 tar:

$tarPath = "$env:TEMP\$nvDriverLeaf.tar"

Remove-Item $tarPath -Force -ErrorAction SilentlyContinue

tar -cf $tarPath -C "C:\Windows\System32\DriverStore\FileRepository" $nvDriverLeaf

Get-Item $tarPath | Select-Object FullName, Length

ssh "${user}@${ip}" "mkdir -p ~/gpu-pv-files/drivers"
scp $tarPath "${user}@${ip}:~/gpu-pv-files/drivers/"

6.4 在 Arch VM 解压 DriverStore

cd ~/gpu-pv-files/drivers

ls -lh

tar -xf *.tar

ls -lah
ls -lah nv_dispi.inf_amd64_* | head -80

7. 安装 NVIDIA DriverStore 到 /usr/lib/wsl/drivers

在 Arch VM 执行:

sudo rm -rf /usr/lib/wsl/drivers
sudo mkdir -p /usr/lib/wsl/drivers

sudo cp -a ~/gpu-pv-files/drivers/nv_dispi.inf_amd64_*/. /usr/lib/wsl/drivers/

sudo chown -R root:root /usr/lib/wsl/drivers
sudo chmod -R 755 /usr/lib/wsl/drivers

创建 NVIDIA 软链接:

cd /usr/lib/wsl/drivers

sudo ln -sf libcuda.so.1.1 libcuda.so
sudo ln -sf libcuda.so.1.1 libcuda.so.1
sudo ln -sf libnvidia-ml.so.1 libnvidia-ml.so
sudo ln -sf libnvidia-encode.so.1 libnvidia-encode.so
sudo ln -sf libnvcuvid.so.1 libnvcuvid.so
sudo ln -sf libnvidia-opticalflow.so.1 libnvidia-opticalflow.so
sudo ln -sf libnvdxgdmal.so.1 libnvdxgdmal.so

检查关键文件:

ls -lah /usr/lib/wsl/drivers | grep -E "libcuda|libnvidia-ml|libnvdxgdmal|nvidia-smi|gsp_"

8. 设置动态库搜索顺序

/usr/lib/wsl/drivers 必须排在 /usr/lib/wsl/lib 前面:

printf "/usr/lib/wsl/drivers\n/usr/lib/wsl/lib\n" | sudo tee /etc/ld.so.conf.d/ld.wsl.conf
sudo ldconfig

ldconfig 可能提示:

ldconfig: /usr/lib/wsl/drivers/libnvidia-ml.so.1 is not a symbolic link

一般可以忽略。

但是,ldconfig 可能把:

/usr/lib/wsl/drivers/libcuda.so.1

改回:

libcuda_loader.so

这会导致:

CUDA Version: ERR!

所以运行 ldconfig 后要修正:

cd /usr/lib/wsl/drivers

sudo ln -sfn libcuda.so.1.1 libcuda.so
sudo ln -sfn libcuda.so.1.1 libcuda.so.1

设置默认 nvidia-smi

sudo ln -sf /usr/lib/wsl/drivers/nvidia-smi /usr/local/bin/nvidia-smi

测试:

ls -l /dev/dxg
readlink -f /usr/lib/wsl/drivers/libcuda.so.1
nvidia-smi

期望看到:

/dev/dxg 存在
/usr/lib/wsl/drivers/libcuda.so.1.1
nvidia-smi 正常显示 GPU
CUDA Version 正常

9. 创建 systemd 服务,自动修复 libcuda symlink

为了防止 ldconfig 或系统更新后把 libcuda.so.1 改回 libcuda_loader.so,创建一个开机修复服务。

9.1 创建修复脚本

sudo tee /usr/local/sbin/fix-wsl-gpupv-libcuda.sh >/dev/null <<'EOF'
#!/usr/bin/env bash
set -e

cd /usr/lib/wsl/drivers

ln -sfn libcuda.so.1.1 libcuda.so
ln -sfn libcuda.so.1.1 libcuda.so.1
ln -sfn libnvidia-ml.so.1 libnvidia-ml.so
ln -sfn libnvidia-encode.so.1 libnvidia-encode.so
ln -sfn libnvcuvid.so.1 libnvcuvid.so
ln -sfn libnvidia-opticalflow.so.1 libnvidia-opticalflow.so
ln -sfn libnvdxgdmal.so.1 libnvdxgdmal.so
EOF

sudo chmod +x /usr/local/sbin/fix-wsl-gpupv-libcuda.sh

9.2 创建 systemd service

sudo tee /etc/systemd/system/wsl-gpupv-fix.service >/dev/null <<'EOF'
[Unit]
Description=Fix WSL GPU-PV NVIDIA library symlinks
After=systemd-modules-load.service
Requires=systemd-modules-load.service

[Service]
Type=oneshot
ExecStart=/usr/local/sbin/fix-wsl-gpupv-libcuda.sh
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload
sudo systemctl enable --now wsl-gpupv-fix.service

检查:

systemctl status wsl-gpupv-fix.service --no-pager
ls -lh /usr/lib/wsl/drivers/libcuda.so /usr/lib/wsl/drivers/libcuda.so.1
nvidia-smi

期望:

wsl-gpupv-fix.service active (exited)
libcuda.so -> libcuda.so.1.1
libcuda.so.1 -> libcuda.so.1.1
CUDA Version 正常

10. 重启验证持久化

sudo reboot

重新 SSH 进入 Arch VM 后执行:

uname -r
lsmod | grep dxg
ls -l /dev/dxg
systemctl status wsl-gpupv-fix.service --no-pager
readlink -f /usr/lib/wsl/drivers/libcuda.so.1
nvidia-smi

全部正常时应看到:

内核版本正常
dxgkrnl 已加载
/dev/dxg 存在
wsl-gpupv-fix.service active (exited)
/usr/lib/wsl/drivers/libcuda.so.1.1
nvidia-smi 正常
CUDA Version 正常

11. 常见问题排查

11.1 /dev/dxg 不存在

检查:

lsmod | grep dxg
sudo modprobe dxgkrnl
sudo dmesg | grep -Ei "dxg|vmbus|hyperv" | tail -120

Windows 侧检查:

Get-VMGpuPartitionAdapter -VMName "Arch-test" | Format-List *

常见原因:

VM 没有关机添加 GPU-PV adapter
没有选择 NVIDIA VEN_10DE
Secure Boot 没关
dxgkrnl DKMS 没有成功编译
内核更新后模块没有重建

11.2 nvidia-smi 报 Driver Not Loaded

优先检查库顺序:

cat /etc/ld.so.conf.d/ld.wsl.conf

必须是:

/usr/lib/wsl/drivers
/usr/lib/wsl/lib

检查 symlink:

readlink -f /usr/lib/wsl/drivers/libcuda.so.1

应是:

/usr/lib/wsl/drivers/libcuda.so.1.1

如果不是:

sudo systemctl restart wsl-gpupv-fix.service

11.3 nvidia-smi 能跑但 CUDA Version 是 ERR!

通常是 libcuda.so.1 被指向了 libcuda_loader.so

修复:

cd /usr/lib/wsl/drivers

sudo ln -sfn libcuda.so.1.1 libcuda.so
sudo ln -sfn libcuda.so.1.1 libcuda.so.1

nvidia-smi

如果之前刚执行过:

sudo ldconfig

则建议:

sudo systemctl restart wsl-gpupv-fix.service

11.4 Arch 更新内核后失效

检查:

uname -r
dkms status
lsmod | grep dxg
ls -l /dev/dxg
nvidia-smi

如果 DKMS 没有自动构建:

sudo find /var/lib/dkms -name make.log -print -exec tail -200 {} \;

根据日志继续修补。

11.5 Windows NVIDIA 驱动更新后失效

NVIDIA DriverStore 目录名可能变化,例如:

nv_dispi.inf_amd64_xxxxx

需要重新按第 6 节提取本机 DriverStore,并覆盖安装到:

/usr/lib/wsl/drivers

然后执行:

printf "/usr/lib/wsl/drivers\n/usr/lib/wsl/lib\n" | sudo tee /etc/ld.so.conf.d/ld.wsl.conf
sudo ldconfig
sudo systemctl restart wsl-gpupv-fix.service
nvidia-smi

12. 注意事项

  1. 添加 GPU-PV adapter 时 VM 必须关机。

  2. Arch VM 里不要安装普通 NVIDIA Linux 驱动。

    不建议安装:

    sudo pacman -S nvidia nvidia-dkms nvidia-utils

    GPU-PV 用的是 /dev/dxg 和 WSL/Windows 用户态库,不是传统 Linux NVIDIA 内核模块。

  3. /usr/lib/wsl/drivers 必须排在 /usr/lib/wsl/lib 前面。

    否则容易加载到 WSL runtime 里的 stub 库,导致:

    Driver Not Loaded
    
  4. 不要把 NVIDIA DriverStore 做成通用包分享。

    NVIDIA DriverStore 必须来自用户自己的 Windows 宿主机,原因包括:

    GPU 型号不同
    驱动版本不同
    CUDA/NVML 版本不同
    nv_dispi.inf_amd64_xxxxx 目录不同
    
  5. 本教程的 WSL runtime 包只解决 WSL 专属 runtime 文件问题。

    下载地址:

    https://github.com/Micro-ATP/wsl-gpupv-runtime/releases/download/7.0.3/wsl-gpupv-runtime.tar
    

    这个包不包含 NVIDIA DriverStore。

  6. 运行 sudo ldconfig 后建议重启修复服务。

    sudo systemctl restart wsl-gpupv-fix.service
  7. nvidia-smi 成功是基础验证。

    后续还应测试实际工作负载,例如:

    PyTorch CUDA
    CUDA samples
    llama.cpp CUDA backend
    其他 AI 推理程序
    

13. 最终成功示例

7.0.3-arch1-1
dxgkrnl               319488  0
crw-rw-rw- 1 root root 10, 262 /dev/dxg
wsl-gpupv-fix.service active (exited)
/usr/lib/wsl/drivers/libcuda.so.1.1
NVIDIA-SMI 590.57
Driver Version: 591.86
CUDA Version: 13.1
NVIDIA GeForce RTX 4070 Ti SUPER

至此,Arch Linux Hyper-V 虚拟机 NVIDIA GPU-PV 部署完成。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions