arm BOOT阅读笔记
全局变量,函数,标号等等这些符合和地址绑定起来.
3.boot上电后开始能够正确执行还有个很重要的原因,是要保证boot在系统加电或复位后最初执行的代码是跟地址无关的,(即在代码搬运前所执行的代码是与地址无关),地址无关即地址无关代码生成的这个映象文件可以被放在内存中的任何一个地址上运行。对于地址无关的代码, 寻址是基于pc值的, 在pc值上+/-一个偏移值, 得到运行地址,如跳转指令B.当我们执行完代码搬运,就需要跳到和地址相关的地方去执行,即我们的RAM中,一般是跳转到一个标号, 这时地址相关代码就开始运行了ldr pc,_start_armboot.因为在bin映象生成的时候,就已经把_start_armboot这个符号,和实际地址绑定在一起,当我们执行ldr pc,_start_armboot 程序就从在ROM中执行跳入到RAM中了,但前提是我们进行了代码搬移,如果没有代码搬运ldr pc,_start_armboot,RAM中没有代码程序就马上飞掉了,所有我们在在搬运之前不能寻址绝对地址有关代码,必须执行代码地址无关.
拿u-boot-1.1.4下的smdk2410来做例子,和smdk2410 board密切相关的就两个文件夹boardsmdk2410和cpuarm920t,里面核心文件就u-boot.lds , config.mk ,start.S .
ENTRY(_start)
SECTIONS
{
. = 0x00000000;//从0地址起始
. = ALIGN(4);
.text :
{
cpu/arm920t/start.o (.text)
*(.text)
}
. = ALIGN(4);
.rodata : { *(.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段地址,方便relocate
.bss : { *(.bss) }
_end = .; //定义整个image的结束地址
}
u-boot.lds 是链接脚本文件, 我刚开始看这个链接脚本文件时,我疑惑很久,不明白lds中VMA= LMA(资料上很多链接脚本包括我们公司项目里面自己写的lds脚本是通过AT命令设置过LMA,这样看起来地址空间分配更清晰),而且整个image 的VMA按照lds为基址为0x0,而2410芯片不能remap,0x0地址是ROM的区域,不是运行时RAM的地址,我的理解是代码段地址应该是指向该硬件板内存区域,设置 .text=TEXT_BASE 而不是lds中的.text=0x0 ,这个疑点弄的我当时很郁闷,想了很久也没想没有搞清楚u-boot这样链接脚本都能让boot跑起来,当我把编译出来的bin烧到norflash中,uboot居然跑起来了,同时发现了一个问题, u-boot.map 中发现 .text 是从config.mk 定义TEXT_BASE =0x33f80000 ,而不是lds设置的0x0,这又让我吃惊,没清楚是怎么会事,手上有介绍移植uboot的资料,但都对uboot链接这部分,写的不够详细,知道事config.mk文件搞的鬼,但把makefile文件看了几遍都没找不到是怎么回事(还是对makefile不熟啊!),最后把编译uboot的过程看了隐藏了个机关是
arm-linux-ld –Tu-boot-1.1.4boardsmdk2410u-boot.lds –Ttext 0x33f80000
arm-linux-objcopy --gap-fill =0xff –O binary uboot ubtoot.bin
不知道uboot设计者为什么要在这里加一个–Ttext 而不是在lds就设置?而很多移植uboot的资料对lds文件都有所描述,但这个重要的细节似乎都漏掉了,不知道是不是因为太基础了,所以没有讲.
不过最后生成的bin 从上看arm-linux-objcopy --gap-fill =0xff –O binary uboot ubtoot.bin没有对链接生成的elf文件进行重定位,因此它的运行地址是config.mk 定义TEXT_BASE为基地址,顺序按照lds的顺序依次增加的,所以整个uboot最初运行的流程是
_start reset cpu_init_crit relocate
这个部分就是完成初始化,设SVC32,关看门狗,关中断,设置时钟,初始化SDRAM(为代码搬运到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指令,网上很多人被这这个指令弄郁闷,我看杜春雷的<>P143讲,这个指令是基于PC或者寄存器的,读到是地址无关的,一般被编译器替换为SUB r0, pc,#offset ,不要理解为读取符合表中_start符号的地址(0x33f80000).在我们上电开始执行时,pc从0开始,所以现在r0值为0 +offset,不等于_TEXT_BASE(0x33f80000).接下来要用到链接时确定的符号地址了,_armboot_start(0x33f80000)., _bss_start(0x33f97954)这些可以在u-boot.map里面的看到, size of armboot =0x33f97954-0x33f80000 ,把_start:0x0 (norflsh)把.text ,.data的代码往SDRAM里_TEXT_BASE确定的地址: 0x33f80000搬运.s3c2410的SDRAM基地址是0x3000_0000,由于uboot支持的这个board SDRAM是64M,(0x3000_0000---0x3400_0000),所以把u-boot.bin搬运到内存的高端地址.然后跳到内存中执行,提高速度.
armBOOT阅读笔 相关文章:
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)
- Windows CE 进程、线程和内存管理(二)(11-09)