uboot之start.s分析1

注:本文是学习朱老师课程整理的笔记,基于uboot-1.3.4和s5pc11x分析。

由uboot.lds链接脚本,我们知道整个程序的入口取决于中ENTRY声明的地方。

ENTRY(_start)

因此_start符号所在的文件就是整个程序的起始文件,_start所在的代码就是整个程序的起始代码。
_start在start.s中的内容:

.globl _start
_start: b   reset

在start.s的一开始是头文件的包含:

#include 
#include 
#if defined(CONFIG_ENABLE_MMU)
#include 
#endif
#include 

#include :config.h是在include目录下的,是配置过程中自动生成的文件(详见mkconfig脚本)。这个文件的内容其实是包含了一个头文件:

#include"

因此,#include 就是:include/configs/x210_sd.h,这个文件里面是好多宏,整个uboot移植时的配置文件。比如上面的CONFIG_ENABLE_MMU就可以去x210_sd.h的文件中查找是否有定义。

#include :在include/version.h中包含了include “version_autogenerated.h”这一句,这个头文件就是配置过程中自动生成的。里面就一行内容:#define U_BOOT_VERSION “U-Boot 1.3.4”。这里面定义的宏U_BOOT_VERSION的值是一个字符串,字符串中的版本号信息来自于Makefile中的配置值。这个宏在程序中会被调用,在uboot启动过程中会串口打印出uboot的版本号,那个版本号信息就是从这来的。

#include :asm目录不是uboot中的原生目录,uboot中本来是没有这个目录的。asm目录是配置时创建的一个符号链接,实际指向的是就是asm-arm(详解见uboot下mkconfig脚本的分析)。而proc指向的是proc-armv目录,最终实际文件是:include/asm-arm/proc-armv/domain.h

#include 这个头文件也是配置过程中自动生成的,指向include/s5pc110.h。

从分析可以看出之前配置时创建的符号链接的作用,如果没有这些符号链接则编译时根本通不过,因为找不到头文件。(所以uboot不能在windows的共享文件夹下配置编译,因为windows中没有符号链接)

思考:为什么start.S不直接包含asm-arm/proc-armv/domain.h,而要用asm/proc/domain.h。

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

  • 启动代码的头16字节
#if defined(CONFIG_EVT1) && !defined(CONFIG_FUSED)
    .word 0x2000
    .word 0x0
    .word 0x0
    .word 0x0
#endif

.word是GNU汇编的伪汇编指令,相当于一个int类型。这里有4个.word,总共占据了16个字节。

在SD卡启动/Nand启动整个镜像,开头需要16字节的校验头。(mkv210image.c中就是为了计算这个校验头)。如果是usb启动直接下载的方式启动的则不需要16字节校验头(irom application note)。

这个占位的16字节只是保证正式的image的头部确实有16字节,但是这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

异常向量表是硬件决定的,软件只是参照硬件的设计来实现它。异常向量表中每种异常都应该被处理,否则真遇到了这种异常就跑飞了。但是在uboot中并未非常细致的处理各种异常。下面有这些向量异常的处理函数入口地址:

_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

复位异常处的代码是:b reset,因此在CPU复位后真正去执行的有效代码是reset处的代码,因此reset符号处才是真正意义上的代码开始的地方。其中 reset是一个标号,在start.s下面有:

/* the actual reset code*/
reset:
    /* set the cpu to SVC32 mode and IRQ & FIQ disable*/
    /*前面4句被注释掉*/
    @;mrs   r0,cpsr
    @;bic   r0,r0,#0x1f
    @;orr   r0,r0,#0xd3
    @;msr   cpsr,r0
    msr cpsr_c, #0xd3       @ I & F disable, Mode: 0x13 - SVC

其实ARM CPU在复位时默认就会进入SVC模式,但是这里还是使用软件将其置为SVC模式。整个uboot工作时CPU一直处于SVC模式。

_end_vect:
    .balignl 16,0xdeadbeef

.balignl 16,0xdeadbeef. 这一句指令是让当前地址16字节对齐,如果当前地址不对齐则自动向后走地址直到对齐,并且向后走的那些内存要用0xdeadbeef来填充。0xdeadbeef这是一个十六进制的数字,这个数字很有意思,刚好组成了英文的dead beef这两个单词,字面意思是坏牛肉。

_TEXT_BASE:
    .word   TEXT_BASE

TEXT_BASE就是Makefile配置阶段写入的TEXT_BASE值,其实就是我们链接时指定的uboot的链接地址。

_TEXT_PHY_BASE:
    .word   CFG_PHY_UBOOT_BASE #uboot在DDR中的物理地址
  • cpu_init_crit
cpu_init_crit:
    bl disable_l2cache              /*禁止L2 cache*/
    bl set_l2cache_auxctrl_cycle    /*l2 cache相关初始化*/
    bl enable_l2cache               /*使能l2 cache*/


   /* Invalidate L1 icache and dcache*/
   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, #0x00000002     @ set bit 1 (--A-) Align
   orr r0, r0, #0x00000800     @ set bit 12 (Z---) BTB
   mcr p15, 0, r0, c1, c0, 0

为什么上面的bic和orr指令都连续执行了2次。因为0x2007和0x802都是非法立即数,不可以直接操作。
上面这几步都是和CPU的cache和mmu有关的,不用去细看,大概知道即可。

  • 启动介质选择
  /* Read booting information */
        ldr r0, =PRO_ID_BASE         
        ldr r1, [r0,#OMR_OFFSET]     /* r1=0xE0000004 */
        bic r2, r1, #0xffffffc1 NAND BOOT */
    cmp r2, #0x0        @ 512B 4-cycle 
                        /* nand的页大小为512B,4个指令周期 */
    moveq   r3, #BOOT_NAND

    cmp r2, #0x2        @ 2KB 5-cycle
    moveq   r3, #BOOT_NAND

    cmp r2, #0x4        @ 4KB 5-cycle   8-bit ECC  
                       /* nand的页大小为4KB,5个指令周期,8位ECC校验 */
    moveq   r3, #BOOT_NAND

    cmp r2, #0x6        @ 4KB 5-cycle   16-bit ECC
    moveq   r3, #BOOT_NAND

    cmp r2, #0x8        @ OneNAND Mux
    moveq   r3, #BOOT_ONENAND

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

    /* NOR BOOT */
    cmp     r2, #0x14
    moveq   r3, #BOOT_NOR   

在x210内部有一个寄存器(地址是0xE0000004),这个寄存器中的值决定真正的启动介质是谁。这个寄存器中的值是硬件根据OM引脚的设置而自动设置值的。在r2寄存器中存储了一个数字,这个数字代表不同的启动介质,然后r3中存储相对应的数值,以后备用。

下面的分析见:uboot之start.s分析2

你可能感兴趣的:(uboot之start.s分析1)