硬盘的读写

个人计算机中的 PATA/SATA 接口,每个 PATA 和 SATA 接口分配了 8个端口。但是,ICH 芯片内部通常集成了两个 PATA/SATA 接口,分别是主硬盘接口和副硬盘接口。这样一来, 主硬盘接口分配的端口号是 0x1f0~0x1f7,副硬盘接口分配的端口号是 0x170~0x177。

硬盘读写的基本单位是扇区。就是说,至少读取或写入一个扇区,而不能仅读写一个扇区中的几个字节。

最早的逻辑扇区编址方法是LBA28,使用 28 个比特来表示逻辑扇区号,从逻辑扇区 0x0000000 到 0xFFFFFFF,共可以表示 2^28=268435456 个扇区。每个扇区有 512 字节,所以 LBA28 可以管理 128 GB 的硬盘。

下面采用LBA28访问硬盘。


1.设置要读取的扇区数量 。这个数值要写入0x1f2端口。这是一个8位端口,因此每次只能读写255个扇区:

mov dx, 0x1f2
mov al, 0x01    ;1个扇区
out dx, al
注意:如果写入的值为0,则表明要读取256个扇区。每读取一个扇区,这个数值就减一。因此,如果在读写过程中发生错误,该端口包含着尚未读取的扇区数。

2.设置LBA扇区号。

扇区的读写是连续的,因此只需要给出第一个扇区的编号就可以了。28 位的扇区号太长,需要将其分成 4 段,分别写入端口 0x1f3、0x1f4、0x1f5 和 0x1f6 号端口。其中,0x1f3 号端口存放的是 0~7 位;0x1f4 号端口存放的是 8~15 位;0x1f5 号端口存放的是 16~23 位,最后 4 位在 0x1f6 号端口。

例:假定需要读写的起始逻辑扇区号为0x02,代码如下

mov dx, 0x1f3
mov al, 0x02
out dx, al    ;LBA地址7~0
inc dx     ;0x1f4
mov al, 0x00
out dx, al    ;LBA地址15~8
inc dx     ;0x1f5
out dx, al    ;LBA地址23~16
inc dx     ;0x1f6
mov al, 0xe0    ;LBA模式,主硬盘,以及LBA地址27~24

在现行的体系下,每个 PATA/SATA 接口允许挂接两块硬盘,分别是主盘(Master)和从盘(Slave)。 0x1f6 端口的低 4 位用于存放逻辑扇区号的 24~27位,第 4 位用于指示硬盘号,0 表示主盘,1 表示从盘。高 3 位是“111”,表示 LBA 模式。

7

6

5

4

3

2

1

0

L

B

A

硬盘

逻辑

3.向端口0x1f7写入0x20,请求硬盘读。 这也是一个8位端口:

mov dx, 0x1f7
mov al, 0x20    ;读命令
out dx, al

4.等待读写操作完成。 端口0x1f7既是命令端口,又是状态端口。在其操作期间,0x1f7端口的第7位置为 1 一旦硬盘准备就绪,它就会将此位清零,同时将第三位设为 1 。准备发送或接受数据。实现代码如下:

mov dx, 0x1f7
.waits:
in al, dx
and al, 0x88    ;寄存器AL中除第七位和第三位,其他全部清0
cmp al, 0x08    ;此时,如果寄存器AL中的二进制数是0x08,说明可以退出等待状态
jnz .waits    ;不忙,且硬盘已准备好数据传送

7

6

5

4

3

2

1

0

BSY

D

RQ

E

RR

BSY位为1说明忙,DRQ位为1说明已准备好和主机交换数据,ERR为1表明前一个命令执行错误,具体原因可访问端口0x1f1

5.连续取出数据。

0x1f0 是硬盘接口的数据端口,而且还是一个 16 位端口。一旦硬盘控制器空闲,且准备就绪,就可以连续从这个端口写入或者读取数据。下面的代码假定是从硬盘读一个扇区(512 字节,或者 256 字节),读取的数据存放到由段寄存器 DS 指定的数据段,偏移地址由寄存器 BX 指定:
mov cx, 256    ;总共要读取的字数
mov dx, 0x1f0
.readw:
in ax, dx
mov [bx], ax
add bx, 2
loop .readw

最后,0x1f1 端口是错误寄存器,包含硬盘驱动器最后一次执行命令后的状态(错误原因)。

Last moify: 2022-12-04 15:11:33
Build time:2025-07-18 09:41:42
Powered By asphinx