时间轴
时间轴
2026-07-18
init
本文介绍了NVIDIA open-gpu-kernel-modules的编译方法,重点说明了使用ARM GNU工具链进行交叉编译的步骤与关键参数,包括ARCH=arm64与TARGET_ARCH=aarch64的区分、工具链路径设置及清理方式。文章还总结了该仓库的两层构建模型:由OS无关核心(src)与Linux内核适配层(kernel-open)拼装组合,最终生成5个内核模块,并概述了各模块的功能、代码量分布及GSP固件在架构演进中的核心作用。
源码
1 | git clone https://github.com/NVIDIA/open-gpu-kernel-modules.git |
交叉工具链
本文使用 Arm GNU Toolchain 11.2-2022.02(aarch64-none-linux-gnu-三元组)。
ARM目前总共发布了8种架构:ARMv1、ARMv2、ARMv3、ARMv4、ARMv5、ARMv6、ARMv7、ARMv8。
针对于支持ARMv8指令集的处理器可以使用-march=armv8-a参数编译代码,ARM GNU编译器可通过下面的链接下载
推荐使用ARM官网的编译器,它是Portable的,解压后即可使用。
本文使用的是11.2版本的交叉编译器
可以将其添加到环境变量
123 | # ~/.bashrc或~/.bash_profileemacs ~/.bashrcexport PATH="$HOME/tools/gcc-arm-11.2-2022.02-x86_64-aarch64-none-linux-gnu/bin:$PATH" |
使用11.2.1版本的aarch64-none-linux-gnu-gcc

如果工具链三元组是
aarch64-linux-gnu-(如 Ubuntu 的gcc-aarch64-linux-gnu包),把下面所有aarch64-none-linux-gnu-替换成aarch64-linux-gnu-即可。
编译
123456789101112131415 | make -j$(nproc) modules \ ARCH=arm64 \ CROSS_COMPILE=aarch64-none-linux-gnu- \ TARGET_ARCH=aarch64 \ TARGET_OS=Linux \ CC=aarch64-none-linux-gnu-gcc \ CXX=aarch64-none-linux-gnu-g++ \ LD=aarch64-none-linux-gnu-ld \ AR=aarch64-none-linux-gnu-ar \ STRIP=aarch64-none-linux-gnu-strip \ OBJCOPY=aarch64-none-linux-gnu-objcopy \ HOSTCC=gcc \ SYSSRC="$HOME/repository/linux/linux-5.10.238" \ SYSOUT="$HOME/repository/linux/linux-5.10.238" |
要点:
- ARCH=arm64 给 Kbuild,TARGET_ARCH=aarch64 给 NVIDIA 的 utils.mk(两者不能混)。
- 工具链通过 PATH + 显式 CC/CXX/LD/AR 双保险,因为 utils.mk 不读 CROSS_COMPILE。
- SYSSRC/SYSOUT 指向已用同一工具链配置好的 linux-5.10.238。
要清理的话:
1234 | make clean \ ARCH=arm64 \ SYSSRC="$HOME/repository/linux/linux-5.10.238" \ SYSOUT="$HOME/repository/linux/linux-5.10.238" |
12345678 | make -j$(nproc) modules \ ARCH=x86_64 \ TARGET_ARCH=x86_64 \ TARGET_OS=Linux \ CC=gcc CXX=g++ LD=ld AR=ar STRIP=strip OBJCOPY=objcopy \ HOSTCC=gcc \ SYSSRC="$HOME/repository/linux/linux-5.10.238-x86_64" \ SYSOUT="$HOME/repository/linux/linux-5.10.238-x86_64" |
说明
- 原生编译不需要 CROSS_COMPILE,工具用本机 gcc 即可。仍要显式传 CC/CXX/LD/AR,因为 utils.mk 不读 CROSS_COMPILE。
- 和 arm64 的区别只在 ARCH/TARGET_ARCH:arm64 时是 ARCH=arm64 + TARGET_ARCH=aarch64;x86_64 时两者都是 x86_64。注意 utils.mk 里没有叫 arm64 的 TARGET_ARCH,只有 aarch64。
清理
1234 | make clean \ ARCH=x86_64 \ SYSSRC="$HOME/repository/linux/linux-5.10.238-x86_64" \ SYSOUT="$HOME/repository/linux/linux-5.10.238-x86_64" |
目录结构
1. 顶层目录结构
12345678910 | open-gpu-kernel-modules/├── Makefile # 顶层入口:make modules → 先编译 src/ 再编译 kernel-open/├── utils.mk # NVIDIA 自有构建框架(CC/CXX/ARCH/对象规则等)├── version.mk # 版本定义(例如:NVIDIA_VERSION = 610.43.03)├── nv-compiler.sh # 探测编译器类型 (gcc/clang) 的脚本├── src/ # ① OS 无关核心驱动源码(freestanding,编译成 .o)├── kernel-open/ # ② Linux 内核适配层(Kbuild,编译成 .ko)├── nouveau/ # 从 nouveau 提取 GPU 固件的脚本(不是驱动本体)├── README.md / COPYING / SECURITY.md / CODE_OF_CONDUCT.md / CONTRIBUTING.md└── .github/ # CI 自动化配置 |
核心机制:两层构建模型
理解该仓库的关键在于其两层构建模型。这个仓库并不是一个单一的 Linux 内核模块,而是由 NVIDIA OS 无关核心 与 Linux 内核适配层 拼装组合,最终生成 5 个 .ko 模块。

第一层产物: 产生在
src/nvidia/_out/Linux_<ARCH>/nv-kernel.o。代码使用-ffreestanding和-fno-stack-protector编译,从而能在不同的操作系统(如 Linux、FreeBSD 等)间复用核心逻辑。第二层: 将第一层生成的 .o 文件当作“黑盒二进制”链接进最终的 .ko 模块中,并包装上 Linux 专属的钩子代码。
2. src: OS 无关核心
(约 211 万行)
123456789101112131415161718192021222324252627 | src/├── nvidia/ # ★ RM(资源管理器)核心,150 万行,仓库主体│ ├── src/kernel/ # 内核态驱动实现│ │ ├── gpu/ # GPU IP 分模块(详细见下文)│ │ ├── core/ # 核心框架(NVOC 对象系统、线程、调度)│ │ ├── rmapi/ # RM API(用户态 ioctl 入口)│ │ ├── mem_mgr/ # 内存管理│ │ └── os/ # OS 抽象层接口(由 kernel-open 实现)│ ├── inc/ # 头文件(与 src/ 结构镜像,外加 libraries/ containers/ mmu/ nvlog/ ...)│ ├── interface/ # 对外接口(rmapi, deprecated)│ ├── arch/nvalloc/ # CPU 架构相关代码(common / unix / x86emu)│ ├── generated/ # 自动生成的代码(NVOC 元数据等)│ └── _out/ # 编译输出目录(Linux_aarch64, Linux_x86_64)│├── nvidia-modeset/ # 显示 modeset 逻辑,10 万行│ └── src/ interface/ os-interface/ kapi/ lib/ include/│└── common/ # 跨模块共享代码,49 万行 ├── sdk/nvidia/inc/ # 公共 SDK 头文件 ├── nvswitch/ # NVSwitch 芯片驱动(lr10/ls10/soe/flcn/...) ├── nvlink/ # NVLink 高速互连 ├── displayport/ # DisplayPort 协议实现 ├── modeset/ # timing / hdmipacket ├── softfloat/ # 软浮点实现(Berkeley softfloat,8086-SSE 后端) ├── unix/ # nvidia-push / nvidia-3d / xzminidec / headsurface ├── uproc/os/ # 微处理器 OS 抽象(libos-v3.1.0) └── shared/ inc/ src/ # 公共工具与状态码 |
3.src/nvidia/src/kernel/gpu/子目录(GPU IP 引擎)
这是驱动最核心的硬件控制部分,按硬件引擎划分:
- gr/:Graphics(光栅化/着色/渲染核心)
- fifo/:命令提交队列管理
- ce/:Copy Engine(高性能内存拷贝引擎)
- intr/:中断处理
- sec2/:安全引擎
- falcon/:Falcon 微控制器核心框架
- gsp/:★ GSP(GPU System Processor) 核心
- fsp/:Firmware Security Processor
- gsplite/:轻量级 GSP 逻辑
- pmu/:性能监控单元
- nvdec/ nvenc/ nvjpg/ ofa/:视频编解码及光流加速引擎
- bif/ bus/:PCIe 总线接口及总线控制
- mem_mgr/ mem_sys/ mmu/ mig_mgr/:显存管理、MMU 页表、MIG 实例切分
- disp/:显示输出控制
- perf/ hwpm/ rc/ timer/ …:性能、硬件监控、Reset 恢复及定时器
架构演进背景: 现代 NVIDIA GPU 的 RM(资源管理器)核心主要运行在 GPU 内部的 GSP(一个 RISC-V 微处理器)上。src/nvidia 里的很大一部分代码实际上就是 GSP 固件本身的源码——这也是 NVIDIA 在 2020 年后逐步走向开源的关键底层演进。
4. kernel-open/ Linux 适配层
(约 22 万行)
1234567891011121314 | kernel-open/├── Kbuild # 模块组装入口:遍历导入所有子模块的 *.Kbuild├── Makefile # 被 Kbuild 调用,负责定位 Linux 内核源码树 (SYSSRC/SYSOUT)├── conftest.sh # ★ 核心机制:编译时动态探测内核 API├── conftest/ # conftest 的测试用例清单│ ├── compile-tests/ # "内核是否有符号 X / 结构体成员 Y" 的 C 源码│ └── header_presence/# "某头文件是否存在" 的检测├── common/inc/ # 适配层公共头文件│├── nvidia/ # → nvidia.ko 主驱动 Linux 钩子(nv.o, nv-pci.o, nv-acpi.o...)├── nvidia-modeset/ # → nvidia-modeset.ko 显示 modeset 钩子├── nvidia-drm/ # → nvidia-drm.ko DRM/KMS 标准图形框架适配├── nvidia-uvm/ # → nvidia-uvm.ko ★ 统一虚拟内存,15 万行(含按代际划分的硬件引用:ampere/turing/hopper/blackwell/rubin)└── nvidia-peermem/ # → nvidia-peermem.ko InfiniBand/RDMA peer-to-peer 内存支持 |
conftest.sh机制: 这是 NVIDIA 驱动能“一份源码兼容无数内核版本”的核心秘密。在编译前,它会针对目标内核进行大量的片段编译测试(例如检测是否存在 kmem_cache_create_usercopy、pgprot_t 等)。测试结果会被写入 conftest/headers.h,随后源码中通过#if NV_IS_ENABLED(...)宏来条件编译对应的兼容代码。
最终生成的内核模块
| 模块名称 | 主要作用 | 主要源码构成 |
|---|---|---|
nvidia.ko | 主驱动核心:创建/dev/nvidia*设备节点,提供核心 ioctl 业务入口。 | kernel-open/nvidia/+src/nvidia/编译出的nv-kernel.o |
nvidia-modeset.ko | 显示模式设置:控制分辨率、刷新率、多屏显示拼接等。 | kernel-open/nvidia-modeset/+src/nvidia-modeset/编译出的核心.o |
nvidia-drm.ko | DRM/KMS 集成:现代 Linux 图形栈(如 Wayland)必需的直接渲染管理器适配。 | kernel-open/nvidia-drm/ |
nvidia-uvm.ko | 统一虚拟内存管理:实现 CPU/GPU 内存统一寻址。HPC 和 AI 计算的核心,体积巨大。 | kernel-open/nvidia-uvm/(约 15 万行独立实现) |
nvidia-peermem.ko | RDMA P2P 支持:允许第三方 PCIe 设备(如 Mellanox 网卡)通过 GPUDirect 直接读写显存。 | kernel-open/nvidia-peermem/ |
代码量分布
1234567 | src/nvidia 150 万行 ████████████████████ ← RM/GSP 核心,绝对主体src/common 49 万行 ██████ ← 共享协议与芯片支持kernel-open/nvidia-uvm 15 万行 ██ ← UVM 独立计算大头src/nvidia-modeset 10 万行 █ ← 显示逻辑kernel-open/nvidia 5 万行 █ ← Linux 主驱动钩子kernel-open/nvidia-drm 1.7 万行 ← DRM 适配层其他 <1 万行 ← 构建脚本与配置 |
