OS-lab3

lab2之后,我们能够通过MMU访问内存了,不过操作系统最重要的是能够让进程运行。

include

  • env.h

    定义了进程控制相关的变量,如进程数量NENV、进程状态ENV_FREE等、进程控制块Env、创建进程的宏函数ENV_CREATEENV_CREATE_PRIORITY等,以及一些在env.c中完成的函数。

  • trap.h

    主要定义了用于保存异常现场的结构体Trapframe,以及方便取出数据的一些宏定义如TF_REGTF_EPC等。

  • stackframe.h

    利用汇编定义了一些处理异常时常用的操作,如开关中断的STICLI,保存现场恢复现场的的SAVE_ALLRESTORE_ALLRESTORE_SOME等,取出内核栈地址的get_sp

lib

  • env.c

    首先是定义了一些全局变量,envs使进程控制块数组,curenv指当前的进程,env_free_list代表空闲的进程控制块,env_shed_list指正在运行的进程队列,用于进行调度。

    mkenvid用于给一个进程建立进程号。具体做法是将该进程的进程控制块偏移和一个静态变量next_env_id结合起来。

    envid2env用于找出给定的进程号对应的进程控制块。首先判断这个进程号是否为0,即该进程是否为当前进程curenv,若是则直接将curenv赋给*penv,若不是,则利用ENVXenvs中找出这个进程号对应的控制块;若这个进程状态为不可运行或env_id不为指定的envid则报错;检查checkperm,如果被置位,则需要检查当前的进程curenv是否能够操作找到的进程控制块,即检查这个进程是否为curenvcurenv的子进程,若不是则报错;将*penv赋值并返回。

    上面两个函数是对进程进行处理过程中经常使用的函数。

    env_init函数用于初始化进程控制的一些变量。首先通过LIST_INIT初始化env_sched_listenv_free_list然后将envs中的控制块状态都设为不可运行,再反向插入env_free_list中,这样才能够保证顺序。

    env_setup_vm函数用于初始化一个新进程的页表。首先分配一页存放页目录,并设置env_cr3为页目录物理地址;然后将映射到UTOP以下的页目录项清零,将UTOP以上的复制为boot_pgdir的值,这样在切换为内核态时就能直接使用这一片内存,不需要修改env_cr3;最后将UVPT项设置为env_cr3和相应的标志位。

    env_alloc函数用于创建一个新进程。与分配内存类似,首先需要检查env_free_list是否为空,然后获得一个空的进程控制块;使用env_setup_vm给新进程设置页表;给进程控制块的成员赋值;将这个进程控制块从env_free_list中删掉。

    上面的三个函数是用于初始化和创建进程的函数,核心是env_alloc

    load_icode_mapper函数用于将二进制文件加载到内存中,主要需要处理.text段、.data段和.bss段。

    这两部分处理方式类似,区别在于.bss段需要用bzero进行清零。具体流程则是用page_alloc分配一页内存,用page_insert加入到进程的页表中,使用bcopybzero对这一页内容进行操作。需要注意的是,这里使用的全部为虚拟地址。

    load_icode函数完成了将二进制文件加载到进程地址中并设置pc值的完整过程。首先是分配一页作为进程的用户栈;然后使用load_elf加载二进制映像;最后设置env_tf.pc,即进程开始执行的pc值。

    env_create_priority函数完成了完整的创建进程并加入运行队列的功能。首先是用env_alloc分配一块空闲的进程;然后给env_pri赋值;再用load_icode加载二进制映像;最后使用LIST_INSERT_HEAD把进程加入到env_sched_list中。

    env_create函数直接调用了env_create_priority函数,将优先级设为1。

    env_run函数用于切换当前进程为指定进程。首先是保存curenv的运行现场,通过bcopyTIMESTACK中存放的运行时信息复制到env_tf中,并设置env_tf.pc的值为env_tf.cp0_epc;接着给curenv赋值并增加env_runs;然后调用lcontext切换进程的地址;最后使用env_pop_tf恢复准备执行的进程的上下文。

    到这里为止就完成了从分配一个空闲进程块到加载程序到切换运行的全部过程。

    env_free函数用于释放一个进程的空间。首先是找到UTOP下已经映射的页目录项,使用page_remove将这个页目录项对应的页表中所有的映射移除;然后将页目录项清零并减少引用;遍历结束后将页目录也清零并减少页目录所在页面的引用;最后修改进程状态并从env_sched_list中移除加入到env_free_list中。

    env_destroy函数用于杀死指定的进程并调度运行一个新进程。先用env_free杀死进程,再判断如果这个进程为curenv,则将KERNEL_SP复制到TIMESTACK中,执行内核的调度函数。

    上面这两个函数用于结束进程。

    最后的env_check用于检查上述函数功能是否正确。

  • env_asm.S

    定义了env.c中使用的两个函数env_pop_tflcontext

    env_pop_tf用于恢复进程的执行现场。首先是恢复CP0_ENTRYHI;接着设置CP0_STATUS关闭全局中断;然后恢复通用寄存器;最后再恢复CP0_STATUS

    lcontext函数用于切换地址空间。就是将进程的页目录地址存入到mCONTEXT中,这个变量专门用于存放页目录地址。

  • kclock.c

    这个文件用于设置系统时钟。

  • kclock_asm.S

    这里定义完成了设置时钟的函数set_timer。主要任务就是将特定的数值写入到时钟的地址,然后设置CP0_STATUS

  • sched.c

    完成了调度函数sched_yeild,采用时间片轮转算法。首先取得当前调度队列的首个进程,判断这个进程是否为空或是否不可执行或时间片是否用完,若满足则需要进行调度;若进程不为空,则将这个进程从当前队列移动到另一个队列尾部;然后判断当前队列是否为空,若为空则需要切换队列,即修改point;循环查找当前的队列,直到找到不为空且可运行的进程,将时间片的值设为优先级,然后进入env_run切换执行。在查找过程中,需要注意队列空了之后需要切换到另一个队列继续这个查找,此外还需处理状态为不可运行和已释放的进程。

另外还修改了tools的链接文件,设置了异常处理地址;在start.S中增加了异常分发代码。

实验流程

在init.c中使用了ENV_CREATE创建了两个进程,接着进入env_create函数完成了创建进程并加入调度队列。在遇到时钟中断或需要切换的时候,首先会触发异常,跳转到start.S中检查触发异常的原因,即时钟中断,接着通过exception_handlers载入处理这种中断的函数timer_irq,接着转到sched_yeild函数进行调度。

OS-lab3的更多相关文章

  1. 【bug记录】OS Lab3 踩坑记

    OS Lab3 踩坑记 Lab3在之前Lab2的基础上,增加了进程建立.调度和中断异常处理.其中测试包括进程建立以及进程调度部分. 由于是第一次做bug记录,而且是调试完bug后再做的记录,所以导致记 ...

  2. MIT 6.824 : Spring 2015 lab3 训练笔记

    摘要: 源代码参见我的github:https://github.com/YaoZengzeng/MIT-6.824 Lab3: Paxos-based Key/Value Service Intro ...

  3. 【bug记录】OS Lab4 踩坑记

    OS Lab4 踩坑记 Lab4在之前Lab3的基础上,增加了系统调用,难度增加了很多.而且加上注释不详细,开玩笑的指导书,自己做起来困难较大.也遇到了大大小小的bug,调试了一整天. 本文记录笔者在 ...

  4. ucore操作系统学习(三) ucore lab3虚拟内存管理分析

    1. ucore lab3介绍 虚拟内存介绍 在目前的硬件体系结构中,程序要想在计算机中运行,必须先加载至物理主存中.在支持多道程序运行的系统上,我们想要让包括操作系统内核在内的各种程序能并发的执行, ...

  5. [OS] 操作系统课程(三)

    工具 源码阅读:understand 源码文档自动生成工具:Doxygen 编译环境:gcc 运行环境:x86机器或QEMU 调试工具:QEMU+(GDB or IDE) IDE:Eclipse-CD ...

  6. NodeJs之OS

    OS Node.js提供了一些基本的底层操作系统的模块OS. API var os = require('os'); console.log('[arch] 操作系统CPU架构'+os.arch()) ...

  7. Node.js:OS模块

    os模块,可以用来获取操作系统相关的信息和机器物理信息,例如操作系统平台,内核,cpu架构,内存,cpu,网卡等信息. 使用如下所示: const os = require('os'); var de ...

  8. Xamarin+Prism开发详解四:简单Mac OS 虚拟机安装方法与Visual Studio for Mac 初体验

    Mac OS 虚拟机安装方法 最近把自己的电脑升级了一下SSD固态硬盘,总算是有容量安装Mac 虚拟机了!经过心碎的安装探索,尝试了国内外的各种安装方法,最后在youtube上找到了一个好方法. 简单 ...

  9. Mac OS 使用 Vagrant 管理虚拟机(VirtualBox)

    Vagrant(官网.github)是一款构建虚拟开发环境的工具,支持 Window,Linux,Mac OS,Vagrant 中的 Boxes 概念类似于 Docker(实质是不同的),你可以把它看 ...

  10. Mac OS、Ubuntu 安装及使用 Consul

    Consul 概念(摘录): Consul 是 HashiCorp 公司推出的开源工具,用于实现分布式系统的服务发现与配置.与其他分布式服务注册与发现的方案,比如 Airbnb 的 SmartStac ...

随机推荐

  1. 11月17日内容总结——黏包现象、struct模块和解决黏包问题的流程、UDP协议、并发编程理论、多道程序设计技术及进程理论

    目录 一.黏包现象 什么是黏包 黏包现象产生的原因 二.struct模块及解决黏包问题的流程 struct模块 解决黏包问题初级版本 解决过程中遇到的问题 解决黏包问题终极解决方案 三.粘包代码实战 ...

  2. 六、python基础知识之变量常量、索引取值和PEP8规范

    目录 一.变量与常量 1.什么是变量? 2.什么是常量? 变量的基本使用 变量使用的语法结构与底层原理 变量名的命名规范和命名风格 变量的命名风格 常量的基本使用 二.索引取值 三.PEP8规范 1. ...

  3. 【学习笔记】Http请求方法总结

    Http常用请求方法对比 请求方法 常见参数传递方式 是否幂等 说明 API举例 GET URL,注意:Http协议对URL长度没有限制,所谓的限制是浏览器和处理服务器的 幂等 用于查询 批量查询:/ ...

  4. Spring Boot Hello World 基于 IDEA 案例详解

    一.Spring Boot 是什么 世界上最好的文档来源自官方的<Spring Boot Reference Guide>,是这样介绍的: Spring Boot makes it eas ...

  5. 以docker方式部署的redis键值查询及清理

    1.首先使用 docker ps 命令来查看正在运行的容器.该命令会列出容器的ID.名称.端口号.状态等信息.也可以使用 docker ps -a 命令来查看所有容器,包括已经停止的容器. docke ...

  6. 一步步入门Jenkins+Net Core3.1+Gitlab,实现 CICD

    架构说明: 由浅入深,我们暂时不考虑分布式,安装Jenkins到用户服务器进行CICD 需要两台服务器 Gitlab:192.168.232.128:12080 源代码仓库,可以参考<安装git ...

  7. LeetCode-780 到达终点

    来源:力扣(LeetCode)链接:https://leetcode-cn.com/problems/reaching-points 题目描述 给定四个整数 sx , sy ,tx 和 ty,如果通过 ...

  8. DevExpress gridControl 字体居住

    设置列的标题居中显示: Designer - Views -右侧输入框中输入Appearance-HeaderPanel-TextOptions-设置HAlignment为Center 设置单元格内容 ...

  9. MDK GCC调试

    openocd调试 https://blog.csdn.net/chunyexixiaoyu/article/details/120448515

  10. XCZU19EG板卡设计资料:610-基于6U VPX 的FPGA XCZU19EG存储阵列

    基于6U VPX 的FPGA XCZU19EG存储阵列 一.板卡概述         高性能存储板基于标准6U VPX架构,是基于Xilinx UltraScale+ 系列FPGA XCZU19EG架 ...