KVM гиперколл с несколькими аргументами - PullRequest
8 голосов
/ 29 марта 2020

В настоящее время я пытаюсь собрать небольшой гипервизор и ядро, используя kvm, и я пытаюсь заставить гиперколлы с несколькими аргументами работать правильно.

Вот что я пробовал:

// 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 с несколькими аргументами?

Заранее спасибо

РЕДАКТИРОВАТЬ: В случае, если это имеет значение: я использую процессор Intel i7 9-го поколения, на котором запущен debian с linux ядро 5.4

Ответы [ 2 ]

1 голос
/ 08 апреля 2020

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 с двумя ответами на этом сайте. Вы пробовали их?

0 голосов
/ 03 апреля 2020

Из документации ядра kvm / api

Если exit_reason - KVM_EXIT_MMIO, тогда vcpu выполнил команду ввода-вывода с отображением в память, которая не могла быть удовлетворена kvm , Элемент «data» содержит записанные данные, если «is_write» имеет значение true, и должен быть заполнен кодом приложения в противном случае.

Гипер-вызов, который вы инициировали, вызвал такой сбой.
Это зависит от кода звонка, который вы называли.

...