hypercall do kvm com vários argumentos

8

No momento, estou tentando criar um pequeno hipervisor e kernel usando o kvm e luto para obter hipercalls com vários argumentos funcionando corretamente.

Aqui está o que eu tentei:

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

Qualquer um desses Hypercalls leva a vcpu->kvm_run->exit_reasonigual a 6, o que é para minha surpresa, em KVM_EXIT_MMIOvez 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

Além do motivo da saída, KVM_EXIT_MMIOpor que os registros não estão definidos? Qual é a maneira correta de acionar um KVM_EXIT_HYPERCALL com vários argumentos?

desde já, obrigado

EDIT: Caso isso importe: estou usando a cpu intel i7 da 9ª geração executando o debian com o kernel 5.4 do linux

Gaetano
fonte

Respostas:

1

KVM_EXIT_HYPERCALLnão é mais usado, de acordo com a documentação :

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

Não utilizado. Isso já foi usado para 'hypercall to userspace'. Para implementar essa funcionalidade, use KVM_EXIT_IO (x86) ou KVM_EXIT_MMIO (todos, exceto o s390). Nota KVM_EXIT_IO é significativamente mais rápido que KVM_EXIT_MMIO.

E parece-me que KVM_EXIT_HYPERCALLtambém não está implementado. Pesquisa rápida e suja com grep . Está definido, mas nunca será atribuído 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>

Versão do Linux:

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

Há uma pergunta mais antiga sobre como implementar VMCALLs personalizadas com duas respostas neste site. Você já experimentou?

krjdev
fonte
As respostas demonstraram apenas como criar hypercalls com 0 argumentos usando kvm_hypercall0 ou assembly. No entanto, estou tentando fazê-lo funcionar para vários argumentos e o kvm_hypercallN fornecido no meu sistema não parece se comportar conforme o esperado. Por exemplo, eu esperava que o regs.rax tivesse os valores que eu atribuí no meu programa de convidados
Gaetano
0

Na documentação do kernel, kvm / api

Se exit_reason for KVM_EXIT_MMIO, o vcpu executou uma instrução de E / S mapeada na memória que não pôde ser satisfeita pelo kvm. O membro 'data' contém os dados gravados se 'is_write' for verdadeiro e, caso contrário, deve ser preenchido pelo código do aplicativo.

A hipercall que você acionou provocou tal falha.
Isso depende do código do hypercall que você chamou.

mpromonet
fonte
1) Executei uma vmcall e não a E / S 2) Como configuro os registradores e o VMM corretamente para que eu possa passar vários argumentos através dos registradores para o VMM? - Eu esperaria que eu seria capaz de ler os registros via ioctl (KVM_GET_REGS, & regs), mas todos os registros parecem ser zero
Gaetano
@Gaetano Eu acho que o vmcall está aumentando o KVM_EXIT_MMIO como uma exceção, ainda não é subestimado por que você está redefinindo o KVM_HYPERCALL em vez de usar a definição em kvm_para.h ou aquela em sua arquitetura correspondente
mpromonet
Obrigado pela sua resposta. Estou usando o kvm_para.h, mas para fins de solução de problemas, copiei e colei no meu projeto e aqui para potencialmente permitir que outras pessoas com um background que não seja do kvm participem da discussão. No final, trata-se de usar o VT-X / AMD-V corretamente
Gaetano