自己动手从零写桌面操作系统GrapeOS系列教程——19.硬盘读写理论知识

学习操作系统原理最好的方法是自己写一个简单的操作系统。


一、硬盘控制器

我们前面已经讲过硬盘控制器是一种I/O接口,CPU通过它就能间接的读写硬盘。硬盘控制器主要有IDE和SATA两种,我们这里只考虑IDE控制器。
电脑里硬盘控制器有2个,一个叫主控制器,另一个叫从控制器。而每个硬盘控制器能连接两个硬盘,一个叫主盘,另一个叫从盘。所以一般一台电脑里最多能安装4个硬盘。

二、硬盘控制器端口

硬盘控制器上的端口很多,下表中只列出我们可能用到的。

I/O端口号 端口用途 端口位数
主控制器 从控制器 读取操作 写入操作
0x1f00x170DataData16
0x1f10x171ErrorFeatures8
0x1f20x172Sector countSector count8
0x1f30x173LBA lowLBA low8
0x1f40x174LBA midLBA mid8
0x1f50x175LBA highLBA high8
0x1f60x176DeviceDevice8
0x1f70x177StatusCommand8

关于上面这张表,其中的端口号不用记,用的时候翻看一下这里就行。从控制器与主控制器除了端口号不同,其它完全相同,以下我们以主控制器为例讲解。需要注意的是同一个端口在读端口和写端口两种操作下可能用途不一样,比如上表里的0x1f1和0x1f7。

端口0x1f0

首先看第1个端口0x1f0,它是这个表中唯一的16位端口,其它都是8位。从硬盘读取的数据或向硬盘写入的数据都是经过这个端口中转的。之前我们讲过硬盘是按扇区读写的,每个扇区都是512个字节,对硬盘每次读写的数据量都是512字节的整数倍。而这个端口是16位,也就是2个字节。如果你要读取一个扇区的数据,需要从这个端口连续读取256次。同样,写一个扇区,也需要向这个端口连续写入256次。

端口0x1f1

下面来看第二个端口0x1f1,在8个端口中,GrapeOS没有用到这个端口,其它都用到了。虽然没有用到,但还是简单介绍一下。当读操作时,里面保存的是错误信息;当写操作时,曾经需要向该端口写入一些参数,目前已废弃。

端口0x1f2

继续看第三个端口0x1f2,该端口保存的是读取或写入硬盘的扇区数量。该端口是8位端口,取值范围是0~255,但当设置为0时,表示读或写256个扇区。也就是说一次读写操作,最多读写256个扇区。

端口0x1f3~0x1f5

往下3个端口0x1f3、0x1f4、0x1f5是存放读取或写入硬盘时的起始扇区编号。这里用的扇区编号方式叫LBA或LBA28,意思是扇区从0开始编号,用28位二进制数来表示扇区号,最多表示2的28次方个扇区,由于每个扇区512字节,所以最大支持128GB的硬盘。对GrapeOS来说足够了。这里需要注意的是28位是3个半字节,这里的3个端口中,0x1f3存放LBA中的最低1个字节(0 ~ 7位),0x1f4存放中间的那个字节(8 ~ 15位),0x1f5存放高处的那个字节(16 ~ 23位),还剩下最高的半个字节(24 ~ 27位)存放在下个端口0x1f6中。

端口0x1f6

接着看0x1f6端口。这个端口中的低4位存放LBA中的最高4位(24~27位)。第4位0表示主盘,1表示从盘。第6位表示扇区寻址模式,0表示CHS,是一种古老的模式,1表示LBA,我们选LBA。另外第5位和第7位固定为1。参见下表:

bit内容说明
71固定为1。
6MOD选择寻址模式,0为CHS模式,1为LBA模式。
51固定为1。
4DEV选择硬盘驱动器,0为主硬盘,1为从硬盘。
3[27]LBA地址的第24~27位。
2[26]
1[25]
0[24]

端口0x1f7

我们来看最后一个端口0x1f7,这个端口有两种用途。
如果读取该端口,该端口将作为状态端口,可以获得硬盘的状态信息。如下表所示,该端口8个位中已经有4个位废弃了,有用的是另外4个位。

bit 内容 说明
7 BSY 此位为1表示硬盘正忙,勿扰。
6 DRDY 此位为1表示设备就绪,等待指令。
5 已废弃。
4 已废弃。
3 DRQ 此位为1表示可以从数据端口读写硬盘数据了。
2 已废弃。
1 已废弃。
0 ERR 此位为1表示有错误发生,错误信息见Error寄存器。

如果写入该端口时,该端口将作为命令端口,需要向该端口写入合适的命令。在GrapeOS中只用到两个命令:

  • 读命令:0x20
  • 写命令:0x30

三、硬盘操作方法

在GrapeOS中只有一块硬盘,安装在了主硬盘控制器主盘的位置,下面讲解读写硬盘时的操作步骤。

读硬盘操作步骤

  1. 读取Status端口,如果该端口位7为0,第6位为1,进入下一步,否则循环当前步骤。
  2. 向Sector count端口中写入要读入的扇区数。
  3. 向LBA low、LBA mid、LBA high3个端口依次写入LBA起始扇区号的低24位。
  4. 向Device端口写入LBA起始扇区号的24~27位,并置第4位为0,第6位为1。
  5. 向Command端口写入0x20。
  6. 读取Status端口,如果该端口位7为0,位3为1,则进入下一步,否则循环当前步骤。
  7. 从Data端口读取数据。如果读1个扇区,则循环读取该端口256次。

写硬盘操作步骤

  1. 读取Status端口,如果该端口位7为0,第6位为1,进入下一步,否则循环当前步骤。
  2. 向Sector count端口中写入要写入的扇区数。
  3. 向LBA low、LBA mid、LBA high3个端口依次写入LBA起始扇区号的低24位。
  4. 向Device端口写入LBA起始扇区号的24~27位,并置第4位为0,第6位为1。
  5. 向Command端口写入0x30。
  6. 读取Status端口,如果该端口位7为0,位3为1,则进入下一步,否则循环当前步骤。
  7. 向Data端口写入数据。如果写入1个扇区,则循环写入该端口256次。

读硬盘操作和写硬盘操作都是7个步骤,其中只有第5步和第7步不同,其它步骤完全相同。


本讲视频版地址:https://www.bilibili.com/video/BV1854y1M7vx/
配套的代码与资料在:https://gitee.com/jackchengyujia/grapeos-course
GrapeOS操作系统交流QQ群:643474045