原文链接:https://blog.csdn.net/itdo_just/article/details/78701886
以下源码以u-boot-1.1.6中的2440为例。
1.start.s的引入
在board/smdk2240/u-boot.lds中可以看到ENTRY(_start),。Uboot整个程序的入口取决于链接脚本中ENTRY声明的地方。ENTRY(_start) 因此_start符号所在的文件就是整个程序的起始文件,_start所在处的代码就是整个程序的起始代码。
2.start.s分析
设置异常向量表
跳转reset
/* globl就是相当于C语言中的Extern,声明此变量,并且告诉链接器此变量是全局的,外部可以访问 指定入口为_start u-boot.lds里面定义了ENTRY(_start),即指定入口为_start */ .globl _start _start: b reset /* ARM是RISC结构,数据从内存到CPU之间的移动只能通过L/S指令来完成,也就是ldr/str指令。 比如想把数据从内存中某处读取到寄存器中,只能使用ldr 将_undefined_instruction这个地址处的word(一字节)定义的值赋给pc。 ARM体系结构规定在上电复位的起始位置必须有8条连续的跳转指令, 通过硬件来实现。它们就是异常向量表。ARM在上电复位后是从0x0开始启动, 如果bootloader存在,则是从_start开始执行上面的跳转没有执行。 设置异常向量表的作用是识别bootloader,以后每当系统有异常出现时, cpu会根据异常号从内存0x0处开始查找并做相应的处理 下面8条即设置异常中断向量表 */ /*构建异常向量表*/ ldr pc, _undefined_instruction ldr pc, _software_interrupt ldr pc, _prefetch_abort ldr pc, _data_abort ldr pc, _not_used ldr pc, _irq ldr pc, _fiq
reset分析:
/*
* the actual reset code
*/
reset:
/* 首先进入SVC管理模式,为什么要进行SVC管理模式而不是其它模式,主要因为SVC模式比其他模式有更多的硬件访问权限,
并且多了影子寄存器,可以访问的硬件资源更多,详情:http://www.360doc.com/content/13/0514/11/7245213_285318786.shtml */
/*
* set the cpu to SVC32 mode
*/
/*
* MRS{条件} 通用寄存器,程序状态寄存器(CPSR或SPSR)
* mrs :程序状态寄存器访问指令
* 通用寄存器 程序状态寄存器(CPSR或SPSR)
* 读取CPSR程序状态寄存器,保存到R0中
*/
mrs r0,cpsr
/*
* bic :BIC{条件}{S} 目的寄存器,操作数1,操作数2,
* BIC指令用于清除操作数1的某些位,并把结果放置到目的寄存器中。操作数1应是一个寄存器
* 操作数2可以是一个寄存器,被移位的寄存器,或一个立即数。操作数2为32位的掩码,如果在掩码中设置了某一
* 位,则清除这一位。未设置的掩码位保持不变。
* 0x1f=00011111,相当于清除低5位,刚好是模式位。
*/
bic r0,r0,#0x1f
/*
* ORR{条件}{S} 目的寄存器,操作数1,操作数2
* ORR指令用于在两个操作数上进行逻辑或运算,并把结果放置到目的寄存器中。操作数1应是一个寄存器,操作数
* 2可以是一个寄存器,被移位的寄存器,或一个立即数。该指令常用于设置操作数1的某些位。
* 0xd3=11010011
* 将r0与0xd3算数或运算,然后将结果给r0,即把r0的bit[7:6]和bit[4]和bit[2:0]置为1。
*/
orr r0,r0,#0xd3
/*
* MSR{条件} 程序状态寄存器(CPSR或SPSR)_<域>,操作数
* MSR指令用于将操作数的内容传送到程序状态寄存器的特定域中
* 将r0中的值赋给状态寄存器cpsr
*/
msr cpsr,r0
/* turn off the watchdog */
#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
#if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410)
ldr r0, =pWTCON
mov r1, #0x0
str r1, [r0]
/*
* mask all IRQs by setting all bits in the INTMR - default
*/
mov r1, #0xffffffff
ldr r0, =INTMSK
str r1, [r0]
# if defined(CONFIG_S3C2410)
ldr r1, =0x3ff
ldr r0, =INTSUBMSK
str r1, [r0]
# endif
/* FCLK:HCLK:PCLK = 1:2:4 */
/* default FCLK is 120 MHz ! */
ldr r0, =CLKDIVN
mov r1, #3
str r1, [r0]
#endif /* CONFIG_S3C2400 || CONFIG_S3C2410 */
/*
* we do sys-critical inits only at reboot,
* not when booting from ram!
*/
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
bl cpu_init_crit
#endif
#ifndef CONFIG_SKIP_RELOCATE_UBOOT
relocate: /* relocate U-Boot to RAM */
adr r0, _start /* r0 <- current position of code */
ldr r1, _TEXT_BASE /* test if we run from flash or RAM */
cmp r0, r1 /* don't reloc during debug */
beq stack_setup
ldr r2, _armboot_start
ldr r3, _bss_start
sub r2, r3, r2 /* r2 <- size of armboot */
add r2, r0, r2 /* r2 <- source end address */
copy_loop:
ldmia r0!, {r3-r10} /* copy from source address [r0] */
stmia r1!, {r3-r10} /* copy to target address [r1] */
cmp r0, r2 /* until source end addreee [r2] */
ble copy_loop
#endif /* CONFIG_SKIP_RELOCATE_UBOOT */
/* Set up the stack */
stack_setup:
ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */
sub r0, r0, #CFG_MALLOC_LEN /* malloc area */
sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo */
#ifdef CONFIG_USE_IRQ
sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
#endif
sub sp, r0, #12 /* leave 3 words for abort-stack */
clear_bss:
ldr r0, _bss_start /* find start of bss segment */
ldr r1, _bss_end /* stop here */
mov r2, #0x00000000 /* clear */
clbss_l:str r2, [r0] /* clear loop... */
add r0, r0, #4
cmp r0, r1
ble clbss_l
#if 0
/* try doing this stuff after the relocation */
ldr r0, =pWTCON
mov r1, #0x0
str r1, [r0]
/*
* mask all IRQs by setting all bits in the INTMR - default
*/
mov r1, #0xffffffff
ldr r0, =INTMR
str r1, [r0]
/* FCLK:HCLK:PCLK = 1:2:4 */
/* default FCLK is 120 MHz ! */
ldr r0, =CLKDIVN
mov r1, #3
str r1, [r0]
/* END stuff after relocation */
#endif
ldr pc, _start_armboot
/* 进入这个C函数后就属于第二阶段的代码了,汇编到此结束 */
_start_armboot: .word start_armboot
设置SVC模式
关看门狗
屏蔽中断
初始化SDRAM
设置stack
设置时钟
重定位(代码从FLASH拷贝到内存中)(怎么拷贝)
清理BSS段()
调用start_armboot
以上完成得是硬件相关初始化,称为uboot的第一阶段。