xref: /kvmtool/arm/aarch64/pvtime.c (revision 6a1f699108e5c2a280d7cd1f1ae4816b8250a29f)
1 #include "kvm/kvm.h"
2 #include "kvm/kvm-cpu.h"
3 #include "kvm/util.h"
4 
5 #include <linux/byteorder.h>
6 #include <linux/types.h>
7 
8 #define ARM_PVTIME_STRUCT_SIZE		(64)
9 
10 static void *usr_mem;
11 
pvtime__alloc_region(struct kvm * kvm)12 static int pvtime__alloc_region(struct kvm *kvm)
13 {
14 	char *mem;
15 	int ret = 0;
16 
17 	mem = mmap(NULL, ARM_PVTIME_SIZE, PROT_RW,
18 		   MAP_ANON_NORESERVE, -1, 0);
19 	if (mem == MAP_FAILED)
20 		return -errno;
21 
22 	ret = kvm__register_ram(kvm, ARM_PVTIME_BASE,
23 				ARM_PVTIME_SIZE, mem);
24 	if (ret) {
25 		munmap(mem, ARM_PVTIME_SIZE);
26 		return ret;
27 	}
28 
29 	usr_mem = mem;
30 	return ret;
31 }
32 
pvtime__teardown_region(struct kvm * kvm)33 static int pvtime__teardown_region(struct kvm *kvm)
34 {
35 	if (usr_mem == NULL)
36 		return 0;
37 
38 	kvm__destroy_mem(kvm, ARM_PVTIME_BASE,
39 			 ARM_PVTIME_SIZE, usr_mem);
40 	munmap(usr_mem, ARM_PVTIME_SIZE);
41 	usr_mem = NULL;
42 	return 0;
43 }
44 
kvm_cpu__setup_pvtime(struct kvm_cpu * vcpu)45 int kvm_cpu__setup_pvtime(struct kvm_cpu *vcpu)
46 {
47 	int ret;
48 	bool has_stolen_time;
49 	u64 pvtime_guest_addr = ARM_PVTIME_BASE + vcpu->cpu_id *
50 		ARM_PVTIME_STRUCT_SIZE;
51 	struct kvm_config_arch *kvm_cfg = NULL;
52 	struct kvm_device_attr pvtime_attr = (struct kvm_device_attr) {
53 		.group	= KVM_ARM_VCPU_PVTIME_CTRL,
54 		.attr	= KVM_ARM_VCPU_PVTIME_IPA
55 	};
56 
57 	kvm_cfg = &vcpu->kvm->cfg.arch;
58 	if (kvm_cfg->no_pvtime)
59 		return 0;
60 
61 	has_stolen_time = kvm__supports_extension(vcpu->kvm,
62 						  KVM_CAP_STEAL_TIME);
63 	if (!has_stolen_time) {
64 		kvm_cfg->no_pvtime = true;
65 		return 0;
66 	}
67 
68 	ret = ioctl(vcpu->vcpu_fd, KVM_HAS_DEVICE_ATTR, &pvtime_attr);
69 	if (ret) {
70 		ret = -errno;
71 		perror("KVM_HAS_DEVICE_ATTR failed\n");
72 		goto out_err;
73 	}
74 
75 	if (!usr_mem) {
76 		ret = pvtime__alloc_region(vcpu->kvm);
77 		if (ret) {
78 			perror("Failed allocating pvtime region\n");
79 			goto out_err;
80 		}
81 	}
82 
83 	pvtime_attr.addr = (u64)&pvtime_guest_addr;
84 	ret = ioctl(vcpu->vcpu_fd, KVM_SET_DEVICE_ATTR, &pvtime_attr);
85 	if (!ret)
86 		return 0;
87 
88 	ret = -errno;
89 	perror("KVM_SET_DEVICE_ATTR failed\n");
90 	pvtime__teardown_region(vcpu->kvm);
91 out_err:
92 	return ret;
93 }
94 
kvm_cpu__teardown_pvtime(struct kvm * kvm)95 int kvm_cpu__teardown_pvtime(struct kvm *kvm)
96 {
97 	return pvtime__teardown_region(kvm);
98 }
99