在 FreeBSD Linuxulator 中运行NVIDIA Cuda
我在构建 FreeBSD机器学习 环境,一直没有解决 在bhyve中实现NVIDIA GPU passthrough ,但是发现基于 Linuxulator 是一种FreeBSD平台特有的解决方案:
linuxulator思路
PyTorch and Stable Diffusion on FreeBSD 思路相同,通过结合FreeBSD nvidia-driver 和 Linuxulator 运行Linux版本CUDA来实现一个机器学习环境:
FreeBSD Host主机安装
nvidia-driver(NVIDIA公司为FreeBSD提供了原生的驱动,但是没有提供CUDA)安装 libc6-shim ( 会同时 依赖安装
nvidia-driver和linux-nvidia-libs)来获取nvidia-sglrun(能够提供CUDA)接下来就可以安装
miniconda以及运行 Pytorch 和 Stable Diffusion模型方法
备注
另一种解决思路是进一步使用 FreeBSD Linux Jail 来构建隔离的 Linuxulator 运行环境: 在FreeBSD Linux Jail中运行NVIDIA Cuda
其实方案的核心都是使用 Linuxulator 来实现Linux CUDA运行在FreeBSD nvidia-driver 上,性能和稳定性会受到一定影响,但是终究还是能够实 FreeBSD机器学习 环境。使用 FreeBSD Linux Jail 比直接使用 Linuxulator 的环境更干净隔离一些,其他差别不大。
两种方案各有优势:
采用 Linuxulator 对于使用者来说还是直面FreeBSD,使用感受较好,也可以少安装一些环境依赖降低系统复杂度
采用 FreeBSD Linux Jail 则提供了隔离且模拟的Linux运行环境,相当于使用了Linux容器(比喻不当),而且在Linux Jail基础上采用 podman (推测待实践)来部署OCI标准运行时,可以进一步实现 Kubernetes 计算节点
BIOS开启 Above 4G Decoding BIOS设置
备注
对于大于8G显存的GPU卡,需要开启 Above 4G Decoding BIOS设置 才能正常工作。本步骤是基于 在FreeBSD Linux Jail中运行NVIDIA Cuda 实践问题排查解决所总结的前置步骤。
如果不启用 Above 4G Decoding BIOS设置 ,那么NVIDIA GPU初始化可能失败,系统日志 dmesg 显示:
dmesg 显示分配BAR错误nvidia0: <Unknown> on vgapci0
vgapci0: child nvidia0 requested pci_enable_io
vgapci0: 0x800000000 bytes of rid 0x14 res 3 failed (0, 0xffffffffffffffff).
nvidia0: NVRM: NVIDIA MEM resource alloc failed, BAR1 @ 0x14.
nvidia0: NVRM: NVIDIA hardware alloc failed.
device_attach: nvidia0 attach returned 6
在 Above 4G Decoding BIOS设置 针对我的 纳斯NASSE C246 ITX主板 需要配置2个BIOS位置:
Above 4G Decoding
above 4GB mmio BIOS Assignment
linuxulator实现CUDA实践
NVIDIA为FreeBSD提供了原生的 nvidia-driver 驱动,所以方案类似 Docker运行NVIDIA容器 ,首先在FreeBSD Host中安装 nvidia-driver 以及支持 Linuxulator 运行模拟Linux驱动的 linux-nvidia-libs 库文件(我理解是将Linux层调用Linux版本 nvidia-driver 的API转换成调用FreeBSD版本 nvidia-driver )。此外,附加安装 libc6-shim 能够获得一个 nv-sglrun 工具来包装使用CUDA:
nvidia-driver (原生) 和 CUDA (Linux版)pkg install nvidia-driver linux-nvidia-libs libc6-shim
手工加载 NVIDIA 驱动:
kldload nvidia
此时检查 kldstat | grep nvidia 看到有一个内核模块加载:
kldstat 输出中有 nvidiakldstat | grep nvidia
需要配置系统启动时自动加载
nvidia-devier,设置/boot/loader.conf:
/boot/loader.conf# NVIDIA
nvidia_load="YES"
警告
我遇到一个非常奇怪的问题,在 /boot/loader.conf 添加了 nvidia_load="YES" ,但是重启没有自动加载 nvidia 驱动,而是启动后每次都需要手工执行 kldload nvidia 加载。这让我很困惑,参考 Loading kernel modules automatically 似乎是配置文件有隐含特殊字符导致的,但是我没有找到解决方法。
输出显示:
kldstat 输出中有 nvidia22 1 0xffffffff83800000 604e158 nvidia.ko
在FreeBSD Host主机上执行
nvidia-smi此时就看到正常的输出信息(表明 Nvidia Tesla P10 GPU运算卡 已经工作正常:
nvidia-smi 输出显示GPU工作正常Fri Sep 26 19:51:25 2025
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 580.82.07 Driver Version: 580.82.07 CUDA Version: N/A |
+-----------------------------------------+------------------------+----------------------+
| GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. |
| | | MIG M. |
|=========================================+========================+======================|
| 0 NVIDIA Graphics Device Off | 00000000:01:00.0 Off | 0 |
| N/A 32C P0 36W / 150W | 0MiB / 23040MiB | 2% Default |
| | | N/A |
+-----------------------------------------+------------------------+----------------------+
+-----------------------------------------------------------------------------------------+
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
|=========================================================================================|
| No running processes found |
+-----------------------------------------------------------------------------------------+
注意,这里输出信息中仅显示 Driver Version: 580.82.07 ,而CUDA版本是空白的 CUDA Version: N/A 。这时因为当前使用的 nvidia-smi 仅仅是FreeBSD原生的 nvidia-driver
通过
nv-sglrun运行nvidia-smi则是执行Linux程序(通过 Linuxulator ),会通过CUDA,此时会看到CUDA版本信息:
nv-sglrun 运行 nvidia-sminv-sglrun nvidia-smi
输出信息:
nv-sglrun 运行 nvidia-smi 输出信息中有CUDA版本信息/usr/local/lib/libc6-shim/libc6.so: shim init
/usr/local/lib/libc6-shim/libc6.so: unable to load libinotify.so.0 (Shared object "libinotify.so.0" not found, required by "nvidia-smi")
Fri Sep 26 19:53:59 2025
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 580.82.07 Driver Version: 580.82.07 CUDA Version: 13.0 |
+-----------------------------------------+------------------------+----------------------+
| GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. |
| | | MIG M. |
|=========================================+========================+======================|
| 0 NVIDIA Graphics Device Off | 00000000:01:00.0 Off | 0 |
| N/A 33C P0 36W / 150W | 0MiB / 23040MiB | 0% Default |
| | | N/A |
+-----------------------------------------+------------------------+----------------------+
+-----------------------------------------------------------------------------------------+
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
|=========================================================================================|
| No running processes found |
+-----------------------------------------------------------------------------------------+
shim
备注
shkhln开发了一个 uvm_ioctl_override.c 工具提供了用于Linux二进制程序的shim,能够在FreeBSD中包装使用CUDA
编译shim : 在 uvm_ioctl_override.c 提供
安装
Rocky Linux 9开发工具(在 Linuxulator 快速起步 中已经安装过linux_base-rl9Rocky Linux 9 userland):
pkg install linux-rl9-devtools
这样在Host主机的 /compat/linux/bin/cc 就是 Rocky Linux 9 提供的 gcc11
获取
uvm_ioctl_override.c:
uvm_ioctl_override.cfetch https://gist.githubusercontent.com/shkhln/40ef290463e78fb2b0000c60f4ad797e/raw/f640983249607e38af405c95c457ce4afc85c608/uvm_ioctl_override.c
编译:
uvm_ioctl_override.c /compat/linux/bin/cc --sysroot=/compat/linux -m64 -std=c99 -Wall -ldl -fPIC -shared -o dummy-uvm.so uvm_ioctl_override.c
初始化设置
初始化设置需要2个步骤:
安装缺失的软件包
linux-rl9-libglvnd(针对Rocky Linux 9,早期针对CentOS 7则安装linux-c7-libglvnd),目的是获取libGL.so.1:
linux-rl9-libglvnd 获取 libGL.so.1pkg install linux-rl9-libglvnd
建立
/sbin/md5软链接: FreeBSD 13.1开始提供/sbin/md5sum,installer需要该执行程序,所以比较可靠的方式是在~/bin目录建立软链接:
/sbin/md5sum 软链接mkdir -p ~/bin
ln -sf /sbin/md5 ~/bin/md5sum
安装路径
设置一个安装路径用于所有的Linux程序安装,我使用 ${linux_dir} 作为存放所有Linux程序的基础目录(原文采用 ${BASE_PATH} 环境变量):
${linux_dir} 作为存放所有Linux程序的基础目录export linux_dir="zdata/linux"
echo 'export linux_dir="zdata/linux"' >> ~/.shrc
# ZFS
zfs create zdata/linux
Conda
备注
Install minianaconda on FreeBSD 提到直接下载官方 Miniconda3-latest-Linux-x86_64.sh 进行安装:
Miniconda installer for Linux 最新版本进行安装fetch https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh
chmod +x Miniconda3-latest-Linux-x86_64.sh
./Miniconda3-latest-Linux-x86_64.sh
但我实践发现也同样报错 [PYI-15462:ERROR] Module object for struct is NULL! (见下文,可能是同时安装了 Python 3.12 和 3.11 导致的)
需要在FreeBSD系统中安装原生python,运行 Miniconda3-latest-Linux-x86_64.sh 会依赖本地安装的python来执行脚本内容:
# 找出发行版提供的python3相关版本命名
pkg search python3
# 安装 python 3.11
pkg install python311
备注
这里选择安装 python 3.11
原因 可能 是安装 python312 会同时安装 python311 ,似乎会导致 miniconda3 安装成勋报错:
miniconda 报错...
Do you accept the license terms? [yes|no]
>>> yes
Miniconda3 will now be installed into this location:
/root/miniconda3
- Press ENTER to confirm the location
- Press CTRL-C to abort the installation
- Or specify a different location below
[/root/miniconda3] >>> /${linux_dir}/conda
PREFIX=/zdata/linux/conda
Unpacking bootstrapper...
Unpacking payload...
[PYI-15660:ERROR] Module object for struct is NULL!
Traceback (most recent call last):
File "struct.py", line 13, in <module>
File "<frozen importlib._bootstrap>", line 1360, in _find_and_load
File "<frozen importlib._bootstrap>", line 1322, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 1262, in _find_spec
File "<frozen importlib._bootstrap_external>", line 1559, in find_spec
File "<frozen importlib._bootstrap_external>", line 1533, in _get_spec
File "<frozen importlib._bootstrap_external>", line 1636, in find_spec
File "<frozen importlib._bootstrap_external>", line 1679, in _fill_cache
OSError: [Errno 22] Invalid argument: '/zdata/linux/conda/install_tmp/_MEIV8CoEC/lib-dynload'
miniconda [PYI-15660:ERROR] Module object for struct is NULL! 错误是由于Python环境损坏或者混乱导致 PyInstaller 无法正确捆绑内置的 struct 模块。这个错误通常在 Conda 环境中使用 PyInstaller 时发生。
根据 linux-miniconda-installer Port details 说明,软件包依赖 lang/python311
PyTorch and Stable Diffusion on FreeBSD 使用 pkg 安装Linux Conda( miniconda ):
minicondapkg install linux-miniconda-installer
# 直接执行 miniconda-installer 会提示不可以root身份执行
# 改为 sudo -u admin miniconda-installer
# 则提示 miniconda-installer 需要参考 https://repo.anaconda.com/miniconda/ 指定安装版本
# 例如: /usr/local/bin/miniconda-installer 3.11 25.3.1-1
# sudo -u admin miniconda-installer 3.12 25.7.0-2
# 则直接因为指定了 python3.12 提示 This miniconda requires python3.12. Install lang/python312 and try again.
# 但如果安装 python3.12 会导致系统同时有2个python版本出现 [PYI-15660:ERROR] Module object for struct is NULL!
# 而且在安装了 python3.12 后执行 sudo -u admin miniconda-installer 3.12 25.7.0-2 (此时系统中有3.11和3.12两个Python)
# 显示报错 fetch: Miniconda3-py312_25.7.0-2-Linux-x86_64.sh: stat()
# 这其实就是python环境混乱导致PyInstaller无法绑定内置的struct模块
sudo -u admin miniconda-installer 3.11 25.7.0-2
# 还是报错 fetch: Miniconda3-py311_25.7.0-2-Linux-x86_64.sh: stat()
# 原来这个 miniconda-installer 只是拼凑一个下载,例如上文拼凑
# fetch: Miniconda3-py311_25.7.0-2-Linux-x86_64.sh: stat()
# 这是根据操作系统使用的python来下载安装包,所以改为执行
fetch https://repo.anaconda.com/miniconda/Miniconda3-py311_25.7.0-2-Linux-x86_64.sh
chmod +x Miniconda3-py311_25.7.0-2-Linux-x86_64.sh
#./Miniconda3-py311_25.7.0-2-Linux-x86_64.sh
./Miniconda3-py311_25.7.0-2-Linux-x86_64.sh -b -u -p /zdata/linux/conda
目前还存在的问题是
miniconda 依然报错PREFIX=/zdata/linux/conda
Unpacking bootstrapper...
Unpacking payload...
[PYI-16429:ERROR] Module object for struct is NULL!
Traceback (most recent call last):
File "struct.py", line 13, in <module>
File "<frozen importlib._bootstrap>", line 1360, in _find_and_load
File "<frozen importlib._bootstrap>", line 1322, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 1262, in _find_spec
File "<frozen importlib._bootstrap_external>", line 1559, in find_spec
File "<frozen importlib._bootstrap_external>", line 1533, in _get_spec
File "<frozen importlib._bootstrap_external>", line 1636, in find_spec
File "<frozen importlib._bootstrap_external>", line 1679, in _fill_cache
OSError: [Errno 22] Invalid argument: '/zdata/linux/conda/install_tmp/_MEIv1pXYW/lib-dynload'
google ai提示可能需要配置好Linux二进制兼容层: If the error persists, there may be a mismatch between the Conda-shipped libraries and the versions in your Linux base installation. Manually finding and replacing shared libraries is not recommended and is often a fragile fix.
想到既然我已经构建过 使用 ubuntu-base tgz 包部署Linux Jail Ubuntu ,那么先尝试在 FreeBSD Linux Jail 中安装 miniconda (反正也是集中在一个目录),然后将 conda 目录取出在Host的 Linuxulator 环境运行,看看问题到底在哪里。
参考
Davinci Resolve installed in Freebsd Jail 油管上NapoleonWils0n围绕FreeBSD有不少视频编码解码的解析,其中关于FreeBSD Jail运行Ubuntu来实现NVIDIA CUDA 文档见 DaVinci Resolve Freebsd
PyTorch and Stable Diffusion on FreeBSD 思路相同,通过结合FreeBSD
nvidia-driver和 Linuxulator 运行Linux版本CUDA来实现一个机器学习环境