u-boot for fun (3) -- read start.S

时间:2021-03-16 04:55:32

start.S:

1.设置cpu模式为svc32

2.初始化看门狗

3.设置中断(根据手册)

4.设置时钟CLKDIV

5.Cpu_critical_setting, memory timing, flush cache

6.重新定位u-boot

这里需要了解lds文件的作用,以及ldr,adr的区别,源码中这里是将代码从flashcopyRam中,如果移植到mini2440上的话,那这里就需要处理把u-boot copyram中。

 

u-boot for fun (3) -- read start.S

 

 

7.留出需要的内存(CFG_MALLOC_LEN, GBL_DATA_SIZE, IRQ+FIQ,定义用户栈区

8.清理bss

9.进入第二阶段

 

汇编基础:

ELF格式相关 参照 http://learn.akae.cn/media/ch18s05.html

汇编条令 参照:http://learn.akae.cn/media/ch18s01.html

 

 

 

 

 

代码解释:

 

 

.globl _start

 

/*_start为程序的入口点, 可以在连接脚本中修改Entry标签(即可以改用其他标签),_start是个全局变量,链接器会给它指定运行/加载地址。程序的第一条指定就存储在_start变量里*/


_start: b       reset

 

/*上面说到_start这个变量(地址)里存放的就是第一条指令,所以程序启动即执行reset,实际就是跳转到reset这个标签指定的地址,这里的b指令执行跳转时需要的偏移量是编译器根据当前和目标计算出来的,是个相对值,所以也是相对跳转*/

     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

 

/*上面这些是跳转到相应中断处理的命令,把各中断标签代表的地址中存放的值传给pc,cpu下条指令就会执行pc所指向地址的命令,也就是各中断标签代表的地址中所存放地址所指向的的命令。这是个绝对跳转,因为pc直接指向需要执行指令的存放的地址*/

 

_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

/*把各处理中断的程序序列地址赋给各标签,这里讨论下ARM汇编中的.word的用法。

官方解释:

.word
Syntax: .word expressions

This directive expects zero or more expressions, of any section, separated by commas. For each expression, as emits a 16-bit number for this target

就是把expression以16bit的方式存放在当前位置, 以上面的代码为例,_undefined_instruction: .word undefined_instruction, 是把undefined_instruction标号地址存放在_undefined_instruction标号地址处, .word就是赤裸裸的引用*/

 

.balignl 16,0xdeadbeef

/*强制对齐*/

 

 

_TEXT_BASE:
    .word TEXT_BASE

/*TEXT_BASE(config.mk定义的一个常量)存放在_TEXT_BASE标号地址处*/

 

.globl _armboot_start
_armboot_start:
    .word _start

 /*定义全局变量_armboot_start,并把_start的地址赋给_armboot_start*/

 

.globl _bss_start
_bss_start:
    .word __bss_start

.globl _bss_end
_bss_end:
    .word _end
/*
 * These are defined in the board-specific linker script.
 */

#ifdef CONFIG_USE_IRQ
/* IRQ stack memory (calculated at run-time) */
.globl IRQ_STACK_START
IRQ_STACK_START:
    .word   0x0badc0de

/* IRQ stack memory (calculated at run-time) */
.globl FIQ_STACK_START
FIQ_STACK_START:
    .word 0x0badc0de
#endif

reset:

    /*
     * set the cpu to SVC32 mode
     */
    mrs r0,cpsr
    bic r0,r0,#0x1f
    orr r0,r0,#0xd3
    msr cpsr,r0

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

 

 

#ifndef CONFIG_SKIP_RELOCATE_UBOOT
relocate:               /* relocate U-Boot to RAM       */
    adr r0, _start      /* r0 <- current position of code   */
    ldr r1, _TEXT_BASE      /* test if we run from flash or RAM */
    cmp     r0, r1                  /* don't reloc during debug         */
    beq     stack_setup

    ldr r2, _armboot_start
    ldr r3, _bss_start
    sub r2, r3, r2      /* r2 <- size of armboot            */
    add r2, r0, r2      /* r2 <- source end address         */

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

 

/*上面的代码块实现了u-boot把自己从flash cp到RAM中。

adr r0, _start      /* r0 <- current position of code   */

adr 是伪指令,是把_start的地址放到r0中,但是需要注意,这里获取_start的地址是汇编器通过计算当前PC到_start的偏移量得到的,我们可以看下u-boot的反汇编

33f80094 <relocate>:
33f80094:   e24f009c    sub r0, pc, #156    ; 0x9c

可以看出上面的伪指令在汇编器处理之后是一条sub语句,是用当前PC值减去156,以为ARM是流水线工作,预取指令,所以执行到这条命令的时候PC值跟程序运行区域有关系,如果u-boot此刻运行在ARM4kflash中,那么PC=0x33f80094 + 8 = 33f8009c,如果运行在RAM,那么PC=0x0 + 8.所以R0就是33f80000(运行在flash中)或者0(运行在RAM中),即_start的地址。*/

ldr r1, _TEXT_BASE      /* test if we run from flash or RAM */

/*ldr 也是一条伪指令,是把_TEXT_BASE的值,最开始的代码段已经给_TEXT_BASE赋值为TEXT_BASE(/board/boadname/config.mk中赋值为33f80000),所以r1=0x33f80000

u-boot反汇编看此条指令为

 33f80098:   e51f1060    ldr r1, [pc, #-96]  ; 33f80040 <_TEXT_BASE>

以此可以看出,可以对比r0和r1的值来确定u-boot现在运行的环境(RAM/Flash)/*

  ldr r2, _armboot_start
    ldr r3, _bss_start
    sub r2, r3, r2      /* r2 <- size of armboot            */
    add r2, r0, r2      /* r2 <- source end address         */

/*ldr 是个比mov更好用的数据传递指令,_armboot_start, _bass_start都是对_start, bss_start的引用,这样就可以把想要的地址传递到r2, r3中了。想要得到u-boot映像的大小,就需要知道起始和截止地址,_start和bss_start的地址在连接后都是确定的,所以r3-r2就是size of u-boot*/


 ldr pc, _start_armboot

_start_armboot: .word start_armboot


/*跳转到第二阶段继续执行函数,此时_start_armboot存放的是全局变量start_armboot的地址,是链接后的地址,也就是运行地址,指向RAM。从而实现了跳到RAM继续执行后面的程序*/