当前位置: 首页 > news >正文

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内核直接访问。

http://www.gsyq.cn/news/1532023.html

相关文章:

  • MultiLogin:如何高效解决Minecraft多认证源共存难题?
  • 北京 16 区上门收酒权威榜单|专业鉴酒、当场结算,靠谱商家排名一览 - 光耀华夏品牌榜
  • WASM AI 推理性能优化:浏览器端模型推理的工程实践
  • 提示工程不是话术,是可复用的AI交互工程体系
  • Windows任务栏视觉定制终极方案:TranslucentTB深度解析与完整指南
  • 中国水文站矢量点位分布数据(近1万个站点)|属性齐全|WGS84坐标|SHP格式
  • AI重塑商业格局:小白程序员必备的10大行业应用解析(收藏版)
  • 官方发布|北京全域上门收酒机构 TOP6 排名,东城西城朝阳海淀通用 - 光耀华夏品牌榜
  • 广州居民搬家服务指南2026:家庭搬迁、家具拆装、空调移机一站式服务商排名 - 从来都是英雄出少年
  • 怎样安全高效使用R3nzSkin:英雄联盟国服皮肤美化专业指南
  • 2026 北京正规礼品酒回收机构排行|全城上门服务,官方号码公示 - 光耀华夏品牌榜
  • 2026 年 6 月更新:劳力士全国维修服务中心地址汇总及常见故障处理指南 - 博客万
  • 2026年更新视角下的南阳工程造价企业官方网站:专业服务商综合推荐与选型指南 - 品牌鉴赏官2026
  • PXD10 DMA模块中断、错误处理与传输控制实战解析
  • 大模型稀疏激活与MoE架构原理及工程实践
  • 把AI塞进U盘或者移动硬盘里,走到哪用到哪
  • 2026年强力磁铁厂家推荐排行榜:东莞亚力克/眼镜盒/圆环/五金/玩具/文具磁铁优质供应商精选 - 品牌发掘
  • 如何快速上手MidiEditor:5个核心技巧让音乐创作更简单
  • 3分钟掌握Illustrator批量替换神器:ReplaceItems.jsx完整使用指南
  • PXD10 LINFlex模块寄存器配置与LIN总线通信实战指南
  • 2026年当前,如何筛选适配的苏州管道焊缝热处理工程项目服务公司? - 品牌鉴赏官2026
  • OpenAI遭遇多州刑事调查与安全诉讼,AI责任边界引争议
  • 2026年新消息:河北行业知名的野营帐篷平台深度解析与实力厂商推荐 - 品牌鉴赏官2026
  • 2026年靠谱公司注册服务机构怎么选?深圳、成都、合肥等多地实情分析 - 优质品牌商家
  • 2026年 天津雷沃/帕金斯发动机厂家推荐:1004TG/1006TG/4缸6缸/天然气发电机组水泵发动机优选品牌榜单 - 品牌发掘
  • MPC866 CPM定时器:通信密集型系统的精准心跳与配置实战
  • Houdini许可优化,两个真实案例加三款工具数据
  • mariadb-libs 被 mysql-community-libs-5.7.28-1.el7.x86_64 取代
  • 怎样5分钟打造极简高效桌面:NoFences免费开源桌面管理实战手册
  • 抖音视频下载器,提供交互性的Web控制台