diff options
author | Sasha Levin <sashal@kernel.org> | 2025-07-03 08:54:54 -0400 |
---|---|---|
committer | Sasha Levin <sashal@kernel.org> | 2025-07-03 09:13:04 -0400 |
commit | e1bd69ff09807d5bf80f17f3279240cb223145a6 (patch) | |
tree | 665c3c107927ffd9d9577e77e266d02ac6e9382a | |
parent | 9290f87d40a38d2fc5b610fbbc86ff0384cbeb32 (diff) | |
download | stable-queue-e1bd69ff09807d5bf80f17f3279240cb223145a6.tar.gz |
Drop queue-6.12/kvm-arm64-set-hcr_el2.tid1-unconditionally.patch
Signed-off-by: Sasha Levin <sashal@kernel.org>
-rw-r--r-- | queue-6.12/kvm-arm64-set-hcr_el2.tid1-unconditionally.patch | 336 | ||||
-rw-r--r-- | queue-6.12/series | 1 |
2 files changed, 0 insertions, 337 deletions
diff --git a/queue-6.12/kvm-arm64-set-hcr_el2.tid1-unconditionally.patch b/queue-6.12/kvm-arm64-set-hcr_el2.tid1-unconditionally.patch deleted file mode 100644 index 0a730fe17f7..00000000000 --- a/queue-6.12/kvm-arm64-set-hcr_el2.tid1-unconditionally.patch +++ /dev/null @@ -1,336 +0,0 @@ -From 0510d3297a23920caf74a63e3f38c0ede70d6555 Mon Sep 17 00:00:00 2001 -From: Sasha Levin <sashal@kernel.org> -Date: Wed, 2 Jul 2025 18:37:48 -0400 -Subject: KVM: arm64: Set HCR_EL2.TID1 unconditionally - -[ Upstream commit 4cd48565b0e5df398e7253c0d2d8c0403d69e7bf ] - -commit 90807748ca3a ("KVM: arm64: Hide SME system registers from -guests") added trap handling for SMIDR_EL1, treating it as UNDEFINED as -KVM does not support SME. This is right for the most part, however KVM -needs to set HCR_EL2.TID1 to _actually_ trap the register. - -Unfortunately, this comes with some collateral damage as TID1 forces -REVIDR_EL1 and AIDR_EL1 to trap as well. KVM has long treated these -registers as "invariant" which is an awful term for the following: - - - Userspace sees the boot CPU values on all vCPUs - - - The guest sees the hardware values of the CPU on which a vCPU is - scheduled - -Keep the plates spinning by adding trap handling for the affected -registers and repaint all of the "invariant" crud into terms of -identifying an implementation. Yes, at this point we only need to -set TID1 on SME hardware, but REVIDR_EL1 and AIDR_EL1 are about to -become mutable anyway. - -Cc: Mark Brown <broonie@kernel.org> -Cc: stable@vger.kernel.org -Fixes: 90807748ca3a ("KVM: arm64: Hide SME system registers from guests") -[maz: handle traps from 32bit] -Co-developed-by: Marc Zyngier <maz@kernel.org> -Signed-off-by: Marc Zyngier <maz@kernel.org> -Link: https://lore.kernel.org/r/20250225005401.679536-2-oliver.upton@linux.dev -Signed-off-by: Oliver Upton <oliver.upton@linux.dev> -Signed-off-by: Sasha Levin <sashal@kernel.org> ---- - arch/arm64/include/asm/kvm_arm.h | 4 +- - arch/arm64/kvm/sys_regs.c | 184 +++++++++++++++++-------------- - 2 files changed, 101 insertions(+), 87 deletions(-) - -diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h -index 109a85ee69100..dd34794cec997 100644 ---- a/arch/arm64/include/asm/kvm_arm.h -+++ b/arch/arm64/include/asm/kvm_arm.h -@@ -92,12 +92,12 @@ - * SWIO: Turn set/way invalidates into set/way clean+invalidate - * PTW: Take a stage2 fault if a stage1 walk steps in device memory - * TID3: Trap EL1 reads of group 3 ID registers -- * TID2: Trap CTR_EL0, CCSIDR2_EL1, CLIDR_EL1, and CSSELR_EL1 -+ * TID1: Trap REVIDR_EL1, AIDR_EL1, and SMIDR_EL1 - */ - #define HCR_GUEST_FLAGS (HCR_TSC | HCR_TSW | HCR_TWE | HCR_TWI | HCR_VM | \ - HCR_BSU_IS | HCR_FB | HCR_TACR | \ - HCR_AMO | HCR_SWIO | HCR_TIDCP | HCR_RW | HCR_TLOR | \ -- HCR_FMO | HCR_IMO | HCR_PTW | HCR_TID3) -+ HCR_FMO | HCR_IMO | HCR_PTW | HCR_TID3 | HCR_TID1) - #define HCR_HOST_NVHE_FLAGS (HCR_RW | HCR_API | HCR_APK | HCR_ATA) - #define HCR_HOST_NVHE_PROTECTED_FLAGS (HCR_HOST_NVHE_FLAGS | HCR_TSC) - #define HCR_HOST_VHE_FLAGS (HCR_RW | HCR_TGE | HCR_E2H) -diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c -index 42791971f7588..05c6f3c9bce25 100644 ---- a/arch/arm64/kvm/sys_regs.c -+++ b/arch/arm64/kvm/sys_regs.c -@@ -2323,6 +2323,94 @@ static unsigned int s1poe_visibility(const struct kvm_vcpu *vcpu, - return REG_HIDDEN; - } - -+/* -+ * For historical (ahem ABI) reasons, KVM treated MIDR_EL1, REVIDR_EL1, and -+ * AIDR_EL1 as "invariant" registers, meaning userspace cannot change them. -+ * The values made visible to userspace were the register values of the boot -+ * CPU. -+ * -+ * At the same time, reads from these registers at EL1 previously were not -+ * trapped, allowing the guest to read the actual hardware value. On big-little -+ * machines, this means the VM can see different values depending on where a -+ * given vCPU got scheduled. -+ * -+ * These registers are now trapped as collateral damage from SME, and what -+ * follows attempts to give a user / guest view consistent with the existing -+ * ABI. -+ */ -+static bool access_imp_id_reg(struct kvm_vcpu *vcpu, -+ struct sys_reg_params *p, -+ const struct sys_reg_desc *r) -+{ -+ if (p->is_write) -+ return write_to_read_only(vcpu, p, r); -+ -+ switch (reg_to_encoding(r)) { -+ case SYS_REVIDR_EL1: -+ p->regval = read_sysreg(revidr_el1); -+ break; -+ case SYS_AIDR_EL1: -+ p->regval = read_sysreg(aidr_el1); -+ break; -+ default: -+ WARN_ON_ONCE(1); -+ } -+ -+ return true; -+} -+ -+static u64 __ro_after_init boot_cpu_midr_val; -+static u64 __ro_after_init boot_cpu_revidr_val; -+static u64 __ro_after_init boot_cpu_aidr_val; -+ -+static void init_imp_id_regs(void) -+{ -+ boot_cpu_midr_val = read_sysreg(midr_el1); -+ boot_cpu_revidr_val = read_sysreg(revidr_el1); -+ boot_cpu_aidr_val = read_sysreg(aidr_el1); -+} -+ -+static int get_imp_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r, -+ u64 *val) -+{ -+ switch (reg_to_encoding(r)) { -+ case SYS_MIDR_EL1: -+ *val = boot_cpu_midr_val; -+ break; -+ case SYS_REVIDR_EL1: -+ *val = boot_cpu_revidr_val; -+ break; -+ case SYS_AIDR_EL1: -+ *val = boot_cpu_aidr_val; -+ break; -+ default: -+ WARN_ON_ONCE(1); -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static int set_imp_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r, -+ u64 val) -+{ -+ u64 expected; -+ int ret; -+ -+ ret = get_imp_id_reg(vcpu, r, &expected); -+ if (ret) -+ return ret; -+ -+ return (expected == val) ? 0 : -EINVAL; -+} -+ -+#define IMPLEMENTATION_ID(reg) { \ -+ SYS_DESC(SYS_##reg), \ -+ .access = access_imp_id_reg, \ -+ .get_user = get_imp_id_reg, \ -+ .set_user = set_imp_id_reg, \ -+} -+ - /* - * Architected system registers. - * Important: Must be sorted ascending by Op0, Op1, CRn, CRm, Op2 -@@ -2371,7 +2459,9 @@ static const struct sys_reg_desc sys_reg_descs[] = { - - { SYS_DESC(SYS_DBGVCR32_EL2), undef_access, reset_val, DBGVCR32_EL2, 0 }, - -+ IMPLEMENTATION_ID(MIDR_EL1), - { SYS_DESC(SYS_MPIDR_EL1), NULL, reset_mpidr, MPIDR_EL1 }, -+ IMPLEMENTATION_ID(REVIDR_EL1), - - /* - * ID regs: all ID_SANITISED() entries here must have corresponding -@@ -2648,6 +2738,7 @@ static const struct sys_reg_desc sys_reg_descs[] = { - .set_user = set_clidr, .val = ~CLIDR_EL1_RES0 }, - { SYS_DESC(SYS_CCSIDR2_EL1), undef_access }, - { SYS_DESC(SYS_SMIDR_EL1), undef_access }, -+ IMPLEMENTATION_ID(AIDR_EL1), - { SYS_DESC(SYS_CSSELR_EL1), access_csselr, reset_unknown, CSSELR_EL1 }, - ID_WRITABLE(CTR_EL0, CTR_EL0_DIC_MASK | - CTR_EL0_IDC_MASK | -@@ -4060,9 +4151,13 @@ int kvm_handle_cp15_32(struct kvm_vcpu *vcpu) - * Certain AArch32 ID registers are handled by rerouting to the AArch64 - * system register table. Registers in the ID range where CRm=0 are - * excluded from this scheme as they do not trivially map into AArch64 -- * system register encodings. -+ * system register encodings, except for AIDR/REVIDR. - */ -- if (params.Op1 == 0 && params.CRn == 0 && params.CRm) -+ if (params.Op1 == 0 && params.CRn == 0 && -+ (params.CRm || params.Op2 == 6 /* REVIDR */)) -+ return kvm_emulate_cp15_id_reg(vcpu, ¶ms); -+ if (params.Op1 == 1 && params.CRn == 0 && -+ params.CRm == 0 && params.Op2 == 7 /* AIDR */) - return kvm_emulate_cp15_id_reg(vcpu, ¶ms); - - return kvm_handle_cp_32(vcpu, ¶ms, cp15_regs, ARRAY_SIZE(cp15_regs)); -@@ -4363,65 +4458,6 @@ id_to_sys_reg_desc(struct kvm_vcpu *vcpu, u64 id, - return r; - } - --/* -- * These are the invariant sys_reg registers: we let the guest see the -- * host versions of these, so they're part of the guest state. -- * -- * A future CPU may provide a mechanism to present different values to -- * the guest, or a future kvm may trap them. -- */ -- --#define FUNCTION_INVARIANT(reg) \ -- static u64 reset_##reg(struct kvm_vcpu *v, \ -- const struct sys_reg_desc *r) \ -- { \ -- ((struct sys_reg_desc *)r)->val = read_sysreg(reg); \ -- return ((struct sys_reg_desc *)r)->val; \ -- } -- --FUNCTION_INVARIANT(midr_el1) --FUNCTION_INVARIANT(revidr_el1) --FUNCTION_INVARIANT(aidr_el1) -- --/* ->val is filled in by kvm_sys_reg_table_init() */ --static struct sys_reg_desc invariant_sys_regs[] __ro_after_init = { -- { SYS_DESC(SYS_MIDR_EL1), NULL, reset_midr_el1 }, -- { SYS_DESC(SYS_REVIDR_EL1), NULL, reset_revidr_el1 }, -- { SYS_DESC(SYS_AIDR_EL1), NULL, reset_aidr_el1 }, --}; -- --static int get_invariant_sys_reg(u64 id, u64 __user *uaddr) --{ -- const struct sys_reg_desc *r; -- -- r = get_reg_by_id(id, invariant_sys_regs, -- ARRAY_SIZE(invariant_sys_regs)); -- if (!r) -- return -ENOENT; -- -- return put_user(r->val, uaddr); --} -- --static int set_invariant_sys_reg(u64 id, u64 __user *uaddr) --{ -- const struct sys_reg_desc *r; -- u64 val; -- -- r = get_reg_by_id(id, invariant_sys_regs, -- ARRAY_SIZE(invariant_sys_regs)); -- if (!r) -- return -ENOENT; -- -- if (get_user(val, uaddr)) -- return -EFAULT; -- -- /* This is what we mean by invariant: you can't change it. */ -- if (r->val != val) -- return -EINVAL; -- -- return 0; --} -- - static int demux_c15_get(struct kvm_vcpu *vcpu, u64 id, void __user *uaddr) - { - u32 val; -@@ -4503,15 +4539,10 @@ int kvm_sys_reg_get_user(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg, - int kvm_arm_sys_reg_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) - { - void __user *uaddr = (void __user *)(unsigned long)reg->addr; -- int err; - - if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_DEMUX) - return demux_c15_get(vcpu, reg->id, uaddr); - -- err = get_invariant_sys_reg(reg->id, uaddr); -- if (err != -ENOENT) -- return err; -- - return kvm_sys_reg_get_user(vcpu, reg, - sys_reg_descs, ARRAY_SIZE(sys_reg_descs)); - } -@@ -4547,15 +4578,10 @@ int kvm_sys_reg_set_user(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg, - int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) - { - void __user *uaddr = (void __user *)(unsigned long)reg->addr; -- int err; - - if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_DEMUX) - return demux_c15_set(vcpu, reg->id, uaddr); - -- err = set_invariant_sys_reg(reg->id, uaddr); -- if (err != -ENOENT) -- return err; -- - return kvm_sys_reg_set_user(vcpu, reg, - sys_reg_descs, ARRAY_SIZE(sys_reg_descs)); - } -@@ -4644,23 +4670,14 @@ static int walk_sys_regs(struct kvm_vcpu *vcpu, u64 __user *uind) - - unsigned long kvm_arm_num_sys_reg_descs(struct kvm_vcpu *vcpu) - { -- return ARRAY_SIZE(invariant_sys_regs) -- + num_demux_regs() -+ return num_demux_regs() - + walk_sys_regs(vcpu, (u64 __user *)NULL); - } - - int kvm_arm_copy_sys_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices) - { -- unsigned int i; - int err; - -- /* Then give them all the invariant registers' indices. */ -- for (i = 0; i < ARRAY_SIZE(invariant_sys_regs); i++) { -- if (put_user(sys_reg_to_index(&invariant_sys_regs[i]), uindices)) -- return -EFAULT; -- uindices++; -- } -- - err = walk_sys_regs(vcpu, uindices); - if (err < 0) - return err; -@@ -4878,15 +4895,12 @@ int __init kvm_sys_reg_table_init(void) - valid &= check_sysreg_table(cp14_64_regs, ARRAY_SIZE(cp14_64_regs), true); - valid &= check_sysreg_table(cp15_regs, ARRAY_SIZE(cp15_regs), true); - valid &= check_sysreg_table(cp15_64_regs, ARRAY_SIZE(cp15_64_regs), true); -- valid &= check_sysreg_table(invariant_sys_regs, ARRAY_SIZE(invariant_sys_regs), false); - valid &= check_sysreg_table(sys_insn_descs, ARRAY_SIZE(sys_insn_descs), false); - - if (!valid) - return -EINVAL; - -- /* We abuse the reset function to overwrite the table itself. */ -- for (i = 0; i < ARRAY_SIZE(invariant_sys_regs); i++) -- invariant_sys_regs[i].reset(NULL, &invariant_sys_regs[i]); -+ init_imp_id_regs(); - - ret = populate_nv_trap_config(); - --- -2.39.5 - diff --git a/queue-6.12/series b/queue-6.12/series index e11942a0592..2da459ee6fa 100644 --- a/queue-6.12/series +++ b/queue-6.12/series @@ -208,7 +208,6 @@ arm64-dts-rockchip-add-avdd-hdmi-supplies-to-rockpro.patch alsa-hda-realtek-bass-speaker-fixup-for-asus-um5606k.patch drm-amdkfd-remove-gfx-12-trap-handler-page-size-cap.patch drm-amdkfd-fix-instruction-hazard-in-gfx12-trap-hand.patch -kvm-arm64-set-hcr_el2.tid1-unconditionally.patch net-stmmac-fix-accessing-freed-irq-affinity_hint.patch spi-spi-mem-extend-spi-mem-operations-with-a-per-ope.patch spi-spi-mem-add-a-new-controller-capability.patch |