原文链接:https://blog.csdn.net/itdo_just/article/details/78701886
以下源码以u-boot-1.1.6中的2410为例。
1.start.s的引入
在board/smdk2240/u-boot.lds中可以看到ENTRY(_start),。Uboot整个程序的入口取决于链接脚本中ENTRY声明的地方。ENTRY(_start) 因此_start符号所在的文件就是整个程序的起始文件,_start所在处的代码就是整个程序的起始代码。
2.start.s分析
~/cpu/arm920t/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 */
/*
* 1.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
/* 2.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]
/*
* 3.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
4.设置时钟
/* 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 //5和6关闭MMU以及初始化SDRAM控制器
#endif
#ifndef CONFIG_SKIP_RELOCATE_UBOOT
7.重定位
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 */
adr 位置无关码,获取_start实际当前位于的地方,_TEXT_BASE 为 0x33f80000 ,这里判断的是代码是否直接运行在 sdram 里了,如果是就不需要重定位了。
拷贝范围:_start 至 _bss_start 前,拷贝到 0x33f80000 处。
/* 8.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 */
9.清BSS段
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
ldr pc, _start_armboot
/* 10.进入这个C函数后就属于第二阶段的代码了,汇编到此结束 */
_start_armboot: .word start_armboot
cpu_init_crit分析
/* ************************************************************************* * * CPU_init_critical registers * * setup important registers * setup memory timing * ************************************************************************* */ #ifndef CONFIG_SKIP_LOWLEVEL_INIT cpu_init_crit:
关 I/D cache 关 TLB
/* * flush v4 I/D caches */ mov r0, #0 mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache */ mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */ /* * disable MMU stuff and caches */ mrc p15, 0, r0, c1, c0, 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 bl lowlevel_init mov lr, ip mov pc, lr #endif /* CONFIG_SKIP_LOWLEVEL_INIT */
根据说明,可以在lowlevel_init.S中找到lowlevel_init的源码
.globl lowlevel_init lowlevel_init: /* memory control configuration */ /* make r0 relative the current location so that it */ /* reads SMRDATA out of FLASH rather than memory ! */ ldr r0, =SMRDATA ldr r1, _TEXT_BASE sub r0, r0, r1 ldr r1, =BWSCON /* Bus Width Status Controller */ add r2, r0, #13*4 0: ldr r3, [r0], #4 str r3, [r1], #4 cmp r2, r0 bne 0b /* everything is fine now */ mov pc, lr .ltorg /* the literal pools origin */ SMRDATA: .word (0+(B1_BWSCON<<4)+(B2_BWSCON<<8)+(B3_BWSCON<<12)+(B4_BWSCON<<16)+(B5_BWSCON<<20)+(B6_BWSCON<<24)+(B7_BWSCON<<28)) .word ((B0_Tacs<<13)+(B0_Tcos<<11)+(B0_Tacc<<8)+(B0_Tcoh<<6)+(B0_Tah<<4)+(B0_Tacp<<2)+(B0_PMC)) .word ((B1_Tacs<<13)+(B1_Tcos<<11)+(B1_Tacc<<8)+(B1_Tcoh<<6)+(B1_Tah<<4)+(B1_Tacp<<2)+(B1_PMC)) .word ((B2_Tacs<<13)+(B2_Tcos<<11)+(B2_Tacc<<8)+(B2_Tcoh<<6)+(B2_Tah<<4)+(B2_Tacp<<2)+(B2_PMC)) .word ((B3_Tacs<<13)+(B3_Tcos<<11)+(B3_Tacc<<8)+(B3_Tcoh<<6)+(B3_Tah<<4)+(B3_Tacp<<2)+(B3_PMC)) .word ((B4_Tacs<<13)+(B4_Tcos<<11)+(B4_Tacc<<8)+(B4_Tcoh<<6)+(B4_Tah<<4)+(B4_Tacp<<2)+(B4_PMC)) .word ((B5_Tacs<<13)+(B5_Tcos<<11)+(B5_Tacc<<8)+(B5_Tcoh<<6)+(B5_Tah<<4)+(B5_Tacp<<2)+(B5_PMC)) .word ((B6_MT<<15)+(B6_Trcd<<2)+(B6_SCAN)) .word ((B7_MT<<15)+(B7_Trcd<<2)+(B7_SCAN)) .word ((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Trc<<18)+(Tchr<<16)+REFCNT) .word 0x32 .word 0x30 .word 0x30
其中TEXT_BASE = 0x33F80000,在~/board/smdk2410/config.mk中有定义,其他一些宏的相关定义在~/include/configs/smdk2410.h
- 设置SVC模式
- 关看门狗
- 屏蔽中断
- 设置时钟
- 关闭MMU
- 初始化SDRAM控制器
- 重定位(代码从FLASH拷贝到内存中)(怎么拷贝)
- 设置stack
- 清理BSS段()
- 调用start_armboot
以上完成得是硬件相关初始化,称为uboot的第一阶段