进程状态保存与恢复数组
特权级变换数据结构
再次理解TSS 、堆栈函数
从外环进入内环(特权级发生变化)时,如何访问TSS?堆栈的变化指针
P193页,中断发生的开始,ESP的值是刚刚从TSS里面渠道的进程表A中regs的最高地址,上述过程的实现代码在哪?rest
造成进程的必要考虑。咱们须要一数据结构来记录一个进程的状态,这样方便进行进程切换时,能够保存原来的进程状态。进程被挂起时就将信息写入这个数据结构,进程从新启动时,这里的信息就被从新读取。进程
因为进程和进程调度运行在不一样层级上,这里为了简单,让全部任务运行在ring1,让进程切换运行在ring0。ip
一个简单的进程切换情形,一个进程在执行时,发生了时钟中断,特权级从ring1跳转到ring0,开始执行时钟中断处理程序,中断处理程序这时调用进程调度模块,指定下一个应该运行的进程,当中断处理程序结束时,下一个进程准备就绪并开始运行,特权级又从ring0跳转回ring1:内存
为了实现这种进程切换,须要如下模块:it
须要保存的是那些可能会发生改变的量,从寄存器和内存两个角度考虑,由于不一样进程之间的内存是互不干涉的,可是CPU却只有一个,不一样的进程共用同一个CPU的一套寄存器,因此应该保存寄存器的值,准备进程被恢复时使用。基础
保存的是处理机状态信息,包括
a. 进程当前暂存信息;
b. 下一条指令地址信息;
c. 进程状态信息;
d. 过程和系统调用参数及调用地址信息.
为了保证进程状态完整不被破坏,在进程刚刚挂起时保存全部寄存器的值。保存的方法为push(即存到PCB中),或者是push ad.
这些代码应该写在时钟中断例程的最顶端,以便中断发生时立刻被执行。
保存使用的是push,恢复用的即是pop,将寄存器的值都恢复,而后执行指令iretd,回到对应进程。
保存进程状态的东西,即进程表,亦或进程控制块(PCB)。
因为会有对个进程,因此会有多个进程表,造成一个进程表数组。
进程表是描述进程的,必须独立于进程以外。
分析代码
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
首先在i8259.c的init8259a中打开中断。
设置EOI使中断持续不停的发生
为了使中断能够被观察,这里经过改变屏幕第0行,第0列的字符来表示中断在运行。中断发生时会一直变成下一个
运行结果以下所示,此时截图到了6
为何不用disp_str,而是直接使用move写显存?
这是由于disp_str会影响不少寄存器,进而可能致使对进程的影响。上面的改变al从结果上时没有产生改变的但为了不没必要要的错误,咱们仍是将全部的寄存器都压入堆栈,执行以后再恢复。
前面咱们知道,进程调度发生时,仅仅切换到进程表是不够的,为了防止进程表相应的栈的有关信息被破坏,咱们还要继续切换栈,这时候就要用到内核栈了。
切换到内核栈的方法很是简单,只需在原代码的基础上增长两行move便可,切换的时机为寄存器刚被压入堆栈之后(压入堆栈后就当即跳转到内核栈,不然此时进行堆栈操做会影响进程表存储的信息),以及对tss.esp0赋值以前(不然下次中断就直接内核栈了)。
这里增长了中断显示消息"",因此会在下面显示“”,以下图所示
为了让中断发生时,还能继续接受中断,咱们须要进行必定的修改。
CPU在响应中断时,会自动的关中断,这是咱们要人为打开,因此要使用指令sti打开中断,并在离开内核栈前用cli关闭中断;
为了实验的方便,咱们须要中断处理的时间足够长,因此增长了延时函数
这样会带来一个问题,即当一次中断未完成时,另外一个中断就发生,致使永远没法执行到中断处理程序的结尾,做用于显示上就是打印一个A0x0后一直打印^。
而且因为一直在压栈而无出栈,会致使堆栈溢出。
解决这个问题,须要让中断处理程序知道本身是否在嵌套执行。设置一个全局变量来实现,中断处理程序执行时自加,结束时自减。这里设置为初始值为-1.当结果不为0时,说明未处理完发生了中断,这时直接跳到最后,结束新的中断。
运行结果以下,可知打印^的速度变慢了,说明不少程序执行了inc byte后并无执行disp_str。中断重入已经解决,因此无需延时函数,最后运行结果如最下方所示
取到进程表A中regs的最高地址的代码
实现的代码其实没有,是CPU本身实现的
将proc.c中的对应函数改成上述,即调用后指向下一个进程,若是进程为最后一个,返回到进程表的第一个。
在a的地方,进行调用后面加入第二句话。在C处使用延时函数。