I’m currently trying to build a small hypervisor and kernel using kvm and I struggle to get hypercalls with multiple args working correctly.
Here is what I’ve tried:
// 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;
}
Any of those Hypercalls lead to vcpu->kvm_run->exit_reason
to equal 6 which is to my surprise KVM_EXIT_MMIO
instead of KVM_EXIT_HYPERCALL
switch (vcpu->kvm_run->exit_reason) {
case KVM_EXIT_MMIO:
printf("syscall: %lldn", vcpu->kvm_run->hypercall.nr); // prints 0
printf("arg 1: %lldn", vcpu->kvm_run->hypercall.args[1]); // prints 0
printf("arg 2: %lldn", vcpu->kvm_run->hypercall.args[2]); // prints 0
printf("arg 3: %lldn", vcpu->kvm_run->hypercall.args[3]); // prints 0
if(ioctl(vcpu->fd, KVM_GET_REGS, ®s)<0) exit 1;
printf("rax: %lldn", regs.rax); // prints 0
printf("rbx: %lldn", regs.rbx); // prints 0
printf("rcx: %lldn", regs.rcx); // prints 0
Aside of the exit reason being KVM_EXIT_MMIO
why are the regs not set?
What is the right way to trigger a KVM_EXIT_HYPERCALL with multple arguments?
Thanks in advance
EDIT:
In case it matters:
I’m using 9th generation intel i7 cpu running debian with linux kernel 5.4
3
Answers
From the kernel documentation kvm/api
The hypercall you trigged raised such failure.
This depend on the code of the hypercall you called.
KVM_EXIT_HYPERCALL
is no longer used, according to the documentation:And it seems to me that
KVM_EXIT_HYPERCALL
is also not implemented. Quick and dirty search with grep. It’s defined, but will never assigned asexit_reason
:Linux version:
There is an older question how to implement custom VMCALL’s with two answers on this site. Have you tried them?
I found this in the KVM API documentation:
So, perhaps you should try implementing the Hypercall using either the KVM_EXIT_IO or KVM_EXIT_MMIO.