|
|
|
@ -1,6 +1,6 @@
|
|
|
|
|
## 第三章.(实验2)系统调用的实现
|
|
|
|
|
# 第三章.(实验2)系统调用的实现
|
|
|
|
|
|
|
|
|
|
### 3.1 实验环境搭建
|
|
|
|
|
## 3.1 实验环境搭建
|
|
|
|
|
|
|
|
|
|
实验2需要在实验1的基础之上完成,所以首先你需要切换到lab2_small的branch,然后commit你的代码。
|
|
|
|
|
|
|
|
|
@ -32,17 +32,13 @@ lab5_small
|
|
|
|
|
|
|
|
|
|
完成一切后,我们就可以正式进入实验二了!
|
|
|
|
|
|
|
|
|
|
### 3.2 实验内容
|
|
|
|
|
## 3.2 实验内容
|
|
|
|
|
|
|
|
|
|
实验要求:了解系统调用的执行过程,并实现一个自定义的系统调用。
|
|
|
|
|
|
|
|
|
|
**3.2.1 练习一:在app中使用系统调用**
|
|
|
|
|
#### 应用: ####
|
|
|
|
|
|
|
|
|
|
系统调用的英文名字是System Call,用户通过系统调用来执行一些需要特权的任务,那么我们具体在app中是如何使用内核所提供的系统调用的呢?
|
|
|
|
|
|
|
|
|
|
RISC-V中提供了ecall指令,用于向运行时环境发出请求,我们可以使用内联汇编使用该指令,进行系统调用,代码如下:
|
|
|
|
|
app2_1.c源文件如下:
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
1 #define ecall() ({\
|
|
|
|
|
2 asm volatile(\
|
|
|
|
|
3 "li x17,81\n"\
|
|
|
|
@ -54,23 +50,58 @@ RISC-V中提供了ecall指令,用于向运行时环境发出请求,我们可
|
|
|
|
|
9 ecall();
|
|
|
|
|
10 return 0;
|
|
|
|
|
11 }
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
例3.1 ecall
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
以上代码中,我们将系统调用号81通过x17寄存器传给内核,再通过ecall指令进行系统调用,当然目前代理内核中并没有81号系统调用的实现,这需要我们在后面的实验中完成。
|
|
|
|
|
|
|
|
|
|
**3.2.2 练习二:系统调用过程跟踪**
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#### 任务一 : 在app中使用系统调用(理解) ####
|
|
|
|
|
|
|
|
|
|
任务描述:
|
|
|
|
|
|
|
|
|
|
系统调用的英文名字是System Call,用户通过系统调用来执行一些需要特权的任务,那么我们具体在app中是如何使用内核所提供的系统调用的呢?
|
|
|
|
|
|
|
|
|
|
RISC-V中提供了ecall指令,用于向运行时环境发出请求,我们可以使用内联汇编使用该指令,进行系统调用。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
预期输出:
|
|
|
|
|
|
|
|
|
|
理解app2_1的调用过程。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#### 任务二 : 系统调用过程跟踪(理解) ####
|
|
|
|
|
|
|
|
|
|
任务描述:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
在我们执行了ecall指令后,代理内核中又是如何执行的呢?
|
|
|
|
|
|
|
|
|
|
在第一章的表1.7中,我们可以看到Environment call from U-mode是exception(trap)的一种,其对应的code是8。我们在实验二中已经讨论过中断入口函数位置的设置,现在继续跟踪中断入口函数,找出系统调用的执行过程。
|
|
|
|
|
在第一章的表1.7中,我们可以看到Environment call from U-mode是exception(trap)的一种,其对应的code是8。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
预期输出:
|
|
|
|
|
|
|
|
|
|
我们在实验二中已经讨论过中断入口函数位置的设置,现在继续跟踪中断入口函数,找出系统调用的执行过程。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#### 任务三 : 自定义系统调用(编程) ####
|
|
|
|
|
|
|
|
|
|
任务描述:
|
|
|
|
|
|
|
|
|
|
**3.2.3 练习三:自定义系统调用(需要编程)**
|
|
|
|
|
|
|
|
|
|
阅读pk目录syscall.c文件,增加一个系统调用sys_get_memsize(),系统调用返回spike设置的内存空间大小, 系统调用号为81。
|
|
|
|
|
|
|
|
|
|
提示:在pk目录下的mmap.c文件中,函数pk_vm_init中定义了代理内核的内存空间大小。
|
|
|
|
|
|
|
|
|
|
预期输出:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
在pk目录下的mmap.c文件中,函数pk_vm_init中定义了代理内核的内存空间大小。
|
|
|
|
|
|
|
|
|
|
spike 通过-m来指定分配的物理内存,单位是MiB,默认为2048。如:
|
|
|
|
|
|
|
|
|
@ -111,7 +142,7 @@ test3_m1024 : OK
|
|
|
|
|
Score: 20/20
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### 3.3 基础知识
|
|
|
|
|
## 3.3 实验指导
|
|
|
|
|
|
|
|
|
|
**3.3.1 系统调用**
|
|
|
|
|
|
|
|
|
@ -236,9 +267,9 @@ Score: 20/20
|
|
|
|
|
221 }
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
在enter_supervisor_mode函数中,将 mstatus的MPP域设置为1,表示中断发生之前的模式是Supervisor,将mstatus的MPIE域设置为0,表示中断发生前MIE的值为0。随即将机器模式的内核栈顶写入mscratch寄存器中,设置mepc为rest_of_boot_loader的地址,并将kernel_stack_top与0作为参数存入a0和a1。
|
|
|
|
|
在enter_supervisor_mode函数中,将 mstatus的MPP域设置为1,表示中断发生之前的模式是Superior,将mstatus的MPIE域设置为0,表示中段发生前MIE的值为0。随机将机器模式的内核栈顶写入mscratch寄存器中,设置mepc为rest_of_boot_loader的地址,并将kernel_stack_top与0作为参数存入a0和a1。
|
|
|
|
|
|
|
|
|
|
最后,执行mret指令,该指令执行时,程序从机器模式的异常返回,将程序计数器pc设置为mepc,即rest_of_boot_loader的地址;将特权级设置为mstatus寄存器的MPP域,即方才所设置的代表Supervisor的1,MPP设置为0;将mstatus寄存器的MIE域设置为MPIE,即方才所设置的表示中断关闭的0,MPIE设置为1。
|
|
|
|
|
最后,执行mret指令,该指令执行时,程序从机器模式的异常返回,将程序计数器pc设置为mepc,即rest_of_boot_loader的地址;将特权级设置为mstatus寄存器的MPP域,即方才所设置的代表Superior的1,MPP设置为0;将mstatus寄存器的MIE域设置为MPIE,即方才所设置的表示中断关闭的0,MPIE设置为1。
|
|
|
|
|
|
|
|
|
|
于是,当mret指令执行完毕,程序将从rest_of_boot_loader继续执行。
|
|
|
|
|
|
|
|
|
@ -308,7 +339,7 @@ Score: 20/20
|
|
|
|
|
|
|
|
|
|
在61行,交换了sp与sscratch的值,这里是为了根据sscratch的值判断该中断是来源于U模式还是S模式。
|
|
|
|
|
|
|
|
|
|
如果sp也就是传入的sscratch值不为零,则跳转至64行,若sscratch的值为零,则恢复原sp中的值。这是因为,当中断来源于S模式时,sscratch的值为0,sp中存储的就是内核的堆栈地址。而当中断来源于U模式时,sp中存储的是用户的堆栈地址,sscratch中存储的则是内核的堆栈地址,需要交换二者,是sp指向内核的堆栈地址。
|
|
|
|
|
如果sp也就是传入的sscratch值不为零,则跳转至64行,若sscratch的值为零,则恢复原sp中的值。这是因为,当中断来源于S模式是,sscratch的值为0,sp中存储的就是内核的堆栈地址。而当中断来源于U模式时,sp中存储的是用户的堆栈地址,sscratch中存储的则是内核的堆栈地址,需要交换二者,是sp指向内核的堆栈地址。
|
|
|
|
|
|
|
|
|
|
接着在64,65行保存上下文,最后跳转至67行处理trap。handle_trap在pk目录下的handlers.c文件中,代码如下:
|
|
|
|
|
|
|
|
|
|