赞
踩
首先还是采用软盘启动,制作一个软盘镜像,然后用虚拟机装载。
❓为什么不用U盘或者硬盘,现在软盘都淘汰了,为什么不用U盘或者硬盘镜像呢?
因为软盘是基础;软盘1.44MB足够了而且格式清楚。
软盘的大小的组织方式: 80cylinders x 2heads x 18sectors x 512 bytes
CHS,是FDISK在分区期间所需磁盘信息。
CHS寻址模式将硬盘划分为磁头(Heads)、柱面(Cylinder)、扇区(Sector)。
△磁头(Heads):每张磁片的正反两面各有一个磁头,一个磁头对应一张磁片的一个面。因此,用第几磁 头就可以表示数据在哪个磁面。
△柱面(Cylinder):所有磁片中半径相同的同心磁道构成“柱面",意思是这一系列的磁道垂直叠在一起,就形成一个柱面的形状。简单地理解,柱面数=磁道数。
△扇区(Sector):将磁道划分为若干个小的区段,就是扇区。虽然很小,但实际是一个扇子的形状,故称为扇区。每个扇区的容量为512字节。
② 知道了磁头数、柱面数、扇区数,就可以很容易地确定数据保存在硬盘的哪个位置。也很容易确定硬盘的容量,其计算公式是:
硬盘容量=磁头数2×柱面数80×扇区数18×512字节=1474560字节
一张软盘1440KB,一共有2880个扇区。
一般只有一个软盘驱动器,因此写0(DL)就可以了,然后磁头数(DH,正面用0反面用1,一般都是两个)×柱面数(CH,一圈一圈的,80个,0~79)×扇区数(CL,就是柱面的一个扇区了,18个,1~18)×512字节
实现软盘启动全知晓
操作系统之所以认识FAT12格式的磁盘,其秘密就在于逻辑0扇区这512B上。如果这512字节的最后两个字节的内容分别是55和AA(0xAA55低字节在前,高字节在后)的话,BIOS在启动时会将这个扇区读取到0x7C00H~0x7DFFH处,然后跳转到0:7C00h处继续执行指令,操作系统即用此来达到引导系统的目的,而这个磁盘就称为引导磁盘。
操作系统标识FAT12文件系统是因为在逻辑0扇区(即引导扇区)处还存储着一个特定的数据结构,此结构有固定的格式,在操作系统将此磁盘格式化时自动生成(也就是说整个512B都是有特殊规格的),具体数据结构如下表所示:
名称 开始字节 长度 内容 参考值 在代码中行号
BS_jmpBOOT 0 3 一个短跳转指令 jmp short LABEL_STARTnop 6
BS_OEMName 3 8 厂商名 'ZGH' 7
BPB_BytesPerSec 11 2 每扇区字节数(Bytes/Sector) 0x200 8
BPB_SecPerClus 13 1 每簇扇区数(Sector/Cluster) 0x1 9
BPB_ResvdSecCnt 14 2 Boot记录占用多少扇区 0x1 10
BPB_NumFATs 16 1 共有多少FAT表 0x2 11
BPB_RootEntCnt 17 2 根目录区文件最大数 0xE0 12
BPB_TotSec16 19 2 扇区总数 0xB40 13
BPB_Media 21 1 介质描述符 0xF0 14
BPB_FATSz16 22 2 每个FAT表所占扇区数 0x9 15
BPB_SecPerTrk 24 2 每磁道扇区数(Sector/track) 0x12 16
BPB_NumHeads 26 2 磁头数(面数) 0x2 17
BPB_HiddSec 28 4 隐藏扇区数 0 18
BPB_TotSec32 32 4 如果BPB_TotSec16=0,则由这里给出扇区数 0 19
BS_DrvNum 36 1 INT 13H的驱动器号 0 20
BS_Reserved1 37 1 保留,未使用 0 20
BS_BootSig 38 1 扩展引导标记(29h) 0x29 20
BS_VolID 39 4 卷序列号 0 21
BS_VolLab 43 11 卷标 'ZGH' 22
BS_FileSysType 54 8 文件系统类型 'FAT12' 23
引导代码 62 448 引导代码及其他数据 引导代码(剩余空间用0填充) 24~42
结束标志0xAA55 510 2 第510字节为0x55,第511字节为0xAA 0xAA55 43
即便是第一行的跳转指令,也是软盘故意设定的。。。
当我们使用了软盘启动系统时,首先会把软盘中第一个扇区(512字节)加载到内存,判断从第510字节开始是否为0xAA55,若是则说明这是一张启动盘,BIOS会开始从0x7C00H进行引导。
0x7C00这个地址来自Intel的第一代个人电脑芯片8088,以后的CPU为了保持兼容,一直使用这个地址。
当时,搭配的操作系统是86-DOS。这个操作系统需要的内存最少是32KB。我们知道,内存地址从0x0000开始编号,32KB的内存就是0x0000~0x7FFF。
8088芯片本身需要占用0x0000~0x03FF,用来保存各种中断处理程序的储存位置。(主引导记录本身就是中断信号INT 19h的处理程序。)所以,内存只剩下0x0400~0x7FFF可以使用。
为了把尽量多的连续内存留给操作系统,主引导记录就被放到了内存地址的尾部。由于一个扇区是512字节,主引导记录本身也会产生数据,需要另外留出512字节保存。所以,它的预留位置就变成了:
0x7FFF - 512 - 512 + 1 = 0x7C00
0x7C00就是这样来的。
根据启动时的内存结构,0x7c00 - 0x7dff 用于载入IPL,而0x7e00 - 0x7fff用于引导区运行时栈,因此空闲的应该是从0x8000开始。
因为引导区的代码实在太少了(512字节还用去不少),所以我们需要在其他地方实现boot,这个脚本叫做ipl,方法就是用ipl读取下一个扇区(512字节,也就是boot),在那里读取所有的扇区。
啊不,是一口气装载完所有的,然后算出绝对地址,用ORG固定(实际上它可能什么也不干,就只在list中有用,毕竟文件都是自己复制到内存中去的),查看bin文件也的确是这样的。
ORG(不行,它会出错)
关于编译的原理
先用edimg制作出helloos.img,这里用到ipl.bin,参数很多,但是感觉自己也能做,也是蛮清晰的
ipl.bin直接用nask生成
我们将剩下的部分拷贝到8200开始的地址,因为boot将启动区放在了7c00,然后磁盘上是没用了,没有临界区的问题,我们把1.44MB的内容复制到0x8000的地址,前512字节被启动区用上了,那么0x8200开始就是真正的程序了(当然启动区需要跳转),
然后在img文件中添加文件,第一个文件的文件名会被放在0x2600的位置,文件的内容会写在4200的位置,然后我们的拷贝到内存中是0x8000位置,所以0x4200处就会在0x8000+0x4200=0xc200位置的地址了。
然鹅我们就是从8200开始存的,因此就跳到8200即可。反正存入内存里谁还管软盘的格式。好好想一想,若从0x800存入数据,存入512个字节,从0开始必然是0x8000-0x81FF,或者0x8001-0x8200。
但是,我为什么,直接拷贝二进制代码呢?毕竟就一个文件,emmmm,实际上,既然前512字节是当作机器码的,后面也应该当作机器码才对。这样是少了16k的,可能是FAT12的问题。
FAT12是DOS时代就开始使用的文件系统(File System),直到现在仍然在软盘上使用,FAT12软盘的被格式化后为:有两个磁头,每个磁头80个柱面(磁道),每个柱面有18个扇区,每个扇区512个字节空间。
2 * 80 *18 * 512=1474560B=1440K=1.44M
FAT12结构图:
1.44M
数据区(长度非固定)
xxxx
根目录区(长度非固定,需要计算)
19*512
18*512
FAT2
10*512
9*512
FAT1
512
引导扇区
0
FAT1和FAT2是两个完全相同的FAT表,每个FAT占用9个扇区。其中FAT1占用1—9扇区,FAT2占用10—18扇区。对于大于512字节的文件,就需要FAT表来寻找该文件占用的所有数据区扇区。那么这里的话就有点问题了呀。但是先不管了
根目录区的开始扇区号是19,它是由若干个目录条目(Directory Entry)组成,条目最多有BPB_RootEntCnt个,由于根目录区的大小是依赖于BPB_RootEntCnt的,所以长度不固定。每个条目占32字节,是一个结构体,里面有该文件的属性。
由于根目录区是从第19扇区开始的,每个扇区512个字节,所以其第一个字节位于偏移19*512=9278=0x2600处。
数据区开始的扇区号=根目录区开始的扇区号+14=19+14=33。
第33扇区的偏移量是512*33=16896=0x00004200。
现在的首要任务是,用自己的语言写出来启动区的汇编代码。
然后是org到底是怎样的存在?
啊可算明白了,罪魁祸首在最后:
RESB 0x7dfe-$ ; 填写0x00直到0x001fe
如果从0x7c00开始是话,刚好没事,要是从0开始的话,就会陡增至32K的文件。所以必须这么做。
先写一下ml文件吧。
写不了,没意义,只能写一半,但是为了美观容易读,还是建议先优化一下
文件虽然可能大于512字节,但是不用担心,FAT12系统倾向于连续分簇,地址是连续的。
但是软盘格式就很难受了,所以说,你做一个简化版软盘也没什么问题。
毕竟都是整个复制,然后执行代码的那种是吧。
这里的ipl10.nas是启动区的汇编代码
asmhead.nas是启动后的设置代码
bootpack.c里面有主函数,naskfunc.nas里面有主函数调用的汇编函数。虽然现在对文件进行文件夹分类还为时尚早,现在先实现汇编化吧。
CYLS EQU 10 柱面什么用的,而且普通变量定义要放在ORG前面,这样就不会执行到。
首先还是ORG 0x7c00这句话,这句话不能丢,这个是汇编自动推断地址用的。启动区512字节被放到0x7c00位置,然后这段代码将剩下的1MB的内容放到0xc200,然后跳转到那里开始执行。
这里asmhead被放到bootpack之前了,然后一起放到0xc200位置,就是收尾相接的那种。
因此,创建一个1.44MB的空文件,里面每个位都是0.
然后,在前512字节填入ipl代码,直接跳转到512字节处!
然后,将其他所有汇编文件统统编译成一个bin文件,从512字节开始填入这个文件即可。
然后用qemu启动即可。
文件夹为mytool,由于工具可能会迭代,因此最好附在版本里最好了。
nasm -f bin test.asm -o test.bin
这样就会把test.asm编译成纯二进制格式的文件test.bin
然后发现nasm跟nask的语法有不同了。。。
nasm已经不能编译这句命令了
RESB 0x7fe-$ ;
会报错:error: attempt to reserve non-constant quantity of BSS space
解决方法呢,就是把$换成一个固定的值,更好的方法呢,
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。