作业要求
请您根据本课程所学内容总结梳理出一个精简的Linux系统概念模型,最大程度统摄整顿本课程及相关的知识信息,模型应该是逻辑上可以运转的、自洽的,并举例某一两个具体例子(比如读写文件、分配内存、使用I/O驱动某个硬件等)纳入模型中验证模型。
谈谈您对课程的心得体会,改进建议等。
一、精简的Linux系统概念模型
二、计算机与操作系统的工作原理
简单来说,计算机有“三大法宝“:存储程序计算机、函数调用堆栈机制、中断,操作系统有”两把宝剑“:中断上下文、进程上下文。
(一)计算机的三大法宝
1、存储程序计算机
基本含义:将编写好的程序和数据先写入存储器中,然后启动计算机工作。
内存中保存指令和数据,CPU从内存中取执行执行、从内存中读取数据。二者通过总线连接起来。
使用程序员的思维对存储程序计算机进行抽象:
可以把CPU抽象成一个for循环,因为它总是在执行next_instruction,然后从内存中取下一条指令执行。
2、函数调用内核堆栈机制
作用:记录函数调用框架、传递函数参数、保存返回值的地址、提供函数内部局部变量的存储空间。
3、中断
中断在Linux操作系统中非常重要的概念,在下方详述。
(二)操作系统的两把宝剑
1、进程上下文
进程上下文包括:
(1)用户地址空间:程序代码、数据、用户堆栈等
(2)控制信息:进程描述符、内核堆栈
(3)硬件上下文:相关寄存器的值
进程切换就是变更进程上下文,有必要了解一下进程相关概念,在下方详述。
2、中断上下文
三、中断
(一)进程的用户态和内核态
(二)中断
1、分类
2、中断过程
中断处理是从用户态进入内核态的主要方式。
中断发生后,从用户态切换到内核态:
在当前进程的内核态堆栈中保存:
当前进程的用户态栈顶地址(SS:ESP)、当时的状态字(EFLAGS)、当时的ES:EIP寄存器的值
(以上都是由int指令完成的)
(1) 中断发生后的第一件事情就是保存现场
SAVE_ALL
保存其他寄存器的值到栈中
(2)将当前进程的内核态的栈顶地址、内核态的状态字(EFLAGS)放入CPU对应的寄存器中,并将CS:EIP寄存器的值指向中断处理函数的入口(对系统调用而言,是指向system_call)
(3)当中断处理结束后:
查看是否发生进程调度:
a. 如果没有发生进程调度:
restore_all 恢复中断现场
iret 返回到原来的状态
实际上就是将中断时保存在当前进程内核态中的信息进行出栈操作到当前CPU中
b. 如果发生进程调度:
当前的这些状态都会保存在系统内核堆栈里
当下一次发生进程调度有机会再切换回当前进程时,就会接着把restore_all和iret执行完,这样中断处理过程就被执行完了。
(iret指令和int指令执行的是完全相反的工作)
中断处理结束前的最后一件事是恢复现场。
3、中断触发
int指令的执行会触发一个中断请求。
(三)系统调用
1、系统调用的三层机制
应用程序调用系统调用【用户态】
第一层:libc标准库对系统调用进行了封装 【用户态】
libc函数库中定义的一些API内部使用了系统调用的封装例程,主要目的就是发布系统调用,使程序员写代码时不需要用汇编指令和寄存器传递参数来触发系统调用,而是直接调用这个API函数就可以触发对应的系统调用。
API内部封装的系统调用会触发int $0x80中断,对应system_call函数的起点,即中断向量0x80对应的中断服务程序的入口system_call。
第二层:系统调用处理入口system_call 【内核态】
里面有系统调用处理函数
第三层:系统调用内核处理函数 【内核态】
2、如何区分系统调用——系统调用号
用户态进程在触发系统调用时,必须指明需要哪个系统调用,使用EAX寄存器传递一个名为系统调用号的参数。
3、系统调用的处理过程
在正常触发系统调用时,用户态有一个int $0x80或syscall指令触发系统调用,跳转到系统调用入口的汇编代码。
【int $0x80触发entry_INT80_32并以iret返回系统调用,syscall触发entry_SYSCALL_64并以sysret或iret返回系统调用】
(1)int $0x80或syscakk触发中断机制,陷入内核态,CPU自动保存与转换堆栈,从用户态堆栈转换到内核态堆栈,把当前进程用户态的堆栈SS:ESP、EFLAGS、CS:EIP都压栈到当前进程的内核堆栈中
(2)int $0x80接下来执行到system_call(entry_INT80_32)的位置,system_call这段代码用于保存现场、执行系统调用内核处理函数(根据系统调用号,查询系统调用表得到对应的函数入口)、系统调用处理完之后的返回、恢复现场
(3)最后iret将CPU关键现场SS:ESP、EFLAGS、CS:EIP从昂前进程的内核堆栈中恢复到对应寄存器中,并回到用户态int $0x80或syscall指令之后的下一条指令的位置继续执行。
四、进程
(一)进程的描述
进程描述符 struct task_struct
进程的状态转换
(二)进程的创建
使用fork系统调用创建新的子进程:
(三)进程的切换
进程调度时机、调度策略与算法、进程上下文的切换等
五、文件系统
六、心得体会
通过对本门课程的学习,我对Linux内核的工作机制和工作原理有了更加深入的理解,原来只是对一般操作系统中进程、中断、文件系统等概念有所了解,现在更是将Linux操作系统与一般操作系统中相关的知识点进行了比较和融合。尤其是通过前面几次的作业和实验,在自己动手操作配置一个虚拟的Linux内核、并且在这个内核上进行系统调用,跟踪中断上下文和进程上下文,体会Linux的一般执行过程之后,我对Linux平台产生了浓厚的兴趣,希望在课程结束之后我还依然能对Linux内核、操作系统和Linux平台上的编程技术做深入的研究。