编写MBR从硬盘启动linux0.11

 

计算机启动时BIOS会把启动盘第一个扇区的数据读入内存0x7C00开始处,然后跳到这里继续执行。从硬盘启动和从软盘启动唯一的区别就是映象文件存储方式的不同:

1. 对于从软盘启动的方式,映象文件连续地存放在软盘开始的位置处。放在第一个扇区的bootsect.s被BIOS读入内存后,就会把余下的映象文件读入内存,然后继续执行

2. 对于从硬盘启动的方式,映象文件存放在Minix格式的硬盘分区里,MBR(硬盘第一个扇区)中的程序需要根据硬盘的参数和Minix文件系统的存储格式读出它

本文描述了如何编写MBR中的程序,把存放在硬盘第一个分区根目录下的linux0.11映像文件Image读入内存。

文章中小字体的括号里的数字表示参考文献的编号(见后面的参考文献列表)。

本文分5个部分: 1、硬盘简介

2、Minix 1.0文件系统简介

3、程序流程

4、上机实验

5、程序代码(以附件形式给出)

一.硬盘简介(1)

图1. 硬盘扇区编号(此图来源文献1)

我们需要了解的是物理扇区编号方式和绝对扇区编号方式。物理扇区号直接按柱面、磁头、扇区3者的组合来定位某个扇区。对于硬盘的第一个扇区,其编号为“0柱面0磁头1扇区”。我们假设硬盘磁头数为16,每磁道扇区数为63,下面描述遍历整个硬盘时柱面号、磁头号、扇区号的变化规律(以(x,y,z)表示x柱面y磁头z扇区): (0,0,1)、(0,0,2)、……、(0,0,63)、

(0,1,1)、(0,1,2)、……、(0,1,63)、

(0,2,1)、(0,2,2)、……、(0,2,63)、

……

(0,15,1)、(0,15,2)、……、(0,15,63)、

(1,0,1)、(1,0,2)、……、(1,0,63)、

(1,1,1)、(1,1,2)、……、(1,1,63)、

换句话说就是扇区号是从1到63的63进制,磁头号是0到15的16进制,“百位”是柱面号,“十位”是磁头号,“个位”是扇区号。

绝对扇区号从0开始,遍历硬盘时依次增1。

两者的换算关系如下(abs_sector表示绝对扇区号,cyl表示柱面号,head表示磁头号,sector表示扇区号,nheads表示磁头数,nspt表示每磁道扇区数):

sector = abs_sector % nspt + 1

track = abs_sector / nspt

head = track % nheads

cyl = track / nheads

如何知道上面说的磁头数nheads、每磁道扇区数nspt呢?启动时BIOS会把硬盘参数表放在内存某个位置。对于第一个硬盘,硬盘参数表的首地址放在中断0x41处,即内存地址4*0x41=0x104开始的4个字节表示硬盘参数表的段地址(后面2字节)和偏移地址(前面2字节)。硬盘参数表的结构如下:

dw cylinders

db nheads

dw 0

dw write pre-comp

db 0

db 0 "control byte"

db 0, 0, 0

dw landing zone

db nspt(sectors/track)

db 0

第二个硬盘的参数表地址放在BIOS中断向量0x46处。

对于硬盘,我们还需要稍微知道一点分区表的信息。分区表放在硬盘第一个扇区的0x1be~0x1fd处(共64字节,第一个分区的信息在0x1be~0x1ce)。我们需要使用的仅仅是存放在0x1c6处的“分区起始绝对扇区号”(对应于程序中的start_sect变量)

二.Minix 1.0文件系统简介(2) (3)

关于Minix 1.0文件系统的更详细知识请参考文献2、3,下面仅介绍理解本程序需要了解的知识。

Minix 1.0格式的分区结构如下:

引导块

超级块

i点位图块…

逻辑块位图块…

i节点块…

数据区………

1、对于Minix 1.0,每个盘块占1k字节(即2个扇区)。引导块的第一个扇区就是本分区的第一个扇区,扇区号存在MBR中0x1c6处(就是上文的“分区起始绝对扇区号”)。盘块从0开始编号,对于盘块n,其绝对扇区号 = 2*n +分区起始绝对扇区号。

2、i点位图块和逻辑块位图块的大小、数据区的起始盘块号等信息存放在超级块中,超级块的数据结构如下:

struct d_super_block{

unsigned short s_ninodes; //节点数

unsigned short s_nzones; //逻辑块数

unsigned short s_imap_blocks; //i节点位图所占用的数据块数

unsigned short s_zmap_blocks; //逻辑块位图所占用的数据块数

unsigned short s_firstdatazone; //第一个数据逻辑块

unsigned short s_log_zone_size; //log2(数据块数/逻辑块)

unsigned long s_max_size; //文件最大长度

unsigned short s_magic;}; //文件系统魔数

我们只需要知道开始存放i节点的盘块号inode_start_zone和第一个数据逻辑块号firstdatazone:

inode_start_zone = 2 + s_imap_blocks + s_zmap_blocks

firstdatazone = s_firstdatazone

3、每个i节点占32字节,其数据结构如下:

struct d_inode{

unsigned short i_mode; //文件类型和属性

unsigned short i_uid; //用户id

unsigned long i_size; //文件大小(字节数)

unsigned long i_time; //修改时间(1970.1.1:0算起,秒)

unsigned char i_gid; //组id

unsigned char i_nlinks; //链接数

unsigned short i_zone[9];}; //直接(0~6)、间接(7)、双重间接

//(8)逻辑块号

根据其中的i_size可以计算出文件占用的盘块数 = (i_size + 1023) / 1024

文件数据的前面7k存放在称为直接块的7个盘块中,这7个盘块的盘块号存在i_zone[0]~i_zone[6]中。如果文件大于7k,则需要使用到一次间接块(i_zone[7]),它对应的盘块里存放的不是文件数据,而是7k之后的文件数据存放的盘块号。比如一次间接块的第1、2字节指出第8k文件数据存放的盘块号码。一次间接块可以存放512个盘块号。如果文件大于(512+7)k,则需要使用二次间接块i_zone[8]。图示如下:

图2. 文件数据存储结构(此图来源文献3)

根据i_zone[0]~i_zone[6],可以直接读出前面7k数据;然后读出一次间接块i_zone[7],根据其中的盘块号即可读出其余的数据;忽略i_zone[8],因为linux0.11映像文件没那么大。

图3是映像文件Image一次间接块的前面部分数据。每两个字节表示一个盘块号。“00 00”表示这1k的数据都是0(比如红圈里的),蓝圈里的“70 05”表示这1k数据存放的盘块号是0x0570。

图3. 映像文件Image一次间接块的前面部分数据

4、第一个数据块存放的就是根目录文件的前1k数据,根目录文件存放的是称为目录项的信息。其数据结构如下:

struct dir_entry{

unsigned short inode; //i节点

char name[14];}; //文件名

图4就是根目录文件第一个盘块的部分信息,图中红圈里面的数据表示本本目录项的i节点,蓝圈里面的数据表示该目录形的名称是Image。从图上我们可以看到,前面两个目录项分别是目录“.”和目录“..”,紧随其后的是bin、dev、etc、mnt、root、tmp、usr等目录,再后面的是hello.c、Image、image文件(至于是目录还是文件,需要找出相应的i节点根据其i_mode项来判断)。

图4. 根目录文件第一个数据块部分信息

三.程序流程

现在可以描述查找映像文件并读出它的过程了:

a. 获取硬盘参数——磁头数、每磁道扇区数(以便计算绝对扇区号对应的柱面号、磁头号、扇区号),获取分区参数——第一个分区起始绝对扇区号(以定位Minix文件系统的逻辑块)

b. 读出超级块,计算出i节点开始存放的盘块号inode_start_zone和第一个数据逻辑块号firstdatazone

c. 读出根目录文件(本程序只读出了它前面的1k数据——即第一个数据逻辑块)

d. 根据映像文件名Image找到对应的目录项,取得其i节点编号(0x004A,图4红圈部分)

e. 根据映像文件i节点编号和inode_start_zone读出i节点

f. 根据i节点的i_size信息确定要读取的盘块数,根据i_zone[0]~i_zone[6]读出前面7k数据

g. 根据i_zone[7]读出一次间接块的数据

h. 根据一次间接块确定的盘块号,读出

linux0.11映像文件由4部分组成:1、bootsect.s,2、setup.s,3、head.s,4、系统模块。从软盘启动时,bootsect.s生成的可执行代码(512字节)被读入0x7C00处,它执行时先把自己移到0x90000处,然后把setup.s生成的可执行代码(大小为2k)从软盘读入到内存0x90200处,并把映像文件余下部分读到内存0x10000处。本MBR程序把映像文件前面2.5k数据(对应512字节的bootsect.s可执行代码和2k的setup.s可执行代码)读到0x90000处,把映像文件余下部分读到内存0x10000处,然后跳到0x90200执行setup.s代码。可见,本程序的功能只是与bootsect.s相似,bootsect.s从软盘读出映像文件,而本程序从硬盘中读出。

程序代码见第5部分的bootload.s,图5是流程图。

图5. MBR程序流程图

四.上机实验

实验工具:

1、Bochs PC仿真软件上运行的SLS-Linux

下载地址:

http://oldlinux.org/Linux.old/bochs/sls-1.0.zip

2、linux-0.11-devel-040809.zip压缩包(里面有Bochs安装程序)

下载地址:

http://oldlinux.org/Linux.old/bochs/linux-0.11-devel-040809.zip

3、DOS格式映像文件工具WinImage

下载地址:

http://ourworld.compuserve.com/homepages/gvollant/winima70.exe

实验步骤:

hdc-0.11.img硬盘映像文件上有linux0.11根文件系统,但现在它不能引导linux0.11:把bochsrc-hd.bxrc文件中的“boot:a”改为“boot:c”,运行bochsrc-hd.bxrc将导致引导失败。下面修改其MBR使得可以引导:

1、把sls-1.0.zip和linux-0.11-devel-040809.zip解压到同一个目录下,安装Bochs2.1.1。

2、用文本编辑器打开bochsrc.bxrc,把69行“floppyb:1_44=tmp1.imz, status=inserted”中的tmp1.imz改为tmp.imz(原文有误)

3、在bochsrc.bxrc中添加一行,挂接hdc-0.11.img:

“ata0-slave: type=disk, path="hdc-0.11.img", mode=flat, cylinders=121, heads=16, spt=63”

4、使用WimImage打开tmp.imz,把我们所写的MBR程序bootload.s和makefile拖入,保存

5、双击运行bochsrc.bxrc,按空格键进入,使用root登录

6、运行如下命令将linux0.11映像文件复制到hdb1的根目录下:

mount /dev/hdb1 /mnt

cp /mnt/usr/src/linux/Image /mnt/Image

7、下面把存在b盘(即tmp.imz软盘映像)中的bootload.s和makefile复制出来:

mkdir asm

cd asm

mcopy b:\makefile makefile

mcopy b:\bootload.s bootload.s

8、汇编、链接bootload.s,把可执行代码写到hdb1的MBR中去:

make //参考附录makefile文件的说明

9、退出:

umount /mnt

关闭Bochs

步骤6~9的运行界面如图6

图6. 修改硬盘映像文件MBR

10、修改bochsrc-hd.bxrc,把boot:a改为boot:c,双击运行。成功!界面如下:

图7. 从硬盘启动linux0.11

五.程序代码

见随本文件发布的附件(一个是MBR程序bootload.s,一个是makefile文件)

参考文献:

1、《带您深入了解硬盘分区表与逻辑锁

作者:迈克尔

来源:家缘硬件网

日期:2005.1.9

链接:

http://www.pcnethome.com/Article/NEWS/skill/200501/1037.html

2、《Linux0.11学习体会》

作者:chenfangjian

来源:http://www.oldlinux.org/论坛子论坛“Linux内核完全注释

链接:

http://www.oldlinux.org/cgi-bin/LB5000XP/topic.cgi?forum=1&topic=1507

3、《Linux内核完全注释》

作者:赵炯

机械工业出版社

4、 http://www.oldlinux.org/论坛子论坛“Linux 0.11系统的建立和实验” 上linuxlala 回复的一篇帖子,他详细描述了编写linux0.11引导程序的方法。

链接:

http://www.oldlinux.org/cgi-bin/LB5000XP/topic.cgi?forum=4&topic=226

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章