RV64 时钟中断处理 ¶
约 1000 个字 63 行代码 2 张图片 预计阅读时间 4 分钟
Abstract
计算机系统 Ⅱ lab5 实验报告(2022.11.17 ~ 2022.12.01)
Warning
仅供学习参考,请勿抄袭
实验内容 ¶
- 完成对异常处理的初始化、实现上下文切换功能、编写异常处理函数、完成对时间中断事件的处理
- 完成代码并编译运行:
- arch/riscv/kernel/head.S
- arch/riscv/kernel/entry.S
- arch/riscv/kernel/trap.c
- arch/riscv/kernel/clock.c
- 其它必要的修改
- 思考题
- 解释 OpenSBI 输出的 MIDELEG、MEDELEG 的含义
- 机器启动后 time、cycle 寄存器分别是从 0 开始计时的吗,从 0 计时是否是必要的呢?
- 谈谈如何在一台不支持乘除法指令扩展的处理器上执行乘除法指令
代码编写 ¶
lab5 提供修改 ¶
按照实验手册和 repo 中提供的代码进行修改。即将 puti、puts 换为 printk,需要额外修改 init/main.c:
#include "printk.h"
extern void test();
int start_kernel(int x) {
printk("%d", x);
printk(" ZJU Computer System II\n");
test(); // DO NOT DELETE !!!
return 0;
}
以及根据指导修改 init/test.c、vmlinux.lds、head.S,这里不再赘述。
head.S 开启异常处理 ¶
根据实验指导中的步骤进行编写:
- 设置 stvec 为 _traps 地址,且使用 direct 模式:
- 因为对齐的原因,后两位一定为 0,即 direct 模式,不需要处理
- 将 sie[STIE] 置 1
- sie 的右数第 5 位为 STIE,所以通过 csrs 将其设置为 1 即可:
- 设置第一次时钟中断
- 按照要求,根据 clock_set_next_event 的逻辑用汇编实现
- (在此前一定要先设置好 sp,因为有 call 了)
- 开启 S 态下中断响应,将 sstatus[SIE] 置 1
- sstatus 的右 1 位为 SIE,通过 csrs 设置
entry.S 中实现针对 trap 的上下文切换 ¶
根据实验指导:
- 保存 CPU 寄存器到栈上
- 后面 sp 需要最后恢复,所以需要最先压入 sp,其它任意
- 调用 trap_handler
- 需要传入参数,第一个参数 scause 放入 a0、第二个参数 sepc 放入 a1
- 从栈上恢复寄存器
- 和第一步的顺序相反
- 从 trap 中返回
- 由于是从 S 态异常返回,所以要使用 sret
trap.c 实现异常处理函数 ¶
需要通过 scause 判断 trap 类型,如果是时钟中断,则打印信息并调用 clock_set_next_event() 函数。
根据手册,时钟中断时 scause 的最高位为 1(Interrupt
#include "clock.h"
#include "printk.h"
void trap_handler(unsigned long scause, unsigned long sepc) {
if ((scause >> 63) && (scause & 0x7FFFFFFFFFFFFFFF) == 5) {
printk("[S] Supervisor Mode Timer Interrupt\n");
clock_set_next_event();
return;
}
}
以及为了使用 clock.c 中的 clock_set_next_event 函数,还需要编写一个 clock.h 头文件:
clock.c 实现中断相关函数 ¶
get_cycles 函数通过内联汇编调用 rdtime 即可:
unsigned long get_cycles() {
unsigned long time;
asm volatile (
"rdtime %[time]"
: [time] "=r" (time)
: : "memory"
);
return time;
}
clock_set_next_event 函数里计算出 next_time 直接调用 sbi_set_timer 即可:
void clock_set_next_event() {
unsigned long next_time = get_cycles() + TIMECLOCK;
sbi_set_timer(next_time);
}
运行结果 ¶
make run 结果输出正确:
思考题 ¶
解释 OpenSBI 输出 MIDELEG、MEDELEG 含义 ¶
MIDELEG(machind interrupt delegation register
MIDELEG 输出值为 0x222(0b1000100010
机器启动后 time、cycle 寄存器分别是从 0 开始计时的吗?¶
make debug 启动,gdb 连接后直接输出 time 寄存器和 cycle 寄存器的值,可见 time 值为 0,cycle 不为 0:
time 在开始时需要为 0,来记录启动时间。cycle 不需要为 0,因为其用处不大。
谈谈如何在一台不支持乘除法指令扩展的处理器上执行乘除法指令 ¶
在一台不支持乘法指令扩展的处理器上遇到乘法指令会触发 Illegal Instruction 异常(对应值为 2
创建日期: 2022年12月10日 22:48:28