Search code examples
embeddedembedded-linuxyoctou-bootyocto-layer

Reading file would overwrite reserved memory. Failed to load 'hello_world.bin with U-boot 2022.04 by technexion


First of all, I must apologize for the conduct and outcome of the topic below. I discovered that the issue was also in U-boot and changes in device-tree (kernel part) were not essential in solving the issue.

This is so true that currently, not even technexion's U-boot 2021.04 pulling directly from github is working without the error mentioned above.

Reading file would overwrite reserved memory. Failed to load 'hello_world.bin

I have imx7d-pico with Carrier board. This tiny computer was used a lot for Android Things. PDF (datasheet) easily found.

With that said, here's the chronology of events:

In April 2022 I customized U-boot 2021.04 from technexion and such uboot works without the error: Reading file would overwrite reserved memory

In April 2023 I customized again U-boot 2021.04 and U-boot 2022.04 from technexion and such uboot DOES NOT work anymore. I have issue: Reading file would overwrite reserved memory ** Failed to load 'hello_world.bin', When I try fatload mmc 0:1 0x7F8000 hello_world.bin

I put '#define LOG_DEBUG' to the top of lmb.c and I see some debugging about the reserved memory:

lmb.c when RPMsg work: https://gist.github.com/neuberfran/c4df18a27974cd6fdc8a967f192d54d6

lmb.c when RPMsg not Work: https://gist.github.com/neuberfran/aebbac2db52c5f78c680f10496cb8784

printenv result U-boot 2021.04 to imx7d-pico When RPMsg not work https://gist.github.com/neuberfran/f07e3d2d83c0f311bdebbf4c12646df8

I made some changes in the uboot/device tree and kernel/device tree of imx7d-pico but it still didn't work.

How can I solve my issue?

enter image description here


Solution

  • I have imx7d-pico with Carrier board.
    ...
    I have issue: Reading file would overwrite reserved memory ** Failed to load 'hello_world.bin,

    Your use of an SoC that has both a microprocessor and an auxiliary microcontroller with shared memory is a salient point. Refer to the NXP Appnote (esp. Table 5) for details. The use of multiple memory address ranges probably makes your problem a boundary case that U-Boot developers may have overlooked.

    Apparently U-Boot has evolved to become more strict on where files can be loaded in address space (probably to help detect mistakes). The dumps of the LMB structure clearly indicate that only main memory, 0x80000000 to 0xbfffffff, is accessible to certain U-Boot commands. Since the address space to access the auxiliary processor memory (0x7f8000 to 0x7fffff) is outside this range of main memory, this auxiliary memory region is unwritable by various load-a-file commands.

    The root cause of the error message is in the Logical Memory Block "library" of U-Boot, lib/lmb.c. The procedure lmb_init_and_reserve() only allocates the available (and hence loadable) memory space(s) based on U-Boot's legacy method for memory definition.

    The legacy method relies on macro definitions, such as CFG_SYS_SDRAM_BASE, and are typically defined in a board-specific header file. For example the following definitions are extracted from include/configs/imx7-cm.h:

    #define CFG_SYS_SDRAM_BASE      PHYS_SDRAM
    #define CFG_SYS_INIT_RAM_ADDR   IRAM_BASE_ADDR
    #define CFG_SYS_INIT_RAM_SIZE   IRAM_SIZE
    

    Then in common/board_f.c, the base address for SDRAM is assigned to a global_data variable for the base address of RAM used by U-Boot:

    static int setup_dest_addr(void)
    {
        ...
        gd->ram_base = CFG_SYS_SDRAM_BASE;
    

    Later the first memory bank of the board info structure is filled with this global_data memory info in common/board_f.c:

    __weak int dram_init_banksize(void)
    {
        gd->bd->bi_dram[0].start = gd->ram_base;
        gd->bd->bi_dram[0].size = get_effective_memsize();
    
        return 0;
    }
    

    That is the board memory info that is later used to fill-in the LMB structure in lib/lmb.c:

    /* Initialize the struct, add memory and call arch/board reserve functions */
    void lmb_init_and_reserve(struct lmb *lmb, struct bd_info *bd, void *fdt_blob)
    {
        int i;
    
        lmb_init(lmb);
    
        for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
            if (bd->bi_dram[i].size) {
                lmb_add(lmb, bd->bi_dram[i].start,
                    bd->bi_dram[i].size);
            }
        }
    
        lmb_reserve_common(lmb, fdt_blob);
    }
    

    So the Logical Memory Block "library" relies on U-Boot's legacy method for defining memory.
    That means the memory definitions in the Device Tree are ignored by U-Boot.


    When you try to load a file from a storage device to memory, the following procedure is called in fs/fs.c

    #ifdef CONFIG_LMB
    /* Check if a file may be read to the given address */
    static int fs_read_lmb_check(const char *filename, ulong addr, loff_t offset,
                     loff_t len, struct fstype_info *info)
    {
        ...
        lmb_init_and_reserve(&lmb, gd->bd, (void *)gd->fdt_blob);
        lmb_dump_all(&lmb);
    
        if (lmb_alloc_addr(&lmb, addr, read_len) == addr)
            return 0;
    
        log_err("** Reading file would overwrite reserved memory **\n");
        return -ENOSPC;
    }
    #endif
    

    Note the conditional compilation for this routine that performs the memory check.
    I tied to build a version of U-Boot 2022.01 without CONFIG_LMB, but the build failed. So even though CONFIG_LMB appears to be an optional library selection in the menuconfig, there seems to be source code changes needed to de-select CONFIG_LMB.
    So you cannot try to bypass this memory check by building an alternate configuration of U-Boot.



    A Workaround

    Rather than try to define the aux memory as a bank of main memory, there is a simple & easy workaround to use a recent & unmodified U-Boot in your situation. Instead of loading the file directly to the auxiliary processor memory, simply load the file to main memory at 0x80008000, and then perform a copy of 32KB to the aux memory at tcm_addr.
    The loadm4image variable should be changed to:

    loadm4image=fatload mmc ${mmcdev}:${mmcpart} 80008000 ${m4image}; \
    cp.b 80008000 ${tcm_addr} 8000
    

    This can be accomplished with the following command to the previously posted environment:

    setenv loadm4image 'fatload mmc ${mmcdev}:${mmcpart} 80008000 ${m4image}; cp.b 80008000 ${tcm_addr} 8000'