您的位置 首页 电源

arm BOOT阅览笔记

做了近两年ARM下的驱动开发,常用的各个设备驱动基本都碰过,不过Boot由于任务安排的缘故(公司一直有专人在做),一直没有机会接触,从刚开始接

做了近两年ARM下的驱动开发,常用的各个设备驱动根本都碰过,不过Boot由于使命组织的原因(公司一向有专人在做),一向没有机会触摸,从刚开端触摸嵌入式的时分,就一向想弄清楚板子上电后,程序是怎样履行的,不过看了下公司boot源码,就很快抛弃了,其时对汇编充满了害怕,做了1年多的驱动后,再看汇编感觉就没那儿苦楚了,最近把boot的材料收拾下,把我觉得boot比较中心的部分,完好的看了一遍,现在做个记号.我把我觉得我之前比较困惑的难点收拾出来,或许咱们一同评论下,或许和我相同的新手就可以少走些弯路.

BOOT的中心便是relocate,现在见到的典型嵌入式体系,除了处理器,至少都有ROM(norflash,nandflash)RAM(SDRAM),一般把Bootloader代码放在norflash里边,而nandflash由于自身硬件原因不能随机拜访,一般仅仅用来放运用程序.在体系加电或复位后,CPU一般由CPU制造商预先组织上地址取指令,arm体系下一般都是0x0地址取它的第一条指令,即PC = 0开端.
和boot严密相关的个人觉得便是一下几点.
1.remap.
remap比较简略,和MMU的功用可以看做是等价的,仅仅一般remap地址估定为0x0 ,网上有个帖子叫<>专门讲了它对remap的了解,对remap的效果是这样讲的: 当ARM处理器上电或许Reset之后,处理器从0x0取指。因而,有必要确保体系上电时,0x0处有指令可以履行。所以,上电的时分,0x0地址处必定是ROM或许Flash(NOR)。 可是,为了加速发动的速度,也便利可以更改反常向量表,加速中止响应速度,往往把反常向量表映射到更快、更宽(32bit/16bit)的RAM中。可是反常向量表的开端地址是由ARM架构决议的,有必要坐落0x0处,因而,有必要把RAM映射到0x0。
文中提到了ARM处理器remap的三种状况,如下
1)假如处理器有专门的寄存器可以完结Remap。那么Remap是经过Remap寄存器的相应bit置1完结的。
如Atmel AT91xx
2)假如处理器没有专门的寄存器,可是memory的bank操控寄存器可以用来装备bank的开端地址,那么只要把RAM的开端地址编程为0x0,也可以完结remap。如samsung s3c4510 .
3)假如上面两种机制都没有,那么Remap就不要做了。由于处理器完结决议了SDRAM对应的bank地址是不能改动的。如Samsung S3c2410.
不过我的观点有点略微不相同,假如上面两种机制都没有,那么Remap就不要做了,它给的典型比如是Samsung S3c2410 ,2410尽管sdram对应的bank地址不能改动,但它有MMU功用, MMU可以起到remap的效果,常用的最典型的应该是比如Samsung S3c44b0,它既没有mmu,又SDRAM对应地址有没办法改动.趁便弥补下除了4510可以改动每个bank的地址,还有华邦的w90P740(arm7),呵呵,我现在用的U便是这款U,可以把bank的地址随意的设置.
2.relocate .
relocate (地址重定位),个人觉得这个是boot里边最费事也是最中心的部分,刚开端看boot代码的时分,它简直是我的恶梦,不知道咱们剖析boot的源码流程是否这样,也或许我大学不是计算机的,没学过编译原理(现在也没看过)对链接和加载一窍不通,有两个星期十分苦楚,便是不了解人家boot里边的链接脚本为什么要那样写.网上关于uboot的帖子许多,但对链接加载这块,一直写的不具体,不知道是不是太过于根底了,高手都不乐意讲,最终自己找材料,发现其实全部苦楚的本源都是对链接和加载不太清楚形成的,但个人感觉boot除了初始化以外便是转移程序,怎样转移?为什么要那样转移都需求对硬件板的地址散布很清楚?而这些都是链接决议的,所以非弄清楚不行!
1.咱们为什么需求relocate ? 经济方面,(nandflash和norflash 每兆价格相差悬殊),把boot代码放在norflash里边(为什么不放在nandflash里边,由于nandflash读需求驱动支撑,norflash可以直接拜访),boot一般很小,只需求占用几十k的空间,所以只需求很小的norflash芯片,这样很廉价,而把运用程序一般很大,所以用价格低廉nandflash来贮存,实践运用,经过履行boot程序,把nandflash里边代码和数据转移到内存中来履行,这样比程序直接放在norflash里履行,可以.别的还有运转速度方面的不同,程序在norflash里履行的速度远远小于在sdram中履行的速度,为了寻求更高的速度,也需求relocate,让程序在sdram里边履行 .
2.关于加载域(VMA)和运转域(LMA),杜春雷在它那本经典的<>一书专门有一章来讲加载域和运转域不一致的状况,但我开端触摸了它的这些加载域和运转域后,看uboot的lds ,uboot的lds没有设置LMA,仅仅设置了VMA,为此我疑问好久.直到耐性的看了那本链接器和加载器的书才豁然了解( http://bbs.chinaunix.net/viewthread.php?tid=817770 ),任何一个链接器和加载器的根本作业都十分简略: 将更笼统的姓名与更底层的姓名绑定起来,好让程序员运用更笼统的姓名编写代码,链接器的便是把源文件进行符号解析,把解析出来的符号和地址的进行绑定,把全局变量,函数,标号等等这些契合和地址绑定起来.
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转移到内存的高端地址.然后跳到内存中履行,进步速度.
之后就relocate stack_setup clear_bss ldr pc, _start_armboot ( ROMRAM)
_start_armboot: .word start_armboot ( u-boot-1.1.4lib_armboard.c)
stack_setup , clear_bss设置仓库清bss段,都是为进入C言语做初始化预备,经过对start_armboot链接后以及把这个函数地址现已绑定在RAM中,当履行完ldr pc, label 指令,程序将从标号绑定地址开端履行,然后完结了从地址无关程序到地址相关的改变,咱们做代码搬移也是为了跳转做预备,假如没有搬移,直接拜访地址相关,由于RAM中都是随机值,一跳转就立刻飞了.当进入start_armboot C函数,剩余的都没什么难度了.可以慢剖析源码搞定.2410没有remap寄存器, relocate时分要简单些,有remap寄存器的芯片在relocate时分进行remap会让状况更杂乱些.不过原理都差不多.
在进入board.c后,uboot还做了一次代码转移如下,大约如下图,不过火两种,一种是把pc机传的image经过串口或许网络传到内存开端履行,或许从nandflash里把运用搬到内存开端履行,不过原理都差不多.
正好公司内部给咱们做了板级初始化培训,把硬件板初始流程留意关键收拾出来,.和boot这部分初始化比照,可以发现硬件板初始化流程都差不多.比较头痛仍是链接这部分,这方面的材料感觉太少了,没人可以点拨,自己看这部分材料看的很苦楚.
【CPU核相关初始化】 【Watchdog初始化】 【GPIO初始化】 【体系时钟初始化】 【内存初始化】 【形式初始化】 【中止向量初始化】 【MMU初始化】 【Cache初始化】 【总线初始化】 【言语相关初始化】 【设备相关初始化】
4.elf 格局和bin格局
executable and linking format (ELF)重定位,可以参加程序的链接(创立一个程序)和程序的履行(运转一个程序) ,首要链接,和履行,但介绍elf文件的材料许多,没时间仔细看和实践亲近的便是调试程序时分都用elf格局调试,由于它包含了调试所需的各种符号, 固化的时分都是用的bin格局,是可履行映象,用objcopy 把elf 转换成bin ,不过网上介绍bin格局的材料很少,仅仅知道bin程序,只要把pc设置为bin映象的进口地址,就可以正确履行, objcopy 可以对elf 转换成bin再进行地址重定位,不过现在还没看见过这么干过,关于elf,和bin这些了解的都不体系,材料也很少,作业中,集成开发工具IDE又把这些设置都给屏蔽起来,有没有那个强者能写一个文档,把这些都体系的讲清楚就好了!
趁便问下,论坛上上海的多不多,咱们找作业都是在网上找的?有个MM拉我去上海,尽管对现在作业很满足,不过MM比作业更重要,要我做挑选,只要去上海了,不过在51job上投了点简历,都杳无音信,按理说2年也不短了,至少也会冒一个泡的,有没有上海的可以点拨下,你们在上海石怎样找相关作业的?
弥补一个其时找材料看见对网上一个帖子,感觉写的很精辟的,关于地址无关的解说,网页地址被改成适当途径了,就没办法地址张贴出来,现在把原文张贴出来.
关键词: 地址无关
术语
地址无关: 编译地址不等于运转地址.
地址相关: 编译地址等于运转地址.
常见的一些Boot(如, U-Boot, VIVI)和Linux Kernel代码开端的一段是方位无关的, 意思便是说运转地址与编译地址无关. 如, Kernel编译地址是0xc0008000, 而运转地址是0x30008000.
为什么?
为什么代码的编译地址和运转地址会不相等呢? 原因首要有以下几种: 1) 关于Boot, 用于寄存Boot代码的存储器容量小于代码量. 如, Boot片有4K, 而代码一般有50-60K. 这样, 一般会在前4K代码里, 让Boot把自己仿制到RAM, 再接着运转.这儿咱们需求作出一个挑选, 是让前面的代码与地址相关, 仍是让后边的代码与地址相关呢? 明显咱们会挑选前面一段代码量小的与地址无关. 2) 关于Linux Kernel, 它是运转在虚拟地址空间的, 如0xc0008000, 但在MMU翻开之前, 一般这个地址是
不存在的, 也便是说在MMU翻开之前, Kernel的代码有必要是地址无关的.
怎样办?
关于方位无关的代码, 寻址是根据pc值的, 在pc值上+/-一个偏移值, 得到运转地址.以ARM为例, 用adr来寻址, adr的实践上是一个宏指令, 在代码编译时, 会被编译器替换成对pc的+/-运算
这儿要留意, 对pc的+/-运转明显是有一个地址规模的, 所以咱们在上面挑选代码量小的地址无关, 是很正确的.
而拜访地址相关的代码, 只需求运用其它的寻址指令就行了. 但在这之前, 有必要确保代码被放在正确的地址上, 所以一般都会有一个仿制代码的进程, 然后便是跳转到一个标号, 地址相关代码就开端运转了.

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/dianyuan/256494.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部