hipervínculo kvm con múltiples args

8

Actualmente estoy tratando de construir un pequeño hipervisor y kernel usando kvm y me cuesta obtener hipercalls con múltiples args funcionando correctamente.

Esto es lo que he intentado:

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

Cualquiera de esas hipercalls conduce a vcpu->kvm_run->exit_reasonigual 6, lo que es una sorpresa para mí en KVM_EXIT_MMIOlugar deKVM_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

Además de la razón de salida, ¿por KVM_EXIT_MMIOqué no se establecen las reglas? ¿Cuál es la forma correcta de desencadenar una KVM_EXIT_HYPERCALL con argumentos múltiples?

Gracias por adelantado

EDITAR: en caso de que sea importante: estoy usando la CPU de Intel i7 de novena generación ejecutando Debian con Linux Kernel 5.4

Gaetano
fuente

Respuestas:

1

KVM_EXIT_HYPERCALLya no se usa, según la documentación :

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

No usado. Esto alguna vez se usó para 'hipercall to userspace'. Para implementar dicha funcionalidad, use KVM_EXIT_IO (x86) o KVM_EXIT_MMIO (todos excepto s390). Nota KVM_EXIT_IO es significativamente más rápido que KVM_EXIT_MMIO.

Y me parece que KVM_EXIT_HYPERCALLtampoco está implementado. Búsqueda rápida y sucia con grep . Está definido, pero nunca se asignará como 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>

Versión de Linux:

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

Hay una pregunta anterior sobre cómo implementar VMCALL personalizados con dos respuestas en este sitio. ¿Los has probado?

krjdev
fuente
Las respuestas solo demostraron cómo crear hipercalls con 0 argumentos usando kvm_hypercall0 o ensamblado. Sin embargo, estoy tratando de que funcione para múltiples argumentos y el kvm_hypercallN proporcionado por mi sistema no parece comportarse como se esperaba. Por ejemplo, esperaba que regs.rax tuviera los valores que asigné en mi programa de invitado
Gaetano el
0

De la documentación del kernel kvm / api

Si exit_reason es KVM_EXIT_MMIO, entonces la vcpu ha ejecutado una instrucción de E / S mapeada en memoria que kvm no pudo satisfacer. El miembro 'data' contiene los datos escritos si 'is_write' es verdadero y, de lo contrario, debe rellenarse con el código de la aplicación.

La hiperllamada que activó provocó tal falla.
Esto depende del código de la hiperllamada que llamó.

mpromonet
fuente
1) Realicé un vmcall, no IO 2) ¿Cómo configuro los registros y VMM correctamente para que pueda pasar varios argumentos a través de los registros al VMM? - Esperaría poder leer los registros a través de ioctl (KVM_GET_REGS, & regs) pero todos los registros parecen ser cero
Gaetano
@Gaetano Supongo que la vmcall está generando KVM_EXIT_MMIO como una excepción, todavía no entiendo por qué está redefiniendo KVM_HYPERCALL en lugar de usar la definición en kvm_para.h o la de su arquitectura correspondiente
mpromonet
gracias por su respuesta. Estoy usando kvm_para.h pero para propósitos de resolución de problemas lo he copiado y pegado en mi proyecto y aquí para permitir potencialmente que otros con antecedentes no kvm se unan a la discusión. Al final se trata de usar VT-X / AMD-V correctamente
Gaetano