oranges 笔记第六章
OS 第六次实验随笔
第六章6.1-6.3相关的问题
进程状态保存与恢复
- 哪些状态
- 何时保存
- 保存在哪
- 如何恢复
特权级变换
- 用户进程到内核
- 内核回到用户进程
再次理解TSS 、堆栈
从外环进入内环(特权级发生变化)时,如何访问TSS?堆栈的变化
P193页,中断发生的开始,ESP的值是刚刚从TSS里面渠道的进程表A中regs的最高地址,上述过程的实现代码在哪?
概述
形成进程的必要考虑。我们需要一数据结构来记录一个进程的状态,这样方便进行进程切换时,可以保存原来的进程状态。进程被挂起时就将信息写入这个数据结构,进程重新启动时,这里的信息就被重新读取。
由于进程和进程调度运行在不同层级上,这里为了简单,让所有任务运行在ring1,让进程切换运行在ring0。
简单的进程
一个简单的进程切换情形,一个进程在执行时,发生了时钟中断,特权级从ring1跳转到ring0,开始执行时钟中断处理程序,中断处理程序这时调用进程调度模块,指定下一个应该运行的进程,当中断处理程序结束时,下一个进程准备就绪并开始运行,特权级又从ring0跳转回ring1:
- 进程A运行中;
- 时钟中断发生,ring1->ring0,时钟中断处理程序启动;
- 进程调度,下一个应运行的进程(这里设为进程B)被指定;
- 进程B被恢复,ring0 -> ring1;
- 进程B运行中。
为了实现这种进程切换,需要以下模块:
- 时钟中断处理程序;
- 进程调度模块;
- 两个进程。
关键技术
进程的哪些状态需要保存?
需要保存的是那些可能会发生改变的量,从寄存器和内存两个角度考虑,因为不同进程之间的内存是互不干涉的,但是CPU却只有一个,不同的进程共用同一个CPU的一套寄存器,所以应该保存寄存器的值,准备进程被恢复时使用。
保存的是处理机状态信息,包括
a. 进程当前暂存信息;
b. 下一条指令地址信息;
c. 进程状态信息;
d. 过程和系统调用参数及调用地址信息.
进程的状态何时以及怎样保存?
为了保证进程状态完整不被破坏,在进程刚刚挂起时保存所有寄存器的值。保存的方法为push(即存到PCB中),或者是push ad.
这些代码应该写在时钟中断例程的最顶端,以便中断发生时马上被执行。
如何恢复?
保存使用的是push,恢复用的便是pop,将寄存器的值都恢复,然后执行指令iretd,回到对应进程。
进程表的引入
保存进程状态的东西,即进程表,亦或进程控制块(PCB)。
由于会有对个进程,所以会有多个进程表,形成一个进程表数组。
进程表是描述进程的,必须独立于进程之外。
进程栈和内核栈
- 进程运行时,esp指向进程栈的某一块;
- 中断发生,从ring1到ring0,esp的值变为TSS中预设的ring0下的esp的值;
- 寄存器的值刚被保存到进程表中,这时候再进行堆栈操作会破坏进程表数组;
- 这时候使用内核栈,使esp指向内核栈即可。
特权级变换
- 发生有特权级变换的转移时,如果是外层向内层转移,我们需要从TSS中取得从当前TSS中取出内层SS和esp作为目标代码的ss和esp,所以每个进程都要有TSS,涉及的描述符应该放在局部描述符表LDT中,所以腰围每个进程准备LDT。
- 利用iretd来实现ring0 到ring1的转换。
ring0 -> ring1
restart
分析代码
358行:将esp更改,即让esp指向进程表,p_proc_ready指针指向的是下一个要启动进程的进程表地址。
359行:设置ldt,esp+p_ldt_sel即指向进程表中的ldt_sel,可知在执行restart之前对ldt_sel进行了初始化
360、361:将进程表的第一个成员的regs末地址赋值给TSS中的ring0堆栈指针域(esp)。下一次执行中断时。esp将变成regs的末地址。
时钟中断处理程序
这里直接使用iretd
进程表,进程体,GDT和TSS
- 需要初始化的寄存器有:cs ds es fs gs ss esp eip eflags
- 要初始化LDT
- 初始化TSS
- 相关关系
- 进程表和GDT。进程表内的LDT Selector对应GDT中的一个描述符,而这个描述符所指向的内存空间就存在于进程表内。
- . 进程表和进程。进程表是进程的描述,进程运行过程中如果被中断,各个寄存器的值都会被保存进进程表中。但是,在 我们的第一个进程开始之前,并不需要初始化太多内容,只需要知道进程的入口地址就足够了。另外,由于程序免不了 用到堆栈,而堆栈是不受程序本身控制的,所以还需要事先指定esp。
- GDT和TSS。GDT中需要有一个描述符来对应TSS,需要事先初始化这个描述符
- 初始化一个进程体
- 初始化进程表
- 定义进程表的结构体。
- 初始化寄存器
- 初始化LDT和LDT Selector
- 准备GDT和TSS。
丰富中断处理程序
时钟中断起作用
首先在i8259.c的init8259a中打开中断。
设置EOI使中断持续不停的发生
为了使中断可以被观察,这里通过改变屏幕第0行,第0列的字符来表示中断在运行。中断发生时会一直变成下一个
运行结果如下所示,此时截图到了6
现场保护与恢复
为什么不用disp_str,而是直接使用move写显存?
这是因为disp_str会影响很多寄存器,进而可能导致对进程的影响。上面的改变al从结果上时没有产生改变的但为了避免不必要的错误,我们还是将所有的寄存器都压入堆栈,执行之后再恢复。
赋值 TSS.esp0
- 中断的发生伴随着频繁的特权级切换,特权级切换除了要有代码的跳转,还需要堆栈的切换。
- 当从ring1回到ring0时,堆栈切换就需要TSS,TSS是用来存储ring0的堆栈信息的,堆栈信息是ss和esp。
- 进程运行时,tss.esp0应该是当前进程的进程表中保存寄存器值的地方,即s_proc中的s_stackframe的最高地址处。
- 实现代码分析
- 首先是跳过四个字节,即跳过retaddr,得到了进程表A中的regs的最高地址。
- 然后是保存寄存器的值
- 使ds,es,指向与ss相同的段
- 接下来是同上面的屏幕显示相关代码;
- 最后将esp+p_stacktop的值给eax,然后赋值给tss.esp0。下一次执行中断时,esp将指向regs的末地址;
- 然后将寄存器出栈,esp+4
内核栈
前面我们知道,进程调度发生时,仅仅切换到进程表是不够的,为了防止进程表相应的栈的有关信息被破坏,我们还要继续切换栈,这时候就要用到内核栈了。
切换到内核栈的方法非常简单,只需在原代码的基础上增加两行move即可,切换的时机为寄存器刚被压入堆栈以后(压入堆栈后就立即跳转到内核栈,否则此时进行堆栈操作会影响进程表存储的信息),以及对tss.esp0赋值之前(否则下次中断就直接内核栈了)。
这里增加了中断显示消息"",所以会在下面显示“”,如下图所示
中断重入
为了让中断发生时,还能继续接受中断,我们需要进行一定的修改。
CPU在响应中断时,会自动的关中断,这是我们要人为打开,所以要使用指令sti打开中断,并在离开内核栈前用cli关闭中断;
为了实验的方便,我们需要中断处理的时间足够长,所以增加了延时函数
这样会带来一个问题,即当一次中断未完成时,另一个中断就发生,导致永远无法执行到中断处理程序的结尾,作用于显示上就是打印一个A0x0后一直打印^。
并且由于一直在压栈而无出栈,会导致堆栈溢出。
解决这个问题,需要让中断处理程序知道自己是否在嵌套执行。设置一个全局变量来实现,中断处理程序执行时自加,结束时自减。这里设置为初始值为-1.当结果不为0时,说明未处理完发生了中断,这时直接跳到最后,结束新的中断。
运行结果如下,可知打印^的速度变慢了,说明很多程序执行了inc byte后并没有执行disp_str。中断重入已经解决,所以无需延时函数,最后运行结果如最下方所示
问题
取到进程表A中regs的最高地址的代码
实现的代码其实没有,是CPU自己实现的
实验
修改系统调用函数
将proc.c中的对应函数改为上述,即调用后指向下一个进程,如果进程为最后一个,返回到进程表的第一个。
修改进程体
在a的地方,进行调用后面加入第二句话。在C处使用延时函数。
oranges 笔记第六章的更多相关文章
- Android群英传笔记——第六章:Android绘图机制与处理技巧
Android群英传笔记--第六章:Android绘图机制与处理技巧 一直在情调,时间都是可以自己调节的,不然世界上哪有这么多牛X的人 今天就开始读第六章了,算日子也刚好一个月了,一个月就读一半,这效 ...
- 深入理解 C 指针阅读笔记 -- 第六章
Chapter6.h #ifndef __CHAPTER_6_ #define __CHAPTER_6_ /*<深入理解C指针>学习笔记 -- 第六章*/ typedef struct _ ...
- JVM学习笔记-第六章-类文件结构
JVM学习笔记-第六章-类文件结构 6.3 Class类文件的结构 本章中,笔者只是通俗地将任意一个有效的类或接口锁应当满足的格式称为"Class文件格式",实际上它完全不需要以磁 ...
- 《Microsoft Sql server 2008 Internals》读书笔记--第六章Indexes:Internals and Management(1)
<Microsoft Sql server 2008 Internals>索引文件夹: <Microsoft Sql server 2008 Internals>读书笔记--文 ...
- C Primer Plus 学习笔记 -- 前六章
记录自己学习C Primer Plus的学习笔记 第一章 C语言高效在于C语言通常是汇编语言才具有的微调控能力设计的一系列内部指令 C不是面向对象编程 编译器把源代码转化成中间代码,链接器把中间代码和 ...
- C primer plus 读书笔记第六章和第七章
这两章的标题是C控制语句:循环以及C控制语句:分支和跳转.之所以一起讲,是因为这两章内容都是讲控制语句. 第六章的第一段示例代码 /* summing.c --对用户输入的整数求和 */ #inclu ...
- [CSAPP笔记][第六章存储器层次结构]
第六章 存储器层次结构 在简单模型中,存储器系统是一个线性的字节数组,CPU能够在一个常数访问每个存储器位置. 虽然是一个行之有效的模型,但没有反应现代系统实际工作方式. 实际上,存储器系统(memo ...
- 韩松毕业论文笔记-第六章-EFFICIENT METHODS AND HARDWARE FOR DEEP LEARNING
难得跟了一次热点,从看到论文到现在已经过了快三周了,又安排了其他方向,觉得再不写又像之前读过的N多篇一样被遗忘在角落,还是先写吧,虽然有些地方还没琢磨透,但是paper总是这样吧,毕竟没有亲手实现一下 ...
- Linux学习笔记(第六章)
第六章-档案权限与目录配置#chgrp:改变档案的所属群组#chown:改变档案的拥有者#chmod:改变档案的权限及属性 chown用法 chmod用法: r:4 w:2 x:1对于文档: 对于目录 ...
随机推荐
- css3系列之伪类选择器
Pseudo-Classes Selectors(伪类选择器) E:not(s) E:root E:target E:first-child E:last-child E:only-child E:n ...
- echarts柱状图接口提供的数据是数值,要在顶部展示百分比
查阅echarts配置文档,柱状图并没有类似于饼图的直接展示百分比的参数,所以需要自己配置. window.onload = function () { var list1=[25.02,19.76, ...
- 牛客练习赛67 D牛妹爱数列 题解(dp)
题目链接 题目大意 给你一个长为n的01串,要你进行最少的操作使得这01串变成全为0,求最少操作次数 有两种不同类型的操作 1:翻转一个前缀 2:单调翻转一个元素 题目思路 居然是一个dp,标程讲的很 ...
- Java蓝桥杯——逻辑推理练习题
逻辑推理题 谁是贼? 公安人员审问四名窃贼嫌疑犯.已知,这四人当中仅有一名是窃贼,还知道这四人中每人要么是诚实的,要么总是说谎.在回答公安人员的问题中: 甲说:"乙没有偷,是丁偷的.&quo ...
- B 站今日黑白页是怎么实现的?
今天是2020年4月4日哀悼活动,不少相关站点都将网站全部变为灰色,以表示哀悼.以下为CSS代码.直接在*.css文件最前面加入. <!-- 置为灰色 --> <style type ...
- redis 压测与乐观锁
单线程没有出现并发问题. 链接太多爆炸了 把连接改到50,没有问题 改回1000: emmm159,看来相当一部分拒绝了 并且8180-10000到头了 cpu爆炸了 观察下这种程度的并发用乐观锁 一 ...
- CentOS 6.5 iso系统定制
前言 更改CentOS6.5背景图片.CentOS标题为DntOS,总之就是用ISO安装或者安装后的系统启动时不能有CentOS标志. ISO光盘目录介绍: (1)isolinux 目录存放光盘启动时 ...
- springboot多模块项目搭建遇到的问题记录
废话不多说,直接上问题报错与解决方法. 问题报错一:(报错信息看下方代码) 问题原因:'com.company.logistics.service.company.CompanyService' 未找 ...
- 喜欢 Dapper 的朋友看过来,送一份厚礼
写在开头 众所周知 Dapper 是 .NET 下最轻最快的 ORM,它是喜欢写 SQL 码农的福音,相对于 SqlHelper 它更加方便,据统计 10个 .NETer 有 9个 用过 Dapper ...
- 第10.10节 Python使用__init__.py自动加载包下内容
在前面章节老猿介绍了包下模块及子包的加载的各种方式,并说明包的加载首先是自动加载包下的__init__.py文件.在<第10.6节 Python包的概念>中介绍了__init__.py文件 ...