最全的uboot start.S分析

#include <config.h>
#include <version.h>

#if defined(CONFIG_S3C2410)
#include <s3c2410.h>
#elif defined(CONFIG_S3C2440)//include\configs\smdk2440.h中定义。
#include <s3c2440.h>
#endif

#include <status_led.h>

/*************************************************************************
  Jump vector table as in table 3.1 in [1]
 *************************************************************************/
//.global声明一个符号可被其它文件引用,相当于声明了一个
//全局变量,.globl与.global相同。
//该部分为处理器的异常处理向量表。地址范围为
//0x0000 0000 ~ 0x0000 0020,刚好8条指令。

//声明全局变量 _start
.globl _start     /*系统复位位置,整个程序入口*/
_start:	b       start_code    /*各个异常向量对应的相对跳转代码,0x00*/
     /*start_code用b,就是因为start_code在MMU建立前后都有可能发生*/
     /*其他的异常只有在MMU建立之后才会发生*/
	ldr	pc, _undefined_instruction  //未定义指令异常,0x04
	ldr	pc, _software_interrupt    //软中断异常,0x08
	ldr	pc, _prefetch_abort  //内存操作异常,0x0c
	ldr	pc, _data_abort     //数据异常,0x10
	ldr	pc, _not_used      //未适用,0x14
	ldr	pc, _irq          //慢速中断异常,0x18 
	ldr	pc, _fiq         //快速中断异常,0x1c

//.word伪操作用于分配一段字内存单元(分配的单元都是字对齐的),并
//用伪操作中的expr初始化。.long与.int作用与之相同。
/*.word 表达式 ==> 就是在当前位置放一个word型的值,这个值就是"表达式"
;rWTCON: .word 0x15300000 就是在当前地址,即_rWTCON处放一个值0x15300000*/ 

_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


/*.balign[wl] abs-expr, abs-expr, abs-expr
;增加位置计数器(在当前子段)使它指向规定的存储边界。
;第一个表达式参数(结果必须是纯粹的数字)是必需参数:边界基准,单位
为字节。
;例如, '.balign 8'向后移动位置计数器直至计数器的值等于8的倍数。
;如果位置计数器已经是8的倍数,则无需移动。
;第2个表达式参数(结果必须是纯粹的数字)给出填充字节的值,用这个值
填充位置计数器越过的地方。
;第2个参数(和逗点)可以省略。如果省略它,填充字节的值通常是0。
;但在某些系统上,如果本段标识为包含代码,而填充值被省略,则使用
no-op指令填充空白区。
;第3个参数的结果也必须是纯粹的数字,这个参数是可选的。如果存在第
3个参数,
;它代表本对齐命令允许跳过字节数的最大值。如果完成这个对齐需要跳
过的字节数比规定的最大值还多,
;则根本无法完成对齐。您可以在边界基准参数后简单地使用两个逗号,
以省略填充值参数(第二参数);
;如果您在想在适当的时候,对齐操作自动使用no-op指令填充

balignw和.balignl是.balign命令的变化形式。.balignw使用2个字节来填充空白区。
.balignl使用4字节来填充。例如,.balignw 4,0x368d将地址对齐到4的倍数,如果它跳
过2个字节,GAS将使用0x368d填充这2个字节(字节的确切存放位置视处理器
的存储方式而定)。
如果它跳过1或3个字节,则填充值不明确。


//它的含义是以16字节边界对齐,为了对齐而越过的地址以字为单位填冲
//值0xdeadbeef。我猜0xdeadbeef可能NOP指令。
	.balignl 16,0xdeadbeef  //对齐内存为16的倍数
/*************************************************************************
 *
 * Startup Code (called from the ARM reset exception vector)
 *
 * do important init only if we don't start from memory!
 * relocate armboot to ram
 * setup stack
 * jump to second stage
 *
 *************************************************************************/

// TEXT_BASE在开发板相关的目录中的config.mk文件中定义, 它定义了
// 代码在运行时所在的地址, 那么_TEXT_BASE中保存了这个地址
/*
 *保存变量的数据区,保存一些全局变量,用于BOOT程序从FLASH拷贝到RAM,或者
 其它的使用。
 *还有一些变量的长度是通过连接脚本里得到,实际上由编译器算出来的
 */
//TEXT_BASE定义在\board\smdk2410\config.mk中。

/*TEXT_BASE是代码执行的起始地址.编译产生的二进制文件必需下载到该地
址,因为所有的函数,全局变量等等定位都是以这个地址为参照的.
如果uboot中是TEXT_BASE就是设的0x33F80000, 那么必需download到这个地址的ram中才
能正常运行.
*/  
_TEXT_BASE:  //_TEXT_BASE=TEXT_BASE.
			.word	TEXT_BASE   /*uboot映像在SDRAM中的重定位地址*/

// 标号_start在前面有定义
	
.globl _armboot_start   // /*在_armboot_start标号处,保存了_start的值*/
_armboot_start:     //_armboot_start=_start。
				.word _start    /*_start是程序入口,链接完毕它的值应该是TEXT_BASE*/ 

/*
 * These are defined in the board-specific linker script.
 */
//__bss_start是uboot 的bss段起始地址,那么uboot映像的大小就是__bss_start - _start;
//实际上,_armboot_start并没有实际意义,它只是在"ldr r2, _armboot_start"中用來寻
//址_start的值而已,_bss_start也是一样的道理,真正有意义的应该是_start和 
//__bss_start本身。 

.globl _bss_start  /*__bss_start是uboot 的bss段起始地址,*/
_bss_start:         /*uboot映像的大小就是__bss_start - _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 start code*/
start_code:/*复位启动子程序*/
	/*设置cpu运行在SVC32模式。共有7种模式*/	
	mrs	r0,cpsr  /*复制当前程序状态寄存器cpsr到r0*/
	bic	r0,r0,#0x1f  //这里使用位清除指令,把中断全部清除,只置位模式控制位
	                          //7种异常,共占0x00 - 0x16空间
	/*ORR{条件}{S}  <dest>, <op 1>, <op 2>*/
       /*OR 将在两个操作数上进行逻辑或,把结果放置到目的寄存器中*/
	orr	r0,r0,#0xd3 /*选择新模式,(现在设为超级保护模式)*/
	
	msr	cpsr,r0  /*设置cpsr为超级保护模式*/
   /*通过设置ARM的CPSR寄存器,让CPU运行在操作系统模式,为后面进行其它操作作好准备*/

//如果定义了CONFIG_AT91RM9200DK,CONFIG_AT91RM9200EK,CONFIG_AT91RM9200DF中的任意一个
//,就会执行其中的语句.这里没有用。
#if	defined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK) || defined(CONFIG_AT91RM9200DF)
	/* relocate exception table*/
	ldr		r0, =_start
	ldr		r1, =0x0
	mov		r2, #16
copyex:
	subs	r2, r2,   #1
	ldr		r3, [r0], #4
	str		r3, [r1], #4
	bne		copyex
#endif

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

#if defined(CONFIG_S3C2400)
#define pWTCON	0x15300000
#define INTMSK	0x14400008	/* Interupt-Controller base addresses */
#define CLKDIVN	0x14800014	/* clock divisor register */
#elif defined(CONFIG_S3C2410) || defined(CONFIG_S3C2440)
#define pWTCON	0x53000000  /*"看门狗定时器控制寄存器"的地址0x53000000*/  
#define INTMSK	0x4A000008 /*"中断屏蔽寄存器"的地址:0x4A000008 */
#define INTSUBMSK	0x4A00001C /*针对INTMAK具体化的一个中断请求屏蔽寄存器,其地
                                                             址0x4A00001C */  
#define LOCKTIME	0x4c000000  //锁时计数寄存器    
#define MPLLCON 	0x4c000004  //MPLL寄存器
#define UPLLCON 	0x4c000008  //UPLL寄存器
#define CLKDIVN	0x4C000014	/*CPU时钟分频控制寄存器,地址0x4C000014*/  
#endif

#if defined(CONFIG_S3C2410)
#define INTSUBMSK_val	0x7ff
#define MPLLCON_val	((0x90 << 12) + (0x7 << 4) + 0x0)	/* 202 MHz */
#define UPLLCON_val	((0x78 << 12) + (0x2 << 4) + 0x3)
#define CLKDIVN_val	3 /* FCLK:HCLK:PCLK = 1:2:4 */
#elif defined(CONFIG_S3C2440)
#define INTSUBMSK_val	0xffff  //以便屏蔽INTSUBMSK的bit[15:0]对应的中断请求
#if (CONFIG_SYS_CLK_FREQ == 16934400)//晶振=16.9344M在include\configs\smdk2440.h中定义。
/*
Mpll = (2 * m * Fin) / (p * 2s)
m = (MDIV + 8), p = (PDIV + 2), s = SDIV

Upll = (m * Fin) / (p * 2s)
m = (MDIV + 8), p = (PDIV + 2), s = SDIV

MDIV =PLLCON[19:12];  PDIV=PLLCON[9:4];  SDIV=PLLCON[1:0];
*/
//# define MPLLCON_val	((0x61 << 12) + (0x1 << 4) + 0x2)	/* 296.35 MHz */
//# define UPLLCON_val	((0x3c << 12) + (0x4 << 4) + 0x2)	/*  47.98 MHz */
                                //MDIV=184        PDIV=2     SDIV=2                                 
#define MPLLCON_val	((184 << 12) + (2 << 4) + 2)	/*406M*/
                                //MDIV=60        PDIV=4     SDIV=2  
#define UPLLCON_val 	((60 << 12) + (4 << 4) + 2)   /*  47M */
#elif (CONFIG_SYS_CLK_FREQ == 12000000)
#define MPLLCON_val	((0x44 << 12) + (0x1 << 4) + 0x1)	/* 304.00 MHz */
#define UPLLCON_val	((0x38 << 12) + (0x2 << 4) + 0x2)	/*  48.00 MHz */
#endif
#define CLKDIVN_val	7 /* FCLK:HCLK:PCLK = 1:3:6   CLKDIVN=7  */
                       //CPU  : 高速设备:  低速设备
#define CAMDIVN	0x4C000018
#endif

        //禁用看门狗
	ldr       r0, =pWTCON
	mov     r1, #0x0
	str       r1, [r0]

	/* mask all IRQs by setting all bits in the INTMR - default*/
	/*在SVC模式下,屏蔽所有中断发生*/
	mov	  r1, #0xffffffff
	ldr	  r0, =INTMSK
	str	  r1, [r0]
	
#if defined(CONFIG_S3C2410) || defined(CONFIG_S3C2440)
	ldr	r1, =INTSUBMSK_val  /*子中断同样屏蔽INTSUBMSK_val=0xffff*/
	ldr	r0, =INTSUBMSK
	str	r1, [r0]

/*To reduce PLL lock time, adjust the LOCKTIME register. */
        ldr     r0,=LOCKTIME
        ldr     r1,=0xffffff
        str     r1,[r0]	
#endif

    /* FCLK:HCLK:PCLK = 1:3:6*//* default FCLK is 406M MHz ! */
	ldr	r0, =CLKDIVN
	mov	r1, #CLKDIVN_val
	str	r1, [r0]

#if defined(CONFIG_S3C2440)
      /* Make sure we get FCLK:HCLK:PCLK = 1:3:6 */
        ldr        r0, =CAMDIVN
        mov     r1, #0
        str       r1, [r0]

        /* Clock asynchronous mode */
        mrc     p15, 0, r1, c1, c0, 0
        orr      r1,   r1, #0xc0000000
        mcr     p15, 0, r1, c1, c0, 0

	ldr	r0,=UPLLCON
	ldr	r1,=UPLLCON_val
	str	r1,[r0]
	
	nop	
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	
	ldr	r0,=MPLLCON
	ldr	r1,=MPLLCON_val
	str	r1,[r0]
//
#define GPJCON      0x560000D0
#define GPJDAT       0x560000D4
#define GPJUP		0x560000D8
/*
        LDR   R0,   = GPJCON
        LDR   R1,   = 0x15555
        STR   R1,   [R0]
        LDR   R0,   = GPJUP
        LDR   R1,   = 0x1f
        STR   R1,   [R0]
        LDR   R0,   = GPJDAT  
//    LDR   R1,   = 0xffff
        LDR   R1,   = 0x00
        STR   R1,   [R0]
*/
#endif

#endif	/* CONFIG_S3C2400 || CONFIG_S3C2410 */

	/*
	 * we do sys-critical inits only at reboot,
	 * not when booting from ram!
	 */
	//bl      LED_FLASH
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
/*这些初始化代码在系统重启的时候执行,运行时热复位从RAM中启动不执行*/
	bl	cpu_init_crit
#endif
#if 1
        LDR   R0,   = GPJCON
        LDR   R1,   = 0x15555
        STR   R1,   [R0]
        LDR   R0,   = GPJUP
        LDR   R1,   = 0x1f
        STR   R1,   [R0]
        LDR   R0,   = GPJDAT
        LDR   R1,   = 0x00
        STR   R1,   [R0]
#endif
	
#if defined(CONFIG_AT91RM9200) || defined(CONFIG_S3C2410) || defined(CONFIG_S3C2440)
#ifndef CONFIG_SKIP_RELOCATE_UBOOT
#ifndef CONFIG_S3C2410_NAND_BOOT
//NOR_BOOT :
relocate:	/* 把U-BOOT重新定位到RAM*/
         //r0=0;
	adr	r0, _start		/* r0是代码的当前位置*/
	//r1=TEXT_BASE = 0x33F80000
	ldr	r1, _TEXT_BASE	/*测试判断是从FLASH启动,还是RAM  */
	cmp     r0, r1     /*比较R0、R1,调试的时候不需要重定位。 */
	beq     stack_setup  /*如果R0等于R1,跳到重定位代码。*/

	//如果不是从RAM运行的话,则将代码拷贝到_TEXT_BASE标识的RAM中。
	/*准备重新定义代码。*/
	ldr	r2, _armboot_start//_armboot_start=_start
	ldr	r3, _bss_start  //
	sub	r2, r3, r2		/* r2得到armboot的大小*/
	add	r2, r0, r2		/* r2得到要复制代码的末尾地址*/
//kaobei guo cheng
copy_loop:/*重新定位代码*/
	ldmia	r0!, {r3-r10}		/*从源地址[r0]复制,r0指向_start(=0)*/
	stmia	r1!, {r3-r10}		/*复制到目的地址[r1],r1指向_TEXT_BASE(=0x33F80000)*/
	cmp	r0, r2			/* 复制数据块直到源数据末尾地址[r2]*/
	ble	copy_loop
#else /* NAND_BOOT */
//relocate:
copy_myself:
	/* mov	r10, lr */
#if defined(CONFIG_S3C2410)
	@ reset NAND
	mov	r1, #S3C2410_NAND_BASE
	ldr	r2, =0xf842		@ initial value enable tacls=3,rph0=6,rph1=0
	str	r2, [r1, #oNFCONF]
	ldr	r2, [r1, #oNFCONF]
	bic	r2, r2, #0x800		@ enable chip
	str	r2, [r1, #oNFCONF]
	mov	r2, #0xff		@ RESET command
	strb	r2, [r1, #oNFCMD]
	mov	r3, #0			@ wait
1:	add	r3, r3, #0x1
	cmp	r3, #0xa
	blt	1b
2:	ldr	r2, [r1, #oNFSTAT]	@ wait ready
	tst	r2, #0x1
	beq	2b
	ldr	r2, [r1, #oNFCONF]
	orr	r2, r2, #0x800		@ disable chip
	str	r2, [r1, #oNFCONF]
#elif defined(CONFIG_S3C2440)
        /*从NAND闪存中把U-BOOT拷贝到RAM*/
	mov	r1, #S3C2440_NAND_BASE //S3C2440_NAND_BASE=0x4E000000
	ldr	r2, =0xfff0		@ initial value tacls=3,rph0=7,rph1=7
	ldr	r3, [r1, #oNFCONF] //oNFCONF=0x00
	orr	r3, r3, r2
	str	r3, [r1, #oNFCONF]//oNFCONF=0x00

	ldr	r3, [r1, #oNFCONT] //oNFCONT=0x04
	orr	r3, r3, #1		@ enable nand controller
	str	r3, [r1, #oNFCONT]//oNFCONT=0x04
#endif  //if defined(CONFIG_S3C2410)

#if 0
	@ get ready to call C functions (for nand_read())
	ldr	sp, DW_STACK_START	@ setup stack pointer
	mov	fp, #0			@ no previous frame, so fp=0
#else
	ldr	r0, _TEXT_BASE		/* upper 128 KiB: relocated uboot   */
	
        /* CFG_MALLOC_LEN=(CFG_ENV_SIZE + 2048*1024) =0x210000 ;   CFG_ENV_SIZE	= 0x10000
             CFG_GBL_DATA_SIZE=128	*/
	sub	r0, r0, #CFG_MALLOC_LEN	/* malloc area                      */
	sub	r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo                        */
#ifdef CONFIG_USE_IRQ  /*include/configs/smdk2440.h*/
	sub	r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)  //8K+4K
#endif
	sub	sp, r0, #12		/* leave 3 words for abort-stack    */
#endif   //#if 0

	@ copy u-boot to RAM
	ldr	r0, _TEXT_BASE //置第1个参数: UBOOT在RAM中的起始地址
	mov     r1, #0x0   //设置第2个参数:NAND闪存的起始地址
	//CFG_UBOOT_SIZE=0x40000=256k
	mov	r2, #CFG_UBOOT_SIZE  // 设置第3个参数: U-BOOT的长度(256KB)
	bl	nand_read_ll   //调用nand_read_whole(),把NAND闪存中的数据读入到RAM中

	tst	r0, #0x0 // 如果函数的返回值为0,表示执行成功
	beq	ok_nand_read  //执行内存比较,把RAM中的前4K内容与NAND闪存中的前4K内容进行比较, 如果完全相同, 则表示搬移成功
#ifdef CONFIG_DEBUG_LL
bad_nand_read:
	ldr	r0, STR_FAIL
	ldr	r1, SerBase
	bl	PrintWord
1:	b	1b		@ infinite loop
#endif

ok_nand_read:
#ifdef CONFIG_DEBUG_LL
	ldr	r0, STR_OK
	ldr	r1, SerBase
	bl	PrintWord
#endif

	@ verify
	mov	r0, #0
	@ldr	r1, =0x33f00000
	ldr	r1, _TEXT_BASE
	mov	r2, #0x400	@ 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	done_nand_read
	bne	go_next
notmatch:
#ifdef CONFIG_DEBUG_LL
	sub	r0, r0, #4
	ldr	r1, SerBase
	bl	PrintHexWord
	ldr	r0, STR_FAIL
	ldr	r1, SerBase
	bl	PrintWord
#endif

#if 1
        LDR   R0,   = GPJDAT
        LDR   R1,   = 0x4
        STR   R1,   [R0]
#endif
1:	b	1b
done_nand_read:
#if 1
        LDR   R0,   = GPJDAT
        LDR   R1,   = 0x2
        STR   R1,   [R0]
#endif

#endif /* NAND_BOOT */
#endif	/* CONFIG_SKIP_RELOCATE_UBOOT */
#endif
	/* 初始化堆栈*/
stack_setup:
	ldr	r0, _TEXT_BASE		/*上面是128kib重定位的u-boot*/
	/*在smdk244.h中定义 #define CFG_MALLOC_LEN		(CFG_ENV_SIZE + 2048*1024)
	                    #define CFG_ENV_SIZE	    0x10000 
			   #define CFG_GBL_DATA_SIZE	128	*/
	sub	r0, r0, #CFG_MALLOC_LEN	/*向下是内存分配空间*/
	sub	r0, r0, #CFG_GBL_DATA_SIZE /*然后是bdinfo结构体地址空间*/
#ifdef CONFIG_USE_IRQ  //在 smdk2440.h中定义。
    /*在smdk244.h中定义#define CONFIG_STACKSIZE_IRQ	(8*1024)	
                                                 #define CONFIG_STACKSIZE_FIQ	(4*1024)	 */
	sub	r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
#endif
	sub	sp, r0, #12		/*为 abort-stack 预留3个字,得到最终sp指针初始值*/

clear_bss:
	ldr	r0, _bss_start		/*找到bss 段起始地址。*/
	ldr	r1, _bss_end		/* bss 段末尾地址。*/
	mov r2, #0x00000000		/* 清零。*/

clbss_l:str	r2, [r0]		/*bss 段地址空间清零循环。。。*/
	add	r0, r0, #4
	cmp	r0, r1
	ble	clbss_l
#if 1
        LDR   R0,   = GPJDAT
        LDR   R1,   = 0x1
        STR   R1,   [R0]
#endif
     /*跳转到start_armboot函数入口,_start_armboot字保存函数入口指针*/
	ldr	pc, _start_armboot

//_start_armboot=start_armboot
//pc=start_armboot;
//去执行void start_armboot (void),在lib_arm/boarb.c中。
_start_armboot:	.word start_armboot


/*
 *************************************************************************
 *
 * CPU_init_critical registers
 *
 * setup important registers
 * setup memory timing
 *
 *************************************************************************
 */

//功能:设置CP15寄存器 这里完成的功能:失效Icache和Dcache,禁能MMU和cache 
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
//关键的初始化子程序。
cpu_init_crit:
	 /*  flush v4 I/D caches  | 失效指令cache和数据cache       */
	mov	r0, #0
	//使I/D cache失效:将寄存器r0的数据传送到协处理器p15的c7中。C7寄存器
	//位对应cp15中的cache控制寄存器
	mcr	p15, 0, r0, c7, c7, 0	/* flush v3/v4 cache */
	//使TLB操作寄存器失效:将r0数据送到cp15的c8、c7中。C8对应TLB操作
	//寄存器
	mcr	p15, 0, r0, c8, c7, 0	/* flush v4 TLB */

	/*
	 * disable MMU stuff and caches
	 */
	 /*   disable MMU stuff and caches |   禁能MMU和cache       */ 
	mrc	p15, 0, r0, c1, c0, 0 //先把c1和c0寄存器的各位置0(r0 = 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
#if	defined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK) || defined(CONFIG_AT91RM9200DF)

#else
	bl	lowlevel_init  //位于board/smdk2440/lowlevel_init.S:用于完成芯片存储器的初始化,
	                             //执行完成后返回
#endif
	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+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分析)