stm32mp1 uboot启动流程分析
本节主要关注uboot启动linux的流程,首先关注下uboot的环境变量
uboot环境变量
进入uboot以后回车输入print即可看到uboot的所有环境变量:
这里很多变量嵌套了一些流程,整理一下格式:
altbootcmd=run bootcmd
arch=arm
autoload=no
baudrate=115200
board=stm32mp1
board_name=stm32mp157d-robot
boot_a_script=load ${devtype} ${devnum}:${distro_bootpart} ${scriptaddr} ${prefix}${script}; source ${scriptaddr}
boot_device=mmc
boot_efi_binary=
if fdt addr ${fdt_addr_r}; then
bootefi bootmgr ${fdt_addr_r};
else
bootefi bootmgr ${fdtcontroladdr};
fi;
load ${devtype} ${devnum}:${distro_bootpart} ${kernel_addr_r} efi/boot/bootarm.efi;
if fdt addr ${fdt_addr_r}; then
bootefi ${kernel_addr_r} ${fdt_addr_r};
else
bootefi ${kernel_addr_r} ${fdtcontroladdr};
fi
boot_extlinux=sysboot ${devtype} ${devnum}:${distro_bootpart} any ${scriptaddr} ${prefix}${boot_syslinux_conf}
boot_instance=0
boot_m4fw=rproc init; rproc load 0 ${m4fw_addr} ${filesize}; rproc start 0
boot_net_usb_start=true
boot_prefixes=/ /boot/
boot_script_dhcp=boot.scr.uimg
boot_scripts=boot.scr.uimg boot.scr
boot_syslinux_conf=extlinux/extlinux.conf
boot_targets=mmc1 ubifs0 mmc0 mmc2 pxe
bootcmd=run bootcmd_stm32mp
bootcmd_mmc0=devnum=0; run mmc_boot
bootcmd_mmc1=devnum=1; run mmc_boot
bootcmd_mmc2=devnum=2; run mmc_boot
bootcmd_pxe=run boot_net_usb_start; dhcp; if pxe get; then pxe boot; fi
bootcmd_stm32mp=
echo "Boot over ${boot_device}${boot_instance}!";
if test ${boot_device} = serial || test ${boot_device} = usb;then
stm32prog ${boot_device} ${boot_instance};
else
run env_check;
if test ${boot_device} = mmc;then
env set boot_targets "mmc${boot_instance}";
fi;
if test ${boot_device} = nand || test ${boot_device} = spi-nand ;then
env set boot_targets ubifs0;
fi;
if test ${boot_device} = nor;then
env set boot_targets mmc0;
fi;
run distro_bootcmd;
fi;
bootcmd_ubifs0=devnum=0; run ubifs_boot
bootcount=4
bootdelay=1
bootfstype=ext4
cpu=armv7
distro_bootcmd=
for target in ${boot_targets};
do
run bootcmd_${target};
done
efi_dtb_prefixes=/ /dtb/ /dtb/current/
env_check=if env info -p -d -q; then env save; fi
fdt_addr_r=0xc4000000
fdtcontroladdr=f3ae4d20
fdtfile=stm32mp157d-robot.dtb
fdtoverlay_addr_r=0xc4100000
fileaddr=c4100000
filesize=b7f
kernel_addr_r=0xc2000000
load_efi_dtb=load ${devtype} ${devnum}:${distro_bootpart} ${fdt_addr_r} ${prefix}${efi_fdtfile}
loadaddr=0xc2000000
m4fw_addr=0xc2000000
m4fw_name=rproc-m4-fw.elf
mmc_boot=
if mmc dev ${devnum}; then
devtype=mmc;
run scan_dev_for_boot_part;
fi
pxefile_addr_r=0xc4200000
ramdisk_addr_r=0xc4400000
scan_dev_for_boot=
echo Scanning ${devtype} ${devnum}:${distro_bootpart}...;
for prefix in ${boot_prefixes};
do
run scan_dev_for_extlinux;
run scan_dev_for_scripts;
done;
run scan_dev_for_efi;
scan_dev_for_boot_part=
part list ${devtype} ${devnum} -bootable devplist;
env exists devplist || setenv devplist 1;
for distro_bootpart in ${devplist};
do
if fstype ${devtype} ${devnum}:${distro_bootpart} bootfstype; then
run scan_dev_for_boot;
fi;
done;
setenv devplist
scan_dev_for_efi=
setenv efi_fdtfile ${fdtfile};
if test -z "${fdtfile}" -a -n "${soc}"; then
setenv efi_fdtfile ${soc}-${board}${boardver}.dtb;
fi;
for prefix in ${efi_dtb_prefixes};
do
if test -e ${devtype} ${devnum}:${distro_bootpart} ${prefix}${efi_fdtfile}; then
run load_efi_dtb;
fi;
done;
if test -e ${devtype} ${devnum}:${distro_bootpart} efi/boot/bootarm.efi; then
echo Found EFI removable media binary efi/boot/bootarm.efi;
run boot_efi_binary; echo EFI LOAD FAILED: continuing...;
fi;
setenv efi_fdtfile
scan_dev_for_extlinux=
if test -e ${devtype} ${devnum}:${distro_bootpart} ${prefix}${boot_syslinux_conf}; then
echo Found ${prefix}${boot_syslinux_conf};
run boot_extlinux;
echo SCRIPT FAILED: continuing...;
fi
scan_dev_for_scripts=
for script in ${boot_scripts};
do
if test -e ${devtype} ${devnum}:${distro_bootpart} ${prefix}${script}; then
echo Found U-Boot script ${prefix}${script};
run boot_a_script;
echo SCRIPT FAILED: continuing...;
fi;
done
scan_m4fw=
if test -e ${devtype} ${devnum}:${distro_bootpart} ${m4fw_name};then
echo Found M4 FW $m4fw_name;
if load ${devtype} ${devnum}:${distro_bootpart} ${m4fw_addr} ${m4fw_name}; then
run boot_m4fw;
fi;
fi;
scriptaddr=0xc4100000
serial#=003A002B3030511039383538
serverip=192.168.1.1
soc=stm32mp
splashimage=0xc4300000
ubifs_boot=
env exists bootubipart || env set bootubipart UBI;
env exists bootubivol || env set bootubivol boot;
if ubi part ${bootubipart} && ubifsmount ubi${devnum}:${bootubivol}; then
devtype=ubi;
run scan_dev_for_boot;
fi
usb_boot=
usb start;
if usb dev ${devnum}; then
devtype=usb;
run scan_dev_for_boot_part;
fi
vendor=st
Environment size: 4413/8187 bytes
我们都知道uboot bootcmd环境变量 保存着 uboot 默认命令, uboot 倒计时结束以后就会执行 bootcmd 中的命令。我们从bootcmd 开始梳理一下启动linux的流程:
bootcmd=run bootcmd_stm32mp
bootcmd_stm32mp=
echo "Boot over ${boot_device}${boot_instance}!"; # ${boot_device}${boot_instance}: mmc0(sdcard 启动)
run env_check;
if test ${boot_device} = mmc;then
env set boot_targets "mmc${boot_instance}"; # 设置boot_targets mmc0
fi;
run distro_bootcmd;
distro_bootcmd=
for target in ${boot_targets};
do
run bootcmd_${target}; # run bootcmd_mmc0
done
bootcmd_mmc0=
devnum=0; # devnum=0
run mmc_boot
mmc_boot=
if mmc dev ${devnum}; then
devtype=mmc; # devtype=mmc
run scan_dev_for_boot_part;
fi
下面重点看下scan_dev_for_boot_part 这个变量:
scan_dev_for_boot_part=
part list ${devtype} ${devnum} -bootable devplist; #查看mmc0的boot分区
env exists devplist || setenv devplist 1;
for distro_bootpart in ${devplist};
do
if fstype ${devtype} ${devnum}:${distro_bootpart} bootfstype; then
run scan_dev_for_boot;
fi;
done;
setenv devplist
part list mmc 0 就是查看mmc0的分区情况,如下图所示
所以上面scan_dev_for_boot_part就是查看mmc0的分区里面是否有bootfs的分区lable,如果有找到分区号,对应上面的4分区,接着执行scan_dev_for_boot,接着看
scan_dev_for_boot=
echo Scanning ${devtype} ${devnum}:${distro_bootpart}...; # 变量对应mmc0:4
for prefix in ${boot_prefixes}; # ${boot_prefixes}:/ /boot/
do
run scan_dev_for_extlinux;
run scan_dev_for_scripts;
done;
run scan_dev_for_efi;
scan_dev_for_extlinux=
下面重要的两个函数scan_dev_for_extlinux 和 scan_dev_for_scripts,先看scan_dev_for_extlinux:
scan_dev_for_extlinux=
if test -e ${devtype} ${devnum}:${distro_bootpart} ${prefix}${boot_syslinux_conf}; then #变量对应:mmc 0:4 (/extlinux/extlinux.conf /boot/extlinux/extlinux.conf)
echo Found ${prefix}${boot_syslinux_conf};
run boot_extlinux;
echo SCRIPT FAILED: continuing...;
fi
boot_extlinux=
sysboot ${devtype} ${devnum}:${distro_bootpart} any ${scriptaddr} ${prefix}${boot_syslinux_conf}
---> sysboot mmc 0:4 any 0xc4100000 (/extlinux/extlinux.conf /boot/extlinux/extlinux.conf)
主要就是查找SD卡boot分区里面/ 和/boot两个路径下是否存在extlinux.conf文件,如果存在就执行boot_extlinux
接着看scan_dev_for_scripts:
scan_dev_for_scripts=
for script in ${boot_scripts}; # boot.scr.uimg boot.scr
do
if test -e ${devtype} ${devnum}:${distro_bootpart} ${prefix}${script}; then # mmc 0:4 (/boot.scr.uimg /boot.scr /boot/boot.scr.uimg /boot/boot.scr)
echo Found U-Boot script ${prefix}${script};
run boot_a_script;
echo SCRIPT FAILED: continuing...;
fi;
done
boot_a_script=
load ${devtype} ${devnum}:${distro_bootpart} ${scriptaddr} ${prefix}${script}; source ${scriptaddr}
---> load mmc 0:4 0xc4100000 (/boot.scr.uimg /boot.scr /boot/boot.scr.uimg /boot/boot.scr)
---> source 0xc4100000
scan_dev_for_scripts主要就是查找SD卡boot分区里面/ 和/boot两个路径下是否存在boot.scr.uimg和boot.scr文件,如果存在就执行boot_a_script
以原子开发板为例,我们使用ls mmc 0:4查看下boot分区的具体内容如下,可以看到没有提供extlinux.conf,提供了一个boot.scr.uimg
搜以执行到这里其实最后会走到
load mmc 0:4 0xc4100000 /boot.scr.uimg
source 0xc4100000
boot.scr.uimg这个其实是一个脚本, st 在yocto里描述boot.scr.uimg可以使用mkimage来生成我这里直接贴st yocto里面 boot.src.cmd 的源码:
echo "Executing SCRIPT on target=${target}"
# M4 Firmware load
env set m4fw_name "rproc-m4-fw.elf"
env set m4fw_addr ${kernel_addr_r}
env set boot_m4fw 'rproc init; rproc load 0 ${m4fw_addr} ${filesize}; rproc start 0'
# boot M4 Firmware when available
env set scan_m4fw 'if test -e ${devtype} ${devnum}:${distro_bootpart} ${m4fw_name};then echo Found M4 FW $m4fw_name; if load ${devtype} ${devnum}:${distro_bootpart} ${m4fw_addr} ${m4fw_name}; then run boot_m4fw; fi; fi;'
# management of overlay
env set ov_init 'load ${devtype} ${devnum}:${distro_bootpart} ${fdt_addr_r} ${fdtfile} && env set fdt_addr ${fdt_addr_r} && fdt addr ${fdt_addr} && setexpr fdtovaddr ${fdt_addr} + C0000'
env set ov_apply 'test -n ${fdtovaddr} && test -n ${overlay} && for ov in ${overlay}; do echo overlaying ${ov}...; load ${devtype} ${devnum}:${distro_bootpart} ${fdtovaddr} /overlays/${ov}.dtbo && fdt resize ${filesize} && fdt apply ${fdtovaddr}; done'
env set scan_overlays 'if test -e ${devtype} ${devnum}:${distro_bootpart} /overlays/overlays.txt && load ${devtype} ${devnum}:${distro_bootpart} ${loadaddr} /overlays/overlays.txt && env import -t ${loadaddr} ${filesize}; then echo loaded overlay.txt: ${overlay}; run ov_init; run ov_apply; fi'
# Update the DISTRO command to search in sub-directory and load M4 firmware
env set boot_prefixes "/${boot_device}${boot_instance}_"
env set boot_extlinux "run scan_m4fw;run scan_overlays; ${boot_extlinux}"
# save the boot config for the 2nd boot
env set boot_targets ${target}
# when {boot_device} = nor, use ${target} = the location of U-Boot
# script boot.scr.img found in DISTRO script
# value can be "mmc0" (SD Card), "mmc1" (eMMC) or "ubifs0" (NAND)
if test ${target} = mmc0; then
if test -d ${devtype} ${devnum}:${distro_bootpart} /mmc0_extlinux; then
env set boot_prefixes "/mmc0_"
fi
elif test ${target} = mmc1; then
if test -d ${devtype} ${devnum}:${distro_bootpart} /mmc1_extlinux; then
env set boot_prefixes "/mmc1_"
fi
elif test ${target} = ubifs0; then
if test -d ${devtype} ${devnum}:${distro_bootpart} /nand0_extlinux; then
env set boot_prefixes "/nand0_"
fi
fi
if test -e ${devtype} ${devnum}:${distro_bootpart} ${boot_prefixes}extlinux/${board_name}_extlinux.conf; then
echo FOUND ${boot_prefixes}extlinux/${board_name}_extlinux.conf
env set boot_syslinux_conf "extlinux/${board_name}_extlinux.conf"
fi
# don't save the updated content of bootfile variable to avoid conflict
env delete bootfile
# save the boot config the 2nd boot (boot_prefixes/boot_extlinux)
env save
# start the correct exlinux.conf
run bootcmd_${target}
echo SCRIPT FAILED... ${boot_prefixes}${boot_syslinux_conf} not found !
# restore environment to default value when failed
env default boot_targets
env default boot_prefixes
env default boot_extlinux
env default boot_syslinux_conf
env save
我们简单过一下boot.src.cmd的流程:
- 设置一些环境变量用来启动M4内核
- 查找bootfs分区下面的extlinux.conf来选择特定的启动配置,包括设备树、镜像、启动命令等等
- 确定号上面的配置以后最后再
我这边uboot是我自己移植的,暂时还没有修改boot分区里面的东西暂时服用原子的,可以看到我运行出错了:
这里脚本找的路径是mmc0_extlinux/extlinux.conf ,而上面原子的boot分区里面只有mmc0_extlinux/stm32mp157d-atk_extlinux.conf。
这里就涉及到yocto bootfs镜像里面的内容了,这部分下节单独再开一章来分析。
找到extlinux.conf 以后执行 sysboot mmc 0:4 any 0xc4100000 xxx_extlinux.conf 就会根据配置启动linux内核了。
本节告一段落