1. 驱动与 Rootfs 概述

做嵌入式 Linux 开发这么多年,我经常被新人问到一个问题:驱动和文件系统到底是什么关系?为什么非要绑在一起?

说实话,我刚入行时也迷糊过。那时候我总觉得驱动就是 .ko 文件,insmod 一下就能用,跟 Rootfs 有啥关系?直到有一次,我在一个量产项目上栽了跟头——板子启动后驱动死活加载不上,查了两天才发现是 Rootfs 里少了依赖的固件文件。嗯,从那以后,我再也不敢把驱动和 Rootfs 分开看了。

这一章,我们就来把这两个概念彻底捋清楚。

什么是 Rootfs

Rootfs,全称 Root Filesystem,根文件系统。说白了,它就是 Linux 内核启动后挂载的第一个文件系统。

你想想看,内核启动完成后,总得有个地方去读取配置文件、加载应用程序、存放临时数据吧?Rootfs 就是干这个的。它提供了 Linux 系统的目录结构,比如 /bin、/etc、/lib、/usr 这些你熟悉的目录,全都在 Rootfs 里。

我习惯把 Rootfs 比作一个房子的内部装修。内核是房子的骨架和地基,Rootfs 就是里面的水电、家具、装饰。没有装修,房子也能住人吗?能,但你会非常难受。

核心要点:Rootfs 是 Linux 系统启动后赖以生存的根目录环境。没有 Rootfs,内核会 panic,系统直接崩溃。

常见的 Rootfs 类型有几种:

类型 特点 适用场景
initramfs 内存中运行,体积小,启动快 早期引导、调试阶段
ext4 镜像 传统块设备文件系统,可读写 量产产品、需要持久化存储
Squashfs 只读压缩文件系统,体积小 只读场景、固件升级
NFS 挂载 通过网络挂载,方便调试 开发阶段、快速迭代

我个人最常用的是 initramfs 配合 NFS 做开发调试,量产时切到 Squashfs 或 ext4。每种方案都有它的脾气,选对了能省不少事。

驱动在系统中的角色

驱动是什么?我给它一个简单的定义:驱动是内核与硬件之间的翻译官。

硬件听不懂内核的指令,内核也看不懂硬件的寄存器。驱动就是那个两头跑的角色——它知道怎么操作硬件,也知道怎么把硬件的能力暴露给内核和应用程序。

举个例子。你写了一个应用程序要读取温度传感器的数据。应用层只需要调用 open() 和 read(),完全不用管 I2C 总线怎么操作、寄存器地址是多少。这些脏活累活,全是驱动在背后帮你干了。

驱动在系统中的位置大概是这样的:

驱动在 Linux 系统中的角色 应用程序 (App) 系统调用 (open/read/ioctl) 虚拟文件系统 (VFS) 设备驱动 (Driver) 硬件 (Hardware) 驱动的作用 • 操作硬件寄存器 • 向上提供统一接口 • 处理中断和 DMA 驱动的类型 • 字符设备 • 块设备 • 网络设备

看到没?驱动在中间层,承上启下。没有驱动,应用层根本碰不到硬件。

为什么需要将驱动集成到 Rootfs

好,现在问题来了:驱动既然是个 .ko 文件,我启动后手动 insmod 不行吗?为什么非要集成到 Rootfs 里?

这个问题,我当年也问过我的导师。他笑了笑,说:你试试量产 10 万台设备,每台都手动 insmod?

我一下就明白了。集成到 Rootfs 不是技术问题,是工程问题。具体来说,有这几个原因:

  1. 自动化加载——系统启动时自动加载驱动,不需要人工干预。量产产品不可能让人去敲命令。
  2. 依赖管理——很多驱动有依赖关系。比如你写了一个 I2C 温度传感器驱动,它依赖 I2C 核心模块。如果加载顺序错了,驱动就起不来。集成到 Rootfs 后,可以通过 depmod 和 modprobe 自动处理依赖。
  3. 固件文件——有些驱动需要额外的固件文件(firmware),比如 WiFi 模组、GPU 驱动。这些文件必须放在 /lib/firmware 目录下,而 /lib 就在 Rootfs 里。
  4. 设备节点——部分驱动需要静态的设备节点,或者需要 udev/mdev 规则来动态创建。这些规则文件也在 Rootfs 里。
  5. 模块参数——有些驱动需要传递参数,比如 modprobe driver_name param=value。这些配置可以写在 /etc/modprobe.d/ 里,同样在 Rootfs 中。

我的经验:曾经有一个项目,驱动在开发板上跑得好好的,一上产线就挂。查到最后发现是 Rootfs 里少了 /lib/firmware/ 下的一个固件文件。从那以后,我每次做 Rootfs 都会列一个清单,把驱动依赖的固件、配置、规则文件全部写进去,一个都不能少。

说白了,把驱动集成到 Rootfs,就是把驱动从「手工调试阶段」推进到「自动化量产阶段」的关键一步。

驱动与 Rootfs 的集成关系

驱动和 Rootfs 不是简单的「放进去」关系。我习惯把它们的关系画成一张图:

驱动集成到 Rootfs 的完整关系 Rootfs 根文件系统 /lib/modules/ 内核模块 .ko 文件 modules.dep 依赖信息 /lib/firmware/ 固件文件 WiFi/GPU/蓝牙等 /etc/ modprobe.d/ 配置 udev/mdev 规则 Linux 内核 (Kernel) 硬件设备 内核启动后 从 Rootfs 读取 驱动和固件

从这张图能看出来,驱动不是孤零零的一个 .ko 文件。它需要:

  • 模块文件放在 /lib/modules/$(uname -r)/
  • 依赖信息由 depmod 生成,存在 modules.dep 里
  • 固件文件放在 /lib/firmware/
  • 加载配置写在 /etc/modprobe.d/
  • 设备规则由 udev/mdev 在 /etc/udev/rules.d/ 管理

这些东西,全都在 Rootfs 里。所以你说,驱动能不集成到 Rootfs 吗?

注意:千万不要把驱动模块直接扔到 Rootfs 里就不管了。我见过有人把 .ko 文件随便丢在 /root/ 目录下,然后写个 rc.local 去 insmod。这种做法在开发阶段勉强能用,但到了量产阶段,依赖管理、版本控制、固件路径全都会出问题。老老实实按标准路径放,用 depmod + modprobe 来管理,才是正道。

小结

这一章我们聊了三个核心问题:

  • Rootfs 是 Linux 系统的根文件系统,提供目录结构和运行环境
  • 驱动 是内核与硬件之间的桥梁,负责操作硬件并向上提供接口
  • 集成到 Rootfs 是为了实现自动化加载、依赖管理、固件配套和量产部署

我个人觉得,理解这三者的关系,是做好嵌入式 Linux 开发的第一步。后面的章节,我们会一步步深入,从编译驱动、制作 Rootfs,到最终把驱动完美集成进去。每一步我都会把踩过的坑、总结的经验分享出来。

嗯,准备好了吗?我们继续往下走。