王雪 原创作品转载请注明出处 《Linux内核分析》MOOC课程 http://mooc.study.163.com/course/USTC-1000029000

一、博客目录:
1、第一周学习总结:计算机是如何工作的?
2、第二周学习总结:操作系统是如何工作的?
3、第三周学习总结:构造一个简单的Linux系统MensOS
4、第四周学习总结:扒开系统调用的三层皮(上)
5、第五周学习总结:扒开系统调用的三层皮(下)
6、第六周学习总结:进程的描述和进程的创建
7、第七周学习总结:可执行程序的装载
8、第八周学习总结:进程的切换和系统的一般执行过程

二、课程总结
在这次学习过程中,我真的学到了很多!刚开始接触Linux时,对于它的很多指令的执行总是摸不到头脑,如:计算机如何启动的啊?计算机启动过程中操作系统为我们做了什么?在Linux中那么多系统调用是如何执行的?等等问题,学习过这门课之后都有了很深刻的体会!
(1)计算机是如何工作的?
在这章中,老师主要为我们介绍了计算机的基本知识,如最基本的冯诺依曼体系结构、x86体系中的寄存器种类和作用、基本的汇编指令以及汇编指令完成的功能和执行的结果、寻址方式等等。老师还为我们详细解析了C语言函数调用过程中堆栈的变化和参数传递的过程。这些是我们学习和理解计算机的基础!
总结:
- 存储程序计算机工作模型——冯诺依曼体系结构。
- 程序:告诉计算机操作的步骤、输入的数据、如何存放处理后的结果。
- 汇编语言:汇编语言是机器语言的一种翻译。
计算机的基本原理是存储程序和程序控制,预先要把指挥计算机如何进行操作的指令序列(称为程序)和原始数据通过输入设备输送到计算机内存贮器中。每一条指令中明确规定了计算机从哪个地址取数,进行什么操作,然后送到什么地址去等步骤。
计算机在运行时,先从内存中取出第一条指令,通过控制器的译码,按指令的要求,从存储器中取出数据进行指定的运算和逻辑操作等加工,然后再按地址把结果送到内存中去。接下来,再取出第二条指令,在控制器的指挥下完成规定操作。依此进行下去。直至遇到停止指令。简单来说就是CPU负责处理和运算,存储器负责保存指令和数据。通过操作系统得调度和安排,不停地进行取址、译码、执行的循环。
(2)操作系统是如何工作的?
在这章中,老师主要为我们介绍了简单模拟内核代码。主要包括函数调用堆栈、函数堆栈框架、内核的初始化、中断、进程上下文切换过程的简述以及基于时间片轮转的多道程序模拟。
在这一章里,我们初步接触到了中断和另一个关键的知识点:在C语言在嵌入汇编代码。
老师通过实验生动地为我们演示了中断、进程切换的过程,模拟了一个小型的操作系统的基本功能,非常高大上!!通过对汇编代码的解析和中断前后函数堆栈的变化,加深了我们对操作系统工作过程的理解!
总结:
- 操作系统三个法宝:存储程序计算机、函数调用堆栈、中断机制。
- 操作系统两把宝剑:中断上下文、进程上下文的切换。
- 中断:多道程序设计,可以多个程序同时运行,当一个中断发生时,由CPU和内核代码共同实现了保存现场和恢复现场。
- 操作系统核心功能:进程调度和中断机制,通过与硬件的配合实现多任务处理,再加上上层应用软件的支持,最终变成可以使用户可以很容易操作的计算机系统。
- 进程切换:当正在运行的进程等待其他的系统资源时,Linux内核将取得CPU的控制权,并将CPU分配给其他正在等待的进程。进程切换机制中包含esp的切换、堆栈的切换。
其中进程切换是操作系统最主要的功能。
进行进程切换就是从正在运行的进程中收回处理器,然后再使待运行进程来占用处理器。这里所说的从某个进程收回处理器,实质上就是把进程存放在处理器 的寄存器中的中间数据找个地方存起来,从而把处理器的寄存器腾出来让其他进程使用。让进程来占用处理器,实质上是把某个进程存放在私有堆栈中寄存器的数据(前一次本进程被中止时的中间数据)再恢复到处理器的寄存器中去,并把待运行进程的断点送入处理器的程序指针PC,于是待运行进程就开始被处理器运行了,也就是这个进程已经占有处理器的使用权了。在切换时,一个进程存储在处理器各寄存器中的中间数据叫做进程的上下文,所以进程的切换实质上就是被中止运行进程与待运行进程上下文的切换。
(3)构造一个简单的Linux系统MenuOS
在这章中,老师主要通过讲解了一个简单的Linux系统MenuxOS,利用gdb追踪了内核启动的过程。
本次实验主要分析了在内核启动过程中的第一个函数:start_kernel的执行。
start_kernel()是init/main.c第一个启动的函数,主要完成了很多重要的与硬件平台相关和内核相关的初始化,并创建了init进程。
在init的start_ kernel()中调用了setup_ arch()进行与体系结构相关的第一个初始化,
通过bottom_init()函数根据系统定义的meminfo结构进行内存初始化,
最后paging_init()开启mmu,创建内核页表,映射所有的物理内存和I/O空间,
完成了创建异常向量表和初始化中断处理函数,初始化系统核心进程调度器和时钟中断处理机制,初始化串口控制台(serial_console)等等,
当所有的相关操作结束后,start_ kernel()会调用rest_ init()进行最后初始化,包括创建系统的第一个进程——init进程,init进程首先进行一系列的硬件初始化,然后通过命令行传递过来的参数挂在根文件系统,init进程会执行用户传递过来的参数执行用户指定的命令或者执行/sbin/init,/etc/init,/bin/init,/bin/sh 之一完成初始化工作,cpu_idle会被调用使系统处于闲置状态并等待用户输入。
到此,Linux内核启动完毕。
最后,老师精辟的总结道: :道生一(start_kernel->cpu_idle),一生二(kernel_init和kthreadd),二生三(即前面0、1和2三个进程),三生万物(1号进程是所有用户态进程的祖先,2号进程是所有内核线程的祖先) 更加加深了我们的理解和记忆!
(4)扒开系统调用的三层皮(上)——-通过time系统调用理解系统调用的执行过程
这一章我们开始跟着老师一起学习系统调用,首先,老师为我们介绍了基本的概念,例如:用户栈与内核栈 、用户态与内核态 、内核态与用户态的切换 等基本知识,
- Intel x86 CPU有四种不同的执行级别0-3,Linux只使用了0级和3级分别表示内核态和用户态。
- 0xc0000000以上的逻辑地址空间只能在内核态下访问,0x00000000-0xbfffffff的逻辑地址空间在两种状态下都能访问。
- 中断处理是从用户态进入内核态的主要方式,而系统调用只是一种特殊的中断。
进而引入了系统调用,下图展示了系统调用的执行过程:

系统调用时执行的操作
1)在进程的内核态堆栈中保存大多数寄存器的内容(即保存恢复进程到用户态执行所需要的上下文)
2)根据用户态传递的系统调用号,确定系统调用的服务例程
3)调用名为系统调用服务例程的相应的C函数来处理系统调用
4)从系统调用返回
简单描述系统调用的执行过程:在用户态下执行某个API函数,在API函数中有一个int 0x80的中断向量,触发后,由用户态进入内核态,保存现场,查找system_ call表找到相应的系统调用号,找到后执行相应的系统调用服务例程,执行过后返回,恢复现场,回到用户态。

在这次实验中,我们还尝试添加了自己的系统调用,尝试用嵌入汇编代码的方法模拟了系统调用的功能。
(5)扒开系统调用的三层皮(下)——-追踪系统调用的执行过程
在这次学习中,我们更加深入的理解了系统调用的过程,将我们自己写的系统调用添加到MenuOS的操作系统中。
对以下问题做出了更加深刻的理解:
1)系统调用机制是什么时候初始化的:
在系统启动时执行start_ kernel,start _ kernel中会调用trap _ init()函数, 用于硬件中断向量初始化,这个函数被定义在/arch/x86/kernel/trap.c中, SYSCALL _ VECTOR系统中断向量 ,system_ call:系统调用入口, 当发生中断或系统调用,直接找到system_call入口地址去执行。
2)系统调用的处理过程:
系统调用的定义在/arch/x86/kernel/entry_32.S中,有一个入口
ENTRY(system_call),是int $0x80后的下一条执行地址,
大致流程:

system _ call->sys call table ->syscall exit(是否处理syscall exit _ work) ->restort _all -> irq _return,work _notifying用于处理信号
在系统调用返回前有可能进行进程调度,有可能需要处理当前进程的信号
进行进程调用在work_resched中call schedule; 中断结束后,从内核态返回用户态!
(6)进程的描述和进程的创建
这章我们主要学习了关于进程的描述和创建。主要包括PCB的组织形式、进程的数据结构进程描述符、fork系统调用的关键执行过程。
- 操作系统三大功能:进程管理(核心)、内存管理、文件系统
- PCB task_struct中包含:进程状态、进程打开的文件、进程优先级信息
- 进程控制块PCB——进程描述符task_stuck提供了内核所需了解的进程信息
- 进程的创建:start_kernel …cpu_idle –>kernel_init和kthreadd –>0、1、2号进程(其中1号进程是所有用户线程的祖先,2号进程是所有内核线程的祖先)
- fork()系统调用:在用户态创建一个子进程,在父进程和子进程中各会返回一次,在子进程中pid的返回值为0,在父进程中的返回值为子进程的pid
- p->thread.ip = (unsigned long) ret_from_fork; //调度到子进程时的第一条指令。
老师为我们详细介绍了进程的状态、相关的数据结构,是我们理解操作系统进程的关键。
在这一章里我们主要解决了:进程是如何被创建起来的?fork函数是怎么执行的?fork出来的子进程从哪里开始执行?
1)fork()调用一次返回两次,只不过返回的分别为父进程和子进程,也就是说,上面的代码有三种返回值,如果fork返回-1代表创建失败,结束。fork在子进程中会返回0,在父进程中会返回子进程pid(>0)。
2)创建一个新进程在内核中的执行过程:复制一个PCB——task_ struct—>要给新进程分配一个新的内核堆栈—>修改复制过来的进程数据,比如pid、进程链表等(在copy_ process中)—> 从用户态的代码看fork();函数返回了两次,即在父子进程中各返回一次,子进程从系统调用中返回,那它在系统调用处理过程开始执行的位置以及
子进程的内核堆栈数据状态和task_struct中thread记录的sp和ip的一致性问题都需要设定。
3)在entry_ 32.S找到ret from work,标识了 p->thread.ip,当子进程获得CPU从内核态返回到用户态,在内核态中是从ret _ from _ work开始执行的。 ret_from _ work 会跳转到sys _ call _exit(这时的状态与调用前是相同的),从iret返回用户态,此时的内核空间变为子进程的内核空间。
总结:
进程管理是操作系统功能的重要组成部分,是理解操作系统的关键,对于fork这个系统调用(调用一次,返回两次)要记住子进程是如何被创建起来的,都拷贝了父进程的哪些信息,修改了哪些信息,子进程是如何找到返回位置的,它在内核中是如何执行起来的等等。
(7)可执行程序的装载
这章我们学习了关于程序的加载过程和ELF文件格式。主要包括得到一个可执行程序过程、ELF文件格式的结构和静态链接、可执行程序的静态加载过程和动态加载过程。
- 链接器的两个任务:符号解析、重定位
- 目标文件的三种形式:可重定位目标文件(编译器和汇编器可生成)、可执行目标文件(链接器可生成)、共享目标文件(编译器和汇编器可生成)
- 新的可执行程序起点——一般是地址空间为0x8048000或0x8048300
- execve执行静态链接程序时,通过修改内核堆栈中保存的eip的值作为新进程的起点
- 动态连接有两种形式:可执行程序装载时动态连接和运行时动态链接
- 运行时动态装载链接至少需要用到dlopen、dlsym函数
在这章中我们主要解决了:
1)可执行程序是怎么来的?
2)可执行文件的内部是怎样的?
3)ELF中三种目标文件
4)ELF头(保存了很多关键信息)
5)可执行的文件加载的工作:当创建或者增加一个进程映像时,系统在理论上将拷贝一个文件的段到虚拟的内存段
6)静态链接的ELF可执行文件与进程的地址空间
7)可执行程序、共享库和动态进程
其中,可执行程序、共享库和动态进程是我们需要重点理解的单元,它综合了这章前面介绍的基本知识,静态装载过程和动态装载过程的区别与联系也应该仔细理解掌握!
(8)进程的切换和系统的一般执行过程
这章我们主要学习了关于进程切换和整体执行过程。主要包括Linux进程调度算法简介、进程切换代码分析、switch_to理解、进程相关的数据结构简析。
- Linux进程调度是基于分时和优先级的
- Linux中,内核线程是只有内核态没有用户态的特殊进程
- 内核可以看作各种中断处理过程和内核线程的集合
- 用户态进程无法主动调度,只能通过系统调用或其他中断陷入内核的时机进行调度
- Linux中,内核线程可以主动调度,主动调度时不需要中断上下文的切换
- Linux内核调用schedule()函数进行调度,并调用context_ switch进行上下文的切换,这个宏调用switch_to来进行关键上下文切换。
- 进程调度的时机——schedule()函数实现调度
此外,老师还帮助我们做了一个知识的整合,将我们这段时间以来学过的知识进行了综合,帮助我们理解Linux操作系统的框架、简单的命令执行过程、从CPU和内存的角度看Linux系统的执行等。通过这段总结,让我对以前学习的知识有了更深刻的认识以及认识到各部分课程之间的关系的紧密!
三、心得与总结
(1)我的收获
感谢老师为我们打开了通向Linux的大门,我在学习过老师的高级软件工程后,对Linux这个操作系统更加有兴趣,这学期和老师一起学习《Linux操作系统分析》受益匪浅,这门课让我对Linux的操作系统有了更深的理解,老师用生动的语言和表达为我们揭示了Linux操作系统的工作方式,比如说操作系统的三大法宝、两把利剑、庄生梦蝶、内核与出租车,舞女、道生一,一生二等等,这些幽默有趣的语言加深了我的理解和记忆。同样,老师也教会了我Linux的“跟踪”方式——gdb调试,对我以后的学习很有帮助。老师将MenuOS再一次带到Linux操作系统分析中,通过简化那复杂的内核代码,让我终于不再害怕那么长的代码,更方便我对关键知识的理解,同时让我明白了知识的整合,“看似没有关联,其实联系千丝万缕”。这些都是我的心得,在学习的过程中我一点一点意识到自己的不足,在老师的讲解下,也明白了自己原来的困惑,也学习到了老师解决问题的方式方法。学习是一个不断探索的过程。
(2)我的遗憾
在这次课程中我的遗憾便是对于一些知识还没有完全掌握,操作系统很复杂,我在动手实践的过程中,也是跟着老师的讲解过的方法进行,没有试着自己动手实践和研究,自己动脑思考研究出新的方法,我觉得这是我欠缺的,以后应该改正!学习,任重而道远。

短短几周的时间很快就要过去了,还没有听够老师讲解又到了结课的时间,这段时间我真的学到了很多,关键是我明白了自己究竟欠缺在哪里,比如知识的整合,动手实践的重要性等等。真心感谢老师,这段时间的学习让我清楚地认识到自己以后该怎么去学习。
感谢老师这段时间的付出,老师辛苦了,祝老师身体健康、工作顺利。

Linux操作系统分析------期末总结、感谢老师、祝我们越来越好相关推荐

  1. 2020中科大软件学院linux操作系统分析期末考试题

    前言:csdn上有关中科大孟老师linux操作系统期末考试复习资料居然是一片空白,考试前两天才知道考试题型,哎,我就填补一下这个空白吧,此试题为回忆版,并无答案. 第一题填空题20分: 如图所示,给了 ...

  2. linux+6.2+期末考试题,2020中科大软件学院linux操作系统分析期末考试题

    前言:csdn上有关中科大孟老师linux操作系统期末考试复习资料居然是一片空白,考试前两天才知道考试题型,哎,我就填补一下这个空白吧,此试题为回忆版,并无答案. 第一题填空题20分: 如图所示,给了 ...

  3. linux操作系统分析实验—基于mykernel的时间片轮转多道程序实现与分析

    linux操作系统分析实验-基于mykernel的时间片轮转多道程序实现与分析 学号384 原创作业转载请注明出处+中国科学技术大学孟宁老师的Linux操作系统分析 https://github.co ...

  4. Linux操作系统分析——课程总结报告

    一.Linux系统的启动过程 1.POST开机自检 linux开机加电后,系统开始开机自检,该过程主要对计算机各种硬件设备进行检测,如CPU.内存.主板.硬盘.CMOS芯片等,如果出现致命故障则停机, ...

  5. Linux操作系统分析-课程总结报告

    一.结合虚拟化技术分析Linux系统的一般执行过程 a. 一个 Linux 系统在虚拟化技术中的一般执行过程: 用户登录:当用户登录到 Linux 系统时,系统会创建一个用户会话. 系统启动:Linu ...

  6. 【Linux操作系统分析】设备驱动处理流程

    1 驱动程序,操作系统,文件系统和应用程序之间的关系 字符设备和块设备映射到操作系统中的文件系统,由文件系统向上提供给应用程序统一的接口用以访问设备. Linux把设备视为文件,称为设备文件,通过对设 ...

  7. Linux操作系统分析 | 深入理解系统调用

    Linux操作系统分析 | 深入理解系统调用 实验要求 1.找一个系统调用,系统调用号为学号最后2位相同的系统调用 2.通过汇编指令触发该系统调用 3.通过gdb跟踪该系统调用的内核处理过程 4.重点 ...

  8. Unix/Linux操作系统分析实验二 内存分配与回收:Linux系统下利用链表实现动态内存分配

    Unix/Linux操作系统分析实验一 进程控制与进程互斥 Unix/Linux操作系统分析实验三 文件操作算法: 实现在/proc目录下添加文件 Unix/Linux操作系统分析实验四 设备驱动: ...

  9. Unix/Linux操作系统分析实验四 设备驱动: Linux系统下的字符设备驱动程序编程

    Unix/Linux操作系统分析实验一 进程控制与进程互斥 Unix/Linux操作系统分析实验二 内存分配与回收:Linux系统下利用链表实现动态内存分配 Unix/Linux操作系统分析实验三 文 ...

最新文章

  1. win2003 服务器超出最大连接+强制重启服务器(方法)
  2. 美国互联网广告07年总开支255亿美元, 增长27%
  3. 【Linux】一步一步学Linux——at命令(133)
  4. 数据库异常关闭后无法启动问题处理
  5. [CB]TForm应用技巧
  6. JavaScript学习(十三)—节点关系
  7. C语言小游戏,编程入门必看,初级扫雷
  8. SVN工具介绍- VisualSVN Server与TortoiseSVN
  9. Kubernetes 集群安全 - 鉴权 实战rolebinding和clusterrole
  10. 复联4定档 4.24——十一年21部漫威电影,用数据为你梳理口碑、票房、主演最佳......
  11. matlab中abs函数,matlab 中的abs函数什么意思 编程知识
  12. 递归实现顺序输出整数
  13. 中年危机也许只是个幻觉
  14. 【LeetCode系列】LCP 25. 古董键盘(一道动态规划困难题)
  15. getElementByClassName
  16. 新浪微博开放平台账号申请(基于dcloud开发)
  17. MDK5怎么查看GPIO
  18. 通信原理 | 虚数j的物理意义
  19. 为什么有些人能力很强却不被提拔?看完这个回答,我心服口服
  20. 手机录制的视频不能导入AE解决办法,86::1,先导入PR

热门文章

  1. (转载)分享申请IDP账号的过程,包含duns申请的分享
  2. verilog 8位计数器
  3. Hexagon LLVM编译架构介绍(3)
  4. 防火墙和系统安全防护及优化
  5. lanmbda表达式
  6. 计算机网络管理入门(一)
  7. “打拼十年,35岁一事无成”:前半生偷的懒,后半生拼命还
  8. 浅析cookie和session
  9. SpringBoot读取资源文件
  10. 鼻腔需要每天清洗吗?