RISC-V体系结构的U-Boot引导过程 第一阶段

news2024/11/24 2:05:43

RISC-V体系结构的U-Boot引导过程 第一阶段

flyfish

.globl _start
_start:

.globl使符号对链接器可见相当于C语言中的Extern,声明此变量,并且告诉链接器此变量是全局变量,外部可以访问.u-boot.lds里的ENTRY(_start)也是这里的_start。
即指定入口为_start,_start就是整个start.S的开始的地方,是整个uboot的代码的开始
_start:表示其是一个标号Label,类似于C语言goto后面的标号

在这里插入图片描述

#if CONFIG_IS_ENABLED(RISCV_MMODE)
	csrr	a0, CSR_MHARTID
#endif

RISCV_MMODE 就是 machine mode
RISCV_SMODE就是supervisor mode
依据

choice
	prompt "Run Mode"
	default RISCV_MMODE

config RISCV_MMODE
	bool "Machine"
	help
	  Choose this option to build U-Boot for RISC-V M-Mode.

config RISCV_SMODE
	bool "Supervisor"
	help
	  Choose this option to build U-Boot for RISC-V S-Mode.
#define CSR_MHARTID		0xf14

执行该语句csrr a0, CSR_MHARTID之后a0寄存器存储了hartid
依据下表
在这里插入图片描述

la	t0, trap_entry

la t0, trap_entry
LA是Load Address,语法是LA rd, symbol
la指令的格式,将内存地址symbol加载到rd寄存器中
trap_entry 可以看mtrap.S
这里是将trap_entry加载到临时寄存器t0中

#include <common.h>
#include <asm/encoding.h>

#ifdef CONFIG_32BIT
#define LREG		lw
#define SREG		sw
#define REGBYTES	4
#else
#define LREG		ld
#define SREG		sd
#define REGBYTES	8
#endif

	.text

	/* trap entry */
	.align 2
	.global trap_entry
trap_entry:
	addi sp, sp, -32 * REGBYTES
	SREG x1,   1 * REGBYTES(sp)
	SREG x2,   2 * REGBYTES(sp)
	SREG x3,   3 * REGBYTES(sp)
	SREG x4,   4 * REGBYTES(sp)
	SREG x5,   5 * REGBYTES(sp)
	SREG x6,   6 * REGBYTES(sp)
	SREG x7,   7 * REGBYTES(sp)
	SREG x8,   8 * REGBYTES(sp)
	SREG x9,   9 * REGBYTES(sp)
	SREG x10, 10 * REGBYTES(sp)
	SREG x11, 11 * REGBYTES(sp)
	SREG x12, 12 * REGBYTES(sp)
	SREG x13, 13 * REGBYTES(sp)
	SREG x14, 14 * REGBYTES(sp)
	SREG x15, 15 * REGBYTES(sp)
	SREG x16, 16 * REGBYTES(sp)
	SREG x17, 17 * REGBYTES(sp)
	SREG x18, 18 * REGBYTES(sp)
	SREG x19, 19 * REGBYTES(sp)
	SREG x20, 20 * REGBYTES(sp)
	SREG x21, 21 * REGBYTES(sp)
	SREG x22, 22 * REGBYTES(sp)
	SREG x23, 23 * REGBYTES(sp)
	SREG x24, 24 * REGBYTES(sp)
	SREG x25, 25 * REGBYTES(sp)
	SREG x26, 26 * REGBYTES(sp)
	SREG x27, 27 * REGBYTES(sp)
	SREG x28, 28 * REGBYTES(sp)
	SREG x29, 29 * REGBYTES(sp)
	SREG x30, 30 * REGBYTES(sp)
	SREG x31, 31 * REGBYTES(sp)
	csrr a0, MODE_PREFIX(cause)
	csrr a1, MODE_PREFIX(epc)
	csrr a2, MODE_PREFIX(tval)
	mv a3, sp
	jal handle_trap
	csrw MODE_PREFIX(epc), a0

	LREG x1,   1 * REGBYTES(sp)
	LREG x3,   3 * REGBYTES(sp)
	LREG x4,   4 * REGBYTES(sp)
	LREG x5,   5 * REGBYTES(sp)
	LREG x6,   6 * REGBYTES(sp)
	LREG x7,   7 * REGBYTES(sp)
	LREG x8,   8 * REGBYTES(sp)
	LREG x9,   9 * REGBYTES(sp)
	LREG x10, 10 * REGBYTES(sp)
	LREG x11, 11 * REGBYTES(sp)
	LREG x12, 12 * REGBYTES(sp)
	LREG x13, 13 * REGBYTES(sp)
	LREG x14, 14 * REGBYTES(sp)
	LREG x15, 15 * REGBYTES(sp)
	LREG x16, 16 * REGBYTES(sp)
	LREG x17, 17 * REGBYTES(sp)
	LREG x18, 18 * REGBYTES(sp)
	LREG x19, 19 * REGBYTES(sp)
	LREG x20, 20 * REGBYTES(sp)
	LREG x21, 21 * REGBYTES(sp)
	LREG x22, 22 * REGBYTES(sp)
	LREG x23, 23 * REGBYTES(sp)
	LREG x24, 24 * REGBYTES(sp)
	LREG x25, 25 * REGBYTES(sp)
	LREG x26, 26 * REGBYTES(sp)
	LREG x27, 27 * REGBYTES(sp)
	LREG x28, 28 * REGBYTES(sp)
	LREG x29, 29 * REGBYTES(sp)
	LREG x30, 30 * REGBYTES(sp)
	LREG x31, 31 * REGBYTES(sp)
	LREG x2,   2 * REGBYTES(sp)
	addi sp, sp, 32 * REGBYTES
	MODE_PREFIX(ret)
csrw	MODE_PREFIX(tvec), t0

根据定义

#if CONFIG_IS_ENABLED(RISCV_SMODE)
#define MODE_PREFIX(__suffix)	s##__suffix
#else
#define MODE_PREFIX(__suffix)	m##__suffix
#endif

MODE_PREFIX(tvec)就是mtvec或者stvec
mtvec(Machine Trap Vector)
中断(interrupt)和异常(exception)在RISCV里被统称为trap
在这里插入图片描述

csrw	MODE_PREFIX(ie), zero

机器模式中断使能控制寄存器(MIE)
机器模式中断使能控制寄存器(MIE)用于控制不同中断类型的使能和屏蔽。该寄存器的位长是 64 位,
寄存器的读写权限是机器模式可读写,即非机器模式访问都会导致非法指令异常。
MSIE-机器模式软件中断使能位:
• 当 MSIE 为 0 时,机器模式软件中断无效。
• 当 MSIE 为 1 时,机器模式软件中断有效

屏蔽所有中断。对于U-Boot,全局禁用中断(处于m/sstatus),但我们需要读取m/sip以确定是否获得IPI

MODE_PREFIX(ie) 就是mie或者sie
m/sstatus 表示mstatus和sstatus
mstatus表示Machine Status,M模式下的处理器状态寄存器
m/sip 表示 mip和sip
mip表示Machine Interrupt Pending, M模式下的中断待定寄存器
表示哪些中断处于待定(Pending,)状态
IPI,全称是Inter-Processor Interrupt,是在SoC内多个core之间触发的中断
在这里插入图片描述

li	t0, CONFIG_NR_CPUS
bge	tp, t0, hart_out_of_bounds_loop

缩写

Branch if equal (BEQ) 
Branch if not equal (BNE) 
Branch if less than (BLT)
Branch if less than unsigned (BLTU) 
Branch if greater than equal (BGE) 

语法

bge reg1, reg2, label   # if reg1 >= reg2, branch to label
beq reg1, reg2, label   # if reg1 == reg2, branch to label
bne reg1, reg2, label   # if reg1 != reg2, branch to label

tp寄存器里是hart id,t0寄存器里是Maximum number of CPUs
如果 tp >=t0 跳转 到 hart_out_of_bounds_loop

bge blt rs1,rs2,imm 如果rs1 >= rs2(有符号方式),跳转

此处跳转到hart_out_of_bounds_loop

li是 Load Immediate
加载立即数
CONFIG_NR_CPUS是预定义的,表示Maximum number of CPUs

CONFIG_NR_CPUS=32

或者

#define CONFIG_NR_CPUS		1

SMP, Symmetric Multi-Processor

#if CONFIG_IS_ENABLED(RISCV_MMODE)
	li	t0, MIE_MSIE
#else
	li	t0, SIE_SSIE
#endif
	csrs	MODE_PREFIX(ie), t0
#endif

根据条件编译 加载立即数 MIE_MSIE 还是SIE_SSIE到t0
SIE (Interrupt Enable)
SIP (Interrupt Pending)

#define MIE_MSIE		(_AC(0x1, UL) << IRQ_M_SOFT)
#define SIE_SSIE		(_AC(0x1, UL) << IRQ_S_SOFT)
#define IRQ_S_SOFT		1
#define IRQ_M_SOFT		3

_AC的意思

用于处理常量的宏

#ifdef __ASSEMBLY__
#define _AC(X,Y)	X
#define _AT(T,X)	X
#else
#define __AC(X,Y)	(X##Y)
#define _AC(X,Y)	__AC(X,Y)
#define _AT(T,X)	((T)(X))
#endif

在C语言里

#define CONNECT(x,y) x##y

表示连接

int n = CONNECT(12,34);

n的值是1234
RISC-V 程序计数器 (PC)程序计数寄存器(Program Counter Register)
RISC-V 引入了一个特殊的通用寄存器 X0 。

RISC-V 通用寄存器 X0 的的特性就是:读出来的值永远为 0 ,写入的值将会被丢弃
RISC-V 将 PC 单独拿出来作为一个特殊的寄存器来对待.

RISC-V 很多伪指令的实现都是通过 X0 通用寄存器与常用的普通指令相结合而实现的
每当完成取指令操作后,PC = PC + 1 这里的 +1 是增加【一条指令的长度 ÷ 寻址粒度】

初始堆栈指针地址

/*
 * Set stackpointer in internal/ex RAM to call board_init_f
 */
call_board_init_f:
	li	t0, -16
#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)
	li	t1, CONFIG_SPL_STACK
#else
	li	t1, SYS_INIT_SP_ADDR
#endif
	and	sp, t1, t0		/* force 16 byte alignment */

加法指令

and	and rd,rs1,rs2

将rs1寄存器的值 和 rs2寄存器的值相加,将结果写入到rd寄存器中

and sp, t1, t0
sp栈指针寄存的初始化

对于我们的初始堆栈指针地址,最常见的情况是,我们定义了一个静态初始RAM地址位置(CFG_SYS_INIT_RAM_ADDR)和大小(CFG_SYS_INIT_RAM_SIZE),并从中减去生成的全局数据(GENERATED_GBL_DATA_SIZE)大小。

#ifdef CONFIG_HAS_CUSTOM_SYS_INIT_SP_ADDR
#define SYS_INIT_SP_ADDR	CONFIG_CUSTOM_SYS_INIT_SP_ADDR
#else
#ifdef CONFIG_MIPS
#define SYS_INIT_SP_ADDR	(CFG_SYS_SDRAM_BASE + CFG_SYS_INIT_SP_OFFSET)
#else
#define SYS_INIT_SP_ADDR	\
	(CFG_SYS_INIT_RAM_ADDR + CFG_SYS_INIT_RAM_SIZE - GENERATED_GBL_DATA_SIZE)
#endif
#endif

CONFIG_SPL_BUILD和CONFIG_SPL_STACK配置的情况下
不同的板子配置也是不同的

#define CONFIG_SPL_TEXT_BASE		0x60		/* sram start+header */
#define CONFIG_SPL_MAX_SIZE		0x5fa0		/* 24KB on sun4i/sun7i */
#define LOW_LEVEL_SRAM_STACK		0x00008000	/* End of sram */
#define CONFIG_SPL_STACK		LOW_LEVEL_SRAM_STACK

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

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

相关文章

SUNet: Swin Transformer UNet for ImageDenoising

Abstract 图像恢复是一个具有挑战性的不适定问题&#xff0c;也是一个长期存在的问题。在过去的几年中&#xff0c;卷积神经网络(cnn)几乎主导了计算机视觉&#xff0c;并在不同层次的视觉任务中取得了相当大的成功&#xff0c;包括图像恢复。然而&#xff0c;最近基于Swin tr…

权限验证框架之Shiro

文章目录 前言shiro 核心项目构建默认Session模式配置测试接口Realm编写权限测试无权限测试登录测试权限测试 前后端分离tokenJWTFilter重写认证修改配置 总结 前言 交替换个脑子&#xff0c;一直搞考研的东西&#xff0c;实在是无聊。所以顺便把工程上的东西&#xff0c;拿来…

软件测试面试大全(全800+题)

1、B/S架构和C/S架构区别 B/S 只需要有操作系统和浏览器就行&#xff0c;可以实现跨平台&#xff0c;客户端零维护&#xff0c;维护成本低&#xff0c;但是个性化能力低&#xff0c;响应速度较慢 C/S响应速度快&#xff0c;安全性强&#xff0c;一般应用于局域网中&#xff0c…

C++ [STL之list模拟实现]

本文已收录至《C语言和高级数据结构》专栏&#xff01; 作者&#xff1a;ARMCSKGT STL之list模拟实现 前言正文基本框架节点类迭代器类list类 迭代器类功能实现list迭代器迭代器设计思想迭代器操作设计 list类功能实现默认成员函数容量查询数据访问节点插删相关头尾插删任意位置…

MySQL数据库索引的种类、创建、删除

目录 一&#xff1a;MySQL 索引 1、MySQL 索引介绍 2、 索引的作用 3、索引的副作用 4、 创建索引的原则依据 二、索引的分类和创建 1、 普通索引 &#xff08;1&#xff09; 直接创建索引 &#xff08;2&#xff09; 修改表方式创建 &#xff08;3&#xff09; 创建表的…

【Turfjs】几何计算,计算地理空间上点坐标的经纬度,距离,围成的闭合空间面积等工作,都可以通过Turfkjs来实现

​​​​​​Turf.js中文网 几何计算&#xff1a; 1. 前端js就用这个 Turfjs的类库。参考网站&#xff1a; 计算两线段相交点 | Turf.js中文网 2. 后端java语言就可以用 JTS这个类库&#xff0c;参考网站&#xff1a;https://locationtech.github.io/jts/ https://github.com…

MVCC和undo log

MVCC多版本并发控制 MVCC是多版本并发控制&#xff08;Multi-Version Concurrency Control&#xff0c;简称MVCC&#xff09;&#xff0c;是MySQL中基于乐观锁理论实现隔离级别的方式&#xff0c;用于实现已提交读和可重复读隔离级别的实现&#xff0c;也经常称为多版本数据库…

面向对象接口

生活中大家每天都在用 USB 接口&#xff0c;那么 USB 接口与我们今天要学习的接口有什 么相同点呢&#xff1f; 在Java程序设计中的接口 接口就是规范&#xff0c;定义的是一组规则&#xff0c;体现了现实世界中“如果你是/要…则必须 能…”的思想。继承是一个"是不是&…

几款GB28181流媒体平台的详细介绍和使用整理

随着监控行业国标GB28181的应用范围越来越广泛&#xff0c;成熟的GB28181接入平台越来越多&#xff0c;本文梳理一下目前各大成熟的流媒体服务器平台及实际应用效果供各位参考。 1)NTV GBS NTV GBS是一款成熟、功能完善、产品化程度很高的GB28181服务平台&#xff0c;从2022年…

原点安全助力金融机构消费者个人信息保护合规

数字经济的发展进一步加速了金融业务与生活场景之间的融合&#xff0c;数亿民众在享受金融数字化便利服务的同时&#xff0c;也更容易遭受个人信息泄露、权益侵害等事件。在实际业务开展过程中&#xff0c;部分金融机构仍存在各种侵害消费者个人信息权益的乱象。 我国对数据安…

工作经验--产品季节性分析

产品季节性分析 1.了解季节性的重要性2.如何发现季节性产品统计方法&#xff1a;季节性指数法&#xff1a;傅里叶分析法&#xff1a;其他&#xff1a; 1.了解季节性的重要性 产品是否存在季节性变化&#xff0c;对于卖家来说相当重要&#xff0c;旺季提前备货、淡季防止库存冗余…

工业无监督缺陷检测,提升缺陷检测能力,解决缺陷样品少、不平衡等问题(二)

1. 工业缺陷检测简介 在工业生产中,质量保证是一个很重要的话题, 因此在生产中细小的缺陷需要被可靠的检出。工业异常检出旨在从正常的样本中检测异常的、有缺陷的情况。工业异常检测主要面临的挑战: 难以获取大量异常样本正常样本和异常样本差异较小异常的类型不能预先得知…

UNITY3D回合制游戏开发教程案例

UNITY3D实现回合制游戏 &#xff0c;类似梦幻西游&#xff0c;口袋妖怪&#xff0c;阴阳师。 先上效果 UNITY3D 回合制游戏案例源码开发教程 普通攻击 AOE技能 游戏概述 回合制游戏是一种策略游戏&#xff0c;玩家需要在自己的回合内进行决策&#xff0c;然后等待对手的回合…

redis学习 -- 常用指令

应用场景 String &#xff1a;缓存&#xff0c;限流&#xff0c;计数器&#xff0c;分布式锁&#xff0c;分布式session Hash&#xff1a;存储y用户信息&#xff0c;用户主页访问量&#xff0c;组合查询 List&#xff1a;关注人时间轴列 Set&#xff1a;点赞&#xff0c;标签&…

【在人间】关于网吧的记忆

高考完的暑假当了两个月夜班的网管&#xff0c;挣得一台小米6&#xff0c;也见识了不少社会人。 乡镇网吧&#xff0c;店里有老虎机&#xff0c;挣的钱比网吧一晚上收入多得多&#xff0c;最狠的一次有人一下输了3000个币(一个币一块钱)&#xff0c;半夜喊老板下楼哭爹喊娘的要…

Docker:启动,停止,删除

1.启动一个容器: docker run 可选参数 镜像名 [COMMAND] [ARG...] docker run -it ubuntu /bin/bash ,启动一个使用ubuntu的docker,并使用/bin/bash做为dcoker中执行的命令。 其中818d5a1c32ac为容器ID 在宿主机上,可以通过docker ps查看容器的状态: 启动容器时常用的可选…

程序员疯抢的 Java 面试宝典(PDF 版)限时开源

Java 面试 2023 届高校毕业生规模预计 1076 万人&#xff0c;同比增加 367 万人&#xff0c;对于 23 届的同学们来说&#xff0c;今年下半年大规模进行的秋招是获得全职 Offer 的最重要的途径&#xff01;对于程序员来说&#xff0c;大家都知道校招难度相对于社招来说会有所降…

解析 HashMap 源码:深入探究核心方法的实现与原理

前言数据结构类属性构造方法核心方法阈值&#xff1a;tableSizeFor插入元素&#xff1a;put树化&#xff1a;treeifyBin扩容&#xff1a;resize获取元素&#xff1a;get删除元素&#xff1a;remove遍历元素&#xff1a;keySet、entrySet 方法 总结 前言 一切的源头从类注释开始…

【Java se】集合——迭代器(Iterator接口)的实现原理

目录 一、迭代器的应用——遍历集合 步骤1&#xff1a;通过集合获取迭代器 步骤2&#xff1a;使用while循环 案例展示&#xff1a; 二、跟踪源代码 #1. 通过集合获取迭代器 #2. 通过成员方法next( ) 获取每一个集合元素对象 #3. 通过成员方法hasNext( )判断是否进行下一次…

计算机组成原理 | 理解二进制编码

二进制的转换 二进制——> 十进制&#xff1a; 从右到左的第 N 位&#xff0c;乘上一个 2 的 N 次方&#xff0c;然后加起来&#xff0c;就变成了一个十进制数例如二进制数&#xff1a;0011&#xff0c;对应的十进制表示&#xff0c;就是 0 2 3 0 2 2 1 2 1 1 2 0…