目录
- 1.前言
- 2.启动整体流程
- 3.启动流程分析
- 3.1 程序入口
- 3.2 返回调用处
- 3.3 关中断并进入SVC32模式
- 3.4 设置异常向量表
- 3.5 cpu_init_cp15
- 3.6 check if ziju flag(TODO)
- 3.7 normal_start_flow
- 3.8 enable syscnt
- 3.9 check_boot_type
- 3.10 do_clr_remap
- 3.11enable I-Cache
- 3.12 ddr_init
- 3.13 check_boot_mode
- 3.14 copy_flash_to_ddr
- 3.15 copy_to_ddr
- 3.16 relocate
- 3.17 _start_armboot
- 3.18 start_armboot
- 4.参考文档
1.前言
本文主要就Hi3556v200的U-boot+Liteos方案的启动流程做简要介绍, 本文主要分析Hi3556v200下的start.S文件。
U-boot版本:u-boot-2016.11
2.启动整体流程
上电时,会从BROM开始启动,此处猜测会将flash中前部分的代码拷贝到SRAM(需要保证不使用绝对跳转,只使用BL相对跳转),然后在SRAM中执行DDR的初始化,然后将hi uboot从flash搬移到ddr,然后执行DDR中的uboot代码(通过LDR绝对跳转)
3.1 程序入口
3.2 返回调用处
3.3 关中断并进入SVC32模式
3.4 设置异常向量表
3.5 cpu_init_cp15
3.6 check if ziju flag
3.7 normal_start_flow
3.8 enable syscnt
3.9 check_boot_type
3.10 do_clr_remap
3.11enable I-Cache
3.12 ddr_init
3.13 check_boot_mode
3.14 copy_flash_to_ddr
3.15 copy_to_ddr
3.16 relocate
3.17 _start_armboot
3.18 start_armboot
3.启动流程分析
3.1 程序入口
uboot/u-boot-2016.11/arch/arm/cpu/armv7/hi3556v200
.globl _start
_start:
b reset
由uboot.lds链接脚本,我们知道整个程序的入口取决于中ENTRY声明的地方。
在uboot.lds中有ENTRY(_start),因此_start符号所在的文件就是整个程序的起始文件,_start所在的代码就是整个程序的起始代码。
.globl XX 语法:给XX外部连接的属性,一般为了在别的文件中引用这个符号
_start后面加上一个冒号’ :’,表示_start是一个标号
_start: b reset 程序开始,跳到reset标号去执行,执行完后不返回
3.2 返回调用处
reset:
/* Allow the board to save important registers */
b save_boot_params
ENTRY(save_boot_params)
b save_boot_params_ret @ back to my caller
ENDPROC(save_boot_params)
.weak save_boot_params
由于此时栈还没有初始化,因此不能保存任何的寄存器,直接返回
3.3 关中断并进入SVC32模式
/*
* disable interrupts (FIQ and IRQ), also set the cpu to SVC32 mode,
* except if in HYP mode already
*/
mrs r0, cpsr
and r1, r0, #0x1f @ mask mode bits
teq r1, #0x1a @ test for HYP mode
bicne r0, r0, #0x1f @ clear all mode bits
orrne r0, r0, #0x13 @ set SVC mode
orr r0, r0, #0xc0 @ disable FIQ and IRQ
msr cpsr,r0
3.4 设置异常向量表
/*
* Setup vector:
* (OMAP4 spl TEXT_BASE is not 32 byte aligned.
* Continue to use ROM code vector only in OMAP4 spl)
*/
#if !(defined(CONFIG_OMAP44XX) && defined(CONFIG_SPL_BUILD))
/* Set V=0 in CP15 SCTLR register - for VBAR to point to vector */
mrc p15, 0, r0, c1, c0, 0 @ Read CP15 SCTLR Register
bic r0, #CR_V @ V = 0
mcr p15, 0, r0, c1, c0, 0 @ Write CP15 SCTLR Register
/* Set vector address in CP15 VBAR register */
adrl r0, _start
mcr p15, 0, r0, c12, c0, 0 @Set VBAR
#endif
3.5 cpu_init_cp15
/* the mask ROM code should have PLL and others stable */
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
bl cpu_init_cp15
#ifndef CONFIG_SKIP_LOWLEVEL_INIT_ONLY
bl cpu_init_crit
#endif
#endif
3.6 check if ziju flag(TODO)
/*
* read system register REG_SC_GEN2
* check if ziju flag
*/
ldr r0, =SYS_CTRL_REG_BASE
ldr r1, [r0, #REG_SC_GEN2]
ldr r2, =0x7a696a75 /* magic for "ziju" */
cmp r1, r2
bne normal_start_flow
mov r1, sp /* save sp */
str r1, [r0, #REG_SC_GEN2] /* clear ziju flag */
3.7 normal_start_flow
normal_start_flow:
/* init serial and printf a string. */
ldr sp, =STACK_TRAINING
#ifdef ENABLE_MINI_BOOT
bl timer_init
#else
bl uart_early_init
bl msg_main_cpu_startup
#endif
3.8 enable syscnt
/*
* enable syscnt
*/
ldr r0, =SYSCNT_REG_BASE
ldr r3, =SYSCNT_FREQ
str r3, [r0, #SYSCNT_FREQ_REG]
mov r3, #0x1
str r3, [r0, #SYSCNT_ENABLE_REG]
@if running not boot from nand/spi/emmc,
@we skipping boot_type checking.
mov r0, pc, lsr#24
cmp r0, #0x0
bne do_clr_remap
3.9 check_boot_type
check_boot_type:
#ifndef ENABLE_MINI_BOOT
ldr r0, =SYS_CTRL_REG_BASE
ldr r0, [r0, #REG_SYSSTAT]
mov r6, r0, lsr#4
and r6, #0x1
cmp r6, #0x1
ldrlo pc, _clr_remap_fmc_entry
#else
ldr pc, _clr_remap_fmc_entry
#endif
3.10 do_clr_remap
do_clr_remap:
#ifndef ENABLE_MINI_BOOT
/* do clear remap */
ldr r4, =SYS_CTRL_REG_BASE
ldr r0, [r4, #REG_SC_CTRL]
@Set clear remap bit.
orr r0, #(1<<8)
str r0, [r4, #REG_SC_CTRL]
#endif
3.11enable I-Cache
@enable I-Cache now
mrc p15, 0, r0, c1, c0, 0
orr r0, r0, #0x00001000 /* set bit 12 (I) I-Cache */
mcr p15, 0, r0, c1, c0, 0
@Check wether I'm running in dynamic mem bank:<0x80000000
mov r0, pc, lsr#28
cmp r0, #8
blo ddr_init
3.12 ddr_init
ddr_init:
ldr r0, _blank_zone_start
ldr r1, _TEXT_BASE
sub r0, r0, r1
adrl r1, _start
add r0, r0, r1
mov r1, #0 /* flags: 0->normal 1->pm */
bl init_registers
ldr sp, =STACK_TRAINING
ldr r0, =REG_BASE_SCTL
bl start_ddr_training /* DDR training */
3.13 check_boot_mode
check_boot_mode:
#ifndef ENABLE_MINI_BOOT
ldr r0, =SYS_CTRL_REG_BASE
ldr r0, [r0, #REG_SYSSTAT]
mov r6, r0, lsr#4
and r6, #0x1
cmp r6, #BOOT_FROM_EMMC
bne copy_flash_to_ddr
#else
b copy_flash_to_ddr
#endif
3.14 copy_flash_to_ddr
copy_flash_to_ddr:
/* relocate SPI nor/nand Boot to DDR */
ldr r0, =FMC_TEXT_ADRS
3.15 copy_to_ddr
copy_to_ddr:
/* now, r0 stores __reset offset from where we get started */
ldr r1, =__image_copy_start
/* compare source and target address, *
*if equal no copy to target address */
cmp r0, r1
beq start_armboot
ldr r2, =__image_copy_start/*_start*/
ldr r3, =__bss_start
sub r2, r3, r2 /* r2 <- size of armboot */
/* memcpy(r1, r0, r2) */
bl memcpy
3.16 relocate
relocate:
ldr r0, =_start_armboot
ldr pc, [r0]
3.17 _start_armboot
_start_armboot:
.word start_armboot
此处可以理解为_start_armboot是一个地址,里面的内容是start_armboot
此处.word的作用是放置一个变量,变量内容为start_armboot函数的地址
3.18 start_armboot
位于u-boot-2016.11/arch/arm/cpu/armv7/hi3556v200/hw_compressed/startup.c中,有如下定义:
const unsigned long IMAGE_ENTRY = (CONFIG_SYS_TEXT_BASE);
osdrv/opensource/uboot/u-boot-2016.11/include/configs/hi3556v200.h中有如下的定义:
#define CONFIG_SYS_TEXT_BASE 0x80800000
如上地址正是编译通用u-boot.bin的链接地址
/uboot/u-boot-2016.11/arch/arm/cpu/armv7/hi3516av300/hw_compressed/image_data.S文件定义如下,将uboot.bin的压缩文件嵌入到此汇编文件,它的起始地址为input_data
.section .image,#alloc
.globl input_data
/*gzip source addr must be 16 bytes aligned*/
.balign 16
input_data:
.incbin "image_data.gzip"
.globl input_data_end
input_data_end:
回到u-boot-2016.11/arch/arm/cpu/armv7/hi3556v200/hw_compressed/startup.c
pdst_l32 = (unsigned char *)IMAGE_ENTRY;
image_data_len = input_data_end - input_data;
ret = hw_dec_decompress(pdst_l32, &pdst_len, input_data, image_data_len, NULL);
如上将通用u-boot.bin的压缩文件解压到pdst_l32地址也就是与uboot.bin的链接地址相同
uboot = (void (*))CONFIG_SYS_TEXT_BASE;
invalidate_icache_all();
uboot();
osdrv/opensource/uboot/u-boot-2016.11/include/configs/hi3556v200.h中:
#define CONFIG_SYS_TEXT_BASE 0x80800000
通过调用uboot运行通用uboot的代码,首先将从start.S开始执行, 执行地址为0x80800000,注意到此前Hi uboot的执行和加载地址为0x80700000,两者之间有1M的空隙
4.参考文档
- https://caibiao-lee.blog.csdn.net/article/details/103292583