Cover image for open-gpu-kernel-modules 编译

open-gpu-kernel-modules 编译

字数 2.2k
阅读
访客

时间轴

时间轴

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.02aarch64-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-none-linux-gnu-gcc
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"

要点:

  1. ARCH=arm64 给 Kbuild,TARGET_ARCH=aarch64 给 NVIDIA 的 utils.mk(两者不能混)。
  2. 工具链通过 PATH + 显式 CC/CXX/LD/AR 双保险,因为 utils.mk 不读 CROSS_COMPILE。
  3. 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"

说明

  1. 原生编译不需要 CROSS_COMPILE,工具用本机 gcc 即可。仍要显式传 CC/CXX/LD/AR,因为 utils.mk 不读 CROSS_COMPILE。
  2. 和 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 模块。

nvidia-two-layer-build.drawio
nvidia-two-layer-build.drawio

  • 第一层产物: 产生在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.koDRM/KMS 集成:现代 Linux 图形栈(如 Wayland)必需的直接渲染管理器适配。kernel-open/nvidia-drm/
nvidia-uvm.ko统一虚拟内存管理:实现 CPU/GPU 内存统一寻址。HPC 和 AI 计算的核心,体积巨大。kernel-open/nvidia-uvm/(约 15 万行独立实现)
nvidia-peermem.koRDMA 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 万行                       ← 构建脚本与配置
评论加载中…