Chinaunix首页 | 论坛 | 博客
  • 博客访问: 346202
  • 博文数量: 39
  • 博客积分: 1931
  • 博客等级: 上尉
  • 技术积分: 778
  • 用 户 组: 普通用户
  • 注册时间: 2008-09-11 10:54
文章分类

全部博文(39)

文章存档

2011年(20)

2010年(15)

2009年(4)

我的朋友

分类: 嵌入式

2010-12-02 13:31:12

1。第一阶段完成的功能

u-boot-2010.06/arch/arm/cpu/arm920t/start.S

<1>硬件初始化。

  设置CPU工作模式为管理模式(svc)

  关闭开门狗

  设置FCLK,HCLK,PCLK的比例(即设置CLKDIVN)

  关闭MMU.CACHE

<2>为加载Bootloader的第二阶段代码准备RAM空间。

  所谓准备RAM空间就是初始化内存芯片,使其能正常工作。在start.S中调用lowlevel_init 函数来设置存储控制器,使得外接的SDRAM可用。代码在board/samsung/smdk2440/lowlevel_init.S中。

<3>复制Bootloader的第二阶段到RAM空间。

  将这个U-Boot的代码(包括第一、第二阶段)都复制到SDRAM中,在arch/arm/cpu/arm920t/start.S中实现。

<4>设置好栈。

<5>跳转到第二阶段的C入口点。

  在跳转之前,还要清除BSS段(初始值为0、无初始化的全局变量、静态变量都放在BSS段)。如果设置了如下命令(1-bootdelay、2-bootm)则直接跳转,调用lib_arm/board.c中的start_armboot()函数。这是第二阶段的入口点。

 

2。源码流程

<1>:初始化硬件:

vi u-boot-2010.06/arch/arm/cpu/arm920t/start.S

.globl _start  //u-boot的主入口,跳入了后面的start_code
_start: b start_code  //这些是跳转向量表,和芯片的体系结构有关 占4字节内存
 ldr pc, _undefined_instruction
//ldr语句的意思是将第二个操作数(如:_undefined_instruction)指向的地址数据传给PC
 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  //.word 为定义一个4字节的空间

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//以上每条指令占4字节内存

 .balignl 16,0xdeadbeef  //16字节对齐,并以0xdeadbeef填充,它是个Magic number

/***********************************************

引用:http://haoyeren.blog.sohu.com/84511571.html

占了4x7=32字节内存。

所以在这个.balignl 16,0xdeadbeef指令之前,一共占了4x15=60个字节的内存,所以本代码的作者当时就简单的在15这个数上,加了个1,即16,把当前指针往后移到地址为64的位置,然后在前面插上了0xdeadbeef这个特殊的值。

我不知道这个地方是作者一个错误,歪打正着呢,还是怎么回子事,其实这个偏移的值还有好多种情况。如果说最小的值的话,那么也可以写成.balignl 8,0xdeadbeef,也可以达到同样的目的。因为60不是8的倍数,但是64是8的倍数,如果写8,也正好插到64前面,也即60这个内存起始地址。如果更大一点儿的呢,那么填32也可以达到同样的效果,即.balignl 32,0xdeadbeef,道理同上。当然,不能为4,因为pc值在任何时候,都是4的倍数,只要不为0就为4的倍数,呵呵,这个值不行,如果用了这个值,0xdeadbeef永远也插不进去,呵呵。

**************************************************/

********************************为BSS段,代码段,中断等地址分配内存********************************

_TEXT_BASE:

         .word         TEXT_BASE   //这些和上面的一样,定义一个4字节的空间存放地址

 

.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

******************************************设置CPU工作模式为管理模式(svc)******************************

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

*******************************************关闭看门狗********************************************************

#  define pWTCON 0x53000000

 

 ldr r0, =pWTCON
 mov r1, #0x0
 str r1, [r0]

*******************************************关闭中断和子中断************************************************

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

 mov r1, #0xffffffff
 ldr r0, =INTMSK
 str r1, [r0]

 ldr  r1, =0x7fff        //根据2440芯片手册,INTSUBMSK寄存器有15位可用     
 ldr  r0, =INTSUBMSK
 str  r1, [r0]

*****************************************设置时钟频率*******************************************************

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

#define MPLLCON   0x4C000004   //系统主频配置寄存器基地址
#define UPLLCON   0x4C000008   //USB时钟频率配置寄存器基地址

 

ldr  r0, =CLKDIVN      //设置分频系数FCLK:HCLK:PCLK = 1:4:8
mov  r1, #5
str  r1, [r0] 
ldr  r0, =MPLLCON  //设置系统主频为405MHz,才能让内核启动。  
ldr  r1, =0x7F021  //这个值参考芯片手册“PLL VALUE SELECTION TABLE”部分
str  r1, [r0]          
ldr  r0, =UPLLCON  //设置USB时钟频率为48MHz  
ldr  r1, =0x38022  //这个值参考芯片手册“PLL VALUE SELECTION TABLE”部
str  r1, [r0]
****************************************关闭mmu、cache初始化内存*************************************

#ifndef CONFIG_SKIP_LOWLEVEL_INIT
       bl cpu_init_crit 
//在start.S文件的最后,里面跳出start.S文件
#endif

//跳入cpu_init_crit ,这是一个系统初始化函数,他还会调用board/samsung/lowlevel_init.S中的lowlevel_init函数。主要是对系统总线的初始化,初始化了连接存储器的位宽、速度、刷新率等重要参数。经过这个函数的正确初始化,Nor Flash、SDRAM才可以被系统使用。下面的代码重定向就依赖它。
<2>为加载Bootloader的第二阶段代码准备RAM空间。

vi u-boot-2010.06/board/samsung/smdk2440/lowlever_init.S

lowlevel_init.S这个函数并不复杂,只是要注意这时的代码、数据都只是保存在Nor Flash上,内存中还没有,所以读取数据时要变化数据。这些都在4kb Stepping Stone中进行。

#define BWSCON 0x48000000  //总线控制寄存器

.....(略)一大堆寄存器位的定义

_TEXT_BASE:
 .word TEXT_BASE

.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 //SMRDATA 表示这13个寄存器的值存放的开始地址(连接地址),值为0x33F8 XXXX,处于内存中。
 ldr r1, _TEXT_BASE
//代码段地址 0x33F8 0000,定义在board/samsung/smdk2440/config.mk中。
 sub r0, r0, r1  //0x33F8 xxxx  与 0x33F8 0000相减,这就是13个寄存器值在NOR Flash上存放的地址。
 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
/* the literal pools origin */

SMRDATA: //根据SDRAM的datasheet,给13个寄存器赋值
    .word (0+(B1_BWSCON<<4)+(B2_BWSCON<<8)+(B3_BWSCON<<12)+(B4_BWSCON<<16)+(B5_BWSCON<<20)+(B6_BWSCON<<24)+(B7_BWSCON<<28))
    .word ((B0_Tacs<<13)+(B0_Tcos<<11)+(B0_Tacc<<8)+(B0_Tcoh<<6)+(B0_Tah<<4)+(B0_Tacp<<2)+(B0_PMC))
    .word ((B1_Tacs<<13)+(B1_Tcos<<11)+(B1_Tacc<<8)+(B1_Tcoh<<6)+(B1_Tah<<4)+(B1_Tacp<<2)+(B1_PMC))
    .word ((B2_Tacs<<13)+(B2_Tcos<<11)+(B2_Tacc<<8)+(B2_Tcoh<<6)+(B2_Tah<<4)+(B2_Tacp<<2)+(B2_PMC))
    .word ((B3_Tacs<<13)+(B3_Tcos<<11)+(B3_Tacc<<8)+(B3_Tcoh<<6)+(B3_Tah<<4)+(B3_Tacp<<2)+(B3_PMC))
    .word ((B4_Tacs<<13)+(B4_Tcos<<11)+(B4_Tacc<<8)+(B4_Tcoh<<6)+(B4_Tah<<4)+(B4_Tacp<<2)+(B4_PMC))
    .word ((B5_Tacs<<13)+(B5_Tcos<<11)+(B5_Tacc<<8)+(B5_Tcoh<<6)+(B5_Tah<<4)+(B5_Tacp<<2)+(B5_PMC))
    .word ((B6_MT<<15)+(B6_Trcd<<2)+(B6_SCAN))
    .word ((B7_MT<<15)+(B7_Trcd<<2)+(B7_SCAN))
    .word ((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Trc<<18)+(Tchr<<16)+REFCNT)
    .word 0x32
    .word 0x30
    .word 0x30

<3>复制Bootloader的第二阶段到RAM空间。(代码重定向)

初始化内存后回到 u-boot-2010.06/arch/arm/cpu/arm920t/start.S。

如果是直接跳到下面的堆栈初始化代码 stack_setup
relocate:   

     adr r0, _start  //R0:当前代码段开始地址

     ldr r1, _TEXT_BASE  //R1:代码段的连接地址

     cmp r0, r1   //测试现在是在Flash中还是在RAM中

     beq stack_setup //如果已经在RAM中了,则不需要复制,直接跳转到设置栈。

//nor/nand flash双启动判断,判断flash类型。
#define BWSCON 0x48000000
     ldr r0, =BWSCON
     ldr r0, [r0]
     ands r0, r0, #6  //判断BWSCON[2:1]是否为00,如果是,Z=1即跳转到nand_boot
     beq nand_boot  

//系统从Norflash启动 

     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

//下面添加2440中u-boot从Nand Flash启动

nand_boot:

 mov r1, #NAND_CTL_BASE   //复位Nand Flash
 ldr r2, =( (0<<12)|(3<<8)|(0<<4)|(3<<2)|(1<<1) )
 str r2, [r1, #oNFCONF]   //设置配置寄存器的初始值,参考s3c2440手册
 ldr r2, [r1, #oNFCONF]

 ldr r2, =( (1<<4)|(1<<1)|(1<<0) )
 str r2, [r1, #oNFCONT]   //设置控制寄存器
 ldr r2, [r1, #oNFCONT]

 //ldr r2, =(0x01)           //RnB Clear
 //str r2, [r1, #oNFSTAT]
 //ldr r2, [r1, #oNFSTAT]
 
 mov r2, #0xff            //复位command
 strb r2, [r1, #oNFCMD]
 mov r3, #0               //等待

nand1:
 add r3, r3, #0x1
 cmp r3, #0xa
 blt nand1

nand2:
 ldr r2, [r1, #oNFSTAT]   //等待就绪
 tst r2, #0x4
 beq nand2

 ldr r2, [r1, #oNFCONT]
 orr r2, r2, #0x02         //取消片选
 str r2, [r1, #oNFCONT]


 //get read to call C functions (for nand_read())
 ldr sp, DW_STACK_START   //为C代码准备堆栈,DW_STACK_START定义在下面
 mov fp, #0

 //copy U-Boot to RAM
 ldr r0, =TEXT_BASE//传递给C代码的第一个参数:u-boot在RAM中的起始地址
 mov r1, #0x0     
//传递给C代码的第二个参数:Nand Flash的起始地址
 mov r2, #0x40000 
//传递给C代码的第三个参数:u-boot的长度大小(256k),这个可以根据具体大小填写。
 bl nand_read_ll  
//此处调用C代码中读Nand的函数,/board/samsung/smdk2440/nand_read.c
 tst r0, #0x0
 beq ok_nand_read

 bad_nand_read:
 loop2: b loop2    //infinite loop
 
ok_nand_read:

 //检查搬移后的数据,如果前4k完全相同,表示搬移成功
     mov r0, #0
     ldr r1, =TEXT_BASE
     mov r2, #0x1000           //4 bytes * 1024 = 4K-bytes

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

<4>设置好栈。

stack_setup:
     ldr r0, _TEXT_BASE  //_TEXT_BASE为代码段的开始地址,值为0x33F8 0000。

     sub r0, r0, #CONFIG_SYS_MALLOC_LEN //代码段下面,留一段内存以实现malloc

     sub r0, r0, #CONFIG_SYS_GBL_DATA_SIZE //再留出一段内存,存一些全局参数

#ifdef CONFIG_USE_IRQ
     sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)  //IRQ,FIQ模式的栈
#endif
     sub sp, r0, #12  
//最后,留出12字节的内存给abort异常
     bic sp, sp, #7  /* 8-byte alignment for ABI compliance */

 

 

 

<5>跳转到第二阶段的C入口点。

clear_bss:  //在跳转之前,清除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

 ldr pc, _start_armboot  //此处跳转到第二阶段。进入喜欢的C环境。

_start_armboot: .word start_armboot
.align 2
DW_STACK_START: .word STACK_BASE+STACK_SIZE-4

 

//最后是第2步中的关闭mmu,cache和调用初始化内存的函数cpu_init_crit:

#ifndef CONFIG_SKIP_LOWLEVEL_INIT
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

 bl lowlevel_init

 mov lr, ip
 mov pc, lr
#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)
 sub r2, r2, #(CONFIG_SYS_MALLOC_LEN)
 /* set base 2 words into abort stack */
 sub r2, r2, #(CONFIG_SYS_GBL_DATA_SIZE+8)
 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 r7, sp, #S_PC
 stmdb r7, {sp, lr}^   @ Calling SP, LR
 str lr, [r7, #0]   @ Save calling PC
 mrs r6, spsr
 str r6, [r7, #4]   @ Save CPSR
 str r0, [r7, #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
 /* return & move spsr_svc into cpsr */
 subs pc, lr, #4
 .endm

 .macro get_bad_stack
 ldr r13, _armboot_start  @ setup our mode stack
 sub r13, r13, #(CONFIG_STACKSIZE)
 sub r13, r13, #(CONFIG_SYS_MALLOC_LEN)
 /* reserve a couple spots in abort stack */
 sub r13, r13, #(CONFIG_SYS_GBL_DATA_SIZE+8)

 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

阅读(2589) | 评论(0) | 转发(4) |
给主人留下些什么吧!~~