其他分享
首页 > 其他分享> > BUAA OS——Lab4实验报告

BUAA OS——Lab4实验报告

作者:互联网

lab4实验报告

思考题

4.1

思考并回答下面的问题:

  • 内核在保存现场的时候是如何避免破坏通用寄存器的?
  • 系统陷入内核调用后可以直接从当时的\(a0-\)a3 参数寄存器中得到用户调用msyscall 留下的信息吗?
  • 我们是怎么做到让sys 开头的函数“认为”我们提供了和用户调用msyscall 时同样的参数的?
  • 内核处理系统调用的过程对Trapframe 做了哪些更改?这种修改对应的用户态的变化是?

4.2

思考下面的问题,并对这两个问题谈谈你的理解:

  • 子进程完全按照fork() 之后父进程的代码执行,说明了什么?
  • 但是子进程却没有执行fork() 之前父进程的代码,又说明了什么?

4.3

关于fork 函数的两个返回值,下面说法正确的是:

A. fork 在父进程中被调用两次,产生两个返回值

B. fork 在两个进程中分别被调用一次,产生两个不同的返回值

C. fork 只在父进程中被调用了一次,在两个进程中各产生一个返回值

D. fork 只在子进程中被调用了一次,在两个进程中各产生一个返回值

答案为C

4.4

如果仔细阅读上述这一段话, 你应该可以发现, 我们并不是对所有的用户空间页都使用duppage 进行了保护。那么究竟哪些用户空间页可以保护,哪些不可以呢,请结合include/mmu.h 里的内存布局图谈谈你的看法。

UTOP以上的空间为内核相关的页表,所有的用户进程都相同,也无权进行更改,因此不需要用duppage进行保护。

USTACKTOP到UXSTACKTOP之间,为Invalid memory和用户进程的异常栈。Invalid memory不会用到为空闲区,不需要保护;异常栈是进行异常处理的地方,不应该受到写时复制机制的保护。

综上,需要保护从UTEXT到USTACKTOP的页表。

4.5

在遍历地址空间存取页表项时你需要使用到vpd 和vpt 这两个“指针的指针”,请思考并回答这几个问题:

  • vpt 和vpd 的作用是什么?怎样使用它们?

  • 从实现的角度谈一下为什么能够通过这种方式来存取进程自身页表?

  • 它们是如何体现自映射设计的?

  • 进程能够通过这种存取的方式来修改自己的页表项吗?

.globl vpt 
vpt:     
     .word UVPT 
     .globl vpd 
vpd:     
     .word (UVPT+(UVPT>>12)*4) 

进程页表的位置为UVPT,则vpt指向UVPT;vpd指向(UVPT+(UVPT>>12)*4) ,不难看出是自映射机制。

4.6

page_fault_handler 函数中,你可能注意到了一个向异常处理栈复制Trapframe 运行现场的过程,请思考并回答这几个问题:

  • 这里实现了一个支持类似于“中断重入”的机制,而在什么时候会出现这种“中断重入”?
  • 内核为什么需要将异常的现场Trapframe 复制到用户空间?

4.7

到这里我们大概知道了这是一个由用户程序处理并由用户程序自身来恢复运行现场的过程,请思考并回答以下几个问题:

  • 用户处理相比于在内核处理写时复制的缺页中断有什么优势?

  • 从通用寄存器的用途角度讨论用户空间下进行现场的恢复是如何做到不破坏通用寄存器的?

4.8

请思考并回答以下几个问题:

  • 为什么需要将set_pgfault_handler 的调用放置在syscall_env_alloc 之前?
  • 如果放置在写时复制保护机制完成之后会有怎样的效果?
  • 子进程需不需要对在entry.S 定义的字__pgfault_handler 赋值?

实验难点

本次实验的难点一共有两处,一处是在系统调用前对传递参数的存取,一处是fork中在不同进程中函数返回值不同机制的理解。

V0和V1会存储函数返回值;

A0 - A3会存储函数传入值(剩余传值在栈里)

S0 - S7在调用函数前后不变

SP存放栈值

RA存放返回地址

在函数调用前后,t0 - t7都有可能发生改变,因此不能用这些寄存器保存栈指针

在fork函数中,对子进程的Trapframe中的v0寄存器设置为0,来使得当子进程进入调度后,从syscall_env_alloc中返回值为0。以及子进程和父进程一些信息的保护和设置。

体会和感想

  1. 许多地方没有思考准确
    fork创建子进程时,何时将子进程加入调度队列,其实跟自己编写的调度算法有关,因为调度算法是不会对ENV_NOT_RUNNABLE的进程进行调度,所以可以在创建子进程时就将其加入,但为了将函数的功能分离,而且有些时候创建子进程时并不想让其加入调度队列,最后还是需要在set_env_status中区实现。
  2. C语言省去了很多对寄存器值调用的步骤
    函数调用时对寄存器的保存以及传值、恢复等,写C时候完全不可见。但与汇编相比较起来,就会感受到高级语言的美好。

标签:fork,调用,Lab4,BUAA,页表,寄存器,进程,返回值,OS
来源: https://www.cnblogs.com/ycg1209/p/15143997.html