一、Linux 设备驱动介绍及开发环境搭建
1.1 Linux 设备驱动介绍
1.1.1 分类及特点
- 计算机系统的硬件主要由 CPU、存储器和外设组成。
- 当前 CPU 内部都集成有存储器和外设适配器。
- 外设适配器有入 UART、IIC 控制器、SPI 控制器、USB 控制器、SDRAM 控制器等,有的 CPU 还集成有 GPU(图形处理器)、视频编辑器等。
- 驱动针对的对象是存储器和外设(包含 CPU 内部集成的存储器和外设),而不是针对 CPU 内核。Linux 将存储器和外设分为 3 个基础大类:
- 字符设备:必须以串行顺序依次进行访问的设备,如触摸屏、磁带驱动器、鼠标等。
- 块设备:可以按任意顺序进行访问,以块为单位进行操作,如硬盘、eMMC等
- 网络设备:面向数据包的接收和发送而设计,并不倾向于对应于文件系统的节点。
1.1.2 设备驱动与整个软硬件的系统的关系
- 除网络设备外,字符设备与块设备都被映射到 Linux 文件系统的文件和目录,通过文件系统的系统调用接口 open()、write() 等即可访问字符设备和块设备。所有字符设备和块设备都统一呈现给用户。
- Linux 的块设备有两种访问方法:
- 一种是类似于 dd 命令对应的原始块设备,如 ”/dev/sdb1“ 等
- 另一种方式是在块设备上建立 FAT、EXT4、BTRFS 等文件系统,然后以文件路径如 "/home/barry/hello.txt" 的形式进行访问
- 在 Linux 中,针对 NOR、NAND 等提供了独立的内存技术设备( Memory Technology Device,MTD) 子系统,其上裕兴 YAFFS2、JFFS2、UBIFS 等具备擦除和负载均衡能力的文件系统
- 针对磁盘或者 Flash 设备的 FAT、EXT4、YAFFS2、JFFS2、UBIFS 等文件系统定义了文件和目录在存储介质上的组织。
- Linux 的虚拟文件系统对上述进行了统一的抽象
- 应用程序可以使用 Linux 的系统调用接口编程,也可以使用 C 库函数。
1.2 QEMU 环境建立
1.2.1 虚拟机环境搭建
略过
1.2.2 安装 uboot-tools
- 用来生成 u-boot 引导的镜像文件
- sudo apt-get install u-boot-tools
1.2.3 安装交叉编译工具链
- 交叉编译是一种计算机环境中编译程序,在另一种环境下运行。或者说在一个平台上编译生成在另一个平台上运行的可执行代码
- ABI 和 EABI
- ABI:二进制应用程序接口(Application Binary Interface(ABI) for the ARM Architecture),在计算机中,应用二进制接口描述了应用程序(或者其他类型)和操作系统之间或其他应用程序的低级接口,涵盖了数据类型的大小,布局和对齐,调用约定
- EABI:嵌入式 ABI,嵌入式应用二进制接口指定了文件格式,数据类型,寄存器使用,堆积组织优化和在一个嵌入式软件中的参数的标准约定
- arm-none-gnueabi-linux 比 arm-linux-gcc 要好,在可移植性、兼容性上面
- 早期的 u-boot 和 linux 编译可能使用的都不是一个 arm-linux-gcc 版本
- 安装
- sudo apt-get install gcc-arm-linux-gnueabi
- sudo apt-get install gcc-arm-linux-gnueabihf
- sudo apt-get install g++-arm-linux-gnueabi
- sudo apt-get install g++-arm-linux-gnueabihf
1.2.4 QEMU 安装
- QEMU 是一个模拟器,可以模拟CPU,ARM、X86、MIPS 等架构
- 可以仿真 ARM 处理器:ARM926E、ARM1136,cortex-A8/A9 等
- 模拟真实的开发板、外设:串口、LCD、网卡、USB、SD 卡...
- 使用 QEMU 可以做的事情:
- 研究内核虚拟化
- 模拟 CPU, 对于芯片公司,流片之前在 QEMU 上做验证、仿真、软硬件协同设计,开发 BSP 和驱动
- 模拟开发板,在模拟平台上进行系统软件开发、驱动开发
- 学生、工程师可以利用 qemu-system-arm 学习嵌入式开发、研究 bootloader、Linux 内核\驱动开发、应用开发等。
- 联网安装:sudo apt-get install qemu qemu-system-common qemu-system qemu-system-arm
- 输入命令显示支持的设备:qemu-system-arm -machine help
- 启动设备:qemu-system-arm -M vexpress-a9 -m 512M -kernel ./zImage -dtb ./vexpress-v2p-cap.dtb -nographic -append "console=ttyAMA0"
- -M 指定开发板
- -m 指定内存大小
- -kernel 指定 kernel 镜像
- -dtb 指定设备树
- -nographic 不使用图形界面,使用串口控制台
- -append 指定串口控制台参数
- 实验用得是 vexpress-a9 得四核处理器开发板,板上集成了 Flash、SD、IIC、LCD 等设备。
- 查看 QEMU 版本:qemu-system-arm --version
1.2.5 开发板选择
- 选用的是 vexpress-a9 开发板,这是ARM 公司推出的一款开发板,全称为 versatile express family
- 主要用于 SOC 厂商设计、验证和测试自己的 SOC 芯片
- 采用主板 + 子板的设计,主板提供各种外围接口,子板提供 CPU 运算
- Vexpress 系列支持的 CPU
- cortex-a9:处理器子板 Express A9 x 4(v2p-ca9 x 4)
- cortex-a5:处理器子板 Express A5 x 4(v2p-ca5 x 2s)
- cortex-r5:
- cortex-a15:处理器子板 Express A15 x 4(v2p-ca15 x 2)
- 开发板:
- 系统框图
- 子板框图
1.2.5 编译内核和 dtb 文件
下载地址:https://mirrors.edge.kernel.org/pub/linux/kernel/v4.x/
也可以下载其他版本得内核,这里选择得是 Linux-4.20.0 版本,发布日期是2018-12-24
下载下来后,解压,修改主目录下的 Makefile:
原始的:
修改后:
配置开发板,主要是生成 .config 文件,可以在 arch/arm/configs 中查看默认配置,执行 make vexpress_defconfig。
执行 make zImage -j8 进行编译,-j8 是使用多线程编译。
编译内核模块:make modules -j8
编译 dts 文件:make dtbs
运行开发板:
qemu-system-arm -M vexpress-a9 -m 512M -kernel arch/arm/boot/zImage -dtb arch/arm/boot/dts/vexpress-v2p-ca9.dtb -nographic -append "console=ttyAMA0”
可以看到内核已经起来,但是无文件系统。
1.2.6 使用 busybox 制作根文件系统
- 文件系统
- 对存储设备上的数据进行组织的机制
- 为什么要使用文件系统
- Linux的哲学:一切皆文件
- 用户与操作系统进行交互的主要工具:文件系统调用
- 用户和底层存储的接口
- 根文件系统
- Linux内核启动后第一个挂载的文件系统
- 主要由基本的shell命令、各种库、字符设备、配置脚本组成
- 提供了根目录 /
- RFS可以放在: nor/nand flash、 SD卡、磁盘、网络空间上
- 什么是busybox?
- 一个集成100多个Linux常用命令和工具的软件
- 一个适合制作嵌入式文件系统的软件工具
- 编译安装
- 下载源代码: http://www.busybox.net/downloads/
- 修改Makefile: ARCH=arm CROSS_COMPILE=arm-linux-gnueabi-
- 配置: make defconfig ; make menuconfig
- 注意要将跟文件系统作为静态库生成:
- 编译: make
- 安装: make install
- 所有生成的二进制文件都在 _install 目录下
- 制作根文件系统
- $ mkdir rootfs
- $ mkdir rootfs/lib
- $ cp –r _install/* rootfs
- 跟文件系统的库存放在编译工具链中的:$ cp -p /usr/arm-linux-gnueabi/lib/* rootfs/lib
- 创建设备:$ mkdir -p rootfs/dev/
- 创建串口节点,串口节点用的比较频繁,所以创建的比较多
- $ mknod –m 666 tty1 c 4 1
- $ mknod –m 666 tty2 c 4 2
- $ mknod –m 666 tty3 c 4 3
- $ mknod –m 666 tty4 c 4 4
- $ mknod –m 666 console c 5 1
- $ mknod –m 666 null c 1 3
- 制作SD卡文件系统镜像
- 生成虚拟文件镜像: dd if=/dev/zero of=rootfs.ext3 bs=1M count=32
- if 输入
- of 输出
- bs 块大小
- count 多少个块
- 格式化为exts文件系统: mkfs.ext3 rootfs.ext3
- 生成虚拟文件镜像: dd if=/dev/zero of=rootfs.ext3 bs=1M count=32
- 往SD卡拷贝东西,将各种文件拷贝到文件系统镜像中:
- 执行挂载:$ mount -t ext3 rootfs.ext3 /mnt/ -o loop
- $ cp -r rootfs/* /mnt
- 卸载:$ umount /mnt/
- 启动内核,挂载rootfs
- $ qemu-system-arm -M vexpress-a9 -m 512M -dtb ./vexpressv2p-ca9.dtb -kernel ./zImage -nographic -append "root=/dev/mmcblk0 rw console=ttyAMA0" -sd rootfs.ext3
- -append 参数做了修改,root是在 /dev/mmcblk0 上启动的,可读写权限,mmcblk0 是 SD 卡的设备节点
- -sd 挂载SD卡
- $ qemu-system-arm -M vexpress-a9 -m 512M -dtb ./vexpressv2p-ca9.dtb -kernel ./zImage -nographic -append "root=/dev/mmcblk0 rw console=ttyAMA0" -sd rootfs.ext3
- 完善文件系统:
- rcS 文件完善
- 修改完成后,再重新走《制作 SD 卡文件系统映像步骤》,mount 步骤,结果如下
- 图形化启动内核
- $ qemu-system-arm -M vexpress-a9 -m 512M -dtb ./vexpressv2p-ca9.dtb -kernel ./zImage -append "root=/dev/mmcblk0 rw
console=tty0" -sd rootfs.ext3
- $ qemu-system-arm -M vexpress-a9 -m 512M -dtb ./vexpressv2p-ca9.dtb -kernel ./zImage -append "root=/dev/mmcblk0 rw
启动命令脚本(无LCD)
1 qemu-system-arm \ 2 -M vexpress-a9 \ 3 -m 512M \ 4 -kernel /home/ubuntu/work/kernel/linux-4.20/arch/arm/boot/zImage \ 5 -dtb /home/ubuntu/work/kernel/linux-4.20/arch/arm/boot/dts/vexpress-v2p-ca9.dtb \ 6 -nographic \ 7 -append "root=/dev/mmcblk0 rw console=ttyAMA0" \ 8 -sd /home/ubuntu/work/rootfs.ext3
启动命令脚本(LCD)
1 qemu-system-arm \ 2 -M vexpress-a9 \ 3 -m 512M \ 4 -kernel /home/ubuntu/work/kernel/linux-4.20/arch/arm/boot/zImage \ 5 -dtb /home/ubuntu/work/kernel/linux-4.20/arch/arm/boot/dts/vexpress-v2p-ca9.dtb \ 6 -append "root=/dev/mmcblk0 rw console=tty0" \ 7 -sd /home/ubuntu/work/rootfs.ext3