基于QEMU的内核调试环境搭建
基于QEMU的内核调试环境搭建
背景
在没有相应的实体硬件,只有自己的一台开发机器,在学习内核或是调试破坏性大的内核功能时,又不想用庞大麻烦的Virtualbox或VMware,只是简单单纯地调试下内核,QEMU是个不错的选择。
关于QEMU
QEMU is a generic and open source machine emulator and virtualizer.
When used as a machine emulator, QEMU can run OSes and programs made for one machine (e.g. an ARM board) on a different machine (e.g. your own PC). By using dynamic translation, it achieves very good performance.
When used as a virtualizer, QEMU achieves near native performance by executing the guest code directly >on the host CPU. QEMU supports virtualization when executing under the Xen hypervisor or using the >KVM kernel module in Linux. When using KVM, QEMU can virtualize x86, server and embedded PowerPC, >64-bit POWER, S390, 32-bit and 64-bit ARM, and MIPS guests.
这里虚拟一个与Host 相同架构的x86机器,也可以使用其他架构,比如 riscv等,只是需要相应交叉编译,使用相应的qemu程序,后面会写一篇基于RISC-V的。
环境
- OS:Ubuntu20.04 x86_x64
- QEMU: 6.2.0
安装QEMU
使用如下命令安装QEMU:
$ sudo apt install qemu qemu-system qemu-kvm
准备文件系统
根据自己的需求大致有4种方式做文件系统:
- 使用自己的程序: 适用于不需要任何核外环境的情况
- 使用busybox:适用于只需要最基本的核外环境,最小文件系统,无需做较多修改定制的情况
- 使用buildroot:适用核外环境需要做较多修改定制的情况
- 使用现成发行版的镜像:适用于需要最完善的核外环境的情况
这里主要测试了前3种情况。
使用自己的程序
如果不需要任何核外,可以直接使用一个最简单的while死循环的helloworld
程序替代:
hello.c
:
#include <stdio.h>
#include <unistd.h>
int main()
{
printf("Hello World!\n");
fflush(stdout);
while(1) {sleep(1);}
return 0;
}
编译并制作rootfs:
#编译 helloworld
$ gcc --static -o hello hello.c
#打包ramfs作为rootfs
$ echo hello | cpio -o --format=newc > hello.rootfs
使用busybox
这里需要一个相对完善点的核外环境,所以基于busybox
制作一个最基本的文件系统。
获取busybox
源码:
$ git clone https://gitee.com/mirrors/busyboxsource.git
配置:
$ make menuconfig
#select `Settings -> Build Options -> Build static binary (no shared libs)`
编译:
$ make -j8
$ make install
会在源码目录生成编译输出文件夹_install
使用buildroot
首先安装一些依赖包,报错需要安装啥就安装啥
#拉取源码
$ git clone https://gitlab.com/buildroot.org/buildroot.git
#配置
$ make menuconfig
#根据自己的需要修改配置
# select `Target Options -> Target Architecture -> x86_64`
# select `Filesystem images -> ext2/3/4 root file system -> ext4`
#编译
make
生成的rootfs就在:output/images/rootfs.ext4
制作基于ramfs的rootfs
$ cd rootfs
$ find . -print0 | cpio --null -ov --format=newc | gzip -9 > ../initramfs.cpio.gz
制作磁盘文件的rootfs
这里需要持久化,所以使用磁盘文件做文件系统。
如果不需要持久化,只需要打包成 ramfs 即可。
生成img文件
#生成 qemu image
$ qemu-img create rootfs.img 1g
#格式化为 ext4
$ mkfs.ext4 rootfs.img
添加和修改img内容
添加和修改 rootfs 内容,这里以 busybox 为例,其他的类似:
$ mkdir rootfs
$ sudo mount -o loop rootfs.img rootfs
#这里以 busybox 为例,其他的类似
$ sudo cp -rfd ../busyboxsource/_install/* .
$ sudo mkdir proc sys dev etc etc/init.d
新建一个简单的init的 rc 文件(etc/init.d/rcS
),内容如下:
#!/bin/sh
mount -t proc none /proc
mount -t sysfs none /sys
/sbin/mdev -s
修改 rc 文件权限:
$ sudo chmod +x etc/init.d/rcS
卸载img
$ sudo umount rootfs
至此,文件系统就准备完成。
准备内核
这里拉取的是清华源的 stable 分支:
$ git clone https://mirrors.tuna.tsinghua.edu.cn/git/linux-stable.git
按照正常流程配置编译:
#配置
$ make x86_64_defconfig
#根据自己的需要修改配置
$ make menuconfig
#编译
$ make -j8
最终会在arch/x86_64/boot/bzImage
目录生成我们需要的内核
运行
#基于ramfs运行qemu
$ qemu-system-x86_64 \
-kernel ./bzImage \
-initrd ./hello.rootfs \
-append "root=/dev/ram rdinit=/hello console=ttyS0" \
# -initrd ./initramfs.cpio.gz \
# -append "console=ttyS0" \
-nographic
#基于磁盘文件运行qemu
$ qemu-system-x86_64 \
-kernel ./bzImage \
-drive file=rootfs.img,format=raw \
# -drive file=rootfs.ext4,format=raw \
-append "root=/dev/sda rw console=ttyS0" \
-nographic
退出 qemu 使用组合键: Ctrl+A X
至此基于QEMU的内核调试环境简单搭建就完成了。