uboot distro_bootcmd 理解

本文详细剖析了U-Boot的bootcmd中的mmc_autodhcp和bootcmd_dhcp部分,涉及环境变量设置、设备检测、脚本加载与执行,重点讲解了从MMC自动分配和DHCP获取boot.scr的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

uboot distro_bootcmd 理解

从 run distro_bootcmd 开始

distro_bootcmd=
	for target in ${boot_targets};
	do
		run bootcmd_${target};
	done

   
   
   
   
  • 1
  • 2
  • 3
  • 4
  • 5

我的 sun8-h3 板子中 boot_targets 为:

boot_targets=fel mmc_auto usb0 pxe dhcp 

   
   
   
   
  • 1

重点分析 mmc_auto dhcp

bootcmd_mmc_auto

以下变量的值,都可以通过 printenv name 查看的到,不过个别变量定义比较长,无法显示完整,这时需要在源代码中查看: \u-boot-2017.11.git\include\config_distro_bootcmd.h

bootcmd_mmc_auto=run bootcmd_mmc0

   
   
   
   
  • 1
bootcmd_mmc0=setenv devnum 0; run mmc_boot

   
   
   
   
  • 1
mmc_boot=
if mmc dev ${devnum};then            # 测试mmc 是否有分区,有则
	setenv devtype mmc;              # devtype = mmc
    run scan_dev_for_boot_part;      
fi

   
   
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
scan_dev_for_boot_part=                                         
	part list ${devtype} ${devnum} -bootable devplist;     # 这里正常会设置 devplist = 分区列表
	env exists devplist || setenv devplist 1;              # 如果为空,devplist 设置为 1
	for distro_bootpart in ${devplist}; do 
		if fstype ${devtype} ${devnum}:${distro_bootpart} bootfstype; then  # 检测fstype, 并设置 bootfstype=fstype
			run scan_dev_for_boot;                                          # help fstype 可以查看 fstype 用法说明
		fi; 
	done

   
   
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
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;        	
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
boot_prefixes=/ /boot/

 
 
 
 
  • 1
scan_dev_for_extlinux=
	if test -e ${devtype} ${devnum}:${distro_bootpart} ${prefix}extlinux/extlinux.conf; then 
		echo Found ${prefix}extlinux/extlinux.conf;  # 如果找到 ${prefix}extlinux/extlinux.conf 文件,则 boot_extlinux
		run boot_extlinux; 
		echo SCRIPT FAILED: continuing...; 
	fi	

 
 
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
boot_extlinux=
	sysboot ${devtype} ${devnum}:${distro_bootpart} any ${scriptaddr} ${prefix}extlinux/extlinux.conf	
	                                                 # 读取 extlinux.conf 到 $scriptaddr

 
 
 
 
  • 1
  • 2
  • 3
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};   # 如果找到 boot.scr* 文件,则 boot_a_script
			run boot_a_script;
			echo SCRIPT FAILED: continuing...; 
		fi; 
	done
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
boot_scripts=boot.scr.uimg boot.scr

 
 
 
 
  • 1
boot_a_script=
		load ${devtype} ${devnum}:${distro_bootpart} ${scriptaddr} ${prefix}${script};  # 将 script 读到 $scriptaddr
		source ${scriptaddr}                                                            # source 执行 $scriptaddr
  • 1
  • 2
  • 3
  • 4

boot.scr 的原始文件如下

setenv fdt_high ffffffff
setenv loadkernel fatload mmc 0 \$kernel_addr_r uImage
setenv loaddtb fatload mmc 0 \$fdt_addr_r dtb
setenv bootargs console=ttyS0,115200 earlyprintk root=/dev/mmcblk0p2 rootwait
setenv uenvcmd run loadkernel \&\& run loaddtb \&\& bootm \$kernel_addr_r - \$fdt_addr_r
run uenvcmd

 
 
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

bootcmd_dhcp

bootcmd_dhcp=
	if dhcp ${scriptaddr} ${boot_script_dhcp}; then   # 从dhcp server 中下载 boot.scr.uimg 并执行
		source ${scriptaddr}; 
	fi;

 
 
 
 
  • 1
  • 2
  • 3
  • 4
boot_script_dhcp=boot.scr.uimg

 
 
 
 
  • 1

小结:不论是从mmc 启动还是 dhcp 启动,最终的步骤都是一样的,获取 boot.scr 到 scriptaddr , 然后 source scriptaddr

source

source 的用法,用途是从内存执行脚本

=> help source
source - run script from memory

Usage:
source [addr]

  • run script starting at addr
    valid image header must be present

boot.scr

boot.scr 如何生成

在 openwrt/package/boot/uboot-sunxi/Makefile 中,使用mkiamge 生成,输入文件为 uEnv-default.txt

        mkimage -C none -A arm -T script -d uEnv-$(UENV).txt \
                $(STAGING_DIR_IMAGE)/$(BUILD_DEVICES)-boot.scr

 
 
 
 
  • 1
  • 2

uEnv-default.txt

setenv fdt_high ffffffff
setenv loadkernel fatload mmc 0 \$kernel_addr_r uImage
setenv loaddtb fatload mmc 0 \$fdt_addr_r dtb
setenv bootargs console=ttyS0,115200 earlyprintk root=/dev/nfs nfsroot=172.16.10.67:/home/lql/my_rootfs/rootfs,vers=3 ip=dhcp rootwait
setenv uenvcmd run loadkernel \&\& run loaddtb \&\& bootm \$kernel_addr_r - \$fdt_addr_r
run uenvcmd

 
 
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

读取 kernel 和 dtb 到指定内存位置,最后执行 bootm $kernel_addr_r - $fdt_addr_r

bootm

bootm 使用说明:

=> help bootm
bootm - boot application image from memory

Usage:
bootm [addr [arg ...]]
    - boot application image stored in memory
        passing arguments 'arg ...'; when booting a Linux kernel,
        'arg' can be the address of an initrd image
        When booting a Linux kernel which requires a flat device-tree
        a third argument is required which is the address of the
        device-tree blob. To boot that kernel without an initrd image,
        use a '-' for the second argument. If you do not pass a third
        a bd_info struct will be passed instead

Sub-commands to do part of the bootm sequence.  The sub-commands must be
issued in the order below (it's ok to not issue all sub-commands):
        start [addr [arg ...]]
        loados  - load OS image
        ramdisk - relocate initrd, set env initrd_start/initrd_end
        fdt     - relocate flat device tree
        cmdline - OS specific command line processing/setup
        bdt     - OS specific bd_t processing
        prep    - OS specific prep before relocation or go
        go      - start OS

第一个参数为 kernel 地址 ,当 要使用 dtb 时 加上 - 符号, 后接 dtb 地址。

小结:uboot 的使命就是执行 bootm , bootm 正常后,cpu 权限交给kernel ,uboot 宣告退休,直到下一次重启。

### 关于U-Boot中`HEADER_IMAGE_ADDR`的定义及作用 在嵌入式开发领域,特别是基于U-Boot的引导加载程序设计中,`HEADER_IMAGE_ADDR`是一个重要的宏或变量,通常用于指定镜像文件头(header)所在的内存地址。以下是关于其定义和作用的具体说明: #### 定义 `HEADER_IMAGE_ADDR`通常是通过配置文件或者Makefile中的宏定义实现的。它的具体值取决于目标平台的硬件架构以及系统的内存布局。例如,在某些ARM平台上,可能被定义为如下形式: ```c #define HEADER_IMAGE_ADDR 0x80000000 ``` 此地址表示操作系统镜像头部放置的位置[^1]。 #### 作用 1. **镜像验证** `HEADER_IMAGE_ADDR`指向的操作系统镜像头部包含了诸如校验和、版本号以及其他元数据的信息。这些信息对于U-Boot验证镜像的有效性和完整性至关重要。 2. **跳转至内核入口点** 当U-Boot完成必要的初始化工作后,会依据`HEADER_IMAGE_ADDR`所指位置提取实际的内核入口点,并将控制权交给Linux或其他操作系统的启动过程[^3]。 3. **支持多分区或多镜像环境** 在复杂的嵌入式设备中可能存在多个固件或应用镜像的情况下,明确指定`HEADER_IMAGE_ADDR`有助于区分不同部分的功能边界及其加载顺序[^4]。 #### 使用场景举例 假设我们正在处理一个Rockchip RK3568芯片上的OpenHarmony项目,则可能会遇到类似于下面这样的代码片段: ```c #include <common.h> #include <image.h> void board_late_init(void){ ulong header_addr = CONFIG_HEADER_IMAGE_ADDR; /* 假设此处需要读取并打印Header信息 */ image_header_t *hdr = (image_header_t *)header_addr; printf("Image Header Info:\n"); printf("- Magic Number: %lx\n", hdr->ih_magic); } ``` 上述例子展示了如何利用预处理器指令获取`CONFIG_HEADER_IMAGE_ADDR`的实际数值,并将其转换成合适的结构体指针以便进一步访问相关内容[^5]。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值