使用bochs和grub建立可引导硬盘镜像

bochs,发音同box,是我非常喜欢的虚拟机,灵活易用方便配置,功能极强,用来调试Linux内核是非常合适的。这篇博文主要讲解如何建立硬盘镜像,并且将grub安装上去,最后的结果就是bochs启动后能进入到grub引导界面。下一篇博客再讲解如何在镜像上安装Linux内核。

实验环境: CentOS 6.4 x86


硬盘基础知识

硬盘的专业术语中有:柱面,磁头,扇区,每磁道扇区数这几个概念。

  1. 每个盘片有两个磁头(Head),分别位于两面上,从0开始依次编号,一般来说硬盘有8个盘片,共计16个磁头,编号0-15。
  2. 每个盘面都有很多同心圆轨道称为磁道(Tracks),所有盘面上半径相同的磁道正好堆叠成一个圆柱面,称为柱面(Cylinders),它和磁道编号相同,都是自外向内从0开始编号。
  3. 每个磁道上划分出很多弧段,称为扇区(Sectors),每个磁道上的扇区都从1开始编号,每个扇区512字节,一个磁道一般有63个扇区,编号1-63。
  4. 磁盘定位可以使用CHS方法,即柱面、磁头、扇区。比如MBR的CHS=0/0/1,也就是第0柱面,第0磁头,第1扇区。
  5. 还有一种定位方式叫LBA,这是一种给所有扇区从0开始标号的定位方法,假设我们的硬盘有16个磁头,每个磁道有63个扇区,则从CHS到LBA的换算公式为:LBA = (C × 16 + H) × 63 + (S - 1)。注意硬盘写数据以柱面为单位,因为所有的磁头都固定到一起,只能同时压向同一柱面,所以先写满第C柱面第H磁头所在的63个扇区,再去写第C柱面第H+1磁头所在的63个扇区,直到第C柱面所有磁头下的扇区都满了,再去写C+1号柱面,如果不注意这一点,就看不懂CHS到LBA的转换公式,LBA是按照扇区写入的先后顺序给扇区编的号。
  6. CHS=0/0/1所定位的扇区称作 Master Boot Record(MBR)。MBR里面前446字节是引导程序,后面紧跟64字节的分区表,再加上2字节的引导标志正好是512字节。每个分区的分区表表项为16字节,整个分区表可以记录四个分区的信息,所以一块硬盘只能有4个主分区,每个分区可以格式化为不同的文件系统。
  7. 每个分区内部的第1个扇区(相对该分区的起始来讲),叫做 Volume Boot Record(VBR),这个概念使用较少。

制作空白硬盘镜像

我们制作一个50M左右的镜像,16个磁头,每磁道扇区数63,即一个柱面有16x63x512=516096个字节,所以大约需要100个柱面。

dd if=/dev/zero of=hd.img bs=516096c count=100

if是输入,of是输出,516096c后面的字母c表示单位是1,即516096个字节,写入100次。
至此,空白镜像制作完毕。

初始化磁盘并分区

fdisk -u -C100 -H16 -S63 hd.img

指定好柱面数、磁头数、每磁道扇区数。
这个命令的操作如下:

注意下面的输出是在 CentOS 6.4 环境下运行的结果,不同系统因为 fdisk 版本不同会略有差异,请自行调整。

Device contains neither a valid DOS partition table, nor Sun, SGI or OSF disklabel
Building a new DOS disklabel with disk identifier 0x49b37849.
Changes will remain in memory only, until you decide to write them.

After that, of course, the previous content won't be recoverable.
Warning: invalid flag 0x0000 of partition table 4 will be corrected by w(rite)

WARNING: DOS-compatible mode is deprecated. It's strongly recommended to switch off the mode (command 'c').

Command (m for help): c  #关闭DOS Compatibility flag,不关闭也没事
DOS Compatibility flag is not set

Command (m for help): n  #新建分区
Command action
	e   extended
	p   primary partition (1-4)
	p	#类型为主分区
Partition number (1-4): 1  #该分区是第一个分区,实际上我们就建立这一个分区
First sector (1-100799, default 1): 63  #注意这里的扇区编号采用了LBA寻址,对应于CHS=0/1/1,可以看到第一个分区并没有从CHS=0/0/2开始,而是空下了一整个磁道从下一个磁头所在磁道开始,这其实是在进行磁道对齐(历史原因造成的)
Last sector, +sectors or +size{K,M,G} (63-100799, default 100799):  #直接回车,让该分区直至硬盘最后的扇区结束
Using default value 100799

Command (m for help): w  #写入分区数据并退出
The partition table has been altered!

Syncing disks.

挂载硬盘镜像

losetup -o 32256 /dev/loop0 hd.img

注意第一分区前面空下了一个磁道,也就是32256个字节(0-32255),所以第一分区从第32256字节处开始,于是我们要用-o 32256这个参数指定挂载的起始字节。
这一步之所以不用mount是因为mount是用来挂载文件系统的,现在硬盘镜像第一分区里还没有文件系统,所以用losetup命令将硬盘的第一分区挂载到loop0设备上。

注意,如果 loop0 设备不存在,则运行 losetup -f 命令生成

格式化文件系统

mkfs.ext3 /dev/loop0

将挂到loop0上的分区格式化为ext3文件系统

挂载文件系统

现在文件系统已经建立,是时候将之挂载了

mount -t ext3 /dev/loop0 /mnt

这命令我就不解释了,很简单。

建立boot和grub目录

mkdir -p /mnt/boot/grub

将当前系统上的grub程序文件复制进去,

cp /boot/grub/stage1 /boot/grub/stage2 /boot/grub/e2fs_stage1_5 /mnt/boot/grub/

这一步你也可以自己下载grub源码编译,编译完后也会出现stage1、stage2、e2fs_stage1_5这几个文件,这是grub的核心程序,stage1待会儿会被放到MBR里,开机时BIOS会把MBR里的stage1取到内存里执行,之后stage1会取出stage2文件执行,然后是e2fs_stage1_5。

我们这里不自己编译了,直接使用宿主系统CentOS 6.4的文件。

创建grub.conf文件

cp /boot/grub/grub.conf /mnt/boot/grub/

配置文件依然借用宿主系统CentOS 6.4的。

ln -s /mnt/boot/grub/grub.conf /mnt/boot/grub/menu.lst

这个软链接如果不建立,待会儿开机进入grub时不会出现启动项选择界面

卸载文件系统

umount /mnt/

卸载硬盘分区

losetup -d /dev/loop0

最终安装grub

grub --device-map=/dev/null

运行后依次输入下面的内容敲回车。

grub> device (hd0) hd.img
grub> geometry (hd0) 100 16 63	#柱面数、磁头数、每磁道扇区数
grub> root (hd0,0)
grub> setup (hd0)
grub> quit

启动bochs

在bochs里设置好,然后启动就行了
应该会看到如下提示:

ata0 master: Generic 1234 ATA-6 Hard-Disk (  49 MBytes)

Press F12 for boot menu.

Booting from Hard Disk...
failed to read image
Press any key to enter the menu


Booting CentOS (2.6.32-358.el6.i686) in 0 seconds...
Error 15: File not found

Press any key to continue...

这界面很正常,毕竟我们只装了grub,操作系统根本不存在,它能找到文件就怪了。按下任意键,就能看到grub启动项选择界面了。因为我们的grub程序文件和配置文件全部来自于宿主系统,所以这里看到的启动项也和宿主系统一样是CentOS 6.4,只不过这个启动项所指定的内核文件不存在而已。

这篇博文就写到这里,下一篇我们将内核镜像写入硬盘镜像,这样就能启动内核了,不过要想真正运行Linux系统还是很麻烦的,因为后面还要向硬盘镜像内写入文件系统里面的主要文件,比如/bin/sh之类的。

3/11/2016 12:37:59 AM 完稿
3/12/2016 10:44:32 AM 修改错别字和句子流畅度
2017-7-3 21:31 修正错误的知识点,调整格式

Show Comments