uboot:源码分析-启动第一阶段-start.S解析

news2024/11/15 9:36:49

start.S引入

进入start.S文件中,发现57行中就是_start标号的定义处

在这里插入图片描述

SourceInsight中添加行号

在这里插入图片描述
在SI中,如果我们知道我们要找的文件的名字,但是我们又不知道他在哪个目录下,我们要怎样找到并打开这个文件?方法是在SI中先打开右边的工程项目管理栏目,然后点击最左边那个(这个是以文件为单位来浏览的),然后在上面输入栏中输入要找的文件的名字。我们在输入的时候,SI在不断帮我们进行匹配,即使你不记得文件的全名只是大概记得名字,也能帮助你找到你要找的文件。

在这里插入图片描述

start.S解析

不简单的头文件包含

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

#ifndef CONFIG_ENABLE_MMU
#ifndef CFG_PHY_UBOOT_BASE
#define CFG_PHY_UBOOT_BASE    CFG_UBOOT_BASE
#endif
#endif

(1)#include <config.h>。config.h是在include目录下的,这个文件不是源码中本身存在的文件,而是配置过程中自动生成的文件。mkconfig文件的134-141行创建(默认情况)/追加(make -a时追加)include/config.h文件,这里仅仅添加了一个头文件。这个文件的内容其实是包含了一个头文件:#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,这个头文件就是配置过程中自动生成的。version_autogenerated.h里面就一行内容:#define U_BOOT_VERSION “U-Boot 1.3.4”。这里面定义的宏U_BOOT_VERSION的值是一个字符串,字符串中的版本号信息来自于Makefile中的配置值。这个宏在程序中会被调用,在uboot启动过程中会串口打印出uboot的版本号,那个版本号信息就是从这来的。
主Makefile的29行VERSION_FILE = $(obj)include/version_autogenerated.h:版本信息将被写入到构建输出目录的include子目录下名为version_autogenerated.h的文件中。编译过后的目录当中才会有这个文件,内容是编译过后的版本号

在这里插入图片描述

(4)#include <asm/proc/domain.h>。asm目录不是uboot中的原生目录,uboot中本来是没有这个目录的。asm目录是配置时创建的一个符号链接,实际指向的是就是asm-arm,在mkconfig文件的第33行到第118行都是创建符号链接
在这里插入图片描述
(5)经过分析后发现,实际文件是:include/asm-arm/proc-armv/domain.h

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

这样的设计主要是为了可移植性。因为如果直接包含,则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

1.#if defined(CONFIG_EVT1) && !defined(CONFIG_FUSED)
:这是一个预处理条件指令。它检查CONFIG_EVT1是否已定义(即是否在代码的某处通过#define CONFIG_EVT1进行了定义),并且检查CONFIG_FUSED是否未定义(即没有通过#define CONFIG_FUSED进行定义)。只有当这两个条件同时满足时,紧随其后的代码块才会被编译。
2…word 0x2000
、.word 0x0、.word 0x0、.word 0x0:这四行代码是汇编语言指令,用于在生成的机器代码中插入字面量值。.word指令通常用于在内存中分配一个或多个字(word)的空间,并将指定的值存储在那里。在这个例子中,它分配了四个连续的32位(或相应大小的)空间,并分别初始化为0x2000、0x0、0x0、0x0。
3.#endif
:这标志着预处理条件指令的结束。

在SD卡启动/Nand启动等整个镜像开头需要16字节的校验头。(mkv210image.c中就是为了计算这个校验头)。

uboot这里start.S中在开头位置放了16字节的填充占位,这个占位的16字节只是保证正式的image的头部确实有16字节,但是这16字节的内容是不对的,还是需要后面去计算校验和然后重新填充的。

/home/aa/work0630/pro/uboottest/uboot/sd_fusing/C110-EVT1-mkbl1.c 内容就是mkv210image.c的内容

在这里插入图片描述
在这里插入图片描述

异常向量表的构建

    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

ldr pc, _label指令的意思是“将标签_label所代表的地址加载到程序计数器(PC)中。

1._undefined_instruction
:未定义指令异常。当执行了一条未定义的指令时,会跳转到这个地址。
2._software_interrupt
:软件中断。这是由软件触发的中断,通常用于操作系统或应用程序之间的通信。
3._prefetch_abort
:预取中止异常。当ARM处理器试图预取一条指令,但由于某种原因(如内存访问权限问题)无法完成时,会发生这种异常。
4._data_abort
:数据中止异常。当处理器试图访问数据(而不是指令)时,由于某种原因(如内存访问权限问题)无法完成,会发生这种异常。
5._not_used
:未使用的异常向量。在ARMv6及更早的版本中,这个位置是保留的,没有被使用。
6._irq
:IRQ(中断请求)异常。这是由外部设备或内部定时器触发的硬件中断。
7._fiq
:FIQ(快速中断请求)异常。这是另一种硬件中断,但优先级高于IRQ,通常用于需要快速响应的情况。

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

有点意思的deadbeef

    .balignl 16,0xdeadbeef

.balignl 16,0xdeadbeef 这条指令是ARM汇编语言中的一条伪指令,用于在代码中插入对齐填充,以确保后续的代码或数据位于一个特定的地址对齐。
具体来说:

  • .balignl 是指示进行长字(long word,即4字节或32位)对齐的伪指令。
  • 16 表示对齐的边界,即对齐到16字节(128位)的边界上。
  • 0xdeadbeef 是一个填充值,用于在对齐过程中填充到内存中,以确保对齐。这个值通常是一个魔数(magic number),用于调试或标记对齐位置。

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

TEXT_BASE等

_TEXT_BASE:
    .word    TEXT_BASE
  • _TEXT_BASE:
    是一个标签,它通常用于表示一个代码段或者数据段的起始地址。在链接(linking)过程中,这个标签会被替换成一个具体的内存地址。
  • .word
    是一条伪指令,用于在当前位置插入一个32位的字(word)。这个字的内容就是紧跟在 .word 后面的表达式或立即数的值。
  • TEXT_BASE
    是一个符号(symbol),它代表了一个具体的数值或者地址。这个符号在链接过程中会被解析成一个具体的地址值。

(1)第100行这个TEXT_BASE就是上个课程中分析Makefile时讲到的那个配置阶段的TEXT_BASE,其实就是我们链接时指定的uboot的链接地址。(值就是c3e00000)
TEXT_BASE变量。最终来源是Makefile中配置对应的命令中,在make xxx_config时得到的
关联知识点:指定程序的链接地址有2种方法
(2)源代码中和配置Makefile中很多变量是可以互相运送的。简单来说有些符号的值可以从Makefile中传递到源代码中。

_TEXT_PHY_BASE:
    .word    CFG_PHY_UBOOT_BASE
#define CFG_PHY_UBOOT_BASE    MEMORY_BASE_ADDRESS + 0x3e00000
#define MEMORY_BASE_ADDRESS    0x30000000

(1)CFG_PHY_UBOOT_BASE 33e00000 uboot在DDR中的物理地址
虚拟地址是C3e00000

设置CPU为SVC模式

在这里插入图片描述

msr    cpsr_c, #0xd3        @ I & F disable, Mode: 0x13 - SVC
  • msr 是 Move to Special Register 的缩写,表示将数据移动到特殊寄存器。
  • cpsr_c 表示当前程序状态寄存器的控制域。CPSR 是一个32位的寄存器,包含了当前处理器的状态和模式信息。其中,c域(控制域)包含了中断(I)和快中断(F)的使能位。
  • #0xd3 是一个立即数,表示要写入c域的值。在ARM架构中,寄存器的值通常以十六进制表示。
  • @ I & F disable, Mode: 0x13 - SVC 是一条注释,解释了这条指令的作用:禁用中断(I)和快中断(F),并将处理器模式设置为0x13,即SVC(Supervisor)模式。
    具体来说,#0xd3 这个值包含了处理器模式和中断使能位的信息。在ARM架构中,CPSR的M[4:0]位用于表示处理器模式,而I位和F位用于控制中断和快中断的使能。
  • M[4:0] = 0x13 表示处理器处于SVC模式。
  • I = 1 表示禁用中断。
  • F = 1 表示禁用快中断(在某些ARM版本中,F位可能用于其他目的,但在这里我们假设它用于控制快中断)。

(1)msr cpsr_c, #0xd3 将CPU设置为禁止FIQ IRQ,ARM状态,SVC模式。
(2)其实ARM 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)刷新L1 cache的icache和dcache。
(5)关闭MMU
总结:上面这5步都是和CPU的cache和mmu有关的,不用去细看,大概知道即可。

识别并暂存启动介质选择

        ldr    r0, =PRO_ID_BASE
        ldr    r1, [r0,#OMR_OFFSET]
        bic    r2, r1, #0xffffffc1

(1)从哪里启动是由SoC的OM5:OM0这6个引脚的高低电平决定的。
(2)实际上在210内部有一个寄存器(地址是0xE0000004),这个寄存器中的值是硬件根据OM引脚的设置而自动设置值的。这个值反映的就是OM引脚的接法(电平高低),也就是真正的启动介质是谁。
(3)我们代码中可以通过读取这个寄存器的值然后判断其值来确定当前选中的启动介质是Nand还是SD还是其他的。
(4)start.S的225-227行执行完后,在r2寄存器中存储了一个数字,这个数字等于某个特定值时就表示SD启动,等于另一个特定值时表示从Nand启动····
(5)260行中给r3中赋值#BOOT_MMCSD(0x03),这个在SD启动时实际会被执行,因此执行完这一段代码后r3中存储了0x03,以后备用。

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

设置栈(SRAM中的栈)并调用lowlevel_init

    /*
     * Go setup Memory and board specific bits prior to relocation.
     */

    ldr    sp, =0xd0036000 /* end of sram dedicated to u-boot */
    sub    sp, sp, #12    /* set stack */
    mov    fp, #0

(1)284-286行第一次设置栈。这次设置栈是在SRAM中设置的,因为当前整个代码还在SRAM中运行,此时DDR还未被初始化还不能用。栈地址0xd0036000是自己指定的,指定的原则就是这块空间只给栈用,不会被别人占用。
(2)在调用函数前初始化栈,主要原因是在被调用的函数内还有再次调用函数,而BL只会将返回地址存储到LR中,但是我们只有一个LR,所以在第二层调用函数前要先将LR入栈,否则函数返回时第一层的返回地址就丢了。

学习记录,侵权联系删除。
来源:朱老师物联网大课堂

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2150328.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

多重指针变量(n重指针变量)实例分析

0 前言 指针之于C语言&#xff0c;就像子弹于枪械。没了子弹的枪械虽然可以用来肉搏&#xff0c;却失去了迅速解决、优雅解决战斗的能力。但上了膛的枪械也非常危险&#xff0c;时刻要注意是否上了保险&#xff0c;使用C语言的指针也是如此&#xff0c;要万分小心&#xff0c;…

usemeno和usecallback区别及使用场景

1. useMemo 用途: useMemo 用于缓存计算结果。它接受一个函数和依赖项数组&#xff0c;只有当依赖项发生变化时&#xff0c;才会重新计算该函数的返回值。否则&#xff0c;它会返回缓存的值。 返回值: useMemo 返回的是函数执行后的结果。 使用场景: 当一个计算量大的函数在每…

Java面试篇基础部分-线程的基本方法

线程的基本方法有wait()、notify()、notifyAll()、sleep()、join()、yield()等等,这些方法都是用来控制线程的运行,并且可以实质性的影响到线程的状态变化情况。 让线程等待的方法:wait()方法 调用wait()方法的线程会进入到WAITING状态,只有等到其他线程通知或者线程被中…

【数据结构-差分】力扣1589. 所有排列中的最大和

有一个整数数组 nums &#xff0c;和一个查询数组 requests &#xff0c;其中 requests[i] [starti, endi] 。第 i 个查询求 nums[starti] nums[starti 1] … nums[endi - 1] nums[endi] 的结果 &#xff0c;starti 和 endi 数组索引都是 从 0 开始 的。 你可以任意排列…

【Java面向对象二】static的注意事项

文章目录 前言一、关于static的三个注意点总结 前言 记录static的学习注意事项。 一、关于static的三个注意点 1、类方法中可以直接访问类的成员&#xff0c;不可用直接访问实例成员。 2、实例方法中既可以直接访问类成员&#xff0c;也可以直接访问实例成员。 3、实例方法…

105.WEB渗透测试-信息收集-FOFA语法(5)

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a; 易锦网校会员专享课 上一个内容&#xff1a;104.WEB渗透测试-信息收集-FOFA语法&#xff08;4&#xff09; 还有一个能查看信息的地方…

linux下的分布式Minio部署实践

Linux下的分布式Minio部署实践 分布式Minio部署可以将多块硬盘&#xff08;位于相同机器或者不同机器&#xff09;组成一个对象存储服务&#xff0c;避免单机环境下硬盘容量不足、单点故障等问题。 1. 简介 在当前的云计算和大数据时代&#xff0c;IT系统通常的设计理念都是…

英伟达Jim Fan预测:未来2~3年机器人将迎来“GPT-3时刻”

在这个科技不断进步的时代&#xff0c;我们终将迎来“与机器人共存”的未来。你认为&#xff0c;未来会是人机和平共处&#xff0c;还是《终结者》式未来&#xff1f; 随着科技发展&#xff0c;这个未来似乎近在咫尺。昨日外媒 The Decoder 发文报道&#xff0c;在最近的一次红…

Jenkins自动化部署后端项目看这篇就够了

本文主要讲解&#xff0c;使用Jenkins自动化部署后端工程。讲解怎么自动化部署前后的分离项目中的后端工程。 前提条件&#xff1a;本地需要Jenkins&#xff0c;如果你不知道怎么安装&#xff0c;可以看我的另外一篇文章。 Jenkins实现自动部署的步骤&#xff1a; 先拉取git…

Jboss 低版本JMX Console未授权

漏洞描述 此漏洞主要是由于JBoss中/jmx-console/HtmlAdaptor路径对外开放&#xff0c;并且没有任何身份验证机制&#xff0c;导致攻击者可以进⼊到 jmx控制台&#xff0c;并在其中执⾏任何功能。 影响范围 Jboss4.x以下 环境搭建 cd vulhub-master/jboss/CVE-2017-7504 d…

力扣题解2414

大家好&#xff0c;欢迎来到无限大的频道。 今日继续给大家带来力扣题解。 题目描述&#xff08;中等&#xff09;&#xff1a; 最长的字母序连续字符串的长度 ​ ​字母序连续字符串 是由字母表中连续字母组成的字符串。换句话说&#xff0c;字符串 "abcdefghijklm…

linux 最简单配置免密登录

需求&#xff1a;两台服务器互信登录需要拉起对端服务 ip&#xff1a; 192.168.1.133 192.168.1.137 一、配置主机hosts&#xff0c;IP及主机名&#xff0c;两台都需要 二、192.168.1.137服务器&#xff0c;生成密钥 ssh-keygen -t rsa三、追加到文件 ~/.ssh/authorized_key…

分布式中间件-Pika一个高效的分布式缓存组件

文章目录 Pika简介Pika特性Pika解决的问题及应用场景Pika架构之存储引擎部署模式1、主从模式2、分布式集群模式 Pika快速上手1、二进制包方式2、源码编译方式2.1 支持的平台2.2 依赖的库软件2.3 编译过程2.4 启动 Pika2.5 清空已编译的结果2.6 Pika 的开发调试 3、容器化3.1 使…

【2025】儿童疫苗接种预约小程序(源码+文档+解答)

博主介绍&#xff1a; ✌我是阿龙&#xff0c;一名专注于Java技术领域的程序员&#xff0c;全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师&#xff0c;我在计算机毕业设计开发方面积累了丰富的经验。同时&#xff0c;我也是掘金、华为云、阿里云、InfoQ等平台…

【C++指南】inline内联函数详解

&#x1f493; 博客主页&#xff1a;倔强的石头的CSDN主页 &#x1f4dd;Gitee主页&#xff1a;倔强的石头的gitee主页 ⏩ 文章专栏&#xff1a;《C指南》 期待您的关注 目录 引言 C为什么引入了inline来替代C语言中的宏 inline的基本用法 定义inline函数 inline的优势与…

DAY20信息打点-红蓝队自动化项目资产侦察武器库部署企查产权网络空间

2.自动化-网络空间-AsamF 1.去GitHub上下载项目之后使用CMD打开 2.输入命令AsamF_windows_amd64.exe -v生成配置文件 3.AsamF会在~/.config/asamf/目录下生成config.json文件 C:\Users\Acer\.config\asamf 5.根据文档输入命令去查询所需信息&#xff08;已经没有用了&#x…

C/C++通过CLion2024进行Linux远程开发保姆级教学

目前来说&#xff0c;对Linux远程开发支持相对比较好的也就是Clion和VSCode了&#xff0c;这两个其实对于C和C语言开发都很友好&#xff0c;大可不必过于纠结使用那个&#xff0c;至于VS和QtCreator&#xff0c;前者太过重量级了&#xff0c;后者更是不用说&#xff0c;主要用于…

解锁自动化新境界:KeymouseGo,让键盘和鼠标动起来!

文章目录 解锁自动化新境界&#xff1a;KeymouseGo&#xff0c;让键盘和鼠标动起来&#xff01;背景&#xff1a;为何选择KeymouseGo&#xff1f;KeymouseGo简介安装KeymouseGo简单函数使用应用场景常见问题与解决方案总结 解锁自动化新境界&#xff1a;KeymouseGo&#xff0c;…

ISSTA 2024现场精彩:“杰出论文奖”超半数属于中国学者

ISSTA会议是软件工程领域中最具影响力的国际会议之一&#xff0c;也是中国计算机学会&#xff08;CCF&#xff09;推荐的A类会议。 第33届ISSTA会议已于奥地利维也纳圆满结束&#xff0c;这场盛会已经吸引了众多来自学术界和工业界的软件测试专家、研究人员和工程师&#xff0c…

学习C++的第三天!

C对C的函数部分的扩充 封装 #include <iostream> #include <memory.h> #include <stdlib.h> #include <string.h> using namespace std; using datatype int; //封装一个顺序表 class SeqList { private:datatype* ptr; //指向堆区空间的起始…