Chinaunix首页 | 论坛 | 博客
  • 博客访问: 144121
  • 博文数量: 29
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 265
  • 用 户 组: 普通用户
  • 注册时间: 2014-01-04 13:11
文章分类

全部博文(29)

文章存档

2015年(2)

2014年(27)

我的朋友

分类: 嵌入式

2014-01-08 16:30:11

U-boot启动代码start.s分析

#include

#include

 

.globl _start

_start:               b       start_code

              ldr         pc, _undefined_instruction

              ldr         pc, _software_interrupt

              ldr         pc, _prefetch_abort

              ldr         pc, _data_abort

              ldr         pc, _not_used

              ldr         pc, _irq

              ldr         pc, _fiq

 

_undefined_instruction:         .word undefined_instruction

_software_interrupt:              .word software_interrupt

_prefetch_abort:        .word prefetch_abort

_data_abort:                .word data_abort

_not_used:                    .word not_used

_irq:                                 .word irq

_fiq:                                 .word fiq

 

              .balignl 16,0xdeadbeef

 

分析1:

1          .globl的用法是声明一个全局变量_start,告诉链接器此变量是全局的,外部可以访问。

2          _start 如果从nor flash启动,_start = 0,nand flash启动,即是重新relocate代码后,_start = TEXT_BASE E=0x33f80000,这个 TEXT_BASE 就是链接地址,即运行代码的地方。

3          这里只以下面这两句话作为示例来解释

ldr pc, _undefined_instruction 

_undefined_instruction: .word undefined_instruction

第一句的意思是将地址为_undefined_instruction 中的一个字(word)的值,赋值给 pc。第二句的意思是此处分配了一个字(word=32bit=4 字节)的地址空间,里面存放的值是undefined_instruction 。在后面的代码,我们可以看到,undefined_instruction 也是一个标号,即一个地址值。Ldr 有两种形式:一种是汇编加载指令,一种是伪指令

4          .balignl 16,0xdeadbeef 意思就是要 16 字节对齐后,再存放接下来的代码。直到能被 16 字节整除的地址出现前,都用 0xdeadbeef这个值来填充。

 

_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

 

#ifdef CONFIG_USE_IRQ

.globl IRQ_STACK_START

IRQ_STACK_START:

              .word  0x0badc0de

.globl FIQ_STACK_START

FIQ_STACK_START:

              .word 0x0badc0de

#endif

 

分析2:

1          _start 是程序入口,链接完毕它的值应该是 TEXT_BASE=33f8000 ,_TEXT_BASE在 board\smdk2410 \config.mk 中有定义,TEXT_BASE=33f80000

2          _armboot_start地址里存放的值是_start

3          __bss_start 、_end、_start 这些东西到 cpu/arm920t/u-boot.lds 中有定义

 

/* * the actual start code*/

start_code:

              mrs      r0,cpsr

              bic         r0,r0,#0x1f

              orr        r0,r0,#0xd3

              msr      cpsr,r0

分析3:复位程序

1          设置cpu为SVC32模式

2          MRS指令用亍将程序状态寄存器的内容传送到通用寄存器中,BIC指令用亍清除操作数1的某些位,把结果放置到目的寄存器中,此行代码的含义就是,清除r0的bit[4:0]位。ORR指令用于在两个操作数上进行逻辑或运算,并把结果放置到目的寄存器中。MSR指令用于将操作数的内容传送到程序状态寄存器中。


 

#if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410)

              /* turn off the watchdog */

 

# if defined(CONFIG_S3C2400)

#  define pWTCON                 0x15300000

#  define INTMSK                   0x14400008    /* Interupt-Controller base addresses */

#  define CLKDIVN    0x14800014    /* clock divisor register */

#else

#  define pWTCON                 0x53000000

#  define INTMSK                   0x4A000008   /* Interupt-Controller base addresses */

#  define INTSUBMSK           0x4A00001C

#  define CLKDIVN    0x4C000014    /* clock divisor register */

# endif

 

              ldr     r0, =pWTCON

              mov     r1, #0x0

              str     r1, [r0]

 

/** mask all IRQs by setting all bits in the INTMR - default*/

              mov     r1, #0xffffffff

              ldr         r0, =INTMSK

              str         r1, [r0]

# if defined(CONFIG_S3C2410)

              ldr         r1, =0x3ff

              ldr         r0, =INTSUBMSK

              str         r1, [r0]

# endif

 

              /* FCLK:HCLK:PCLK = 1:2:4 */

              /* default FCLK is 120 MHz ! */

              ldr         r0, =CLKDIVN

              mov     r1, #3

              str         r1, [r0]

#endif  /* CONFIG_S3C2400 || CONFIG_S3C2410 */

 

#ifndef CONFIG_SKIP_LOWLEVEL_INIT

              bl           cpu_init_crit

#endif

 

分析4:关看门狗,关中断,设置时钟,跳转到cpu_init_crit

1          宏定义s3c2440需要的寄存器地址

2          这里的ldr为伪指令,ldr伪指令和mov是比较相似的,另外 mov 指令后面的立即数是有限制的,这个立即数,必须由一个 8 位的二进制数,即0x00-0xFF 内的某个值,经过偶数次右移后得到,这样才是合法数据,而ldr伪指令没有这个限制。

3          关看门狗,pWTCON = 0

4          INTMSK寄存器设置为0xffffffff,即,将所有的中断都mask了。S3c2440 INTSUBMSK寄存器的值应该设置为0x7fff

5          CLKDIVN寄存器设置时钟分频

6          就是当没有定义CONFIG_SKIP_LOWLEVEL_INIT的时候,就掉转到cpu_init_crit的位置,而在后面的代码cpu_init_crit中,你可以看到最后一行汇编,代码就是mov pc, lr,又将PC跳转回来,所以整个的含义就是,调用子程序cpu_init_crit,等cpu_init_crit执行完毕,再返回此处继续执行下面的代码,cpu_init_crit 会调用 board/smdk2410/lowlevel_init.S 来初始化 SDRAM。就是设置与 SDRAM相关的 13 个存储控制器。

 

#ifndef CONFIG_SKIP_RELOCATE_UBOOT

relocate:                                                            /* relocate U-Boot to RAM */

              adr       r0, _start                               /* r0  =  代码此刻的位置*/

              ldr         r1, _TEXT_BASE                           /* r1  =  代码需要放置的位置*/

              cmp     r0, r1                  /*比较r0,r1*/

              beq     stack_setup             /*若相等,跳过,直接设置栈 */

 

              ldr         r2, _armboot_start          /*第一条代码的运行地址 */

              ldr         r3, _bss_start              /*代码段的结束地址 */

              sub       r2, r3, r2                        /* r2  =  代码段长度*/

              add       r2, r0, r2                        /* r2  = nor flash 上代码的结束地址 */

 

copy_loop:                   /*复制代码*/

ldmia   r0!, {r3-r10}                  /* copy from source address [r0]    */

              stmia   r1!, {r3-r10}                  /* copy to   target address [r1]    */

              cmp      r0, r2                               /* until source end addreee [r2]    */

              ble        copy_loop

#endif  /* CONFIG_SKIP_RELOCATE_UBOOT */

 

分析5:复制代码

1          adr  r0, _start的伪代码,被翻译成实际汇编代码为:33d000a4:  e24f00ac    sub  r0, pc, #172  ; 0xac其含义就是,通过计算PC+8-172 => _start的地址,而_start的地址,即相对代码段的0地址,是返个地址在运行时刻的值,而当ARM920T加电启动后,,此处是从Nor Flash启动,对应的代码,也是在Nor Flash中,对应的物理地址是0x0,所以,此时_start的值就是0,而不是0x33f80000。

2            beq指令和ble指令

 

/* Set up the stack                                                                               */

stack_setup:

              ldr         r0, _TEXT_BASE                        /* upper 128 KiB: relocated uboot   */

              sub       r0, r0, #CONFIG_SYS_MALLOC_LEN            /* malloc area                      */

              sub       r0, r0, #CONFIG_SYS_GBL_DATA_SIZE /* bdinfo                        */

#ifdef CONFIG_USE_IRQ

              sub       r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)

#endif

              sub       sp, r0, #12                     /* leave 3 words for abort-stack    */

 

分析6:设置堆栈指针sp

1            r0  =  _TEXT_BASE - CONFIG_SYS_MALLOC_LEN - CONFIG_SYS_GBL_DATA_SIZE ,其中CONFIG_SYS_MALLOC_LEN

2            如果定义了CONFIG_USE_IRQ,即如果使用中断的话,那么再把r0的值减去IRQ和FIQ的堆栈的值。

3            最后再减去终止异常所用到的堆栈大小,即12个字节。r0的值赋值给sp,即堆栈指针。

 

clear_bss:

              ldr         r0, _bss_start                            /* find start of bss segment */

              ldr         r1, _bss_end                /* stop here */

              mov     r2, #0x00000000                      /* clear */

 

clbss_l:str        r2, [r0]                           

              add       r0, r0, #4

              cmp      r0, r1

              ble        clbss_l

 

              ldr         pc, _start_armboot

_start_armboot:         .word start_armboot

 

分析7:清除bss段

1            先将r2,即0x0,存到地址为r0的内存中去,然后r0地址加上4,比较r0地址和r1地址,即比较当前地址是否到了bss段的结束位置,如果小于或等于,那么就跳到clbss_l循环,直到地址超过了bss的_end位置,即实现了将整个bss段,都清零。

2            将地址为_start_armboot中的内容,即start_armboot,赋值给PC,即调用start_armboot函数。至此,汇编语言的start.S的整个工作,就完成了。

3            为什么要清bss段?

 

#ifndef CONFIG_SKIP_LOWLEVEL_INIT

cpu_init_crit:

              /** flush v4 I/D caches*/

              mov     r0, #0

              mcr      p15, 0, r0, c7, c7, 0    /* flush v3/v4 cache */

              mcr      p15, 0, r0, c8, c7, 0    /* flush v4 TLB */

 

              /** disable MMU stuff and caches*/

              mrc      p15, 0, r0, c1, c0, 0

              bic         r0, r0, #0x00002300 @ clear bits 13, 9:8 (--V- --RS)

              bic         r0, r0, #0x00000087 @ clear bits 7, 2:0 (B--- -CAM)

              orr        r0, r0, #0x00000002 @ set bit 2 (A) Align

              orr        r0, r0, #0x00001000 @ set bit 12 (I) I-Cache

              mcr      p15, 0, r0, c1, c0, 0

 

              /*

               * before relocating, we have to setup RAM timing

               * because memory timing is board-dependend, you will

               * find a lowlevel_init.S in your board directory.

               */

              mov     ip, lr

              bl           lowlevel_init

              mov     lr, ip

              mov     pc, lr

#endif /* CONFIG_SKIP_LOWLEVEL_INIT */

分析8:

1            MCR指令将ARM处理器的寄存器中的数据传送到协处理器寄存器中。如果协处理器不能成功地执行该操作,将产生未定义的指令异常中断。

/*

 *************************************************************************

 *

 * Interrupt handling

 *

 *************************************************************************

 */

 

@

@ IRQ stack frame.

@

#define S_FRAME_SIZE         72

 

#define S_OLD_R0     68

#define S_PSR              64

#define S_PC                60

#define S_LR                 56

#define S_SP                52

 

#define S_IP                 48

#define S_FP                44

#define S_R10              40

#define S_R9                36

#define S_R8                32

#define S_R7                28

#define S_R6                24

#define S_R5                20

#define S_R4                16

#define S_R3                12

#define S_R2                8

#define S_R1                4

#define S_R0                0

 

#define MODE_SVC 0x13

#define I_BIT  0x80

 

/*

 * use bad_save_user_regs for abort/prefetch/undef/swi ...

 * use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling

 */

 

              .macro              bad_save_user_regs

              sub       sp, sp, #S_FRAME_SIZE

              stmia   sp, {r0 - r12}                               @ Calling r0-r12

              ldr         r2, _armboot_start

              sub       r2, r2, #(CONFIG_STACKSIZE)

              sub       r2, r2, #(CONFIG_SYS_MALLOC_LEN)

              sub       r2, r2, #(CONFIG_SYS_GBL_DATA_SIZE+8)  @ set base 2 words into abort stack

              ldmia   r2, {r2 - r3}                                  @ get pc, cpsr

              add       r0, sp, #S_FRAME_SIZE                      @ restore sp_SVC

 

              add       r5, sp, #S_SP

              mov     r1, lr

              stmia   r5, {r0 - r3}                                  @ save sp_SVC, lr_SVC, pc, cpsr

              mov     r0, sp

              .endm

 

              .macro              irq_save_user_regs

              sub       sp, sp, #S_FRAME_SIZE

              stmia   sp, {r0 - r12}                               @ Calling r0-r12

              add     r7, sp, #S_PC

              stmdb   r7, {sp, lr}^                   @ Calling SP, LR

              str     lr, [r7, #0]                    @ Save calling PC

              mrs     r6, spsr

              str     r6, [r7, #4]                    @ Save CPSR

              str     r0, [r7, #8]                    @ Save OLD_R0

              mov     r0, sp

              .endm

 

              .macro              irq_restore_user_regs

              ldmia   sp, {r0 - lr}^                                 @ Calling r0 - lr

              mov     r0, r0

              ldr         lr, [sp, #S_PC]                                           @ Get PC

              add       sp, sp, #S_FRAME_SIZE

              subs     pc, lr, #4                                       @ return & move spsr_svc into cpsr

              .endm

 

              .macro get_bad_stack

              ldr         r13, _armboot_start                             @ setup our mode stack

              sub       r13, r13, #(CONFIG_STACKSIZE)

              sub       r13, r13, #(CONFIG_SYS_MALLOC_LEN)

              sub       r13, r13, #(CONFIG_SYS_GBL_DATA_SIZE+8) @ reserved a couple spots in abort stack

 

              str         lr, [r13]                                         @ save caller lr / spsr

              mrs      lr, spsr

              str     lr, [r13, #4]

 

              mov     r13, #MODE_SVC                                  @ prepare SVC-Mode

              @ msr               spsr_c, r13

              msr      spsr, r13

              mov     lr, pc

              movs   pc, lr

              .endm

 

              .macro get_irq_stack                                         @ setup IRQ stack

              ldr         sp, IRQ_STACK_START

              .endm

 

              .macro get_fiq_stack                                          @ setup FIQ stack

              ldr         sp, FIQ_STACK_START

              .endm

 

/*

 * exception handlers

 */

              .align  5

undefined_instruction:

              get_bad_stack

              bad_save_user_regs

              bl           do_undefined_instruction

 

              .align   5

software_interrupt:

              get_bad_stack

              bad_save_user_regs

              bl           do_software_interrupt

 

              .align   5

prefetch_abort:

              get_bad_stack

              bad_save_user_regs

              bl           do_prefetch_abort

 

              .align   5

data_abort:

              get_bad_stack

              bad_save_user_regs

              bl           do_data_abort

 

              .align   5

not_used:

              get_bad_stack

              bad_save_user_regs

              bl           do_not_used

 

#ifdef CONFIG_USE_IRQ

 

              .align   5

irq:

              get_irq_stack

              irq_save_user_regs

              bl           do_irq

              irq_restore_user_regs

 

              .align   5

fiq:

              get_fiq_stack

              /* someone ought to write a more effiction fiq_save_user_regs */

              irq_save_user_regs

              bl           do_fiq

              irq_restore_user_regs

 

#else

 

              .align   5

irq:

              get_bad_stack

              bad_save_user_regs

              bl           do_irq

 

              .align   5

fiq:

              get_bad_stack

              bad_save_user_regs

              bl           do_fiq

 

#endif

 

 

 

 

 

 

阅读(1425) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~