riscv架构下Linux中断学习笔记

资料来源:
https://www.cnblogs.com/dream397/p/15687184.html
https://riscv-rtthread-programming-manual.readthedocs.io/zh-cn/latest/zh_CN/2.html
https://www.riscv-mcu.com/quickstart-show-id-1.html#9
https://www.riscv-mcu.com/site/nuclei_interrupt_quickstart/#23-n
https://www.cnblogs.com/harrypotterjackson/p/17548837.html#_label12
https://rcore-os.cn/rCore-Tutorial-Book-v3/chapter2/4trap-handling.html

特权架构

RISCV架构下有三种特权级别,分别是Machine、Supervisor和User,简称M模式、S模式和U模式。M模式权限最高,在这个级别下的程序可以访问一切硬件和执行所有特权指令,可以直接使用物理地址进行访问,不经过MMU;S模式一般用于运行操作系统,可以设置MMU使用虚拟地址;U模式一般是普通应用程序使用,权限最低。在微控制器上使用的RISCV架构一般只有M模式,或者使用M和U两种模式,类似于cortex-m架构的定位;而在带MMU的芯片上,RISCV架构一般都使用M、S和U三种模式,这样通过“拼积木”的方式就可以让RISCV架构适用于各种场景了。
在这里插入图片描述

在RISCV中,默认产生中断和异常时,处理器自动切换到M模式处理,但通过中断托管允许某些中断和异常直接在S模式下处理。RISCV的架构设计就决定了必须要有程序运行在M模式下,来为S模式提供一些基础的服务,RISCV为此定义了SBI(Supervisor Binary Interface)接口规范,让运行在S模式下的操作系统在不同的RISCV处理器上都可以使用标准的SBI接口来使用相应的功能。在RISCV中,通过“ecall”指令可以从低特权切换到高特权,在U模式下执行就切换到S模式,在S模式下调用就切换到M模式。

寄存器

RISC-V 架构提供 1 个只读寄存器 x0 和 31 个用户可修改的通用寄存器 x1 到 x31,所有寄存器都可以作为通用寄存器使用。其中 Caller 由调用者保存,Callee 由被调用者保存。
在这里插入图片描述
RISC-V 支持单精度浮点数和双精度浮点数,分别使用 32 位和 64 位来表示,分为两种类型:浮点临时寄存器和浮点保存寄存器。
在这里插入图片描述

在RISCV架构设计中,有一系列的控制和状态寄存器( Control and Status Registers)简称CSR,能够反映和控制 CPU 当前的状态和执行机制,访问不存在的 CSR 将触发无效指令异常。在三种特权级别下都有其对应的CSR,比如m模式下的命名都为mxxxx,s模式下的都为sxxxx等等。用于设置异常向量表、设置页表基址、获取异常信息等等。

在机器模式(Machine Mode)下CSR主要包括以下六类:

  • 处理器信息相关:例如处理器的厂商信息,架构信息,核心数等等,是一个芯片自身的I固有信息。
  • 中断配置相关:例如中断开关以及中断入口等信息。
  • 中断响应相关:例如中断原因,中断返回地址等信息。
  • 存储器保护相关:设置不同地址空间的存储器的访问属性,例如可读可写可执行等等。
  • 性能统计相关。
  • 调试接口相关。

跟异常相关的寄存器介绍跳转到此博客

异常和中断

在 RISC-V 中,中断(interrupt)和异常(exception)被统称为 trap。
RISC-V 中断被分为两类局部中断和全局中断:

  • 局部中断,算是内部中断,标准是只规定了有两种,即使系统定时器中断和软件中断。局部中断连接在 CLINT(Core Local Interruptor)上。
  • 全局中断,也就是所说的外部中断,其他外设统统都是外部中断。外部中断连接在 PLIC(Platform-Level Interrupt Controlle)上。

CLINT 和 PLIC 最大的区别在于,CLINT 没有仲裁,包括 software 和 timer,一有中断马上响应,PLIC 需要一个仲裁决定谁先中断,存在个优先级的问题。
在这里插入图片描述
“定时器中断”是由一个独立的计时器电路发出的信号,表示预定的时间间隔已经结束。计时器子系统将中断当前正在执行的代码。定时器中断可以由操作系统处理,用于实现时间片多线程,但是对于 MTIME 和 MTIMECMP 的读写只能由 M-mode 的代码实现,因此内核需要调用 SBI 的服务。
mtime 需要以固定的频率递增,并在发生溢出时回绕。当 mtime 大于或等于 mtimecmp 时,由核内中断控制器 (CLINT, Core-Local Interrupt Controller) 产生 timer 中断。中断的使能由 mie 寄存器中的 MTIE 和 STIE 位控制,mip 中的 MPIE 和 SPIE 则指示了 timer 中断是否处于 pending。在 RV32 中读取 mtimecmp 结果为低 32 位, mtimecmp 的高 32 位需要读取 mtimecmph 得到。

特权级转换

当执行一条 Trap 类指令(如 ecall 时),CPU 发现触发了一个异常并需要进行特殊处理,这涉及到 执行环境切换 。

在 RISC-V 架构中,关于 Trap 有一条重要的规则:在 Trap 前的特权级不会高于 Trap 后的特权级。因此如果触发 Trap 之后切换到 S 特权级(下称 Trap 到 S),说明 Trap 发生之前 CPU 只能运行在 S/U 特权级。

U 切换到 S

当执行一个 trap 时,除了 timer interrupt,所有的过程都是相同的,硬件会自动完成下述过程:

  1. 如果该 trap 是一个设备中断并且 sstatus 的 SIE bit 为 0,那么不再执行下述过程
  2. 通过置零 SIE 禁用中断
  3. 将 pc 拷贝到 sepc
  4. 保存当前的特权级到 sstatus 的 SPP 字段
  5. 将 scause 设置成 trap 的原因
  6. 设置当前特权级为 supervisor
  7. 拷贝 stvec(中断服务程序的首地址)到 pc
  8. 开始执行中断服务程序

在这里插入图片描述

CPU 不会自动切换到内核的页表,也不会切换到内核栈,也不会保存除了 pc 之外的寄存器的值,内核需要自行完成。对于Linux而言,内核空间与用户态空间是使用的同一套页表,不需要切换页表。详情可以参考用户态进程的虚拟内存布局。内核空间一般位于进程的高虚拟地址空间。

S 切换到 U

在从 S 切换到 U 时,要手动清除 sstatus 的 SPP 字段,将其置为零;将 sstatus 的 SPIE 字段置为 1,启用用户中断;设置 sepc 为用户进程的 PC 值(你可能疑惑在 U 转换到 S 时不是已经将用户进程的保存在了 sepc 了吗?因为在 S-mode 也会发生中断呀,那么 sepc 就会被用来保存发生中断位置时的 PC 了)。如果启用了页表,就需要想还原用户进程的页表,即将用户进程的页表地址写入 satp,之后恢复上下文,然后执行 sret 指令,硬件会自动完成以下操作:

  1. 从 sepc 寄存器中取出要恢复的下一条指令地址,将其复制到程序计数器 pc 中,以恢复现场;
  2. 从 sstatus 寄存器中取出用户模式的相关状态,包括中断使能位、虚拟存储模式等,以恢复用户模式的状态;
  3. 将当前特权模式设置为用户模式,即取消特权模式,回到用户模式。

S 切换到 M

S 切换到 M 与从 U 切换到 M 类似,都是从低特权级到高特权级的切换。在 S 运行的代码,也可以通过 ecall 指令陷入到 M 中。

  1. S-mode 的代码执行一个指令触发了异常或陷阱,例如环境调用(ECALL)指令
  2. 处理器将当前的 S-mode 上下文的状态保存下来,包括程序计数器 (PC)、S-mode 特权级别和其他相关寄存器,保存在当前特权级别堆栈中的 S-MODE 陷阱帧(trap frame,其实就是一个页面)中
  3. 处理器通过将 mstatus 寄存器中的 MPP 字段设置为 0b11(表示先前的模式是 S 模式)将特权级别设置为 M-mode
  4. 处理器将程序计数器设置为在 M-mode 中的陷阱处理程序例程的地址
  5. 处理器还在 mstatus 寄存器中设置 M-mode 中断使能位 (MIE) 为 0,以在陷阱处理程序中禁用中断

地址空间布局

启用分页模式下,内核代码的访存地址也会被视为一个虚拟地址并需要经过 MMU 的地址转换,因此我们也需要为内核对应构造一个地址空间,它除了仍然需要允许内核的各数据段能够被正常访问之后,还需要包含所有应用的内核栈以及一个 跳板 (Trampoline) 。

使能了分页机制之后,我们必须在 trap 过程中同时完成地址空间的切换。具体来说,当 __alltraps 保存 Trap 上下文的时候,我们必须通过修改 satp 从应用地址空间切换到内核地址空间,因为 trap handler 只有在内核地址空间中才能访问;同理,在 __restore 恢复 Trap 上下文的时候,我们也必须从内核地址空间切换回应用地址空间,因为应用的代码和数据只能在它自己的地址空间中才能访问,应用是看不到内核地址空间的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值