结束了ARM架构的学习,现在开始Linux驱动模块的学习。首先是Linux系统移植,我们需要把Linux系统移植到硬件平台。今天从头到尾完整实操了整套流程:从理解Linux内核基础概念、搭建Ubuntu虚拟机开发环境,配置双网卡网络,使用烧写工具烧写U‑Boot,完成U‑Boot编译、Linux内核编译,用BusyBox制作根文件系统,学习Linux完整启动流程。
一、关于Linux系统
一、为什么要将Linux系统移植到硬件平台?
1.屏蔽底层不同的硬件平台,为上层应用提供统一接口,从而简化应用层的编程,使得应用软件具备通用性。
2.Linux操作系统的五大核心功能:
1.内存管理(文本区、数据区、堆区、栈区、内核、虚拟空间、物理地址空间、进程空间)
2.多任务管理(进程和线程、任务的调度)
3.进程间通信(管理、信号、消息队列)
4.文件系统管理
5.网络协议(通信栈)
3.Linux系统分为两层:
1.用户层:shell(c语言利用库函数及系统调用编写的一些功能命令)、库函数(对系统调用的封装)
2.内核层:五大功能
3.两者之间的交互方法:系统调用、信号、文件系统
二、如何移植Linux系统?
1.开发板启动方式:
1.USB启动(第一次启动、调试时使用USB启动)
2.SD卡启动(调试阶段使用SD卡启动) 选用这种方式完成Linux系统烧录
3.EMMC启动(出厂时固化已经调试好的代码)
4.Nand Flash启动(批量化生产)
2.Linux系统所需要烧录的文件:
1.uboot 在Linux内核启动前,为加载内核做准备的一段逻辑代码
2.zImage 压缩的内核镜像文件,Linux系统的五大功能
3.dtb文件 设备树文件(描述硬件资源)
4.rootfs文件系统 提供人机交换的一个系统
3.如何将Linux系统(4个镜像文件)烧录到SD卡上?
使用芯片原厂提供的烧录工具mfgtool完成烧录
1.windows工具烧录(mfgtool)
2.Ubuntu烧录(mksdboot.sh)
三、Linux系统如何在开发板上启动加载的?
1.BotROM阶段
1.上电启动执行,芯片执行0x0地址的一段BotRom代码,这段代码是由厂家出场时固化,不允许修改
2.BotROM可以利用片内128K的SRAM执行代码
3.做一些芯片校验工作后,根据拨码开关设置的启动方式在对应的位置找uboot的代码
4.如果设置SD卡启动,BotROM会找到SD卡中的uboot.imx文件,uboot.imx文件是由3部分组成(IVT、uboot.bin、DCD)组成
5.BotROM会根据IVT向量表记录的位置找到DCD数据,DCD中包含了对DDR初始化的寄存器及时钟配置
6.BotROM初始化根据DCD初始化DDR
7.将uboot.bin拷贝到DDR中
8.跳转执行uboot.bin,uboot.bin是一段裸机代码
2.uboot阶段
1.初始化相应的外设
2.找到zImage和DTB文件,并将它们加载到DDR中
3.启动zImage内核,将DTB文件及其文件系统以参数的形式传入内核中
3.zImage内核阶段
1.Linux内核五大功能
2.找到文件系统
4.rootfs文件系统
1.启动文件系统
2.启动shell
二、开发环境搭建:Ubuntu双网卡配置
想要实现模式三网络启动,虚拟机网络配置是第一步。给VMware虚拟机添加两块网卡,分工明确:
网卡1:NAT模式,用来让Ubuntu访问外网,执行apt下载各类软件包。
网卡2:桥接模式,网线直连IMX6ULL开发板,充当TFTP、NFS服务器;虚拟机静态IP设置192.168.1.100,开发板IP设置为192.168.1.50。
- 桥接模式网卡,一定要桥接到电脑有线网卡,如果桥接无线网卡,开发板网络大概率不通。
- 默认网关要交给NAT网卡,不能把网关设置到桥接网卡,否则Ubuntu无法访问互联网。这里我写了systemd开机自启服务,开机自动修改路由,保证同时可以访问外网,又可以和开发板通信。
- Windows系统防火墙尽量关闭,不然会出现ping丢包、网络访问异常。
网络调通之后,安装全套开发需要工具:
- 将apt软件源替换为阿里源,更新软件索引。
- 安装minicom串口工具,用来接收开发板串口输出日志。
- 安装
tftpd‑hpaTFTP服务器、nfs‑kernel‑serverNFS服务器。 - 部署交叉编译工具链
gcc‑linaro‑4.9.4,把工具链路径加入环境变量PATH。
TFTP服务器配置
修改配置文件/etc/default/tftpd‑hpa,指定共享目录/home/linux/tftpboot,zImage和dtb设备树文件放到这个目录,开发板就可以通过网络下载镜像。给目录开放权限,重启tftpd‑hpa服务。
NFS服务器配置
修改/etc/exports,配置根文件系统目录共享权限:
/home/linux/nfs/rootfs *(rw,sync,no_subtree_check,no_root_squash)
修改完成重启nfs‑kernel‑server服务。这个共享目录就是开发板挂载的根文件系统,在Ubuntu这边修改程序,开发板可以直接运行,不需要拷贝到板载存储。
三、U‑Boot编译与烧写
U‑Boot是整个系统的入口,先编译源码得到镜像文件。
shell
# 清理历史编译产物
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean
# 加载开发板默认配置
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- imx_alientek_emmc_defconfig
# 编译
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j16
编译结束生成u‑boot.imx镜像。
烧写操作:使用烧写工具在Windows下将U‑Boot烧写到SD卡。开发板拨码开关设置为SD卡启动,上电后打开minicom,就能看到U‑Boot打印信息,按下任意按键可以进入uboot命令交互行。
注意:烧写的时候虚拟机需要关闭,不能占用开发板的OTG设备,否则烧写工具识别不到硬件。
四、Linux内核编译
接下来编译Linux内核源码:
shell
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- imx_alientek_emmc_defconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- all -j16
编译完成得到两个核心产物:
arch/arm/boot/zImage:Linux内核镜像,复制到tftpboot目录arch/arm/boot/dts/imx6ull‑alientek‑emmc.dtb:设备树文件,复制到tftpboot目录
五、BusyBox构建根文件系统rootfs
光有内核还不够,内核本身没有ls、cd这些用户命令,需要制作根文件系统。这里使用BusyBox来构建最小化根文件系统:
- 解压BusyBox源码,修改顶层Makefile,指定
ARCH=arm,配置交叉编译器CROSS_COMPILE=arm‑linux‑gnueabihf‑。 make defconfig加载默认配置,打开make menuconfig,取消静态编译选项。- 执行
make && make install CONFIG_PREFIX=/home/linux/nfs/rootfs,生成基础文件。 - 把交叉工具链里面的库文件拷贝到rootfs的lib目录,手动创建
dev、proc、sys、tmp等必要文件夹。 - 编写系统启动相关配置文件:
/etc/inittab、/etc/init.d/rcS、/etc/fstab,完成根文件系统搭建。
六、模式三网络启动配置
三种主流启动方式
模式一:全套系统烧写到SD卡,适用于刷机、系统恢复、量产测试。
模式二:全套系统烧写到板载EMMC,适用于产品成品,设备独立运行
模式三:SD卡启动U‑Boot,TFTP下载内核设备树,NFS挂载根文件系统。
模式三是嵌入式开发调试阶段非常好用的启动方式,不用反复烧录SD卡或者EMMC。只要修改内核、设备树或者应用程序,把文件放到Ubuntu对应的服务目录,重启开发板就能加载新版本镜像,省去频繁烧卡的时间,调试效率提升非常明显。
模式三工作逻辑:SD卡存放U‑Boot;上电运行U‑Boot,通过TFTP协议从Ubuntu服务器下载zImage内核和dtb设备树,加载到DDR内存;再通过NFS网络挂载Ubuntu主机上的rootfs作为根文件系统,完整启动Linux操作系统。
进入uboot命令行,配置环境变量:
shell
setenv ipaddr 192.168.1.50 #开发板本地IP
setenv serverip 192.168.1.100 #Ubuntu服务器IP
setenv gatewayip 192.168.1.1
setenv netmask 255.255.255.0
setenv ethaddr 00:04:9f:04:d2:35
# bootcmd:开机自动执行,tftp下载内核、设备树,bootz启动内核
setenv bootcmd 'tftp 80800000 zImage;tftp 83000000 imx6ull-alientek-emmc.dtb;bootz 80800000 - 83000000'
# bootargs:内核启动参数,指定使用NFS作为根文件系统
setenv bootargs 'console=ttymxc0,115200 root=/dev/nfs nfsroot=192.168.1.100:/home/linux/nfs/rootfs,proto=tcp,nfsvers=3 rw ip=192.168.1.50:192.168.1.100:192.168.1.1:255.255.0::eth0:off'
saveenv #保存环境变量,重启不丢失
配置完毕复位开发板,U‑Boot自动执行bootcmd,网络下载内核与设备树,挂载NFS根文件系统,串口成功进入Linux shell交互终端。
裸机开发是我们直接读写寄存器操作硬件,而进入Linux系统移植之后开发思路完全转变。U‑Boot、Linux内核已经帮我们处理了绝大部分底层硬件初始化工作,我们更多的工作集中在配置、裁剪、编译、调试。