start.s详解.doc

近日在开发uboot的过程中遇到_start_armboot阶段LED灯不亮,于是郁闷之余只好通过调试工具找问题。在调试过程中发现网络上的关于start.s的分析很多,不过都不是很详细。本人通过ADX调试uboot.bin,可惜都是汇编代码,只能硬着头皮分析。庆幸的是通过调试分析深刻地了解了启动过程,现在我详细的分析一下。本人还是初学,有什么分析不对的地方请高人指正。

我使用的是STR711,所以通过说s3c44b0的代码进行修改。下面的分析就基于s3c44b0start.s(略有改动)。

代码分析:

.globl _start 

_start:  b       reset

add pc, pc, #0x20000000

add pc, pc, #0x20000000

add pc, pc, #0x20000000

add pc, pc, #0x20000000

add pc, pc, #0x20000000

add pc, pc, #0x20000000

add pc, pc, #0x20000000

.balignl 16,0xdeadbeef

这是uboot中开始的一段代码,功能是实现异常中断向量跳转的设置。_start
系统复位位置,uboot.lds文件中指定,0x00000000.系统复位后,b指令跳转
reset出开始执行,从而进入第二阶段继续执行下面的add pc, pc, #0x0c0000000
用于跳转到sdram中的中断处理程序处。b指令的寻址空间是32M,而add的寻址空间是4G,reset同处在start.S,因此只需b指令就可寻址,但另外6个中断处理函数在sdram中,因此需要用有较大寻址空间能力的指令进行跳转.。当一个中断发生时,ARM会强制把PC指针设置为对应中断类型地址处,该处的指令会跳转到自己的中断处理处继续执行。最后一句是数据对齐,不用太了解。

_TEXT_BASE:

       .word     TEXT_BASE

.globl _armboot_start

_armboot_start:

       .word _start

.globl _bss_start

_bss_start:

       .word __bss_start

.globl _bss_end

_bss_end:

       .word _end

这一段定义了_TEXT_BASE 这个是基地址,在config.mk中定义。_armboot_start注意这个变量和后面_start_armboot的区别。前者是其实就是给_start分配地址,后者则是为第二阶段的起始分配地址,也就是board.c中的start_armboot函数的地址。_bss_start数据段的起始地址,_bss_end数据段结尾的地址。

reset:

       mrs r0,cpsr

       bic  r0,r0,#0x1f

       orr  r0,r0,#0x13

       msr cpsr,r0

这一段是将cpu配置为管理模式,cpsr具体的参数比较简单,就不说了。可以参考关于arm的书籍,基本都有说。

bl    cpu_init_crit

跳转到cpu_init_crit段,具体代码如下:

cpu_init_crit:

       /* disable watch dog 禁用看门狗电路*/  

       ldr r0, =WDG_CR

       ldr  r1, =0x0

       str  r1, [r0]

       /* mask all IRQs by clearing all bits in the EIC_IER0*/

    /*关闭除21位即TIME3之外的所有中断*/

       ldr  r1,=EIC_IER0

       ldr  r0, =0x00100000

       str  r0, [r1] 

   /*设置中断控制器,禁用FIQ中断,允许IRQ中断*/

       ldr  r1, =EIC_ICR

       ldr  r0, =0x01

       str  r0, [r1]

       /* Set Clock Control Register */

       ldr  r1, =RCCU_CCR

       ldrb       r0, =800

       strb       r0, [r1]       

    /*设置PLL寄存器,设置倍频*/

       ldr  r1, =RCCU_PLL1CR

    #if CONFIG_STR711_CLOCK_SPEED==24

       ldr  r0, =0x0051       /* 24MHz */

    #else

    # error CONFIG_STR711_CLOCK_SPEED undefined

    #endif

       str  r0, [r1]

       ldr  r1,=RCCU_CCR

       ldr  r0, =0x0400

       str  r0, [r1]

mov pc, lr

以上代码主要是对看门狗、中断寄存器和PLL的设置,根据不同的芯片进行修改。这样cpu初始化完成,跳转回刚才的数据段。

bl    lowlevel_init

跳转到lowlevel_init,该段在lowlevel_init.s中。主要是完成存储器的配置。由于我没有外部存储器,所以不用怎么修改。

relocate:                          

       adr  r0, _start          

       ldr  r1, _TEXT_BASE            

       cmp     r0, r1                

       beq     stack_setup

该段首先将当前_start的地址传递到r0中,然后将基地址_TEXT_BASE传递到r1中,比较相等的话就跳入堆栈中,如果不相等继续执行下面的数据拷贝。

如果还在Flash中的话,这时的_TEXT_BASE0x20000000_start地址为0x00000000,所以不相等,进行数据拷贝(在下面详细介绍)。

如果在RAM中运行了,也就是数据已经拷贝到RAM中了,那这时的_start就变成了0x20000000,这样和_TEXT_BASE相等,不再进行数据拷贝,直接跳转到数据堆栈。

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

这两段由于关联性很大,所以放在一起讲有助理解。本段的作用主要是将flash中的数据拷贝到ram中。前一小段将_armboot_start也就是起始地址放入r2,数据段起始地址_bss_start放入r3,通过sub       r2, r3, r2得到了_armboot_start段的大小,然后加上r0得到的就是_bss_start段实际的起始地址,也就是我们到拷贝到的目标地的那段起始地址。

下面一段就是通过ldmiastmia进行拷贝,这两个指令的用法见书本。下面介绍一下过程:

开始时,r0=0x00000000r1=0x00000000r2=0x1FFDE000

然后每次比较r0r2只要不相等就重复将r1开始的寄存器数据拷贝到r3-r10中,然后r0增加0x20,不段的拷贝,直到r0r2相等,说明所有的都已拷贝完。

adr  r0, real_vectors

       add r2, r0, #1024

       ldr  r1, =0x20010000

       add r1, r1, #0x08

vector_copy_loop:

       ldmia      r0!, {r3-r10}

       stmia     r1!, {r3-r10}

       cmp r0, r2

       ble  vector_copy_loop

这一段是拷贝中断数据,过程和上面数据拷贝类似。其中需要注意的是0x20010000

,该参数需要根据自己的芯片进行修改,因为这个中断数据的拷贝起始地址,不能与前面的数据拷贝重叠,这个要非常小心,要先分析前面数据一共存放了多少空间。具体的数据在文件结尾:

real_vectors:

       b     reset

       b     undefined_instruction

       b     software_interrupt

       b     prefetch_abort

       b     data_abort

       b     not_used

       b     irq

       b     fiq

undefined_instruction:

       mov r6, #3

       b     reset

software_interrupt:

       mov r6, #4

       b     reset

prefetch_abort:

       mov r6, #5

       b     reset

data_abort:

       mov r6, #6

       b     reset

not_used:

       /* we *should* never reach this */

       mov r6, #7

       b     reset

irq:

       mov r6, #8

       b     reset

fiq:

       mov r6, #9

       b     reset

这些都是发生中断时的跳转语句,这里不用修改,所以就不解析了。

stack_setup:

ldr  r0, _TEXT_BASE            

sub  r0, r0, #CFG_MALLOC_LEN 

sub  r0, r0, #CFG_GBL_DATA_SIZE

sub  sp, r0, #12

该段就是在进行堆栈了,其中CFG_MALLOC_LENCFG_GBL_DATA_SIZEinclude/config/mycoard.h中定义,需要根据不同的芯片进行修改。一般情况下ram空间很大的话就不用改了,基本没什么问题。

ldr  pc, _start_armboot

_start_armboot:       .word start_armboot

再来这两句将_start_armboot的地址载入pc,也就是跳转到该地址。那这个地址在哪定义呢?就是下面一句,这句的汇编代码是andcs   r0,r0,r4,lsl #7 根据此得出跳转的_start_armboot地址。接下来就到board.c中执行c代码。

想要更好的理解start.s,需要大家亲自去调试,一定会有很大的收获的!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值