Skip to content

Latest commit

 

History

History
111 lines (74 loc) · 4.01 KB

lab1_practice.md

File metadata and controls

111 lines (74 loc) · 4.01 KB

实验一:中断

实验之前

git clone https://github.com/rcore-os/rCore-Tutorial.git
cd rCore-Tutorial
git checkout lab-1

实验题

  1. 简述:在 rust_main 函数中,执行 ebreak 命令后至函数结束前,sp 寄存器的值是怎样变化的?

    分析过程:

    1. 修改Makefile,为gdb增加-tui参数,方便调试

    2. 执行make debug,并在rust_main__interrupt处,及第44行打断点,然后continue

      $ make debug
      (gdb) b rust_main
      (gdb) b __interrupt
      (gdb) b 44
      (gdb) c
    3. 使用next指令单步执行到llvm_asm!("ebreak");,执行info registers sp查看此时的sp值,

      (gdb) info registers sp
      sp             0x802165f0       0x802165f0
    4. 输入continue使其继续执行,然后代码在__interrupt处暂停,再次查看此时的sp值:

      (gdb) info registers sp
      sp             0x802164e0       0x802164e0

      这里sp的值改变了,原因为__interrupt内第一条指令即为:addi sp, sp, -34*8

      计算一下它们的差值:0x802165f0 - 0x802164e0 = 272 = 34 * 8,没有问题

    5. 继续在handle_interrupt函数处打断点,然后continue,此时sp的值为:

      (gdb) info registers sp
      sp             0x80216490       0x80216490

      计算得,栈顶减小了80 = 10 * 8字节

    6. 函数将执行match语句,并进入到breakpoint函数中,所以再打断点、continue,此时sp的值为:

      (gdb) info registers sp
      sp             0x80216400       0x80216400

      计算得,栈顶减小了144 = 18 * 8字节

    7. breakpoint函数结束后,栈顶变回0x80216490

    8. handler_interrupt函数结束后,栈顶变回0x802164e0

    9. __restore执行结束后,panic!宏执行前,栈顶变回0x802165f0

    回答:执行ebreak前,栈顶位置在0x802165f0,进入__interrupt后栈顶下降到0x802164e0,进入handler_interrupt函数后栈顶下降到0x80216490,进入breakpoint函数后栈顶下降到0x80216400

    从函数中退出后,栈顶再沿下降顺序逐次上升,最终执行完ebreak后又回到0x802165f0

  2. 回答:如果去掉 rust_main 后的 panic 会发生什么,为什么?

    首先,进入src/main.rs,将第44行panic!语句注释起来,然后开启gdb,在44行打断点,然后continuestep,发现此时函数进入了riscv::register::scause::Scause::is_interrupt函数内

    继续使用next单步跟踪,进入到了riscv::register::scause::Scause::cause函数……

    最终的结果为,触发LoadFault异常而退出:

    src/interrupt/handler.rs:59: 'Unresolved interrupt: Exception(LoadFault)

    解答:去掉panic后,代码会随即进入entry.asm后面的库函数,最终会因为LoadFault异常而终止运行。

  3. 实验

    1. src/interrupt/handler.rshandler_interrupt函数的match语句中添加如下代码:

      // 访存异常
      Trap::Exception(Exception::LoadFault) => loadfault(context, stval),
    2. 查询《RISC-V手册》得知:异常发生时,stval会被设置成出错的地址或者其它特定异常的信息字,这里应设为出错的地址,所以在src/interrupt/handler.rs中定义如下函数:

      /// 处理访存异常情况
      ///
      /// 如果要访问的内存为0x0,则输出SUCCESS!
      /// 处理完成后要将 `sepc` 增加 2 字节,否则 `pc` 值不变的话会发生死循环,不停输出SUCCESS!
      fn loadfault(context: &mut Context, stval: usize) {
          if stval == 0 {
              println!("SUCCESS!");
          }
          context.sepc += 2;
      }
    3. 去掉src/main.rs中,rust_main函数最后的panic!,因为它会导致关机,然后在src/entry.asm中,jal rust_main之后添加jr x0,运行即可