uboot启动时遇到设备树头校验错误

Posted

技术标签:

【中文标题】uboot启动时遇到设备树头校验错误【英文标题】:The device tree header verification error was encountered during uboot startup 【发布时间】:2021-12-27 06:33:21 【问题描述】:

我在使用 orangepi3 时遇到问题。

我有一张正常情况下可以使用的图片,

但偶尔会出现以下问题。 一旦出现这个问题,此时烧录的镜像就不能再使用了,只能复制烧录的镜像

uboot启动时报以下错误。

Hit any key to stop autoboot:  0
no mmc device at slot 0
mmc2(part 0) is current device
2512 bytes read in 5 ms (490.2 KiB/s)
## Executing script at 43100000
U-boot loaded from SD
Boot script loaded from mmc
** Bad device mmc 0 **
** File not found /boot/dtb/sunxi/sun50i-h6-orangepi3.dtb **
libfdt fdt_check_header(): FDT_ERR_BADMAGIC
8247895 bytes read in 404 ms (19.5 MiB/s)
19425352 bytes read in 945 ms (19.6 MiB/s)

但我确定这个文件是存在的; 因为当这个错误存在的时候,我进入uboot,打印设备树。可以正常打印,但是执行命令boot还是会报这个错误。

然后我检查了文件系统,发现该文件存在于路径中 .

查了uboot源码,在函数fdt_check_header中发现了这个错误

int fdt_check_header(const void *fdt)

        if (fdt_magic(fdt) == FDT_MAGIC) 
                /* Complete tree */
                if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
                        return -FDT_ERR_BADVERSION;
                if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION)
                        return -FDT_ERR_BADVERSION;
         else if (fdt_magic(fdt) == FDT_SW_MAGIC) 
                /* Unfinished sequential-write blob */
                if (fdt_size_dt_struct(fdt) == 0)
                        return -FDT_ERR_BADSTATE;
         else 
                return -FDT_ERR_BADMAGIC;
        

        return 0;

但是在uboot中init_sequence_f exereserve_fdt也有设备树头的校验,校验通过。 但是在uboot autoboot_command run_command_list cmd_list中checked device tree header发生错误,导致无法正确进入内核。

进入FDT前_check_我在header函数前加了一个打印函数

在输入函数 fdt_check_header() 之前,我在 reserve_fdt() 中添加如下打印

静态 int reserve_fdt(void)

/*
 * If the device tree is sitting immediate above our image then we
 * must relocate it. If it is embedded in the data section, then it
 * will be relocated with other data.
 */

if (gd->fdt_blob) 
    pr_msg("reserve_fdt fdt_check_headeris %d\n",fdt_magic(gd->fdt_blob));
    if(fdt_check_header(gd->fdt_blob) != 0)
    
        pr_msg("fdt header check error\n");
        return -1;
    
    //reserve memory for expand dtb ,because cmd_fdt will update the base dtb
    gd->fdt_size = ALIGN(fdt_totalsize(gd->fdt_blob) + 0x1000, 32);
    fdt_set_totalsize((void*)gd->fdt_blob,gd->fdt_size);

    gd->start_addr_sp -= gd->fdt_size * 2;
    gd->new_fdt = map_sysmem(gd->start_addr_sp, gd->fdt_size);
    debug("Reserving %lu Bytes for FDT at: %08lx\n",
          gd->fdt_size, gd->start_addr_sp);


return 0;

并且在函数 fdt_valid() 中也添加;

static int fdt_valid(struct fdt_header **blobp)


    const void *blob = *blobp;
    int err;

    if (blob == NULL) 
        printf ("The address of the fdt is invalid (NULL).\n");
        return 0;
    
    printf("fdt_valid fdt_check_header is %d\n",fdt_magic(blob));
    err = fdt_check_header(blob);
    if (err == 0)
        return 1;   /* valid */

    if (err < 0) 
        printf("libfdt fdt_check_header(): %s", fdt_strerror(err));
        /*
         * Be more informative on bad version.
         */
        if (err == -FDT_ERR_BADVERSION) 
            if (fdt_version(blob) <
                FDT_FIRST_SUPPORTED_VERSION) 
                printf (" - too old, fdt %d < %d",
                    fdt_version(blob),
                    FDT_FIRST_SUPPORTED_VERSION);
            
            if (fdt_last_comp_version(blob) >
                FDT_LAST_SUPPORTED_VERSION) 
                printf (" - too new, fdt %d > %d",
                    fdt_version(blob),
                    FDT_LAST_SUPPORTED_VERSION);
            
        
        printf("\n");
        *blobp = NULL;
        return 0;
    
    return 1;
    

那么,当错误发生时,日志如下:

U-Boot 2014.07-orangepi (Oct 29 2021 - 09:07:58) Xunlong Software

[1.947]uboot commit : b65841975dcb31f64a2c69344f60db12b98791ae

[1.947]secure enable bit: 0
[1.947]normal mode: with secure monitor
I2C:   ready
[1.949]pmbus:   ready
[1.949][ARISC] :arisc initialize
[1.975][ARISC] :arisc para ok
[SCP] :sunxi-arisc driver begin startup 2
[SCP] :arisc version: []
[SCP] :sunxi-arisc driver v1.10 is starting
[1.987][ARISC] :sunxi-arisc driver startup succeeded
[1.989]PMU: AXP806
[1.989]PMU: AXP806 found
[1.989]bat_vol=0, ratio=0
[1.989]set pc_bias(1) bias:1800
[1.989]set pg_bias(5) bias:1800
[1.989]set power on vol to default
[1.989]dcdca_vol = 1000, onoff=1
[1.993]aldo2_vol = 3300, onoff=1
[1.998]bldo3_vol = 1800, onoff=1
[2.002]cldo2_vol = 3300, onoff=1
[2.006]cldo3_vol = 3300, onoff=1
[2.010]find power_sply to end
[2.010]cant find pll setting(1320M) from  pll table,use default(408M)
[2.012]PMU: cpux 408 Mhz,AXI=204 Mhz
[2.013]PLL6=600 Mhz,AHB1=200 Mhz, APB1=100Mhz MBus=400Mhz
[2.017]DRAM:  1 GiB
[2.019]reserve_fdt fdt_check_headeris -804389139
[2.026]fdt addr: 0x79ccb0e0
[2.026]gd->fdt_size: 0x1a6c0
[2.030]Relocation Offset is: 34e03000
[2.095]gic: sec monitor mode
[2.095]line:180 func:check_ir_boot_recovery start
[2.095]ir boot recovery not used
[2.095][key recovery] no use
[2.096][box standby] read rtc = 0x0
[2.096][box standby] start_type = 0x1
[2.096][box standby] to kernel
[2.096]workmode = 0,storage type = 2
[2.098]MMC:      2
SUNXI SD/MMC: 2
[mmc]: [0-60|61]
[mmc]: [0-51|52]
[mmc]: [7-48|42]
[mmc]: [0-11|12] [26-29|4] [34-50|17]
[mmc]: [0-48|49] [54-56|3] [58-63|6]
[mmc]: [0-26|27] [54-63|10]
[mmc]: [0-58|59]
[mmc]: [6-51|46] [53-58|6]
[mmc]: [1-7|7] [9-56|48]
[mmc]: [1-26|26]
Normal
[6.618]MMC:      2
SUNXI SD/MMC: 2, SUNXI SD/MMC: 2
[6.624]sunxi flash init ok
[6.624]hdmi hdcp not enable!
Using default environment

[6.625]inter uboot shell
Hit any key to stop autoboot:  0
no mmc device at slot 0
mmc2(part 0) is current device
2512 bytes read in 5 ms (490.2 KiB/s)
## Executing script at 43100000
U-boot loaded from SD
Boot script loaded from mmc
** Bad device mmc 0 **
**** File not found /boot/dtb/sunxi/sun50i-h6-orangepi3.dtb **
fdt_valid fdt_check_header is -1271711085
libfdt fdt_check_header(): FDT_ERR_BADMAGIC
fdt_valid fdt_check_header is -1271711085
libfdt fdt_check_header(): FDT_ERR_BADMAGIC**
8247895 bytes read in 404 ms (19.5 MiB/s)
19425352 bytes read in 945 ms (19.6 MiB/s)
## Booting kernel from Legacy Image at 41000000 ...
   Image Name:
   Image Type:   ARM Linux Kernel Image (uncompressed)
   Data Size:    19425288 Bytes = 18.5 MiB
   Load Address: 41000000
   Entry Point:  41000000
   Verifying Checksum ... OK
## Loading init Ramdisk from Legacy Image at 43300000 ...
   Image Name:   uInitrd
   Image Type:   ARM Linux RAMDisk Image (gzip compressed)
   Data Size:    8247831 Bytes = 7.9 MiB
   Load Address: 00000000
   Entry Point:  00000000
   Verifying Checksum ... OK
   Loading Kernel Image ... OK
   reserving fdt memory region: addr=40020000 size=800
   reserving fdt memory region: addr=48000000 size=1000000
   reserving fdt memory region: addr=48100000 size=4000
   reserving fdt memory region: addr=48104000 size=1000
   reserving fdt memory region: addr=48105000 size=1000
   reserving fdt memory region: addr=79ccb0e0 size=18f20
   Loading Ramdisk to 49822000, end 49fffa17 ... OK
   Using Device Tree in place at 44000000, end 4401d6bf
[8.736]disp_ioctl, display not init yet
[8.736]disp_ioctl, display not init yet

Starting kernel ...

INFO:    BL3-1: Next image address = 0x41000000
INFO:    BL3-1: Next image spsr = 0x3c5
WARNING: Unimplemented Standard Service Call: 0xc0000026

和编号 fdt_check_headeris -804389139 id normol;

这是为什么呢? 为什么前面验证还是正确,后面却出错了?

你遇到过这个问题吗?或者你能给我一些建议吗?谢谢!

【问题讨论】:

【参考方案1】:

每次重启时报告日志是否相同?

如果相同,则硬件存储中的 DTB 没问题。

您应该担心两个fdt_magic 函数调用之间的内存覆盖。

【讨论】:

大部分情况下,镜像可以正常启动。只是偶尔找不到设备树文件。但是一旦出现这个问题,镜像就不能再正常使用了,必须重新烧录 出现问题时第一次检查fdt头没问题,但是第二次检查失败。我认为应该是内存中的数据被更改了。 感谢您的提醒。我再看一遍代码。【参考方案2】:

您在 2014.07 上,它既缺少对现代 ext4 文件系统映像的支持,也缺少对安装现代 ext4 文件系统映像的警告/拒绝,这些映像具有默认启用的功能,显示诸如“文件我知道存在,我可以在 Linux 中看到它,但没有找到”。请升级到当前的 U-Boot。

【讨论】:

以上是关于uboot启动时遇到设备树头校验错误的主要内容,如果未能解决你的问题,请参考以下文章

嵌入式linux开发uboot移植——uboot启动过程源码分析

smart210看不到uboot启动信息

zynq中uboot的qspi启动报错及解决办法

uboot使用命令整理(2016.03)

如何提高UBOOT的启动速度

海思Hi35xx uboot启动分析总结