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
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值