计算机操作系统引导程序的研究

摘要: 现代计算机操作系统已经比较成熟,它们可以兼容运行于多种平台,提供强大的功能。这些并一开始计算机就拥着它们,它们需要操作系统引导程序一步步配置地址,让计算机可用资源由少变多。本文研究了计算机的引导过程,伴随着它的是从二进制到汇编语言再到高级语言的过程, 处理器使用16位到32位的硬件资源的过程。文章介绍了开发实现引导程序的软件环境,可以引用这些工具实现一个引导程序。通过对引导程序的研究,我们会对计算机硬件与软件有更清晰的认识,进而对软件开发与使用有很大帮助。

关键词: 引导程序,操作系统,汇编语言

一、研究背景
 操作系统是计算机的最底层与硬件打交道的软件。现代应用软件规模越来越大,逻辑也非常复杂。要保证应用软件的稳定性,需要一个稳定的操作系统。操作系统的稳定又开始于正确的使用硬件资源。操作系统的引导程序就是用来配置与使用磁盘、内存、显卡等硬件的。

研究操作系统引导程序,可以帮助我们理解操作系统的一些使用问题。比如计算机是如何把硬盘中的一个图片显示到显示器的? 理解内存、中断(int)这些过程,对软件开发工作有较大的帮助。

现代已经有很多成熟的软件、资料来支持引导程序的开发工作。虽然硬件复杂,但也能找到相应的资料。再配合一些软件,就能开发出引导程序,并在虚拟机上模似它的执行过程。

二、 开发操作系统引导程序的环境    
计算机设备多种多样,有台式机、笔记本。如果算上单片机,就更多了,手机、机顶盒、学习机都是。虽然这些硬件设备都是处理数据的,但设备并不是出于同一个公司, 就算计算机里的关键硬件cpu,也是五花八门各种型号都有。要研究一项技术,最好从最简单、最基础的开始。那么Intel 8086cpu就成了最好的选择,本文后面的研究的硬件环境就是以8086为基础的。当然现在不可能再去找一个真实的8086cpu,但是一般民用计算机也用的是Intel、AMD或与其兼容的cpu,而这些cpu都是向下兼容的,就是说8086的软件照样可以用于我们现在的电脑上。

既然找不到真实的8086计算机,那么可以使用虚拟机软件来模拟,效果是一样的。存储设备选择最简单的软盘。真实的软盘现在也是找不到的,但可以制作软盘映像文件来代替。

要生成cpu识别的机器码,需要一个汇编语言环境,我们选择nasm。nasm是一款开源软件,既可完成目前的任务,也方便以后更加深入的学习和研究。微软的masm语法与nasm类似,但masm不开源。由于masm早于nasm,所以masm的中文资料比较丰富,masm的大多资料也适用于nasm。

三 、背景知识
首先,我们知道在计算机的世界里,所有数据的传输、存储都是二进制。比如,应用8086cpu完成运算s=768+12288-1280,二进制如下[2]:
101110000000000000000011
000001010000000000110000
001011010000000000000101


每段二进制的格式都是操作码+操作数,不同操作码对应了固定的电气操作,cpu驱动内部运算部件完成运算,然后把结果放到某个存储设备,可能是寄存器,内存等。虽然二进制方便cpu理解,但不方便人们的记忆。于是人们通过一些英文的缩写来代表二进制。比如用英文“MOV”代表二进制“1000”, 人们编写程序只需要写“MOV”就行了,这就是汇编语言。后来发展到C、Java之类高级语言,它们的源代码最终形成的可执行二进制代码也对应着相应的汇编语言代码。所以不管编程语言用的是什么,形式上不同,但最后都是二进制。

汇编语言对数据的操作,需要一系列寄存器的支持。16位cpu中的寄存器又分为段寄存器,通用寄存器,标志寄存器等。根据寄存器的用途,又可分成代码寄存器(CS,IP),栈寄存器(SS,SP),数据寄存器(DS),计数寄存器(CX)等。内存的访问可以用“[地址]”的方式读取和写入。汇编子程序既可在代码中用段来表示,然后用jmp直接调用。也可以注册到内存,用int方式调用。外围设备通过int调用BIOS的程序。


引导程序也是二进制,我们用汇编语言编写。计算机加电开机后,处理器会执行硬件初始化,将内部所有寄存器的内容初始化到一个预置的状态。以我们常用的台式机与笔记本(兼容Intel 8086)为例,初始化会使代码段寄存器(CS)的内容为0xFFFF,其它所有寄存器内容都为0x0000,然后从CS:IP处读取指令,这个地址正是基本输入输出系统(Base Input & Ouput System,BIOS).在启动界面可以配置BIOS的引导设备,一般都是默认引导设备都是硬盘。为了简单,我的实验是以软盘为研究对象的。

软盘的文件格式是FAT12,BIOS读取软盘就按这个格式的规则来读数据的。

FAT12整体数据分布是这样:


软盘的引导扇区在0扇区,在这里有一组数据是用于告诉BIOS和操作系统如何正确使用软盘的[4]。0扇区的前11个字节(0-10)并没有使用。第11-12字节存放值是每个扇区放多少字节,一般是512字节。第13字节是一个簇有几个扇区,一般是1个。簇是文件占用磁盘空间的单位。第14-15字节是保留给系统使用的扇区数(保留空间),用户程序不可使用。现在介绍的0扇区就是属于保留空间。第16字节是FAT(File Allocation Table)的个数。第17-18字节是根目录最大文件数,固定值224。第19-20字节是软盘总扇区数,固定值2280。第21字节是空的。第22-23字节是每个FAT有多少个扇区,固定值9。第24-25字节是每个柱面有多少个扇区,固定值18。第26-27字节是软件磁头的数量,固定值2。第28-31字节是空的。第32-35字节也是总扇区数2280,不过是给FAT32用的。第36-37字节是空的。第38字节是引导标识,如果是是引导盘,那么值应为0x29。第39-42字节是序列号。第43-53字节是卷标名。第54-61字节是文件系统类型,就是FAT12了。第62字节之后,系统没有占用,就可以放我们的引导程序了。



软盘的第1-9和10-18扇区分别放了一个FAT的文件的簇信息。第19-32扇区放的是根目录信息。第33扇区及其后面都是数据区。软盘的0扇区只有512字节,显然放不下所有的程序。33扇区以后就是给用户用的,可以把其它的程序放到这个位置。这个位置相对于软盘的开始位置就是33*512=16896,转为16进制是0x4200。



在软盘上的引导程序要得到执行,必须先加载到内存中去,cpu才能访问得到。而软盘的0扇区(引导区)加载到内存的目的地址,并非是内存的0地址。我们知道,内存地址从0x0000开始编号,早期的电脑内存只有32KB,就是0x0000~0x7FFF[3]。0x0000~0x03FF用来保存实模式(16位)下各种中断处理程序。所以,内存只剩下0x0400~0x7FFF可以使用。为了把尽量多的连续内存留给操作系统,主引导记录就被放到了内存地址的尾部。由于一个扇区是512字节,主引导记录本身也会产生数据,需要另外留出512字节保存。所以,它的预留位置就变成了:0x7FFF - 512 - 512 + 1 = 0x7C00
除了软盘的第0扇区的512字节被加载到内存的0x7c00处,其它的程序可以放到0x7e00到0x9ffff,这是x86内存分布决定的。




四、引导程序从16位到32位
BIOS将引导扇区加载到内存中后,就可以执行引导程序了。现在引导程序可以通过中断来调用BIOS程序或调用自己的汇编程序,在显示器上显示字符串等操作。对于简单的应用,比如字符的显示、键盘的输入输出,这个已经足够。对于现代的应用来讲,这还不够。在引导区的程序还处于16位的”实模式”。实模式下能做的工作非常有限,地址线只有20根,只能处理1MB内数据。另外,实模式下修改内存是自由的,这有一些安全问题,我们写的程序可能会修改系统使用的内存,进而让系统出现故障。还有,后来的高级语言可以实现丰富的功能,但它是在32位的基础上的。为解决这些问题,寻址空间达到32位(保护模式),那么做一系列的设置。其中包括GDT(Global Descriptor Table)的设置,这个设置告诉cpu那些段地址是可执行的代码段,那些段地址是数据段。什么地方保存着整个GDT的大小等。cpu发展到现代已经64位,但为兼容286电脑对第二十一根地址线(A20)的特殊处理,进入保护模式还需要设置A20。另外,还需设置保护模式允许位(Protection Enable,PE)。

其中GDT的设置最为复杂[1],为了跟踪GDT数据 ,处理器内部有一个48位的寄存器,称为全局描述符表寄存器(GDTR)。该寄存器分为两部分,分别是32位的线性地址(全局描述符表线性内存中的起始地址)和16位的边界(表的大小)。段描述符包含了32位的段基地址信息,20位段界限。除此之外还有以下域:
段界限的粒度(Granularity)用来表示是字节还是4k。
描述符的类型(Descriptor Type,S),0表示是系统段,1表示是代码段或数据段。
特权级(Descriptor Privilege Level,DPL),取值可以有0、1、2、3,其中0是最高特权级。
段存在位(Segment Present),1表示在内存中,0表示不在内存里。
D/B位:“默认操作数大小”或”默认的栈指针大小”位,分别表示操作数的偏移地址或栈段的上部边界。64位代码段标志位(L),标志是否为64位处理器。
TYPE字段有4位,根据其是代码还是数据描述符来决定每一位代表的含义。
AVL位,处理器并不使用,由操作系统使用。


进入32位之后,我们就可以用C语言编写代码,但C语言需经过编译、链接才能转为二进制。一般现在的C语言编辑环境(IDE)都会调用操作系统的函数,但我们的操作系统还没启动起来,启动之前我们调用不了这些函数。所以编辑C语言程序,用最普通的记事本就行。编译、链接的过程可使用gcc命令完成。可用gcc先把C语言转为汇编语言,然后用nasm编译汇编语言,形成的二进制复制到软盘的映像文件,就可以引导系统启动了。

为了看到引导程序的效果,可以在显示器上显示一串字符:”boot successful”。这有两种做法,第一种是调用BIOS程序,设置寄存器AL、AH、BX,调用INT 0x10就可显示一个字符。上面的一串字符可分成一个一个的字符调用来完成。第二种是直接修改内存值,文本模式下显示器对应的内存地址为0xB8000,所以我们只要在从这开始的地址写相应字符的字节值就可以了。

五、结束语

操作系统的引导程序相对于操作系统只是很小一部分,但这是一个从硬件到软件的桥梁,其重要性不言而喻。对于不同位处理器,不但要考虑地址线兼容的,还要考虑内存不同的分配方式。不同磁盘对数据的存储格式也不一样,本文只介绍了软盘的FAT12格式。引导程序是具体的物理层到抽象的逻辑层的过程,同时伴随着编程语言从低级语言到高级语言的过程。虽然过程比较复杂,设计的硬件类型也多,但我们有文中介绍的软件环境。可以把这些都模拟出来,并进行调试,使得其各类数据得以显示,以验证资料数据与实际情况是否一致。通过对引导程序的深入了解,我们对应用软件的正常运行、硬件配置和选择都有更加清晰的认识,这将会给我们的计算机工作和学习带来很大帮助。

参考文献:
[1]李忠 王晓波 余洁.x86汇编语言从实模式到保护模式[M].北京:电子工业出版社,2019:8–12.
[2]王爽.汇编语言[M].北京:清华出版社,2020:1–21.
[3]Memory Map (x86).https://wiki.osdev.org/Memory_Map_(x86)  2020年1月15日

[4]Archana Chidanandan.An overview of FAT12.http://www.disc.ua.es/~gil/FAT12Description.pdf 2004-2005年



文/中中 浏览次数:0次   2020-05-31 11:27:40

相关阅读


评论: