xref: /kvmtool/arm/aarch64/pvtime.c (revision 6a1f699108e5c2a280d7cd1f1ae4816b8250a29f)
17d4671e5SSebastian Ene #include "kvm/kvm.h"
27d4671e5SSebastian Ene #include "kvm/kvm-cpu.h"
37d4671e5SSebastian Ene #include "kvm/util.h"
47d4671e5SSebastian Ene 
57d4671e5SSebastian Ene #include <linux/byteorder.h>
67d4671e5SSebastian Ene #include <linux/types.h>
77d4671e5SSebastian Ene 
87d4671e5SSebastian Ene #define ARM_PVTIME_STRUCT_SIZE		(64)
97d4671e5SSebastian Ene 
107d4671e5SSebastian Ene static void *usr_mem;
117d4671e5SSebastian Ene 
pvtime__alloc_region(struct kvm * kvm)127d4671e5SSebastian Ene static int pvtime__alloc_region(struct kvm *kvm)
137d4671e5SSebastian Ene {
147d4671e5SSebastian Ene 	char *mem;
157d4671e5SSebastian Ene 	int ret = 0;
167d4671e5SSebastian Ene 
17*6a1f6991SAlexandru Elisei 	mem = mmap(NULL, ARM_PVTIME_SIZE, PROT_RW,
187d4671e5SSebastian Ene 		   MAP_ANON_NORESERVE, -1, 0);
197d4671e5SSebastian Ene 	if (mem == MAP_FAILED)
207d4671e5SSebastian Ene 		return -errno;
217d4671e5SSebastian Ene 
227d4671e5SSebastian Ene 	ret = kvm__register_ram(kvm, ARM_PVTIME_BASE,
23*6a1f6991SAlexandru Elisei 				ARM_PVTIME_SIZE, mem);
247d4671e5SSebastian Ene 	if (ret) {
25*6a1f6991SAlexandru Elisei 		munmap(mem, ARM_PVTIME_SIZE);
267d4671e5SSebastian Ene 		return ret;
277d4671e5SSebastian Ene 	}
287d4671e5SSebastian Ene 
297d4671e5SSebastian Ene 	usr_mem = mem;
307d4671e5SSebastian Ene 	return ret;
317d4671e5SSebastian Ene }
327d4671e5SSebastian Ene 
pvtime__teardown_region(struct kvm * kvm)337d4671e5SSebastian Ene static int pvtime__teardown_region(struct kvm *kvm)
347d4671e5SSebastian Ene {
357d4671e5SSebastian Ene 	if (usr_mem == NULL)
367d4671e5SSebastian Ene 		return 0;
377d4671e5SSebastian Ene 
387d4671e5SSebastian Ene 	kvm__destroy_mem(kvm, ARM_PVTIME_BASE,
39*6a1f6991SAlexandru Elisei 			 ARM_PVTIME_SIZE, usr_mem);
40*6a1f6991SAlexandru Elisei 	munmap(usr_mem, ARM_PVTIME_SIZE);
417d4671e5SSebastian Ene 	usr_mem = NULL;
427d4671e5SSebastian Ene 	return 0;
437d4671e5SSebastian Ene }
447d4671e5SSebastian Ene 
kvm_cpu__setup_pvtime(struct kvm_cpu * vcpu)457d4671e5SSebastian Ene int kvm_cpu__setup_pvtime(struct kvm_cpu *vcpu)
467d4671e5SSebastian Ene {
477d4671e5SSebastian Ene 	int ret;
487d4671e5SSebastian Ene 	bool has_stolen_time;
497d4671e5SSebastian Ene 	u64 pvtime_guest_addr = ARM_PVTIME_BASE + vcpu->cpu_id *
507d4671e5SSebastian Ene 		ARM_PVTIME_STRUCT_SIZE;
51ffa86546SSebastian Ene 	struct kvm_config_arch *kvm_cfg = NULL;
527d4671e5SSebastian Ene 	struct kvm_device_attr pvtime_attr = (struct kvm_device_attr) {
537d4671e5SSebastian Ene 		.group	= KVM_ARM_VCPU_PVTIME_CTRL,
547d4671e5SSebastian Ene 		.attr	= KVM_ARM_VCPU_PVTIME_IPA
557d4671e5SSebastian Ene 	};
567d4671e5SSebastian Ene 
57ffa86546SSebastian Ene 	kvm_cfg = &vcpu->kvm->cfg.arch;
587d4671e5SSebastian Ene 	if (kvm_cfg->no_pvtime)
597d4671e5SSebastian Ene 		return 0;
607d4671e5SSebastian Ene 
617d4671e5SSebastian Ene 	has_stolen_time = kvm__supports_extension(vcpu->kvm,
627d4671e5SSebastian Ene 						  KVM_CAP_STEAL_TIME);
637d4671e5SSebastian Ene 	if (!has_stolen_time) {
647d4671e5SSebastian Ene 		kvm_cfg->no_pvtime = true;
657d4671e5SSebastian Ene 		return 0;
667d4671e5SSebastian Ene 	}
677d4671e5SSebastian Ene 
687d4671e5SSebastian Ene 	ret = ioctl(vcpu->vcpu_fd, KVM_HAS_DEVICE_ATTR, &pvtime_attr);
697d4671e5SSebastian Ene 	if (ret) {
707d4671e5SSebastian Ene 		ret = -errno;
717d4671e5SSebastian Ene 		perror("KVM_HAS_DEVICE_ATTR failed\n");
727d4671e5SSebastian Ene 		goto out_err;
737d4671e5SSebastian Ene 	}
747d4671e5SSebastian Ene 
757d4671e5SSebastian Ene 	if (!usr_mem) {
767d4671e5SSebastian Ene 		ret = pvtime__alloc_region(vcpu->kvm);
777d4671e5SSebastian Ene 		if (ret) {
787d4671e5SSebastian Ene 			perror("Failed allocating pvtime region\n");
797d4671e5SSebastian Ene 			goto out_err;
807d4671e5SSebastian Ene 		}
817d4671e5SSebastian Ene 	}
827d4671e5SSebastian Ene 
837d4671e5SSebastian Ene 	pvtime_attr.addr = (u64)&pvtime_guest_addr;
847d4671e5SSebastian Ene 	ret = ioctl(vcpu->vcpu_fd, KVM_SET_DEVICE_ATTR, &pvtime_attr);
857d4671e5SSebastian Ene 	if (!ret)
867d4671e5SSebastian Ene 		return 0;
877d4671e5SSebastian Ene 
887d4671e5SSebastian Ene 	ret = -errno;
897d4671e5SSebastian Ene 	perror("KVM_SET_DEVICE_ATTR failed\n");
907d4671e5SSebastian Ene 	pvtime__teardown_region(vcpu->kvm);
917d4671e5SSebastian Ene out_err:
927d4671e5SSebastian Ene 	return ret;
937d4671e5SSebastian Ene }
947d4671e5SSebastian Ene 
kvm_cpu__teardown_pvtime(struct kvm * kvm)957d4671e5SSebastian Ene int kvm_cpu__teardown_pvtime(struct kvm *kvm)
967d4671e5SSebastian Ene {
977d4671e5SSebastian Ene 	return pvtime__teardown_region(kvm);
987d4671e5SSebastian Ene }
99