Skip to content

Commit 028bf27

Browse files
eaugerMarc Zyngier
authored andcommitted
KVM: arm/arm64: Adapt vgic_v3_check_base to multiple rdist regions
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 <eric.auger@redhat.com> Reviewed-by: Christoffer Dall <christoffer.dall@arm.com> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
1 parent ba7b3f1 commit 028bf27

2 files changed

Lines changed: 42 additions & 17 deletions

File tree

virt/kvm/arm/vgic/vgic-v3.c

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -419,38 +419,53 @@ int vgic_v3_save_pending_tables(struct kvm *kvm)
419419
return 0;
420420
}
421421

422+
/**
423+
* vgic_v3_rdist_overlap - check if a region overlaps with any
424+
* existing redistributor region
425+
*
426+
* @kvm: kvm handle
427+
* @base: base of the region
428+
* @size: size of region
429+
*
430+
* Return: true if there is an overlap
431+
*/
432+
bool vgic_v3_rdist_overlap(struct kvm *kvm, gpa_t base, size_t size)
433+
{
434+
struct vgic_dist *d = &kvm->arch.vgic;
435+
struct vgic_redist_region *rdreg;
436+
437+
list_for_each_entry(rdreg, &d->rd_regions, list) {
438+
if ((base + size > rdreg->base) &&
439+
(base < rdreg->base + vgic_v3_rd_region_size(kvm, rdreg)))
440+
return true;
441+
}
442+
return false;
443+
}
444+
422445
/*
423446
* Check for overlapping regions and for regions crossing the end of memory
424447
* for base addresses which have already been set.
425448
*/
426449
bool vgic_v3_check_base(struct kvm *kvm)
427450
{
428451
struct vgic_dist *d = &kvm->arch.vgic;
429-
gpa_t redist_size = KVM_VGIC_V3_REDIST_SIZE;
430-
struct vgic_redist_region *rdreg =
431-
list_first_entry(&d->rd_regions,
432-
struct vgic_redist_region, list);
433-
434-
redist_size *= atomic_read(&kvm->online_vcpus);
452+
struct vgic_redist_region *rdreg;
435453

436454
if (!IS_VGIC_ADDR_UNDEF(d->vgic_dist_base) &&
437455
d->vgic_dist_base + KVM_VGIC_V3_DIST_SIZE < d->vgic_dist_base)
438456
return false;
439457

440-
if (rdreg && (rdreg->base + redist_size < rdreg->base))
441-
return false;
442-
443-
/* Both base addresses must be set to check if they overlap */
444-
if (IS_VGIC_ADDR_UNDEF(d->vgic_dist_base) || !rdreg)
445-
return true;
446-
447-
if (d->vgic_dist_base + KVM_VGIC_V3_DIST_SIZE <= rdreg->base)
448-
return true;
458+
list_for_each_entry(rdreg, &d->rd_regions, list) {
459+
if (rdreg->base + vgic_v3_rd_region_size(kvm, rdreg) <
460+
rdreg->base)
461+
return false;
462+
}
449463

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

453-
return false;
467+
return !vgic_v3_rdist_overlap(kvm, d->vgic_dist_base,
468+
KVM_VGIC_V3_DIST_SIZE);
454469
}
455470

456471
/**

virt/kvm/arm/vgic/vgic.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,16 @@ vgic_v3_redist_region_full(struct vgic_redist_region *region)
276276

277277
struct vgic_redist_region *vgic_v3_rdist_free_slot(struct list_head *rdregs);
278278

279+
static inline size_t
280+
vgic_v3_rd_region_size(struct kvm *kvm, struct vgic_redist_region *rdreg)
281+
{
282+
if (!rdreg->count)
283+
return atomic_read(&kvm->online_vcpus) * KVM_VGIC_V3_REDIST_SIZE;
284+
else
285+
return rdreg->count * KVM_VGIC_V3_REDIST_SIZE;
286+
}
287+
bool vgic_v3_rdist_overlap(struct kvm *kvm, gpa_t base, size_t size);
288+
279289
int vgic_its_resolve_lpi(struct kvm *kvm, struct vgic_its *its,
280290
u32 devid, u32 eventid, struct vgic_irq **irq);
281291
struct vgic_its *vgic_msi_to_its(struct kvm *kvm, struct kvm_msi *msi);

0 commit comments

Comments
 (0)