From: Marc Zyngier <maz@kernel.org>
To: Sascha Bischoff <Sascha.Bischoff@arm.com>
Cc: "linux-arm-kernel@lists.infradead.org"
<linux-arm-kernel@lists.infradead.org>,
"kvmarm@lists.linux.dev" <kvmarm@lists.linux.dev>,
"kvm@vger.kernel.org" <kvm@vger.kernel.org>, nd <nd@arm.com>,
"oliver.upton@linux.dev" <oliver.upton@linux.dev>,
Joey Gouly <Joey.Gouly@arm.com>,
Suzuki Poulose <Suzuki.Poulose@arm.com>,
"yuzenghui@huawei.com" <yuzenghui@huawei.com>,
"peter.maydell@linaro.org" <peter.maydell@linaro.org>,
"lpieralisi@kernel.org" <lpieralisi@kernel.org>,
Timothy Hayes <Timothy.Hayes@arm.com>,
"jonathan.cameron@huawei.com" <jonathan.cameron@huawei.com>
Subject: Re: [PATCH v5 15/36] KVM: arm64: gic-v5: Implement GICv5 load/put and save/restore
Date: Wed, 04 Mar 2026 09:26:52 +0000 [thread overview]
Message-ID: <865x7c7xnn.wl-maz@kernel.org> (raw)
In-Reply-To: <20260226155515.1164292-16-sascha.bischoff@arm.com>
On Thu, 26 Feb 2026 15:59:18 +0000,
Sascha Bischoff <Sascha.Bischoff@arm.com> wrote:
>
> This change introduces GICv5 load/put. Additionally, it plumbs in
> save/restore for:
>
> * PPIs (ICH_PPI_x_EL2 regs)
> * ICH_VMCR_EL2
> * ICH_APR_EL2
> * ICC_ICSR_EL1
>
> A GICv5-specific enable bit is added to struct vgic_vmcr as this
> differs from previous GICs. On GICv5-native systems, the VMCR only
> contains the enable bit (driven by the guest via ICC_CR0_EL1.EN) and
> the priority mask (PCR).
>
> A struct gicv5_vpe is also introduced. This currently only contains a
> single field - bool resident - which is used to track if a VPE is
> currently running or not, and is used to avoid a case of double load
> or double put on the WFI path for a vCPU. This struct will be extended
> as additional GICv5 support is merged, specifically for VPE doorbells.
>
> Co-authored-by: Timothy Hayes <timothy.hayes@arm.com>
> Signed-off-by: Timothy Hayes <timothy.hayes@arm.com>
> Signed-off-by: Sascha Bischoff <sascha.bischoff@arm.com>
> Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
> ---
> arch/arm64/kvm/hyp/nvhe/switch.c | 12 +++++
> arch/arm64/kvm/vgic/vgic-mmio.c | 28 +++++++----
> arch/arm64/kvm/vgic/vgic-v5.c | 74 ++++++++++++++++++++++++++++++
> arch/arm64/kvm/vgic/vgic.c | 32 ++++++++-----
> arch/arm64/kvm/vgic/vgic.h | 7 +++
> include/kvm/arm_vgic.h | 2 +
> include/linux/irqchip/arm-gic-v5.h | 5 ++
> 7 files changed, 141 insertions(+), 19 deletions(-)
>
> diff --git a/arch/arm64/kvm/hyp/nvhe/switch.c b/arch/arm64/kvm/hyp/nvhe/switch.c
> index b41485ce295ab..a88da302b6d08 100644
> --- a/arch/arm64/kvm/hyp/nvhe/switch.c
> +++ b/arch/arm64/kvm/hyp/nvhe/switch.c
> @@ -113,6 +113,12 @@ static void __deactivate_traps(struct kvm_vcpu *vcpu)
> /* Save VGICv3 state on non-VHE systems */
> static void __hyp_vgic_save_state(struct kvm_vcpu *vcpu)
> {
> + if (vgic_is_v5(kern_hyp_va(vcpu->kvm))) {
> + __vgic_v5_save_state(&vcpu->arch.vgic_cpu.vgic_v5);
> + __vgic_v5_save_ppi_state(&vcpu->arch.vgic_cpu.vgic_v5);
> + return;
> + }
> +
> if (static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif)) {
> __vgic_v3_save_state(&vcpu->arch.vgic_cpu.vgic_v3);
> __vgic_v3_deactivate_traps(&vcpu->arch.vgic_cpu.vgic_v3);
> @@ -122,6 +128,12 @@ static void __hyp_vgic_save_state(struct kvm_vcpu *vcpu)
> /* Restore VGICv3 state on non-VHE systems */
> static void __hyp_vgic_restore_state(struct kvm_vcpu *vcpu)
> {
> + if (vgic_is_v5(kern_hyp_va(vcpu->kvm))) {
> + __vgic_v5_restore_state(&vcpu->arch.vgic_cpu.vgic_v5);
> + __vgic_v5_restore_ppi_state(&vcpu->arch.vgic_cpu.vgic_v5);
> + return;
> + }
> +
> if (static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif)) {
> __vgic_v3_activate_traps(&vcpu->arch.vgic_cpu.vgic_v3);
> __vgic_v3_restore_state(&vcpu->arch.vgic_cpu.vgic_v3);
> diff --git a/arch/arm64/kvm/vgic/vgic-mmio.c b/arch/arm64/kvm/vgic/vgic-mmio.c
> index a573b1f0c6cbe..675c2844f5e5c 100644
> --- a/arch/arm64/kvm/vgic/vgic-mmio.c
> +++ b/arch/arm64/kvm/vgic/vgic-mmio.c
> @@ -842,18 +842,30 @@ vgic_find_mmio_region(const struct vgic_register_region *regions,
>
> void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
> {
> - if (kvm_vgic_global_state.type == VGIC_V2)
> - vgic_v2_set_vmcr(vcpu, vmcr);
> - else
> - vgic_v3_set_vmcr(vcpu, vmcr);
> + const struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
> +
> + if (dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V5) {
> + vgic_v5_set_vmcr(vcpu, vmcr);
> + } else {
> + if (kvm_vgic_global_state.type == VGIC_V2)
> + vgic_v2_set_vmcr(vcpu, vmcr);
> + else
> + vgic_v3_set_vmcr(vcpu, vmcr);
> + }
This looks rather ugly, and doesn't make use of the helpers you
introduced in patch #1. How about:
switch (dist->vgic_model) {
case KVM_DEV_TYPE_ARM_VGIC_V5:
vgic_v5_set_vmcr(vcpu, vmcr);
break;
case KVM_DEV_TYPE_ARM_VGIC_V3:
vgic_v3_set_vmcr(vcpu, vmcr);
break;
case KVM_DEV_TYPE_ARM_VGIC_V2:
if (static_branch_likely(&kvm_vgic_global_state.gicv3_cpuif))
vgic_v3_set_vmcr(vcpu, vmcr);
else
vgic_v2_set_vmcr(vcpu, vmcr);
break;
default:
BUG();
}
Yes, the handling of v3 is a bit redundant, but I find it overall more
readable.
> }
>
> void vgic_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
> {
> - if (kvm_vgic_global_state.type == VGIC_V2)
> - vgic_v2_get_vmcr(vcpu, vmcr);
> - else
> - vgic_v3_get_vmcr(vcpu, vmcr);
> + const struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
> +
> + if (dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V5) {
> + vgic_v5_get_vmcr(vcpu, vmcr);
> + } else {
> + if (kvm_vgic_global_state.type == VGIC_V2)
> + vgic_v2_get_vmcr(vcpu, vmcr);
> + else
> + vgic_v3_get_vmcr(vcpu, vmcr);
> + }
> }
>
> /*
> diff --git a/arch/arm64/kvm/vgic/vgic-v5.c b/arch/arm64/kvm/vgic/vgic-v5.c
> index 2c51b9ba4f118..5b35c756887a9 100644
> --- a/arch/arm64/kvm/vgic/vgic-v5.c
> +++ b/arch/arm64/kvm/vgic/vgic-v5.c
> @@ -85,3 +85,77 @@ int vgic_v5_probe(const struct gic_kvm_info *info)
>
> return 0;
> }
> +
> +void vgic_v5_load(struct kvm_vcpu *vcpu)
> +{
> + struct vgic_v5_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
> +
> + /*
> + * On the WFI path, vgic_load is called a second time. The first is when
> + * scheduling in the vcpu thread again, and the second is when leaving
> + * WFI. Skip the second instance as it serves no purpose and just
> + * restores the same state again.
> + */
> + if (READ_ONCE(cpu_if->gicv5_vpe.resident))
> + return;
I'm perplex. What is READ_ONCE()/WRITE_ONCE() guaranteeing?
> +
> + kvm_call_hyp(__vgic_v5_restore_vmcr_apr, cpu_if);
> +
> + WRITE_ONCE(cpu_if->gicv5_vpe.resident, true);
> +}
> +
> +void vgic_v5_put(struct kvm_vcpu *vcpu)
> +{
> + struct vgic_v5_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
> +
> + /*
> + * Do nothing if we're not resident. This can happen in the WFI path
> + * where we do a vgic_put in the WFI path and again later when
> + * descheduling the thread. We risk losing VMCR state if we sync it
> + * twice, so instead return early in this case.
> + */
> + if (!READ_ONCE(cpu_if->gicv5_vpe.resident))
> + return;
> +
> + kvm_call_hyp(__vgic_v5_save_apr, cpu_if);
> +
> + WRITE_ONCE(cpu_if->gicv5_vpe.resident, false);
> +}
> +
> +void vgic_v5_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
> +{
> + struct vgic_v5_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
> + u64 vmcr = cpu_if->vgic_vmcr;
> +
> + vmcrp->en = FIELD_GET(FEAT_GCIE_ICH_VMCR_EL2_EN, vmcr);
> + vmcrp->pmr = FIELD_GET(FEAT_GCIE_ICH_VMCR_EL2_VPMR, vmcr);
> +}
> +
> +void vgic_v5_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
> +{
> + struct vgic_v5_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
> + u64 vmcr;
> +
> + vmcr = FIELD_PREP(FEAT_GCIE_ICH_VMCR_EL2_VPMR, vmcrp->pmr) |
> + FIELD_PREP(FEAT_GCIE_ICH_VMCR_EL2_EN, vmcrp->en);
> +
> + cpu_if->vgic_vmcr = vmcr;
> +}
> +
> +void vgic_v5_restore_state(struct kvm_vcpu *vcpu)
> +{
> + struct vgic_v5_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
> +
> + __vgic_v5_restore_state(cpu_if);
> + kvm_call_hyp(__vgic_v5_restore_ppi_state, cpu_if);
> + dsb(sy);
> +}
> +
> +void vgic_v5_save_state(struct kvm_vcpu *vcpu)
> +{
> + struct vgic_v5_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
> +
> + __vgic_v5_save_state(cpu_if);
> + kvm_call_hyp(__vgic_v5_save_ppi_state, cpu_if);
> + dsb(sy);
> +}
> diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c
> index 2c0e8803342e2..1005ff5f36235 100644
> --- a/arch/arm64/kvm/vgic/vgic.c
> +++ b/arch/arm64/kvm/vgic/vgic.c
> @@ -996,7 +996,9 @@ static inline bool can_access_vgic_from_kernel(void)
>
> static inline void vgic_save_state(struct kvm_vcpu *vcpu)
> {
> - if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
> + if (vgic_is_v5(vcpu->kvm))
> + vgic_v5_save_state(vcpu);
> + else if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
> vgic_v2_save_state(vcpu);
> else
> __vgic_v3_save_state(&vcpu->arch.vgic_cpu.vgic_v3);
> @@ -1005,14 +1007,16 @@ static inline void vgic_save_state(struct kvm_vcpu *vcpu)
> /* Sync back the hardware VGIC state into our emulation after a guest's run. */
> void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
> {
> - /* If nesting, emulate the HW effect from L0 to L1 */
> - if (vgic_state_is_nested(vcpu)) {
> - vgic_v3_sync_nested(vcpu);
> - return;
> - }
> + if (!vgic_is_v5(vcpu->kvm)) {
This should directly check for v3. Even once we add v5 support to NV,
I don't expect the code to be common at all.
> + /* If nesting, emulate the HW effect from L0 to L1 */
> + if (vgic_state_is_nested(vcpu)) {
> + vgic_v3_sync_nested(vcpu);
> + return;
> + }
>
> - if (vcpu_has_nv(vcpu))
> - vgic_v3_nested_update_mi(vcpu);
> + if (vcpu_has_nv(vcpu))
> + vgic_v3_nested_update_mi(vcpu);
> + }
>
> if (can_access_vgic_from_kernel())
> vgic_save_state(vcpu);
> @@ -1034,7 +1038,9 @@ void kvm_vgic_process_async_update(struct kvm_vcpu *vcpu)
>
> static inline void vgic_restore_state(struct kvm_vcpu *vcpu)
> {
> - if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
> + if (vgic_is_v5(vcpu->kvm))
> + vgic_v5_restore_state(vcpu);
> + else if (!static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
> vgic_v2_restore_state(vcpu);
> else
> __vgic_v3_restore_state(&vcpu->arch.vgic_cpu.vgic_v3);
I have similar comments as some the previous hunks. Using switch/case
statements would be more readable IMO.
Thanks,
M.
--
Without deviation from the norm, progress is not possible.
next prev parent reply other threads:[~2026-03-04 9:26 UTC|newest]
Thread overview: 56+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-02-26 15:55 [PATCH v5 00/36] KVM: arm64: Introduce vGIC-v5 with PPI support Sascha Bischoff
2026-02-26 15:55 ` [PATCH v5 01/36] KVM: arm64: vgic-v3: Drop userspace write sanitization for ID_AA64PFR0.GIC on GICv5 Sascha Bischoff
2026-02-26 15:55 ` [PATCH v5 02/36] KVM: arm64: vgic: Rework vgic_is_v3() and add vgic_host_has_gicvX() Sascha Bischoff
2026-02-26 15:56 ` [PATCH v5 03/36] KVM: arm64: Return early from kvm_finalize_sys_regs() if guest has run Sascha Bischoff
2026-02-26 15:56 ` [PATCH v5 04/36] arm64/sysreg: Add remaining GICv5 ICC_ & ICH_ sysregs for KVM support Sascha Bischoff
2026-02-26 15:56 ` [PATCH v5 05/36] arm64/sysreg: Add GICR CDNMIA encoding Sascha Bischoff
2026-02-26 15:56 ` [PATCH v5 06/36] KVM: arm64: gic-v5: Add ARM_VGIC_V5 device to KVM headers Sascha Bischoff
2026-02-26 15:57 ` [PATCH v5 07/36] KVM: arm64: gic: Introduce interrupt type helpers Sascha Bischoff
2026-03-03 15:04 ` Marc Zyngier
2026-03-03 17:21 ` Sascha Bischoff
2026-02-26 15:57 ` [PATCH v5 08/36] KVM: arm64: gic-v5: Add Arm copyright header Sascha Bischoff
2026-02-26 15:57 ` [PATCH v5 09/36] KVM: arm64: gic-v5: Detect implemented PPIs on boot Sascha Bischoff
2026-03-03 15:10 ` Marc Zyngier
2026-03-03 17:22 ` Sascha Bischoff
2026-02-26 15:58 ` [PATCH v5 10/36] KVM: arm64: gic-v5: Sanitize ID_AA64PFR2_EL1.GCIE Sascha Bischoff
2026-03-03 15:54 ` Marc Zyngier
2026-03-03 17:49 ` Sascha Bischoff
2026-02-26 15:58 ` [PATCH v5 11/36] KVM: arm64: gic-v5: Support GICv5 FGTs & FGUs Sascha Bischoff
2026-02-26 15:58 ` [PATCH v5 12/36] KVM: arm64: gic-v5: Add emulation for ICC_IAFFIDR_EL1 accesses Sascha Bischoff
2026-03-03 16:02 ` Marc Zyngier
2026-03-03 17:54 ` Sascha Bischoff
2026-02-26 15:58 ` [PATCH v5 13/36] KVM: arm64: gic-v5: Trap and emulate ICC_IDR0_EL1 accesses Sascha Bischoff
2026-02-26 15:59 ` [PATCH v5 14/36] KVM: arm64: gic-v5: Add vgic-v5 save/restore hyp interface Sascha Bischoff
2026-03-03 17:10 ` Marc Zyngier
2026-03-04 11:32 ` Sascha Bischoff
2026-02-26 15:59 ` [PATCH v5 15/36] KVM: arm64: gic-v5: Implement GICv5 load/put and save/restore Sascha Bischoff
2026-03-04 9:26 ` Marc Zyngier [this message]
2026-03-04 14:21 ` Sascha Bischoff
2026-02-26 15:59 ` [PATCH v5 16/36] KVM: arm64: gic-v5: Implement direct injection of PPIs Sascha Bischoff
2026-03-04 9:35 ` Marc Zyngier
2026-03-05 11:22 ` Sascha Bischoff
2026-02-26 15:59 ` [PATCH v5 17/36] KVM: arm64: gic-v5: Finalize GICv5 PPIs and generate mask Sascha Bischoff
2026-03-04 10:50 ` Marc Zyngier
2026-03-04 17:38 ` Sascha Bischoff
2026-02-26 16:00 ` [PATCH v5 18/36] KVM: arm64: gic: Introduce queue_irq_unlock to irq_ops Sascha Bischoff
2026-02-26 16:00 ` [PATCH v5 19/36] KVM: arm64: gic-v5: Implement PPI interrupt injection Sascha Bischoff
2026-03-04 13:08 ` Marc Zyngier
2026-02-26 16:00 ` [PATCH v5 20/36] KVM: arm64: gic-v5: Init Private IRQs (PPIs) for GICv5 Sascha Bischoff
2026-03-04 14:21 ` Marc Zyngier
2026-03-05 13:35 ` Sascha Bischoff
2026-02-26 16:00 ` [PATCH v5 21/36] KVM: arm64: gic-v5: Check for pending PPIs Sascha Bischoff
2026-02-26 16:01 ` [PATCH v5 22/36] KVM: arm64: gic-v5: Trap and mask guest ICC_PPI_ENABLERx_EL1 writes Sascha Bischoff
2026-02-26 16:01 ` [PATCH v5 23/36] KVM: arm64: gic-v5: Support GICv5 interrupts with KVM_IRQ_LINE Sascha Bischoff
2026-02-26 16:01 ` [PATCH v5 24/36] KVM: arm64: gic-v5: Create and initialise vgic_v5 Sascha Bischoff
2026-02-26 16:01 ` [PATCH v5 25/36] KVM: arm64: gic-v5: Initialise ID and priority bits when resetting vcpu Sascha Bischoff
2026-02-26 16:02 ` [PATCH v5 26/36] KVM: arm64: gic-v5: Enlighten arch timer for GICv5 Sascha Bischoff
2026-02-26 16:02 ` [PATCH v5 27/36] KVM: arm64: gic-v5: Mandate architected PPI for PMU emulation on GICv5 Sascha Bischoff
2026-02-26 16:02 ` [PATCH v5 28/36] KVM: arm64: gic: Hide GICv5 for protected guests Sascha Bischoff
2026-02-26 16:02 ` [PATCH v5 29/36] KVM: arm64: gic-v5: Hide FEAT_GCIE from NV GICv5 guests Sascha Bischoff
2026-02-26 16:03 ` [PATCH v5 30/36] KVM: arm64: gic-v5: Introduce kvm_arm_vgic_v5_ops and register them Sascha Bischoff
2026-02-26 16:03 ` [PATCH v5 31/36] KVM: arm64: gic-v5: Set ICH_VCTLR_EL2.En on boot Sascha Bischoff
2026-02-26 16:03 ` [PATCH v5 32/36] KVM: arm64: gic-v5: Probe for GICv5 device Sascha Bischoff
2026-02-26 16:04 ` [PATCH v5 33/36] Documentation: KVM: Introduce documentation for VGICv5 Sascha Bischoff
2026-02-26 16:04 ` [PATCH v5 34/36] KVM: arm64: selftests: Introduce a minimal GICv5 PPI selftest Sascha Bischoff
2026-02-26 16:04 ` [PATCH v5 35/36] KVM: arm64: gic-v5: Communicate userspace-driveable PPIs via a UAPI Sascha Bischoff
2026-02-26 16:04 ` [PATCH v5 36/36] KVM: arm64: selftests: Add no-vgic-v5 selftest Sascha Bischoff
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=865x7c7xnn.wl-maz@kernel.org \
--to=maz@kernel.org \
--cc=Joey.Gouly@arm.com \
--cc=Sascha.Bischoff@arm.com \
--cc=Suzuki.Poulose@arm.com \
--cc=Timothy.Hayes@arm.com \
--cc=jonathan.cameron@huawei.com \
--cc=kvm@vger.kernel.org \
--cc=kvmarm@lists.linux.dev \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=lpieralisi@kernel.org \
--cc=nd@arm.com \
--cc=oliver.upton@linux.dev \
--cc=peter.maydell@linaro.org \
--cc=yuzenghui@huawei.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.