zoukankan      html  css  js  c++  java
  • 调试dcc 试图将u-boot放入ocm运行碰到的问题

    1.

    起因:

    gd->mon_len = (ulong)&__bss_end - (ulong)_start;

    在u-boot.map中查找,发现__bss_end并不是u-boot.bin的结束

    根据u-boot-2018.07/arch/arm/mach-xxx/u-boot.lds

    /*
     * Copyright (c) 2004-2008 Texas Instruments
     *
     * (C) Copyright 2002
     * Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
     *
     * SPDX-License-Identifier:    GPL-2.0+
     */

    OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
    OUTPUT_ARCH(arm)
    ENTRY(_start)
    SECTIONS
    {
        . = 0x00000000;

        . = ALIGN(4);
        .text :
        {
            *(.__image_copy_start)
            *(.vectors)
            CPUDIR/start.o (.text*)
            *(.text*)
        }

        . = ALIGN(4);
        .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }

        . = ALIGN(4);
        .data : {
            *(.data*)
        }

        . = ALIGN(4);

        . = .;

        . = ALIGN(4);
        .u_boot_list : {
            KEEP(*(SORT(.u_boot_list*)));
        }

        . = ALIGN(4);

        .image_copy_end :
        {
            *(.__image_copy_end)
        }

        .rel_dyn_start :
        {
            *(.__rel_dyn_start)
        }

        .rel.dyn : {
            *(.rel*)
        }

        .rel_dyn_end :
        {
            *(.__rel_dyn_end)
        }

        .end :
        {
            *(.__end)
        }

        _image_binary_end = .;

    /*
     * Compiler-generated __bss_start and __bss_end, see arch/arm/lib/bss.c
     * __bss_base and __bss_limit are for linker only (overlay ordering)
     */

        .bss_start __rel_dyn_start (OVERLAY) : {
            KEEP(*(.__bss_start));
            __bss_base = .;
        }

        .bss __bss_base (OVERLAY) : {
            *(.bss*)
             . = ALIGN(4);
             __bss_limit = .;
        }

        .bss_end __bss_limit (OVERLAY) : {
            KEEP(*(.__bss_end));
        }

        /*
         * Zynq needs to discard these sections because the user
         * is expected to pass this image on to tools for boot.bin
         * generation that require them to be dropped.
        */
        /DISCARD/ : { *(.dynsym) }
        /DISCARD/ : { *(.dynbss*) }
        /DISCARD/ : { *(.dynstr*) }
        /DISCARD/ : { *(.dynamic*) }
        /DISCARD/ : { *(.plt*) }
        /DISCARD/ : { *(.interp*) }
        /DISCARD/ : { *(.gnu*) }
        /DISCARD/ : { *(.ARM.exidx*) }
        /DISCARD/ : { *(.gnu.linkonce.armexidx.*) }
     
    }
    和u-boot.map分析

    u-boot.lds中是如下分布

     relocate_code

    ① 将地址__image_copy_start至__image_copy_end的u-boot code 重定位到地址gd->relocaddr;
    ② 通过.rel.dyn段确定u-boot code中所有符号索引的内存地址,用重定位偏移校正符号索引的值[1]; 参考uboot的relocation原理详细分析

    其实只是做了个地址校正,校正完了,这个数据就没用了。

     relocate_code之后,执行memset(__bss_start,__bss_end,__bss_end-__bss_start)清零BSS段;

    所以真正运行时候的地址分布如下:

     所以并不是没有拷贝全。

    2.

    由于之前的做法是将u-boot代码放置在ram的高区,可以避免搬运。

    这样存在一个问题,就是如果u-boot代码大小变动,那么CONFIG_SYS_TEXT_BASE需要变化,

    相应的上位机软件也要调整,带来更多的工作量和不确定性。

    看了下zynq的做法,zynq是将nor nand qspi分成不同的defconfig,而且zynq的u-boot.bin小于ocm一半的大小,所以支持搬运。

    zynq将初始gd放在CONFIG_SYS_INIT_RAM_ADDR  +CONFIG_SYS_INIT_RAM_SIZE     0xFFFDE000+0x1000

    #define CONFIG_SYS_INIT_RAM_ADDR    0xFFFDE000
    #define CONFIG_SYS_INIT_RAM_SIZE    0x1000

    留出120K空间足够放u-boot (0xFFFDE000-0xFFFC0000)

    CONFIG_SYS_TEXT_BASE=0xFFFC0000

    剩下空间(0xFFFFFFFF-0xFFFDE000-0x1000)131k足够搬运u-boot代码

    zynq调试时候碰到一开始无法访问0xFFFC0000地址

    vivado中要将 allow access to high ocm选上。

    需要在fsbl跑完,手动更改两个寄存器

    1.

    0x0000DF0D解锁写功能

    2.

     0x0000001F

    将地址映射到0xFFFC0000

     3.

    想要将u-boot拷贝到地地址,并且跳过reloc(本质是gd->relocaddr和__image_copy_start相等

    __image_copy_start在defconfig中的CONFIG_SYS_TEXT_BASE设置,设置为比较低的一个地址

    只能从gd->relocaddr上下工夫了。

    gd->relocaddr最初在setup_dest_addr出现

    static int setup_dest_addr(void)
    {
        debug("Monitor len: %08lX ", gd->mon_len);
        /*
         * Ram is setup, size stored in gd !!
         */
        debug("Ram size: %08lX ", (ulong)gd->ram_size);
    #if defined(CONFIG_SYS_MEM_TOP_HIDE)
        /*
         * Subtract specified amount of memory to hide so that it won't
         * get "touched" at all by U-Boot. By fixing up gd->ram_size
         * the Linux kernel should now get passed the now "corrected"
         * memory size and won't touch it either. This should work
         * for arch/ppc and arch/powerpc. Only Linux board ports in
         * arch/powerpc with bootwrapper support, that recalculate the
         * memory size from the SDRAM controller setup will have to
         * get fixed.
         */
        gd->ram_size -= CONFIG_SYS_MEM_TOP_HIDE;
    #endif
    #ifdef CONFIG_SYS_SDRAM_BASE
        gd->ram_top = CONFIG_SYS_SDRAM_BASE;
    #endif
        gd->ram_top += get_effective_memsize();
        gd->ram_top = board_get_usable_ram_top(gd->mon_len);
        gd->relocaddr = gd->ram_top;
        debug("Ram top: %08lX ", (ulong)gd->ram_top);
    #if defined(CONFIG_MP) && (defined(CONFIG_MPC86xx) || defined(CONFIG_E500))
        /*
         * We need to make sure the location we intend to put secondary core
         * boot code is reserved and not used by any part of u-boot
         */
        if (gd->relocaddr > determine_mp_bootpg(NULL)) {
            gd->relocaddr = determine_mp_bootpg(NULL);
            debug("Reserving MP boot page to %08lx ", gd->relocaddr);
        }
    #endif
        return 0;
    }

    (1)

    一开始想从 CONFIG_SYS_MEM_TOP_HIDE入手,将CONFIG_SYS_MEM_TOP_HIDE根据u-boot反算设置为某个值,

    经提醒,CONFIG_SYS_MEM_TOP_HIDE在预编译阶段,而bss_end在链接阶段才有效,所以该方法不行。

    (2)

    想从get_effective_memsize()入手,那么就是要改gd->ram_size的值,在int dram_init(void)中得到,但是这样显示出来的值就不对了,总感觉做法不正规

    int dram_init(void)

    {
        gd->ram_size = get_ram_size((void *)CONFIG_SYS_SDRAM_BASE,
                        CONFIG_SYS_SDRAM_SIZE);
        fmxx_ddrc_init();

        return 0;
    }

    (3)只能从board_get_usable_ram_top入手了

    在board_f.c中有__weak ulong board_get_usable_ram_top(ulong total_size)

    所以可以在自己的board.c中定义一个自己的board_get_usable_ram_top

    传入的参数是gd->mon_len(u-boot.bin的长度)

    ulong board_get_usable_ram_top(ulong total_size)
    {
        ulong mon_len = total_size;
        
    #ifdef CONFIG_SYS_SDRAM_BASE
        /*
         * Detect whether we have so much RAM that it goes past the end of our
         * 32-bit address space. If so, clip the usable RAM so it doesn't.
         */
        if (gd->ram_top < CONFIG_SYS_SDRAM_BASE)
            /*
             * Will wrap back to top of 32-bit space when reservations
             * are made.
             */
            return 0;
    #endif

        if( total_size%4096 )
            mon_len = ( (total_size & ~(4096 - 1)) + 4096);  //u-boot.bin长度4k对齐

        gd->ram_top =  CONFIG_SYS_SDRAM_BASE + SYS_DCC_RESERVE_SIZE + mon_len;
        //ram_top=0x20000 + 0x3000+4k对齐的u-boot长度

        //0x3000=12k
        return gd->ram_top;
    }

    关于4k对齐:

    因为设置好gd->ram_top后:

    reserve_round_4k  代码如下:

    gd->relocaddr &= ~(4096 - 1);

    reserve_uboot 代码如下:

            gd->relocaddr -= gd->mon_len;
            gd->relocaddr &= ~(4096 - 1);

    后就是gd->relocaddr

    因为SYS_DCC_RESERVE_SIZE和CONFIG_SYS_SDRAM_BASE 是4k整数倍,所以如果mon_len是4k整数倍,两条对齐的命令等于不执行。

    如果mon_len不是4k整数倍,那么就需要特殊处理下,加到4k的整数倍。

     

    所以__image_copy_start在defconfig中的CONFIG_SYS_TEXT_BASE设置CONFIG_SYS_SDRAM_BASE + SYS_DCC_RESERVE_SIZE=0x20000+0x3000

    SYS_DCC_RESERVE_SIZE=0x3000 12K是如果估算出来的呢 首先 SYS_DCC_RESERVE_SIZE要4k对齐。

    reserve_malloc代码如下:

    gd->start_addr_sp = gd->start_addr_sp - TOTAL_MALLOC_LEN;

    #define TOTAL_MALLOC_LEN    (CONFIG_SYS_MALLOC_LEN + CONFIG_ENV_SIZE)   //0x1000 400 这里就超过4K了

     

    reserve_board

    sizeof(bd_t)

    reserve_global_data

    sizeof(gd_t)

    bd gd都是在几百个字节的样子

    加上malloc的超过4K了,对齐4K,所以是8K

    最开始设置为0x22000,打开debug运动不到命令行,关闭debug,运行到命令行,可是输入命令就死了。

    后来调试半天郁闷无果,不知道怎么想到了,有没有可能是把最开始存放的gd覆盖了,

    然后掉转头看地址:

    archarmlib crt0.S

    1.设置sp为CONFIG_SYS_INIT_SP_ADDR

     include/configs/xxx.h

    #define CONFIG_SYS_INIT_SP_ADDR     (CONFIG_SYS_INIT_RAM_ADDR +
                        CONFIG_SYS_INIT_RAM_SIZE - GENERATED_GBL_DATA_SIZE)

    #define CONFIG_SYS_INIT_RAM_ADDR    0x20000
    #define CONFIG_SYS_INIT_RAM_SIZE    0x1000

    include/generated/generic-asm-offsets.h

    #define GENERATED_GBL_DATA_SIZE 192 /* (sizeof(struct global_data) + 15) & ~15  @ */

    CONFIG_SYS_INIT_SP_ADDR=0x20F40

    2.调用board_init_f_alloc_reserve

    没有定义SYS_MALLOC_F_LEN,不执行。这里不对

    make distclean后,CONFIG_SYS_MALLOC_F_LEN默认值0x400

    top初始值0x20F40

    #if CONFIG_VAL(SYS_MALLOC_F_LEN)
        top -= CONFIG_VAL(SYS_MALLOC_F_LEN);  #top=0x20B40
    #endif

    top = rounddown(top-sizeof(struct global_data), 16);  #top=0x20A80

    所以大体上0x21000 精确点就是0x20F40以下空间都不能动。

    如果我们将CONFIG_SYS_TEXT_BASE设置在0x22000

    malloc的空间为0x1000 加env size 400  再加上bd 100多字节 gd 200多字节信息,大概是0x20ce0

    reserve bd信息时候会将那块空间清零,

    setup_reloc会重定位gd_t内容到gd->new_gd;

    而bd和gd都位于最初的malloc区域,所以会有问题。

     

  • 相关阅读:
    网络端口
    Jmeter安装
    【紫光同创国产FPGA教程】【第一章】Pango Design Suite 2020.3安装 ALINX
    【ZYNQ Ultrascale+ MPSOC FPGA教程】第三十章 自定义IP实验
    【ZYNQ Ultrascale+ MPSOC FPGA教程】第二十九章PL端AXI GPIO的使用
    【ZYNQ Ultrascale+ MPSOC FPGA教程】第二十八章 PS端EMIO的使用
    【ZYNQ Ultrascale+ MPSOC FPGA教程】第二十七章System Monitor
    【ZYNQ Ultrascale+ MPSOC FPGA教程】第二十六章 PS端网络远程更新QSPI
    【ZYNQ Ultrascale+ MPSOC FPGA教程】第二十五章 PS端以太网使用之lwip
    【ZYNQ Ultrascale+ MPSOC FPGA教程】第二十四章 PS端SD卡读写
  • 原文地址:https://www.cnblogs.com/idyllcheung/p/11946875.html
Copyright © 2011-2022 走看看