news 2026/6/16 0:50:51

Linux kvmtool Kernel Virtual Machine Tool and ramfs Loading

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Linux kvmtool Kernel Virtual Machine Tool and ramfs Loading

Linux kvmtool Kernel Virtual Machine Tool and ramfs Loading

kvmtool(也称为lkvm或kvm-tool)是比QEMU轻量得多的KVM用户态VMM,源码位于tools/kvm/目录。它的核心设计哲学是直接使用KVM API,避免QEMU的完整设备模型,专注于快速启动Guest Linux内核。ramfs(initramfs/rootfs)加载是kvmtool启动流程的关键环节,决定了Guest内核完成初始化的根文件系统来源。

kvmtool的主入口在kvm.c的kvm__init和kvm__start:

```c
int kvm__init(struct kvm *kvm)
{
int ret;

/* 打开/dev/kvm获取KVM文件描述符 */
kvm->sys_fd = open("/dev/kvm", O_RDWR);
if (kvm->sys_fd < 0)
return -errno;

/* 通过KVM_API_VERSION检查接口版本兼容性 */
ret = ioctl(kvm->sys_fd, KVM_GET_API_VERSION, 0);
if (ret != KVM_API_VERSION)
die("KVM API version mismatch");

/* 创建VM fd */
kvm->vm_fd = ioctl(kvm->sys_fd, KVM_CREATE_VM, 0);

/* 获取KVM支持的能力 */
ioctl(kvm->sys_fd, KVM_CHECK_EXTENSION, KVM_CAP_IRQCHIP);
ioctl(kvm->sys_fd, KVM_CHECK_EXTENSION, KVM_CAP_USER_MEMORY);

return 0;
}

int kvm__start(struct kvm *kvm)
{
/* 加载内核elf镜像 */
if (kvm->cfg.firmware_filename)
load_bzimage(kvm, kvm->cfg.firmware_filename);

/* 加载initramfs */
if (kvm->cfg.initrd_filename)
load_ramdisk(kvm, kvm->cfg.initrd_filename);

/* 设置启动参数 */
kvm__setup_bootargs(kvm);

/* 创建VCPU并启动 */
kvm__create_vcpus(kvm);
kvm__run(kvm);

return 0;
}
```

ramfs加载通过load_ramdisk函数实现,将initramfs或rootfs镜像加载到Guest物理内存中的指定位置:

```c
int load_ramdisk(struct kvm *kvm, const char *filename)
{
int fd;
ssize_t file_size;
struct stat st;
unsigned long addr;
const char *p;

/* 打开ramdisk文件 */
fd = open(filename, O_RDONLY);
if (fd < 0)
return -errno;

/* 获取文件大小 */
if (fstat(fd, &st) < 0) {
close(fd);
return -errno;
}
file_size = st.st_size;

/* 计算ramdisk在Guest物理内存中的地址
* 通常放在内核加载地址之后,紧接内核末尾
*/
addr = kvm->arch.kern_start + kvm->arch.kern_size;
/* 4KB对齐 */
addr = (addr + 0xfff) & ~0xfff;

/* 使用KVM_SET_USER_MEMORY_REGION映射 */
if (!kvm->ram_size_enough(addr, file_size)) {
/* 扩展Guest物理内存映射 */
kvm__register_mem(kvm, addr, ALIGN(file_size, PAGE_SIZE),
NULL);
}

/* 使用mmap映射文件到Guest地址空间 */
p = mmap(NULL, file_size, PROT_READ,
MAP_PRIVATE | MAP_POPULATE, fd, 0);
if (p == MAP_FAILED) {
close(fd);
return -errno;
}

/* 拷贝ramdisk内容到Guest内存 */
memcpy(guest_flat_to_host(kvm, addr), p, file_size);

munmap((void *)p, file_size);
close(fd);

/* 更新内核启动参数中的ramdisk地址和大小 */
kvm->arch.ramdisk_addr = addr;
kvm->arch.ramdisk_size = file_size;

pr_debug(" RAM disk: %s, @ 0x%lx, size %ld bytes\n",
filename, addr, file_size);

return 0;
}
```

加载完成后,kvmtool通过setup_bootargs在boot_params结构中填充initrd_start和initrd_size字段。x86架构下,boot_params由Linux boot protocol定义,位于实模式启动代码段(0x90000偏移处)。kvmtool使用kvm__setup_boot_args直接在Guest物理内存的boot_params结构体上写入:

```c
void kvm__setup_boot_args(struct kvm *kvm)
{
struct boot_params *boot;
unsigned long bp_addr = 0x90000;

/* 获取boot_params的Host指针 */
boot = guest_flat_to_host(kvm, bp_addr);

/* 填充initrd地址和大小 */
boot->hdr.ramdisk_image = kvm->arch.ramdisk_addr;
boot->hdr.ramdisk_size = kvm->arch.ramdisk_size;

/* 设置启动参数行 */
if (kvm->cfg.real_cmdline)
strncpy((char *)boot->hdr.cmd_line_ptr,
kvm->cfg.real_cmdline, 255);

/* 设置header标志 */
boot->hdr.type_of_loader = 0xFF;
boot->hdr.loadflags |= CAN_USE_HEAP | LOAD_HIGH;
}
```

kvmtool的ramfs加载路径与QEMU有显著区别。QEMU通过fw_cfg将initramfs传递给SeaBIOS或OVMF,而kvmtool直接在内核启动参数中设置initrd地址,由内核本身在启动过程中解压并挂载initramfs。这种方式减少了启动链中的中间环节。

kvmtool的Guest内存映射使用kvm__register_mem创建KVM_SET_USER_MEMORY_REGION slot,每个slot对应一段连续的Guest物理地址范围。ramfs加载完成后,内核解压initramfs时通过arch/x86/kernel/setup.c中的populate_initrd_image访问这些地址。如果ramfs大于可用slot大小,kvmtool会合并或扩展已有slot来容纳。

内存映射的核心数据结构为:

```c
struct kvm_mem_bank {
struct list_head list;
u64 guest_phys_addr;
u64 size;
void *host_addr;
struct kvm_userspace_memory_region region;
};
```

每个mem_bank对应一个KVM memory slot,kvmtool通过KVM_SET_USER_MEMORY_REGION将host_addr线性映射到guest_phys_addr供Guest内核直接访问。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/16 0:47:56

猫抓浏览器扩展:终极网页视频下载工具完全指南

猫抓浏览器扩展&#xff1a;终极网页视频下载工具完全指南 【免费下载链接】cat-catch 猫抓 浏览器资源嗅探扩展 / cat-catch Browser Resource Sniffing Extension 项目地址: https://gitcode.com/GitHub_Trending/ca/cat-catch 你是否曾经在网上看到一个精彩的视频&am…

作者头像 李华
网站建设 2026/6/16 0:46:10

从ZET6到C8T6:STM32型号移植时,除了Flash和RAM,别忘了RTC的“隐藏”差异

从ZET6到C8T6&#xff1a;STM32型号移植中那些容易被忽视的硬件差异当我们需要将项目从STM32F103ZET6迁移到C8T6时&#xff0c;大多数人首先关注的是Flash和RAM的容量变化。但真正让工程师头疼的&#xff0c;往往是那些数据手册上没有明确标注的细微差异。就像在黑暗森林中行走…

作者头像 李华
网站建设 2026/6/16 0:45:58

CANN ops-nn神经网络算子库概念拆解:从矩阵运算到昇腾NPU指令映射的算子注册与内核调度机制类比解读

前言 你以为神经网络推理的瓶颈在模型架构设计上&#xff1f;恰恰不是。当一个训练好的模型被部署到硬件上执行推理时&#xff0c;真正的性能差距往往出现在算子层——那一行行把高维张量映射为底层硬件指令的代码里。CANN&#xff08;Compute Architecture for Neural Network…

作者头像 李华
网站建设 2026/6/16 0:45:51

Parsec VDD虚拟显示器完整方案:解决Windows无头主机与多屏扩展挑战

Parsec VDD虚拟显示器完整方案&#xff1a;解决Windows无头主机与多屏扩展挑战 【免费下载链接】parsec-vdd ✨ Perfect virtual display for game streaming 项目地址: https://gitcode.com/gh_mirrors/pa/parsec-vdd 在远程工作、游戏串流和无头服务器管理的技术实践中…

作者头像 李华