计算机科学家David Wheeler有一句名言:计算机科学中的任何问题都可以通过增加一个中间层来解决。这句话简洁而深刻地说明了虚拟化的思想存在于计算机科学中的各个领域。QEMU就是这种思想的一个具体实现。

系统环境

我们用neofetch看一下系统环境信息:

neofetch && uname -a|lolcat

linux4.15 arm qemu @ubuntu18.04环境搭建与bootgraph启动优化_GDB

下载QEMU以及runtime工具

sudo apt-get install qemu libncurses5-dev gcc-arm-linux-gnueabi build-essential

linux4.15 arm qemu @ubuntu18.04环境搭建与bootgraph启动优化_Linux_02

安装busybox

wget https://busybox.net/downloads/busybox-1.24.2.tar.bz2

linux4.15 arm qemu @ubuntu18.04环境搭建与bootgraph启动优化_ARM_03

编译静态busybox库:

export ARCH=arm
export CROSS_COMPILE=arm-linux-gnueabi-
make menuconfig

linux4.15 arm qemu @ubuntu18.04环境搭建与bootgraph启动优化_ARM_04

编译

make install

编译完成之后,在busybox目录下得到安装好的文件系统目录

linux4.15 arm qemu @ubuntu18.04环境搭建与bootgraph启动优化_Linux_05

下载内核,如果觉得下载过慢,可以使用axel多线程下载

axel -a -n 8 https://www.kernel.org/pub/linux/kernel/v4.x/linux-4.0.tar.gz

linux4.15 arm qemu @ubuntu18.04环境搭建与bootgraph启动优化_文件系统_06

创建文件系统:

cp -fr ../../busybox-1.24.2/_install .
cd _install/
mkdir etc/ dev/ mnt/ -p etc/init.d

linux4.15 arm qemu @ubuntu18.04环境搭建与bootgraph启动优化_GDB_07

​进入linux-4.0/_install/etc/init.d​​,创建rcS文件,并写入

mkdir -p /proc                                                                                                                                                                                          
mkdir -p /tmp
mkdir -p /sys
mkdir -p /mnt
/bin/mount -a
mkdir -p /dev/pts
mount -t devpts devpts /dev/pts
echo /sbin/mdev > /proc/sys/kernel/hotplug
mdev -s

之后,执行 chmod a+x rcS修改为可执行

linux4.15 arm qemu @ubuntu18.04环境搭建与bootgraph启动优化_GDB_08

linux4.15 arm qemu @ubuntu18.04环境搭建与bootgraph启动优化_GDB_09

 进入​​linux-4.0/_install/etc​​,创建fstab文件,并写入

linux4.15 arm qemu @ubuntu18.04环境搭建与bootgraph启动优化_Linux_10

proc /proc proc defaults 0 0
tmpfs /tmp tmpfs defaults 0 0
sysfs /sys sysfs defaults 0 0
tmpfs /tmp tmpfs defaults 0 0
debugfs /sys/kernel/debug debugfs defaults 0 0

进入​​linux-4.0/_install/etc​​,创建inittab文件,并写入

linux4.15 arm qemu @ubuntu18.04环境搭建与bootgraph启动优化_ARM_11

::sysinit:/etc/init.d/rcS
::respawn:-/bin/sh
::askfirst:-/bin/sh
::ctrlaltdel:/bin/umount -a -r

进入​​linux-4.0/_install/dev​​,在root权限下创建如下节点

linux4.15 arm qemu @ubuntu18.04环境搭建与bootgraph启动优化_ARM_12

设置编译环境:

export ARCH=arm
export CROSS_COMPILE=arm-linux-gnueabi-
make vexpress_defconfig
make menuconfig

linux4.15 arm qemu @ubuntu18.04环境搭建与bootgraph启动优化_GDB_13

配置initarmfs

linux4.15 arm qemu @ubuntu18.04环境搭建与bootgraph启动优化_linux_14

将配置好的根文件系统设置进来:

linux4.15 arm qemu @ubuntu18.04环境搭建与bootgraph启动优化_ARM_15

 设置地址空间的3G/1G划分

linux4.15 arm qemu @ubuntu18.04环境搭建与bootgraph启动优化_文件系统_16

开始编译kernel

make bzImage -j4 ARCH=arm CROSS_COMPILE=arm-linux-gnueabi-
make dtbs

linux4.15 arm qemu @ubuntu18.04环境搭建与bootgraph启动优化_Linux_17

期间遇见缺少​​inlude/linux/compiler-gcc7.h​​​时,可以将​​compiler-gcc4.h​​​重名为​​compiler-gcc7.h​​即可

之后执行 make dtbs创建device tree blob.

linux4.15 arm qemu @ubuntu18.04环境搭建与bootgraph启动优化_文件系统_18

万事具备,只欠运行了

运行QEMU模拟4核Cortex-A9

qemu-system-arm -M vexpress-a9 -m 1024M -kernel arch/arm/boot/zImage -append "rdinit=/linuxrc console=ttyAMA0 loglevel=8" -dtb arch/arm/boot/dts/vexpress-v2p-ca9.dtb -nographic

linux4.15 arm qemu @ubuntu18.04环境搭建与bootgraph启动优化_linux_19

退出qemu,直接 ctral+a X即可。

使用linux-4.15.18搭建环境重新测试,内和配置方法相同,发现linux-4.15.18仍然可以和当前的busybox匹配兼容使用,并且没有了上面的编译错误,那就用linux-4.15.18了。

linux4.15 arm qemu @ubuntu18.04环境搭建与bootgraph启动优化_文件系统_20

linux4.15 arm qemu @ubuntu18.04环境搭建与bootgraph启动优化_文件系统_21

ctrl+x A推出QEMU或者在另一个终端中输入killall qemu-system-arm退出

调试

用如下命令安装ARM GDB 

sudo apt install gcc-arm-none-eabi

linux4.15 arm qemu @ubuntu18.04环境搭建与bootgraph启动优化_Linux_22

安装完之后发现还是没有arm gdb命令,问杜娘才知道UBUNTU18.04对ARM GDB的支持比较特殊,至于怎么特殊是个long story,感兴趣的可以去查,这里不想在GDB安装上浪费时间,直接用MELIS 的裸机GDB尝试一下,感觉裸机的GDB应该也是可以的,都支持标准的GDB调试协议嘛。

又不得不祭出melis:

linux4.15 arm qemu @ubuntu18.04环境搭建与bootgraph启动优化_linux_23

 之后输入调试命令

qemu-system-arm -M vexpress-a9 -m 1024M -kernel arch/arm/boot/zImage -append "rdinit=/linuxrc console=ttyAMA0 loglevel=8" -dtb arch/arm/boot/dts/vexpress-v2p-ca9.dtb -S -s

根据命令选项,第一个-S表示CPU 停止住,第二个-s表示在1234端口等待GDB连接调试。

linux4.15 arm qemu @ubuntu18.04环境搭建与bootgraph启动优化_linux_24

 编译代DEBUG INFO的内核,默认已经打开了DEBUG INFO选项。 

linux4.15 arm qemu @ubuntu18.04环境搭建与bootgraph启动优化_linux_25

新开一个调试

$/home/caozilong/Workspace/arm-tool/gcc-arm-melis-eabi-9-2020-q2-update/bin/arm-melis-eabi-gdb -tui vmlinux
$target remote localhost:1234
$b start_kernel
$c

linux4.15 arm qemu @ubuntu18.04环境搭建与bootgraph启动优化_Linux_26

linux4.15 arm qemu @ubuntu18.04环境搭建与bootgraph启动优化_ARM_27

 果然melis也是可以的,之后,就可以愉快的展开调试了。

优化GDB的调试环境

GDB调试环境虽然已经建立,但是还不太友好,表现在每次都要重复输入连接命令,可以擦考下面这篇博客对GDB环境进行优化。

针对qemu的调试环境,我们可以创建.gdbinit文件并收入如下命令

linux4.15 arm qemu @ubuntu18.04环境搭建与bootgraph启动优化_Linux_28

arm-melis-eabi-gdb -x .gdbinit 命令进行触发。

linux4.15 arm qemu @ubuntu18.04环境搭建与bootgraph启动优化_ARM_29

使用命令 CTRL X + A进行TUI窗口的切换。

磁盘挂载

为了方便HOST机和QEMU机之间的文件传输,可以使用QEMU提供的 -sd选项将HOST机上的一个文件系统镜像文件映射为QEMU机上的文件系统的方式来实现。

首先生成文件系统镜像文件:

dd if=/dev/zero of=disk.img bs=1024 count=65536

并将其格式化为EXT4

mkfs.ext4 ./disk.img

linux4.15 arm qemu @ubuntu18.04环境搭建与bootgraph启动优化_linux_30

挂载为本地回环:

mkdir tempfs
sudo mount -o loop ./disk.img ./tempfs/
sudo cp ./a.out tempfs/
sudo umount ./tempfs

添加helloworld程序,并且为静态链接。

linux4.15 arm qemu @ubuntu18.04环境搭建与bootgraph启动优化_GDB_31

 启动,在前面QEMU启动命令的基础上,添加-sd disk.img 选项。

qemu-system-arm -M vexpress-a9 -m 1024M -kernel arch/arm/boot/zImage -append "rdinit=/linuxrc console=ttyAMA0 loglevel=8" -dtb arch/arm/boot/dts/vexpress-v2p-ca9.dtb -nographic -sd disk.img

成功启动后,我们可以看到了/dev/mmcblk0设备,它就是disk.img对应的设备。

linux4.15 arm qemu @ubuntu18.04环境搭建与bootgraph启动优化_ARM_32

输入挂载命令

mount -t ext4 /dev/mmcblk0 /mnt

出错,提示开启CONFIG_LBDAF

linux4.15 arm qemu @ubuntu18.04环境搭建与bootgraph启动优化_ARM_33

开启CONFIG_LBDAF,重新配置内核:

linux4.15 arm qemu @ubuntu18.04环境搭建与bootgraph启动优化_ARM_34

之后,就可以正常的启动测试了,可以看到helloworld正确执行。

linux4.15 arm qemu @ubuntu18.04环境搭建与bootgraph启动优化_文件系统_35

device-tree反编译

dtc -I dtb -O dts -o zilong.dts vexpress-v2p-ca9.dtb

设置开机登陆

linux4.15 arm qemu @ubuntu18.04环境搭建与bootgraph启动优化_文件系统_36

linux4.15 arm qemu @ubuntu18.04环境搭建与bootgraph启动优化_ARM_37

增加时间戳打印

qemu-system-arm -M vexpress-a9 -m 1024M -kernel arch/arm/boot/zImage -append "rdinit=/linuxrc console=ttyAMA0 loglevel=8 printk.time=1" -dtb arch/arm/boot/dts/vexpress-v2p-ca9.dtb -nographic

linux4.15 arm qemu @ubuntu18.04环境搭建与bootgraph启动优化_ARM_38

打印INIT CALL 信息

qemu-system-arm -M vexpress-a9 -m 1024M -kernel arch/arm/boot/zImage -append "rdinit=/linuxrc console=ttyAMA0 loglevel=8 printk.time=1 initcall_debug" -dtb arch/arm/boot/dts/vexpress-v2p-ca9.dtb -nographic

linux4.15 arm qemu @ubuntu18.04环境搭建与bootgraph启动优化_Linux_39

生成BOOTCHART

在前面的基础上,获取启动LOG打印,之后执行如下命令

perl bootgraph.pl dmesg.txt > boot.svg

linux4.15 arm qemu @ubuntu18.04环境搭建与bootgraph启动优化_Linux_40

生成BOOTCHART

linux4.15 arm qemu @ubuntu18.04环境搭建与bootgraph启动优化_linux_41

使用bootgraph.py

Linux 自带的bootgraph.pl不够友好,GITHUB上另外有一个类似的更好用的工具,bootgraph.py,可以得到更加丰富的信息:

​GitHub - arnoldlu/pm-graph: The Suspend/Resume project provides a tool for system developers to visualize the activity between suspend and resume, allowing them to identify inefficiencies and bottlenecks.​

linux4.15 arm qemu @ubuntu18.04环境搭建与bootgraph启动优化_linux_42

处理命令为:

sudo python ~/../caozilong/Workspace/bootchart/pm-graph-master/bootgraph.py -dmesg dmesg.txt -addlogs

命令执行后,得到如下两个输出文件:

linux4.15 arm qemu @ubuntu18.04环境搭建与bootgraph启动优化_Linux_43

用浏览器打开HTML文件:

linux4.15 arm qemu @ubuntu18.04环境搭建与bootgraph启动优化_文件系统_44


结束