要求:根据本课程所学内容总结梳理出一个精简的Linux系统概念模型,最大程度统摄整顿本课程及相关的知识信息,模型应该是逻辑上可以运转的、自洽的,并举例某一两个具体例子(比如读写文件、分配内存、使用I/O驱动某个硬件等)纳入模型中验证模型。并谈谈您对课程的心得体会,改进建议等。
一、Linux系统概念模型
Linux系统主要由Linux内核和其他外部程序组成,其主要结构如下图所示:
从上图可见,已学习的内核的工作主要有:进程管理、内存管理、文件系统、驱动管理等。用户通过系统调用,申请系统的内核服务。下面根据学习的时间顺序分别归纳这些知识点:
1、进程管理
首先我们要知道,Linux是一个多任务多用户操作系统, 一个任务(task)就是一个进程(process)。每一个进程都具有一定的功能和权限,它们都运行在各自独立的虚拟地址空间。 它们是系统资源分配的基本单位,也是使用CPU运行的基本调度单位。存放在磁盘上的可执行文件的代码和数据的集合称为可执行映象(Executable Image)。当一个可执行映像装入系统中运行时,它就形成了一 个进程。而为了使系统有效的管理进程,当一个进程被创建时,系统就为该进程建立一个task_struct任务结构体,即:进程控制块(PCB),它容纳了一个进程的所有信息,是进程存在的唯一标志,也是系统实现进程调度的主要依据。当进程运行结束时,系统撤消该进程的任务结构体,其结构如下:
通常情况下,由于CPU的计算资源是有限的,某一时刻只能处理一个进程,故处理多个进程需要进行进程调度,进程调度下进程的状态如下所示:
? 进程切换主要有以下两步组成:切换页全局目录以安装一个新的地址空间;切换内核态堆栈和硬件上下文。
其中,硬件上下文提供了内核执行新进程所需要的所有信息,包括CPU寄存器。尽管每个进程可以有自己的地址空间,但所有的进程只能共享CPU的寄存器。 因此,在恢复一个进程执行之前,内核必须确保每个寄存器装入了挂起进程时的值。这样才能正确的恢复一个进程的执行硬件上下文:进程恢复执行前必须装入寄存器的一组数据,包括通用寄存器的值以及一些系统寄存器。我们通过switch_to宏执行进程切换,schedule()函数调用这个宏来调度一个新的进程在CPU上运行。
? Linux提供了几个系统调用来创建和终止进程,以及执行新程序 ;
① Fork,vfork和clone系统调用创建新进程;
② exec系统调用执行一个新程序;
③ exit系统调用终止进程。
? 进程调度共有两种类型:
非剥夺方式:分派程序一旦把处理机分配给某进程后便让它一直运行下去,直到进程完成或发生某事件而 阻塞时,才把处理机分配给另一个进程。
剥夺方式:当一个进程正在运行时,系统可以基于某 种原则,剥夺已分配给它的处理机,将之分配给其它进程。
而剥夺原则有:优先权原则、短进程、优先原则、 时间片原则等。
? 进程调度的时机有:
进程状态发生变化时;当前进程时间片用完时;进程从系统调用返回到用户态时;中断处理后,进程返回到用户态时。
2、中断和异常
首先我们要弄清这两者的区别,中断是异步的,由硬件随机产生,在程序执行的任何时候可能出现;异常是同步的,在(特殊的或出错的)指令执行时由CPU控制单元产生。二者统称为“中断信号”。当一个中断信号到达时,CPU必须停止它当前正在做的事,并且切换到一个新的活动。该操作的步骤是:在进程的内核态堆栈,保存程序计数器的当前值(即eip和cs寄存器)以便处理完中断的时候能正确返回到中断点,并把与中断信号相关的一个地址放入进程序计数器,从而进入中断的处理。
这里需要讨论一下中断上下文,不同于进程上下文,中断或异常处理程序执行的代码不是一个进程而是一个内核控制路径,代表了中断发生时正在运行的进程执行。作为一个进程的内核控制路径,中断上下文只包含了很有限的几个寄存器,建立和终止这个上下文所需要的时间很少。
? 中断可分为:
① 可屏蔽中断:I/O设备发出的所有中断请求(IRQ)都可以产生可屏蔽中断,它共有两种状态:屏蔽的和非屏蔽的;
② 非屏蔽中断:只有几个特定的危急事件才引起非屏蔽中断。如硬件故障或是掉电。
? 异常可分为:
① 处理器探测异常:由CPU执行指令时探测到一个反常条件时产生,如溢出、除0错等;
② 编程异常:由编程者发出的特定请求产生,又叫做“软中断” ,如系统调用。而根据异常时保存在内核堆栈中的eip的值可以进一步将异常分为:
故障(fault):通常可以被纠正,处理完异常时,该指令被重新执行,如缺页异常,eip存储引起故障的指令的地址;
陷阱(trap):即系统调用,eip存储随后要执行的指令的地址;
异常中止(abort):此时eip值无效,只有强制终止受影响的进程。
? 当发生了一个中断或异常,CPU会进行如下操作:
① 确定与中断或者异常关联的向量i;
② 读idtr寄存器指向的IDT表中的第i项;
③ 从gdtr寄存器获得GDT的基地址,并在GDT中查找, 以读取IDT表项中的段选择符所标识的段描述符;
④ 确定中断是由授权的发生源发出的。 中断:中断处理程序的特权不能低于引起中断的程序的特权(对应GDT表项中的DPL vs CS寄存器中的 CPL);编程异常:还需比较CPL与对应IDT表项中的DPL;
⑤ 检查是否发生了特权级的变化,一般指是否由用户态陷入了内核态。 如果是由用户态陷入了内核态,控制单元必须开始使用与新的特权级相关的堆栈
a,读tr寄存器,访问运行进程的tss段
b,用与新特权级相关的栈段和栈指针装载ss和esp寄存器。这些值可以在进程的tss段中找到
c,在新的栈中保存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段寄存器的内容,如 果其中一个寄存器包含的选择符是一个段描 述符,并且特权级比当前特权级高,则清除 相应的寄存器。这么做是防止怀有恶意的用 户程序利用这些寄存器访问内核空间
原文:https://www.cnblogs.com/wzh711/p/13252517.html