一个操作系统的实现(11)-让操作系统进入保护模式
2016-06-15 13:33
441 查看
这节首先介绍了突破引导扇区只有512字节的原理,然后介绍了FAT12文件系统,最后通过实验加载loader并将控制权交给loader来实现突破512字节的束缚。
前面所用的引导扇区只有512字节。然而实际上操作系统在启动过程需要做的事情是很多的。所以需要通过某种方法突破512字节的限制。
那么如何突破512字节的限制呢?一种方法是再建立一个文件,通过引导扇区把它加载到内存,然后把控制权教给它。这样,512字节的束缚就没有了。
这里被引导扇区加载进内存的并不是操作系统的内核。因为从开机到开始运行,操作系统经历了“引导→加载内核入内存→跳入保护模式→开始执行内核”这样一个过程。也就是说,才内核开始执行之前不但要加载内核,而且还有准备保护模式等一系列工作,如果全都交给引导扇区来做,512字节很可能是不够用的。因此,这里加载进内存的并不是内核,而是另外一个模块叫Loader。引导扇区把Loader加载进内存并把控制权交给它。上面所说的其他工作都交给Loader来做。Loader没有512字节的限制。所以会灵活很多。
接下来最主要的是如何找到Loader文件并加载进入内存。首先介绍FAT12文件系统
FAT的全称是File Allocation Table。它是DOS时代就开始使用的文件系统(File System),现在的软盘上面仍旧使用此文件系统。FAT把磁盘划分成若干层次以方便组织和管理,这些层次如下:
扇区(Sector):磁盘上的最小数据单元。
簇(Cluster):一个或多个扇区。
分区(Partition):通常指整个文件系统。
下面是FAT12格式的软盘的结构:
首先是引导扇区,它位于第0个扇区。它的结构如下图
引导扇区有一个很重要的数据结构叫做BPB(BIOS ParameterBlock),它以
Sector)的一部分。
可以看到有两个FAT表,FAT2可看作是FAT1的备份,他们通常是一样的。FAT有点像是一个位图。每12位称为一个FAT项(FATEntry),代表一个簇。
通常FAT项的值代表的是文件下一个簇号。从这里可以计算出FAT12中数据区的最大簇号是
当FAT表项的值大于或等于
其中第0个和第1个FAT项始终不使用,从第2个FAT项开始表示数据区的每一个簇。也就是说,第二个FAT项表示数据区的第一个簇,所以数据区的第一个簇号是2。
根目录区位于第二个FAT表之后,开始的扇区号是19,它由若干个目录条目(Directory Entry)组成,条目最多有
根目录区的每一个条目占用32字节,格式如下:
根目录区主要定义了
数据区的簇号从2开始。这是因为上面所说的FAT表项从第二个开始。因为根目录区长度不是固定的。所以需要计算数据区的第一个簇号的位置。
首先是进入根目录区根据文件名和属性来寻找文件。找到文件目录项后根据目录向中的开始簇号读取文件第一簇的信息,接下来查看FAT表项,找到文件的下一簇号是啥?如果小于0xFF7,则数据没读取完,如果大于或等于0xFF8则说明文件读取结束
接下来,实现一个最简单的loader并实现加载过程。主要有如下几步:
引导扇区需要有BPB等头信息才能被微软识别,我们首先加上它,代码大致如下:
现在的软盘已经能够被DOS和Linux识别了,我们已经可以方便地往上添加或删除文件了。
要将
将此代码大保存在
这里面编译出的二进制代码加载到内存的任意位置都可以正确执行,但是我们要扩展它,为了将来的执行不会出现问题,要保证把它放入某个段内偏移0x100的位置。
加载软盘上的一个文件进入内存,使用的是BIOS中断
从上图可以看出,中断需要的参数不是从第0扇区开始的扇区号,而是柱面号、磁头号以及在当前柱面上的扇区号三个分量。所以要通过下图方法来转换:
转换的原理如下:
首先,1.44M的软盘结构:一个软盘包括2个盘面(0和1),每个盘面有80条磁道(磁柱),每个磁道有18个扇区,每个扇区大小位512Byte。所以总容量:
然后,从第0扇区开始一次编号叫做相对扇区,它与物理位置的关系如下:
因为loader可能包含多个扇区,所以接下来写一个读软盘扇区的函数:
上面的代码用到了堆栈,所以程序开头要初始化
读扇区的函数写好了,接下来就开始在软盘中寻找
主要包括两个寻找:
在根目录区寻找
在FAT表中寻找
上面的代码的逻辑过程是:遍历根目录区所有的扇区,将每一个扇区加载入内存,然后从中寻找文件名为
还有一些变量和字符串的值定义如下:
读取过程中会打印一些字符,打印字符串的函数如下:
loader的第一个扇区找到了,接下来寻找loader的剩下扇区,在FAT表项中寻找下一个扇区号。
上面寻找loader的工作已经做完了,接下来加载loader:
万事具备,只差最后一步,向loader交出控制权,可以理解为直接跳转到loader所在的代码执行:
接下来看成果
运行结果如下:
突破512字节的限制
前面所用的引导扇区只有512字节。然而实际上操作系统在启动过程需要做的事情是很多的。所以需要通过某种方法突破512字节的限制。那么如何突破512字节的限制呢?一种方法是再建立一个文件,通过引导扇区把它加载到内存,然后把控制权教给它。这样,512字节的束缚就没有了。
这里被引导扇区加载进内存的并不是操作系统的内核。因为从开机到开始运行,操作系统经历了“引导→加载内核入内存→跳入保护模式→开始执行内核”这样一个过程。也就是说,才内核开始执行之前不但要加载内核,而且还有准备保护模式等一系列工作,如果全都交给引导扇区来做,512字节很可能是不够用的。因此,这里加载进内存的并不是内核,而是另外一个模块叫Loader。引导扇区把Loader加载进内存并把控制权交给它。上面所说的其他工作都交给Loader来做。Loader没有512字节的限制。所以会灵活很多。
接下来最主要的是如何找到Loader文件并加载进入内存。首先介绍FAT12文件系统
FAT12
FAT的全称是File Allocation Table。它是DOS时代就开始使用的文件系统(File System),现在的软盘上面仍旧使用此文件系统。FAT把磁盘划分成若干层次以方便组织和管理,这些层次如下:扇区(Sector):磁盘上的最小数据单元。
簇(Cluster):一个或多个扇区。
分区(Partition):通常指整个文件系统。
下面是FAT12格式的软盘的结构:
引导扇区
首先是引导扇区,它位于第0个扇区。它的结构如下图引导扇区有一个很重要的数据结构叫做BPB(BIOS ParameterBlock),它以
BPB_开头。以
BS_开头的域不属于BPB,只是引导扇区(Boot
Sector)的一部分。
FAT
可以看到有两个FAT表,FAT2可看作是FAT1的备份,他们通常是一样的。FAT有点像是一个位图。每12位称为一个FAT项(FATEntry),代表一个簇。通常FAT项的值代表的是文件下一个簇号。从这里可以计算出FAT12中数据区的最大簇号是
2^12=4K,如果每簇512字节,那么最大数据量是
4K×512B=2MB
当FAT表项的值大于或等于
0xFF8时,表示当前簇已经是文件的最后一个簇。如果值为
0xFF7,表示它是一个坏簇。
其中第0个和第1个FAT项始终不使用,从第2个FAT项开始表示数据区的每一个簇。也就是说,第二个FAT项表示数据区的第一个簇,所以数据区的第一个簇号是2。
根目录区
根目录区位于第二个FAT表之后,开始的扇区号是19,它由若干个目录条目(Directory Entry)组成,条目最多有BPB_RootEntCnt个。由于根目录区的大小是依赖于BPB_RootEntCnt的,所以长度不固定。
根目录区的每一个条目占用32字节,格式如下:
根目录区主要定义了
名称、
属性、
时间、
开始簇号、
大小。
数据区
数据区的簇号从2开始。这是因为上面所说的FAT表项从第二个开始。因为根目录区长度不是固定的。所以需要计算数据区的第一个簇号的位置。
如何读取某一文件
首先是进入根目录区根据文件名和属性来寻找文件。找到文件目录项后根据目录向中的开始簇号读取文件第一簇的信息,接下来查看FAT表项,找到文件的下一簇号是啥?如果小于0xFF7,则数据没读取完,如果大于或等于0xFF8则说明文件读取结束接下来,实现一个最简单的loader并实现加载过程。主要有如下几步:
制作一个DOS可以识别的引导盘
引导扇区需要有BPB等头信息才能被微软识别,我们首先加上它,代码大致如下:现在的软盘已经能够被DOS和Linux识别了,我们已经可以方便地往上添加或删除文件了。
编写一个简单的loader程序
要将Loader加载到内存中,首先需要有一个
Loader。所以接下来就是写一个最简单的loader,代码如下:
将此代码大保存在
loader.asm文件中。这段代码被编译成
.COM文件直接在DOS下执行,效果是在屏幕中央输出字符
L,然后进入死循环。在这里,我们用下面的命令行来编译:
这里面编译出的二进制代码加载到内存的任意位置都可以正确执行,但是我们要扩展它,为了将来的执行不会出现问题,要保证把它放入某个段内偏移0x100的位置。
加载loader进入内存
int 13h
加载软盘上的一个文件进入内存,使用的是BIOS中断int 13h。它的用法如下图:
从上图可以看出,中断需要的参数不是从第0扇区开始的扇区号,而是柱面号、磁头号以及在当前柱面上的扇区号三个分量。所以要通过下图方法来转换:
软盘相对扇区号的转换
转换的原理如下:
首先,1.44M的软盘结构:一个软盘包括2个盘面(0和1),每个盘面有80条磁道(磁柱),每个磁道有18个扇区,每个扇区大小位512Byte。所以总容量:
2×80×18×512Byte=1474569Byte=1.44MB
然后,从第0扇区开始一次编号叫做相对扇区,它与物理位置的关系如下:
0面,0道,1扇区 0 0面,0道,2扇区 1 0面,0道,3扇区 2 ... 0面,0道,18扇区 17 1面,0道,1扇区 18 ... 1面,0道,18扇区 35 0面,1道,1扇区 36 ... 0面,1道,18扇区 53 1面,1道,1扇区 54
读软盘扇区
因为loader可能包含多个扇区,所以接下来写一个读软盘扇区的函数:上面的代码用到了堆栈,所以程序开头要初始化
ss和
esp:
读扇区的函数写好了,接下来就开始在软盘中寻找
Loader.bin
寻找loader
主要包括两个寻找:在根目录区寻找
Loader的第一个扇区
在FAT表中寻找
Loader的其余扇区
根目录区寻找loader.bin
上面的代码的逻辑过程是:遍历根目录区所有的扇区,将每一个扇区加载入内存,然后从中寻找文件名为
loader.bin的条目,指导找到为止。找到的那一刻,
es:di是指向条目中字母N后面的哪个字符。其中有一些宏定义如下:
还有一些变量和字符串的值定义如下:
读取过程中会打印一些字符,打印字符串的函数如下:
loader的第一个扇区找到了,接下来寻找loader的剩下扇区,在FAT表项中寻找下一个扇区号。
由扇区号寻找FAT项的值
上面寻找loader的工作已经做完了,接下来加载loader:
向loader交出控制权
万事具备,只差最后一步,向loader交出控制权,可以理解为直接跳转到loader所在的代码执行:接下来看成果
bochs调试与运行
运行结果如下:
源代码
相关文章推荐
- 应用领航:盘点那些年我们一起追过的OS
- 无奇不有!盘点各国自己开发的操作系统
- As3.0 xml + Loader应用代码
- 可自定义oem的萝卜家园 Ghost XP 新春装机版 V200801 下载
- 基于jquery的lazy loader插件实现图片的延迟加载[简单使用]
- AS3.0 实例学习 熟悉addChild和removeChild在不同的swf之间的运用,以及loader的用法
- C#实现判断操作系统是否为Win8以上版本
- js获取本机操作系统类型的两种方法
- Linux操作系统添加新硬盘方法
- java如何获取本地操作系统进程列表
- Linux rdesktop操作系统下远程登录Windows XP桌面
- 32位操作系统认出超出4G内存的方法
- Linux rpm tar 操作系统下软件的安装与卸载方法
- 借用Google的Javascript API Loader来加速你的网站
- JavaScript 获取用户客户端操作系统版本
- jsp 获取客户端的浏览器和操作系统信息
- Windows 操作系统的安全设置
- php判断当前操作系统类型
- PHP获取用户的浏览器与操作系统信息的代码
- Zend Framework教程之Loader以及PluginLoader用法详解