History

KVM: arm64: timers: Allow userspace to set the global counter offset

And this is the moment you have all been waiting for: setting the counter offset from userspace. We expose a brand new capability that reports the ability to set the offset for both the virtual and physical sides. In keeping with the architecture, the offset is expressed as a delta that is substracted from the physical counter value. Once this new API is used, there is no going back, and the counters cannot be written to to set the offsets implicitly (the writes are instead ignored).

Marc Zyngier committed 3 years ago

Commit 30ec7991 parent 96906a95 files · +73 −5Browse files

Unified · Split

5 files
  1. arch/arm64/include/asm/kvm_host.h +4 −0
  2. arch/arm64/include/uapi/asm/kvm.h +9 −0
  3. arch/arm64/kvm/arch_timer.c +49 −5
  4. arch/arm64/kvm/arm.c +8 −0
  5. include/uapi/linux/kvm.h +3 −0
arch/arm64/include/asm/kvm_host.h+4−0
@@ -221,6 +221,8 @@ struct kvm_arch { · 220 unmodified lines
221221 #define KVM_ARCH_FLAG_EL1_32BIT 4
222222 /* PSCI SYSTEM_SUSPEND enabled for the guest */
223223 #define KVM_ARCH_FLAG_SYSTEM_SUSPEND_ENABLED 5
224+ /* VM counter offset */
225+#define KVM_ARCH_FLAG_VM_COUNTER_OFFSET 6
224226
225227 unsigned long flags;
226228
@@ -1010,6 +1012,8 @@ int kvm_arm_vcpu_arch_has_attr(struct kvm_vcpu *vcpu, · 783 unmodified lines
10101012
10111013 long kvm_vm_ioctl_mte_copy_tags(struct kvm *kvm,
10121014 struct kvm_arm_copy_mte_tags *copy_tags);
1015+int kvm_vm_ioctl_set_counter_offset(struct kvm *kvm,
1016+ struct kvm_arm_counter_offset *offset);
10131017
10141018 /* Guest/host FPSIMD coordination helpers */
10151019 int kvm_arch_vcpu_run_map_fp(struct kvm_vcpu *vcpu);
arch/arm64/include/uapi/asm/kvm.h+9−0
@@ -198,6 +198,15 @@ struct kvm_arm_copy_mte_tags { · 197 unmodified lines
198198 __u64 reserved[2];
199199 };
200200
201+/*
202+ * Counter/Timer offset structure. Describe the virtual/physical offset.
203+ * To be used with KVM_ARM_SET_COUNTER_OFFSET.
204+ */
205+struct kvm_arm_counter_offset {
206+ __u64 counter_offset;
207+ __u64 reserved;
208+};
209+
201210 #define KVM_ARM_TAGS_TO_GUEST 0
202211 #define KVM_ARM_TAGS_FROM_GUEST 1
203212
arch/arm64/kvm/arch_timer.c+49−5
@@ -851,9 +851,11 @@ void kvm_timer_vcpu_init(struct kvm_vcpu *vcpu) · 850 unmodified lines
851851 ptimer->vcpu = vcpu;
852852 ptimer->offset.vm_offset = &vcpu->kvm->arch.timer_data.poffset;
853853
854− /* Synchronize cntvoff across all vtimers of a VM. */
855− timer_set_offset(vtimer, kvm_phys_timer_read());
856− timer_set_offset(ptimer, 0);
854+ /* Synchronize offsets across timers of a VM if not already provided */
855+ if (!test_bit(KVM_ARCH_FLAG_VM_COUNTER_OFFSET, &vcpu->kvm->arch.flags)) {
856+ timer_set_offset(vtimer, kvm_phys_timer_read());
857+ timer_set_offset(ptimer, 0);
858+ }
857859
858860 hrtimer_init(&timer->bg_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS_HARD);
859861 timer->bg_timer.function = kvm_bg_timer_expire;
@@ -897,8 +899,11 @@ int kvm_arm_timer_set_reg(struct kvm_vcpu *vcpu, u64 regid, u64 value) · 37 unmodified lines
897899 kvm_arm_timer_write(vcpu, timer, TIMER_REG_CTL, value);
898900 break;
899901 case KVM_REG_ARM_TIMER_CNT:
900− timer = vcpu_vtimer(vcpu);
901− timer_set_offset(timer, kvm_phys_timer_read() - value);
902+ if (!test_bit(KVM_ARCH_FLAG_VM_COUNTER_OFFSET,
903+ &vcpu->kvm->arch.flags)) {
904+ timer = vcpu_vtimer(vcpu);
905+ timer_set_offset(timer, kvm_phys_timer_read() - value);
906+ }
902907 break;
903908 case KVM_REG_ARM_TIMER_CVAL:
904909 timer = vcpu_vtimer(vcpu);
@@ -908,6 +913,13 @@ int kvm_arm_timer_set_reg(struct kvm_vcpu *vcpu, u64 regid, u64 value) · 3 unmodified lines
908913 timer = vcpu_ptimer(vcpu);
909914 kvm_arm_timer_write(vcpu, timer, TIMER_REG_CTL, value);
910915 break;
916+ case KVM_REG_ARM_PTIMER_CNT:
917+ if (!test_bit(KVM_ARCH_FLAG_VM_COUNTER_OFFSET,
918+ &vcpu->kvm->arch.flags)) {
919+ timer = vcpu_ptimer(vcpu);
920+ timer_set_offset(timer, kvm_phys_timer_read() - value);
921+ }
922+ break;
911923 case KVM_REG_ARM_PTIMER_CVAL:
912924 timer = vcpu_ptimer(vcpu);
913925 kvm_arm_timer_write(vcpu, timer, TIMER_REG_CVAL, value);
@@ -1443,3 +1455,35 @@ int kvm_arm_timer_has_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr) · 529 unmodified lines
14431455
14441456 return -ENXIO;
14451457 }
1458+
1459+int kvm_vm_ioctl_set_counter_offset(struct kvm *kvm,
1460+ struct kvm_arm_counter_offset *offset)
1461+{
1462+ int ret = 0;
1463+
1464+ if (offset->reserved)
1465+ return -EINVAL;
1466+
1467+ mutex_lock(&kvm->lock);
1468+
1469+ if (lock_all_vcpus(kvm)) {
1470+ set_bit(KVM_ARCH_FLAG_VM_COUNTER_OFFSET, &kvm->arch.flags);
1471+
1472+ /*
1473+ * If userspace decides to set the offset using this
1474+ * API rather than merely restoring the counter
1475+ * values, the offset applies to both the virtual and
1476+ * physical views.
1477+ */
1478+ kvm->arch.timer_data.voffset = offset->counter_offset;
1479+ kvm->arch.timer_data.poffset = offset->counter_offset;
1480+
1481+ unlock_all_vcpus(kvm);
1482+ } else {
1483+ ret = -EBUSY;
1484+ }
1485+
1486+ mutex_unlock(&kvm->lock);
1487+
1488+ return ret;
1489+}
arch/arm64/kvm/arm.c+8−0
@@ -220,6 +220,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) · 219 unmodified lines
220220 case KVM_CAP_VCPU_ATTRIBUTES:
221221 case KVM_CAP_PTP_KVM:
222222 case KVM_CAP_ARM_SYSTEM_SUSPEND:
223+ case KVM_CAP_COUNTER_OFFSET:
223224 r = 1;
224225 break;
225226 case KVM_CAP_SET_GUEST_DEBUG2:
@@ -1479,6 +1480,13 @@ long kvm_arch_vm_ioctl(struct file *filp, · 1253 unmodified lines
14791480 return -EFAULT;
14801481 return kvm_vm_ioctl_mte_copy_tags(kvm, &copy_tags);
14811482 }
1483+ case KVM_ARM_SET_COUNTER_OFFSET: {
1484+ struct kvm_arm_counter_offset offset;
1485+
1486+ if (copy_from_user(&offset, argp, sizeof(offset)))
1487+ return -EFAULT;
1488+ return kvm_vm_ioctl_set_counter_offset(kvm, &offset);
1489+ }
14821490 default:
14831491 return -EINVAL;
14841492 }
include/uapi/linux/kvm.h+3−0
@@ -1184,6 +1184,7 @@ struct kvm_ppc_resize_hpt { · 1183 unmodified lines
11841184 #define KVM_CAP_S390_PROTECTED_ASYNC_DISABLE 224
11851185 #define KVM_CAP_DIRTY_LOG_RING_WITH_BITMAP 225
11861186 #define KVM_CAP_PMU_EVENT_MASKED_EVENTS 226
1187+#define KVM_CAP_COUNTER_OFFSET 227
11871188
11881189 #ifdef KVM_CAP_IRQ_ROUTING
11891190
@@ -1543,6 +1544,8 @@ struct kvm_s390_ucas_mapping { · 353 unmodified lines
15431544 #define KVM_SET_PMU_EVENT_FILTER _IOW(KVMIO, 0xb2, struct kvm_pmu_event_filter)
15441545 #define KVM_PPC_SVM_OFF _IO(KVMIO, 0xb3)
15451546 #define KVM_ARM_MTE_COPY_TAGS _IOR(KVMIO, 0xb4, struct kvm_arm_copy_mte_tags)
1547+/* Available with KVM_CAP_COUNTER_OFFSET */
1548+#define KVM_ARM_SET_COUNTER_OFFSET _IOW(KVMIO, 0xb5, struct kvm_arm_counter_offset)
15461549
15471550 /* ioctl for vm fd */
15481551 #define KVM_CREATE_DEVICE _IOWR(KVMIO, 0xe0, struct kvm_create_device)

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t