功能概述
kvm_emulate_hypercall
是 KVM(Kernel-based Virtual Machine)中处理虚拟机发起的 超级调用(Hypercall) 的核心函数。Hypercall 是虚拟机(Guest)向宿主机(Host)请求特权操作的机制,类似于系统调用(但针对虚拟化场景)。
csv_init
ops->handle_exit = csv_handle_exit;
vcpu_run
vcpu_enter_guest
svm_x86_ops
handle_exit
svm_invoke_exit_handler
svm_exit_handlers
vmmcall_interception
kvm_emulate_hypercall
kvm_pv_psp_copy_forward_op
输入参数
struct kvm_vcpu *vcpu
:表示当前发起 Hypercall 的虚拟 CPU(vCPU)。
执行流程
1. Hyper-V 兼容性检查
if (kvm_hv_hypercall_enabled(vcpu->kvm))
return kvm_hv_hypercall(vcpu);
- 如果启用了 Hyper-V 兼容模式,直接调用 Hyper-V 的 Hypercall 处理函数。
2. 读取寄存器参数
从 vCPU 的寄存器中读取 Hypercall 的编号和参数:
nr = kvm_rax_read(vcpu); // Hypercall 编号
a0 = kvm_rbx_read(vcpu); // 参数 0
a1 = kvm_rcx_read(vcpu); // 参数 1
a2 = kvm_rdx_read(vcpu); // 参数 2
a3 = kvm_rsi_read(vcpu); // 参数 3
- x86 约定:Hypercall 编号通过
RAX
传递,参数通过RBX
,RCX
,RDX
,RSI
传递。
3. 模式检查(32/64 位)
op_64_bit = is_64_bit_hypercall(vcpu);
if (!op_64_bit) {
nr &= 0xFFFFFFFF; // 截断为 32 位
a0 &= 0xFFFFFFFF;
a1 &= 0xFFFFFFFF;
a2 &= 0xFFFFFFFF;
a3 &= 0xFFFFFFFF;
}
- 根据 vCPU 模式(32/64 位)决定是否截断参数的高 32 位。
4. 特权级检查
if (kvm_x86_ops.get_cpl(vcpu) != 0 && ...) {
ret = -KVM_EPERM;
goto out;
}
- CPL(Current Privilege Level) 必须为 0(内核态),否则返回权限错误(
-EPERM
)。 - 例外:允许
KVM_HC_VM_ATTESTATION
等特定 Hypercall 在非特权级调用。
5. Hypercall 分发与处理
通过 switch (nr)
分发到具体操作:
- 典型 Hypercall 示例:
- KVM_HC_VAPIC_POLL_IRQ: 虚拟中断轮询(直接返回成功)。
- KVM_HC_KICK_CPU: 唤醒指定 vCPU(需启用
KVM_FEATURE_PV_UNHALT
)。 - KVM_HC_CLOCK_PAIRING: 时钟同步(仅 x86_64)。
- KVM_HC_MAP_GPA_RANGE: 映射 Guest 物理地址范围(需用户空间处理)。
6. 用户空间处理(以 MAP_GPA_RANGE 为例)
vcpu->run->exit_reason = KVM_EXIT_HYPERCALL;
vcpu->run->hypercall.nr = KVM_HC_MAP_GPA_RANGE;
...
vcpu->arch.complete_userspace_io = complete_hypercall_exit;
return 0;
- 设置
KVM_EXIT_HYPERCALL
退出原因,并将参数传递给用户空间。 - 用户空间处理完成后,通过
complete_hypercall_exit
回调恢复执行。
7. 返回值处理
out:
if (!op_64_bit)
ret = (u32)ret; // 32 位模式下截断返回值
kvm_rax_write(vcpu, ret); // 结果写入 RAX
++vcpu->stat.hypercalls; // 统计计数器
return kvm_skip_emulated_instruction(vcpu); // 跳过当前指令
- 结果通过
RAX
返回给 Guest。 - 更新 Hypercall 调用统计。
关键设计点
-
兼容性:
- 支持 Hyper-V 和 KVM 原生 Hypercall。
- 区分 32/64 位模式。
-
安全性:
- 特权级(CPL)检查防止非法调用。
- 参数合法性验证(如地址对齐)。
-
扩展性:
- 通过
kvm_x86_ops
抽象架构相关操作(如vm_attestation
)。 - 允许用户空间处理复杂 Hypercall(如内存映射)。
- 通过
应用场景
- 虚拟中断管理:唤醒其他 vCPU(
KICK_CPU
)。 - 时钟同步:保证 Guest 与 Host 时间一致。
- 安全认证:虚拟机证明(
VM_ATTESTATION
)。 - 内存管理:动态调整 Guest 物理地址映射。
总结
kvm_emulate_hypercall
是 KVM 实现 Hypercall 的核心分发逻辑,结合特权检查、模式适配和用户空间协作,为虚拟机提供了与宿主机交互的安全通道。