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\n", gd->mon_len);
    /*
     * Ram is setup, size stored in gd !!
     */
    debug("Ram size: %08lX\n", (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\n", (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\n", 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覆盖了,

然后掉转头看地址:

arch\arm\lib 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区域,所以会有问题。

调试dcc 试图将u-boot放入ocm运行碰到的问题的更多相关文章

  1. ios-将代码创建的视图控件放入拖拽控件的下面

    如图所示 图片是拖拽上去的imageView,橘黄色控件是在代码中创建的添加上去的,此时黄色view在imageView 上方 调用方法bringSubviewToFront:试图将imageView ...

  2. android 中对于采用okhttp时获取cookie并放入webview实现跳过登陆显示页面的功能

    最近项目需要将网页的一些信息展示到app当中,由于采用的是okhttp进行网络的访问,并采用了cookie对于每次的访问请求都做了验证,所以在加入webview显示网页的时候会需要进行一下验证,为了跳 ...

  3. .NET采集数据,放入数据库总结

    第一次做采集Json的还简单一些但是XML的简直了......... JSON //采集数据 public string GetBetRecordToRepository()//随便你返回什么 { t ...

  4. 在区块链上表白——使用C#将一句话放入比特币的区块链上

    最近在看区块链和比特币的知识,顺便简单研究了一下BitCoin的脚本语言,发现OP_RETURN这个命令可以在后面放入自己想说的内容,很多侧链啊,公证之类就是利用了这个特性,可以把一句话,或者一个哈希 ...

  5. java使用POI将数据导出放入Excel

    本文主要是将数据库取出的数据按照自定义的行列格式导出到excel中,POI则是实现我们需求所用到的技术. POI介绍 使用spring boot导入相关依赖 获取数据(自行处理) 完整代码实例:创建e ...

  6. idea新建项目打包 ,运行jar,并放入maven仓库

    1.新建项目(转自:http://www.cnblogs.com/wql025/p/5215570.html) 创建一个新Maven项目 new 一个project 不选择任何Maven模板 起个Gr ...

  7. EC笔记:第三部分:17、使用独立的语句将newed对象放入智能指针

    一般的智能指针都是通过一个普通指针来初始化,所以很容易写出以下的代码: #include <iostream> using namespace std; int func1(){ //返回 ...

  8. tuple放入dict中

    tuple放入dict中是否可以正常运行 # 将tuple放入dict中 a = ('AI','Kobe','Yao') b = ('AI',['Kobe','Yao']) dict1 = {'a': ...

  9. java通过文件路径读取该路径下的所有文件并将其放入list中

    java通过文件路径读取该路径下的所有文件并将其放入list中   java中可以通过递归的方式获取指定路径下的所有文件并将其放入List集合中.假设指定路径为path,目标集合为fileList,遍 ...

随机推荐

  1. AS基本设置

    1,点开as之前应该做的事  很多人一定会在这个界面卡顿很久,其实这是as在检测更新.所以我们在点开as之前先修改它的配置文件,让它不再更新. 找到你安装as的目录,进入bin文件夹找到idea.pr ...

  2. emqtt emq 的用户密码认证

    MQTT 认证设置 EMQ 消息服务器认证由一系列认证插件(Plugin)提供,系统支持按用户名密码.ClientID 或匿名认证. 系统默认开启匿名认证(anonymous),通过加载认证插件可开启 ...

  3. 逻辑回归2-scikit-learn参数介绍

    1.1     scikit-learn参数介绍 1.1.1  导入 from sklearn.linear_model import LogisticRegression 1.1.2  版本 sci ...

  4. lua基础学习(三)

    一.lua函数 1.在Lua中,函数是对语句和表达式进行抽象的主要方法.既可以用来处理一些特殊的工作,也可以用来计算一些值.Lua 提供了许多的内建函数,你可以很方便的在程序中调用它们,如print( ...

  5. MyBatis批量插入性能及问题

    1.mybatis三种批量插入方式对比 2.Mybatis与JDBC批量插入MySQL数据库性能测试及解决方案 3.Mybatis批量插入引发的血案 4.Oracle批量插入数据SQL语句太长出错

  6. [转帖]linux /proc目录下的文件为何无法用vi编辑保存

    linux /proc目录下的文件为何无法用vi编辑保存 https://blog.51cto.com/xlogin/1216914 学习一下 之前看过书 这一点 没太仔细看.. xlogin关注8人 ...

  7. <<C++ Primer>> 第二章 变量和基本类型 术语表

    术语表 第 2 章 变量和基本类型 地址(address): 是一个数字,根据它可以找到内存中的一个字节    别名生命(alias declaration): 为另一种类型定义一个同义词:使用 &q ...

  8. Centos7安装elasticsearch6.3及ik分词器,设置开机自启

    参考Elasticsearch 在CentOs7 环境中开机启动 建议虚拟机的内存大小为4G 1. 新建一个用户john 出于安全考虑,elasticsearch默认不允许以root账号运行. 创建用 ...

  9. Git+码云安装

    注册码云 1.1 下载git https://git-scm.com 1.2 安装 git安装一直next 下一步就行 1.3 测试 1.4 git原理

  10. linux:RAID(磁盘阵列)笔记

    RAID磁盘阵列简述:     RAID0(条带): 把多个同样大小的磁盘串联起来当做一个磁盘来用.         优点:读写速度快.         缺点:数据容易丢失(没有容错能力).     ...