Prepare vPMC registers for user-initiated changes after first run. This is important specifically for debugging Windows on QEMU with GDB; QEMU tries to write back all visible registers when resuming the VM execution with GDB, corrupting the PMU state. Windows always uses the PMU so this can cause adverse effects on that particular OS.
This series also contains patch "KVM: arm64: PMU: Set raw values from user to PM{C,I}NTEN{SET,CLR}, PMOVS{SET,CLR}", which reverts semantic changes made for the mentioned registers in the past. It is necessary to migrate the PMU state properly on Firecracker, QEMU, and crosvm.
Signed-off-by: Akihiko Odaki akihiko.odaki@daynix.com --- Changes in v3: - Added patch "KVM: arm64: PMU: Assume PMU presence in pmu-emul.c". - Added an explanation of this path series' motivation to each patch. - Explained why userspace register writes and register reset should be covered in patch "KVM: arm64: PMU: Reload when user modifies registers". - Marked patch "KVM: arm64: PMU: Set raw values from user to PM{C,I}NTEN{SET,CLR}, PMOVS{SET,CLR}" for stable. - Reoreded so that patch "KVM: arm64: PMU: Set raw values from user to PM{C,I}NTEN{SET,CLR}, PMOVS{SET,CLR}" would come first. - Added patch "KVM: arm64: PMU: Call kvm_pmu_handle_pmcr() after masking PMCNTENSET_EL0". - Added patch "KVM: arm64: Reload PMCNTENSET_EL0". - Link to v2: https://lore.kernel.org/r/20250307-pmc-v2-0-6c3375a5f1e4@daynix.com
Changes in v2: - Changed to utilize KVM_REQ_RELOAD_PMU as suggested by Oliver Upton. - Added patch "KVM: arm64: PMU: Reload when user modifies registers" to cover more registers. - Added patch "KVM: arm64: PMU: Set raw values from user to PM{C,I}NTEN{SET,CLR}, PMOVS{SET,CLR}". - Link to v1: https://lore.kernel.org/r/20250302-pmc-v1-1-caff989093dc@daynix.com
--- Akihiko Odaki (6): KVM: arm64: PMU: Set raw values from user to PM{C,I}NTEN{SET,CLR}, PMOVS{SET,CLR} KVM: arm64: PMU: Assume PMU presence in pmu-emul.c KVM: arm64: PMU: Fix SET_ONE_REG for vPMC regs KVM: arm64: PMU: Reload when user modifies registers KVM: arm64: PMU: Call kvm_pmu_handle_pmcr() after masking PMCNTENSET_EL0 KVM: arm64: Reload PMCNTENSET_EL0
arch/arm64/kvm/arm.c | 8 ++++--- arch/arm64/kvm/guest.c | 12 +++++++++++ arch/arm64/kvm/pmu-emul.c | 54 ++++++++++++++++------------------------------- arch/arm64/kvm/sys_regs.c | 53 ++++++++++++++++++++++++++-------------------- include/kvm/arm_pmu.h | 1 + 5 files changed, 66 insertions(+), 62 deletions(-) --- base-commit: da2f480cb24d39d480b1e235eda0dd2d01f8765b change-id: 20250302-pmc-b90a86af945c
Best regards,
Commit a45f41d754e0 ("KVM: arm64: Add {get,set}_user for PM{C,I}NTEN{SET,CLR}, PMOVS{SET,CLR}") changed KVM_SET_ONE_REG to update the mentioned registers in a way matching with the behavior of guest register writes. This is a breaking change of a UAPI though the new semantics looks cleaner and VMMs are not prepared for this.
Firecracker, QEMU, and crosvm perform migration by listing registers with KVM_GET_REG_LIST, getting their values with KVM_GET_ONE_REG and setting them with KVM_SET_ONE_REG. This algorithm assumes KVM_SET_ONE_REG restores the values retrieved with KVM_GET_ONE_REG without any alteration. However, bit operations added by the earlier commit do not preserve the values retried with KVM_GET_ONE_REG and potentially break migration.
Remove the bit operations that alter the values retrieved with KVM_GET_ONE_REG.
Cc: stable@vger.kernel.org Fixes: a45f41d754e0 ("KVM: arm64: Add {get,set}_user for PM{C,I}NTEN{SET,CLR}, PMOVS{SET,CLR}") Signed-off-by: Akihiko Odaki akihiko.odaki@daynix.com Acked-by: Marc Zyngier maz@kernel.org --- arch/arm64/kvm/sys_regs.c | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-)
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 42791971f758..0a2ce931a946 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -1126,26 +1126,7 @@ static bool access_pmu_evtyper(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
static int set_pmreg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r, u64 val) { - bool set; - - val &= kvm_pmu_valid_counter_mask(vcpu); - - switch (r->reg) { - case PMOVSSET_EL0: - /* CRm[1] being set indicates a SET register, and CLR otherwise */ - set = r->CRm & 2; - break; - default: - /* Op2[0] being set indicates a SET register, and CLR otherwise */ - set = r->Op2 & 1; - break; - } - - if (set) - __vcpu_sys_reg(vcpu, r->reg) |= val; - else - __vcpu_sys_reg(vcpu, r->reg) &= ~val; - + __vcpu_sys_reg(vcpu, r->reg) = val & kvm_pmu_valid_counter_mask(vcpu); return 0; }
linux-stable-mirror@lists.linaro.org