KVM: arm64: vgic-v2: Add helper for legacy dist/cpuif base address setting
authorMarc Zyngier <maz@kernel.org>
Tue, 5 Jul 2022 13:34:33 +0000 (14:34 +0100)
committerMarc Zyngier <maz@kernel.org>
Sun, 17 Jul 2022 10:55:33 +0000 (11:55 +0100)
We carry a legacy interface to set the base addresses for GICv2.
As this is currently plumbed into the same handling code as
the modern interface, it limits the evolution we can make there.

Add a helper dedicated to this handling, with a view of maybe
removing this in the future.

Signed-off-by: Marc Zyngier <maz@kernel.org>
arch/arm64/kvm/arm.c
arch/arm64/kvm/vgic/vgic-kvm-device.c
include/kvm/arm_vgic.h

index a0188144a122be9ea8e7673f13a98c2dbd9eae64..fd26beacbbe5486a87bc34980f75c3b32e83e823 100644 (file)
@@ -1414,18 +1414,11 @@ void kvm_arch_flush_remote_tlbs_memslot(struct kvm *kvm,
 static int kvm_vm_ioctl_set_device_addr(struct kvm *kvm,
                                        struct kvm_arm_device_addr *dev_addr)
 {
-       unsigned long dev_id, type;
-
-       dev_id = (dev_addr->id & KVM_ARM_DEVICE_ID_MASK) >>
-               KVM_ARM_DEVICE_ID_SHIFT;
-       type = (dev_addr->id & KVM_ARM_DEVICE_TYPE_MASK) >>
-               KVM_ARM_DEVICE_TYPE_SHIFT;
-
-       switch (dev_id) {
+       switch (FIELD_GET(KVM_ARM_DEVICE_ID_MASK, dev_addr->id)) {
        case KVM_ARM_DEVICE_VGIC_V2:
                if (!vgic_present)
                        return -ENXIO;
-               return kvm_vgic_addr(kvm, type, &dev_addr->addr, true);
+               return kvm_set_legacy_vgic_v2_addr(kvm, dev_addr);
        default:
                return -ENODEV;
        }
index c17e5502c0b3b153fb0c01086480ab1906c230d9..04175fd55da6eaf783752fb59eb2541406458e96 100644 (file)
@@ -41,6 +41,38 @@ static int vgic_check_type(struct kvm *kvm, int type_needed)
                return 0;
 }
 
+int kvm_set_legacy_vgic_v2_addr(struct kvm *kvm, struct kvm_arm_device_addr *dev_addr)
+{
+       struct vgic_dist *vgic = &kvm->arch.vgic;
+       int r;
+
+       mutex_lock(&kvm->lock);
+       switch (FIELD_GET(KVM_ARM_DEVICE_TYPE_MASK, dev_addr->id)) {
+       case KVM_VGIC_V2_ADDR_TYPE_DIST:
+               r = vgic_check_type(kvm, KVM_DEV_TYPE_ARM_VGIC_V2);
+               if (!r)
+                       r = vgic_check_iorange(kvm, vgic->vgic_dist_base, dev_addr->addr,
+                                              SZ_4K, KVM_VGIC_V2_DIST_SIZE);
+               if (!r)
+                       vgic->vgic_dist_base = dev_addr->addr;
+               break;
+       case KVM_VGIC_V2_ADDR_TYPE_CPU:
+               r = vgic_check_type(kvm, KVM_DEV_TYPE_ARM_VGIC_V2);
+               if (!r)
+                       r = vgic_check_iorange(kvm, vgic->vgic_cpu_base, dev_addr->addr,
+                                              SZ_4K, KVM_VGIC_V2_CPU_SIZE);
+               if (!r)
+                       vgic->vgic_cpu_base = dev_addr->addr;
+               break;
+       default:
+               r = -ENODEV;
+       }
+
+       mutex_unlock(&kvm->lock);
+
+       return r;
+}
+
 /**
  * kvm_vgic_addr - set or get vgic VM base addresses
  * @kvm:   pointer to the vm struct
index 2d8f2e90edc2d88975b63d9d7c08eb47c31611b6..f79cce67563ea5d3bce1cdfeb52816a602e0c41c 100644 (file)
@@ -365,6 +365,7 @@ extern struct static_key_false vgic_v2_cpuif_trap;
 extern struct static_key_false vgic_v3_cpuif_trap;
 
 int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write);
+int kvm_set_legacy_vgic_v2_addr(struct kvm *kvm, struct kvm_arm_device_addr *dev_addr);
 void kvm_vgic_early_init(struct kvm *kvm);
 int kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu);
 int kvm_vgic_create(struct kvm *kvm, u32 type);