#include <config.h>
#include <version.h>
#if defined(CONFIG_S3C2410)
#include <s3c2410.h>
#elif defined(CONFIG_S3C2440)
#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 <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