0%

《linux内核设计的艺术:图解linux操作系统架构设计与实现原理》(第二版)

  要知道,写一本好书并不是说说就那么简单的,思路清晰、知道重点、保持严谨、不厌其烦,应该是写文章做报告写书的人都应该具备的特点,我虽然没写过,但也知道这本书很好的起到了反面例子。但即使没那么好的书,也比某些单独的文章要好得多。
  这本书不像Orange’s是个玩具操作系统,而是实实在在讲的linux-0.11——可以实际运行、实际使用的内核。从加电引导,到保护模式启动,内核建立中断,到第0、1、2个进程建立,再到文件系统、内存管理、进程调度,跟着源码一步步将系统带入到“怠速”状态,很神奇的过程。从这里边会明白linux进程调度用到的switch_to(n)是怎么加载TSS,怎么从一个进程转移到另一个进程;会知道系统调用的代码执行路线;内核中的文件系统是怎么组织的,以前想不明白的dup()/dup2()函数是怎么个过程,看了源码立马就清晰了;pipe()原来是个内存页,怪不得最大长度是4096字节(页大小);内存的段页管理机制到底是怎样的。源码之前,了无秘密


  1. 加电启动过程

    1
    2
    3
    4
    1. BIOS:处理器加电启动时会执行0xFFFF0处的代码,也就是BIOS所在区域(直接写在ROM中,不需要加载)。BIOS会加载bootsect进入内存0x007c0位置。
    2. bootsect: 规划内核内存使用,将自己复制到合适的位置 (因为占用了0x007c0的位置,这部分是要给后边的程序用的),加载setup、system代码进入内存;跳到seup
    3. setup: 利用BIOS的中断服务程序从设备提取内核运行所需的机器系统数据,覆盖掉bootsect程序,关中断;将位于0x10000的内核程序复制到内存地址0x00000处(这里原来放着BIOS的中断向量表和BIOS数据区,在bootsect运行的时候还需要用到中断,所以bootsect一开始不能直接把内核载入到0x00000处),设置中断描述符表和全局描述符表;打开A20,实现32位寻址;建立保护模式下的中断机制,对8259A进行重编程;跳到head
    4. head:跟kernel编译在一起,执行本段代码的时候,会覆盖掉本段已经用过的代码(自己吃自己);让所有中断描述符指向ignore_int忽略中断;废除已有的GDT,在新位置重建GDT(原来的GDT是setup建立的,现在setup没用了,这段内存会被覆盖,其中的GDT也会被覆盖。);检验A20是否真正打开;检验数学协处理器;将L6和main地址压栈;建立内核的分页机制;打开分页;调用ret执行main
  2. 进程要想与块设备进行沟通,必须经过主机内存中的缓冲区。

  3. 对物理内存的规划
    除了内核代码和数据所占的内存外,其余物理内存主要分为3部分:
    1) 主内存区:进程代码运行的空间,也包括内核管理进程的数据结构
    2) 缓冲区:主机与外设进行数据交互的中转站
    3) 虚拟盘:可选区域,如果选择使用虚拟盘,就可以将外设上的数据先复制到虚拟盘区,然后加以使用,这样可以提高系统执行效率。

  4. 进程切换,用的是switch_to(n),切换之前会保存当前进程的所有状态,包括下一条指令,再次切换回来后会从先前状态继续执行,沿着自己的函数调用链依次进行或返回。

  5. 逻辑地址的形式是CS:DS。实模式下,CS中存放的是段基址,跟DS组成线性地址,线性地址直接映射到物理地址(也就是通过地址线的地址);保护模式下,CS中存放的是段选择子,段选择子会在段描述符表(GDT)中找到相应的段描述符,段描述符中存放的有段基址、段属性、段权限(用于保护)等信息,段描述符中的段基址跟DS组成线性地址,这里如果没有开启分页(只有保护模式才有分页机制),线性地址就直接映射到物理地址;如果开启了分页,线性地址会分成3部分,分别指示处理器找到页目录表、页表、页(页帧),再用线性地址的最后一部分找到页中的某个实际的物理位置。这么麻烦的使用段描述符,是为了保护;这么麻烦的使用分页,一是为了保护,二是为了实现虚拟内存。


新设计团队