学号:SA12***279 姓名:*湜
一、操作系统工作的基础:存储程序计算机、堆栈(函数调用堆栈)机制和中断机制
1、 存储程序计算机
存储程序计算机又被称为冯-诺伊曼计算机,它是由著名数学家冯-诺伊曼等人在1946年总结并明确提出来的,存储程序计算机的体系结构主要包括中央处理器和内存,其中内存里存储指令和数据,CPU从内存中读出指令和数据,并一直不间断地执行指令、读取下一条指令。其组成框图如下所示:
图一 存储程序计算机的组成框图
存储程序计算机在体系结构上的主要特点有:
(1) 以运算单元为中心
(2) 采用存储程序原理
(3) 存储器是按地址访问、线性编址的空间
(4) 控制流由指令流产生
(5) 指令由操作码和地址码组成
(6) 数据以二进制编码组成
2、 堆栈(函数调用堆栈)机制
Linux把进程地址空间分为内核区和用户区两部分:
(1)操作系统内核的代码和数据等被映射到内核区;
(2)进程可执行映像(代码和数据)映射到虚拟内存的用户区:一个进程所需的虚拟空间中的各个部分未必连续,这通常会形成若干离散的虚存“区间”;一个虚拟“区间”是进程虚拟空间的一部分,这部分的虚拟空间是连续的并且有相同的一些属性。
进程地址空间的分配如下图所示:
图二 Linux操作系统的进程地址空间
一个函数调用堆栈其实就代表了一个进程,即每个堆栈帧都对应一个函数调用。当函数调用发生时,新的堆栈帧被压入堆栈,当函数返回时,相应的堆栈帧从堆栈中弹出。
大多数CPU上的程序实现使用堆栈来支持函数调用操作,堆栈被用来传递函数参数、存储返回信息、临时保存寄存器原有值以及用来存储局部数据。
函数调用堆栈如下图所示:
图三 函数调用堆栈机构示意图
3、 中断机制
中断分为同步和异步中断,中断是由间隔定时器和I/O设备产生的。
中断的过程其实就是CPU停下现在正在处理的进程,转而响应中断信号来自的进程,保存当前进程的状态和信息,进而执行申请处理的进程,执行完中断进程之后,CPU再返回到之前进程中停下工作的地方继续执行原进程。
二、操作系统(内核)是如何工作的,宏观概述结合关键点的微观(CS:EIP、EBP/ESP等的变化)分析
内核本身并不是一个进程,而是进程的管理者。Linux内核由所有进程共享控制路径和内核服务线程组成,Linux内核也提供了模块,即其代码可以在运行时链接到内核或从内核解除链接。CPU即可以运行在用户态下,也可以运行在内核态下。
当一个程序在用户态下执行时,它不能直接访问内核数据结构或内核的程序,然而,当应用程序在内核态下运行时,这些限制不再有效。每种CPU模型都为从用户态到内核态的转换提供了特殊的指令,反之亦然。一个程序执行时,大部分时间都处在用户态下,只有需要内核所提供的服务时才切换到内核态。当内核满足了用户程序的请求后,它让程序又回到用户态下。如果进程运行在内核态,处理器就执行一些内核例程。
Linux操作系统工作的最重要的是用户内核切换及进程间切换,下面先从内核控制路径不包含嵌套角度出发进行研究。
每个中断或异常都会引起一个内核控制路径,或者说代表当前进程在内核态执行单独的指令序列。例如:当I/O设备发出一个中断时,相应的内核控制路径的第一部分指令就是那些把寄存器的内容保存在内核堆栈的那些指令。
其过程如下:(首先假定内核已经初始化,CPU在保护模式下运行。)
CPU的正常运行:
(1) 当执行了一条指令后,cs和eip这对寄存器包含了下一条将要执行的指令的逻辑地址。
(2) 在执行这条指令之前,CPU控制单元会检查在运行前一条指令时是否发生了一个中断或者异常。
(3) 如果发生了一个中断或异常,那么CPU控制单元执行下列操作:
① 确定与中断或者异常关联的向量i(0~255)
② 读idtr寄存器指向的IDT表中的第i项
③ 从gdtr寄存器获得GDT的基地址,并在GDT中查找,以读取IDT表项中的段选择符所标识的段描述符。(这个描述符指定中断或异常处理程序所在段的基地址)
④ 确定中断是由授权的发生源发出的。
中断:中断处理程序的特权不能低于引起中断的程序的特权(对应GDT表项中的DPL vs CS寄存器中的CPL)
编程异常:还需比较CPL与对应IDT表项中的DPL
⑤ 检查是否发生了特权级的变化,一般指是否由用户态陷入了内核态。
如果是由用户态陷入了内核态,控制单元必须开始使用与新的特权级相关的堆栈
Ø 读tr寄存器,访问运行进程的tss段
Ø 用与新特权级相关的栈段和栈指针装载ss和esp寄存器。这些值可以在进程的tss段中找到
Ø 在新的栈中保存ss和esp以前的值,这些值指明了与旧特权级相关的栈的逻辑地址
⑥若发生的是故障,用引起异常的指令地址修改cs和eip寄存器的值,以使得这条指令在异常处理结束后能被再次执行
⑥ 在栈中保存eflags、cs和eip的内容
⑧如果异常产生一个硬件出错码,则将它保存在栈中
⑨装载cs和eip寄存器,其值分别是IDT表中第i项门描述符的段选择符和偏移量字段。这对寄存器值给出中断或者异常处理程序逻辑地址的开始处。
中断/异常处理完后,相应的处理程序会执行一条iret汇编指令,使得CPU完成以下工作:
1,用保存在栈中的值装载cs、eip和eflags寄存器。如果一个硬件出错码曾被压入栈中,那么弹出这个硬件出错码
2,检查处理程序的特权级是否等于cs中最低两位的值(这意味着进程在被中断的时候是运行在内核态还是用户态)。若是,iret终止执行;否则,转入3
3,从栈中装载ss和esp寄存器。这步意味着返回到与旧特权级相关的栈
4,检查ds、es、fs和gs段寄存器的内容,如果其中一个寄存器包含的选择符是一个段描述符,并且特权级比当前特权级高,则清除相应的寄存器。这么做是防止怀有恶意的用户程序利用这些寄存器访问内核空间
其具体寄存器变化流程如下图所示:
图四 用户内核切换的寄存器变化流程图
三、总结
操作系统是横跨软件和硬件的桥梁,它是一个基本程序集合,在这个集合里,最重要的程序就是内核。当操作系统启动时,内核被装入到RAM中,内核中包含了系统运行所必不可少的很多核心过程。内核为系统中所有事情提供了主要功能,并决定高层软件的很多特性。
Linux是一个多处理系统,它允许进程并发活动,并能竞争系统资源。类Unix操作系统采用进程/内核模式,每个进程都自以为是系统中唯一的进程,可以独占操作系统所提供的服务。只要进程发出系统调用(即对内核提出请求),硬件就会把特权模式由用户态变成内核态,然后进程以非常有限的目的开始一个内核过程的执行。Linux的进程/内核模式是CPU既可以工作在用户态下,也可以工作在内核态下,只有当应用程序在内核态下运行时,才可以直接访问内核数据结构或内核的程序。总之,内核本身不是一个进程,而是进程的管理者。内核由内核线程、系统调用处理程序、中断处理程序(I/O,时钟等)等构成。
参考:《深入理解Linux内核》