u-boot之启动第一阶段(代码片段)

yinshijia yinshijia     2023-05-05     237

关键词:

基于samsung的Exynos 4412

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

#include <config.h>
#include <version.h>
#if defined(CONFIG_ENABLE_MMU)
#include <asm/proc/domain.h>
#endif
#if defined(CONFIG_S5PV310)
#include <s5pv310.h>
#endif
#if defined(CONFIG_S5PC210)
#include <s5pc210.h>
#endif

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

    .word 0x2000
    .word 0x0
    .word 0x0
    .word 0x0

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

.globl _start
_start: b   reset
    ldr pc, _undefined_instruction
    ldr pc, _software_interrupt
    ldr pc, _prefetch_abort
    ldr pc, _data_abort
    ldr pc, _not_used
    ldr pc, _irq
    ldr pc, _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
     */
    mrs r0, cpsr
    bic r0, r0, #0x3f
    orr r0, r0, #0xd3
    msr cpsr, r0
#else//*****ly
    mrs r0, cpsr
    bic r0, r0, #0x1f
    orr r0, r0, #0xd3
    msr cpsr,r0
#endif

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

#if 1 //*****ly
cache_init:
    mrc p15, 0, r0, c0, c0, 0   @ read main ID register
    and r1, r0, #0x00f00000 @ variant
    and r2, r0, #0x0000000f @ revision
    orr r2, r2, r1, lsr #20-4   @ combine variant and revision
    cmp r2, #0x30
    mrceq   p15, 0, r0, c1, c0, 1   @ read ACTLR
    orreq   r0, r0, #0x6        @ Enable DP1(2), DP2(1)
    mcreq   p15, 0, r0, c1, c0, 1   @ write ACTLR
    /*
     * Invalidate L1 I/D
     */
    mov r0, #0          @ set up for MCR
    mcr p15, 0, r0, c8, c7, 0   @ invalidate TLBs
    mcr p15, 0, r0, c7, c5, 0   @ invalidate icache

    /*
     * disable MMU stuff and caches
     */
    mrc p15, 0, r0, c1, c0, 0
    bic r0, r0, #0x00002000 @ clear bits 13 (--V-)
    bic r0, r0, #0x00000007 @ clear bits 2:0 (-CAM)
    orr r0, r0, #0x00001000 @ set bit 12 (---I) Icache
    orr r0, r0, #0x00000002 @ set bit 1  (--A-) Align
    orr r0, r0, #0x00000800 @ set bit 11 (Z---) BTB
    mcr p15, 0, r0, c1, c0, 0
#endif

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

    /* Read booting information */
    ldr r0, =POWER_BASE
    ldr r1, [r0,#OMR_OFFSET]
    bic r2, r1, #0xffffffc1

    cmp     r2, #0xA
    moveq   r3, #BOOT_ONENAND

    /* SD/MMC BOOT */
    cmp     r2, #0x4
        moveq   r3, #BOOT_MMCSD 

    /* eMMC4.3 BOOT */
    cmp     r2, #0x6
    moveq   r3, #BOOT_EMMC43

    /* eMMC441 BOOT */
    cmp     r2, #0x28
    moveq   r3, #BOOT_EMMC441
    
    ldr r0, =INF_REG_BASE
    str r3, [r0, #INF_REG3_OFFSET]   

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

    bl  lowlevel_init   /* go setup pll,mux,memory */

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

lowlevel_init:
#if 1//*****ly
    /* use iROM stack in bl2 */
    ldr sp, =0x02060000
#endif
    push    lr

    /* check reset status  */
    ldr     r0, =(INF_REG_BASE + INF_REG1_OFFSET)
        ldr     r1, [r0]

    /* AFTR wakeup reset */
    ldr r2, =S5P_CHECK_DIDLE
    cmp r1, r2
    beq exit_wakeup

    /* Sleep wakeup reset */
    ldr r2, =S5P_CHECK_SLEEP
    cmp r1, r2
    beq wakeup_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.
     */
    ldr r0, =0xff000fff
    bic r1, pc, r0      /* r0 <- current base addr of code */
    ldr r2, _TEXT_BASE      /* r1 <- original base addr in ram */
    bic r2, r2, r0      /* r0 <- current base addr of code */
    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
    
    b   1f
    1:

#ifdef CONFIG_EVT1___
    /* store DMC density information in DRAM */
    /* mem_ctrl_asm_init returns dmc_density in r6 */
    ldr r0, =CFG_UBOOT_BASE
    sub r0, r0, #4
    str r6, [r0]
#endif
#if 0 //test for mt6620 turn off GPC1(0)
    /*wenpin.cui: headphone and sw uart switch init*/
    ldr r0, =0x11000C44
    ldr r1, [r0]
    and r1, r1, #0x4    
    cmp r1, #0x4    /*uart*/    
    beq out 

    ldr     r0, =0x11400084  /* GPC1(0)  */
    ldr     r1, [r0]    /* read GPC1DAT status*/
    orr r1, r1, #0x1    /* GPC1(0) output high  */
    str     r1, [r0]

    ldr     r0, =0x11400080  /* GPC1(0)  */
    ldr r1, [r0]
    and r1, 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文件中

    ldr r0, =0x1002330C  /* PS_HOLD_CONTROL register */
    ldr r1, =0x00005300  /* PS_HOLD output high */
    str r1, [r0]

设置开发板供电锁存

    /* get ready to call C functions */
    ldr sp, _TEXT_PHY_BASE  /* setup temp stack pointer */
    sub sp, sp, #12
    mov fp, #0          /* no previous frame, so fp=0 */

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

    ldr r0, =0xff000fff
    bic r1, pc, r0      /* r0 <- current base addr of code */
    ldr r2, _TEXT_BASE      /* r1 <- original base addr in ram */
    bic r2, r2, r0      /* r0 <- current base addr of code */
    cmp     r1, r2                  /* compare r0, r1                  */
    beq     after_copy      /* r0 == r1 then skip flash copy   */

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

    ldr r0, =INF_REG_BASE
    ldr r1, [r0, #INF_REG3_OFFSET]
    cmp r1, #BOOT_NAND      /* 0x0 => boot device is nand */
    beq     nand_boot
    
    cmp r1, #BOOT_ONENAND   /* 0x1 => boot device is onenand */
    beq     onenand_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:
    mov r0, #0x1000
    bl  copy_from_nand
    b   after_copy

onenand_boot:
    bl  onenand_bl2_copy  /*goto 0x1010*/
    b   after_copy
//ly
second_mmcsd_boot:
    ldr   r3, =BOOT_MMCSD   
    ldr r0, =INF_REG_BASE
    str r3, [r0, #INF_REG3_OFFSET]
    
mmcsd_boot:
#ifdef CONFIG_CLK_1000_400_200
    ldr r0, =CMU_BASE
    ldr r2, =CLK_DIV_FSYS2_OFFSET
    ldr r1, [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)
    ldr r0, =CMU_BASE
    ldr r2, =CLK_DIV_FSYS1_OFFSET
    ldr r1, [r0, r2]
    orr r1, r1, #0x3
    str r1, [r0, r2]
#endif
    bl      emmc_uboot_copy
    b   after_copy

emmc441_boot:
#if defined(CONFIG_CLK_1000_400_200) || defined(CONFIG_CLK_1000_200_200) || defined(CONFIG_CLK_800_400_200)
    ldr r0, =CMU_BASE
    ldr r2, =CLK_DIV_FSYS3_OFFSET
    ldr r1, [r0, r2]
    orr r1, r1, #0x3
    str r1, [r0, r2]
#endif
    bl      emmc441_uboot_copy
//ly 20110824
    ldr   r0, =0x43e00000
    ldr   r1, [r0]
    ldr   r2, =0x2000
    cmp r1, r2
    bne  second_mmcsd_boot
    b   after_copy


nor_boot:
@   bl  read_hword
    b   after_copy

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

#if defined(CONFIG_ENABLE_MMU)
enable_mmu:
    /* enable domain access */
    ldr r5, =0x0000ffff
    mcr p15, 0, r5, c3, c0, 0       @load domain access register

    /* Set the TTB register */
    ldr r0, _mmu_table_base
    ldr r1, =CFG_PHY_UBOOT_BASE
    ldr r2, =0xfff00000
    bic r0, r0, r2
    orr r1, r0, r1
    mcr p15, 0, r1, c2, c0, 0

    /* Enable the MMU */
mmu_on:
    mrc p15, 0, r0, c1, c0, 0
    orr r0, r0, #1
    mcr p15, 0, r0, c1, c0, 0
    nop
    nop
    nop
    nop
#endif

设置mmu,使能mmu

stack_setup:
#if defined(CONFIG_MEMORY_UPPER_CODE)
    ldr sp, =(CFG_UBOOT_BASE + CFG_UBOOT_SIZE - 0x1000)
#else
    ldr r0, _TEXT_BASE      /* upper 128 KiB: relocated uboot   */
    sub r0, r0, #CONFIG_SYS_MALLOC_LEN  /* malloc area                      */
    sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo                        */
#if defined(CONFIG_USE_IRQ)
    sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
#endif
    sub sp, r0, #12     /* leave 3 words for abort-stack    */

#endif

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

clear_bss:
    ldr r0, _bss_start      /* find start of bss segment        */
    ldr r1, _bss_end        /* stop here                        */
    mov     r2, #0x00000000     /* clear                            */

clbss_l:
    str r2, [r0]        /* clear loop...                    */
    add r0, r0, #4
    cmp r0, r1
    ble clbss_l
    
    ldr pc, _start_armboot

_start_armboot:
    .word start_armboot

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

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

  1. 设置异常向量(exception vector)
  2. 关闭IRQ、FIQ,设置SVC模式
  3. 关闭缓存、MMU
  4. 确定启动方式
  5. lowlevel_init(主要初始化系统时钟、SDRAM初始化、串口初始化等)
  6. 设置开发板供电锁存
  7. 设置内存中的栈
  8. 将uboot从EMMC拷贝到内存中
  9. 设置并开启MMU
  10. 通过对内存整体使用规划,在内存中合适的地方设置栈
  11. 清除bss段,远跳转到start_armboot执行,u-boot第一阶段执行完

u-boot分析与使用(代码片段)

文章目录一、u-boot介绍二、u-boot源码结构三、u-boot打补丁、编译、烧写四、uboot功能、结构,结合Makefile进行分析五、u-boot分析之源码阶段六、u-boot分析之命令实现七、uboot启动内核一、u-boot介绍u-boot即通用的BootLoader,是... 查看详情

u-boot之nand启动与nor启动的区别(代码片段)

nand启动与nor启动的区别主要分为以下几部分说明:1、nandflash与norflash的最主要区别2、s3c2440的nand启动与nor启动原理3、nand启动与nor启动的时候uboot做了什么 1、在JZ2440开发板上有两种Flash,分别为nandflash和norflash。这两种flash的... 查看详情

内核如何启动根文件系统?

当u-boot開始运行bootcmd命令,就进入Linux内核启动阶段。与u-boot类似,普通Linux内核的启动过程也能够分为两个阶段,但针对压缩了的内核如uImage就要包含内核自解压过程了。本文以linux-2.6.37版源代码为例分三个阶段来描写叙述内... 查看详情

u-boot启动流程分成哪两个阶段?分别要完成哪些功能

第一阶段(汇编):设置中断向量表、设置cpu模式为svc、关中断、关mmu、关D-Cache、初始化系统时钟、内存、网卡、串口、设置堆栈,将第二阶段代码搬移到内存,清空BSS段、跳转执行第二阶段代码第二阶段(c):初始化外设、进... 查看详情

u-boot.2012.10——mini2440(启动流程分析)

...ails/72399491、第一阶段功能  *硬件设备初始化  *加载u-boot第二段代码到RAM空间  *设置好栈  *跳转到第二段代码入口2、第二段代码的功能  *初始化本阶段使用的硬件设备  *检测系统的内存映射  *将内核从Flash读... 查看详情

第一阶段复习(代码片段)

...什么?计算机三大组成?应用程序操作系统硬件应用程序的启动和操作系统的启动?编程语言分类机器语言汇编语言高级语言解释型语言编译型语言执行Pyt 查看详情

linux学习:uboot移植

U-Boot启动内核的过程可以分为两个阶段,两个阶段的功能如下: 1)第一阶段的功能硬件设备初始化加载U-Boot第二阶段代码到RAM空间设置好栈跳转到第二阶段代码入口 2)第二阶段的功能初始化本阶段使用的硬件设备检测... 查看详情

u-boot-2014-07代码流程分析

前言以前接触到的u-boot启动方式只有Flash和NandFlash这两种方式,最近接触是SD卡启动方式,SoC是S5P4418,启动方式也第一次接触到,根据S5P4418用户手册可以找到系统使用SD卡启动时,片内iROM内固化的代码会自动映射到0x00地址,也... 查看详情

[firefly-rk3399]u-boot配置u盘启动(代码片段)

...直接启动U盘中的BootLoader,因此需要别的存储媒介在U-Boot阶段读取U盘中的内核。下面是U-Boot代码中U盘启动的代码部分,位于arch/arm/mach-rockchip/board.c:#ifdefCONFIG_ROCKCHIP_USB_BOOTstaticintboot_from_udis 查看详情

u-boot代码分析--第一节(代码片段)

u-boot代码分析--第一节编者:weirdo时间:2020-5-12QQ:2651293248标题:u-boot代码分析第一节1.u-boot.lds文件?? 这里指的是顶层目录下面的u-boot.lds,这里需要注意的是这个文件是根据arch/arm/cpu/armvx/对应的u-boot.lds模板生成的,在不严格的... 查看详情

uboot启动第一阶段详解——汇编代码部分start.s(代码片段)

...是uboot启动的第一句代码。详细介绍可以看博客:《u-boot的链接脚本分析》。2、16字节的头信息填充#ifdefined(CONFIG_EVT1)&&!defined(CONFIG_FUSED) .word0x2000 .word0x0 .word0x0 .word0x0#endifS5PV210的uboot要求有16字节的头信息,里面会放... 查看详情

tiny4412u-boot分析u-boot启动流程

从大方面来说,u-boot的启动分成两个阶段,第一个阶段主要的职责是准备初始化的环境,主要有以下几点①设置异常向量表②把CPU的工作模式设置为SVC32模式③关闭中断、MMU和cache④关闭看门狗⑤初始化内存、时钟、串口⑥设置... 查看详情

uboot启动第一阶段分析(代码片段)

...oot第一阶段初识  1.1.什么是uboot第一阶段    1.1.1.启动os三个阶段      1.1.1.1.bl0阶段        a.这段代码是三星固化到iROM中,可以查看《S5PV210_iROM_ApplicationNote_Preliminary_20091126.pdf》        b.这段... 查看详情

u-boot分析与使用(代码片段)

文章目录一、u-boot介绍二、u-boot源码结构三、u-boot打补丁、编译、烧写四、uboot功能、结构,结合Makefile进行分析五、u-boot分析之源码阶段六、u-boot分析之命令实现七、uboot启动内核一、u-boot介绍u-boot即通用的BootLoader,是... 查看详情

u-boot内核启动(代码片段)

目录u-boot(五)内核启动概述分区空间内核文件格式内核复制跳转内核启动机器ID启动参数(起始tag)setup_start_tag内存设置根文件系统,启动程序,串口设备(结束)setup_end_tagtitle:u-boot(五)内核启动tags:linuxdate:2018-09-2619:58:05---u-boot(五)内核启... 查看详情

红队视角下的防御体系突破之第一篇介绍阶段方法(代码片段)

...三、红队的组成0x02红队三板斧——攻击的三个阶段一、第一阶段:情报收集二、第二阶段:建立据点三、第三阶段:横向移动0x03红队也套路——常用的攻击战术一、利用弱口令获得权限二、利用社工来进入内网三、... 查看详情

uboot启动过程(代码片段)

uboot运行有两个阶段,一个阶段是运行在SRAM中的汇编阶段,另一个是运行在DDR中的C语言阶段。我们先进行第一阶段的分析。start.S文件start.S文件组成了uboot的第一阶段运行内容,在链接脚本中的代码段中第一句链接的s... 查看详情

uboot启动第二阶段——c语言(代码片段)

...c;也就是uboot启动第一阶段的起始。不清楚的参考:《u-boot的链接脚本分析》和《uboot启动第一阶段详解——汇编代码部分start.S》。补充:bss段不需要重定位。3、通过函数指针数组的方式执行初始化函数//函数指针类型type... 查看详情