Skip to content

Commit

Permalink
KVM: arm/arm64: Adapt vgic_v3_check_base to multiple rdist regions
Browse files Browse the repository at this point in the history
vgic_v3_check_base() currently only handles the case of a unique
legacy redistributor region whose size is not explicitly set but
inferred, instead, from the number of online vcpus.

We adapt it to handle the case of multiple redistributor regions
with explicitly defined size. We rely on two new helpers:
- vgic_v3_rdist_overlap() is used to detect overlap with the dist
  region if defined
- vgic_v3_rd_region_size computes the size of the redist region,
  would it be a legacy unique region or a new explicitly sized
  region.

Signed-off-by: Eric Auger <[email protected]>
Reviewed-by: Christoffer Dall <[email protected]>
Signed-off-by: Marc Zyngier <[email protected]>
  • Loading branch information
eauger authored and Marc Zyngier committed May 25, 2018
1 parent ba7b3f1 commit 028bf27
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 17 deletions.
49 changes: 32 additions & 17 deletions virt/kvm/arm/vgic/vgic-v3.c
Original file line number Diff line number Diff line change
Expand Up @@ -419,38 +419,53 @@ int vgic_v3_save_pending_tables(struct kvm *kvm)
return 0;
}

/**
* vgic_v3_rdist_overlap - check if a region overlaps with any
* existing redistributor region
*
* @kvm: kvm handle
* @base: base of the region
* @size: size of region
*
* Return: true if there is an overlap
*/
bool vgic_v3_rdist_overlap(struct kvm *kvm, gpa_t base, size_t size)
{
struct vgic_dist *d = &kvm->arch.vgic;
struct vgic_redist_region *rdreg;

list_for_each_entry(rdreg, &d->rd_regions, list) {
if ((base + size > rdreg->base) &&
(base < rdreg->base + vgic_v3_rd_region_size(kvm, rdreg)))
return true;
}
return false;
}

/*
* 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;
struct vgic_redist_region *rdreg =
list_first_entry(&d->rd_regions,
struct vgic_redist_region, list);

redist_size *= atomic_read(&kvm->online_vcpus);
struct vgic_redist_region *rdreg;

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 (rdreg && (rdreg->base + redist_size < rdreg->base))
return false;

/* Both base addresses must be set to check if they overlap */
if (IS_VGIC_ADDR_UNDEF(d->vgic_dist_base) || !rdreg)
return true;

if (d->vgic_dist_base + KVM_VGIC_V3_DIST_SIZE <= rdreg->base)
return true;
list_for_each_entry(rdreg, &d->rd_regions, list) {
if (rdreg->base + vgic_v3_rd_region_size(kvm, rdreg) <
rdreg->base)
return false;
}

if (rdreg->base + redist_size <= d->vgic_dist_base)
if (IS_VGIC_ADDR_UNDEF(d->vgic_dist_base))
return true;

return false;
return !vgic_v3_rdist_overlap(kvm, d->vgic_dist_base,
KVM_VGIC_V3_DIST_SIZE);
}

/**
Expand Down
10 changes: 10 additions & 0 deletions virt/kvm/arm/vgic/vgic.h
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,16 @@ vgic_v3_redist_region_full(struct vgic_redist_region *region)

struct vgic_redist_region *vgic_v3_rdist_free_slot(struct list_head *rdregs);

static inline size_t
vgic_v3_rd_region_size(struct kvm *kvm, struct vgic_redist_region *rdreg)
{
if (!rdreg->count)
return atomic_read(&kvm->online_vcpus) * KVM_VGIC_V3_REDIST_SIZE;
else
return rdreg->count * KVM_VGIC_V3_REDIST_SIZE;
}
bool vgic_v3_rdist_overlap(struct kvm *kvm, gpa_t base, size_t size);

int vgic_its_resolve_lpi(struct kvm *kvm, struct vgic_its *its,
u32 devid, u32 eventid, struct vgic_irq **irq);
struct vgic_its *vgic_msi_to_its(struct kvm *kvm, struct kvm_msi *msi);
Expand Down

0 comments on commit 028bf27

Please sign in to comment.