环境:ubuntu 20.04
准备工作
1 2 $ sudo apt-get install qemu qemu-system-arm gcc-aarch64-linux-gnu gdb-multiarch $ sudo apt install flex bison libssl-dev
编译内核
下载 Linux 源码:kernel 各版本下载
下载完内核之后,如放在 ~/linux-5.10
目录下:
1 2 3 4 $ cd linux-5.10 $ mkdir out $ make O=out ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- defconfig $ make O=out ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- Image -j8
制作 rootfs
我使用 busybox 制作 rootfs。这里使用 busybox-1.36.1.tar.bz2
作为演示:
注:如果是编译平台是 Linux 6.8+ 版本内核,需要打上 https://gitweb.gentoo.org/repo/gentoo.git/tree/sys-apps/busybox/files/busybox-1.36.1-kernel-6.8.patch?id=d8ad860a1ed9aa92adaa7dcf1c3fc78d0e2f80ce patch,否则会出现 https://github.com/gramineproject/gramine/issues/1909 问题(error: ‘TCA_CBQ_RATE’ undeclared):
1 2 3 4 5 $ wget https://busybox.net/downloads/busybox-1.36.1.tar.bz2 $ tar -xvf busybox-1.36.1.tar.bz2 $ cd busybox-1.36.1/ $ make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- defconfig $ make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- menuconfig
修改:
-> Settings
[*] Build static binary (no shared libs)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 $ make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j8 && make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- install $ make _install $ cd _install $ sudo mkdir dev etc mnt $ sudo mkdir -p etc/init.d/ $ sudo vim etc/init.d/rcS mkdir /procmkdir /tmpmkdir /sys/bin/mount -a mkdir -p /dev/ptsmount -t devpts devpts /dev/pts $ sudo chmod 777 etc/init.d/rcS $ sudo vim etc/fstab proc /proc proc defaults 0 0 tmpfs /tmp tmpfs defaults 0 0 sysfs /sys sysfs defaults 0 0 devtmpfs /dev devtmpfs defaults 0 0 debugfs /sys/kernel/debug debugfs defaults 0 0 $ sudo vim etc/inittab ::sysinit:/etc/init.d/rcS ::respawn:-/bin/sh ::askfirst:-/bin/sh ::ctrlaltdel:/bin/umount -a -r $ find . | cpio -o -H newc | gzip > rootfs.cpio.gz
启动内核
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 $ cd ~ $ mkdir arm64 $ cd arm64 $ cp ~/busybox-1.36.1/_install/rootfs.cpio.gz . $ cp ~/linux-5.10/out/arch/arm64/boot/Image . $ cat qemu.sh qemu-system-aarch64 \ -machine virt,virtualization=true ,gic-version=3 \ -nographic \ -m size=8192M \ -cpu cortex-a72 \ -smp 2 \ -kernel Image \ -initrd rootfs.cpio.gz \ --append "console=ttyAMA0 rdinit=/linuxrc crashkernel=128M" $ chmod a+x qemu.sh $ ./qemu.sh
正常启动会输出 kernel log,并按回车键可以到控制台,类似:
qemu 和 host 文件共享
参考 https://tjtech.me/transfer-files-between-qemu-and-host-via-mount.html
有时需要从 qemu 中将文件传到 host 中,或者需要将 host 中的文件传到 qemu 中:
1 2 3 4 $ dd if =/dev/zero of=disk.img bs=1M count=1024 $ mkfs.ext4 disk.img $ mkdir disk_mnt //建个挂载点 $ sudo mount disk.img disk_mnt/
可以将需要传送到 qemu 的文件放到 disk_mnt 下了,然后 sudo umount disk_mnt
。
修改 qemu.sh :
1 2 3 4 5 6 7 8 9 10 11 #!/usr/bin/sh qemu-system-aarch64 \ -machine virt,virtualization=true ,gic-version=3 \ -nographic \ -m size=8192M \ -cpu cortex-a72 \ -smp 2 \ -kernel Image \ -initrd rootfs.cpio.gz \ -drive file=disk.img,format=raw,if =virtio \ --append "console=ttyAMA0 rdinit=/linuxrc crashkernel=128M"
这个块设备我还没研究过,在我这里启动 qemu 之后的块设备是 /dev/vda
:
1 2 3 4 5 6 7 / Disk /dev/vda: 1024 MB, 1073741824 bytes, 2097152 sectors 2080 cylinders, 16 heads, 63 sectors/track Units: sectors of 1 * 512 = 512 bytes Disk /dev/vda doesn't contain a valid partition table / #
那么就可以开机时将 /dev/vda 挂载起来,如修改 etc/init.d/rcS
文件,增加一行:
1 mount -t ext4 /dev/vda /mnt/
启动 qemu 之后可以将需要传送到 host 的文件拷贝到 /mnt
目录下,host 想要查看则需要重新 mount。
内核调试
修改 qemu.sh 脚本,增加 -s -S
参数:
1 2 3 4 5 6 7 8 9 10 11 12 #!/usr/bin/sh qemu-system-aarch64 \ -machine virt,virtualization=true ,gic-version=3 \ -s -S \ -nographic \ -m size=8192M \ -cpu cortex-a72 \ -smp 2 \ -kernel Image \ -initrd rootfs.cpio.gz \ -drive file=disk.img,format=raw,if =virtio \ --append "console=ttyAMA0 rdinit=/linuxrc crashkernel=128M"
-s
是 -gdb tcp::1234
简写。
-S
是在冻结 CPU。
在另外一个终端,运行 gdb
调试:
1 2 3 $ cd ~/arm64 $ cp ~/linux-5.10/out/vmlinux . $ gdb-multiarch vmlinux -ex "target remote :1234"