1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (C) 2019 Arm Ltd.
4 #include <linux/arm-smccc.h>
5 #include <linux/kvm_host.h>
7 #include <asm/kvm_mmu.h>
8 #include <asm/pvclock-abi.h>
10 #include <kvm/arm_hypercalls.h>
12 void kvm_update_stolen_time(struct kvm_vcpu
*vcpu
)
14 struct kvm
*kvm
= vcpu
->kvm
;
19 u64 base
= vcpu
->arch
.steal
.base
;
21 if (base
== GPA_INVALID
)
24 /* Let's do the local bookkeeping */
25 steal
= vcpu
->arch
.steal
.steal
;
26 steal
+= current
->sched_info
.run_delay
- vcpu
->arch
.steal
.last_steal
;
27 vcpu
->arch
.steal
.last_steal
= current
->sched_info
.run_delay
;
28 vcpu
->arch
.steal
.steal
= steal
;
30 steal_le
= cpu_to_le64(steal
);
31 idx
= srcu_read_lock(&kvm
->srcu
);
32 offset
= offsetof(struct pvclock_vcpu_stolen_time
, stolen_time
);
33 kvm_put_guest(kvm
, base
+ offset
, steal_le
, u64
);
34 srcu_read_unlock(&kvm
->srcu
, idx
);
37 long kvm_hypercall_pv_features(struct kvm_vcpu
*vcpu
)
39 u32 feature
= smccc_get_arg1(vcpu
);
40 long val
= SMCCC_RET_NOT_SUPPORTED
;
43 case ARM_SMCCC_HV_PV_TIME_FEATURES
:
44 case ARM_SMCCC_HV_PV_TIME_ST
:
45 val
= SMCCC_RET_SUCCESS
;
52 gpa_t
kvm_init_stolen_time(struct kvm_vcpu
*vcpu
)
54 struct pvclock_vcpu_stolen_time init_values
= {};
55 struct kvm
*kvm
= vcpu
->kvm
;
56 u64 base
= vcpu
->arch
.steal
.base
;
59 if (base
== GPA_INVALID
)
63 * Start counting stolen time from the time the guest requests
64 * the feature enabled.
66 vcpu
->arch
.steal
.steal
= 0;
67 vcpu
->arch
.steal
.last_steal
= current
->sched_info
.run_delay
;
69 idx
= srcu_read_lock(&kvm
->srcu
);
70 kvm_write_guest(kvm
, base
, &init_values
, sizeof(init_values
));
71 srcu_read_unlock(&kvm
->srcu
, idx
);
76 int kvm_arm_pvtime_set_attr(struct kvm_vcpu
*vcpu
,
77 struct kvm_device_attr
*attr
)
79 u64 __user
*user
= (u64 __user
*)attr
->addr
;
80 struct kvm
*kvm
= vcpu
->kvm
;
85 if (attr
->attr
!= KVM_ARM_VCPU_PVTIME_IPA
)
88 if (get_user(ipa
, user
))
90 if (!IS_ALIGNED(ipa
, 64))
92 if (vcpu
->arch
.steal
.base
!= GPA_INVALID
)
95 /* Check the address is in a valid memslot */
96 idx
= srcu_read_lock(&kvm
->srcu
);
97 if (kvm_is_error_hva(gfn_to_hva(kvm
, ipa
>> PAGE_SHIFT
)))
99 srcu_read_unlock(&kvm
->srcu
, idx
);
102 vcpu
->arch
.steal
.base
= ipa
;
107 int kvm_arm_pvtime_get_attr(struct kvm_vcpu
*vcpu
,
108 struct kvm_device_attr
*attr
)
110 u64 __user
*user
= (u64 __user
*)attr
->addr
;
113 if (attr
->attr
!= KVM_ARM_VCPU_PVTIME_IPA
)
116 ipa
= vcpu
->arch
.steal
.base
;
118 if (put_user(ipa
, user
))
123 int kvm_arm_pvtime_has_attr(struct kvm_vcpu
*vcpu
,
124 struct kvm_device_attr
*attr
)
126 switch (attr
->attr
) {
127 case KVM_ARM_VCPU_PVTIME_IPA
: