AMD Xilinx U-Boot 2020.2 找不到文件“boot.scr”,导致启动失败,报告错误“Wrong image format for "source" command”

U-Boot 2020.2 启动问题

最近有客户反馈,U-Boot 2020.2 启动有问题。 SD卡里有BOOT.BIN, image.ub等文件,也不能正常启动。

下面是常见的启动信息。 U-Boot报告多个错误,最主要的错误是“Wrong image format for "source" command”。

U-Boot 2020.01 (Nov 20 2020 - 19:24:17 +0000)

Model: ZynqMP ZCU106 RevA
Board: Xilinx ZynqMP
DRAM:  4 GiB
PMUFW:  v1.1
EL Level:       EL2
Chip ID:        zu7ev
NAND:  0 MiB
MMC:   mmc@ff170000: 0
In:    serial@ff000000
Out:   serial@ff000000
Err:   serial@ff000000
Bootmode: LVL_SHFT_SD_MODE1
Reset reason:   EXTERNAL
Net:
ZYNQ GEM: ff0e0000, mdio bus ff0e0000, phyaddr 12, interface rgmii-id

Warning: ethernet@ff0e0000 using MAC address from ROM
eth0: ethernet@ff0e0000
Hit any key to stop autoboot:  0
switch to partitions #0, OK
mmc0 is current device
Scanning mmc 0:1...
JTAG: Trying to boot script at 0x20000000
## Executing script at 20000000
Wrong image format for "source" command
JTAG: SCRIPT FAILED: continuing...
switch to partitions #0, OK
mmc0 is current device
Scanning mmc 0:1...
MMC Device 1 not found
no mmc device at slot 1
SF: Detected n25q512a with page size 512 Bytes, erase size 128 KiB, total 128 MiB
device 0 offset 0x3e80000, size 0x80000
SF: 524288 bytes @ 0x3e80000 Read: OK
QSPI: Trying to boot script at 0x20000000
## Executing script at 20000000
Wrong image format for "source" command
QSPI: SCRIPT FAILED: continuing...


no devices available
NAND: SCRIPT FAILED: continuing...
starting USB...
Bus dwc3@fe200000: usb maximum-speed not found
Register 2000440 NbrPorts 2
Starting the controller
USB XHCI 1.00
scanning bus dwc3@fe200000 for devices... 1 USB Device(s) found
       scanning usb for storage devices... 0 Storage Device(s) found

Device 0: unknown device

Device 1: unknown device
scanning bus for devices...
SATA link 0 timeout.
SATA link 1 timeout.
AHCI 0001.0301 32 slots 2 ports 6 Gbps 0x3 impl SATA mode
flags: 64bit ncq pm clo only pmp fbss pio slum part ccc apst

Device 0: unknown device
BOOTP broadcast 1
DHCP client bound to address 10.164.16.148 (166 ms)
*** ERROR: `serverip' not set
Cannot autoload with TFTPGET
missing environment variable: pxeuuid
Retrieving file: pxelinux.cfg/01-00-0a-35-04-d2-38
*** ERROR: `serverip' not set
Retrieving file: pxelinux.cfg/0AA41094
*** ERROR: `serverip' not set
Retrieving file: pxelinux.cfg/0AA4109
*** ERROR: `serverip' not set
Retrieving file: pxelinux.cfg/0AA410
*** ERROR: `serverip' not set
Retrieving file: pxelinux.cfg/0AA41
*** ERROR: `serverip' not set
Retrieving file: pxelinux.cfg/0AA4
*** ERROR: `serverip' not set
Retrieving file: pxelinux.cfg/0AA
*** ERROR: `serverip' not set
Retrieving file: pxelinux.cfg/0A
*** ERROR: `serverip' not set
Retrieving file: pxelinux.cfg/0
*** ERROR: `serverip' not set
Retrieving file: pxelinux.cfg/default-arm-zynqmp-zynqmp
*** ERROR: `serverip' not set
Retrieving file: pxelinux.cfg/default-arm-zynqmp
*** ERROR: `serverip' not set
Retrieving file: pxelinux.cfg/default-arm
*** ERROR: `serverip' not set
Retrieving file: pxelinux.cfg/default
*** ERROR: `serverip' not set
Config file not found
BOOTP broadcast 1
DHCP client bound to address 10.164.16.148 (164 ms)
*** ERROR: `serverip' not set
Cannot autoload with TFTPGET
BOOTP broadcast 1
DHCP client bound to address 10.164.16.148 (176 ms)
*** ERROR: `serverip' not set
Cannot autoload with TFTPGET

问题原因和解决办法

上述问题是在启动设备里没有文件“boot.scr”导致的。 如果在SD卡里,提供文件 boot.scr,就能正常启动。

U-Boot 2020.01 (Nov 20 2020 - 19:24:17 +0000)

Model: ZynqMP ZCU106 RevA
Board: Xilinx ZynqMP
DRAM:  4 GiB
PMUFW:  v1.1
EL Level:       EL2
Chip ID:        zu7ev
NAND:  0 MiB
MMC:   mmc@ff170000: 0
In:    serial@ff000000
Out:   serial@ff000000
Err:   serial@ff000000
Bootmode: LVL_SHFT_SD_MODE1
Reset reason:   EXTERNAL
Net:
ZYNQ GEM: ff0e0000, mdio bus ff0e0000, phyaddr 12, interface rgmii-id

Warning: ethernet@ff0e0000 using MAC address from ROM
eth0: ethernet@ff0e0000
Hit any key to stop autoboot:  0
switch to partitions #0, OK
mmc0 is current device
Scanning mmc 0:1...
Found U-Boot script /boot.scr
1718 bytes read in 21 ms (79.1 KiB/s)
## Executing script at 20000000
124511736 bytes read in 8225 ms (14.4 MiB/s)
## Loading kernel from FIT Image at 10000000 ...
   Using 'conf@system-top.dtb' configuration
   Trying 'kernel@1' kernel subimage
......

U-Boot 2020.2 启动流程分析

U-Boot 文档

U-Boot为了支持各种Linux发行版,增加通用性,增加了启动时的Script的功能。 详细信息可以参考文档文件doc/develop/distro.rst和Generic Distro Configuration Concept

U-Boot对Script是逐步完善的。软件代码文件“include/config_distro_bootcmd.h”在2015.01就已经存在。文档文件“doc/develop/distro.rst”在2022.01里加入。

业界对Script功能也逐步接受,目前很多芯片都都已经默认使能,比如AMD的MPSoC的U-Boot。

如果不想使用Script功能,可以禁止选项CONFIG_DISTRO_DEFAULTS。

U-Boot启动命令

没有人工参与的自动启动,或者直接执行命令“boot”, U-Boot启动命令都是“bootcmd”。

超时启动代码

下面是没有人工参与,超时启动时选择启动命令的代码。

const char *bootdelay_process(void)
{
    char *s;
    int bootdelay;

    bootcount_inc();

    s = env_get("bootdelay");
    bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;

    if (IS_ENABLED(CONFIG_OF_CONTROL)) {
        bootdelay = ofnode_conf_read_int("bootdelay", bootdelay);
    }

    debug("### main_loop entered: bootdelay=%d\n\n", bootdelay);

    if (IS_ENABLED(CONFIG_AUTOBOOT_MENU_SHOW)) {
        bootdelay = menu_show(bootdelay);
    }
    bootretry_init_cmd_timeout();

#ifdef CONFIG_POST
    if (gd->flags & GD_FLG_POSTFAIL) {
        s = env_get("failbootcmd");
    } else
#endif /* CONFIG_POST */
        if (bootcount_error()) {
            s = env_get("altbootcmd");
        } else {
            s = env_get("bootcmd");
        }

    if (IS_ENABLED(CONFIG_OF_CONTROL)) {
        process_fdt_options(gd->fdt_blob);
    }
    stored_bootdelay = bootdelay;

    return s;
}

命令“boot”的启动代码

下面是直接执行命令“boot”选择启动命令的代码。

int do_bootd(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
{
    return run_command(env_get("bootcmd"), flag);
}

U_BOOT_CMD(
    boot,	1,	1,	do_bootd,
    "boot default, i.e., run 'bootcmd'",
    ""
);

/* keep old command name "bootd" for backward compatibility */
U_BOOT_CMD(
    bootd, 1,	1,	do_bootd,
    "boot default, i.e., run 'bootcmd'",
    ""
);

命令distro_bootcmd

启动命令“bootcmd”通常是“run distro_bootcmd”。 它在“boot\Kconfig”中定义,能在配置U-Boot时更改。

config BOOTCOMMAND
	string "bootcmd value"
	depends on USE_BOOTCOMMAND && !USE_DEFAULT_ENV_FILE
	default "run distro_bootcmd" if DISTRO_DEFAULTS
	help
	  This is the string of commands that will be used as bootcmd and if
	  AUTOBOOT is set, automatically run.

“distro_bootcmd”的定义在include\Config_distro_bootcmd.h里。

	"distro_bootcmd=" BOOTENV_SET_SCSI_NEED_INIT                      \
		BOOTENV_SET_NVME_NEED_INIT                                \
		BOOTENV_SET_IDE_NEED_INIT                                 \
		BOOTENV_SET_VIRTIO_NEED_INIT                              \
		"for target in ${boot_targets}; do "                      \
			"run bootcmd_${target}; "                         \
		"done\0"

在U-Boot启动时,使用键盘进入U-Boot的命令行界面,使用命令“printenv”也可以查看真实的“distro_bootcmd”。 与“distro_bootcmd”相关的环境变量如下:

boot_a_script=load ${devtype} ${devnum}:${distro_bootpart} ${scriptaddr} ${prefix}${script}; source ${scriptaddr}

boot_scripts=boot.scr.uimg boot.scr

boot_targets=mmc0 jtag mmc0 mmc1 qspi0 nand0 usb0 usb1 scsi0 pxe dhcp

bootcmd=run distro_bootcmd

bootcmd_jtag=echo JTAG: Trying to boot script at ${scriptaddr} && source ${scriptaddr}; echo JTAG: SCRIPT FAILED: continuing...;

bootcmd_mmc0=devnum=0; run mmc_boot
bootcmd_mmc1=devnum=1; run mmc_boot

bootcmd_qspi0=sf probe 0 0 0 && sf read $scriptaddr $script_offset_f $script_size_f && echo QSPI: Trying to boot script at ${scriptaddr} && source ${scriptaddr}; echo QSPI: SCRIPT FAILED: continuing...;

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

mmc_boot=if mmc dev ${devnum}; then devtype=mmc; run scan_dev_for_boot_part; fi
modeboot=sdboot

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_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

script_offset_f=3e80000
script_size_f=0x80000
scriptaddr=0x20000000

可以看到,U-Boot会依次执行bootcmd_mmc0, bootcmd_jtag, bootcmd_mmc0, bootcmd_mmc1, bootcmd_qspi0,与上述的错误信息中的设备启动顺序一致。也说明U-Boot能从各种设备启动Linux。

另外bootcmd_mmc0会依次调用mmc_boot, scan_dev_for_boot_part, scan_dev_for_boot, scan_dev_for_scripts。最后scan_dev_for_scripts检查U-Boot script,也就是前述的“boot.scr”。如果发现,就会输出“Found U-Boot script”,并执行“boot_a_script”。 对于ZCU106单板,mmc0就是SD卡。 如果没有前述的“boot.scr”,就会尝试后续的启动设备。

因此,默认的U-Boot启动过程中,需要“boot.scr”。如果不想使用“boot.scr”,可以在配置U-Boot时禁止选项CONFIG_DISTRO_DEFAULTS,或者把替换启动命令“bootcmd”成直接从某个固定设备启动Linux的命令。当然,也可以在运行时,直接修改U-Boot环境变量中的命令“bootcmd”,让它直接从某个固定设备启动Linux。

posted @ 2023-04-06 16:53  HankFu  阅读(805)  评论(0编辑  收藏  举报