1. KVM_MEMORY_ENCRYPT_OP初始化
main() // QEMU 入口函数
qemu_init() // 初始化虚拟机
configure_accelerators
kvm_init
sev_guest_init
KVM_SEV_INIT
sev_launch_start
KVM_SEV_LAUNCH_START
ram_block_notifier_add(&sev_ram_notifier); //sev_ram_block_added KVM_MEMORY_ENCRYPT_REG_REGION
kvm_state->memcrypt_encrypt_data = sev_encrypt_data;
kvm_arch_init
kvm_vm_enable_cap
kvm_memory_listener_register
memory_listener_register
cpus_register_accel
machine_run_board_init() //pc_init_isa
pc_init1()
pc_memory_init
pc_system_firmware_init
pc_system_flash_map
kvm_memcrypt_encrypt_data
kvm_state->memcrypt_encrypt_data
1.1、代码逻辑解析
此代码段属于 KVM 对 KVM_MEMORY_ENCRYPT_OP ioctl 的处理核心逻辑,其作用是为内存加密操作提供统一的入口,但实际功能由架构相关代码(如 AMD SVM)实现。以下为逐行分析:
case KVM_MEMORY_ENCRYPT_OP: {
r = -ENOTTY; // 默认返回“不支持该操作”
if (kvm_x86_ops->mem_enc_op) // 检查架构是否实现内存加密操作
r = kvm_x86_ops->mem_enc_op(kvm, argp); // 调用具体实现(如 AMD SEV)
break;
}
1.2、关键行为解读
1. 兼容性控制机制
-
-ENOTTY的深层含义:表示当前内核或硬件不支持内存加密功能,可能原因包括:- 未启用
CONFIG_KVM_AMD_SEV内核编译选项 - 硬件无 SEV 支持(如非 AMD EPYC CPU)
- 内核版本过旧(<4.16)或过新(≥5.10,此接口已废弃)
- 未启用
-
kvm_x86_ops->mem_enc_op的动态绑定:- AMD 实现:指向
svm_mem_enc_op()(定义于arch/x86/kvm/svm/sev.c) - Intel 实现:始终为
NULL(Intel 无等效 SEV 功能)
- AMD 实现:指向
2. 参数传递流程
// 用户态(QEMU)调用示例:
struct kvm_sev_cmd cmd = {
.id = KVM_SEV_INIT, // 子命令类型
.data = (unsigned long)&init_params // 具体参数结构体
};
ioctl(kvm_fd, KVM_MEMORY_ENCRYPT_OP, &cmd);
// 内核态处理(svm_mem_enc_op):
static int svm_mem_enc_op(struct kvm *kvm, void __user *argp)
{
struct kvm_sev_cmd cmd;
copy_from_user(&cmd, argp, sizeof(cmd)); // 从用户空间复制命令
return sev_handle_cmd(kvm, cmd.id, cmd.data); // 分发到 SEV 子处理函数
}
1.3、与新版接口的差异
旧版(KVM_MEMORY_ENCRYPT_OP) vs 新版(KVM_SEV_*)
| 特性 | 旧版接口 | 新版接口(≥5.10) |
|---|---|---|
| 命令结构 | 统一入口 + 子命令 ID | 独立 ioctl 命令(如 KVM_SEV_INIT) |
| 可维护性 | 参数解析耦合度高 | 类型安全,减少错误传递 |
| 功能扩展性 | 需修改共用结构体 | 独立命令互不影响 |
| 典型调用栈 | ioctl(KVM_MEMORY_ENCRYPT_OP) → svm_mem_enc_op() → sev_handle_cmd() |
ioctl(KVM_SEV_INIT) → sev_guest_init() |
淘汰原因分析(内核 ≥5.10)
- 安全性:旧接口允许任意
cmd.id传递,存在非法命令注入风险 - 性能:新版省去多层间接跳转,调用路径更短
- 代码清晰度:每个 SEV 操作有独立入口,便于维护
1.4、实际应用场景验证
若在 5.4 内核 中执行以下 QEMU 命令:
qemu-system-x86_64 -machine confidential-guest-support=sev0...
内核日志将出现:
kvm_amd: SEV supported: 255 ASIDs
kvm_amd: SEV-ES supported: 255 ASIDs
svm_mem_enc_op: handling command KVM_SEV_INIT
此时旧接口仍有效,但 5.10+ 内核会拒绝此调用,需改用 KVM_SEV_INIT。
1.5、调试技巧
-
动态追踪调用路径:
echo 'p:svm_mem_enc_op arch/x86/kvm/svm/sev.c:1800 cmd_id=+0(%dx):u32' > /sys/kernel/debug/tracing/kprobe_events echo 1 > /sys/kernel/debug/tracing/events/kprobes/enable可捕获所有经过
svm_mem_enc_op的命令 ID。 -
错误码解读:
-ENOTTY→ 检查硬件/Kconfig/内核版本-EINVAL→ 参数结构体不匹配(如 32/64 位模式混合)
1.6、迁移到新接口的代码示例
// 旧版(废弃):
struct kvm_sev_cmd cmd = {
.id = KVM_SEV_INIT};
ioctl(kvm_fd, KVM_MEMORY_ENCRYPT_OP, &cmd);
// 新版(推荐):
ioctl(kvm_fd, KVM_SEV_INIT, &launch_params); // 直接使用独立命令
该代码段是 KVM 内存加密功能演进的历史产物,理解其工作原理有助于调试旧版本兼容性问题,但在新开发中应遵循 AMD 官方推荐使用 KVM_SEV_* 系列专用命令。
2 qemu中设置逻辑
kvm_init
kvm_memory_listener_register
memory_listener_register
listener_add_address_space
kvm_region_add (kml->lis

最低0.47元/天 解锁文章
4292

被折叠的 条评论
为什么被折叠?



