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