课程导学与环境准备

说实话,每次带新人入门内核驱动,我都要先问一句:你为什么要学字符设备驱动?

很多人觉得驱动开发高深莫测,其实不然。字符设备驱动,说白了就是内核里最简单的一类驱动。它就像你写的第一行"Hello World"——虽然简单,但五脏俱全。

我个人习惯把字符设备驱动比作内核与用户空间之间的一个管道。应用程序通过这个管道,跟硬件设备打交道。你想想看,键盘、鼠标、串口,这些不都是字符设备吗?

什么是字符设备驱动?

先给个准确定义:字符设备驱动,是指以字节流方式访问设备的驱动程序。数据按顺序读写,没有缓冲区,没有随机访问。

举个例子。你在终端敲键盘,每个按键就是一个字符。驱动收到这个字符,直接传给应用程序。就这么简单。

我在项目中遇到过不少新手,上来就想写块设备驱动。结果被复杂的缓存机制搞得晕头转向。我建议:从字符设备开始,稳扎稳打

核心特征:

  • 数据以字节流方式传输
  • 顺序访问,不支持随机定位
  • 没有内核缓存层(对比块设备)
  • 通过设备文件(/dev/xxx)与用户交互

课程目标与学习路径

这门课的目标很明确:让你亲手写出一个能跑起来的字符设备驱动。不是纸上谈兵,是真正在QEMU虚拟机上加载、测试、验证。

我设计的路径是这样的:

  1. 环境搭建——先把锅碗瓢盆准备好
  2. 内核编译——理解内核构建流程
  3. 驱动框架——掌握file_operations结构体
  4. 设备号管理——学会申请和释放设备号
  5. 实现读写——让驱动真正干活
  6. 测试验证——用应用程序测试驱动

嗯,这里要注意:不要跳步。我见过太多人急着写代码,结果环境没配好,编译都过不了,白白浪费时间。

开发环境搭建

工欲善其事,必先利其器。我们的开发环境是:Ubuntu + QEMU + Busybox

为什么选这套组合?

  • Ubuntu:开发主机,编译内核和驱动
  • QEMU:模拟ARM开发板,运行内核
  • Busybox:制作根文件系统,提供shell环境

我曾经在真实开发板上调试驱动,每次烧写都要几分钟。后来改用QEMU,编译完直接启动,效率提升了好几倍。所以这次课程,我们全程用QEMU。

安装依赖包

sudo apt-get update
sudo apt-get install build-essential git vim
sudo apt-get install qemu-system-arm
sudo apt-get install gcc-arm-linux-gnueabihf
sudo apt-get install libncurses5-dev bison flex
sudo apt-get install libssl-dev bc

这些包缺一不可。我踩过坑:忘了装libssl-dev,编译内核到一半报错,折腾了半天才发现。

下载内核源码

我们使用Linux 5.10 LTS版本,稳定且文档齐全。

wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.10.210.tar.xz
tar -xf linux-5.10.210.tar.xz
cd linux-5.10.210

配置并编译内核

针对ARM架构,我们使用vexpress开发板配置。

export ARCH=arm
export CROSS_COMPILE=arm-linux-gnueabihf-
make vexpress_defconfig
make -j4

编译时间取决于你的机器。我建议第一次编译时,泡杯咖啡,耐心等待。

小技巧:如果编译过程中断,下次执行 make 会从断点继续,不用重新开始。

制作根文件系统

用Busybox制作一个最小根文件系统。

wget https://busybox.net/downloads/busybox-1.36.0.tar.bz2
tar -xf busybox-1.36.0.tar.bz2
cd busybox-1.36.0
make defconfig
make menuconfig  # 确保选中 "Build static binary (no shared libs)"
make -j4
make install

安装完成后,在 _install 目录下生成根文件系统。我们需要手动创建一些目录:

cd _install
mkdir -p proc sys dev etc/init.d
touch etc/init.d/rcS
chmod +x etc/init.d/rcS

rcS 文件中写入:

#!/bin/sh
mount -t proc none /proc
mount -t sysfs none /sys
mdev -s

启动QEMU验证

一切就绪后,用以下命令启动:

qemu-system-arm -M vexpress-a9 \
  -kernel linux-5.10.210/arch/arm/boot/zImage \
  -dtb linux-5.10.210/arch/arm/boot/dts/vexpress-v2p-ca9.dtb \
  -append "console=ttyAMA0 root=/dev/mmcblk0" \
  -sd rootfs.ext3 \
  -nographic

如果看到内核启动日志,最后出现 # 提示符,恭喜你,环境搭建成功!

常见问题:

  • QEMU启动后黑屏:检查 -nographic 参数是否添加
  • 内核崩溃:确认dtb文件路径是否正确
  • 根文件系统挂载失败:检查rootfs.ext3格式是否正确

知识体系总览

为了让你对整个课程有个全局认识,我画了一张图:

字符设备驱动学习路径 第1步:环境搭建 Ubuntu主机 → 交叉编译工具链 → QEMU模拟器 → Busybox根文件系统 第2步:内核编译与模块机制 下载内核源码 → 配置内核选项 → 编译内核 → 理解模块加载/卸载 第3步:编写字符设备驱动 file_operations结构体 → 设备号申请 → 实现open/read/write → 编译为内核模块 第4步:测试与验证 加载模块 → 创建设备文件 → 编写测试程序 → 验证读写功能

这张图把整个课程串起来了。你跟着这个路径走,每一步都有明确的目标。不会迷路。

避坑指南

最后,分享几个我当年踩过的坑:

  • 交叉编译工具链版本不匹配:我曾经用gcc-9编译内核,结果QEMU启动就崩溃。后来换成gcc-7,一切正常。建议使用Ubuntu官方源提供的工具链。
  • 根文件系统权限问题:Busybox编译时一定要选静态链接,否则动态库找不到,启动就报错。
  • QEMU参数顺序-kernel-dtb-append 的顺序不能乱,否则内核无法正确解析参数。

我的建议:第一次搭建环境时,每一步都做记录。出了问题,回头查记录,比重新搜索快得多。

好了,环境准备就绪。接下来,我们就要真正动手写驱动了。记住:驱动开发不是魔法,是工程。每一步都有章可循。


公众号:蓝海资料掘金营,微信deep3321