首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

uboot启动第一阶段

从链接脚本u-boot.lds中我们知道u-boot是从start.s这个汇编文件开始的,所以u-boot启动的第一阶段肯定也是从这里开始的,这个文件在cpu/arm_cortexa9/文件夹下,下面我们依照这个文件一步一步分析u-boot启动的第一阶段。

#include

#include

#if defined(CONFIG_ENABLE_MMU)

#include

#endif

#if defined(CONFIG_S5PV310)

#include

#endif

#if defined(CONFIG_S5PC210)

#include

#endif

上面的代码包含了一些必要的头文件。

.word 0x2000

.word 0x0

.word 0x0

.word 0x0

定义uboot程序开头的16字节校验头信息填充空间,头校验信息块内的值需要在后面写入。

.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

中断向量表定义,这里我们看到有reset标号,但是它并没有像其它的中断向量一样放在向量表中,而是通过start跳转来实现的。下面我们分析reset

#if 0

/*

* set the cpu to SVC32 mode and IRQ & FIQ disable

*/

mrsr0, cpsr

bicr0, r0, #0x3f

orrr0, r0, #0xd3

msrcpsr, r0

#else//*****ly

mrsr0, cpsr

bicr0, r0, #0x1f

orrr0, r0, #0xd3

msrcpsr,r0

#endif

以上代码将CPU的工作模式设置为管理模式,并屏蔽IRQ和FIQ中断。

#if 1 //*****ly

cache_init:

mrcp15, 0, r0, c0, c0, 0@ read main ID register

andr1, r0, #0x00f00000@ variant

andr2, r0, #0x0000000f@ revision

orrr2, r2, r1, lsr #20-4@ combine variant and revision

cmpr2, #0x30

mrceqp15, 0, r0, c1, c0, 1@ read ACTLR

orreqr0, r0, #0x6@ Enable DP1(2), DP2(1)

mcreqp15, 0, r0, c1, c0, 1@ write ACTLR

/*

* 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

bicr0, r0, #0x00002000@ clear bits 13 (--V-)

bicr0, r0, #0x00000007@ clear bits 2:0 (-CAM)

orrr0, r0, #0x00001000@ set bit 12 (---I) Icache

orrr0, r0, #0x00000002@ set bit 1 (--A-) Align

orrr0, r0, #0x00000800@ set bit 11 (Z---) BTB

mcrp15, 0, r0, c1, c0, 0

#endif

关闭缓存和MMU,缓存和MMU是由CP15协处理器管理的,所以要做的就是设置CP15相应的寄存器

/* Read booting information */

ldrr0, =POWER_BASE

ldrr1, [r0,#OMR_OFFSET]

bicr2, r1, #0xffffffc1

cmp r2, #0xA

moveq r3, #BOOT_ONENAND

/* SD/MMC BOOT */

cmp r2, #0x4

moveq r3, #BOOT_MMCSD

/* eMMC4.3 BOOT */

cmpr2, #0x6

moveqr3, #BOOT_EMMC43

/* eMMC441 BOOT */

cmpr2, #0x28

moveqr3, #BOOT_EMMC441

ldrr0, =INF_REG_BASE

strr3, [r0, #INF_REG3_OFFSET]

读取boot信息,判断是从哪种启动介质启动

bllowlevel_init/* go setup pll,mux,memory */

跳转到lowlevel_init进行初始化,下面我们进入lowlevel_init,由于它是和开发板相关的,所以是放在board这个文件夹里面

lowlevel_init:

#if 1//*****ly

/* use iROM stack in bl2 */

ldrsp, =0x02060000

#endif

push{lr}

/* check reset status */

ldr r0, =(INF_REG_BASE + INF_REG1_OFFSET)

ldr r1, [r0]

/* AFTR wakeup reset */

ldrr2, =S5P_CHECK_DIDLE

cmpr1, r2

beqexit_wakeup

/* Sleep wakeup reset */

ldrr2, =S5P_CHECK_SLEEP

cmpr1, r2

beqwakeup_reset

/* PS-Hold high */

ldr r0, =0x1002330c

ldr r1, [r0]

orr r1, r1, #0x300

str r1, [r0]

ldr r0, =0x11000c08

ldr r1, =0x0

str r1, [r0]

/* Clear MASK_WDT_RESET_REQUEST */

ldr r0, =0x1002040c

ldr r1, =0x00

str r1, [r0]

#ifdef check_mem /*liyang 20110822*/

/* when we already run in ram, we don't need to relocate U-Boot.

* and actually, memory controller must be configured before U-Boot

* is running in ram.

*/

ldrr0, =0xff000fff

bicr1, pc, r0/* r0

ldrr2, _TEXT_BASE/* r1

bicr2, r2, r0/* r0

cmp r1, r2 /* compare r0, r1 */

beq 1f/* r0 == r1 then skip sdram init */

#endif

/* add by cym 20130218 */

/* init system clock */

bl system_clock_init_scp

/* Memory initialize */

bl mem_ctrl_asm_init_ddr3

/* end add */

bl tzpc_init

b1f

1:

#ifdef CONFIG_EVT1___

/* store DMC density information in DRAM */

/* mem_ctrl_asm_init returns dmc_density in r6 */

ldrr0, =CFG_UBOOT_BASE

subr0, r0, #4

strr6, [r0]

#endif

#if 0 //test for mt6620 turn off GPC1(0)

/*wenpin.cui: headphone and sw uart switch init*/

ldrr0, =0x11000C44

ldrr1, [r0]

andr1, r1, #0x4

cmpr1, #0x4/*uart*/

beqout

ldr r0, =0x11400084 /* GPC1(0) */

ldr r1, [r0]/* read GPC1DAT status*/

orrr1, r1, #0x1/* GPC1(0) output high */

str r1, [r0]

ldr r0, =0x11400080 /* GPC1(0) */

ldrr1, [r0]

andr1, r1, #0xfffffff0

orr r1, r1, #0x1/* GPC1(0) output */

str r1, [r0]

#endif

out:

/* for UART */

bl uart_asm_init

它做的主要事情有:判断代码是否在内存中(如果u-boot已经在内存中,则直接跳过下面三步),系统时钟初始化,内存初始化,tzpc初始化,最后是串口初始化,回到start.s文件中

ldrr0, =0x1002330C /* PS_HOLD_CONTROL register */

ldrr1, =0x00005300 /* PS_HOLD output high*/

strr1, [r0]

设置开发板供电锁存

/* 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 */

在内存中为接下来的C函数设置栈

ldrr0, =0xff000fff

bicr1, pc, r0/* r0

ldrr2, _TEXT_BASE/* r1

bicr2, r2, r0/* r0

cmp r1, r2 /* compare r0, r1 */

beq after_copy/* r0 == r1 then skip flash copy */

判断当前代码是否运行在SDRAM中,如果当前代码运行在SDRAM中,则跳过代码重定位。

ldrr0, =INF_REG_BASE

ldrr1, [r0, #INF_REG3_OFFSET]

cmpr1, #BOOT_NAND/* 0x0 => boot device is nand */

beqnand_boot

cmpr1, #BOOT_ONENAND/* 0x1 => boot device is onenand */

beqonenand_boot

cmp r1, #BOOT_EMMC441

beq emmc441_boot

cmp r1, #BOOT_EMMC43

beq emmc_boot

cmp r1, #BOOT_MMCSD

beq mmcsd_boot

cmp r1, #BOOT_NOR

beq nor_boot

cmp r1, #BOOT_SEC_DEV

beq mmcsd_boot

判断启动方式

nand_boot:

movr0, #0x1000

blcopy_from_nand

bafter_copy

onenand_boot:

blonenand_bl2_copy /*goto 0x1010*/

bafter_copy

//ly

second_mmcsd_boot:

ldr r3, =BOOT_MMCSD

ldrr0, =INF_REG_BASE

strr3, [r0, #INF_REG3_OFFSET]

mmcsd_boot:

#ifdef CONFIG_CLK_1000_400_200

ldrr0, =CMU_BASE

ldrr2, =CLK_DIV_FSYS2_OFFSET

ldrr1, [r0, r2]

orr r1, r1, #0xf

str r1, [r0, r2]

#endif

bl movi_uboot_copy

b after_copy

emmc_boot:

#if defined(CONFIG_CLK_1000_400_200) || defined(CONFIG_CLK_1000_200_200) || defined(CONFIG_CLK_800_400_200)

ldrr0, =CMU_BASE

ldrr2, =CLK_DIV_FSYS1_OFFSET

ldrr1, [r0, r2]

orr r1, r1, #0x3

str r1, [r0, r2]

#endif

blemmc_uboot_copy

bafter_copy

emmc441_boot:

#if defined(CONFIG_CLK_1000_400_200) || defined(CONFIG_CLK_1000_200_200) || defined(CONFIG_CLK_800_400_200)

ldrr0, =CMU_BASE

ldrr2, =CLK_DIV_FSYS3_OFFSET

ldrr1, [r0, r2]

orr r1, r1, #0x3

str r1, [r0, r2]

#endif

blemmc441_uboot_copy

//ly 20110824

ldr r0, =0x43e00000

ldr r1, [r0]

ldr r2, =0x2000

cmp r1, r2

bne second_mmcsd_boot

bafter_copy

nor_boot:

@blread_hword

bafter_copy

不同的启动方式所对应的启动代码,注意,这部分的代码,只有当u-boot不在内存中时才会执行

#if defined(CONFIG_ENABLE_MMU)

enable_mmu:

/* enable domain access */

ldrr5, =0x0000ffff

mcrp15, 0, r5, c3, c0, 0@load domain access register

/* 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

/* Enable the MMU */

mmu_on:

mrcp15, 0, r0, c1, c0, 0

orrr0, r0, #1

mcrp15, 0, r0, c1, c0, 0

nop

nop

nop

nop

#endif

设置mmu,使能mmu

stack_setup:

#if defined(CONFIG_MEMORY_UPPER_CODE)

ldrsp, =(CFG_UBOOT_BASE + CFG_UBOOT_SIZE - 0x1000)

#else

ldrr0, _TEXT_BASE/* upper 128 KiB: relocated uboot */

subr0, r0, #CONFIG_SYS_MALLOC_LEN/* malloc area */

subr0, r0, #CFG_GBL_DATA_SIZE /* bdinfo */

#if defined(CONFIG_USE_IRQ)

subr0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)

#endif

subsp, r0, #12/* leave 3 words for abort-stack */

#endif

通过对内存整体使用规划,在内存中合适的地方设置栈

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

ldrpc, _start_armboot

_start_armboot:

.word start_armboot

清除bss段,跳转到start_armboot执行,u-boot启动第一阶段完成。

下面总结一下,u-boot第一阶段做了哪些事情:

设置异常向量(exception vector)

关闭IRQ、FIQ,设置SVC模式

关闭缓存、MMU

确定启动介质

lowlevel_init(主要初始化系统时钟、内存初始化、串口初始化等)

设置开发板供电锁存

设置内存中的栈

将uboot从EMMC拷贝到内存中

设置并开启MMU

通过对内存整体使用规划,在内存中合适的地方设置栈

清除bss段,远跳转到start_armboot执行,u-boot第一阶段执行完

  • 发表于:
  • 原文链接https://page.om.qq.com/page/O47cIG8vCD8N16oAMGBqazJw0
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券