u-boot详细分析(一)

时间:2021-05-05 16:45:54

uboot详细分析(一)

本文尽可能详细的分析uboot1.1.6.截止目前,作者仅仅将uboot1.1.6移植到TQ2440上,能够从NAND Flash自启动.本文的目的在于总结自己在移植过程中需要掌握的知识点.

.globl_start : .globl 是为了声明_start为全局的一个标号,为其他文件能够引用.

还记得在分析start.lds文中提到ENTRY(_start)吗,它指明了CPU上电启动的入口函数地址,就是此处的_start

_start:    b      reset

    ldr pc,_undefined_instruction     /* 未定义指令向量   */

    ldr pc,_software_interrupt       /* 软件中断向量      */

    ldr pc,_prefetch_abort           /* 预取指令异常向量 */

    ldr pc,_data_abort               /* 数据操作异常向量 */

    ldr pc,_not_used                 /* 未使用           */

    ldr pc,_irq                      /* irq 中断向量     */

    ldr pc,_fiq                      /* fiq 中断向量     */

 

_undefined_instruction:   .word undefined_instruction

_software_interrupt:      .word software_interrupt

_prefetch_abort:          .wordprefetch_abort

_data_abort:             .word data_abort

_not_used:               .word not_used

_irq:                     .word irq

_fiq:                     .word fiq

根据中断ARM异常处理规定,8个中断向量异常处理的地址依次为0x0(复位),0x4(未定义指令异常),0x8(软件中断异常),0xc(预取指令异常),0x10(数据操作异常),0x14(保留),0x18(irq中断向量),0x1c(fiq中断向量);所以必须将这八种异常指定的地址中存放我们自己的异常处理指令,我们的指令都是存放一条跳转指令来处理相应的异常,这个应该不难理解.

 

.balignl16,0xdeadbeef

可以参照这位仁兄的分析http://haoyeren.blog.sohu.com/84511571.html,这里0xdeadbeef只是一个标识.

 

_TEXT_BASE:

    .word  TEXT_BASE

这里定义了一个TEXT_BASE,这个标识的值我们可以在源代码的borad/smdk2410/config.mk里面找到,用它将来标识我们代码存放在内存中的位置.

.globl_armboot_start

_armboot_start:

    .word _start

这里同样将_armboot_start声明为全局标号,它的值就是我们的首地址_start

 

.globl_bss_start

_bss_start:

    .word __bss_start

 

.globl_bss_end

_bss_end:

    .word _end

这里同样有声明两个全局的标识_bss_start,_bss_end,它们分别被定为__bss_start和_end,这两个值是外部的两个标识,它们的值指定在u-boot.lds文件指定的,查看section布局即可看到它们的位置.

 

#ifdefCONFIG_USE_IRQ

/*IRQ stack memory (calculated at run-time) */

.globlIRQ_STACK_START

IRQ_STACK_START:

    .word  0x0badc0de

 

/*IRQ stack memory (calculated at run-time) */

.globlFIQ_STACK_START

FIQ_STACK_START:

    .word 0x0badc0de

#endif

由于CONFIG_USE_IRQ没有定义所以以上的一段略过!

reset:

    /*

     * setthe cpu to SVC32 mode

     */

    mrs r0,cpsr

    bic r0,r0,#0x1f

    orr r0,r0,#0xd3

    msr cpsr,r0

终于看到了reset了,这个在我们的_start标号后面的第一条语句就是

_start:    b      reset

我们上电给CPU后,立即执行这个复位指令

首先我们看下cpsr,cpsr是程序状态寄存器,它的定义如下所示:

31 30 29 28    27   --  8    7  6 5  4   3  2   1   0

N  Z  C V  (   DNM(RAZ)   ) I  F  T  M4  M3  M2  M1  M0

 

N:N = 1 表示运算结果为负数;N = 0 表示结果为正数

Z:Z = 1 表示运算结果为0;Z = 0 表示运算结果不为0

C: C= 0 表示在加法指令中当结果产生进位,无符号数运算发生上溢出

   C = 1 表示在减法指令中当结果产生借位,无符号数运算发生下溢出

V:在加减法运算指令中,当操作数和运算结果为二进制补码表示的带符号数时,V = 1表示符号溢出

I:I = 1 时禁止IRQ中断

F:F = 1 时禁止FIQ中断

T:T = 0 表示执行ARM指令

   T = 1 表示Thumb指令

 

M4 M3 M2 M1 M0

1  0 0  0  0    用户模式

1  0 0  0  1    快速中断模式

1  0 0  1  0    外部中断模式

1  0 0  1  1    特权模式

1  0 1  1  1    数据访问中止模式

1  1 0  1  1    未定义指令中止模式

1  1 1  1  1    系统模式

 

 

mrs r0,cpsr 指令是将cpsr中的值读到r0中

bic r0,r0,#0x1f

orr r0,r0,#0xd3

将读出来的值修改,后再次写回r0,此时欲将FIQ,IRQ关闭,处理器模式设定为特权模式

msr cpsr,r0 将修改后的值再次写回到cpsr中

 

接下来设置:看门狗,中断控制器,以及时钟

以下是s3c2440/s3c2410芯片这些外设的地址

#define pWTCON      0x53000000

#define INTMSK      0x4A000008

#define INTSUBMSK   0x4A00001C

#define CLKDIVN     0x4C000014

 

    ldr    r0, =pWTCON

    mov    r1, #0x0

    str    r1, [r0]

以上三条指令是为了关闭看门狗,如果此处不关闭的话会出现uboot正常启动以后不停重启的现象.

    mov r1,#0xffffffff

    ldr r0,=INTMSK

    str r1,[r0]

将中断源屏蔽

    ldr    r1,=0x3ff

    ldr r0,=INTSUBMSK

    str r1,[r0]

将子中断源屏蔽

 

 

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

 

以上代码是使数据cache和指令cache无效,关闭MMU.具体寄存器设置是怎么操作的,我想有必要另外开一个专题进行研究.

 

    /*

     *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

现在看上面代码,需要注意的是以上代码是cpu_init_crit:段的一部分,所以在执行完以后需要函数返回,所以在最后会有mov   pc, lr指令.但是期间又一次调用了lowlevel_init,所以需要首先将lr中的值保存起来,这里这个ip感觉怪怪的,其实就是r12,它只不过是个别名罢了.当从lowlevel_init返回后再将原来的lr恢复.

下面我们进入lowlevel_init中分析.该函数在

board/smdk2410/lowlevel_init.S文件中.

_TEXT_BASE:

   .word  TEXT_BASE

此处也定义了一个_TEXT_BASE,它的值也是在/board/smdk2410/config.mk

 

下面来分析代码

.globl lowlevel_init

lowlevel_init:

   /*memory control configuration */

   /*make r0 relative the current location so that it */

   /*reads SMRDATA out of FLASH rather than memory ! */

   ldr     r0, =SMRDATA

   ldr r1, _TEXT_BASE

   sub r0, r0, r1

   ldr r1, =BWSCON   /*Bus Width Status Controller */

   add     r2, r0, #13*4

0:

   ldr     r3, [r0], #4

   str     r3, [r1], #4

   cmp     r2, r0

   bne     0b

 

   /*everything is fine now */

   mov pc, lr

 

   .ltorg

 

首先将lowlevel_init声明为全局标识,为其他模块能够引用.

接下来 ldr     r0, =SMRDATA

       ldr r1, _TEXT_BASE

       sub r0,r0, r1

这三条指令指的我们去分析一下,从指令的表面看来将来执行完毕后r0中保存的就是SMRDATA相对_TEXT_BASE的偏移地址,但是为什么需要的是偏移地址而不是绝对地址呢?其实我们回过头来想想,我们是从start.S文件开始执行的,从u-boot.lds连接脚本文件中可以知道,我们的start.S是被连接在前4K的,如果从NandFlash启动,S3C2440会将前4K的内容自动复制到片内RAM中,当然片内RAM的地址是从0开始,所以我们的代码执行时从0地址开始执行的.如果从NorFlash启动,NorFlash启动地址本来就映射在S3C2440的0地址空间,同样代码是从0地址启动.当然我们会把lowlevel_init也连接在前4K的空间内,这样看来我们r0中虽然是一个偏移地址,但是相对于从0地址空间开始的代码这个偏移地址其实就是一个绝对地址(0+偏移量).(啰嗦写这么多不知道解释清楚没有).

接着往下看

   ldr r1, =BWSCON   /* Bus Width Status Controller */

   add     r2, r0, #13*4

r1装入内存控制器的首地址,r2装入内存控制器的末地址

0:

   ldr     r3, [r0], #4

   str     r3, [r1], #4

   cmp     r2, r0

   bne     0b

 

   /* everything is fine now */

   mov pc, lr

 

   .ltorg

/* the literal pools origin*/

SMRDATA:

.word (此处放BWSCON的配置)

.word (此处放BANKCON0的配置)

.word (此处放BANKCON1的配置)

.word (此处放BANKCON2的配置)

.word (此处放BANKCON3的配置)

.word (此处放BANKCON4的配置)

.word (此处放BANKCON5的配置)

.word (此处放BANKCON6的配置)

.word (此处放BANKCON7的配置)

.word (此处放REFRESH的配置)

.word (此处放BANKSIZE的配置)

.word (此处放MRSR的配置)

上面的一段代码将SMDATA处所有关于内存控制器的配置保存到内存控制器中,关于这些配置uboot已经给出了一些默认的值,但是我们需要根据自己的开发板来调整这些配置.尤其是要注意bank6/7的配置,因为我们的SDRAM都挂载在这两个bank上,bank6的起始地址是0x30000000,所以我们下载代码的地址都是在这个地址之后.

 

接下来我们返回到start.S中,继续往下执行

stack_setup:

   ldr r0, _TEXT_BASE      

   sub r0, r0, #CFG_MALLOC_LEN 

   sub r0, r0,#CFG_GBL_DATA_SIZE

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

这是进行堆栈的分配,此处为malloc分配128k的堆,分配128个字节的栈区,r0就是指向的栈顶的指针,再预留3个word空间大小,然后把这个栈顶给真正用来管理堆栈的指针sp寄存器.此处另外在多预留3个word不知道用意是什么,还没有弄清楚.

本节先暂时分析至此!