QEMU运行x86_64虚拟机

命令一览

  1. sudo apt-get install -y qemu-kvm kpartx bsdmainutils
  2. dd if=/dev/zero of=./disk.img bs=1M count=100
  3. echo "n
  4. p
  5. 1
  6. w
  7. " | fdisk disk.img
  8. sudo losetup /dev/loop0 disk.img
  9. sudo kpartx -av /dev/loop0
  10. sudo mkfs.ext4 /dev/mapper/loop0p1
  11. sudo mkdir /mnt/rootfs
  12. sudo mount /dev/mapper/loop0p1 /mnt/rootfs
  13. mkdir busybox
  14. cd busybox
  15. wget https://busybox.net/downloads/busybox-1.29.3.tar.bz2 --no-check-certificate
  16. tar -xjf busybox-1.29.3.tar.bz2
  17. cd busybox-1.29.3
  18. make menuconfig
  19. make
  20. make install
  21. ldd bin/ping
  22. sudo mkdir /mnt/rootfs/lib
  23. sudo cp -r /lib/i386-linux-gnu /mnt/rootfs/lib/
  24. sudo cp -r /lib/ld-linux.so.2 /mnt/rootfs/lib/
  25. sudo cp -r _install/* /mnt/rootfs/
  26. cd /mnt/rootfs
  27. sudo cp -r /boot/vmlinuz-3.5.0-17-generic ./boot/
  28. sudo cp -r /boot/initrd.img-3.5.0-17-generic ./boot/
  29. cd boot
  30. sudo ln -svf vmlinuz-3.5.0-17-generic vmlinuz
  31. sudo ln -svf initrd.img-3.5.0-17-generic initrd
  32. cd /mnt/rootfs
  33. sudo mkdir dev proc run etc root sys
  34. sudo grub-install --root-directory=/mnt/rootfs/ /dev/loop0
  35. qemu-system-x86_64 -m 1024M -drive format=raw,file=disk.img
  36. ls
  37. set root=(hd0,msdos1)
  38. set prefix=(hd0,msdos1)/boot/grub
  39. linux /boot/vmlinuz root=/dev/sda1
  40. initrd /boot/initrd
  41. sudo umount /dev/mapper/loop0p1
  42. sudo dmsetup remove /dev/mapper/loop0p1
  43. sudo losetup -d /dev/loop0

环境搭建

Ubuntu 12.10(手头刚好在运行的直接抓来实验了,现年头都用19.10的(⊙o⊙)…)

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

制作启动文件( disk.img = mbr+rootfs)

创建100M启动文件,用来模拟后续的物理磁盘

  1. dd if=/dev/zero of=./disk.img bs=1M count=100
  2. echo "n
  3. p
  4. 1
  5. w
  6. " | 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根文件系统

制作rootfs根文件系统

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

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

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

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

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

  1. mkdir busybox
  2. cd busybox
  3. wget https://busybox.net/downloads/busybox-1.29.3.tar.bz2 --no-check-certificate
  4. tar -xjf busybox-1.29.3.tar.bz2
  5. cd busybox-1.29.3
  6. make menuconfig
  7. make
  8. make install

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

  1. ldd bin/ping

20200206_103625_53

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

20200206_103704_12

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

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

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

20200206_104359_53

通过查看

  1. 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是有能力读取到这两个文件的。

  1. cd /mnt/rootfs
  2. sudo cp -r /boot/vmlinuz-3.5.0-17-generic ./boot/
  3. sudo cp -r /boot/initrd.img-3.5.0-17-generic ./boot/
  4. cd boot
  5. sudo ln -svf vmlinuz-3.5.0-17-generic vmlinuz
  6. sudo ln -svf initrd.img-3.5.0-17-generic initrd

创建其他依赖目录

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

测试grub

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

  1. 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即可:

  1. ls
  2. set root=(hd0,msdos1)
  3. set prefix=(hd0,msdos1)/boot/grub
  4. linux /boot/vmlinuz root=/dev/sda1
  5. initrd /boot/initrd

20200206_112550_42

grub启动菜单grub.cfg

  1. cd /mnt/rootfs
  2. sudo cat > boot/grub/grub.cfg << EOF
  3. set timeout=5
  4. set default=0
  5. menuentry 'Linux, busybox, root=/dev/sda1' {
  6. linux /boot/vmlinuz root=/dev/sda1
  7. initrd /boot/initrd
  8. }
  9. menuentry 'Reboot' {
  10. reboot
  11. }
  12. menuentry 'Shutdown' {
  13. halt
  14. }
  15. EOF

最终测试

一切准备就绪,执行该启动文件测试效果:

20200206_113056_19

搞不懂这里为嘛会。。权限不够,sudo不行了??

20200206_113130_18

卸载disk.img

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

参考