本帖最后由 小麦克 于 2024-8-4 04:47 编辑
U-Boot编译与实践
从这期开始,我们从底层uboot开始,构建嵌入式Linux系统,系统的学习一下嵌入式Linux开发的整个流程。
环境准备
从ARM官网下载最新的交叉编译器:https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads
这里需要选择 AArch64 GNU/Linux target (aarch64-none-linux-gnu)
交叉编译器下载地址
在Ubuntu中安装必要的工具
sudo apt install flex bison libssl-dev gcc-aarch64-linux-gnu u-boot-tools libncurses5-dev libncursesw5-dev uuid-dev gnutls-dev
为了后续操作方便,写个简单的脚本linux_imx93.sh
将CROSS_COMPILE
变量导入到当前的环境中
#!/bin/bash
export ARCH=arm64
export CROSS_COMPILE=aarch64-none-linux-gnu-
export PATH=$PATH:/opt/tools/arm-gnu-toolchain-13.3.rel1-x86_64-aarch64-none-linux-gnu/bin
每次打开终端开始编译时执行一下source linux_imx93.sh
IMX93启动镜像
镜像组成
i.MX93上电时会首先运行内部的BOOT ROM,BOOT ROM根据拨码盘或者eFUSE确定从哪个设备启动。启动的设备必须在特定的位置存储下面的镜像。
从上面的框图可以看出,启动镜像必须按照上面的要求封装起来。由于使用uboot启动linux,所以只需要把uboot的镜像按照要求封装即可。BOOT ROM负责加载uboot,uboot启动好就可以加载内核和文件系统。
好在NXP提供了imx-mkimage
https://github.com/nxp-imx/imx-mkimage.git ,有了这个工具,可以通过一条命令将所有文件打包成imx-boot
镜像
在 《IMX_LINUX_USERS_GUIDE.pdf》提到了打包imx-boot
需要的物料。
从文档中得知需要如下部分:
SPL:second program loader,二级程序加载器,为 uboot 的一部分,编译 uboot 的时候会一并编译出;
U-Boot:编译 uboot 的时候一并编译出;
ATF:Arm Trusted Firmware,由 Arm 提供的项目,支持 Arm 架构上的安全启动和运行时需求;
OP-TEE:Open Portable Trusted Execution Environment,开源的可信执行环境(TEE)框架;
Sentinel Firmware:应该就是指 EdgeLock Secure Enclave (ELE) firmware;
DDR PHY Firmware:ddr 固件
UBOOT编译
首先尝试使用NXP官方uboot来尝试一下,然后再用myir官方提供的uboot。
官方uboot编译实践体验
需要提前配置好交叉编译器
git clone https://github.com/nxp-imx/uboot-imx -b lf_v2023.04
cd uboot
make distclean
make imx93_11x11_evk_defconfig
make menuconfig
make -j$(nproc --all)
ls -alh u-boot.bin
ls -alh ./spl/u-boot-spl.bin
ATF 编译
git clone https://github.com/nxp-imx/imx-atf
cd imx-atf
git checkout lf-6.6.3-1.0.0
make help
make PLAT=imx93 bl31
ls -alh build/imx93/release/bl31.bin
ELE 固件下载
wget https://www.nxp.com/lgfiles/NMG/MAD/YOCTO/firmware-ele-imx-0.1.1.bin
chmod u+x firmware-ele-imx-0.1.1.bin
./firmware-ele-imx-0.1.1.bin
ls -alh firmware-ele-imx-0.1.1/mx93a1-ahab-container.img
DDR 固件下载
wget https://www.nxp.com/lgfiles/NMG/MAD/YOCTO/firmware-imx-8.23.bin
chmod u+x firmware-imx-8.23.bin
./firmware-imx-8.23.bin
ls -alh firmware-imx-8.23/firmware/ddr/synopsys/lpddr4*
imx-mkimage 工具下载
git clone https:
cd imx-mkimage
git checkout lf-6.6.3-1.0.0
打包
将上面的生成的固件通过 imx-mkimage
打包成一个文件 flash.bin
cp uboot-imx/u-boot.bin uboot-imx/spl/u-boot-spl.bin imx-mkimage/iMX93/
cp imx-atf/build/imx93/release/bl31.bin imx-mkimage/iMX93/
cp firmware-ele-imx-0.1.1/mx93a1-ahab-container.img imx-mkimage/iMX93/
cp firmware-imx-8.23/firmware/ddr/synopsys/lpddr4* imx-mkimage/iMX93/
cd imx-mkimage
make SOC=iMX9 REV=A1 flash_singleboot
ls -alh iMX93/flash.bin
myir uboot
参考《MYD-LMX9X_Linux软件开发指南.pdf》4.2节,编译成功会在output/1g
文件夹下生成 imx-boot-myd-lmx9x-sd.bin-flash_singleboot
烧录到SD卡
编译出flash.bin
文件,下面将SD卡(此次是64GB)插入Ubuntu系统。
从SD卡32KB开始的位置写flash.bin
,从8MB开始的位置格式化成FAT32boot
分区。
文档《IMX_LINUX_USERS_GUIDE.pdf》中描述,iMX93从0x8000(32KB)开始的位置启动
SD卡设备确认
警告:操作时必须先确认SD卡的设备名,防止操作失误导致数据丢失!
sudo fdisk -l
Disk /dev/sda: 500 GiB, 536870912000 bytes, 1048576000 sectors
Disk model: VMware Virtual S
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0xd6bcc382
Device Boot Start End Sectors Size Id Type
/dev/sda1 * 2048 1050623 1048576 512M b W95 FAT32
/dev/sda2 1052670 1048573951 1047521282 499.5G 5 Extended
/dev/sda5 1052672 1048573951 1047521280 499.5G 83 Linux
Disk /dev/sdb: 58.27 GiB, 62562238464 bytes, 122191872 sectors
Disk model: STORAGE DEVICE
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x00000000
通过以上信息,可以确认SD卡盘设备名为 /dev/sdb
前半部分处理
将SD卡前面的8MB空间全部清零
dd if=/dev/zero of=/dev/sdb bs=1024 count=8096
sync
创建分区
使用fdisk工具创建boot
分区。
新建分区n
,类型 p
,First sector16384
,保存 w
, 退出 q
注意,由于电脑配置差异,SD卡的盘符可能不一致,我这里是 /dev/sdb
,操作不当可能会导致数据丢失。请谨慎操作
sudo fdisk /dev/sdb
Welcome to fdisk (util-linux 2.34).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.
Command (m for help): n
Partition type
p primary (0 primary, 0 extended, 4 free)
e extended (container for logical partitions)
Select (default p): p
Partition number (1-4, default 1):
First sector (2048-122191871, default 2048): 16384
Last sector, +/-sectors or +/-size{K,M,G,T,P} (16384-122191871, default 122191871):
Created a new partition 1 of type 'Linux' and of size 58.3 GiB.
Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.
操作完成检查确认是否出现 /dev/sdb1
sudo fdisk -l
Disk /dev/sdb: 58.27 GiB, 62562238464 bytes, 122191872 sectors
Disk model: STORAGE DEVICE
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x00000000
Device Boot Start End Sectors Size Id Type
/dev/sdb1 16384 122191871 122175488 58.3G 83 Linux
格式化成FAT32
分区,分区名boot
sudo mkfs.vfat -F 32 -n "boot" /dev/sdb1
将之前编译好的flash.bin
写入SD卡32KB开始的位置
dd if=flash.bin of=/dev/sdb bs=32K seek=1 conv=fsync
sync
这样SD卡就处理好了。后面flash.bin
如果有更新,只要执行最后一步就行,之前的boot分区不需要动了。
将SD卡插入开发板,接上串口,开始DEBUG
启动日志
补充 DDR配置
从NXP官方提供的UBOOT源码编译的源码发现启动的时候识别到DDR为2GB,其实开发板只有1GB。
尝试在UBOOT中修改配置,发现无效。
uboot中比较重要和初始化相关的源文件
common/board_f.c
board/freescale/imx93_evk/imx93_evk.c
arch/arm/mach-imx/imx9/native/soc.c
soc.c
中通过读取DDR控制器的得到DDR的大小,所有上面的配置无效。
通过查阅代码,这个DDR控制器的寄存器是在 SPL
阶段配置好的。
在 board/freescale/imx93_evk/spl.c
spl_dram_init
函数通过结构体dram_timing
拿到DDR
的配置信息。
这个 dram_timing
是通过NXP的配置工具Config Tool 生成的。配置1GB的内存,生成c配置文件覆盖board/freescale/imx93_evk/lpddr4x_timing.c
将修改后的uboot重新打包成flash.bin
并烧入SD卡,重新启动开发板成功识别成1GB的内存
结论
我们从头构建了imx-boot,掌握了IMX镜像的原理;还学习了通过Config Tool配置内存的方法。