Delete '18组实验报告(栗端宇、贺子然) .md'

master
pv9jfohxb 4 years ago
parent 530c472321
commit e629819c4c

@ -1,357 +0,0 @@
# 操作系统实 验 报 告
## 实验名称: 系统调用扩充
---
学 员1栗端宇 学 号: 201902001022
学 员2贺子然 学 号: 201902001027
培养类型:无军籍本科学员
年 级2019级
专 业:计算机类
所属学院:计算机学院
指导教员:文艳军
职 称:教授
实 验 室306-704
实验日期: 2021.7.8
国防科学技术大学训练部制
---
《实验报告》填写说明
1. 学员完成人才培养方案和课程标准要所要求的每个实验后,均须提交实验报告。
2. 实验报告封面必须打印,报告内容可以手写或打印。
3. 实验报告内容编排及打印应符合以下要求:
1采用A421cm×29.7cm白色复印纸单面黑字打印。上下左右各侧的页边距均为3cm缺省文档网格字号为小4号中文为宋体英文和阿拉伯数字为Times New Roman每页30行每行36字页脚距边界为2.5cm页码置于页脚、居中采用小5号阿拉伯数字从1开始连续编排封面不编页码。
2报告正文最多可设四级标题字体均为黑体第一级标题字号为4号其余各级标题为小4号标题序号第一级用“一、”、“二、”……第二级用“”、“” ……第三级用“1.”、“2.” ……第四级用“1”、“2” ……,分别按序连续编排。
3正文插图、表格中的文字字号均为5号。
---
## 一、实验目的和内容
(一)实验目的:深入掌握系统调用的实现方法,掌握进程地址空间的表示方法,掌握可执行文件的加载过程,掌握 Linux 的页故障处理过程。
(二)实验内容:以版本 0 内核为基础,增加一组系统调用(详情如下),并通过给定的测试用例。
| **系统调用名字** | **功能** | **是否必做** |
| ---------------- | ------------------------------------------------------------ | ------------ |
| execve2 | 以“立即加载”方式执行一个可执行文件,要求加载完后运行时该进程不产生缺页异常。 | 是 |
| getdents | 获取一组目录项 | 是 |
| pipe2 | 创建管道 | 是 |
| sleep | 进程睡眠 | 是 |
| getcwd | 获取当前工作目录 | 否 |
| mmap | 将一个文件映射到进程地址空间中 | 否 |
| munmap | 解除文件到地址空间的映射 | 否 |
| clone | 创建进程,要求新进程共享当前进程除栈以外的地址空间 | 否 |
要求提交实验报告和所有源码,实验报告应记录各系统调用的设计思路、实现方法和测试过程及画面。
## 二、操作方法与实验步骤
### 1. 首先了解整个实验的工作流程,明确小组分工
认真阅读实验说明对实验进行整体把握通过011文件中的oscomp_syscalls.md文件了解实验的系统调用需要做什么事情然后明确小组分工。
### **2.** 添加八个系统调用的声明
因为使用到的系统调用都没有声明,因此应在内核代码中统一添加八个系统调用的声明和实现,修改unistd.h中的宏定义,sys_call_table。并且要保证虚拟机内的头文件与内核中保持一致。
添加系统调用号,在系统调用表中添加系统调用实现函数,声明系统调用实现函数(在sys.h中):
unistd.h代码修改如下
```C
#define __NR_execve2 87
#define __NR_getdents 88
#define __NR_pipe2 89
#define __NR_sleep 90
#define __NR_getcwd 91
#define __NR_mmap 92
#define __NR_munmap 93
#define __NR_clone 94
```
sys.h代码修改如下
```C
extern int sys_execve2();
extern int sys_getdents();
extern int sys_pipe2();
extern int sys_sleep();
extern int sys_getcwd();
extern int sys_mmap();
extern int sys_munmap();
extern int sys_clone();
fn_ptr sys_call_table[] = { sys_setup, sys_exit, sys_fork, sys_read,
sys_write, sys_open, sys_close, sys_waitpid, sys_creat, sys_link,
sys_unlink, sys_execve, sys_chdir, sys_time, sys_mknod, sys_chmod,
sys_chown, sys_break, sys_stat, sys_lseek, sys_getpid, sys_mount,
sys_umount, sys_setuid, sys_getuid, sys_stime, sys_ptrace, sys_alarm,
sys_fstat, sys_pause, sys_utime, sys_stty, sys_gtty, sys_access,
sys_nice, sys_ftime, sys_sync, sys_kill, sys_rename, sys_mkdir,
sys_rmdir, sys_dup, sys_pipe, sys_times, sys_prof, sys_brk, sys_setgid,
sys_getgid, sys_signal, sys_geteuid, sys_getegid, sys_acct, sys_phys,
sys_lock, sys_ioctl, sys_fcntl, sys_mpx, sys_setpgid, sys_ulimit,
sys_uname, sys_umask, sys_chroot, sys_ustat, sys_dup2, sys_getppid,
sys_getpgrp, sys_setsid, sys_sigaction, sys_sgetmask, sys_ssetmask,
sys_setreuid,sys_setregid, sys_sigsuspend, sys_sigpending, sys_sethostname,sys_setrlimit, sys_getrlimit, sys_getrusage, sys_gettimeofday, sys_settimeofday, sys_getgroups, sys_setgroups, sys_select, sys_symlink,sys_lstat, sys_readlink, sys_uselib,
sys_execve2,sys_getdents,sys_pipe2,sys_sleep,sys_getcwd,sys_mmap,sys_munmap,sys_clone
};
```
修改系统调用数量的宏定义如下图所示由原来的87个修改为95个:
```C
nr_system_calls = 95 /* 72 */
```
### **3.** 对内核进行修改,完成系统调用
使用mkdir test命令新建文件夹将老师给的include以及测试文件放入test文件夹将文件导入b文件夹使用mcopy命令导入内核在这里由于文件夹不能导入所以每导入一个文件夹需要创建一个空文件夹再导入其中的内容然后使用make指令生成可执行文件
![img](file:///C:\Users\19076\AppData\Local\Temp\ksohtml16212\wps4.jpg)![img](file:///C:\Users\19076\AppData\Local\Temp\ksohtml16212\wps5.jpg)
![img](file:///C:\Users\19076\AppData\Local\Temp\ksohtml16212\wps6.jpg)
![img](file:///C:\Users\19076\AppData\Local\Temp\ksohtml16212\wps7.jpg)
---
#### **(1) sys_execve2**
关键在于“立即加载”的实现。考虑在execve的基础上进行修改,先考察sys_execve的实现。其中调用了do_execve。先根据sys_execve的实现完全复制一个sys_execve2的实现:
```assembly
.align 4
sys_execve2:
lea EIP(%esp),%eax
pushl %eax
call do_execve2
addl $4,%esp
ret
```
同样复制一份do_execve2下面修改do_execve2:
do_no_page函数是处理缺页故障的函数,如果在do_execve2执行功能结束后人工调用do_no_page来处理故障,可以使得每一次do_execve2处理后都不出现缺页。(等于是把本来操作系统做的缺页处理提前到了do_execve2中),因此从current结构体里面找到do_no_page需要的参数:分别是进程的起始地址和数据段偏移。
```c
void do_no_page_myself(unsigned long error_code,unsigned long address)
{
int nr[4];
unsigned long tmp;
unsigned long page;
int block,i;
address &= 0xfffff000;
tmp = address - current->start_code;
if (!current->executable || tmp >= current->end_data) {
get_empty_page(address);
return;
}
if (share_page(tmp))
return;
if (!(page = get_free_page()))
oom();
/* remember that 1 block is used for header */
block = 1 + tmp/BLOCK_SIZE;
for (i=0 ; i<4 ; block++,i++)
nr[i] = bmap(current->executable,block);
bread_page(page,current->executable->i_dev,nr);
i = tmp + 4096 - current->end_data;
tmp = page + 4096;
while (i-- > 0) {
tmp--;
*(char *)tmp = 0;
}
if (put_page(page,address))
return;
free_page(page);
oom();
}
```
其中do_no_page_myself函数与do_no_page函数完全一致,重新复制是为了区分do_execve2与其余系统调用产生缺页的区别,方便调试。在execve2中修改代码如下修改部分红框标出
![img](file:///C:\Users\19076\AppData\Local\Temp\ksohtml16212\wps10.jpg)
测试代码运行如下,测试成功
![img](file:///C:\Users\19076\AppData\Local\Temp\ksohtml16212\wps11.jpg)
---
#### **(2) sys_getdents**
通过文件可知该系统调用目的在于获取目录项由上课学习的知识可知文件系统有PCB打开文件表、读写状态信息表、活跃文件目录表其中目录中的目录项储存在活跃文件目录表所指向的块中
![img](file:///C:\Users\19076\AppData\Local\Temp\ksohtml16212\wps12.jpg)
根据函数的参数类型可以发现我们可以根据fd变量找到当前目录并获得其读写信息表信息
```C
int getdents(unsigned int fd, struct linux_dirent *dirp, unsigned int count);
```
根据struct file的结构我们发现有指向活跃文件目录表的f_inode指针并据此我们得到该目录内容
![img](file:///C:\Users\19076\AppData\Local\Temp\ksohtml16212\wps13.jpg)
通过i_zone[]我们可以得到存放目录项得块内容
![img](file:///C:\Users\19076\AppData\Local\Temp\ksohtml16212\wps14.jpg)
![img](file:///C:\Users\19076\AppData\Local\Temp\ksohtml16212\wps15.jpg)
为了读取块中信息我们使用bread函数来读取理论上应该遍历i_zone但由于目录项只有16字节而一个块有1024字节可容纳64个目录项故不予考虑
```c
block=bread(f_inode->i_dev,f_inode->i_zone[0]);
```
根据bread函数返回值block是buffer_head *类型,指向块内容,块中目录项结构如图所示:
![img](file:///C:\Users\19076\AppData\Local\Temp\ksohtml16212\wps17.jpg)
然后根据老师要求的输出格式中将目录项结构中的inode和name进行赋值d_reclen赋linux_direntd_off赋0可以通过for循环遍历直到所有目录项被录入。
![img](file:///C:\Users\19076\AppData\Local\Temp\ksohtml16212\wps18.jpg)
![img](file:///C:\Users\19076\AppData\Local\Temp\ksohtml16212\wps19.jpg)
同时我们需要将用户态的数据传入内核态
![img](file:///C:\Users\19076\AppData\Local\Temp\ksohtml16212\wps20.jpg)
定义一个int类型变量用来记录目录项长度。
运行检验代码如下
![img](file:///C:\Users\19076\AppData\Local\Temp\ksohtml16212\wps21.jpg)
---
#### **(3) sys_sleep:**
sleep的功能是使进程睡眠seconds秒。利用sys_signal函数,sys_alarm函数和sys_pause函数实现功能:首先分析睡眠的含义:进程挂起一段确定时间后继续重新调度并且运行。
要达到挂起进程,我们想到使用sys_pause,但是sys_pause挂起后就不会按时唤醒,只能依靠固有的调度算法,所以我们需要用sys_alarm函数来唤醒进程。
但如果仅仅使用sys_alarm唤醒,该函数会向系统发出一个软中断信号SIGALRM,来使得操作系统中断掉这个进程,因此我们需要屏蔽掉这个信号产生的效果。
利用sys_signal函数 ,其第一个参数是需要处理的信号,第二个参数是处理信号的方式,以如下方式使用代表忽略接下来产生的SIGALRM信号。因此可以实现目的功能。
![img](file:///C:\Users\19076\AppData\Local\Temp\ksohtml16212\wps22.jpg)
---
#### **(4) sys_pipe2:**
根据名称判断该系统调用为sys_pipe的变形。同时根据描述两者功能没有区别故尝试直接对sys_pipe进行封装
![img](file:///C:\Users\19076\AppData\Local\Temp\ksohtml16212\wps23.jpg)
其中filedes[0] 和filedes[1]分别是管道的读取端和写入端。
直接将利用pipe2封装pipe即可:
![img](file:///C:\Users\19076\AppData\Local\Temp\ksohtml16212\wps24.jpg)
运行检测代码测试如下:
![img](file:///C:\Users\19076\AppData\Local\Temp\ksohtml16212\wps25.jpg)
#### **(5)sys_getcwd:**
与getdents相似都运用了文件管理方面的知识。为了获取当前工作目录我们可以访问“..”从而我们可以获得上一级目录的目录项的i节点号所有同时我们可以得到当前目录的i节点号采用这种方法我们就可以通过匹配来得到当前目录的名称并以此类推直到达到根目录具体数据结构与sys_getdents相同故不再赘述
获取上级目录,记录目录内容并计数
```C
while (i >= 0)
{
int last_node=dr->inode;
node = iget(current->root->i_dev, (dr + 1)->inode);
bh = bread(current->root->i_dev, node->i_zone[0]);
dr = (struct dir_entry *)(bh->b_data);
int j = 2;
while (dr->name[0] != '\0')
{
if ((dr + j)->inode == last_node)
break;
j++;
}
if ((dr + j)->name[0] == '\0')
break;
dir[i] = (dr + j)->name;
i++;
}
```
将保存的数据链接成路径导入rd中
```C
for (; i >= 0; i--)
{
k2 = 0;
while (dir[i][k2] != '\0')
{
rd[k1] = dir[i][k2];
k1++;
k2++;
}
if (i == 0)
break;
rd[k1] = '/';
k1++;
}
```
将用户内容导入内核
```C
char word;
for (i = 0; i <= k1; i++)
{
word = rd[i];
put_fs_byte(word, (char *)(buf + i));
}
return rd;
```
运行测试程序结果如下:
![img](file:///C:\Users\19076\AppData\Local\Temp\ksohtml16212\wps29.jpg)
## 三、实验结果与分析
添加了8个系统调用完成了其中必做的四个系统调用并且全部通过检验。检验结果已截图展示在实验步骤中。
## 四、问题与建议(可选)
<对实验过程中出现的问题进行描述、分析,提出解决思路和方法,无法解决的,要说明原因;记录实验心得体会,提出建议。>
Loading…
Cancel
Save