实验一: 中断
实验题:
1.原理:在rust_main函数中,执行ebreak
命令后至函数结束前,sp
寄存器的值是怎样变化的?
在rust_main函数中执行ebreak
进入中断,首先需要在栈上开辟Context所需空间,即将栈顶(即sp
寄存器)减去 34*8 bits。随后在__restore
中恢复了sp
寄存器中位置。
2.分析:如果去掉 rust_main
后的 panic
会发生什么,为什么?
去掉rust_main后的panic
后程序将不会立刻返回。执行ebreak
函数后进入到interrupt_handler
函数中,判断为断点后进入breakpoint
函数进行处理,在breakpoint
函数中打印出断点位置并将sepc
寄存器+2后返回,调用__restore
函数恢复所有寄存器,并跳转至Context
中sepc
的位置上,即会回到entry.asm
中,此时entry.asm
函数后并未做任何处理。
3.实验:
I. 如果程序访问不存在的地址,会得到 Exception::LoadFault
。模仿捕获 ebreak
和时钟中断的方法,捕获 LoadFault
(之后 panic
即可)
1 | pub fn handle_interrupt(context: &mut Context, scause: Scause, stval: usize) { |
在match
中加入对Exception::LoadFault
异常的处理。在load_falut
函数中直接panic!
II. 在处理异常的过程中,如果程序想要非法访问的地址是 0x0
,则打印 SUCCESS!
答:
1 | // Handler Load Fault |
III. 添加或修改少量代码,使得运行时触发这个异常,并且打印出 SUCCESS!
。
- 要求:不允许添加或修改任何 unsafe 代码
在handle_interript
函数下加入context.sepc = 0;
将触发中断指令地址设置为0,即可跳转到加载地址异常。