1 // SPDX-License-Identifier: GPL-2.0
3 * ucall support. A ucall is a "hypercall to userspace".
5 * Copyright (C) 2018, Red Hat, Inc.
8 #include "../kvm_util_internal.h"
10 static vm_vaddr_t
*ucall_exit_mmio_addr
;
12 static bool ucall_mmio_init(struct kvm_vm
*vm
, vm_paddr_t gpa
)
14 if (kvm_userspace_memory_region_find(vm
, gpa
, gpa
+ 1))
17 virt_pg_map(vm
, gpa
, gpa
, 0);
19 ucall_exit_mmio_addr
= (vm_vaddr_t
*)gpa
;
20 sync_global_to_guest(vm
, ucall_exit_mmio_addr
);
25 void ucall_init(struct kvm_vm
*vm
, void *arg
)
27 vm_paddr_t gpa
, start
, end
, step
, offset
;
32 gpa
= (vm_paddr_t
)arg
;
33 ret
= ucall_mmio_init(vm
, gpa
);
34 TEST_ASSERT(ret
, "Can't set ucall mmio address to %lx", gpa
);
39 * Find an address within the allowed physical and virtual address
40 * spaces, that does _not_ have a KVM memory region associated with
41 * it. Identity mapping an address like this allows the guest to
42 * access it, but as KVM doesn't know what to do with it, it
43 * will assume it's something userspace handles and exit with
44 * KVM_EXIT_MMIO. Well, at least that's how it works for AArch64.
45 * Here we start with a guess that the addresses around 5/8th
46 * of the allowed space are unmapped and then work both down and
47 * up from there in 1/16th allowed space sized steps.
49 * Note, we need to use VA-bits - 1 when calculating the allowed
50 * virtual address space for an identity mapping because the upper
51 * half of the virtual address space is the two's complement of the
52 * lower and won't match physical addresses.
54 bits
= vm
->va_bits
- 1;
55 bits
= vm
->pa_bits
< bits
? vm
->pa_bits
: bits
;
59 for (offset
= 0; offset
< end
- start
; offset
+= step
) {
60 if (ucall_mmio_init(vm
, start
- offset
))
62 if (ucall_mmio_init(vm
, start
+ offset
))
65 TEST_FAIL("Can't find a ucall mmio address");
68 void ucall_uninit(struct kvm_vm
*vm
)
70 ucall_exit_mmio_addr
= 0;
71 sync_global_to_guest(vm
, ucall_exit_mmio_addr
);
74 void ucall(uint64_t cmd
, int nargs
, ...)
82 nargs
= nargs
<= UCALL_MAX_ARGS
? nargs
: UCALL_MAX_ARGS
;
85 for (i
= 0; i
< nargs
; ++i
)
86 uc
.args
[i
] = va_arg(va
, uint64_t);
89 *ucall_exit_mmio_addr
= (vm_vaddr_t
)&uc
;
92 uint64_t get_ucall(struct kvm_vm
*vm
, uint32_t vcpu_id
, struct ucall
*uc
)
94 struct kvm_run
*run
= vcpu_state(vm
, vcpu_id
);
95 struct ucall ucall
= {};
98 memset(uc
, 0, sizeof(*uc
));
100 if (run
->exit_reason
== KVM_EXIT_MMIO
&&
101 run
->mmio
.phys_addr
== (uint64_t)ucall_exit_mmio_addr
) {
104 TEST_ASSERT(run
->mmio
.is_write
&& run
->mmio
.len
== 8,
105 "Unexpected ucall exit mmio address access");
106 memcpy(&gva
, run
->mmio
.data
, sizeof(gva
));
107 memcpy(&ucall
, addr_gva2hva(vm
, gva
), sizeof(ucall
));
109 vcpu_run_complete_io(vm
, vcpu_id
);
111 memcpy(uc
, &ucall
, sizeof(ucall
));