Update chapter3_traps.md

pull/1/head
Zhiyuan Shao 3 years ago
parent 87e90fbd66
commit 467f78500f

@ -957,7 +957,7 @@ lab1_1实验需要读者了解和掌握操作系统中系统调用机制的实
27 } 27 }
``` ```
我们发现do_user_call函数是通过ecall指令完成系统调用的且在执行ecall指令前所有的参数即do_user_call函数的8个参数实际上都已经载入到RISC-V机器的a0到a7这8个寄存器中这一步是我们的编译器生成的代码帮我们完成的。ecall指令的执行将根据a0中的值获得系统调用号并使RISC-V转到S模式因为我们的操作系统内核启动时将所有的中断、异常、系统调用都代理给了S模式的trap处理入口执行在kernel/strap_vector.S文件中定义 我们发现do_user_call函数是通过ecall指令完成系统调用的且在执行ecall指令前所有的参数即do_user_call函数的8个参数实际上都已经载入到RISC-V机器的a0到a7这8个寄存器中这一步是我们的编译器生成的代码帮我们完成的。ecall指令的执行将根据a0寄存器中的值获得系统调用号并使RISC-V转到S模式因为我们的操作系统内核启动时将所有的中断、异常、系统调用都代理给了S模式的trap处理入口执行在kernel/strap_vector.S文件中定义
```assembly ```assembly
16 .globl smode_trap_vector 16 .globl smode_trap_vector
@ -984,7 +984,13 @@ lab1_1实验需要读者了解和掌握操作系统中系统调用机制的实
37 jr t0 37 jr t0
``` ```
从以上代码我们可以看到trap的入口处理函数首先将“进程”即我们的obj/app_helloworld的运行现场进行保存第24行接下来将a0寄存器中的系统调用号保存到内核堆栈第27--28行再将p->trapframe->kernel_sp指向的为应用进程分配的内核栈设置到sp寄存器第31行即切换堆栈而不使用PKE内核自己的栈**这里请读者思考为何要这样安排?**后续的执行将使用应用进程所附带的内核栈来保存执行的上下文如函数调用、临时变量这些最后将应用进程中的p->trapframe->kernel_trap写入t0寄存器第34行并最后第37行调用p->trapframe->kernel_trap所指向的smode_trap_handler()函数。 从以上代码我们可以看到trap的入口处理函数首先将“进程”即我们的obj/app_helloworld的运行现场进行保存第24行接下来将a0寄存器中的系统调用号保存到内核堆栈第27--28行再将p->trapframe->kernel_sp指向的为应用进程分配的内核栈设置到sp寄存器第31行**该过程实际上完成了栈的切换**。完整的切换过程为:
- 1应用程序在U模式即应用态执行这个时候是使用的操作系统为其分配的栈称为用户栈这一部分参见`kernel/kernel.c`文件中`load_user_program`的实现;
- 2应用程序调用ecall后陷入内核开始执行`smode_trap_vector`函数,此时使用的是操作系统内核的栈。参见`kernel/machine/mentry.S`文件中的PKE入口`_mentry`
- 3中断处理例程`smode_trap_vector`函数执行到第31行时将栈切换到用户进程“自带”的“用户内核栈“也就是`kernel/process.c`文件中`switch_to`函数的第35行所引用的`proc->kstack`而不使用PKE内核自己的栈**这里请读者思考为何要这样安排**
后续的执行将使用应用进程所附带的内核栈来保存执行的上下文如函数调用、临时变量这些最后将应用进程中的p->trapframe->kernel_trap写入t0寄存器第34行并最后第37行调用p->trapframe->kernel_trap所指向的smode_trap_handler()函数。
smode_trap_handler()函数的定义在kernel/strap.c文件中采用C语言编写 smode_trap_handler()函数的定义在kernel/strap.c文件中采用C语言编写
@ -1051,7 +1057,7 @@ handle_syscall()函数的定义也在kernel/strap.c文件中
但是做实验的时候需要读者思考在handle_syscall()函数中调用do_syscall()函数后者的参数怎么办毕竟有8个long类型因为我们的机器是RV64Glong类型占据8个字节的参数另外do_syscall()函数的返回值怎么处理毕竟do_syscall()函数有一个long类型的返回值而这个返回值是要通知应用程序它发出的系统调用是否成功的。 但是做实验的时候需要读者思考在handle_syscall()函数中调用do_syscall()函数后者的参数怎么办毕竟有8个long类型因为我们的机器是RV64Glong类型占据8个字节的参数另外do_syscall()函数的返回值怎么处理毕竟do_syscall()函数有一个long类型的返回值而这个返回值是要通知应用程序它发出的系统调用是否成功的。
除了实验内容之外在handle_syscall()函数的第19行有一个`tf->epc += 4;`语句,**这里请读者思考为什么要将tf->epc的值进行加4处理**这个问题请结合你对RISC-V指令集架构的理解以及系统调用的原理回答。 除了实验内容之外在handle_syscall()函数的第19行有一个`tf->epc += 4;`语句,**这里请读者思考为什么要将tf->epc的值进行加4处理**这个问题请结合你对RISC-V指令集架构的理解以及系统调用的原理回答。另外,**我们的PKE操作系统内核是如何得到应用程序中“hello world!”字符串的地址的呢**

Loading…
Cancel
Save