Differences

This shows you the differences between two versions of the page.

Link to this comparison view

ass:labs-2025:03:tasks:01 [2025/08/06 12:00]
florin.stancu
ass:labs-2025:03:tasks:01 [2026/07/15 15:33] (current)
florin.stancu [01. Automatically booting our Linux]
Line 2: Line 2:
  
 You are probably be tired of using u-boot CLI to load the Linux FIT uImage into RAM and booting it manually. 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!+Surely, there must be something to be done to automate this (yep, there is!).
  
-TODO+First, let's learn about u-boot environment more... Start your board to a ''​u-boot''​ prompt and enter ''​env print''​... 
 + 
 +<spoiler env print output...>​ 
 +<code bash> 
 +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 
 +</​code>​ 
 +</​spoiler>​ 
 + 
 +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: 
 + 
 +<code C> 
 +/* 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 
 +# 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=3 
 +TODO: enter a valid uImage file DRAM load address (the one used with '​bootm'​) 
 +loadaddr=TODO 
 +# TODO: enter the 'load mmc 0 ...' script (will be executed using 'run loadimage'​) 
 +loadimage=TODO 
 +image=linux.itb 
 +# this can be executed using 'run linux' to boot your Linux kernel! 
 +linux=echo Booting Linux ...; run loadimage; bootm ${loadaddr};​ 
 +</​code>​ 
 + 
 +Notice in the original environment that you may use the ''​run''​ command to run scripts from other defined variables, here's its reference:​ 
 +<​code>​ 
 +run - run commands in an environment variable 
 +</​code>​ 
 + 
 +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 ''​ENV_DEFAULT_ENV_TEXT_FILE''​ menuconfig item? Modify it to point to your ''​mydefault.env''​ (you can simply use a relative path to ''​u-boot''​s source dir). Note that you need to enable ''​ENV_USE_DEFAULT_ENV_TEXT_FILE''​ checkbox first to let you modify that value! 
 + 
 +For advanced use cases / build automation, you can override any config items by creating extra .config files and using the included ''​./​scripts/​kconfig/​merge_config.sh''​ u-boot host script! 
 + 
 +Afterwards, [re]compile u-boot, copy the newly compiled u-boot ''​.bin''​ files to ''​imx-mkimage''​ directory again (if not doing it automatically using a Makefile) and regenerate your ''​flash.bin''​. 
 + 
 +Test it by booting your new firmware using ''​uuu''​. 
 +Always check the UBoot version and build time printed on the serial console during the boot process to ensure you loaded your latest firmware image! 
 + 
 +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 (try the ''​gpio''​ command!), but it's out of scope for today (we don't have any physical buttons). 
 + 
 +=== Bonus: load uboot environment from FAT32 partition === 
 + 
 +If you wish to change without uboot'​s environment without recompiling u-boot itself, it's also possible (and very easy to do). 
 + 
 +Since this is usually desirable for flexibility during upgrades, there are many ways to do this: activate one of ''​CONFIG_ENV_IS_IN_*''​ config options or use a startup script which loads the env from a .txt file on the FAT32 partition. We'll prefer the latter since it's more fun (& failproof on most boards!). 
 + 
 +Basically, we will write a custom script to be executed by u-boot at startup. To do this, search for the ''​PREBOOT''​ config item inside u-boot'​s ''​menuconfig''​. 
 +Since we added a custom default.env file, we need to activate ''​USE_PREBOOT''​ and specify our script as a hardcoded ''​preboot=''​ environment variable. 
 + 
 +Sample script: 
 +<​code>​ 
 +preboot=if fatload mmc 0:1 ${loadaddr} uboot.txt; then env import -t ${loadaddr} ${filesize};​ fi 
 +</​code>​ 
 + 
 +That's it! Create this file on your board'​s FAT32 partition (using the same ''​key=value''​ assignments separated by newlines syntax) and boot it! You should now see your new environment values (''​env print''​)!
  
ass/labs-2025/03/tasks/01.1754470839.txt.gz · Last modified: 2025/08/06 12:00 by florin.stancu
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0