看Linux驱动相关的代码, 却没有一个好的调试环境可以跟踪内核相关的调用流程。于是,想着用QEMU虚拟机来搭建一个Linux系统。花了大半天时间,终于能够启动一个简单的Linux系统了。中间踩了不少坑,找了不少资料,这里简单总结下整个过程。
以下操作都是基于Ubuntu 18.04 x86_64平台
最开始参考了如何使用QEMU跑内核,使用系统自带的QEMU工具,结果提示如下错误:
1 |
|
怀疑是QEMU的版本太低导致,于是只好又重新编译QEMU源码,最后总算大功告成。总的说来,大致要做的事情有这么几个:
- 编译Linux内核,利用busybox来生成一个小的rootfs(关于什么是rootfs,可以参考The rootfs FS)
- 编译QEMU,确保正常配置ARM64架构的虚拟环境
- 一切就绪,通过
qemu-system-aarch64
跑起来虚拟机来
编译Linux内核
交叉编译Linux内核,需要确保系统中存在必须的编译环境与工具:
1 |
|
编译成功后,会在arch/arm64/boot
下面生成内核镜像:
1 |
|
这个就是后面用于跑Linux内核的镜像文件。
编译Qemu源码
编译QEMU比较方便,先下载源码:
1 |
|
编译大概会持续十几分钟的样子,最后记得编译完成后执行make install
, 否则在最后启动虚拟机时会提示:
1 |
|
编译Busybox,制作rootfs
编译Busybox稍微麻烦一点,需要编辑配置列表,确保生成的是静态库形式的执行文件, 大概有这么几个步骤:
1 |
|
菜单配置的方式与Linux内核的配置类似,按下/
可以直接搜索你要设置的选项; 如果觉得菜单配置比较麻烦,也可以通过直接编辑生成的.config
来配置选项编译为静态的方式:
1 |
|
完成配置后,执行编译:
1 |
|
在busybox/_install
下面可以看到编译的产物。有了busybox我们就可以制作一个简单的rootfs文件系统了。对于busybox的系统来说,大致的启动顺序如下:
1 |
|
进入busybox/_install
目录可以看到当前生成的目录结构:
1 |
|
制作一个rootfs,可以按照如下几个步骤操作:
- 创建目录
1 |
|
生成启动所需的文件
- etc/inittab: 将如下内容写入到该文件
1
2
3
4
5
6
::sysinit:/etc/init.d/rcS
::respawn:-/bin/sh
::askfirst:-/bin/sh
::cttlaltdel:/bin/umount -a -r编辑完成后,修改文件权限:
chmod 0755 etc/inittab
- etc/init.d: 系统初始化脚本,可以用于创建设备以及执行文件系统挂载等操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
mkdir -p etc/init.d/
#编辑rcS文件,输入如下内容
#!/bin/sh
echo "mount pseudo sys"
mount -t proc none /proc
mount -t sysfs none /sys
echo /sbin/mdev > /proc/sys/kernel/hotplug
/sbin/mdev -s
echo "init rc done"为了确保该文件正常执行,需要修改权限
chmod 0755 etc/init.d/rcS
. 如果除了上述proc/sys
文件系统外,还有其他需要挂载的设备,可以放在etc/fstab
中:1
2
3
4
5
temps/tmp rpoc defaults 0 0
none /tmp ramfs defaults 0 0
mdev /dev ramfs defaults 0 0- 创建特殊文件节点
1
2
3
4
5
cd dev
sudo mknod console c 5 1
sudo mknod null c 1 3- 将该目录的文件打包成rootfs压缩文件
1
2
3
4
find . | cpio -o -H newc > rootfs.cpio
gzip -c rootfs.cpio > rootfs.cpio.gz
到这里,所有的准备工作就绪了,就下来可以测试下虚拟机是否正常能跑起来了.
QEMU跑起来
执行如下命令,启动Linux虚拟机(具体的参数可以通过qemu-system-aarch64 -h
查看)
1 |
|
正常启动的话,可以看到内核加载的日志以及一个虚拟的终端设备:
有了这个虚拟环境,无论是驱动开发,还是学习Linux内核都会方便很多了。
参考资料
- https://yuankun.me/posts/running-raw-linux-kernel-in-qemu/
- https://ops.tips/notes/booting-linux-on-qemu/
- https://gts3.org/2017/cross-kernel.html
- http://events17.linuxfoundation.org/sites/events/files/slides/Shuah_Khan_cross_compile_linux.pdf
- https://android.googlesource.com/platform/external/syzkaller/+/HEAD/docs/linux/setup_linux-host_qemu-vm_arm64-kernel.md
- http://nickdesaulniers.github.io/blog/2018/10/24/booting-a-custom-linux-kernel-in-qemu-and-debugging-it-with-gdb/