• 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<

    强调实验之前需要切换到对应的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

  • 相关阅读:
    最新发现:《羊了个羊》通关靠运气,项目通关靠双商
    GLB/GLTF在线纹理编辑
    洛谷千题详解 | P1005 [NOIP2007 提高组] 矩阵取数游戏【C++、 Java、Python语言】
    tcr历史比赛竞赛规则
    恢复chrome浏览器书签
    java计算机毕业设计基于springboot 口腔卫生防护口腔牙科诊所管理系统
    cmake应用:集成gtest进行单元测试
    亚微米聚苯乙烯微球乳化剂β-环糊精/表面接枝β环糊精聚苯乙烯纤维的制备过程
    提升VR全景摄影画质的8个因素
    《人月神话》小结
  • 原文地址:https://blog.csdn.net/qq_41945053/article/details/126819041