转自:http://zqwt.012.blog.163.com/blog/static/12044684201332662650711/
l 下面这几行代码的作用是定义了一些宏,给寄存器赋值(其实赋的是寄存器的地址),以后会用到
#if defined(CONFIG_S3C2400)
# define pWTCON 0x15300000
# define INTMSK 0x14400008 /* Interupt-Controller base addresses */
# define CLKDIVN 0x14800014 /* clock divisor register */
#elif defined(CONFIG_S3C2410)
# define pWTCON 0x53000000
# define INTMSK 0x4A000008 /* Interupt-Controller base addresses */
# define INTSUBMSK 0x4A00001C
# define CLKDIVN 0x4C000014 /* clock divisor register */
#endif
l 下面这里就是所谓的关闭看门狗
l 看门狗即watchdog timer,是一个定时器电路,一般有一个输入叫喂狗,一个输出叫MCU(Micro Controller Unit多点控制单元)的RST端(复位端)。MCU正常工作的时候,每隔一段时间输出一个信号到喂狗端,给WDT(watchdog timer abbreviation)清零,如果超过规定的时间不喂狗(一般在程序跑飞时,会发生这种情况,此时WDT规定的时间被超过),RST就给出一个复位信号到MCU,然后MCU复位。很明显,看门狗的作用就是防止程序发生死循环或者等待超时的情况下进行主控的复位操作。寄存器具体怎么设置,可以根据S3C2410的用户手册来实现。
#if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410)
ldr r0, =pWTCON // 还是把寄存器pWTCON的地址装载到r0中
mov r1, #0x0 // 给r1清零,关闭看门狗定时器
str r1, [r0]
/* 上面几行中,把r1中的数据(全0)装载
*(存储)到寄存器[r0]所包含的有效地址,
* 即给寄存器WTCON清零,目的是关闭看门狗 */
l 禁止所有中断(第一个要修改的地方)
/*
* mask all IRQs by setting all bits in the INTMR - default
*/
mov r1, #0xffffffff
ldr r0, =INTMSK //是不是把INTMSK的地址0X4A000008存储在r0中
str r1, [r0] //把r1中的数据存储在寄存器[r0]所包含的有效地址,屏蔽所有中断源
# if defined(CONFIG_S3C2410)
ldr r1, =0x3ff // 0x3ff =00111111 (0x3ff =0000 0011 1111 1111 --转者)
ldr r0, =INTSUBMSK
str r1, [r0]
# endif
这是S3C2410参考手册中列出的中断控制器(Interrupt Controller)表格:
l 设置时钟频率(第二个要修改的地方)
S3C2410用户手册推荐FLCK:HCLK:PCLK=1:2:4,其中FCLK默认是120MHz,通常FCLK用于CPU,HCLK用于AHB总线,PCLK用于APB总线,具体实现如下:
/* FCLK:HCLK:PCLK = 1:2:4 */
/* default FCLK is 120 MHz ! */
ldr r0, =CLKDIVN
mov r1, #3 //0011 HDIVN=1;PDIVN=1
str r1, [r0]
#endif /* CONFIG_S3C2400 || CONFIG_S3C2410 */
l /* we do sys-critical inits only at reboot, not when booting from ram! */
我们只在系统reboot的时候做一些至关重要的系统初始化,而不在从sram启动的时候做这件事情。
B 转移指令,跳转到指令中指定的目的地址,BL 带链接的转移指令,像B一样跳转,但是会把转移后面紧接的一条指令地址保存到链接寄存器LR(R14)中,以此来完成子程式的调用。
该语句首先调用cpu_init_crit进行CPU的初始化,并把下一条指令的地址保存在LR中,以使得执行完后能够正常返回。
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
bl cpu_init_crit //跳转(第三个要修改的地方)
#endif
l 下面这段代码的作用是所谓搬运代码(把uboot拷贝到DDR中去执行),即重定向(第四个要修改的地方)
#ifndef CONFIG_SKIP_RELOCATE_UBOOT
relocate: /* relocate U-Boot to RAM */
adr r0, _start /* r0 <- current position of code */
//_start为当前程序的入口地址
ldr r1, _TEXT_BASE /* test if we run from flash or RAM */
//_TEXT_BASE为uboot从SDRAM中开始执行的基地址(加载地址)
cmp r0, r1 /* don't reloc during debug */
//我们的目的就是把uboot从当前的地址_start
//拷贝到sdram中的所谓基地址_TEXT_BASE=0x33f80000)
/* 要调用C子程序,必须分配堆栈空间。因为子程序调用时,
* 要进行入栈出栈处理。又因为从nand flash启动,
* 而nand flash在S3C2410下的特点规定堆栈不能超过4K。
*/
beq stack_setup // 如果r0等于r1(入口地址等于加载地址),那么就先去设置堆栈,再回来搬运代码(重定向) (原文中说明错误,此处判断如果r0==r1,即执行地址_start与加载地址_TEXT_BASE相同,就直接跳到设置堆栈(stack_setup),不用再搬运代码(重定向)。从前文注释“don't reloc during debug ”可推断,debug过程中应该是从ram启动,不需要relocate --转者)
ldr r2, _armboot_start //堆栈
//_armboot_start 目前的值为uboot的入口地址
ldr r3, _bss_start
// _bss_start为uboot代码存放的结束地址,也是BSS段的起始地址
sub r2, r3, r2 /* r2 <- size of armboot */
// 让r3和r2做算数减法的目的是计算出uboot镜像的大小
add r2, r0, r2 /* r2 <- source end address */
l 下面这几行代码是一个循环,做的事儿就是所谓的搬运代码,这里有条指令ldmia,解释如下: