手写操作系统(四十四)-硬盘及分区表

代码、内容参考来自于包括《操作系统真象还原》、《一个64位操作系统的设计与实现》以及《ORANGE’S:一个操作系统的实现》。

1.概述

文件系统是运行在操作系统中的软件模块,是操作系统提供的一套管理磁盘文件读写的方法和数据组织、存储形式,它的管理对象是文件,管辖范围是分区,因此它建立在分区的基础上,每个分区都可以有不同的文件系统。

盘片:类似光盘中的一个圆盘,上面布满了磁性介质。

扇区:扇区是硬盘读写的基本单位,它在磁道上均匀分布,与磁头和磁道不同,扇区从1开始编号。扇区的大小字节数=256XN, N为自然数。通常取N为2,因此扇区大小为512字节。簇或块这些是操作系统中读写数据的单位,并不是磁盘原生支持的,一个簇或块等于1个以上的扇区。因为磁盘是速度较低的设备,因此操作系统不可能一次只写一个扇区,操作系统把数据积攒到多个扇区时再一次性写入磁盘,这里的“多个扇区”就是指操作系统的簇或块。通常标准库函数还进行了二次优化,数据可以积攒到多个族或块时才写入,不过标准库中还提供了控制选项,可以立即把数据刷进硬盘。

磁道;盘片上的一个个同心圈就是磁道,它是扇区的载体,每一个磁道由外向里从0开始编号。同一盘片上的每一个磁道上都由扇区组成,即磁道其实是一圈扇区。磁盘上的磁道数取决于制作工艺。离圆心近的磁道与最外圈的磁道周长不一致,老硬盘磁道上的扇区数是一样的,新式硬盘中已经改进了,外圈磁道会容纳更多的扇区,在新硬盘中有个地址转换器来兼容老硬盘的扇区寻址,因此依然可以认为硬盘中每个磁道上的扇区数一样多。

磁头:磁头是硬盘上的读取和写入数据的组件。一个盘片分为上下两个面,各面都有一个磁头,因此一个盘片包括两个磁头,磁头号就表示盘面,平时所说的盘面号就是磁头号。虽然单个盘片的容量不断在增长,但其潜力毕竟是有限的。为了实现大容量,硬盘中必须由多个盘片来组成。既然有多个盘片,两个磁头就自然不够用了,肯定要有盘片×2个磁头,磁头编号由上到下从0开始。

柱面:为了让硬盘的读写更快,使用并行写入的方式。这个并行就是指多个磁头同时写入。也就是通常我们在写一个文件时,是由多个磁头同时写入到不同的盘面中编号位置相同的磁道上,采用并行的方式,读写速度是单盘的(磁头数)倍。这些由不同盘面上的编号相同的磁道(这些编号相同的同心圆大小一致)从上到下所组成的圆柱体的回转面就称为柱面,因此柱面的大小等于盘面数(磁头数)乘以每磁道扇区数。既然一组编号相同的磁道是柱面,而且柱面上的所有磁道号都相同,所以磁道号就称为柱面号。

分区:是由多个编号连续的柱面组成的,因此分区在物理上的表现是由某段范围内的所有柱面组成的通心环,并不是像饼图那种逻辑表示,当然若整个硬盘只有1个分区,那这个分区就是个所有柱面组成的圆柱体。分区不能跨柱面,也就是同一个柱面不能包含两个分区,一个柱面只属于一个分区,分区的起始和终止都落在完整的柱面上,并不会出现多个分区共享同一柱面的情况,这就是所谓的分区粒度。因此,分区大小等于每柱面上的扇区数乘以柱面数,这就是我们实际分区时,键入的大小往往与实际大小不同的原因,分区大小总会是每柱面上的扇区数的整数倍,也就是会以柱面向上取整。假如硬盘上有n个柱面,1~10 柱面是 a 分区,11~23 是 b分区,这两个分区不共享 11 号柱面。

硬盘容量=单片容量×磁头数。

单片容量=每磁道扇区数×磁道数×512 字节。

硬盘容量=每磁道扇区数×柱面数×512字节×磁头数

 

2.创建磁盘分区表

目前我们只有一个盘dreams.img

在物理地址 0x475 处存储着主机上安装的硬盘的数量,它是由 BIOS 检测并写入的

xp/b 0x475

我们先创建个从盘

cd /bochs/bin/
sudo ./bximage

将该配置加入配置文件boshsrc.disk

ata0-slave: type=disk, path="/bochs/bin/dreamsFS.img", mode=flat

再查看,就可以看到有两个盘了。

查看以下

ll /bochs/bin/dreamsFS.img

sudo fdisk -l dreamsFS.img

磁盘参数,柱面数=162,磁头数=16,每磁道扇区数=63,总大小是79.73MB。这是工具bximage为咱们配置好的硬件参数

硬盘容量=63×162×512×16=83607552字节,将其换算成MB为79.734375MB,约等于79.73MB。验证下DreamsFS.img的真实大小。

分区是逻辑上划分磁盘空间的方式,归根结底是人为地将硬盘上的柱面扇区划分成不同的分组,每个分组都是单独的分区。 各分区都有描述符来描述分区本身所在硬盘上的起止界限等信息,在硬盘的MBR中有个64字节固定大小的数据结构,这就是著名的分区表,分区表中的每个表项就是一个分区的描述符,表项大小是16字节,因此64字节的分区表总共可容纳4个表项,所以最多有4个分区

为了支持任意数量分区,发明了扩展分区,通过id属性值判断分区类型

分区表中共 4个分区,哪个做扩展分区都可以,扩展分区是可选的,但最多只有1个,其余的都是主分区。在过去没有扩展分区时,这 4 个分区都是主分区;为了兼容 4 个主分区的情况,扩展分区中的第 1 个逻辑分区的编号从 5 开始。

接下来我们先分区。

我们先设置以下显模式

fdisk -c="dos" -u="cylinders" ./dreamsFS.img

输入x进入专家命令

输入c设置柱面数为162,输入h设置磁头数为16,输入r回到上一级菜单

接着创建主分区

创建扩展分区

查看目前分区

创建5个逻辑分区

查看分区

查看已知文件系统id

键入t设置分区id

输入p打印分区表,扩展分区中的全部逻辑分区id已经变成0x66

输入w将分区表写入硬盘并退出fdisk

查看分区

sudo fdisk -l dreamsFS.img

 

3.磁盘分区简介

磁盘分区表(Disk Partition Table)简称DPT,是由多个分区元信息汇成的表,表中每一个表项都对应一个分区,主要记录各分区的起始扇区地址,大小界限等。

最初的磁盘分区表位于MBR引导扇区中,MBR (Main Boot Record)即主引导记录,它是一段引导程序,其所在的扇区称为主引导扇区,该扇区位于0盘0道1扇区(物理扇区编号从1开始,逻辑扇区地址LBA从0开始),也就是硬盘最开始的扇区,扇区大小为512字节,在这512字节中,前446字节是硬盘的参数和引导程序,然后才是64字节的分区表,最后是2字节的魔数55aa。

这512字节内容由三部分组成:

  • 主引导记录 MBR。
  • 磁盘分区表 DPT。
  • 结束魔数55AA,表示此扇区为主引导扇区,里面包含控制程序。

MBR引导程序位于主引导扇区中偏移0~0x1BD的空间,共计446字节大小,这其中包括硬盘参数及部分指令(由BIOS跳入执行),它是由分区工具产生的,独立于任何操作系统。

磁盘分区表位于主引导扇区中偏移0x1BE-0x1FD的空间,总共64字节大小,分区表中的每个表项就是一个分区的描述符,每个分区表项是16字节,因此 64 字节的分区表总共可容纳 4 个表项,因此磁盘分区表最大支持4个分区。

魔数55AA作为主引导扇区的有效标志,位于扇区偏移0x1FE-0x1FF,也就是最后2个字节。

分区表项中有个属性是文件系统id,它表示文件系统的类型,为支持更多的分区,专门增加一种id属性值(id为5),用来表示该分区可被再次划分出更多的子分区,这就是逻辑分区。 因为只是在分区表项中通过属性来判断分区类型,所以这4个分区中的任意一个都可以作为扩展分区。 扩展分区是可选项,最多只有1个,1个扩展分区在理论上可被划分出任意多的子扩展分区。

分区表中共4个分区,哪个做扩展分区都可以,扩展分区是可选的,但最多只有1个,其余的都是主分区。在过去没有扩展分区时,这4个分区都是主分区,为了兼容4个主分区的情况,扩展分区中的第1个逻辑分区的编号从5开始。

在硬盘中,最开始的扇区是MBR引导扇区,接着是空闲的多个扇区,随后是具体的分区。

如图:

分区粒度也就是分区都要占用完整的柱面,柱面是由不同盘面上相同的磁道组成的,因此从定义上看,柱面肯定不能跨磁道,同一个磁道也不能被多个分区共享,而第0 块又被 MBR 引导扇区占据,因此MBR 所在的磁道不能划入分区了,故分区起始地址要偏移磁盘 1 个磁道的大小,也就是一般为 63 扇区(分区起始是 0x3F,即63)。总之,分区偏移MBR所在的磁道后,分区的起始地址便会是柱面的整数倍,这是由分区工具规划好的,对于不够一个柱面的剩余的空间一般不再利用,,并不参与分区。 除去MBR引导扇区占用的1扇区,这部分剩余空间是62个扇区。由于仅仅是62个扇区的空间,能用它做的事情有限,因为空间太小会使扩展性很差,比如文件系统中的块位图大小是与分区大小成正比的,若将块位图存放在此处,受到这62个扇区的限制,能管理的分区范围也将大大缩水,因此很少有操作系统会用到这个磁道,我们也不用它。

为了兼容此固定长度为4个分区的分区表,又要突破固定分区数的限制,所以视个扩展分区为总扩展分区,将它划分成多个子扩展分区,每个子扩展分区在逻辑上相当于硬盘,因此每个子扩展分区都可以有1个分区表。 这样一来,各个分区表的长度依然固定为4,但是允许有无限多个分区表,分区表项多了,自然支持的分区数就多了。

扩展分区表采用链式结构,将所有子扩展分区的分区表串在一起,形成可容纳无限个分区表的单向链表。 链表是要有结点的,这里的每个分区表就是结点,一般的链表结点除了包括数据外,还必须要包括下一个结点的地址,分区表也采用了这种结构,其表项就分为两部分,一部分是描述逻辑分区的信息,另一部分是描述下一个子扩展分区的地址。

扩展分区之下是子扩展分区,要想使用分区,就离不开分区表,逻辑分区也是分区,为了使用它,也需要有元信息来描述它的范围、边界、类型等信息,因此在子扩展分区中也要有分区表来描述这些逻辑分区。

分区表本身也要在子扩展分区中占磁盘空间,因此实际情况是每个子扩展分区的空间并不是只有逻辑分区,在每个子扩展分区中最开始的扇区(此扇区称为EBR引导扇区)用于存储此子扩展分区中的分区表,此扇区中的内容也是前446字节是引导程序,中间64字节是分区表,后2字节是0x55和0xAA,它同MBR引导扇区的结构相同。 紧随其后的是空闲的一部分扇区,其余剩下的大部分扇区才被用作存储数据的分区,即逻辑分区。 因此,子扩展分区包含逻辑分区。

扩展分区被划分出多个子扩展分区,每个子扩展分区都有自己的分区表,所以子扩展分区在逻辑上相当于单独的硬盘,各分区表在各个子扩展分区最开始的扇区中,该扇区同MBR引导扇区结构相同,由于是经扩展分区划分出来的,所以它们称为EBR,即扩展引导记录。MBR只有1个,EBR理论上有无限个,MBR和EBR所在的扇区统称为引导扇区,它们的结构是相同的,MBR中有的EMR中也有。可以把子扩展分区视为硬盘,因为各子扩展分区的结构也同整个硬盘结构一样,最开始的扇区都是引导扇区,中间都是空闲一小部分扇区,最后的大片扇区空间作为数据存储的分区。

为了MBR方便找到活动分区上的内核加载器,内核加载器的入口地址也必须在固定的位置,这个位置就是各分区最开始的扇区,这也是约定好的。这个各分区起始的扇区中存放的是操作系统引导程序–内核加载器,因此该扇区称为操作系统引导扇区,其中的引导程序(内核加载器)称为操作系统引导记录OBR,即OS Boot Record,此扇区也称为OBR引导扇区。 在OBR扇区的前3个字节存放了跳转指令,这同样是约定,因此MBR找到活动分区后,就大胆主动跳到活动分区OBR引导扇区的起始处,该起始处的跳转指令马上将处理器带入操作系统引导程序。

由于扩展分区采用了链式分区表,理论上可以存在无限个分区表,支持无限个逻辑分区。每一个逻辑分区所在的子扩展分区都有一个与MBR结构相同的EBR,EBR中分区表的第一分区表项用来描述所包含的逻辑分区的元信息,第二分区表项用来描述下一个子扩展分区的地址,第三、四表项未用到。位于EBR中的分区表相当于链表中的结点,第一个分区表项存的是分区数据,第二个分区表项存的是后继分区的指针。值得一提的是这两个分区表项都是指向一个分区的起始,起始地址都是个扇区地址,只不过第一个分区表项指向的是该逻辑分区最开始的扇区,此扇区称为操作系统引导扇区,即OBR引导扇区。第二个分区表项指向下一个子扩展分区的EBR引导扇区。

OBR 引导扇区不是 EBR 引导扇区。EBR 不属于分区之内,不属于操作系统管理的范围。而OBR引导扇区位于分区(主分区和逻辑分区)最开始的扇区,属于操作系统管理的范围。

他们的位置如图:

 

MBR位于整个硬盘最开始的块,EBR位于每个子扩展分区,各子扩展分区中只有一个逻辑分区。MBR和EBR位于分区之外的扇区,而OBR则属于主分区和逻辑分区最开始的扇区,每个主分区和逻辑分区中都有OBR 引导扇区。

分区表项的结构如图:

活动分区是指引导程序所在的分区,活动分区标记是给MBR或其他需要移交CPU使用权的程序看的,它们通过此位来判断该分区的引导扇区中是否有可执行的程序,也就是引导程序,这个引导程序通常是操作系统内核加载器,故此引导程序通常被称为操作系统引导记录,即OBR (OS Boot Record),如果MBR发现该分区表项的活动分区标记为0x80,这就表示该分区的引导扇区中有引导程序,MBR就将CPU使用权交给此引导程序,如果此引导程序是操作系统或其加载器,此时操作系统便掌握了CPU使用权,也就是平时所说的加载内核。 这里一直说的分区引导扇区是位于分区最开始的扇区,是分区引导程序所在的扇区,由于此引导程序通常都是操作系统内核加载器,故此扇区被称为操作系统引导扇区,也就是 OBR 所在的扇区,即 OBR 引导扇区。

OBR引导扇区并不是EBR或MBR引导扇区,它们虽然都包含引导程序,并且都以0x55和0xaa结束,但它们最大的区别是分区表只包含在MBR和EBR中,OBR中可没有分区表。 MBR和EBR所在的扇区不属于分区范围之内,它们是由分区工具创建并管理的,因此不归操作系统管理,操作系统不可以随意往里面写数据,尽管操作系统有能力这样做。 而OBR引导扇区是分区中最开始的扇区,归操作系统的文件系统管理,因此操作系统通常往OBR引导扇区中添加内核加载器的代码,供MBR调用以实现操作系统自举。

分区起始偏移扇区是个相对量,它表示各分区的起始扇区地址是相对于某基准的偏移扇区数,各分区的绝对扇区LBA地址=基准的绝对扇区起始LBA地址+各分区的起始偏移扇区,这个基准是指分区所依赖的上层对象,或者说是创建该分区的父对象。对于逻辑分区而言,逻辑分区是在子扩展分区中拆分出来的,其具体地址依赖于子扩展分区自身的起始地址,因此逻辑分区的基准是子扩展分区的起始扇区 LBA 地址。对于子扩展分区而言,子扩展分区是在总扩展分区中拆分出来的,其具体地址依赖于总扩展分区自身的起始地址,因此子扩展分区的基准是总扩展分区的起始扇区LBA地址。对于主分区或总扩展分区而言,这两类分区本身是独立、无依赖的分区,因此基准为0。

分区容量扇区数表示分区的容量扇区数。

地址0~0x1b0之间的数字全是0,xxd已经在输出中将其省略了,在偏移 0x1be 的地方才是分区表,一直到0x1fd,一共是64字节,最后才是魔数55 AA。在分区表中只创建了2个分区,第1分区用来创建主分区,第4分区用来创建扩展分区,第2~3分区没占用,因此是一系列的0值。

如图:

第 4 分区是总扩展分区,其类型是 0x05,这说明它确实是扩展分区

结构如图:

 

下面查看扩展分区的分区表。扩展分区中的所有分区表被组织成单向链表,咱们查看链表中的第1个结点,也就是第1个子扩展分区的EBR引导扇区。

总扩展分区的起始扇区地址是 0x7e00,将其乘以512换算为字节。该分区表中有两个分区表项,第1 个表项在此扇区中偏移范围是 0x1be~0x1cd,它是逻辑分区 dreamsFS.img5的元信息,第 2 个表项在此扇区中偏移范围是 0x1ce~0x1dd,这是下一个扩展分区的扇区 LBA 地址。

子扩展分区是在总扩展分区中创建的,子扩展分区的偏移扇区理应以总扩展分区的绝对扇区LBA地址为基准,因此,子扩展分区的绝对扇区LBA地址=总扩展分区绝对扇区LBA地址+子扩展分区的偏移扇区。

逻辑分区是在子扩展分区中创建的,逻辑分区的偏移扇区理应以子扩展分区的绝对扇区LBA地址为基准,因此,逻辑分区的绝对扇区LBA地址=子扩展分区绝对扇区LBA地址+逻辑分区偏移扇区。这里的子扩展分区就是当前子扩展分区。

类似的,如下图:

所有分区布局如下:

 

4.参考

郑钢著操作系统真象还原

田宇著一个64位操作系统的设计与实现

丁渊著ORANGE’S:一个操作系统的实现

暂无评论

发送评论 编辑评论

|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇