这是 os summer of code 2020 每日记录的一部分:
github地址:https://github.com/yunwei37/os-summer-of-code-daily
参考:RISC-V 手册 一本开源指令集的指南
第一章 为什么要有 RISC-V
RISC-V的目标是成为一个通用的指令集架构(ISA):
- 它要能适应包括从最袖珍的嵌入式控制器,到最快的高性能计算机等各种规模的处理器
- 它应该能兼容各种流行的软件栈和编程语言
- 它应该适应所有实现技术,包括现场可编程门阵列(FPGA)、 专用集成电路(ASIC)、 全定制芯片, 甚至未来的设备技术
- 它应该对所有微体系结构样式都有效:例如微编码或硬连线控制;顺序或乱序执行流水线; 单发射或超标量等等
- 它应该支持广泛的专业化,成为定制加速器的基础,因为随着摩尔定律的消退,加速器的重要性日益提高。
- 它应该是稳定的,基础的指令集架构不应该改变。
它是一个最近诞生的指令集架构,也是一个开源的指令集架构。
模块化与增量型 ISA
RISC-V的不同寻常之处,除了在于它是最近诞生的和开源的以外,还在于:和几乎所有以往的ISA不同,它是模块化的。
它的核心是一个名为RV32I的基础ISA,RV32I是固定的,永远不会改变。
模块化来源于可选的标准扩展,根据应用程序的需要,硬件可以包含或不包含这些扩展。
ISA 设计 101
架构师在设计 ISA 时的基本原则和必须做出的权衡:
- 成本(美元硬币)
- 简洁性(轮子)
- 性能(速度计)
- 架构和具体实现的分离(分开的两个半圆)
- 提升空间(手风琴)
- 程序大小(相对的压迫着一条线的两个箭头)
- 易于编程/编译/链接(儿童积木“像 ABC 一样简单”)
第二章 RV32I: RISC-V 基础整数指令集
- 32 位字节可寻址的地址空间
- 所有指令均为 32 位长
- 31 个寄存器,全部 32 位宽,寄存器 0 硬连线为零
- 所有操作都在寄存器之间(没有寄存器到内存的操作)
- 加载/存储字加上有符号和无符号加载/存储字节和半字
- 所有算术,逻辑和移位指令都有立即数版本的指令
- 立即数总是符号扩展
- 仅提供一种数据寻址模式(寄存器 立即数)和 PC 相对分支
- 无乘法或除法指令
- 一个指令,用于将大立即数加载到寄存器的高位,这样加载 32 位常量到寄存器只需要两条指令
六种基本指令格式:
- 用于寄存器-寄存器操作的 R 类型指令
- 用于短立即数和访存 load 操作的 I 型指令
- 用于访存 store 操作的 S 型指令
- 用于条件跳转操作的 B 类型指令
- 用于长立即数的 U 型指令
- 用于无条件跳转的 J 型指令
RV32I 寄存器:
- RV32I 有 31 寄存器加上一个值恒为 0 的 x0 寄存器
RV32I 整数计算:
- 简单的算术指令(add, sub)、逻辑指令(and, or, xor),以及图 2.1 中的移位指令(sll, srl, sra) 和其他 ISA 差不多。
- RV32I 提供一个当小于时置位的指令
- RISC-V 中没有字节或半字宽度的整数计算操作
- RV32I 也不包含乘法和除法,它们包含在可选的 RV32M 扩展中
RV32I 的 Load 和 Store
- RV32I 支持加载有符号和无符号字节和半字(lb, lbu, lh, lhu)和存储字节和半字(sb, sh)
RV32I 条件分支 无条件跳转
- RV32I 可以比较两个寄存器并根据比较结果上进行分支跳转。
- 跳转并链接指令(jal)具有双重功能。
RV32I 杂项
- 控制状态寄存器指令 (csrrc、 csrrs、 csrrw、 csrrci、 csrrsi、 csrrwi),使我们可以轻松地访问一些程序性能计数器
- ecall 指令用于向运行时环境发出请求,例如系统调用。
- fence 指令对外部可见的访存请求,如设备 I / O 和内存访问等进行串行化。
第三章 RISC-V 汇编语言
- 汇编器向 RISC-V ISA 中增加了 60 条伪指令,使得 RISC-V 代码更易于读写,并且不增加硬件开销。
- 将一个寄存器硬编码为 0 使得其中许多伪指令更容易实现。
- 使用加载高位立即数(lui)和程序计数器与高位立即数相加(auipc)两条指令,简化了编译器和链接器寻找外部数据/函数的地址的过程。
- 使用相对地址转移的代码与位置无关,减少了链接器的工作。
- 大量的寄存器减少了寄存器保存和恢复的次数,加速函数调用和返回。
第十章 RV32/64 特权架构
本章介绍两种新的权限模式:运行最可信的代码的机器模式(machine mode),以及为 Linux, FreeBSD 和 Windows 等操作系统提供支持的监管者模式(supervisor mode)。
简单嵌入式系统的机器模式
- 机器模式(缩写为 M 模式, M-mode)是 RISC-V 中 hart(hardware thread,硬件线程)可以执行的最高权限模式。
- 在 M 模式下运行的 hart 对内存, I/O 和一些对于启动和配置系统来说必要的底层功能有着完全的使用权。
- 简单的 RISC-V 微控制器仅支持 M 模式。
- 机器模式最重要的特性是拦截和处理异常(不寻常的运行时事件)的能力。
同步异常类型:
- 访问错误异常
- 断点异常
- 环境调用异常
- 非法指令异常
- 非对齐地址异常
有三种标准的中断源:软件、时钟和外部来源。
机器模式下的异常处理
( 这部分和lab1高度相关:
八个控制状态寄存器(CSR)是机器模式下异常处理的必要部分:
- mtvec(Machine Trap Vector) 它保存发生异常时处理器需要跳转到的地址。
- mepc(Machine Exception PC)它指向发生异常的指令
- mcause(Machine Exception Cause)它指示发生异常的种类
- mie(Machine Interrupt Enable)它指出处理器目前能处理和必须忽略的中断。
- mip(Machine Interrupt Pending)它列出目前正准备处理的中断。
- mtval(Machine Trap Value)它保存了陷入(trap) 的附加信息:地址例外中出错的地址、发生非法指令例外的指令本身,对于其他异常,它的值为 0。
- mscratch(Machine Scratch)它暂时存放一个字大小的数据。
- mstatus(Machine Status)它保存全局中断使能,以及许多其他的状态
当一个 hart 发生异常时,硬件自动经历如下的状态转换:
- 异常指令的 PC 被保存在 mepc 中, PC 被设置为 mtvec。(对于同步异常, mepc指向导致异常的指令;对于中断,它指向中断处理后应该恢复执行的位置。)
- 根据异常来源设置 mcause(如图 10.3 所示),并将 mtval 设置为出错的地址或者其它适用于特定异常的信息字。
- 把控制状态寄存器 mstatus 中的 MIE 位置零以禁用中断,并把先前的 MIE 值保留到 MPIE 中。
- 发生异常之前的权限模式保留在 mstatus 的 MPP 域中,再把权限模式更改为M。图 10.5 显示了 MPP 域的编码(如果处理器仅实现 M 模式,则有效地跳过这个步骤)。
有时需要在处理异常的过程中转到处理更高优先级的中断。 mepc,mcause, mtval 和 mstatus 这些控制寄存器只有一个副本,处理第二个中断的时候如果软件不进行一些帮助的话,这些寄存器中的旧值会被破坏,导致数据丢失。
嵌入式系统中的用户模式和进程隔离
RISC-V 提供了保护系统免受不可信的代码危害的机制,并且为不受信任的进程提供隔离保护。这样的限制很容易实现,只要加入一种额外的权限模式: 用户模式(U 模式)。
实现了 M 和 U 模式的处理器具有一个叫做物理内存保护(PMP, Physical Memory Protection)的功能,允许 M 模式指定 U 模式可以访问的内存地址。
现代操作系统的监管者模式
使用基于页面的虚拟内存。这个功能构成了监管者模式(S 模式)的核心,这是一种可选的权限模式,旨在支持现代类 Unix 操作系统,如 Linux, FreeBSD 和 Windows。 S 模式比 U 模式权限更高,但比 M 模式低。
RISC-V 提供了一种异常委托机制。通过该机制可以选择性地将中 断和同步异常交给 S 模式处理,而完全绕过 M 模式。mideleg(Machine Interrupt Delegation,机器中断委托) CSR 控制将哪些中断委托给 S模式。
基于页面的虚拟内存
S 模式提供了一种传统的虚拟内存系统,它将内存划分为固定大小的页来进行地址转换和对内存内容的保护。启用分页的时候,大多数地址(包括 load 和 store 的有效地址和PC 中的地址)都是虚拟地址。要访问物理内存,它们必须被转换为真正的物理地址,这通过遍历一种称为页表的高基数树实现。
这里重点关注 Sv39 分页方案:
Sv39 的 512GiB 地址空间划分为 29个 1 GiB 大小的吉页。每个吉页被进一步划分为 29 个巨页。在Sv39 中这些巨页大小为 2 MiB,比 Sv32 中略小。每个巨页再进一步分为 29个 4 KiB 大小的基页。
一个叫 satp(Supervisor Address Translation and Protection,监管者地址转换和保护)的 S 模式控制状态寄存器控制了分页系统。satp 有三个域:
- MODE 域可以开启分页并选择页表级数
- ASID(Address Space Identifier,地址空间标识符)域是可选的,它可以用来降低上下文切换的开销
- PPN 字段保存了根页表的物理地址
当在 satp 寄存器中启用了分页时, S 模式和 U 模式中的虚拟地址会以从根部遍历页表的方式转换为物理地址:
- satp.PPN 给出了一级页表的基址, VA [31:22] 给出了一级页号,因此处理器会读取位于地址(satp. PPN × 4096 VA[31: 22] × 4)的页表项。
- 该 PTE 包含二级页表的基址, VA[21:12]给出了二级页号,因此处理器读取位于地址(PTE. PPN × 4096 VA[21: 12] × 4)的叶节点页表项。
- 叶节点页表项的 PPN 字段和页内偏移(原始虚址的最低 12 个有效位)组成了最终结果:物理地址就是(LeafPTE. PPN × 4096 VA[11: 0])
RISC-V 特权架构的模块化特性满足了各种系统的需求。十分精简的机器模式以低成本的特征支持裸机嵌入式应用。附加的用户模式和物理内存保护功能共同支持了更复杂的嵌入式系统中的多任务处理。最后,监管者模式和基于页面的虚拟内存提供了运行现代操作系统所必需的灵活性。