Hi3556v200 u-boot+Liteos方案启动流程分析--2.通用uboot start.S分析

1.前言

本文主要就Hi3556v200的U-boot+Liteos方案的启动流程做简要介绍, 前面主要分析了Hi3556v200下的start.S文件,在这之后它将解压通用uboot的代码执行,执行的入口位于通用uboot的start.S文件。
U-boot版本:u-boot-2016.11

2.主要流程

2.1 _start

上文分析到从Hi3556v200下的start.S文件执行的最后会通过start_armboot函数解压通用uboot的压缩文件,然后跳转到首地址进行执行,这个首地址就是通用uboot的链接地址0x80800000,通过链接脚本u-boot-2016.11/arch/arm/cpu/u-boot.lds可以知道入口地址为_start.位于u-boot-2016.11/arch/arm/cpu/armv7/start.S

2.2 reset

reset:
#ifndef CONFIG_MINI_BOOT
        /* Allow the board to save important registers */
ENTRY(save_boot_params)
        b       save_boot_params_ret            @ back to my caller
ENDPROC(save_boot_params)
        .weak   save_boot_params
#endif

save_boot_params_ret:
#ifdef CONFIG_ARMV7_LPAE
/*
 * check for Hypervisor support
 */
        mrc     p15, 0, r0, c0, c1, 1           @ read ID_PFR1
        and     r0, r0, #CPUID_ARM_VIRT_MASK    @ mask virtualization bits
        cmp     r0, #(1 << CPUID_ARM_VIRT_SHIFT)
        beq     switch_to_hypervisor
switch_to_hypervisor_ret:
#endif

2.3 set SVC32 mode

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

2.4 Setup vector

/*
 * 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 */
        ldr     r0, =_start
        mcr     p15, 0, r0, c12, c0, 0  @Set VBAR
#endif

2.5 cpu_init_cp15

#ifndef CONFIG_SKIP_LOWLEVEL_INIT
        bl      cpu_init_cp15
#ifndef CONFIG_SKIP_LOWLEVEL_INIT_ONLY
        bl      cpu_init_crit
#endif
#endif

2.6 _main

 bl      _main

_main函数的定义位于./arch/arm/lib/crt0.S

Set up initial C runtime environment and call board_init_f(0)

2.6.1 设置初始运行环境

#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)
        ldr     sp, =(CONFIG_SPL_STACK)
#else
        ldr     sp, =(CONFIG_SYS_INIT_SP_ADDR)
#endif

设置栈指针,CONFIG_SYS_INIT_SP_ADDR宏的定义位于
osdrv/opensource/uboot/u-boot-2016.11/include/configs/hi3556v200.h文件中

#define CONFIG_SYS_INIT_SP_ADDR     0x04014000

此位于片内RAM地址空间
0x0401_0000 0x0401_9FFF 片内 RAM 地址空间

#if defined(CONFIG_CPU_V7M)     /* v7M forbids using SP as BIC destination */
        mov     r3, sp
        bic     r3, r3, #7
        mov     sp, r3
#else
        bic     sp, sp, #7      /* 8-byte alignment for ABI compliance */
#endif

8字节对齐

2.6.2 board_init_f

mov     r0, sp //r0的值为0x04014000
bl      board_init_f_alloc_reserve //返回后r0保存地址变为0x04014000-0x2000
mov     sp, r0 //sp栈变为0x04014000-0x2000
/* set up gd here, outside any C code */
mov     r9, r0  //r9保存地址0x04014000-0x2000
bl      board_init_f_init_reserve

mov     r0, #0
bl      board_init_f

board_init_f_alloc_reserve :分配一块空间(0x04014000-0x2000~ 0x04014000)作为malloc区域,返回后r0保存地址变为0x04014000-0x2000

board_init_f_init_reserve:对分配的malloc区域(0x04014000-0x2000~ 0x04014000)进行初始化

board_init_f_alloc_reserve
ulong board_init_f_alloc_reserve(ulong top)
{
        /* Reserve early malloc arena */
#if defined(CONFIG_SYS_MALLOC_F)
        top -= CONFIG_SYS_MALLOC_F_LEN;
#endif
        /* LAST : reserve GD (rounded up to a multiple of 16 bytes) */
        top = rounddown(top-sizeof(struct global_data), 16);

        return top;
}

CONFIG_SYS_MALLOC_F_LEN位于uboot/u-boot-2016.11/include/generated/autoconf.h
#define CONFIG_SYS_MALLOC_F_LEN 0x2000
通过调用board_init_f_alloc_reserve从CONFIG_SYS_INIT_SP_ADDR 开始来分配一段大小为CONFIG_SYS_MALLOC_F_LEN 的全局空间,用于堆使用

board_init_f_init_reserve

通过调用board_init_f_init_reserve来对分配的malloc区域(0x04014000-0x2000~ 0x04014000)进行初始化,主要是将这段区域通过"\0"填充,同时初始化了gd->malloc_base的地址为
0x04014000 - 0x2000

board_init_f

位于/u-boot-2016.11/common/board_f.c
此时r0被清零,也就是参数boot_flags为0
board_init_f首先通过栈来分配
gd_t data;
gd = &data;
之后再通过重定位到新的地址
之后主要是调用了init_sequence_f函数数组

2.6.3 Set up intermediate environment

osdrv/opensource/uboot/u-boot-2016.11/include/asm-generic/u-boot.h中定义了struct bd_info结构体,它主要包含了一些板级的信息,用于传递给kernel,如:dram的起始地址和大小,sram的起始地址和大小,flash的起始地址和大小等。struct bd_info结构体指针关联于struct global_data结构体。

  1. 重新设置新的堆栈指针
ldr     sp, [r9, #GD_START_ADDR_SP]     /* sp = gd->start_addr_sp */
bic     sp, sp, #7      /* 8-byte alignment for ABI compliance */

可参考uboot重定位地址空间布局图

  1. relocate_code
    ldr     r9, [r9, #GD_BD]                /* r9 = gd->bd */
    sub     r9, r9, #GD_SIZE                /* new GD is below bd */
    adr     lr, here //保存链接地址为here标号地址
    ldr     r0, [r9, #GD_RELOC_OFF]         /* r0 = gd->reloc_off */
    add     lr, lr, r0

b       relocate_code

分析board_init_f时就会知道r9保存的地址位于sram的0x04014000 -0x2000,它是old gd_t存放的位置,偏移GD_RELOC_OFF就是gd->reloc_off,此时r0存放着gd->reloc_off,也就是uboot加载地址与重定位地址之间的偏移
relocate_code函数定义在/u-boot-2016.11/arch/arm/lib/relocate.S 中
(1)首先通过为编译器指定编译选项-fpic或-fpie产生位置无关码,这样调用函数可以做到位置无关
(2)对于全局变量的访问需要重定位
uboot是通过增加了一个rel.dyn段,这个段保存了所有需要重定位的变量,通过将每个变量的地址加上gd->reloc_off来达到uboot变量重定位的目的
注:通过查看反汇编可以看到,如果函数访问到全局变量,全局变量会被放置到函数的末尾,重定位的思路也就是改变放置到函数末尾的全局变量的地址
关于relocate的原理可以详细参考如下文章:
https://blog.csdn.net/skyflying2012/article/details/37660265

relocate_code函数的最后会执行如下语句,跳转到here,执行relocate_vectors

 bx      lr
  1. relocate_vectors
here:
/*
 * now relocate vectors
 */
        bl      relocate_vectors

重定位异常向量表

  1. Set up final (full) environment
 bl      c_runtime_cpu_setup     /* we still call old routine here */
  1. bss clear
       ldr     r0, =__bss_start        /* this is auto-relocated! */

#ifdef CONFIG_USE_ARCH_MEMSET
        ldr     r3, =__bss_end          /* this is auto-relocated! */
        mov     r1, #0x00000000         /* prepare zero to clear BSS */

        subs    r2, r3, r0              /* r2 = memset len */
        bl      memset
#else
        ldr     r1, =__bss_end          /* this is auto-relocated! */
        mov     r2, #0x00000000         /* prepare zero to clear BSS */

clbss_l:cmp     r0, r1                  /* while not at end of BSS */
        strlo   r2, [r0]                /* clear 32-bit BSS word */
        addlo   r0, r0, #4              /* move to next */
        blo     clbss_l
#endif

清重定位后的uboot的bss段

  1. board_init_r
/* call board_init_r(gd_t *id, ulong dest_addr) */
        mov     r0, r9                  /* gd_t */
        ldr     r1, [r9, #GD_RELOCADDR] /* dest_addr */
        /* call board_init_r */
        ldr     pc, =board_init_r       /* this is auto-relocated! */

board_init_r主要位于common/board_r.c,遍历执行init_sequence_r数组

参考文档

  1. https://caibiao-lee.blog.csdn.net/article/details/103292583
    海思(Hi3521a)uboot详细分析(5)——uboot启动第一阶段start.S文件分析
  2. https://blog.csdn.net/skyflying2012/article/details/37660265
    uboot的relocation原理详细分析
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值