diff --git a/source/chapter2/4trap-handling.rst b/source/chapter2/4trap-handling.rst index 07a586398..c7563bb9d 100644 --- a/source/chapter2/4trap-handling.rst +++ b/source/chapter2/4trap-handling.rst @@ -119,7 +119,7 @@ RISC-V特权级切换 当 CPU 执行完一条指令(如 ``ecall`` )并准备从用户特权级 陷入( ``Trap`` )到 S 特权级的时候,硬件会自动完成如下这些事情: - ``sstatus`` 的 ``SPP`` 字段会被修改为 CPU 当前的特权级(U/S)。 -- ``sepc`` 会被修改为 Trap 处理完成后默认会执行的下一条指令的地址。 +- ``sepc`` 会被修改为被中断或触发异常的指令的地址。如 CPU 执行 ``ecall`` 指令会触发异常,则 ``sepc`` 会被设置为 ``ecall`` 指令的地址。 - ``scause/stval`` 分别会被修改成这次 Trap 的原因以及相关的附加信息。 - CPU 会跳转到 ``stvec`` 所设置的 Trap 处理入口地址,并将当前特权级设置为 S ,然后从Trap 处理入口地址处开始执行。 @@ -150,7 +150,7 @@ RISC-V特权级切换 .. chy:我们在一个作为用户栈的特别留出的内存区域上保存应用程序的栈信息,而 Trap 执行流则使用另一个内核栈。 -使用两个不同的栈主要是为了安全性:如果两个控制流(即应用程序的控制流和内核的控制流)使用同一个栈,在返回之后应用程序就能读到 Trap 控制流的历史信息,比如内核一些函数的地址,这样会带来安全隐患。于是,我们要做的是,在批处理操作系统中添加一段汇编代码,实现从用户栈切换到内核栈,并在内核栈上保存应用程序控制流的寄存器状态。 +使用两个不同的栈主要是为了安全性:如果两个控制流(即应用程序的控制流和内核的控制流)使用同一个栈,在返回之后应用程序就能读到 Trap 控制流的历史信息,比如内核一些函数的地址,这样会带来安全隐患。于是,我们要做的是,在批处理操作系统中添加一段汇编代码,实现从用户栈切换到内核栈,并在内核栈上保存应用程序控制流的寄存器状态。不过需要注意的是,在没有启用虚拟内存的情况下,用户态代码依然可以通过物理地址访问整个内存空间,包括内核栈区域。 我们声明两个类型 ``KernelStack`` 和 ``UserStack`` 分别表示内核栈和用户栈,它们都只是字节数组的简单包装: