You are probably be tired of using u-boot CLI to load the Linux FIT uImage into RAM and booting it manually.
Surely, there must be something to be done to automate this… and you're right! Let's learn to do this!
First, boot your board into u-boot
prompt. Enter env print
…
arch=arm
auth_os=auth_cntr ${cntr_addr}
baudrate=115200
board=imx93_frdm
board_name=imx93_frdm
boot_a_script=load ${devtype} ${devnum}:${distro_bootpart} ${scriptaddr} ${prefix}${script}; source ${scriptaddr}
boot_efi_binary=load ${devtype} ${devnum}:${distro_bootpart} ${kernel_addr_r} efi/boot/bootaa64.efi; if fdt addr -q ${fdt_addr_r}; then bootefi ${kernel_addr_r} ${fdt_addr_r};else bootefi ${kernel_addr_r} ${fdtcontroladdr};fi
boot_efi_bootmgr=if fdt addr -q ${fdt_addr_r}; then bootefi bootmgr ${fdt_addr_r};else bootefi bootmgr;fi
boot_extlinux=sysboot ${devtype} ${devnum}:${distro_bootpart} any ${scriptaddr} ${prefix}${boot_syslinux_conf}
boot_fit=no
boot_net_usb_start=usb start
boot_os=booti ${loadaddr} - ${fdt_addr_r};
boot_prefixes=/ /boot/
boot_script_dhcp=boot.scr.uimg
boot_scripts=boot.scr.uimg boot.scr
boot_syslinux_conf=extlinux/extlinux.conf
boot_targets=mmc0 mmc1 usb0
bootargs=console=ttyLP0,115200 earlycon,115200 rdinit=/linuxrc clk_ignore_unused
bootcmd=run sr_ir_v2_cmd;run distro_bootcmd;run bsp_bootcmd
bootcmd_mfg=run mfgtool_args;if iminfo ${initrd_addr}; then if test ${tee} = yes; then bootm ${tee_addr} ${initrd_addr} ${fdt_addr}; else booti ${loadaddr} ${initrd_addr} ${fdt_addr}; fi; else echo "Run fastboot ..."; fastboot auto; fi;
bootcmd_mmc0=devnum=0; run mmc_boot
bootcmd_mmc1=devnum=1; run mmc_boot
bootcmd_usb0=devnum=0; run usb_boot
bootdelay=2
bootm_size=0x10000000
bootscript=echo Running bootscript from mmc ...; source
bsp_bootcmd=echo Running BSP bootcmd ...; mmc dev ${mmcdev}; if mmc rescan; then if run loadbootscript; then run bootscript; else if test ${sec_boot} = yes; then if run loadcntr; then run mmcboot; else run netboot; fi; else if run loadimage; then run mmcboot; else run netboot; fi; fi; fi; fi;
cntr_addr=0x98000000
cntr_file=os_cntr_signed.bin
console=ttyLP0,115200 earlycon
cpu=armv8
distro_bootcmd=for target in ${boot_targets}; do run bootcmd_${target}; done
efi_dtb_prefixes=/ /dtb/ /dtb/current/
emmc_dev=0
ethprime=eth1
fdt_addr=0x83000000
fdt_addr_r=0x83000000
fdt_high=0xffffffffffffffff
fdtfile=imx93-11x11-frdm.dtb
image=Image
initrd_addr=0x83800000
initrd_high=0xffffffffffffffff
jh_mmcboot=setenv fdtfile ${jh_root_dtb}; setenv jh_clk clk_ignore_unused mem=1248MB kvm-arm.mode=nvhe; if run loadimage; then run mmcboot;else run jh_netboot; fi;
jh_netboot=setenv fdtfile ${jh_root_dtb}; setenv jh_clk clk_ignore_unused mem=1248MB kvm-arm.mode=nvhe; run netboot;
jh_root_dtb=imx93-11x11-frdm-root.dtb
kboot=booti
kernel_addr_r=0x80400000
load_efi_dtb=load ${devtype} ${devnum}:${distro_bootpart} ${fdt_addr_r} ${prefix}${efi_fdtfile}
loadaddr=0x80400000
loadbootscript=fatload mmc ${mmcdev}:${mmcpart} ${loadaddr} ${script};
loadcntr=fatload mmc ${mmcdev}:${mmcpart} ${cntr_addr} ${cntr_file}
loadfdt=fatload mmc ${mmcdev}:${mmcpart} ${fdt_addr_r} ${fdtfile}
loadimage=fatload mmc ${mmcdev}:${mmcpart} ${loadaddr} ${image}
mfgtool_args=setenv bootargs console=${console},${baudrate} rdinit=/linuxrc clk_ignore_unused
mmc_boot=if mmc dev ${devnum}; then devtype=mmc; run scan_dev_for_boot_part; fi
mmcargs=setenv bootargs ${jh_clk} ${mcore_clk} console=${console} root=${mmcroot}
mmcautodetect=yes
mmcboot=echo Booting from mmc ...; run mmcargs; if test ${sec_boot} = yes; then if run auth_os; then run boot_os; else echo ERR: failed to authenticate; fi; else if test ${boot_fit} = yes || test ${boot_fit} = try; then bootm ${loadaddr}; else if run loadfdt; then run boot_os; else echo WARN: Cannot load the DT; fi; fi;fi;
mmcdev=0
mmcpart=1
mmcroot=/dev/mmcblk1p2 rootwait rw
netargs=setenv bootargs ${jh_clk} ${mcore_clk} console=${console} root=/dev/nfs ip=dhcp nfsroot=${serverip}:${nfsroot},v3,tcp
netboot=echo Booting from net ...; run netargs; if test ${ip_dyn} = yes; then setenv get_cmd dhcp; else setenv get_cmd tftp; fi; if test ${sec_boot} = yes; then ${get_cmd} ${cntr_addr} ${cntr_file}; if run auth_os; then run boot_os; else echo ERR: failed to authenticate; fi; else ${get_cmd} ${loadaddr} ${image}; if test ${boot_fit} = yes || test ${boot_fit} = try; then bootm ${loadaddr}; else if ${get_cmd} ${fdt_addr_r} ${fdtfile}; then run boot_os; else echo WARN: Cannot load the DT; fi; fi;fi;
nodes=/usbg1 /usbg2 /wdt-reboot /rm67199_panel /dsi-host /display-subsystem /soc@0/bus@44000000/dma-controller@44000000 /soc@0/bus@44000000/sai@443b0000 /soc@0/bus@44000000/mqs1 /soc@0/bus@44000000/bbnsm@44440000 /soc@0/bus@44000000/system-controller@44460000 /soc@0/bus@44000000/tmu@44482000 /soc@0/bus@44000000/micfil@44520000 /soc@0/bus@42000000/dma-controller@42000000 /soc@0/bus@44000000/i3c-master@44330000 /soc@0/bus@42000000/i3c-master@42520000 /soc@0/bus@42000000/sai@42650000 /soc@0/bus@42000000/sai@42660000 /soc@0/bus@42000000/mqs2 /soc@0/bus@42000000/xcvr@42680000 /soc@0/bus@42000000/flexio@425c0000 /soc@0/bus@42800000/epxp@4ae20000 /soc@0/bus@42800000/camera /soc@0/efuse@47510000 /soc@0/system-controller@4ac10000 /soc@0/ldb@4ac10020 /soc@0/phy@4ac10024 /soc@0/ele-mu /soc@0/dsi@4ae10000 /soc@0/lcd-controller@4ae30000 /soc@0/blk-ctrl@4e010000 /soc@0/memory-controller@4e300000 /soc@0/bus@44000000/i2c@44350000/pmic@25 /imx93-lpm
prepare_mcore=setenv mcore_clk clk-imx93.mcore_booted;
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 part uuid ${devtype} ${devnum}:${distro_bootpart} distro_bootpart_uuid ; run scan_dev_for_boot; fi; done; setenv devplist
scan_dev_for_efi=setenv efi_fdtfile ${fdtfile}; for prefix in ${efi_dtb_prefixes}; do if test -e ${devtype} ${devnum}:${distro_bootpart} ${prefix}${efi_fdtfile}; then run load_efi_dtb; fi;done;run boot_efi_bootmgr;if test -e ${devtype} ${devnum}:${distro_bootpart} efi/boot/bootaa64.efi; then echo Found EFI removable media binary efi/boot/bootaa64.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 EXTLINUX 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
scriptaddr=0x83500000
sd_dev=1
sec_boot=no
soc=imx9
splashimage=0x90000000
sr_ir_v2_cmd=cp.b ${fdtcontroladdr} ${fdt_addr_r} 0x10000;fdt addr ${fdt_addr_r};fdt resize 0x400;fdt set /soc@0/bus@44000000/i2c@44350000/gpio@34 compatible adi,adp5585;for i in ${nodes}; do fdt rm ${i}; done
usb_boot=usb start; if usb dev ${devnum}; then devtype=usb; run scan_dev_for_boot_part; fi
vendor=freescale
Environment size: 7010/16380 bytes
Notice various environment variables? There are various addresses, strings and even scripts! Can you figure out the command executed automatically at boot?
We hope you're getting the same idea… what if we can modify this environment when compiling U-Boot such that it executes our own script?
The KConfig item for doing this is called something like DEFAULT_ENV
, try searching for it!
It allows us to specify a custom file that contains our default environment…
First, let's create this file, let's say mydefault.env
inside the uboot source directory. Let's start from a minimal example:
/* default u-boot environment variables */
/* this file is passed through the C preprocessor (so we can use C-style macros!) */
/* someone in uboot source code re-defined `linux`... */
#undef linux
arch=arm
baseboard=autodetect
baudrate=115200
mmcdev=0
mmcpart=1
emmc_dev=0
console=ttyLP0
bootargs=console=ttyLP0,115200 earlycon,115200 rdinit=/linuxrc clk_ignore_unused
# TODO: this is the command executed automatically when uboot starts...
bootcmd=echo Fastboot mode... press Ctrl-C to exit; fastboot auto
# This runs instead of bootcmd when booted using `uuu` via USB
bootcmd_mfg=run bootcmd
bootdelay=2
image=linux.itb
loadaddr=TODO
loadimage=TODO
linux=echo Booting Linux ...; run loadimage; bootm ${loadaddr};
Notice in the original environment that you may use the run
command to run scripts from other defined variables, here's its reference:
run - run commands in an environment variable
We can also use ${varname}
expressions to do variable expansion like in Linux shells!
Enter your boot script inside the bootcmd
var and let's proceed with overwriting the default environment.
Recall the DEFAULT_ENV
menuconfig item? Modify it to point to your mydefault.env
(you can simply use a relative path). Note that you need to enable USE_DEFAULT_ENV_FILE
checkbox first to let you supply your value!
Afterwards, [re]compile u-boot, copy the u-boot .bin
files again to the imx-mkimage
directory and regenerate your flash.bin
.
Test it by booting your new firmware using uuu
.
Try using run linux
to run the linux
script (if you used that), otherwise edit the bootcmd
to do that automatically after the timeout!
Did it work? if not, you may need to repeat this process (this is where a script comes in handy!).
Note that real devices have their uboot configuration proceed automatically with booting the OS if a physical button is NOT pressed (remember those old Android phones? you could stop this process by holding several volume keys together!). You can script this using GPIO, but it's out of scope for today.