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

计算机是如何工作的

这部分从最简单的汇编代码以及堆栈调用开始引入

大部分是曾经学过的内容,这一块比较特别的是冯诺依曼原理。

基本思想:存储程序与程序控制。

计算机工作的三个法宝

  • 存储程序计算机工作模型

  • 函数调用堆栈

  • 中断

计算机是如何工作的

操作系统是如何工作的

堆栈调用:

有压栈必有出栈,有生必有死

main开始执行=>调用p1=>压栈参数
				   =>压栈eip
				   =>ret

操作系统的两把剑:

         中断上下文      
		进程上下文切换

操作系统是如何工作的

构造一个简单的Linux系统MenuOS

  • 实验中的menu程序以及跟踪分析的方法
  • 一些重要的内核代码(都在原博客中啦)

构造一个简单的Linux系统MenuOS

扒开系统调用的三层皮(上)

  • 用户态,内核态,和中断以及他们的关系

    中断的完整过程:

      1)inter rupt(ex: int 0x80)_save
      cs:eip/ss:eip(当前栈顶)/eflcgs(标志寄存器)(current) to kernel stack ,
      then load cs:eip lentry of a specific ISR (加载新入口内核信息)) 
      and ss:eip (point to kernel stack)  
      2)SAVE_ALL
         |
      /*进程调度(不是必经)*/  
         |
      3)RESTORE_ALL(内核代码完成中断服务,发生进程调度)
      4)iret
    
  • 系统调用

    三层皮:

      1)API
      2)中断向量
      3)中断服务程序
    

    具体调用过程

  • 使用库函数API和C代码中嵌入汇编代码触发同一个系统调用(在实验部分可以具体找到)

扒开系统调用的三层皮(上)

扒开应用系统的三层皮(下)

实验中:

  • 给MenuOS增加time和time-asm命令
  • 使用gdb跟踪系统调用内核函数sys_time

系统调用在内核代码中的处理过程

从system_call到iret的过程

system_call的处理过程中:

xyz<=系统调用号=>sys_xyz()
int 0x80<=中断向量=>system_call

扒开应用系统的三层皮(下)

进程的描述和进程的创建

实验部分:gdb跟踪调试fork中的sys_ clone

内核三大功能:

进程管理
文件管理
内核系统

task_struct的代码分析查看

进程创建:

  • 0号进程(手写)->1号进程(复制0号进程的PCB,根据其修改pid加载init可执行程序)

  • 在fork中,两个进程,fork系统调用在父子进程个返回一次

          1)子 pid=0
          2)父 pid=子进程的id
    

新进程是从ret_ from_ fork开始执行

进程的描述和进程的创建

可执行程序的装载

  • 可执行文件的创建——预处理、编译和链接

    c代码——>1.编译器预处理.cpp(把.h文件宏替换)——>2.汇编代码.s——>3.目标代码.o——4.链接称为可执行文件a.out——>5.memory

  • 三种主要文件

      可重定位文件:【主要为.o文件】
      可执行文件:保存一个用来执行的程序,指出exec(BA_OS)如何创建程序映像(如何加载?执行?)
      共享Object文件:保存着两个连接器用来链接的数据
    
  • 两个链接器:

      链接编辑器
      动态链接器
    
  • 可执行程序、共享库和动态链接

      装载可执行程序之前的工作
      两种动态链接
      可执行程序的装载
      execve
    
  • 庄生梦蝶

庄周(调用execve的可执行程序)入睡(调用execve陷入内核),醒来(系统调用execve返回用户态)发现自己是蝴蝶(被execve加载的可执行程序)
修改int 0x80压入内核堆栈的EIP

可执行程序的装载

进程的切换和系统的一般执行过程

  • 进程进度与进程调度的时机

      原因:各类不同的切换需求(两种调度需求分类方式)
      时机:中断处理过程
    

    此处分为相对于

      a)内核线程(只有内核态,没有用户态)
      b)用户进程(只能被动)
    
  • 进程上下文切换相关代码分析

    schedule细节查看

  • Linux系统的一般执行过程

      	最一般的情况:正在运行的用户态进程X切换到运行用户态进程Y的过程
      	
      	正在运行的用户态进程X
      	        |
      	发生中断——save cs:eip/esp/eflags(current) to kernel stack,then load cs:eip(entry of a specific ISR) and ss:esp(point to kernel stack).
      	        |
      	SAVE_ALL //保存现场
      	        |
      	中断处理过程中或中断返回前调用了schedule(),其中的switch_to做了关键的进程上下文切换
      	标号1之后开始运行用户态进程Y(这里Y曾经通过以上步骤被切换出去过因此可以从标号1继续执行)
      	        |
      	restore_all //恢复现场
      	        |
      	iret - pop cs:eip/ss:esp/eflags from kernel stack
      	        |
      	继续运行用户态进程Y
    
  • 几个特殊情况

      1.通过中断处理过程中的调度时机,用户态进程与内核线程之间互相切换和内核线程之间互相切换,与最一般的情况非常类似,只是内核线程运行过程中发生中断没有进程用户态和内核态的转换;
      2.内核线程主动调用schedule(),只有进程上下文的切换,没有发生中断上下文的切换,与最一般的情况略简略;
      3.创建子进程的系统调用在子进程中的执行起点及返回用户态,如fork;
      3.内核与舞女
    
  • Linux系统架构和执行过程

进程的切换和系统的一般执行过程


各章读书笔记链接:

第一二章读书笔记

第五章读书笔记

第三章读书笔记

第十八章读书笔记

第四章读书笔记

类似于深入理解第七章的学期总结


个人总结:

这一部分的慕课学习以来,自己有好好抓紧的时候,也有松懈的时候,具体情况竟然从学生作业互评的分数中就能看出来。整个课程我可以说思考是一定有收获的,本来略感散乱的章节也在最后一节课的Linux系统结构和执行过程的总览里看到了紧紧联系在一起的意味。
内核中进程管理,进程调度,内存管理...很多很多架构和处理机制联系在一起,在发挥了操作系统中对各类进程执行及处理的能力,真不能说是学懂了,但能知道是个了不起的伟大结果。
这课其实还是有难度的,有一头雾水学不下去的时候,这种时候看一看优秀的同学的学习笔记,也能够吸收更多,并且在学生互评的时候,就能看到人和人的差距。然后此处应该展望一下未来,课程还没有结束,在后半部分的学习过程当中,也希望自己学到更多。