免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1057 | 回复: 0
打印 上一主题 下一主题

uboot之start.S源码分析 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-04-21 00:01 |只看该作者 |倒序浏览

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


/*
*************************************************************************
*
* 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    */
查看当前代码的地址信息,若从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             */代码段的长度
     add  r2, r0, r2         /* r2          */代码的长度

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



本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u3/93598/showart_1904947.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP