pull/18/head
liguo 2 years ago
parent 08c5b4f8d2
commit 353b3406bb

@ -433,20 +433,18 @@ SUMpermit Supervisor User Memory access位用于控制S模式下的虚拟
实际系统中导致中断发生的事件往往是比较复杂的,它们的来源、处理时机和返回方式都不尽相同。为了便于读者对中断的理解以及表达的准确性,我们借鉴参考文献[SiFive Interrupt](#refenences)的中断分类标准将系统中发生的可能中断当前执行程序的事件分为3类
**Exception**(异常):这类中断是处理器在执行某条指令时,由于条件不满足而产生的。典型的异常有缺页、执行当前特权级不支持的指令等。**相对于正在执行的程序而言exception是同步synchronous发生的。exception产生的时机是指令执行的过程中即处理器流水线的执行阶段在exception处理完毕后系统将返回发生exception的那条指令重新执行**。
**Trap**即我们通常理解的“系统调用”或者“软件中断”但是我们不建议把它翻译为“陷阱”因为“陷阱”这个词在中文语境的含义甚至和“中断”一样宽泛。RISC-V中trap等同于syscall为了与其他类型的中断进行区分**我们更推荐使用syscall来指代这类中断**这类中断是当前执行的程序主动发出的ecall指令类似8086中的int指令导致的。典型的trap有屏幕输出printf、磁盘文件读写read/write这些高级语言函数调用通过系统函数库libc的转换在RISC-V平台都会转换成ecall指令。**与exception类似相对于正在执行的程序而言syscall也是同步synchronous发生的。但与exception不同的地方在于syscall在处理完成后返回的是下一条指令。**
**Interrupt**我们不建议对它进行任何形式的翻译因为“中断”在中文语境中的含义过于宽泛这类中断一般是由外部设备产生的事件而导致的。在Intel的x86系列处理器中interrupt也被称为IRQInterrupt ReQuest实际上**我们更推荐使用IRQ来指代外部中断**用Interrupt往往导致指代范围太宽泛的问题。典型的IRQ有可编程时钟计时器PIT所产生的timer事件、DMA控制器发出的I/O完成事件、声卡发出的缓存空间用完事件等。**相对于正在执行的程序而言interrupt是异步asynchronous发生的。另外对于处理器流水线而言interrupt的处理时机是指令的间隙。不同于exception但与trap类似interrupt在处理完成后返回的是下一条指令**。
**Syscall**系统调用这类中断是当前执行的程序主动发出的ecall指令类似8086中的int指令导致的即我们通常理解的“系统调用”。实际上RISC-V术语中称这类中断为trap但是我们认为trap并不准确且强烈不建议把它翻译为“陷阱”因为“陷阱”这个词在中文语境的含义甚至和“中断”一样宽泛**我们更推荐使用syscall对应的中文翻译是“系统调用”来指代这类中断**。典型的syscall有屏幕输出printf、磁盘文件读写read/write这些高级语言函数调用通过系统函数库libc的转换在RISC-V平台都会转换成ecall指令。与exception类似相对于正在执行的程序而言**syscall也是同步synchronous发生的。但与exception不同的地方在于syscall在处理完成后返回的是下一条指令**。
**IRQ**外部中断这类中断一般是由外部设备产生的事件而导致的。实际上RISC-V术语中称这类中断为interrupt但我们认为在操作系统语境下用这个词并不合适因为interrupt特别是它的中文翻译“中断”往往导致指代范围太宽泛的问题。IRQInterrupt ReQuest来源于Intel的术语我们认为用它来指代外部中断更加准确和不容易导致混淆。典型的IRQ有可编程时钟计时器PIT所产生的timer事件、DMA控制器发出的I/O完成事件、声卡发出的缓存空间用完事件等。**相对于正在执行的程序而言IRQ是异步asynchronous发生的**。另外对于处理器流水线而言IRQ的处理时机是指令的间隙。不同于exception但与syscall类似**IRQ在处理完成后返回的是下一条指令**。
表1.6 中断的分类
| 中断类型 | 产生时机 | 处理时机 | 返回地址 |
| ------------------- | ------------------ | ------------ | -------------- |
| Exception | 同步(于当前程序) | 指令执行阶段 | 发生异常的指令 |
| Trap (**syscall**) | 同步(于当前程序) | - | 下一条指令 |
| Interrupt (**IRQ**) | 异步(于当前程序) | 指令执行间隙 | 下一条指令 |
| Exception(异常) | 同步(于当前程序) | 指令执行阶段 | 发生异常的指令 |
| Syscall系统调用 | 同步(于当前程序) | - | 下一条指令 |
| IRQ外部中断 | 异步(于当前程序) | 指令执行间隙 | 下一条指令 |
表1.6对这3类中断进行了归纳和比较。需要注意的是不同文献特别是中文文献对于某个类型的中断可能用了不同的名字例如trap在很多文献和参考书中又被称为“陷阱”、“陷入”、“软件中断”或“系统调用”等等。
表1.6对这3类中断进行了归纳和比较。需要注意的是不同文献特别是中文文献对于某个类型的中断可能用了不同的名字例如trap在很多文献和参考书中又被称为“陷阱”、“陷入”、“软件中断”或“系统调用”等等,具体指代往往不知所云
面对纷繁复杂的术语,我们给读者的建议是:**描述某个确定的中断时,尽量用英文单词来表达(不要翻译成中文,特别是避免使用“中断”或“陷入”这类含义太宽泛的名词)**。实际上,当需要描述某个新类型的中断时,可以试着根据这个中断的产生、处理的时机,以及返回的位置来对它进行分类和归纳,并翻译成它对应的类名。这样,听众一听就知道该中断的类型以及对应的处理方式了,避免了很多不必要、啰嗦且含糊的解释。
@ -494,7 +492,7 @@ SUMpermit Supervisor User Memory access位用于控制S模式下的虚拟
从表1.7中我们可以看到首先当发生的中断类型是interrupt时mcause的高位为1而如果发生的中断类型是exception或trapmcause的高位为0其次对于interrupt而言一个特权模式只有一些可能的取值。例如对于M模式interrupt的code的可能典型取值和含义为
● 3Machine software interrupt。这种类型的中断是由软件产生的但是却不是exception或者trap实际上这类interrupt主要是指在多核实际上RISC-V中的硬件处理单元称作硬件线程Hardware Threads简称Harts一般情况下它等同于“处理器核”的概念环境下的处理期间中断。为了实现这类中断RISC-V是通过让一个核直接写另一个核的本地中断控制器来实现的。需要注意的是这里的software interrupt并不是我们通常理解的“软件中断”更不是trap或syscall
● 3Machine software interrupt。这种类型的中断是由软件产生的但是却不是exception或者syscall实际上这类interrupt主要是指在多核实际上RISC-V中的硬件处理单元称作硬件线程Hardware Threads简称Harts一般情况下它等同于“处理器核”的概念环境下,发生在处理器之间的中断。为了实现这类中断RISC-V是通过让一个处理器核直接写另一个处理器核的本地中断控制器来实现的。
● 7Machine timer interrupt。即时钟中断它也是由处理器核所带的本地中断控制器产生的。
@ -502,11 +500,11 @@ SUMpermit Supervisor User Memory access位用于控制S模式下的虚拟
● >=16Implementation defined local interrupts。与实现相关的其他中断源对于RV64G指令集而言这个数字可以到48RV32G是16。数字越大意味着可以接更多的外部中断源。
最后对于非interrupt即表1.7的Interrupt=0情况Code=8时表示发生的是一个来自U模式的trapEnvironment call from U-modeCode=9时表示发生的是一个来自S模式的trapEnvironment call from S-mode而Code=11时表示发生的是一个来自M模式的trapEnvironment call from M-mode。需要再次强调的是这里的trap就是我们平时所说的“系统调用”或者“syscall在8086环境下它们由int指令产生而在RISC-V环境下它们由ecall指令产生。
最后对于非interrupt即表1.7的Interrupt=0情况Code=8时表示发生的是一个来自U模式的syscallEnvironment call from U-modeCode=9时表示发生的是一个来自S模式的syscallEnvironment call from S-mode而Code=11时表示发生的是一个来自M模式的syscallEnvironment call from M-mode。需要再次强调的是这里的syscall就是我们平时所说的“系统调用在8086环境下它们由int指令产生而在RISC-V环境下它们由ecall指令产生。
除了这几个取值外表1.7中其他的Interrupt=0的情况就都是exception。例如当Code=13Load page fault就是常见的所谓“缺页中断实际上应该叫它缺页exception”了Code=15Store/AMO page fault就是访存Store或原子操作AMO异常这些异常在我们的PKE实验中都能接触到。
除了这几个取值外表1.7中其他的Interrupt=0的情况就都是exception。例如当Code=13Load page fault就是常见的所谓“缺页中断实际上应该叫它缺页exception”了Code=15Store/AMO page fault就是访存Store或原子操作AMO异常这些异常在我们的PKE实验中都能接触到,碰到这类异常往往意味着代码里存在写空指针错误
仍然以机器模式为例在RISC-V处理器中中断向量表的组织和实现有两种方式一种是直接模式Direct Mode另一种是向量模式Vectored Mode。前一种模式将CSR中的mtvec指向所有中断包括表1.7中所有的interruption、trap和exception的总入口函数然后由该函数根据mcause中具体的值调用对应的中断例程。向量模式则严格按照表1.7所示的顺序将所有中断例程的入口地址组织成一个向量类似8086中的中断向量表并将mtvec指向该表的首地址。当发生中断时根据mcause中的值计算向量中的偏移并调用对应例程。RISC-V是根据mtvec的最低位mtvec.mode来判断系统具体采用了哪种模式如果采用了直接模式其最低位为0如果采用了向量模式则其最低位为1。需要指出的是我们的PKE在中断向量上使用的是直接模式
仍然以机器模式为例在RISC-V处理器中中断向量表的组织和实现有两种方式一种是直接模式Direct Mode另一种是向量模式Vectored Mode。前一种模式将CSR中的mtvec指向所有中断包括表1.7中所有的interruption、trap和exception的总入口函数然后由该函数根据mcause中具体的值调用对应的中断例程。向量模式则严格按照表1.7所示的顺序将所有中断例程的入口地址组织成一个向量类似8086中的中断向量表并将mtvec指向该表的首地址。当发生中断时根据mcause中的值计算向量中的偏移并调用对应例程。RISC-V是根据mtvec的最低位mtvec.mode来判断系统具体采用了哪种模式如果采用了直接模式其最低位为0如果采用了向量模式则其最低位为1。在PKE实验中我们在中断向量上使用的是直接模式Direct Mode
@ -514,13 +512,13 @@ SUMpermit Supervisor User Memory access位用于控制S模式下的虚拟
当发生一个中断假设其目标模式即执行中断例程的模式为机器模式RISC-V处理器硬件将执行以下动作
1保存进入中断处理历程之前的pc如果是trap或者interrupt则保存下一条指令的pc到mepc寄存器
1保存进入中断处理例程之前的pc如果是syscall或者IRQ则保存下一条指令的pc到mepc寄存器
2进入中断处理程之前的特权级保存到mstatus寄存器的MPP字段
2进入中断处理程之前的特权级保存到mstatus寄存器的MPP字段
3将mstatus寄存器中的MIE字段保存到它自己的MPIE字段
4设置mcause其值与表1.6中的Interrupt和Exception code对应;
4设置mcause其值与表1.7中的Interrupt和Code值对应;
5将pc设置为中断例程的入口如果为直接模式则设置为mtvec的值
@ -566,7 +564,7 @@ mret
**1.4.4 RISC-V的中断代理机制**
RISC-V在中断处理上有一个很有意思的设计就是可以将系统中的特定中断或者异常通过设置较高特权级的CSR寄存器“代理”某个更低的特权级处理。例如我们可以设置机器模式的mideleg以及medeleg中的某些位将系统中的部分中断对应mideleg或异常对应medeleg“代理”给较低特权级的监管模式来处理同理我们也可以设置监管模式的sideleg以及sedeleg中的某些位将系统中的部分中断或异常“代理”给用户特权级的代码来处理。
RISC-V在中断处理上有一个很有意思的设计就是可以将系统中的特定中断或者异常通过设置较高特权级的CSR寄存器“代理”某个更低的特权级处理。例如我们可以设置机器模式的mideleg以及medeleg中的某些位将系统中的部分中断对应mideleg或异常对应medeleg“代理”给较低特权级的监管模式来处理同理我们也可以设置监管模式的sideleg以及sedeleg中的某些位将系统中的部分中断或异常“代理”给用户特权级的代码来处理。
例如我们的PKE代码中有以下的等效代码
@ -575,7 +573,7 @@ csrw mideleg, 1<<1 | 1<<5 | 1<<9
csrw medeleg, 1<<0 | 1<< 3 | 1<<8 | 1<<12 | 1<<13 | 1<<15
```
这段代码的作用是将M模式中interrupt中的1、5和9号分别对应Supervisor software interruptSupervisor timer interrupt和Supervisor external interrupt代理出去到S模式处理再将M模式中的exceptiontrap中的0、3、8、12、13和15号分别对应Instruction address misaligned调试中断Breakpoint3号用户态系统调用Environment call from U-mode8号缺页或访存异常12、13和15号代理出去到S模式处理。实际上将这些重要的中断代理出去后系统中产生的绝大部分中断事件将都在S模式处理。所以在其后的PKE实验中读者主要跟U模式以及S模式的代码打交道除启动过程和一些简单的设置如访存、中断代理等实验也基本不涉及M模式的代码。
这段代码的作用是将M模式中interrupt中的1、5和9号分别对应Supervisor software interruptSupervisor timer interrupt和Supervisor external interrupt代理出去到S模式处理再将M模式中的exceptionsyscall中的0、3、8、12、13和15号分别对应Instruction address misaligned调试中断Breakpoint3号用户态系统调用Environment call from U-mode8号缺页或访存异常12、13和15号代理出去到S模式处理。实际上将这些重要的中断代理出去后系统中产生的绝大部分中断事件将都在S模式处理。所以在其后的PKE实验中读者主要跟U模式以及S模式的代码打交道除启动过程和一些简单的设置如访存、中断代理等实验也基本不涉及M模式的代码。
<a name="paging"></a>
### 1.5 页式虚存管理

@ -236,7 +236,7 @@ PKE实验中创建一个进程需要先调用kernel/process.c文件中的allo
156 }
```
通过以上代码可以发现alloc_process()函数除了找到一个空的进程结构外还为新创建的进程建立了KERN_BASE以上逻辑地址的映射这段代码在实验3之前位于kernel/kernel.c文件的load_user_program()函数中在本实验中还额外添加了HEAP_SEGMENT段的映射),并将映射信息保存到了进程结构中
通过以上代码可以发现alloc_process()函数除了找到一个空的进程结构外还为新创建的进程建立了KERN_BASE以上逻辑地址的映射这段代码在实验3之前位于kernel/kernel.c文件的load_user_program()函数中并将映射信息保存到了进程结构中。在本实验中还额外添加了HEAP_SEGMENT段的映射第148--150行。同时可以看出对于未调用sys_user_allocate_page分配堆区页面的进程其堆段的大小为0第149行不会被分配页面
对于给定应用PKE将通过调用load_bincode_from_host_elf()函数载入给定应用对应的ELF文件的各个段。之后被调用的elf_load()函数在载入段后,将对被载入的段进行判断,以记录它们的虚地址映射:

Loading…
Cancel
Save