问:作为嵌入式软件工程师,你会写驱动吗?
答:会呀,我会控制gpio输出把LED点亮!😂
我想这是我扎根嵌入式软件开发多年的尴尬之处——不太会写驱动!所以,我决定系统地学习一下这个领域,一来是工作需要弥补我在驱动层的空白,二来自己也想全面了解Linux内核机制。基本上我主要通过《Linux设备驱动开发详解,基于最新的Linux4.0内核》以及《Linux设备驱动程序》作为主要参考教材(毕竟手上就这两本书)。
废话结束
为了避免繁琐地硬件环境搭建,学习过程尽可能基于虚拟的arm开发板,既能保证环境统一,又能快速上手👍。
另外,我个人的“战果”全部放在git仓库:github/philon/varm
个人开发环境:
- 宿主机:Ubuntu 18.04
- 开发板:qemu+vexpress-a9
- 编辑器:visual studio code
- 编译器:arm-linux-gnueabihf-gcc
关于如何安装Linux虚拟机以及交叉编译环境的搭建这里就不写了,网上教程一大堆。所以从现在开始,阅读下文的前提是:Linux、arm-linux-gcc、各种源码编辑器环境已就绪。
好,下面亲手动手,来做一块arm开发板😅。
ARM虚拟机——QEMU
QEMU是一款免费开源且跨平台的虚拟机,可以虚拟各种架构的处理器,和vmware/virtualbox不同,我们更喜欢用它来仿真ARM环境,即一款ARM虚拟机。
第一步:下载并安装qemu
1 | # macOS用户 |
第二步:选择一款arm
装好后可以通过以下命令qemu支持哪些arm处理器(开发板):
1 | $ qemu-system-arm -M help |
选中自己喜欢的“硬件”环境后,理论上就可以“上电”了,不过且慢——操作系统还没装呢!所以接下来很重要的一步就是制作自己的Linux系统镜像。
制作Linux系统镜像
做嵌入式Linux的人都知道,一个完整的嵌入式Linux操作系统基本分为三大块:
- u-boot:上电初始化并引导内核
- kernel:Linux内核
- rootfs:根文件系统,busybox
由于qemu可以直接引导内核,所以这里暂且略过u-boot的移植。其它两个源码建议选择“稳定版”,别给自己找麻烦。
第一步:移植内核
从linux内核官网下载源码并解压(我嘞个去!Linux都步入5.0时代了,果断下载),然后根据以下命令移植:
1 | # 0. 可能需要安装flex、bsion,如果之前没装的话,否则编译镜像时会出错 |
根据上述命令完成kernel移植之后,所有需要的镜像及其相关文件全部放在<kernel_dir>/arch/arm/boot
中:
1 | # zImage和dts就是真正需要的东西 |
第二步:启动内核
既然有了内核镜像文件,就可以先小试牛刀了,qemu走起!
1 | ~/varm/os/linux-5.0.3$ cd .. |
可以看到kernel被成功启动了,但由于没有文件系统,内核向你抛出了一个异常。
此外,上述命令比较长,简单解释下:
1 | qemu-system-arm \ # 虚拟机启动 |
还有一点,quem启动后是一个独立进程,所有的Ctrl+C和其他中断信号都会被这个进程来接,程序无法关闭,最好的办法是新建一个终端,用kill来杀!
1 | $ killall qemu-system-arm |
第三步:移植busybox
同样先从busybox官网把源码包下载下来,然后开始移植:
1 | # 1. 解压源码并进入目录 |
第四步:制作根文件系统rootfs
busybox已经生成了linux常用的一些命令和简单的目录结构,现在还差两个东西:
- busybox的命令执行是依赖于交叉编译工具的动态库的,所以要把动态库放入rootfs
- 需要给文件系统一些默认的设备描述符,否则你想让它往哪输出
1 | # 1. 拷贝根文件系统的“必需品”到rootfs目录 |
第五步:创建rootfs镜像
所谓镜像可以理解为一张虚拟的光盘,存放操作系统。但玩过树莓派的同学应该都知道它的存储其实就是一个SD卡,那好,我们就创建一张虚拟的SD卡给qemu加载。
1 | # 1. 生成镜像文件(虚拟SD卡),且大小为32M |
现在整个rootfs.ext3镜像制作完成,再加上zImage内核镜像,可以起飞了可以开机正常加载了,重新调整一下qemu的启动命令:
1 | ~/varm/os$ qemu-system-arm -M vexpress-a9 -m 512M -kernel zImage -dtb vexpress-v2p-ca9.dtb -sd rootfs.ext3 -nographic -append "root=/dev/mmcblk0 console=ttyAMA0" |
上边的命令大体上和内核启动时一样,主要是增加了-sd rootfs.ext3
文件系统的SD卡和对应分区,以确保内核能正确加载文件系统。经过一分钟左右的等待,我们的最小Linux系统成功运行起来了😄:
如果顺利的话内核会成功挂在文件系统,从此可以愉快玩耍了。以上就是整个ArmLinux的虚拟机搭建过程,目前位置整个环境基本OK,但在真正写代码之前还有些事情要做,总之等遇到了再查缺补漏。
小结一下
- QEMU是一款虚拟机,可以虚拟常见的通用处理器架构,包括ARM,支持很多开发板模拟
- vexpress-a9是ARM官方出的一款开发板
- QEMU可以直接引导内核,因此可以不用移植u-boot