操作系统应当具备读写硬盘的能力。因此,本章将要实现的是硬盘驱动。硬盘驱动由两个函数构成:读硬盘函数与写硬盘函数。
9.1 读硬盘
想要读硬盘,就需要提供以下三个信息:
- 起始扇区号
- 读取的扇区数
- 数据存储的地址
需要注意的是:读取的扇区数只能是一个8字节的整数。
由于读硬盘需要使用大量的端口读写指令,所以,该函数使用汇编语言实现。
请看本章代码9/HD.h
。
第5行,声明了读硬盘函数。
接下来,请看本章代码9/HD.s
。
第1行,将编译模式设定为32位。
第3行,将读硬盘函数hdRead
声明为外部链接的。
第13~15行,将读取的扇区数写入0x1f2
端口。hdRead
函数使用栈传参,sectorCount
是第三个参数,故其在栈中的位置是[ebp + 16]
。
第17~32行,将起始扇区号写入0x1f3~0x1f6
端口。startSector
是hdRead
函数的第二个参数,故其在栈中的位置是[ebp + 12]
。
第34~36行,将读硬盘命令0x20
写入0x1f7
端口。
第38~43行,等待硬盘准备就绪。
第46~47行,计算循环的总次数。一个扇区是512字节,insw
指令一次处理2字节,所以,每读一个扇区,就需要256次循环。循环的总次数等于读取的扇区数左移8位。
第48行,从栈中取得数据存储的地址。tarPtr
是hdRead
函数的第一个参数,故其在栈中的位置是[ebp + 8]
。
第49行,将硬盘中的数据读出。
9.2 写硬盘
写硬盘与读硬盘在实现上仅有以下不同:
- 写硬盘命令是
0x30
- 当硬盘准备就绪后,需要向
0x1f0
端口连续写入数据
请看本章代码9/HD.h
。
第6行,声明了写硬盘函数。
接下来,请看本章代码9/HD.s
。
第58~82行,与hdRead
函数一致。
第84~86行,将写硬盘命令0x30
写入0x1f7
端口。
第88~97行,与hdRead
函数一致。
第98行,从栈中取得数据存储的地址。
第99行,将数据写入硬盘。
接下来,请看本章代码9/Makefile
。
第5行,将HD.s
编译成ELF文件。
第6行,将HD.o
文件添加到链接器。
9.3 测试
本章代码9/Kernel.c
用于测试两个硬盘驱动函数。