没有阅读过源码之前,对操作系统总是抱有神秘感,总是认为操作系统是很奥妙的东西. 其实,对于一个有一定编程基础和系统知识的程序员,操作系统并不是可望而不可及的东西. 操作系统的最终目标只是在应用程序层面与硬件层面之间做的一层协调,可能这个定义有些片面,但本着这样的思想读代码应该会轻松一点.
由于发展到现在,LINUX已经可以支持各种平台,本文讲主要针对一个"古老"的版本--0.11--进行讨论,这也是赵炯博士在"linux内核完全注释"一书中做使用的版本,由于本人也是初学者,不敢妄自对2.6内核作出定论. 我将在以下分析的过程中偶尔加入一些自己对2.6的理解.
linux的启动过程主要涉及到三个源文件: bootsect.s head.s setup.s
在0.11版本中,这三个文件均位于linux/boot/目录下,而在最新版本中,因为支持的平台的多样性,我们可以在linux/arch/i386/下找到它们.
i386体系结构的启动过程大致是这样的:机器首先进入实模式,然后从地址0xFFFF0处开始执行,一般这个地址是在BIOS中,于是BIOS程序会对机器做一些自检工作. 在此之后,一般从磁盘启动的机器会从可启动设备的第一扇区中把启动程序读入内存0x07C00位置,并且跳转到该处继续执行.这里所说到的从磁盘读入的第一扇区内容,其实就是bootsect.s经过汇编以后的二进制码,也就是说,在操作系统意义上系统是从bootsect.s开始的. 在观看bootsect.s源码之前,让我们先看看操作系统得到运行机会以后是如何安排一切的:
Linus对bootsect.s被载入的位置不太满意,事实上这的确不是个良好的位置.0x07C00是一个相当低的位置,Linus期望操作系统的真正内核部分可以从0x00000起始,并且占据整个内存区域的最低位置. boot的程序内容只会在机器启动的时候被运行一次,以后基本就没有用了. 而现在,bootsect.s位于0x07C00的位置上,显然已经"挡住"了操作系统的"路". 要知道,即使是0.11版本的linux,内核的长度(这里应该更准确的称之为system模块,而不是广义上的linux内核. 这个概念在下且跳转到那里执行.文中讲述.)也达到了0x3000, 而在2.6中,更是达到了0x7F00之多. 于是,很自然的,我们首先要做的工作就是把bootsect.s的位置挪开,挪到更高的地址上去,并跳转到那里执行.
做完迁移之后,bootsect.s需要做的第二件事情就是要把后续代码load进来. 这部分代码就是setup.s,它的二进制编码应该存放在启动设备的第二个扇区,长度为4个扇区. load这段程序并没有想象中的那么困难,程序通过int 0x13来完成的. setup.s将被放在紧接在bootsect.s的