Skip to content

Commit

Permalink
Complete ch2-2.
Browse files Browse the repository at this point in the history
  • Loading branch information
wyfcyx committed Jan 4, 2022
1 parent 5bc45bf commit 7a4707a
Show file tree
Hide file tree
Showing 6 changed files with 145 additions and 209 deletions.
2 changes: 1 addition & 1 deletion source/appendix-d/1asm.rst
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
RISCV汇编相关
RISCV 汇编相关
=========================

- `RISC-V Assembly Programmer's Manual <https://github.com/riscv/riscv-asm-manual/blob/master/riscv-asm.md>`_
Expand Down
2 changes: 1 addition & 1 deletion source/appendix-d/2rv.rst
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
RISCV硬件相关
RISCV 硬件相关
=========================

Quick Reference
Expand Down
2 changes: 2 additions & 0 deletions source/chapter1/6print-and-shutdown-based-on-sbi.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@

之前我们对 RustSBI 的了解仅限于它会在计算机启动时进行它所负责的环境初始化工作,并将计算机控制权移交给内核。但实际上作为内核的执行环境,它还有另一项职责:即在内核运行时响应内核的请求为内核提供服务。当内核发出请求时,计算机会转由 RustSBI 控制来响应内核的请求,待请求处理完毕后,计算机控制权会被交还给内核。从内存布局的角度来思考,每一层执行环境(或称软件栈)都对应到内存中的一段代码和数据,这里的控制权转移指的是 CPU 从执行一层软件的代码到执行另一层软件的代码的过程。这个过程和函数调用比较像,但是内核无法通过函数调用来请求 RustSBI 提供的服务,这是因为内核并没有和 RustSBI 链接到一起,我们仅仅使用 RustSBI 构建后的可执行文件,因此内核对于 RustSBI 的符号一无所知。事实上,内核需要通过另一种复杂的方式来“调用” RustSBI 的服务:

.. _term-llvm-sbicall:

.. code-block:: rust
:linenos:
Expand Down
68 changes: 40 additions & 28 deletions source/chapter2/0intro.rst
Original file line number Diff line number Diff line change
Expand Up @@ -123,33 +123,43 @@

.. code-block::
[RustSBI output]
[kernel] Hello, world!
[kernel] num_app = 3
[kernel] app_0 [0x8020b028, 0x8020c000)
[kernel] app_1 [0x8020c000, 0x8020d070)
[kernel] app_2 [0x8020d070, 0x8020e218)
[kernel] Loading app_0
Hello, world!
[kernel] IllegalInstruction in application, core dumped.
[kernel] Loading app_1
Into Test store_fault, we will insert an invalid store operation...
Kernel should kill this application!
[kernel] PageFault in application, core dumped.
[kernel] Loading app_2
3^10000=5079(MOD 10007)
3^20000=8202(MOD 10007)
3^30000=8824(MOD 10007)
3^40000=5750(MOD 10007)
3^50000=3824(MOD 10007)
3^60000=8516(MOD 10007)
3^70000=2510(MOD 10007)
3^80000=9379(MOD 10007)
3^90000=2621(MOD 10007)
3^100000=2749(MOD 10007)
Test power OK!
[kernel] Application exited with code 0
[kernel] Panicked at src/batch.rs:57 All applications completed!
[RustSBI output]
[kernel] Hello, world!
[kernel] num_app = 5
[kernel] app_0 [0x8020a038, 0x8020af90)
[kernel] app_1 [0x8020af90, 0x8020bf80)
[kernel] app_2 [0x8020bf80, 0x8020d108)
[kernel] app_3 [0x8020d108, 0x8020e0e0)
[kernel] app_4 [0x8020e0e0, 0x8020f0b8)
[kernel] Loading app_0
Hello, world!
[kernel] Application exited with code 0
[kernel] Loading app_1
Into Test store_fault, we will insert an invalid store operation...
Kernel should kill this application!
[kernel] PageFault in application, kernel killed it.
[kernel] Loading app_2
3^10000=5079(MOD 10007)
3^20000=8202(MOD 10007)
3^30000=8824(MOD 10007)
3^40000=5750(MOD 10007)
3^50000=3824(MOD 10007)
3^60000=8516(MOD 10007)
3^70000=2510(MOD 10007)
3^80000=9379(MOD 10007)
3^90000=2621(MOD 10007)
3^100000=2749(MOD 10007)
Test power OK!
[kernel] Application exited with code 0
[kernel] Loading app_3
Try to execute privileged instruction in U Mode
Kernel should kill this application!
[kernel] IllegalInstruction in application, kernel killed it.
[kernel] Loading app_4
Try to access privileged CSR in U Mode
Kernel should kill this application!
[kernel] IllegalInstruction in application, kernel killed it.
[kernel] Panicked at src/batch.rs:58 All applications completed!
本章代码树
-------------------------------------------------
Expand Down Expand Up @@ -204,7 +214,9 @@
├── bin(基于用户库 user_lib 开发的应用,每个应用放在一个源文件中)
│   ├── 00hello_world.rs
│   ├── 01store_fault.rs
│   └── 02power.rs
│   ├── 02power.rs
│   ├── 03priv_inst.rs
│   └── 04priv_csr.rs
├── console.rs
├── lang_items.rs
├── lib.rs(用户库 user_lib)
Expand Down
32 changes: 14 additions & 18 deletions source/chapter2/1rv-privilege.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@
本节导读
-------------------------------

为了保护我们的批处理操作系统不受到出错应用程序的影响并全程稳定工作,单凭软件实现是很难做到的,而是需要 CPU 提供一种特权级隔离机制,使CPU在执行应用程序和操作系统内核的指令时处于不同的特权级。本节主要介绍了特权级机制的软硬件设计思路,以及 RISC-V 的特权级架构,包括特权指令的描述。
为了保护我们的批处理操作系统不受到出错应用程序的影响并全程稳定工作,单凭软件实现是很难做到的,而是需要 CPU 提供一种特权级隔离机制,使 CPU 在执行应用程序和操作系统内核的指令时处于不同的特权级。本节主要介绍了特权级机制的软硬件设计思路,以及 RISC-V 的特权级架构,包括特权指令的描述。

特权级的软硬件协同设计
------------------------------------------

实现特权级机制的根本原因是应用程序运行的安全性不可充分信任。在上一章里,操作系统以库的形式和应用紧密连接在一起,构成一个整体来执行。随着应用需求的增加,操作系统的体积也越来越大;同时应用自身也会越来越复杂。由于操作系统会被频繁访问,来给多个应用提供服务,所以它可能的错误会比较快地被发现。但应用自身的错误可能就不会很快发现。由于二者通过编译器形成一个单一执行程序来执行,导致即使是应用程序本身的问题,也会让操作系统受到连累,从而可能导致整个计算机系统都不可用了。
所以,计算机科学家和工程师就想到一个方法,让相对安全可靠的操作系统运行在一个硬件保护的安全执行环境中,不受到应用程序的破坏;而让应用程序运行在另外一个无法破坏操作系统的执行环境中。

所以,计算机科学家和工程师就想到一个方法,让相对安全可靠的操作系统运行在一个硬件保护的安全执行环境中,不受到应用程序的破坏;而让应用程序运行在另外一个无法破坏操作系统的受限执行环境中。

为确保操作系统的安全,对应用程序而言,需要限制的主要有两个方面:

Expand Down Expand Up @@ -157,20 +158,14 @@ RISC-V 架构中一共定义了 4 种特权级:

.. _term-environment-call:

其中 **断点** (Breakpoint) 和 **执行环境调用** (Environment call) 两个异常(为了与其他非有意为之的异常区分,会把这种有意为之的指令称为 ``陷入````trap`` 类指令)是通过在上层软件中执行一条特定的指令触发的:执行 ``ebreak`` 这条指令之后就会触发断点陷入异常;而执行 ``ecall`` 这条指令时候则会随着 CPU 当前所处特权级而触发不同的 ``陷入`` 情况。从表中可以看出,当 CPU 分别处于 M/S/U 三种特权级时执行 ``ecall`` 这条指令会触发三种陷入(分别参考上表 Exception Code 为 11/9/8 对应的行)。
其中 **断点** (Breakpoint) 和 **执行环境调用** (Environment call) 两个异常(为了与其他非有意为之的异常区分,会把这种有意为之的指令称为 *陷入**trap* 类指令)是通过在上层软件中执行一条特定的指令触发的:执行 ``ebreak`` 这条指令之后就会触发断点陷入异常;而执行 ``ecall`` 这条指令时候则会随着 CPU 当前所处特权级而触发不同的 ``陷入`` 情况。从表中可以看出,当 CPU 分别处于 M/S/U 三种特权级时执行 ``ecall`` 这条指令会触发三种陷入(分别参考上表 Exception Code 为 11/9/8 对应的行)。

.. _term-sbi:
.. _term-abi:

在这里我们需要说明一下执行环境调用 ``ecall`` ,这是一种很特殊的会产生 ``陷入`` 的指令, :ref:`上图 <PrivilegeStack>` 中相邻两特权级软件之间的接口正是基于这种陷入
机制实现的。M 模式软件 SEE 和 S 模式的内核之间的接口被称为 **监督模式二进制接口** (Supervisor Binary Interface, SBI),而内核和
U 模式的应用程序之间的接口被称为 **应用程序二进制接口** (Application Binary Interface, ABI),当然它有一个更加通俗的名字—— **系统调用**
(syscall, System Call) 。而之所以叫做二进制接口,是因为它与高级编程语言的内部调用接口不同,是机器/汇编指令级的一种接口。事实上 M/S/U
三个特权级的软件可分别由不同的编程语言实现,即使是用同一种编程语言实现的,其调用也并不是普通的函数调用控制流,而是**陷入异常控制流** ,在该过程中会
切换 CPU 特权级。因此只有将接口下降到机器/汇编指令级才能够满足其跨高级语言的通用性和灵活性。
在这里我们需要说明一下执行环境调用 ``ecall`` ,这是一种很特殊的会产生 *陷入* 的指令, :ref:`上图 <PrivilegeStack>` 中相邻两特权级软件之间的接口正是基于这种陷入机制实现的。M 模式软件 SEE 和 S 模式的内核之间的接口被称为 **监督模式二进制接口** (Supervisor Binary Interface, SBI),而内核和 U 模式的应用程序之间的接口被称为 **应用程序二进制接口** (Application Binary Interface, ABI),当然它有一个更加通俗的名字—— **系统调用** (syscall, System Call) 。而之所以叫做二进制接口,是因为它与高级编程语言的内部调用接口不同,是机器/汇编指令级的一种接口。事实上 M/S/U 三个特权级的软件可分别由不同的编程语言实现,即使是用同一种编程语言实现的,其调用也并不是普通的函数调用控制流,而是 **陷入异常控制流** ,在该过程中会切换 CPU 特权级。因此只有将接口下降到机器/汇编指令级才能够满足其跨高级语言的通用性和灵活性。

可以看到,在这样的架构之下,每层特权级的软件都只能做高特权级软件允许它做的、且不会产生什么撼动高特权级软件的事情,一旦低特权级软件的要求超出了其能力范围,
就必须寻求高特权级软件的帮助,否则就是一种异常行为了。因此,在软件(应用、操作系统等)执行过程中我们经常能够看到特权级切换。如下图所示:
可以看到,在这样的架构之下,每层特权级的软件都只能做高特权级软件允许它做的、且不会产生什么撼动高特权级软件的事情,一旦低特权级软件的要求超出了其能力范围,就必须寻求高特权级软件的帮助,否则就是一种异常行为了。因此,在软件(应用、操作系统等)执行过程中我们经常能够看到特权级切换。如下图所示:

.. image:: EnvironmentCallFlow.png
:align: center
Expand All @@ -184,7 +179,8 @@ U 模式的应用程序之间的接口被称为 **应用程序二进制接口**

RISC-V的特权指令
^^^^^^^^^^^^^^^^^^^^^^^^^
与特权级无关的一般的指令和通用寄存器 ``x0~x31`` 在任何特权级都可以执行。而每个特权级都对应一些特殊指令和 **控制状态寄存器** (CSR, Control and Status Register) ,来控制该特权级的某些行为并描述其状态。当然特权指令不仅具有读写 CSR 的指令,还有其他功能的特权指令。

与特权级无关的一般的指令和通用寄存器 ``x0`` ~ ``x31`` 在任何特权级都可以执行。而每个特权级都对应一些特殊指令和 **控制状态寄存器** (CSR, Control and Status Register) ,来控制该特权级的某些行为并描述其状态。当然特权指令不仅具有读写 CSR 的指令,还有其他功能的特权指令。

如果处于低特权级状态的处理器执行了高特权级的指令,会产生非法指令错误的异常。这样,位于高特权级的执行环境能够得知低特权级的软件出现了错误,这个错误一般是不可恢复的,此时执行环境会将低特权级的软件终止。这在某种程度上体现了特权级保护机制的作用。

Expand All @@ -201,15 +197,15 @@ RISC-V的特权指令
* - 指令
- 含义
* - sret
- 从S模式返回U模式:在U模式下执行会产生非法指令异常
- 从 S 模式返回 U 模式:在 U 模式下执行会产生非法指令异常
* - wfi
- 处理器在空闲时进入低功耗状态等待中断:在U模式下执行会产生非法指令异常
- 处理器在空闲时进入低功耗状态等待中断:在 U 模式下执行会产生非法指令异常
* - sfence.vma
- 刷新TLB缓存:在U模式下执行会产生非法指令异常
* - 访问S模式CSR的指令
- 通过访问 :ref:`sepc/stvec/scause/sscartch/stval/sstatus/satp等CSR <term-s-mod-csr>` 来改变系统状态:在U模式下执行会产生非法指令异常
- 刷新 TLB 缓存:在 U 模式下执行会产生非法指令异常
* - 访问 S 模式 CSR 的指令
- 通过访问 :ref:`sepc/stvec/scause/sscartch/stval/sstatus/satp等CSR <term-s-mod-csr>` 来改变系统状态:在 U 模式下执行会产生非法指令异常

在下一节中,我们将看到 :ref:`在U模式下运行的用户态应用程序 <term-csr-instr-app>` ,如果执行上述S模式特权指令,将会产生非法指令异常,从而看出RISC-V的特权模式提供了对操作系统一定程度的保护
在下一节中,我们将看到 :ref:`在 U 模式下运行的用户态应用程序 <term-csr-instr-app>` ,如果执行上述 S 模式特权指令,将会产生非法指令异常,从而看出 RISC-V 的特权模式提供了对操作系统一定程度的保护


..
Expand Down
Loading

0 comments on commit 7a4707a

Please sign in to comment.