当前位置:操作系统 > Unix/Linux >>

Linux系统的引导过程和磁盘分区信息

系统的引导过程和磁盘分区信息

  在PC机上,最初的启动由BIOS完成。当开机自检(Power-On Self Test,POST)结束时, BIOS尝试读入磁盘的第一个扇区,把它看作引导扇区。由于大多数BIOS不提供SCSI支持,若要从SCSI磁盘启动,SCSI适配器要提供他自己的 BIOS。如果什么都找不到,老的BIOS会启动内置的ROM BASIC,或直接打印“NO ROM-BASIC”。

  操作系统的启动分几步完成。由于引导扇区比较小,通常它主要任务是读入第二个loader,第二个loader再读入第三个loader,直到整个操作系统被完全读入。

  硬盘的引导区:

  代码:

  OFFSET

  0x000 JMP xx Near jump into the program code

  0x003 Disk parameters

  0x03E Program code loading the DOS kernel

  0x1FE 0xAA55 Magic number for BIOS

  可见,引导区的结构相对比较简单。它的长度总是512字节。重要的是引导区从0开始,以BIOS的0x1FE处的0xAA55结束。

  从软盘启动比较简单,因为只有一个引导扇区:第一个扇区。硬盘则困难一些,它被分成很多分区。但是,BIOS根本不管分区信息,它象对待软盘一样对待硬盘,仍读入第一个分区,叫作:master boot record。(MBR)。所以MBR也应该和上面介绍的结构一样,在MBR的最后部分,有分区表。如下图:

  代码:

  OFFSET Length

  0x000 0x1BE code loading and starting the boot sector of the active

  partitian

  0x1BE 0x010 partition1

  0x1CE 0x010 partition2

  0x1DE 0x010 partition3

  0x1EE 0x010 partition4

  0x1FE 0x0012 0xAA55 Disk parameters

  从0x1BE处(即第462字节处)开始,是一个个主分区信息。每个分区信息占16字节,结构如下:

  1 BOOT Boot flag: 0=not active ,0x80 active

  1 HD Begin:head number

  2 SEC CYL Begin:sector and cylinder number of boot sector

  1 SYS System Code:0x83 linux , 0x82 linux swap etc。

  1 HD End:head number

  2 SEC CYL End: sector and cylinder number of boot sector

  4 low byte high byte Relative sector number of start sector

  4 low byte high byte Number of sectors in the partition

  所以硬盘可以有4个主分区:primary prititions。假如它们不够用,可以设置所谓的扩展分区。扩展分区包含至少一个逻辑分区。扩展分区的第一个扇区结构类似MBR,它的分区表的第一表项对应第一个逻辑分区。如果存在第二个逻辑分区,那么分区表的第二个表项就包含了一个指针。这个指针指向第一个逻辑分区后面的一个地址,这个地址包含一个分区表,该分区表的第一表项对应第二个逻辑分区。这样就组成一个链表,从而扩展分区可以有任意多的逻辑分区。

  每一个主分区和扩展区都包含一个引导扇区。系统只能从这几个地方之一启动。BOOT标志决定哪个区被引导。

  MBR的代码要作以下的操作:

  1:确定活动分区。

  2:使用BIOS,将活跃分区的启动扇区读入。

  3:跳到启动扇区的0位置。

  MBR的空间足够完成这些工作。如上所述,每个分区理论上包含一个引导扇区,而且,存在的第二个硬盘也包含和第一个类似的结构。MBR完全可以容纳一个复杂的引导程序。即所谓的boot manager,动态的决定活动分区。Linux为我们提供了lilo及grub等工具来管理启动各启动项。

  下面这段C程序可以用来检测磁盘分区信息以验证上述理论的正确性。

  代码:

  /* marco corvi <marco_corvi@geocities.com>

  * @date

  feb 2003

  *

  * \brief Read disk partition table

  * modified by zhoulifa <zhoulifa@163.com http://zhoulifa.bokee.com

  * 周立发 Linux爱好者 Linux知识传播者 SOHO族 开发者

  */

  #include <stdio.h>

  // printf

  #include <stdlib.h>

  // exit

  #include <sys/types.h>

  #include <sys/stat.h>

  #include <fcntl.h>

  #include <errno.h>

  #include <unistd.h>

  int

  main(int argc, char ** argv )

  {

  int fd;

  unsigned char mbs[512]; // master boot sector

  unsigned char * pp;

  // partition pointer

  int head, sect, cyl;

  unsigned int sector;

  int n;

  if (argc <= 1) {

  fprintf(stderr, "Usage: %s <device>\n", argv[0] );

  exit(1);

  }

  fd = open( argv[1], O_RDONLY );

  if ( fd < 0 ) {

  fprintf(stderr, "Error: unable to open device %s\n", argv[1] );

  perror("");

  exit(1);

  }

  n = read( fd, mbs, 512);

  close(fd);

  if ( n < 512 ) {

  fprintf(stderr, "Error: short read %d\n", n );

  exit(1);

  }

  pp = mbs + 0x1BE;

  for (n=0; n<4; n++) {

  printf("PARTITION %d\n", n );

  printf("Boot flag

  %2x\n", pp[0] );

  printf("System flag %2x\n", pp[4] );

  // C/H/S as 10+8+6

  if(argc == 3)

  {

  head = pp[1];

  sect = pp[2]; sect = (sect<<2) | (pp[3]>>6);

  cyl

  = pp[3] & 0x3f;

  /*

  cyl = pp[1] >> 2;

  head = ((pp[1] & 0x03)<<6) | (pp[2]>>2);

  sect = pp[2] & 0x03;

  sect = (sect << 8) | pp[3];

  head = pp[1];

  sect = pp[3]>>6;

  sect = (sect<<8) | pp[2];

  cyl

  = pp[3] & 0x3f;

  */

  printf("Start Cylinder %d Head %d Sector %d \n", cyl, head, sect );

  head = pp[5];

  sect = pp[6]; sect = (sect<<2) | (pp[7]>>6);

  cyl

  = pp[7] & 0x3f;

  cyl = pp[5];

  printf("End

  Cylinder %d Head %d Sector %d \n", cyl, head, sect );

  }

  sector = pp[8] + (1<<8)*pp[9] + (1<<16)*pp[10] + (1<<24)*pp[11];

  printf("Sector number %u\n", sector);

  sector = pp[12] + (1<<8)*pp[13] + (1<<16)*pp[14] + (1<<24)*pp[15];

  printf("Number of sectors %u\n", sector);

  pp += 0x10;

  }

  }

  编译此程序后可以直接运行,如果没有任何参数,会从/dev/partitions文件里读取相应信息。如果有参数,则第一个参数指明要查看的设备。

  参考了 http://www.linuxdby.com/articlesdisplay.php?newsid=75 及 marco_corvi的“Linux kernel programming by example”,并在Red Hat Linux 7.2系统上验证通过。

  

上一个:RedHatLinuxTroubleshooting系统启动部分概要
下一个:Linux上shmmax参数的设置及含义

更多Unix/Linux疑问解答:
路由原理介绍
子网掩码快速算法
改变网络接口的速度和协商方式的工具miitool和ethtool
Loopback口的作用汇总
OSPF的童话
增强的ACL修改功能
三层交换机和路由器的比较
用三层交换机组建校园网
4到7层交换识别内容
SPARC中如何安装Linux系统(2)
SPARC中如何安装Linux系统(1)
用Swatch做Linux日志分析
实战多种Linux操作系统共存
浅析Linux系统帐户的管理和审计
Linux2.6对新型CPU的支持(2)
电脑通通透
玩转网络
IE/注册表
DOS/Win9x
Windows Xp
Windows 2000
Windows 2003
Windows Vista
Windows 2008
Windows7
Unix/Linux
苹果机Mac OS
windows8
安卓/Android
Windows10
如果你遇到操作系统难题:
访问www.zzzyk.com 试试
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,