一、课程概述
这次选修的 Linux 操作系统课是我们院的孟宁老师和李春杰老师一起教授的,两位老师风格不同,各有侧重点,对我们来说同一门课有了不同的感受。
在孟老师的课里,我们先熟悉了 linux 汇编,然后通过一个简单的内核 mykernel 学习到了 linux 是如何启动的,后面又学到了函数调用堆栈、中断上下文切换、系统调用、进程上下文切换等方面的基础知识并结合 linux 代码进行内核分析。
在李老师的课中,分别从中断和异常、时钟、进程管理、驱动程序基础、内核跟文件系统挂载、文件系统等角度讲授了很多 linux 内核方面的知识。
二、Linux 系统概念模型
结合课程重点,我总结了如下几个部分的一些简要概述
1、系统调用
系统调用涉及到了中断上下文的转换,因为程序一般是从用户态转到内核态,所以需要进行中断上下文的保存现场和恢复现场的工作。
-
用户态程序代码调用系统调用,会执行一个包装系统调用的库函数
-
库函数向内核传递参数,触发软中断切换到内核
-
保存现场,执行中断处理程序,即系统调用处理程序(system_call)
-
系统调用处理函数会调用系统调用服务例程,处理该系统调用
2、进程管理
进程管理是操作系统中最核心的功能,因为它可以把内存管理、文件系统、进程间通信等内容串起来。在操作系统中用进程控制块 PCB 来描述进程,进程描述符来描述进程,进而进行进程的管理。
fork() 系统调用创建新进程,进程进入就绪态(TASK_RUNNING),当调度器选择该进程运行时,进程进入运行态(TASK_RUNNING),即 TASK_RUNNING 表示就绪态和运行态,具体由该进程是否被调用来区分。
运行态的进程调用用户态函数 exit() 会陷入执行内核态函数 do_exit(),终止进程,进程进入终止态,此时称为僵尸进程。内核处理掉僵尸进程,释放进程描述符后,进程会在内核中消失。
3、可执⾏程序⼯作原理
我们编写的可执行程序要作为一个进程来工作,这就涉及到了可执行文件的格式、编译、链接、装载等相关知识。
源代码编译生成的目标文件与目标平台有关,平台决定了编译器使用的机器指令集。
ELF 是可执行和可链接的文件格式标准,用于存储 Linux 程序
ELF 文件的 3 种类型
-
可重定位文件:中间文件,还需要继续处理,一个源代码文件生成一个可重定位文件,文件后缀为 .o;静态链接库⽂件实际上是可重定位⽂件的打包,它也是可重定位⽂件,⼀般以 .a 作为⽂件名后缀
-
可执行文件:由多个可重定位⽂件结合⽣成
-
4、Linux 驱动程序
驱动程序沟通着硬件和应用软件,应用软件只需要调用系统 API 就可以操作硬件工作。
用户通过内核模块机制可以把驱动程序静态编译进内核或动态加入内核,内核模块直接操作内核函数,比库函数更加偏向底层。
内核模块的基本结构
-
头文件声明
-
模块许可声明
-
初始化、卸载函数声明
模块的编译需要配置过的内核源代码,编译首先在内核源码目录下读取顶层的 makefile 文件,然后回到模块源代码目录编译。
用驱动程序操作外设,由于外设的操作时间长,一般采用轮询和中断模式(注册中断号或者检测中断号)进行。
中断处理程序
-
上半部分:立即被内核执行
-
对时间敏感
-
和硬件相关
-
具有原子性
-
-
下半部分:推迟执行
-
软中断
-
Tasklet:在软中断的上下文中运行,代码是原子的
-
工作队列:在内核线程上下文运行,非原子
-
中断模式的简单例子
-
在设备文件上进行系统调用,一条输入命令发往设备的控制寄存器
-
设备响应后中断,数据返回到输入寄存器
-
驱动程序将改数据作为系统调用结果返回
-
一般在第一次打开设备时注册中断,最后一次关闭时释放中断
Linux 将硬件设备看做一个特殊的文件(设备文件)来操作,系统通过对设备文件的读写操作,实现对外设的读写操作。驱动程序沟通设备文件和直接外设。
三、总结
通过这门课,我对 Linux 底层操作系统有了更加深刻的认识,感谢老师们在疫情期间的悉心指导。