From patchwork Tue Oct 1 22:58:55 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mark Brown X-Patchwork-Id: 13818916 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 79E8CCF3189 for ; Tue, 1 Oct 2024 23:02:53 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 0E3E8440159; Tue, 1 Oct 2024 19:02:53 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 094C068002B; Tue, 1 Oct 2024 19:02:53 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id E4E36440159; Tue, 1 Oct 2024 19:02:52 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0015.hostedemail.com [216.40.44.15]) by kanga.kvack.org (Postfix) with ESMTP id C22A168002B for ; Tue, 1 Oct 2024 19:02:52 -0400 (EDT) Received: from smtpin26.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay05.hostedemail.com (Postfix) with ESMTP id 7437A40C6E for ; Tue, 1 Oct 2024 23:02:52 +0000 (UTC) X-FDA: 82626560184.26.687C8AF Received: from dfw.source.kernel.org (dfw.source.kernel.org [139.178.84.217]) by imf18.hostedemail.com (Postfix) with ESMTP id 7357B1C000A for ; Tue, 1 Oct 2024 23:02:50 +0000 (UTC) Authentication-Results: imf18.hostedemail.com; dkim=pass header.d=kernel.org header.s=k20201202 header.b=Cyuq51xc; spf=pass (imf18.hostedemail.com: domain of broonie@kernel.org designates 139.178.84.217 as permitted sender) smtp.mailfrom=broonie@kernel.org; dmarc=pass (policy=quarantine) header.from=kernel.org ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1727823705; a=rsa-sha256; cv=none; b=3yiHQRDNMUJ9ggSP53mGjpVZQuheCtTlep+Gzb9k3raBa6PTMkpH8lPiZus0VxB53YXen8 BZ9FDyg+EPnoWqwLQY5cAf96wTjEd4VCAcDPAj3kknA4Nq3y9d6CxgVNB8bBhDFKP5a/K8 KwZXdOwfLhZQV9o3baZde6bjiL4fwC0= ARC-Authentication-Results: i=1; imf18.hostedemail.com; dkim=pass header.d=kernel.org header.s=k20201202 header.b=Cyuq51xc; spf=pass (imf18.hostedemail.com: domain of broonie@kernel.org designates 139.178.84.217 as permitted sender) smtp.mailfrom=broonie@kernel.org; dmarc=pass (policy=quarantine) header.from=kernel.org ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1727823705; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=+iLPDj0OL/c+5vgNPTbzrpEtTVrnXNerOXcPtm/Qzko=; b=nvMO9hP8wPyhbFmB1JKuDOtRI4vz1QlufbJdfRMKqMLznvqZPjIb4GVhCzpLDrmfXOzKvv OMa2a7WeTr+0Kyo/tpg9U4yrQ0FpDG779k3HA9wPPL9F0PW2trK1l3YdELB/1/fb/S/iQg eGANlThHNgIBfhPYSfx90z3PbmGc2vI= Received: from smtp.kernel.org (transwarp.subspace.kernel.org [100.75.92.58]) by dfw.source.kernel.org (Postfix) with ESMTP id 8F4F55C555A; Tue, 1 Oct 2024 23:02:45 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id B9403C4CECD; Tue, 1 Oct 2024 23:02:38 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1727823769; bh=dqJA7CeD4vDcg20Hjx10axKKnX1cmEUmt4xdYA5Muo8=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=Cyuq51xcu4Oe8SNzKmI9mGsDHX68xKiyGFKZPwgb0GMZ5mEOIM7xefF0QQXcF69Qx shu2AIFZJRFRPZerp50grzako6nPLG2JEum3Ds3CTS9lb15KHd64u8oQsXoJMrnsMv oNTe3/YFs1LoYBKCCGVTCGfiBJ2QZpQ7WPrRD4SKglR4syksYUMb2RaIp/f45T4ghl +onU/HjwvBT7HS4MyOCWdCbvRHGJ0xz8l/Bn/o0auYC77tiEEk7HExXeCza9wmn4PM hkO0R8z3PfwsMy8RQ+mXYI4JYe+T5ALrxq9bD/ChRrgQCbeQrBOJlfAUiVmYOJ/KQZ OhmTeyE0H2VXw== From: Mark Brown Date: Tue, 01 Oct 2024 23:58:55 +0100 Subject: [PATCH v13 16/40] KVM: arm64: Manage GCS access and registers for guests MIME-Version: 1.0 Message-Id: <20241001-arm64-gcs-v13-16-222b78d87eee@kernel.org> References: <20241001-arm64-gcs-v13-0-222b78d87eee@kernel.org> In-Reply-To: <20241001-arm64-gcs-v13-0-222b78d87eee@kernel.org> To: Catalin Marinas , Will Deacon , Jonathan Corbet , Andrew Morton , Marc Zyngier , Oliver Upton , James Morse , Suzuki K Poulose , Arnd Bergmann , Oleg Nesterov , Eric Biederman , Shuah Khan , "Rick P. Edgecombe" , Deepak Gupta , Ard Biesheuvel , Szabolcs Nagy , Kees Cook Cc: "H.J. Lu" , Paul Walmsley , Palmer Dabbelt , Albert Ou , Florian Weimer , Christian Brauner , Thiago Jung Bauermann , Ross Burton , David Spickett , Yury Khrustalev , Wilco Dijkstra , linux-arm-kernel@lists.infradead.org, linux-doc@vger.kernel.org, kvmarm@lists.linux.dev, linux-fsdevel@vger.kernel.org, linux-arch@vger.kernel.org, linux-mm@kvack.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org, linux-riscv@lists.infradead.org, Mark Brown X-Mailer: b4 0.15-dev-99b12 X-Developer-Signature: v=1; a=openpgp-sha256; l=8542; i=broonie@kernel.org; h=from:subject:message-id; bh=dqJA7CeD4vDcg20Hjx10axKKnX1cmEUmt4xdYA5Muo8=; b=owEBbQGS/pANAwAKASTWi3JdVIfQAcsmYgBm/H7QVskmTvV6wCYz4hF3WV/qZEiKwsSyT7GkyHu7 SVCPg/eJATMEAAEKAB0WIQSt5miqZ1cYtZ/in+ok1otyXVSH0AUCZvx+0AAKCRAk1otyXVSH0LB3B/ 9hUvASp3PrfOYF9blcy86vvimsjQu6j2TgaaQ9yRen9IwMLRFt4xjIU+kGLaJ605pqC0tFUKFygXUd 5/ZS0661yKBdG9X4FGQt4QsbNxNptWpcIpEvGDR06KsegWrpMTt0CFtivrtnFORBbsVY9DhrgarPbf jN/EcKgOagIpuMsQsSzJqSDOwGe19HJlSu16DaJpV7gBULZI359zMxtZ8ppjYbl9eH7PIZfTthSDgK 9J/QGtjH1hkG8bOGYzf7VvchPyPXocNdE7+YEJV8CijQomqs/+x8S1sYwFmsFewuCcMH74W/ucxMlg WA/eh72Tapk2TZ8Sc/2bW37aDcFAJy X-Developer-Key: i=broonie@kernel.org; a=openpgp; fpr=3F2568AAC26998F9E813A1C5C3F436CA30F5D8EB X-Stat-Signature: uga5oacebxeyxdosr3x8m356kpfuq6ho X-Rspamd-Queue-Id: 7357B1C000A X-Rspam-User: X-Rspamd-Server: rspam10 X-HE-Tag: 1727823770-777919 X-HE-Meta: U2FsdGVkX19A/yk/uMDjYKbBgOYhhkKzjVvhh4KZoZ76ugePSZSleV1MgM1HzQ5rnFMvJlLjO4P5yVpOt7Ax1kCvYeX/A5XvnuKVQd2dtMiaTif/nLQorA8Z5acYZyvX9q/iLCKMDI75+kLol5Z/LK3i03w4yLI0Tei9pkzFNgcEpqetBQ2PMNSSjy/+ZPRAqETz/yH/nmbZOUURrxNukiI7ar2FhloVdYieNFctcRoTw3IUhbboxEpcq72LA3K0nVSRYVq4Od6+erfoXKnB1RFu8fcOYoecNRx3vC3a0qr45Cmq3kRZtXEnSnzT66WaJyljxYhNxym0KJ+ZtvSDqzputvE8TmmigtnYE9ko/wwLzIuJ9aZvQ+BjDU1OBQqiLDO0qipdRQuj22xSlHx2lEPiwt5+P1wx72ams6+L+ybs7WPZth8p1F4QHz8GaYccnWZq4Tss187xNekTvP9DqlCxREoqovhEg5Snah6c+UrX4TFQeZUxY0W2wPoWCjG9dhXfvgFBM5r6bdrnlZ7TwPjwzJms9Z0xLdGmN9jjWmgjlByBMnAkMv+/tFe/E0YMcgDUpPA3TJptFQlnezMyfzdSWg8sHZtUHr3UWrYOVkOQLgT1haWUbhs9cqnv/qMiZaOK5PDMWe6z5kJlP2gB+kuEH0pllIWIdXa0gxg9L85rbJX0UBO2QJiwn4pNvMo754rV0P2fV5/mYQSE5JKrtv0cOyACL/EYqzThrRzrVyshMiWBYrfy4uHohIq+0R0+uUh9Voc5O5RtooBZQ92FpdzMDAmUFC5fb4goan9HDySZ7sCrWXjOIuv3vuU59eeH2PHjMhQlXdGIff55zuD8Niv7OjEMh5j8RKejVuDCV6WvOkwe6w1p3+BHHTx3f6+tgfyBM4uWvklZXBtbaajgF3o5XeMzefVQPkYV9a9jUtndGMiTxAaC8qaGH0mlykEwRw/ELLCJX6hLE52YMDN HAryqCVG JDOtmEvnMk+MyP8sMcgpOXBX3Js2LtuvuEyosZJLxy7luqjbsewZyuxq4Q2BO/FgObSaZh9uQ5ew7ocXt7YY4EWkbJFl/K5PtONqc7xpMpY70inPgO8fbQdC8wVQx2Cblj3iTHVg4LSExlQzunTziZpMQjuylUjSTYlFwUGILGj9q10WafEO62KJpXZDn84GHKugQzNK/SZd1GUF7t2JXsnhZr7Z1mt4exqAjLfyVfQSvn1kZtHQ13f+o037BFy0C12kov27xiZ/B3bg8mY2o6DcP567eIsys5nbIyfKWoh1wz1sMpnHpQAe0m3+bN1hOHzqJO+6JxawiTrWOfr5R7FS2ktcaSbi4StiUmZ6EQxr9813iV252PFYruIFxQM2EEDGY X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: GCS introduces a number of system registers for EL1 and EL0, on systems with GCS we need to context switch them and expose them to VMMs to allow guests to use GCS. In order to allow guests to use GCS we also need to configure HCRX_EL2.GCSEn, if this is not set GCS instructions will be noops and CHKFEAT will report GCS as disabled. Also enable fine grained traps for access to the GCS registers by guests which do not have the feature enabled. In order to allow userspace to control availability of the feature to guests we enable writability for only ID_AA64PFR1_EL1.GCS, this is a deliberately conservative choice to avoid errors due to oversights. Further fields should be made writable in future. Reviewed-by: Thiago Jung Bauermann Signed-off-by: Mark Brown --- arch/arm64/include/asm/kvm_host.h | 12 ++++++++++++ arch/arm64/include/asm/vncr_mapping.h | 2 ++ arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h | 31 ++++++++++++++++++++++++++++++ arch/arm64/kvm/sys_regs.c | 27 +++++++++++++++++++++++++- 4 files changed, 71 insertions(+), 1 deletion(-) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 329619c6fa96..31887d3f3de1 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -448,6 +448,10 @@ enum vcpu_sysreg { POR_EL0, /* Permission Overlay Register 0 (EL0) */ + /* Guarded Control Stack registers */ + GCSCRE0_EL1, /* Guarded Control Stack Control (EL0) */ + GCSPR_EL0, /* Guarded Control Stack Pointer (EL0) */ + /* FP/SIMD/SVE */ SVCR, FPMR, @@ -525,6 +529,10 @@ enum vcpu_sysreg { VNCR(POR_EL1), /* Permission Overlay Register 1 (EL1) */ + /* Guarded Control Stack registers */ + VNCR(GCSPR_EL1), /* Guarded Control Stack Pointer (EL1) */ + VNCR(GCSCR_EL1), /* Guarded Control Stack Control (EL1) */ + VNCR(HFGRTR_EL2), VNCR(HFGWTR_EL2), VNCR(HFGITR_EL2), @@ -1495,4 +1503,8 @@ void kvm_set_vm_id_reg(struct kvm *kvm, u32 reg, u64 val); (system_supports_fpmr() && \ kvm_has_feat((k), ID_AA64PFR2_EL1, FPMR, IMP)) +#define kvm_has_gcs(k) \ + (system_supports_gcs() && \ + kvm_has_feat((k), ID_AA64PFR1_EL1, GCS, IMP)) + #endif /* __ARM64_KVM_HOST_H__ */ diff --git a/arch/arm64/include/asm/vncr_mapping.h b/arch/arm64/include/asm/vncr_mapping.h index 06f8ec0906a6..e289064148b3 100644 --- a/arch/arm64/include/asm/vncr_mapping.h +++ b/arch/arm64/include/asm/vncr_mapping.h @@ -89,6 +89,8 @@ #define VNCR_PMSIRR_EL1 0x840 #define VNCR_PMSLATFR_EL1 0x848 #define VNCR_TRFCR_EL1 0x880 +#define VNCR_GCSPR_EL1 0x8C0 +#define VNCR_GCSCR_EL1 0x8D0 #define VNCR_MPAM1_EL1 0x900 #define VNCR_MPAMHCR_EL2 0x930 #define VNCR_MPAMVPMV_EL2 0x938 diff --git a/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h b/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h index 1579a3c08a36..70bd61430834 100644 --- a/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h +++ b/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h @@ -17,6 +17,7 @@ #include static inline bool ctxt_has_s1poe(struct kvm_cpu_context *ctxt); +static inline bool ctxt_has_gcs(struct kvm_cpu_context *ctxt); static inline void __sysreg_save_common_state(struct kvm_cpu_context *ctxt) { @@ -31,6 +32,11 @@ static inline void __sysreg_save_user_state(struct kvm_cpu_context *ctxt) { ctxt_sys_reg(ctxt, TPIDR_EL0) = read_sysreg(tpidr_el0); ctxt_sys_reg(ctxt, TPIDRRO_EL0) = read_sysreg(tpidrro_el0); + + if (ctxt_has_gcs(ctxt)) { + ctxt_sys_reg(ctxt, GCSPR_EL0) = read_sysreg_s(SYS_GCSPR_EL0); + ctxt_sys_reg(ctxt, GCSCRE0_EL1) = read_sysreg_s(SYS_GCSCRE0_EL1); + } } static inline struct kvm_vcpu *ctxt_to_vcpu(struct kvm_cpu_context *ctxt) @@ -83,6 +89,17 @@ static inline bool ctxt_has_s1poe(struct kvm_cpu_context *ctxt) return kvm_has_feat(kern_hyp_va(vcpu->kvm), ID_AA64MMFR3_EL1, S1POE, IMP); } +static inline bool ctxt_has_gcs(struct kvm_cpu_context *ctxt) +{ + struct kvm_vcpu *vcpu; + + if (!cpus_have_final_cap(ARM64_HAS_GCS)) + return false; + + vcpu = ctxt_to_vcpu(ctxt); + return kvm_has_feat(kern_hyp_va(vcpu->kvm), ID_AA64PFR1_EL1, GCS, IMP); +} + static inline void __sysreg_save_el1_state(struct kvm_cpu_context *ctxt) { ctxt_sys_reg(ctxt, SCTLR_EL1) = read_sysreg_el1(SYS_SCTLR); @@ -96,6 +113,10 @@ static inline void __sysreg_save_el1_state(struct kvm_cpu_context *ctxt) if (ctxt_has_s1pie(ctxt)) { ctxt_sys_reg(ctxt, PIR_EL1) = read_sysreg_el1(SYS_PIR); ctxt_sys_reg(ctxt, PIRE0_EL1) = read_sysreg_el1(SYS_PIRE0); + if (ctxt_has_gcs(ctxt)) { + ctxt_sys_reg(ctxt, GCSPR_EL1) = read_sysreg_el1(SYS_GCSPR); + ctxt_sys_reg(ctxt, GCSCR_EL1) = read_sysreg_el1(SYS_GCSCR); + } } if (ctxt_has_s1poe(ctxt)) @@ -150,6 +171,11 @@ static inline void __sysreg_restore_user_state(struct kvm_cpu_context *ctxt) { write_sysreg(ctxt_sys_reg(ctxt, TPIDR_EL0), tpidr_el0); write_sysreg(ctxt_sys_reg(ctxt, TPIDRRO_EL0), tpidrro_el0); + if (ctxt_has_gcs(ctxt)) { + write_sysreg_s(ctxt_sys_reg(ctxt, GCSPR_EL0), SYS_GCSPR_EL0); + write_sysreg_s(ctxt_sys_reg(ctxt, GCSCRE0_EL1), + SYS_GCSCRE0_EL1); + } } static inline void __sysreg_restore_el1_state(struct kvm_cpu_context *ctxt) @@ -181,6 +207,11 @@ static inline void __sysreg_restore_el1_state(struct kvm_cpu_context *ctxt) if (ctxt_has_s1pie(ctxt)) { write_sysreg_el1(ctxt_sys_reg(ctxt, PIR_EL1), SYS_PIR); write_sysreg_el1(ctxt_sys_reg(ctxt, PIRE0_EL1), SYS_PIRE0); + + if (ctxt_has_gcs(ctxt)) { + write_sysreg_el1(ctxt_sys_reg(ctxt, GCSPR_EL1), SYS_GCSPR); + write_sysreg_el1(ctxt_sys_reg(ctxt, GCSCR_EL1), SYS_GCSCR); + } } if (ctxt_has_s1poe(ctxt)) diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index dad88e31f953..bafdf6b31d25 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -1641,6 +1641,15 @@ static unsigned int raz_visibility(const struct kvm_vcpu *vcpu, return REG_RAZ; } +static unsigned int gcs_visibility(const struct kvm_vcpu *vcpu, + const struct sys_reg_desc *r) +{ + if (kvm_has_gcs(vcpu->kvm)) + return 0; + + return REG_HIDDEN; +} + /* cpufeature ID register access trap handlers */ static bool access_id_reg(struct kvm_vcpu *vcpu, @@ -2376,7 +2385,7 @@ static const struct sys_reg_desc sys_reg_descs[] = { ID_AA64PFR0_EL1_RAS | ID_AA64PFR0_EL1_AdvSIMD | ID_AA64PFR0_EL1_FP), }, - ID_SANITISED(ID_AA64PFR1_EL1), + ID_WRITABLE(ID_AA64PFR1_EL1, ID_AA64PFR1_EL1_GCS), ID_WRITABLE(ID_AA64PFR2_EL1, ID_AA64PFR2_EL1_FPMR), ID_UNALLOCATED(4,3), ID_WRITABLE(ID_AA64ZFR0_EL1, ~ID_AA64ZFR0_EL1_RES0), @@ -2461,6 +2470,13 @@ static const struct sys_reg_desc sys_reg_descs[] = { PTRAUTH_KEY(APDB), PTRAUTH_KEY(APGA), + { SYS_DESC(SYS_GCSCR_EL1), NULL, reset_val, GCSCR_EL1, 0, + .visibility = gcs_visibility }, + { SYS_DESC(SYS_GCSPR_EL1), NULL, reset_unknown, GCSPR_EL1, + .visibility = gcs_visibility }, + { SYS_DESC(SYS_GCSCRE0_EL1), NULL, reset_val, GCSCRE0_EL1, 0, + .visibility = gcs_visibility }, + { SYS_DESC(SYS_SPSR_EL1), access_spsr}, { SYS_DESC(SYS_ELR_EL1), access_elr}, @@ -2567,6 +2583,8 @@ static const struct sys_reg_desc sys_reg_descs[] = { CTR_EL0_IDC_MASK | CTR_EL0_DminLine_MASK | CTR_EL0_IminLine_MASK), + { SYS_DESC(SYS_GCSPR_EL0), NULL, reset_unknown, GCSPR_EL0, + .visibility = gcs_visibility }, { SYS_DESC(SYS_SVCR), undef_access, reset_val, SVCR, 0, .visibility = sme_visibility }, { SYS_DESC(SYS_FPMR), undef_access, reset_val, FPMR, 0, .visibility = fp8_visibility }, @@ -4661,6 +4679,9 @@ void kvm_calculate_traps(struct kvm_vcpu *vcpu) if (kvm_has_fpmr(kvm)) vcpu->arch.hcrx_el2 |= HCRX_EL2_EnFPM; + + if (kvm_has_gcs(kvm)) + vcpu->arch.hcrx_el2 |= HCRX_EL2_GCSEn; } if (test_bit(KVM_ARCH_FLAG_FGU_INITIALIZED, &kvm->arch.flags)) @@ -4714,6 +4735,10 @@ void kvm_calculate_traps(struct kvm_vcpu *vcpu) kvm->arch.fgu[HFGxTR_GROUP] |= (HFGxTR_EL2_nPOR_EL1 | HFGxTR_EL2_nPOR_EL0); + if (!kvm_has_gcs(kvm)) + kvm->arch.fgu[HFGxTR_GROUP] |= (HFGxTR_EL2_nGCS_EL0 | + HFGxTR_EL2_nGCS_EL1); + if (!kvm_has_feat(kvm, ID_AA64PFR0_EL1, AMU, IMP)) kvm->arch.fgu[HAFGRTR_GROUP] |= ~(HAFGRTR_EL2_RES0 | HAFGRTR_EL2_RES1);