无法加载:jzrcmloader使用教程.doll是怎么回事啊

1821人阅读
操作系统实现(8)
一、 FAT12
FAT12是DOS时代就开始使用的文件系统(File System),直到现在仍然在软盘上使用,FAT12软盘的被格式化后为:有两个磁头,每个磁头80个柱面(磁道),每个柱面有18个扇区,每个扇区512个字节空间。所以标准软盘的总空间为:
2 * 80 *18 * 512=40K=1.44M
下面是FAT12的结构图:
1、引导扇区
操作系统之所以认识FAT12格式的磁盘,其秘密就在于逻辑0扇区这512B上。如果这512字节的最后两个字节的内容分别是55和AA(0xAA55低字节在前,高字节在后)的话,BIOS在启动时会将这个扇区读取到0:7C00h-0:7DFFh处,然后跳转到0:7C00h处继续执行指令,操作系统即用此来达到引导系统的目的,而这个磁盘就称为引导磁盘。
操作系统标识FAT12文件系统是因为在逻辑0扇区(即引导扇区)处还存储着一个特定的数据结构,此结构有固定的格式,在操作系统将此磁盘格式化时自动生成,具体数据结构如下表所示:
参考值
BS_jmpBOOT
一个短跳转指令
jmp short LABEL_START
BS_OEMName
BPB_BytesPerSec
每扇区字节数(Bytes/Sector)
BPB_SecPerClus
每簇扇区数(Sector/Cluster)
BPB_ResvdSecCnt
Boot记录占用多少扇区
BPB_NumFATs
共有多少FAT表
BPB_RootEntCnt
根目录区文件最大数
BPB_TotSec16
介质描述符
BPB_FATSz16
每个FAT表所占扇区数
BPB_SecPerTrk
每磁道扇区数(Sector/track)
BPB_NumHeads
磁头数(面数)
BPB_HiddSec
隐藏扇区数
BPB_TotSec32
如果BPB_TotSec16=0,则由这里给出扇区数
INT 13H的驱动器号
BS_Reserved1
保留,未使用
BS_BootSig
扩展引导标记(29h)
BS_FileSysType
文件系统类型
引导代码及其他内容
引导代码及其他数据
引导代码(剩余空间用0填充)
结束标志0xAA55
第510字节为0x55,第511字节为0xAA
下面我们介绍其中的一些变量的含义:
BS_jmpBoot:是跳转指令,偏移0处的跳转指令必须是合法的可执行的基于x86的CPU指令,如:jmp start,这样可以生成3字节长的指令,(加关键字short的短跳转指令的长度是2字节),指向操作系统引导代码部分。Windows和MS-DOS生成的FAT12启动扇区中的跳转指令是短跳转,如:jmp
short LABEL_START,然后加一个nop的空指令来保持3字节的长度。
BPB_BytsPerSec:每扇区的字节数,类型是双字节长,标准分区上的每扇区字节数一般是512B, FAT12的格式下设置为512(0x200h)。
BPB_SecPerClus:每簇扇区数,偏移13处,类型是字节,簇是数据存储的最小单位,在FAT12格式下一般为1,即每簇只有1个扇区(512字节)。
BPB_RsvdSecCnt:Boot记录占用多少扇区,即在FAT1之前的 引导扇区,一般情况下,引导扇区占用1个扇区。
BPB_NumFATs:共有多少个FAT表,默认情况下此字段的值为2,也就是有两个FAT表,FAT1和FAT2的内容相同,当FAT1表出错的时候可以使用FAT2来恢复文件分配表。
BPB_RootEntCnt:根目录文件数最大值,默认为224,每个目录条目占用32B的空间,因此根目录的大小为:224*32/512=14,即占用14个扇区。
BPB_TotSec16:扇区总数=0xB40=2880
BPB_FATSz16:每个FAT占用的扇区数=0x9=9,即FAT1占用1—9逻辑扇区,FAT2占用10—18逻辑扇区。
BPB_SecPerTrk:每磁道扇区数=0x12=18,即标准FAT12文件系统中,每个磁道的扇区数就是为18。
BPB_NumHeads:磁头数=0x2=2,该磁盘包括2个磁头,也就是面数是2。
&&&&&&&& FAT1和FAT2是两个完全相同的FAT表,每个FAT占用9个扇区。其中FAT1占用1—9扇区,FAT2占用10—18扇区。具体详细介绍看下面4。
3、根目录区
根目录区的开始扇区号是19,它是由若干个目录条目(Directory Entry)组成,条目最多有BPB_RootEntCnt个,由于根目录区的大小是依赖于BPB_RootEntCnt的,所以长度不固定。
&&&&&&&& 在本FAT12中,因为BPB_RootEntCnt=0xE0=14*16+0=244,即条目最多为244个,又因为每个条目占用32个字节,故244*32/512=14,即该根目录区占14个扇区,即19—32。
&&&&&&&& 根目录区中的每个条目占用32字节,它的格式如下图:
这里主要定义了文件的名字,属性,最后写入的时间和日期,文件的开始簇数以及文件大小。
下面我们通过实例来认识这些内容,
1、&首先创建一个虚拟软盘,在这里我们使用WinImage,具体下载地址在我的下载资源中。
打开WinImage:
选择文件—》新建
新建一个虚拟软盘之后,需要向里面添加文件,我们需要提前写好下面几个文件
RIVER.TXT,内容为riverriverriver
FLOWER.TXT,内容为flowerflower………flower,至少要100个flower,使得数据空间大于512个字节,这样该文件将占用两个连续的扇区。
TREE.TXT,内容为treetreetree
再添加一个HOUSE目录,然后在目录\HOUSE下添加两个文本文件:
CAT.TXT,内容为catcatcat
DOG.TXT,内容为dogdogdog
选择映像—》加入,依次加入RIVER.TXT,FLOWER.TXT,TREE.TXT三个文件
映像—》创建文件夹&&HOUSE
添加HOUSE目录
双击house,进入house的文件夹内,然后添加CAT.TXT,DOG.TXT两个文件
添加文件完成,然后保存,其中注意事项,保存类型为:虚拟软盘映像(*.vfd),我不知道这个类型与IMG有什么区别,但是我知道这个类型得到的结果是对的。呵呵!文件名为FLOOPY,这样我们就创建了一个虚拟软盘FLOOPY.vfd
然后使用UltraEdit打开FLOOPY.vfd,由于根目录区是从第19扇区开始的,每个扇区512个字节,所以其第一个字节位于偏移19*512=0处,好的,现在就让我们去定位到0x2600处看看到底Directory Entry为何物?
RIVER.TXT的各项值:
在这里,我们只需要关心RIVER.TXT的DIR_FstClus,即文件的开始簇号,由于本FAT12中的BPB_SecPerClus=1,故一个簇为一个扇区,DIR_FstClus=2,意味着该文件的在数据区的起始扇区号为2。在这里需要注意的是,数据区的第一个簇的簇号是2,而不是0或者1,故该文件的数据开始于数据区的第一个簇,也就是第一个扇区。
那么数据区的第一个扇区在哪里呢?
首先计算根目录区所占有的扇区数:
RootDirSectors =((BPB_RootEntCnt*32)+(BPB_BytsPerSec-1))/BPB_BytsPerSec。
之所以分子要加上(BPB_BytsPerSec-1),是为了保证此公式在根目录区无法填满整数扇区时仍然成立。
在本例中,因为BPB_RootEntCnt=224,计算得到根目录区所占有的扇区为14个。所以
数据区开始的扇区号=根目录区开始的扇区号+14=19+14=33。
现在就让我们跳入到第33扇区的偏移量是512*33=04200,让我们看看这里的内容:
果然是riverriverriver。
在这里,由于RIVER.TXT小于512字节,所以我们不需要FAT表就在数据区中找到了RIVER.TXT的内容,但是对于大于512字节的文件来说,就没有这么简单了,需要使用FAT表来寻找到该文件占用的所有数据区扇区。
下面让我们跳入FAT1的内容,FAT1的开始扇区号是1,故偏移为1*512=512=0x200。
一堆看不懂的符号,好像很多F。其实并不复杂,它有点像是一个位图,其中,每12位成为一个FAT项(FAT Entry),代表一个数据区中的簇。第0个和第1个FAT项始终不使用,第2个FAT项开始表示数据区的每一个簇,也就是说,第2个FAT项表示数据区第一个簇,依次类推。前文说过,数据区的第一个簇的簇号是2,和这里相呼应。
要注意,由于每一个FAT项占12位,包含一个字节和另一个字节的一般,所以觉得特别别扭。具体情况是这样的,假设连续3个字节分别是如图所示:
通常,FAT项的值代表的是文件的下一个簇号,但如果值大于或等于0xFF8,则表示当前簇已经是文件的最后一个簇了。如果值为0xFF7,表示它是一个坏簇。
文件RIVER.TXT的开始簇号为2,对应的FAT表中的值为0xFFF,表示这个簇已经是最后一个。
文件FLOWER.TXT的开始簇号为3,对应的FAT表中的值为0x004,表示文件还没有结束,下一个簇号是0x004,然后我们再看FAT表中第4个簇相对应的FAT值为0xFFF,则表示该是最后一个簇,则文件FLOWER.TXT占用第3、4簇。
如果想使文件内容分存在不连续的扇区内,有一个方法可以做到,就是先将该文件加入到软盘驱动中,然后在进行添加相同的文件,进行覆盖。当然该文件的大小必须大于512个字节。
1、突破512字节的限制
2、加载Loader进入内存
一、突破512字节的限制
一个操作系统从开机到开始运行,大致经历&引导—》加载内核入内存—》跳入保护模式—》开始执行内核&这样一个过程。也就是说,在内核开始执行之前不但要加载内核,还要准备保护模式等一系列工作,如果全部交给引导扇区来做,512字节很可能不够用,所以,不放把这个过程交给另外的模块来完成,我们把这个模块叫做Loader。引导扇区负责把Loader加载如内存并且把控制权交它,其他的工作放心地交给 Loader来做,因为它没有512字节的限制,将会灵活很多。
二、加载Loader进入内存
上一节我们已经详细介绍了FAT12文件系统的数据结构,下面我们需要思考的是两个问题:1、引导扇区通过怎样的步骤才能找到文件;2、如何能够把文件内容全都读出来并加载进入内存。
下面我们先解决第一个问题:
1、& 如何读取软盘?
(1)&&&&我们需要使用BIOS中断int 13h来读取软盘。它的用法如下表所示:
在这里我们只介绍了2种工作方式,中断int 13h还有其他的工作方式,如果需要可以自行查看内容。
(2)&&&&由上表我们可以知道:当读取某些扇区时,需要柱面(磁道)号(ch),起始扇区号(cl),磁头号(dh)。我们如何通过计算得到这些数据呢?
(3)&&&&现在万事俱备只欠东风了,下面我们就书写读取软盘扇区的函数ReadSector。
首先我们要知道该函数需要什么参数,这些参数存储在什么位置?
参数1:扇区号,存储在ax中
参数2:要读取扇区的个数,存储在cl中
参数3:数据缓冲区,即读取扇区数据后,将其存储在什么位置,用es:bx指向该缓冲区。
即函数的作用:从第ax个Sector开始,将cl个Sector读入es:bx中。
2、& 如何在软盘中寻找Loader.bin文件
(1)&&&&结合上一节所介绍的FAT12数据结构,从中我们可以知道,要寻找一个文件,首先需要在根目录区中寻找该文件的根目录条目;然后根据根目录条目获取文件开始簇数(也就是在数据区中存储的扇区);最后读取文件内容到内存。
(2)&&&&嗯,是的,下面就让我们来完成第一步-----在根目录区中寻找该文件的根目录条目。
让我们开始思考这个问题,
首先要知道根目录区的开始扇区号是19,也就是说从第19扇区开始,根目录区占用扇区总数为14,也就是说,如果不能发现Loader.bin,需要将14个扇区都进行查找,于是需要一个大的循环在外围,控制着扇区的读取。
紧接着,我们每读取一个扇区,一个扇区是512个字节,一个根目录条目占32个字节,故一个扇区中存在512/32=16个根目录条目,所以需要添加一个循环,控制根目录条目的变化,从0—16进行循环。
最后,针对每一个根目录条目,我们只是要比较文件名,一个根目录条目的文件名占用11个字节,所以需要对每一个字节与&LOADER&& BIN&中的每一个字节进行比较,所以还是要添加一个循环,来控制字符的变化,即从0—11.
用C语言来表示该问题就是:
for( i = 根目录区的起始扇区号(19); i & 根目录区占有的扇区数(14);& i++)&&&&& {
&&&&&&&&&& for( j = 0;j & 一个扇区内存储的根目录条目个数(512/32=16); j++)&&& {
&&&&&&&&&&&&&&&&&&& for(k =0; k & 根目录条目中文件名占用的空间(11个字符); k++) &&&& {
&&&&&&&&&&&&&&&&&&&&&&&&&&&& if(k=10)jmp LABEL_FILENAMEFOUND
&&&&&&&&&&&&&&&&&&&&&&&&&&&& if(ds:si= es:di) si++; di++;
&&&&&&&&&&&&&&&&&&&&&&&&&&&& else&
&&&&&&&&&&&&&&&&&&& }
&&&&&&&&&& }
(3)&&&&下面让我们来分析代码:
首先需要介绍下面可能需要用到的几个变量值:
BaseOfLoader&&&&&&&&&& equ& 09000h&&&& ;LOADER.BIN被加载到的位置---段地址
OffsetOfLoader&&&&&&& equ& 0100h&&&&&& ;LOADER.BIN被加载到的位置---偏移地址
RootDirSectors&&&&&&&& equ& 14&&&& ;根目录占用空间(BPB_RootEntCnt*32+511)/512
SectorNoOfRootDirectory&&&&&&& equ& 19&&&& ;Root Directory 的第一个扇区号
wRootDirSizeForLoop&&&&& dw&&& RootDirSectors&&&&&&&& ;Root Directory占用的扇区数,在循环中会递减至0
wSectorNo&&&&&&&&&&&&&&&& dw&&& 0&&&&&&&&&&&&&&& ;要读取的扇区号
bOdd&&&&&&&&&&&&&&&&&&&&&&&&&& db&&&& 0&&&&&&&&&&&&&&& ;奇数还是偶数
LoaderFileName&&&&&& db&&&& &LOADER& BIN&,&&&& 0&&&&&& ;LOADER.BIN之文件名
(4)&&&&对上面这段代码画出它的简易流程图如下:
3、& 如何将Loader.bin文件加载到内存?
现在我们已经有了Loader.bin的起始扇区号,我们需要用这个扇区号来做两件事情:一件是把起始扇区装入内存,另一件则是通过它找到FAT中的项,从而找到Loader占用的其余所有扇区。
此时装入一个扇区对我们来说已经是很轻松的事了,可从FAT中找到一个项还是多少有些麻烦,下面我们就根据扇区号去FAT表中找到相应的项。在这里,将要写一个函数GetFATEntry,函数的输入就是扇区号(ax),输出则是其对应的FAT项的值(ax)。
我们一起来思考这个函数如何去实现,我们知道了扇区号x,然后我们去FAT1中寻找x所对应的FATEntry,我们已经知道一个FAT项占1.5个字节。所以我们用x*3/2=y………z,y为商(偏移量)(字节),相对于FAT1的初始位置的偏移量;Z为余数(0或者1),是判断FATEntry是奇数还是偶数,0表示偶数,1表示奇数。然后我们让y/512=m………n,m为商,n为余数,此时m为FATEntry所在的相对扇区,n为在此扇区内的偏移量(字节)。因为FAT1表前面还有1个引导扇区,所以FATEntry所在的实际扇区号为m+1。然后读取m+1和m+2两个扇区,然后在偏移n个字节处,取出FATEntry,相当于读取两个字节。此时再利用z,如果z为0的话,此FAT项为前一个字节和后一个字节的后4位,如果z为1的话,此FATEntry取前一个字节的前4位和后一个字节。
下面我们实现GetFATEntry函数,函数的输入就是扇区号,输出则是其对应的FATEntry的值。
下面我们开始加载Loader.bin进入内存。
首先我们从根目录区中的Loader.bin的条目,获取文件的起始扇区号,然后加上BPB_RsrvSecCnt+BPB_FATSz16*2-2+RootDirSectors=1+(9*2)+14-2=31,,其中DeltaSectorNo=BPB_RsrvSecCnt+BPB_FATSz16*2-2=17。得到的结果才是文件的实际的起始扇区。获得起始扇区后,我们就可以调用ReadSector来读取扇区了。然后从FAT1表中获取FATEntry的值,判断是否为0FFFh,如果是,结束加载;如果不为0FFFh,意味着该文件没有读取完成,需要读取下一个扇区,此时的FATEntry的值,就是下一个扇区号,再将其转换为实际扇区号,再进行读取。
下面是函数的实现和注释
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:158369次
积分:2296
积分:2296
排名:第11839名
原创:63篇
转载:41篇
评论:15条
(2)(3)(5)(3)(1)(2)(8)(1)(2)(1)(2)(7)(3)(1)(1)(8)(1)(1)(6)(5)(10)(2)(4)(1)(2)(23)(1)刺客信条大革命uplay r1 loader64.dll,找不到入口点,求解_百度知道问题补充&&
本页链接:
猜你感兴趣

我要回帖

更多关于 rcmloader使用教程 的文章

 

随机推荐