课程学习总结报告

课程学习总结报告

进程地址空间

linux把进程地址空间分为内核区和用户区。有关于操作系统内核的代码和数据被映射到内核区,进程的代码和数据被映射到虚拟内存的用户区。进程地址空间中有很多离散的虚存区间,也就是说分配给进程的地址空间未必连续。线性区的概念来自于给用户态进程分配内存,用户态申请空间,和内核态申请内存不同,它不直接分配内存,而是仅仅分配一个线性地址区间,当然这个区间也包含在进程地址空间中,没有获得实际的物理页框,所以还不能使用,称为线性区。内存描述符是管理进程地址空间全部信息的结构。具体结构如下:

 

 每个进程都会有这样一个内存描述符mm_struct,进程描述符的mm字段指向mm_struct结构。另外,所有内存描述符通过其中的mmlist域连接到一个双向链表上。内核调用mmap()等调用分配了线性地址空间给进程,没有分配实际物理页框。当访问到对应的空间时,由于没有物理页框,发生缺页中断,会调用缺页异常处理函数do_page_fault,在一系列条件判断通过后,按照请求调页或者写时复制的策略分配页框。

 

中断和异常

中断和异常在计算机中起着重要作用,可以改变处理器当前的指令执行顺序。中断和异常产生的信号在这里我们统称为“中断信号”。但是实际上中断和异常的含义范畴是不同的。中断通常是指的的外部设备或者定时器产生的硬件的中断,分为可屏蔽中断和非可屏蔽中断。异常则主要分为:故障、陷阱、异常中止,往往和指令执行相关。需要注意两点:中断上下文在被中断进程的内核栈中、中断程序不会被用户进程抢占,但可以发生中断嵌套。

中断和异常的主要处理过程:

1、通过中断控制器的I/O端口得到中断向量i

2、从idtr寄存器中获取中断向量表IDT的基地址,然后结合中断向量i得到表的第i项

3、通过gdtr寄存器找到全局描述表GDT的基地址,再通过cs段选择符找到对应的段描述符,在段描述符中找到代码段的基地址,然后再加上eip就得到中断处理程序的入口。

4、比较被中断进程的权限(在cs中的CPL)是否高于中断处理程序(GDT表项中的DPL)的权限,若是,进入异常。

5、从上一步判断是中断嵌套还是用户态中断。若是从用户态中断,需要切换到内核栈,并在内核栈中保存用户栈的ss和esp。

6、在栈中继续保存:eflags、cs、eip(若有硬件出错码,也压栈)。

7、用IDT中得到的段选择符和偏移量字段装载cs和eip,下一步就会进入中断处理入口。

以上都是中断和异常发生时,硬件自动处理部分,程序员不可见。

 

 

如上图,左边为用户态进入的中断,右边的栈为中断嵌套时的栈。对于中断和异常的返回,是用一条iret指令执行的,这条指令使得:1、将栈中的eflags、eip、cs弹栈装载到CPU。2、如果是用户态进入的中断,还需要继续弹栈装载ss和esp切换回用户栈。

以上是中断和异常的硬件级处理,两者流程基本相同,而中断和异常的软件级中断处理部分有所不同:

  • 异常处理主要做了:1、进一步保存现场(在内核栈中保存寄存器的内容)2、调用异常处理函数(一般以以do_开头)3、从异常处理程序退出
  • 中断处理主要做了:1、先将中断向量入栈  2、进一步保存现场(在内核栈中保存寄存器的内容)3、do_IRQ执行所有设备中断服务例程  4、跳转到ret_from_intr后执行完跳出中断

 

文件系统

 文件系统中,首先要提到的数据结构就是FCB(文件控制块),它是文件存在的标志,记录了系统管理文件的全部信息。在Linux中,文件控制块又被称为inode。文件控制块的有序集合构成了文件目录,每个目录项对应一个文件控制块,而为了方便文件目录的管理,操作系统又将文件目录以文件的形式存在外存,这就是目录文件。对文件可以进行一系列的基本操作,如:open、read、write、close等。其中最基本的就是open,系统调用open一般在调用后会返回一个文件描述符。

为了使操作系统支持不同类型的文件系统,我们对不同的文件系统进行了抽象,隐藏了细节的差异,为各种文件系统提供一个通用的接口,这就是:虚拟文件系统(VFS)。每一个VFS对象都有四个数据结构:超级块对象、索引节点对象、文件对象、目录项对象。

超级块对象代表一个文件系统,描述一个文件系统的信息。每种文件系统具有自己的super_block结构,每个文件系统具有一个所属文件系统类型的super_block实例。索引节点对象代表单个文件,就类似于FCB或者inode。目录项对象对应于磁盘上的目录结构。文件对象对应打开的一个文件,在文件被打开时创建,由file结构体组成。

下面这张图给出了Linux文件系统的一个逻辑结构:

 

 

结合一个open系统调用的例子,介绍整个过程的流程:

1、在C的库函数open中,使用int 0x80指令触发了系统调用。

2、在中断向量表中找到对应的中断向量号128对应的表项,得到段选择符和段内偏移

3、装载cs和eip,跳转到系统调用程序入口

4、在系统调用程序中保存现场,通过系统调用号在系统调用表中找到open对应的sys_open函数

5、执行sys_open:进行命名查找,得到文件控制块,根据文件类型调用对应的文件打开函数

6、创建文件的系统文件打开表,使用文件控制块填充其中的部分内容

7、返回到进程,在进程的文件打开表中,从fd数组中找到一个空闲的表项,将表项对应的指针指向刚才的系统文件打开表

8、返回fd数组刚才分配表项的索引号

 在上图中,task_struct是进程控制块PCB,files_struct是进程打开文件表,file结构是文件对应的系统文件打开表。

 

心得与体会

我觉得这门课和本科上的操作系统体验很不一样,以前比较注重基本的概念,例如优先级反转、进程调用算法等等,大学的时候上课也没有结合具体环境和代码分析,感觉非常抽象。这门课以linux环境,每堂课都结合了底层的代码让我们看到linux操作系统是如何运行的。感觉收获到了很多,尤其是系统调用、中断处理、内核栈分析、文件系统等等。真正地把一些看似简单的函数的调用过程搞清楚了。总之,收获很大,从两位老师那都学到了很多。

基本没有什么需要提的建议,唯一可以想到的一点就是可以适当布置理论作业,不是像博客这样总结性的,是那种有明确对错的题目,这样我们能知道自己的理解是否和正确思路有偏差,方便我们了解自己的掌握状况。

posted @ 2020-07-09 20:34  Jaroo  阅读(205)  评论(0)    收藏  举报