KVM: arm64: Add LR overflow infrastructure
Marc Zyngier
maintainerv2 cover KVM: arm64: Add LR overflow infrastructure
This is the 2nd version of the series originally posted at [1]. The series has significantly evolved with a bunch of bug fixes, some additional optimisations, and a number of test cases.
This has now been extensively tested on much of what I have access to, specially on some of the most broken stuff (Apple, Qualcomm, Cavium, ARMv8.0 CPUs without TDIR), but also on some less shitty systems (which are the minority, unsurprisingly).
Given that this is fixing some really ugly vgic bugs, I'm aiming this at 6.19, though these bugs being 10 year old, any form of urgency is very questionable.
Patches still against -rc4.
* From v1 [1]:
- Fixed the ICH_HCR_EL2.TDIR detection code to include the Apple stuff, and to deal with GICv5's legacy mode
- Fixed compilation issue for old toolchains that don't understand the GICv3 sysreg names
- Allow GICv3 in-LR deactivation even when DIR trapping is enabled
- Dropped the split overflow list, once I convinced myself it wasn't bringing much to the table
- Turned kvm_vgic_vcpu_enable() into a vgic reset helper
- Remove IPI-ing on GICv3 systems without TDIR
- Fixed the out-of-LR deactivation when dealing with asymmetric SPI deactivation
- Fixed broken MMIO offset computation
- Added group enable to the GIC selftest library
- Added fixes and improvements to the vgic_irq selftest:
- Fixed definition of spurious interrupt
- Fixed config/enable ordering
- Prevent timer interrupts from being injected from userspace
- Removed limit of 4 interrupts being injected at any given time
- Added an asymmetric SPI deactivation test case
- Added a Group-0 enable test case
- Added a timer interrupt + SPI interrupt test case
- Fixed a couple of spelling mistakes (and added many more, I'm sure)
- Reordered the series slightly
[1] https://lore.kernel.org/r/[email protected]
Marc Zyngier (45):
irqchip/gic: Add missing GICH_HCR control bits irqchip/gic: Expose CPU interface VA to KVM irqchip/apple-aic: Spit out ICH_MISR_EL2 value on spurious vGIC MI
KVM: arm64: Turn vgic-v3 errata traps into a patched-in constant
KVM: arm64: GICv3: Detect and work around the lack of ICV_DIR_EL1
trapping
KVM: arm64: Repack struct vgic_irq fields
KVM: arm64: Add tracking of vgic_irq being present in a LR
KVM: arm64: Add LR overflow handling documentation
KVM: arm64: GICv3: Drop LPI active state when folding LRs
KVM: arm64: GICv3: Preserve EOIcount on exit
KVM: arm64: GICv3: Decouple ICH_HCR_EL2 programming from LRs
KVM: arm64: GICv3: Extract LR folding primitive
KVM: arm64: GICv3: Extract LR computing primitive
KVM: arm64: GICv2: Preserve EOIcount on exit
KVM: arm64: GICv2: Decouple GICH_HCR programming from LRs being loaded
KVM: arm64: GICv2: Extract LR folding primitive
KVM: arm64: GICv2: Extract LR computing primitive
KVM: arm64: Compute vgic state irrespective of the number of
interrupts
KVM: arm64: Eagerly save VMCR on exit
KVM: arm64: Revamp vgic maintenance interrupt configuration
KVM: arm64: Turn kvm_vgic_vcpu_enable() into kvm_vgic_vcpu_reset()
KVM: arm64: Make vgic_target_oracle() globally available
KVM: arm64: Invert ap_list sorting to push active interrupts out
KVM: arm64: Move undeliverable interrupts to the end of ap_list
KVM: arm64: Use MI to detect groups being enabled/disabled
KVM: arm64: GICv3: Handle LR overflow when EOImode==0
KVM: arm64: GICv3: Handle deactivation via ICV_DIR_EL1 traps
KVM: arm64: GICv3: Add GICv2 SGI handling to deactivation primitive
KVM: arm64: GICv3: Set ICH_HCR_EL2.TDIR when interrupts overflow LR
capacity
KVM: arm64: GICv3: Add SPI tracking to handle asymmetric deactivation
KVM: arm64: GICv3: Handle in-LR deactivation when possible
KVM: arm64: GICv3: Avoid broadcast kick on CPUs lacking TDIR
KVM: arm64: GICv2: Handle LR overflow when EOImode==0
KVM: arm64: GICv2: Handle deactivation via GICV_DIR traps
KVM: arm64: GICv2: Always trap GICV_DIR register
KVM: arm64: selftests: gic_v3: Add irq group setting helper
KVM: arm64: selftests: gic_v3: Disable Group-0 interrupts by default
KVM: arm64: selftests: vgic_irq: Fix GUEST_ASSERT_IAR_EMPTY() helper
KVM: arm64: selftests: vgic_irq: Change configuration before enabling
interrupt
KVM: arm64: selftests: vgic_irq: Exclude timer-controlled interrupts
KVM: arm64: selftests: vgic_irq: Remove LR-bound limitation
KVM: arm64: selftests: vgic_irq: Perform EOImode==1 deactivation in
ack order
KVM: arm64: selftests: vgic_irq: Add asymmetric SPI deaectivation test
KVM: arm64: selftests: vgic_irq: Add Group-0 enable test
KVM: arm64: selftests: vgic_irq: Add timer deactivation test
arch/arm64/include/asm/kvm_asm.h | 2 +- arch/arm64/include/asm/kvm_host.h | 1 + arch/arm64/include/asm/kvm_hyp.h | 2 +- arch/arm64/include/asm/virt.h | 7 +- arch/arm64/kernel/cpufeature.c | 52 +++ arch/arm64/kernel/hyp-stub.S | 5 + arch/arm64/kernel/image-vars.h | 1 + arch/arm64/kvm/arm.c | 7 +- arch/arm64/kvm/hyp/nvhe/hyp-main.c | 7 +- arch/arm64/kvm/hyp/vgic-v2-cpuif-proxy.c | 4 + arch/arm64/kvm/hyp/vgic-v3-sr.c | 87 ++-- arch/arm64/kvm/sys_regs.c | 19 +- arch/arm64/kvm/vgic/vgic-init.c | 9 +- arch/arm64/kvm/vgic/vgic-mmio-v2.c | 24 + arch/arm64/kvm/vgic/vgic-mmio.h | 1 + arch/arm64/kvm/vgic/vgic-v2.c | 291 +++++++++--- arch/arm64/kvm/vgic/vgic-v3-nested.c | 11 +- arch/arm64/kvm/vgic/vgic-v3.c | 421 ++++++++++++++---- arch/arm64/kvm/vgic/vgic-v4.c | 5 +- arch/arm64/kvm/vgic/vgic.c | 294 +++++++----- arch/arm64/kvm/vgic/vgic.h | 42 +- arch/arm64/tools/cpucaps | 1 + drivers/irqchip/irq-apple-aic.c | 7 +- drivers/irqchip/irq-gic.c | 3 + include/kvm/arm_vgic.h | 29 +- include/linux/irqchip/arm-gic.h | 6 + include/linux/irqchip/arm-vgic-info.h | 2 + tools/testing/selftests/kvm/arm64/vgic_irq.c | 285 +++++++++++- .../testing/selftests/kvm/include/arm64/gic.h | 1 + tools/testing/selftests/kvm/lib/arm64/gic.c | 6 + .../selftests/kvm/lib/arm64/gic_private.h | 1 + .../testing/selftests/kvm/lib/arm64/gic_v3.c | 17 + 32 files changed, 1276 insertions(+), 374 deletions(-)
Signature · 1 line
2.47.3
Marc Zyngier
maintainerPATCH v2 1/45 irqchip/gic: Add missing GICH_HCR control bits
The GICH_HCR description is missing a bunch of additional control bits for the maintenance interrupt. Add them.
--- include/linux/irqchip/arm-gic.h | 6 ++++++ 1 file changed, 6 insertions(+)
include/linux/irqchip/arm-gic.h +6 -0
@@ -86,7 +86,13 @@#define GICH_HCR_EN (1 << 0)#define GICH_HCR_UIE (1 << 1) +#define GICH_HCR_LRENPIE (1 << 2)#define GICH_HCR_NPIE (1 << 3) +#define GICH_HCR_VGrp0EIE (1 << 4) +#define GICH_HCR_VGrp0DIE (1 << 5) +#define GICH_HCR_VGrp1EIE (1 << 6) +#define GICH_HCR_VGrp1DIE (1 << 7) +#define GICH_HCR_EOICOUNT GENMASK(31, 27)#define GICH_LR_VIRTUALID (0x3ff << 0)#define GICH_LR_PHYSID_CPUID_SHIFT (10)
Signature · 1 line
2.47.3
Marc Zyngier
maintainerPATCH v2 2/45 irqchip/gic: Expose CPU interface VA to KVM
In reply to Marc ZyngierFuture changes will require KVM to be able to perform deactivations by writing to the physical CPU interface. Add the corresponding VA to the kvm_info structure, and let KVM stash it.
--- arch/arm64/kvm/vgic/vgic-v2.c | 1 + drivers/irqchip/irq-gic.c | 3 +++ include/kvm/arm_vgic.h | 3 +++ include/linux/irqchip/arm-vgic-info.h | 2 ++ 4 files changed, 9 insertions(+)
arch/arm64/kvm/vgic/vgic-v2.c +1 -0
@@ -385,6 +385,7 @@ int vgic_v2_probe(const struct gic_kvm_info *info) kvm_vgic_global_state.can_emulate_gicv2 = true; kvm_vgic_global_state.vcpu_base = info->vcpu.start; + kvm_vgic_global_state.gicc_base = info->gicc_base; kvm_vgic_global_state.type =VGIC_V2 ; kvm_vgic_global_state.max_gic_vcpus =VGIC_V2_MAX_CPUS ;
drivers/irqchip/irq-gic.c +3 -0
@@ -1459,6 +1459,8 @@ static void __init gic_of_setup_kvm_info(struct device_node *node)if (ret)return ; + gic_v2_kvm_info.gicc_base = gic_data[0 ].cpu_base.common_base; +if (static_branch_likely (&supports_deactivate_key))vgic_set_kvm_info (&gic_v2_kvm_info); }
@@ -1620,6 +1622,7 @@ static void __init gic_acpi_setup_kvm_info(void)return ; gic_v2_kvm_info.maint_irq = irq; + gic_v2_kvm_info.gicc_base = gic_data[0 ].cpu_base.common_base;vgic_set_kvm_info (&gic_v2_kvm_info); }
include/kvm/arm_vgic.h +3 -0
@@ -59,6 +59,9 @@ struct vgic_global {/* virtual control interface mapping, HYP VA */ void __iomem *vctrl_hyp; +/* Physical CPU interface, kernel VA */ +void __iomem *gicc_base; +/* Number of implemented list registers */ int nr_lr;
include/linux/irqchip/arm-vgic-info.h +2 -0
@@ -24,6 +24,8 @@ struct gic_kvm_info {enum gic_type type;/* Virtual CPU interface */ struct resource vcpu; +/* GICv2 GICC VA */ +void __iomem *gicc_base;/* Interrupt number */ unsigned int maint_irq;/* No interrupt mask, no need to use the above field */
Signature · 1 line
2.47.3
Marc Zyngier
maintainerPATCH v2 3/45 irqchip/apple-aic: Spit out ICH_MISR_EL2 value on spurious vGIC MI
In reply to Marc ZyngierIt is all good and well to scream about spurious vGIC maintenance interrupts. It would be even better to output the reason why, which is already checked, but not printed out.
The unsuspecting kernel tinkerer thanks you.
--- drivers/irqchip/irq-apple-aic.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
drivers/irqchip/irq-apple-aic.c +5 -2
@@ -411,12 +411,15 @@ static void __exception_irq_entry aic_handle_irq(struct pt_regs *regs)if (is_kernel_in_hyp_mode () && (read_sysreg_s (SYS_ICH_HCR_EL2 ) & ICH_HCR_EL2_En) &&read_sysreg_s (SYS_ICH_MISR_EL2 ) !=0 ) { +u64 val; +generic_handle_domain_irq (aic_irqc->hw_domain,AIC_FIQ_HWIRQ (AIC_VGIC_MI ));if (unlikely ((read_sysreg_s (SYS_ICH_HCR_EL2 ) & ICH_HCR_EL2_En) && -read_sysreg_s (SYS_ICH_MISR_EL2 ))) { -pr_err_ratelimited ("vGIC IRQ fired and not handled by KVM, disabling.\n" ); + (val =read_sysreg_s (SYS_ICH_MISR_EL2 )))) { +pr_err_ratelimited ("vGIC IRQ fired and not handled by KVM (MISR=%llx), disabling.\n" , + val);sysreg_clear_set_s (SYS_ICH_HCR_EL2 , ICH_HCR_EL2_En,0 ); } }
Signature · 1 line
2.47.3
Marc Zyngier
maintainerPATCH v2 4/45 KVM: arm64: Turn vgic-v3 errata traps into a patched-in constant
In reply to Marc ZyngierThe trap bits are currently only set to manage CPU errata. However, we are about to make use of them for purposes beyond beating broken CPUs into submission.
For this purpose, turn these errata-driven bits into a patched-in constant that is merged with the KVM-driven value at the point of programming the ICH_HCR_EL2 register, rather than being directly stored with with the shadow value..
This allows the KVM code to distinguish between a trap being handled for the purpose of an erratum workaround, or for KVM's own need.
--- arch/arm64/kernel/image-vars.h | 1 + arch/arm64/kvm/hyp/vgic-v3-sr.c | 21 +++++--- arch/arm64/kvm/vgic/vgic-v3-nested.c | 9 ---- arch/arm64/kvm/vgic/vgic-v3.c | 81 +++++++++++++++++----------- arch/arm64/kvm/vgic/vgic.h | 16 ++++++ 5 files changed, 82 insertions(+), 46 deletions(-)
arch/arm64/kernel/image-vars.h +1 -0
@@ -91,6 +91,7 @@ KVM_NVHE_ALIAS(spectre_bhb_patch_loop_mitigation_enable);KVM_NVHE_ALIAS (spectre_bhb_patch_wa3);KVM_NVHE_ALIAS (spectre_bhb_patch_clearbhb);KVM_NVHE_ALIAS (alt_cb_patch_nops); +KVM_NVHE_ALIAS (kvm_compute_ich_hcr_trap_bits);/* Global kernel state accessed by nVHE hyp code. */ KVM_NVHE_ALIAS (kvm_vgic_global_state);
arch/arm64/kvm/hyp/vgic-v3-sr.c +14 -7
@@ -14,6 +14,8 @@#include <asm/kvm_hyp.h> #include <asm/kvm_mmu.h> +#include "../../vgic/vgic.h" +#define vtr_to_max_lr_idx (v) ((v) & 0xf)#define vtr_to_nr_pre_bits (v) ((((u32)(v) >> 26) & 7) + 1)#define vtr_to_nr_apr_regs (v) (1 << (vtr_to_nr_pre_bits(v) - 5))
@@ -196,6 +198,11 @@ static u32 __vgic_v3_read_ap1rn(int n)return val; } +static u64 compute_ich_hcr (struct vgic_v3_cpu_if *cpu_if) +{ +return cpu_if->vgic_hcr |vgic_ich_hcr_trap_bits (); +} +void __vgic_v3_save_state (struct vgic_v3_cpu_if *cpu_if) {u64 used_lrs = cpu_if->used_lrs;
@@ -218,7 +225,7 @@ void __vgic_v3_save_state(struct vgic_v3_cpu_if *cpu_if) elrsr =read_gicreg (ICH_ELRSR_EL2 ); -write_gicreg (cpu_if->vgic_hcr & ~ICH_HCR_EL2_En,ICH_HCR_EL2 ); +write_gicreg (compute_ich_hcr (cpu_if) & ~ICH_HCR_EL2_En,ICH_HCR_EL2 );for (i =0 ; i < used_lrs; i++) {if (elrsr & (1 << i))
@@ -237,7 +244,7 @@ void __vgic_v3_restore_state(struct vgic_v3_cpu_if *cpu_if)int i;if (used_lrs || cpu_if->its_vpe.its_vm) { -write_gicreg (cpu_if->vgic_hcr,ICH_HCR_EL2 ); +write_gicreg (compute_ich_hcr (cpu_if),ICH_HCR_EL2 );for (i =0 ; i < used_lrs; i++)__gic_v3_set_lr (cpu_if->vgic_lr[i], i);
@@ -307,14 +314,14 @@ void __vgic_v3_activate_traps(struct vgic_v3_cpu_if *cpu_if) }/* -* If we need to trap system registers, we must write -* ICH_HCR_EL2 anyway, even if no interrupts are being -* injected. Note that this also applies if we don't expect -* any system register access (no vgic at all). +* If we need to trap system registers, we must write ICH_HCR_EL2 +* anyway, even if no interrupts are being injected. Note that this +* also applies if we don't expect any system register access (no +* vgic at all). In any case, no need to provide MI configuration. */ if (static_branch_unlikely (&vgic_v3_cpuif_trap) || cpu_if->its_vpe.its_vm || !cpu_if->vgic_sre) -write_gicreg (cpu_if->vgic_hcr,ICH_HCR_EL2 ); +write_gicreg (vgic_ich_hcr_trap_bits () | ICH_HCR_EL2_En,ICH_HCR_EL2 ); }void __vgic_v3_deactivate_traps (struct vgic_v3_cpu_if *cpu_if)
arch/arm64/kvm/vgic/vgic-v3-nested.c +0 -9
@@ -301,15 +301,6 @@ static void vgic_v3_create_shadow_state(struct kvm_vcpu *vcpu,u64 val =0 ;int i; -/* -* If we're on a system with a broken vgic that requires -* trapping, propagate the trapping requirements. -* -* Ah, the smell of rotten fruits... -*/ -if (static_branch_unlikely (&vgic_v3_cpuif_trap)) - val = host_if->vgic_hcr & (ICH_HCR_EL2_TALL0 |ICH_HCR_EL2_TALL1 | -ICH_HCR_EL2_TC |ICH_HCR_EL2_TDIR ); s_cpu_if->vgic_hcr =__vcpu_sys_reg (vcpu,ICH_HCR_EL2 ) | val; s_cpu_if->vgic_vmcr =__vcpu_sys_reg (vcpu,ICH_VMCR_EL2 ); s_cpu_if->vgic_sre = host_if->vgic_sre;
arch/arm64/kvm/vgic/vgic-v3.c +51 -30
116 lines not on this page · raw message
arch/arm64/kvm/vgic/vgic.h +16 -0
@@ -164,6 +164,22 @@ static inline int vgic_write_guest_lock(struct kvm *kvm, gpa_t gpa,return ret; } +void kvm_compute_ich_hcr_trap_bits (struct alt_instr *alt, +__le32 *origptr,__le32 *updptr,int nr_inst); + +static inline u64 vgic_ich_hcr_trap_bits (void ) +{ +u64 hcr; + +/* All the traps are in the bottom 16bits */ + asm volatile(ALTERNATIVE_CB("movz %0, #0\n", + ARM64_ALWAYS_SYSTEM, + kvm_compute_ich_hcr_trap_bits) + : "=r" (hcr)); + +return hcr; +} +/* * This struct provides an intermediate representation of the fields contained * in the GICH_VMCR and ICH_VMCR registers, such that code exporting the GIC
Signature · 1 line
2.47.3
Suzuki K Poulose
reviewerRe: [PATCH v2 04/45] KVM: arm64: Turn vgic-v3 errata traps into a patched-in constant
Hi Marc,
Quoted 14 lines · Marc Zyngier
The trap bits are currently only set to manage CPU errata. However, we are about to make use of them for purposes beyond beating broken CPUs into submission.
For this purpose, turn these errata-driven bits into a patched-in constant that is merged with the KVM-driven value at the point of programming the
ICH_HCR_EL2register, rather than being directly stored with with the shadow value..This allows the KVM code to distinguish between a trap being handled for the purpose of an erratum workaround, or for KVM's own need.
Signed-off-by Marc Zyngier <[email protected]>---
...
Quoted 5 lines
arch/arm64/kvm/vgic/vgic.h +0
-0
arch/arm64/kvm/vgic/vgic.h static inline int vgic_write_guest_lock(struct kvm *kvm, gpa_t gpa, · line 172
Quoted 9 lines
arch/arm64/kvm/vgic/vgic.h +6
-0@@ -164,6 +164,22 @@ static inline int vgic_write_guest_lock(struct kvm *kvm, gpa_t gpa,return ret; } +void kvm_compute_ich_hcr_trap_bits (struct alt_instr *alt, +__le32 *origptr,__le32 *updptr,int nr_inst); + +static inline u64 vgic_ich_hcr_trap_bits (void ) +{ +u64 hcr;
minor nit: Do we need a guard to make sure this isn't called before the capabilities are finalized (given we may use it outside VM context, e.g. VGIC probe). perhaps :
WARN_ON(!system_capabilities_finalized());
arch/arm64/kvm/vgic/vgic.h static inline int vgic_write_guest_lock(struct kvm *kvm, gpa_t gpa, · line 178
Quoted 6 lines
arch/arm64/kvm/vgic/vgic.h +6
-0+ +/* All the traps are in the bottom 16bits */ + asm volatile(ALTERNATIVE_CB("movz %0, #0\n", + ARM64_ALWAYS_SYSTEM, + kvm_compute_ich_hcr_trap_bits) + : "=r" (hcr));
Suzuki
Marc Zyngier
maintainerRe: [PATCH v2 04/45] KVM: arm64: Turn vgic-v3 errata traps into a patched-in constant
Quoted 39 lines · Suzuki K Poulose
Hi Marc,
Quoted 14 lines · Marc Zyngier
The trap bits are currently only set to manage CPU errata. However, we are about to make use of them for purposes beyond beating broken CPUs into submission.
For this purpose, turn these errata-driven bits into a patched-in constant that is merged with the KVM-driven value at the point of programming the
ICH_HCR_EL2register, rather than being directly stored with with the shadow value..This allows the KVM code to distinguish between a trap being handled for the purpose of an erratum workaround, or for KVM's own need.
Signed-off-by Marc Zyngier <[email protected]>---
...
arch/arm64/kvm/vgic/vgic.h static inline int vgic_write_guest_lock(struct kvm *kvm, gpa_t gpa, · line 171
Quoted 13 lines
arch/arm64/kvm/vgic/vgic.h +5
-0@@ -164,6 +164,22 @@ static inline int vgic_write_guest_lock(struct kvm *kvm, gpa_t gpa,return ret; } +void kvm_compute_ich_hcr_trap_bits(struct alt_instr *alt, + __le32 *origptr, __le32 *updptr, int nr_inst); + +static inline u64 vgic_ich_hcr_trap_bits (void ) +{ +u64 hcr;minor nit: Do we need a guard to make sure this isn't called before the capabilities are finalized (given we may use it outside VM context, e.g. VGIC probe). perhaps :
Quoted 1 line
WARN_ON(!system_capabilities_finalized());
We already have a BUG_ON() for that at the point of setting up the vectors for pKVM. It wouldn't hurt to move this up as a general check for KVM, but I don't think placing these checks in random leaf functions is very appealing.
And if we do, it should be gated to not emit code in the hot path, with something like this (which I find awful):
arch/arm64/kvm/vgic/vgic.h +3 -0
@@ -171,6 +171,9 @@ static inline u64 vgic_ich_hcr_trap_bits(void) {u64 hcr; +#if !defined(__KVM_VHE_HYPERVISOR__) && !defined(__KVM_NVHE_HYPERVISOR__) +WARN_ON (!system_capabilities_finalized ()); +#endif /* All the traps are in the bottom 16bits */ asm volatile(ALTERNATIVE_CB("movz %0, #0\n", ARM64_ALWAYS_SYSTEM,
Thanks,
M.
Signature · 1 line
Without deviation from the norm, progress is not possible.
Oliver Upton
maintainerRe: [PATCH v2 04/45] KVM: arm64: Turn vgic-v3 errata traps into a patched-in constant
In reply to Marc ZyngierHey,
Quoted 3 lines · Marc Zyngier
The trap bits are currently only set to manage CPU errata. However, we are about to make use of them for purposes beyond beating broken CPUs into submission.
There's also the command-line hacks for configuring traps, which should still work given the relative ordering of alternatives patching. But might be worth a mention.
Thanks,
Oliver
Quoted 266 lines
For this purpose, turn these errata-driven bits into a patched-in constant that is merged with the KVM-driven value at the point of programming the
ICH_HCR_EL2register, rather than being directly stored with with the shadow value..This allows the KVM code to distinguish between a trap being handled for the purpose of an erratum workaround, or for KVM's own need.
Signed-off-by Marc Zyngier <[email protected]>--- arch/arm64/kernel/image-vars.h | 1 + arch/arm64/kvm/hyp/vgic-v3-sr.c | 21 +++++--- arch/arm64/kvm/vgic/vgic-v3-nested.c | 9 ---- arch/arm64/kvm/vgic/vgic-v3.c | 81 +++++++++++++++++----------- arch/arm64/kvm/vgic/vgic.h | 16 ++++++ 5 files changed, 82 insertions(+), 46 deletions(-)arch/arm64/kernel/image-vars.h +1
-0@@ -91,6 +91,7 @@ KVM_NVHE_ALIAS(spectre_bhb_patch_loop_mitigation_enable);KVM_NVHE_ALIAS (spectre_bhb_patch_wa3);KVM_NVHE_ALIAS (spectre_bhb_patch_clearbhb);KVM_NVHE_ALIAS (alt_cb_patch_nops); +KVM_NVHE_ALIAS (kvm_compute_ich_hcr_trap_bits);/* Global kernel state accessed by nVHE hyp code. */ KVM_NVHE_ALIAS (kvm_vgic_global_state);arch/arm64/kvm/hyp/vgic-v3-sr.c +14
-7@@ -14,6 +14,8 @@#include <asm/kvm_hyp.h> #include <asm/kvm_mmu.h> +#include "../../vgic/vgic.h" +#define vtr_to_max_lr_idx (v) ((v) & 0xf)#define vtr_to_nr_pre_bits (v) ((((u32)(v) >> 26) & 7) + 1)#define vtr_to_nr_apr_regs (v) (1 << (vtr_to_nr_pre_bits(v) - 5))@@ -196,6 +198,11 @@ static u32 __vgic_v3_read_ap1rn(int n)return val; } +static u64 compute_ich_hcr (struct vgic_v3_cpu_if *cpu_if) +{ +return cpu_if->vgic_hcr |vgic_ich_hcr_trap_bits (); +} +void __vgic_v3_save_state (struct vgic_v3_cpu_if *cpu_if) {u64 used_lrs = cpu_if->used_lrs;@@ -218,7 +225,7 @@ void __vgic_v3_save_state(struct vgic_v3_cpu_if *cpu_if) elrsr =read_gicreg (ICH_ELRSR_EL2 ); -write_gicreg (cpu_if->vgic_hcr & ~ICH_HCR_EL2_En,ICH_HCR_EL2 ); +write_gicreg (compute_ich_hcr (cpu_if) & ~ICH_HCR_EL2_En,ICH_HCR_EL2 );for (i =0 ; i < used_lrs; i++) {if (elrsr & (1 << i))@@ -237,7 +244,7 @@ void __vgic_v3_restore_state(struct vgic_v3_cpu_if *cpu_if)int i;if (used_lrs || cpu_if->its_vpe.its_vm) { -write_gicreg (cpu_if->vgic_hcr,ICH_HCR_EL2 ); +write_gicreg (compute_ich_hcr (cpu_if),ICH_HCR_EL2 );for (i =0 ; i < used_lrs; i++)__gic_v3_set_lr (cpu_if->vgic_lr[i], i);@@ -307,14 +314,14 @@ void __vgic_v3_activate_traps(struct vgic_v3_cpu_if *cpu_if) }/* -* If we need to trap system registers, we must write -* ICH_HCR_EL2 anyway, even if no interrupts are being -* injected. Note that this also applies if we don't expect -* any system register access (no vgic at all). +* If we need to trap system registers, we must write ICH_HCR_EL2 +* anyway, even if no interrupts are being injected. Note that this +* also applies if we don't expect any system register access (no +* vgic at all). In any case, no need to provide MI configuration. */ if (static_branch_unlikely (&vgic_v3_cpuif_trap) || cpu_if->its_vpe.its_vm || !cpu_if->vgic_sre) -write_gicreg (cpu_if->vgic_hcr,ICH_HCR_EL2 ); +write_gicreg (vgic_ich_hcr_trap_bits () | ICH_HCR_EL2_En,ICH_HCR_EL2 ); }void __vgic_v3_deactivate_traps (struct vgic_v3_cpu_if *cpu_if)arch/arm64/kvm/vgic/vgic-v3-nested.c +0
-9@@ -301,15 +301,6 @@ static void vgic_v3_create_shadow_state(struct kvm_vcpu *vcpu,u64 val =0 ;int i; -/* -* If we're on a system with a broken vgic that requires -* trapping, propagate the trapping requirements. -* -* Ah, the smell of rotten fruits... -*/ -if (static_branch_unlikely (&vgic_v3_cpuif_trap)) - val = host_if->vgic_hcr & (ICH_HCR_EL2_TALL0 |ICH_HCR_EL2_TALL1 | -ICH_HCR_EL2_TC |ICH_HCR_EL2_TDIR ); s_cpu_if->vgic_hcr =__vcpu_sys_reg (vcpu,ICH_HCR_EL2 ) | val; s_cpu_if->vgic_vmcr =__vcpu_sys_reg (vcpu,ICH_VMCR_EL2 ); s_cpu_if->vgic_sre = host_if->vgic_sre;arch/arm64/kvm/vgic/vgic-v3.c +51
-30@@ -301,20 +301,9 @@ void vcpu_set_ich_hcr(struct kvm_vcpu *vcpu)return ;/* Hide GICv3 sysreg if necessary */ -if (vcpu->kvm->arch.vgic.vgic_model ==KVM_DEV_TYPE_ARM_VGIC_V2 ) { +if (vcpu->kvm->arch.vgic.vgic_model ==KVM_DEV_TYPE_ARM_VGIC_V2 ) vgic_v3->vgic_hcr |= (ICH_HCR_EL2_TALL0 |ICH_HCR_EL2_TALL1 |ICH_HCR_EL2_TC ); -return ; - } - -if (group0_trap) - vgic_v3->vgic_hcr |=ICH_HCR_EL2_TALL0 ; -if (group1_trap) - vgic_v3->vgic_hcr |=ICH_HCR_EL2_TALL1 ; -if (common_trap) - vgic_v3->vgic_hcr |=ICH_HCR_EL2_TC ; -if (dir_trap) - vgic_v3->vgic_hcr |=ICH_HCR_EL2_TDIR ; }int vgic_v3_lpi_sync_pending_status (struct kvm *kvm,struct vgic_irq *irq)@@ -635,10 +624,52 @@ static const struct midr_range broken_seis[] = {static bool vgic_v3_broken_seis (void ) { -return ((kvm_vgic_global_state.ich_vtr_el2 &ICH_VTR_EL2_SEIS ) && +return (is_kernel_in_hyp_mode () && + (read_sysreg_s (SYS_ICH_VTR_EL2 ) &ICH_VTR_EL2_SEIS ) &&is_midr_in_range_list (broken_seis)); } +void noinstr kvm_compute_ich_hcr_trap_bits(struct alt_instr *alt, +__le32 *origptr,__le32 *updptr, +int nr_inst) +{ +u32 insn, oinsn, rd; +u64 hcr =0 ; + +if (cpus_have_cap (ARM64_WORKAROUND_CAVIUM_30115 )) { + group0_trap = true; + group1_trap = true; + } + +if (vgic_v3_broken_seis ()) { +/* We know that these machines have ICH_HCR_EL2.TDIR */ + group0_trap = true; + group1_trap = true; + dir_trap = true; + } + +if (group0_trap) + hcr |=ICH_HCR_EL2_TALL0 ; +if (group1_trap) + hcr |=ICH_HCR_EL2_TALL1 ; +if (common_trap) + hcr |=ICH_HCR_EL2_TC ; +if (dir_trap) + hcr |=ICH_HCR_EL2_TDIR ; + +/* Compute target register */ + oinsn =le32_to_cpu (*origptr); + rd =aarch64_insn_decode_register (AARCH64_INSN_REGTYPE_RD , oinsn); + +/* movz rd, #(val & 0xffff) */ + insn =aarch64_insn_gen_movewide (rd, + (u16 )hcr, +0 , +AARCH64_INSN_VARIANT_64BIT , +AARCH64_INSN_MOVEWIDE_ZERO ); + *updptr =cpu_to_le32 (insn); +} +/** * vgic_v3_probe - probe for a VGICv3 compatible interrupt controller * @info: pointer to the GIC description @@ -650,6 +681,7 @@ int vgic_v3_probe(const struct gic_kvm_info *info) {u64 ich_vtr_el2 =kvm_call_hyp_ret (__vgic_v3_get_gic_config);bool has_v2; +u64 traps;int ret; has_v2 = ich_vtr_el2 >>63 ;@@ -708,29 +740,18 @@ int vgic_v3_probe(const struct gic_kvm_info *info)if (has_v2)static_branch_enable (&vgic_v3_has_v2_compat); -if (cpus_have_final_cap (ARM64_WORKAROUND_CAVIUM_30115 )) { - group0_trap = true; - group1_trap = true; - } -if (vgic_v3_broken_seis ()) {kvm_info ("GICv3 with broken locally generated SEI\n" ); - kvm_vgic_global_state.ich_vtr_el2 &= ~ICH_VTR_EL2_SEIS ; - group0_trap = true; - group1_trap = true; -if (ich_vtr_el2 &ICH_VTR_EL2_TDS ) - dir_trap = true; -else - common_trap = true; } -if (group0_trap || group1_trap || common_trap | dir_trap) { + traps =vgic_ich_hcr_trap_bits (); +if (traps) {kvm_info ("GICv3 sysreg trapping enabled ([%s%s%s%s], reduced performance)\n" , - group0_trap ?"G0" :"" , - group1_trap ?"G1" :"" , - common_trap ?"C" :"" , - dir_trap ?"D" :"" ); + (traps &ICH_HCR_EL2_TALL0 ) ?"G0" :"" , + (traps &ICH_HCR_EL2_TALL1 ) ?"G1" :"" , + (traps &ICH_HCR_EL2_TC ) ?"C" :"" , + (traps &ICH_HCR_EL2_TDIR ) ?"D" :"" );static_branch_enable (&vgic_v3_cpuif_trap); }arch/arm64/kvm/vgic/vgic.h +16
-0@@ -164,6 +164,22 @@ static inline int vgic_write_guest_lock(struct kvm *kvm, gpa_t gpa,return ret; } +void kvm_compute_ich_hcr_trap_bits (struct alt_instr *alt, +__le32 *origptr,__le32 *updptr,int nr_inst); + +static inline u64 vgic_ich_hcr_trap_bits (void ) +{ +u64 hcr; + +/* All the traps are in the bottom 16bits */ + asm volatile(ALTERNATIVE_CB("movz %0, #0\n", + ARM64_ALWAYS_SYSTEM, + kvm_compute_ich_hcr_trap_bits) + : "=r" (hcr)); + +return hcr; +} +/* * This struct provides an intermediate representation of the fields contained * in the GICH_VMCR and ICH_VMCR registers, such that code exporting the GIC Signature · 1 line
2.47.3
Re: [PATCH v2 04/45] KVM: arm64: Turn vgic-v3 errata traps into a patched-in constant
In reply to Marc ZyngierQuoted 9 lines · Marc Zyngier
The trap bits are currently only set to manage CPU errata. However, we are about to make use of them for purposes beyond beating broken CPUs into submission.
For this purpose, turn these errata-driven bits into a patched-in constant that is merged with the KVM-driven value at the point of programming the
ICH_HCR_EL2register, rather than being directly stored with with the shadow value..
Quoted 4 lines
This allows the KVM code to distinguish between a trap being handled for the purpose of an erratum workaround, or for KVM's own need.
Signed-off-by Marc Zyngier <[email protected]>
This patch landed in today's linux-next as commit ca30799f7c2d ("KVM:
arm64: Turn vgic-v3 errata traps into a patched-in constant"). In my tests I found that it triggers oops and breaks booting on Raspberry Pi5 and Amlogic SM1 based boards: Odroid-C4 and Khadas VIM3l. Here is the failure log:
alternatives: applying system-wide alternatives
Internal error: Oops - Undefined instruction: 0000000002000000 [#1] SMP Modules linked in: CPU: 0 UID: 0 PID: 18 Comm: migration/0 Not tainted 6.18.0-rc3+ #11665 PREEMPT Hardware name: Raspberry Pi 5 Model B Rev 1.0 (DT) Stopper: multi_cpu_stop+0x0/0x178 <- __stop_cpus.constprop.0+0x7c/0xc8 pstate: 604000c9 (nZCv daIF +PAN -UAO -TCO -DIT -SSBS BTYPE=--) pc : vgic_v3_broken_seis+0x14/0x44 lr : kvm_compute_ich_hcr_trap_bits+0x48/0xd8 ... Call trace: vgic_v3_broken_seis+0x14/0x44 (P) __apply_alternatives+0x1b4/0x200 __apply_alternatives_multi_stop+0xac/0xc8 multi_cpu_stop+0x90/0x178 cpu_stopper_thread+0x8c/0x11c smpboot_thread_fn+0x160/0x32c kthread+0x150/0x228 ret_from_fork+0x10/0x20 Code: 52800000 f100203f 54000040 d65f03c0 (d53ccb21) ---[ end trace 0000000000000000 ]--- note: migration/0[18] exited with irqs disabled note: migration/0[18] exited with preempt_count 1 rcu: INFO: rcu_preempt detected stalls on CPUs/tasks:
rcu: 1-...0: (7 ticks this GP) idle=0124/1/0x4000000000000000 softirq=9/10 fqs=3250
rcu: 2-...0: (7 ticks this GP) idle=0154/1/0x4000000000000000 softirq=9/10 fqs=3250
rcu: 3-...0: (7 ticks this GP) idle=018c/1/0x4000000000000000 softirq=9/10 fqs=3250
rcu: (detected by 0, t=6502 jiffies, g=-1179, q=2 ncpus=4) Sending NMI from CPU 0 to CPUs 1:
Sending NMI from CPU 0 to CPUs 2:
Sending NMI from CPU 0 to CPUs 3:
Let me know how I can help in debugging this issue.
Quoted 9 lines
--- arch/arm64/kernel/image-vars.h | 1 + arch/arm64/kvm/hyp/vgic-v3-sr.c | 21 +++++--- arch/arm64/kvm/vgic/vgic-v3-nested.c | 9 ---- arch/arm64/kvm/vgic/vgic-v3.c | 81 +++++++++++++++++----------- arch/arm64/kvm/vgic/vgic.h | 16 ++++++ 5 files changed, 82 insertions(+), 46 deletions(-)...
Best regards
Signature · 2 lines
Marek Szyprowski, PhD Samsung R&D Institute Poland
Marc Zyngier
maintainerRe: [PATCH v2 04/45] KVM: arm64: Turn vgic-v3 errata traps into a patched-in constant
Hi Marek,
Quoted 58 lines · Marek Szyprowski
Quoted 9 lines · Marc Zyngier
The trap bits are currently only set to manage CPU errata. However, we are about to make use of them for purposes beyond beating broken CPUs into submission.
For this purpose, turn these errata-driven bits into a patched-in constant that is merged with the KVM-driven value at the point of programming the
ICH_HCR_EL2register, rather than being directly stored with with the shadow value..Quoted 4 lines
This allows the KVM code to distinguish between a trap being handled for the purpose of an erratum workaround, or for KVM's own need.
Signed-off-by Marc Zyngier <[email protected]>This patch landed in today's linux-next as commit
ca30799f7c2d("KVM:
arm64: Turn vgic-v3 errata traps into a patched-in constant"). In my tests I found that it triggers oops and breaks booting on Raspberry Pi5 and Amlogic SM1 based boards: Odroid-C4 and Khadas VIM3l. Here is the failure log:alternatives: applying system-wide alternatives
Internal error: Oops - Undefined instruction: 0000000002000000 [#1] SMP Modules linked in: CPU: 0 UID: 0 PID: 18 Comm: migration/0 Not tainted 6.18.0-rc3+ #11665 PREEMPT Hardware name: Raspberry Pi 5 Model B Rev 1.0 (DT) Stopper: multi_cpu_stop+0x0/0x178 <- __stop_cpus.constprop.0+0x7c/0xc8 pstate: 604000c9 (nZCv daIF +PAN -UAO -TCO -DIT -SSBS BTYPE=--) pc : vgic_v3_broken_seis+0x14/0x44 lr : kvm_compute_ich_hcr_trap_bits+0x48/0xd8 ... Call trace: vgic_v3_broken_seis+0x14/0x44 (P) __apply_alternatives+0x1b4/0x200 __apply_alternatives_multi_stop+0xac/0xc8 multi_cpu_stop+0x90/0x178 cpu_stopper_thread+0x8c/0x11c smpboot_thread_fn+0x160/0x32c kthread+0x150/0x228 ret_from_fork+0x10/0x20 Code: 52800000 f100203f 54000040 d65f03c0 (d53ccb21) ---[ end trace 0000000000000000 ]--- note: migration/0[18] exited with irqs disabled note: migration/0[18] exited with preempt_count 1 rcu: INFO: rcu_preempt detected stalls on CPUs/tasks:rcu: 1-...0: (7 ticks this GP) idle=0124/1/0x4000000000000000 softirq=9/10 fqs=3250
rcu: 2-...0: (7 ticks this GP) idle=0154/1/0x4000000000000000 softirq=9/10 fqs=3250
rcu: 3-...0: (7 ticks this GP) idle=018c/1/0x4000000000000000 softirq=9/10 fqs=3250
rcu: (detected by 0, t=6502 jiffies, g=-1179, q=2 ncpus=4) Sending NMI from CPU 0 to CPUs 1:
Sending NMI from CPU 0 to CPUs 2:
Sending NMI from CPU 0 to CPUs 3:
Quoted 1 line
Let me know how I can help in debugging this issue.
I think the common thing between these machines is that although they run VHE, they are stuck with a GICv2, and should never get to this code path.
Can you dump the kernel log until this point? Something must be screwed in the detection logic.
Thanks,
M.
Signature · 1 line
Without deviation from the norm, progress is not possible.
Re: [PATCH v2 04/45] KVM: arm64: Turn vgic-v3 errata traps into a patched-in constant
Quoted 60 lines · Marc Zyngier
Hi Marek,
Quoted 56 lines · Marek Szyprowski
Quoted 9 lines · Marc Zyngier
The trap bits are currently only set to manage CPU errata. However, we are about to make use of them for purposes beyond beating broken CPUs into submission.
For this purpose, turn these errata-driven bits into a patched-in constant that is merged with the KVM-driven value at the point of programming the
ICH_HCR_EL2register, rather than being directly stored with with the shadow value..Quoted 4 lines
This allows the KVM code to distinguish between a trap being handled for the purpose of an erratum workaround, or for KVM's own need.
Signed-off-by Marc Zyngier <[email protected]>This patch landed in today's linux-next as commit
ca30799f7c2d("KVM:
arm64: Turn vgic-v3 errata traps into a patched-in constant"). In my tests I found that it triggers oops and breaks booting on Raspberry Pi5 and Amlogic SM1 based boards: Odroid-C4 and Khadas VIM3l. Here is the failure log:alternatives: applying system-wide alternatives
Internal error: Oops - Undefined instruction: 0000000002000000 [#1] SMP Modules linked in: CPU: 0 UID: 0 PID: 18 Comm: migration/0 Not tainted 6.18.0-rc3+ #11665 PREEMPT Hardware name: Raspberry Pi 5 Model B Rev 1.0 (DT) Stopper: multi_cpu_stop+0x0/0x178 <- __stop_cpus.constprop.0+0x7c/0xc8 pstate: 604000c9 (nZCv daIF +PAN -UAO -TCO -DIT -SSBS BTYPE=--) pc : vgic_v3_broken_seis+0x14/0x44 lr : kvm_compute_ich_hcr_trap_bits+0x48/0xd8 ... Call trace: vgic_v3_broken_seis+0x14/0x44 (P) __apply_alternatives+0x1b4/0x200 __apply_alternatives_multi_stop+0xac/0xc8 multi_cpu_stop+0x90/0x178 cpu_stopper_thread+0x8c/0x11c smpboot_thread_fn+0x160/0x32c kthread+0x150/0x228 ret_from_fork+0x10/0x20 Code: 52800000 f100203f 54000040 d65f03c0 (d53ccb21) ---[ end trace 0000000000000000 ]--- note: migration/0[18] exited with irqs disabled note: migration/0[18] exited with preempt_count 1 rcu: INFO: rcu_preempt detected stalls on CPUs/tasks:rcu: 1-...0: (7 ticks this GP) idle=0124/1/0x4000000000000000 softirq=9/10 fqs=3250
rcu: 2-...0: (7 ticks this GP) idle=0154/1/0x4000000000000000 softirq=9/10 fqs=3250
rcu: 3-...0: (7 ticks this GP) idle=018c/1/0x4000000000000000 softirq=9/10 fqs=3250
rcu: (detected by 0, t=6502 jiffies, g=-1179, q=2 ncpus=4) Sending NMI from CPU 0 to CPUs 1:
Sending NMI from CPU 0 to CPUs 2:
Sending NMI from CPU 0 to CPUs 3:
Quoted 7 lines
Quoted 1 line
Let me know how I can help in debugging this issue.
I think the common thing between these machines is that although they run VHE, they are stuck with a GICv2, and should never get to this code path.
Can you dump the kernel log until this point? Something must be screwed in the detection logic.
Here is a complete boot log:
Booting Linux on physical CPU 0x0000000000 [0x414fd0b1]
Linux version 6.18.0-rc3+ (m.szyprowski@AMDC4653) (aarch64-linux-gnu-gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0, GNU ld (GNU Binutils for Ubuntu) 2.38) #11666 SMP PREEMPT Thu Nov 13 11:58:18 CET 2025
KASLR enabled
Machine model: Raspberry Pi 5 Model B Rev 1.0
earlycon: pl11 at MMIO 0x000000107d001000 (options '115200n8')
printk: legacy bootconsole [pl11] enabled
printk: debug: ignoring loglevel setting.
Reserved memory: created CMA memory pool at 0x000000003bc00000, size 64 MiB
OF: reserved mem: initialized node linux,cma, compatible id shared-dma-pool
OF: reserved mem: 0x000000003bc00000..0x000000003fbfffff (65536 KiB) map reusable linux,cma
OF: reserved mem: 0x0000000000000000..0x000000000007ffff (512 KiB) nomap non-reusable atf@0
NUMA: Faking a node at [mem 0x0000000000000000-0x00000001ffffffff] NODE_DATA(0) allocated [mem 0x1fefe4a00-0x1fefe763f]
Zone ranges:
DMA [mem 0x0000000000000000-0x00000000ffffffff]
DMA32 empty
Normal [mem 0x0000000100000000-0x00000001ffffffff]
Movable zone start for each node
Early memory node ranges
node 0: [mem 0x0000000000000000-0x000000000007ffff]
node 0: [mem 0x0000000000080000-0x000000003fbfffff]
node 0: [mem 0x0000000040000000-0x00000001ffffffff]
Initmem setup node 0 [mem 0x0000000000000000-0x00000001ffffffff] On node 0, zone DMA: 1024 pages in unavailable ranges
psci: probing for conduit method from DT.
psci: PSCIv1.1 detected in firmware.
psci: Using standard PSCI v0.2 function IDs
psci: MIGRATE_INFO_TYPE not supported.
psci: SMC Calling Convention v1.2
percpu: Embedded 35 pages/cpu s104336 r8192 d30832 u143360
pcpu-alloc: s104336 r8192 d30832 u143360 alloc=35*4096
pcpu-alloc: [0] 0 [0] 1 [0] 2 [0] 3
Detected PIPT I-cache on CPU0
CPU features: detected: Virtualization Host Extensions
CPU features: detected: Spectre-v4
CPU features: detected: Spectre-BHB
CPU features: kernel page table isolation forced ON by KASLR
CPU features: detected: Kernel page table isolation (KPTI)
CPU features: detected: SSBS not fully self-synchronizing
alternatives: applying boot alternatives
Kernel command line: console=ttyAMA10,115200n8 earlycon root=PARTUUID=11111111-03 rw clk_ignore_unused rootdelay=2 ignore_loglevel earlycon
printk: log buffer data + meta data: 131072 + 458752 = 589824 bytes Dentry cache hash table entries: 1048576 (order: 11, 8388608 bytes, linear) Inode-cache hash table entries: 524288 (order: 10, 4194304 bytes, linear) software IO TLB: area num 4.
software IO TLB: mapped [mem 0x00000000fbfff000-0x00000000fffff000] (64MB) Fallback order for Node 0: 0
Built 1 zonelists, mobility grouping on. Total pages: 2096128 Policy zone: Normal
mem auto-init: stack:off, heap alloc:off, heap free:off
SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=4, Nodes=1 Running RCU self tests
Running RCU synchronous self tests
rcu: Preemptible hierarchical RCU implementation.
rcu: RCU event tracing is enabled.
rcu: RCU lockdep checking is enabled.
rcu: RCU restricting CPUs from NR_CPUS=512 to nr_cpu_ids=4.
Trampoline variant of Tasks RCU enabled.
Tracing variant of Tasks RCU enabled.
rcu: RCU calculated value of scheduler-enlistment delay is 25 jiffies.
rcu: Adjusting geometry for rcu_fanout_leaf=16, nr_cpu_ids=4 Running RCU synchronous self tests
RCU Tasks: Setting shift to 2 and lim to 1 rcu_task_cb_adjust=1 rcu_task_cpu_ids=4.
RCU Tasks Trace: Setting shift to 2 and lim to 1 rcu_task_cb_adjust=1 rcu_task_cpu_ids=4.NR_IRQS: 64, nr_irqs: 64, preallocated irqs: 0
Root IRQ handler: gic_handle_irq
GIC: Using split EOI/Deactivate mode
rcu: srcu_init: Setting srcu_struct sizes based on contention.arch_timer: cp15 timer running at 54.00MHz (phys).
clocksource: arch_sys_counter: mask: 0xffffffffffffff max_cycles:0xc743ce346, max_idle_ns: 440795203123 nssched_clock: 56 bits at 54MHz, resolution 18ns, wraps every 4398046511102ns
Console: colour dummy device 80x25
Lock dependency validator: Copyright (c) 2006 Red Hat, Inc., Ingo Molnar ... MAX_LOCKDEP_SUBCLASSES: 8
... MAX_LOCK_DEPTH: 48
... MAX_LOCKDEP_KEYS: 8192
... CLASSHASH_SIZE: 4096
... MAX_LOCKDEP_ENTRIES: 32768
... MAX_LOCKDEP_CHAINS: 65536
... CHAINHASH_SIZE: 32768
memory used by lock dependency info: 6429 kB
memory used for stack traces: 4224 kB
per task-struct memory footprint: 1920 bytes
Calibrating delay loop (skipped), value calculated using timer frequency.. 108.00 BogoMIPS (lpj=216000)pid_max: default: 32768 minimum: 301
LSM: initializing lsm=capability
Mount-cache hash table entries: 16384 (order: 5, 131072 bytes, linear) Mountpoint-cache hash table entries: 16384 (order: 5, 131072 bytes, linear) Running RCU synchronous self tests
Running RCU synchronous self tests
rcu: Hierarchical SRCU implementation.
rcu: Max phase no-delay instances is 1000.
Timer migration: 1 hierarchy levels; 8 children per group; 1 crossnode level
smp: Bringing up secondary CPUs ...
Detected PIPT I-cache on CPU1
CPU1: Booted secondary processor 0x0000000100 [0x414fd0b1] Detected PIPT I-cache on CPU2
CPU2: Booted secondary processor 0x0000000200 [0x414fd0b1] Detected PIPT I-cache on CPU3
CPU3: Booted secondary processor 0x0000000300 [0x414fd0b1]
smp: Brought up 1 node, 4 CPUs
SMP: Total of 4 processors activated.
CPU: All CPU(s) started at EL2
CPU features: detected: 32-bit EL0 Support
CPU features: detected: Data cache clean to the PoU not required for I/D coherence
CPU features: detected: Common not Private translations
CPU features: detected: CRC32 instructions
CPU features: detected: RCpc load-acquire (LDAPR)
CPU features: detected: LSE atomic instructions
CPU features: detected: Privileged Access Never
CPU features: detected: PMUv3
CPU features: detected: RAS Extension Support
CPU features: detected: Speculative Store Bypassing Safe (SSBS)
alternatives: applying system-wide alternatives
Internal error: Oops - Undefined instruction: 0000000002000000 [#1] SMP Modules linked in: CPU: 0 UID: 0 PID: 18 Comm: migration/0 Not tainted 6.18.0-rc3+ #11666 PREEMPT Hardware name: Raspberry Pi 5 Model B Rev 1.0 (DT) Stopper: multi_cpu_stop+0x0/0x178 <- __stop_cpus.constprop.0+0x7c/0xc8 pstate: 604000c9 (nZCv daIF +PAN -UAO -TCO -DIT -SSBS BTYPE=--) pc : vgic_v3_broken_seis+0x14/0x44 lr : kvm_compute_ich_hcr_trap_bits+0x48/0xd8
sp : ffff8000800b3c90
x29: ffff8000800b3c90 x28: ffff8000800b3d58 x27: ffffa07c4e48dd28
x26: 0000000000000001 x25: ffffa07c50461000 x24: ffffa07c50460000
x23: ffffa07c51864000 x22: ffffa07c4e48dd28 x21: ffff00000028dd28
x20: ffffa07c51864598 x19: ffffa07c505b2e10 x18: 00000000ffffffff
x17: 6465726975716572 x16: 20746f6e20556f50 x15: 0000000000000001
x14: 0000000000000000 x13: 0000000000000000 x12: ffff000100292520
x11: ffffa07c51f7e620 x10: 0000000000000000 x9 : 0000000000000001 x8 : ffff8000800b3c98 x7 : ffff8000800b3d60 x6 : ffffa07c5060dc28 x5 : 0000000000000001 x4 : ffffa07c4f7645cc x3 : 0000000000000001 x2 : ffff00000028dd28 x1 : 0000000000000008 x0 : 0000000000000000
Call trace: vgic_v3_broken_seis+0x14/0x44 (P) __apply_alternatives+0x1b4/0x200 __apply_alternatives_multi_stop+0xac/0xc8 multi_cpu_stop+0x90/0x178 cpu_stopper_thread+0x8c/0x11c smpboot_thread_fn+0x160/0x32c kthread+0x150/0x228 ret_from_fork+0x10/0x20 Code: 52800000 f100203f 54000040 d65f03c0 (d53ccb21) ---[ end trace 0000000000000000 ]--- note: migration/0[18] exited with irqs disabled note: migration/0[18] exited with preempt_count 1 rcu: INFO: rcu_preempt detected stalls on CPUs/tasks:
rcu: 1-...0: (7 ticks this GP) idle=0194/1/0x4000000000000000 softirq=9/10 fqs=3250
rcu: 2-...0: (7 ticks this GP) idle=00c4/1/0x4000000000000000 softirq=9/10 fqs=3250
rcu: 3-...0: (7 ticks this GP) idle=01bc/1/0x4000000000000000 softirq=9/10 fqs=3250
rcu: (detected by 0, t=6502 jiffies, g=-1179, q=2 ncpus=4) Sending NMI from CPU 0 to CPUs 1:
Sending NMI from CPU 0 to CPUs 2:
Sending NMI from CPU 0 to CPUs 3:
Best regards
Signature · 2 lines
Marek Szyprowski, PhD Samsung R&D Institute Poland
Joey Gouly
reviewerRe: [PATCH v2 04/45] KVM: arm64: Turn vgic-v3 errata traps into a patched-in constant
Quoted 230 lines · Marek Szyprowski
Quoted 60 lines · Marc Zyngier
Hi Marek,
Quoted 56 lines · Marek Szyprowski
Quoted 9 lines · Marc Zyngier
The trap bits are currently only set to manage CPU errata. However, we are about to make use of them for purposes beyond beating broken CPUs into submission.
For this purpose, turn these errata-driven bits into a patched-in constant that is merged with the KVM-driven value at the point of programming the
ICH_HCR_EL2register, rather than being directly stored with with the shadow value..Quoted 4 lines
This allows the KVM code to distinguish between a trap being handled for the purpose of an erratum workaround, or for KVM's own need.
Signed-off-by Marc Zyngier <[email protected]>This patch landed in today's linux-next as commit
ca30799f7c2d("KVM:
arm64: Turn vgic-v3 errata traps into a patched-in constant"). In my tests I found that it triggers oops and breaks booting on Raspberry Pi5 and Amlogic SM1 based boards: Odroid-C4 and Khadas VIM3l. Here is the failure log:alternatives: applying system-wide alternatives
Internal error: Oops - Undefined instruction: 0000000002000000 [#1] SMP Modules linked in: CPU: 0 UID: 0 PID: 18 Comm: migration/0 Not tainted 6.18.0-rc3+ #11665 PREEMPT Hardware name: Raspberry Pi 5 Model B Rev 1.0 (DT) Stopper: multi_cpu_stop+0x0/0x178 <- __stop_cpus.constprop.0+0x7c/0xc8 pstate: 604000c9 (nZCv daIF +PAN -UAO -TCO -DIT -SSBS BTYPE=--) pc : vgic_v3_broken_seis+0x14/0x44 lr : kvm_compute_ich_hcr_trap_bits+0x48/0xd8 ... Call trace: vgic_v3_broken_seis+0x14/0x44 (P) __apply_alternatives+0x1b4/0x200 __apply_alternatives_multi_stop+0xac/0xc8 multi_cpu_stop+0x90/0x178 cpu_stopper_thread+0x8c/0x11c smpboot_thread_fn+0x160/0x32c kthread+0x150/0x228 ret_from_fork+0x10/0x20 Code: 52800000 f100203f 54000040 d65f03c0 (d53ccb21) ---[ end trace 0000000000000000 ]--- note: migration/0[18] exited with irqs disabled note: migration/0[18] exited with preempt_count 1 rcu: INFO: rcu_preempt detected stalls on CPUs/tasks:rcu: 1-...0: (7 ticks this GP) idle=0124/1/0x4000000000000000 softirq=9/10 fqs=3250
rcu: 2-...0: (7 ticks this GP) idle=0154/1/0x4000000000000000 softirq=9/10 fqs=3250
rcu: 3-...0: (7 ticks this GP) idle=018c/1/0x4000000000000000 softirq=9/10 fqs=3250
rcu: (detected by 0, t=6502 jiffies, g=-1179, q=2 ncpus=4) Sending NMI from CPU 0 to CPUs 1:
Sending NMI from CPU 0 to CPUs 2:
Sending NMI from CPU 0 to CPUs 3:Quoted 7 lines
Quoted 1 line
Let me know how I can help in debugging this issue.
I think the common thing between these machines is that although they run VHE, they are stuck with a GICv2, and should never get to this code path.
Can you dump the kernel log until this point? Something must be screwed in the detection logic.
Here is a complete boot log:
Booting Linux on physical CPU
0x0000000000[0x414fd0b1]
Linux version 6.18.0-rc3+ (m.szyprowski@AMDC4653) (aarch64-linux-gnu-gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0, GNU ld (GNU Binutils for Ubuntu) 2.38) #11666 SMP PREEMPT Thu Nov 13 11:58:18 CET 2025
KASLR enabled
Machine model: Raspberry Pi 5 Model B Rev 1.0
earlycon: pl11 at MMIO0x000000107d001000(options '115200n8')
printk: legacy bootconsole [pl11] enabled
printk: debug: ignoring loglevel setting.
Reserved memory: created CMA memory pool at0x000000003bc00000, size 64 MiB
OF: reserved mem: initialized node linux,cma, compatible id shared-dma-pool
OF: reserved mem: 0x000000003bc00000..0x000000003fbfffff (65536 KiB) map reusable linux,cma
OF: reserved mem: 0x0000000000000000..0x000000000007ffff (512 KiB) nomap non-reusable atf@0
NUMA: Faking a node at [mem 0x0000000000000000-0x00000001ffffffff]NODE_DATA(0)allocated [mem 0x1fefe4a00-0x1fefe763f]
Zone ranges:
DMA [mem 0x0000000000000000-0x00000000ffffffff]
DMA32 empty
Normal [mem 0x0000000100000000-0x00000001ffffffff]
Movable zone start for each node
Early memory node ranges
node 0: [mem 0x0000000000000000-0x000000000007ffff]
node 0: [mem 0x0000000000080000-0x000000003fbfffff]
node 0: [mem 0x0000000040000000-0x00000001ffffffff]
Initmem setup node 0 [mem 0x0000000000000000-0x00000001ffffffff] On node 0, zone DMA: 1024 pages in unavailable ranges
psci: probing for conduit method from DT.
psci: PSCIv1.1 detected in firmware.
psci: Using standard PSCI v0.2 function IDs
psci:MIGRATE_INFO_TYPEnot supported.
psci: SMC Calling Convention v1.2
percpu: Embedded 35 pages/cpu s104336 r8192 d30832 u143360
pcpu-alloc: s104336 r8192 d30832 u143360 alloc=35*4096
pcpu-alloc: [0] 0 [0] 1 [0] 2 [0] 3
Detected PIPT I-cache on CPU0
CPU features: detected: Virtualization Host Extensions
CPU features: detected: Spectre-v4
CPU features: detected: Spectre-BHB
CPU features: kernel page table isolation forced ON by KASLR
CPU features: detected: Kernel page table isolation (KPTI)
CPU features: detected: SSBS not fully self-synchronizing
alternatives: applying boot alternatives
Kernel command line: console=ttyAMA10,115200n8 earlycon root=PARTUUID=11111111-03 rwclk_ignore_unusedrootdelay=2ignore_loglevelearlycon
printk: log buffer data + meta data: 131072 + 458752 = 589824 bytes Dentry cache hash table entries: 1048576 (order: 11, 8388608 bytes, linear) Inode-cache hash table entries: 524288 (order: 10, 4194304 bytes, linear) software IO TLB: area num 4.
software IO TLB: mapped [mem 0x00000000fbfff000-0x00000000fffff000] (64MB) Fallback order for Node 0: 0
Built 1 zonelists, mobility grouping on. Total pages: 2096128 Policy zone: Normal
mem auto-init: stack:off, heap alloc:off, heap free:off
SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=4, Nodes=1 Running RCU self tests
Running RCU synchronous self tests
rcu: Preemptible hierarchical RCU implementation.
rcu: RCU event tracing is enabled.
rcu: RCU lockdep checking is enabled.
rcu: RCU restricting CPUs from NR_CPUS=512 to nr_cpu_ids=4.
Trampoline variant of Tasks RCU enabled.
Tracing variant of Tasks RCU enabled.
rcu: RCU calculated value of scheduler-enlistment delay is 25 jiffies.
rcu: Adjusting geometry for rcu_fanout_leaf=16, nr_cpu_ids=4 Running RCU synchronous self tests
RCU Tasks: Setting shift to 2 and lim to 1 rcu_task_cb_adjust=1 rcu_task_cpu_ids=4.
RCU Tasks Trace: Setting shift to 2 and lim to 1 rcu_task_cb_adjust=1 rcu_task_cpu_ids=4.NR_IRQS: 64,nr_irqs: 64, preallocated irqs: 0
Root IRQ handler:gic_handle_irq
GIC: Using split EOI/Deactivate mode
rcu:srcu_init: Settingsrcu_structsizes based on contention.arch_timer: cp15 timer running at 54.00MHz (phys).
clocksource:arch_sys_counter: mask:0xffffffffffffffmax_cycles:0xc743ce346,max_idle_ns: 440795203123 nssched_clock: 56 bits at 54MHz, resolution 18ns, wraps every 4398046511102ns
Console: colour dummy device 80x25
Lock dependency validator: Copyright (c) 2006 Red Hat, Inc., Ingo Molnar ... MAX_LOCKDEP_SUBCLASSES: 8
... MAX_LOCK_DEPTH: 48
... MAX_LOCKDEP_KEYS: 8192
... CLASSHASH_SIZE: 4096
... MAX_LOCKDEP_ENTRIES: 32768
... MAX_LOCKDEP_CHAINS: 65536
... CHAINHASH_SIZE: 32768
memory used by lock dependency info: 6429 kB
memory used for stack traces: 4224 kB
per task-struct memory footprint: 1920 bytes
Calibrating delay loop (skipped), value calculated using timer frequency.. 108.00 BogoMIPS (lpj=216000)pid_max: default: 32768 minimum: 301
LSM: initializing lsm=capability
Mount-cache hash table entries: 16384 (order: 5, 131072 bytes, linear) Mountpoint-cache hash table entries: 16384 (order: 5, 131072 bytes, linear) Running RCU synchronous self tests
Running RCU synchronous self tests
rcu: Hierarchical SRCU implementation.
rcu: Max phase no-delay instances is 1000.
Timer migration: 1 hierarchy levels; 8 children per group; 1 crossnode level
smp: Bringing up secondary CPUs ...
Detected PIPT I-cache on CPU1
CPU1: Booted secondary processor0x0000000100[0x414fd0b1] Detected PIPT I-cache on CPU2
CPU2: Booted secondary processor0x0000000200[0x414fd0b1] Detected PIPT I-cache on CPU3
CPU3: Booted secondary processor0x0000000300[0x414fd0b1]
smp: Brought up 1 node, 4 CPUs
SMP: Total of 4 processors activated.
CPU: All CPU(s) started at EL2
CPU features: detected: 32-bit EL0 Support
CPU features: detected: Data cache clean to the PoU not required for I/D coherence
CPU features: detected: Common not Private translations
CPU features: detected: CRC32 instructions
CPU features: detected: RCpc load-acquire (LDAPR)
CPU features: detected: LSE atomic instructions
CPU features: detected: Privileged Access Never
CPU features: detected: PMUv3
CPU features: detected: RAS Extension Support
CPU features: detected: Speculative Store Bypassing Safe (SSBS)
alternatives: applying system-wide alternativesInternal error: Oops - Undefined instruction: 0000000002000000 [#1] SMP Modules linked in: CPU: 0 UID: 0 PID: 18 Comm: migration/0 Not tainted 6.18.0-rc3+ #11666 PREEMPT Hardware name: Raspberry Pi 5 Model B Rev 1.0 (DT) Stopper: multi_cpu_stop+0x0/0x178 <- __stop_cpus.constprop.0+0x7c/0xc8 pstate: 604000c9 (nZCv daIF +PAN -UAO -TCO -DIT -SSBS BTYPE=--) pc : vgic_v3_broken_seis+0x14/0x44 lr : kvm_compute_ich_hcr_trap_bits+0x48/0xd8sp :
ffff8000800b3c90
x29:ffff8000800b3c90x28:ffff8000800b3d58x27:ffffa07c4e48dd28
x26: 0000000000000001 x25:ffffa07c50461000x24:ffffa07c50460000
x23:ffffa07c51864000x22:ffffa07c4e48dd28x21:ffff00000028dd28
x20:ffffa07c51864598x19:ffffa07c505b2e10x18:00000000ffffffff
x17: 6465726975716572 x16:20746f6e20556f50x15: 0000000000000001
x14: 0000000000000000 x13: 0000000000000000 x12:ffff000100292520
x11:ffffa07c51f7e620x10: 0000000000000000 x9 : 0000000000000001 x8 :ffff8000800b3c98x7 :ffff8000800b3d60x6 :ffffa07c5060dc28x5 : 0000000000000001 x4 :ffffa07c4f7645ccx3 : 0000000000000001 x2 :ffff00000028dd28x1 : 0000000000000008 x0 : 0000000000000000Call trace: vgic_v3_broken_seis+0x14/0x44 (P) __apply_alternatives+0x1b4/0x200 __apply_alternatives_multi_stop+0xac/0xc8 multi_cpu_stop+0x90/0x178 cpu_stopper_thread+0x8c/0x11c smpboot_thread_fn+0x160/0x32c kthread+0x150/0x228 ret_from_fork+0x10/0x20 Code: 52800000 f100203f 54000040 d65f03c0 (d53ccb21) ---[ end trace 0000000000000000 ]--- note: migration/0[18] exited with irqs disabled note: migration/0[18] exited with preempt_count 1 rcu: INFO: rcu_preempt detected stalls on CPUs/tasks:
Quoted 10 lines
rcu: 1-...0: (7 ticks this GP) idle=0194/1/0x4000000000000000 softirq=9/10 fqs=3250
rcu: 2-...0: (7 ticks this GP) idle=00c4/1/0x4000000000000000 softirq=9/10 fqs=3250
rcu: 3-...0: (7 ticks this GP) idle=01bc/1/0x4000000000000000 softirq=9/10 fqs=3250
rcu: (detected by 0, t=6502 jiffies, g=-1179, q=2 ncpus=4) Sending NMI from CPU 0 to CPUs 1:
Sending NMI from CPU 0 to CPUs 2:
Sending NMI from CPU 0 to CPUs 3:
I suppose the issue is that the alternatives in vgic_ich_hcr_trap_bits() are always calculated, even if that function is only used from the gic-v3 code. Calculating the trap bits reads ICH_VTR_EL2, which needs FEAT_GICv3.
Thanks,
Joey
Quoted 7 lines
Best regards
Signature · 2 lines
Marek Szyprowski, PhD Samsung R&D Institute Poland
Marc Zyngier
maintainerRe: [PATCH v2 04/45] KVM: arm64: Turn vgic-v3 errata traps into a patched-in constant
Quoted 3 lines · Joey Gouly
I suppose the issue is that the alternatives in
vgic_ich_hcr_trap_bits()are always calculated, even if that function is only used from the gic-v3 code. Calculating the trap bits readsICH_VTR_EL2, which needsFEAT_GICv3.
Except that we have a bunch of rotten fruits that only have half a GICv3, so relying on FEAT_GICv3 isn't useful if we want to continue supporting these machines in the foreseeable future.
The fix for this is, I expect, what I posted at [1].
Thanks,
M.
[1] https://lore.kernel.org/r/[email protected]
Signature · 1 line
Without deviation from the norm, progress is not possible.
Marc Zyngier
maintainerRe: [PATCH v2 04/45] KVM: arm64: Turn vgic-v3 errata traps into a patched-in constant
In reply to Marek SzyprowskiQuoted 58 lines · Marek Szyprowski
Quoted 9 lines · Marc Zyngier
The trap bits are currently only set to manage CPU errata. However, we are about to make use of them for purposes beyond beating broken CPUs into submission.
For this purpose, turn these errata-driven bits into a patched-in constant that is merged with the KVM-driven value at the point of programming the
ICH_HCR_EL2register, rather than being directly stored with with the shadow value..Quoted 4 lines
This allows the KVM code to distinguish between a trap being handled for the purpose of an erratum workaround, or for KVM's own need.
Signed-off-by Marc Zyngier <[email protected]>This patch landed in today's linux-next as commit
ca30799f7c2d("KVM:
arm64: Turn vgic-v3 errata traps into a patched-in constant"). In my tests I found that it triggers oops and breaks booting on Raspberry Pi5 and Amlogic SM1 based boards: Odroid-C4 and Khadas VIM3l. Here is the failure log:alternatives: applying system-wide alternatives
Internal error: Oops - Undefined instruction: 0000000002000000 [#1] SMP Modules linked in: CPU: 0 UID: 0 PID: 18 Comm: migration/0 Not tainted 6.18.0-rc3+ #11665 PREEMPT Hardware name: Raspberry Pi 5 Model B Rev 1.0 (DT) Stopper: multi_cpu_stop+0x0/0x178 <- __stop_cpus.constprop.0+0x7c/0xc8 pstate: 604000c9 (nZCv daIF +PAN -UAO -TCO -DIT -SSBS BTYPE=--) pc : vgic_v3_broken_seis+0x14/0x44 lr : kvm_compute_ich_hcr_trap_bits+0x48/0xd8 ... Call trace: vgic_v3_broken_seis+0x14/0x44 (P) __apply_alternatives+0x1b4/0x200 __apply_alternatives_multi_stop+0xac/0xc8 multi_cpu_stop+0x90/0x178 cpu_stopper_thread+0x8c/0x11c smpboot_thread_fn+0x160/0x32c kthread+0x150/0x228 ret_from_fork+0x10/0x20 Code: 52800000 f100203f 54000040 d65f03c0 (d53ccb21) ---[ end trace 0000000000000000 ]--- note: migration/0[18] exited with irqs disabled note: migration/0[18] exited with preempt_count 1 rcu: INFO: rcu_preempt detected stalls on CPUs/tasks:rcu: 1-...0: (7 ticks this GP) idle=0124/1/0x4000000000000000 softirq=9/10 fqs=3250
rcu: 2-...0: (7 ticks this GP) idle=0154/1/0x4000000000000000 softirq=9/10 fqs=3250
rcu: 3-...0: (7 ticks this GP) idle=018c/1/0x4000000000000000 softirq=9/10 fqs=3250
rcu: (detected by 0, t=6502 jiffies, g=-1179, q=2 ncpus=4) Sending NMI from CPU 0 to CPUs 1:
Sending NMI from CPU 0 to CPUs 2:
Sending NMI from CPU 0 to CPUs 3:
Quoted 1 line
Let me know how I can help in debugging this issue.
Wild guess. Can you try this (untested)?
M.
arch/arm64/kvm/vgic/vgic-v3.c +2 -2
@@ -829,8 +829,8 @@ static const struct midr_range broken_seis[] = {static bool vgic_v3_broken_seis (void ) {return (is_kernel_in_hyp_mode () && - (read_sysreg_s (SYS_ICH_VTR_EL2 ) &ICH_VTR_EL2_SEIS ) && -is_midr_in_range_list (broken_seis)); +is_midr_in_range_list (broken_seis) && + (read_sysreg_s (SYS_ICH_VTR_EL2 ) &ICH_VTR_EL2_SEIS )); } void noinstr kvm_compute_ich_hcr_trap_bits(struct alt_instr *alt,
Signature · 1 line
Without deviation from the norm, progress is not possible.
Marek Szyprowski
Tested-byRe: [PATCH v2 04/45] KVM: arm64: Turn vgic-v3 errata traps into a patched-in constant
Quoted 68 lines · Marc Zyngier
Quoted 56 lines · Marek Szyprowski
Quoted 9 lines · Marc Zyngier
The trap bits are currently only set to manage CPU errata. However, we are about to make use of them for purposes beyond beating broken CPUs into submission.
For this purpose, turn these errata-driven bits into a patched-in constant that is merged with the KVM-driven value at the point of programming the
ICH_HCR_EL2register, rather than being directly stored with with the shadow value..Quoted 4 lines
This allows the KVM code to distinguish between a trap being handled for the purpose of an erratum workaround, or for KVM's own need.
Signed-off-by Marc Zyngier <[email protected]>This patch landed in today's linux-next as commit
ca30799f7c2d("KVM:
arm64: Turn vgic-v3 errata traps into a patched-in constant"). In my tests I found that it triggers oops and breaks booting on Raspberry Pi5 and Amlogic SM1 based boards: Odroid-C4 and Khadas VIM3l. Here is the failure log:alternatives: applying system-wide alternatives
Internal error: Oops - Undefined instruction: 0000000002000000 [#1] SMP Modules linked in: CPU: 0 UID: 0 PID: 18 Comm: migration/0 Not tainted 6.18.0-rc3+ #11665 PREEMPT Hardware name: Raspberry Pi 5 Model B Rev 1.0 (DT) Stopper: multi_cpu_stop+0x0/0x178 <- __stop_cpus.constprop.0+0x7c/0xc8 pstate: 604000c9 (nZCv daIF +PAN -UAO -TCO -DIT -SSBS BTYPE=--) pc : vgic_v3_broken_seis+0x14/0x44 lr : kvm_compute_ich_hcr_trap_bits+0x48/0xd8 ... Call trace: vgic_v3_broken_seis+0x14/0x44 (P) __apply_alternatives+0x1b4/0x200 __apply_alternatives_multi_stop+0xac/0xc8 multi_cpu_stop+0x90/0x178 cpu_stopper_thread+0x8c/0x11c smpboot_thread_fn+0x160/0x32c kthread+0x150/0x228 ret_from_fork+0x10/0x20 Code: 52800000 f100203f 54000040 d65f03c0 (d53ccb21) ---[ end trace 0000000000000000 ]--- note: migration/0[18] exited with irqs disabled note: migration/0[18] exited with preempt_count 1 rcu: INFO: rcu_preempt detected stalls on CPUs/tasks:rcu: 1-...0: (7 ticks this GP) idle=0124/1/0x4000000000000000 softirq=9/10 fqs=3250
rcu: 2-...0: (7 ticks this GP) idle=0154/1/0x4000000000000000 softirq=9/10 fqs=3250
rcu: 3-...0: (7 ticks this GP) idle=018c/1/0x4000000000000000 softirq=9/10 fqs=3250
rcu: (detected by 0, t=6502 jiffies, g=-1179, q=2 ncpus=4) Sending NMI from CPU 0 to CPUs 1:
Sending NMI from CPU 0 to CPUs 2:
Sending NMI from CPU 0 to CPUs 3:Quoted 1 line
Let me know how I can help in debugging this issue.
Wild guess. Can you try this (untested)?
M.arch/arm64/kvm/vgic/vgic-v3.c +0
-0
arch/arm64/kvm/vgic/vgic-v3.c static const struct midr_range broken_seis[] = { · line 836
Quoted 10 lines
arch/arm64/kvm/vgic/vgic-v3.c +2
-2@@ -829,8 +829,8 @@ static const struct midr_range broken_seis[] = {static bool vgic_v3_broken_seis (void ) {return (is_kernel_in_hyp_mode () && - (read_sysreg_s (SYS_ICH_VTR_EL2 ) &ICH_VTR_EL2_SEIS ) && -is_midr_in_range_list (broken_seis)); +is_midr_in_range_list (broken_seis) && + (read_sysreg_s (SYS_ICH_VTR_EL2 ) &ICH_VTR_EL2_SEIS )); } void noinstr kvm_compute_ich_hcr_trap_bits(struct alt_instr *alt,
That's it! Now it boots fine on the mentioned boards. Feel free to add:
Best regards
Signature · 2 lines
Marek Szyprowski, PhD Samsung R&D Institute Poland
Re: [PATCH v2 04/45] KVM: arm64: Turn vgic-v3 errata traps into a patched-in constant
In reply to Marc ZyngierQuoted 8 lines · Marc Zyngier
The trap bits are currently only set to manage CPU errata. However, we are about to make use of them for purposes beyond beating broken CPUs into submission.
For this purpose, turn these errata-driven bits into a patched-in constant that is merged with the KVM-driven value at the point of programming the
ICH_HCR_EL2register, rather than being directly stored with with the shadow value..
We're seeing the no-vgic-v3 failures in -next with slightly different symptoms to those that were seen in mainline and fixed with Sacha's change da888524c393 ("KVM: arm64: vgic-v3: Trap all if no in-kernel irqchip"). That change generated a conflict with this patch which Stephen resolved in what looks like a reasonable fashion tactically but I suspect needs some wider changes. The test now fails with:
# selftests: kvm: no-vgic-v3
# Random seed: 0x6b8b4567
# ==== Test Assertion Failure ====
# lib/arm64/processor.c:487: false
# pid=2080 tid=2080 errno=4 - Interrupted system call
# 1 0x0000000000413d27: assert_on_unhandled_exception at processor.c:487 # 2 0x0000000000406c1f: _vcpu_run at kvm_util.c:1699 # 3 (inlined by) vcpu_run at kvm_util.c:1710 # 4 0x000000000040308b: test_run_vcpu at no-vgic-v3.c:124 # 5 0x0000000000402253: test_guest_no_gicv3 at no-vgic-v3.c:155 # 6 (inlined by) main at no-vgic-v3.c:174 # 7 0x0000ffff9dc17543: ?? ??:0 # 8 0x0000ffff9dc17617: ?? ??:0 # 9 0x000000000040242f: _start at ??:?
# Unexpected exception (vector:0x4, ec:0x18)
not ok 25 selftests: kvm: no-vgic-v3 # exit=254
Log showing the failure:
https://lava.sirena.org.uk/scheduler/job/2079953#L2994
This is on i.MX8MP-EVK, 4xA53 and a GICv3.
No bisect or anything, between unrelated DRM breakage in -next and the same test failing in Linus' tree in -rc3 which the kvm-arm tree is based on it's a bit of a mess.
Marc Zyngier
maintainerRe: [PATCH v2 04/45] KVM: arm64: Turn vgic-v3 errata traps into a patched-in constant
Quoted 33 lines · Mark Brown
[1 <text/plain; us-ascii (quoted-printable)>]
Quoted 8 lines · Marc Zyngier
The trap bits are currently only set to manage CPU errata. However, we are about to make use of them for purposes beyond beating broken CPUs into submission.
For this purpose, turn these errata-driven bits into a patched-in constant that is merged with the KVM-driven value at the point of programming the
ICH_HCR_EL2register, rather than being directly stored with with the shadow value..We're seeing the no-vgic-v3 failures in -next with slightly different symptoms to those that were seen in mainline and fixed with Sacha's change
da888524c393("KVM: arm64: vgic-v3: Trap all if no in-kernel irqchip"). That change generated a conflict with this patch which Stephen resolved in what looks like a reasonable fashion tactically but I suspect needs some wider changes. The test now fails with:# selftests: kvm: no-vgic-v3
# Random seed:0x6b8b4567
# ==== Test Assertion Failure ====
#lib/arm64/processor.c:487: false
# pid=2080 tid=2080 errno=4 - Interrupted system call# 1 0x0000000000413d27: assert_on_unhandled_exception at processor.c:487 # 2 0x0000000000406c1f: _vcpu_run at kvm_util.c:1699 # 3 (inlined by) vcpu_run at kvm_util.c:1710 # 4 0x000000000040308b: test_run_vcpu at no-vgic-v3.c:124 # 5 0x0000000000402253: test_guest_no_gicv3 at no-vgic-v3.c:155 # 6 (inlined by) main at no-vgic-v3.c:174 # 7 0x0000ffff9dc17543: ?? ??:0 # 8 0x0000ffff9dc17617: ?? ??:0 # 9 0x000000000040242f: _start at ??:?
Quoted 2 lines
# Unexpected exception (vector:0x4, ec:0x18)
not ok 25 selftests: kvm: no-vgic-v3 # exit=254
Fix at [email protected] based on kvmarm/next. I haven't tried -next.
M.
Signature · 1 line
Without deviation from the norm, progress is not possible.
Marc Zyngier
maintainerPATCH v2 5/45 KVM: arm64: GICv3: Detect and work around the lack of ICV_DIR_EL1 trapping
In reply to Marc ZyngierA long time ago, an unsuspecting architect forgot to add a trap bit for ICV_DIR_EL1 in ICH_HCR_EL2. Which was unfortunate, but what's a bit of spec between friends? Thankfully, this was fixed in a later revision, and ARM "deprecates" the lack of trapping ability.
Unfortuantely, a few (billion) CPUs went out with that defect, anything ARMv8.0 from ARM, give or take. And on these CPUs, you can't trap DIR on its own, full stop.
As the next best thing, we can trap everything in the common group, which is a tad expensive, but hey ho, that's what you get. You can otherwise recycle the HW in the neaby bin.
--- arch/arm64/include/asm/virt.h | 7 ++++- arch/arm64/kernel/cpufeature.c | 52 ++++++++++++++++++++++++++++++++++ arch/arm64/kernel/hyp-stub.S | 5 ++++ arch/arm64/kvm/vgic/vgic-v3.c | 3 ++ arch/arm64/tools/cpucaps | 1 + 5 files changed, 67 insertions(+), 1 deletion(-)
arch/arm64/include/asm/virt.h +6 -1
@@ -40,8 +40,13 @@*/ #define HVC_FINALISE_EL2 3 +/* +* HVC_GET_ICH_VTR_EL2 - Retrieve the ICH_VTR_EL2 value +*/ +#define HVC_GET_ICH_VTR_EL2 4 +/* Max number of HYP stub hypercalls */ -#define HVC_STUB_HCALL_NR 4 +#define HVC_STUB_HCALL_NR 5/* Error returned when an invalid stub number is passed into x0 */ #define HVC_STUB_ERR 0xbadca11
arch/arm64/kernel/cpufeature.c +52 -0
64 lines not on this page · raw message
arch/arm64/kernel/hyp-stub.S +5 -0
@@ -54,6 +54,11 @@ SYM_CODE_START_LOCAL(elx_sync) 1: cmp x0, #HVC_FINALISE_EL2 b.eq __finalise_el2 + cmp x0, #HVC_GET_ICH_VTR_EL2 + b.ne 2f + mrs_s x1, SYS_ICH_VTR_EL2 + b 9f + 2: cmp x0, #HVC_SOFT_RESTART b.ne 3f mov x0, x2
arch/arm64/kvm/vgic/vgic-v3.c +3 -0
@@ -648,6 +648,9 @@ void noinstr kvm_compute_ich_hcr_trap_bits(struct alt_instr *alt, dir_trap = true; } +if (!cpus_have_cap (ARM64_HAS_ICH_HCR_EL2_TDIR )) + common_trap = true; +if (group0_trap) hcr |=ICH_HCR_EL2_TALL0 ;if (group1_trap)
arch/arm64/tools/cpucaps +1 -0
@@ -40,6 +40,7 @@ HAS_GICV5_CPUIF HAS_GICV5_LEGACY HAS_GIC_PRIO_MASKING HAS_GIC_PRIO_RELAXED_SYNC +HAS_ICH_HCR_EL2_TDIR HAS_HCR_NV1 HAS_HCX HAS_LDAPR
Signature · 1 line
2.47.3
Re: [PATCH v2 05/45] KVM: arm64: GICv3: Detect and work around the lack of ICV_DIR_EL1 trapping
Quoted 5 lines · Marc Zyngier
A long time ago, an unsuspecting architect forgot to add a trap bit for
ICV_DIR_EL1inICH_HCR_EL2. Which was unfortunate, but what's a bit of spec between friends? Thankfully, this was fixed in a later revision, and ARM "deprecates" the lack of trapping ability.
I'm seeing a regression on i.MX8MP-EVK and Toradax AM625+Mallow boards (both 4xA53+GICv3) in protected mode only with a bunch of the KVM selftests, including the arch_timer one:
# selftests: kvm: arch_timer
# Random seed: 0x6b8b4567
# ==== Test Assertion Failure ====
# lib/arm64/processor.c:487: false
# pid=4469 tid=4473 errno=4 - Interrupted system call
# ==== Test Assertion Failure ====
# lib/arm64/processor.c:487: false
# pid=4469 tid=4471 errno=4 - Interrupted system call
# ==== Test Assertion Failure ====
# lib/arm64/processor.c:487: false
# pid=4469 tid=4472 errno=4 - Interrupted system call
# ==== Test Assertion Failure ====
# lib/arm64/processor.c:487: false
# pid=4469 tid=4470 errno=4 - Interrupted system call
# 1 0x0000000000414387: assert_on_unhandled_exception at processor.c:487 # 2 0x000000000040727f: _vcpu_run at kvm_util.c:1699 # 3 (inlined by) vcpu_run at kvm_util.c:1710 # 4 0x0000000000402b07: test_vcpu_run at arch_timer.c:55 # 5 0x0000ffffb12f2f9b: ?? ??:0 # 6 0x0000ffffb135e58b: ?? ??:0 # 1 0x0000000000414387: assert_on_unhandled_exception at processor.c:487 # 2 0x000000000040727f: _vcpu_run at kvm_util.c:1699 # 3 (inlined by) vcpu_run at kvm_util.c:1710 # 4 0x0000000000402b07: test_vcpu_run at arch_timer.c:55 # 5 0x0000ffffb12f2f9b: ?? ??:0 # 6 0x0000ffffb135e58b: ?? ??:0 # Unexpected exception (vector:0x4, ec:0x0) # 1 0x0000000000414387: assert_on_unhandled_exception at processor.c:487 # 2 0x000000000040727f: _vcpu_run at kvm_util.c:1699 # 3 (inlined by) vcpu_run at kvm_util.c:1710 # 4 0x0000000000402b07: test_vcpu_run at arch_timer.c:55 # 5 0x0000ffffb12f2f9b: ?? ??:0 # 6 0x0000ffffb135e58b: ?? ??:0 # 1 0x0000000000414387: assert_on_unhandled_exception at processor.c:487 # 2 0x000000000040727f: _vcpu_run at kvm_util.c:1699 # 3 (inlined by) vcpu_run at kvm_util.c:1710 # 4 0x0000000000402b07: test_vcpu_run at arch_timer.c:55 # 5 0x0000ffffb12f2f9b: ?? ??:0 # 6 0x0000ffffb135e58b: ?? ??:0
not ok 28 selftests: kvm: arch_timer # exit=254
The arch_timer case bisects to this patch in -next, regular nVHE mode runs this test happily. Full log (on the i.MX8MP-EVK):
https://lava.sirena.org.uk/scheduler/job/2079917#L3993
bisect log:
# bad: [6d7e7251d03f98f26f2ee0dfd21bb0a0480a2178] Add linux-next specific files for 20251113
# good: [aeee991e3a4cb03497cda0f879619c2e71143b49] Merge branch 'for-linux-next-fixes' of https://gitlab.freedesktop.org/drm/misc/kernel.git
# good: [4d6e2211aeb932e096f673c88475016b1cc0f8ab] ASoC: Intel: boards: fix HDMI playback lookup when HDMI-In capture used
# good: [1d562ba0aa7df81335bf96c02be77efe8d5bab87] spi: dt-bindings: nuvoton,npcm-pspi: Convert to DT schema
# good: [b3a5302484033331af37569f7277d00131694b57] ASoC: Intel: sof_rt5682: Add quirk override support
# good: [32172cf3cb543a04c41a1677c97a38e60cad05b6] ASoC: cs35l56: Allow restoring factory calibration through ALSA control
# good: [873bc94689d832878befbcadc10b6ad5bb4e0027] ASoC: Intel: sof_sdw: add codec speaker support for the SKU
# good: [772ada50282b0c80343c8989147db816961f571d] ASoC: cs35l56: Alter error codes for calibration routine
# good: [6985defd1d832f1dd9d1977a6a2cc2cef7632704] regmap: sdw-mbq: Reorder regmap_mbq_context struct for better packing
# good: [fb1ebb10468da414d57153ddebaab29c38ef1a78] regulator: core: disable supply if enabling main regulator fails
# good: [2089f086303b773e181567fd8d5df3038bd85937] regulator: mt6363: Remove unneeded semicolon
# good: [4e92abd0a11b91af3742197a9ca962c3c00d0948] spi: imx: add i.MX51 ECSPI target mode support
# good: [6951be397ca8b8b167c9f99b5a11c541148c38cb] ASoC: codecs: pm4125: remove duplicate code
# good: [abc9a349b87ac0fd3ba8787ca00971b59c2e1257] spi: fsl-qspi: support the SpacemiT K1 SoC
# good: [1b0f3f9ee41ee2bdd206667f85ea2aa36dfe6e69] ASoC: SDCA: support Q7.8 volume format
# good: [6bd1ad97eb790570c167d4de4ca59fbc9c33722a] regulator: pf9453: Fix kernel doc for mux_poll()
# good: [55d03b5b5bdd04daf9a35ce49db18d8bb488dffb] spi: imx: remove CLK calculation and check for target mode
# good: [655079ac8a7721ac215a0596e3f33b740e01144a] ASoC: qcom: q6asm: Use guard() for spin locks
# good: [3c36965df80801344850388592e95033eceea05b] regulator: Add support for MediaTek MT6363 SPMI PMIC Regulators
# good: [2f538ef9f6f7c3d700c68536f21447dfc598f8c8] spi: aspeed: Use devm_iounmap() to unmap devm_ioremap() memory
# good: [aa897ffc396b48cc39eee133b6b43175d0df9eb5] ASoC: dt-bindings: ti,pcm1862: convert to dtschema
# good: [c4e68959af66df525d71db619ffe44af9178bb22] ASoC: dt-bindings: ti,tas2781: Add TAS5822 support
# good: [af9c8092d84244ca54ffb590435735f788e7a170] regmap: i3c: Use ARRAY_SIZE()
# good: [380fd29d57abe6679d87ec56babe65ddc5873a37] spi: tegra210-quad: Check hardware status on timeout
# good: [84194c66aaf78fed150edb217b9f341518b1cba2] ASoC: codecs: aw88261: pass pointer directly instead of passing the address
# good: [252abf2d07d33b1c70a59ba1c9395ba42bbd793e] regulator: Small cleanup in of_get_regulation_constraints()
# good: [2ecc8c089802e033d2e5204d21a9f467e2517df9] regulator: pf9453: remove unused I2C_LT register
# good: [ed5d499b5c9cc11dd3edae1a7a55db7dfa4f1bdc] regcache: maple: Split ->populate() from ->init()
# good: [e73b743bfe8a6ff4e05b5657d3f7586a17ac3ba0] ASoC: soc-core: check ops & auto_selectable_formats in snd_soc_dai_get_fmt() to prevent dereference error
# good: [f1dfbc1b5cf8650ae9a0d543e5f5335fc0f478ce] ASoC: max98090/91: fixing the stream index
# good: [6ef8e042cdcaabe3e3c68592ba8bfbaee2fa10a3] ASoC: codec: wm8400: replace printk() calls with dev_*() device aware logging
# good: [ecd0de438c1f0ee86cf8f6d5047965a2a181444b] spi: tle62x0: Add newline to sysfs attribute output
# good: [20bcda681f8597e86070a4b3b12d1e4f541865d3] ASoC: codecs: va-macro: fix revision checking
# good: [8fdb030fe283c84fd8d378c97ad0f32d6cdec6ce] ASoC: qcom: sc7280: make use of common helpers
# good: [e062bdfdd6adbb2dee7751d054c1d8df63ddb8b8] regmap: warn users about uninitialized flat cache
# good: [28039efa4d8e8bbf98b066133a906bd4e307d496] MAINTAINERS: remove obsolete file entry in DIALOG SEMICONDUCTOR DRIVERS
# good: [cf6bf51b53252284bafc7377a4d8dbf10f048b4d] ASoC: cs4271: Add support for the external mclk
# good: [66fecfa91deb536a12ddf3d878a99590d7900277] ASoC: spacemit: use depends on instead of select
# good: [f034c16a4663eaf3198dc18b201ba50533fb5b81] ASoC: spacemit: add failure check for spacemit_i2s_init_dai()
# good: [4a5ac6cd05a7e54f1585d7779464d6ed6272c134] ASoC: sun4i-spdif: Support SPDIF output on A523 family
# good: [4c33cef58965eb655a0ac8e243aa323581ec025f] regulator: pca9450: link regulator inputs to supply groups
# good: [4795375d8aa072e9aacb0b278e6203c6ca41816a] ASoC: cs-amp-lib-test: Add test cases for cs_amp_set_efi_calibration_data()
# good: [ef042df96d0e1089764f39ede61bc8f140a4be00] ASoC: SDCA: Add HID button IRQ
# good: [77a58ba7c64ccca20616aa03599766ccb0d1a330] spi: spi-mem: Trace exec_op
# good: [01313661b248c5ba586acae09bff57077dbec0a5] regulator: Let raspberrypi drivers depend on ARM
# good: [e973dfe9259095fb509ab12658c68d46f0e439d7] ASoC: qcom: sm8250: add qrb2210-sndcard compatible string
# good: [e7434adf0c53a84d548226304cdb41c8818da1cb] ASoC: cs530x: Add SPI bus support for cs530x parts
# good: [d29479abaded34b2b1dab2e17efe96a65eba3d61] ASoC: renesas: fsi: Constify struct fsi_stream_handler
# good: [c17fa4cbc546c431ccf13e9354d5d9c1cd247b7c] ASoC: sdw_utils: add name_prefix for rt1321 part id
# good: [2528c15f314ece50218d1273654f630d74109583] ASoC: max98090/91: adding DAPM routing for digital output for max98091
# good: [fd5ef3d69f8975bad16c437a337b5cb04c8217a2] spi: spi-qpic-snand: make qcom_spi_ecc_engine_ops_pipelined const
# good: [310bf433c01f78e0756fd5056a43118a2f77318c] ASoC: max98090/91: fixing a space
# good: [d054cc3a2ccfb19484f3b54d69b6e416832dc8f4] regulator: rpmh-regulator: Add RPMH regulator support for PMR735D
# good: [638bae3fb225a708dc67db613af62f6d14c4eff4] ASoC: max98090/91: added DAPM widget for digital output for max98091
# good: [ecba655bf54a661ffe078856cd8dbc898270e4b5] ASoC: fsl_aud2htx: add IEC958_SUBFRAME_LE format in supported list
# good: [7e1906643a7374529af74b013bba35e4fa4e6ffc] ASoC: codecs: va-macro: Clean up on error path in probe()
# good: [d742ebcfe524dc54023f7c520d2ed2e4b7203c19] ASoC: soc.h: remove snd_soc_kcontrol_component()
# good: [fce217449075d59b29052b8cdac567f0f3e22641] ASoC: spacemit: add i2s support for K1 SoC
# good: [6658472a3e2de08197acfe099ba71ee0e2505ecf] ASoC: amd: amd_sdw: Propagate the PCI subsystem Vendor and Device IDs
# good: [0cc08c8130ac8f74419f99fe707dc193b7f79d86] spi: aspeed: Fix an IS_ERR() vs NULL bug in probe()
# good: [0743acf746a81e0460a56fd5ff847d97fa7eb370] spi: airoha: buffer must be 0xff-ed before writing
# good: [79eaabc61dfbf5a4b680f42d3a113d05333c3960] irqchip/riscv-imsic: Embed the vector array in lpriv
# good: [00a155c691befdb10bea52c91d4c8c930bdaf73a] Merge branch 'objtool/core' of https://git.kernel.org/pub/scm/linux/kernel/git/jpoimboe/linux
# good: [1e570e77392f43a3cdab2849d1f81535f8a033e2] ASoC: mxs-saif: support usage with simple-audio-card
# good: [d77daa49085b067137d0adbe3263f75a7ee13a1b] spi: aspeed: fix spelling mistake "triming" -> "trimming"
# good: [15afe57a874eaf104bfbb61ec598fa31627f7b19] ASoC: dt-bindings: qcom: Add Kaanapali LPASS macro codecs
# good: [65efe5404d151767653c7b7dd39bd2e7ad532c2d] regulator: rpmh-regulator: Add RPMH regulator support for Glymur
# good: [fb25114cd760c13cf177d9ac37837fafcc9657b5] regulator: sy7636a: add gpios and input regulator
# good: [6621b0f118d500092f5f3d72ddddb22aeeb3c3a0] ASoC: codecs: rt5670: use SOC_VALUE_ENUM_SINGLE_DECL for DAC2 L/R MX-1B
# good: [50062baa536bcac03804cf04579c71b9351e829c] perf print-events: Remove print_symbol_events
# good: [433e294c3c5b5d2020085a0e36c1cb47b694690a] regulator: core: forward undervoltage events downstream by default
# good: [0b0eb7702a9fa410755e86124b4b7cd36e7d1cb4] ASoC: replace use of system_wq with system_dfl_wq
# good: [c2d420796a427dda71a2400909864e7f8e037fd4] elfnote: Change ELFNOTE() to use __UNIQUE_ID()
# good: [3049fc4b5f1d2320a84e2902b3ac5a735f60ca04] x86/alternative: Refactor INT3 call emulation selftest
# good: [07e1c3fd86d7a2ddce3ebc6b7390590c8524a484] objtool: Make find_symbol_containing() less arbitrary
# good: [9f14f1f91883aa2bfd6663161d2002c8ce937c43] compiler.h: Make addressable symbols less of an eyesore
# good: [6717e8f91db71641cb52855ed14c7900972ed0bc] kbuild: Remove 'kmod_' prefix from __KBUILD_MODNAME
# good: [4109043bff31f95d3da9ace33eb3c1925fd62cbd] modpost: Ignore unresolved section bounds symbols
# good: [a1526bcfcb6cb7cb601b9ff8e24d08881ef9afb8] objtool: Mark prefix functions
# good: [122679ebf90eeff97c5f793ed9a289197e0fbb2c] x86/kprobes: Remove STACK_FRAME_NON_STANDARD annotation
# good: [7e7e2c6e2a1cb250f8d03bb99eed01f6d982d5dd] ASoC: sof-function-topology-lib: escalate the log when missing function topoplogy
# good: [4d410ba9aa275e7990a270f63ce436990ace1bea] dt-bindings: sound: Update ADMAIF bindings for tegra264
# good: [fe8cc44dd173cde5788ab4e3730ac61f3d316d9c] spi: dw: add target mode support
# good: [9797329220a2c6622411eb9ecf6a35b24ce09d04] ASoC: sof-function-topology-lib: escalate the log when missing function topoplogy
# good: [5e537031f322d55315cd384398b726a9a0748d47] ASoC: codecs: Fix the error of excessive semicolons
# good: [4412ab501677606436e5c49e41151a1e6eac7ac0] spi: dt-bindings: spi-qpic-snand: Add IPQ5332 compatible
# good: [64d87ccfae3326a9561fe41dc6073064a083e0df] spi: aspeed: Only map necessary address window region
# good: [b83fb1b14c06bdd765903ac852ba20a14e24f227] spi: offload: Add offset parameter
# good: [6277a486a7faaa6c87f4bf1d59a2de233a093248] regulator: dt-bindings: Convert Dialog DA9211 Regulators to DT schema
# good: [a3a8c9c18f6904a777ff21f300d3da8c2b214c80] usb: vhci-hcd: Replace pr_*() with dev_*() logging
# good: [561f0ed96a626c53fbd9a06ce2de6349fd0c31d2] staging: rtl8723bs: sdio: clarify OQT free page comment
# good: [fe3a615dadd398f73cde00a5ba32389958242dec] drm/xe/vf: Kickstart after resfix in VF post migration recovery
# good: [59fedf46f782c024b74ceab7868e13f0e0f10c45] drm/ast: Split ast_detect_tx_chip() per chip generation
git bisect start '6d7e7251d03f98f26f2ee0dfd21bb0a0480a2178' 'aeee991e3a4cb03497cda0f879619c2e71143b49' '4d6e2211aeb932e096f673c88475016b1cc0f8ab' '1d562ba0aa7df81335bf96c02be77efe8d5bab87' 'b3a5302484033331af37569f7277d00131694b57' '32172cf3cb543a04c41a1677c97a38e60cad05b6' '873bc94689d832878befbcadc10b6ad5bb4e0027' '772ada50282b0c80343c8989147db816961f571d' '6985defd1d832f1dd9d1977a6a2cc2cef7632704' 'fb1ebb10468da414d57153ddebaab29c38ef1a78' '2089f086303b773e181567fd8d5df3038bd85937' '4e92abd0a11b91af3742197a9ca962c3c00d0948' '6951be397ca8b8b167c9f99b5a11c541148c38cb' 'abc9a349b87ac0fd3ba8787ca00971b59c2e1257' '1b0f3f9ee41ee2bdd206667f85ea2aa36dfe6e69' '6bd1ad97eb790570c167d4de4ca59fbc9c33722a' '55d03b5b5bdd04daf9a35ce49db18d8bb488dffb' '655079ac8a7721ac215a0596e3f33b740e01144a' '3c36965df80801344850388592e95033eceea05b' '2f538ef9f6f7c3d700c68536f21447dfc598f8c8' 'aa897ffc396b48cc39eee133b6b43175d0df9eb5' 'c4e68959af66df525d71db619ffe44af9178bb22' 'af9c8092d84244ca54ffb590435735f788e7a170' '380fd29d57abe6679d87ec56babe65ddc5873a37' '84194c66aaf78fed150edb217b9f341518b1cba2' '252abf2d07d33b1c70a59ba1c9395ba42bbd793e' '2ecc8c089802e033d2e5204d21a9f467e2517df9' 'ed5d499b5c9cc11dd3edae1a7a55db7dfa4f1bdc' 'e73b743bfe8a6ff4e05b5657d3f7586a17ac3ba0' 'f1dfbc1b5cf8650ae9a0d543e5f5335fc0f478ce' '6ef8e042cdcaabe3e3c68592ba8bfbaee2fa10a3' 'ecd0de438c1f0ee86cf8f6d5047965a2a181444b' '20bcda681f8597e86070a4b3b12d1e4f541865d3' '8fdb030fe283c84fd8d378c97ad0f32d6cdec6ce' 'e062bdfdd6adbb2dee7751d054c1d8df63ddb8b8' '28039efa4d8e8bbf98b066133a906bd4e307d496' 'cf6bf51b53252284bafc7377a4d8dbf10f048b4d' '66fecfa91deb536a12ddf3d878a99590d7900277' 'f034c16a4663eaf3198dc18b201ba50533fb5b81' '4a5ac6cd05a7e54f1585d7779464d6ed6272c134' '4c33cef58965eb655a0ac8e243aa323581ec025f' '4795375d8aa072e9aacb0b278e6203c6ca41816a' 'ef042df96d0e1089764f39ede61bc8f140a4be00' '77a58ba7c64ccca20616aa03599766ccb0d1a330' '01313661b248c5ba586acae09bff57077dbec0a5' 'e973dfe9259095fb509ab12658c68d46f0e439d7' 'e7434adf0c53a84d548226304cdb41c8818da1cb' 'd29479abaded34b2b1dab2e17efe96a65eba3d61' 'c17fa4cbc546c431ccf13e9354d5d9c1cd247b7c' '2528c15f314ece50218d1273654f630d74109583' 'fd5ef3d69f8975bad16c437a337b5cb04c8217a2' '310bf433c01f78e0756fd5056a43118a2f77318c' 'd054cc3a2ccfb19484f3b54d69b6e416832dc8f4' '638bae3fb225a708dc67db613af62f6d14c4eff4' 'ecba655bf54a661ffe078856cd8dbc898270e4b5' '7e1906643a7374529af74b013bba35e4fa4e6ffc' 'd742ebcfe524dc54023f7c520d2ed2e4b7203c19' 'fce217449075d59b29052b8cdac567f0f3e22641' '6658472a3e2de08197acfe099ba71ee0e2505ecf' '0cc08c8130ac8f74419f99fe707dc193b7f79d86' '0743acf746a81e0460a56fd5ff847d97fa7eb370' '79eaabc61dfbf5a4b680f42d3a113d05333c3960' '00a155c691befdb10bea52c91d4c8c930bdaf73a' '1e570e77392f43a3cdab2849d1f81535f8a033e2' 'd77daa49085b067137d0adbe3263f75a7ee13a1b' '15afe57a874eaf104bfbb61ec598fa31627f7b19' '65efe5404d151767653c7b7dd39bd2e7ad532c2d' 'fb25114cd760c13cf177d9ac37837fafcc9657b5' '6621b0f118d500092f5f3d72ddddb22aeeb3c3a0' '50062baa536bcac03804cf04579c71b9351e829c' '433e294c3c5b5d2020085a0e36c1cb47b694690a' '0b0eb7702a9fa410755e86124b4b7cd36e7d1cb4' 'c2d420796a427dda71a2400909864e7f8e037fd4' '3049fc4b5f1d2320a84e2902b3ac5a735f60ca04' '07e1c3fd86d7a2ddce3ebc6b7390590c8524a484' '9f14f1f91883aa2bfd6663161d2002c8ce937c43' '6717e8f91db71641cb52855ed14c7900972ed0bc' '4109043bff31f95d3da9ace33eb3c1925fd62cbd' 'a1526bcfcb6cb7cb601b9ff8e24d08881ef9afb8' '122679ebf90eeff97c5f793ed9a289197e0fbb2c' '7e7e2c6e2a1cb250f8d03bb99eed01f6d982d5dd' '4d410ba9aa275e7990a270f63ce436990ace1bea' 'fe8cc44dd173cde5788ab4e3730ac61f3d316d9c' '9797329220a2c6622411eb9ecf6a35b24ce09d04' '5e537031f322d55315cd384398b726a9a0748d47' '4412ab501677606436e5c49e41151a1e6eac7ac0' '64d87ccfae3326a9561fe41dc6073064a083e0df' 'b83fb1b14c06bdd765903ac852ba20a14e24f227' '6277a486a7faaa6c87f4bf1d59a2de233a093248' 'a3a8c9c18f6904a777ff21f300d3da8c2b214c80' '561f0ed96a626c53fbd9a06ce2de6349fd0c31d2' 'fe3a615dadd398f73cde00a5ba32389958242dec' '59fedf46f782c024b74ceab7868e13f0e0f10c45'
# test job: [4d6e2211aeb932e096f673c88475016b1cc0f8ab] https://lava.sirena.org.uk/scheduler/job/2078045 # test job: [1d562ba0aa7df81335bf96c02be77efe8d5bab87] https://lava.sirena.org.uk/scheduler/job/2078452 # test job: [b3a5302484033331af37569f7277d00131694b57] https://lava.sirena.org.uk/scheduler/job/2074506 # test job: [32172cf3cb543a04c41a1677c97a38e60cad05b6] https://lava.sirena.org.uk/scheduler/job/2075063 # test job: [873bc94689d832878befbcadc10b6ad5bb4e0027] https://lava.sirena.org.uk/scheduler/job/2074989 # test job: [772ada50282b0c80343c8989147db816961f571d] https://lava.sirena.org.uk/scheduler/job/2069151 # test job: [6985defd1d832f1dd9d1977a6a2cc2cef7632704] https://lava.sirena.org.uk/scheduler/job/2059206 # test job: [fb1ebb10468da414d57153ddebaab29c38ef1a78] https://lava.sirena.org.uk/scheduler/job/2059735 # test job: [2089f086303b773e181567fd8d5df3038bd85937] https://lava.sirena.org.uk/scheduler/job/2058045 # test job: [4e92abd0a11b91af3742197a9ca962c3c00d0948] https://lava.sirena.org.uk/scheduler/job/2055814 # test job: [6951be397ca8b8b167c9f99b5a11c541148c38cb] https://lava.sirena.org.uk/scheduler/job/2056393 # test job: [abc9a349b87ac0fd3ba8787ca00971b59c2e1257] https://lava.sirena.org.uk/scheduler/job/2054629 # test job: [1b0f3f9ee41ee2bdd206667f85ea2aa36dfe6e69] https://lava.sirena.org.uk/scheduler/job/2053476 # test job: [6bd1ad97eb790570c167d4de4ca59fbc9c33722a] https://lava.sirena.org.uk/scheduler/job/2053930 # test job: [55d03b5b5bdd04daf9a35ce49db18d8bb488dffb] https://lava.sirena.org.uk/scheduler/job/2054195 # test job: [655079ac8a7721ac215a0596e3f33b740e01144a] https://lava.sirena.org.uk/scheduler/job/2049656 # test job: [3c36965df80801344850388592e95033eceea05b] https://lava.sirena.org.uk/scheduler/job/2050587 # test job: [2f538ef9f6f7c3d700c68536f21447dfc598f8c8] https://lava.sirena.org.uk/scheduler/job/2048586 # test job: [aa897ffc396b48cc39eee133b6b43175d0df9eb5] https://lava.sirena.org.uk/scheduler/job/2048671 # test job: [c4e68959af66df525d71db619ffe44af9178bb22] https://lava.sirena.org.uk/scheduler/job/2044470 # test job: [af9c8092d84244ca54ffb590435735f788e7a170] https://lava.sirena.org.uk/scheduler/job/2043681 # test job: [380fd29d57abe6679d87ec56babe65ddc5873a37] https://lava.sirena.org.uk/scheduler/job/2044549 # test job: [84194c66aaf78fed150edb217b9f341518b1cba2] https://lava.sirena.org.uk/scheduler/job/2038332 # test job: [252abf2d07d33b1c70a59ba1c9395ba42bbd793e] https://lava.sirena.org.uk/scheduler/job/2038504 # test job: [2ecc8c089802e033d2e5204d21a9f467e2517df9] https://lava.sirena.org.uk/scheduler/job/2038909 # test job: [ed5d499b5c9cc11dd3edae1a7a55db7dfa4f1bdc] https://lava.sirena.org.uk/scheduler/job/2029006 # test job: [e73b743bfe8a6ff4e05b5657d3f7586a17ac3ba0] https://lava.sirena.org.uk/scheduler/job/2026401 # test job: [f1dfbc1b5cf8650ae9a0d543e5f5335fc0f478ce] https://lava.sirena.org.uk/scheduler/job/2025480 # test job: [6ef8e042cdcaabe3e3c68592ba8bfbaee2fa10a3] https://lava.sirena.org.uk/scheduler/job/2025879 # test job: [ecd0de438c1f0ee86cf8f6d5047965a2a181444b] https://lava.sirena.org.uk/scheduler/job/2026088 # test job: [20bcda681f8597e86070a4b3b12d1e4f541865d3] https://lava.sirena.org.uk/scheduler/job/2022933 # test job: [8fdb030fe283c84fd8d378c97ad0f32d6cdec6ce] https://lava.sirena.org.uk/scheduler/job/2021446 # test job: [e062bdfdd6adbb2dee7751d054c1d8df63ddb8b8] https://lava.sirena.org.uk/scheduler/job/2020179 # test job: [28039efa4d8e8bbf98b066133a906bd4e307d496] https://lava.sirena.org.uk/scheduler/job/2020283 # test job: [cf6bf51b53252284bafc7377a4d8dbf10f048b4d] https://lava.sirena.org.uk/scheduler/job/2022983 # test job: [66fecfa91deb536a12ddf3d878a99590d7900277] https://lava.sirena.org.uk/scheduler/job/2015329 # test job: [f034c16a4663eaf3198dc18b201ba50533fb5b81] https://lava.sirena.org.uk/scheduler/job/2015473 # test job: [4a5ac6cd05a7e54f1585d7779464d6ed6272c134] https://lava.sirena.org.uk/scheduler/job/2011241 # test job: [4c33cef58965eb655a0ac8e243aa323581ec025f] https://lava.sirena.org.uk/scheduler/job/2010807 # test job: [4795375d8aa072e9aacb0b278e6203c6ca41816a] https://lava.sirena.org.uk/scheduler/job/2011005 # test job: [ef042df96d0e1089764f39ede61bc8f140a4be00] https://lava.sirena.org.uk/scheduler/job/2011039 # test job: [77a58ba7c64ccca20616aa03599766ccb0d1a330] https://lava.sirena.org.uk/scheduler/job/2007290 # test job: [01313661b248c5ba586acae09bff57077dbec0a5] https://lava.sirena.org.uk/scheduler/job/2008742 # test job: [e973dfe9259095fb509ab12658c68d46f0e439d7] https://lava.sirena.org.uk/scheduler/job/2012324 # test job: [e7434adf0c53a84d548226304cdb41c8818da1cb] https://lava.sirena.org.uk/scheduler/job/2007744 # test job: [d29479abaded34b2b1dab2e17efe96a65eba3d61] https://lava.sirena.org.uk/scheduler/job/2008412 # test job: [c17fa4cbc546c431ccf13e9354d5d9c1cd247b7c] https://lava.sirena.org.uk/scheduler/job/2000004 # test job: [2528c15f314ece50218d1273654f630d74109583] https://lava.sirena.org.uk/scheduler/job/1997593 # test job: [fd5ef3d69f8975bad16c437a337b5cb04c8217a2] https://lava.sirena.org.uk/scheduler/job/1996100 # test job: [310bf433c01f78e0756fd5056a43118a2f77318c] https://lava.sirena.org.uk/scheduler/job/1996021 # test job: [d054cc3a2ccfb19484f3b54d69b6e416832dc8f4] https://lava.sirena.org.uk/scheduler/job/1995684 # test job: [638bae3fb225a708dc67db613af62f6d14c4eff4] https://lava.sirena.org.uk/scheduler/job/1991853 # test job: [ecba655bf54a661ffe078856cd8dbc898270e4b5] https://lava.sirena.org.uk/scheduler/job/1985116 # test job: [7e1906643a7374529af74b013bba35e4fa4e6ffc] https://lava.sirena.org.uk/scheduler/job/1978575 # test job: [d742ebcfe524dc54023f7c520d2ed2e4b7203c19] https://lava.sirena.org.uk/scheduler/job/1976775 # test job: [fce217449075d59b29052b8cdac567f0f3e22641] https://lava.sirena.org.uk/scheduler/job/1975621 # test job: [6658472a3e2de08197acfe099ba71ee0e2505ecf] https://lava.sirena.org.uk/scheduler/job/1976196 # test job: [0cc08c8130ac8f74419f99fe707dc193b7f79d86] https://lava.sirena.org.uk/scheduler/job/1965692 # test job: [0743acf746a81e0460a56fd5ff847d97fa7eb370] https://lava.sirena.org.uk/scheduler/job/1964813 # test job: [79eaabc61dfbf5a4b680f42d3a113d05333c3960] https://lava.sirena.org.uk/scheduler/job/1979980 # test job: [00a155c691befdb10bea52c91d4c8c930bdaf73a] https://lava.sirena.org.uk/scheduler/job/1980696 # test job: [1e570e77392f43a3cdab2849d1f81535f8a033e2] https://lava.sirena.org.uk/scheduler/job/1963814 # test job: [d77daa49085b067137d0adbe3263f75a7ee13a1b] https://lava.sirena.org.uk/scheduler/job/1964718 # test job: [15afe57a874eaf104bfbb61ec598fa31627f7b19] https://lava.sirena.org.uk/scheduler/job/1963938 # test job: [65efe5404d151767653c7b7dd39bd2e7ad532c2d] https://lava.sirena.org.uk/scheduler/job/1962057 # test job: [fb25114cd760c13cf177d9ac37837fafcc9657b5] https://lava.sirena.org.uk/scheduler/job/1963349 # test job: [6621b0f118d500092f5f3d72ddddb22aeeb3c3a0] https://lava.sirena.org.uk/scheduler/job/1962085 # test job: [50062baa536bcac03804cf04579c71b9351e829c] https://lava.sirena.org.uk/scheduler/job/1978269 # test job: [433e294c3c5b5d2020085a0e36c1cb47b694690a] https://lava.sirena.org.uk/scheduler/job/1957339 # test job: [0b0eb7702a9fa410755e86124b4b7cd36e7d1cb4] https://lava.sirena.org.uk/scheduler/job/1957395 # test job: [c2d420796a427dda71a2400909864e7f8e037fd4] https://lava.sirena.org.uk/scheduler/job/1981809 # test job: [3049fc4b5f1d2320a84e2902b3ac5a735f60ca04] https://lava.sirena.org.uk/scheduler/job/1989503 # test job: [07e1c3fd86d7a2ddce3ebc6b7390590c8524a484] https://lava.sirena.org.uk/scheduler/job/1980837 # test job: [9f14f1f91883aa2bfd6663161d2002c8ce937c43] https://lava.sirena.org.uk/scheduler/job/1981518 # test job: [6717e8f91db71641cb52855ed14c7900972ed0bc] https://lava.sirena.org.uk/scheduler/job/1981667 # test job: [4109043bff31f95d3da9ace33eb3c1925fd62cbd] https://lava.sirena.org.uk/scheduler/job/1981316 # test job: [a1526bcfcb6cb7cb601b9ff8e24d08881ef9afb8] https://lava.sirena.org.uk/scheduler/job/1980768 # test job: [122679ebf90eeff97c5f793ed9a289197e0fbb2c] https://lava.sirena.org.uk/scheduler/job/1981229 # test job: [7e7e2c6e2a1cb250f8d03bb99eed01f6d982d5dd] https://lava.sirena.org.uk/scheduler/job/1954246 # test job: [4d410ba9aa275e7990a270f63ce436990ace1bea] https://lava.sirena.org.uk/scheduler/job/1947847 # test job: [fe8cc44dd173cde5788ab4e3730ac61f3d316d9c] https://lava.sirena.org.uk/scheduler/job/1947074 # test job: [9797329220a2c6622411eb9ecf6a35b24ce09d04] https://lava.sirena.org.uk/scheduler/job/1947363 # test job: [5e537031f322d55315cd384398b726a9a0748d47] https://lava.sirena.org.uk/scheduler/job/1946632 # test job: [4412ab501677606436e5c49e41151a1e6eac7ac0] https://lava.sirena.org.uk/scheduler/job/1946228 # test job: [64d87ccfae3326a9561fe41dc6073064a083e0df] https://lava.sirena.org.uk/scheduler/job/1953764 # test job: [b83fb1b14c06bdd765903ac852ba20a14e24f227] https://lava.sirena.org.uk/scheduler/job/1946821 # test job: [6277a486a7faaa6c87f4bf1d59a2de233a093248] https://lava.sirena.org.uk/scheduler/job/1953762 # test job: [a3a8c9c18f6904a777ff21f300d3da8c2b214c80] https://lava.sirena.org.uk/scheduler/job/1979592 # test job: [561f0ed96a626c53fbd9a06ce2de6349fd0c31d2] https://lava.sirena.org.uk/scheduler/job/1978456 # test job: [fe3a615dadd398f73cde00a5ba32389958242dec] https://lava.sirena.org.uk/scheduler/job/1978703 # test job: [59fedf46f782c024b74ceab7868e13f0e0f10c45] https://lava.sirena.org.uk/scheduler/job/1979218 # test job: [6d7e7251d03f98f26f2ee0dfd21bb0a0480a2178] https://lava.sirena.org.uk/scheduler/job/2079917 # bad: [6d7e7251d03f98f26f2ee0dfd21bb0a0480a2178] Add linux-next specific files for 20251113 git bisect bad 6d7e7251d03f98f26f2ee0dfd21bb0a0480a2178 # test job: [3d08639208ff9f52d988c95781bc45d41d94ffd0] https://lava.sirena.org.uk/scheduler/job/2080233 # good: [3d08639208ff9f52d988c95781bc45d41d94ffd0] Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git git bisect good 3d08639208ff9f52d988c95781bc45d41d94ffd0 # test job: [f7bef466d6ea35a35e9c852a7b5315ce969c7877] https://lava.sirena.org.uk/scheduler/job/2080382 # good: [f7bef466d6ea35a35e9c852a7b5315ce969c7877] Merge branch 'for-next' of https://git.kernel.org/pub/scm/linux/kernel/git/libata/linux git bisect good f7bef466d6ea35a35e9c852a7b5315ce969c7877 # test job: [362f39fb330b5578824bd5330403d6c438582483] https://lava.sirena.org.uk/scheduler/job/2080519 # bad: [362f39fb330b5578824bd5330403d6c438582483] Merge branch 'driver-core-next' of https://git.kernel.org/pub/scm/linux/kernel/git/driver-core/driver-core.git git bisect bad 362f39fb330b5578824bd5330403d6c438582483 # test job: [f6e1d0d9e619027062eed9217d4804c11044a27a] https://lava.sirena.org.uk/scheduler/job/2080640 # good: [f6e1d0d9e619027062eed9217d4804c11044a27a] Merge branch 'master' of https://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git git bisect good f6e1d0d9e619027062eed9217d4804c11044a27a # test job: [44d048590effc717acf997ff9b7545193289fbf0] https://lava.sirena.org.uk/scheduler/job/2080756 # bad: [44d048590effc717acf997ff9b7545193289fbf0] Merge branch 'next' of https://github.com/kvm-x86/linux.git git bisect bad 44d048590effc717acf997ff9b7545193289fbf0 # test job: [b50267d5e8901940dfb948ad8d36628e8392c5dc] https://lava.sirena.org.uk/scheduler/job/2080827 # good: [b50267d5e8901940dfb948ad8d36628e8392c5dc] Merge branch 'non-rcu/next' of https://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu.git git bisect good b50267d5e8901940dfb948ad8d36628e8392c5dc # test job: [5acf839dcad8bdfc6d646c34680c008bd1167cde] https://lava.sirena.org.uk/scheduler/job/2080878 # good: [5acf839dcad8bdfc6d646c34680c008bd1167cde] Merge branch 'tdx' git bisect good 5acf839dcad8bdfc6d646c34680c008bd1167cde # test job: [182853c7680aaaf00fffd7cd347ae4aa50805fdf] https://lava.sirena.org.uk/scheduler/job/2080989 # bad: [182853c7680aaaf00fffd7cd347ae4aa50805fdf] KVM: arm64: GICv2: Handle deactivation via GICV_DIR traps git bisect bad 182853c7680aaaf00fffd7cd347ae4aa50805fdf # test job: [d78124a65a03f1483c62d8612594d5d833b8e4a5] https://lava.sirena.org.uk/scheduler/job/2081054 # bad: [d78124a65a03f1483c62d8612594d5d833b8e4a5] KVM: arm64: GICv2: Extract LR computing primitive git bisect bad d78124a65a03f1483c62d8612594d5d833b8e4a5 # test job: [2a69aca33cac6b191fd13c7ea16c33df680a1b0e] https://lava.sirena.org.uk/scheduler/job/2081151 # bad: [2a69aca33cac6b191fd13c7ea16c33df680a1b0e] KVM: arm64: Add LR overflow handling documentation git bisect bad 2a69aca33cac6b191fd13c7ea16c33df680a1b0e # test job: [ca30799f7c2d04400a428fbc82aa49dc2493cc1a] https://lava.sirena.org.uk/scheduler/job/2081229 # good: [ca30799f7c2d04400a428fbc82aa49dc2493cc1a] KVM: arm64: Turn vgic-v3 errata traps into a patched-in constant git bisect good ca30799f7c2d04400a428fbc82aa49dc2493cc1a # test job: [10576b2d86522cc70d8e1d8e121a2cb9c44c2ff3] https://lava.sirena.org.uk/scheduler/job/2081295 # bad: [10576b2d86522cc70d8e1d8e121a2cb9c44c2ff3] KVM: arm64: Repack struct vgic_irq fields git bisect bad 10576b2d86522cc70d8e1d8e121a2cb9c44c2ff3 # test job: [375e16720b4c8ee04a01de03fb7103ac0a7a4856] https://lava.sirena.org.uk/scheduler/job/2081327 # bad: [375e16720b4c8ee04a01de03fb7103ac0a7a4856] KVM: arm64: GICv3: Detect and work around the lack of ICV_DIR_EL1 trapping git bisect bad 375e16720b4c8ee04a01de03fb7103ac0a7a4856 # first bad commit: [375e16720b4c8ee04a01de03fb7103ac0a7a4856] KVM: arm64: GICv3: Detect and work around the lack of ICV_DIR_EL1 trapping
Marc Zyngier
maintainerRe: [PATCH v2 05/45] KVM: arm64: GICv3: Detect and work around the lack of ICV_DIR_EL1 trapping
Quoted 52 lines · Mark Brown
[1 <text/plain; us-ascii (quoted-printable)>]
Quoted 5 lines · Marc Zyngier
A long time ago, an unsuspecting architect forgot to add a trap bit for
ICV_DIR_EL1inICH_HCR_EL2. Which was unfortunate, but what's a bit of spec between friends? Thankfully, this was fixed in a later revision, and ARM "deprecates" the lack of trapping ability.I'm seeing a regression on i.MX8MP-EVK and Toradax AM625+Mallow boards (both 4xA53+GICv3) in protected mode only with a bunch of the KVM selftests, including the
arch_timerone:# selftests: kvm:
arch_timer
# Random seed:0x6b8b4567
# ==== Test Assertion Failure ====
#lib/arm64/processor.c:487: false
# pid=4469 tid=4473 errno=4 - Interrupted system call
# ==== Test Assertion Failure ====
#lib/arm64/processor.c:487: false
# pid=4469 tid=4471 errno=4 - Interrupted system call
# ==== Test Assertion Failure ====
#lib/arm64/processor.c:487: false
# pid=4469 tid=4472 errno=4 - Interrupted system call
# ==== Test Assertion Failure ====
#lib/arm64/processor.c:487: false
# pid=4469 tid=4470 errno=4 - Interrupted system call# 1 0x0000000000414387: assert_on_unhandled_exception at processor.c:487 # 2 0x000000000040727f: _vcpu_run at kvm_util.c:1699 # 3 (inlined by) vcpu_run at kvm_util.c:1710 # 4 0x0000000000402b07: test_vcpu_run at arch_timer.c:55 # 5 0x0000ffffb12f2f9b: ?? ??:0 # 6 0x0000ffffb135e58b: ?? ??:0 # 1 0x0000000000414387: assert_on_unhandled_exception at processor.c:487 # 2 0x000000000040727f: _vcpu_run at kvm_util.c:1699 # 3 (inlined by) vcpu_run at kvm_util.c:1710 # 4 0x0000000000402b07: test_vcpu_run at arch_timer.c:55 # 5 0x0000ffffb12f2f9b: ?? ??:0 # 6 0x0000ffffb135e58b: ?? ??:0 # Unexpected exception (vector:0x4, ec:0x0) # 1 0x0000000000414387: assert_on_unhandled_exception at processor.c:487 # 2 0x000000000040727f: _vcpu_run at kvm_util.c:1699 # 3 (inlined by) vcpu_run at kvm_util.c:1710 # 4 0x0000000000402b07: test_vcpu_run at arch_timer.c:55 # 5 0x0000ffffb12f2f9b: ?? ??:0 # 6 0x0000ffffb135e58b: ?? ??:0 # 1 0x0000000000414387: assert_on_unhandled_exception at processor.c:487 # 2 0x000000000040727f: _vcpu_run at kvm_util.c:1699 # 3 (inlined by) vcpu_run at kvm_util.c:1710 # 4 0x0000000000402b07: test_vcpu_run at arch_timer.c:55 # 5 0x0000ffffb12f2f9b: ?? ??:0 # 6 0x0000ffffb135e58b: ?? ??:0
Quoted 4 lines
not ok 28 selftests: kvm:
arch_timer# exit=254The
arch_timercase bisects to this patch in -next, regular nVHE mode runs this test happily.
My hunch is that we're missing something like the hack below, but I haven't tried it yet.
I'll probably get to it tomorrow.
M.
arch/arm64/kvm/hyp/nvhe/sys_regs.c +5 -0
@@ -444,6 +444,8 @@ static const struct sys_reg_desc pvm_sys_reg_descs[] = {/* Scalable Vector Registers are restricted. */ +HOST_HANDLED (SYS_ICC_PMR_EL1 ), +RAZ_WI (SYS_ERRIDR_EL1 ),RAZ_WI (SYS_ERRSELR_EL1 ), RAZ_WI(SYS_ERXFR_EL1),
@@ -457,9 +459,12 @@ static const struct sys_reg_desc pvm_sys_reg_descs[] = {/* Limited Ordering Regions Registers are restricted. */ +HOST_HANDLED (SYS_ICC_DIR_EL1 ), +HOST_HANDLED (SYS_ICC_RPR_EL1 ),HOST_HANDLED (SYS_ICC_SGI1R_EL1 ),HOST_HANDLED (SYS_ICC_ASGI1R_EL1 ),HOST_HANDLED (SYS_ICC_SGI0R_EL1 ), +HOST_HANDLED (SYS_ICC_CTLR_EL1 ), { SYS_DESC(SYS_ICC_SRE_EL1), .access = pvm_gic_read_sre, }, HOST_HANDLED(SYS_CCSIDR_EL1),
Signature · 1 line
Without deviation from the norm, progress is not possible.
Re: [PATCH v2 05/45] KVM: arm64: GICv3: Detect and work around the lack of ICV_DIR_EL1 trapping
Quoted 9 lines · Marc Zyngier
Quoted 2 lines · Mark Brown
The
arch_timercase bisects to this patch in -next, regular nVHE mode runs this test happily.My hunch is that we're missing something like the hack below, but I haven't tried it yet.
I'll probably get to it tomorrow.
That still fails FWIW.
Marc Zyngier
maintainerRe: [PATCH v2 05/45] KVM: arm64: GICv3: Detect and work around the lack of ICV_DIR_EL1 trapping
+Fuad
Quoted 8 lines · Mark Brown
[1 <text/plain; us-ascii (7bit)>]
Quoted 4 lines · Marc Zyngier
Quoted 2 lines · Mark Brown
The
arch_timercase bisects to this patch in -next, regular nVHE mode runs this test happily.
Quoted 6 lines
Quoted 4 lines
My hunch is that we're missing something like the hack below, but I haven't tried it yet.
I'll probably get to it tomorrow.
That still fails FWIW.
Yup, this has uncovered yet another pKVM bug, which doesn't preserve the vgic_model in its private kvm structure. I'm able to make it work with this:
arch/arm64/kvm/hyp/nvhe/pkvm.c +3 -0
@@ -337,6 +337,9 @@ static void pkvm_init_features_from_host(struct pkvm_hyp_vm *hyp_vm, const struc/* CTR_EL0 is always under host control, even for protected VMs. */ hyp_vm->kvm.arch.ctr_el0 = host_kvm->arch.ctr_el0; +/* Preserve the vgic model so that GICv3 emulation works */ + hyp_vm->kvm.arch.vgic.vgic_model = host_kvm->arch.vgic.vgic_model; +if (test_bit (KVM_ARCH_FLAG_MTE_ENABLED , &host_kvm->arch.flags))set_bit (KVM_ARCH_FLAG_MTE_ENABLED , &kvm->arch.flags);
arch/arm64/kvm/hyp/nvhe/sys_regs.c +5 -0
@@ -444,6 +444,8 @@ static const struct sys_reg_desc pvm_sys_reg_descs[] = {/* Scalable Vector Registers are restricted. */ +HOST_HANDLED (SYS_ICC_PMR_EL1 ), +RAZ_WI (SYS_ERRIDR_EL1 ),RAZ_WI (SYS_ERRSELR_EL1 ), RAZ_WI(SYS_ERXFR_EL1),
@@ -457,9 +459,12 @@ static const struct sys_reg_desc pvm_sys_reg_descs[] = {/* Limited Ordering Regions Registers are restricted. */ +HOST_HANDLED (SYS_ICC_DIR_EL1 ), +HOST_HANDLED (SYS_ICC_RPR_EL1 ),HOST_HANDLED (SYS_ICC_SGI1R_EL1 ),HOST_HANDLED (SYS_ICC_ASGI1R_EL1 ),HOST_HANDLED (SYS_ICC_SGI0R_EL1 ), +HOST_HANDLED (SYS_ICC_CTLR_EL1 ), { SYS_DESC(SYS_ICC_SRE_EL1), .access = pvm_gic_read_sre, }, HOST_HANDLED(SYS_CCSIDR_EL1),
Thanks,
M.
Signature · 1 line
Without deviation from the norm, progress is not possible.
Oliver Upton
maintainerRe: [PATCH v2 05/45] KVM: arm64: GICv3: Detect and work around the lack of ICV_DIR_EL1 trapping
Quoted 15 lines · Marc Zyngier
+Fuad
Quoted 11 lines · Mark Brown
[1 <text/plain; us-ascii (7bit)>]
Quoted 7 lines · Marc Zyngier
Quoted 2 lines · Mark Brown
The
arch_timercase bisects to this patch in -next, regular nVHE mode runs this test happily.My hunch is that we're missing something like the hack below, but I haven't tried it yet.
Quoted 7 lines
Quoted 3 lines
Quoted 1 line
I'll probably get to it tomorrow.
That still fails FWIW.
Yup, this has uncovered yet another pKVM bug, which doesn't preserve the
vgic_modelin its private kvm structure. I'm able to make it work with this:
Thanks for debugging this Marc. I've added a patch on top of kvmarm/next with this. I don't have any A53 machines around but I was able to repro using kvm-arm.vgic_v3_common_trap=1 on QEMU.
Thanks,
Oliver
Marc Zyngier
maintainerPATCH v2 6/45 KVM: arm64: Repack struct vgic_irq fields
In reply to Marc Zyngierstruct vgic_irq has grown over the years, in a rather bad way. Repack it using bitfields so that the individual flags, and move things around a bit so that it a bit smaller.
--- arch/arm64/kvm/vgic/vgic-v4.c | 5 ++++- include/kvm/arm_vgic.h | 20 ++++++++++---------- 2 files changed, 14 insertions(+), 11 deletions(-)
arch/arm64/kvm/vgic/vgic-v4.c +4 -1
@@ -163,6 +163,7 @@ static void vgic_v4_disable_vsgis(struct kvm_vcpu *vcpu)struct vgic_irq *irq =vgic_get_vcpu_irq (vcpu, i);struct irq_desc *desc;unsigned long flags; +bool pending;int ret;raw_spin_lock_irqsave (&irq->irq_lock, flags);
@@ -173,9 +174,11 @@ static void vgic_v4_disable_vsgis(struct kvm_vcpu *vcpu) irq->hw = false; ret =irq_get_irqchip_state (irq->host_irq,IRQCHIP_STATE_PENDING , - &irq->pending_latch); + &pending);WARN_ON (ret); + irq->pending_latch = pending; + desc =irq_to_desc (irq->host_irq);irq_domain_deactivate_irq (irq_desc_get_irq_data (desc)); unlock:
include/kvm/arm_vgic.h +10 -10
@@ -123,6 +123,7 @@ struct irq_ops {struct vgic_irq {raw_spinlock_t irq_lock;/* Protects the content of the struct */ +u32 intid;/* Guest visible INTID */ struct rcu_head rcu;struct list_head ap_list;
@@ -137,17 +138,17 @@ struct vgic_irq {* affinity reg (v3). */ -u32 intid;/* Guest visible INTID */ -bool line_level;/* Level only */ -bool pending_latch;/* The pending latch state used to calculate -* the pending state for both level -* and edge triggered IRQs. */ -bool active; -bool pending_release;/* Used for LPIs only, unreferenced IRQ + bool pending_release:1; /* Used for LPIs only, unreferenced IRQ* pending a release */ -bool enabled; -bool hw;/* Tied to HW IRQ */ + bool pending_latch:1; /* The pending latch state used to calculate +* the pending state for both level +* and edge triggered IRQs. */ + enum vgic_irq_config config:1; /* Level or edge */ + bool line_level:1; /* Level only */ + bool enabled:1; + bool active:1; + bool hw:1; /* Tied to HW IRQ */refcount_t refcount;/* Used for LPIs */ u32 hwintid;/* HW INTID number */ unsigned int host_irq;/* linux irq corresponding to hwintid */
@@ -159,7 +160,6 @@ struct vgic_irq {u8 active_source;/* GICv2 SGIs only */ u8 priority;u8 group;/* 0 == group 0, 1 == group 1 */ -enum vgic_irq_config config;/* Level or edge */ struct irq_ops *ops;
Signature · 1 line
2.47.3
Marc Zyngier
maintainerPATCH v2 7/45 KVM: arm64: Add tracking of vgic_irq being present in a LR
In reply to Marc ZyngierWe currently cannot identify whether an interrupt is queued into a LR. It wasn't needed until now, but that's about to change.
Add yet another flag to track that state.
--- arch/arm64/kvm/vgic/vgic-v2.c | 6 ++++++ arch/arm64/kvm/vgic/vgic-v3.c | 6 ++++++ include/kvm/arm_vgic.h | 1 + 3 files changed, 13 insertions(+)
arch/arm64/kvm/vgic/vgic-v2.c +6 -0
@@ -101,6 +101,8 @@ void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu)/* Handle resampling for mapped interrupts if required */ vgic_irq_handle_resampling (irq, deactivated, val &GICH_LR_PENDING_BIT ); + irq->on_lr = false; +raw_spin_unlock (&irq->irq_lock);vgic_put_irq (vcpu->kvm, irq); }
@@ -124,6 +126,8 @@ void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)u32 val = irq->intid;bool allow_pending = true; +WARN_ON (irq->on_lr); +if (irq->active) { val |=GICH_LR_ACTIVE_BIT ;if (vgic_irq_is_sgi (irq->intid))
@@ -194,6 +198,8 @@ void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)/* The GICv2 LR only holds five bits of priority. */ val |= (irq->priority >>3 ) <<GICH_LR_PRIORITY_SHIFT ; + irq->on_lr = true; + vcpu->arch.vgic_cpu.vgic_v2.vgic_lr[lr] = val; }
arch/arm64/kvm/vgic/vgic-v3.c +6 -0
@@ -97,6 +97,8 @@ void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)/* Handle resampling for mapped interrupts if required */ vgic_irq_handle_resampling (irq, deactivated, val &ICH_LR_PENDING_BIT ); + irq->on_lr = false; +raw_spin_unlock (&irq->irq_lock);vgic_put_irq (vcpu->kvm, irq); }
@@ -111,6 +113,8 @@ void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)u64 val = irq->intid;bool allow_pending = true, is_v2_sgi; +WARN_ON (irq->on_lr); + is_v2_sgi = (vgic_irq_is_sgi (irq->intid) && model ==KVM_DEV_TYPE_ARM_VGIC_V2 );
@@ -185,6 +189,8 @@ void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr) val |= (u64 )irq->priority <<ICH_LR_PRIORITY_SHIFT ; vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[lr] = val; + + irq->on_lr = true; }void vgic_v3_clear_lr (struct kvm_vcpu *vcpu,int lr)
include/kvm/arm_vgic.h +1 -0
@@ -149,6 +149,7 @@ struct vgic_irq { bool enabled:1; bool active:1; bool hw:1; /* Tied to HW IRQ */ + bool on_lr:1; /* Present in a CPU LR */refcount_t refcount;/* Used for LPIs */ u32 hwintid;/* HW INTID number */ unsigned int host_irq;/* linux irq corresponding to hwintid */
Signature · 1 line
2.47.3
Marc Zyngier
maintainerPATCH v2 8/45 KVM: arm64: Add LR overflow handling documentation
In reply to Marc ZyngierAdd a bit of documentation describing how we are dealing with LR overflow. This is mostly a braindump of how things are expected to work. For now anyway.
--- arch/arm64/kvm/vgic/vgic.c | 81 +++++++++++++++++++++++++++++++++++++- 1 file changed, 80 insertions(+), 1 deletion(-)
arch/arm64/kvm/vgic/vgic.c +80 -1
@@ -825,7 +825,86 @@ static int compute_ap_list_depth(struct kvm_vcpu *vcpu,return count; } -/* Requires the VCPU's ap_list_lock to be held. */ +/* +* Dealing with LR overflow is close to black magic -- dress accordingly. +* +* We have to present an almost infinite number of interrupts through a very +* limited number of registers. Therefore crucial decisions must be made to +* ensure we feed the most relevant interrupts into the LRs, and yet have +* some facilities to let the guest interact with those that are not there. +* +* All considerations below are in the context of interrupts targeting a +* single vcpu with non-idle state (either pending, active, or both), +* colloquially called the ap_list: +* +* - Pending interrupts must have priority over active interrupts. This also +* excludes pending+active interrupts. This ensures that a guest can +* perform priority drops on any number of interrupts, and yet be +* presented the next pending one. +* +* - Deactivation of interrupts outside of the LRs must be tracked by using +* either the EOIcount-driven maintenance interrupt, and sometimes by +* trapping the DIR register. +* +* - For EOImode=0, a non-zero EOIcount means walking the ap_list past the +* point that made it into the LRs, and deactivate interrupts that would +* have made it onto the LRs if we had the space. +* +* - The MI-generation bits must be used to try and force an exit when the +* guest has done enough changes to the LRs that we want to reevaluate the +* situation: +* +* - if the total number of pending interrupts exceeds the number of +* LR, NPIE must be set in order to exit once no pending interrupts +* are present in the LRs, allowing us to populate the next batch. +* +* - if there are active interrupts outside of the LRs, then LRENPIE +* must be set so that we exit on deactivation of one of these, and +* work out which one is to be deactivated. Note that this is not +* enough to deal with EOImode=1, see below. +* +* - if the overall number of interrupts exceeds the number of LRs, +* then UIE must be set to allow refilling of the LRs once the +* majority of them has been processed. +* +* - as usual, MI triggers are only an optimisation, since we cannot +* rely on the MI being delivered in timely manner... +* +* - EOImode=1 creates some additional problems: +* +* - deactivation can happen in any order, and we cannot rely on +* EOImode=0's coupling of priority-drop and deactivation which +* imposes strict reverse Ack order. This means that DIR must be set +* if we have active interrupts outside of the LRs. +* +* - deactivation of SPIs can occur on any CPU, while the SPI is only +* present in the ap_list of the CPU that actually ack-ed it. In that +* case, EOIcount doesn't provide enough information, and we must +* resort to trapping DIR even if we don't overflow the LRs. Bonus +* point for not trapping DIR when no SPIs are pending or active in +* the whole VM. +* +* - LPIs do not suffer the same problem as SPIs on deactivation, as we +* have to essentially discard the active state, see below. +* +* - Virtual LPIs have an active state (surprise!), which gets removed on +* priority drop (EOI). However, EOIcount doesn't get bumped when the LPI +* is not present in the LR (surprise again!). Special care must therefore +* be taken to remove the active state from any activated LPI when exiting +* from the guest. This is in a way no different from what happens on the +* physical side. We still rely on the running priority to have been +* removed from the APRs, irrespective of the LPI being present in the LRs +* or not. +* +* - Virtual SGIs directly injected via GICv4.1 must not affect EOIcount, as +* they are not managed in SW and don't have a true active state. So only +* set vSGIEOICount when no SGIs are in the ap_list. +* +* - GICv2 SGIs with multiple sources are injected one source at a time, as +* if they were made pending sequentially. This may mean that we don't +* always present the HPPI if other interrupts with lower priority are +* pending in the LRs. Big deal. +*/ static void vgic_flush_lr_state (struct kvm_vcpu *vcpu) {struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
Signature · 1 line
2.47.3
Marc Zyngier
maintainerPATCH v2 9/45 KVM: arm64: GICv3: Drop LPI active state when folding LRs
In reply to Marc ZyngierDespite LPIs not having an active state, *virtual* LPIs do have one, which gets cleared on EOI. So far, so good.
However, this leads to a small problem: when an active LPI is not in the LRs, that EOImode==0 and that the guest EOIs it, EOIcount doesn't get bumped up. Which means that in these condition, the LPI would stay active forever.
Clearly, we can't have that. So if we spot an active LPI, we drop that state. It's pretty pointless anyway, and only serves as a way to trip SW over.
--- arch/arm64/kvm/vgic/vgic-v3.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
arch/arm64/kvm/vgic/vgic-v3.c +3 -1
@@ -72,7 +72,9 @@ void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)raw_spin_lock (&irq->irq_lock); -/* Always preserve the active bit, note deactivation */ +/* Always preserve the active bit for !LPIs, note deactivation */ +if (irq->intid >=VGIC_MIN_LPI ) + val &= ~ICH_LR_ACTIVE_BIT ; deactivated = irq->active && !(val &ICH_LR_ACTIVE_BIT ); irq->active = !!(val &ICH_LR_ACTIVE_BIT );
Signature · 1 line
2.47.3
Marc Zyngier
maintainerPATCH v2 10/45 KVM: arm64: GICv3: Preserve EOIcount on exit
In reply to Marc ZyngierEOIcount is how the virtual CPU interface signals that the guest is deactivating interrupts outside of the LRs when EOImode==0.
We therefore need to preserve that information so that we can find out what actually needs deactivating.
--- arch/arm64/kvm/hyp/vgic-v3-sr.c | 6 ++++++ 1 file changed, 6 insertions(+)
arch/arm64/kvm/hyp/vgic-v3-sr.c +6 -0
@@ -225,6 +225,12 @@ void __vgic_v3_save_state(struct vgic_v3_cpu_if *cpu_if) elrsr =read_gicreg (ICH_ELRSR_EL2 ); +if (cpu_if->vgic_hcr &ICH_HCR_EL2_LRENPIE ) { +u64 val =read_gicreg (ICH_HCR_EL2 ); + cpu_if->vgic_hcr &= ~ICH_HCR_EL2_EOIcount; + cpu_if->vgic_hcr |= val & ICH_HCR_EL2_EOIcount; + } +write_gicreg (compute_ich_hcr (cpu_if) & ~ICH_HCR_EL2_En,ICH_HCR_EL2 );for (i =0 ; i < used_lrs; i++) {
Signature · 1 line
2.47.3
Marc Zyngier
maintainerPATCH v2 11/45 KVM: arm64: GICv3: Decouple ICH_HCR_EL2 programming from LRs
In reply to Marc ZyngierNot programming ICH_HCR_EL2 while no LRs are populated is a bit of an issue, as we otherwise don't see any maintenance interrupt when the guest interacts with the LRs.
Decouple the two and always program the control register, even when we don't have to touch the LRs.
--- arch/arm64/kvm/hyp/vgic-v3-sr.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-)
arch/arm64/kvm/hyp/vgic-v3-sr.c +12 -14
@@ -219,20 +219,12 @@ void __vgic_v3_save_state(struct vgic_v3_cpu_if *cpu_if) } } -if (used_lrs || cpu_if->its_vpe.its_vm) { +if (used_lrs) {int i;u32 elrsr; elrsr =read_gicreg (ICH_ELRSR_EL2 ); -if (cpu_if->vgic_hcr &ICH_HCR_EL2_LRENPIE ) { -u64 val =read_gicreg (ICH_HCR_EL2 ); - cpu_if->vgic_hcr &= ~ICH_HCR_EL2_EOIcount; - cpu_if->vgic_hcr |= val & ICH_HCR_EL2_EOIcount; - } - -write_gicreg (compute_ich_hcr (cpu_if) & ~ICH_HCR_EL2_En,ICH_HCR_EL2 ); -for (i =0 ; i < used_lrs; i++) {if (elrsr & (1 << i)) cpu_if->vgic_lr[i] &= ~ICH_LR_STATE ;
@@ -242,6 +234,14 @@ void __vgic_v3_save_state(struct vgic_v3_cpu_if *cpu_if)__gic_v3_set_lr (0 , i); } } + +if (cpu_if->vgic_hcr &ICH_HCR_EL2_LRENPIE ) { +u64 val =read_gicreg (ICH_HCR_EL2 ); + cpu_if->vgic_hcr &= ~ICH_HCR_EL2_EOIcount; + cpu_if->vgic_hcr |= val & ICH_HCR_EL2_EOIcount; + } + +write_gicreg (compute_ich_hcr (cpu_if) & ~ICH_HCR_EL2_En,ICH_HCR_EL2 ); }void __vgic_v3_restore_state (struct vgic_v3_cpu_if *cpu_if)
@@ -249,12 +249,10 @@ void __vgic_v3_restore_state(struct vgic_v3_cpu_if *cpu_if)u64 used_lrs = cpu_if->used_lrs;int i; -if (used_lrs || cpu_if->its_vpe.its_vm) { -write_gicreg (compute_ich_hcr (cpu_if),ICH_HCR_EL2 ); +write_gicreg (compute_ich_hcr (cpu_if),ICH_HCR_EL2 ); -for (i =0 ; i < used_lrs; i++) -__gic_v3_set_lr (cpu_if->vgic_lr[i], i); - } +for (i =0 ; i < used_lrs; i++) +__gic_v3_set_lr (cpu_if->vgic_lr[i], i);/* * Ensure that writes to the LRs, and on non-VHE systems ensure that
Signature · 1 line
2.47.3
Marc Zyngier
maintainerPATCH v2 12/45 KVM: arm64: GICv3: Extract LR folding primitive
In reply to Marc ZyngierAs we are going to need to handle deactivation for interrupts that are not in the LRs, split vgic_v3_fold_lr_state() into a helper that deals with a single interrupt, and the function that loops over the used LRs.
--- arch/arm64/kvm/vgic/vgic-v3.c | 88 +++++++++++++++++------------------ 1 file changed, 43 insertions(+), 45 deletions(-)
arch/arm64/kvm/vgic/vgic-v3.c +43 -45
@@ -33,78 +33,76 @@ static bool lr_signals_eoi_mi(u64 lr_val) !(lr_val &ICH_LR_HW ); } -void vgic_v3_fold_lr_state (struct kvm_vcpu *vcpu) +static void vgic_v3_fold_lr (struct kvm_vcpu *vcpu,u64 val) { -struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu; -struct vgic_v3_cpu_if *cpuif = &vgic_cpu->vgic_v3; -u32 model = vcpu->kvm->arch.vgic.vgic_model; -int lr; - -DEBUG_SPINLOCK_BUG_ON (!irqs_disabled ()); - - cpuif->vgic_hcr &= ~ICH_HCR_EL2_UIE ; - -for (lr =0 ; lr < cpuif->used_lrs; lr++) { -u64 val = cpuif->vgic_lr[lr]; -u32 intid, cpuid; -struct vgic_irq *irq; -bool is_v2_sgi = false; -bool deactivated; - - cpuid = val &GICH_LR_PHYSID_CPUID ; - cpuid >>=GICH_LR_PHYSID_CPUID_SHIFT ; - -if (model ==KVM_DEV_TYPE_ARM_VGIC_V3 ) { - intid = val &ICH_LR_VIRTUAL_ID_MASK ; - }else { - intid = val &GICH_LR_VIRTUALID ; - is_v2_sgi =vgic_irq_is_sgi (intid); - } +struct vgic_irq *irq; +bool is_v2_sgi = false; +bool deactivated; +u32 intid; -/* Notify fds when the guest EOI'ed a level-triggered IRQ */ -if (lr_signals_eoi_mi (val) &&vgic_valid_spi (vcpu->kvm, intid)) -kvm_notify_acked_irq (vcpu->kvm,0 , - intid -VGIC_NR_PRIVATE_IRQS ); +if (vcpu->kvm->arch.vgic.vgic_model ==KVM_DEV_TYPE_ARM_VGIC_V3 ) { + intid = val &ICH_LR_VIRTUAL_ID_MASK ; + }else { + intid = val &GICH_LR_VIRTUALID ; + is_v2_sgi =vgic_irq_is_sgi (intid); + } - irq =vgic_get_vcpu_irq (vcpu, intid); -if (!irq)/* An LPI could have been unmapped. */ -continue ; + irq =vgic_get_vcpu_irq (vcpu, intid); +if (!irq)/* An LPI could have been unmapped. */ +return ; -raw_spin_lock (&irq->irq_lock); +/* Notify fds when the guest EOI'ed a level-triggered IRQ */ +if (lr_signals_eoi_mi (val) &&vgic_valid_spi (vcpu->kvm, intid)) +kvm_notify_acked_irq (vcpu->kvm,0 , + intid -VGIC_NR_PRIVATE_IRQS ); + scoped_guard(raw_spinlock, &irq->irq_lock) {/* Always preserve the active bit for !LPIs, note deactivation */ if (irq->intid >=VGIC_MIN_LPI ) val &= ~ICH_LR_ACTIVE_BIT ; deactivated = irq->active && !(val &ICH_LR_ACTIVE_BIT ); irq->active = !!(val &ICH_LR_ACTIVE_BIT ); -if (irq->active && is_v2_sgi) - irq->active_source = cpuid; -/* Edge is the only case where we preserve the pending bit */ if (irq->config ==VGIC_CONFIG_EDGE && - (val &ICH_LR_PENDING_BIT )) { + (val &ICH_LR_PENDING_BIT )) irq->pending_latch = true; -if (is_v2_sgi) - irq->source |= (1 << cpuid); - } -/* * Clear soft pending state when level irqs have been acked. */ if (irq->config ==VGIC_CONFIG_LEVEL && !(val &ICH_LR_STATE )) irq->pending_latch = false; +if (is_v2_sgi) { +u8 cpuid =FIELD_GET (GICH_LR_PHYSID_CPUID , val); + +if (irq->active) + irq->active_source = cpuid; + +if (val &ICH_LR_PENDING_BIT ) + irq->source |=BIT (cpuid); + } +/* Handle resampling for mapped interrupts if required */ vgic_irq_handle_resampling (irq, deactivated, val &ICH_LR_PENDING_BIT ); irq->on_lr = false; - -raw_spin_unlock (&irq->irq_lock); -vgic_put_irq (vcpu->kvm, irq); } +vgic_put_irq (vcpu->kvm, irq); +} + +void vgic_v3_fold_lr_state (struct kvm_vcpu *vcpu) +{ +struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu; +struct vgic_v3_cpu_if *cpuif = &vgic_cpu->vgic_v3; + +DEBUG_SPINLOCK_BUG_ON (!irqs_disabled ()); + +for (int lr =0 ; lr < cpuif->used_lrs; lr++) +vgic_v3_fold_lr (vcpu, cpuif->vgic_lr[lr]); + cpuif->used_lrs =0 ; }
Signature · 1 line
2.47.3
Re: [PATCH v2 12/45] KVM: arm64: GICv3: Extract LR folding primitive
Quoted 64 lines · Marc Zyngier
As we are going to need to handle deactivation for interrupts that are not in the LRs, split
vgic_v3_fold_lr_state()into a helper that deals with a single interrupt, and the function that loops over the used LRs.Signed-off-by Marc Zyngier <[email protected]>--- arch/arm64/kvm/vgic/vgic-v3.c | 88 +++++++++++++++++------------------ 1 file changed, 43 insertions(+), 45 deletions(-)arch/arm64/kvm/vgic/vgic-v3.c +11
-32@@ -33,78 +33,76 @@ static bool lr_signals_eoi_mi(u64 lr_val) !(lr_val &ICH_LR_HW ); } -void vgic_v3_fold_lr_state (struct kvm_vcpu *vcpu) +static void vgic_v3_fold_lr (struct kvm_vcpu *vcpu,u64 val) { -struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu; -struct vgic_v3_cpu_if *cpuif = &vgic_cpu->vgic_v3; -u32 model = vcpu->kvm->arch.vgic.vgic_model; -int lr; - -DEBUG_SPINLOCK_BUG_ON (!irqs_disabled ()); - - cpuif->vgic_hcr &= ~ICH_HCR_EL2_UIE ; - -for (lr =0 ; lr < cpuif->used_lrs; lr++) { -u64 val = cpuif->vgic_lr[lr]; -u32 intid, cpuid; -struct vgic_irq *irq; -bool is_v2_sgi = false; -bool deactivated; - - cpuid = val &GICH_LR_PHYSID_CPUID ; - cpuid >>=GICH_LR_PHYSID_CPUID_SHIFT ; - -if (model ==KVM_DEV_TYPE_ARM_VGIC_V3 ) { - intid = val &ICH_LR_VIRTUAL_ID_MASK ; - }else { - intid = val &GICH_LR_VIRTUALID ; - is_v2_sgi =vgic_irq_is_sgi (intid); - } +struct vgic_irq *irq; +bool is_v2_sgi = false; +bool deactivated; +u32 intid; -/* Notify fds when the guest EOI'ed a level-triggered IRQ */ -if (lr_signals_eoi_mi (val) &&vgic_valid_spi (vcpu->kvm, intid)) -kvm_notify_acked_irq (vcpu->kvm,0 , - intid -VGIC_NR_PRIVATE_IRQS ); +if (vcpu->kvm->arch.vgic.vgic_model ==KVM_DEV_TYPE_ARM_VGIC_V3 ) { + intid = val &ICH_LR_VIRTUAL_ID_MASK ; + }else { + intid = val &GICH_LR_VIRTUALID ; + is_v2_sgi =vgic_irq_is_sgi (intid); + } - irq =vgic_get_vcpu_irq (vcpu, intid); -if (!irq)/* An LPI could have been unmapped. */
arch/arm64/kvm/vgic/vgic-v3.c static bool lr_signals_eoi_mi(u64 lr_val) · line 57
Quoted 10 lines
arch/arm64/kvm/vgic/vgic-v3.c +7
-2-continue ; + irq =vgic_get_vcpu_irq (vcpu, intid); +if (!irq)/* An LPI could have been unmapped. */ +return ; -raw_spin_lock (&irq->irq_lock); +/* Notify fds when the guest EOI'ed a level-triggered IRQ */ +if (lr_signals_eoi_mi (val) &&vgic_valid_spi (vcpu->kvm, intid)) +kvm_notify_acked_irq (vcpu->kvm,0 , + intid -VGIC_NR_PRIVATE_IRQS );
The fds notifiy happens before checking irq's mapping before this patch, and now in reversal order w/ above change. It's fine for vLPI, and for vSPI no necessary call kvm_notify_acked_irq() if the it has been remapped, no gsi<->pin mapping there. Is above understanding correct ?
Quoted 64 lines
arch/arm64/kvm/vgic/vgic-v3.c +25
-12+ scoped_guard(raw_spinlock, &irq->irq_lock) {/* Always preserve the active bit for !LPIs, note deactivation */ if (irq->intid >=VGIC_MIN_LPI ) val &= ~ICH_LR_ACTIVE_BIT ; deactivated = irq->active && !(val &ICH_LR_ACTIVE_BIT ); irq->active = !!(val &ICH_LR_ACTIVE_BIT ); -if (irq->active && is_v2_sgi) - irq->active_source = cpuid; -/* Edge is the only case where we preserve the pending bit */ if (irq->config ==VGIC_CONFIG_EDGE && - (val &ICH_LR_PENDING_BIT )) { + (val &ICH_LR_PENDING_BIT )) irq->pending_latch = true; -if (is_v2_sgi) - irq->source |= (1 << cpuid); - } -/* * Clear soft pending state when level irqs have been acked. */ if (irq->config ==VGIC_CONFIG_LEVEL && !(val &ICH_LR_STATE )) irq->pending_latch = false; +if (is_v2_sgi) { +u8 cpuid =FIELD_GET (GICH_LR_PHYSID_CPUID , val); + +if (irq->active) + irq->active_source = cpuid; + +if (val &ICH_LR_PENDING_BIT ) + irq->source |=BIT (cpuid); + } +/* Handle resampling for mapped interrupts if required */ vgic_irq_handle_resampling (irq, deactivated, val &ICH_LR_PENDING_BIT ); irq->on_lr = false; - -raw_spin_unlock (&irq->irq_lock); -vgic_put_irq (vcpu->kvm, irq); } +vgic_put_irq (vcpu->kvm, irq); +} + +void vgic_v3_fold_lr_state (struct kvm_vcpu *vcpu) +{ +struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu; +struct vgic_v3_cpu_if *cpuif = &vgic_cpu->vgic_v3; + +DEBUG_SPINLOCK_BUG_ON (!irqs_disabled ()); + +for (int lr =0 ; lr < cpuif->used_lrs; lr++) +vgic_v3_fold_lr (vcpu, cpuif->vgic_lr[lr]); + cpuif->used_lrs =0 ; } --2.47.3
Marc Zyngier
maintainerRe: [PATCH v2 12/45] KVM: arm64: GICv3: Extract LR folding primitive
Quoted 71 lines · Yao Yuan
Quoted 69 lines · Marc Zyngier
As we are going to need to handle deactivation for interrupts that are not in the LRs, split
vgic_v3_fold_lr_state()into a helper that deals with a single interrupt, and the function that loops over the used LRs.Signed-off-by Marc Zyngier <[email protected]>--- arch/arm64/kvm/vgic/vgic-v3.c | 88 +++++++++++++++++------------------ 1 file changed, 43 insertions(+), 45 deletions(-)arch/arm64/kvm/vgic/vgic-v3.c +14
-33@@ -33,78 +33,76 @@ static bool lr_signals_eoi_mi(u64 lr_val) !(lr_val &ICH_LR_HW ); } -void vgic_v3_fold_lr_state (struct kvm_vcpu *vcpu) +static void vgic_v3_fold_lr (struct kvm_vcpu *vcpu,u64 val) { -struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu; -struct vgic_v3_cpu_if *cpuif = &vgic_cpu->vgic_v3; -u32 model = vcpu->kvm->arch.vgic.vgic_model; -int lr; - -DEBUG_SPINLOCK_BUG_ON (!irqs_disabled ()); - - cpuif->vgic_hcr &= ~ICH_HCR_EL2_UIE ; - -for (lr =0 ; lr < cpuif->used_lrs; lr++) { -u64 val = cpuif->vgic_lr[lr]; -u32 intid, cpuid; -struct vgic_irq *irq; -bool is_v2_sgi = false; -bool deactivated; - - cpuid = val &GICH_LR_PHYSID_CPUID ; - cpuid >>=GICH_LR_PHYSID_CPUID_SHIFT ; - -if (model ==KVM_DEV_TYPE_ARM_VGIC_V3 ) { - intid = val &ICH_LR_VIRTUAL_ID_MASK ; - }else { - intid = val &GICH_LR_VIRTUALID ; - is_v2_sgi =vgic_irq_is_sgi (intid); - } +struct vgic_irq *irq; +bool is_v2_sgi = false; +bool deactivated; +u32 intid; -/* Notify fds when the guest EOI'ed a level-triggered IRQ */ -if (lr_signals_eoi_mi (val) &&vgic_valid_spi (vcpu->kvm, intid)) -kvm_notify_acked_irq (vcpu->kvm,0 , - intid -VGIC_NR_PRIVATE_IRQS ); +if (vcpu->kvm->arch.vgic.vgic_model ==KVM_DEV_TYPE_ARM_VGIC_V3 ) { + intid = val &ICH_LR_VIRTUAL_ID_MASK ; + }else { + intid = val &GICH_LR_VIRTUALID ; + is_v2_sgi =vgic_irq_is_sgi (intid); + } - irq =vgic_get_vcpu_irq (vcpu, intid); -if (!irq)/* An LPI could have been unmapped. */ -continue ; + irq =vgic_get_vcpu_irq (vcpu, intid); +if (!irq)/* An LPI could have been unmapped. */ +return ;
Quoted 11 lines
arch/arm64/kvm/vgic/vgic-v3.c static bool lr_signals_eoi_mi(u64 lr_val) · line 57
Quoted 5 lines
arch/arm64/kvm/vgic/vgic-v3.c +4
-1-raw_spin_lock (&irq->irq_lock); +/* Notify fds when the guest EOI'ed a level-triggered IRQ */ +if (lr_signals_eoi_mi (val) &&vgic_valid_spi (vcpu->kvm, intid)) +kvm_notify_acked_irq (vcpu->kvm,0 , + intid -VGIC_NR_PRIVATE_IRQS );The fds notifiy happens before checking irq's mapping before this patch, and now in reversal order w/ above change. It's fine for vLPI, and for vSPI no necessary call
kvm_notify_acked_irq()if the it has been remapped, no gsi<->pin mapping there. Is above understanding correct ?
We can only notify an irqfd for an SPI, never for an LPI. Given that only looking up an LPI can result in a NULL pointer (if it has been concurrently removed), this change is immaterial
This results in something that is easier to understand, as I find it more logical to weed out the error cases first before taking any significant action.
Thanks,
M.
Signature · 1 line
Without deviation from the norm, progress is not possible.
Re: [PATCH v2 12/45] KVM: arm64: GICv3: Extract LR folding primitive
Quoted 73 lines · Marc Zyngier
Quoted 71 lines · Yao Yuan
Quoted 69 lines · Marc Zyngier
As we are going to need to handle deactivation for interrupts that are not in the LRs, split
vgic_v3_fold_lr_state()into a helper that deals with a single interrupt, and the function that loops over the used LRs.Signed-off-by Marc Zyngier <[email protected]>--- arch/arm64/kvm/vgic/vgic-v3.c | 88 +++++++++++++++++------------------ 1 file changed, 43 insertions(+), 45 deletions(-)arch/arm64/kvm/vgic/vgic-v3.c +14
-33@@ -33,78 +33,76 @@ static bool lr_signals_eoi_mi(u64 lr_val) !(lr_val &ICH_LR_HW ); } -void vgic_v3_fold_lr_state (struct kvm_vcpu *vcpu) +static void vgic_v3_fold_lr (struct kvm_vcpu *vcpu,u64 val) { -struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu; -struct vgic_v3_cpu_if *cpuif = &vgic_cpu->vgic_v3; -u32 model = vcpu->kvm->arch.vgic.vgic_model; -int lr; - -DEBUG_SPINLOCK_BUG_ON (!irqs_disabled ()); - - cpuif->vgic_hcr &= ~ICH_HCR_EL2_UIE ; - -for (lr =0 ; lr < cpuif->used_lrs; lr++) { -u64 val = cpuif->vgic_lr[lr]; -u32 intid, cpuid; -struct vgic_irq *irq; -bool is_v2_sgi = false; -bool deactivated; - - cpuid = val &GICH_LR_PHYSID_CPUID ; - cpuid >>=GICH_LR_PHYSID_CPUID_SHIFT ; - -if (model ==KVM_DEV_TYPE_ARM_VGIC_V3 ) { - intid = val &ICH_LR_VIRTUAL_ID_MASK ; - }else { - intid = val &GICH_LR_VIRTUALID ; - is_v2_sgi =vgic_irq_is_sgi (intid); - } +struct vgic_irq *irq; +bool is_v2_sgi = false; +bool deactivated; +u32 intid; -/* Notify fds when the guest EOI'ed a level-triggered IRQ */ -if (lr_signals_eoi_mi (val) &&vgic_valid_spi (vcpu->kvm, intid)) -kvm_notify_acked_irq (vcpu->kvm,0 , - intid -VGIC_NR_PRIVATE_IRQS ); +if (vcpu->kvm->arch.vgic.vgic_model ==KVM_DEV_TYPE_ARM_VGIC_V3 ) { + intid = val &ICH_LR_VIRTUAL_ID_MASK ; + }else { + intid = val &GICH_LR_VIRTUALID ; + is_v2_sgi =vgic_irq_is_sgi (intid); + } - irq =vgic_get_vcpu_irq (vcpu, intid); -if (!irq)/* An LPI could have been unmapped. */ -continue ; + irq =vgic_get_vcpu_irq (vcpu, intid); +if (!irq)/* An LPI could have been unmapped. */ +return ;
Quoted 10 lines
Quoted 10 lines
arch/arm64/kvm/vgic/vgic-v3.c static bool lr_signals_eoi_mi(u64 lr_val) · line 57
Quoted 5 lines
arch/arm64/kvm/vgic/vgic-v3.c +4
-1-raw_spin_lock (&irq->irq_lock); +/* Notify fds when the guest EOI'ed a level-triggered IRQ */ +if (lr_signals_eoi_mi (val) &&vgic_valid_spi (vcpu->kvm, intid)) +kvm_notify_acked_irq (vcpu->kvm,0 , + intid -VGIC_NR_PRIVATE_IRQS );The fds notifiy happens before checking irq's mapping before this patch, and now in reversal order w/ above change. It's fine for vLPI, and for vSPI no necessary call
kvm_notify_acked_irq()if the it has been remapped, no
Oops.. I want to say "and for vSPI no necessary call kvm_notify_acked_irq() if it has been unmapped...".
Quoted 6 lines
Quoted 1 line
gsi<->pin mapping there. Is above understanding correct ?
We can only notify an irqfd for an SPI, never for an LPI. Given that
only looking up an LPI can result in a NULL pointer (if it has been concurrently removed), this change is immaterial
You're right. The spis is allocated in vgic_init().
Quoted 4 lines
This results in something that is easier to understand, as I find it more logical to weed out the error cases first before taking any significant action.
Yes, this makes the code better than beforem and thanks for your explanation!
Quoted 7 lines
Thanks,
M.--
Without deviation from the norm, progress is not possible.
Marc Zyngier
maintainerPATCH v2 13/45 KVM: arm64: GICv3: Extract LR computing primitive
In reply to Marc ZyngierSplit vgic_v3_populate_lr() into two, so that we have another primitive that computes the LR from a vgic_irq, but doesn't update anything in the shadow structure.
--- arch/arm64/kvm/vgic/vgic-v3.c | 49 +++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 17 deletions(-)
arch/arm64/kvm/vgic/vgic-v3.c +32 -17
@@ -107,7 +107,7 @@ void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu) }/* Requires the irq to be locked already */ -void vgic_v3_populate_lr (struct kvm_vcpu *vcpu,struct vgic_irq *irq,int lr) +static u64 vgic_v3_compute_lr (struct kvm_vcpu *vcpu,struct vgic_irq *irq) {u32 model = vcpu->kvm->arch.vgic.vgic_model;u64 val = irq->intid;
@@ -154,6 +154,35 @@ void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)if (allow_pending &&irq_is_pending (irq)) { val |=ICH_LR_PENDING_BIT ; +if (is_v2_sgi) { +u32 src =ffs (irq->source); + +if (WARN_RATELIMIT (!src,"No SGI source for INTID %d\n" , + irq->intid)) +return 0 ; + + val |= (src -1 ) <<GICH_LR_PHYSID_CPUID_SHIFT ; +if (irq->source & ~BIT (src -1 )) + val |=ICH_LR_EOI ; + } + } + +if (irq->group) + val |=ICH_LR_GROUP ; + + val |= (u64 )irq->priority <<ICH_LR_PRIORITY_SHIFT ; + +return val; +} + +void vgic_v3_populate_lr (struct kvm_vcpu *vcpu,struct vgic_irq *irq,int lr) +{ +u32 model = vcpu->kvm->arch.vgic.vgic_model; +u64 val =vgic_v3_compute_lr (vcpu, irq); + + vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[lr] = val; + +if (val &ICH_LR_PENDING_BIT ) {if (irq->config ==VGIC_CONFIG_EDGE ) irq->pending_latch = false;
@@ -161,16 +190,9 @@ void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr) model == KVM_DEV_TYPE_ARM_VGIC_V2) {u32 src =ffs (irq->source); -if (WARN_RATELIMIT (!src,"No SGI source for INTID %d\n" , - irq->intid)) -return ; - - val |= (src -1 ) <<GICH_LR_PHYSID_CPUID_SHIFT ; - irq->source &= ~(1 << (src -1 )); -if (irq->source) { + irq->source &= ~BIT (src -1 ); +if (irq->source) irq->pending_latch = true; - val |=ICH_LR_EOI ; - } } }
@@ -183,13 +205,6 @@ void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)if (vgic_irq_is_mapped_level (irq) && (val &ICH_LR_PENDING_BIT )) irq->line_level = false; -if (irq->group) - val |=ICH_LR_GROUP ; - - val |= (u64 )irq->priority <<ICH_LR_PRIORITY_SHIFT ; - - vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[lr] = val; - irq->on_lr = true; }
Signature · 1 line
2.47.3
Marc Zyngier
maintainerPATCH v2 14/45 KVM: arm64: GICv2: Preserve EOIcount on exit
In reply to Marc ZyngierEOIcount is how the virtual CPU interface signals that the guest is deactivating interrupts outside of the LRs when EOImode==0.
We therefore need to preserve that information so that we can find out what actually needs deactivating, just like we already do on GICv3.
--- arch/arm64/kvm/vgic/vgic-v2.c | 6 ++++++ 1 file changed, 6 insertions(+)
arch/arm64/kvm/vgic/vgic-v2.c +6 -0
@@ -437,6 +437,12 @@ void vgic_v2_save_state(struct kvm_vcpu *vcpu)return ;if (used_lrs) { +if (vcpu->arch.vgic_cpu.vgic_v2.vgic_hcr &GICH_HCR_LRENPIE ) { +u32 val =readl_relaxed (base +GICH_HCR ); + + vcpu->arch.vgic_cpu.vgic_v2.vgic_hcr &= ~GICH_HCR_EOICOUNT ; + vcpu->arch.vgic_cpu.vgic_v2.vgic_hcr |= val &GICH_HCR_EOICOUNT ; + }save_lrs (vcpu, base);writel_relaxed (0 , base +GICH_HCR ); }
Signature · 1 line
2.47.3
Marc Zyngier
maintainerPATCH v2 15/45 KVM: arm64: GICv2: Decouple GICH_HCR programming from LRs being loaded
In reply to Marc ZyngierNot programming GICH_HCR while no LRs are populated is a bit of an issue, as we otherwise don't see any maintenance interrupt when the guest interacts with the LRs.
Decouple the two and always program the control register, even when we don't have to touch the LRs.
This is very similar to what we are already doing for GICv3.
--- arch/arm64/kvm/vgic/vgic-v2.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-)
arch/arm64/kvm/vgic/vgic-v2.c +14 -14
@@ -430,22 +430,25 @@ static void save_lrs(struct kvm_vcpu *vcpu, void __iomem *base)void vgic_v2_save_state (struct kvm_vcpu *vcpu) { +struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;void __iomem *base = kvm_vgic_global_state.vctrl_base;u64 used_lrs = vcpu->arch.vgic_cpu.vgic_v2.used_lrs;if (!base)return ; -if (used_lrs) { -if (vcpu->arch.vgic_cpu.vgic_v2.vgic_hcr &GICH_HCR_LRENPIE ) { -u32 val =readl_relaxed (base +GICH_HCR ); - vcpu->arch.vgic_cpu.vgic_v2.vgic_hcr &= ~GICH_HCR_EOICOUNT ; - vcpu->arch.vgic_cpu.vgic_v2.vgic_hcr |= val &GICH_HCR_EOICOUNT ; - } +if (used_lrs)save_lrs (vcpu, base); -writel_relaxed (0 , base +GICH_HCR ); + +if (cpu_if->vgic_hcr &GICH_HCR_LRENPIE ) { +u32 val =readl_relaxed (base +GICH_HCR ); + + cpu_if->vgic_hcr &= ~GICH_HCR_EOICOUNT ; + cpu_if->vgic_hcr |= val &GICH_HCR_EOICOUNT ; } + +writel_relaxed (0 , base +GICH_HCR ); }void vgic_v2_restore_state (struct kvm_vcpu *vcpu)
@@ -458,13 +461,10 @@ void vgic_v2_restore_state(struct kvm_vcpu *vcpu)if (!base)return ; -if (used_lrs) { -writel_relaxed (cpu_if->vgic_hcr, base +GICH_HCR ); -for (i =0 ; i < used_lrs; i++) { -writel_relaxed (cpu_if->vgic_lr[i], - base +GICH_LR0 + (i *4 )); - } - } +writel_relaxed (cpu_if->vgic_hcr, base +GICH_HCR ); + +for (i =0 ; i < used_lrs; i++) +writel_relaxed (cpu_if->vgic_lr[i], base +GICH_LR0 + (i *4 )); }void vgic_v2_load (struct kvm_vcpu *vcpu)
Signature · 1 line
2.47.3
Marc Zyngier
maintainerPATCH v2 16/45 KVM: arm64: GICv2: Extract LR folding primitive
In reply to Marc ZyngierAs we are going to need to handle deactivation for interrupts that are not in the LRs, split vgic_v2_fold_lr_state() into a helper that deals with a single interrupt, and the function that loops over the used LRs.
--- arch/arm64/kvm/vgic/vgic-v2.c | 67 +++++++++++++++++------------------ 1 file changed, 32 insertions(+), 35 deletions(-)
arch/arm64/kvm/vgic/vgic-v2.c +32 -35
@@ -39,43 +39,23 @@ static bool lr_signals_eoi_mi(u32 lr_val) !(lr_val &GICH_LR_HW ); } -/* -* transfer the content of the LRs back into the corresponding ap_list: -* - active bit is transferred as is -* - pending bit is -* - transferred as is in case of edge sensitive IRQs -* - set to the line-level (resample time) for level sensitive IRQs -*/ -void vgic_v2_fold_lr_state (struct kvm_vcpu *vcpu) +static void vgic_v2_fold_lr (struct kvm_vcpu *vcpu,u32 val) { -struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu; -struct vgic_v2_cpu_if *cpuif = &vgic_cpu->vgic_v2; -int lr; - -DEBUG_SPINLOCK_BUG_ON (!irqs_disabled ()); - - cpuif->vgic_hcr &= ~GICH_HCR_UIE ; +u32 cpuid, intid = val &GICH_LR_VIRTUALID ; +struct vgic_irq *irq; +bool deactivated; -for (lr =0 ; lr < vgic_cpu->vgic_v2.used_lrs; lr++) { -u32 val = cpuif->vgic_lr[lr]; -u32 cpuid, intid = val &GICH_LR_VIRTUALID ; -struct vgic_irq *irq; -bool deactivated; +/* Extract the source vCPU id from the LR */ + cpuid =FIELD_GET (GICH_LR_PHYSID_CPUID , val) &7 ; -/* Extract the source vCPU id from the LR */ - cpuid = val &GICH_LR_PHYSID_CPUID ; - cpuid >>=GICH_LR_PHYSID_CPUID_SHIFT ; - cpuid &=7 ; +/* Notify fds when the guest EOI'ed a level-triggered SPI */ +if (lr_signals_eoi_mi (val) &&vgic_valid_spi (vcpu->kvm, intid)) +kvm_notify_acked_irq (vcpu->kvm,0 , + intid -VGIC_NR_PRIVATE_IRQS ); -/* Notify fds when the guest EOI'ed a level-triggered SPI */ -if (lr_signals_eoi_mi (val) &&vgic_valid_spi (vcpu->kvm, intid)) -kvm_notify_acked_irq (vcpu->kvm,0 , - intid -VGIC_NR_PRIVATE_IRQS ); - - irq =vgic_get_vcpu_irq (vcpu, intid); - -raw_spin_lock (&irq->irq_lock); + irq =vgic_get_vcpu_irq (vcpu, intid); + scoped_guard(raw_spinlock, &irq->irq_lock) {/* Always preserve the active bit, note deactivation */ deactivated = irq->active && !(val &GICH_LR_ACTIVE_BIT ); irq->active = !!(val &GICH_LR_ACTIVE_BIT );
@@ -102,11 +82,28 @@ void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu)vgic_irq_handle_resampling (irq, deactivated, val &GICH_LR_PENDING_BIT ); irq->on_lr = false; - -raw_spin_unlock (&irq->irq_lock); -vgic_put_irq (vcpu->kvm, irq); } +vgic_put_irq (vcpu->kvm, irq); +} + +/* +* transfer the content of the LRs back into the corresponding ap_list: +* - active bit is transferred as is +* - pending bit is +* - transferred as is in case of edge sensitive IRQs +* - set to the line-level (resample time) for level sensitive IRQs +*/ +void vgic_v2_fold_lr_state (struct kvm_vcpu *vcpu) +{ +struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu; +struct vgic_v2_cpu_if *cpuif = &vgic_cpu->vgic_v2; + +DEBUG_SPINLOCK_BUG_ON (!irqs_disabled ()); + +for (int lr =0 ; lr < vgic_cpu->vgic_v2.used_lrs; lr++) +vgic_v2_fold_lr (vcpu, cpuif->vgic_lr[lr]); + cpuif->used_lrs =0 ; }
Signature · 1 line
2.47.3
Marc Zyngier
maintainerPATCH v2 17/45 KVM: arm64: GICv2: Extract LR computing primitive
In reply to Marc ZyngierSplit vgic_v2_populate_lr() into two helpers, so that we have another primitive that computes the LR from a vgic_irq, but doesn't update anything in the shadow structure.
--- arch/arm64/kvm/vgic/vgic-v2.c | 61 ++++++++++++++++++++++------------- 1 file changed, 39 insertions(+), 22 deletions(-)
arch/arm64/kvm/vgic/vgic-v2.c +39 -22
@@ -107,18 +107,7 @@ void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu) cpuif->used_lrs =0 ; } -/* -* Populates the particular LR with the state of a given IRQ: -* - for an edge sensitive IRQ the pending state is cleared in struct vgic_irq -* - for a level sensitive IRQ the pending state value is unchanged; -* it is dictated directly by the input level -* -* If @irq describes an SGI with multiple sources, we choose the -* lowest-numbered source VCPU and clear that bit in the source bitmap. -* -* The irq_lock must be held by the caller. -*/ -void vgic_v2_populate_lr (struct kvm_vcpu *vcpu,struct vgic_irq *irq,int lr) +static u32 vgic_v2_compute_lr (struct kvm_vcpu *vcpu,struct vgic_irq *irq) {u32 val = irq->intid;bool allow_pending = true;
@@ -164,22 +153,52 @@ void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)if (allow_pending &&irq_is_pending (irq)) { val |=GICH_LR_PENDING_BIT ; -if (irq->config ==VGIC_CONFIG_EDGE ) - irq->pending_latch = false; -if (vgic_irq_is_sgi (irq->intid)) {u32 src =ffs (irq->source);if (WARN_RATELIMIT (!src,"No SGI source for INTID %d\n" , irq->intid)) -return ; +return 0 ; val |= (src -1 ) <<GICH_LR_PHYSID_CPUID_SHIFT ; - irq->source &= ~(1 << (src -1 )); -if (irq->source) { - irq->pending_latch = true; +if (irq->source & ~BIT (src -1 )) val |=GICH_LR_EOI ; - } + } + } + +/* The GICv2 LR only holds five bits of priority. */ + val |= (irq->priority >>3 ) <<GICH_LR_PRIORITY_SHIFT ; + +return val; +} + +/* +* Populates the particular LR with the state of a given IRQ: +* - for an edge sensitive IRQ the pending state is cleared in struct vgic_irq +* - for a level sensitive IRQ the pending state value is unchanged; +* it is dictated directly by the input level +* +* If @irq describes an SGI with multiple sources, we choose the +* lowest-numbered source VCPU and clear that bit in the source bitmap. +* +* The irq_lock must be held by the caller. +*/ +void vgic_v2_populate_lr (struct kvm_vcpu *vcpu,struct vgic_irq *irq,int lr) +{ +u32 val =vgic_v2_compute_lr (vcpu, irq); + + vcpu->arch.vgic_cpu.vgic_v2.vgic_lr[lr] = val; + +if (val &GICH_LR_PENDING_BIT ) { +if (irq->config ==VGIC_CONFIG_EDGE ) + irq->pending_latch = false; + +if (vgic_irq_is_sgi (irq->intid)) { +u32 src =ffs (irq->source); + + irq->source &= ~BIT (src -1 ); +if (irq->source) + irq->pending_latch = true; } }
@@ -196,8 +215,6 @@ void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr) val |= (irq->priority >>3 ) <<GICH_LR_PRIORITY_SHIFT ; irq->on_lr = true; - - vcpu->arch.vgic_cpu.vgic_v2.vgic_lr[lr] = val; }void vgic_v2_clear_lr (struct kvm_vcpu *vcpu,int lr)
Signature · 1 line
2.47.3
Marc Zyngier
maintainerPATCH v2 18/45 KVM: arm64: Compute vgic state irrespective of the number of interrupts
In reply to Marc ZyngierAs we are going to rely on the [G]ICH_HCR{,_EL2} register to be programmed with MI information at all times, slightly de-optimise the flush/sync code to always be called. This is rather lightweight when no interrupts are in flight.
--- arch/arm64/kvm/vgic/vgic.c | 35 ++--------------------------------- 1 file changed, 2 insertions(+), 33 deletions(-)
arch/arm64/kvm/vgic/vgic.c +2 -33
@@ -985,8 +985,6 @@ 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) { -int used_lrs; -/* If nesting, emulate the HW effect from L0 to L1 */ if (vgic_state_is_nested (vcpu)) {vgic_v3_sync_nested (vcpu);
@@ -996,20 +994,10 @@ void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)if (vcpu_has_nv (vcpu))vgic_v3_nested_update_mi (vcpu); -/* An empty ap_list_head implies used_lrs == 0 */ -if (list_empty (&vcpu->arch.vgic_cpu.ap_list_head)) -return ; -if (can_access_vgic_from_kernel ())vgic_save_state (vcpu); -if (!static_branch_unlikely (&kvm_vgic_global_state.gicv3_cpuif)) - used_lrs = vcpu->arch.vgic_cpu.vgic_v2.used_lrs; -else - used_lrs = vcpu->arch.vgic_cpu.vgic_v3.used_lrs; - -if (used_lrs) -vgic_fold_lr_state (vcpu); +vgic_fold_lr_state (vcpu);vgic_prune_ap_list (vcpu); }
@@ -1053,29 +1041,10 @@ void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)if (vcpu_has_nv (vcpu))vgic_v3_nested_update_mi (vcpu); -/* -* If there are no virtual interrupts active or pending for this -* VCPU, then there is no work to do and we can bail out without -* taking any lock. There is a potential race with someone injecting -* interrupts to the VCPU, but it is a benign race as the VCPU will -* either observe the new interrupt before or after doing this check, -* and introducing additional synchronization mechanism doesn't change -* this. -* -* Note that we still need to go through the whole thing if anything -* can be directly injected (GICv4). -*/ -if (list_empty (&vcpu->arch.vgic_cpu.ap_list_head) && - !vgic_supports_direct_irqs (vcpu->kvm)) -return ; -DEBUG_SPINLOCK_BUG_ON (!irqs_disabled ()); -if (!list_empty (&vcpu->arch.vgic_cpu.ap_list_head)) { -raw_spin_lock (&vcpu->arch.vgic_cpu.ap_list_lock); + scoped_guard(raw_spinlock, &vcpu->arch.vgic_cpu.ap_list_lock)vgic_flush_lr_state (vcpu); -raw_spin_unlock (&vcpu->arch.vgic_cpu.ap_list_lock); - }if (can_access_vgic_from_kernel ())vgic_restore_state (vcpu);
Signature · 1 line
2.47.3
Marc Zyngier
maintainerPATCH v2 19/45 KVM: arm64: Eagerly save VMCR on exit
In reply to Marc ZyngierWe currently save/restore the VMCR register in a pretty lazy way (on load/put, consistently with what we do with the APRs).
However, we are going to need the group-enable bits that are backed by VMCR on each entry (so that we can avoid injecting interrupts for disabled groups).
Move the synchronisation from put to sync, which results in some minor churn in the nVHE hypercalls to simplify things.
--- arch/arm64/include/asm/kvm_asm.h | 2 +- arch/arm64/include/asm/kvm_hyp.h | 2 +- arch/arm64/kvm/arm.c | 3 +-- arch/arm64/kvm/hyp/nvhe/hyp-main.c | 7 ++++--- arch/arm64/kvm/hyp/vgic-v3-sr.c | 15 +++------------ arch/arm64/kvm/vgic/vgic-v2.c | 2 +- arch/arm64/kvm/vgic/vgic-v3-nested.c | 2 +- arch/arm64/kvm/vgic/vgic-v3.c | 2 +- 8 files changed, 13 insertions(+), 22 deletions(-)
arch/arm64/include/asm/kvm_asm.h +1 -1
@@ -79,7 +79,7 @@ enum __kvm_host_smccc_func { __KVM_HOST_SMCCC_FUNC___kvm_tlb_flush_vmid_range, __KVM_HOST_SMCCC_FUNC___kvm_flush_cpu_context, __KVM_HOST_SMCCC_FUNC___kvm_timer_set_cntvoff, - __KVM_HOST_SMCCC_FUNC___vgic_v3_save_vmcr_aprs, + __KVM_HOST_SMCCC_FUNC___vgic_v3_save_aprs, __KVM_HOST_SMCCC_FUNC___vgic_v3_restore_vmcr_aprs, __KVM_HOST_SMCCC_FUNC___pkvm_reserve_vm, __KVM_HOST_SMCCC_FUNC___pkvm_unreserve_vm,
arch/arm64/include/asm/kvm_hyp.h +1 -1
@@ -82,7 +82,7 @@ void __vgic_v3_save_state(struct vgic_v3_cpu_if *cpu_if);void __vgic_v3_restore_state (struct vgic_v3_cpu_if *cpu_if);void __vgic_v3_activate_traps (struct vgic_v3_cpu_if *cpu_if);void __vgic_v3_deactivate_traps (struct vgic_v3_cpu_if *cpu_if); -void __vgic_v3_save_vmcr_aprs (struct vgic_v3_cpu_if *cpu_if); +void __vgic_v3_save_aprs (struct vgic_v3_cpu_if *cpu_if);void __vgic_v3_restore_vmcr_aprs (struct vgic_v3_cpu_if *cpu_if);int __vgic_v3_perform_cpuif_access (struct kvm_vcpu *vcpu);
arch/arm64/kvm/arm.c +1 -2
@@ -659,8 +659,7 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)void kvm_arch_vcpu_put (struct kvm_vcpu *vcpu) {if (is_protected_kvm_enabled ()) { -kvm_call_hyp (__vgic_v3_save_vmcr_aprs, - &vcpu->arch.vgic_cpu.vgic_v3); +kvm_call_hyp (__vgic_v3_save_aprs, &vcpu->arch.vgic_cpu.vgic_v3);kvm_call_hyp_nvhe (__pkvm_vcpu_put); }
arch/arm64/kvm/hyp/nvhe/hyp-main.c +4 -3
@@ -157,6 +157,7 @@ static void sync_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu) host_vcpu->arch.iflags = hyp_vcpu->vcpu.arch.iflags; host_cpu_if->vgic_hcr = hyp_cpu_if->vgic_hcr; + host_cpu_if->vgic_vmcr = hyp_cpu_if->vgic_vmcr;for (i =0 ; i < hyp_cpu_if->used_lrs; ++i) host_cpu_if->vgic_lr[i] = hyp_cpu_if->vgic_lr[i]; }
@@ -464,11 +465,11 @@ static void handle___vgic_v3_init_lrs(struct kvm_cpu_context *host_ctxt)__vgic_v3_init_lrs (); } -static void handle___vgic_v3_save_vmcr_aprs (struct kvm_cpu_context *host_ctxt) +static void handle___vgic_v3_save_aprs (struct kvm_cpu_context *host_ctxt) { DECLARE_REG(struct vgic_v3_cpu_if *, cpu_if, host_ctxt, 1); -__vgic_v3_save_vmcr_aprs (kern_hyp_va (cpu_if)); +__vgic_v3_save_aprs (kern_hyp_va (cpu_if)); }static void handle___vgic_v3_restore_vmcr_aprs (struct kvm_cpu_context *host_ctxt)
@@ -616,7 +617,7 @@ static const hcall_t host_hcall[] = {HANDLE_FUNC (__kvm_tlb_flush_vmid_range),HANDLE_FUNC (__kvm_flush_cpu_context),HANDLE_FUNC (__kvm_timer_set_cntvoff), -HANDLE_FUNC (__vgic_v3_save_vmcr_aprs), +HANDLE_FUNC (__vgic_v3_save_aprs),HANDLE_FUNC (__vgic_v3_restore_vmcr_aprs),HANDLE_FUNC (__pkvm_reserve_vm), HANDLE_FUNC(__pkvm_unreserve_vm),
arch/arm64/kvm/hyp/vgic-v3-sr.c +3 -12
@@ -235,6 +235,8 @@ void __vgic_v3_save_state(struct vgic_v3_cpu_if *cpu_if) } } + cpu_if->vgic_vmcr =read_gicreg (ICH_VMCR_EL2 ); +if (cpu_if->vgic_hcr &ICH_HCR_EL2_LRENPIE ) {u64 val =read_gicreg (ICH_HCR_EL2 ); cpu_if->vgic_hcr &= ~ICH_HCR_EL2_EOIcount;
@@ -332,10 +334,6 @@ void __vgic_v3_deactivate_traps(struct vgic_v3_cpu_if *cpu_if) {u64 val; -if (!cpu_if->vgic_sre) { - cpu_if->vgic_vmcr =read_gicreg (ICH_VMCR_EL2 ); - } -/* Only restore SRE if the host implements the GICv2 interface */ if (static_branch_unlikely (&vgic_v3_has_v2_compat)) { val =read_gicreg (ICC_SRE_EL2 );
@@ -357,7 +355,7 @@ void __vgic_v3_deactivate_traps(struct vgic_v3_cpu_if *cpu_if)write_gicreg (0 ,ICH_HCR_EL2 ); } -static void __vgic_v3_save_aprs (struct vgic_v3_cpu_if *cpu_if) +void __vgic_v3_save_aprs (struct vgic_v3_cpu_if *cpu_if) {u64 val;u32 nr_pre_bits;
@@ -518,13 +516,6 @@ static void __vgic_v3_write_vmcr(u32 vmcr)write_gicreg (vmcr,ICH_VMCR_EL2 ); } -void __vgic_v3_save_vmcr_aprs (struct vgic_v3_cpu_if *cpu_if) -{ -__vgic_v3_save_aprs (cpu_if); -if (cpu_if->vgic_sre) - cpu_if->vgic_vmcr =__vgic_v3_read_vmcr (); -} -void __vgic_v3_restore_vmcr_aprs (struct vgic_v3_cpu_if *cpu_if) {__vgic_v3_compat_mode_enable ();
arch/arm64/kvm/vgic/vgic-v2.c +1 -1
@@ -451,6 +451,7 @@ void vgic_v2_save_state(struct kvm_vcpu *vcpu)if (!base)return ; + cpu_if->vgic_vmcr =readl_relaxed (kvm_vgic_global_state.vctrl_base +GICH_VMCR );if (used_lrs)save_lrs (vcpu, base);
@@ -495,6 +496,5 @@ void vgic_v2_put(struct kvm_vcpu *vcpu) {struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2; - cpu_if->vgic_vmcr =readl_relaxed (kvm_vgic_global_state.vctrl_base +GICH_VMCR ); cpu_if->vgic_apr =readl_relaxed (kvm_vgic_global_state.vctrl_base +GICH_APR ); }
arch/arm64/kvm/vgic/vgic-v3-nested.c +1 -1
@@ -341,7 +341,7 @@ void vgic_v3_put_nested(struct kvm_vcpu *vcpu)u64 val;int i; -__vgic_v3_save_vmcr_aprs (s_cpu_if); +__vgic_v3_save_aprs (s_cpu_if);__vgic_v3_deactivate_traps (s_cpu_if);__vgic_v3_save_state (s_cpu_if);
arch/arm64/kvm/vgic/vgic-v3.c +1 -1
@@ -815,7 +815,7 @@ void vgic_v3_put(struct kvm_vcpu *vcpu) }if (likely (!is_protected_kvm_enabled ())) -kvm_call_hyp (__vgic_v3_save_vmcr_aprs, cpu_if); +kvm_call_hyp (__vgic_v3_save_aprs, cpu_if);WARN_ON (vgic_v4_put (vcpu));if (has_vhe ())
Signature · 1 line
2.47.3
Marc Zyngier
maintainerPATCH v2 20/45 KVM: arm64: Revamp vgic maintenance interrupt configuration
In reply to Marc ZyngierWe currently don't use the maintenance interrupt very much, apart from EOI on level interrupts, and for LR underflow in limited cases.
However, as we are moving toward a setup where active interrupts can live outside of the LRs, we need to use the MIs in a more diverse set of cases.
Add a new helper that produces a digest of the ap_list, and use that summary to set the various control bits as required.
This slightly changes the way v2 SGIs are handled, as they used to count for more than one interrupt, but not anymore.
--- arch/arm64/kvm/vgic/vgic-v2.c | 12 ++++- arch/arm64/kvm/vgic/vgic-v3.c | 15 +++++- arch/arm64/kvm/vgic/vgic.c | 91 ++++++++++++----------------------- arch/arm64/kvm/vgic/vgic.h | 19 +++++++- 4 files changed, 71 insertions(+), 66 deletions(-)
arch/arm64/kvm/vgic/vgic-v2.c +10 -2
@@ -26,11 +26,19 @@ void vgic_v2_init_lrs(void)vgic_v2_write_lr (i,0 ); } -void vgic_v2_set_underflow (struct kvm_vcpu *vcpu) +void vgic_v2_configure_hcr (struct kvm_vcpu *vcpu, +struct ap_list_summary *als) {struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2; - cpuif->vgic_hcr |=GICH_HCR_UIE ; + cpuif->vgic_hcr =GICH_HCR_EN ; + +if (irqs_pending_outside_lrs (als)) + cpuif->vgic_hcr |=GICH_HCR_NPIE ; +if (irqs_active_outside_lrs (als)) + cpuif->vgic_hcr |=GICH_HCR_LRENPIE ; +if (irqs_outside_lrs (als)) + cpuif->vgic_hcr |=GICH_HCR_UIE ; }static bool lr_signals_eoi_mi (u32 lr_val)
arch/arm64/kvm/vgic/vgic-v3.c +13 -2
@@ -20,11 +20,22 @@ static bool common_trap;static bool dir_trap;static bool gicv4_enable; -void vgic_v3_set_underflow (struct kvm_vcpu *vcpu) +void vgic_v3_configure_hcr (struct kvm_vcpu *vcpu, +struct ap_list_summary *als) {struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3; - cpuif->vgic_hcr |=ICH_HCR_EL2_UIE ; + cpuif->vgic_hcr = ICH_HCR_EL2_En; + +if (irqs_pending_outside_lrs (als)) + cpuif->vgic_hcr |=ICH_HCR_EL2_NPIE ; +if (irqs_active_outside_lrs (als)) + cpuif->vgic_hcr |=ICH_HCR_EL2_LRENPIE ; +if (irqs_outside_lrs (als)) + cpuif->vgic_hcr |=ICH_HCR_EL2_UIE ; + +if (!als->nr_sgi) + cpuif->vgic_hcr |= ICH_HCR_EL2_vSGIEOICount; }static bool lr_signals_eoi_mi (u64 lr_val)
arch/arm64/kvm/vgic/vgic.c +31 -60
129 lines not on this page · raw message
arch/arm64/kvm/vgic/vgic.h +17 -2
@@ -236,6 +236,21 @@ struct its_ite {u32 event_id; }; +struct ap_list_summary { +unsigned int nr_pend;/* purely pending, not active */ +unsigned int nr_act;/* active, or active+pending */ +unsigned int nr_sgi;/* any SGI */ +}; + +#define irqs_outside_lrs (s) \ + (((s)->nr_pend + (s)->nr_act) > kvm_vgic_global_state.nr_lr) + +#define irqs_pending_outside_lrs (s) \ + ((s)->nr_pend > kvm_vgic_global_state.nr_lr) + +#define irqs_active_outside_lrs (s) \ + ((s)->nr_act && irqs_outside_lrs(s)) +int vgic_v3_parse_attr (struct kvm_device *dev,struct kvm_device_attr *attr,struct vgic_reg_attr *reg_attr); int vgic_v2_parse_attr(struct kvm_device *dev, struct kvm_device_attr *attr,
@@ -262,7 +277,7 @@ int vgic_check_iorange(struct kvm *kvm, phys_addr_t ioaddr,void vgic_v2_fold_lr_state (struct kvm_vcpu *vcpu);void vgic_v2_populate_lr (struct kvm_vcpu *vcpu,struct vgic_irq *irq,int lr);void vgic_v2_clear_lr (struct kvm_vcpu *vcpu,int lr); -void vgic_v2_set_underflow (struct kvm_vcpu *vcpu); +void vgic_v2_configure_hcr (struct kvm_vcpu *vcpu,struct ap_list_summary *als);int vgic_v2_has_attr_regs (struct kvm_device *dev,struct kvm_device_attr *attr);int vgic_v2_dist_uaccess (struct kvm_vcpu *vcpu,bool is_write,int offset,u32 *val);
@@ -302,7 +317,7 @@ static inline void vgic_get_irq_ref(struct vgic_irq *irq)void vgic_v3_fold_lr_state (struct kvm_vcpu *vcpu);void vgic_v3_populate_lr (struct kvm_vcpu *vcpu,struct vgic_irq *irq,int lr);void vgic_v3_clear_lr (struct kvm_vcpu *vcpu,int lr); -void vgic_v3_set_underflow (struct kvm_vcpu *vcpu); +void vgic_v3_configure_hcr (struct kvm_vcpu *vcpu,struct ap_list_summary *als);void vgic_v3_set_vmcr (struct kvm_vcpu *vcpu,struct vgic_vmcr *vmcr);void vgic_v3_get_vmcr (struct kvm_vcpu *vcpu,struct vgic_vmcr *vmcr);void vgic_v3_enable (struct kvm_vcpu *vcpu);
Signature · 1 line
2.47.3
Oliver Upton
maintainerRe: [PATCH v2 20/45] KVM: arm64: Revamp vgic maintenance interrupt configuration
Quoted 13 lines · Marc Zyngier
arch/arm64/kvm/vgic/vgic.c +2
-5+static void summarize_ap_list (struct kvm_vcpu *vcpu, +struct ap_list_summary *als) {struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;struct vgic_irq *irq; -int count =0 ; - - *multi_sgi = false;lockdep_assert_held (&vgic_cpu->ap_list_lock); -list_for_each_entry (irq, &vgic_cpu->ap_list_head, ap_list) { -int w;
arch/arm64/kvm/vgic/vgic.c static inline void vgic_clear_lr(struct kvm_vcpu *vcpu, int lr) · line 807
Quoted 10 lines
arch/arm64/kvm/vgic/vgic.c +5
-4+ *als = (typeof(*als)){}; -raw_spin_lock (&irq->irq_lock); -/* GICv2 SGIs can count for more than one... */ - w =vgic_irq_get_lr_count (irq); -raw_spin_unlock (&irq->irq_lock); +list_for_each_entry (irq, &vgic_cpu->ap_list_head, ap_list) { + scoped_guard(raw_spinlock, &irq->irq_lock) { +if (vgic_target_oracle (irq) != vcpu) +continue ;
From our conversation about this sort of thing a few weeks ago, wont this 'continue' interact pooly with the for loop that scoped_guard() expands to?
Consistent with the other checks against the destination oracle you'll probably want a branch hint too.
Thanks,
Oliver
Marc Zyngier
maintainerRe: [PATCH v2 20/45] KVM: arm64: Revamp vgic maintenance interrupt configuration
Quoted 17 lines · Oliver Upton
Quoted 15 lines · Marc Zyngier
arch/arm64/kvm/vgic/vgic.c +3
-5+static void summarize_ap_list (struct kvm_vcpu *vcpu, +struct ap_list_summary *als) {struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;struct vgic_irq *irq; -int count =0 ; - - *multi_sgi = false;lockdep_assert_held (&vgic_cpu->ap_list_lock); -list_for_each_entry (irq, &vgic_cpu->ap_list_head, ap_list) { -int w; + *als = (typeof(*als)){};
Quoted 12 lines
arch/arm64/kvm/vgic/vgic.c static inline void vgic_clear_lr(struct kvm_vcpu *vcpu, int lr) · line 807
Quoted 8 lines
arch/arm64/kvm/vgic/vgic.c +4
-4-raw_spin_lock (&irq->irq_lock); -/* GICv2 SGIs can count for more than one... */ - w =vgic_irq_get_lr_count (irq); -raw_spin_unlock (&irq->irq_lock); +list_for_each_entry (irq, &vgic_cpu->ap_list_head, ap_list) { + scoped_guard(raw_spinlock, &irq->irq_lock) { +if (vgic_target_oracle (irq) != vcpu) +continue ;From our conversation about this sort of thing a few weeks ago, wont this 'continue' interact pooly with the for loop that
scoped_guard()expands to?
Gahhh... I was sure I had killed that everywhere, but obviously failed to. I wish there was a coccinelle script to detect this sort of broken constructs (where are the script kiddies when you really need them?).
Thanks for spotting it!
Quoted 2 lines
Consistent with the other checks against the destination oracle you'll probably want a branch hint too.
Yup, I'll add that.
Thanks again,
M.
Signature · 1 line
Without deviation from the norm, progress is not possible.
Oliver Upton
maintainerRe: [PATCH v2 20/45] KVM: arm64: Revamp vgic maintenance interrupt configuration
Quoted 36 lines · Marc Zyngier
Quoted 17 lines · Oliver Upton
Quoted 15 lines · Marc Zyngier
arch/arm64/kvm/vgic/vgic.c +3
-5+static void summarize_ap_list (struct kvm_vcpu *vcpu, +struct ap_list_summary *als) {struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;struct vgic_irq *irq; -int count =0 ; - - *multi_sgi = false;lockdep_assert_held (&vgic_cpu->ap_list_lock); -list_for_each_entry (irq, &vgic_cpu->ap_list_head, ap_list) { -int w; + *als = (typeof(*als)){};Quoted 12 lines
arch/arm64/kvm/vgic/vgic.c static inline void vgic_clear_lr(struct kvm_vcpu *vcpu, int lr) · line 807
Quoted 8 lines
arch/arm64/kvm/vgic/vgic.c +4
-4-raw_spin_lock (&irq->irq_lock); -/* GICv2 SGIs can count for more than one... */ - w =vgic_irq_get_lr_count (irq); -raw_spin_unlock (&irq->irq_lock); +list_for_each_entry (irq, &vgic_cpu->ap_list_head, ap_list) { + scoped_guard(raw_spinlock, &irq->irq_lock) { +if (vgic_target_oracle (irq) != vcpu) +continue ;From our conversation about this sort of thing a few weeks ago, wont this 'continue' interact pooly with the for loop that
scoped_guard()expands to?Gahhh... I was sure I had killed that everywhere, but obviously failed to. I wish there was a coccinelle script to detect this sort of broken constructs (where are the script kiddies when you really need them?).
Quoted 6 lines
Thanks for spotting it!
Quoted 2 lines
Consistent with the other checks against the destination oracle you'll probably want a branch hint too.
Yup, I'll add that.
I can take care of it when applying. These patches need to bake :)
Thanks,
Oliver
Marc Zyngier
maintainerRe: [PATCH v2 20/45] KVM: arm64: Revamp vgic maintenance interrupt configuration
Quoted 38 lines · Oliver Upton
Quoted 36 lines · Marc Zyngier
Quoted 17 lines · Oliver Upton
Quoted 15 lines · Marc Zyngier
(quoted diff) +3
-5+static void summarize_ap_list(struct kvm_vcpu *vcpu, + struct ap_list_summary *als) { struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu; struct vgic_irq *irq; - int count = 0; - - *multi_sgi = false; lockdep_assert_held(&vgic_cpu->ap_list_lock); - list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) { - int w; + *als = (typeof(*als)){};Quoted 12 lines
Review
Quoted 8 lines
(quoted diff) +4
-4- raw_spin_lock(&irq->irq_lock); - /* GICv2 SGIs can count for more than one... */ - w = vgic_irq_get_lr_count(irq); - raw_spin_unlock(&irq->irq_lock); + list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) { + scoped_guard(raw_spinlock, &irq->irq_lock) { + if (vgic_target_oracle(irq) != vcpu) + continue;From our conversation about this sort of thing a few weeks ago, wont this 'continue' interact pooly with the for loop that
scoped_guard()expands to?Gahhh... I was sure I had killed that everywhere, but obviously failed to. I wish there was a coccinelle script to detect this sort of broken constructs (where are the script kiddies when you really need them?).
Quoted 8 lines
Quoted 6 lines
Thanks for spotting it!
Quoted 2 lines
Consistent with the other checks against the destination oracle you'll probably want a branch hint too.
Yup, I'll add that.
I can take care of it when applying. These patches need to bake :)
Yes, they do. Here's the current state of additional changes I have (compile tested only).
Thanks,
M.
arch/arm64/kvm/vgic/vgic.c +11 -11
@@ -851,15 +851,15 @@ static void summarize_ap_list(struct kvm_vcpu *vcpu, *als = (typeof(*als)){};list_for_each_entry (irq, &vgic_cpu->ap_list_head, ap_list) { - scoped_guard(raw_spinlock, &irq->irq_lock) { -if (vgic_target_oracle (irq) != vcpu) -continue ; - -if (!irq->active) - als->nr_pend++; -else - als->nr_act++; - } +guard (raw_spinlock)(&irq->irq_lock); + +if (unlikely (vgic_target_oracle (irq) != vcpu)) +continue ; + +if (!irq->active) + als->nr_pend++; +else + als->nr_act++;if (irq->intid <VGIC_NR_SGIS ) als->nr_sgi++;
@@ -915,8 +915,8 @@ static void summarize_ap_list(struct kvm_vcpu *vcpu,* * - deactivation can happen in any order, and we cannot rely on * EOImode=0's coupling of priority-drop and deactivation which -* imposes strict reverse Ack order. This means that DIR must be set -* if we have active interrupts outside of the LRs. +* imposes strict reverse Ack order. This means that DIR must +* trap if we have active interrupts outside of the LRs. * * - deactivation of SPIs can occur on any CPU, while the SPI is only * present in the ap_list of the CPU that actually ack-ed it. In that
Signature · 1 line
Without deviation from the norm, progress is not possible.
Marc Zyngier
maintainerPATCH v2 21/45 KVM: arm64: Turn kvm_vgic_vcpu_enable() into kvm_vgic_vcpu_reset()
In reply to Marc ZyngierNow that we always reconfigure the vgic HCR register on entry, the "enable" part of kvm_vgic_vcpu_enable() is pretty useless.
Removing the enable bits from these functions makes it plain that they are just about computing the reset state. Just rename the functions accordingly.
--- arch/arm64/kvm/vgic/vgic-init.c | 8 ++++---- arch/arm64/kvm/vgic/vgic-v2.c | 5 +---- arch/arm64/kvm/vgic/vgic-v3.c | 5 +---- arch/arm64/kvm/vgic/vgic.h | 4 ++-- 4 files changed, 8 insertions(+), 14 deletions(-)
arch/arm64/kvm/vgic/vgic-init.c +4 -4
@@ -353,12 +353,12 @@ int kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu)return ret; } -static void kvm_vgic_vcpu_enable (struct kvm_vcpu *vcpu) +static void kvm_vgic_vcpu_reset (struct kvm_vcpu *vcpu) {if (kvm_vgic_global_state.type ==VGIC_V2 ) -vgic_v2_enable (vcpu); +vgic_v2_reset (vcpu);else -vgic_v3_enable (vcpu); +vgic_v3_reset (vcpu); }/*
@@ -405,7 +405,7 @@ int vgic_init(struct kvm *kvm) }kvm_for_each_vcpu (idx, vcpu, kvm) -kvm_vgic_vcpu_enable (vcpu); +kvm_vgic_vcpu_reset (vcpu); ret =kvm_vgic_setup_default_irq_routing (kvm);if (ret)
arch/arm64/kvm/vgic/vgic-v2.c +1 -4
@@ -285,7 +285,7 @@ void vgic_v2_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp) GICH_VMCR_PRIMASK_SHIFT) << GICV_PMR_PRIORITY_SHIFT; } -void vgic_v2_enable (struct kvm_vcpu *vcpu) +void vgic_v2_reset (struct kvm_vcpu *vcpu) {/* * By forcing VMCR to zero, the GIC will restore the binary
@@ -293,9 +293,6 @@ void vgic_v2_enable(struct kvm_vcpu *vcpu)* anyway. */ vcpu->arch.vgic_cpu.vgic_v2.vgic_vmcr =0 ; - -/* Get the show on the road... */ - vcpu->arch.vgic_cpu.vgic_v2.vgic_hcr =GICH_HCR_EN ; }/* check for overlapping regions and for regions crossing the end of memory */
arch/arm64/kvm/vgic/vgic-v3.c +1 -4
@@ -290,7 +290,7 @@ void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp) GIC_BASER_CACHEABILITY(GICR_PENDBASER, OUTER, SameAsInner) | \ GIC_BASER_SHAREABILITY(GICR_PENDBASER, InnerShareable)) -void vgic_v3_enable (struct kvm_vcpu *vcpu) +void vgic_v3_reset (struct kvm_vcpu *vcpu) {struct vgic_v3_cpu_if *vgic_v3 = &vcpu->arch.vgic_cpu.vgic_v3;
@@ -320,9 +320,6 @@ void vgic_v3_enable(struct kvm_vcpu *vcpu) kvm_vgic_global_state.ich_vtr_el2); vcpu->arch.vgic_cpu.num_pri_bits =FIELD_GET (ICH_VTR_EL2_PRIbits, kvm_vgic_global_state.ich_vtr_el2) +1 ; - -/* Get the show on the road... */ - vgic_v3->vgic_hcr = ICH_HCR_EL2_En; }void vcpu_set_ich_hcr (struct kvm_vcpu *vcpu)
arch/arm64/kvm/vgic/vgic.h +2 -2
@@ -285,7 +285,7 @@ int vgic_v2_cpuif_uaccess(struct kvm_vcpu *vcpu, bool is_write, int offset, u32 *val);void vgic_v2_set_vmcr (struct kvm_vcpu *vcpu,struct vgic_vmcr *vmcr);void vgic_v2_get_vmcr (struct kvm_vcpu *vcpu,struct vgic_vmcr *vmcr); -void vgic_v2_enable (struct kvm_vcpu *vcpu); +void vgic_v2_reset (struct kvm_vcpu *vcpu);int vgic_v2_probe (const struct gic_kvm_info *info);int vgic_v2_map_resources (struct kvm *kvm); int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address,
@@ -320,7 +320,7 @@ void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr);void vgic_v3_configure_hcr (struct kvm_vcpu *vcpu,struct ap_list_summary *als);void vgic_v3_set_vmcr (struct kvm_vcpu *vcpu,struct vgic_vmcr *vmcr);void vgic_v3_get_vmcr (struct kvm_vcpu *vcpu,struct vgic_vmcr *vmcr); -void vgic_v3_enable (struct kvm_vcpu *vcpu); +void vgic_v3_reset (struct kvm_vcpu *vcpu);int vgic_v3_probe (const struct gic_kvm_info *info);int vgic_v3_map_resources (struct kvm *kvm);int vgic_v3_lpi_sync_pending_status (struct kvm *kvm,struct vgic_irq *irq);
Signature · 1 line
2.47.3
Marc Zyngier
maintainerPATCH v2 22/45 KVM: arm64: Make vgic_target_oracle() globally available
In reply to Marc ZyngierMake the internal crystal ball global, so that implementation-specific code can use it.
--- arch/arm64/kvm/vgic/vgic.c | 2 +- arch/arm64/kvm/vgic/vgic.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-)
arch/arm64/kvm/vgic/vgic.c +1 -1
@@ -237,7 +237,7 @@ void vgic_irq_set_phys_active(struct vgic_irq *irq, bool active)* * Requires the IRQ lock to be held. */ -static struct kvm_vcpu *vgic_target_oracle (struct vgic_irq *irq) +struct kvm_vcpu *vgic_target_oracle (struct vgic_irq *irq) {lockdep_assert_held (&irq->irq_lock);
arch/arm64/kvm/vgic/vgic.h +1 -0
@@ -261,6 +261,7 @@ vgic_get_mmio_region(struct kvm_vcpu *vcpu, struct vgic_io_device *iodev,struct vgic_irq *vgic_get_irq (struct kvm *kvm,u32 intid);struct vgic_irq *vgic_get_vcpu_irq (struct kvm_vcpu *vcpu,u32 intid);void vgic_put_irq (struct kvm *kvm,struct vgic_irq *irq); +struct kvm_vcpu *vgic_target_oracle (struct vgic_irq *irq);bool vgic_get_phys_line_level (struct vgic_irq *irq);void vgic_irq_set_phys_pending (struct vgic_irq *irq,bool pending);void vgic_irq_set_phys_active (struct vgic_irq *irq,bool active);
Signature · 1 line
2.47.3
Marc Zyngier
maintainerPATCH v2 23/45 KVM: arm64: Invert ap_list sorting to push active interrupts out
In reply to Marc ZyngierHaving established that pending interrupts should have priority to be moved into the LRs over the active interrupts, implement this in the ap_list sorting.
--- arch/arm64/kvm/vgic/vgic.c | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-)
arch/arm64/kvm/vgic/vgic.c +12 -15
@@ -270,10 +270,7 @@ struct kvm_vcpu *vgic_target_oracle(struct vgic_irq *irq)* well, the first items in the list being the first things populated in the * LRs. * -* A hard rule is that active interrupts can never be pushed out of the LRs -* (and therefore take priority) since we cannot reliably trap on deactivation -* of IRQs and therefore they have to be present in the LRs. -* +* Pending, non-active interrupts must be placed at the head of the list. * Otherwise things should be sorted by the priority field and the GIC * hardware support will take care of preemption of priority groups etc. *
@@ -298,21 +295,21 @@ static int vgic_irq_cmp(void *priv, const struct list_head *a,raw_spin_lock (&irqa->irq_lock);raw_spin_lock_nested (&irqb->irq_lock,SINGLE_DEPTH_NESTING ); -if (irqa->active || irqb->active) { - ret = (int )irqb->active - (int )irqa->active; - goto out; - } + penda = irqa->enabled &&irq_is_pending (irqa) && !irqa->active; + pendb = irqb->enabled &&irq_is_pending (irqb) && !irqb->active; - penda = irqa->enabled &&irq_is_pending (irqa); - pendb = irqb->enabled &&irq_is_pending (irqb); + ret = (int )pendb - (int )penda; +if (ret) + goto out; -if (!penda || !pendb) { - ret = (int )pendb - (int )penda; +/* Both pending and enabled, sort by priority (lower number first) */ + ret = (int )irqa->priority - (int )irqb->priority; +if (ret) goto out; - } -/* Both pending and enabled, sort by priority */ - ret = irqa->priority - irqb->priority; +/* Finally, HW bit active interrupts have priority over non-HW ones */ + ret = (int )irqb->hw - (int )irqa->hw; + out:raw_spin_unlock (&irqb->irq_lock);raw_spin_unlock (&irqa->irq_lock);
Signature · 1 line
2.47.3
Marc Zyngier
maintainerPATCH v2 24/45 KVM: arm64: Move undeliverable interrupts to the end of ap_list
In reply to Marc ZyngierInterrupts in the ap_list that cannot be acted upon because they are not enabled, or that their group is not enabled, shouldn't make it into the LRs if we are space-constrained.
--- arch/arm64/kvm/vgic/vgic.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-)
arch/arm64/kvm/vgic/vgic.c +22 -1
@@ -265,6 +265,11 @@ struct kvm_vcpu *vgic_target_oracle(struct vgic_irq *irq)return NULL ; } +struct vgic_sort_info { +struct kvm_vcpu *vcpu; +struct vgic_vmcr vmcr; +}; +/* * The order of items in the ap_lists defines how we'll pack things in LRs as * well, the first items in the list being the first things populated in the
@@ -273,6 +278,7 @@ struct kvm_vcpu *vgic_target_oracle(struct vgic_irq *irq)* Pending, non-active interrupts must be placed at the head of the list. * Otherwise things should be sorted by the priority field and the GIC * hardware support will take care of preemption of priority groups etc. +* Interrupts that are not deliverable should be at the end of the list. * * Return negative if "a" sorts before "b", 0 to preserve order, and positive * to sort "b" before "a".
@@ -282,6 +288,8 @@ static int vgic_irq_cmp(void *priv, const struct list_head *a, { struct vgic_irq *irqa = container_of(a, struct vgic_irq, ap_list); struct vgic_irq *irqb = container_of(b, struct vgic_irq, ap_list); +struct vgic_sort_info *info = priv; +struct kvm_vcpu *vcpu = info->vcpu;bool penda, pendb;int ret;
@@ -295,6 +303,17 @@ static int vgic_irq_cmp(void *priv, const struct list_head *a,raw_spin_lock (&irqa->irq_lock);raw_spin_lock_nested (&irqb->irq_lock,SINGLE_DEPTH_NESTING ); +/* Undeliverable interrupts should be last */ + ret = (int )(vgic_target_oracle (irqb) == vcpu) - (int )(vgic_target_oracle (irqa) == vcpu); +if (ret) + goto out; + +/* Same thing for interrupts targeting a disabled group */ + ret = (int )(irqb->group ? info->vmcr.grpen1 : info->vmcr.grpen0); + ret -= (int )(irqa->group ? info->vmcr.grpen1 : info->vmcr.grpen0); +if (ret) + goto out; + penda = irqa->enabled &&irq_is_pending (irqa) && !irqa->active; pendb = irqb->enabled &&irq_is_pending (irqb) && !irqb->active;
@@ -320,10 +339,12 @@ static int vgic_irq_cmp(void *priv, const struct list_head *a,static void vgic_sort_ap_list (struct kvm_vcpu *vcpu) {struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu; +struct vgic_sort_info info = { .vcpu = vcpu, };lockdep_assert_held (&vgic_cpu->ap_list_lock); -list_sort (NULL , &vgic_cpu->ap_list_head, vgic_irq_cmp); +vgic_get_vmcr (vcpu, &info.vmcr); +list_sort (&info, &vgic_cpu->ap_list_head, vgic_irq_cmp); }/*
Signature · 1 line
2.47.3
Marc Zyngier
maintainerPATCH v2 25/45 KVM: arm64: Use MI to detect groups being enabled/disabled
In reply to Marc ZyngierAdd the maintenance interrupt to force an exit when the guest enables/disables individual groups, so that we can resort the ap_list accordingly.
--- arch/arm64/kvm/vgic/vgic-v2.c | 5 +++++ arch/arm64/kvm/vgic/vgic-v3.c | 5 +++++ 2 files changed, 10 insertions(+)
arch/arm64/kvm/vgic/vgic-v2.c +5 -0
@@ -39,6 +39,11 @@ void vgic_v2_configure_hcr(struct kvm_vcpu *vcpu, cpuif->vgic_hcr |=GICH_HCR_LRENPIE ;if (irqs_outside_lrs (als)) cpuif->vgic_hcr |=GICH_HCR_UIE ; + + cpuif->vgic_hcr |= (cpuif->vgic_vmcr &GICH_VMCR_ENABLE_GRP0_MASK ) ? + GICH_HCR_VGrp0DIE : GICH_HCR_VGrp0EIE; + cpuif->vgic_hcr |= (cpuif->vgic_vmcr &GICH_VMCR_ENABLE_GRP1_MASK ) ? + GICH_HCR_VGrp1DIE : GICH_HCR_VGrp1EIE; }static bool lr_signals_eoi_mi (u32 lr_val)
arch/arm64/kvm/vgic/vgic-v3.c +5 -0
@@ -36,6 +36,11 @@ void vgic_v3_configure_hcr(struct kvm_vcpu *vcpu,if (!als->nr_sgi) cpuif->vgic_hcr |= ICH_HCR_EL2_vSGIEOICount; + + cpuif->vgic_hcr |= (cpuif->vgic_vmcr &ICH_VMCR_ENG0_MASK ) ? + ICH_HCR_EL2_VGrp0DIE : ICH_HCR_EL2_VGrp0EIE; + cpuif->vgic_hcr |= (cpuif->vgic_vmcr &ICH_VMCR_ENG1_MASK ) ? + ICH_HCR_EL2_VGrp1DIE : ICH_HCR_EL2_VGrp1EIE; }static bool lr_signals_eoi_mi (u64 lr_val)
Signature · 1 line
2.47.3
Marc Zyngier
maintainerPATCH v2 26/45 KVM: arm64: GICv3: Handle LR overflow when EOImode==0
In reply to Marc ZyngierNow that we can identify interrupts that have not made it into the LRs, it becomes relatively easy to use EOIcount to walk the overflow list.
What is a bit odd is that we compute a fake LR for the original state of the interrupt, clear the active bit, and feed into the existing logic for processing. In a way, this is what would have happened if the interrupt was in an LR.
--- arch/arm64/kvm/vgic/vgic-v3.c | 46 +++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+)
arch/arm64/kvm/vgic/vgic-v3.c +46 -0
@@ -109,16 +109,62 @@ static void vgic_v3_fold_lr(struct kvm_vcpu *vcpu, u64 val)vgic_put_irq (vcpu->kvm, irq); } +static u64 vgic_v3_compute_lr (struct kvm_vcpu *vcpu,struct vgic_irq *irq); + +static void vgic_v3_deactivate_phys (u32 intid) +{ +if (cpus_have_final_cap (ARM64_HAS_GICV5_LEGACY )) +gic_insn (intid |FIELD_PREP (GICV5_GIC_CDDI_TYPE_MASK ,1 ),CDDI ); +else +gic_write_dir (intid); +} +void vgic_v3_fold_lr_state (struct kvm_vcpu *vcpu) {struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;struct vgic_v3_cpu_if *cpuif = &vgic_cpu->vgic_v3; +u32 eoicount =FIELD_GET (ICH_HCR_EL2_EOIcount, cpuif->vgic_hcr); +struct vgic_irq *irq;DEBUG_SPINLOCK_BUG_ON (!irqs_disabled ());for (int lr =0 ; lr < cpuif->used_lrs; lr++)vgic_v3_fold_lr (vcpu, cpuif->vgic_lr[lr]); +/* +* EOIMode=0: use EOIcount to emulate deactivation. We are +* guaranteed to deactivate in reverse order of the activation, so +* just pick one active interrupt after the other in the ap_list, +* and replay the deactivation as if the CPU was doing it. We also +* rely on priority drop to have taken place, and the list to be +* sorted by priority. +*/ +list_for_each_entry (irq, &vgic_cpu->ap_list_head, ap_list) { +u64 lr; + +/* +* I would have loved to write this using a scoped_guard(), +* but using 'continue' here is a total train wreck. +*/ +if (!eoicount) { +break ; + }else { +guard (raw_spinlock)(&irq->irq_lock); + +if (!(likely (vgic_target_oracle (irq) == vcpu) && + irq->active)) +continue ; + + lr =vgic_v3_compute_lr (vcpu, irq) & ~ICH_LR_ACTIVE_BIT ; + } + +if (lr &ICH_LR_HW ) +vgic_v3_deactivate_phys (FIELD_GET (ICH_LR_PHYS_ID_MASK , lr)); + +vgic_v3_fold_lr (vcpu, lr); + eoicount--; + } + cpuif->used_lrs =0 ; }
Signature · 1 line
2.47.3
Marc Zyngier
maintainerPATCH v2 27/45 KVM: arm64: GICv3: Handle deactivation via ICV_DIR_EL1 traps
In reply to Marc ZyngierDeactivation via ICV_DIR_EL1 is both relatively straightforward (we have the interrupt that needs deactivation) and really awkward.
The main issue is that the interrupt may either be in an LR on another CPU, or ourside of any LR.
In the former case, we process the deactivation is if ot was a write to GICD_CACTIVERn, which is already implemented as a big hammer IPI'ing all vcpus. In the latter case, we just perform a normal deactivation, similar to what we do for EOImode==0.
Another annoying aspect is that we need to tell the CPU owning the interrupt that its ap_list needs laudering. We use a brand new vcpu request to that effect.
Note that this doesn't address deactivation via the GICV MMIO view, which will be taken care of in a later change.
--- arch/arm64/include/asm/kvm_host.h | 1 + arch/arm64/kvm/arm.c | 4 ++ arch/arm64/kvm/hyp/vgic-v3-sr.c | 3 ++ arch/arm64/kvm/sys_regs.c | 19 ++++++- arch/arm64/kvm/vgic/vgic-v3.c | 85 +++++++++++++++++++++++++++++++ arch/arm64/kvm/vgic/vgic.c | 11 ++++ arch/arm64/kvm/vgic/vgic.h | 1 + include/kvm/arm_vgic.h | 1 + 8 files changed, 123 insertions(+), 2 deletions(-)
arch/arm64/include/asm/kvm_host.h +1 -0
@@ -54,6 +54,7 @@#define KVM_REQ_NESTED_S2_UNMAP KVM_ARCH_REQ(8)#define KVM_REQ_GUEST_HYP_IRQ_PENDING KVM_ARCH_REQ(9)#define KVM_REQ_MAP_L1_VNCR_EL2 KVM_ARCH_REQ(10) +#define KVM_REQ_VGIC_PROCESS_UPDATE KVM_ARCH_REQ(11)#define KVM_DIRTY_LOG_MANUAL_CAPS (KVM_DIRTY_LOG_MANUAL_PROTECT_ENABLE | \ KVM_DIRTY_LOG_INITIALLY_SET)
arch/arm64/kvm/arm.c +4 -0
@@ -1041,6 +1041,10 @@ static int check_vcpu_requests(struct kvm_vcpu *vcpu)*/ kvm_check_request (KVM_REQ_IRQ_PENDING , vcpu); +/* Process interrupts deactivated through a trap */ +if (kvm_check_request (KVM_REQ_VGIC_PROCESS_UPDATE , vcpu)) +kvm_vgic_process_async_update (vcpu); +if (kvm_check_request (KVM_REQ_RECORD_STEAL , vcpu))kvm_update_stolen_time (vcpu);
arch/arm64/kvm/hyp/vgic-v3-sr.c +3 -0
@@ -1247,6 +1247,9 @@ int __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)case SYS_ICC_DIR_EL1 :if (unlikely (is_read))return 0 ; +/* Full exit if required to handle overflow deactivation... */ +if (vcpu->arch.vgic_cpu.vgic_v3.vgic_hcr &ICH_HCR_EL2_TDIR ) +return 0 ; fn = __vgic_v3_write_dir;break ;case SYS_ICC_RPR_EL1 :
arch/arm64/kvm/sys_regs.c +17 -2
@@ -666,6 +666,21 @@ static bool access_gic_sre(struct kvm_vcpu *vcpu,return true; } +static bool access_gic_dir (struct kvm_vcpu *vcpu, +struct sys_reg_params *p, +const struct sys_reg_desc *r) +{ +if (!kvm_has_gicv3 (vcpu->kvm)) +return undef_access (vcpu, p, r); + +if (!p->is_write) +return undef_access (vcpu, p, r); + +vgic_v3_deactivate (vcpu, p->regval); + +return true; +} +static bool trap_raz_wi (struct kvm_vcpu *vcpu,struct sys_reg_params *p,const struct sys_reg_desc *r)
@@ -3370,7 +3385,7 @@ static const struct sys_reg_desc sys_reg_descs[] = { { SYS_DESC(SYS_ICC_AP1R1_EL1), undef_access }, { SYS_DESC(SYS_ICC_AP1R2_EL1), undef_access }, { SYS_DESC(SYS_ICC_AP1R3_EL1), undef_access }, - { SYS_DESC(SYS_ICC_DIR_EL1), undef_access }, + { SYS_DESC(SYS_ICC_DIR_EL1), access_gic_dir }, { SYS_DESC(SYS_ICC_RPR_EL1), undef_access }, { SYS_DESC(SYS_ICC_SGI1R_EL1), access_gic_sgi }, { SYS_DESC(SYS_ICC_ASGI1R_EL1), access_gic_sgi },
@@ -4495,7 +4510,7 @@ static const struct sys_reg_desc cp15_regs[] = { { CP15_SYS_DESC(SYS_ICC_AP1R1_EL1), undef_access }, { CP15_SYS_DESC(SYS_ICC_AP1R2_EL1), undef_access }, { CP15_SYS_DESC(SYS_ICC_AP1R3_EL1), undef_access }, - { CP15_SYS_DESC(SYS_ICC_DIR_EL1), undef_access }, + { CP15_SYS_DESC(SYS_ICC_DIR_EL1), access_gic_dir }, { CP15_SYS_DESC(SYS_ICC_RPR_EL1), undef_access }, { CP15_SYS_DESC(SYS_ICC_IAR1_EL1), undef_access }, { CP15_SYS_DESC(SYS_ICC_EOIR1_EL1), undef_access },
arch/arm64/kvm/vgic/vgic-v3.c +85 -0
97 lines not on this page · raw message
arch/arm64/kvm/vgic/vgic.c +11 -0
@@ -990,6 +990,17 @@ void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)vgic_prune_ap_list (vcpu); } +/* Sync interrupts that were deactivated through a DIR trap */ +void kvm_vgic_process_async_update (struct kvm_vcpu *vcpu) +{ +unsigned long flags; + +/* Make sure we're in the same context as LR handling */ +local_irq_save (flags); +vgic_prune_ap_list (vcpu); +local_irq_restore (flags); +} +static inline void vgic_restore_state (struct kvm_vcpu *vcpu) {if (!static_branch_unlikely (&kvm_vgic_global_state.gicv3_cpuif))
arch/arm64/kvm/vgic/vgic.h +1 -0
@@ -318,6 +318,7 @@ static inline void vgic_get_irq_ref(struct vgic_irq *irq)void vgic_v3_fold_lr_state (struct kvm_vcpu *vcpu);void vgic_v3_populate_lr (struct kvm_vcpu *vcpu,struct vgic_irq *irq,int lr);void vgic_v3_clear_lr (struct kvm_vcpu *vcpu,int lr); +void vgic_v3_deactivate (struct kvm_vcpu *vcpu,u64 val);void vgic_v3_configure_hcr (struct kvm_vcpu *vcpu,struct ap_list_summary *als);void vgic_v3_set_vmcr (struct kvm_vcpu *vcpu,struct vgic_vmcr *vmcr);void vgic_v3_get_vmcr (struct kvm_vcpu *vcpu,struct vgic_vmcr *vmcr);
include/kvm/arm_vgic.h +1 -0
@@ -421,6 +421,7 @@ bool kvm_vcpu_has_pending_irqs(struct kvm_vcpu *vcpu);void kvm_vgic_sync_hwstate (struct kvm_vcpu *vcpu);void kvm_vgic_flush_hwstate (struct kvm_vcpu *vcpu);void kvm_vgic_reset_mapped_irq (struct kvm_vcpu *vcpu,u32 vintid); +void kvm_vgic_process_async_update (struct kvm_vcpu *vcpu);void vgic_v3_dispatch_sgi (struct kvm_vcpu *vcpu,u64 reg,bool allow_group1);
Signature · 1 line
2.47.3
Marc Zyngier
maintainerPATCH v2 28/45 KVM: arm64: GICv3: Add GICv2 SGI handling to deactivation primitive
In reply to Marc ZyngierThe GICv2 SGIs require additional handling for deactivation, as they are effectively multiple interrrupts muxed into one. Make sure we check for the source CPU when deactivating.
--- arch/arm64/kvm/vgic/vgic-v3.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-)
arch/arm64/kvm/vgic/vgic-v3.c +19 -1
@@ -173,11 +173,20 @@ void vgic_v3_deactivate(struct kvm_vcpu *vcpu, u64 val) {struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;struct vgic_v3_cpu_if *cpuif = &vgic_cpu->vgic_v3; +u32 model = vcpu->kvm->arch.vgic.vgic_model;struct kvm_vcpu *target_vcpu =NULL ; +bool mmio = false, is_v2_sgi;struct vgic_irq *irq;unsigned long flags; -bool mmio = false;u64 lr =0 ; +u8 cpuid; + +/* Snapshot CPUID, and remove it from the INTID */ + cpuid =FIELD_GET (GENMASK_ULL (12 ,10 ), val); + val &= ~GENMASK_ULL (12 ,10 ); + + is_v2_sgi = (model ==KVM_DEV_TYPE_ARM_VGIC_V2 && + val <VGIC_NR_SGIS );/* * We only deal with DIR when EOIMode==1, and only for SGI,
@@ -213,6 +222,9 @@ void vgic_v3_deactivate(struct kvm_vcpu *vcpu, u64 val)* - Or the irq is active, but not in an LR, and we can * directly deactivate it by building a pseudo-LR, fold it, * and queue a request to prune the resulting ap_list, +* +* Special care must be taken to match the source CPUID when +* deactivating a GICv2 SGI. */ scoped_guard(raw_spinlock, &irq->irq_lock) { target_vcpu = irq->vcpu;
@@ -230,6 +242,12 @@ void vgic_v3_deactivate(struct kvm_vcpu *vcpu, u64 val) goto put; } +/* GICv2 SGI: check that the cpuid matches */ +if (is_v2_sgi && irq->active_source != cpuid) { + target_vcpu =NULL ; + goto put; + } +/* (with a Dalek voice) DEACTIVATE!!!! */ lr =vgic_v3_compute_lr (vcpu, irq) & ~ICH_LR_ACTIVE_BIT ; }
Signature · 1 line
2.47.3
Marc Zyngier
maintainerPATCH v2 29/45 KVM: arm64: GICv3: Set ICH_HCR_EL2.TDIR when interrupts overflow LR capacity
In reply to Marc ZyngierNow that we are ready to handle deactivation through ICV_DIR_EL1, set the trap bit if we have active interrupts outside of the LRs.
--- arch/arm64/kvm/vgic/vgic-v3.c | 7 +++++++ 1 file changed, 7 insertions(+)
arch/arm64/kvm/vgic/vgic-v3.c +7 -0
@@ -42,6 +42,13 @@ void vgic_v3_configure_hcr(struct kvm_vcpu *vcpu, ICH_HCR_EL2_VGrp0DIE : ICH_HCR_EL2_VGrp0EIE; cpuif->vgic_hcr |= (cpuif->vgic_vmcr &ICH_VMCR_ENG1_MASK ) ? ICH_HCR_EL2_VGrp1DIE : ICH_HCR_EL2_VGrp1EIE; + +/* +* Note that we set the trap irrespective of EOIMode, as that +* can change behind our back without any warning... +*/ +if (irqs_active_outside_lrs (als)) + cpuif->vgic_hcr |=ICH_HCR_EL2_TDIR ; }static bool lr_signals_eoi_mi (u64 lr_val)
Signature · 1 line
2.47.3
Re: [PATCH v2 29/45] KVM: arm64: GICv3: Set ICH_HCR_EL2.TDIR when interrupts overflow LR capacity
Hi Marc,
Quoted 15 lines · Marc Zyngier
Now that we are ready to handle deactivation through
ICV_DIR_EL1, set the trap bit if we have active interrupts outside of the LRs.Signed-off-by Marc Zyngier <[email protected]>--- arch/arm64/kvm/vgic/vgic-v3.c | 7 +++++++ 1 file changed, 7 insertions(+)arch/arm64/kvm/vgic/vgic-v3.c +0
-0@@ -42,6 +42,13 @@ void vgic_v3_configure_hcr(struct kvm_vcpu *vcpu, ICH_HCR_EL2_VGrp0DIE : ICH_HCR_EL2_VGrp0EIE;
arch/arm64/kvm/vgic/vgic-v3.c void vgic_v3_configure_hcr(struct kvm_vcpu *vcpu, · line 52
Quoted 10 lines
arch/arm64/kvm/vgic/vgic-v3.c +7
-0cpuif->vgic_hcr |= (cpuif->vgic_vmcr &ICH_VMCR_ENG1_MASK ) ? ICH_HCR_EL2_VGrp1DIE : ICH_HCR_EL2_VGrp1EIE; + +/* +* Note that we set the trap irrespective of EOIMode, as that +* can change behind our back without any warning... +*/ +if (irqs_active_outside_lrs (als)) + cpuif->vgic_hcr |=ICH_HCR_EL2_TDIR ; }
I just tested these patches as they are on kvmarm/next 2ea7215187c5759fc5d277280e3095b350ca6a50 ("Merge branch 'kvm-arm64/vgic-lr-overflow' into kvmarm/next"), without any additional pKVM patches. I tried running it with pKVM (non-protected) and with just plain nVHE. In both cases, I get a trap to EL2 (0x18) when booting a non-protected guest, which triggers a bug in handle_trap() arch/arm64/kvm/hyp/nvhe/hyp-main.c:706
This trap is happening because of setting this particular trap (TDIR). Just removing this trap from vgic_v3_configure_hcr() from the ToT on kvmarm/next boots fine.
I'm running this on QEMU with '-machine virt,gic-version=3 -cpu max' and the kernel with 'kvm-arm.mode=protected' and with 'kvm-arm.mode=nvhe'.
Let me know if you need any more info or help testing.
Cheers,
/fuad
Quoted 5 lines
arch/arm64/kvm/vgic/vgic-v3.c +0
-1static bool lr_signals_eoi_mi (u64 lr_val) --2.47.3
Marc Zyngier
maintainerRe: [PATCH v2 29/45] KVM: arm64: GICv3: Set ICH_HCR_EL2.TDIR when interrupts overflow LR capacity
Quoted 38 lines · Fuad Tabba
Hi Marc,
Quoted 15 lines · Marc Zyngier
Now that we are ready to handle deactivation through
ICV_DIR_EL1, set the trap bit if we have active interrupts outside of the LRs.Signed-off-by Marc Zyngier <[email protected]>--- arch/arm64/kvm/vgic/vgic-v3.c | 7 +++++++ 1 file changed, 7 insertions(+)arch/arm64/kvm/vgic/vgic-v3.c +0
-0@@ -42,6 +42,13 @@ void vgic_v3_configure_hcr(struct kvm_vcpu *vcpu, ICH_HCR_EL2_VGrp0DIE : ICH_HCR_EL2_VGrp0EIE;arch/arm64/kvm/vgic/vgic-v3.c void vgic_v3_configure_hcr(struct kvm_vcpu *vcpu, · line 52
Quoted 10 lines
arch/arm64/kvm/vgic/vgic-v3.c +7
-0cpuif->vgic_hcr |= (cpuif->vgic_vmcr &ICH_VMCR_ENG1_MASK ) ? ICH_HCR_EL2_VGrp1DIE : ICH_HCR_EL2_VGrp1EIE; + +/* +* Note that we set the trap irrespective of EOIMode, as that +* can change behind our back without any warning... +*/ +if (irqs_active_outside_lrs (als)) + cpuif->vgic_hcr |=ICH_HCR_EL2_TDIR ; }I just tested these patches as they are on kvmarm/next
2ea7215187c5759fc5d277280e3095b350ca6a50("Merge branch 'kvm-arm64/vgic-lr-overflow' into kvmarm/next"), without any additional pKVM patches. I tried running it with pKVM (non-protected) and with just plain nVHE. In both cases, I get a trap to EL2 (0x18) when booting a non-protected guest, which triggers a bug inhandle_trap()arch/arm64/kvm/hyp/nvhe/hyp-main.c:706
Quoted 3 lines
This trap is happening because of setting this particular trap (TDIR). Just removing this trap from
vgic_v3_configure_hcr()from the ToT on kvmarm/next boots fine.
This is surprising, as I'm not hitting this on actual HW. Are you getting a 0x18 trap? If so, is it coming from the host? Can you correlate the PC with what the host is doing?
It would indicate that we are leaking trap bits on exit, and that QEMU is trapping ICC_DIR_EL1 on top of ICV_DIR_EL1 (which the HW I have access to doesn't seem to do).
Quoted 5 lines
I'm running this on QEMU with '-machine virt,gic-version=3 -cpu max' and the kernel with 'kvm-arm.mode=protected' and with 'kvm-arm.mode=nvhe'.
Let me know if you need any more info or help testing.
On top of the above, could you give the hack below a go? I haven't tested it at all (I'm in the middle of a bisect from hell...)
Thanks,
M.
arch/arm64/kvm/hyp/vgic-v3-sr.c +1 -1
@@ -243,7 +243,7 @@ void __vgic_v3_save_state(struct vgic_v3_cpu_if *cpu_if) cpu_if->vgic_hcr |= val & ICH_HCR_EL2_EOIcount; } -write_gicreg (compute_ich_hcr (cpu_if) & ~ICH_HCR_EL2_En,ICH_HCR_EL2 ); +write_gicreg (0 ,ICH_HCR_EL2 ); }void __vgic_v3_restore_state (struct vgic_v3_cpu_if *cpu_if)
Signature · 1 line
Without deviation from the norm, progress is not possible.
Re: [PATCH v2 29/45] KVM: arm64: GICv3: Set ICH_HCR_EL2.TDIR when interrupts overflow LR capacity
Hi Marc,
Quoted 41 lines · Marc Zyngier
Quoted 38 lines · Fuad Tabba
Hi Marc,
Quoted 15 lines · Marc Zyngier
Now that we are ready to handle deactivation through
ICV_DIR_EL1, set the trap bit if we have active interrupts outside of the LRs.Signed-off-by Marc Zyngier <[email protected]>--- arch/arm64/kvm/vgic/vgic-v3.c | 7 +++++++ 1 file changed, 7 insertions(+)arch/arm64/kvm/vgic/vgic-v3.c +0
-0@@ -42,6 +42,13 @@ void vgic_v3_configure_hcr(struct kvm_vcpu *vcpu, ICH_HCR_EL2_VGrp0DIE : ICH_HCR_EL2_VGrp0EIE;arch/arm64/kvm/vgic/vgic-v3.c void vgic_v3_configure_hcr(struct kvm_vcpu *vcpu, · line 52
Quoted 10 lines
arch/arm64/kvm/vgic/vgic-v3.c +7
-0cpuif->vgic_hcr |= (cpuif->vgic_vmcr &ICH_VMCR_ENG1_MASK ) ? ICH_HCR_EL2_VGrp1DIE : ICH_HCR_EL2_VGrp1EIE; + +/* +* Note that we set the trap irrespective of EOIMode, as that +* can change behind our back without any warning... +*/ +if (irqs_active_outside_lrs (als)) + cpuif->vgic_hcr |=ICH_HCR_EL2_TDIR ; }I just tested these patches as they are on kvmarm/next
2ea7215187c5759fc5d277280e3095b350ca6a50("Merge branch 'kvm-arm64/vgic-lr-overflow' into kvmarm/next"), without any additional pKVM patches. I tried running it with pKVM (non-protected) and with just plain nVHE. In both cases, I get a trap to EL2 (0x18) when booting a non-protected guest, which triggers a bug inhandle_trap()arch/arm64/kvm/hyp/nvhe/hyp-main.c:706
Quoted 7 lines
Quoted 3 lines
This trap is happening because of setting this particular trap (TDIR). Just removing this trap from
vgic_v3_configure_hcr()from the ToT on kvmarm/next boots fine.This is surprising, as I'm not hitting this on actual HW. Are you getting a
0x18trap? If so, is it coming from the host? Can you correlate the PC with what the host is doing?
I should have given you that earlier, sorry.
Yes, it's an 0x18 trap from the host (although it happens when I boot a guest). Here is the relevant part of the backtrace addr2lined and the full one below.
handle_percpu_devid_irq+0x90/0x120 (kernel/irq/chip.c:930) generic_handle_domain_irq+0x40/0x64 (include/linux/irqdesc.h:?) gic_handle_irq+0x4c/0x110 (include/linux/irqdesc.h:?) call_on_irq_stack+0x30/0x48 (arch/arm64/kernel/entry.S:893)
[ 28.454804] Code: d65f03c0 92800008 f9000008 17fffffa (d4210000) [ 28.454873] kvm [266]: Hyp Offset: 0xfff1205c3fe00000 [ 28.455157] Kernel panic - not syncing: HYP panic: [ 28.455157] PS:204023c9 PC:000e5fa4413e39bc ESR:00000000f2000800 [ 28.455157] FAR:ffff800082733d3c HPFAR:0000000000500000 PAR:0000000000000000 [ 28.455157] VCPU:0000000000000000 [ 28.459703] CPU: 5 UID: 0 PID: 266 Comm: kvm-vcpu-0 Not tainted 6.18.0-rc3-g2ea7215187c5 #8 PREEMPT [ 28.460247] Hardware name: linux,dummy-virt (DT) [ 28.460615] Call trace: [ 28.460900] show_stack+0x18/0x24 (C) [ 28.461234] dump_stack_lvl+0x40/0x84 [ 28.461421] dump_stack+0x18/0x24 [ 28.461566] vpanic+0x11c/0x364 [ 28.461698] vpanic+0x0/0x364 [ 28.461838] nvhe_hyp_panic_handler+0x118/0x190 [ 28.462056] handle_percpu_devid_irq+0x90/0x120 [ 28.462248] handle_percpu_devid_irq+0x90/0x120 [ 28.462439] generic_handle_domain_irq+0x40/0x64 [ 28.462643] gic_handle_irq+0x4c/0x110 [ 28.462814] call_on_irq_stack+0x30/0x48 [ 28.463003] do_interrupt_handler+0x4c/0x6c [ 28.463184] el1_interrupt+0x3c/0x60 [ 28.463348] el1h_64_irq_handler+0x18/0x24 [ 28.463525] el1h_64_irq+0x6c/0x70 [ 28.463799] local_daif_restore+0x8/0xc (P) [ 28.463980] el0t_64_sync_handler+0x84/0x12c [ 28.464164] el0t_64_sync+0x198/0x19c
Quoted 4 lines
It would indicate that we are leaking trap bits on exit, and that QEMU is trapping
ICC_DIR_EL1on top ofICV_DIR_EL1(which the HW I have access to doesn't seem to do).
Quoted 8 lines
Quoted 5 lines
I'm running this on QEMU with '-machine virt,gic-version=3 -cpu max' and the kernel with 'kvm-arm.mode=protected' and with 'kvm-arm.mode=nvhe'.
Let me know if you need any more info or help testing.
On top of the above, could you give the hack below a go? I haven't tested it at all (I'm in the middle of a bisect from hell...)
With the hack it boots, both nvhe and protected mode.
Cheers,
/fuad
Quoted 20 lines
Thanks,
M.arch/arm64/kvm/hyp/vgic-v3-sr.c +1
-2@@ -243,7 +243,7 @@ void __vgic_v3_save_state(struct vgic_v3_cpu_if *cpu_if) cpu_if->vgic_hcr |= val & ICH_HCR_EL2_EOIcount; } -write_gicreg (compute_ich_hcr (cpu_if) & ~ICH_HCR_EL2_En,ICH_HCR_EL2 ); +write_gicreg (0 ,ICH_HCR_EL2 ); }void __vgic_v3_restore_state (struct vgic_v3_cpu_if *cpu_if) --Without deviation from the norm, progress is not possible.
Marc Zyngier
maintainerRe: [PATCH v2 29/45] KVM: arm64: GICv3: Set ICH_HCR_EL2.TDIR when interrupts overflow LR capacity
Quoted 64 lines · Fuad Tabba
Hi Marc,
Quoted 41 lines · Marc Zyngier
Quoted 38 lines · Fuad Tabba
Hi Marc,
Quoted 15 lines · Marc Zyngier
Now that we are ready to handle deactivation through
ICV_DIR_EL1, set the trap bit if we have active interrupts outside of the LRs.Signed-off-by Marc Zyngier <[email protected]>--- arch/arm64/kvm/vgic/vgic-v3.c | 7 +++++++ 1 file changed, 7 insertions(+)arch/arm64/kvm/vgic/vgic-v3.c +0
-0@@ -42,6 +42,13 @@ void vgic_v3_configure_hcr(struct kvm_vcpu *vcpu, ICH_HCR_EL2_VGrp0DIE : ICH_HCR_EL2_VGrp0EIE;arch/arm64/kvm/vgic/vgic-v3.c void vgic_v3_configure_hcr(struct kvm_vcpu *vcpu, · line 52
Quoted 10 lines
arch/arm64/kvm/vgic/vgic-v3.c +7
-0cpuif->vgic_hcr |= (cpuif->vgic_vmcr &ICH_VMCR_ENG1_MASK ) ? ICH_HCR_EL2_VGrp1DIE : ICH_HCR_EL2_VGrp1EIE; + +/* +* Note that we set the trap irrespective of EOIMode, as that +* can change behind our back without any warning... +*/ +if (irqs_active_outside_lrs (als)) + cpuif->vgic_hcr |=ICH_HCR_EL2_TDIR ; }I just tested these patches as they are on kvmarm/next
2ea7215187c5759fc5d277280e3095b350ca6a50("Merge branch 'kvm-arm64/vgic-lr-overflow' into kvmarm/next"), without any additional pKVM patches. I tried running it with pKVM (non-protected) and with just plain nVHE. In both cases, I get a trap to EL2 (0x18) when booting a non-protected guest, which triggers a bug inhandle_trap()arch/arm64/kvm/hyp/nvhe/hyp-main.c:706Quoted 7 lines
Quoted 3 lines
This trap is happening because of setting this particular trap (TDIR). Just removing this trap from
vgic_v3_configure_hcr()from the ToT on kvmarm/next boots fine.This is surprising, as I'm not hitting this on actual HW. Are you getting a
0x18trap? If so, is it coming from the host? Can you correlate the PC with what the host is doing?I should have given you that earlier, sorry.
Yes, it's an
0x18trap from the host (although it happens when I boot a guest). Here is the relevant part of the backtrace addr2lined and the full one below.handle_percpu_devid_irq+0x90/0x120 (kernel/irq/chip.c:930) generic_handle_domain_irq+0x40/0x64 (include/linux/irqdesc.h:?) gic_handle_irq+0x4c/0x110 (include/linux/irqdesc.h:?) call_on_irq_stack+0x30/0x48 (arch/arm64/kernel/entry.S:893)
Quoted 5 lines
[ 28.454804] Code: d65f03c0 92800008 f9000008 17fffffa (d4210000) [ 28.454873] kvm [266]: Hyp Offset: 0xfff1205c3fe00000 [ 28.455157] Kernel panic - not syncing: HYP panic: [ 28.455157] PS:204023c9 PC:000e5fa4413e39bc ESR:00000000f2000800 [ 28.455157] FAR:ffff800082733d3c HPFAR:0000000000500000 PAR:0000000000000000
I expect you have a write to ICC_DIR_EL1 at this address?
Quoted 32 lines
[ 28.455157] VCPU:0000000000000000 [ 28.459703] CPU: 5 UID: 0 PID: 266 Comm: kvm-vcpu-0 Not tainted 6.18.0-rc3-g2ea7215187c5 #8 PREEMPT [ 28.460247] Hardware name: linux,dummy-virt (DT) [ 28.460615] Call trace: [ 28.460900] show_stack+0x18/0x24 (C) [ 28.461234] dump_stack_lvl+0x40/0x84 [ 28.461421] dump_stack+0x18/0x24 [ 28.461566] vpanic+0x11c/0x364 [ 28.461698] vpanic+0x0/0x364 [ 28.461838] nvhe_hyp_panic_handler+0x118/0x190 [ 28.462056] handle_percpu_devid_irq+0x90/0x120 [ 28.462248] handle_percpu_devid_irq+0x90/0x120 [ 28.462439] generic_handle_domain_irq+0x40/0x64 [ 28.462643] gic_handle_irq+0x4c/0x110 [ 28.462814] call_on_irq_stack+0x30/0x48 [ 28.463003] do_interrupt_handler+0x4c/0x6c [ 28.463184] el1_interrupt+0x3c/0x60 [ 28.463348] el1h_64_irq_handler+0x18/0x24 [ 28.463525] el1h_64_irq+0x6c/0x70 [ 28.463799] local_daif_restore+0x8/0xc (P) [ 28.463980] el0t_64_sync_handler+0x84/0x12c [ 28.464164] el0t_64_sync+0x198/0x19cQuoted 8 lines
It would indicate that we are leaking trap bits on exit, and that QEMU is trapping
ICC_DIR_EL1on top ofICV_DIR_EL1(which the HW I have access to doesn't seem to do).Quoted 4 lines
I'm running this on QEMU with '-machine virt,gic-version=3 -cpu max' and the kernel with 'kvm-arm.mode=protected' and with 'kvm-arm.mode=nvhe'.
Quoted 6 lines
Quoted 4 lines
Quoted 1 line
Let me know if you need any more info or help testing.
On top of the above, could you give the hack below a go? I haven't tested it at all (I'm in the middle of a bisect from hell...)
With the hack it boots, both nvhe and protected mode.
OK. At least we know what the issue is, and it shouldn't be too hard to fix. I guess there is an opportunity for cleanup here, and I'll look into it shortly (probably not before Monday though).
Thanks again,
M.
Signature · 1 line
Without deviation from the norm, progress is not possible.
Re: [PATCH v2 29/45] KVM: arm64: GICv3: Set ICH_HCR_EL2.TDIR when interrupts overflow LR capacity
Hi Marc,
Quoted 67 lines · Marc Zyngier
Quoted 64 lines · Fuad Tabba
Hi Marc,
Quoted 41 lines · Marc Zyngier
Quoted 38 lines · Fuad Tabba
Hi Marc,
Quoted 15 lines · Marc Zyngier
Now that we are ready to handle deactivation through
ICV_DIR_EL1, set the trap bit if we have active interrupts outside of the LRs.Signed-off-by Marc Zyngier <[email protected]>--- arch/arm64/kvm/vgic/vgic-v3.c | 7 +++++++ 1 file changed, 7 insertions(+)arch/arm64/kvm/vgic/vgic-v3.c +0
-0@@ -42,6 +42,13 @@ void vgic_v3_configure_hcr(struct kvm_vcpu *vcpu, ICH_HCR_EL2_VGrp0DIE : ICH_HCR_EL2_VGrp0EIE;arch/arm64/kvm/vgic/vgic-v3.c void vgic_v3_configure_hcr(struct kvm_vcpu *vcpu, · line 52
Quoted 10 lines
arch/arm64/kvm/vgic/vgic-v3.c +7
-0cpuif->vgic_hcr |= (cpuif->vgic_vmcr &ICH_VMCR_ENG1_MASK ) ? ICH_HCR_EL2_VGrp1DIE : ICH_HCR_EL2_VGrp1EIE; + +/* +* Note that we set the trap irrespective of EOIMode, as that +* can change behind our back without any warning... +*/ +if (irqs_active_outside_lrs (als)) + cpuif->vgic_hcr |=ICH_HCR_EL2_TDIR ; }I just tested these patches as they are on kvmarm/next
2ea7215187c5759fc5d277280e3095b350ca6a50("Merge branch 'kvm-arm64/vgic-lr-overflow' into kvmarm/next"), without any additional pKVM patches. I tried running it with pKVM (non-protected) and with just plain nVHE. In both cases, I get a trap to EL2 (0x18) when booting a non-protected guest, which triggers a bug inhandle_trap()arch/arm64/kvm/hyp/nvhe/hyp-main.c:706Quoted 7 lines
Quoted 3 lines
This trap is happening because of setting this particular trap (TDIR). Just removing this trap from
vgic_v3_configure_hcr()from the ToT on kvmarm/next boots fine.This is surprising, as I'm not hitting this on actual HW. Are you getting a
0x18trap? If so, is it coming from the host? Can you correlate the PC with what the host is doing?I should have given you that earlier, sorry.
Yes, it's an
0x18trap from the host (although it happens when I boot a guest). Here is the relevant part of the backtrace addr2lined and the full one below.handle_percpu_devid_irq+0x90/0x120 (kernel/irq/chip.c:930) generic_handle_domain_irq+0x40/0x64 (include/linux/irqdesc.h:?) gic_handle_irq+0x4c/0x110 (include/linux/irqdesc.h:?) call_on_irq_stack+0x30/0x48 (arch/arm64/kernel/entry.S:893)
Quoted 7 lines
Quoted 5 lines
[ 28.454804] Code: d65f03c0 92800008 f9000008 17fffffa (d4210000) [ 28.454873] kvm [266]: Hyp Offset: 0xfff1205c3fe00000 [ 28.455157] Kernel panic - not syncing: HYP panic: [ 28.455157] PS:204023c9 PC:000e5fa4413e39bc ESR:00000000f2000800 [ 28.455157] FAR:ffff800082733d3c HPFAR:0000000000500000 PAR:0000000000000000I expect you have a write to
ICC_DIR_EL1at this address?
It almost surely must be, but tracking it down hasn't been that easy. That said, I think it's ending up in gic_eoimode1_eoi_irq(), which calls gic_write_dir() if !gic_arm64_erratum_2941627_needed(d).
I wonder if your hardware needs that erratum.
Quoted 34 lines
Quoted 34 lines
[ 28.455157] VCPU:0000000000000000 [ 28.459703] CPU: 5 UID: 0 PID: 266 Comm: kvm-vcpu-0 Not tainted 6.18.0-rc3-g2ea7215187c5 #8 PREEMPT [ 28.460247] Hardware name: linux,dummy-virt (DT) [ 28.460615] Call trace: [ 28.460900] show_stack+0x18/0x24 (C) [ 28.461234] dump_stack_lvl+0x40/0x84 [ 28.461421] dump_stack+0x18/0x24 [ 28.461566] vpanic+0x11c/0x364 [ 28.461698] vpanic+0x0/0x364 [ 28.461838] nvhe_hyp_panic_handler+0x118/0x190 [ 28.462056] handle_percpu_devid_irq+0x90/0x120 [ 28.462248] handle_percpu_devid_irq+0x90/0x120 [ 28.462439] generic_handle_domain_irq+0x40/0x64 [ 28.462643] gic_handle_irq+0x4c/0x110 [ 28.462814] call_on_irq_stack+0x30/0x48 [ 28.463003] do_interrupt_handler+0x4c/0x6c [ 28.463184] el1_interrupt+0x3c/0x60 [ 28.463348] el1h_64_irq_handler+0x18/0x24 [ 28.463525] el1h_64_irq+0x6c/0x70 [ 28.463799] local_daif_restore+0x8/0xc (P) [ 28.463980] el0t_64_sync_handler+0x84/0x12c [ 28.464164] el0t_64_sync+0x198/0x19cQuoted 10 lines
It would indicate that we are leaking trap bits on exit, and that QEMU is trapping
ICC_DIR_EL1on top ofICV_DIR_EL1(which the HW I have access to doesn't seem to do).Quoted 5 lines
I'm running this on QEMU with '-machine virt,gic-version=3 -cpu max' and the kernel with 'kvm-arm.mode=protected' and with 'kvm-arm.mode=nvhe'.
Let me know if you need any more info or help testing.
Quoted 8 lines
Quoted 4 lines
Quoted 2 lines
On top of the above, could you give the hack below a go? I haven't tested it at all (I'm in the middle of a bisect from hell...)
With the hack it boots, both nvhe and protected mode.
OK. At least we know what the issue is, and it shouldn't be too hard to fix. I guess there is an opportunity for cleanup here, and I'll look into it shortly (probably not before Monday though).
No hurry on my part. I'm just here for the reviews :)
Cheers,
/fuad
Quoted 6 lines
Thanks again,
M.--
Without deviation from the norm, progress is not possible.
Marc Zyngier
maintainerRe: [PATCH v2 29/45] KVM: arm64: GICv3: Set ICH_HCR_EL2.TDIR when interrupts overflow LR capacity
Quoted 77 lines · Fuad Tabba
Hi Marc,
Quoted 73 lines · Marc Zyngier
Quoted 69 lines · Fuad Tabba
Hi Marc,
Quoted 41 lines · Marc Zyngier
Quoted 38 lines · Fuad Tabba
Hi Marc,
Quoted 15 lines · Marc Zyngier
Now that we are ready to handle deactivation through
ICV_DIR_EL1, set the trap bit if we have active interrupts outside of the LRs.Signed-off-by Marc Zyngier <[email protected]>--- arch/arm64/kvm/vgic/vgic-v3.c | 7 +++++++ 1 file changed, 7 insertions(+)arch/arm64/kvm/vgic/vgic-v3.c +0
-0@@ -42,6 +42,13 @@ void vgic_v3_configure_hcr(struct kvm_vcpu *vcpu, ICH_HCR_EL2_VGrp0DIE : ICH_HCR_EL2_VGrp0EIE;arch/arm64/kvm/vgic/vgic-v3.c void vgic_v3_configure_hcr(struct kvm_vcpu *vcpu, · line 52
Quoted 10 lines
arch/arm64/kvm/vgic/vgic-v3.c +7
-0cpuif->vgic_hcr |= (cpuif->vgic_vmcr &ICH_VMCR_ENG1_MASK ) ? ICH_HCR_EL2_VGrp1DIE : ICH_HCR_EL2_VGrp1EIE; + +/* +* Note that we set the trap irrespective of EOIMode, as that +* can change behind our back without any warning... +*/ +if (irqs_active_outside_lrs (als)) + cpuif->vgic_hcr |=ICH_HCR_EL2_TDIR ; }I just tested these patches as they are on kvmarm/next
2ea7215187c5759fc5d277280e3095b350ca6a50("Merge branch 'kvm-arm64/vgic-lr-overflow' into kvmarm/next"), without any additional pKVM patches. I tried running it with pKVM (non-protected) and with just plain nVHE. In both cases, I get a trap to EL2 (0x18) when booting a non-protected guest, which triggers a bug inhandle_trap()arch/arm64/kvm/hyp/nvhe/hyp-main.c:706Quoted 7 lines
Quoted 3 lines
This trap is happening because of setting this particular trap (TDIR). Just removing this trap from
vgic_v3_configure_hcr()from the ToT on kvmarm/next boots fine.This is surprising, as I'm not hitting this on actual HW. Are you getting a
0x18trap? If so, is it coming from the host? Can you correlate the PC with what the host is doing?I should have given you that earlier, sorry.
Yes, it's an
0x18trap from the host (although it happens when I boot a guest). Here is the relevant part of the backtrace addr2lined and the full one below.handle_percpu_devid_irq+0x90/0x120 (kernel/irq/chip.c:930) generic_handle_domain_irq+0x40/0x64 (include/linux/irqdesc.h:?) gic_handle_irq+0x4c/0x110 (include/linux/irqdesc.h:?) call_on_irq_stack+0x30/0x48 (arch/arm64/kernel/entry.S:893)[ 28.454804] Code: d65f03c0 92800008 f9000008 17fffffa (d4210000) [ 28.454873] kvm [266]: Hyp Offset: 0xfff1205c3fe00000 [ 28.455157] Kernel panic - not syncing: HYP panic: [ 28.455157] PS:204023c9 PC:000e5fa4413e39bc ESR:00000000f2000800 [ 28.455157] FAR:ffff800082733d3c HPFAR:0000000000500000 PAR:0000000000000000
Quoted 7 lines
Quoted 1 line
I expect you have a write to
ICC_DIR_EL1at this address?It almost surely must be, but tracking it down hasn't been that easy. That said, I think it's ending up in
gic_eoimode1_eoi_irq(), which callsgic_write_dir()if !gic_arm64_erratum_2941627_needed(d).I wonder if your hardware needs that erratum.
No, it doesn't. And this erratum only kicks in if the deactivated interrupt is an SPI that has been moved to another CPU while being handled (i.e. never).
It really isn't related to the GIC itself (which the erratum above is about), but to the CPU interface, and whether TDIR applies to ICC_DIR_EL1 on top of the virtual variant.
The architecture "deprecates" not trapping, and QEMU abides by this deprecation. HW that predates the deprecation didn't get the message, oddly enough... Neither did I, until you reported the crash!
Thanks,
M.
Signature · 1 line
Without deviation from the norm, progress is not possible.
Re: [PATCH v2 29/45] KVM: arm64: GICv3: Set ICH_HCR_EL2.TDIR when interrupts overflow LR capacity
In reply to Marc ZyngierQuoted 19 lines · Marc Zyngier
Quoted 17 lines · Fuad Tabba
Review
Quoted 7 lines · Marc Zyngier
(quoted diff) +6
-0+ /* + * Note that we set the trap irrespective of EOIMode, as that + * can change behind our back without any warning... + */ + if (irqs_active_outside_lrs(als)) + cpuif->vgic_hcr |= ICH_HCR_EL2_TDIR; }I just tested these patches as they are on kvmarm/next
2ea7215187c5759fc5d277280e3095b350ca6a50("Merge branch 'kvm-arm64/vgic-lr-overflow' into kvmarm/next"), without any additional pKVM patches. I tried running it with pKVM (non-protected) and with just plain nVHE. In both cases, I get a trap to EL2 (0x18) when booting a non-protected guest, which triggers a bug inhandle_trap()arch/arm64/kvm/hyp/nvhe/hyp-main.c:706
Quoted 7 lines
Quoted 3 lines
This trap is happening because of setting this particular trap (TDIR). Just removing this trap from
vgic_v3_configure_hcr()from the ToT on kvmarm/next boots fine.This is surprising, as I'm not hitting this on actual HW. Are you getting a
0x18trap? If so, is it coming from the host? Can you correlate the PC with what the host is doing?
FWIW I am seeing this on i.MX8MP (4xA53+GICv3):
https://lava.sirena.org.uk/scheduler/job/2118713#L1044
I'm also seeing boot failures on AM625 in pKVM mode but much earlier, before any console output, so there's some confounding issue in that case (non-pKVM boots on the platform seemed fine, I'll investigate if it's still a problem in today's -next).
Marc Zyngier
maintainerRe: [PATCH v2 29/45] KVM: arm64: GICv3: Set ICH_HCR_EL2.TDIR when interrupts overflow LR capacity
Quoted 26 lines · Mark Brown
[1 <text/plain; us-ascii (quoted-printable)>]
Quoted 22 lines · Marc Zyngier
Quoted 21 lines · Fuad Tabba
Review
Quoted 7 lines · Marc Zyngier
(quoted diff) +6
-0+ /* + * Note that we set the trap irrespective of EOIMode, as that + * can change behind our back without any warning... + */ + if (irqs_active_outside_lrs(als)) + cpuif->vgic_hcr |= ICH_HCR_EL2_TDIR; }I just tested these patches as they are on kvmarm/next
2ea7215187c5759fc5d277280e3095b350ca6a50("Merge branch 'kvm-arm64/vgic-lr-overflow' into kvmarm/next"), without any additional pKVM patches. I tried running it with pKVM (non-protected) and with just plain nVHE. In both cases, I get a trap to EL2 (0x18) when booting a non-protected guest, which triggers a bug inhandle_trap()arch/arm64/kvm/hyp/nvhe/hyp-main.c:706This trap is happening because of setting this particular trap (TDIR). Just removing this trap from
vgic_v3_configure_hcr()from the ToT on kvmarm/next boots fine.
Quoted 7 lines
Quoted 3 lines
This is surprising, as I'm not hitting this on actual HW. Are you getting a
0x18trap? If so, is it coming from the host? Can you correlate the PC with what the host is doing?FWIW I am seeing this on i.MX8MP (4xA53+GICv3):
There are worrying errors way before that, in the VMID allocator init, and I can't see what the GIC has to do with it. The issue Fuad reported was at run time, not boot time. so this really doesn't align with what you are seeing.
M.
Signature · 1 line
Without deviation from the norm, progress is not possible.
Re: [PATCH v2 29/45] KVM: arm64: GICv3: Set ICH_HCR_EL2.TDIR when interrupts overflow LR capacity
Quoted 10 lines · Marc Zyngier
Quoted 3 lines · Mark Brown
FWIW I am seeing this on i.MX8MP (4xA53+GICv3):
There are worrying errors way before that, in the VMID allocator init, and I can't see what the GIC has to do with it. The issue Fuad reported was at run time, not boot time. so this really doesn't align with what you are seeing.
Yeah, I was just looking further and realising it was probably different - sorry about that. I was checking what else was failing after seeing the qemu issue he was, all the platforms aren't booting one way or another. FWIW with earlycon on the AM625 is showing similar issues to the i.MX8MP.
Marc Zyngier
maintainerRe: [PATCH v2 29/45] KVM: arm64: GICv3: Set ICH_HCR_EL2.TDIR when interrupts overflow LR capacity
Quoted 14 lines · Mark Brown
[1 <text/plain; us-ascii (7bit)>]
Quoted 10 lines · Marc Zyngier
Quoted 3 lines · Mark Brown
FWIW I am seeing this on i.MX8MP (4xA53+GICv3):
There are worrying errors way before that, in the VMID allocator init, and I can't see what the GIC has to do with it. The issue Fuad reported was at run time, not boot time. so this really doesn't align with what you are seeing.
Quoted 5 lines
Yeah, I was just looking further and realising it was probably different - sorry about that. I was checking what else was failing after seeing the qemu issue he was, all the platforms aren't booting one way or another. FWIW with earlycon on the AM625 is showing similar issues to the i.MX8MP.
That's the initial warning:
WARN_ON(NUM_USER_VMIDS - 1 <= num_possible_cpus());
The register state:
[ 224.378174] pc : kvm_arm_vmid_alloc_init+0xa0/0xc0 [ 224.382954] lr : kvm_arm_vmid_alloc_init+0x24/0xc0 [ 224.387734] sp : ffff80008009bd40 [ 224.391035] x29: ffff80008009bd40 x28: ffff0020209bd3c0 x27: ffffce5349159068 [ 224.398162] x26: ffffce5349070118 x25: ffffce5348fb8eb8 x24: ffffce5349059128 [ 224.405287] x23: 0000000000000109 x22: ffff0020208ea6c0 x21: 0000000000000004 [ 224.412413] x20: ffffce5349c20b78 x19: 0000000000000000 x18: 00000000ffffffff [ 224.419538] x17: 00000000e9a61a0d x16: 00000000b1c06f2c x15: 00000000ffffffff [ 224.426663] x14: 0000000000000000 x13: 7374696220343420 x12: 3a74696d694c2065 [ 224.433789] x11: ffffffffffe00000 x10: ffff00275c260000 x9 : ffffce5348048be0 [ 224.440914] x8 : 00000000fffeffff x7 : ffff00275c260000 x6 : 80000000ffff0000 [ 224.448039] x5 : 0000000000000048 x4 : 0000000000000110 x3 : ffffce5348fc1000 [ 224.455164] x2 : 0000000000000100 x1 : 0000000000000100 x0 : 00000000000000ff
The disassembly:
ffff8000816ff220 <kvm_arm_vmid_alloc_init>:
ffff8000816ff220: d503201f nop ffff8000816ff224: d503201f nop ffff8000816ff228: d503233f paciasp ffff8000816ff22c: a9be7bfd stp x29, x30, [sp, #-32]! ffff8000816ff230: 5280e400 mov w0, #0x720 // #1824 ffff8000816ff234: 910003fd mov x29, sp ffff8000816ff238: 72a00300 movk w0, #0x18, lsl #16 ffff8000816ff23c: f9000bf3 str x19, [sp, #16] ffff8000816ff240: 97a4a61c bl ffff800080028ab0 <read_sanitised_ftr_reg> ffff8000816ff244: d3441c00 ubfx x0, x0, #4, #4 ffff8000816ff248: d0fffa02 adrp x2, ffff800081641000 <rodata_full> ffff8000816ff24c: d0fffa03 adrp x3, ffff800081641000 <rodata_full> ffff8000816ff250: f100081f cmp x0, #0x2 ffff8000816ff254: 52800201 mov w1, #0x10 // #16 ffff8000816ff258: b940f044 ldr w4, [x2, #240] ffff8000816ff25c: 52800102 mov w2, #0x8 // #8 ffff8000816ff260: d29fffe0 mov x0, #0xffff // #65535 ffff8000816ff264: 1a820021 csel w1, w1, w2, eq // eq = none ffff8000816ff268: d2801fe2 mov x2, #0xff // #255 ffff8000816ff26c: b9005061 str w1, [x3, #80] ffff8000816ff270: 9a820000 csel x0, x0, x2, eq // eq = none ffff8000816ff274: d2802001 mov x1, #0x100 // #256 ffff8000816ff278: d2a00022 mov x2, #0x10000 // #65536 ffff8000816ff27c: 9a810042 csel x2, x2, x1, eq // eq = none ffff8000816ff280: eb00009f cmp x4, x0 ffff8000816ff284: 540001e2 b.cs ffff8000816ff2c0 <kvm_arm_vmid_alloc_init+0xa0> // b.hs, b.nlast
That's the branch to the...
[...]
ffff8000816ff2c0: d4210000 brk #0x800
... BRK instruction.
So x0=255 and x4=272. 272 possible CPUs on a machine with only 16? Bollocks.
Something is badly screwed in -next, and I'm not convinced it is KVM.
d0f23ccf6ba9e cpumask: Cache num_possible_cpus()
is my current suspect.
M.
Signature · 1 line
Without deviation from the norm, progress is not possible.
Marc Zyngier
maintainerRe: [PATCH v2 29/45] KVM: arm64: GICv3: Set ICH_HCR_EL2.TDIR when interrupts overflow LR capacity
Quoted 6 lines · Marc Zyngier
Something is badly screwed in -next, and I'm not convinced it is KVM.
d0f23ccf6ba9ecpumask: Cachenum_possible_cpus()is my current suspect.
Confirmed, and the fix is at 21782b3a5cd40892cb2995aa1ec3e74dd1112f1d.
M.
Signature · 1 line
Without deviation from the norm, progress is not possible.
Re: [PATCH v2 29/45] KVM: arm64: GICv3: Set ICH_HCR_EL2.TDIR when interrupts overflow LR capacity
Quoted 9 lines · Marc Zyngier
Quoted 5 lines · Marc Zyngier
Something is badly screwed in -next, and I'm not convinced it is KVM.
d0f23ccf6ba9ecpumask: Cachenum_possible_cpus()is my current suspect.
Confirmed, and the fix is at
21782b3a5cd40892cb2995aa1ec3e74dd1112f1d.
Great, thanks for checking. Unfortunately it looks like that missed today's -next but hopefully it'll show up tomorrow.
Marc Zyngier
maintainerPATCH v2 30/45 KVM: arm64: GICv3: Add SPI tracking to handle asymmetric deactivation
In reply to Marc ZyngierSPIs are specially annpying, as they can be activated on a CPU and deactivated on another. WHich means that when an SPI is in flight anywhere, all CPUs need to have their TDIR trap bit set.
This translates into broadcasting an IPI across all CPUs to make sure they set their trap bit, The number of in-flight SPIs is kept in an atomic variable so that CPUs can turn the trap bit off as soon as possible.
--- arch/arm64/kvm/vgic/vgic-init.c | 1 + arch/arm64/kvm/vgic/vgic-v3.c | 21 +++++++++++++++------ arch/arm64/kvm/vgic/vgic.c | 25 +++++++++++++++++++++++-- include/kvm/arm_vgic.h | 3 +++ 4 files changed, 42 insertions(+), 8 deletions(-)
arch/arm64/kvm/vgic/vgic-init.c +1 -0
@@ -188,6 +188,7 @@ static int kvm_vgic_dist_init(struct kvm *kvm, unsigned int nr_spis)struct kvm_vcpu *vcpu0 =kvm_get_vcpu (kvm,0 );int i; + dist->active_spis = (atomic_t )ATOMIC_INIT (0 ); dist->spis =kcalloc (nr_spis,sizeof (struct vgic_irq ),GFP_KERNEL_ACCOUNT );if (!dist->spis)return -ENOMEM ;
arch/arm64/kvm/vgic/vgic-v3.c +15 -6
@@ -44,10 +44,17 @@ void vgic_v3_configure_hcr(struct kvm_vcpu *vcpu, ICH_HCR_EL2_VGrp1DIE : ICH_HCR_EL2_VGrp1EIE;/* +* Dealing with EOImode=1 is a massive source of headache. Not +* only do we need to track that we have active interrupts +* outside of the LRs and force DIR to be trapped, we also +* need to deal with SPIs that can be deactivated on another +* CPU. +* * Note that we set the trap irrespective of EOIMode, as that * can change behind our back without any warning... */ -if (irqs_active_outside_lrs (als)) +if (irqs_active_outside_lrs (als) || +atomic_read (&vcpu->kvm->arch.vgic.active_spis)) cpuif->vgic_hcr |=ICH_HCR_EL2_TDIR ; }
@@ -75,11 +82,6 @@ static void vgic_v3_fold_lr(struct kvm_vcpu *vcpu, u64 val)if (!irq)/* An LPI could have been unmapped. */ return ; -/* Notify fds when the guest EOI'ed a level-triggered IRQ */ -if (lr_signals_eoi_mi (val) &&vgic_valid_spi (vcpu->kvm, intid)) -kvm_notify_acked_irq (vcpu->kvm,0 , - intid -VGIC_NR_PRIVATE_IRQS ); - scoped_guard(raw_spinlock, &irq->irq_lock) {/* Always preserve the active bit for !LPIs, note deactivation */ if (irq->intid >=VGIC_MIN_LPI )
@@ -114,6 +116,13 @@ static void vgic_v3_fold_lr(struct kvm_vcpu *vcpu, u64 val) irq->on_lr = false; } +/* Notify fds when the guest EOI'ed a level-triggered SPI, and drop the refcount */ +if (deactivated &&lr_signals_eoi_mi (val) &&vgic_valid_spi (vcpu->kvm, intid)) { +kvm_notify_acked_irq (vcpu->kvm,0 , + intid -VGIC_NR_PRIVATE_IRQS ); +atomic_dec_if_positive (&vcpu->kvm->arch.vgic.active_spis); + } +vgic_put_irq (vcpu->kvm, irq); }
arch/arm64/kvm/vgic/vgic.c +23 -2
@@ -367,6 +367,17 @@ static bool vgic_validate_injection(struct vgic_irq *irq, bool level, void *ownereturn false; } +static bool vgic_model_needs_bcst_kick (struct kvm *kvm) +{ +/* +* A GICv3 (or GICv3-like) system exposing a GICv3 to the +* guest needs a broadcast kick to set TDIR globally, even if +* the bit doesn't really exist (we still need to check for +* the shadow bit in the DIR emulation fast-path). +*/ +return (kvm->arch.vgic.vgic_model ==KVM_DEV_TYPE_ARM_VGIC_V3 ); +} +/* * Check whether an IRQ needs to (and can) be queued to a VCPU's ap list. * Do the queuing if necessary, taking the right locks in the right order.
@@ -379,6 +390,7 @@ bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq, unsigned long flags) __releases(&irq->irq_lock) {struct kvm_vcpu *vcpu; +bool bcast;lockdep_assert_held (&irq->irq_lock);
@@ -453,11 +465,20 @@ bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq,list_add_tail (&irq->ap_list, &vcpu->arch.vgic_cpu.ap_list_head); irq->vcpu = vcpu; +/* A new SPI may result in deactivation trapping on all vcpus */ + bcast = (vgic_model_needs_bcst_kick (vcpu->kvm) && +vgic_valid_spi (vcpu->kvm, irq->intid) && +atomic_fetch_inc (&vcpu->kvm->arch.vgic.active_spis) ==0 ); +raw_spin_unlock (&irq->irq_lock);raw_spin_unlock_irqrestore (&vcpu->arch.vgic_cpu.ap_list_lock, flags); -kvm_make_request (KVM_REQ_IRQ_PENDING , vcpu); -kvm_vcpu_kick (vcpu); +if (!bcast) { +kvm_make_request (KVM_REQ_IRQ_PENDING , vcpu); +kvm_vcpu_kick (vcpu); + }else { +kvm_make_all_cpus_request (vcpu->kvm,KVM_REQ_IRQ_PENDING ); + }return true; }
include/kvm/arm_vgic.h +3 -0
@@ -263,6 +263,9 @@ struct vgic_dist {/* The GIC maintenance IRQ for nested hypervisors. */ u32 mi_intid; +/* Track the number of in-flight active SPIs */ +atomic_t active_spis; +/* base addresses in guest physical address space: */ gpa_t vgic_dist_base;/* distributor */ union {
Signature · 1 line
2.47.3
Marc Zyngier
maintainerPATCH v2 31/45 KVM: arm64: GICv3: Handle in-LR deactivation when possible
In reply to Marc ZyngierEven when we have either an LR overflow or SPIs in flight, it is extremely likely that the interrupt being deactivated is still in the LRs, and that going all the way back to the the generic trap handling code is a waste of time.
Instead, try and deactivate in place when possible, and only if this fails, perform a full exit.
--- arch/arm64/kvm/hyp/vgic-v3-sr.c | 38 ++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 10 deletions(-)
arch/arm64/kvm/hyp/vgic-v3-sr.c +28 -10
@@ -792,7 +792,7 @@ static void __vgic_v3_bump_eoicount(void)write_gicreg (hcr,ICH_HCR_EL2 ); } -static void __vgic_v3_write_dir (struct kvm_vcpu *vcpu,u32 vmcr,int rt) +static int ___vgic_v3_write_dir (struct kvm_vcpu *vcpu,u32 vmcr,int rt) {u32 vid =vcpu_get_reg (vcpu, rt);u64 lr_val;
@@ -800,19 +800,25 @@ static void __vgic_v3_write_dir(struct kvm_vcpu *vcpu, u32 vmcr, int rt)/* EOImode == 0, nothing to be done here */ if (!(vmcr &ICH_VMCR_EOIM_MASK )) -return ; +return 1 ;/* No deactivate to be performed on an LPI */ if (vid >=VGIC_MIN_LPI ) -return ; +return 1 ; lr =__vgic_v3_find_active_lr (vcpu, vid, &lr_val); -if (lr ==-1 ) { -__vgic_v3_bump_eoicount (); -return ; +if (lr !=-1 ) { +__vgic_v3_clear_active_lr (lr, lr_val); +return 1 ; } -__vgic_v3_clear_active_lr (lr, lr_val); +return 0 ; +} + +static void __vgic_v3_write_dir (struct kvm_vcpu *vcpu,u32 vmcr,int rt) +{ +if (!___vgic_v3_write_dir (vcpu, vmcr, rt)) +__vgic_v3_bump_eoicount (); }static void __vgic_v3_write_eoir (struct kvm_vcpu *vcpu,u32 vmcr,int rt)
@@ -1247,9 +1253,21 @@ int __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)case SYS_ICC_DIR_EL1 :if (unlikely (is_read))return 0 ; -/* Full exit if required to handle overflow deactivation... */ -if (vcpu->arch.vgic_cpu.vgic_v3.vgic_hcr &ICH_HCR_EL2_TDIR ) -return 0 ; +/* +* Full exit if required to handle overflow deactivation, +* unless we can emulate it in the LRs (likely the majority +* of the cases). +*/ +if (vcpu->arch.vgic_cpu.vgic_v3.vgic_hcr &ICH_HCR_EL2_TDIR ) { +int ret; + + ret =___vgic_v3_write_dir (vcpu,__vgic_v3_read_vmcr (), +kvm_vcpu_sys_get_rt (vcpu)); +if (ret) +__kvm_skip_instr (vcpu); + +return ret; + } fn = __vgic_v3_write_dir;break ;case SYS_ICC_RPR_EL1 :
Signature · 1 line
2.47.3
Marc Zyngier
maintainerPATCH v2 32/45 KVM: arm64: GICv3: Avoid broadcast kick on CPUs lacking TDIR
In reply to Marc ZyngierCPUs lacking TDIR always trap ICV_DIR_EL1, no matter what, since we have ICH_HCR_EL2.TC set permanently. For these CPUs, it is useless to use a broadcast kick on SPI injection, as the sole purpose of this is to set TDIR.
We can therefore skip this on these CPUs, which are challenged enough not to be burdened by extra IPIs. As a consequence, permanently set the TDIR bit in the shadow state to notify the fast-path emulation code of the exit reason.
--- arch/arm64/kvm/vgic/vgic-v3.c | 6 +++++- arch/arm64/kvm/vgic/vgic.c | 13 ++++++++----- 2 files changed, 13 insertions(+), 6 deletions(-)
arch/arm64/kvm/vgic/vgic-v3.c +5 -1
@@ -50,10 +50,14 @@ void vgic_v3_configure_hcr(struct kvm_vcpu *vcpu,* need to deal with SPIs that can be deactivated on another * CPU. * +* On systems that do not implement TDIR, force the bit in the +* shadow state anyway to avoid IPI-ing on these poor sods. +* * Note that we set the trap irrespective of EOIMode, as that * can change behind our back without any warning... */ -if (irqs_active_outside_lrs (als) || +if (!cpus_have_final_cap (ARM64_HAS_ICH_HCR_EL2_TDIR ) || +irqs_active_outside_lrs (als) ||atomic_read (&vcpu->kvm->arch.vgic.active_spis)) cpuif->vgic_hcr |=ICH_HCR_EL2_TDIR ; }
arch/arm64/kvm/vgic/vgic.c +8 -5
@@ -370,12 +370,15 @@ static bool vgic_validate_injection(struct vgic_irq *irq, bool level, void *ownestatic bool vgic_model_needs_bcst_kick (struct kvm *kvm) {/* -* A GICv3 (or GICv3-like) system exposing a GICv3 to the -* guest needs a broadcast kick to set TDIR globally, even if -* the bit doesn't really exist (we still need to check for -* the shadow bit in the DIR emulation fast-path). +* A GICv3 (or GICv3-like) system exposing a GICv3 to the guest +* needs a broadcast kick to set TDIR globally. +* +* For systems that do not have TDIR (ARM's own v8.0 CPUs), the +* shadow TDIR bit is always set, and so is the register's TC bit, +* so no need to kick the CPUs. */ -return (kvm->arch.vgic.vgic_model ==KVM_DEV_TYPE_ARM_VGIC_V3 ); +return (cpus_have_final_cap (ARM64_HAS_ICH_HCR_EL2_TDIR ) && + kvm->arch.vgic.vgic_model ==KVM_DEV_TYPE_ARM_VGIC_V3 ); }/*
Signature · 1 line
2.47.3
Marc Zyngier
maintainerPATCH v2 33/45 KVM: arm64: GICv2: Handle LR overflow when EOImode==0
In reply to Marc ZyngierSimilarly to the GICv3 version, handle the EOIcount-driven deactivation by walking the overflow list.
--- arch/arm64/kvm/vgic/vgic-v2.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+)
arch/arm64/kvm/vgic/vgic-v2.c +27 -0
@@ -100,6 +100,8 @@ static void vgic_v2_fold_lr(struct kvm_vcpu *vcpu, u32 val)vgic_put_irq (vcpu->kvm, irq); } +static u32 vgic_v2_compute_lr (struct kvm_vcpu *vcpu,struct vgic_irq *irq); +/* * transfer the content of the LRs back into the corresponding ap_list: * - active bit is transferred as is
@@ -111,12 +113,37 @@ void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu) {struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;struct vgic_v2_cpu_if *cpuif = &vgic_cpu->vgic_v2; +u32 eoicount =FIELD_GET (GICH_HCR_EOICOUNT , cpuif->vgic_hcr); +struct vgic_irq *irq;DEBUG_SPINLOCK_BUG_ON (!irqs_disabled ());for (int lr =0 ; lr < vgic_cpu->vgic_v2.used_lrs; lr++)vgic_v2_fold_lr (vcpu, cpuif->vgic_lr[lr]); +/* See the GICv3 equivalent for the EOIcount handling rationale */ +list_for_each_entry (irq, &vgic_cpu->ap_list_head, ap_list) { +u32 lr; + +if (!eoicount) { +break ; + }else { +guard (raw_spinlock)(&irq->irq_lock); + +if (!(likely (vgic_target_oracle (irq) == vcpu) && + irq->active)) +continue ; + + lr =vgic_v2_compute_lr (vcpu, irq) & ~GICH_LR_ACTIVE_BIT ; + } + +if (lr &GICH_LR_HW ) +writel_relaxed (FIELD_GET (GICH_LR_PHYSID_CPUID , lr), + kvm_vgic_global_state.gicc_base +GIC_CPU_DEACTIVATE ); +vgic_v2_fold_lr (vcpu, lr); + eoicount--; + } + cpuif->used_lrs =0 ; }
Signature · 1 line
2.47.3
Marc Zyngier
maintainerPATCH v2 34/45 KVM: arm64: GICv2: Handle deactivation via GICV_DIR traps
In reply to Marc ZyngierAdd the plumbing of GICv2 interrupt deactivation via GICV_DIR. This requires adding a new device so that we can easily decode the DIR address.
The deactivation itself is very similar to the GICv3 version.
--- arch/arm64/kvm/vgic/vgic-mmio-v2.c | 24 +++++++++ arch/arm64/kvm/vgic/vgic-mmio.h | 1 + arch/arm64/kvm/vgic/vgic-v2.c | 85 ++++++++++++++++++++++++++++++ arch/arm64/kvm/vgic/vgic.h | 1 + include/kvm/arm_vgic.h | 1 + 5 files changed, 112 insertions(+)
arch/arm64/kvm/vgic/vgic-mmio-v2.c +24 -0
@@ -359,6 +359,16 @@ static void vgic_mmio_write_vcpuif(struct kvm_vcpu *vcpu,vgic_set_vmcr (vcpu, &vmcr); } +static void vgic_mmio_write_dir (struct kvm_vcpu *vcpu, +gpa_t addr,unsigned int len, +unsigned long val) +{ +if (kvm_vgic_global_state.type ==VGIC_V2 ) +vgic_v2_deactivate (vcpu, val); +else +vgic_v3_deactivate (vcpu, val); +} +static unsigned long vgic_mmio_read_apr (struct kvm_vcpu *vcpu,gpa_t addr,unsigned int len) {
@@ -482,6 +492,10 @@ static const struct vgic_register_region vgic_v2_cpu_registers[] = {REGISTER_DESC_WITH_LENGTH (GIC_CPU_IDENT , vgic_mmio_read_vcpuif, vgic_mmio_write_vcpuif,4 , VGIC_ACCESS_32bit), +REGISTER_DESC_WITH_LENGTH_UACCESS (GIC_CPU_DEACTIVATE , + vgic_mmio_read_raz, vgic_mmio_write_dir, + vgic_mmio_read_raz, vgic_mmio_uaccess_write_wi, + 4, VGIC_ACCESS_32bit), };unsigned int vgic_v2_init_dist_iodev (struct vgic_io_device *dev)
@@ -494,6 +508,16 @@ unsigned int vgic_v2_init_dist_iodev(struct vgic_io_device *dev)return SZ_4K ; } +unsigned int vgic_v2_init_cpuif_iodev (struct vgic_io_device *dev) +{ + dev->regions = vgic_v2_cpu_registers; + dev->nr_regions =ARRAY_SIZE (vgic_v2_cpu_registers); + +kvm_iodevice_init (&dev->dev, &kvm_io_gic_ops); + +return KVM_VGIC_V2_CPU_SIZE ; +} +int vgic_v2_has_attr_regs (struct kvm_device *dev,struct kvm_device_attr *attr) {const struct vgic_register_region *region;
arch/arm64/kvm/vgic/vgic-mmio.h +1 -0
@@ -213,6 +213,7 @@ void vgic_write_irq_line_level_info(struct kvm_vcpu *vcpu, u32 intid, const u32 val);unsigned int vgic_v2_init_dist_iodev (struct vgic_io_device *dev); +unsigned int vgic_v2_init_cpuif_iodev (struct vgic_io_device *dev);unsigned int vgic_v3_init_dist_iodev (struct vgic_io_device *dev);
arch/arm64/kvm/vgic/vgic-v2.c +85 -0
109 lines not on this page · raw message
arch/arm64/kvm/vgic/vgic.h +1 -0
@@ -277,6 +277,7 @@ int vgic_check_iorange(struct kvm *kvm, phys_addr_t ioaddr,void vgic_v2_fold_lr_state (struct kvm_vcpu *vcpu);void vgic_v2_populate_lr (struct kvm_vcpu *vcpu,struct vgic_irq *irq,int lr); +void vgic_v2_deactivate (struct kvm_vcpu *vcpu,u32 val);void vgic_v2_clear_lr (struct kvm_vcpu *vcpu,int lr);void vgic_v2_configure_hcr (struct kvm_vcpu *vcpu,struct ap_list_summary *als);int vgic_v2_has_attr_regs (struct kvm_device *dev,struct kvm_device_attr *attr);
include/kvm/arm_vgic.h +1 -0
@@ -287,6 +287,7 @@ struct vgic_dist {struct vgic_irq *spis;struct vgic_io_device dist_iodev; +struct vgic_io_device cpuif_iodev;bool has_its;bool table_write_in_progress;
Signature · 1 line
2.47.3
Marc Zyngier
maintainerPATCH v2 35/45 KVM: arm64: GICv2: Always trap GICV_DIR register
In reply to Marc ZyngierSince we can't decide to trap the DIR register on a per-vcpu basis, always trap the second page of the GIC CPU interface. Yes, this is costly. On the bright side, no sane SW should use EOImode==1 on GICv2...
--- arch/arm64/kvm/hyp/vgic-v2-cpuif-proxy.c | 4 ++++ arch/arm64/kvm/vgic/vgic-v2.c | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-)
arch/arm64/kvm/hyp/vgic-v2-cpuif-proxy.c +4 -0
@@ -63,6 +63,10 @@ int __vgic_v2_perform_cpuif_access(struct kvm_vcpu *vcpu)return -1 ; } +/* Handle deactivation as a normal exit */ +if ((fault_ipa - vgic->vgic_cpu_base) >=GIC_CPU_DEACTIVATE ) +return 0 ; + rd =kvm_vcpu_dabt_get_rd (vcpu); addr = kvm_vgic_global_state.vcpu_hyp_va; addr += fault_ipa - vgic->vgic_cpu_base;
arch/arm64/kvm/vgic/vgic-v2.c +1 -1
@@ -457,7 +457,7 @@ int vgic_v2_map_resources(struct kvm *kvm)if (!static_branch_unlikely (&vgic_v2_cpuif_trap)) { ret =kvm_phys_addr_ioremap (kvm, dist->vgic_cpu_base, kvm_vgic_global_state.vcpu_base, -KVM_VGIC_V2_CPU_SIZE , true); +KVM_VGIC_V2_CPU_SIZE -SZ_4K , true);if (ret) {kvm_err ("Unable to remap VGIC CPU to VCPU\n" );return ret;
Signature · 1 line
2.47.3
Marc Zyngier
maintainerPATCH v2 36/45 KVM: arm64: selftests: gic_v3: Add irq group setting helper
In reply to Marc ZyngierBeing able to set the group of an interrupt is pretty useful. Add such a helper.
--- tools/testing/selftests/kvm/include/arm64/gic.h | 1 + tools/testing/selftests/kvm/lib/arm64/gic.c | 6 ++++++ .../testing/selftests/kvm/lib/arm64/gic_private.h | 1 + tools/testing/selftests/kvm/lib/arm64/gic_v3.c | 15 +++++++++++++++ 4 files changed, 23 insertions(+)
tools/testing/selftests/kvm/include/arm64/gic.h +1 -0
@@ -57,6 +57,7 @@ void gic_irq_set_pending(unsigned int intid);void gic_irq_clear_pending (unsigned int intid);bool gic_irq_get_pending (unsigned int intid);void gic_irq_set_config (unsigned int intid,bool is_edge); +void gic_irq_set_group (unsigned int intid,bool group);void gic_rdist_enable_lpis (vm_paddr_t cfg_table,size_t cfg_table_size,vm_paddr_t pend_table);
tools/testing/selftests/kvm/lib/arm64/gic.c +6 -0
@@ -155,3 +155,9 @@ void gic_irq_set_config(unsigned int intid, bool is_edge)GUEST_ASSERT (gic_common_ops); gic_common_ops->gic_irq_set_config (intid, is_edge); } + +void gic_irq_set_group (unsigned int intid,bool group) +{ +GUEST_ASSERT (gic_common_ops); + gic_common_ops->gic_irq_set_group (intid, group); +}
tools/testing/selftests/kvm/lib/arm64/gic_private.h +1 -0
@@ -25,6 +25,7 @@ struct gic_common_ops {void (*gic_irq_clear_pending)(uint32_t intid);bool (*gic_irq_get_pending)(uint32_t intid);void (*gic_irq_set_config)(uint32_t intid,bool is_edge); +void (*gic_irq_set_group)(uint32_t intid,bool group); };extern const struct gic_common_ops gicv3_ops;
tools/testing/selftests/kvm/lib/arm64/gic_v3.c +15 -0
@@ -293,6 +293,20 @@ static void gicv3_enable_redist(volatile void *redist_base) } } +static void gicv3_set_group (uint32_t intid,bool grp) +{ +uint32_t cpu_or_dist; +uint32_t val; + + cpu_or_dist = (get_intid_range (intid) ==SPI_RANGE ) ?DIST_BIT :guest_get_vcpuid (); + val =gicv3_reg_readl (cpu_or_dist,GICD_IGROUPR + (intid /32 ) *4 ); +if (grp) + val |=BIT (intid %32 ); +else + val &= ~BIT (intid %32 ); +gicv3_reg_writel (cpu_or_dist,GICD_IGROUPR + (intid /32 ) *4 , val); +} +static void gicv3_cpu_init (unsigned int cpu) {volatile void *sgi_base;
@@ -400,6 +414,7 @@ const struct gic_common_ops gicv3_ops = { .gic_irq_clear_pending = gicv3_irq_clear_pending, .gic_irq_get_pending = gicv3_irq_get_pending, .gic_irq_set_config = gicv3_irq_set_config, + .gic_irq_set_group = gicv3_set_group, }; void gic_rdist_enable_lpis(vm_paddr_t cfg_table, size_t cfg_table_size,
Signature · 1 line
2.47.3
Marc Zyngier
maintainerPATCH v2 37/45 KVM: arm64: selftests: gic_v3: Disable Group-0 interrupts by default
In reply to Marc ZyngierMake sure G0 is disabled at the point of initialising the GIC.
--- tools/testing/selftests/kvm/lib/arm64/gic_v3.c | 2 ++ 1 file changed, 2 insertions(+)
tools/testing/selftests/kvm/lib/arm64/gic_v3.c +2 -0
@@ -342,6 +342,8 @@ static void gicv3_cpu_init(unsigned int cpu)/* Set a default priority threshold */ write_sysreg_s (ICC_PMR_DEF_PRIO ,SYS_ICC_PMR_EL1 ); +/* Disable Group-0 interrupts */ +write_sysreg_s (ICC_IGRPEN0_EL1_MASK ,SYS_ICC_IGRPEN1_EL1 );/* Enable non-secure Group-1 interrupts */ write_sysreg_s (ICC_IGRPEN1_EL1_MASK ,SYS_ICC_IGRPEN1_EL1 ); }
Signature · 1 line
2.47.3
Marc Zyngier
maintainerPATCH v2 38/45 KVM: arm64: selftests: vgic_irq: Fix GUEST_ASSERT_IAR_EMPTY() helper
In reply to Marc ZyngierNo, 0 is not a spurious INTID. Never been, never was.
--- tools/testing/selftests/kvm/arm64/vgic_irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/testing/selftests/kvm/arm64/vgic_irq.c +1 -1
@@ -205,7 +205,7 @@ static void kvm_inject_call(kvm_inject_cmd cmd, uint32_t first_intid,do { \uint32_t _intid; \ _intid =gic_get_and_ack_irq (); \ -GUEST_ASSERT (_intid ==0 || _intid ==IAR_SPURIOUS ); \ +GUEST_ASSERT (_intid ==IAR_SPURIOUS ); \ } while (0)#define CAT_HELPER (a, b) a ## b
Signature · 1 line
2.47.3
Marc Zyngier
maintainerPATCH v2 39/45 KVM: arm64: selftests: vgic_irq: Change configuration before enabling interrupt
In reply to Marc ZyngierThe architecture is pretty clear that changing the configuration of an enable interrupt is not OK. It doesn't really matter here, but doing the right thing is not more expensive.
--- tools/testing/selftests/kvm/arm64/vgic_irq.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
tools/testing/selftests/kvm/arm64/vgic_irq.c +3 -3
@@ -473,12 +473,12 @@ static void guest_code(struct test_args *args)gic_init (GIC_V3 ,1 ); -for (i =0 ; i < nr_irqs; i++) -gic_irq_enable (i); -for (i =MIN_SPI ; i < nr_irqs; i++)gic_irq_set_config (i, !level_sensitive); +for (i =0 ; i < nr_irqs; i++) +gic_irq_enable (i); +gic_set_eoi_split (args->eoi_split);reset_priorities (args);
Signature · 1 line
2.47.3
Marc Zyngier
maintainerPATCH v2 40/45 KVM: arm64: selftests: vgic_irq: Exclude timer-controlled interrupts
In reply to Marc ZyngierThe PPI injection API is clear that you can't inject the timer PPIs from userspace, since they are controlled by the timers themselves.
Add an exclusion list for this purpose.
--- tools/testing/selftests/kvm/arm64/vgic_irq.c | 31 ++++++++++++++++---- 1 file changed, 25 insertions(+), 6 deletions(-)
tools/testing/selftests/kvm/arm64/vgic_irq.c +25 -6
@@ -359,8 +359,9 @@ static uint32_t wait_for_and_activate_irq(void)* interrupts for the whole test. */ static void test_inject_preemption (struct test_args *args, -uint32_t first_intid,int num, -kvm_inject_cmd cmd) +uint32_t first_intid,int num, +const unsigned long *exclude, +kvm_inject_cmd cmd) {uint32_t intid, prio, step =KVM_PRIO_STEPS ;int i;
@@ -379,6 +380,10 @@ static void test_inject_preemption(struct test_args *args,for (i =0 ; i < num; i++) {uint32_t tmp; intid = i + first_intid; + +if (exclude &&test_bit (i, exclude)) +continue ; +KVM_INJECT (cmd, intid);/* Each successive IRQ will preempt the previous one. */ tmp =wait_for_and_activate_irq ();
@@ -390,6 +395,10 @@ static void test_inject_preemption(struct test_args *args,/* finish handling the IRQs starting with the highest priority one. */ for (i =0 ; i < num; i++) { intid = num - i -1 + first_intid; + +if (exclude &&test_bit (intid - first_intid, exclude)) +continue ; +gic_set_eoi (intid);if (args->eoi_split)gic_set_dir (intid);
@@ -397,8 +406,12 @@ static void test_inject_preemption(struct test_args *args,local_irq_enable (); -for (i =0 ; i < num; i++) +for (i =0 ; i < num; i++) { +if (exclude &&test_bit (i, exclude)) +continue ; +GUEST_ASSERT (!gic_irq_get_active (i + first_intid)); + }GUEST_ASSERT_EQ (gic_read_ap1r0 (),0 );GUEST_ASSERT_IAR_EMPTY ();
@@ -442,14 +455,20 @@ static void test_preemption(struct test_args *args, struct kvm_inject_desc *f)* number of concurrently active IRQs. The number of LRs implemented is * IMPLEMENTATION DEFINED, however, it seems that most implement 4. */ +/* Timer PPIs cannot be injected from userspace */ +static const unsigned long ppi_exclude = (BIT (27 -MIN_PPI ) | +BIT (30 -MIN_PPI ) | +BIT (28 -MIN_PPI ) | +BIT (26 -MIN_PPI )); +if (f->sgi) -test_inject_preemption (args,MIN_SGI ,4 , f->cmd); +test_inject_preemption (args,MIN_SGI ,4 ,NULL , f->cmd);if (f->ppi) -test_inject_preemption (args,MIN_PPI ,4 , f->cmd); +test_inject_preemption (args,MIN_PPI ,4 , &ppi_exclude, f->cmd);if (f->spi) -test_inject_preemption (args,MIN_SPI ,4 , f->cmd); +test_inject_preemption (args,MIN_SPI ,4 ,NULL , f->cmd); }static void test_restore_active (struct test_args *args,struct kvm_inject_desc *f)
Signature · 1 line
2.47.3
Marc Zyngier
maintainerPATCH v2 41/45 KVM: arm64: selftests: vgic_irq: Remove LR-bound limitation
In reply to Marc ZyngierGood news: our GIC emulation is not completely broken, and we can activate as many interrupts as we want.
Bump the test to cover all the SGIs, all the allowed PPIs, and 31 SPIs. Yes, 31, because we have 31 available priorities, and the test is not happy with having two interrupts with the same priority.
--- tools/testing/selftests/kvm/arm64/vgic_irq.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-)
tools/testing/selftests/kvm/arm64/vgic_irq.c +6 -13
@@ -449,12 +449,6 @@ static void test_injection_failure(struct test_args *args,static void test_preemption (struct test_args *args,struct kvm_inject_desc *f) { -/* -* Test up to 4 levels of preemption. The reason is that KVM doesn't -* currently implement the ability to have more than the number-of-LRs -* number of concurrently active IRQs. The number of LRs implemented is -* IMPLEMENTATION DEFINED, however, it seems that most implement 4. -*/ /* Timer PPIs cannot be injected from userspace */ static const unsigned long ppi_exclude = (BIT(27 - MIN_PPI) | BIT(30 - MIN_PPI) |
@@ -462,26 +456,25 @@ static void test_preemption(struct test_args *args, struct kvm_inject_desc *f) BIT(26 - MIN_PPI));if (f->sgi) -test_inject_preemption (args,MIN_SGI ,4 ,NULL , f->cmd); +test_inject_preemption (args,MIN_SGI ,16 ,NULL , f->cmd);if (f->ppi) -test_inject_preemption (args,MIN_PPI ,4 , &ppi_exclude, f->cmd); +test_inject_preemption (args,MIN_PPI ,16 , &ppi_exclude, f->cmd);if (f->spi) -test_inject_preemption (args,MIN_SPI ,4 ,NULL , f->cmd); +test_inject_preemption (args,MIN_SPI ,31 ,NULL , f->cmd); }static void test_restore_active (struct test_args *args,struct kvm_inject_desc *f) { -/* Test up to 4 active IRQs. Same reason as in test_preemption. */ if (f->sgi) -guest_restore_active (args,MIN_SGI ,4 , f->cmd); +guest_restore_active (args,MIN_SGI ,16 , f->cmd);if (f->ppi) -guest_restore_active (args,MIN_PPI ,4 , f->cmd); +guest_restore_active (args,MIN_PPI ,16 , f->cmd);if (f->spi) -guest_restore_active (args,MIN_SPI ,4 , f->cmd); +guest_restore_active (args,MIN_SPI ,31 , f->cmd); }static void guest_code (struct test_args *args)
Signature · 1 line
2.47.3
Marc Zyngier
maintainerPATCH v2 42/45 KVM: arm64: selftests: vgic_irq: Perform EOImode==1 deactivation in ack order
In reply to Marc ZyngierWhen EOImode==1, perform the deactivation in the order of activation, just to make things a bit worse for KVM. Yes, I'm nasty.
--- tools/testing/selftests/kvm/arm64/vgic_irq.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-)
tools/testing/selftests/kvm/arm64/vgic_irq.c +12 -2
@@ -400,8 +400,18 @@ static void test_inject_preemption(struct test_args *args,continue ;gic_set_eoi (intid); -if (args->eoi_split) -gic_set_dir (intid); + } + +if (args->eoi_split) { +for (i =0 ; i < num; i++) { + intid = i + first_intid; + +if (exclude &&test_bit (i, exclude)) +continue ; + +if (args->eoi_split) +gic_set_dir (intid); + } }local_irq_enable ();
Signature · 1 line
2.47.3
Marc Zyngier
maintainerPATCH v2 43/45 KVM: arm64: selftests: vgic_irq: Add asymmetric SPI deaectivation test
In reply to Marc ZyngierAdd a new test case that makes an interrupt pending on a vcpu, activates it, do the priority drop, and then get *another* vcpu to do the deactivation.
Special care is taken not to trigger an exit in the process, so that we are sure that the active interrupt is in an LR. Joy.
--- tools/testing/selftests/kvm/arm64/vgic_irq.c | 105 +++++++++++++++++++ 1 file changed, 105 insertions(+)
tools/testing/selftests/kvm/arm64/vgic_irq.c +105 -0
@@ -29,6 +29,7 @@ struct test_args {bool level_sensitive;/* 1 is level, 0 is edge */ int kvm_max_routes;/* output of KVM_CAP_IRQ_ROUTING */ bool kvm_supports_irqfd;/* output of KVM_CAP_IRQFD */ +uint32_t shared_data; };/*
@@ -801,6 +802,109 @@ static void test_vgic(uint32_t nr_irqs, bool level_sensitive, bool eoi_split)kvm_vm_free (vm); } +static void guest_code_asym_dir (struct test_args *args,int cpuid) +{ +gic_init (GIC_V3 ,2 ); + +gic_set_eoi_split (1 ); +gic_set_priority_mask (CPU_PRIO_MASK ); + +if (cpuid ==0 ) { +uint32_t intid; + +local_irq_disable (); + +gic_set_priority (MIN_PPI ,IRQ_DEFAULT_PRIO ); +gic_irq_enable (MIN_SPI ); +gic_irq_set_pending (MIN_SPI ); + + intid =wait_for_and_activate_irq (); +GUEST_ASSERT_EQ (intid,MIN_SPI ); + +gic_set_eoi (intid); +isb (); + +WRITE_ONCE (args->shared_data,MIN_SPI ); +dsb (ishst); + +do { +dsb (ishld); + }while (READ_ONCE (args->shared_data) ==MIN_SPI ); +GUEST_ASSERT (!gic_irq_get_active (MIN_SPI )); + }else { +do { +dsb (ishld); + }while (READ_ONCE (args->shared_data) !=MIN_SPI ); + +gic_set_dir (MIN_SPI ); +isb (); + +WRITE_ONCE (args->shared_data,0 ); +dsb (ishst); + } + +GUEST_DONE (); +} + +static void *test_vcpu_run (void *arg) +{ +struct kvm_vcpu *vcpu = arg; +struct ucall uc; + +while (1 ) { +vcpu_run (vcpu); + +switch (get_ucall (vcpu, &uc)) { +case UCALL_ABORT : +REPORT_GUEST_ASSERT (uc); +break ; +case UCALL_DONE : +return NULL ; +default : +TEST_FAIL ("Unknown ucall %lu" , uc.cmd); + } + } + +return NULL ; +} + +static void test_vgic_two_cpus (void *gcode) +{ +pthread_t thr[2 ]; +struct kvm_vcpu *vcpus[2 ]; +struct test_args args = {}; +struct kvm_vm *vm; +vm_vaddr_t args_gva; +int gic_fd, ret; + + vm =vm_create_with_vcpus (2 , gcode, vcpus); + +vm_init_descriptor_tables (vm); +vcpu_init_descriptor_tables (vcpus[0 ]); +vcpu_init_descriptor_tables (vcpus[1 ]); + +/* Setup the guest args page (so it gets the args). */ + args_gva =vm_vaddr_alloc_page (vm); +memcpy (addr_gva2hva (vm, args_gva), &args,sizeof (args)); +vcpu_args_set (vcpus[0 ],2 , args_gva,0 ); +vcpu_args_set (vcpus[1 ],2 , args_gva,1 ); + + gic_fd =vgic_v3_setup (vm,2 ,64 ); + + ret =pthread_create (&thr[0 ],NULL , test_vcpu_run, vcpus[0 ]); +if (ret) +TEST_FAIL ("Can't create thread for vcpu 0 (%d)\n" , ret); + ret =pthread_create (&thr[1 ],NULL , test_vcpu_run, vcpus[1 ]); +if (ret) +TEST_FAIL ("Can't create thread for vcpu 1 (%d)\n" , ret); + +pthread_join (thr[0 ],NULL ); +pthread_join (thr[1 ],NULL ); + +close (gic_fd); +kvm_vm_free (vm); +} +static void help (const char *name) { printf(
@@ -857,6 +961,7 @@ int main(int argc, char **argv)test_vgic (nr_irqs, false/* level */ , true/* eoi_split */ );test_vgic (nr_irqs, true/* level */ , false/* eoi_split */ );test_vgic (nr_irqs, true/* level */ , true/* eoi_split */ ); +test_vgic_two_cpus (guest_code_asym_dir); }else {test_vgic (nr_irqs, level_sensitive, eoi_split); }
Signature · 1 line
2.47.3
Marc Zyngier
maintainerPATCH v2 44/45 KVM: arm64: selftests: vgic_irq: Add Group-0 enable test
In reply to Marc ZyngierAdd a new test case that inject a Group-0 interrupt together with a bunch of Group-1 interrupts, Ack/EOI the G1 interrupts, and only then enable G0, expecting to get the G0 interrupt.
--- tools/testing/selftests/kvm/arm64/vgic_irq.c | 49 ++++++++++++++++++++ 1 file changed, 49 insertions(+)
tools/testing/selftests/kvm/arm64/vgic_irq.c +49 -0
@@ -846,6 +846,54 @@ static void guest_code_asym_dir(struct test_args *args, int cpuid)GUEST_DONE (); } +static void guest_code_group_en (struct test_args *args,int cpuid) +{ +uint32_t intid; + +gic_init (GIC_V3 ,2 ); + +gic_set_eoi_split (0 ); +gic_set_priority_mask (CPU_PRIO_MASK ); +/* SGI0 is G0, which is disabled */ +gic_irq_set_group (0 ,0 ); + +/* Configure all SGIs with decreasing priority */ +for (intid =0 ; intid <MIN_PPI ; intid++) { +gic_set_priority (intid, (intid +1 ) *8 ); +gic_irq_enable (intid); +gic_irq_set_pending (intid); + } + +/* Ack and EOI all G1 interrupts */ +for (int i =1 ; i <MIN_PPI ; i++) { + intid =wait_for_and_activate_irq (); + +GUEST_ASSERT (intid <MIN_PPI ); +gic_set_eoi (intid); +isb (); + } + +/* +* Check that SGI0 is still pending, inactive, and that we cannot +* ack anything. +*/ +GUEST_ASSERT (gic_irq_get_pending (0 )); +GUEST_ASSERT (!gic_irq_get_active (0 )); +GUEST_ASSERT_IAR_EMPTY (); +GUEST_ASSERT (read_sysreg_s (SYS_ICC_IAR0_EL1 ) ==IAR_SPURIOUS ); + +/* Open the G0 gates, and verify we can ack SGI0 */ +write_sysreg_s (1 ,SYS_ICC_IGRPEN0_EL1 ); +isb (); + +do { + intid =read_sysreg_s (SYS_ICC_IAR0_EL1 ); + }while (intid ==IAR_SPURIOUS ); + +GUEST_ASSERT (intid ==0 ); +GUEST_DONE (); +} +static void *test_vcpu_run (void *arg) {struct kvm_vcpu *vcpu = arg;
@@ -962,6 +1010,7 @@ int main(int argc, char **argv)test_vgic (nr_irqs, true/* level */ , false/* eoi_split */ );test_vgic (nr_irqs, true/* level */ , true/* eoi_split */ );test_vgic_two_cpus (guest_code_asym_dir); +test_vgic_two_cpus (guest_code_group_en); }else {test_vgic (nr_irqs, level_sensitive, eoi_split); }
Signature · 1 line
2.47.3
Marc Zyngier
maintainerPATCH v2 45/45 KVM: arm64: selftests: vgic_irq: Add timer deactivation test
In reply to Marc ZyngierAdd a new test case that triggers the HW deactivation emulation path when trapping ICV_DIR_EL1. This is obviously tied to the way KVM works now, but the test follows the expected architectural behaviour.
--- tools/testing/selftests/kvm/arm64/vgic_irq.c | 65 ++++++++++++++++++++ 1 file changed, 65 insertions(+)
tools/testing/selftests/kvm/arm64/vgic_irq.c +65 -0
@@ -894,6 +894,70 @@ static void guest_code_group_en(struct test_args *args, int cpuid)GUEST_DONE (); } +static void guest_code_timer_spi (struct test_args *args,int cpuid) +{ +uint32_t intid; +u64 val; + +gic_init (GIC_V3 ,2 ); + +gic_set_eoi_split (1 ); +gic_set_priority_mask (CPU_PRIO_MASK ); + +/* Add a pending SPI so that KVM starts trapping DIR */ +gic_set_priority (MIN_SPI + cpuid,IRQ_DEFAULT_PRIO ); +gic_irq_set_pending (MIN_SPI + cpuid); + +/* Configure the timer with a higher priority, make it pending */ +gic_set_priority (27 ,IRQ_DEFAULT_PRIO -8 ); + +isb (); + val =read_sysreg (cntvct_el0); +write_sysreg (val, cntv_cval_el0); +write_sysreg (1 , cntv_ctl_el0); +isb (); + +GUEST_ASSERT (gic_irq_get_pending (27 )); + +/* Enable both interrupts */ +gic_irq_enable (MIN_SPI + cpuid); +gic_irq_enable (27 ); + +/* The timer must fire */ + intid =wait_for_and_activate_irq (); +GUEST_ASSERT (intid ==27 ); + +/* Check that we can deassert it */ +write_sysreg (0 , cntv_ctl_el0); +isb (); + +GUEST_ASSERT (!gic_irq_get_pending (27 )); + +/* +* Priority drop, deactivation -- we expect that the host +* deactivation will have been effective +*/ +gic_set_eoi (27 ); +gic_set_dir (27 ); + +GUEST_ASSERT (!gic_irq_get_active (27 )); + +/* Do it one more time */ +isb (); + val =read_sysreg (cntvct_el0); +write_sysreg (val, cntv_cval_el0); +write_sysreg (1 , cntv_ctl_el0); +isb (); + +GUEST_ASSERT (gic_irq_get_pending (27 )); + +/* The timer must fire again */ + intid =wait_for_and_activate_irq (); +GUEST_ASSERT (intid ==27 ); + +GUEST_DONE (); +} +static void *test_vcpu_run (void *arg) {struct kvm_vcpu *vcpu = arg;
@@ -1011,6 +1075,7 @@ int main(int argc, char **argv)test_vgic (nr_irqs, true/* level */ , true/* eoi_split */ );test_vgic_two_cpus (guest_code_asym_dir);test_vgic_two_cpus (guest_code_group_en); +test_vgic_two_cpus (guest_code_timer_spi); }else {test_vgic (nr_irqs, level_sensitive, eoi_split); }
Signature · 1 line
2.47.3
Quoted 10 lines · Marc Zyngier
This is the 2nd version of the series originally posted at [1]. The series has significantly evolved with a bunch of bug fixes, some additional optimisations, and a number of test cases.
This has now been extensively tested on much of what I have access to, specially on some of the most broken stuff (Apple, Qualcomm, Cavium, ARMv8.0 CPUs without TDIR), but also on some less shitty systems (which are the minority, unsurprisingly).
[...]
Applied to next, thanks!
[01/45] irqchip/gic: Add missing GICH_HCR control bits
https://git.kernel.org/kvmarm/kvmarm/c/435d529bf5cd [02/45] irqchip/gic: Expose CPU interface VA to KVM https://git.kernel.org/kvmarm/kvmarm/c/5bebf839b2e7 [03/45] irqchip/apple-aic: Spit out ICH_MISR_EL2 value on spurious vGIC MI https://git.kernel.org/kvmarm/kvmarm/c/5a9655de7241 [04/45] KVM: arm64: Turn vgic-v3 errata traps into a patched-in constant https://git.kernel.org/kvmarm/kvmarm/c/ca30799f7c2d [05/45] KVM: arm64: GICv3: Detect and work around the lack of ICV_DIR_EL1 trapping https://git.kernel.org/kvmarm/kvmarm/c/375e16720b4c [06/45] KVM: arm64: Repack struct vgic_irq fields https://git.kernel.org/kvmarm/kvmarm/c/10576b2d8652 [07/45] KVM: arm64: Add tracking of vgic_irq being present in a LR https://git.kernel.org/kvmarm/kvmarm/c/023c81ada994 [08/45] KVM: arm64: Add LR overflow handling documentation https://git.kernel.org/kvmarm/kvmarm/c/2a69aca33cac [09/45] KVM: arm64: GICv3: Drop LPI active state when folding LRs https://git.kernel.org/kvmarm/kvmarm/c/9fc8456206e8 [10/45] KVM: arm64: GICv3: Preserve EOIcount on exit https://git.kernel.org/kvmarm/kvmarm/c/a3a4ca462fdb [11/45] KVM: arm64: GICv3: Decouple ICH_HCR_EL2 programming from LRs https://git.kernel.org/kvmarm/kvmarm/c/417714763ec1 [12/45] KVM: arm64: GICv3: Extract LR folding primitive https://git.kernel.org/kvmarm/kvmarm/c/7f69d30b7024 [13/45] KVM: arm64: GICv3: Extract LR computing primitive https://git.kernel.org/kvmarm/kvmarm/c/4b963cd815c0 [14/45] KVM: arm64: GICv2: Preserve EOIcount on exit https://git.kernel.org/kvmarm/kvmarm/c/fc2fda4298ba [15/45] KVM: arm64: GICv2: Decouple GICH_HCR programming from LRs being loaded https://git.kernel.org/kvmarm/kvmarm/c/8ff2bf028907 [16/45] KVM: arm64: GICv2: Extract LR folding primitive https://git.kernel.org/kvmarm/kvmarm/c/a8306bb15afd [17/45] KVM: arm64: GICv2: Extract LR computing primitive https://git.kernel.org/kvmarm/kvmarm/c/d78124a65a03 [18/45] KVM: arm64: Compute vgic state irrespective of the number of interrupts https://git.kernel.org/kvmarm/kvmarm/c/f9bb784186be [19/45] KVM: arm64: Eagerly save VMCR on exit https://git.kernel.org/kvmarm/kvmarm/c/d3c2036861c6 [20/45] KVM: arm64: Revamp vgic maintenance interrupt configuration https://git.kernel.org/kvmarm/kvmarm/c/877324a1b541 [21/45] KVM: arm64: Turn kvm_vgic_vcpu_enable() into kvm_vgic_vcpu_reset() https://git.kernel.org/kvmarm/kvmarm/c/df5dfcad48ca [22/45] KVM: arm64: Make vgic_target_oracle() globally available https://git.kernel.org/kvmarm/kvmarm/c/0cb4b6d1c73e [23/45] KVM: arm64: Invert ap_list sorting to push active interrupts out https://git.kernel.org/kvmarm/kvmarm/c/c6a5d4815634 [24/45] KVM: arm64: Move undeliverable interrupts to the end of ap_list https://git.kernel.org/kvmarm/kvmarm/c/7fb79d1a03e6 [25/45] KVM: arm64: Use MI to detect groups being enabled/disabled https://git.kernel.org/kvmarm/kvmarm/c/f259e2c758dc [26/45] KVM: arm64: GICv3: Handle LR overflow when EOImode==0 https://git.kernel.org/kvmarm/kvmarm/c/81ef83de9440 [27/45] KVM: arm64: GICv3: Handle deactivation via ICV_DIR_EL1 traps https://git.kernel.org/kvmarm/kvmarm/c/f1d440106c3f [28/45] KVM: arm64: GICv3: Add GICv2 SGI handling to deactivation primitive https://git.kernel.org/kvmarm/kvmarm/c/90d527ac928c [29/45] KVM: arm64: GICv3: Set ICH_HCR_EL2.TDIR when interrupts overflow LR capacity https://git.kernel.org/kvmarm/kvmarm/c/9a2292c50d1c [30/45] KVM: arm64: GICv3: Add SPI tracking to handle asymmetric deactivation https://git.kernel.org/kvmarm/kvmarm/c/0f64bed159d2 [31/45] KVM: arm64: GICv3: Handle in-LR deactivation when possible https://git.kernel.org/kvmarm/kvmarm/c/164dd4bae47b [32/45] KVM: arm64: GICv3: Avoid broadcast kick on CPUs lacking TDIR https://git.kernel.org/kvmarm/kvmarm/c/2b36853d7e58 [33/45] KVM: arm64: GICv2: Handle LR overflow when EOImode==0 https://git.kernel.org/kvmarm/kvmarm/c/d4537c8d3116 [34/45] KVM: arm64: GICv2: Handle deactivation via GICV_DIR traps https://git.kernel.org/kvmarm/kvmarm/c/182853c7680a [35/45] KVM: arm64: GICv2: Always trap GICV_DIR register https://git.kernel.org/kvmarm/kvmarm/c/efa05bae8936 [36/45] KVM: arm64: selftests: gic_v3: Add irq group setting helper https://git.kernel.org/kvmarm/kvmarm/c/0f0e2b4108b3 [37/45] KVM: arm64: selftests: gic_v3: Disable Group-0 interrupts by default https://git.kernel.org/kvmarm/kvmarm/c/eea5d19518f2 [38/45] KVM: arm64: selftests: vgic_irq: Fix GUEST_ASSERT_IAR_EMPTY() helper https://git.kernel.org/kvmarm/kvmarm/c/eecb216b2f74 [39/45] KVM: arm64: selftests: vgic_irq: Change configuration before enabling interrupt https://git.kernel.org/kvmarm/kvmarm/c/9f3f3ddbc730 [40/45] KVM: arm64: selftests: vgic_irq: Exclude timer-controlled interrupts https://git.kernel.org/kvmarm/kvmarm/c/bbaf6ed67c41 [41/45] KVM: arm64: selftests: vgic_irq: Remove LR-bound limitation https://git.kernel.org/kvmarm/kvmarm/c/0b7c2f50f3fd [42/45] KVM: arm64: selftests: vgic_irq: Perform EOImode==1 deactivation in ack order https://git.kernel.org/kvmarm/kvmarm/c/d64e3140ab5f [43/45] KVM: arm64: selftests: vgic_irq: Add asymmetric SPI deaectivation test https://git.kernel.org/kvmarm/kvmarm/c/170b047e15af [44/45] KVM: arm64: selftests: vgic_irq: Add Group-0 enable test https://git.kernel.org/kvmarm/kvmarm/c/2423a2369fc1 [45/45] KVM: arm64: selftests: vgic_irq: Add timer deactivation test https://git.kernel.org/kvmarm/kvmarm/c/eaaaaab4b530
--
Best,
Oliver