uboot之start.S源码分析

/arch/arm920t/cpu/start.s文件就是uboot的第一阶段,uboot的前4K内容,即nandflash中的前4K内容会被拷贝到cpu中的SRAM中运行,这一小段代码负责初始化硬件环境,并将剩余的Uboot代码加载到内存中去。从而跳转到第二阶段,在第二阶段运行之前需要建立堆栈。

IRQ_STACK_START    .word 0x0badc0de

FRQ_STACK_START    .word 0x0badc0de

/*

 *  armboot - Startup Code for ARM920 CPU-core

 *

  */

 

 

#include <config.h>

#include <version.h>

 

 

/*

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

 *

 * Jump vector table as in table 3.1 in [1]

 *

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

 */

 

 

.globl _start

_start:  b       reset        //b是跳转指令,即跳转到reset标签处。接着返回到此处。

     ldr  pc, _undefined_instruction设置中断向量表 0x0 0x4.....0x8 0xc

     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

利用.word来在当前位置放置一个值,这个值实际上就用对应的中断处理函数的地址
;.word的意义为在当前地址处放入一个16bits值

     .balignl 16,0xdeadbeef

 

 

/*

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

 *

 * Startup Code (reset vector)

 *

 * do important init only if we don't start from memory!

 * relocate armboot to ram

 * setup stack

 * jump to second stage //从英文注释中可以看出starts.o的作用。

 *

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

 */

 

_TEXT_BASE:

     .word    TEXT_BASE

 

.globl _armboot_start

_armboot_start:

     .word _start

 

/*

 * These are defined in the board-specific linker script. 针对不同板类型的链接脚本中已经定义过了,具体的脚本??

 */

.globl _bss_start   //未初始化的数据段开始地址

_bss_start:

     .word __bss_start

 

.globl _bss_end  //结束地址

_bss_end:

     .word _end

 

#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

 

 

/*

 * the actual reset code

 */

_start:入口处,马上跳转到reset处,在SVC状态下要关闭所有中断。

reset:

     /*

      * set the cpu to SVC32 mode //超级用户态,操作系统使用的保护模式。系统复位和软件中断时进入该模式。

      */

     mrs  r0,cpsr   //将当前cpsr的状态为保存到r0中。

     bic  r0,r0,#0x1f  //bic,位清零指令。0x1f=00011111,相当于清除低5位。刚好是模式位。

     orr  r0,r0,#0xd3  //或指令。很明显是置模式位。0xd3=11010011以及设置5,6,7位的状态位。禁止FIQ,IRQ,处于arm状态。低5位为10011,则对应超级用户态。

     msr  cpsr,r0  //在将r0中的值赋给状态寄存器cpsr

 

/* 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)我们的是2410,如果移植其它的,则可以添加相关的基地址

# define pWTCON        0x53000000  //pWTCON 看门狗寄存器的基地址,手册上就是WTCON,这里多一个p

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

# define INTSUBMSK 0x4A00001C 中断子掩码寄存器

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

#endif

 

将看门狗寄存器清空,其各位含义为,第0位为1则当看门狗定时器溢出时重启,为0则不重启,初始值为1

第2位为中断使能位,初值为0

第3,4位为时钟分频银子,初值为00

第5位为看门狗的使能位,初值为1

第8~15位为比例因子,初值为0x80

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

     ldr     r0, =pWTCON //将pWTCON寄存器的地址赋给r0

     mov     r1, #0x0

     str     r1, [r0]  //将pWTCON所有位置为0,就关闭看门狗了,实际上只要将第5位置0即可。

 

     /*

      * 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, =0x7ff   011111111111,很多资料上是0x3ff。手册上规定有13位可用

     ldr  r0, =INTSUBMSK如果是2410,这个寄存器也要屏蔽

     str  r1, [r0] //将低13位全都置1 13位可用 而不是12位

# 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 */

 

     /*

      * we do sys-critical inits only at reboot,

      * not when booting from ram!

      */

#ifndef CONFIG_SKIP_LOWLEVEL_INIT 防止重复引用cpu_init_crit函数。

     bl   cpu_init_crit

#endif

 

橙色的部分代码,是针对从nor flash中启动的设备。对于不是从nandflash中启动的设备,没什么用。这一段好像也能执行代码复制.

#ifndef CONFIG_SKIP_RELOCATE_UBOOT 

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

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

查看当前代码的地址信息,若从ram中运行,则_start=_TEXT_BASE,否则_start = 0x00000000

     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     若不等,则表示从flash中运行,重定向代码

     ldr  r3, _bss_start         获取未初始化数据段地址

     sub  r2, r3, r2         /* r2 <- size of armboot            */代码段的长度

     add  r2, r0, r2         /* r2 <- source end address         */代码的长度

 

copy_loop:

复制代码,r0为代码的起始地址,r1为ram中地址,r2为代码的终止地址,每次copy后将r0的值递增同r2比较来判断是否复制完成。

     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 */

     /* Set up the stack                                */

stack_setup:

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

     sub  r0, r0, #CFG_MALLOC_LEN /* malloc area  192K                    */

     sub  r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo 分配128字节来存储开发板信息        */

#ifdef CONFIG_USE_IRQ

     sub  r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)

#endif再减去12字节用于栈起点

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

 

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]      /* clear loop...                    */

     add  r0, r0, #4

     cmp  r0, r1

     ble  clbss_l

 

#if 0

     /* try doing this stuff after the relocation */

     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, =INTMR

     str  r1, [r0]

 

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

     /* default FCLK is 120 MHz ! */

     ldr  r0, =CLKDIVN

     mov  r1, #3

     str  r1, [r0]

     /* END stuff after relocation */

#endif

现在的设别,大都是利用SDRAM与NANDFLASH共同作用,因此为了支持能从nand_flash中启动,需要添加下面的红色代码。

 

#ifdef CONFIG_S3C2410_NAND_BOOT

bl copy_myself

 

@jump to ram

ldr r1,=on_the_ram

add pc,r1,#0

nop

nop

1:

b 1b

on_the_ram

#endif

 

     ldr  pc, _start_armboot

 

_start_armboot:    .word start_armboot

 

#ifdef CONFIG_S3C2410_NAND_BOOT

copy_myself:

mov r10.lr  将当前的lr保存到r10中,保存断点地址

@reset nand

mov r1,#NAND_CTL_BASE nandflash基地址

ldr r2,0xf830 r2 = 1111,1000,0011,0000 第15位为nandflash控制器使能位,第12位初始化ECC,第11位nFCE使能?????有问题

str r2,[r1,#oNFCONF]

ldr r2,[r1,#oNFCONF]

 

bic r2,r2,#0x800   将第11位清零指令,使能芯片

str r2,[r1,#oNFCONF]

写入命令

mov r2,#0xff   @reset command

strb r2,[r1,#oNFCMD]

 

mov r3,#0 

1:
  add r3, r3, #0x1     //循环等待  

cmp r3, #0xa
  blt 1b

2:利用状态寄存器测试flash内部操作是否完成,如果完成则状态寄存器将返回1.NFSTAT最后一位为0时,表示正在忙,为1表示空闲
  ldr r2, [r1, #oNFSTAT] @ wait ready
  tst r2, #0x1 //tst位测试指令
  beq 2b

  ldr r2, [r1, #oNFCONF] 禁止芯片
  orr r2, r2, #0x800 @ disable chip
  str r2, [r1, #oNFCONF]

@ get read to call C functions (for nand_read()) 建立堆栈,栈起点0x33f00000,大小为0x8000
  ldr sp, DW_STACK_START         @ setup stack pointer
  mov fp, #0                     @ no previous frame, so fp=0


 

 

@ copy U-Boot to RAM。r0 r1 r2为传入到Nand_read_ll中的三个参数,nand_read_ll(unsigned char *buf, unsigned long start_addr, int size)

可知,
  ldr r0, =UBOOT_RAM_BASE 
  mov r1, #0x0
  //mov r2, #0x20000  //UBOOT大小为128K 这三个参数传入到nand_read_ll中

mov r2. #0x30000 //设置为192k
  bl nand_read_ll
  tst r0, #0x0     r0为返回值nand_read_ll的返回值
  beq ok_nand_read

bad_nand_read:
loop2: b loop2 @ infinite loop


ok_nand_read: nand_flash通过ecc校验来保证拷贝到SDRAM中的内容是正确的
@ verify
  mov r0, #0
  ldr r1, =TEXT_BASE
  mov r2, #0x400 @ 4 bytes * 1024 = 4K-bytes,每条指令占4个字节,共移动0x400即1024次,加起来就移动了4*1024即4K的大小
go_next:
  ldr r3, [r0], #4
  ldr r4, [r1], #4
  teq r3, r4
  bne notmatch
  subs r2, r2, #4
  beq stack_setup
  bne go_next

notmatch:
loop3: b loop3 @ infinite loop

#endif @ CONFIG_S3C2410_NAND_BOOT

 

 

/*

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

 *

 * CPU_init_critical registers

 *

 * setup important registers

 * setup memory timing

 *

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

 */

 

 

#ifndef CONFIG_SKIP_LOWLEVEL_INIT  cpu的设置,清楚I/D cache,清除TLB

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        //返回到reset

     bl   lowlevel_init

     mov  lr, ip

     mov  pc, lr        //从lowlevel_init中,返回到reset

#endif /* CONFIG_SKIP_LOWLEVEL_INIT */

 

/*

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

 *

 * 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+CFG_MALLOC_LEN)

     sub  r2, r2, #(CFG_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     r8, sp, #S_PC

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

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

     mrs     r6, spsr

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

     str     r0, [r8, #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+CFG_MALLOC_LEN)

     sub  r13, r13, #(CFG_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

你可能感兴趣的:(uboot之start.S源码分析)