声明:本文由个人学习过程中整理而成,转载请注明出处。


1、uboot的启动第一阶段是在SRAM中运行。

(1)因为有汇编阶段参与,整个程序的入口取决于链接脚本中ENTRY的声明。

uboot的u-boot.lds脚本中ENTRY(_start)处的声明表示了整个程序的起始代码是从_start符号开始的。


2、uboot\cpu\s5pc11x\start.S

2.1、头文件包含

(1)#include <config.h>:实际是包含了/include/configs/x210_sd.h,这个文件是整个uboot移植时的关键配置文件。


(2)#include <version.h>:实际是包含了include/version_autogenerated.h文件,文件里面的内容是uboot的版本号信息。


(3)#include <asm/proc/domain.h>:

asm是mkconfig脚本创建的一个符号链接,指向的是asm-arm。

proc是mkconfig脚本创建的一个符号链接,指向的是proc-armv。

实际包含是include/asm-arm/proc-armv/domain.h。


(4)通过mkconfig脚本创建的符号链接来包含,这样做的目的是为了可移植性。


(5)#include <regs.h>:实际是包含了include/s5pc110.h文件。


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和系统移植---朱有鹏老师》