自己動手從零寫桌面作業系統GrapeOS系列教學——19.硬碟讀寫理論知識

2023-03-20 12:03:31

學習作業系統原理最好的方法是自己寫一個簡單的作業系統。


一、硬碟控制器

我們前面已經講過硬碟控制器是一種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