* [PATCH v4 0/4] KVM: arm64: fix VGICv3 redistributor rollback
@ 2026-08-31 8:10 Karl Mehltretter
2026-08-31 8:10 ` [PATCH v4 1/4] KVM: arm64: vgic-v3: Undo assignment on iodev registration failure Karl Mehltretter
` (3 more replies)
0 siblings, 4 replies; 5+ messages in thread
From: Karl Mehltretter @ 2026-08-31 8:10 UTC (permalink / raw)
To: Marc Zyngier, Oliver Upton, kvmarm
Cc: Karl Mehltretter, Fuad Tabba, Joey Gouly, Steffen Eiden,
Suzuki K Poulose, Zenghui Yu, Catalin Marinas, Will Deacon,
Paolo Bonzini, Shuah Khan, Eric Auger, Christoffer Dall,
linux-arm-kernel, linux-kernel, kvm, linux-kselftest
A failed REDIST_REGION write can unregister redistributor iodevs while
leaving their assignments cached. A retry then skips those vCPUs and leaves
their iodevs missing.
Patch 1 fixes the accounting when an individual MMIO-bus registration
fails. It reserves the selected region slot before registration and undoes
that assignment on failure.
Patch 2 limits rollback to assignments from the new region. Resetting
assignments from an older region can miss one held by a vCPU that is not
yet visible to kvm_for_each_vcpu() and move free_index behind that live
assignment.
slots_lock prevents a concurrent vCPU from acquiring an assignment from the
new region before a failed write removes it.
Patches 3 and 4 add regression coverage for an overlapping region, retry,
and final GICR_TYPER accesses to all four redistributors.
Testing:
- Built the modified arm64 KVM objects with W=1 and the arm64 vgic_init
selftest using GCC 13.3.0.
- On an Arm Base RevC AEMvA FVP with GICv3, vgic_init passed with nVHE,
VHE and protected hVHE. A VHE kernel with PROVE_LOCKING and KASAN also
passed without lockdep or KASAN reports. A control kernel containing
only patches 3 and 4 failed at the first GICR_TYPER access, 0x8030008.
- Under QEMU 11.0.2 TCG, test-only instrumentation paused vCPU creation
after assigning a redistributor but before kvm_for_each_vcpu() could see
it. An MMIO-bus registration failure was injected after one vCPU was
assigned to the new region.
Rollback preserved the old assignment before and after the vCPU became
visible. A valid retry succeeded and guest GICR_TYPER accesses found all
four redistributors.
- An adapted Linux 5.10.268 backport of patches 1 and 2, on top of
8542a8f95a67 ("KVM: arm64: vgic-v3: Fix error handling in
vgic_v3_set_redist_base()"), passed the isolated retry test. The
prerequisite-only control failed at the same GICR_TYPER access.
---
Changes since v3:
- Dropped the REDIST/REDIST_REGION serialization and VGIC init/destroy
rework, keeping the fix close to v2. (Marc)
- Limited rollback to assignments from the new region so an older-region
assignment cannot be missed during concurrent vCPU creation.
- Added Fuad's Reviewed-by tags to patches 1, 3 and 4. These are otherwise
unchanged from v3 (formerly patches 1, 4 and 5).
Previous version:
v3: https://lore.kernel.org/r/20260822095346.53882-1-kmehltretter@gmail.com
Karl Mehltretter (4):
KVM: arm64: vgic-v3: Undo assignment on iodev registration failure
KVM: arm64: vgic-v3: Roll back assignments from the new region
KVM: arm64: selftests: Pass guest code to vm_gic_create_with_vcpus()
KVM: arm64: selftests: Test VGICv3 redistributor region retry
arch/arm64/kvm/vgic/vgic-mmio-v3.c | 54 ++++++--
tools/testing/selftests/kvm/arm64/vgic_init.c | 116 ++++++++++++++++--
2 files changed, 151 insertions(+), 19 deletions(-)
base-commit: cf72cbb39da84b6f02f90c07f33b102fc10b16f0
--
2.39.5 (Apple Git-154)
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v4 1/4] KVM: arm64: vgic-v3: Undo assignment on iodev registration failure
2026-08-31 8:10 [PATCH v4 0/4] KVM: arm64: fix VGICv3 redistributor rollback Karl Mehltretter
@ 2026-08-31 8:10 ` Karl Mehltretter
2026-08-31 8:10 ` [PATCH v4 2/4] KVM: arm64: vgic-v3: Roll back assignments from the new region Karl Mehltretter
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Karl Mehltretter @ 2026-08-31 8:10 UTC (permalink / raw)
To: Marc Zyngier, Oliver Upton, kvmarm
Cc: Karl Mehltretter, Fuad Tabba, Joey Gouly, Steffen Eiden,
Suzuki K Poulose, Zenghui Yu, Catalin Marinas, Will Deacon,
Paolo Bonzini, Shuah Khan, Eric Auger, Christoffer Dall,
linux-arm-kernel, linux-kernel, kvm, linux-kselftest
vgic_register_redist_iodev() assigns a redistributor region and base
address to the vCPU before adding its iodev to the MMIO bus. However, the
region's free_index is advanced only after registration succeeds.
If kvm_io_bus_register_dev() fails, the vCPU retains the assignment while
free_index still identifies the same slot as free. A later registration can
therefore reuse a slot that remains assigned to the vCPU.
Reserve the slot before registering its iodev. The caller holds slots_lock,
so a registration failure cannot race with a later assignment. Undo the
reservation and clear the cached assignment on failure.
Fixes: dbd9733ab674 ("KVM: arm/arm64: Replace the single rdist region by a list")
Cc: stable@vger.kernel.org
Assisted-by: Codex:gpt-5.6-sol
Signed-off-by: Karl Mehltretter <kmehltretter@gmail.com>
Reviewed-by: Fuad Tabba <fuad.tabba@linux.dev>
---
arch/arm64/kvm/vgic/vgic-mmio-v3.c | 22 ++++++++++++++++++----
1 file changed, 18 insertions(+), 4 deletions(-)
diff --git a/arch/arm64/kvm/vgic/vgic-mmio-v3.c b/arch/arm64/kvm/vgic/vgic-mmio-v3.c
index 5913a20d8301..22897ce64dbf 100644
--- a/arch/arm64/kvm/vgic/vgic-mmio-v3.c
+++ b/arch/arm64/kvm/vgic/vgic-mmio-v3.c
@@ -766,6 +766,19 @@ unsigned int vgic_v3_init_dist_iodev(struct vgic_io_device *dev)
return SZ_64K;
}
+static void vgic_undo_redist_assignment(struct kvm_vcpu *vcpu)
+{
+ struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
+
+ lockdep_assert_held(&vcpu->kvm->slots_lock);
+
+ guard(mutex)(&vcpu->kvm->arch.config_lock);
+
+ vgic_cpu->rdreg->free_index--;
+ vgic_cpu->rdreg = NULL;
+ vgic_cpu->rd_iodev.base_addr = VGIC_ADDR_UNDEF;
+}
+
/**
* vgic_register_redist_iodev - register a single redist iodev
* @vcpu: The VCPU to which the redistributor belongs
@@ -818,16 +831,17 @@ int vgic_register_redist_iodev(struct kvm_vcpu *vcpu)
rd_dev->nr_regions = ARRAY_SIZE(vgic_v3_rd_registers);
rd_dev->redist_vcpu = vcpu;
+ /* Protected by slots_lock */
+ rdreg->free_index++;
+
mutex_unlock(&kvm->arch.config_lock);
ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS, rd_base,
2 * SZ_64K, &rd_dev->dev);
if (ret)
- return ret;
+ vgic_undo_redist_assignment(vcpu);
- /* Protected by slots_lock */
- rdreg->free_index++;
- return 0;
+ return ret;
out_unlock:
mutex_unlock(&kvm->arch.config_lock);
base-commit: cf72cbb39da84b6f02f90c07f33b102fc10b16f0
--
2.39.5 (Apple Git-154)
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH v4 2/4] KVM: arm64: vgic-v3: Roll back assignments from the new region
2026-08-31 8:10 [PATCH v4 0/4] KVM: arm64: fix VGICv3 redistributor rollback Karl Mehltretter
2026-08-31 8:10 ` [PATCH v4 1/4] KVM: arm64: vgic-v3: Undo assignment on iodev registration failure Karl Mehltretter
@ 2026-08-31 8:10 ` Karl Mehltretter
2026-08-31 8:10 ` [PATCH v4 3/4] KVM: arm64: selftests: Pass guest code to vm_gic_create_with_vcpus() Karl Mehltretter
2026-08-31 8:10 ` [PATCH v4 4/4] KVM: arm64: selftests: Test VGICv3 redistributor region retry Karl Mehltretter
3 siblings, 0 replies; 5+ messages in thread
From: Karl Mehltretter @ 2026-08-31 8:10 UTC (permalink / raw)
To: Marc Zyngier, Oliver Upton, kvmarm
Cc: Karl Mehltretter, Fuad Tabba, Joey Gouly, Steffen Eiden,
Suzuki K Poulose, Zenghui Yu, Catalin Marinas, Will Deacon,
Paolo Bonzini, Shuah Khan, Eric Auger, Christoffer Dall,
linux-arm-kernel, linux-kernel, kvm, linux-kselftest
A failed REDIST_REGION write unregisters the redistributor iodevs of every
vCPU processed before the failure. This includes vCPUs assigned to older
regions. Their assignments remain cached, so a retry does not register the
iodevs again.
The vCPU whose registration fails has no assignment to roll back. For vCPUs
processed earlier, limit rollback to those assigned to the new region. The
region is removed on failure, so its free_index does not need restoring.
Resetting assignments from older regions is unsafe because a vCPU can own
one before kvm_for_each_vcpu() can see it. Rollback could then move
free_index behind that live assignment.
kvm_vgic_addr() holds slots_lock across the REDIST_REGION write. vCPU
creation takes the same lock before assigning a redistributor. A concurrent
vCPU cannot acquire an assignment from the new region before rollback
completes. The lock also keeps rdreg valid across the config_lock drop
required by MMIO-bus registration.
Fixes: c011f4ea106b ("KVM: arm/arm64: Check vcpu redist base before registering an iodev")
Cc: stable@vger.kernel.org
Assisted-by: Codex:gpt-5.6-sol
Signed-off-by: Karl Mehltretter <kmehltretter@gmail.com>
---
arch/arm64/kvm/vgic/vgic-mmio-v3.c | 32 +++++++++++++++++++++++-------
1 file changed, 25 insertions(+), 7 deletions(-)
diff --git a/arch/arm64/kvm/vgic/vgic-mmio-v3.c b/arch/arm64/kvm/vgic/vgic-mmio-v3.c
index 22897ce64dbf..77aa8433701a 100644
--- a/arch/arm64/kvm/vgic/vgic-mmio-v3.c
+++ b/arch/arm64/kvm/vgic/vgic-mmio-v3.c
@@ -855,7 +855,25 @@ void vgic_unregister_redist_iodev(struct kvm_vcpu *vcpu)
kvm_io_bus_unregister_dev(vcpu->kvm, KVM_MMIO_BUS, &rd_dev->dev);
}
-static int vgic_register_all_redist_iodevs(struct kvm *kvm)
+static void vgic_rollback_redist_iodev(struct kvm_vcpu *vcpu,
+ struct vgic_redist_region *rdreg)
+{
+ struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
+
+ lockdep_assert_held(&vcpu->kvm->slots_lock);
+
+ if (vgic_cpu->rdreg != rdreg)
+ return;
+
+ vgic_unregister_redist_iodev(vcpu);
+
+ guard(mutex)(&vcpu->kvm->arch.config_lock);
+ vgic_cpu->rdreg = NULL;
+ vgic_cpu->rd_iodev.base_addr = VGIC_ADDR_UNDEF;
+}
+
+static int vgic_register_all_redist_iodevs(struct kvm *kvm,
+ struct vgic_redist_region *rdreg)
{
struct kvm_vcpu *vcpu;
unsigned long c;
@@ -870,12 +888,12 @@ static int vgic_register_all_redist_iodevs(struct kvm *kvm)
}
if (ret) {
- /* The current c failed, so iterate over the previous ones. */
+ /* Undo assignments made from the region being added. */
int i;
for (i = 0; i < c; i++) {
vcpu = kvm_get_vcpu(kvm, i);
- vgic_unregister_redist_iodev(vcpu);
+ vgic_rollback_redist_iodev(vcpu, rdreg);
}
}
@@ -984,10 +1002,13 @@ void vgic_v3_free_redist_region(struct kvm *kvm, struct vgic_redist_region *rdre
int vgic_v3_set_redist_base(struct kvm *kvm, u32 index, u64 addr, u32 count)
{
+ struct vgic_redist_region *rdreg;
int ret;
mutex_lock(&kvm->arch.config_lock);
ret = vgic_v3_alloc_redist_region(kvm, index, addr, count);
+ if (!ret)
+ rdreg = vgic_v3_rdist_region_from_index(kvm, index);
mutex_unlock(&kvm->arch.config_lock);
if (ret)
return ret;
@@ -996,12 +1017,9 @@ int vgic_v3_set_redist_base(struct kvm *kvm, u32 index, u64 addr, u32 count)
* Register iodevs for each existing VCPU. Adding more VCPUs
* afterwards will register the iodevs when needed.
*/
- ret = vgic_register_all_redist_iodevs(kvm);
+ ret = vgic_register_all_redist_iodevs(kvm, rdreg);
if (ret) {
- struct vgic_redist_region *rdreg;
-
mutex_lock(&kvm->arch.config_lock);
- rdreg = vgic_v3_rdist_region_from_index(kvm, index);
vgic_v3_free_redist_region(kvm, rdreg);
mutex_unlock(&kvm->arch.config_lock);
return ret;
--
2.39.5 (Apple Git-154)
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH v4 3/4] KVM: arm64: selftests: Pass guest code to vm_gic_create_with_vcpus()
2026-08-31 8:10 [PATCH v4 0/4] KVM: arm64: fix VGICv3 redistributor rollback Karl Mehltretter
2026-08-31 8:10 ` [PATCH v4 1/4] KVM: arm64: vgic-v3: Undo assignment on iodev registration failure Karl Mehltretter
2026-08-31 8:10 ` [PATCH v4 2/4] KVM: arm64: vgic-v3: Roll back assignments from the new region Karl Mehltretter
@ 2026-08-31 8:10 ` Karl Mehltretter
2026-08-31 8:10 ` [PATCH v4 4/4] KVM: arm64: selftests: Test VGICv3 redistributor region retry Karl Mehltretter
3 siblings, 0 replies; 5+ messages in thread
From: Karl Mehltretter @ 2026-08-31 8:10 UTC (permalink / raw)
To: Marc Zyngier, Oliver Upton, kvmarm
Cc: Karl Mehltretter, Fuad Tabba, Joey Gouly, Steffen Eiden,
Suzuki K Poulose, Zenghui Yu, Catalin Marinas, Will Deacon,
Paolo Bonzini, Shuah Khan, Eric Auger, Christoffer Dall,
linux-arm-kernel, linux-kernel, kvm, linux-kselftest
Pass the guest-code address to vm_gic_create_with_vcpus(), and use
guest_code at the existing call sites. This lets tests with different guest
code reuse the common VM and VGIC setup while retaining the void *
interface of vm_create_with_vcpus().
Assisted-by: Codex:gpt-5.6-sol
Signed-off-by: Karl Mehltretter <kmehltretter@gmail.com>
Reviewed-by: Fuad Tabba <fuad.tabba@linux.dev>
---
tools/testing/selftests/kvm/arm64/vgic_init.c | 24 ++++++++++++-------
1 file changed, 16 insertions(+), 8 deletions(-)
diff --git a/tools/testing/selftests/kvm/arm64/vgic_init.c b/tools/testing/selftests/kvm/arm64/vgic_init.c
index 47e34b43afb2..84aa97204b7f 100644
--- a/tools/testing/selftests/kvm/arm64/vgic_init.c
+++ b/tools/testing/selftests/kvm/arm64/vgic_init.c
@@ -73,6 +73,7 @@ static int run_vcpu(struct kvm_vcpu *vcpu)
static struct vm_gic vm_gic_create_with_vcpus(u32 gic_dev_type,
u32 nr_vcpus,
+ void *guest_code,
struct kvm_vcpu *vcpus[])
{
struct vm_gic v;
@@ -338,7 +339,7 @@ static void test_vgic_then_vcpus(u32 gic_dev_type)
struct vm_gic v;
int ret, i;
- v = vm_gic_create_with_vcpus(gic_dev_type, 1, vcpus);
+ v = vm_gic_create_with_vcpus(gic_dev_type, 1, guest_code, vcpus);
subtest_dist_rdist(&v);
@@ -359,7 +360,8 @@ static void test_vcpus_then_vgic(u32 gic_dev_type)
struct vm_gic v;
int ret;
- v = vm_gic_create_with_vcpus(gic_dev_type, NR_VCPUS, vcpus);
+ v = vm_gic_create_with_vcpus(gic_dev_type, NR_VCPUS, guest_code,
+ vcpus);
subtest_dist_rdist(&v);
@@ -411,7 +413,8 @@ static void test_v3_new_redist_regions(void)
u64 addr;
int ret;
- v = vm_gic_create_with_vcpus(KVM_DEV_TYPE_ARM_VGIC_V3, NR_VCPUS, vcpus);
+ v = vm_gic_create_with_vcpus(KVM_DEV_TYPE_ARM_VGIC_V3, NR_VCPUS,
+ guest_code, vcpus);
subtest_v3_redist_regions(&v);
kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
KVM_DEV_ARM_VGIC_CTRL_INIT, NULL);
@@ -422,7 +425,8 @@ static void test_v3_new_redist_regions(void)
/* step2 */
- v = vm_gic_create_with_vcpus(KVM_DEV_TYPE_ARM_VGIC_V3, NR_VCPUS, vcpus);
+ v = vm_gic_create_with_vcpus(KVM_DEV_TYPE_ARM_VGIC_V3, NR_VCPUS,
+ guest_code, vcpus);
subtest_v3_redist_regions(&v);
addr = REDIST_REGION_ATTR_ADDR(1, 0x280000, 0, 2);
@@ -436,7 +440,8 @@ static void test_v3_new_redist_regions(void)
/* step 3 */
- v = vm_gic_create_with_vcpus(KVM_DEV_TYPE_ARM_VGIC_V3, NR_VCPUS, vcpus);
+ v = vm_gic_create_with_vcpus(KVM_DEV_TYPE_ARM_VGIC_V3, NR_VCPUS,
+ guest_code, vcpus);
subtest_v3_redist_regions(&v);
ret = __kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
@@ -608,7 +613,8 @@ static void test_v3_redist_ipa_range_check_at_vcpu_run(void)
int ret, i;
u64 addr;
- v = vm_gic_create_with_vcpus(KVM_DEV_TYPE_ARM_VGIC_V3, 1, vcpus);
+ v = vm_gic_create_with_vcpus(KVM_DEV_TYPE_ARM_VGIC_V3, 1, guest_code,
+ vcpus);
/* Set space for 3 redists, we have 1 vcpu, so this succeeds. */
addr = max_phys_size - (3 * 2 * 0x10000);
@@ -641,7 +647,8 @@ static void test_v3_its_region(void)
u64 addr;
int its_fd, ret;
- v = vm_gic_create_with_vcpus(KVM_DEV_TYPE_ARM_VGIC_V3, NR_VCPUS, vcpus);
+ v = vm_gic_create_with_vcpus(KVM_DEV_TYPE_ARM_VGIC_V3, NR_VCPUS,
+ guest_code, vcpus);
its_fd = kvm_create_device(v.vm, KVM_DEV_TYPE_ARM_VGIC_ITS);
addr = 0x401000;
@@ -684,7 +691,8 @@ static void test_v3_nassgicap(void)
u32 typer2;
int ret;
- vm = vm_gic_create_with_vcpus(KVM_DEV_TYPE_ARM_VGIC_V3, NR_VCPUS, vcpus);
+ vm = vm_gic_create_with_vcpus(KVM_DEV_TYPE_ARM_VGIC_V3, NR_VCPUS,
+ guest_code, vcpus);
kvm_device_attr_get(vm.gic_fd, KVM_DEV_ARM_VGIC_GRP_DIST_REGS,
GICD_TYPER2, &typer2);
has_nassgicap = typer2 & GICD_TYPER2_nASSGIcap;
--
2.39.5 (Apple Git-154)
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH v4 4/4] KVM: arm64: selftests: Test VGICv3 redistributor region retry
2026-08-31 8:10 [PATCH v4 0/4] KVM: arm64: fix VGICv3 redistributor rollback Karl Mehltretter
` (2 preceding siblings ...)
2026-08-31 8:10 ` [PATCH v4 3/4] KVM: arm64: selftests: Pass guest code to vm_gic_create_with_vcpus() Karl Mehltretter
@ 2026-08-31 8:10 ` Karl Mehltretter
3 siblings, 0 replies; 5+ messages in thread
From: Karl Mehltretter @ 2026-08-31 8:10 UTC (permalink / raw)
To: Marc Zyngier, Oliver Upton, kvmarm
Cc: Karl Mehltretter, Fuad Tabba, Joey Gouly, Steffen Eiden,
Suzuki K Poulose, Zenghui Yu, Catalin Marinas, Will Deacon,
Paolo Bonzini, Shuah Khan, Eric Auger, Christoffer Dall,
linux-arm-kernel, linux-kernel, kvm, linux-kselftest
A failed REDIST_REGION write can remove redistributor iodevs without
clearing their cached vCPU assignments. A retry then skips those
assignments and leaves the redistributors absent from the MMIO bus.
Create two partial regions, reject a third region that overlaps the
distributor, and retry at a valid address. After initializing the VGIC,
have the guest read GICR_TYPER from all four redistributors and check their
processor numbers. This verifies the final configuration without assuming
that assignments survive the failed write.
Keep the redistributor IPAs outside the guest RAM memslot and install only
the stage-1 mappings needed for the MMIO accesses. If an iodev is missing,
KVM_RUN therefore exits with KVM_EXIT_MMIO. Without the fix, the first
redistributor access exits at 0x8030008.
Assisted-by: Codex:gpt-5.6-sol
Signed-off-by: Karl Mehltretter <kmehltretter@gmail.com>
Reviewed-by: Fuad Tabba <fuad.tabba@linux.dev>
---
tools/testing/selftests/kvm/arm64/vgic_init.c | 92 +++++++++++++++++++
1 file changed, 92 insertions(+)
diff --git a/tools/testing/selftests/kvm/arm64/vgic_init.c b/tools/testing/selftests/kvm/arm64/vgic_init.c
index 84aa97204b7f..5a30f3cb039b 100644
--- a/tools/testing/selftests/kvm/arm64/vgic_init.c
+++ b/tools/testing/selftests/kvm/arm64/vgic_init.c
@@ -5,6 +5,7 @@
* Copyright (C) 2020, Red Hat, Inc.
*/
#include <linux/kernel.h>
+#include <linux/sizes.h>
#include <sys/syscall.h>
#include <asm/kvm.h>
#include <asm/kvm_para.h>
@@ -13,12 +14,21 @@
#include "test_util.h"
#include "kvm_util.h"
+#include "gic.h"
#include "processor.h"
#include "vgic.h"
#include "gic_v3.h"
#define NR_VCPUS 4
+#define REDIST_RETRY_REGION0_BASE GICR_BASE_GPA
+#define REDIST_RETRY_REGION1_BASE \
+ (REDIST_RETRY_REGION0_BASE + 2 * KVM_VGIC_V3_REDIST_SIZE)
+#define REDIST_RETRY_DIST_BASE \
+ (REDIST_RETRY_REGION1_BASE + KVM_VGIC_V3_REDIST_SIZE)
+#define REDIST_RETRY_REGION2_BASE \
+ (REDIST_RETRY_DIST_BASE + KVM_VGIC_V3_DIST_SIZE)
+
#define REG_OFFSET(vcpu, offset) (((u64)vcpu << 32) | offset)
#define VGIC_DEV_IS_V2(_d) ((_d) == KVM_DEV_TYPE_ARM_VGIC_V2)
@@ -65,6 +75,23 @@ static void guest_code(void)
GUEST_DONE();
}
+static void guest_check_redist_retry(void)
+{
+ unsigned int i;
+
+ /* The first three redistributors span adjacent regions 0 and 1. */
+ for (i = 0; i < NR_VCPUS; i++) {
+ u64 base = i < 3 ? REDIST_RETRY_REGION0_BASE +
+ i * KVM_VGIC_V3_REDIST_SIZE :
+ REDIST_RETRY_REGION2_BASE;
+ u64 typer = readq((void *)(unsigned long)(base + GICR_TYPER));
+
+ GUEST_ASSERT_EQ(GICR_TYPER_CPU_NUMBER(typer), i);
+ }
+
+ GUEST_DONE();
+}
+
/* we don't want to assert on run execution, hence that helper */
static int run_vcpu(struct kvm_vcpu *vcpu)
{
@@ -462,6 +489,70 @@ static void test_v3_new_redist_regions(void)
vm_gic_destroy(&v);
}
+static void test_v3_redist_region_retry(void)
+{
+ struct kvm_vcpu *vcpus[NR_VCPUS];
+ struct vm_gic v;
+ struct ucall uc;
+ u64 addr;
+ int ret;
+
+ v = vm_gic_create_with_vcpus(KVM_DEV_TYPE_ARM_VGIC_V3, NR_VCPUS,
+ guest_check_redist_retry, vcpus);
+
+ addr = REDIST_REGION_ATTR_ADDR(2, REDIST_RETRY_REGION0_BASE, 0, 0);
+ kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
+ KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
+
+ addr = REDIST_REGION_ATTR_ADDR(1, REDIST_RETRY_REGION1_BASE, 0, 1);
+ kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
+ KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
+
+ addr = REDIST_RETRY_DIST_BASE;
+ kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
+ KVM_VGIC_V3_ADDR_TYPE_DIST, &addr);
+
+ addr = REDIST_REGION_ATTR_ADDR(1, REDIST_RETRY_DIST_BASE, 0, 2);
+ ret = __kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
+ KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION,
+ &addr);
+ TEST_ASSERT(ret && errno == EINVAL,
+ "register redist region colliding with dist");
+
+ addr = REDIST_REGION_ATTR_ADDR(1, REDIST_RETRY_REGION2_BASE, 0, 2);
+ kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR,
+ KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &addr);
+
+ virt_map(v.vm, REDIST_RETRY_REGION0_BASE, REDIST_RETRY_REGION0_BASE,
+ vm_calc_num_guest_pages(v.vm->mode,
+ 3 * KVM_VGIC_V3_REDIST_SIZE));
+ virt_map(v.vm, REDIST_RETRY_REGION2_BASE, REDIST_RETRY_REGION2_BASE,
+ vm_calc_num_guest_pages(v.vm->mode,
+ KVM_VGIC_V3_REDIST_SIZE));
+
+ kvm_device_attr_set(v.gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
+ KVM_DEV_ARM_VGIC_CTRL_INIT, NULL);
+
+ vcpu_run(vcpus[0]);
+ switch (get_ucall(vcpus[0], &uc)) {
+ case UCALL_DONE:
+ break;
+ case UCALL_ABORT:
+ REPORT_GUEST_ASSERT(uc);
+ break;
+ case UCALL_NONE:
+ if (vcpus[0]->run->exit_reason == KVM_EXIT_MMIO)
+ TEST_FAIL("Unexpected MMIO exit at 0x%llx",
+ vcpus[0]->run->mmio.phys_addr);
+ fallthrough;
+ default:
+ TEST_FAIL("Unexpected ucall %lu, exit_reason %u",
+ uc.cmd, vcpus[0]->run->exit_reason);
+ }
+
+ vm_gic_destroy(&v);
+}
+
static void test_v3_typer_accesses(void)
{
struct vm_gic v;
@@ -986,6 +1077,7 @@ void run_tests(u32 gic_dev_type)
if (VGIC_DEV_IS_V3(gic_dev_type)) {
test_v3_new_redist_regions();
+ test_v3_redist_region_retry();
test_v3_typer_accesses();
test_v3_last_bit_redist_regions();
test_v3_last_bit_single_rdist();
--
2.39.5 (Apple Git-154)
^ permalink raw reply related [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-08-31 8:10 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-31 8:10 [PATCH v4 0/4] KVM: arm64: fix VGICv3 redistributor rollback Karl Mehltretter
2026-08-31 8:10 ` [PATCH v4 1/4] KVM: arm64: vgic-v3: Undo assignment on iodev registration failure Karl Mehltretter
2026-08-31 8:10 ` [PATCH v4 2/4] KVM: arm64: vgic-v3: Roll back assignments from the new region Karl Mehltretter
2026-08-31 8:10 ` [PATCH v4 3/4] KVM: arm64: selftests: Pass guest code to vm_gic_create_with_vcpus() Karl Mehltretter
2026-08-31 8:10 ` [PATCH v4 4/4] KVM: arm64: selftests: Test VGICv3 redistributor region retry Karl Mehltretter
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox