使用 C++23 从零实现 RISC-V 模拟器(6):权限支持
本节内容增加了权限表示,设置了三种权限。当 cpu 初始化时默认的权限为 Machine 模式。接下来实现这三种特权模式,随后实现 sret 和 mret 指令。
RISC-V定义了三种特权等级,分别是用户态(User Mode)、监管态(Supervisor Mode)、和机器态(Machine Mode)。这三种特权等级对应着不同的操作系统和应用场景,提供了不同级别的访问权限。
1. 权限表示
定义下面三个参数来表示不同的权限级别。
// 使用 uint64_t 定义 Mode 类型
using Mode = uint64_t;// 定义 User 模式,二进制表示为 00
constexpr Mode User = 0b00;// 定义 Supervisor 模式,二进制表示为 01
constexpr Mode Supervisor = 0b01;// 定义 Machine 模式,二进制表示为 11
constexpr Mode Machine = 0b11;
在 CPU 类中增加表示权限的成员变量并修改构造函数,最初的级别为 Machine 模式。
class Cpu {
public://...Mode mode;//... Cpu(const std::vector<uint8_t>& code): pc(DRAM_BASE),bus(code),csr() // 初始化 Csr{regs.fill(0); // 初始化寄存器为0regs[2] = DRAM_END; // 设置堆栈指针寄存器的初始值mode = Machine;}
}
2. FENCE / SFENCE.VMA
在RISC-V(RV)中,FENCE(Fence)和SFENCE.VMA(Store Fence Virtual Memory Atomic)是两个不同的指令,它们用于控制内存访问和同步。下面是它们的主要区别:
-
FENCE(Fence):
- 它是一个轻量级的同步指令,它确保在
FENCE
之前和之后的指令不会重排序,保证了程序的顺序一致性。 FENCE
没有特定的参数,因此它执行的同步操作是通用的,对所有处理器和内存操作都生效。
- 它是一个轻量级的同步指令,它确保在
-
SFENCE.VMA(Store Fence Virtual Memory Atomic):
SFENCE.VMA
指令是用于确保内存中原子操作的完成,并对虚拟内存进行同步的指令。- 它通常与原子指令(如原子加载-存储指令)一起使用,以确保在
SFENCE.VMA
之前的原子操作完成后,再执行SFENCE.VMA
之后的指令。 - 这个指令在多核或多处理器系统中确保对共享内存的原子访问的顺序性。
总体而言,FENCE
主要用于轻量级的指令序列同步,而 SFENCE.VMA
更专注于保障对虚拟内存中原子操作的完成和同步。在实际使用中,程序员需要根据具体情况选择使用哪个指令,以满足程序的同步和顺序一致性需求。
此处的 FENCE
和 SFENCE.VMA
都暂时简化处理,直接跳过。
std::optional<uint64_t> executeSFENCE_VMA(Cpu& cpu, uint32_t inst) {// 此时模拟器没有实现虚拟内存或者页表,// 暂时该指令不需要执行任何操作。// 更新程序计数器return cpu.update_pc();
}std::optional<uint64_t> executeFence(Cpu& cpu, uint32_t inst) {return cpu.update_pc();
}
3. SRET(Supervisor Return):
SRET
指令用于从 Supervisor 模式返回到先前的特权级别。在执行异常处理程序时,如果发生了从用户态到 Supervisor 模式的特权级别切换,那么 SRET
会将程序计数器(PC)和一些相关的状态从 sepc
和 sstatus
寄存器中恢复,从而返回到用户态。以下是一个示例:
# Exception or interrupt handler in Supervisor mode
exception_handler:# ... (处理异常的代码)# 返回到用户态sret
在上述示例中,当异常处理完成后,SRET
指令被用来将控制权返回到先前的用户态。
4. MRET(Machine Return):
MRET
指令类似于 SRET
,但用于从 Machine 模式返回到先前的特权级别。在执行异常处理程序时,如果发生了从用户态到 Machine 模式的特权级别切换,MRET
会将程序计数器(PC)和一些相关的状态从 mepc
和 mstatus
寄存器中恢复,从而返回到用户态。以下是一个示例:
# Exception or interrupt handler in Machine mode
exception_handler:# ... (处理异常的代码)# 返回到用户态mret
在这个示例中,当异常处理完成后,MRET
指令被用来将控制权返回到先前的用户态。
总体而言,SRET
和 MRET
是在异常处理或中断处理过程中用于恢复先前特权级别的重要指令。这样的特权级别切换机制使得 RISC-V 处理器可以有效地处理不同特权级别下的异常和中断,保持系统的稳定性和安全性。
6. 实现
先编写单元测试,然后增肌对应指令的实现逻辑,例如 sret 代码如下。
std::optional<uint64_t> executeSRET(Cpu& cpu, uint32_t inst) {// 从 CSR 寄存器加载 sstatus 的值uint64_t sstatus = cpu.csr.load(SSTATUS);// 根据 SPP 位设置权限级别,SPP 位是 sstatus 的第 8 位cpu.mode = (sstatus & MASK_SPP) >> 8;// SPIE 位是 sstatus 的第 5 位uint64_t spie = (sstatus & MASK_SPIE) >> 5;// 将 SIE 位设置为 SPIE 位的值,SIE 位是 sstatus 的第 1 位sstatus = (sstatus & ~MASK_SIE) | (spie << 1);// 将 SPIE 位设置为 1sstatus |= MASK_SPIE;// 将 SPP 位设置为最低权限模式(U-mode)sstatus &= ~MASK_SPP;// 将修改后的 sstatus 值存回 sstatus 寄存器cpu.csr.store(SSTATUS, sstatus);// 将程序计数器(PC)设置为 sepc 寄存器的值// 当 IALIGN=32 时,sepc[1] 位在读取时被屏蔽,使其看起来像是 0。这种屏蔽也发生在 SRET 指令的隐式读取中uint64_t new_pc = cpu.csr.load(SEPC) & ~0b11;// 返回新的程序计数器(PC)的值return new_pc;
}
mret 指令的解析代码没有列出来,完整代码可以参考该分支:https://github.com/weijiew/crvemu/tree/lab6-pm
👉🏻 文章汇总「从零实现模拟器、操作系统、数据库、编译器…」:https://okaitserrj.feishu.cn/docx/R4tCdkEbsoFGnuxbho4cgW2Yntc
相关文章:
使用 C++23 从零实现 RISC-V 模拟器(6):权限支持
本节内容增加了权限表示,设置了三种权限。当 cpu 初始化时默认的权限为 Machine 模式。接下来实现这三种特权模式,随后实现 sret 和 mret 指令。 RISC-V定义了三种特权等级,分别是用户态(User Mode)、监管态ÿ…...

针对某终端安全自检钓鱼工具的分析
前言 朋友微信找到我,说某微信群利用0day通告进行钓鱼,传播名为“终端安全自检工具”的恶意文件,然后还给了两个IP地址,如下: 咱们就来详细看看这个工具吧。 样本信息 拿到样本,样本的图标,如…...

XSS数据接收平台
一.使用xss数据接收平台的好处: 正常执行反射型xss和存储型xss,反射型xss在执行poc时,会直接在页面弹出执行注入的poc代码;存储型则是,在将poc代码注入用户的系统中后,用户访问有存储型xss的地方ÿ…...

MySQL 基础知识(六)之数据查询(一)
目录 1 基本查询 1.1 查询相关列 (select * / 列名) 1.2 别名 (as) 1.3 去重 (distinct) 1.4 对列中的数据进行运算 (、-、*、/) 2 条件查询 (where) 2.1 等值查询 () 2.2 非等值查询 (>、<、>、<、!、><) 2.3 逻辑判断 (and、or、not) 2.4 区间判…...

C#使用哈希表对XML文件进行查询
目录 一、使用的方法 1.Hashtable哈希表 2.Hashtable哈希表的Add方法 (1)定义 (2)示例 3.XML文件的使用 二、实例 1.源码 2.生成效果 可以通过使用哈希表可以对XML文件进行查询。 一、使用的方法 1.Hashtable哈希表…...

vscode写MATLAB配置
vscode写MATLAB python下载 官网说明Versions of Python Compatible with MATLAB Products by Release - MATLAB & Simulink 不确定这三列都表示什么意思,尽量安装这三列都有的python版本吧,我安装的 MATLAB R2023b,python选择的是3.11.5 …...

第13章 网络 Page734 “I/O对象”的链式传递 单独的火箭发射函数,没有用对的智能指针
上一篇博文中,我们使用单独的火箭发射函数,结果什么结果也没有得到,原因是launch_rocket()函数结束时,其内的局部对象counter生命周期也结束了 那么可以将counter改为指针吗?在堆中分配,这样当函数退出时&…...
Git 存储大文件
Git 存储大文件处理方法 寻找大文件的后缀LFS的安装让仓库支持LFS添加到LFS提交 寻找大文件的后缀 find . -type f -size 10M | grep -v ".git" | rev | cut -d. -f1 | rev | sort | uniq这个命令的工作原理如下: find .-type f -size 10M:查…...

使用 Mermaid 创建流程图,序列图,甘特图
使用 Mermaid 创建流程图和图表 Mermaid 是一个流行的 JavaScript 库,用于创建流程图、序列图、甘特图和其他各种图表。它的简洁语法使得创建图表变得非常简单,无需复杂的绘图工具或专业的编程技能。在本文中,我们将讲解如何使用 Mermaid 来创…...

政安晨:在Jupyter中【示例演绎】Matplotlib的官方指南(二){Image tutorial}·{Python语言}
咱们接着上一篇,这次咱们讲使用Matplotlib绘制图像的简短尝试。 我的这个系列的上一篇文章在这里: 政安晨:在Jupyter中【示例演绎】Matplotlib的官方指南(一){Pyplot tutorial}https://blog.csdn.net/snowdenkeke/ar…...
gem5学习(20):替换策略——Replacement Policies
目录 一、Random 二、Least Recently Used (LRU) 三、Tree Pseudo Least Recently Used (TreePLRU) 四、Bimodal Insertion Policy (BIP) 五、LRU Insertion Policy (LIP) 六、Most Recently Used (MRU) 七、Least Frequently Used (LFU) 八、First-In, First-Out (FIF…...

嵌入式Qt Qt中的字符串类
一.Qt中的字符串类 QString vs string: QString在Qt库中几乎是无所不在的 所有的Qt图形用户组件都依赖于QString 实验1 :QString 初体验 #include <QDebug> void Sample_1() {QString s "add";s.append(" "); // &q…...
函数高级(C++)
师从黑马程序员 函数默认参数 在C中,函数的形参列表中的形参是可以有默认值的 语法:返回值类型 函数名 (参数默认值 {}) #include <iostream> using namespace std;//函数默认参数//如果我们自己传入数据,…...

jmeter-10调试取样器
文章目录 作用设置使用举例 作用 jmeter中添加调试取样器,可以用于检测测试过程的值如:变量、参数、系统设置等 设置 选择线程组右键 >>> 添加 >>> 取样器 >>> 调试取样器(Debug Sampler) jmeter …...

C#,二进制数的按位旋转(Bits Rotate)算法与源代码
1 二进制数的按位旋转 二进制数的按位旋转(翻转)是编程中常见的按位运算方法。 二进制数的按位旋转分为左转、右转。 左转意味着数据变大,右转意味着数据变小(有损)。 2 源程序 using System; using System.Text; us…...

解决ubuntu登录密码问题
解决ubuntu登录密码问题 不要随便删除密码,不要随便改密码,很容导致密码过期,或者密码无效。参考了很多人的做法,都没有得到解决。下面的过程,够详细了,我就是这么搞好的。 1、重启虚拟机,不停…...

Ubuntu忘记登录密码重置步骤
Ubuntu忘记登录密码重置步骤 1.开机界面长按shitf键,进入grub,并选择Advanced options for ubuntu,按下回车 2.选择一个较新版本的recovery mode,按下回车 3.会跑一些数据,等待跑完后会出现下面的界面,选择…...

MySQL数据库基础(五):SQL语言讲解
文章目录 SQL语言讲解 一、SQL概述 二、SQL语句分类 1、DDL 2、DML 3、DQL 4、DCL 三、SQL基本语法 1、SQL语句可以单行或多行书写,以分号结尾 2、可使用空格和缩进来增强语句的可读性 3、MySQL数据库的SQL语句不区分大小写,关键字建议使用大写…...
python-使用ffmpeg批量修改文件的后缀名
import os import subprocessdef convert_ogg_to_mp3(directory):for filename in os.listdir(directory):if filename.endswith(".ogg"):# 获取文件的完整路径file_path os.path.join(directory, filename)# 创建一个新的文件名,只是将扩展名从.ogg更改…...
关于jupyter的一些小笔记
关于jupyter的一些小笔记 1.Jupyter Notebook:单/多行注释,组合键:选中代码,按Ctrl /。 2.安装PHATE包 使用pip直接进行安装 pip install --user phate成功解决AttributeError: module ‘numpy’ has no attribute ‘float’. 报…...

什么是库存周转?如何用进销存系统提高库存周转率?
你可能听说过这样一句话: “利润不是赚出来的,是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业,很多企业看着销售不错,账上却没钱、利润也不见了,一翻库存才发现: 一堆卖不动的旧货…...

2025 后端自学UNIAPP【项目实战:旅游项目】6、我的收藏页面
代码框架视图 1、先添加一个获取收藏景点的列表请求 【在文件my_api.js文件中添加】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口(适配服务端返回 Token) export const login async (code, avatar) > {const res await http…...

ardupilot 开发环境eclipse 中import 缺少C++
目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...
JDK 17 新特性
#JDK 17 新特性 /**************** 文本块 *****************/ python/scala中早就支持,不稀奇 String json “”" { “name”: “Java”, “version”: 17 } “”"; /**************** Switch 语句 -> 表达式 *****************/ 挺好的ÿ…...

QT: `long long` 类型转换为 `QString` 2025.6.5
在 Qt 中,将 long long 类型转换为 QString 可以通过以下两种常用方法实现: 方法 1:使用 QString::number() 直接调用 QString 的静态方法 number(),将数值转换为字符串: long long value 1234567890123456789LL; …...
Spring是如何解决Bean的循环依赖:三级缓存机制
1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间互相持有对方引用,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…...

【从零学习JVM|第三篇】类的生命周期(高频面试题)
前言: 在Java编程中,类的生命周期是指类从被加载到内存中开始,到被卸载出内存为止的整个过程。了解类的生命周期对于理解Java程序的运行机制以及性能优化非常重要。本文会深入探寻类的生命周期,让读者对此有深刻印象。 目录 …...

(一)单例模式
一、前言 单例模式属于六大创建型模式,即在软件设计过程中,主要关注创建对象的结果,并不关心创建对象的过程及细节。创建型设计模式将类对象的实例化过程进行抽象化接口设计,从而隐藏了类对象的实例是如何被创建的,封装了软件系统使用的具体对象类型。 六大创建型模式包括…...

MyBatis中关于缓存的理解
MyBatis缓存 MyBatis系统当中默认定义两级缓存:一级缓存、二级缓存 默认情况下,只有一级缓存开启(sqlSession级别的缓存)二级缓存需要手动开启配置,需要局域namespace级别的缓存 一级缓存(本地缓存&#…...
十九、【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建
【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建 前言准备工作第一部分:回顾 Django 内置的 `User` 模型第二部分:设计并创建 `Role` 和 `UserProfile` 模型第三部分:创建 Serializers第四部分:创建 ViewSets第五部分:注册 API 路由第六部分:后端初步测…...