kvm hypercall mit mehreren args

8

Ich versuche derzeit, mit kvm einen kleinen Hypervisor und Kernel zu erstellen, und ich habe Probleme, Hypercalls mit mehreren Argumenten zum Funktionieren zu bringen.

Folgendes habe ich versucht:

// 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;
}

Jeder dieser Hypercalls führt zu vcpu->kvm_run->exit_reason6, was zu meiner Überraschung KVM_EXIT_MMIOstatt istKVM_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

Abgesehen vom Exit-Grund, KVM_EXIT_MMIOwarum werden die Regs nicht gesetzt? Was ist der richtige Weg, um einen KVM_EXIT_HYPERCALL mit mehreren Argumenten auszulösen?

Danke im Voraus

EDIT: Für den Fall, dass es wichtig ist: Ich verwende Intel i7 CPU der 9. Generation, auf der Debian mit Linux Kernel 5.4 ausgeführt wird

Gaetano
quelle

Antworten:

1

KVM_EXIT_HYPERCALLwird laut Dokumentation nicht mehr verwendet :

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

Ungebraucht. Dies wurde einmal für "Hypercall to Userspace" verwendet. Verwenden Sie zum Implementieren dieser Funktionalität KVM_EXIT_IO (x86) oder KVM_EXIT_MMIO (alle außer s390). Hinweis KVM_EXIT_IO ist erheblich schneller als KVM_EXIT_MMIO.

Und es scheint mir, dass KVM_EXIT_HYPERCALLauch nicht umgesetzt wird. Schnelle und schmutzige Suche mit grep . Es ist definiert, wird aber niemals zugewiesen als 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-Version:

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

Es gibt eine ältere Frage zur Implementierung benutzerdefinierter VMCALLs mit zwei Antworten auf dieser Site. Hast du sie ausprobiert?

krjdev
quelle
Die Antworten zeigten nur, wie Hypercalls mit 0 Argumenten mit kvm_hypercall0 oder Assembly erstellt werden. Ich versuche jedoch, es für mehrere Argumente zum Laufen zu bringen, und der von meinem System bereitgestellte kvm_hypercallN scheint sich nicht wie erwartet zu verhalten. Zum Beispiel hatte ich erwartet, dass regs.rax die Werte haben würde, die ich in meinem Gastprogramm zugewiesen habe
Gaetano
0

Aus der Kerneldokumentation kvm / api

Wenn exit_reason KVM_EXIT_MMIO ist, hat die vcpu einen speicherabgebildeten E / A-Befehl ausgeführt, der von kvm nicht erfüllt werden konnte. Das 'data'-Mitglied enthält die geschriebenen Daten, wenn' is_write 'wahr ist, und sollte ansonsten mit dem Anwendungscode gefüllt werden.

Der von Ihnen ausgelöste Hypercall hat einen solchen Fehler ausgelöst.
Dies hängt vom Code des von Ihnen angerufenen Hypercalls ab.

mpromonet
quelle
1) Ich habe einen vmcall nicht IO durchgeführt. 2) Wie richte ich die Register und den VMM korrekt ein, damit ich mehrere Argumente über die Register an den VMM übergeben kann? - Ich würde erwarten, dass ich die Register über ioctl (KVM_GET_REGS, & regs) lesen kann, aber alle Regs scheinen Null zu sein
Gaetano
@Gaetano Ich denke, der vmcall löst KVM_EXIT_MMIO als Ausnahme aus, immer noch nicht zu verstehen, warum Sie KVM_HYPERCALL neu definieren, anstatt die Definition in kvm_para.h oder die in Ihrer entsprechenden Architektur zu verwenden
mpromonet
Danke für deine Antwort. Ich verwende kvm_para.h, aber zur Fehlerbehebung habe ich es kopiert und in mein Projekt eingefügt und hier, damit möglicherweise andere Personen mit nicht kvm-Hintergrund an der Diskussion teilnehmen können. Am Ende geht es darum, VT-X / AMD-V richtig
Gaetano