掌握QEMU虚拟化技术:搭建ARM64+Linux调试环境实战指南

简介: 掌握QEMU虚拟化技术:搭建ARM64+Linux调试环境实战指南

环境

主机ubuntu版本: 20.04

qemu模拟处理器:ARM64

Linux内核版本:https://www.kernel.org/ 最新版

step1:安装编译工具链

sudo apt-get install gcc-aarch64-linux-gnu
sudo apt-get install libncurses5-dev  build-essential git bison flex libssl-dev

查看版本号

leon@leon:~/work$ aarch64-linux-gnu-gcc -v
Using built-in specs.
COLLECT_GCC=aarch64-linux-gnu-gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc-cross/aarch64-linux-gnu/9/lto-wrapper
Target: aarch64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 9.3.0-10ubuntu1' --with-bugurl=file:///usr/share/doc/gcc-9/README.Bugs --enable-languages=c,ada,c++,go,d,fortran,objc,obj-c++,gm2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-9 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-libquadmath --disable-libquadmath-support --enable-plugin --enable-default-pie --with-system-zlib --without-target-system-zlib --enable-libpth-m2 --enable-multiarch --enable-fix-cortex-a53-843419 --disable-werror --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=aarch64-linux-gnu --program-prefix=aarch64-linux-gnu- --includedir=/usr/aarch64-linux-gnu/include
Thread model: posix
gcc version 9.3.0 (Ubuntu 9.3.0-10ubuntu1)

step2:安装qemu

2.1ubuntu仓库安装

sudo apt-get install qemu-system-arm

查看版本:

leon@leon:~/work$ qemu-system-aarch64 --version
QEMU emulator version 4.2.1 (Debian 1:4.2-3ubuntu6.16)
Copyright (c) 2003-2019 Fabrice Bellard and the QEMU Project developers
leon@leon:~/work$

从源码安装

wget https://download.qemu.org/qemu-4.1.0.tar.xz
tar xvJf qemu-4.1.0.tar.xz
cd qemu-4.1.0/
./configure 
make  -j 8
sudo make install
qemu-system-aarch64   --version

step3:制作根文件系统rootfs

3.1 下载busybox源码:

官网:http://busybox.net/downloads/下载最新版本即可,这里

tar jxvf busybox-1.33.1.tar.bz2

3.2 配置busybox

指定编译工具

export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-

打开静态库编译选项

make menuconfig
Settings --->
 [*] Build static binary (no shared libs)

如果报错:

<command-line>: fatal error: curses.h: No such file or directory
compilation terminated.

安装ncurses库

sudo apt-get install libncurses5-dev libncursesw5-dev

PS:编译过程报错的话,把相应项去掉即可;

编译完成,在busybox生成_install目录

【文章福利】小编推荐自己的Linux内核技术交流群:【 865977150】整理了一些个人觉得比较好的学习书籍、视频资料共享在群文件里面,有需要的可以自行添加哦!!!

3.4 补充rootfs目录结构

(1) 根目录添加etc、dev和lib目录

etc目录:

leon@leon:~/work/Linux/busybox-1.33.1/_install$ ls
bin  linuxrc  sbin  usr
leon@leon:~/work/Linux/busybox-1.33.1/_install$ mkdir etc dev lib
leon@leon:~/work/Linux/busybox-1.33.1/_install$ ls
bin  dev  etc  lib  linuxrc  sbin  usr
leon@leon:~/work/Linux/busybox-1.33.1/_install$

在etc分别创建文件:

leon@leon:~/work/Linux/busybox-1.33.1/_install/etc$  cat profile 
#!/bin/sh
export HOSTNAME=myQEMU
export USER=root
export HOME=/home
export PS1="[$USER@$HOSTNAME \W]\# "
PATH=/bin:/sbin:/usr/bin:/usr/sbin
LD_LIBRARY_PATH=/lib:/usr/lib:$LD_LIBRARY_PATH
export PATH LD_LIBRARY_PATH


leon@leon:~/work/Linux/busybox-1.33.1/_install/etc$ cat fstab 
#device  mount-point    type     options   dump   fsck order
proc /proc proc defaults 0 0
tmpfs /tmp tmpfs defaults 0 0
sysfs /sys sysfs defaults 0 0
tmpfs /dev tmpfs defaults 0 0
debugfs /sys/kernel/debug debugfs defaults 0 0
kmod_mount /mnt 9p trans=virtio 0 0


leon@leon:~/work/Linux/busybox-1.33.1/_install/etc$ cat inittab 
::sysinit:/etc/init.d/rcS
::respawn:-/bin/sh
::askfirst:-/bin/sh
::ctrlaltdel:/bin/umount -a -r

指定挂载的文件系统

leon@leon:~/work/Linux/busybox-1.33.1/_install/etc/init.d$ cat rcS 
mkdir -p /sys
mkdir -p /tmp
mkdir -p /proc
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
leon@leon:~/work/Linux/busybox-1.33.1/_install/etc/init.d$

dev目录:

leon@leon:~/work/Linux/busybox-1.33.1/_install/dev$ sudo mknod console c 5 1
leon@leon:~/work/Linux/busybox-1.33.1/_install/dev$ sudo mknod null c 1 3
leon@leon:~/work/Linux/busybox-1.33.1/_install/dev$

lib目录:拷贝lib库,支持动态编译的应用程序运行

leon@leon:~/work/Linux/busybox-1.33.1/_install/lib$ cp /usr/aarch64-linux-gnu/lib/*.so*  -a .
leon@leon:~/work/Linux/busybox-1.33.1/_install/lib$ ls
ld-2.31.so               libdl-2.31.so     libnsl.so              libnss_nisplus-2.31.so  libSegFault.so
ld-linux-aarch64.so.1    libdl.so          libnsl.so.1            libnss_nisplus.so       libstdc++.so.6
libanl-2.31.so           libdl.so.2        libnss_compat-2.31.so  libnss_nisplus.so.2     libstdc++.so.6.0.28
libanl.so                libgcc_s.so.1     libnss_compat.so       libnss_nis.so           libthread_db-1.0.so
libanl.so.1              libgomp.so.1      libnss_compat.so.2     libnss_nis.so.2         libthread_db.so
libasan.so.5             libgomp.so.1.0.0  libnss_dns-2.31.so     libpcprofile.so         libthread_db.so.1
libasan.so.5.0.0         libitm.so.1       libnss_dns.so          libpthread-2.31.so      libtsan.so.0
libatomic.so.1           libitm.so.1.0.0   libnss_dns.so.2        libpthread.so           libtsan.so.0.0.0
libatomic.so.1.2.0       liblsan.so.0      libnss_files-2.31.so   libpthread.so.0         libubsan.so.1
libBrokenLocale-2.31.so  liblsan.so.0.0.0  libnss_files.so        libresolv-2.31.so       libubsan.so.1.0.0
libBrokenLocale.so       libm-2.31.so      libnss_files.so.2      libresolv.so            libutil-2.31.so
libBrokenLocale.so.1     libmemusage.so    libnss_hesiod-2.31.so  libresolv.so.2          libutil.so
libc-2.31.so             libm.so           libnss_hesiod.so       librt-2.31.so           libutil.so.1
libc.so                  libm.so.6         libnss_hesiod.so.2     librt.so
libc.so.6                libnsl-2.31.so    libnss_nis-2.31.so     librt.so.1
leon@leon:~/work/Linux/busybox-1.33.1/_install/lib$

step4 编译内核

(1)下载代码:

#我从torvalds的仓库fork了一个分支,方便自己添加注释笔记
git clone https://github.com/luteresa/linux.git

(2) 指定编译工具:

export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-

配置内核:这里采用ARM公司提供的Versatile Express开发平台模拟;

sudo cp ../busybox-1.33.1/_install/  ./_install_arm64 -a
cp arch/arm/configs/vexpress_defconfig  .config
make menuconfig

添加hotplug支持:

Device Drivers                                                                                                 
    -> Generic Driver Options                                                                                             
        -> Support for uevent helper                                                                                                                
            (/sbin/hotplug) path to uevent helper

添加initramfs的支持:

General setup --->
    [*]Initial RAM filesystem and RAM disk(initramfs/initrd) 
    support(_install_arm64) Initramfs souce file(s)

内核页分别配置为

Kernel Features  --->
    Page size(4KB)  --->
    Virtual address space size(48-bit)--->

编译:

make all -j8

在内核根目录下添加共享目录

mkdir kmodules

启动Linux:

qemu-system-aarch64 -machine virt -cpu cortex-a57 -machine type=virt -m 1024 -smp 4 -kernel arch/arm64/boot/Image --append "rdinit=/linuxrc root=/dev/vda rw console=ttyAMA0 loglevel=8"  -nographic --fsdev local,id=kmod_dev,path=$PWD/kmodules,security_model=none -device virtio-9p-device,fsdev=kmod_dev,mount_tag=kmod_mount
  • cpu指定模拟的cpu为 cortex-a57
  • m 1024 指定内存大小为1G
  • smp4指定模拟的系统为4核处理器
  • kernel指定启动的内核镜像
  • append指定传递的命令行参数

后面的选项指定共享目录已经使用的9P协议。

如果报类似错:

qemu-system-aarch64: rom check and register reset failed

大概率是qemu版本问题,换个版本,可以从源码直接编译;经测试

ubuntu18.04用qemu-4.1.0可以正常工作;

ubuntu20.04用apt安装即可;

wget https://download.qemu.org/qemu-4.1.0.tar.xz
tar xvJf qemu-4.1.0.tar.xz
cd qemu-4.1.0
./configure
make -j 8
编译完安装:
sudo make install   
默认编译支持很多个平台

报错:

mount: mounting debugfs on /sys/kernel/debug failed: No such file or directory

内核配置加上CONFIG_DEBUG_FS=y :

Kernel hacking  ---> 
     Generic Kernel Debugging Instruments  --->  
         [*] Debug Filesystem

step5: 使用模拟磁盘

上述initramfs的方式,将根文件系统打包到内核源码,运行时都是在内存中,可以操作,但系统重启就会丢失,下面用模拟磁盘方式挂载根文件系统。制作磁盘文件:

dd if=/dev/zero of=rootfs_ext4.img bs=1M count=1024
mkfs.ext4 rootfs_ext4.img
mkdir -p tmpfs
sudo mount  -t ext4 rootfs_ext4.img  tmpfs/ -o loop
sudo cp -af _install_arm64/* tmpfs/
sudo umount  tmpfs
chmod 777 rootfs_ext4.img

rootfs_ext4.img就是即将用来挂载的磁盘,再次启动内核:

qemu-system-aarch64 -machine virt -cpu cortex-a57 -machine type=virt -m 1024 -smp 4 -kernel arch/arm64/boot/Image --append "noinitrd root=/dev/vda rw console=ttyAMA0 loglevel=8"  -nographic -drive if=none,file=rootfs_ext4.img,id=hd0 -device virtio-blk-device,drive=hd0 --fsdev local,id=kmod_dev,path=$PWD/kmodules,security_model=none -device virtio-9p-device,fsdev=kmod_dev,mount_tag=kmod_mount

传递给内核的命令行参数变化了,添加了noinitrd选项,这样就会挂载我们自己的模拟磁盘。

[root@myQEMU ]# df -mh
Filesystem                Size      Used Available Use% Mounted on
/dev/root               975.9M     12.8M    895.9M   1% /
tmpfs                   496.1M         0    496.1M   0% /tmp
tmpfs                   496.1M         0    496.1M   0% /dev
kmod_mount              981.8G     32.5G    899.4G   3% /mnt
[root@myQEMU ]#

这样在文件系统的读写,就会存在磁盘,重启后,数据不会丢失。

step6: qemu与主机ubuntu文件共享

前面已经支持了主机和qemu上的系统共享目录,这个目录就是kmodules目录:通过mount可以查看被挂载到了qemu上的系统的/mnt目录下

[root@myQEMU mnt]# mount
/dev/root on / type ext4 (rw,relatime)
proc on /proc type proc (rw,relatime)
tmpfs on /tmp type tmpfs (rw,relatime)
sysfs on /sys type sysfs (rw,relatime)
tmpfs on /dev type tmpfs (rw,relatime)
kmod_mount on /mnt type 9p (rw,sync,dirsync,relatime,access=client,trans=virtio)
devpts on /dev/pts type devpts (rw,relatime,mode=600,ptmxmode=000)

在ubuntu的kmodules目录,创建一个文件hello.c

#include <stdio.h>
int main(int argc, char **argv)
{
        printf("Hello World,Qemu!\n");
        return 0;
}

在qemu查看

[root@myQEMU mnt]# cat /proc/cpuinfo  > cpu.txt
[root@myQEMU mnt]# cat hello.c
#include <stdio.h>
int main(int argc, char **argv)
{ 
        printf("Hello World,Qemu!\n"); 
        return 0; 
}
random: fast init done
[root@myQEMU mnt]#

在ubuntu编译

aarch64-linux-gnu-gcc  hello.c

在qemu运行

[root@myQEMU mnt]# ./a.out 
Hello World,Qemu!
[root@myQEMU mnt]#

可见,在共享目录,可以执行含动态库的应用程序;

step7:内核模块测试:

Makefile文件

step7:内核模块测试:
Makefile文件,

驱动测试文件module_test.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
   static int __init module_test_init(void)
{
        printk("---module_test_init\n");
        return 0;
}    
  static void __exit module_test_exit(void)
{
        printk("---module_test_exit\n");
}
module_init(module_test_init);
module_exit(module_test_exit);
MODULE_LICENSE("GPL");

在ubuntu上交叉编译

leon@leon:~/work/Linux/linux/kmodules$ make
make -C ~/work/Linux/linux M=/home/leon/work/Linux/linux/kmodules modules
make[1]: Entering directory '/home/leon/work/Linux/linux'
  CC [M]  /home/leon/work/Linux/linux/kmodules/module_test.o
  MODPOST /home/leon/work/Linux/linux/kmodules/Module.symvers
  CC [M]  /home/leon/work/Linux/linux/kmodules/module_test.mod.o
  LD [M]  /home/leon/work/Linux/linux/kmodules/module_test.ko
make[1]: Leaving directory '/home/leon/work/Linux/linux'
leon@leon:~/work/Linux/linux/kmodules$

在qemu加载驱动

[root@myQEMU mnt]# insmod module_test.ko 
---module_test_init.
[root@myQEMU mnt]# rmmod module_test
---module_test_exit.
[root@myQEMU mnt]#

可见,内核模块正常运行了。

step8:gdb调试

安装arm-none-eabi-gdb

https://askubuntu.com/questions/1243252/how-to-install-arm-none-eabi-gdb-on-ubuntu-20-04-lts-focal-fossa

sudo apt-get install gdb-multiarch

qemu模拟端启动内核:

qemu-system-aarch64 -machine virt -cpu cortex-a57 -machine type=virt -m 1024 -smp 4 -kernel arch/arm64/boot/Image --append "rdinit=/linuxrc root=/dev/vda rw console=ttyAMA0 loglevel=8"  -nographic --fsdev local,id=kmod_dev,path=$PWD/k_shared,security_model=none -device virtio-9p-device,fsdev=kmod_dev,mount_tag=kmod_mount  -S  -s

X86启动gdb:

$ gdb-multiarch --tui vmlinux


(gdb)target remote localhost:1234  //通过1234端口远程连接到qemu端
(gdb)b start_kernel                //在内核的start_kernel设置断点
(gdb)c

gdb接管linux内核,在断点处(start_kernel)暂停,即可通过gdb来调试内核。

用Eclipse可视化环境,单步调试Linux内核

目的:通过可视化环境,单步调试linux内核

开发环境:ubuntu20.04

安装java环境

Eclipse运行依赖jave环境;

sudo apt install openjdk-13-jre

安装Eclipse-CDT

官网:http://www.eclipse.org/cdt/

配置Eclipse-CDT

(1)创建工程

在Eclipse菜单选择File->New->Project,选择Makefile Project with Exiting Code,即可创建一个新工程;

(2)配置调选项

选择Eclipse菜单中的Run->Debug Configurations, 弹出Debug configurations

(3)debugger选项卡,配置

Debugger:gdbserver

GDB debugger:gdb-multiarch

进行单步调试Linux内核

主机端运行qemu仿真系统

qemu-system-aarch64 -machine virt -cpu cortex-a57 -machine type=virt -m 1024 -smp 1 -kernel arch/arm64/boot/Image --append "rdinit=/linuxrc root=/dev/vda rw console=ttyAMA0 loglevel=8"  -nographic --fsdev local,id=kmod_dev,path=$PWD/k_shared,security_model=none -device virtio-9p-device,fsdev=kmod_dev,mount_tag=kmod_mount -S -s

启动Eclipse,选择Run->Debug History, 在Debugger Console选项卡输入file vmlinux导入调试文件的符号表;输入set architecture aarch64命令,设定GDB支持ARM64架构:

配置完成,便可在Eclipse可视化环境,进行linux内核单步调试;

Eclipse比GDB命令直观很多,可以方便查看参数,局部变量,寄存器值等;

精品文章推荐阅读:

相关实践学习
阿里云图数据库GDB入门与应用
图数据库(Graph Database,简称GDB)是一种支持Property Graph图模型、用于处理高度连接数据查询与存储的实时、可靠的在线数据库服务。它支持Apache TinkerPop Gremlin查询语言,可以帮您快速构建基于高度连接的数据集的应用程序。GDB非常适合社交网络、欺诈检测、推荐引擎、实时图谱、网络/IT运营这类高度互连数据集的场景。 GDB由阿里云自主研发,具备如下优势: 标准图查询语言:支持属性图,高度兼容Gremlin图查询语言。 高度优化的自研引擎:高度优化的自研图计算层和存储层,云盘多副本保障数据超高可靠,支持ACID事务。 服务高可用:支持高可用实例,节点故障迅速转移,保障业务连续性。 易运维:提供备份恢复、自动升级、监控告警、故障切换等丰富的运维功能,大幅降低运维成本。 产品主页:https://www.aliyun.com/product/gdb
相关文章
|
10天前
|
缓存 NoSQL Linux
Linux调试
本文介绍了Linux调试、性能分析和追踪的培训资料,涵盖调试、性能分析和追踪的基础知识及常用工具。
164 6
Linux调试
|
1月前
|
存储 分布式计算 分布式数据库
云计算和虚拟化技术
云计算是指把计算资源、存储资源、网络资源、应用软件等集合起来,采用虚拟化技术,将这些资源池化,组成资源共享池,共享池即是“云”。
140 64
|
20天前
|
存储 持续交付 虚拟化
|
2月前
|
KVM 虚拟化
虚拟化技术概述及KVM环境安装
关于虚拟化技术概述及KVM环境安装的教程,涵盖了虚拟化的定义、分类、管理工具,以及KVM的系统需求、安装步骤和使用指南。
76 11
虚拟化技术概述及KVM环境安装
|
1月前
|
安全 KVM 虚拟化
OpenEuler 中配置 KVM 虚拟化环境指南
本文档详细介绍了如何在OpenEuler系统中配置和管理KVM虚拟化环境,包括环境准备、组件安装、虚拟机安装及管理命令等,适合初学者和有经验的用户。内容覆盖了从桥接网卡配置到虚拟机的安装与管理,以及常见问题的解决方法,帮助用户高效利用虚拟化技术。
|
1月前
|
监控 安全 物联网
|
3月前
|
NoSQL Linux C语言
Linux GDB 调试
Linux GDB 调试
62 10
|
3月前
|
Devops 虚拟化 Docker
DevOps 中的标准虚拟化技术
【8月更文挑战第27天】
58 5
|
3月前
|
NoSQL Linux C语言
嵌入式GDB调试Linux C程序或交叉编译(开发板)
【8月更文挑战第24天】本文档介绍了如何在嵌入式环境下使用GDB调试Linux C程序及进行交叉编译。调试步骤包括:编译程序时加入`-g`选项以生成调试信息;启动GDB并加载程序;设置断点;运行程序至断点;单步执行代码;查看变量值;继续执行或退出GDB。对于交叉编译,需安装对应架构的交叉编译工具链,配置编译环境,使用工具链编译程序,并将程序传输到开发板进行调试。过程中可能遇到工具链不匹配等问题,需针对性解决。
|
3月前
|
Ubuntu Linux
内核实验(四):Qemu调试Linux内核,实现NFS挂载
本文介绍了在Qemu虚拟机中配置NFS挂载的过程,包括服务端的NFS服务器安装、配置和启动,客户端的DHCP脚本添加和开机脚本修改,以及在Qemu中挂载NFS、测试连通性和解决挂载失败的方法。
189 0
内核实验(四):Qemu调试Linux内核,实现NFS挂载