当前位置: 首页 > news >正文

Uboot 运行时内存的分配 -- 转

u-boot链接分析
http://www.rritw.com/a/bianchengyuyan/C__/20130312/279763.html

一个典型的嵌入式系统中,bootloader代码放在NOR Flash或NAND Flash里面,系统加电或复位后,首先运行这段代码。通常把bootloader代码放在NOR Flash里面,NAND Flash由于硬件原因不能随机访问,需要特殊的硬件支持机制。

bootloader代码除了初始化以外就是搬运程序,即地址重定位(relocate)。我们为什么需要relocate?主要是经济方面和速度方面的原因。经济方面,NOR Flash和NAND Flash每兆价格相差悬殊,bootloader代码一般在几十到几百K大小,而应用程序通常都很大,几M到几十M的大小,所以用价格低廉的NAND Flash存储。速度方面,程序在NOR Flash里执行的速度远远小于在SDRAM中执行的速度,为了追求更高的速度,也需要relocate,让程序在SDRAM里面执行。

relocate涉及到加载域(VMA)和运行域(LMA)两个概念。加载域是程序代码在ROM、FLASH中的排列次序及地址安排,运行域是程序运行时代码在SRAM、SDRAM中地址安排。存储代码时按照加载域存放在FLASH中,运行时再从FLASH中取出代码到RAM运行域运行,一段代码的加载域和存储域可以不同。(可以参考杜春雷的《arm体系结构与编程》一书的有关章节)。

以smdk2410为例,密切相关的就两个文件夹/board/smdk2410和/cpu/arm920t,里面核心文件就u-boot.lds 、config.mk 、start.S。

/cpu/arm920t/u-boot.lds
        OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
        OUTPUT_ARCH(arm)
        ENTRY(_start)
        SECTIONS
        {
                . = 0x00000000; // 从0地址起始

        . = ALIGN(4);
                .text :
                {
                        cpu/arm920t/start.o (.text)
                        *(.text)
                }

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

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

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

        . = .;
                __u_boot_cmd_start = .;
                .u_boot_cmd : { *(.u_boot_cmd) }
                __u_boot_cmd_end = .;

        . = ALIGN(4);
                __bss_start = .;
                .bss (NOLOAD) : { *(.bss) . = ALIGN(4); }
                _end = .;
        }

连接脚本文件lds中没有设置LMA,只是设置了VMA。VMA的设置是通过顶层目录下的config.mk文件中的LDFLAGS实现的,TEXT_BASE在/board/smdk2410/config.mk中定义为0x33F80000(SDRAM地址)。

LDFLAGS += -Bstatic -T $(obj)u-boot.lds $(PLATFORM_LDFLAGS)
        ifneq ($(TEXT_BASE),)
        LDFLAGS += -Ttext $(TEXT_BASE)
        endif

查看u-boot.map文件,代码的连接地址是从0x33F80000开始的。

167 .text         0x33f80000        0x232c8
        168        cpu/arm920t/start.o(.text)
        169        .text                0x33f80000                0x4a0 cpu/arm920t/start.o
        170                                0x33f80048                _bss_start
        171                                0x33f8004c                _bss_end
        172                                0x33f80044                _armboot_start
        173                                0x33f80000                _start
        174        board/samsung/fs2410/lowlevel_init.o(.text)
        175        .text                0x33f804a0         0x64 board/samsung/fs2410/lowlevel_init.o
        176                                0x33f804a4                lowlevel_init
        177        board/samsung/fs2410/nand_read.o(.text)
        178        .text                0x33f80504        0xe8 board/samsung/fs2410/nand_read.o
        179                                0x33f80504                wait_idle
        180                                0x33f80518                nand_read_ll

bootloader代码上电之后之所以能够正确执行,有个很重要的原因,就是最初执行的bootloader代码是地址无关的,即这个映象文件可以被放在内存中的任何一个地址上运行。

对于地址无关的代码, 寻址是基于pc值的, 在pc值上+/-一个偏移值得到运行地址,如跳转指令B。当执行完代码搬运,就需要跳到和地址相关的地方去执行,即RAM中。一般是跳转到一个标号,这时地址相关代码就开始运行了,如:ldr pc,_start_armboot。

因为在bin映象生成的时候,就已经把_start_armboot这个符号和实际地址绑定在一起,当执行ldr pc,_start_armboot 语句时,程序就从在ROM中执行跳入到RAM中了,前提是进行了代码搬移。如果没有代码搬运就执行ldr pc,_start_armboot,因为RAM中没有正确的可执行代码,程序就马上飞掉了,所有在搬运之前不能寻址绝对地址有关代码,必须执行代码地址无关.

下面的代码是从NOR Flash向SDRAM搬运的代码:

relocate:
                adr r0, _start
                ldr r1, _TEXT_BASE
                cmp r0, r1
                beq stack_setup
                ldr r2, _armboot_start
                ldr r3, _bss_start
                sub r2, r3, r2
                add r2, r0, r2
        copy_loop:
                ldmia r0!, {r3-r10}
                stmia r1!, {r3-r10}
                cmp r0, r2
                ble copy_loop

注意其中的 adr r0, _start,这是一条伪指令,一般被编译器替换为sub r0, pc,#offset ,不要理解为读取符合表中_start符号的地址(0x33F80000)。上电开始执行时,pc从0开始,所以现在r0值为0+offset,不等于_TEXT_BASE(0x33F80000)。接下来要用到链接时确定的符号地址_armboot_start(0x33F80044)了,把_start:0x0 (NOR Flash)里的.text、.data的代码往SDRAM里_TEXT_BASE确定的地址: 0x33f80000搬运。s3c2410的SDRAM基地址是0x3000_0000,由于uboot支持的这个board SDRAM64M(0x3000_0000-0x3400_0000),所以把u-boot.bin搬运到内存的高端地址.然后跳到内存中执行,提高速度。

转载于:https://www.cnblogs.com/chenchenluo/archive/2013/06/09/3129383.html

相关文章:

  • Linux系统下4个扇区的解释
  • Kerberos简介
  • ArgoUML 的简单用法
  • 修改eclipse自动生成的comments中的author名字
  • 怎么配置zen coding,我用的是Adobe Dreamweaver CS5 这个有解决么?
  • 安装jdk、安装Tomcat
  • MongoDB学习笔记
  • 中小企业如何设计存储系统方案
  • 九位不同数字乘法等式的递归与非递归回溯算法(三)
  • 超棒的JS移动设备滑动内容幻灯实现 - Swiper
  • 关于SQLite,SQLCipher和FMDB
  • Android自定义组合控件
  • js判断客户浏览器类型,版本
  • Eclipse Deepin 12.12 代码提示崩溃
  • 做技术到底可以做到哪种地步-技术为什么越走越窄
  • $translatePartialLoader加载失败及解决方式
  • Java Agent 学习笔记
  • Java深入 - 深入理解Java集合
  • PHP 小技巧
  • ReactNative开发常用的三方模块
  • Redis 中的布隆过滤器
  • seaborn 安装成功 + ImportError: DLL load failed: 找不到指定的模块 问题解决
  • Travix是如何部署应用程序到Kubernetes上的
  • vue-router 实现分析
  • yii2中session跨域名的问题
  • 力扣(LeetCode)56
  • 前端面试总结(at, md)
  • 通过获取异步加载JS文件进度实现一个canvas环形loading图
  • 详解移动APP与web APP的区别
  • 再谈express与koa的对比
  • ionic异常记录
  • 新海诚画集[秒速5センチメートル:樱花抄·春]
  • 昨天1024程序员节,我故意写了个死循环~
  • # Panda3d 碰撞检测系统介绍
  • ###项目技术发展史
  • #Linux(帮助手册)
  • #我与Java虚拟机的故事#连载02:“小蓝”陪伴的日日夜夜
  • #我与Java虚拟机的故事#连载17:我的Java技术水平有了一个本质的提升
  • (Mirage系列之二)VMware Horizon Mirage的经典用户用例及真实案例分析
  • (定时器/计数器)中断系统(详解与使用)
  • (二)基于wpr_simulation 的Ros机器人运动控制,gazebo仿真
  • (翻译)terry crowley: 写给程序员
  • (离散数学)逻辑连接词
  • (六)软件测试分工
  • (已解决)报错:Could not load the Qt platform plugin “xcb“
  • (原创) cocos2dx使用Curl连接网络(客户端)
  • (转)项目管理杂谈-我所期望的新人
  • .net 中viewstate的原理和使用
  • .NET构架之我见
  • /etc/fstab和/etc/mtab的区别
  • @ComponentScan比较
  • @Transactional类内部访问失效原因详解
  • @取消转义
  • [BZOJ1040][P2607][ZJOI2008]骑士[树形DP+基环树]
  • [CTF]2022美团CTF WEB WP