OS-lab4
OS-lab4
系统调用
系统调用的流程
按照上述的流程逐个分析。
user/syscall_lib.c
这个文件位于user文件夹下,也就是用户程序可以调用的函数,相当于操作系统提供给用户程序的一些库函数。里面定义了一系列系统调用函数如
syscall_putchar
、syscall_yeild
等,而这些函数都通过调用msyscall
实现。user/syscall_wrap.S
这个汇编文件定义了
msyscall
函数,也就是通过一个syscall
指令使得操作系统陷入内核。经过lab3中的异常分发,就能够定位到处理syscall
这类指令引起的异常的函数。lib/syscall.S
这个汇编文件定义了
handle_sys
函数,也就是专门用于处理系统调用异常的函数,准确地说,这个函数是预处理一些信息。首先是保存现场关中断;接着需要判断CP0_CAUSE
寄存器中的BD
位,也就是判断是否是延时槽指令,根据这个修改CP0_EPC
的值(我觉得有点奇怪,按照计组p7,这一过程是交给硬件来完成的);接着取出系统调用号处理后获得对应系统调用函数的入口地址;最后将前四个参数载入到a0-a3中,后两个参数压栈,并跳转至对应的系统调用,返回后弹栈。
lib/syscall_all.c
这个就是内核态具体处理系统调用的文件,所有的系统调用最后都会到这里。
sys_yield
函数用于进行进程调度。首先是将内核栈复制到TIMESTACK
中,然后调用sched_yeild
进行调度。
sys_mem_alloc
函数用于在指定虚拟地址处分配一页给对应的进程。首先需要判断标志位信息和地址合法性,写时复制是不被允许的;接着获得进程控制块;使用page_alloc
获得一页内存,再使用page_insert
加入到页表中,并增加引用。
sys_mem_map
函数用于将一处虚拟地址所在的页面映射到另一处地址,也就相当于这一页内存可以被两个进程共享访问。首先需要对这两个地址向下取整;然后判断标志位和地址合法性接着分别获取两个进程的进程控制块;再使用page_lookup
查找源页面,并使用page_insert
加入到目标进程的页表中。
sys_mem_unmap
函数将指定虚拟地址的映射关系移除。先找到进程控制块,然后使用page_remove
移除映射关系。
上面就是第一部分主要完成的内容,实现了用户态函数调用到操作系统内核实现的完整过程。
进程间通信
user/ipc.c
这个文件中定义了进程间通信基本的函数
ipc_send
和ipc_recv
。ipc_send
函数用于尝试发送信息。主体是一个循环,利用系统调用函数不断判断是否能够发送,若不能发送则调用syscall_yeild
进行调度。
ipc_recv
函数用于接收信息。首先是调用syscall_ipc_recv
接受地址信息,然后设置接收进程的信息,返回接收到的信息。这两个函数的核心分别基于两个系统调用
syscall_ipc_can_send
和syscall_ipc_recv
。lib/syscall_all.c
这个文件最后两个函数就是进程通信需要实现的两个函数。
sys_ipc_can_send
函数用于尝试向目标进程发送信息。首先判断地址的合法性;然后获取目标进程;判断目标进程的接收状态,如果不能接收则报错,可以接收则则设置相关的信息,并利用page_lookup
和page_insert
把源页面共享给目标进程,最后要关掉目标进程的接收。
sys_ipc_recv
函数就是设置进程使得进程能够接收消息。首先判断地址合法性,然后设置接收状态为可接收,并修改进程运行状态为不可运行,最后进入进程调度。
fork
fork
函数用于创建一个子进程。
lib/syscall_all.c
fork
函数首先需要通过sys_env_alloc
来创建一个进程。具体做法则是通过env_alloc
得到一个空闲的进程,接着将KERNEL_SP
的内容复制到env_tf
中,将pc值设为epc,这样子进程就会从父进程fork
的地方开始执行,然后设置a0寄存器为0,这样就能保证子进程fork
的返回值是0,最后设置进程状态为不可执行,此时子进程的页表等信息还没有设置,所以还不能执行,返回子进程进程号。user/fork.c
创建进程后,需要利用
duppage
给子进程设置页表,也就是将父进程的页表复制一份给子进程。对于只读页面、共享页面、写时复制页面只需要按照原来的标志位,以用syscall_mem_map
共享给子进程即可,可写页面则需要加上写时复制标记PTE_COW
保护,这里需要给子进程和父进程都加上。由于这是用户态程序,所以不能直接访问页表,而是需要通过指向页表的指针vpt
来完成。lib/suscall_all.c
接下来需要给子进程设置缺页处理函数,这一操作通过系统调用
syscall_set_pgfault_handler
完成,对应内核态函数sys_set_pgfault_handler
。这个函数先找到进程控制块,然后给env_pgfault_handler
赋上缺页处理函数的地址,给异常处理栈env_xstacktop
赋值,然后返回。user/entry.S
上面的系统调用在实际运行中,载入的函数是
__asm_pgfault_handler
,这个函数定义在user/entry.S中。但这个函数只完成了处理参数和返回恢复现场的操作,具体缺页处理则是跳转到__pgfault_handler
函数,由这个函数来完成。user/fork.c
这个真正的处理函数是
pgfault
,这个函数用来处理写时复制引起的缺页异常。首先需要判断这一地址所在页是否是写时复制页面;接着将地址向下取整,在用户栈的位置分配一页,将源页面的内容复制过去,然后把新的页面映射到原来的虚拟地址上,把新的页面的映射移除。user/syscall_all.c
进行到这里,子进程执行的条件就都具备了,这时候需要设置子进程的状态,让子进程可以运行。也就是通过系统调用
sys_set_env_status
完成。首先判断状态的合法性,然后获取进程控制块,将进程的状态赋值。
上面的流程全部完成后,返回子进程的进程号,fork
函数就基本完成了,但还有个细节没有做到。在给子进程设置了缺页处理函数后,子进程能够处理写时复制异常,但父进程似乎没有设置。因此在写时复制机制完成前,也就是duppage
之前,需要利用set_pgfault_handler
设置缺页处理函数。
现在fork
函数就算完成了。在之后父进程或子进程遇到写时复制异常处理时,就是通过触发异常,经过异常分发确定为写时复制异常,然后通过一个函数跳转到这个进程安装的缺页异常处理函数。这个函数page_fault_handler
位于lib/traps.c中,这个函数首先将进程的执行现场复制到临时的Trapframe
中,再复制到异常处理栈中,最后设置epc的值,使得接下来进程会进入缺页异常处理函数。
从这个异常处理过程中可以看出微内核的设计思想,真正处理异常的函数处于用户态,交给用户进程来完成,而内核只进行异常分发,跳转到对应处理函数的过程。
梳理一下lab4的整个过程,首先是实现了从用户态到内核态的完整的系统调用流程,中间涉及到了MIPS的函数传参的规定和用户态内核态的转换;接着是完成了进程间通信;最后实现了从创建一个新进程、设置页表和异常处理函数、最后使这个新进程能够正常运行正常处理写时复制的完整过程。
最后的fork
函数涉及到了很多系统调用,尤其是缺页异常函数,在完成缺页处理的过程中,首先是触发异常陷入内核,经过异常分发后进入缺页异常处理函数page_fault_handler
,接着转到用户态的_asm_pgfault_handler
函数,在取出异常指令地址后进入处理异常的核心函数pgfault
,处理完后逐层返回。
OS-lab4的更多相关文章
- 【bug记录】OS Lab4 踩坑记
OS Lab4 踩坑记 Lab4在之前Lab3的基础上,增加了系统调用,难度增加了很多.而且加上注释不详细,开玩笑的指导书,自己做起来困难较大.也遇到了大大小小的bug,调试了一整天. 本文记录笔者在 ...
- OO第四次博客作业(第四单元作业及期末总结)
(注意:本文写作顺序与作业要求不完全一致,但涵盖了作业的所有要求) 一学期的BUAA特色OO课程结束了. PART 1 我想先写我这一学期的感想 从第一单元满怀期待地写完多项式求值到最后看着60分不 ...
- ucore操作系统学习(四) ucore lab4内核线程管理
1. ucore lab4介绍 什么是进程? 现代操作系统为了满足人们对于多道编程的需求,希望在计算机系统上能并发的同时运行多个程序,且彼此间互相不干扰.当一个程序受制于等待I/O完成等事件时,可以让 ...
- BUAA_OS lab4 难点梳理
BUAA_OS lab4 难点梳理 lab4体会到了OS难度的飞升.实验需要掌握的重点有以下: 系统调用流程 进程通信机制 fork 本lab理解难度较高,接下来将以以上三部分分别梳理. 系统调用 概 ...
- BUAA OS实验调试指南:从看懂到看开
一般的调试流程其实很简单:发现问题,稳定复现,确定临界条件,定位问题,修复问题,核查结果.迭代这个过程,形成一个闭环 老实说,OS的实验代码,开箱体验极差,程序跳来跳去,进了Lab4后还要考虑内核态切 ...
- [OS] 操作系统课程(三)
工具 源码阅读:understand 源码文档自动生成工具:Doxygen 编译环境:gcc 运行环境:x86机器或QEMU 调试工具:QEMU+(GDB or IDE) IDE:Eclipse-CD ...
- ChCore Lab4 多核处理 实验笔记
本文为上海交大 ipads 研究所陈海波老师等人所著的<现代操作系统:原理与实现>的课程实验(LAB)的学习笔记的第四篇:多核处理.所有章节的笔记可在此处查看:chcore | 康宇PL' ...
- NodeJs之OS
OS Node.js提供了一些基本的底层操作系统的模块OS. API var os = require('os'); console.log('[arch] 操作系统CPU架构'+os.arch()) ...
- Node.js:OS模块
os模块,可以用来获取操作系统相关的信息和机器物理信息,例如操作系统平台,内核,cpu架构,内存,cpu,网卡等信息. 使用如下所示: const os = require('os'); var de ...
- Xamarin+Prism开发详解四:简单Mac OS 虚拟机安装方法与Visual Studio for Mac 初体验
Mac OS 虚拟机安装方法 最近把自己的电脑升级了一下SSD固态硬盘,总算是有容量安装Mac 虚拟机了!经过心碎的安装探索,尝试了国内外的各种安装方法,最后在youtube上找到了一个好方法. 简单 ...
随机推荐
- 力扣---1148. 文章浏览 I
Views 表:+---------------+---------+| Column Name | Type |+---------------+---------+| article_i ...
- Nginx09 http的keepalive及在nginx的配置使用
1 为什么要有Connection: keep-alive? 在早期的HTTP/1.0中,每次http请求都要创建一个连接,而创建连接的过程需要消耗资源和时间,为了减少资源消耗,缩短响应时间,就需要重 ...
- 栈——stack的用法
介绍 栈(stack)又名堆栈,它是一种运算受限的线性表.限定仅在表尾进行插入和删除操作的线性表.这一端被称为栈顶,相对地,把另一端称为栈底.向一个栈插入新元素又称作进栈.入栈或压栈,它是把新元素放到 ...
- Axios、Vue组件-生命周期、计算属性、Slot插槽、自定义事件、v-router、钩子函数
Axios:网络通信 <script> var vm =new vue({ el:"#app", data(){ return{ info:{ //返回的数据必须和js ...
- 斜率优化建图学习笔记 & JZOJ 地壳运动题解
本章学习斜率优化建图 请放心食用 引言 最小生成树(\(mst\)) (\(Algorithm: \text {Prim or Kruskal}\)) 从裸题到一丁点技巧,再到丧心病狂的神仙题 原始时 ...
- JZOJ 2934. 【NOIP2012模拟8.7】字符串函数
题目大意 个等长的由大写英文字母构成的字符串 \(a\) 和 \(b\),从 \(a\) 中选择连续子串 \(x\),从 \(b\) 中选出连续子串y. 定义函数 \(f_{x,y}\) 为满足条件 ...
- K3S 系列文章-RHEL7.8 离线有代理条件下安装 K3S
一 基础信息 1.1 前提 本次安装的为 k3s 1.21.7+k3s1 VM 版本为 RHEL 7.8, 7.9 或 8.2, 8.3, 8.4(K3s 官网要求) VM YUM 仓库:已配置对应版 ...
- sqlite3数据库Linux 系统移植和使用
sqlite3数据库是一个小型的数据库,当数据量不大,要求不是特别高的时候,是个不错的选择. 在Linux上移植和使用也非常的方便. 本示例是在硬件全志r528 .linux5.4 上验证的. 移植操 ...
- Nextcloud的一些错误提示
Nextcloud的一些错误提示 PHP 内存限制低于建议值 512MB 您可以通过以下步骤增加PHP内存限制: 打开php.ini文件 在终端中输入以下命令打开php.ini文件: bash sud ...
- Java/.Net双平台核心,Jvm和CLR运行异同点
前言: 本篇以.Net 7.0.2 CLR 和 OpenJDk19参照,解析下它们各自调用函数的异同. 以下为个人理解. 概述 JDK大约5.9G,CLR大约7.6G,两者相差1.7G左右. root ...