使用kvmtool运行和调试Linux内核

关注微信公众号:Linux内核拾遗

文章来源:mp.weixin.qq.com/s/M4Y92PomJ...

一、为什么选择kvmtool

在虚拟化技术领域,QEMU(Quick Emulator)无疑是应用最广泛的全能型选手。这个开源机器仿真器能够:

  • 支持x86、ARM、RISC-V等20+处理器架构。
  • 提供完整的设备模拟(网卡、显卡、声卡等)。
  • 兼容多种虚拟化方案(KVM、Xen、TCG等)。
  • 实现复杂的功能特性(实时迁移、快照管理)。

但正是这种全能性使得QEMU的代码规模超过150万行,学习其源码如同大海捞针。当我们的目标是专注学习KVM虚拟化技术的核心原理时,QEMU的复杂性反而成为了认知负担:

KVMtool(全称Linux Kernel Virtual Machine Tool)则采取了截然不同的设计思路:

c 复制代码
+---------------------+
|    KVMtool (用户态)  |
+---------------------+
|      /dev/kvm       |
+---------------------+
|   KVM内核模块        |
+---------------------+
|  硬件虚拟化支持 (VT-x) |
+---------------------+

其核心特点包括:

  • 代码精简:约1万行C代码(仅为QEMU的0.6%)。
  • 功能聚焦:仅使用KVM进行硬件辅助虚拟化。
  • 零抽象层:直接操作虚拟化扩展指令集。
  • 开发友好:代码逻辑线性可追踪。

如果只是为了学习 kvm 虚拟化技术,那么就可以尽量简化用户态管理程序。这里以开源的工具 kvmtool 为例讲讲 kvm 是如何运行和调试我们的Linux系统的。

二、环境准备

由于kvmtool底层使用的是kvm,因此我们在实践之前,需要准备一台运行Linux内核、并且带有kvm子系统的主机。目前主流的Linux发行版都能满足要求,可以通过lsmod | grep kvm命令来检查:

如果你是在Windows或者macOS环境中安装Linux虚拟机,请确保处理器硬件支持嵌套虚拟化,并且在VMWare、Parallel Desktop等虚拟机软件中为虚拟机开启嵌套虚拟化能力。这里不再深入展开,如果恰好你是这种情况,麻烦各位自行采取各种手段解决吧。

三、源码获取与编译

1. kvmtool编译和安装

可以直接从Github上获取kvmtool源代码:

bash 复制代码
git clone https://github.com/kvmtool/kvmtool.git
cd kvmtool

kvmtool的编译很简单,直接make即可,然后使用make install进行安装:

bash 复制代码
make -j$(nproc)
make install

安装完成后,可以通过lkvm来使用kvmtool了:

bash 复制代码
[root@iZbp1a2ioxwnzygize00vnZ kvmtool]# lkvm version
kvm tool 3.18.0

2. Linux系统准备

为了运行Linux系统,我们需要准备"Linux内核映像"和"根文件系统映像"这两个东西。

具体过程这里不再详细阐述,大家可以参考:mp.weixin.qq.com/s/y27zD6DPY...

最后只需要两个文件:

  • Linux内核映像:linux/arch/x86/boot/bzImage
  • 根文件系统映像:initramfs.img

四、使用kvmtool启动虚拟机

kvmtool启动虚拟机的方式和QEMU很类似,基本就是指定内核文件、根文件系统,然后配置核心数、内存大小以及内核启动参数等:

bash 复制代码
lkvm run \
	-k ../linux/arch/x86/boot/bzImage \
	--initrd ../initramfs.img \
	-m 1G \
	-c 2 \
	--console serial \
	-p "console=ttyS0,115200n8 earlycon=uart8250,io,0x3f8,115200n8 root=/dev/ram0 rw init=/init"

可以看到,Linux内核正常跑起来了:

同样也支持基本的BusyBox命令:

1. kvmtool常用命令

kvmtool允许用户对虚拟机执行一些基本操作,例如查看当前虚拟机状态、暂停或者恢复虚拟机执行等:

2. GDB调试虚拟机

kvmtool支持通过gdb来调试我们的虚拟机,其底层利用的是Linux内核的kgdb调试机制。

这里先贴一下kvmtool官方提供的调试步骤

但是我在实践过程中没有办法直接复现,下面就介绍一下我自己摸索过后切实可行的步骤。

首先我们需要重新编译我们的Linux内核映像,编辑.config文件如下:

bash 复制代码
# 模板1:
# CONFIG_STRICT_KERNEL_RWX is not set
CONFIG_FRAME_POINTER=y
CONFIG_KGDB=y
CONFIG_KGDB_SERIAL_CONSOLE=y
CONFIG_KGDB_KDB=n
CONFIG_KDB_KEYBOARD=n

# 或者使用模板2:
CONFIG_STRICT_KERNEL_RWX=y
CONFIG_KGDB=y
CONFIG_KGDB_SERIAL_CONSOLE=y
CONFIG_KGDB_KDB=n
CONFIG_KDB_KEYBOARD=n

上面的配置只启用了KGDB,没有使用KDB,原因后面说明。

重新编译内核,得到arch/x86/boot/bzImage

然后kvmtool启动虚拟机,并且添加kgdb相关启动参数:

bash 复制代码
lkvm run \
	-m 512M \
	-c 2 \
	-k ./linux/arch/x86/boot/bzImage \
	--initrd ./initramfs.img \
	-p "kgdboc=ttyS1,115200 kgdbwait nokaslr" \
	--tty 1

终端输出内核日志如下:

![image-20250405171549983](/Users/peihongchen/Library/Application Support/typora-user-images/image-20250405171549983.png)

日志中Info: Assigned terminal 1 to pty /dev/pts/1意思是说虚拟机的串口1ttyS1绑定到了宿主机上的伪终端/dev/pts/1

我们可以另起一个宿主机终端,通过gdb来连接到调试串口/dev/pts/1

bash 复制代码
gdb --tui ./linux/vmlinux
target remote /dev/pts/1

可以看到虚拟机执行暂停在了kgdb断点处:

接下来我们就可以跟调试普通程序一样,使用常用的gdb命令来调试Linux内核了。对于需要修改内核代码,或者开发驱动模块,使用kgdb调试是非常有用的。

3. 使用KDB?

上一节提到过,我们重新编译Linux内核前将KDB模式给关闭了,原因是我当时在开启KDB的情况下,gdb无论如何也连接不上去,从kdb也没法切换到kgdb模式,遂放弃了Orz。。。

开启KDB模式的情况下,虚拟机启动后自动进入了KDB shell:

Linux内核官方文档中指出,有两种方式从KDB模式切换到KGDB模式:

一种方式是通过gdb连接到调试端口后kdb shell会自动识别到并切换到kgdb模式,另一种是直接在kdb shell中直接执行kgdb命令来手动切换。

但是我两种方式尝试下来都不行。

下面是gdb连接报错:

然后尝试直接进入kdb shell,手动切换kgdb:

bash 复制代码
screen /dev/pts/1
[1]kdb> kgdb

有哪位大佬知道是什么原因吗?欢迎私信或者留言探讨交流,非非非常感谢!

关注微信公众号:Linux内核拾遗

文章来源:mp.weixin.qq.com/s/M4Y92PomJ...

相关推荐
张彦峰ZYF1 小时前
高频面试题(含笔试高频算法整理)基本总结回顾63
linux·运维·算法
椰萝Yerosius3 小时前
Ubuntu Wayland启动腾讯会议并实现原生屏幕共享
linux·ubuntu·腾讯会议
爪娃侠4 小时前
LeetCode热题100记录-【二叉树】
linux·算法·leetcode
rufeike7 小时前
Rclone同步Linux数据到google云盘
linux·运维·服务器
csdn_aspnet7 小时前
如何在 Linux 上安装 Python
linux·运维·python
良许Linux7 小时前
怎么自学嵌入式?
linux
良许Linux7 小时前
你见过的最差的程序员是怎样的?
linux
良许Linux7 小时前
想从事嵌入式软件,有推荐的吗?
linux
bookish_2010_prj9 小时前
Jupyter notebook定制字体
linux·python·jupyter
zhglhy10 小时前
查看 Linux 操作系统信息的常用命令
linux·运维·服务器