KVM.... 这里使用的是RK3588来测试:
- kernel-6.6
内核开启KVM
我们需要在内核开启如下功能:
# For Kvm
CONFIG_VIRTUALIZATION=y
CONFIG_KVM=y # 启用 KVM 支持
CONFIG_KVM_ARM=y # 启用 ARM 平台的 KVM 支持
CONFIG_KVM_ARM_HOST=y # 启用 ARM 主机支持编程
我们会用到kvm的ioctl调用,具体的目录在:arm/arm64/kvm和virt/kvm,当遇到需要使用的寄存器,我们可以查看该部分代码。 在这里,会介绍三种使用示例:
- 纯使用
kvm 相关系统调用启动一个操作系统 - 介绍使用
arm64-kvm-hello-world项目 - 介绍使用
kvm-tools项目
kvm 启动kernel
该部分主要是通过借鉴
uboot进入内核跳转的过程,进而在host中启动虚拟内核。
略.... 寄存器如何知道ID,我们可以参考kernel/tools/testing/selftests/kvm/get-reg-list.c中的代码。
arm64-kvm-hello-world
该项目地址为:https://github.com/Lenz-K/arm64-kvm-hello-world 我们使用如下命令:
git clone https://github.com/Lenz-K/arm64-kvm-hello-world
make该项目是利用kvm加载一段应用程序(bare-metal-aarch64/hello_world.elf)。 而目录bare-metal-aarch64-qemu是可以使用qemu进行测试的版本:
qemu-system-aarch64 -M virt -cpu host -enable-kvm -nographic -kernel hello_world.elf我们测试纯代码的话直接执行:
./kvm_test如果我们希望改变程序中的打印:
// arm64-kvm-hello-world/bare-metal-aarch64/hello_world.c
void main() {
print_uart0("Hello World, This is Px!\n");
}这里增加了字符,还需要修改输出:
#define MAX_VM_RUNS 20
//修改为更大的数字
#define MAX_VM_RUNS 64kvm-tools
这是一款虚拟机启动以及管理工具,他可以不借助qemu启动内核。
- 下载/编译/安装
# 多个网址
git clone https://github.com/kvmtool/kvmtool
# https://git.kernel.org/pub/scm/linux/kernel/git/will/kvmtool.git也可以下载
sudo apt update
sudo apt install -y build-essential flex bison pkg-config libssl-dev libglib2.0-dev libpixman-1-dev libfdt-dev
cd kvmtool
make
cp ./lkvm /usr/bin
cp ./vm /usr/bin- 使用,我们这里主要介绍子命令
run的用法
# 执行Image内核,以及加载rootfs_minimal.img
lkvm run -c 2 -m 512M --kernel Image --disk rootfs_minimal.img --console serial -p "root=/dev/vda console=ttyS0 initcall_call loglevel=8"
# 执行Image内核,以及加载rootfs.img,并且输出自动生成的设备树到output.dtb
lkvm run -c 2 -m 512M --kernel Image --disk rootfs.img --console serial -p "root=/dev/vda1 console=ttyS0" --dump-dtb output.dtb
# 如果使用busybox,然后将系统(initramfs)打包进Image(kernel)
lkvm run -c 2 -m 512M --kernel Image --console serial -p "rdinit=/sbin/init console=ttyS0"-c 2:
- 指定虚拟机使用的 CPU 核心数。这里设置为 2 核心。
-m 512M:
- 为虚拟机分配 512MB 的内存。
--kernel Image:
Image是内核映像的文件名。这里指定了启动时加载的内核。
--disk format=raw,file=rootfs_minimal.img:
--disk参数用于指定虚拟机的磁盘映像。format=raw表示输入的磁盘映像是原始格式(raw format)。这意味着rootfs_minimal.img并不是一个压缩或特定格式的镜像文件(如.iso或.qcow2),而是一个直接的原始磁盘镜像。file=rootfs_minimal.img指定了用于虚拟机的根文件系统映像。
--console serial:
- 通过
serial控制台连接虚拟机,意味着虚拟机的输出会通过串口输出。这通常用于调试或者无图形界面的操作。
-p "root=/dev/vda console=ttyS0 initcall_call loglevel=8":
-p参数用于传递内核启动参数(命令行)。root=/dev/vda:指定根文件系统的位置为/dev/vda,这是虚拟磁盘设备的默认名称。这样,内核会尝试从该磁盘设备加载根文件系统。console=ttyS0:设置串口控制台的输出为ttyS0。这与--console serial配合使用,使虚拟机的输出通过串口进行显示。initcall_call:这是内核的启动参数,用来调试内核的初始化过程,通常用于开发和调试。loglevel=8:设置日志级别为 8,表示内核将输出更多的日志信息。更高的级别通常意味着更详细的调试信息。 这里需要注意的是:
rootfs使用的格式是:raw或者qcow2。我们可以下载标准测试用例linux-0.2.img- 使用外部虚拟硬盘需要开启内核以下功能:
# 在README有说明
CONFIG_VIRTIO=y
CONFIG_VIRTIO_RING=y
CONFIG_VIRTIO_PCI=y
- For virtio-blk devices (--disk, -d):
CONFIG_VIRTIO_BLK=y
- For virtio-net devices ([--network, -n] virtio):
CONFIG_VIRTIO_NET=y
- For virtio-9p devices (--virtio-9p):
CONFIG_NET_9P=y
CONFIG_NET_9P_VIRTIO=y
CONFIG_9P_FS=y
- For virtio-balloon device (--balloon):
CONFIG_VIRTIO_BALLOON=y
- For virtio-console device (--console virtio):
CONFIG_VIRTIO_CONSOLE=y
- For virtio-rng device (--rng):
CONFIG_HW_RANDOM_VIRTIO=y
- For vesa device (--sdl or --vnc):
CONFIG_FB_VESA=y这里我尝试了多种办法都没有能够从外部加载rootfs,包括标准测试用例,最终它停留在无法识别到任何硬盘的情况下: ![[笔记/01 附件/image.png|KVM编程使用/image.png]] 这输入内核驱动问题,这里不再深入探究。 我们使用第三种办法,使用initramfs来进入rootfs,这里需要制作一个简单的文件系统,具体可以查看Linux小技巧-利用busybox制作最小系统,我们注意启动参数中的rdinit=/sbin/init而非/init。使用该方式可以进入initramfs,期间遇到warning unable to open an initial console,该问题主要是由于在构建rootfs未创建console节点导致的。