KVM: arm/arm64: Make vgic_v3_check_base more broadly usable
authorChristoffer Dall <cdall@linaro.org>
Mon, 8 May 2017 10:23:51 +0000 (12:23 +0200)
committerChristoffer Dall <cdall@linaro.org>
Tue, 9 May 2017 10:19:31 +0000 (12:19 +0200)
As we are about to fiddle with the IO device registration mechanism,
let's be a little more careful when setting base addresses as early as
possible.  When setting a base address, we can check that there's
address space enough for its scope and when the last of the two
base addresses (dist and redist) get set, we can also check if the
regions overlap at that time.

This allows us to provide error messages to the user at time when trying
to set the base address, as opposed to later when trying to run the VM.

To do this,  we make vgic_v3_check_base available in the core vgic-v3
code as well as in the other parts of the GICv3 code, namely the MMIO
config code.

We also return true for undefined base addresses so that the function
can be used before all base addresses are set; all callers already check
for uninitialized addresses before calling this function.

Signed-off-by: Christoffer Dall <cdall@linaro.org>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
virt/kvm/arm/vgic/vgic-v3.c
virt/kvm/arm/vgic/vgic.h

index 12e52a06e14691eddb925eccc144a9d04c596654..2d53d7a24bda65e439f8b4138654ae1a24db46be 100644 (file)
@@ -329,19 +329,30 @@ int vgic_v3_save_pending_tables(struct kvm *kvm)
        return 0;
 }
 
-/* check for overlapping regions and for regions crossing the end of memory */
-static bool vgic_v3_check_base(struct kvm *kvm)
+/*
+ * Check for overlapping regions and for regions crossing the end of memory
+ * for base addresses which have already been set.
+ */
+bool vgic_v3_check_base(struct kvm *kvm)
 {
        struct vgic_dist *d = &kvm->arch.vgic;
        gpa_t redist_size = KVM_VGIC_V3_REDIST_SIZE;
 
        redist_size *= atomic_read(&kvm->online_vcpus);
 
-       if (d->vgic_dist_base + KVM_VGIC_V3_DIST_SIZE < d->vgic_dist_base)
+       if (!IS_VGIC_ADDR_UNDEF(d->vgic_dist_base) &&
+           d->vgic_dist_base + KVM_VGIC_V3_DIST_SIZE < d->vgic_dist_base)
                return false;
-       if (d->vgic_redist_base + redist_size < d->vgic_redist_base)
+
+       if (!IS_VGIC_ADDR_UNDEF(d->vgic_redist_base) &&
+           d->vgic_redist_base + redist_size < d->vgic_redist_base)
                return false;
 
+       /* Both base addresses must be set to check if they overlap */
+       if (IS_VGIC_ADDR_UNDEF(d->vgic_dist_base) ||
+           IS_VGIC_ADDR_UNDEF(d->vgic_redist_base))
+               return true;
+
        if (d->vgic_dist_base + KVM_VGIC_V3_DIST_SIZE <= d->vgic_redist_base)
                return true;
        if (d->vgic_redist_base + redist_size <= d->vgic_dist_base)
index a2aeaa866b18f4232efc06d8def74015f2c6ccb2..89eb935c05befb9c10f295dedeb0e54f5dee0701 100644 (file)
@@ -175,6 +175,7 @@ int vgic_v3_map_resources(struct kvm *kvm);
 int vgic_v3_lpi_sync_pending_status(struct kvm *kvm, struct vgic_irq *irq);
 int vgic_v3_save_pending_tables(struct kvm *kvm);
 int vgic_register_redist_iodevs(struct kvm *kvm);
+bool vgic_v3_check_base(struct kvm *kvm);
 
 void vgic_v3_load(struct kvm_vcpu *vcpu);
 void vgic_v3_put(struct kvm_vcpu *vcpu);