@@ -271,3 +271,39 @@ Returns:
Request initialization of the Statistical Profiling Extension for this VCPU.
Must be done after initializaing the in-kernel irqchip and after setting the
Profiling Buffer management interrupt number for the VCPU.
+
+5.3 ATTRIBUTE: KVM_ARM_VCPU_SPE_STOP
+------------------------------------
+
+:Parameters: in kvm_device_attr.addr the address to the flag that specifies
+ what KVM should do when the guest enables profiling
+
+The flag must be exactly one of:
+
+- KVM_ARM_VCPU_SPE_STOP_TRAP: trap all register accesses and ignore the guest
+ trying to enable profiling.
+- KVM_ARM_VCPU_SPE_STOP_EXIT: exit to userspace when the guest tries to enable
+ profiling.
+- KVM_ARM_VCPU_SPE_RESUME: resume profiling, if it was previously stopped using
+ this attribute.
+
+If KVM detects that a vcpu is trying to run with SPE enabled when
+KVM_ARM_VCPU_STOP_EXIT is set, KVM_RUN will return without entering the guest
+with kvm_run.exit_reason equal to KVM_EXIT_FAIL_ENTRY, and the fail_entry struct
+will be zeroed.
+
+Returns:
+
+ ======= ============================================
+ -EAGAIN SPE not initialized
+ -EFAULT Error accessing the flag
+ -EINVAL Invalid flag
+ -ENXIO SPE not supported or not properly configured
+ ======= ============================================
+
+Request that KVM disables SPE for the given vcpu. This can be useful for
+migration, which relies on tracking dirty pages by write-protecting memory, but
+breaks SPE in the guest as KVM does not handle buffer stage 2 faults.
+
+The attribute must be set after SPE has been initialized successfully. It can be
+set multiple times, with the latest value overwritting the previous one.
@@ -371,6 +371,10 @@ struct kvm_arm_copy_mte_tags {
#define KVM_ARM_VCPU_SPE_CTRL 3
#define KVM_ARM_VCPU_SPE_IRQ 0
#define KVM_ARM_VCPU_SPE_INIT 1
+#define KVM_ARM_VCPU_SPE_STOP 2
+#define KVM_ARM_VCPU_SPE_STOP_TRAP (1 << 0)
+#define KVM_ARM_VCPU_SPE_STOP_EXIT (1 << 1)
+#define KVM_ARM_VCPU_SPE_RESUME (1 << 2)
/* KVM_IRQ_LINE irq field index values */
#define KVM_ARM_IRQ_VCPU2_SHIFT 28
@@ -222,14 +222,14 @@ int kvm_spe_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
if (!kvm_vcpu_supports_spe(vcpu))
return -ENXIO;
- if (vcpu->arch.spe.initialized)
- return -EBUSY;
-
switch (attr->attr) {
case KVM_ARM_VCPU_SPE_IRQ: {
int __user *uaddr = (int __user *)(long)attr->addr;
int irq;
+ if (vcpu->arch.spe.initialized)
+ return -EBUSY;
+
if (vcpu->arch.spe.irq_num)
return -EBUSY;
@@ -250,11 +250,27 @@ int kvm_spe_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
if (!vgic_initialized(vcpu->kvm))
return -ENXIO;
+ if (vcpu->arch.spe.initialized)
+ return -EBUSY;
+
if (kvm_vgic_set_owner(vcpu, vcpu->arch.spe.irq_num, &vcpu->arch.spe))
return -ENXIO;
vcpu->arch.spe.initialized = true;
return 0;
+ case KVM_ARM_VCPU_SPE_STOP: {
+ int __user *uaddr = (int __user *)(long)attr->addr;
+ int flags;
+
+ if (!vcpu->arch.spe.initialized)
+ return -EAGAIN;
+
+ if (get_user(flags, uaddr))
+ return -EFAULT;
+
+ if (!flags)
+ return -EINVAL;
+ }
}
return -ENXIO;
@@ -292,6 +308,7 @@ int kvm_spe_has_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
switch(attr->attr) {
case KVM_ARM_VCPU_SPE_IRQ:
case KVM_ARM_VCPU_SPE_INIT:
+ case KVM_ARM_VCPU_SPE_STOP:
return 0;
}
Add the KVM_ARM_VCPU_SPE_CTRL(KVM_ARM_VCPU_SPE_STOP) VCPU attribute to allow userspace to request that KVM disables profiling for that VCPU. The ioctl does nothing yet. Signed-off-by: Alexandru Elisei <alexandru.elisei@arm.com> --- Documentation/virt/kvm/devices/vcpu.rst | 36 +++++++++++++++++++++++++ arch/arm64/include/uapi/asm/kvm.h | 4 +++ arch/arm64/kvm/spe.c | 23 +++++++++++++--- 3 files changed, 60 insertions(+), 3 deletions(-)