]> 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 2d9b4795edb2beecd04588c791735d155cc05741..ac658bd6319641248cd6ef6d88ed8b36132cff7b 100644 (file)
@@ -16,6 +16,7 @@
  * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 
+#include <linux/bug.h>
 #include <linux/cpu_pm.h>
 #include <linux/errno.h>
 #include <linux/err.h>
@@ -29,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>
@@ -41,6 +43,7 @@
 #include <asm/mman.h>
 #include <asm/tlbflush.h>
 #include <asm/cacheflush.h>
+#include <asm/cpufeature.h>
 #include <asm/virt.h>
 #include <asm/kvm_arm.h>
 #include <asm/kvm_asm.h>
@@ -163,7 +166,7 @@ int kvm_arch_create_vcpu_debugfs(struct kvm_vcpu *vcpu)
        return 0;
 }
 
-int kvm_arch_vcpu_fault(struct kvm_vcpu *vcpu, struct vm_fault *vmf)
+vm_fault_t kvm_arch_vcpu_fault(struct kvm_vcpu *vcpu, struct vm_fault *vmf)
 {
        return VM_FAULT_SIGBUS;
 }
@@ -249,6 +252,21 @@ long kvm_arch_dev_ioctl(struct file *filp,
        return -EINVAL;
 }
 
+struct kvm *kvm_arch_alloc_vm(void)
+{
+       if (!has_vhe())
+               return kzalloc(sizeof(struct kvm), GFP_KERNEL);
+
+       return vzalloc(sizeof(struct kvm));
+}
+
+void kvm_arch_free_vm(struct kvm *kvm)
+{
+       if (!has_vhe())
+               kfree(kvm);
+       else
+               vfree(kvm);
+}
 
 struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, unsigned int id)
 {
@@ -290,7 +308,6 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, unsigned int id)
 
 void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu)
 {
-       kvm_vgic_vcpu_early_init(vcpu);
 }
 
 void kvm_arch_vcpu_free(struct kvm_vcpu *vcpu)
@@ -363,10 +380,17 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
        kvm_vgic_load(vcpu);
        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)
 {
+       kvm_arch_vcpu_put_fp(vcpu);
        kvm_vcpu_put_sysregs(vcpu);
        kvm_timer_vcpu_put(vcpu);
        kvm_vgic_put(vcpu);
@@ -678,9 +702,6 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
                 */
                preempt_disable();
 
-               /* Flush FP/SIMD state that can't survive guest entry/exit */
-               kvm_fpsimd_flush_cpu_state();
-
                kvm_pmu_flush_hwstate(vcpu);
 
                local_irq_disable();
@@ -778,6 +799,8 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
                if (static_branch_unlikely(&userspace_irqchip_in_use))
                        kvm_timer_sync_hwstate(vcpu);
 
+               kvm_arch_vcpu_ctxsync_fp(vcpu);
+
                /*
                 * We may have taken a host interrupt in HYP mode (ie
                 * while executing the guest). This interrupt is still
@@ -1027,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)
 {
@@ -1107,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;
        }
@@ -1574,6 +1642,11 @@ int kvm_arch_init(void *opaque)
                return -ENODEV;
        }
 
+       if (!kvm_arch_check_sve_has_vhe()) {
+               kvm_pr_unimpl("SVE system without VHE unsupported.  Broken cpu?");
+               return -ENODEV;
+       }
+
        for_each_online_cpu(cpu) {
                smp_call_function_single(cpu, check_kvm_target_cpu, &ret, 1);
                if (ret < 0) {