环境搭建

以 ubuntu 系统为例

sudo apt-get install -y qemu-kvm kpartx bsdmainutils

制作启动文件

 disk.img = mbr+rootfs。创建100M启动文件,用来模拟后续的物理磁盘

dd if=/dev/zero of=./disk.img bs=1M count=100

echo "n
p
1


w
" | fdisk disk.img

通过命令hd(hexdump)命令可以查看前512字节(后面作为mbr结构)的内容:

20200206_102119_62

可以看到 disk.img 的前512字节末尾为 0x55 0xAA (存储时低位在前,高位在后,因此也就是0xAA55,表明为mbr,且为活跃状态),另从00 20 21 00 83 be 32 0c 00 08 00 00 00 00 18 03 00为第一个磁盘分区项,用于描述该分区的相关信息也在mbr中。

制作rootfs根文件系统

将 disk.img 的第一个分区格式化为ext4文件系统:

sudo losetup /dev/loop0 disk.img
sudo kpartx -av /dev/loop0
sudo mkfs.ext4 /dev/mapper/loop0p1
  • 将 disk.img 关联到/dev/loop0设备,这样linux操作系统可以将disk.img当作块设备(磁盘)来进行操作
  • 将 disk.img 的分区生成设备到/dev/mapper中,这里第一个分区即为/dev/mapper/loop0p1
  • 将 disk.img 的第一个分区格式化为ext4文件系统

挂载第一分区,开始制作rootfs根文件系统: 

sudo mkdir /mnt/rootfs
sudo mount /dev/mapper/loop0p1 /mnt/rootfs
# 这样便可以对第一个分区的文件系统进行文件目录等操作了

编译busybox

这里选择动态编译,后续的网络ping静态编译会出bug

mkdir busybox
cd busybox
wget https://busybox.net/downloads/busybox-1.29.3.tar.bz2 --no-check-certificate
tar -xjf busybox-1.29.3.tar.bz2
cd busybox-1.29.3
make menuconfig

make
make install

ldd bin/ping

因为是动态编译,需要将查看 bin 和 sbin 下的命令需要什么动态.so文件,使用 ldd 指令查看即可

20200206_103625_53

sudo mkdir /mnt/rootfs/lib
sudo cp -r /lib/i386-linux-gnu  /mnt/rootfs/lib/
sudo cp -r /lib/ld-linux.so.2  /mnt/rootfs/lib/
sudo cp -r _install/*  /mnt/rootfs/

根据上面的操作,我们已经有个rootfs根文件系统了,该rootfs根文件系统安装在第一分区

安装 grub2 bootloader 第一阶段,MBR引导

sudo grub-install --root-directory=/mnt/rootfs/ /dev/loop0
  • 将 grub2 bootloader程序安装到 disk.im g的 mbr 中(前512字节的代码内容),以及将 grub 启动过程中需要的一些驱动文件安装到根目录 rootfs下的 boot/grub 目录下,之类会报错,可以忽略

20200206_104359_53

通过查看

hd disk.img -n 512

可以看到前面的内容已经不再全是0,而且也能通过右边字符看到一些grub的描述,可以知道grub将bootloader的代码安装到了disk.img的mbr中:

20200206_105126_89

拷贝vmlinuz和initrd

告知 vmlinuz 和 initrd.img 的位置信息给 grub2:

有 mbr 的 bootloader 程序,我们也已经为磁盘 disk.img 的第一个分区划分了存储容量,并且文件系统格式为 ext4 和制作成了 rootfs 根文件系统。而 grub2 bootloader 程序是能够识别 ext4 文件系统,因此其能够知道第一个分区到底存储了什么内容,因此只需要将 vmlinuz 和 initrd.img 存放到第一分区,grub2 bootloader是有能力读取到这两个文件的。

cd /mnt/rootfs
sudo cp -r /boot/vmlinuz-3.5.0-17-generic ./boot/
sudo cp -r /boot/initrd.img-3.5.0-17-generic ./boot/
cd boot
sudo ln -svf vmlinuz-3.5.0-17-generic vmlinuz
sudo ln -svf initrd.img-3.5.0-17-generic initrd

创建其他依赖目录

cd /mnt/rootfs
sudo mkdir dev proc run etc root sys

测试grub

这样disk.img启动文件便制作完成,使用qemu启动:

qemu-system-x86_64 -m 1024M -drive format=raw,file=disk.img

20200206_112433_56

启动界面会到达 grub 命令行模式,虽然 grub 能够识别 ext4 文件系统,但是并没有告诉它具体的 vmlinuz 和 initrd.img 的路径,因此通过手动方式来告知 grub 这两个位置

其中set root是告知 grub 路径 /vmlinuz和 /initrd所在的磁盘分区,这里hd0,msdos1表示第一块磁盘的第一个分区即 disk.img 的第一个分区,set prefix是告知 grub 后续的命令和驱动的目录位置在哪,如这里的 linux 命令和 initrd 命令

最后执行启动boot即可

ls
set root=(hd0,msdos1)
set prefix=(hd0,msdos1)/boot/grub
linux /boot/vmlinuz root=/dev/sda1
initrd /boot/initrd

20200206_112550_42

grub 启动菜单 grub.cfg

cd /mnt/rootfs
sudo cat > boot/grub/grub.cfg << EOF
set timeout=5
set default=0

menuentry 'Linux, busybox, root=/dev/sda1' {
    linux /boot/vmlinuz root=/dev/sda1
    initrd /boot/initrd
}

menuentry 'Reboot' {
    reboot
}

menuentry 'Shutdown' {
    halt
}
EOF

卸载 disk.img

sudo umount /dev/mapper/loop0p1
sudo dmsetup remove /dev/mapper/loop0p1
sudo losetup -d /dev/loop0
  • 卸载 disk.img 的第一分区
  • 删除 disk.img 第一分区所生成的设备
  • 取消 disk.img 关联到/dev/loop0设备

  • 无标签
写评论...