mits6.081-lab2

lab2

lesson03

3.1 上一节课回顾

image-20220908102741314

学习完第一课之后,你应该对操作系统的结构有个大致的认知。

  • 首先,会有类似于Shell,echo,find或者任何你实现的工具程序,这些程序运行在操作系统之上。
  • 而操作系统又抽象了一些硬件资源,例如磁盘,CPU。
  • 通常来说操作系统和应用程序之前的接口被称为系统调用接口(System call interface),我们这门课程看到的接口都是Unix风格的接口。基于这些Unix接口,你们在lab1中,完成了不同的应用程序。

3.2 操作系统隔离性

使用操作系统的一个原因,甚至可以说是主要原因就是为了实现multiplexing和内存隔离。如果你不使用操作系统,并且应用程序直接与硬件交互,就很难实现这两点。所以,将操作系统设计成一个库,并不是一种常见的设计。你或许可以在一些实时操作系统中看到这样的设计,因为在这些实时操作系统中,应用程序之间彼此相互信任。但是在大部分的其他操作系统中,都会强制实现硬件资源的隔离。

如果我们从隔离的角度来稍微看看Unix接口,那么我们可以发现,接口被精心设计以实现资源的强隔离,也就是multiplexing和物理内存的隔离。接口通过抽象硬件资源,从而使得提供强隔离性成为可能。

image-20220908104008272

CPU对进程进行分时复用

3.3 操作系统防御性

OS不能因为应用程序的崩溃导致整个OS崩溃

所以需要具有防御性

通常来说,需要通过硬件来实现这的强隔离性。我们这节课会简单介绍一些硬件隔离的内容,但是在后续的课程我们会介绍的更加详细。这里的硬件支持包括了两部分,第一部分是user/kernel mode,kernel mode在RISC-V中被称为Supervisor mode但是其实是同一个东西;第二部分是page table或者虚拟内存(Virtual Memory)。

3.4 硬件对于强隔离的支持

硬件对于强隔离的支持包括了:user/kernle mode虚拟内存

首先,我们来看一下user/kernel mode,这里会以尽可能全局的视角来介绍,有很多重要的细节在这节课中都不会涉及。为了支持user/kernel mode,处理器会有两种操作模式,第一种是user mode,第二种是kernel mode。当运行在kernel mode时,CPU可以运行特定权限的指令(privileged instructions);当运行在user mode时,CPU只能运行普通权限的指令(unprivileged instructions)。

普通权限的指令都是一些你们熟悉的指令,例如将两个寄存器相加的指令ADD、将两个寄存器相减的指令SUB、跳转指令JRC、BRANCH指令等等。这些都是普通权限指令,所有的应用程序都允许执行这些指令。

特殊权限指令主要是一些直接操纵硬件的指令和设置保护的指令,例如设置page table寄存器、关闭时钟中断。在处理器上有各种各样的状态,操作系统会使用这些状态,但是只能通过特殊权限指令来变更这些状态。

image-20220908105008745

image-20220908105311013

BOIS!!! yyds

系统开机后,CPU会对计算机自带的BOIS程序进程初始化,BOIS会指向硬盘的第一扇区,也就是启动区,里面存放了已经编译好的启动程序,然后原封不动的把他拷贝到内存的第一扇区0x7c00处。

每一个进程都会有自己独立的page table,这样的话,每一个进程只能访问出现在自己page table中的物理内存。操作系统会设置page table,使得每一个进程都有不重合的物理内存,这样一个进程就不能访问其他进程的物理内存,因为其他进程的物理内存都不在它的page table中。一个进程甚至都不能随意编造一个内存地址,然后通过这个内存地址来访问其他进程的物理内存。这样就给了我们内存的强隔离性。

image-20220908105742006

3.5 User/Kernel mode切换

image-20220908105910004

用户空间和内核空间的界限是一个硬性的界限,用户不能直接调用fork,用户的应用程序执行系统调用的唯一方法就是通过这里的ECALL指令。

假设我现在要执行另一个系统调用write,相应的流程是类似的,write系统调用不能直接调用内核中的write代码,而是由封装好的系统调用函数执行ECALL指令。所以write函数实际上调用的是ECALL指令,指令的参数是代表了write系统调用的数字。之后控制权到了syscall函数,syscall会实际调用write系统调用。

image-20220908110219895

3.6 宏内核 vs 微内核

大多数的Unix操作系统实现都运行在kernel mode。比如,XV6中,所有的操作系统服务都在kernel mode中,这种形式被称为Monolithic Kernel Design(宏内核)。

image-20220908110517364

微内核

image-20220908110543803

3.7 编译运行kernel

image-20220908121701642

预处理->编译->汇编->链接

这里生成的内核文件就是我们将会在QEMU中运行的文件。同时,为了你们的方便,Makefile还会创建kernel.asm,这里包含了内核的完整汇编语言,你们可以通过查看它来定位究竟是哪个指令导致了Bug。比如,我接下来查看kernel.asm文件,我们可以看到用汇编指令描述的内核:

image-20220908130620641

image-20220908130817289

3.8 QEMU

image-20220908130956374

3.9 xv6启动过程

image-20220908131907999

第二列为实际的二进制编码

gdb调试

image-20220908133942719

设置断点 b _entry

image-20220908133959016

显示源代码和反汇编窗口 layout split

image-20220908134257561

在xv6目录下执行make qemu-gdb;新开一个窗口,在相同目录下执行gdb-multiarch

image-20220908140735904

此处和实验有稍许不同

教程如下

image-20220908140818035

image-20220908140940227

最终效果:

image-20220908141113685

gdb参考教程:

https://blog.csdn.net/niyaozuozuihao/article/details/91802994?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522166261519116782425169512%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=166261519116782425169512&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2alltop_positive~default-1-91802994-null-null.142v47body_digest,201v3control_2&utm_term=gdb%E8%B0%83%E8%AF%95&spm=1018.2226.3001.4187

实验

System call tracing

==任务:==在xv6中添加一个系统调用跟踪功能,该功能可帮助你在以后的实验中调试程序。您将创建一个新的trace系统调用来控制跟踪。它应该有一个参数,一个整数“mask”,其位指定要跟踪的系统调用。例如,为了跟踪fork系统调用,程序调用trace(1<<SYS_fork),其中SYS_fork是kernel/syscall.h中的syscall编号。如果在掩码中设置了系统调用的编号,则必须修改xv6内核,以便在每个系统调用即将返回时输出一行。该行应包含进程id、系统调用的名称和返回值;不需要输出系统调用参数。trace系统调用应启用对调用它的进程及其随后派生的任何子进程的跟踪,但不应影响其他进程。

强调实验之前需要切换到对应的lab 否则make qemu会不成功

image-20220912152932043

实验二主要涉及对系统函数调用过程的理解以及尝试自己手动添加系统调用。首先需要大致了解一下xv6系统调用的过程,这里以fork为例:

img

  1. 在user.h中添加

image-20220911164055623

2.usys.pl中(用来生成usys.S的辅助脚本)添加入口

image-20220911164134099

3.汇编文件usys.S

image-20220911164219143

4.syscall.h文件中添加对应的函数的系统调用号

image-20220911164329987

5.syscall.c文件中添加对应的函数指针和函数头

image-20220911173336545

6.sysproc.c实现函数实现 sysproc.c里主要接收参数并给proc结构体复制

image-20220911174527208

7.syscall.c里打印其他系统调用信息的操作

image-20220911174818246

运行结果:

image-20220912153128392

输出主要有三段:

(1)pid

(2)系统调用名称

(3)返回的参数值

Sysinfo

image-20220912154357116

  • Add $U/_sysinfotest to UPROGS in Makefile,注意添加的是**$U/_sysinfotest** , 不是$U/_sysinfo
  • 系统调用函数添加

image-20220912160430783

image-20220912160745122

image-20220912160857722

image-20220912160808327

syscall.c

image-20220912161234367

image-20220912161241889

image-20220912161249088

参考filestat() (kernel/file.c),sys_fstat() (kernel/sysfile.c) 以及copyout(),编写sys_sysinfo(),从内核中获取freemem和nproc,输出给用户

image-20220912161743594

接下来,就是要编写 get_amount_freemem()get_nproc()从而获得freememnproc

defs.h

image-20220912161939863

image-20220912161954642

image-20220912162110445

image-20220912162129020

运行结果

image-20220912162617642

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

-特立独行的猪-

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值