基于TQ2440的Uboot-1.1.6代码分析--------start.s


http://blog.csdn.net/yongbudl2012/article/details/28614305


本打算直接移植uboot来着,但想了想,还是把uboot整个整理一下吧,集网上资料之大全,好好分析下,慢慢编辑,争取弄细些,采用TQ2440的uboot,是因为自己的开发板就是天嵌的。方便以后查阅。

   分析uboot代码应该从start.s开始,从名称就可以看出来,start,开始的地方,但为什么从start.s开始呢,这是因为u-boot.lds中有这样的一段代码:

     .......

     .......

ENTRY(_start)

     .......

     cpu/arm920t/start.o (.text)

     .......

   这就决定了start为整个uboot的入口地址,这个_start,就是start.s开始处的

.globl _start

_start: b       reset
下面,先分析start.s,以后再看看u-boot.lds.

#include <config.h>
#include <version.h>
.globl _start  
_start: b       reset

  *ldr用法:

  *1,LDR Rd,[Rn]  
  *2, LDR Rd,[Rn,Flexoffset]
  *3, LDR Rd,[Rn],Flexoffset
  *4, LDR Rd,label
  *ldr只能在当前PC的4KB范围内跳转

  *_undefined_instruction、_software_interrupt等都是标号(label),就是把标号地址中的内容赋给pc指针。

  *还有一种用法:

  *#define WTCON          (*(volatile unsigned *)0x53000000)

  *ldr r1,=WTCON,则WTCON是一个变量,并不是标号

 */

 ldr pc, _undefined_instruction  //未定义指令,arm处理器遇到不能处理的指令时会发生该异常,

                                 //可以通过软件仿真扩展ARM或Thumb指令集。
 ldr pc, _software_interrupt     //该异常由软件中断指令(SWI)产生,用于进入管理模式,常用于

                                 //请求执行特定的管理工能
 ldr pc, _prefetch_abort         //指令预取中止
 ldr pc, _data_abort             //数据访问中止
 ldr pc, _not_used               //没有使用
 ldr pc, _irq                    //外部中断请求
 ldr pc, _fiq                    //快速中断请求

_undefined_instruction: .word undefined_instruction  

//.word的含义是,在_undefined_instruction这个标号(就是在地址0x0000,0004)处放置一个 word型的值,

//即放置undefined_instruction这个值,而 undefined_instruction 就是一个地址值( word 型,32位),

//也就是说地址0x0000,0004中存放的内容为undefined_instruction这个值,这样,

//就可以用ldr pc,_undefined_instruction,

//将_undefined_instruction地址(即0x0000,0004)中的内容装入pc中,跳转到undefined_instruction处,

//执行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

 .balignl 16,0xdeadbeef 

//在以当前地址开始,在地址为16的倍数的位置的前面填入四个字节内容为0xdeadbeef,.balign的用法见


_TEXT_BASE:
 .word TEXT_BASE

//TEXT_BASE在board\EmbedSky\config.mk中定义,定义了代码在运行时所在的内存地址

.globl _armboot_start
_armboot_start:
 .word _start

// 声明_bss_start并用__bss_start来初始化,其中__bss_start定义在与板相关的u-boot.lds中。
// _bss_start保存的是__bss_start这个标号所在的地址, 是程序链接时被链接器所确定的值,这里涉及到当前

//代码所在
// 的地址不是编译时的地址的情况, 这里直接取得该标号对应的地址, 不受编译时
// 地址的影响. _bss_end也是同样的道理.

//未初始化数据区。亦称 BSS 区(uninitialized data segment),存入的是全局未初始化
//变量。BSS 这个叫法是根据一个早期的汇编运算符而来,这个汇编运算符标志着一个块的开
//始。BSS 区的数据在程序开始执行之前被内核初始化为 0 或者空指针(NULL)。

//__bss_start的值是多少,这是由连接脚本lds决定的,是一个肯定大于0x33D80000(TQ所规定的TEXT_BASE的

//值)

.globl _bss_start
_bss_start:
 .word __bss_start

.globl _bss_end
_bss_end:
 .word _end             //道理同_bss_start

.globl FREE_RAM_END     //由于使用usb DNW下载功能
FREE_RAM_END:           //在cpu\arm920t\cpu.c中,int cpu_init(void)定义,此处以后还会详细分析。
 .word 0x0badc0de

.globl FREE_RAM_SIZE
FREE_RAM_SIZE:
 .word 0x0badc0de

#ifdef CONFIG_USE_IRQ

.globl IRQ_STACK_START  
IRQ_STACK_START:
 .word 0x0badc0de


.globl FIQ_STACK_START
FIQ_STACK_START:
 .word 0x0badc0de
#endif


reset:
 
 mrs r0,cpsr     //mrs指令:专用寄存器到通过寄存器的存取,把CPSR(程序状态寄存器)内容存入r0。
 bic r0,r0,#0x1f //bic指令(bit clear): r0= r0 & (~0x1f)。该指令目的是把bit0~bit4清零。
 orr r0,r0,#0xd3 //r0:= r0 | 0xd3 . r0值为:**** **** **** **** **** ***** 11*1 0011
 msr cpsr,r0     //msr指令是专用的通用寄存器到特殊功能寄存器的指令与mrs对应

                 //将r0赋于cpsr。进入了SVC32模式。
#if defined(CONFIG_S3C2400)
# define pWTCON  0x15300000
# define INTMSK  0x14400008 
# define CLKDIVN 0x14800014 
#elif defined(CONFIG_S3C2410)
# define pWTCON  0x53000000   //WTCON(看门狗定时器控制寄存器)的地址是0x53000000
# define INTMOD     0X4A000004 //中断方式寄存器
# define INTMSK  0x4A000008    //中断屏蔽寄存器
# define INTSUBMSK 0x4A00001C  //中断屏蔽寄存器
# define CLKDIVN 0x4C000014    //时钟分频控制寄存器
#endif

#if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410)
 ldr     r0, =pWTCON   //将0x53000000放入r0中。
 mov     r1, #0x0      //将立即数0x0存入r1.
 str     r1, [r0]      //str指令用于从源寄存器中将一个32位的字数据写入存储器,即将0x0000 0000

                       //写入0x53000000地址单元中,WTCON寄存器被赋值0. 
 

 mov r1, #0xffffffff
 ldr r0, =INTMSK
 str r1, [r0]  //将0xffffffff写入INTMSK寄存器,中断被屏蔽。
# if defined(CONFIG_S3C2410)
 ldr r1, =0x3ff   //ldr在这里是伪指令,将0x3ff赋给r1,但这里确实应该是0x7fff。
 ldr r0, =INTSUBMSK
 str r1, [r0]
# endif

#if 0   //此处不编译
 
 
 ldr r0, =CLKDIVN
 mov r1, #3
 str r1, [r0]
#endif
#endif 

  

//cpu_init_crit 主要完成内存管理相关的寄存器设置,CP15协处理器,配置内存区控制寄存器。另外这段代码

//中调用了lowlevel_init 函数,进行寄存器的具体设置,与采用的内存芯片有关
#ifndef CONFIG_SKIP_LOWLEVEL_INIT    //没有定义CONFIG_SKIP_LOWLEVEL_INIT,跳转
 bl cpu_init_crit                    //bl是带跳转返回指令,执行完后再跳回此处。
#endif

 
stack_setup:                        //堆栈是进入C函数前必须初始化的
 ldr r0, _TEXT_BASE  
 sub r0, r0, #CFG_MALLOC_LEN        //CFG_MALLOC_LEN是堆大小+环境数据区大小
 sub r0, r0, #CFG_GBL_DATA_SIZE

#ifdef CONFIG_USE_IRQ
 sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
#endif
 sub sp, r0, #12  //1字=4Byte,3字=12Byte,为abort-stack预留3个字。

    bl clock_init

#ifndef CONFIG_SKIP_RELOCATE_UBOOT
relocate:    
 adr r0, _start         //链接时_start的地址确实被链接为0x33D80000,但程序的地址有加载地址和运行地

//址两种,uboot被下载到nandflash中,nand boot时,被加载到steppingstone中,这个sram的起始地址是

//0x0000 0000,所以uboot被加载到此处,即uboot的加载地址是0x00000000,这就出现个问题,uboot在链接时被链接到0x33D80000开始的地方,即内存中的地址,按理说得把uboot下载到0x33D80000处才能正常工作,那为什么加载到0x00000000时也可以运行呢,这是因为uboot运用了arm的位置无关程序设计(PIC),跳转都是基于pc指针的。详见......


这就保证了uboot被下载任何地方都可以运行,而adr r0, _start就是取_start此刻所在的地址,即0x00000000,

 ldr r1, _TEXT_BASE   //把_TEXT_BASE标号的地址里存的是TEXT_BASE=0x33D80000赋给r1

 cmp     r0, r1                 
 beq     clear_bss

 ldr r2, _armboot_start
 ldr r3, _bss_start
 sub r2, r3, r2  
#if 1
 bl  CopyCode2Ram 
#else
 add r2, r0, r2  

copy_loop:
 ldmia r0!, {r3-r10}  
 stmia r1!, {r3-r10}  
 cmp r0, r2   
 ble copy_loop
#endif
#endif 

clear_bss:
 ldr r0, _bss_start  
 ldr r1, _bss_end  
 mov  r2, #0x00000000  

clbss_l:str r2, [r0]  
 add r0, r0, #4
 cmp r0, r1
 ble clbss_l

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

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

 
 
 ldr r0, =CLKDIVN
 mov r1, #3
 str r1, [r0]
 
#endif

 ldr pc, _start_armboot

_start_armboot: .word start_armboot



#ifndef CONFIG_SKIP_LOWLEVEL_INIT
cpu_init_crit:
 
 mov r0, #0
 mcr p15, 0, r0, c7, c7, 0   
 mcr p15, 0, r0, c8, c7, 0          // 刷新TLB  

 
 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

 
 mov ip, lr
 bl lowlevel_init    
 mov lr, ip
 mov pc, lr
#endif

 

@
@ 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

 

 .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


 .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

@ HJ
.globl Launch
    .align 4
Launch:   
    mov r7, r0
    @ diable interrupt
 @ disable watch dog timer
 mov r1, #0x53000000
 mov r2, #0x0
 str r2, [r1]

    ldr r1,=INTMSK
    ldr r2,=0xffffffff  @ all interrupt disable
    str r2,[r1]

    ldr r1,=INTSUBMSK
    ldr r2,=0x7ff       @ all sub interrupt disable
    str r2,[r1]

    ldr     r1, = INTMOD
    mov r2, #0x0        @ set all interrupt as IRQ (not FIQ)
    str     r2, [r1]

    @
 mov ip, #0
 mcr p15, 0, ip, c13, c0, 0      @ 
 mcr p15, 0, ip, c7, c7, 0       @ 
 mcr p15, 0, ip, c7, c10, 4      @ 
 mcr p15, 0, ip, c8, c7, 0       @ 
 mrc p15, 0, ip, c1, c0, 0       @ 
 bic ip, ip, #0x0001             @ 
 mcr p15, 0, ip, c1, c0, 0       @ 

    @ MMU_EnableICache
    @mrc p15,0,r1,c1,c0,0
    @orr r1,r1,#(1<<12)
    @mcr p15,0,r1,c1,c0,0

#ifdef CONFIG_SURPORT_WINCE
    bl Wince_Port_Init
#endif

    @ clear SDRAM: the end of free mem(has wince on it now) to the end of SDRAM
    ldr     r3, FREE_RAM_END
    ldr     r4, =PHYS_SDRAM_1+PHYS_SDRAM_1_SIZE    @ must clear all the memory unused to zero
    mov     r5, #0

    ldr     r1, _armboot_start
    ldr     r2, =On_Steppingstone
    sub     r2, r2, r1
    mov     pc, r2
On_Steppingstone:
2:  stmia   r3!, {r5}
    cmp     r3, r4
    bne     2b

    @ set sp = 0 on sys mode
    mov sp, #0

    @ add by HJ, switch to SVC mode
 msr cpsr_c, #0xdf @ set the I-bit = 1, diable the IRQ interrupt
 msr cpsr_c, #0xd3 @ set the I-bit = 1, diable the IRQ interrupt
    ldr sp, =0x31ff5800 
   
    nop
 nop
    nop
 nop

 mov     pc, r7  @ Jump to PhysicalAddress
 nop
    mov pc, lr

#ifdef CONFIG_USE_IRQ

 .align 5
irq:

 sub lr, lr, #4           @ the return address
 ldr sp, IRQ_STACK_START         @ the stack for irq
 stmdb sp!,  { r0-r12,lr } @ save registers
 
 ldr lr, =int_return          @ set the return addr
 ldr pc, =IRQ_Handle          @ call the isr
int_return:
 ldmia sp!,  { r0-r12,pc }^ @ return from interrupt

 .align 5
fiq:
 get_fiq_stack
 
 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

你可能感兴趣的:(linux,异常处理,指针,单片机,汇编语言)