Skip to content

Commit

Permalink
KVM: selftests: Consolidate boilerplate code in get_ucall()
Browse files Browse the repository at this point in the history
Consolidate the actual copying of a ucall struct from guest=>host into
the common get_ucall().  Return a host virtual address instead of a guest
virtual address even though the addr_gva2hva() part could be moved to
get_ucall() too.  Conceptually, get_ucall() is invoked from the host and
should return a host virtual address (and returning NULL for "nothing to
see here" is far superior to returning 0).

Use pointer shenanigans instead of an unnecessary bounce buffer when the
caller of get_ucall() provides a valid pointer.

Reviewed-by: Andrew Jones <andrew.jones@linux.dev>
Tested-by: Peter Gonda <pgonda@google.com>
Signed-off-by: Sean Christopherson <seanjc@google.com>
Link: https://lore.kernel.org/r/20221006003409.649993-3-seanjc@google.com
  • Loading branch information
Sean Christopherson committed Nov 17, 2022
1 parent 7046638 commit ef38871
Show file tree
Hide file tree
Showing 6 changed files with 33 additions and 59 deletions.
8 changes: 2 additions & 6 deletions tools/testing/selftests/kvm/include/ucall_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,10 @@ struct ucall {
void ucall_arch_init(struct kvm_vm *vm, void *arg);
void ucall_arch_uninit(struct kvm_vm *vm);
void ucall_arch_do_ucall(vm_vaddr_t uc);
uint64_t ucall_arch_get_ucall(struct kvm_vcpu *vcpu, struct ucall *uc);
void *ucall_arch_get_ucall(struct kvm_vcpu *vcpu);

void ucall(uint64_t cmd, int nargs, ...);
uint64_t get_ucall(struct kvm_vcpu *vcpu, struct ucall *uc);

static inline void ucall_init(struct kvm_vm *vm, void *arg)
{
Expand All @@ -41,11 +42,6 @@ static inline void ucall_uninit(struct kvm_vm *vm)
ucall_arch_uninit(vm);
}

static inline uint64_t get_ucall(struct kvm_vcpu *vcpu, struct ucall *uc)
{
return ucall_arch_get_ucall(vcpu, uc);
}

#define GUEST_SYNC_ARGS(stage, arg1, arg2, arg3, arg4) \
ucall(UCALL_SYNC, 6, "hello", stage, arg1, arg2, arg3, arg4)
#define GUEST_SYNC(stage) ucall(UCALL_SYNC, 2, "hello", stage)
Expand Down
14 changes: 3 additions & 11 deletions tools/testing/selftests/kvm/lib/aarch64/ucall.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,13 +75,9 @@ void ucall_arch_do_ucall(vm_vaddr_t uc)
WRITE_ONCE(*ucall_exit_mmio_addr, uc);
}

uint64_t ucall_arch_get_ucall(struct kvm_vcpu *vcpu, struct ucall *uc)
void *ucall_arch_get_ucall(struct kvm_vcpu *vcpu)
{
struct kvm_run *run = vcpu->run;
struct ucall ucall = {};

if (uc)
memset(uc, 0, sizeof(*uc));

if (run->exit_reason == KVM_EXIT_MMIO &&
run->mmio.phys_addr == (uint64_t)ucall_exit_mmio_addr) {
Expand All @@ -90,12 +86,8 @@ uint64_t ucall_arch_get_ucall(struct kvm_vcpu *vcpu, struct ucall *uc)
TEST_ASSERT(run->mmio.is_write && run->mmio.len == 8,
"Unexpected ucall exit mmio address access");
memcpy(&gva, run->mmio.data, sizeof(gva));
memcpy(&ucall, addr_gva2hva(vcpu->vm, gva), sizeof(ucall));

vcpu_run_complete_io(vcpu);
if (uc)
memcpy(uc, &ucall, sizeof(ucall));
return addr_gva2hva(vcpu->vm, gva);
}

return ucall.cmd;
return NULL;
}
19 changes: 3 additions & 16 deletions tools/testing/selftests/kvm/lib/riscv/ucall.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,27 +51,15 @@ void ucall_arch_do_ucall(vm_vaddr_t uc)
uc, 0, 0, 0, 0, 0);
}

uint64_t ucall_arch_get_ucall(struct kvm_vcpu *vcpu, struct ucall *uc)
void *ucall_arch_get_ucall(struct kvm_vcpu *vcpu)
{
struct kvm_run *run = vcpu->run;
struct ucall ucall = {};

if (uc)
memset(uc, 0, sizeof(*uc));

if (run->exit_reason == KVM_EXIT_RISCV_SBI &&
run->riscv_sbi.extension_id == KVM_RISCV_SELFTESTS_SBI_EXT) {
switch (run->riscv_sbi.function_id) {
case KVM_RISCV_SELFTESTS_SBI_UCALL:
memcpy(&ucall,
addr_gva2hva(vcpu->vm, run->riscv_sbi.args[0]),
sizeof(ucall));

vcpu_run_complete_io(vcpu);
if (uc)
memcpy(uc, &ucall, sizeof(ucall));

break;
return addr_gva2hva(vcpu->vm, run->riscv_sbi.args[0]);
case KVM_RISCV_SELFTESTS_SBI_UNEXP:
vcpu_dump(stderr, vcpu, 2);
TEST_ASSERT(0, "Unexpected trap taken by guest");
Expand All @@ -80,6 +68,5 @@ uint64_t ucall_arch_get_ucall(struct kvm_vcpu *vcpu, struct ucall *uc)
break;
}
}

return ucall.cmd;
return NULL;
}
16 changes: 3 additions & 13 deletions tools/testing/selftests/kvm/lib/s390x/ucall.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,27 +20,17 @@ void ucall_arch_do_ucall(vm_vaddr_t uc)
asm volatile ("diag 0,%0,0x501" : : "a"(uc) : "memory");
}

uint64_t ucall_arch_get_ucall(struct kvm_vcpu *vcpu, struct ucall *uc)
void *ucall_arch_get_ucall(struct kvm_vcpu *vcpu)
{
struct kvm_run *run = vcpu->run;
struct ucall ucall = {};

if (uc)
memset(uc, 0, sizeof(*uc));

if (run->exit_reason == KVM_EXIT_S390_SIEIC &&
run->s390_sieic.icptcode == 4 &&
(run->s390_sieic.ipa >> 8) == 0x83 && /* 0x83 means DIAGNOSE */
(run->s390_sieic.ipb >> 16) == 0x501) {
int reg = run->s390_sieic.ipa & 0xf;

memcpy(&ucall, addr_gva2hva(vcpu->vm, run->s.regs.gprs[reg]),
sizeof(ucall));

vcpu_run_complete_io(vcpu);
if (uc)
memcpy(uc, &ucall, sizeof(ucall));
return addr_gva2hva(vcpu->vm, run->s.regs.gprs[reg]);
}

return ucall.cmd;
return NULL;
}
19 changes: 19 additions & 0 deletions tools/testing/selftests/kvm/lib/ucall_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,22 @@ void ucall(uint64_t cmd, int nargs, ...)

ucall_arch_do_ucall((vm_vaddr_t)&uc);
}

uint64_t get_ucall(struct kvm_vcpu *vcpu, struct ucall *uc)
{
struct ucall ucall;
void *addr;

if (!uc)
uc = &ucall;

addr = ucall_arch_get_ucall(vcpu);
if (addr) {
memcpy(uc, addr, sizeof(*uc));
vcpu_run_complete_io(vcpu);
} else {
memset(uc, 0, sizeof(*uc));
}

return uc->cmd;
}
16 changes: 3 additions & 13 deletions tools/testing/selftests/kvm/lib/x86_64/ucall.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,25 +22,15 @@ void ucall_arch_do_ucall(vm_vaddr_t uc)
: : [port] "d" (UCALL_PIO_PORT), "D" (uc) : "rax", "memory");
}

uint64_t ucall_arch_get_ucall(struct kvm_vcpu *vcpu, struct ucall *uc)
void *ucall_arch_get_ucall(struct kvm_vcpu *vcpu)
{
struct kvm_run *run = vcpu->run;
struct ucall ucall = {};

if (uc)
memset(uc, 0, sizeof(*uc));

if (run->exit_reason == KVM_EXIT_IO && run->io.port == UCALL_PIO_PORT) {
struct kvm_regs regs;

vcpu_regs_get(vcpu, &regs);
memcpy(&ucall, addr_gva2hva(vcpu->vm, (vm_vaddr_t)regs.rdi),
sizeof(ucall));

vcpu_run_complete_io(vcpu);
if (uc)
memcpy(uc, &ucall, sizeof(ucall));
return addr_gva2hva(vcpu->vm, regs.rdi);
}

return ucall.cmd;
return NULL;
}

0 comments on commit ef38871

Please sign in to comment.