2007年4月6日星期五

電腦開機流程

自 MBR 一路開機到 Linux 第一個 user-space process 的過程

典型 x86 Linux 啟動程序

典型 ARM / PowerPC Linux 啟動程序

發信人: suzhe (I Love Linux), 信區: FreeDevelop
標 題: HardDisk,Partition,Boot,OSLoader專題
發信站: BBS 水木清華站 (Sat Nov 20 16:45:44 1999)

第一部分 簡 介
1,1
一. 硬碟結構簡介

1. 硬碟參數釋疑

到目前為止, 人們常說的硬碟參數還是古老的 CHS (Cylinder/
Head/Sector)參數. 那麼為什麼要使用這些參數, 它們的意義是什麼?
它們的取值範圍是什麼?
很久以前, 硬碟的容量還非常小的時候, 人們採用與軟碟類似的結
構生產硬碟. 也就是硬碟盤片的每一條磁道都具有相同的扇區數. 由此
產生了所謂的3D參數 (Disk Geometry). 既磁頭數(Heads), 柱面數
(Cylinders), 扇區數(Sectors),以及相應的尋址方式.

其中:

磁頭數(Heads) 表示硬碟總共有幾個磁頭,也就是有幾面盤片, 最大
為 255 (用 8 個二進製位存儲);
柱面數(Cylinders) 表示硬碟每一面盤片上有幾條磁道, 最大為 1023
(用 10 個二進製位存儲);
扇區數(Sectors) 表示每一條磁道上有幾個扇區, 最大為 63 (用 6
個二進製位存儲).
每個扇區一般是 512個位元組, 理論上講這不是必須的, 但好象沒有取
別的值的.

所以磁碟最大容量為:

255 * 1023 * 63 * 512 / 1048576 = 8024 GB ( 1M = 1048576 Bytes )
或硬碟廠商常用的單位:
255 * 1023 * 63 * 512 / 1000000 = 8414 GB ( 1M = 1000000 Bytes )

在 CHS 尋址方式中, 磁頭, 柱面, 扇區的取值範圍分別為 0 到 Heads - 1,
0 到 Cylinders - 1, 1 到 Sectors (注意是從 1 開始).

2. 基本 Int 13H 調用簡介

BIOS Int 13H 調用是 BIOS 提供的磁碟基本輸入輸出中斷調用, 它可以
完成磁碟(包括硬碟和軟碟)的復位, 讀寫, 校驗, 定位, 診斷, 格式化等功能.
它使用的就是 CHS 尋址方式, 因此最大識能訪問 8 GB 左右的硬碟 ( 本文中
如不作特殊說明, 均以 1M = 1048576 位元組為單位).

3. 現代硬碟結構簡介

在老式硬碟中, 由於每個磁道的扇區數相等, 所以外道的記錄密度要遠低
於內道, 因此會浪費很多磁碟空間 (與軟碟一樣). 為了解決這一問題, 進一
步提高硬碟容量, 人們改用等密度結構生產硬碟. 也就是說, 外圈磁道的扇區
比內圈磁道多. 採用這種結構後, 硬碟不再具有實際的3D參數, 尋址方式也改
為線性尋址, 即以扇區為單位進行尋址.
為了與使用3D尋址的老軟體兼容 (如使用BIOS Int13H接口的軟體), 在硬
盤控制器內部安裝了一個地址翻譯器, 由它負責將老式3D參數翻譯成新的線性
參數. 這也是為什麼現在硬碟的3D參數可以有多種選擇的原因 (不同的工作模
式, 對應不同的3D參數, 如 LBA, LARGE, NORMAL).

4. 擴展 Int 13H 簡介

雖然現代硬碟都已經採用了線性尋址, 但是由於基本 Int 13H 的制約, 使
用 BIOS Int 13H 接口的程式, 如 DOS 等還只能訪問 8 G 以內的硬碟空間.
為了打破這一限制, Microsoft 等幾家公司制定了擴展 Int 13H 標準
(Extended Int13H), 採用線性尋址方式存取硬碟, 所以突破了 8 G 的限制,
而且還加入了對可拆卸介質 (如活動硬碟) 的支持.

二. Boot Sector 結構簡介

1. Boot Sector 的組成

Boot Sector 也就是硬碟的第一個扇區, 它由 MBR (Master Boot Record),
DPT (Disk Partition Table) 和 Boot Record ID 三部分組成.

MBR 又稱作主引導記錄佔用 Boot Sector 的前 446 個位元組 ( 0 to 0x1BD ),
存放系統主引導程式 (它負責從活動分區中裝載並運行系統引導程式).
DPT 即主分區表佔用 64 個位元組 (0x1BE to 0x1FD), 記錄了磁碟的基本分區
資訊. 主分區表分為四個分區項, 每項 16 位元組, 分別記錄了每個主分區的資訊
(因此最多可以有四個主分區).
Boot Record ID 即引導區標記佔用兩個位元組 (0x1FE and 0x1FF), 對於合法
引導區, 它等於 0xAA55, 這是判別引導區是否合法的標誌.
Boot Sector 的具體結構如下圖所示 (參見 NightOwl 大俠的文章):
      0000  |------------------------------------------------|
| |
| |
| Master Boot Record |
| |
| |
| 主引導記錄(446位元組) |
| |
| |
| |
01BD | |
01BE |------------------------------------------------|
| |
01CD | 分區資訊 1(16位元組) |
01CE |------------------------------------------------|
| |
01DD | 分區資訊 2(16位元組) |
01DE |------------------------------------------------|
| |
01ED | 分區資訊 3(16位元組) |
01EE |------------------------------------------------|
| |
01FD | 分區資訊 4(16位元組) |
|------------------------------------------------|
| 01FE | 01FF |
| 55 | AA |
|------------------------------------------------|

2. 分區表結構簡介

分區表由四個分區項構成, 每一項的結構如下:

BYTE State : 分區狀態, 0 = 未激活, 0x80 = 激活 (注意此項)
BYTE StartHead : 分區起始磁頭號
WORD StartSC : 分區起始扇區和柱面號, 底位元組的低6位為扇區號,
高2位為柱面號的第 9,10 位, 高位元組為柱面號的低 8 位
BYTE Type : 分區類型, 如 0x0B = FAT32, 0x83 = Linux 等,
00 表示此項未用
BYTE EndHead : 分區結束磁頭號
WORD EndSC : 分區結束扇區和柱面號, 定義同前
DWORD Relative : 在線性尋址方式下的分區相對扇區地址
(對於基本分區即為絕對地址)
DWORD Sectors : 分區大小 (總扇區數)

注意: 在 DOS / Windows 系統下, 基本分區必須以柱面為單位劃分
( Sectors * Heads 個扇區), 如對於 CHS 為 764/255/63 的硬碟, 分區的
最小尺寸為 255 * 63 * 512 / 1048576 = 7.844 MB.

3. 擴展分區簡介

由於主分區表中只能分四個分區, 無法滿足需求, 因此設計了一種擴展
分區格式. 基本上說, 擴展分區的資訊是以鏈表形式存放的, 但也有一些特
別的地方.
首先, 主分區表中要有一個基本擴展分區項, 所有擴展分區都隸屬於它,
也就是說其他所有擴展分區的空間都必須包括在這個基本擴展分區中. 對於
DOS / Windows 來說, 擴展分區的類型為 0x05.
除基本擴展分區以外的其他所有擴展分區則以鏈表的形式級聯存放, 後
一個擴展分區的數據項記錄在前一個擴展分區的分區表中, 但兩個擴展分區
的空間並不重疊.
擴展分區類似於一個完整的硬碟, 必須進一步分區才能使用. 但每個擴
展分區中只能存在一個其他分區. 此分區在 DOS/Windows 環境中即為邏輯盤.
因此每一個擴展分區的分區表 (同樣存儲在擴展分區的第一個扇區中)中最多
只能有兩個分區數據項(包括下一個擴展分區的數據項).
擴展分區和邏輯盤的示意圖如下:
  |-----------------------|             --------
| 主擴展分區(/dev/hda2) | ^
|-----------------------| |
| 擴 展 | 分區項 1 |-- |
| |------------| | |
| 分區表 | 分區項 2 |--+-- |
|-----------------------| | | |
| | | | |
| 邏輯盤 1 (/dev/hda5) |<-/ | |
| | | |
|-----------------------| | 主
| 擴展分區 2 |<----/
|-----------------------| 擴
| 擴 展 | 分區項 1 |--
| |------------| | 展
| 分區表 | 分區項 2 |--+--
|-----------------------| | | 分
| | | |
| 邏輯盤 2 (/dev/hda6) |<-/ | 區
| | | |
|-----------------------| | |
| 擴展分區 3 |<----/ |
|-----------------------| |
| 擴 展 | 分區項 1 |-- |
| |------------| | |
| 分區表 | 分區項 2 | | |
|-----------------------| | |
| | | |
| 邏輯盤 3 (/dev/hda7) |<-/ |
| | |
|-----------------------| ---------

三. 系統啟動過程簡介

系統啟動過程主要由一下幾步組成(以硬碟啟動為例):

1. 開機 :-)
2. BIOS 加電自檢 ( Power On Self Test -- POST )
內存地址為 0ffff:0000
3. 將硬碟第一個扇區 (0頭0道1扇區, 也就是Boot Sector)
讀入內存地址 0000:7c00 處.
4. 檢查 (WORD) 0000:7dfe 是否等於 0xaa55, 若不等於
則轉去嘗試其他啟動介質, 如果沒有其他啟動介質則顯示
"No ROM BASIC" 然後死機.
5. 跳轉到 0000:7c00 處執行 MBR 中的程式.
6. MBR 首先將自己複製到 0000:0600 處, 然後繼續執行.
7. 在主分區表中搜索標誌為活動的分區. 如果發現沒有活動
分區或有不止一個活動分區, 則轉停止.
8. 將活動分區的第一個扇區讀入內存地址 0000:7c00 處.
9. 檢查 (WORD) 0000:7dfe 是否等於 0xaa55, 若不等於則
顯示 "Missing Operating System" 然後停止, 或嘗試
軟碟啟動.
10. 跳轉到 0000:7c00 處繼續執行特定系統的啟動程式.
11. 啟動系統 ...

以上步驟中 2,3,4,5 步是由 BIOS 的引導程式完成. 6,7,8,9,10
步由MBR中的引導程式完成.

一般多系統引導程式 (如 SmartFDISK, BootStar, PQBoot 等)
都是將標準主引導記錄替換成自己的引導程式, 在運行系統啟動程式
之前讓用戶選擇要啟動的分區.
而某些系統自帶的多系統引導程式 (如 lilo, NT Loader 等)
則可以將自己的引導程式放在系統所處分區的第一個扇區中, 在 Linux
中即為 SuperBlock (其實 SuperBlock 是兩個扇區).

注: 以上各步驟中使用的是標準 MBR, 其他多系統引導程式的引導
過程與此不同.


第二部分 技術資料
第一章 擴展 Int13H 技術資料

一. 簡介
設計擴展 Int13H 接口的目的是為了擴展 BIOS 的功能, 使其支持
多於1024柱面的硬碟, 以及可移動介質的瑣定, 解鎖及彈出等功能.

二. 數據結構

1. 數據類型約定
BYTE 1 位元組整型 ( 8 位 )
WORD 2 位元組整型 ( 16 位 )
DWORD 4 位元組整型 ( 32 位 )
QWORD 8 位元組整型 ( 64 位 )

2. 磁碟地址數據包 Disk Address Packet (DAP)
DAP 是基於絕對扇區地址的, 因此利用 DAP, Int13H 可以輕鬆地逾
越 1024 柱面的限制, 因為它根本就不需要 CHS 的概念.
DAP 的結構如下:
    struct DiskAddressPacket
{
BYTE PacketSize; // 數據包尺寸(16位元組)
BYTE Reserved; // ==0
WORD BlockCount; // 要傳輸的數據塊個數(以扇區為單位)
DWORD BufferAddr; // 傳輸緩衝地址(segment:offset)
QWORD BlockNum; // 磁碟起始絕對塊地址
};


PacketSize 保存了 DAP 結構的尺寸, 以便將來對其進行擴充. 在
目前使用的擴展 Int13H 版本中 PacketSize 恆等於 16. 如果它小於
16, 擴展 Int13H 將返回錯誤碼( AH=01, CF=1 ).
BlockCount 對於輸入來說是需要傳輸的數據塊總數, 對於輸出來說
是實際傳輸的數據塊個數. BlockCount = 0 表示不傳輸任何數據塊.
BufferAddr 是傳輸數據緩衝區的 32 位地址 (段地址:偏移量). 數據
緩衝區必須位於常規內存以內(1M).
BlockNum 表示的是從磁碟開始算起的絕對塊地址(以扇區為單位),
與分區無關. 第一個塊地址為 0. 一般來說, BlockNum 與 CHS 地址的關係
是:
    BlockNum = cylinder * NumberOfHeads +
head * SectorsPerTrack +
sector - 1;

其中 cylinder, head, sector 是 CHS 地址, NumberOfHeads 是磁碟
的磁頭數, SectorsPerTrack 是磁碟每磁道的扇區數.
也就是說 BlockNum 是沿著 扇區->;磁道->;柱面 的順序記數的. 這一順
序是由磁碟控制器虛擬的, 磁碟表面數據塊的實際排列順序可能與此不同
(如為了提高磁碟速度而設置的間隔因子將會打亂扇區的排列順序).

3. 驅動器參數數據包 Drive Parameters Packet
驅動器參數數據包是在擴展 Int13H 的取得驅動器參數子功能調用中
使用的數據包. 格式如下:
    struct DriveParametersPacket
{
WORD InfoSize; // 數據包尺寸 (26 位元組)
WORD Flags; // 資訊標誌
DWORD Cylinders; // 磁碟柱面數
DWORD Heads; // 磁碟磁頭數
DWORD SectorsPerTrack; // 每磁道扇區數
QWORD Sectors; // 磁碟總扇區數
WORD SectorSize; // 扇區尺寸 (以位元組為單位)
};
資訊標誌用于返回磁碟的附加資訊, 每一位的定義如下:

0 位:
0 = 可能發生 DMA 邊界錯誤
1 = DMA 邊界錯誤將被透明處理
如果這位置 1, 表示 BIOS 將自動處理 DMA 邊界錯誤, 也就是說
錯誤代碼 09H 永遠也不會出現.

1 位:
0 = 未提供 CHS 資訊
1 = CHS 資訊合法
如果塊設備的傳統 CHS 幾何資訊不適當的話, 該位將置 0.

2 位:
0 = 驅動器不可移動
1 = 驅動器可移動

3 位: 表示該驅動器是否支持寫入時校驗.

4 位:
0 = 驅動器不具備介質更換檢測線
1 = 驅動器具備介質更換檢測線

5 位:
0 = 驅動器不可鎖定
1 = 驅動器可以鎖定
要存取驅動器號大於 0x80 的可移動驅動器, 該位必須置 1
(某些驅動器號為 0 到 0x7F 的設備也需要置位)

6 位:
0 = CHS 值是當前存儲介質的值 (僅對於可移動介質), 如果
驅動器中有存儲介質, CHS 值將被返回.
1 = CHS 值是驅動器支持的最大值 (此時驅動器中沒有介質).

7 - 15 位: 保留, 必須置 0.


三. 接口規範

1. 寄存器約定
在擴展 Int13H 調用中一般使用如下寄存器約定:

ds:di ==>; 磁碟地址數據包( disk address packet )
dl ==>; 驅動器號
ah ==>; 功能代碼 / 返回碼

在基本 Int13H 調用中, 0 - 0x7F 之間的驅動器號代表可移動驅動器
0x80 - 0xFF 之間的驅動器號代表固定驅動器. 但在擴展 Int13H 調用中
0x80 - 0xFF 之間還包括一些新出現的可移動驅動器, 比如活動硬碟等.
這些驅動器支持先進的鎖定,解鎖等功能.
ah 返回的錯誤碼除了標準 Int13H 調用規定的基本錯誤碼以外,又增加
了以下錯誤碼:

B0h 驅動器中的介質未被鎖定

B1h 驅動器中的介質已經鎖定

B2h 介質是可移動的

B3h 介質正在被使用

B4h 鎖定記數溢出

B5h 合法的彈出請求失敗

2. API 子集介紹
1.x 版的擴展 Int13H 調用中規定了兩個主要的 API 子集.

第一個子集提供了訪問大硬碟所必須的功能, 包括 檢查擴展 In13H
是否存在( 41h ), 擴展讀( 42h ), 擴展寫( 43h ), 校驗扇區( 44h ),
擴展定位( 47h ) 和 取得驅動器參數( 48h ).
第二個子集提供了對軟體控制驅動器鎖定和彈出的支持, 包括 檢查擴展
Int13H 是否存在( 41h ), 鎖定/解鎖驅動器( 45h ), 彈出驅動器( 46h ),
取得驅動器參數( 48h ), 取得擴展驅動器改變狀態( 49h ), int 15h.
如果使用了調用規範中不支持的功能, BIOS 將返回錯誤碼 ah = 01h,
CF = 1.

3. API 詳解

1) 檢驗擴展功能是否存在
入口:
AH = 41h
BX = 55AAh
DL = 驅動器號

返回:
CF = 0
AH = 擴展功能的主版本號
AL = 內部使用
BX = AA55h
CX = API 子集支持位圖
CF = 1
AH = 錯誤碼 01h, 無效命令

這個調用檢驗對特定的驅動器是否存在擴展功能. 如果進位標誌置 1
則此驅動器不支持擴展功能. 如果進位標誌為 0, 同時 BX = AA55h, 則
存在擴展功能. 此時 CX 的 0 位表示是否支持第一個子集, 1位表示是否
支持第二個子集.
對於 1.x 版的擴展 Int13H 來說, 主版本號 AH = 1. AL 是副版本號,
但這僅限於 BIOS 內部使用, 任何軟體不得檢查 AL 的值.

2) 擴展讀
入口:
AH = 42h
DL = 驅動器號
DS:DI = 磁碟地址數據包(Disk Address Packet)

返回:
CF = 0, AH = 0 成功
CF = 1, AH = 錯誤碼

這個調用將磁碟上的數據讀入內存. 如果出現錯誤, DAP 的 BlockCount
項中則記錄了出錯前實際讀取的數據塊個數.

3) 擴展寫
入口:
AH = 43h
AL
0 位 = 0 關閉寫校驗
1 打開寫校驗
1 - 7 位保留, 置 0
DL = 驅動器號
DS:DI = 磁碟地址數據包(DAP)
返回:
CF = 0, AH = 0 成功
CF = 1, AH = 錯誤碼

這個調用將內存中的數據寫入磁碟. 如果打開了寫校驗選項, 但 BIOS
不支持, 則會返回錯誤碼 AH = 01h, CF = 1. 功能 48h 可以檢測BIOS是否
支持寫校驗.
如果出現錯誤, DAP 的 BlockCount 項中則記錄了出錯前實際寫入的數
據塊個數.

4) 校驗扇區
入口:
AH = 44h
DL = 驅動器號
DS:DI = 磁碟地址數據包(Disk Address Packet)

返回:
CF = 0, AH = 0 成功
CF = 1, AH = 錯誤碼

這個調用校驗磁碟數據, 但並不將數據讀入內存.如果出現錯誤, DAP 的
BlockCount 項中則記錄了出錯前實際校驗的數據塊個數.


5) 鎖定/解鎖驅動器
入口:
AH = 45h
AL
= 0 鎖定驅動器
= 1 驅動器解鎖
= 02 返回鎖定/解鎖狀態
= 03h-FFh - 保留
DL = 驅動器號

返回:
CF = 0, AH = 0 成功
CF = 1, AH = 錯誤碼

這個調用用來縮定指定驅動器中的介質.
所有標號大於等於 0x80 的可移動驅動器必須支持這個功能. 如果
在支持可移動驅動器控制功能子集的固定驅動器上使用這個功能調用, 將
會成功返回.
驅動器必須支持最大255次鎖定, 在所有鎖定被解鎖之前, 不能在物理上
將驅動器解鎖. 解鎖一個未鎖定的驅動器,將返回錯誤碼 AH= B0h. 如果鎖定一
個已鎖定了255次的驅動器, 將返回錯誤碼 AH = B4h.
鎖定一個沒有介質的驅動器是合法的.

6) 彈出可移動驅動器中的介質
入口:
AH = 46h
AL = 0 保留
DL = 驅動器號

返回:
CF = 0, AH = 0 成功
CF = 1, AH = 錯誤碼

這個調用用來彈出指定的可移動驅動器中的介質.
所有標號大於等於 0x80 的可移動驅動器必須支持這個功能. 如果
在支持可移動驅動器控制功能子集的固定驅動器上使用這個功能調用, 將
會返回錯誤碼 AH = B2h (介質不可移動). 如果試圖彈出一個被鎖定的介質
將返回錯誤碼 AH = B1h (介質被鎖定).
如果試圖彈出一個沒有介質的驅動器, 則返回錯誤碼 Ah = 31h (驅動器
中沒有介質).
如果試圖彈出一個未鎖定的可移動驅動器中的介質, Int13h會調用 Int15h
(AH = 52h) 來檢查彈出請求能否執行. 如果彈出請求被拒絕則返回錯誤碼(同
Int15h). 如果彈出請求被接受,但出現了其他錯誤, 則返回錯誤碼 AH = B5h.

7) 擴展定位
入口:
AH = 47h
DL = 驅動器號
DS:DI = 磁碟地址數據包(Disk Address Packet)

返回:
CF = 0, AH = 0 成功
CF = 1, AH = 錯誤碼

這個調用將磁頭定位到指定扇區.

8) 取得驅動器參數
入口:
AH = 48h
DL = 驅動器號
DS:DI = 返回數據緩衝區地址

返回:
CF = 0, AH = 0 成功
DS:DI 驅動器參數數據包地址, (參見前面的文章)
CF = 1, AH = 錯誤碼

這個調用返回指定驅動器的參數.

9) 取得擴展驅動器介質更換檢測線狀態
入口:
AH = 49h
DL = 驅動器號

返回:
CF = 0, AH = 0 介質未更換
CF = 1, AH = 06h 介質可能已更換

這個調用返回指定驅動器的介質更換狀態.
這個調用與 Int13h AH = 16h 子功能調用相同, 只是允許任何驅動器
標號. 如果對一台支持可移動介質功能子集的固定驅動器使用此功能,則永遠
返回 CF = 0, AH = 0.
簡單地將可移動介質鎖定再解鎖就可以激活檢測線, 而無須真正更換介質.

返回:
CF = 0, AH = 0 介質未更換
CF = 1, AH = 06h 介質可能已更換

這個調用返回指定驅動器的介質更換狀態.
這個調用與 Int13h AH = 16h 子功能調用相同, 只是允許任何驅動器
標號. 如果對一台支持可移動介質功能子集的固定驅動器使用此功能,則永遠
返回 CF = 0, AH = 0.
簡單地將可移動介質鎖定再解鎖就可以激活檢測線, 而無須真正更換介質.

10) Int 15h 可移動介質彈出支持
入口:
AH = 52h
DL = 驅動器號
返回:
CF = 0, AH = 0 彈出請求可能可以執行
CF = 1, AH = 錯誤碼 B1h 或 B3h 彈出請求不能執行

這個調用是由 Int13h AH=46h 彈出介質功能調用內部使用的.

====================================================================
下面再說一下 linux 的啟動過程。
1,前面說到,MBR 會加載 OS LOADER 到 0x07C0:0000 然後開始運行,
linux 的 OS LOADER 代碼名字叫 bootsect.s,是一個長度為 512 位元組的小程式。前面也提到,多個作業系統的切換通過激活不同的分區表記錄來完成,DOS/LINUX 都有個 fdisk 程式用來做這件事,windows 的磁碟管理器可以完成類似功能,但是活動分區每次設置完之後得重啟才能生效,因此多個作業系統之間的選擇似乎不是那麼方便,因此就有了多作業系統引導程式,如 grub lilo 等等。這些程式在 MBR 的眼中看來,就是引導記錄,你甚至可以將它們直接寫到 MBR 中,覆蓋掉原有的 MBR 程式,但是我建議不要這麼做,因為 MBR 只有一個,多個作業系統之間爭奪起來會比較討厭,經常會發生你剛寫了我又寫一遍的情形,因此建議統統裝到 BOOT SECTOR,並且在硬碟分區表中將含有最強功能 OS LOADER 的那個分區激活。這樣 MBR 會將控制權交給 OS LOADER。

2,OS LOADER 接受用戶的選擇,然後啟動需要啟動的作業系統。linux 系統則開始運行 bootsect.s,

3,bootsect.s 什麼都不做,因為它只是一個 OS LOADER,它首先將自己移動到 0x9000:0000 處,然後將另一個組件 setup.s 加載到 0x9000:0200,然後 JMP 0x9000:0200 開始運行 setup.s

4,setup.s 加載作業系統的頭部 head.s 及緊隨其後的 linux 內核 main.c 移動到 0x1000:0000,然後調用 BIOS 功能獲取並保存一大堆系統參數,如磁碟參數表等等,準備接下來準備覆蓋掉 BIOS 向量表,覆蓋後所有的 BIOS 中斷都不再可用。

5,設置完畢之後,setup.s 將以 head.s 為首的 Linux 內核鏡像移動到物理地址 0x0000:0000,然後設置段表、頁表,最後調整機器狀態字到 32 位保護模式。

6,JMP 0x0 跳轉到線性地址 0x0,開始執行 head.s。
head.s 設定一些參數之後,調用 C 語言程式入口 main() 函數,作業系統進入 C 程式控制。
=====================================================================
http://www.ascc.sinica.edu.tw/nl/86/1318/05.txt

《電腦病毒與防治專題》

從硬碟架構看病毒所在

作者:譚安成

何謂病毒?病毒的分類、傳播、感染途徑、發病症狀等已在其它
文章發表過,故不在此篇文章討論範圍之內。本文將使各位讀者了
解電腦"開機的過程"、"硬碟的Partition Table"及"DBR(DOS啟動記
錄)"的結構內容,此時各位一定有所疑惑?這些又跟病毒有什麼關
係呢?想想是否曾經聽過周遭的朋友電腦,因中毒而使得硬碟無法
正常開機、硬碟資料亂掉的情形呢?這些情形大多是由於病毒破壞
電腦硬碟的Partition Table(以下簡稱 PT)、DBR、FAT 表或ROOT
(DIR)所導致的結果,然而只要PT 或DBR 遭到損壞將會使你硬碟內
寶貴且重要的資料因無法開機而無法讀取。這也是撰寫病毒之程式
設計師所喜愛下毒的兩個區域,因此如何事先備份PT、DBR 以備中
毒後之復原,將是本篇所研討的重點,除此之外也會介紹FAT 及
ROOT (DIR)架構。

開機的程序

電腦是如何開機的呢?在此我們以DOS 作業系統為例。當我們打
開電腦主機電源時主機板上的BIOS就開始測試電腦硬體及周邊設備
,此時螢幕左上角處將會看到RAM 數字從 0開始累加直至主機板上
DRAM的數目為止,之後你會聽到硬碟測試的聲音,且硬碟指示燈亮
一下表示硬碟測試沒有問題,接下來依序載入MBR(主開機程式)、
DBR(DOS啟動記錄)、IO.SYS、MSDOS.SYS、CONFIG.SYS、
COMMAND.COM、AUTOEXEC.BAT等,待螢幕出現C:>或A:>時即表示開機
成功。以圖式如下。
┌────┐   ┌────┐   ┌────┐
│POWER ON├→ │BIOS測試├→ │載入 MBR├→
└────┘ └────┘ └────┘
┌────┐ ┌────┐ ┌─────┐ ┌───────┐
│載入 DBR├→ │IO.SYS ├→ │MSDOS.SYS ├→│載入CONFIG.SYS├→
└────┘ └────┘ └─────┘ └───────┘
┌────────┐ ┌────────┐ ┌─────┐
│載入AUTOEXEC.BAT├→│螢幕出現C:>或A:>├→ │ 開機成功 │
└────────┘ └────────┘ └─────┘


硬碟的邏輯結構

硬碟的邏輯結構有如倉庫之擺設,為了有效管理倉庫我們將它依
儲存類別畫分區塊,而各區塊間又有其先後順序,就以DOS 作業系
統為例,其將整顆硬碟依序畫分為MBR、DBR、FAT、ROOT (DIR)、
DATA。
       HDD 的邏輯結構
┌───────┐
│ MBR │┐
├───────┤├ 開機時的重要程式及資料
│ DBR │┘
├───────┤
│ FAT │┐
├───────┤├ DOS 檔案組織的兩大架構
│ ROOT │┘
├───────┤
│ DATA │─ 使用者儲存在硬碟中的檔案、資料
└───────┘


DOS檔案組織的兩大架構

DOS作業系統在使用者下達DIR指令時是如何在螢幕上顯示其檔案
的階層架構呢?其實DOS 在硬碟中儲存了兩份重要的資訊即FAT和
DIR,它們用來記錄檔案位於硬碟之位址/所在,因此FAT 及DIR將
是DOS檔案組織的兩大架構,缺一不可。

何謂 FAT(File Allocation Table) 表

FAT 就是大家所稱的檔案配置表,其位於DBR 之後,而FAT 表中
記錄著硬碟內所有空間的位置,因此當我們欲建立一檔案時,DOS
作業系統將會到FAT 表處尋找何處有空位,如有空位則FAT 表將會
把此空位標成已使用,所以此動作就有如戲院的售票員,當有觀眾
買票入席時則將手上座位表上之空白座位標(上)打勾,簡言之,
FAT 表就是在硬碟中的某一區域,此區域都是記錄硬碟中那些"磁簇
(Clusters)"已被使用而那些磁簇還未被使用。

何謂 ROOT (DIR=Directory)

ROOT又有人稱做DIR,而此DIR並非DOS指令的DIR,而是我們所說
的根目錄區的意思,即然是根目錄區,那就是用來儲存DOS作業系統
根目錄的檔案及目錄,而 ROOT 配合檔案記錄表(FAT)來記錄這些檔
案及目錄,每個檔案或目錄用32 Bytes 表示,ROOT區中一共可記錄
512 個目錄或檔案。

何謂 MBR (Master Boot Record:主開機記錄)

每當我們拿到一顆新硬碟時,第一步驟就是將硬碟做分割
(Partition),並設定那一分割區為可開機磁區,這些設定值連同開
機程式將在執行分割程式後,由分割程式(如:FDISK)寫入MBR ,因
此MBR 是硬碟最重要的開機磁區,這個磁區位於硬碟的磁柱 0,磁
頭 0,磁區1 的位置也是大家俗稱的第0 軌,然而我們再將MBR分成
兩個部份;分別為MBP(主開機程式:Master Boot Program)及
Partition Table(硬碟分割表)。簡言之MBR 就是硬碟的某一區域其
大小為512 Bytes(000 - 1FF),存放著"開機程式"及"硬碟分割表"
因此一旦此區域招受破壞肯定將會無法正常開機。
    000┌───┐    ┐   000┌────────┐     ┐
│ M │ │ │ M B P │ │
│ │ │ │ │ ├ 218
│ │ │ │ │ │BYTES
│ │ │ │ │ │
│ B │ ├ 512 ─→ ├────────┤0D9 ┘
│ │ │BYTES │ 保 留 │ ┐ 228
│ │ │ ─→ ├────────┤1BE ┘BYTES
│ R │ │ │ Partition │ ┐
│ │ │ │ Table ┌──┤ │
│ │ │ │ │55AA│ ├ 66
└───┘1FF ┘ └─────┴──┘1FF ┘BYTES

MBR 的細分

下以DEBUG程式來說明MBR的內容:

1.首先以手動的方式來觀看MBR 的內容,因此就得介紹各位如何
撰寫一段小小的組合語言程式。
STEP1:在DOS 環境下執行DEBUG
STEP2:在DEBUG 環境的提示符號(-)下輸入A,即表示欲開始撰
寫組合語言程式依當時ES暫存器值而定(因此會與各位操
作時不同)

15C1:0100 mov ax,201 ┐
15C1:0103 mov bx,200 │
15C1:0106 mov cx,1 ├ 呼叫BIOS INT 13中斷服務程式讀出硬碟(DL =
15C1:0109 mov dx,80 │ 80)第0 軌(CH = 0)、第0 磁頭(DH = 0)、第1
15C1:010C int 13 │ 磁區(CL = 1)的MBR 資料放至記憶體ES:BX(
15C1:010E int 20 ┘ 15C1:200)
15C1:0110


STEP3:在DEBUG 環境的提示符號(-)下輸入G,則程式從15C1:0100
執行至15C1:010E的INT 20 結束
STEP4:在DEBUG 環境的提示符號(-)下輸入D 200,即看到15C1:200
內容如果的15C1:0280到15C1:02D0,看到"Invalid partition
tale.Error loading...."等字串,則表示主開機程式沒
有被病毒侵入。再比照前面15C1:03CE - 15C1:03FD為00
即表示此顆硬碟只切割了一個分割表。

2.接下來說明如何自行儲存PT,這時你一定會有所疑問為何不儲
存MBP呢?因為當您在使用FDISK時只要附加參數/MBR,則FDISK
將只會自動重寫一份主開機程式(MBP ) 而不會重建PT。
Step1:在DOS 環境下執行DEBUG
Step2:在DEBUG 環境的提示符號(-)下輸入A,即表示欲開始撰寫
組合語言程式

     15C1:0100 mov ax,12c   ┐
15C1:0103 mov cx,0 ├ 呼叫DOS INT 21的3C中斷服務程式開啟一空檔
15C1:0106 mov ah,3c │ PT.DAT
15C1:0108 int 21 ┘
15C1:010A push ax
15C1:010B mov ax,201 ┐ 呼叫BIOS INT 13中斷服務程式讀出硬碟(DL =
15C1:010E mov bx,200 ├ 80)第0 軌(CH = 0)、第0 磁頭(DH = 0)、第1
15C1:0111 mov cx,1 │ 磁區(CL = 1)的MBR 資料放至記憶體ES:BX(
15C1:0114 mov dx,80 │ 15C1:200)
15C1:0117 int 13 ┘
15C1:0119 pop ax
15C1:011A mov bx,ax ┐呼叫DOS INT 21的40 (AH)中斷服務程式從記憶
15C1:011C mov dx,3be ├體15C1:03BE(DX)開始寫64 Bytes(CX)資料存入
15C1:011F mov ah,40 │PT.DAT
15C1:0121 mov cx,40 │
15C1:0124 int 21 ┘
15C1:0126 mov ah,3e ┐呼叫DOS INT 21的3E (AH)中斷服務程式關閉己
15C1:0128 int 21 ┘開的檔案
15C1:012A int 20
15C1:012C db 'a:\pt.dat$' → 定義一檔名為PT.DAT
15C1:0136
-n mbr.com → 將上述程式定義一檔名MBR.COM
-rcx
-:0136 → 定義MBR.COM檔案大小為311Bytes
-w → 將MBR.COM存成一可執行檔
-q
C:>

Step3:請將一磁片放入A槽後在C:>下執行mbr.com,當程式執行
後會在A槽的根目錄下產生一大小為64Bytes的Partition
Table備份檔pt.dat。

何謂 DBR (Dos Boot Record:DOS 啟動記錄)

DBR就是存放DOS的啟動程式,主要功能就是用來載入DOS的兩個隱
藏檔(IO.SYS、 MSDOS.SYS。

同樣的底下以DEBUG 程式來說明DBR 的內容

1.首先以手動的方式來觀看DBR 的內容。
Step1:在DOS 環境下執行DEBUG
Step2:在DEBUG 環境的提示符號(-)下輸入A
      15C1:0100 mov ax,201   ┐
15C1:0103 mov bx,200 │
15C1:0106 mov cx,1 ├ 呼叫BIOS INT 13中斷服務程式讀出硬碟(DL =
15C1:0109 mov dx,180 │ 80)第0 軌(CH = 0)、第1 磁頭(DH = 1)、第1
15C1:010C int 13 │ 磁區(CL = 1)的DBR 資料放至記憶體ES:BX(
15C1:010E int 20 ┘ 15C1:200)
15C1:0110

Step3:在DEBUG 環境的提示符號(-)下輸入G,則程式從15C1:0100
執行至15C1:010E 的INT 20 結束
Step4:在DEBUG 環境的提示符號(-)下輸入D 200,即看到15C1:200
內容

2.同樣的我們也事先將DBR 儲存起來。
Step1:在DOS 環境下執行DEBUG
Step2:在DEBUG 環境的提示符號(-)下輸入A,即表示欲開始撰
寫組合語言程式

      15C1:0100 mov ax,12c   ┐
15C1:0103 mov cx,0 ├ 呼叫DOS INT 21的3C中斷服務程式開啟一空檔
15C1:0106 mov ah,3c │ DBR.DAT
15C1:0108 int 21 ┘
15C1:010A push ax
15C1:010B mov ax,201 ┐ 呼叫BIOS INT 13中斷服務程式讀出硬碟(DL =
15C1:010E mov bx,200 ├ 80)第0 軌(CH = 0)、第1 磁頭(DH = 1)、第1
15C1:0111 mov cx,1 │ 磁區(CL = 1)的DBR 資料放至記憶體ES:BX(
15C1:0114 mov dx,180 │ 15C1:200)
15C1:0117 int 13 ┘
15C1:0119 pop ax
15C1:011A mov bx,ax ┐呼叫DOS INT 21的40 (AH)中斷服務程式從記憶
15C1:011C mov dx,200 ├體15C1:0200(DX)開始寫512Bytes(AH)資料存入
15C1:011F mov ah,40 │DBR.DAT
15C1:0121 mov cx,200 │
15C1:0124 int 21 ┘
15C1:0126 mov ah,3e ┐呼叫DOS INT 21的3E (AH)中斷服務程式關閉己
15C1:0128 int 21 ┘開的檔案
15C1:012A int 20
15C1:012C db 'a:\dbr.dat$' → 定義一檔名為DBR.DAT
15C1:0136
-n dbr.com → 將上述程式定義一檔名DBR.COM
-rcx
-:0136 → 定義DBR.COM檔案大小為311Bytes
-w → 將DBR.COM存成一可執行檔
-q
C:>

Step3:請將一磁片於入A槽後在C:>下執行dbr.com,當程式執行
後會在A槽的根目錄下產生dbr.dat。

如何救復已中毒的MBR、DBR

我們將如何把未中毒前備份的PT.DAT、DBR.DAT 復原呢?另外需
告知讀者的是因為上文所備份的DBR.DAT只針對單一分割區為準,因
此做完下述步驟只能救回主分割區的資料,以下所做的步驟需特別
小心,否則一不注意將有自己破壞硬碟之虞。

Step1:使用原版DOS 磁片由軟碟開機
Step2:在A:>下執行FDISK/MBR,此時FDISK會重新寫一份新的MBP
至硬碟內。
Step3:執行DEBUG.EXE
Step4:-a
 15C1:0100 mov ax,201  ┐
15C1:0103 mov bx,200 │
15C1:0106 mov cx,1 │
15C1:0109 mov dx,80 ├ 讀取硬碟MBR(MBP+Partition Table)
15C1:010C int 13 │ 資料進入記憶體且從ES:BX(15C1:0200)
15C1:010E int 20 │ 擺起
15C1:0110 ┘
-g
Program terminated normally
-q

Step5:做完上述步驟已完全恢復硬碟的MBR
Step6:接下來恢復DBR
Step7:在A:>下執行DEBUG.EXE
Step8:
 -n dbr.dat ┐將事先備份好的資料載入記憶體,且從
15C1:0200放起 -l 200 ┘
-a
15C1:0110 mov ax,301 ┐
15C1:0113 mov bx,200 │
15C1:0116 mov cx,1 │
15C1:0119 mov dx,80 ├ 呼叫BIOS INT 13,AH = 03的中
15C1:011C int 13 │ 斷服務程式,將15C1:0200起之
15C1:011E int 20 │ 資料寫1(AL = 1) 磁區入硬碟
15C1:0110 ┘ (DL =80),第0 磁頭(DH = 0),
第0 磁軌(CH = 0),第1 磁區(CL=1)
-g

Program terminated normally
-q


Step9:救復DBR 後請重新由A 開機,在出現A:>後打入SYS C:
即可殺掉開機型病毒常隱藏的區域

十、結語

了解硬碟的邏輯架構將有助於讀者在自行PC中了開機型病毒後如
何自行救護而不借助掃毒程式,希望此篇文章能讓各位更清楚DOS
環境下硬碟的整體架構,倘若你對組合語言還不是很熟悉,想信"二
、硬碟的邏輯結構"能讓你清楚了解。

================================================================
ARM開機程序(ARM處理器核心是一個32位元的精簡指令集架構 RISC,Reduced Instruction Set Computer)

電源開啟
初始化硬體
映像檔複製到RAM
從RAM啟動映像檔
從Flash直接啟動映像檔

X86開機程序

電源開啟
BIOS初始化
POST&硬體組態檔(DRAM Controller, host bridge, PCI enumeration)
載入MBR
載入啟動區段
啟動DOS
執行Autoexec.bat

===================================================================
移植Linux至ARM嵌入式處理器
http://speed.cis.nctu.edu.tw/~ydlin/miscpub/hands-on_port-linux-to-ARM.pdf
開機程式與系統初始化
想要在一台機器上啟動一個作業系統,首先就是要能夠將處理器初始化,接著將核心載入到某個固定的起始位址上,
這個位置通常指的是SDRAM的起始點,會因處理器的不同而有所區分,也就是說,上述這些行為是具有平台相依性問題的,
而這些動作是由開機程式(bootstrap loader)來進行。接著就是將核心的本文(text)位置放到正確的位址,
如Linux 2.4.x都是將核心載入到執行位址的起始位置加上0x1000 bytes的地方,如圖8所示,此為一段核心原始碼,
裡面就註明了我們所使用的平台FootBridge,在系統開始時,需要把核心解壓縮到0x7c000000位址。
這些設定在進行核心的編譯前就需要完成,如此才能夠正確的啟動核心。
===================================================================
參考文章
(1)Migrating from x86 to PowerPC, Part 2: Anatomy of the Linux boot process
http://www-128.ibm.com/developerworks/library/pa-migrate2/?ca=dgr-lnxw01BootProcess
(2)Inside the Linux boot process
http://www-128.ibm.com/developerworks/linux/library/l-linuxboot/?ca=dgr-lnxw09LinuxBoot
(3)All the Details of many versions of both MBR and OS Boot Records
http://mirror.href.com/thestarman/asm/mbr/MBR_in_detail.htm

沒有留言: