首页 > 代码库 > 自己学驱动7——uboot代码阅读二(start.S)

自己学驱动7——uboot代码阅读二(start.S)

#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
    在uboot的start.S中上面的这一段程序是对IRQ栈起始地址的一个初始化,这里往IRQ_STACK_START和FIQ_STACK_START地址处的内容都写上了0x0badc0de这个值,这个值可以看做是“bad code”,因为这个值现在是没有意义的,只是随意填充的一个值,真正需要设置这个值的时候会是在cpu_init(void)函数里面(这个函数的路径为:cpu\arm920t/Cpu.c)。


/* turn off the watchdog */
#if defined(CONFIG_S3C2400)
# define pWTCON        0x15300000
# define INTMSK        0x14400008    /* Interupt-Controller base addresses */
# define CLKDIVN    0x14800014    /* clock divisor register */
#elif defined(CONFIG_S3C2410)
# define pWTCON        0x53000000
# define INTMSK        0x4A000008    /* Interupt-Controller base addresses */
# define INTSUBMSK    0x4A00001C
# define CLKDIVN    0x4C000014    /* clock divisor register */
#endif

#if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410)
    ldr     r0, =pWTCON
    mov     r1, #0x0
    str     r1, [r0]
    这一小段代码中,首先根据CPU的类型,定义了相应的寄存器的地址,然后使用ldr和str指令对该寄存器进行设置(这里只列出了pWTCON看门狗寄存器的设置语句)。
# define pWTCON        0x15300000 /*定义了看门狗寄存器的地址*/
ldr     r0, =pWTCON /*ldr指令在使用=号的时候,是一个伪指令,会将后面标号本身的值
                      而不是标号所代表的地址处的内容赋给目标,所以这个语句完成的
                      功能就是把0x15300000这个值赋给了pWTCON*/
str     r1, [r0] /*这个是把r0寄存器里面的值当做一个地址值,将r1的值赋值到这个内寸*/


#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
#endif    /* CONFIG_SKIP_RELOCATE_UBOOT */
    这一段代码非常有意义,是一段重定位代码的程序。在重定位之前首先会判断一下是否需要重定位,判断的方法如下:
adr    r0, _start /*这是一个地址读取的位置无关指令,将_start的地址读取到r0中
                     如果当前的start.S被放在Flash中,那么这个得到的_start为0
                     而如果当前的start.S被加载到了内存中,那么这时候得到的值
                     将会是一个不为0的值,因为2440外接的Flash和RAM是在起始地
                     址不同的bank处*/
ldr    r1, _TEXT_BASE /*这条指令会将_TEXT_BASE代表的地址处的值读取到r1中,然而
                         根据_TEXT_BASE: .word    TEXT_BASE这个地址存放的值来自于
                         链接脚本中,代表的是其运行地址*/
    后面的工作就是比较r0和r1的值,如果是相等的,那么证明这个时候代码已经位于了其应该位于的地方,这个时候是不需要重定位代码的。但是有一点使人比较迷惑的就是,现在我们分析的start.S代码是系统上电就会执行的一段代码,前面根本没有重定位的代码,代码怎么还会可能就位于其应该位于的地方?答案是这种情况发生在使用仿真器仿真的时候,这种情况下,仿真器帮我们做了重定位的工作。如果r1和r0的值相等,那么将会是一个跳转,直接跳转到刚好重定位代码结束的地方继续往下执行。
    再继续往下看:
_armboot_start: .word _start
    r2寄存器中存放的是_start标号的值,也就是所有代码的开始地址。而r3寄存器里面的值稍微复杂一些。下面就来分析r3的值:
_bss_start: .word __bss_start根据这条语句可见先必须找到__bss_start的值。而这个值定义在board/smdk2410/u-boot.lds文件中,定义如下:
. = ALIGN(4);
     __bss_start = .;
     .bss : { *(.bss) }
     _end = .;
    从上面的定义中可以看出__bss_start=.; 表示__bss_start值就是当前位置的值。当前位置是多少呢?从下面一句.bss:{*(.ss)}知道。紧接该位置后面马上就是放.bss段数据了。所以,当然就是.bss段的起始地址。然而根据整个链接脚本来看,编译完之后的代码会包含代码段和.bss段等,而代码段之后紧接着的就是.bss段,所以.bss端的起始地址减去代码段的起始地址就可以得到代码段的大小!
    上面已经算出了代码段的大小,现在就来看搬移的具体代码。
ldmia    r0!, {r3-r10} /*这个是内存加载指令,会把r0代表的地址处的内存的内容加载到后
                        面的寄存器列表中,ia表示Increment After即先将4字节的数据搬
                        移到一个寄存器,然后再将内存地址和寄存器都往后跳往下一个*/
stmia    r1!, {r3-r10} /*这个跟上一条语句类似,只不过变成了从寄存器到内存的搬移*/
cmp    r0, r2 /*这是来判断是否重定位完成的一个判断语句*/

自己学驱动7——uboot代码阅读二(start.S)