一、Linux移植概述
Linux 的移植主要包括3部分:
- 移植bootloader 代码, Linux 系统要启动就必须需要一个 bootloader 程序,也就说芯片上电以后先运行一段bootloader程序。 这段bootloader程序会先初始化DDR等外设, 然后将Linux内核从flash(NAND,NOR FLASH,SD,MMC 等)拷贝到 DDR 中,最后启动 Linux 内核。 bootloader 有很多,常用的就是 U-Boot。DDR就是随机存储器的一种,也就是内存。
bootloader 和 Linux 内核的关系就跟 PC 上的 BIOS 和 Windows 的关系一样,bootloader 就相当于 BIOS。 - 移植Linux 内核,Linux内核由一系列程序组成,包括负责响应中断的中断服务程序、负责管理多个进程从而分享处理器时间的调度程序、负责管理地址空间的内存管理程序、网络、进程间通信的系统服务程序等。内核负责管理系统的硬件设备。
- 移植根文件系统(rootfs),Linux 中的根文件系统更像是一个文件夹或者叫做目录,在这个目录里面会有很多的子目录。根目录下和子目录中会有很多的文件,这些文件是 Linux 运行所必须的,比如库、常用的软件和命令、设备文件、配置文件等等。根文件系统里面包含了一些最常用的命令和文件。
U-Boot、Linux kernel 和 rootfs这三者一起构成了一个完整的 Linux 系统,一个可以正常使用、功能完善的 Linux 系统。
二、UBOOT简介
uboot 的全称是Universal Boot Loader,遵循 GPL 协议的开源软件。
uboot 是一个裸机代码,可以看作是一个裸机综合例程。现在的 uboot 已经支持液晶屏、网络、USB 等高级功能。uboot 官网为 https://www.denx.de/wiki/U-Boot/。
但我们移植uboot时一般不会直接用 uboot 官方的源码的,官方的源码是给半导体厂商准备的,半导 体厂商会根据自家的芯片,维护自己芯片对应的uboot。
三、NXP uboot测试
uboot移植并不需要从零开始将 uboot 移植到我们现在所使用的开发板上。因为半导体厂商通常都会自己做一个开发板(原厂开发板), 将uboot移植到他们自己的原厂开发板上,再将这个uboot(原厂BSP 包)发布出去。
市面上的开发板,通常会参考原厂的开发板做硬件,然后在原厂提供的 BSP 包上做修改,如正点原子和野火的 I.MX6ULL 开发板参考的就是NXP官方的 I.MX6ULL EVK 开发板做的硬件。
四、UBOOT命令使用
信息查询指令
环境变量操作命令
setenv bootargs 'console=ttymxc0,115200 root=/dev/mmcblk1p2 rootwait rw'
saveenv
网络操作命令
Ping命令是一种网络诊断工具,用于测试主机之间的连通性。它的实现原理基于ICMP(Internet Control Message Protocol,Internet控制消息协议)。
以下是Ping命令的实现原理:
-
发送ICMP Echo请求:Ping命令向目标主机发送一个ICMP Echo请求。ICMP Echo请求的作用是请求目标主机返回一个ICMP Echo Reply响应。
-
接收ICMP Echo Reply响应:目标主机收到ICMP Echo请求后,如果目标主机正常工作并且网络连接正常,它将会返回一个ICMP Echo Reply响应。ICMP Echo Reply中包含了原始请求的数据,以便发送主机可以确认响应是否与请求匹配。
-
计算往返时间(Round-Trip Time,RTT):发送主机接收到ICMP Echo Reply响应后,它会计算往返时间(RTT),即从发送请求到接收响应的时间。RTT通常用于衡量网络延迟。
-
显示结果:Ping命令将收到的ICMP Echo Reply响应和计算得到的往返时间显示给用户。这些信息可以用来判断网络连接的质量和稳定性。
需要注意的是,Ping命令通常需要在发送主机和目标主机之间存在双向的网络连接,并且目标主机需要正确地响应ICMP Echo请求。如果目标主机的网络连接出现故障或者目标主机配置了防火墙,可能会导致Ping命令无法正常工作。
nfs 80800000 192.168.1.253:/home/zuozhongkai/linux/nfs/zImage
tftp 80800000 zImage
EMMC和SD卡操作
BOOT 操作命令
bootz [addr [initrd[:size]] [fdt]]
zImage:更轻便
- zImage是Linux内核的一种压缩格式。它是一种轻量级的内核映像文件,通常用于嵌入式系统或者对启动速度有较高要求的场景。
- 在编译内核时,可以选择生成zImage格式的内核映像文件。这个文件通常命名为"zImage",并且是一个压缩过的内核镜像。
uImage:更灵活更扩展
- uImage是一种带有头部和校验和的Linux内核映像文件格式,用于各种体系结构。
- 与zImage/bzImage/vmlinuz相比,uImage提供了更多的元数据,如内核命令行参数、内核的加载地址等。
setenv bootcmd 'tftp 80800000 zImage; tftp 83000000 imx6ull-14x14-emmc-7-1024x600-c.dtb;
bootz 80800000 - 83000000'
saveenv
boot
boot命令是在设置好环境变量bootcmd基础上执行的,boot命令会读取bootcmd参数启动Linux。
五、编译环境搭建
1、交叉编译工具链下载并设置
2、编译原厂uboot
首先、在Ubuntu中下载解压原厂uboot源码,然后编译uboot。
编译uboot使用下面3条指令:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- mx6ull_14x14_evk_emmc_defconfig
make V=1 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j8
这3条命令中 :
ARCH=arm
设置目标为 arm 架构CROSS_COMPILE
指定所使用的交叉编译器。- 第1条命令相当于
make distclean
,目的是清除工程,一般在第一次编译的时候最好清理一下工程。 - 第2条指令相当于
make mx6ull_14x14_evk_emmc_defconfig
,用于配置 uboot,配置文件为 mx6ull_14x14_evk_emmc_defconfig。 - 第3条指令相当于
make -j8
,也就是使用8核来编译uboot。
为了方便的执行着3条指令,可以将这些指令写成shell脚本,比如在uboot源码目录下新建一个build.sh文件,写入如下内容:
#!/bin/bash
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- mx6ull_14x14_evk_emmc_defconfig
make V=1 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j8
然后编译,编译完成以后uboot 源码多了一些文件,其中u-boot.bin
就是编译出来的 uboot二进制文件。 uboot是个裸机程序, 因此需要在其前面加上头部(IVT、 DCD等数据)才能在I.MX6U上执行,u-boot.imx
文件就是添加头部以后的 u-boot.bin。
u-boot.imx 就是我们最终要烧写到开发板中的 uboot 镜像文件。
3、烧录开发板
这是的烧录开发板,实际是要烧录uboot镜像文件到SD卡中,然后将SD卡插入开发板,让开发板从SD卡启动(需要在开发板上设置拨码开关来选择启动方式)。
3.1 烧录到SD卡
正点原子专门编写了一个小软件用来将编译出来的.bin 文件烧写到 SD 卡中,这个软件叫做“imxdownload
”
将imxdownload 复制到 Ubuntu 中的uboot源码文件夹,再使用如下指令,给予 imxdownload 可执行权限:
chmod 777 imxdownload
然后电脑USB中插入SD卡(读卡器),并在虚拟机中设置usb加载(VMware或VirtualBox虚拟机需要先安装增强功能才能使用)
然后可以使用如下指令来查看SD卡的挂载标识符:
ls /dev/sd*
查看输出结果:
这里的/dev/sdb
就是我的SD卡。
注:我第一次使用SD卡烧录时,只多出了/dev/sdb,但不知什么情况,用了几次后,再插入SD卡,就会同时多出来/dev/sdb和/dev/sdb1,但实际测试,仍然把程序烧录到/dev/sdb也能用)。
imxdownload向SD卡烧写led.bin文件,命令格式如下:
./imxdownload u-boot.bin /dev/sdb
注意不能烧写到/dev/sda
或sda1
设备里面!那是系统磁盘。
烧写过程会输入如下信息:
烧写的最后一行会显示烧写大小、用时和速度,比如u-boot.bin
烧写到SD卡中的大小是 423KB,用时 1.7s,烧写速度是 236KB/s。
注意这个烧写速度,如果这个烧写速度在几百KB/s 以下那么就是正常烧写。 如果这个烧写速度大于几十MB/s、甚至几百MB/s那么肯定是烧写失败了! 重新插拔/格式化SD卡或重启ubuntu再试。
烧写完成以后会在当前工程目录下生成一个load.imx
的文件,这个文件就是软件 imxdownload 根据 NXP 官方启动方式介绍的内容, 在 bin 文件前面添加了一些数据头以后生成的。最终烧写到 SD卡里面的就是这个imx文件。
4. 启动开发板
烧录完之后,将SD卡插入开发板启动,使用串口连接电脑,查看uboot启动信息。
设置好串口参数(波特率115200)并打开,按键复位开发板。
当串口打印上出现“Hit any key to stop autoboot
”倒计时的时候按下键盘上的回车键,默认是 3 秒倒计时,在 3 秒倒计时结束以后如果没有按下回车键的话 uboot 就会使用默认参数来启动 Linux 内核了。
如果在 3 秒倒计时结束之前按下回车键,那么就会进入 uboot 的命令行模式:
解读一下这些信息的含义:
- 第1行是 uboot 版本号和编译时间:当前的 uboot 版本号是 2016.03,编译时间是 2021/7 /11/15:22:25
- 第3、4 行是 CPU 信息:当前使用的 CPU 是飞思卡尔(属于NXP)的 I.MX6ULL (频率为 792MHz),此时运行在 396MHz。这颗芯片是工业级的,结温为-40°C~105°C
- 第 5 行是复位原因:I.MX6ULL 芯片上有个 POR_B 引脚,将这个引脚拉低即可复位 I.MX6ULL。
- 第 6 行是板子名字,“MX6ULL 14x14 EVK”即NXP原厂开发板的名字 。
- 第 7 行提示 I2C 准备就绪。
- 第 8 行提示当前板子的DRAM(内存) 为 512MB
- 第 9 行提示当前有两个MMC/SD 卡控制器:FSL_SDHC(0)和 FSL_SDHC(1)。I.MX6ULL支持两个 MMC/SD,正点原子的 I.MX6ULL EMMC 核心板上 FSL_SDHC(0)接的 SD(TF)卡,FSL_SDHC(1)接的 EMMC。
- 第10行是一条警告信息,先忽略。
- 第 12、13 行是 LCD 型号,原厂默认的是TFT43AB (480x272)。
- 第 14~16 是标准输入、标准输出和标准错误所使用的终端,这里都使用串口(serial)作为终端。
- 第 17 、18行是切换到emmc的第0个分区上,因为当前的 uboot 是 emmc 版本的,也就是从 emmc 启动的。我们只是为了方便将其烧写到了 SD 卡上,但是它的“内心”还是 EMMC的。所以 uboot 启动以后会将 emmc 作为默认存储器 。
- 第 19行是网口信息,提示我们当前使用的 FEC1 这个网口,I.MX6ULL 支持两个网口。
- 第 20行提示 FEC1 网卡地址没有设置(后面我们会讲解如何在uboot 里面设置网卡地址)。
- 第 22行提示正常启动, 也就是说 uboot要从emmc里面读取环境变量和参数信息启动 Linux内核了。
- 第23行是倒计时提示,默认倒计时 3 秒,倒计时结束之前按下回车键就会进入 Linux 命令行模式。如果在倒计时结束以后没有按下回车键,那么 Linux 内核就会启动,Linux 内核一旦启动,uboot 就运行结束了。
- 第23行是在倒计时 3 秒内按了回车键,符号
=>
表示可以继续与uboot进行命令交互。
看过了串口的uboot信息,再来看一下板子是实际运行情况:
由于原厂的uboot驱动的屏幕是TFT43AB (480x272),与我这里屏幕不一样,所以屏幕没有正常显示(现在的屏幕看起来有许多彩色的小点点),接下来,就是对uboot进行屏幕驱动的修改。
参考资料:安全验证 - 知乎