⚠這篇文章比較無聊,因為涉及到一些硬件相關的東西,所以大部分的知識內容都很刻板,基本只能當作字典用。
之前講了關於主引導扇區上的內容,這次就來講講BootLoader具體是怎麼編寫和加載系統的.
首先我們需要知道硬盤是如何工作的,以及它的結構。
🤣服了,搞個軟件還得知道硬件的工作方法就離譜。
首先每個扇區的大小是固定在512字節的,現代硬盤的尋址方式一般都是通過LBA(邏輯塊尋址)來進行。老式的叫做CHS(柱面-磁頭-扇區)。這篇文章主要使用的是LBA28方式,也就是最高支持28位尋址。
當下的計算機應該採用的是更高位的LBA了。不過基本原理都是差不多的。
硬盤內部也是存在類似寄存器的結構,我們在彙編中會用端口的方式來訪問它們。
| 端口地址 | 作用 | 說明 |
|---|---|---|
0x1F0 | 數據寄存器 | 負責數據管理,用於讀取或寫入數據 |
0x1F1 | 錯誤寄存器 / 特性寄存器 | 記錄錯誤信息(讀)、設置功能(寫) |
0x1F2 | 扇區計數寄存器 | 指定待讀取或寫入的扇區數 |
0x1F3 | LBA 低 8 位 | LBA 地址的 0-7 位 |
0x1F4 | LBA 中 8-15 位 | LBA 地址的 8-15 位 |
0x1F5 | LBA 高 16-23 位 | LBA 地址的 16-23 位 |
0x1F6 | 設備寄存器 | 選擇主盤/從盤,LBA 高 24-27 位 |
0x1F7 | 狀態寄存器 / 命令寄存器 | 讀時返回狀態,寫時執行命令 |
數據寄存器(0x1F0)
- 作用:用於 讀取/寫入數據,一次傳輸 16 位(2 字節)。
- 數據大小:一個扇區(512 字節)= 256 次 16 位傳輸。
扇區計數寄存器(0x1F2)
- 作用:指定要讀/寫的 扇區數。
- 數值範圍:1-255,0 表示 256 個扇區。
LBA 地址寄存器
LBA 地址由 28 位組成,分佈在 4 個寄存器:
| 端口地址 | 寄存器 | 位範圍 | 作用 |
|---|---|---|---|
0x1F3 | LBA 低 8 位 | 0-7 | LBA 低 8 位 |
0x1F4 | LBA 中 8-15 位 | 8-15 | LBA 中 8 位 |
0x1F5 | LBA 高 16-23 位 | 16-23 | LBA 高 8 位 |
0x1F6 | LBA 最高 4 位 + 設備選擇 | 24-27 | LBA 最高 4 位 |
設備/磁盤選擇寄存器(0x1F6)
- 作用:選擇 主盤 / 從盤,並存儲 LBA 最高 4 位。
| 位 | 描述 |
|---|---|
7 | 必須為 1 |
6 | 1 = LBA 模式,0 = CHS 模式 |
5 | 必須為 1 |
4 | 0 = 主盤,1 = 從盤 |
3 | LBA 地址的 第 24 位 |
2 | LBA 地址的 第 25 位 |
1 | LBA 地址的 第 26 位 |
0 | LBA 地址的 第 27 位 |
狀態寄存器(0x1F7,讀)
- 作用:用於檢查硬盤狀態,確定何時可以讀取/寫入數據。
| 位 | 名稱 | 描述 |
|---|---|---|
7 | BUSY | 1 = 硬盤忙,無法執行新命令 |
6 | DRDY | 1 = 硬盤準備就緒 |
5 | DF | 1 = 磁盤錯誤(寫保護或數據錯誤) |
4 | SEEK COMPLETE | 1 = 磁頭已定位到正確位置 |
3 | DRQ | 1 = 數據準備就緒(可讀/寫) |
2 | CORR | 1 = 硬盤糾錯 |
1 | IDX | 索引標誌(幾乎不使用) |
0 | ERR | 1 = 發生錯誤 |
命令寄存器(0x1F7,寫)
- 作用:向
0x1F7端口寫入命令,通知硬盤執行相應的操作。 - 使用方式:在正確設置 LBA 地址和扇區數 後,向該寄存器寫入相應命令。
| 命令值 | 功能 |
|---|---|
0x20 | 讀取扇區(LBA 模式) |
0x30 | 寫入扇區(LBA 模式) |
0xEC | 識別硬盤信息 |
0xE7 | 刷新硬盤緩存 |
0xF8 | 設備重置 |
LBA 方式讀取磁盤
LBA 是現代磁盤的標準尋址方式,它將磁盤看作 連續的扇區序列,計算方式如下:
1LBA 地址 = (柱面號 × 磁頭數 + 磁頭號) × 每磁道扇區數 + 扇區號 - 1
LBA 讀取磁盤步驟
- 選擇通道: 向 0x1F2(扇區計數寄存器)寫入 待讀取的扇區數。
- 設置 LBA 地址: 1、將 LBA 低 24 位 寫入 0x1F3、0x1F4、0x1F5;2、將 LBA 高 4 位 寫入 0x1F6,並置位第 6 位(LBA 模式)。
- 發送讀取命令: 向 0x1F7(命令寄存器)寫入 0x20(讀取扇區命令)。
- 檢查狀態: 讀取 0x1F7(狀態寄存器),確認硬盤數據準備就緒。
- 讀取數據: 從 0x1F0 讀取 512 字節(1 個扇區)到內存。
知道了上述知識,我們就知道了如何控制硬盤,接下來我們可以開始編寫BootLoader辣!