操作系统综合实验二

实验目的与要求

    实验目的:

(1)、掌握计算机操作系统管理进程、处理机、存储器、文件系统的基本方法。

(2)、了解进程的创建、撤消和运行,进程并发执行;自行设计解决哲学家就餐问题的并发线程,了解线程(进程)调度方法;掌握内存空间的分配与回收的基本原理;通过模拟文件管理的工作过程,了解文件操作命令的实质。

(3)、了解现代计算机操作系统的工作原理,具有初步分析、设计操作系统的能力。

(4)、通过在计算机上编程实现操作系统中的各种管理功能,在系统程序设计能力方面得到提升。

实验要求:

(1)、题目1:(30%)

阅读xv6中文文档中的Chapter 4 Traps and system calls;

阅读这个很不错的网上课程翻译中的Lec06:

https://mit-public-courses-cn-translatio.gitbook.io/mit6-s081/

结合xv6-riscv代码,回答以下的代码理解问题:

在user/zombie.c中,sleep(5); (L12)。sleep是一个系统调用。请分析代码,阐述在代码中,这一系统调用如何一步步的转化为一个对核心函数sleep(kernel/proc.c / L536)的调用?

(1)、题目2:(70%)

 一个在xv6-riscv上的游戏实例(xv6-riscv-2048.zip,a, d, w, s 分别代表左,右,上,下。):


这个小游戏移植于https://github.com/nyuichi/xv6。

可以读一下这个中文报道:

https://finance.sina.com.cn/tech/2020-10-08/doc-iivhuipp8489972.shtml

但我们只是完成了部分移植。原有版本上还有一些重要的重要功能我们并没有移植到risc-v上。比如原本包含的ioctl系统调用等。Nyuichi的xv6版本上还包含更多有趣的小程序,比如一个迷你的vi,一个扫雷游戏等。

请参考2048的的示例代码,实现一个xv6-riscv上的小游戏,或者小编辑器。

你可以:

  1. 自己写一个小游戏,或者类似nano的小编辑器;

移植一个开源的小应用程序到xv6-riscv上,比如移植Nyuichi的xv6版本上的mini-vi或扫雷程序到xv6-riscv上。

解析: 

(1)、题目1回答以下的代码理解问题:

在user/zombie.c中,sleep(5); (L12)。sleep是一个系统调用。请分析代码,阐述在代码中,这一系统调用如何一步步的转化为一个对核心函数sleep(kernel/proc.c / L536)的调用?

结合文档、相关资料和xv6源码,下面对sleep系统调用逐步转化为对核心函数sleep(kernel/proc.c)的调用的过程进行分析。

  •  用户空间sleep调用

在user/zombie.c文件中,当程序执行到sleep(5);时,实际上是在调用用户库函数sleep,如图1-1所示。

图 1- 1 用户空间调用sleep

这个函数在user.h(L23)中声明,并在usys.S(L30)中定义,如图1-2所示。

图 1- 2 用户库函数sleep声明和定义

在usys.S中,sleep系统调用通过汇编语言实现的,它设置eax寄存器为SYS_sleep的值(这是sleep系统调用的标识符,定义在syscall.h),然后触发中断来发起系统调用,如图1-3所示。

图 1- 3 sleep系统调用标识符定义

  • 系统调用的触发

usys.S中的宏SYSCALL(sleep)展开后,生成了相应的汇编指令,这些指令配置了系统调用的环境,并触发了中断int $T_SYSCALL。这个中断将控制权转移到内核的陷阱处理代码。

  • 进入内核的陷阱处理

系统调用触发后,控制权首先到达trapasm.S中的alltraps标签处的代码。这是RISC-V硬件触发的所有陷阱的入口点。在trapasm.S中,硬件上下文被保存到trapframe结构中,并且根据陷阱类型调用相应的处理函数。

  • 系统调用处理

由于sleep是一个系统调用(T_SYSCALL),alltraps中的代码将调用trap.c中的trap函数,并传入保存的trapframe。在trap函数中,会检查scause寄存器的值来确定发生的是哪种类型的陷阱,并相应地调用处理函数。

  • 调用syscall函数

在trap.c的usertrap函数中,syscall函数被调用,如图1-4所示。

图 1- 4 调用syscall函数

这个函数定义在syscall.c中,通过读取a7寄存器中的系统调用号(在我们的情况下是SYS_sleep),并在函数指针数组syscalls中查找对应的函数指针,来确定应该调用哪个系统调用处理函数,如图1-5所示。

图 1- 5 syscall函数定义

  • 系统调用分发

syscall函数通过索引syscalls数组找到sleep对应的处理函数sys_sleep(定义在sysproc.c)。syscalls数组在编译时根据系统调用的编号填充正确的函数指针。sys_sleep函数定义如图1-6所示。

图 1- 6 sys_sleep函数定义

  • 执行sys_sleep函数

sys_sleep函数被调用,它接收传递给sleep的参数(在我们的情况下是5,表示睡眠5个时钟滴答)。sys_sleep函数内部调用了kernel/proc.c中的sleep函数,将当前进程置于睡眠状态,直到指定的时间过去或者被唤醒。

  • 核心函数sleep的执行

kernel/proc.c中的sleep函数执行实际的睡眠逻辑,包括释放进程锁、将进程状态设置为SLEEPING、调用sched函数让出CPU,并在适当的时候重新获取CPU执行。该函数定义如图1-7所示。

图 1- 7 核心函数sleep定义

以上为sleep系统调用逐步转化为对核心函数sleep的调用的详细过程。

(2)、题目2请参考2048的的示例代码,实现一个xv6-riscv上的小游戏,或者小编辑器。

首先尝试运行移植到xv6上的2048程序。将压缩包解压并移动到WSL下,进入xv6-riscv-2048文件夹。查看Makefile文件,发现编译指令与xv6相同,可以通过2048命令来运行2048小游戏程序,如图2-1所示。

图 2- 1 xv6-2048 Makefile片段

执行make qemu后进入xv6系统。执行2048,即可启动游戏程序,如图2-2所示。

图 2- 2 xv6下的2048游戏程序

接下来将仿照移植2048的代码,对扫雷程序进行移植。分析移植程序的方法,需要完成的工作有:1.获取已实现的扫雷小游戏代码;2.实现程序在xv6下所需要相关的函数等;3.将程序代码加入编译,使其可以被启动。

在xv6-2048中,很多原本xv6缺少的重要的库函数,如首要的终端交互功能等等,示例给出的做法是在xv6目录下新建一个include目录,将改进后的头文件放进当中,如图2-3所示。

图 2- 3 include目录下放进改进后的头文件

其中包括stdio、termios等重要的库,因为xv6本身没有标准输入输出等库来提供一些终端功能,如刷新终端。

然后在include的同级目录下创建lib目录,其中创建lib.c文件用于实现之前 include 文件夹下定义的改进函数。

在user目录中新建2048.c文件,存放实现2048小游戏的代码,并修改Makefile文件,将程序代码加入编译。

有了2048移植的功能库后,移植扫雷便简单了很多。从网络上找到minesweeper的实现代码,将其修改为移植后xv6的依赖项,将代码放到user目录下,并添加编译项,如图2-4所示。

图 2- 4 添加扫雷代码编译项

接着在移植的xv6目录下运行make qemu编译,进入xv6环境,接着运行minesweeper即可进入游戏程序,如图2-5所示。

图 2- 5 成功进入xv6下扫雷程序

此外,尝试对sl小火车进行了移植,同样直接将依赖已有的库实现的代码放到user目录下并添加编译项即可。编译后进入xv6环境,输入sl即可查看效果,实现效果如图2-6所示。

图 2- 6 sl小火车效果预览

至此本次实验圆满完成。

  • 11
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值