最近开始接触操作系统,在用了Linux操作系统这么久,一直不明白他是怎么做到在电脑上运行的?首先我便开始了解了这一问题,即从电脑开机加电到main函数的执行干了什么?
通过自己这几日没事看看书终于了这个过程分了三步,其目的是实现从启动盘加载操作系统程序,完成执行main函数所需要的准备工作。
【第2步】:从启动盘加载操作系统程序到内存,加载操作系统程序的工作就是利用第1步中准备的中断服务程序实现的;
【第3步】:为执行32位的main函数做过渡工作。
下面我们说说BIOS的启动原理
从我们使用计算机的经验得知:要想执行一个程序,不许再窗口中双击它,或者在命令行界面中输入相应的执行命令。从计算机底层机制上讲,这其实是在一个已经运行起来的操作系统的可视化界面或命令行界面中执行一个程序。但是,在开机加电的一瞬间,内存中什么程序也没有,没有任何程序在运行,不可能有操作系统,更不可能有操作系统的用户界面。我们无法人为地执行BIOS程序,那BIOS程序又是有谁来执行的呢?从体系的角度来看,不难得出这样的结论:既然软件方法不可能执行BIOS,那么就只能靠硬件方法完成了。
从硬件的角度看,Intel80x86系列的CPU可以分别在16位实模式和32位保护模式下运行。为了兼容,也为了解决最开始的启动问题,Intel将所有80x86系列的CPU(包括最新型号的CPU)的硬件都设计为加电即进入16位的实模式状态运行。同时,还有一点非常关键,即将CPU硬件逻辑设计为加电瞬间强行将CS(代码段寄存器,指向CPU当前执行代码在内存中所在区域)的值置为0xFFFF,IP(指令指针寄存器,存在于CPU中,记录将要执行的指令在代码段内的偏移地址。与CS结合便可以指向将要执行的指令内存地址。实模式为绝对地址,指令指针为16位,即IP,保护模式下为32位,即EIP)的值置为0x0000,这样CS:IP就指向0xFFFF0这个地址范围。
BIOS程序在内存最开始的位置(即:0x00000)用1KB的内存空间(0x00000--0x3FF)构建中断向量表,并在紧挨着它的位置用256字节的内存空间构建BIOS数据区(0x00400--0x004FF),在数据区后的某一位加载了与中断向量表相应的若干中断服务程序中断向量表中有256个中断向量,每个中断向量占4个字节,其中两个字节是CS的值,两个字节是IP的值,每个中断向量都指向一个具体的中断服务程序。
执行BIOS程序后,到此,就要开始执行boot操作了,即我们需要将硬盘中的操作系统文件加载到内存。在计算机完成了一系列自检工作后,出于计算机的结构预先设计,BIOS会让CPU接收到一个int 0x19 中断,当CPU接收到这个中断后,会立即在中断向量表中找到int 0x19中断向量,其对应的就是对应的启动加载服务程序,加载硬盘第一扇区的内容到内存。在此需要说的是第一扇区中的程序是由bootsect.s(引导程序)中的汇编程序汇编而成。之后当我们已经把引导程序载入内存时,他的作用就是将之后的第二、三批程序陆续加载到内存,在此之前这个引导程序bootsect首先需要对内存进行规划。这里就需要操作系统的设计者,要全面的整体的考虑内存的规划,确保无论操作系统如何运行都不会出现代码与代码、数据与数据、代码与数据之间的相互覆盖。在实模式下,寻址空间最大为1MB,bootsect的代码设计首先就需要对后续操作所涉及的内存位置进行设置,包括要加载的setup程序的扇区数要加载的setup程序的扇区数(SETUPLEN)、被加载到的位置(SETUPSEG)、启动扇区被BIOS加载的位置(BOOTSEG)、将要移动到的新位置(INITSEG)、内核被加载的位置(SYSSEG)、内核的末尾位置(SYSEND)、根文件系统设备号(ROOT_DEV)、设置这些位置就是确保将要载入内存的代码和已载入内存的代码以及数据区分,互不覆盖。
内存规划部分还需要复制bootsect以及将setup程序加载到内存。今天就先写到这里,之后的博文会继续对这一问题的阐述。包括之后的加载第三部分代码-----system模块,以及整体过程的最后一步【开始向32位模式转变,为mian函数的调用做准备】。
有什么错误希望指正。