声明:本文由个人学习过程中整理而成,转载请注明出处。
1、uboot的启动第一阶段是在SRAM中运行。
(1)因为有汇编阶段参与,整个程序的入口取决于链接脚本中ENTRY的声明。
uboot的u-boot.lds脚本中ENTRY(_start)处的声明表示了整个程序的起始代码是从_start符号开始的。
2、uboot\cpu\s5pc11x\start.S
2.1、头文件包含
(1)#include
(2)#include
(3)#include
asm是mkconfig脚本创建的一个符号链接,指向的是asm-arm。
proc是mkconfig脚本创建的一个符号链接,指向的是proc-armv。
实际包含是include/asm-arm/proc-armv/domain.h。
(4)通过mkconfig脚本创建的符号链接来包含,这样做的目的是为了可移植性。
(5)#include
2.2、16字节的填充占位
(1)start.S中在开头位置有16字节的占位,后面需要通过目录uboot/sd_fusing下的mkbl1工具对p_w_picpath的头部16字节进行校验加工(SD卡启动)。
(2).word伪操作用于分配一段字内存单元(4字节)。
.word 0x2000//大小不要超过16KB
.word 0x0
.word 0x0
.word 0x0
2.3、设置异常向量
(1)当一个异常或中断发生时,CPU会自动到异常向量表中查找相应异常向量并跳转到异常处理程序。
(2).globl与.global用法相同,声明一个符号可被外部文件引用。
.globl _start
_start: breset
ldrpc, _undefined_instruction
ldrpc, _software_interrupt
ldrpc, _prefetch_abort
ldrpc, _data_abort
ldrpc, _not_used
ldrpc, _irq
ldrpc, _fiq
_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
(4).balignl16,0xdeadbeef指令表示让当前地址对齐排布。不对齐则用0xdeadbeef来填充,直到对齐。
2.4、设置CPU为SVC模式
(1)msrcpsr_c, #0xd3指令表示将CPU设置为ARM状态、SVC模式、禁止FIQ、IRQ模式。
(2)整个uboot工作时CPU要处于SVC模式。ARM的CPU在复位时默认进入SVC模式。
2.5、关闭icache和MMU
/* Invalidate L1 I/D */
movr0, #0 @ set up for MCR
mcrp15, 0, r0, c8, c7, 0 @ invalidate TLBs
mcrp15, 0, r0, c7, c5, 0 @ invalidate icache
/* disable MMU stuff and caches */
mrcp15, 0, r0, c1, c0, 0
icr0, r0, #0x00002000 @ clear bits 13 (--V-)
bicr0, r0, #0x00000007 @ clear bits 2:0 (-CAM)
orrr0, r0, #0x00000002 @ set bit 1 (--A-) Align
orrr0, r0, #0x00000800 @ set bit 12 (Z---) BTB
mcr p15, 0, r0, c1, c0, 0
2.6、记录启动介质的选择
r2保存了判断启动介质的值,后面判断启动介质时会用到。
/* Read booting information */
ldrr0, =PRO_ID_BASE
ldrr1, [r0,#OMR_OFFSET]
bicr2, r1, #0xffffffc1
2.7、判断启动介质
判断启动方式,将结果保存到INF_REG_BASE。
/* NAND BOOT */
cmpr2, #0x0@ 512B 4-cycle
moveqr3, #BOOT_NAND
cmpr2, #0x2@ 2KB 5-cycle
moveqr3, #BOOT_NAND
cmpr2, #0x4@ 4KB 5-cycle8-bit ECC
moveqr3, #BOOT_NAND
cmpr2, #0x6@ 4KB 5-cycle16-bit ECC
moveqr3, #BOOT_NAND
cmpr2, #0x8@ OneNAND Mux
moveqr3, #BOOT_ONENAND
/* SD/MMC BOOT */
cmp r2, #0xc
moveq r3, #BOOT_MMCSD
/* NOR BOOT */
cmp r2, #0x14
moveq r3, #BOOT_NOR
/* Uart BOOTONG failed */
cmp r2, #(0x1<<4)
moveq r3, #BOOT_SEC_DEV
ldrr0, =INF_REG_BASE
strr3, [r0, #INF_REG3_OFFSET]
2.8、第一次设置栈(SRAM中的栈)并调用lowlevel_init
(1)因为当前整个代码还在SRAM中运行,此时DDR还未被初始化还不能用。
(2)栈初始化后方便函数调用。
ldrsp, =0xd0036000 /* end of sram dedicated to u-boot */
subsp, sp, #12/* set stack */
movfp, #0
bllowlevel_init/* go setup pll,mux,memory */
2.9、lowlevel_init
目录uboot\board\samsung\x210\lowlevel_init.S
2.9.1、关看门狗
uboot启动的第一阶段并没有喂×××作,防止看门狗超时复位。
/* Disable Watchdog */
ldrr0, =ELFIN_WATCHDOG_BASE/* 0xE2700000 */
movr1, #0
strr1, [r0]
2.9.2、供电置锁开发板
/* PS_HOLD pin(GPH0_0) set to high */
ldrr0, =(ELFIN_CLOCK_POWER_BASE + PS_HOLD_CONTROL_OFFSET)
ldrr1, [r0]
orrr1, r1, #0x300
orrr1, r1, #0x1
strr1, [r0]
2.9.3、判断当前代码所处位置是在DDR还是SRAM
读取当前运行时地址和链接地址,进行对比是否相等,从而决定是否跳过下面的时钟和DDR初始化。
ldrr0, =0xff000fff
bicr1, pc, r0/* r0 <- current base addr of code */
ldrr2, _TEXT_BASE/* r1 <- original base addr in ram */
bicr2, r2, r0/* r0 <- current base addr of code */
cmp r1, r2 /* compare r0, r1 */
beq 1f/* r0 == r1 then skip sdram init */
2.9.4、时钟初始化
/* init system clock */
bl system_clock_init
2.9.5、内存初始化
目录uboot\cpu\s5pc11x\s5pc110\cpu_init.S
/* Memory initialize */
bl mem_ctrl_asm_init
2.9.6、串口初始化
/* for UART */
bl uart_asm_init
2.10、第二次设置栈(DDR中的栈)
(1)DDR已经被初始化了,可以把栈设置到DDR中。
(2)调用C语言代码执行初始化工作,需要用到栈。
/* get ready to call C functions */
ldrsp, _TEXT_PHY_BASE/* setup temp stack pointer */
subsp, sp, #12
movfp, #0/* no previous frame, so fp=0 */
2.11、判断当前地址是否需要重定位
2.12、根据启动方式,进行重定位。
SD卡重定位为例,函数movi_bl2_copy。
(1)目录uboot\cpu\s5pc11x\movi.c
(2)copy_bl2(2, MOVI_BL2_POS, MOVI_BL2_BLKCNT,CFG_PHY_UBOOT_BASE, 0);
分析参数:
2表示通道2;MOVI_BL2_POS是uboot的第二部分在SD卡中的开始扇区;
MOVI_BL2_BLKCNT是uboot所占用长度的扇区数;
CFG_PHY_UBOOT_BASE是需要重定位到的位置。
通道:2
BL2开始扇区:49
BL2占用的扇区大小:1024
copy_bl2(2, 49, 1024,0x33e00000, 0);
2.9、MMU(内存管理单元)的相关设置
cp15协处理器内部有c0到c15共16个寄存器。
(1)、设置域访问
c3寄存器在mmu中的作用是控制域访问。
/* enable domain access */
ldrr5, =0x0000ffff
mcrp15, 0, r5, c3, c0, 0@load domain access register
(2)、设置TTB(translation table base)
将转换表基地址设置到c2寄存器,MMU工作时会自动去查转换表。
/* Set the TTB register */
ldrr0, _mmu_table_base
ldrr1, =CFG_PHY_UBOOT_BASE
ldrr2, =0xfff00000
bicr0, r0, r2
orrr1, r0, r1
mcrp15, 0, r1, c2, c0, 0
(3)、设置MMU开关
c1寄存器的bit0控制MMU的开关。只要将这一个bit0置1即可开启MMU。
/* Enable the MMU */
mmu_on:
mrcp15, 0, r0, c1, c0, 0
orrr0, r0, #1
mcrp15, 0, r0, c1, c0, 0
nop
nop
nop
nop
2.10、第三次设置栈(DDR中的栈)
(1)第三次设置栈到合适的位置(安全、内存紧凑)。
ldrsp, =(CFG_UBOOT_BASE + CFG_UBOOT_SIZE - 0x1000)
2.11、清bss段
clear_bss:
ldrr0, _bss_start/* find start of bss segment */
ldrr1, _bss_end/* stop here */
mov r2, #0x00000000/* clear */
clbss_l:
strr2, [r0]/* clear loop... */
addr0, r0, #4
cmpr0, r1
bleclbss_l
2.12、跳转到uboot启动的第二阶段
uboot启动的第二阶段的代码入口_start_armboot。
ldrpc, _start_armboot
总结:
(1)设置异常向量表
(2)设置CPU为SVC模式
(3)关看门狗
(4)供电置锁开发板
(5)时钟初始化
(6)内存初始化
(7)串口初始化
(8)重定位
(9)MMU(内存管理单元)的相关设置
(10)跳转到uboot启动的第二阶段
参考资料:《uboot和系统移植---朱有鹏老师》