imx6ull开发板cortex-A7系列上有多种外部存储模块:
- SD 卡:外置可插拔存储,存放代码,多用于裸机程序烧录与调试
- eMMC(8G):板载固化式存储芯片,内部集成 NAND 闪存与控制单元,容量大、稳定性强,用于存放Linux系统与用户数据;
- DDR 内存(512M):高速运行内存,负责系统与程序运行时的数据临时缓存,断电数据自动丢失,是嵌入式系统运行的核心临时存储介质。
在裸机开发阶段,我们通过 SD 卡启动实现硬件的基础控制,但这种方式无法高效管理 eMMC、DDR 等板载存储,也不支持复杂的系统调度。为了充分利用硬件资源、实现多任务运行与标准化外设控制,需要学习 Linux 驱动开发,通过驱动程序完成硬件抽象与系统对接,让嵌入式系统真正走向实用化与工程化。
一、系统移植概念
inux系统想要移植到开发板上,我们需要移植三部分:U-Boot(bootloader)、zImage(内核镜 像)、rootfs(文件系统),我们需要将其烧写到开发板的存储器中,这个过程称为系统移植。
- uboot:一段加载引导系统启动的裸机代码。其核心功能是为操作系统内核的启动提供硬件初始化、镜像加载及参数传递等支持。
- zImage(80800000):内核镜像文件。内核可以理解为一个软件,具备管理处理器、内存管理、硬件设备管理、进程调度、网络通信等功能。
- .dtb(83000000):设备树文件。描述硬件设备信息,从内核中独立分出的设备文件。
- rootfs:文件系统。用户层与内核层交互、对文件系统管理和操作。
1. Linux系统烧写
uboot烧写到SD卡 + zImage通过tftp下载 + rootfs通过nfs挂载
1.1 操作方式
将uboot烧录到SD卡上,并设置为SD卡启动,开发板上电即可启动uboot, 然后将zImage放入到tftp管理目录,通过tftp下载zImage和设备树文件到DDR中,并加载内核,最后将 文件系统设置在nfs服务器上,内核挂载nfs服务器的文件系统,启动Linux系统。
这样做的目的在于每次下载的zImage和dts设备树文件都是最新裁剪出来的,减少了烧录固化的时间,并且文件系统也是最新版本的,适合用于开发时使用。
1.2 双网卡设置
Ubuntu需要一个网卡与开发板连接,用来实现基于网络的tftp(文件传输)及nfs(目录共享)服务功能,我们需要设置双网卡来实现既能上网又能与开发板通信的效果。
- NAT模式:window有IP地址,ubuntu作为windows上的一个软件是虚拟地址。
- 桥接模式:windows和ubuntu各有一个独立的IP地址。
- 有线网卡工作在桥接模式,因为它需要作为开发板的服务器,提供 TFTP 和 NFS 服务。
- 无线网卡工作中NAT模式,与路由器连接用于上网。
2. 内核编译及裁剪
内核编译及裁剪通过make menuconfig图形化配置界面实现,本质是通过宏定义控制驱动的编译方式,通过配置宏开关,可保留必要功能、剔除无用组件,实现内核精简与定制化。
<*>表示静态加载(obj-y),驱动编译进内核镜像 zImage,开机自动加载;<M>表示动态加载(obj-m),驱动编译为 .ko 模块文件,需手动加载;- 不选择表示不编译,对应功能被裁剪,不参与内核构建。
3. busybox制作文件系统
采用busybox构建根文件系统,其特点是易于构建简单的根文件系统,而且文件系统占用空间小。
1)./etc/inittab文件,该文件指定启动后一些代码的运行方式。
#etc/inittab
#指定系统启动时要执行的脚本文件
::sysinit:/etc/init.d/rcS
#终端启动时要执行的脚本文件
console::askfirst:-/bin/sh
#重启时要执行的脚本文件
::restart:/sbin/init
::ctrlaltdel:/sbin/reboot
#关闭时要执行的脚本文件
::shutdown:/bin/umount -a -r
::shutdown:/sbin/swapoff -a
2)./etc/init.d/rcS文件,该文件是一个shell脚本,Linux内核启动后需要启动的一些服务都可以通过该脚本进行配置。
#!/bin/sh
#环境变量
PATH=/sbin:/bin:/usr/sbin:/usr/bin:$PATH
#库路径
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/lib:/usr/lib
#导出,使后续子进程继承环境变量
export PATH LD_LIBRARY_PATH
#去执行/etc/fstab,将每个文件系统进行挂载
mount -a
mkdir /dev/pts
mount -t devpts devpts /dev/pts
#支持热插拔
echo /sbin/mdev > /proc/sys/kernel/hotplug
mdev -s
**3)./etc/fstab文件,**将内核的分区挂载在应用层,可在应用层查看内核的文件信息。
#<file system> <mount point> <type> <options> <dump> <pass>
proc /proc proc defaults 0 0
tmpfs /tmp tmpfs defaults 0 0
sysfs /sys sysfs defaults 0 0
4. 系统启动流程
bootROM阶段:
- 上电后,芯片从0x0地址加载BootROM代码:这是芯片出厂内置的固件,负责初始化基本硬件并检测启动模式。
- BootROM在芯片内部RAM(128K)中执行:由于此时DDR尚未初始化,因此BootROM代码在片内RAM中运行,完成芯片校验和启动方式判断。
- 根据启动模式定位U-Boot镜像:选择SD卡启动,BootROM会从SD卡读取u-boot.imx文件(uboot.bin + DCD数据头)。
- 将U-Boot搬运至DDR并跳转执行:BootROM初始化DDR后,将u-boot.imx从存储介质复制到DDR中,并跳转至U-Boot入口地址,由U-Boot接管后续启动流程。
uboot阶段:
- 重新设置异常向量表,执行reset复位异常
- 关闭MMU、dcache、看门狗,打开icache
- 对硬件设备初始化
- 进入人机交互,倒计时结束未交互则执行bootcmd加载内核
内核阶段:
- 解析设备树文件
- 启动内核(内存管理、多任务管理、进程间通信、网络通信、文件系统管理)
- 根据uboot中的bootargs挂载文件系统,如果没有文件系统会内核恐慌
文件系统阶段:
- 内核启动完成后自动拉起init 进程,接管系统上层管理;
- init 读取
/etc/inittab配置文件,确定系统开机执行规则; - 自动运行
/etc/init.d/rcS初始化脚本,完成网络、设备、环境等基础配置; - 解析
/etc/fstab挂载配置文件,自动完成 SD 卡、eMMC 等存储设备要挂载到哪个文件夹; - 最后启动串口终端,提供人机交互命令行界面,完成整个 Linux 系统启动。