首页 > 解决方案 > 具有多个参数的 kvm 超级调用

问题描述

我目前正在尝试使用 kvm 构建一个小型虚拟机管理程序和内核,但我很难让具有多个 args 的超级调用正常工作。

这是我尝试过的:

// guest.c

#define KVM_HYPERCALL vmcall
// #define KVM_HYPERCALL vmmcall
// #define KVM_HYPERCALL ".byte 0x0f,0x01,0xd9"
// #define KVM_HYPERCALL .byte 0x0f,0x01,0xc1"

static inline long kvm_hypercall4(int nr, unsigned long p1,
                  unsigned long p2, unsigned long p3,
                  unsigned long p4) {
    long ret;
    asm volatile(KVM_HYPERCALL
             : "=a"(ret)
             : "a"(nr), "b"(p1), "c"(p2), "d"(p3), "S"(p4)
             : "memory");
    return ret;
}

这些超级调用中的任何一个都会导致vcpu->kvm_run->exit_reason等于 6,这让我感到惊讶KVM_EXIT_MMIO,而不是KVM_EXIT_HYPERCALL

switch (vcpu->kvm_run->exit_reason) {
  case KVM_EXIT_MMIO:
    printf("syscall: %lld\n", vcpu->kvm_run->hypercall.nr); // prints 0
    printf("arg 1: %lld\n",  vcpu->kvm_run->hypercall.args[1]); // prints 0
    printf("arg 2: %lld\n", vcpu->kvm_run->hypercall.args[2]); // prints 0
    printf("arg 3: %lld\n",  vcpu->kvm_run->hypercall.args[3]); // prints 0

    if(ioctl(vcpu->fd, KVM_GET_REGS, &regs)<0) exit 1;

    printf("rax: %lld\n", regs.rax); // prints 0
    printf("rbx: %lld\n", regs.rbx); // prints 0
    printf("rcx: %lld\n", regs.rcx); // prints 0

除了退出原因是KVM_EXIT_MMIO为什么没有设置规则?使用多个参数触发 KVM_EXIT_HYPERCALL 的正确方法是什么?

提前致谢

编辑:以防万一:我使用的是第 9 代英特尔 i7 cpu,运行带有 linux 内核 5.4 的 debian

标签: cvirtual-machinevirtualizationkvm

解决方案


KVM_EXIT_HYPERCALL根据文档,不再使用:

/* KVM_EXIT_HYPERCALL */
      struct {
          __u64 nr;
          __u64 args[6];
          __u64 ret;
          __u32 longmode;
          __u32 pad;
      } hypercall;

没用过。这曾经被用于“对用户空间的超级调用”。要实现此类功能,请使用 KVM_EXIT_IO (x86) 或 KVM_EXIT_MMIO(除 s390 之外的所有)。注意 KVM_EXIT_IO 比 KVM_EXIT_MMIO 快得多。

在我看来,这KVM_EXIT_HYPERCALL也没有实施。使用grep进行快速而肮脏的搜索。它已定义,但永远不会分配为exit_reason

user@host:~/Linux/src> grep -R KVM_EXIT_HYPERCALL
include/uapi/linux/kvm.h:#define KVM_EXIT_HYPERCALL        3
include/uapi/linux/kvm.h:               /* KVM_EXIT_HYPERCALL */
Documentation/virt/kvm/api.rst:         /* KVM_EXIT_HYPERCALL */
tools/include/uapi/linux/kvm.h:#define KVM_EXIT_HYPERCALL        3
tools/include/uapi/linux/kvm.h:         /* KVM_EXIT_HYPERCALL */
tools/testing/selftests/kvm/lib/kvm_util.c:     {KVM_EXIT_HYPERCALL, "HYPERCALL"},
user@host:~/Linux/src>

Linux 版本:

user@host:~/Linux/src> git-describe --tags
v5.6-10895-g4c205c84e249
user@host:~/Linux/src>

有一个较旧的问题,如何在此站点上实现自定义 VMCALL,并提供两个答案。你试过了吗?


推荐阅读