Start.S引入
u-boot.lds中找到start.S入口
(1)在C语言中整个项目的入口就是main函数,所以譬如说一个有10000个.c文件的项目,第一要分析的文件就是包含了main函数的那个文件
(2)在uboot中因为有汇编阶段参与,因此不能直接找main.c,整个程序的入口取决于链接脚本中ENTRY声明的地方。ENTRY(_start)因此 _start符号所在的文件就是整个程序的起始文件,_start所在的代码就是整个程序的起始代码。
SourceInsight中如何找到文件
(1)当前状况:我们知道在uboot中的1000多个文件中有一个符号叫_start。但是我们不知道这个符号在哪个文件中。这种情况下找一个符号所在项目中文件中的引用。要使用SourceInsight的搜索功能。
(2)搜索栏所在的位置
分析我们搜索出我们_start的内容,2个API和2个onenand,还有一个我们本地解压出来的,都不是我们需要的_start,剩下3个的都在uboot/cpu/s5pc11x/start.s文件中,然后进入其中,于是乎找到了整个uboot的入口代码,就是58行
(3)设置显示行号
不简单的头文件包含
(1)以上,找到了start.S文件,下面我们就从start.S文件开始分析uboot第一阶段
(2)在SI中,如果我们知道我们要找的文件的名字,但是我们不知道他在哪个目录下,我们要怎样找到并打开这个文件?方法是在SI中先打开右边的工程项目管理栏目,然后点击最左边的那个(这个是以文件为单位来浏览的),然后在上面输入栏输入想要找的文件的名字。我们输入的时候,SI在不断帮我们进行匹配,即使不记得文件的全名只是大概记得名字,也能帮助你找到你要找的文件。
start.S解析1
头文件包含
(1)#include <config.h> 。config.h是在include目录下的,这个文件不是源码中本身存在的文件,而是配置过程中自动生成的文件。(前面的mkconfig脚本中有讲解)。这个文件的内容其实是包含了一个头文件:#include<config/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-BOOT 1.3.4”。这里面定义的宏U_BOOT_VERSION的值是一个字符串,字符串中的版本号信息来自于 Makefile 中的配置值,这个宏在程序中会被调用,在uboot启动过程中会串口打印出uboot的版本号,那个版本号就是从这里来的。
(4)#include <asm/proc/domain.h>。asm目录不是uboot中的原生目录,uboot中本来是没有这个目录的。asm目录时配置时创建的一个符号链接,实际指向的是asm-arn(详解上一章分析mkconfig脚本时)
(5)经过分析后可以看出,实际文件是:include/asm-arm/proc-arm/domain.h
(6)从这可以看出之前配置创建的符号链接的作用,如果没有这些符号链接则编译时根本无法通过,因为找不到头文件
思考:为啥start.S不直接包含asm-arm/proc-armv/domain.h,而要用asm/proc/domain.h。这样的设计主要是为了可移植性。因为直接包含,那么我们的start.s和CPU的架构(硬件)有关了,可移植性变差。譬如我要把uboot移植到mips架构下,则start.S源代码中所有的头文件包含全部要修改。我们用了符号链接之后,则start.S源代码不需修改,只需要在具体的硬件移植时配置不同,创建的符号链接指向不同,则可以具有可移植性。
start.S解析2
启动代码的16字节头部
#if defined(CONFIG_EVT1) && !defined(CONFIG_FUSED)
.word 0x2000
.word 0x0
.word 0x0
.word 0x0
#endif
(1)裸机上说过,在SD卡启动/Nand启动等整个镜像开头需要字节的校验头。(mkv210imag.c中就是为了计算这个校验头)。我们以前做裸机程序时根本没考虑这16字节校验头,因为:1.如果我们是usb启动直接下载的方式启动的则不需要16字节的校验头(irom application note);2.如果是SD卡启动mkv210imag.c中会给原镜像前加16字节的校验头。
(2)uboot这里start.S中开头位置放了16字节的填充占位,这个占位的16字节只是保证了正式的imag的头部确实有16字节,但是这16字节的内容是不对的,只是需要后面去计算校验和然后重新填充的。
在C110-EVT1-mkbl1.c文件下对校验码的计算
异常向量表
(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
有意思的deafbeef,
(1)16,0xdeadbeef,字面意思是坏牛肉,无实际意义。
//字节对齐,以16字节对齐,如果没有对齐,以后面来进行填充
.balignl 16,0xdeadbeef
TEXT_BASE
(1)第100行的这个TEXT_BASE就是上个课程中分析Makefile时讲到的那个配置阶段的TEXT_BASE,其实就是我们链接是指定的uboot的链接地址,(值就是c3e0000)
(2)源代码中和配置Makefile中很多变量是可以相互使用的,简单来说就是有些符号的值可以从Makefile中传递到源代码中。
//相当于定义一个4字节的指针,以后我们可以通过ldr加载_TEXT_BASE,从而直接加载TEXT_BASE的值,汇编的使用技巧
_TEXT_BASE://这个是名称,标号
.word//这个是4字节的类型的 TEXT_BASE//这个是变量
start.S解析3
(1)CFG_PHY_UBOOT_BASE 33e00000,uboot在DDR中的物理地址,
_TEXT_PHY_BASE:
.word CFG_PHY_UBOOT_BASE
(2)和中断相关的
#if defined(CONFIG_USE_IRQ)
/* IRQ stack memory (calculated at run-time) */
.globl IRQ_STACK_START
IRQ_STACK_START:
.word 0x0badc0de
/* IRQ stack memory (calculated at run-time) */
.globl FIQ_STACK_START
FIQ_STACK_START:
.word 0x0badc0de
#endif
设置CPU为SVC模式
(1)设置CPU设置为FIQ,IRQ,ARM状态,SVC模式
msr cpsr_c, #0xd3 @ I & F disable, Mode: 0x13 - SVC
(2)其实CPU在复位就会进入SVC模式,但是这里还是使用软件将其设置为SVC模式,整个在uboot工作时CPU一直处于SVC模式下。
设置L2,L1cache和MMU
(1) bl disable_l2cache //禁止L2 cache
(2) bl set_l2cache_auxctrl_cycle// L2 cache相关初始化
(3) bl enable_l2cache//使能L2 cache
(4) Invalidate L1 I/D 刷新cache的icache和dcache,icache是我们的指令cache,dcache是我们的数据cache
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
(5)关闭MMU
mrc p15, 0, r0, c1, c0, 0
bic r0, r0, #0x00002000 @ clear bits 13