uboot——启动第一阶段分析

本文详细分析了U-Boot启动的第一阶段,包括程序开始、Start.S文件解析、异常向量表构建、TEXT_BASE设置、启动介质识别、栈与lowlevel_init的调用、时钟和DDR初始化、串口初始化等步骤。第一阶段的重点工作包括异常处理、CPU模式设置、内存管理初始化、重定位以及MMU的启用,为后续第二阶段的执行做好准备。
摘要由CSDN通过智能技术生成

一、程序的开始
  在C语言中,main函数是整个程序的入口,这是规定。在uboot中因为有汇编参与,因此不能直接找main.c,整个程序的入口取决于中ENTRY声明的地方 ENTRY(_start),因此_start所在的文件就是整个程序的起始文件,所在的程序就是起始程序。
  
二、Start.S文件的分析

1、头文件包含

#include <config.h>
#include <version.h>
#if defined(CONFIG_ENABLE_MMU)
#include <asm/proc/domain.h>
#endif
#include <regs.h>

(1)#include <config.h>。config.h是在include目录下的,这个文件不是源码中本身存在的文件,而是配置过程中自动生成的文件。(详见mkconfig脚本)。这个文件的内容其实是包含了一个头文件:#include <configs/x210_sd.h>".
(2)经过分析后,发现start.S中包含的第一个头文件就是:include/configs/x210_sd.h,这个文件是整个uboot移植时的配置文件。这里面是很多宏。因此这个头文件将include/configs/x210_sd.h文件和start.S文件关联了起来。之后在分析start.S文件时,主要要考虑的就是x210_sd.h文件。
(3)#include <version.h>。include/version.h中包含了include/version_autogenerated.h,这个头文件就是配置过程中自动生成的。里面就一行内容:#define U_BOOT_VERSION "U-Boot1.3.4"。这里面定义的宏U_BOOT_VERSION的值是一个字符串,字符串中的版本号信息来自于Makefile中的配置值。这个宏在程序中会被调用,在uboot启动过程中会串口打印出uboot的版本号,那个版本号信息就是从这来的。
(4)#include <asm/proc/domain.h>。asm目录不是uboot中的原生目录,uboot中本来是没有这个目录的。asm目录是配置时创建的一个符号链接,实际指向的是就是asm-arm.经过分析后发现,实际文件是:include/asm-arm/proc-armv/domain.h
(5)从这里可以看出之前配置时创建的符号链接的作用,如果没有这些符号链接则编译时根本通不过,因为找不到头文件。(所以uboot不能在windows的共享文件夹下配置编译,因为windows中没有符号链接)

思考:为什么start.S不直接包含asm-arm/proc-armv/domain.h,而要用asm/proc/domain.h。这样的设计主要是为了可移植性。因为如果直接包含,则start
.S文件和CPU架构(和硬件)有关了,可移植性就差了。譬如我要把uboot移植到mips架构下,则start.S源代码中所有的头文件包含全部要修改。我们用了符号链接之后,则start.S中源代码不用改,只需要在具体的硬件移植时配置不同,创建的符号链接指向的不同,则可以具有可移植性。

2、启动代码的16字节头部
  在SD卡启动/Nand启动等整个镜像开头需要16字节的校验头。(mkv210image.c中就是为了计算这个校验头)。做裸机程序时根本没考虑这16字节校验头,因为:1、如果我们是usb启动直接下载的方式启动的则不需要16字节校验头(irom application note);2、如果是SD卡启动mkv210image.c中会给原镜像前加16字节的校验头。

 /*
  *启动代码的16字节头部,SD卡启动\Nand启动等整个镜像开头需要16字节的校验头。
  *mkv210image.c就是校验头。如果usb启动直接下载不需要校验头(irom application note),如果是SD卡启动
  *mkv210image.c中会给原镜像前加16字节的校验头。
  *uboot这里start.S中在开头位置放了16字节的填充占位,保证正式的image的头部确实有16字节,但目前这16
  *字节内容不对,需要后面去计算校验和重新填充。sd_fusing文件夹中计算。
  */
#if defined(CONFIG_EVT1) && !defined(CONFIG_FUSED)
    .word 0x2000
    .word 0x0
    .word 0x0
    .word 0x0
#endif

3、异常向量表的构建
(1)异常向量表是硬件决定的,软件只是参照硬件的设计来实现它。
(2)异常向量表中每种异常都应该被处理,否则真遇到了这种异常就跑飞了。但是我们在uboot中并未非常细致的处理各种异常。
(3)复位异常处的代码是:b reset,因此在CPU复位后真正去执行的有效代码是reset处的代码,因此reset符号处才是真正的有意义的代码开始的地方。

.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
_pad:
    .word 0x12345678 /* now 16*4=64 */
.global _end_vect
_end_vect:

    .balignl 16,0xdeadbeef
    /*有点意思的deadbeef
(1).balignl 16,0xdeadbeef.  这一句指令是让当前地址对齐排布,如果当前地址不对齐则自动向后走地址直到对齐,并且向后走的那些内存要用0xdeadbeef来填充。
(2)0xdeadbeef这是一个十六进制的数字,这个数字很有意思,组成这个数字的十六进制数全是abcdef之中的字母,而且这8个字母刚好组成了英文的dead beef这两个单词,字面意思是坏牛肉。
(3)为什么要对齐访问?有时候是效率的要求,有时候是硬件的特殊要求。*/

4、TEXT_BASE
(1)TEXT_BASE就是Makefile中配置阶段的TEXT_BASE,是链接时指定的uboot的链接地址。(值是c3e00000)
(2)源代码中和配置Makefile中很多变量是可以互相运送的。简单来说有些符号的值可以从Makefile中传递到源代码中。

_TEXT_BASE:
    .word   TEXT_BASE

5、CFG_PHY_UBOOT_BASE
  uboot在DDR中的物理地址 33e00000

_TEXT_PHY_BASE:
    .word   CFG_PHY_UBOOT_BASE

6、设置CPU为SVC模式
(1)msr cpsr_c, #0xd3 将CPU设置为禁止FIQ IRQ,ARM状态,SVC模式。
(2)其实ARM CPU在复位时默认就会进入SVC模式,但是这里还是使用软件将其置为SVC模式。整个uboot工作时CPU一直处于SVC模式。

reset:
    /*
     * set the cpu to SVC32 mode and IRQ & FIQ disable
     */
    @;mrs   r0,cpsr
    @;bic   r0,r0,#0x1f
    @;orr   r0,r0,#0xd3
    @;msr   cpsr,r0
    msr cpsr_c, #0xd3       @ I & F disable, Mode: 0x13 - SVC

7、设置L2、L1cache和MMU
1)bl disable_l2cache // 禁止L2 cache
(2)bl set_l2cache_auxctrl_cycle // l2 cache相关初始化
(3)bl enable_l2cache // 使能l2 cache
(4)刷新L1 cache的icache和dcache。
(5)关闭MMU
总结:上面这5步都是和CPU的cache和mmu有关的,不用去细看,大概知道即可。

cpu_init_crit:

#ifndef CONFIG_EVT1
#if 0   
    bl  v7_flush_dcache_all
#else
    bl  disable_l2cache

    mov r0, #0x0    @ 
    mov r1, #0x0    @ i 
    mov r3, #0x0
    mov r4, #0x0
lp1:
    mov r2, #0x0    @ j
lp2:    
    mov r3, r1, LSL #29     @ r3 = r1(i) <<29
    mov r4, r2, LSL #6      @ r4 = r2(j) <<6
    orr r4, r4, #0x2        @ r3 = (i<<29)|(j<<6)|(1<<1)
    orr r3, r3, r4
    mov r0, r3          @ r0 = r3
    bl  CoInvalidateDCacheIndex
    add r2, #0x1        @ r2(j)++
    cmp r2, #1024       @ r2 < 1024
    bne lp2         @ jump to lp2
    add r1, #0x1        @ r1(i)++
    cmp r1, #8          @ r1(i) < 8
    bne lp1         @ jump to lp1

    bl  set_l2cache_auxctrl

    bl  enable_l2cache
#endif
#endif

    bl  disable_l2cache

    bl  set_l2cache_auxctrl_cycle

    bl  enable_l2cache

       /*
        * Invalidate L1 I/D
        */
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值