]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - virt/kvm/arm/arm.c
KVM: arm: Add 32bit get/set events support
[linux.git] / virt / kvm / arm / arm.c
index 04e554cae3a2066e5eb6e4d2544efc84a62d88de..ac658bd6319641248cd6ef6d88ed8b36132cff7b 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/kvm.h>
 #include <linux/kvm_irqfd.h>
 #include <linux/irqbypass.h>
+#include <linux/sched/stat.h>
 #include <trace/events/kvm.h>
 #include <kvm/arm_pmu.h>
 #include <kvm/arm_psci.h>
@@ -380,6 +381,11 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
        kvm_timer_vcpu_load(vcpu);
        kvm_vcpu_load_sysregs(vcpu);
        kvm_arch_vcpu_load_fp(vcpu);
+
+       if (single_task_running())
+               vcpu_clear_wfe_traps(vcpu);
+       else
+               vcpu_set_wfe_traps(vcpu);
 }
 
 void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
@@ -1044,6 +1050,32 @@ static int kvm_arm_vcpu_has_attr(struct kvm_vcpu *vcpu,
        return ret;
 }
 
+static int kvm_arm_vcpu_get_events(struct kvm_vcpu *vcpu,
+                                  struct kvm_vcpu_events *events)
+{
+       memset(events, 0, sizeof(*events));
+
+       return __kvm_arm_vcpu_get_events(vcpu, events);
+}
+
+static int kvm_arm_vcpu_set_events(struct kvm_vcpu *vcpu,
+                                  struct kvm_vcpu_events *events)
+{
+       int i;
+
+       /* check whether the reserved field is zero */
+       for (i = 0; i < ARRAY_SIZE(events->reserved); i++)
+               if (events->reserved[i])
+                       return -EINVAL;
+
+       /* check whether the pad field is zero */
+       for (i = 0; i < ARRAY_SIZE(events->exception.pad); i++)
+               if (events->exception.pad[i])
+                       return -EINVAL;
+
+       return __kvm_arm_vcpu_set_events(vcpu, events);
+}
+
 long kvm_arch_vcpu_ioctl(struct file *filp,
                         unsigned int ioctl, unsigned long arg)
 {
@@ -1124,6 +1156,25 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
                r = kvm_arm_vcpu_has_attr(vcpu, &attr);
                break;
        }
+       case KVM_GET_VCPU_EVENTS: {
+               struct kvm_vcpu_events events;
+
+               if (kvm_arm_vcpu_get_events(vcpu, &events))
+                       return -EINVAL;
+
+               if (copy_to_user(argp, &events, sizeof(events)))
+                       return -EFAULT;
+
+               return 0;
+       }
+       case KVM_SET_VCPU_EVENTS: {
+               struct kvm_vcpu_events events;
+
+               if (copy_from_user(&events, argp, sizeof(events)))
+                       return -EFAULT;
+
+               return kvm_arm_vcpu_set_events(vcpu, &events);
+       }
        default:
                r = -EINVAL;
        }