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