在前一篇文档,我只是简要地介绍了如何编写引导装载程序。做这件事令人开心,同时也具有挑战性。我非常乐意做这件事。在我了解了如何编写引导装载程序后,我想编写更好的功能,比如向引导装载程序中嵌入更多功能。然而,这么做的话引导装载程序的大小就会逐渐地增长,会超出512个字节。这样,每次从引导盘重新启动系统的时候,我都可以看到这样的错误提示:“这张盘不是系统引导盘”。
我将在这篇文档简要介绍引导装载程序所在的文件系统的重要性,然后再编写一个虚拟内核,这个虚拟内核除了以文本的形式提示用户输入之外再没有其他功能。为什么我要把引导程序存储在FAT格式的软盘呢?这么做能给我带来哪些好处呢?由于这篇文章太短无法详细的说明文件系统,所以我将尽可能简短地说明文件系统内容。
如果你之前有任何编程语言的经验,那么这篇文章将会给你提供一些帮助。虽然这篇文章是一个简单的介绍,但是使用C或者汇编写引导程序仍旧是一个艰巨的任务。如果你是一个写程序的新手,那么我建议你读一下如何写程序以及介绍电脑的基本知识的教程,然后你再来阅读这篇文章。
通过这篇文章,我将向你介绍各种与电脑有关的问题和回答的相关术语。坦白说,我写下这篇文章就好像我正在介绍这篇文章给我自己。所以许多的问题和回答尽力做到像谈话的方式,以便在我每天生活之中就能够明白它的重要与目的。例如:计算机是什么意思?或者为什么我需要它们因为我比它们更聪明?
你可以翻阅我之前的文章以便学习如何使用汇编和C写一个boot-loader。
http://www.codeproject.com/Articles/664165/Writing-a-boot-loader-in-Assembly-and-C-Part
http://www.codeproject.com/Articles/668422/Writing-a-boot-loader-in-Assembly-and-C-Part
这是这篇文章的主题。
Boot-loader 限制
从boot-loader调用磁盘上的文件
FAT 文件系统
FAT 工作流程
写一个 FAT boot-loader
写一个16-bit的虚拟内核
在以前的文章中,我试图编写 boot-loader,在打印出一些带颜色的矩形后,我想在其中嵌入更多的功能。但是,对我而言,512 字节是个极大的限制,无法更改 boot-loader 的代码来做更多的事情。。。
挑战如下:
按照功能嵌入更多的代码到 boot-loader 中
限制 boot-loader 的大小为仅有的 512 字节
简述如下。
我会用 C 语言写一个叫做 kernel.c 的程序,确保我期望的其它全部功能都正确的在其中实现。
编译,并将执行程序保存为 kernel.bin。
现在,拷贝 kernel.bin 文件到启动盘的第二扇区中。
第 2 部分:
在我们的 boot-loader 中,所有我们能做的是 加载 启动盘的第二扇区(kernel.bin)到内存的 0x1000 地址处,然后从 0x7c00 跳转到 0x1000 地址处,开始执行 kernel.bin 文件。
下图供您参考,可以了解一下。
之前,我们逐渐意识到,我们可以从 bootloader(0x7c00地址)将控制跳转到其它地方,如磁盘文件 kernel.bin 加载到内存中的地址,然后继续执行。但我心中还有几个疑问。
这很容易。我们要做的是以下这些
1扇区=512bytes
因此,如果kernel.bin的大小是512 bytes,它将占用1个扇区,如果是1024 bytes,那么它将占用两个扇区,等等...
现在,指针是建立在kernel.bin文件大小的基础上,在boot-loader中,你必须硬编码一定数量的扇区以便读取kernel.bin文件(译者注:所谓的硬编码指指将可变变量用一个固定值来代替的方法,但是采用这种方式之后,如果以后需要更改此变量就非常困难了,比如 if(a==2)就是硬编码,而 if(a==b)就不是硬编码)
考虑到将来,你想要通过频繁的更新内核来升级内核,你必须在引导中写个小笔记纪录kenrl.bin文件的占用扇区,否则内核会崩溃。
在某种程度上是这样的,你要做的就是添加一个一个的文件到你软盘中,在这个过程中,你必须保证在引导盘中,每个文件都在其正确的位置,而且每个文件都会占据一定的扇区或者很多扇区。
但有点我想要你注意,系统将会变得越来越复杂,但我非常喜欢这样做。
我们做的是从boot-loader加载各自的扇区程序到内存中然后开始执行它。但是这非常的不完美,一些东西将会丢失。
我认为boot-loader盲目地加载扇区的一个一个程序文件,然后执行文件。但即使在boot-loader尝试加载文件到内存之前,应该要检查文件是否存在在引导盘中。
我的系统仅仅会崩溃,我的用户会抛弃我的系统,因为这不是他们想要的结果。所以,在这种情况下我们需要在引导盘中有固定的位置,所有的文件写成书中的索引。
我的boot-loader会执行软盘中索引以便寻找文件,如果文件名在索引中被列出来的话,然后继续加载文件到内存中。
哇!!! 这非常的棒,它为我节省了大量的步骤。
这回避免一些问题,因为早期的boot-loader常常盲目地加载扇区程序,然后硬编码它。
为什么你要加载这个文件,如果你不知道文件是否被正确加载?
我们所需要做的是在磁盘上组织上面所列的信息,之后开始组织这些数据,并重新编写 boot-loader,以便它可以真正有效的加载文件。
这种大规模组织数据的方式被认为是文件系统。存在许多类型的文件系统,不管是商业的还是免费的。我在下面列出其中的一些。
FAT
FAT16
FAT32
NTFS
EXT
EXT2
EXT3
EXT4
在 FAT 文件系统中,一个簇占据了一个扇区,一个扇区在存储介质上占用了 512 字节。所以,在用 FAT 格式化过的磁盘上,1个簇等于1个扇区。
在 FAT 文件系统上,簇和扇区是最小的单位。
为了方便使用,FAT 文件系统被划分为四大部分,如下所示。
引导扇区
文件分配表
根目录
数据区
我尽可能以图片的形式展示给你,以便更好的理解它。
现在让我们简单描述一下每个部分。
其它翻译版本 (1) 加载中在 FAT 格式的磁盘上,引导扇区中写有与 FAT 相关的信息;因此每次磁盘加载到系统时,操作系统都能自动获取到它的文件系统信息。
操作系统读取 FAT 格式磁盘的引导扇区,解析出所需信息,然后识别出文件系统的类型,据此读取文件内容。
写在引导扇区中的 FAT 文件系统信息称为启动参数块(Boot Parameter Block)。
让我来带您看看,引导扇区的启动参数块里都有哪些值吧:
文件分配表实际是一个单链表,结点中存有文件的下一个簇值(cluster value)。
FAT 中的簇值有两种用途。
标记文件的结束
如果簇值在 0x0ff8 到 0x0fff 之间,则说明文件不再有别的数据块了(达到文件末尾EOF )。
标记文件数据所在的下一个扇区
我在图中提到了两张 FAT 表,表1和表2。你需要记住的就是,一张表是另一张表的拷贝。一旦一张表的数据丢失或损坏,另一张表的数据可以作为备份。这就是使用两张表而不是一张表的唯一原因。
根目录可以看作磁盘上所有文件名的索引。所以 bootloader 会从根目录中查找文件名,如果能找到,就能从根目录中得到文件的第一个簇,并据此加载数据。
bootloader 从根目录中找到文件的第一个簇之后,会从 FAT 表中查找文件的下一个簇,直至达到文件末尾EOF。
这是实际存放文件数据的区域。
一旦程序能识别相应的扇区,就可以从数据区中提取出文件的数据。
举个例子,假设 boot-loader 需要把 kernel.bin 文件加载到内存中,然后运行。要完成这个任务,我们只需为 boot-loader 编写以下的功能。
将根目录表中,从偏移量为0的位置开始的前11字节数据与 "kernel.bin" 这个字符串相比较。
如果能匹配这个字符串,则从根目录表中偏移量为26的位置提取 "kernel.bin" 文件的第一个簇。
现在我们已经得到 "kernel.bin" 文件的起始簇了。
只需将簇值转化为对应的扇区,然后把数据加载入内存。
在找到 "kernel.bin" 文件的第一个扇区并载入内存后,再从文件分配表(FAT表)中查找文件的下一个簇,检查是否还有剩余数据,或是已经到达文件末尾。
整个流程可以参考下图。
2KB项目(www.2kb.com,源码交易平台),提供担保交易、源码交易、虚拟商品、在家创业、在线创业、任务交易、网站设计、软件设计、网络兼职、站长交易、域名交易、链接买卖、网站交易、广告买卖、站长培训、建站美工等服务