Linux 啓 動 分 析 專 題

Linux 啓 動 分 析 專 題    EP^){h

開機過程制的是從打開計算機電源直到LINUX顯示用戶登錄畫面的全過程。分析LINUX開機過程也是深入瞭解LINUX核心工作原理的一個很好的途徑。在不同的計算機平臺上,LINUX的開機過程稍有不同,本節以X386微機系統爲例,介紹LINUX的開機過程。
1。開機自檢

在剛開機時,根據X386CUP的特性,代碼段(CS,CODE SEGMENT)寄存器的值爲全1,指令計數器(IP,INSTRUCTION POINTER)的值爲全0,既CS=FFFF、IP=0000。這時CPU根據CS和IP 的值執行FFFF0H處的指令。由於FFFF0H已經到了基本內存的高地址頂端,所以,FFFF0H處的指令一般總是一個JMP指令,以便CPU能夠跳到比較低的地址去執行那裏的代碼,這個地址通常是ROM BIOS 的入口地址。接着,ROM BIOS 進行開機自檢,如檢查內存,鍵盤等。在自檢過程中,ROM BIOS會在上位內存(UMB,UPPERMEMORY BLOCK)中進行掃描,看看是否存在合法的設備控制卡ROM BIOS(如:SCSI卡上的ROM),如果有,就執行其中的一些初始化代碼。最後,ROM BIOS 讀取磁盤上的第一個扇區並將這個扇區的內存裝入內存。

2。預引導

假定硬盤是系統的啓動磁盤。硬盤的第一扇區稱爲主引導記錄(MBR, MASTER BOOTRECORD)。MBR 的長度爲512字節。可分爲兩部分:第一部分爲引導(PRE-BOOT)區,佔了446個字節;第二部分爲分區表(PARTITION PABLE),共有66個字節,記錄硬盤的分區信息。預引導區的作用之一是找到標記爲活動(ACTIVE)的分區,並將活動分區的引導區讀入內存。

如果用軟盤啓動計算機,ROM BIOS 讀入的是軟盤的引導區,既軟盤的第一個扇區。

3。核心映像裝入

在LINUX系統中,人們通常把LILO(LINUX LOADER)放在MBR或某個分區的超級塊(SUPERBLOCK)中。假定LILO在MBR中,讀取MBR後,LILO就會被首先執行。此時,屏幕上出現“BOOT:”字樣,接下來的工作是裝入LINUX核心映像。如果LILO安裝在某個分區的超級塊中,通常還會有一個管理開機的程序,這個管理開機的程序負責讀取LILO,進而進行核心映像的裝入工作。

4。核心啓動

核心裝入完畢後,CPU的控制權就交給了核心啓動代碼。此時,核心首先進行硬件的檢測和設備驅動程序的初始化,然後運行INIT。INIT 是LINUX核心啓動的第一個用戶進程,其進程號爲1,是系統其它用戶進程的祖先。

5。系統初始化

INIT進程負責進行一系列系統初始化程序和腳本文件,/ETC/INITTAB中包含了INIT所做的所有工作。

6。等待用戶登錄

系統初始化完畢後,INIT 切換到多用戶模式,併爲每一個虛擬控制檯和川行終端啓動一個GETTY進程。GETTY進程負責接受和檢驗用戶的登錄要求。

至此,LINUX系統的啓動工作全部完成。不同核心版本的LINUX 的啓動過程有一定的差異,不同發行版本的LINUX 的啓動也可能稍有不同,但基本過程是類似的。另外,在“BOOT:”後,利用“LINUX SINGLE”命令可以迫使LINUX進入單用戶模式,除不要求用戶登錄和不啓動虛擬終端以外,啓動過程的其它部分也基本類似。

©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  <j
  第一部分 背景知識簡介 4
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  )QtD>A
  幾乎所有編寫代碼的人都有這種體會:如今在計算機這個行業中,許多技術不是你不懂,而是你不知道。所以,在分析之前有些背景知識是必須要知道的。 )C
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  zg"y'9
  一. 硬盤結構簡介 o,l
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  8;
  1. 硬盤參數釋疑 1R+A
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  p#^
  到目前爲止, 人們常說的硬盤參數還是古老的 CHS (Cylinder/Head/Sector)參數. 那麼爲什麼要使用這些參數, 它們的意義是什麼? 它們的取值範圍是什麼? '
  很久以前, 硬盤的容量還非常小的時候, 人們採用與軟盤類似的結構生產硬盤,也就是硬盤盤片的每一條磁道都具有相同的扇區數,由此產生了所謂的3D參數 (Disk Geometry)。既磁頭數(Heads), 柱面數(Cylinders), 扇區數(Sectors),以及相應的尋址方式。 !/
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  $
  其中: #
  磁頭數(Heads) 表示硬盤總共有幾個磁頭,也就是有幾面盤片, 最大爲 255 (用 8 個二進制位存儲); ZZP92
  柱面數(Cylinders) 表示硬盤每一面盤片上有幾條磁道, 最大爲 1023(用 10 個二進制位存儲); a[iRd"
  扇區數(Sectors) 表示每一條磁道上有幾個扇區, 最大爲 63 (用 6個二進制位存儲); L~&p
  每個扇區一般是 512個字節(理論上講這不是必須的, 但好象都取此值)。 RZ<4
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  qiA5
  據此,磁盤最大容量爲: X
  255 * 1023 * 63 * 512 / 1048576 = 8024 MB ( 1M = 1048576 Bytes ) =$[sP
  或硬盤廠商常用的單位: %eq!
  255 * 1023 * 63 * 512 / 1000000 = 8414 MB ( 1M = 1000000 Bytes ) /-
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  !N;.
  在 CHS 尋址方式中, 磁頭, 柱面, 扇區的取值範圍分別爲 0 到 Heads - 1,0 到 Cylinders - 1, 1 到 Sectors (注意是從 1 開始)。 XY!
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  ~
  2. 基本 Int 13H 調用簡介 &+KR
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  L6()OE
  BIOS Int 13H調用是 BIOS 提供的磁盤基本輸入輸出中斷調用, 它可以完成磁盤(包括硬盤和軟盤)的復位, 讀/寫, 校驗, 定位, 診斷, 格式化等功能。它使用的就是 CHS 尋址方式, 因此最大隻能訪問 8 GB 左右的硬盤 ( 本文中如不作特殊說明, 均以 1M = 1048576 字節爲單位). Z]mo]
  而更不幸的是,標準的IDE接口容許256個扇區/磁道、65536個柱面及16個磁頭。它自己本身可以存取 137438953472(128 GB),但是加上BIOS方面63個扇區與1024個柱面的限制後,就只剩528482304(1024*16*63 = 504MB)可以定址得到,這就是所謂標準IDE硬盤只認前504MB問題。 h
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  ]r
  3. 現代硬盤結構簡介 <D,
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  Tg (
  在老式硬盤中, 由於每個磁道的扇區數相等 (與軟盤一樣), 所以外道的記錄密度要遠低於內道, 因此會浪費很多磁盤空間。爲了解決這一問題, 進一步提高硬盤容量, 人們改用等密度結構生產硬盤, 也就是說, 外圈磁道的扇區比內圈磁道多。採用這種結構後, 硬盤不再具有實際的3D參數, 尋址方式也改爲線性尋址, 即以扇區爲單位進行尋址。 j
  爲了與使用3D尋址的老軟件兼容 (如使用BIOS Int13H接口的軟件), 在硬盤控制器內部安裝了一個地址翻譯器, 由它負責將老式3D參數翻譯成新的線性參數。這也是爲什麼現在硬盤的3D參數可以有多種選擇的原因 (不同的工作模式對應不同的3D參數, 如 LBA, LARGE, NORMAL)。 qk)Fwn
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  !#AD:)
  4. 擴展 Int 13H 簡介 e[|-
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  @-F0
  雖然現代硬盤都已經採用了線性尋址, 但是由於基本 Int 13H 的制約, 使用 BIOS Int 13H 接口的程序, 如 DOS 等還是隻能訪問 8 G 以內的硬盤空間。爲了打破這一限制, Microsoft 等幾家公司制定了擴展 Int 13H 標準(Extended Int13H,詳見附錄A), 採用線性尋址方式存取硬盤,所以突破了 8 G 的限制,而且還加入了對可拆卸介質 (如活動硬盤) 的支持。 ey^
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  3*WW
  二. Boot Sector 結構簡介 b7p@:I
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  BR_
  1. Boot Sector 的組成 6Nz
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  BhAI/
  Boot Sector 也就是硬盤的第一個扇區, 它由 MBR (Master Boot Record),DPT (Disk Partition Table) 和 Boot Record ID(Magic Number) 三部分組成。 *B hz
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  7P$aE
  MBR 又稱作主引導記錄,佔用 Boot Sector 的前 446 個字節 ( 0 to 0x1BD ),包含了硬盤的一系列參數和一段系統主引導程序。引導程序主要是用來在系統硬件自檢完後負責從活動分區中裝載並運行系統引導程序(引導操作系統)。它的最後一條執行語句是一條JMP指令,跳到操作系統的引導程序去。這裏往往是引導型病毒的注入點,也是各種多系統引導程序的注入點。但是由於引導程序本身完成的功能比較簡單,所以我們完全可以判斷該引導程序的合法性(比如看JMP指令的合法性),因而也易於修復。象命令fdisk/mbr可以修復MBR和KV300這類軟件可以查殺任意類型的引導型病毒,就是這個道理。 09
  DPT 即主分區表,佔用 64 個字節 (0x1BE to 0x1FD),記錄了磁盤的基本分區信息。主分區表分爲四個分區項, 每項 16 字節, 分別記錄了每個主分區的信息(因此最多可以有四個主分區)。 )R
  Boot Record ID 即引導區標記,佔用兩個字節 (0x1FE and 0x1FF), 對於合法引導區, 它等於 0xAA55, 這是判別引導區是否合法的標誌. >#B[E%
  Boot Sector 的具體結構如下圖所示: D'a
的論壇。  W?9G
  2. 主分區表的結構 n#u6/
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  4M}
  主分區表由四個分區項構成, 每一項的結構如下: t&fB,}
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  ~Y@Qct
  BYTE State : 分區狀態, 0 = 未激活, 0x80 = 激活 (注意此項) cB;("%
  BYTE StartHead : 分區起始磁頭號 -M~U[
  WORD StartSC : 分區起始扇區和柱面號, 低字節的低6位爲扇區號,高2位爲柱面號的第 9,10 位, 高字節 爲柱面號的低 8 位 ual
  BYTE Type : 分區類型, 如 0x0B = FAT32, 0x83 = Linux 等, 00 表示此項未用 C~
  BYTE EndHead : 分區結束磁頭號 (C'";,
  WORD EndSC : 分區結束扇區和柱面號, 定義同前 S".
  DWORD Relative : 在線性尋址方式下的分區相對扇區地址 (對於基本分區即爲絕對地址) 0o.$
  DWORD Sectors : 分區大小 (總扇區數) R'""S
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  ,(
  注意:在 DOS / Windows 系統下, 基本分區必須以柱面爲單位劃分( Sectors * Heads 個扇區), 如對於 CHS 爲 764/255/63 的硬盤, 分區的最小尺寸爲 255 * 63 * 512 / 1048576 = 7.844 MB。 mqc
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  AU
  3. 擴展分區簡介 wnP
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  `
  由於主分區表中只能分四個分區, 有時無法滿足需求, 因此設計了一種擴展分區格式。 基本上說, 擴展分區的信息是以鏈表形式存放的, 但也有一些特別的地方。 h
  首先,主分區表中要有一個基本擴展分區項, 所有擴展分區都隸屬於它,也就是說其他所有擴展分區的空間都必須包括在這個基本擴展分區中。 對於DOS / Windows 來說, 擴展分區的類型爲 0x05。 z6gSG
  除基本擴展分區以外的其他所有擴展分區則以鏈表的形式級聯存放, 後一個擴展分區的數據項記錄在前一個擴展分區的分區表中, 但兩個擴展分區的空間並不重疊。 YS
  擴展分區類似於一個完整的硬盤, 必須進一步分區才能使用。但每個擴展分區中只能存在一個其他分區, 此分區在 DOS/Windows 環境中即爲邏輯盤。因此每一個擴展分區的分區表 (同樣存儲在擴展分區的第一個扇區中)中最多只能有兩個分區數據項(包括下一個擴展分區的數據項)。 9e3
  擴展分區和邏輯盤的示意圖如下: gP<@n
 

。  Rq.!E
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  X
  三. 系統啓動過程簡介 +P!
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  VE'd8~
  系統啓動過程主要由一下幾步組成(以硬盤啓動爲例): @
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  .!c
  1. 開機; B'2'
  2. BIOS 加電或按reset鍵後都要進行系統復位,復位後指令地址爲 0ffff:fff0,這個地方只有一條JMP指令, 跳轉到系統自檢 ( Power On Self Test -- POST )程序處; c*97(o
  3. 系統自檢完成後,將硬盤的第一個扇區 (0頭0道1扇區, 也就是Boot Sector)讀入內存地址 0000:7c00 處; <
  4. 檢查 (WORD) 0000:7dfe 是否等於 0xaa55, 若不等於則轉去嘗試其他啓動介質, 如果沒有其他啓動介質 則顯示 "No ROM BASIC" 然後死機; (a+1V
  5. 跳轉到 0000:7c00 處執行 MBR 中的程序; f`SL/t
  6. MBR程序 首先將自己複製到 0000:0600 處, 然後繼續執行; n/O
  7. 在主分區表中搜索標誌爲活動的分區,如果沒有發現活動分區或有不止一個活動分區, 則轉停止; ckuH
  8. 將活動分區的第一個扇區讀入內存地址 0000:7c00 處; $z(v
  9. 檢查 (WORD) 0000:7dfe 是否等於 0xaa55, 若不等於則 顯示 "Missing Operating System" 然後停止, 或嘗 試軟盤啓動或; Rr
  10. 跳轉到 0000:7c00 處繼續執行特定系統的啓動程序; M_f>(]
  11. 啓動系統... PS'V/
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  ;Kj=
  以上步驟中 2,3,4,5 步是由 BIOS 的引導程序完成. 6,7,8,9,10步由MBR中的引導程序完成. 7>h
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  1Oi9I
  一般多系統引導程序 (如 SmartFDISK, BootStar, PQBoot 等)都是將標準主引導記錄替換成自己的引導程序, 在運行系統啓動程序之前讓用戶選擇要啓動的分區。 ?{{]"
  而某些系統自帶的多系統引導程序 (如 lilo, NT Loader 等)則可以將自己的引導程序放在系統所處分區的第一個扇區中, 在 Linux中即爲 SuperBlock (其實 SuperBlock 是兩個扇區)。 q;X
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  1*n
  注:以上各步驟中使用的是標準 MBR, 其他多系統引導程序的引導過程可能與此不同。 'p
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  OsU/
  下面簡要說明一下系統復位後的指令地址0ffff:fff0(物理地址0x0fffffff0): w
  在實地址模式下,內存有兩個保留區域:系統初始化區和中斷向量表區。地址0x00000~0x003ff 是爲中斷向量保留的,256個可能的中斷,每一個保留4字節的跳轉向量;地址0xfffffff0~0xffffffff是爲系 統初始化保留的,此處一般只有一條JMP指令,跳到系統初始引導程序。 Y
  系統復位後,cs = 0x0f000、eip = 0x0000fff0,而系統初始引導程序安排在 0x0ffff0000~0x0ffffffff, 一般爲ROM固件,使初始引導程序工作於內存實際地址空間以外的另一存儲段中。此區域的16~31位都 應爲1,cs及eip的初值已保證地址線的16~19位爲1,而20~31位,即地址線的高12位,則須由硬件強制置 1,這由一個標誌觸發器在系統每次復位時置位實現觸發。而由於段間轉移指令要重新裝入cs寄存器, 因此,每當執行段間轉移指令時,此標誌觸發器復位,以後,再次訪問時,不再向高12位地址線提供“1”信號,程序從此正常地工作於前1MB的地址空間。 suuy:
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  &Gh
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  /7BZ
  第二部分 硬盤MBR主引導代碼分析 "z#3D
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  [BY_&?
  一.程序流程 )MlM
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  ZTSU
  (引導扇區是指硬盤相應分區的第一個扇區,是和操作系統有關的,操作系統的引導是由它來完成的;而MBR主引導程序並不負責引導操作系統,MBR是和操作系統無關的,他的任務是把控制權轉交給操作系統的引導程序.) iXA[JD
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  }p
  1 將程序代碼由0:7C00H移動到0:0600H(注,BIOS把MBR放在0:7C00H處) gN5j
  2 搜索可引導分區,即80H標誌 ;B?X
  成功:goto 3 B
  失敗:跳入ROM BASIC x7<FzZ
  無效分區表:goto 5 33
  3 讀引導扇區 *sv-Rf
  失敗:goto 5 9VE-H>
  成功:goto 4 <
  4 驗證引導扇區最後是否爲55AAH LqDO
  失敗:goto 5 6xXw
  成功:goto 6 ?
  5 打印錯誤進入無窮循環 }uTa
  6 跳到0:7C00H進行下一步啓動工作 IW$/Ei
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  f
  二.代碼註釋 ;<R
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  $
  下面將用彙編語言寫出這一段代碼,並進行說明。 c$RF
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  V
;MBR.ASM V>'
; MASM MBR _T
; LINK MBR _
; EXE2BIN MBR B:C~@L
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  1|
.MODEL tiny e7fz
.CODE ~ae8
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  _+(&.
  ;設置寄存器及堆棧值 (Y
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  ]yD:K
org 0 k2
Head: /Y(x
Start: 1kv5
cli ©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  `W+(k
xor ax,ax C'
mov ss,ax CRH]M
mov sp,7C00H ;ss:sp=0:7C00H Lz)Z
mov si,sp U58l
push ax ]|B
pop es `IPRud
push ax 84p{p
pop ds ;es=ds=0 ^SH
sti ©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  $
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  )`"
  ;將程序代碼由0:7C00H移動到0:0600H處 :+
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  _s?
cld ©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  j>Zl
mov di,600H - $R
mov cx,100H ;100H Words=512 Bytes,即一個扇區大小 ?L"*c@
repne movsw X
db 0EAH ;這個是FAR JUMP的機器碼 0&0&<p
dw offset Continue+600H, 0000H ;這個是跳轉目的地址,即0:061DH )N51
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  >,j
  ;搜索可引導分區 $bw
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  x|>m
Continue: wQ7a.B
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  Nazsn
mov si,600H+1BEH ;si指向分區表 e
mov bl,4 ;四個分區 l
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  g_5
FindBoot: /f)U
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  R2m5
cmp byte ptr[si],80H bMN,5X
je SaveRec ;讀扇區位置 w
cmp byte ptr[si],0 -r
jne Invaild ;無效分區 >}=Q
add si,10H Ydm si
dec bl I<,
jnz FindBoot p
int 18H ;進入ROM BASIC 5z
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  B'
  ;讀取引導分區的扇區,柱面號 A
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  x~
SaveRec: WO/e|^
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  "|fH
mov dx,[si] rh
mov cx,[si+2] tW(sxb
mov bp,si $4
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  e
  ;檢查其餘分區表 Z)
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  40Wx*/
FindNext: .
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  "mkss
add si,10H >FZ.u
dec bl VAw}'
jz SetRead 4i-Nfo
cmp byte ptr[si],0 ;是否存在非法分區 S+V
je FindNext .
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  @
Invaild: `:H{Ha
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  Ry/h
mov si,offset ErrMsg1+600H q3nL
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  %/
  ;字符串輸出子程序 T`r'54
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  G#Oy
PrintStr: ?|M
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  2J6
lodsb QlW%n6
cmp al,0 wH+I
je DeadLock X
push si s,hsl
mov bx,7 x
mov ah,0EH ;輸出字符 VI`D|
int 10H j/0
pop si 6V
jmp short PrintStr ;下一字符 &H@9/
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  n]T
DeadLock: /+NSTg
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  C"r"
jmp short DeadLock ;無窮循環,也可以寫成jmp $ s|K
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  Y
  ;讀引導扇區 &Zyl
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  v]OH9B
SetRead: *"Qc
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  de
mov di,5 ;讀取次數 43kDA
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  28;5
ReadBoot: nuPJ
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  1bY
mov bx,7C00H 5UX
mov ax,201H s
push di A8;[+
int 13H ;cx,dx已經在SaveRec處得到 4>x
pop di 2
jnc GoBoot ;成功則啓動 n;}
xor ax,ax q.
int 13H ;reset驅動器,然後再讀取 Ij<F
dec di +bz2
jnz ReadBoot l
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  uAE$d
mov si,offset ErrMsg2+600H "WklW
jmp short PrintStr 失敗輸出信息,並進入無窮循環 b#gr/
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  Vb{9S
  ;檢查讀入的引導扇區 e{
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  /InY>R
GoBoot: ]M!0"
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  [u{Cc
mov si,offsetErrMsg3+600H iy
mov di,7C00H+1FEH _4
cmp word ptr[di],0AA55H @;0+9
jne PrintStr ;非AA55標誌則輸出錯誤信息 ZM
mov si,bp ;si指向可啓動分區 Vw
db 0EAH,0,7CH,0,0 ;跳轉至0:7C00H h;.k
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  s,o/ZE
ErrMsg1 db 'Invaild partition table',0 _
ErrMsg2 db 'Error loading operating system',0 P}$
ErrMsg3 db 'Missing operating system',0 x>
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  x0
Tail: W1q7IF
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  c, .H#
FillNum equ 1BEH-(Tail-Head) ;計算填0數目 ]
db FillNum dup(0) NK1?
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  u
  ;四個分區表項數據,跟分區情況有關,詳細含義另解 /
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  .7
PartTable db 80H,1,1,0,4,4,0D1H,2,11H,0,0,0,0FEH,0FFH,0,0 TJK9
db 0,0,0C1H,3,5,4,0D1H,0FEH,0FFH,0FFH,0,0,0ACH,53H,0,0 NRd{q
db 20H dup(0) bu
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  T
ID dw 0AA55H tMxNL
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  T6|Ex
end start &tHA
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  H@U[
;如果開始試用org 600H,那麼訪問數據時就不必加上600H,如mov si,offset haTtz
ErrMsg2+600H [
;可寫爲mov si,offset ErrMsg2,這時就不能用exe2bin得到數據,必須試用debug 3y
;debug mbr.exe CBQ!xv
;-nmbr.bin @Y{EwZ
;-rcx 200 Hv
;-wcs:600 1)-
;-q ?d@
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  =a{!mj
  在硬盤的第一個扇區上保存着分區信息,即主分區表,共有四項,讀取分區表必須使用bios的int 13h,一般使用debug就可以了: k2r
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  T!S}TU
debug .IzL
-a ©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  GIzc
xxxx:0100 mov ax,201 n
mov bx,200 []xPW
mov cx,1 cU6
mov dx,80 ;如果是第二個硬盤則是81... ,!-L.
int 13 nl*p B
int 20 FD
xxxx:???? #M@H
-g=100 jWDAWp
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  vXlS
  這時xxxx:0200開始的512字節就是分區表所在的扇區,前面一部分爲MBR,在debug中用-d3be l40就可以看到64字節的分區表信息,16個字節爲一項,用-e命令就可以修改,改完後可以重新寫回去,只要把前面代碼中的mov ax,201改爲mov ax,301即可,或者直接把102處的2改成3,比如: 9eS
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  gDGj.
-e 102 Ga
xxxx:0102 02.3 sV8
-g=100 ,bM
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  _?
  這樣就寫回去了,不過修改硬盤的第一個扇區須非常謹慎。 gN
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  }0c
  下面說一下分區表項的具體意義,取其中一項舉個例子: $qLn?,
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  G5"
  80 01 01 00 0B 3F FF 00 3F 00-00 00 81 4F 2F 00 ^,O
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  mg6pT
  1 (80)引導標誌,80代表可引導,00代表不可引導,一般必須且只能有一個分區表項的引導標誌爲 80,除非你自己修改MBR
  2 (01)分區開始磁頭 2;+
  3,4 (01 00)=(0,1)分區開始柱面和扇區(後面後詳解) ;i
  5 (0B)分區類型(後面有詳解) I#T
  6 (3F)=(63)分區結束磁頭 /
  7,8 (FF 00)=(768,63)分區結束柱面和扇區(同上) }
  9-12 (3F 00 00 00)=(63)此分區前扇區總數,即相對扇區數 ~
  13-16 (81 4F 2F 00)=(002F4F81H=3100545)此分區扇區總數 r/B1c
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  $P
  柱面和扇區共用兩個字節表示,而柱面號爲10位,最大1023,扇區號爲6位,最大63,具體各位分佈如下圖: t
           扇區號 O
         _____|____ J%STiZ
          |   | MBK:)#
  ( 7 6 5 4 3 2 1 0 ) ( 7 6 5 4 3 2 1 0 ) uT
   |__|         |___________| =2b/
    |___________________| G!n]
         | S
        柱面號 #wOg.B
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  1Q+
  關於分區類型,常見的有: Ac]v
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  "@9W x
  00 未用,Unused _-gXa>
  01 DOS-12(FAT 12) k8'L
  02 XENIX 8uVz
  04 DOS-16(FAT 16)(分區<32M的,應該已沒有了) ,D
  05 EXTEND(DOS擴展分區) t?)RP
  06 BIGDOS(>32M)(這個纔是現在常說的FAT 16) s)51Q
  07 HPFS(OS/2)(NTFS也是這個標記,好像是) '
  0B FAT 32 1sS~
  0F 這個一時不確定 y5uoEh
  50 DM OGe|w
  63 386/ix(unix) kmDe
  64 NET286(Novell) 9v
  65 NET386(Novell) 4<r
  82 Linux swap -V".c
  83 Linux native @Y
  FF BBT(UNIX Bad Block Table) 7C!{
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  1|8z
  下面有幾個算式用來計算分區參數: k{Qc(L
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  Of#Ig
  1)第一分區參數 }Jn
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  ?T<qs
  扇區總數=(結束柱面+1)*磁頭數*每柱面扇區數-相對扇區數,例如:3100545=(768+1)*64*63-63 x~
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  v}[H65
  2)其它分區參數 1
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  sr!
  扇區總數=(結束柱面-起始柱面+1)*磁頭數*每柱面扇區數,如下例: Pb/
  00 00 C1 01 05 3F FF FD C0 4F-2F 00 C0 90 0F 00 X!|
  000F90C0H=1020096,(FF FD)=(1021,63),(C1 01)=(769,1),1020096=(1021-769+1)*64*63 ok
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  B
  3)第一分區相對扇區=每柱面扇區數 a{DJM
  其它分區相對扇區=上一分區相對扇區+上一分區扇區總數 Rp
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  8T]6
  擴展分區信息是一個鏈狀結構,在刪除分區時,把前面的分區刪掉會導致後面的分區也找不到,原因就在於此,我們從主分區表中取出擴展分區項進行一下分析,如下: +1j~5
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  30YI`
  00 00 01 C0 05 FE BF 6E C0 10-2F 00 EF A6 69 00 #
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  eUp
  由此我們可以得到數據: /
  開始磁頭:00  8/g
  開始柱面扇區:01 C0=(192,1) Ot%o
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  g/Ty
  用debug V{'j
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  o8
  debug &`<s|
  -a100 &i?
  xxxx:0100 mov ax,201 E0St
  mov bx,200 `-DDz
  mov cx,c001 ;開始柱面扇區號 >
  mov dx,80 ;dh中爲開始磁頭號,這裏爲0 zzU^(E
  int 13 CO/8P
  int 20 ^F/|o
  xxxx:???? K&p6%
  -g=100 /
  -d3be l10 V(TA=
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  .0'
  讀出的扇區中有兩個16字節的分區表項和最後的一個55AA標誌,這兩個分區表項爲: 5MBd
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  ^4c|
  00 01 01 C0 06 FE 7F 97 3F 00-00 00 99 F2 34 00 WT/
  00 00 41 98 05 FE BF 6E D8 F2-34 00 17 B4 34 00 `s~
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  }n
  第一個分區類型爲6,其實這是第一個邏輯分區,含義和主分區表項相同 X-q/Q-
  第二個分區類型爲5,這其實是指向下一個擴展分區表的 &pTz
  從這裏我們可以得到: Jxi
  開始磁頭:0 xNN
  開始柱面扇區:41 98=(408,1) 0Y$z]
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  :.pV
  繼續用debug讀出(mov cx,9841)得到 $ag
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  b
  00 01 41 98 06 FE BF 6E 3F 00-00 00 D8 B3 34 00 Bs:|,
©OldLinux論壇 -- 有關早期Linux內核代碼發展的論壇。  @h<
  只有一個表項,是第二個邏輯盤,而且是邏輯盤鏈的最後一個。 tm
  可以看到,主分區表是非常重要的,所以除了小心操作外,還應當進行備份,最安全的備份方式就是用筆抄下來,當然,每次重新進行分區後還應當及時更新。從前面可以看出,分區表裏最重要的還是柱面號,其它比如磁頭號都是0或者1或者最大值,扇區號都是1或63(最大值),扇區總數什麼的也都能算出來,所以分區時最好把各分區的柱面號記下來,這樣一旦分區信息被破壞就可以進行恢復了。 />:k
  如果主分區表不幸丟失或者邏輯分區鏈被破壞,那麼只要從硬盤上找出還存在的分區信息,就有可能部分恢復分區信息,甚至全部可以恢復,不過這樣的麻煩大家還是應儘量避免。 `Y6
  在Linux裏有一種方法可以恢復主引導扇區(包括主分區表),用如下的命令: C!8V
  dd if=/boot/boot.NNNN of=/dev/hda bs=512 count=1 t
  其中:boot.NNNN 是我們在安裝Linux之前整個主引導扇區的備份,NNNN是分區的主次設備號;bs(buffer size)是指重寫的字節數。如只是爲了修復主引導記錄MBR(比如,想把LILO卸載掉),而不是恢復整個主引導扇區,則用如下的命令: rNb^]
  dd if=/boot/boot.NNNN of=/dev/hda bs=446 count=1 ay
  只把主引導扇區的備份文件boot.NNNN的前446個字節重寫入主引導扇區。 9L]st
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章