Linux 0.11 的代码是用 C 语言编写的,但是在操作系统启动时先执行的是三个由汇编语言写成的程序(bootsect, setup, head)。因为 C 语言编写的用户应用程序必须在操作系统的平台上执行,所以需要先加载操作系统。
加载操作系统的时候,计算机刚刚加电,只有 BIOS 程序在运行,而且此时计算机处在 16 位实模式状态,通过 BIOS 程序自身的代码形成的 16 位的中断向量表及相关的 16 位的中断服务程序,将操作系统在启动盘的第一个扇区(512字节)的代码加载到内存,BIOS 能主动操作的内容也就到此为止了。对于第一扇区代码的加载,不论是什么操作系统都是一样的;从第二扇区开始,就要由第一扇区中的代码来完成后续的代码加载工作。
第一扇区:第一部分内核代码,引导程序,bootsect.s 规划内存载入 setup.s载入系统模块 system 模块(屏幕显示:Loading System…)确定根文件系统 4 个扇区:第二部分内核代码,setup.s 提取内核运行所需的机器系统数据破旧立新:废除 BIOS 中断,将 system.s 移动到内存地址起始位置为保护模式做准备 240 个扇区:第三部分内核代码,system 模块 执行 head.s 创建内核分页机制,是内核能够掌控用户进程的基础之一加载工作完成后,并没有立即执行 main 函数。开机时的 16 位实模式与 main 函数执行需要的 32 位保护模式之间有很大的差距,head.s 来弥补这个差距。此时中断仍处于关闭状态。
硬件初始化:
与主机有关的硬件初始化:规划内存格局,设置及初始化缓冲区,设置及初始化虚拟盘,初始化 mem_map,初始化缓冲区管理结构。与外设有关的硬件初始化:设置根设备,初始化软盘,初始化硬盘。为内核及进程的正确运行所做的初始化:中断服务程序的挂接,初始化进程 0。
用模拟中断的方法将进程 0 的特权级由 0 翻转到 3,实现激活进程 0。(除了进程 0 外,所有进程都要由一个已有进程在 3 特权级下创建)
操作系统启动以来,内核第一次进行进程调度。
进程 1 第一次执行后,设置硬盘信息,格式化虚拟盘,加载根文件系统。
进程 1 创建进程 2,加载 shell 程序,创建 update 进程,重建 shell,实现系统怠速。
进程 0 和进程 1 的代码都是操作系统设计者直接写到内核代码中的,进程 2 则是从硬盘中加载的执行代码,而且 shell 进程是对操作系统非常重要的用户界面进程,所以涉及打开终端设备以及大量的文件操作。
操作系统对文件的一切操作都可以分为两个方面:
对文件管理信息的操作:新建,打开,关闭,删除文件对文件数据内容的操作:读文件,写文件,修改文件操作文件管理信息就是建立或解除进程与文件的关系链条,进程可以沿着关系链条,依托缓冲区与硬盘进行数据交互。当关系链条解除后,进程则不再具备操作指定文件的能力。
如果文件管理信息被更改,则操作系统要将此更改落实在硬盘上,以免失去对文件数据内容的控制。而文件数据内容的更改需要先在缓冲区进行操作,再写入磁盘。
多进程操作文件的核心是多进程对缓冲区的操作。缓冲区关联着用户进程,文件系统和内存。
进程间通信通过管道。
信号机制是一种模仿软件中断机制。
运行 Hello World 程序,操作系统为程序运行做了哪些工作。
用户输入命令./hello,shell 进程被唤醒,对命令进行解析。 用户敲击键盘后,以文件系统的操作方式将输入的信息记录在终端设备文件上(tty0)。(需要一整套文件系统)敲击键盘后,产生键盘中断信号,系统对通过搜索中断描述符表找到键盘中断处理程序,并执行该程序。(需要一整套中断服务体系)中断服务程序开始执行后,唤醒 shell 进程,通过进程调度机制,由进程 0 切换到 shell 进程去执行。(需要一整套进程管理机制)shell 进程通过执行自己的程序从 tty0 终端设备文件上读取用户键入的指令信息,然后解析该指令,并进行相应的处理。每个字符的敲击都会重复上述动作。 shell 程序解析出用户命令后,调用 fork 函数创建一个用户进程,以便对 Hello World 文件的程序进程控制。 进程结构包括:时间片,优先级,进程状态,进程对应的文件,进程的任务状态描述符(TSS)和进程的局部数据描述符表(LDT)。进程的任务状态描述符(TSS):当前进程运行时所有寄存器中的数据。进程的局部数据描述符表(LDT):当前进程的代码段描述符和数据段描述符。 新进程创建完毕后,加载 Hello World 文件对应的程序。 文件加载前检测可执行文件是否可用。若具备载入文件的条件,则将文件载入内存。(页写保护和缺页中断) 程序执行,显示 Hello World。在特权机制下,操作系统和应用程序为主奴关系。
通过进程的 task_struct 结构来划分程序的边界,创建进程就是创建 task_struct,所以进程 0 只能由操作系统创建,而可以由进程 0 复制创建子进程。
为什么内核程序能获得高优先级,而用户程序就不能?
计算机开机启动的时候是实模式,没有特权级的概念。当操作系统的启动程序打开保护模式的时候,特权级状态必须是最高级。
一些恶意程序可以将代码驻留到系统引导区,甚至 BIOS,抢占先机来获取最高特权级。
软件就是进程,硬件就是文件。
非用户进程:进程 0,进程 1,shell 进程。
进程 0 为在主机中有运行能力的进程。进程 1 为有使用外设(文件)能力的进程。shell 进程为使用特殊外设的进程。在子进程加载自身的代码之前,共享父进程的代码,等到加载自己的代码之后,在切断共享父进程代码的关系。否则没有加载自己代码的代码,就无法完成加载代码的工作。
为避免父子进程写数据冲突,有页写保护机制,防止多进程访问共享数据导致的数据混乱。