使用qemu来学习linux内核是一个很好的方法,效率很高,不需要开发板。可以快速编译运行。
本文编译一个最新的longterm内核6.12,arch为arm64。qemu系统为:qemu-system-aarch64。
$ sudo dnf install qemu-system-aarch64
我自己使用crosstool-ng 1.26编译了一个arm64的工具链。网上也有很多编译好的工具链,比如buildroot有,可以直接使用。
编译内核需要指定两个环境变量:下面我的编译指令,我省略了这两个环境变量的定义:
ARCH=arm64 CROSS_COMPILE=/home/yuan/toolchain/crosstool-mt7981/bin/aarch64-linux-gnu-
第一种,使用默认配置,然后合并arch/arm64/configs/virt.config,virt.config会删除很多其它的配置,加快编译时间。
$ make defconfig
$ make virt.config
第二种,使用tinyconfig,这个是最小的内核。
$ make tinyconfig
编译:
$ make Image -j12
运行命令如下:
$ qemu-system-aarch64 -machine virt -cpu cortex-a53 -kernel arch/arm64/boot/Image -nographic
-machine 指定模拟的设备类型。
使用help可以查看所有的设备类型。
$ qemu-system-aarch64 -machine help
这里我们使用virt,这个虚拟设备类型,virt是qemu自己标准的虚拟设备,而且指向最新版本的virt设备:
virt-9.0 QEMU 9.0 ARM Virtual Machine
virt QEMU 9.1 ARM Virtual Machine (alias of virt-9.1)
virt-9.1 QEMU 9.1 ARM Virtual Machine
-cpu 指定cpu的类型,
使用help可以查看所有的cpu。
$ qemu-system-aarch64 -machine virt -cpu help
cpu默认为32位的cortex-a15,这里我们指定64位架构的cortex-a53
-kernel 指定内核的路径,这里我们使用Image。
-nographic,指定不使用图形界面,这样qemu会使用当前终端作为输入输出。
tinyconfig编译非常快,几十秒就可以完成内核的编译,编译后的内核也非常小,
没压缩的Image为2.4M,压缩后的Image.lzma仅有655KB
$ ls arch/arm64/boot/ -l
-rwxr-xr-x. 1 yuan yuan 2539528 Dec 17 18:06 Image
-rw-r--r--. 1 yuan yuan 670951 Dec 17 18:06 Image.lzma
但是运行会没有输出,我们需要开启一些virt的配置,因为tinyconfig没有开启驱动和printk等支持。
qemu在启动kernel的时候,会自动加载它内置的dtb。可以使用dumpdtb指令存储dtb到本地文件,如:
$ qemu-system-aarch64 -machine virt,dumpdtb=virt.dtb -cpu cortex-a53
然后我们可以转成dts看看:
$ dtc -i dtb virt.dtb > virt.dts
可以得到串口设备的dts,virt使用的是PL011串口。
pl011@9000000 {
clock-names = "uartclk", "apb_pclk";
clocks = <0x8000 0x8000>;
interrupts = <0x00 0x01 0x04>;
reg = <0x00 0x9000000 0x00 0x1000>;
compatible = "arm,pl011", "arm,primecell";
};
aliases {
serial0 = "/pl011@9000000";
};
因此我们开启下面几个配置项即可:
CONFIG_PRINTK
CONFIG_TTY
CONFIG_SERIAL_AMBA_PL011
CONFIG_SERIAL_AMBA_PL011_CONSOLE
编译后启动,可以看到内核输出了启动信息:
$ qemu-system-aarch64 -machine virt -cpu cortex-a53 -kernel arch/arm64/boot/Image -nographic
Booting Linux on physical CPU 0x0000000000 [0x410fd034]
Linux version 6.12.1+ (yuan@fedora) (aarch64-linux-gnu-gcc (crosstool-NG 1.26.0) 13.2.0, GNU ld (crosstool-NG 1.26.0) 2.40) #5 SMP Tue Dec 17 18:0
6:05 CST 2024
random: crng init done
Machine model: linux,dummy-virt
Zone ranges:
Normal [mem 0x0000000040000000-0x0000000047ffffff]
Movable zone start for each node
Early memory node ranges
node 0: [mem 0x0000000040000000-0x0000000047ffffff]
Initmem setup node 0 [mem 0x0000000040000000-0x0000000047ffffff]
psci: probing for conduit method from DT.
psci: PSCIv1.1 detected in firmware.
psci: Using standard PSCI v0.2 function IDs
psci: Trusted OS migration not required
psci: SMC Calling Convention v1.0
percpu: Embedded 16 pages/cpu s35488 r0 d30048 u65536
Detected VIPT I-cache on CPU0
CPU features: kernel page table isolation disabled by kernel configuration
alternatives: applying boot alternatives
Kernel command line:
Dentry cache hash table entries: 16384 (order: 5, 131072 bytes, linear)
Inode-cache hash table entries: 8192 (order: 4, 65536 bytes, linear)
由于没有rootfs,所以内核启动后会panic。后续移植一个initramfs,这样就可以快速的调试和学习内核了。按CTRL+a,然后再按x,可以退出qemu。
参考:
generic virtual platform (virt). https://www.qemu.org/docs/master/system/arm/virt.html