From patchwork Sun Feb 21 18:56:16 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Chang S. Bae" X-Patchwork-Id: 12097595 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 536B2C433E6 for ; Sun, 21 Feb 2021 19:02:51 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 2875064ED6 for ; Sun, 21 Feb 2021 19:02:51 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230393AbhBUTC3 (ORCPT ); Sun, 21 Feb 2021 14:02:29 -0500 Received: from mga11.intel.com ([192.55.52.93]:31443 "EHLO mga11.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230213AbhBUTCU (ORCPT ); Sun, 21 Feb 2021 14:02:20 -0500 IronPort-SDR: IM7Dd/VkgPcfl97h4I2Kju/4GEAFAZ71fr7pvNHhNx8Pq1WhMJoarXRXMdKz8OhvrSKOCuDSEx 1d+AVCrdJg7A== X-IronPort-AV: E=McAfee;i="6000,8403,9902"; a="180813507" X-IronPort-AV: E=Sophos;i="5.81,195,1610438400"; d="scan'208";a="180813507" Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga102.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Feb 2021 11:01:26 -0800 IronPort-SDR: dqtSDVN9tT4dWgA06J0lIKh9YuY8F6P+syXxOg+8RAKn8rSWNB9GxT6Xl7v2FhtNiCIAiwAiyY 5MKFra0vo9iw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.81,195,1610438400"; d="scan'208";a="429792080" Received: from chang-linux-3.sc.intel.com ([172.25.66.175]) by FMSMGA003.fm.intel.com with ESMTP; 21 Feb 2021 11:01:25 -0800 From: "Chang S. Bae" To: bp@suse.de, luto@kernel.org, tglx@linutronix.de, mingo@kernel.org, x86@kernel.org Cc: len.brown@intel.com, dave.hansen@intel.com, jing2.liu@intel.com, ravi.v.shankar@intel.com, linux-kernel@vger.kernel.org, chang.seok.bae@intel.com, kvm@vger.kernel.org Subject: [PATCH v4 01/22] x86/fpu/xstate: Modify the initialization helper to handle both static and dynamic buffers Date: Sun, 21 Feb 2021 10:56:16 -0800 Message-Id: <20210221185637.19281-2-chang.seok.bae@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210221185637.19281-1-chang.seok.bae@intel.com> References: <20210221185637.19281-1-chang.seok.bae@intel.com> Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org Have the function initializing the xstate buffer take a struct fpu * pointer in preparation for dynamic state buffer support. init_fpstate is a special case, which is indicated by a null pointer parameter to fpstate_init(). Also, fpstate_init_xstate() now accepts the state component bitmap to configure XCOMP_BV for the compacted format. No functional change. Signed-off-by: Chang S. Bae Reviewed-by: Len Brown Cc: x86@kernel.org Cc: linux-kernel@vger.kernel.org Cc: kvm@vger.kernel.org --- Changes from v3: * Updated the changelog. (Borislav Petkov) * Updated the function comment to use kernel-doc style. (Borislav Petkov) Changes from v2: * Updated the changelog with task->fpu removed. (Borislav Petkov) --- arch/x86/include/asm/fpu/internal.h | 6 +++--- arch/x86/kernel/fpu/core.c | 16 +++++++++++++--- arch/x86/kernel/fpu/init.c | 2 +- arch/x86/kernel/fpu/regset.c | 2 +- arch/x86/kernel/fpu/xstate.c | 3 +-- arch/x86/kvm/x86.c | 2 +- 6 files changed, 20 insertions(+), 11 deletions(-) diff --git a/arch/x86/include/asm/fpu/internal.h b/arch/x86/include/asm/fpu/internal.h index 8d33ad80704f..d81d8c407dc0 100644 --- a/arch/x86/include/asm/fpu/internal.h +++ b/arch/x86/include/asm/fpu/internal.h @@ -80,20 +80,20 @@ static __always_inline __pure bool use_fxsr(void) extern union fpregs_state init_fpstate; -extern void fpstate_init(union fpregs_state *state); +extern void fpstate_init(struct fpu *fpu); #ifdef CONFIG_MATH_EMULATION extern void fpstate_init_soft(struct swregs_state *soft); #else static inline void fpstate_init_soft(struct swregs_state *soft) {} #endif -static inline void fpstate_init_xstate(struct xregs_state *xsave) +static inline void fpstate_init_xstate(struct xregs_state *xsave, u64 xcomp_mask) { /* * XRSTORS requires these bits set in xcomp_bv, or it will * trigger #GP: */ - xsave->header.xcomp_bv = XCOMP_BV_COMPACTED_FORMAT | xfeatures_mask_all; + xsave->header.xcomp_bv = XCOMP_BV_COMPACTED_FORMAT | xcomp_mask; } static inline void fpstate_init_fxstate(struct fxregs_state *fx) diff --git a/arch/x86/kernel/fpu/core.c b/arch/x86/kernel/fpu/core.c index 571220ac8bea..d43661d309ab 100644 --- a/arch/x86/kernel/fpu/core.c +++ b/arch/x86/kernel/fpu/core.c @@ -192,8 +192,18 @@ static inline void fpstate_init_fstate(struct fregs_state *fp) fp->fos = 0xffff0000u; } -void fpstate_init(union fpregs_state *state) +/* + * @fpu: If NULL, use init_fpstate + */ +void fpstate_init(struct fpu *fpu) { + union fpregs_state *state; + + if (fpu) + state = &fpu->state; + else + state = &init_fpstate; + if (!static_cpu_has(X86_FEATURE_FPU)) { fpstate_init_soft(&state->soft); return; @@ -202,7 +212,7 @@ void fpstate_init(union fpregs_state *state) memset(state, 0, fpu_kernel_xstate_size); if (static_cpu_has(X86_FEATURE_XSAVES)) - fpstate_init_xstate(&state->xsave); + fpstate_init_xstate(&state->xsave, xfeatures_mask_all); if (static_cpu_has(X86_FEATURE_FXSR)) fpstate_init_fxstate(&state->fxsave); else @@ -262,7 +272,7 @@ static void fpu__initialize(struct fpu *fpu) WARN_ON_FPU(fpu != ¤t->thread.fpu); set_thread_flag(TIF_NEED_FPU_LOAD); - fpstate_init(&fpu->state); + fpstate_init(fpu); trace_x86_fpu_init_state(fpu); } diff --git a/arch/x86/kernel/fpu/init.c b/arch/x86/kernel/fpu/init.c index 701f196d7c68..74e03e3bc20f 100644 --- a/arch/x86/kernel/fpu/init.c +++ b/arch/x86/kernel/fpu/init.c @@ -124,7 +124,7 @@ static void __init fpu__init_system_generic(void) * Set up the legacy init FPU context. (xstate init might overwrite this * with a more modern format, if the CPU supports it.) */ - fpstate_init(&init_fpstate); + fpstate_init(NULL); fpu__init_system_mxcsr(); } diff --git a/arch/x86/kernel/fpu/regset.c b/arch/x86/kernel/fpu/regset.c index c413756ba89f..4c4d9059ff36 100644 --- a/arch/x86/kernel/fpu/regset.c +++ b/arch/x86/kernel/fpu/regset.c @@ -144,7 +144,7 @@ int xstateregs_set(struct task_struct *target, const struct user_regset *regset, * In case of failure, mark all states as init: */ if (ret) - fpstate_init(&fpu->state); + fpstate_init(fpu); return ret; } diff --git a/arch/x86/kernel/fpu/xstate.c b/arch/x86/kernel/fpu/xstate.c index 5d8047441a0a..1a3e5effe0fa 100644 --- a/arch/x86/kernel/fpu/xstate.c +++ b/arch/x86/kernel/fpu/xstate.c @@ -457,8 +457,7 @@ static void __init setup_init_fpu_buf(void) print_xstate_features(); if (boot_cpu_has(X86_FEATURE_XSAVES)) - init_fpstate.xsave.header.xcomp_bv = XCOMP_BV_COMPACTED_FORMAT | - xfeatures_mask_all; + fpstate_init_xstate(&init_fpstate.xsave, xfeatures_mask_all); /* * Init all the features state with header.xfeatures being 0x0 diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 1b404e4d7dd8..b933d005d45e 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -9911,7 +9911,7 @@ static void fx_init(struct kvm_vcpu *vcpu) if (!vcpu->arch.guest_fpu) return; - fpstate_init(&vcpu->arch.guest_fpu->state); + fpstate_init(vcpu->arch.guest_fpu); if (boot_cpu_has(X86_FEATURE_XSAVES)) vcpu->arch.guest_fpu->state.xsave.header.xcomp_bv = host_xcr0 | XSTATE_COMPACTION_ENABLED; From patchwork Sun Feb 21 18:56:18 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Chang S. Bae" X-Patchwork-Id: 12097593 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9622BC43381 for ; Sun, 21 Feb 2021 19:02:16 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 6EF2664ED6 for ; Sun, 21 Feb 2021 19:02:16 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230331AbhBUTCM (ORCPT ); Sun, 21 Feb 2021 14:02:12 -0500 Received: from mga09.intel.com ([134.134.136.24]:2045 "EHLO mga09.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230223AbhBUTCJ (ORCPT ); Sun, 21 Feb 2021 14:02:09 -0500 IronPort-SDR: psePmfTaYjuugRMNXf60EEfs4zcPrN6HGZPdqQ7c60T2/wEQveFR82rkXHf+JzLwSht1igxZ7L QH09IxwJX1hA== X-IronPort-AV: E=McAfee;i="6000,8403,9902"; a="184382821" X-IronPort-AV: E=Sophos;i="5.81,195,1610438400"; d="scan'208";a="184382821" Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by orsmga102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Feb 2021 11:01:27 -0800 IronPort-SDR: f6odO9q7o9IhGt5O1DRgZs3PH1a5IjWH9wrT4V6V2L6FpuFM0Ixsm9mZWqtkqZn/gPEcWVjJdy ZG5y/A3YWPNw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.81,195,1610438400"; d="scan'208";a="429792087" Received: from chang-linux-3.sc.intel.com ([172.25.66.175]) by FMSMGA003.fm.intel.com with ESMTP; 21 Feb 2021 11:01:26 -0800 From: "Chang S. Bae" To: bp@suse.de, luto@kernel.org, tglx@linutronix.de, mingo@kernel.org, x86@kernel.org Cc: len.brown@intel.com, dave.hansen@intel.com, jing2.liu@intel.com, ravi.v.shankar@intel.com, linux-kernel@vger.kernel.org, chang.seok.bae@intel.com, kvm@vger.kernel.org Subject: [PATCH v4 03/22] x86/fpu/xstate: Modify address finders to handle both static and dynamic buffers Date: Sun, 21 Feb 2021 10:56:18 -0800 Message-Id: <20210221185637.19281-4-chang.seok.bae@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210221185637.19281-1-chang.seok.bae@intel.com> References: <20210221185637.19281-1-chang.seok.bae@intel.com> Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org Have all the functions finding xstate address take a struct fpu * pointer in preparation for dynamic state buffer support. init_fpstate is a special case, which is indicated by a null pointer parameter to get_xsave_addr() and __raw_xsave_addr(). No functional change. Signed-off-by: Chang S. Bae Reviewed-by: Len Brown Cc: x86@kernel.org Cc: linux-kernel@vger.kernel.org Cc: kvm@vger.kernel.org --- Changes from v3: * Updated the changelog. (Borislav Petkov) * Updated the function comment to use kernel-doc style. (Borislav Petkov) Changes from v2: * Updated the changelog with task->fpu removed. (Borislav Petkov) Changes from v1: * Rebased on the upstream kernel (5.10) --- arch/x86/include/asm/fpu/internal.h | 2 +- arch/x86/include/asm/fpu/xstate.h | 2 +- arch/x86/include/asm/pgtable.h | 2 +- arch/x86/kernel/cpu/common.c | 2 +- arch/x86/kernel/fpu/xstate.c | 38 +++++++++++++++++++++-------- arch/x86/kvm/x86.c | 10 +++----- arch/x86/mm/pkeys.c | 2 +- 7 files changed, 37 insertions(+), 21 deletions(-) diff --git a/arch/x86/include/asm/fpu/internal.h b/arch/x86/include/asm/fpu/internal.h index d81d8c407dc0..0153c4d4ca77 100644 --- a/arch/x86/include/asm/fpu/internal.h +++ b/arch/x86/include/asm/fpu/internal.h @@ -579,7 +579,7 @@ static inline void switch_fpu_finish(struct fpu *new_fpu) * return to userland e.g. for a copy_to_user() operation. */ if (current->mm) { - pk = get_xsave_addr(&new_fpu->state.xsave, XFEATURE_PKRU); + pk = get_xsave_addr(new_fpu, XFEATURE_PKRU); if (pk) pkru_val = pk->pkru; } diff --git a/arch/x86/include/asm/fpu/xstate.h b/arch/x86/include/asm/fpu/xstate.h index e0f1b22f53ce..24bf8d3f559a 100644 --- a/arch/x86/include/asm/fpu/xstate.h +++ b/arch/x86/include/asm/fpu/xstate.h @@ -100,7 +100,7 @@ extern u64 xstate_fx_sw_bytes[USER_XSTATE_FX_SW_WORDS]; extern void __init update_regset_xstate_info(unsigned int size, u64 xstate_mask); -void *get_xsave_addr(struct xregs_state *xsave, int xfeature_nr); +void *get_xsave_addr(struct fpu *fpu, int xfeature_nr); const void *get_xsave_field_ptr(int xfeature_nr); int using_compacted_format(void); int xfeature_size(int xfeature_nr); diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h index a02c67291cfc..83268b41444f 100644 --- a/arch/x86/include/asm/pgtable.h +++ b/arch/x86/include/asm/pgtable.h @@ -141,7 +141,7 @@ static inline void write_pkru(u32 pkru) if (!boot_cpu_has(X86_FEATURE_OSPKE)) return; - pk = get_xsave_addr(¤t->thread.fpu.state.xsave, XFEATURE_PKRU); + pk = get_xsave_addr(¤t->thread.fpu, XFEATURE_PKRU); /* * The PKRU value in xstate needs to be in sync with the value that is diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index 35ad8480c464..860b19db208b 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -478,7 +478,7 @@ static __always_inline void setup_pku(struct cpuinfo_x86 *c) return; cr4_set_bits(X86_CR4_PKE); - pk = get_xsave_addr(&init_fpstate.xsave, XFEATURE_PKRU); + pk = get_xsave_addr(NULL, XFEATURE_PKRU); if (pk) pk->pkru = init_pkru_value; /* diff --git a/arch/x86/kernel/fpu/xstate.c b/arch/x86/kernel/fpu/xstate.c index 6156dad0feb6..5401a71dd15e 100644 --- a/arch/x86/kernel/fpu/xstate.c +++ b/arch/x86/kernel/fpu/xstate.c @@ -894,15 +894,24 @@ void fpu__resume_cpu(void) * Given an xstate feature nr, calculate where in the xsave * buffer the state is. Callers should ensure that the buffer * is valid. + * + * @fpu: If NULL, use init_fpstate */ -static void *__raw_xsave_addr(struct xregs_state *xsave, int xfeature_nr) +static void *__raw_xsave_addr(struct fpu *fpu, int xfeature_nr) { + void *xsave; + if (!xfeature_enabled(xfeature_nr)) { WARN_ON_FPU(1); return NULL; } - return (void *)xsave + xstate_comp_offsets[xfeature_nr]; + if (fpu) + xsave = &fpu->state.xsave; + else + xsave = &init_fpstate.xsave; + + return xsave + xstate_comp_offsets[xfeature_nr]; } /* * Given the xsave area and a state inside, this function returns the @@ -915,15 +924,18 @@ static void *__raw_xsave_addr(struct xregs_state *xsave, int xfeature_nr) * this will return NULL. * * Inputs: - * xstate: the thread's storage area for all FPU data + * fpu: the thread's FPU data to reference xstate buffer(s). + * (A null pointer parameter indicates init_fpstate.) * xfeature_nr: state which is defined in xsave.h (e.g. XFEATURE_FP, * XFEATURE_SSE, etc...) * Output: * address of the state in the xsave area, or NULL if the * field is not present in the xsave buffer. */ -void *get_xsave_addr(struct xregs_state *xsave, int xfeature_nr) +void *get_xsave_addr(struct fpu *fpu, int xfeature_nr) { + struct xregs_state *xsave; + /* * Do we even *have* xsave state? */ @@ -936,6 +948,12 @@ void *get_xsave_addr(struct xregs_state *xsave, int xfeature_nr) */ WARN_ONCE(!(xfeatures_mask_all & BIT_ULL(xfeature_nr)), "get of unsupported state"); + + if (fpu) + xsave = &fpu->state.xsave; + else + xsave = &init_fpstate.xsave; + /* * This assumes the last 'xsave*' instruction to * have requested that 'xfeature_nr' be saved. @@ -950,7 +968,7 @@ void *get_xsave_addr(struct xregs_state *xsave, int xfeature_nr) if (!(xsave->header.xfeatures & BIT_ULL(xfeature_nr))) return NULL; - return __raw_xsave_addr(xsave, xfeature_nr); + return __raw_xsave_addr(fpu, xfeature_nr); } EXPORT_SYMBOL_GPL(get_xsave_addr); @@ -981,7 +999,7 @@ const void *get_xsave_field_ptr(int xfeature_nr) */ fpu__save(fpu); - return get_xsave_addr(&fpu->state.xsave, xfeature_nr); + return get_xsave_addr(fpu, xfeature_nr); } #ifdef CONFIG_ARCH_HAS_PKEYS @@ -1116,7 +1134,7 @@ void copy_xstate_to_kernel(struct membuf to, struct fpu *fpu) * Copy only in-use xstates: */ if ((header.xfeatures >> i) & 1) { - void *src = __raw_xsave_addr(xsave, i); + void *src = __raw_xsave_addr(fpu, i); copy_part(&to, &last, xstate_offsets[i], xstate_sizes[i], src); @@ -1151,7 +1169,7 @@ int copy_kernel_to_xstate(struct fpu *fpu, const void *kbuf) u64 mask = ((u64)1 << i); if (hdr.xfeatures & mask) { - void *dst = __raw_xsave_addr(xsave, i); + void *dst = __raw_xsave_addr(fpu, i); offset = xstate_offsets[i]; size = xstate_sizes[i]; @@ -1208,7 +1226,7 @@ int copy_user_to_xstate(struct fpu *fpu, const void __user *ubuf) u64 mask = ((u64)1 << i); if (hdr.xfeatures & mask) { - void *dst = __raw_xsave_addr(xsave, i); + void *dst = __raw_xsave_addr(fpu, i); offset = xstate_offsets[i]; size = xstate_sizes[i]; @@ -1450,7 +1468,7 @@ void update_pasid(void) */ xsave = &fpu->state.xsave; xsave->header.xfeatures |= XFEATURE_MASK_PASID; - ppasid_state = get_xsave_addr(xsave, XFEATURE_PASID); + ppasid_state = get_xsave_addr(fpu, XFEATURE_PASID); /* * Since XFEATURE_MASK_PASID is set in xfeatures, ppasid_state * won't be NULL and no need to check its value. diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index b933d005d45e..cc3b604ddcd2 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -4461,7 +4461,7 @@ static void fill_xsave(u8 *dest, struct kvm_vcpu *vcpu) while (valid) { u64 xfeature_mask = valid & -valid; int xfeature_nr = fls64(xfeature_mask) - 1; - void *src = get_xsave_addr(xsave, xfeature_nr); + void *src = get_xsave_addr(vcpu->arch.guest_fpu, xfeature_nr); if (src) { u32 size, offset, ecx, edx; @@ -4504,7 +4504,7 @@ static void load_xsave(struct kvm_vcpu *vcpu, u8 *src) while (valid) { u64 xfeature_mask = valid & -valid; int xfeature_nr = fls64(xfeature_mask) - 1; - void *dest = get_xsave_addr(xsave, xfeature_nr); + void *dest = get_xsave_addr(vcpu->arch.guest_fpu, xfeature_nr); if (dest) { u32 size, offset, ecx, edx; @@ -10140,12 +10140,10 @@ void kvm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event) */ if (init_event) kvm_put_guest_fpu(vcpu); - mpx_state_buffer = get_xsave_addr(&vcpu->arch.guest_fpu->state.xsave, - XFEATURE_BNDREGS); + mpx_state_buffer = get_xsave_addr(vcpu->arch.guest_fpu, XFEATURE_BNDREGS); if (mpx_state_buffer) memset(mpx_state_buffer, 0, sizeof(struct mpx_bndreg_state)); - mpx_state_buffer = get_xsave_addr(&vcpu->arch.guest_fpu->state.xsave, - XFEATURE_BNDCSR); + mpx_state_buffer = get_xsave_addr(vcpu->arch.guest_fpu, XFEATURE_BNDCSR); if (mpx_state_buffer) memset(mpx_state_buffer, 0, sizeof(struct mpx_bndcsr)); if (init_event) diff --git a/arch/x86/mm/pkeys.c b/arch/x86/mm/pkeys.c index 8873ed1438a9..772e8bc3d49d 100644 --- a/arch/x86/mm/pkeys.c +++ b/arch/x86/mm/pkeys.c @@ -177,7 +177,7 @@ static ssize_t init_pkru_write_file(struct file *file, return -EINVAL; WRITE_ONCE(init_pkru_value, new_init_pkru); - pk = get_xsave_addr(&init_fpstate.xsave, XFEATURE_PKRU); + pk = get_xsave_addr(NULL, XFEATURE_PKRU); if (!pk) return -EINVAL; pk->pkru = new_init_pkru; From patchwork Sun Feb 21 18:56:19 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Chang S. Bae" X-Patchwork-Id: 12097591 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6A6C3C433E6 for ; Sun, 21 Feb 2021 19:02:16 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 3D74B64EDB for ; Sun, 21 Feb 2021 19:02:16 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230291AbhBUTCL (ORCPT ); Sun, 21 Feb 2021 14:02:11 -0500 Received: from mga09.intel.com ([134.134.136.24]:2043 "EHLO mga09.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230211AbhBUTCH (ORCPT ); Sun, 21 Feb 2021 14:02:07 -0500 IronPort-SDR: QGSWx0DRrz3Lfv5P3X+rMwbzXIfxk6SLPgJo4zAvBGVsXdLu2XTx/TLgfDi94Bfc5WopKuhaMb RncTBvvmSnNA== X-IronPort-AV: E=McAfee;i="6000,8403,9902"; a="184382822" X-IronPort-AV: E=Sophos;i="5.81,195,1610438400"; d="scan'208";a="184382822" Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by orsmga102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Feb 2021 11:01:27 -0800 IronPort-SDR: Ysf2RZIskvNXoH8suu3ScNj3GRZjUQEmezzxdcQt9tI7P014yLuA6EC214DzBs/xjpMvlHsuQU RFmXEtBoxWaA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.81,195,1610438400"; d="scan'208";a="429792089" Received: from chang-linux-3.sc.intel.com ([172.25.66.175]) by FMSMGA003.fm.intel.com with ESMTP; 21 Feb 2021 11:01:26 -0800 From: "Chang S. Bae" To: bp@suse.de, luto@kernel.org, tglx@linutronix.de, mingo@kernel.org, x86@kernel.org Cc: len.brown@intel.com, dave.hansen@intel.com, jing2.liu@intel.com, ravi.v.shankar@intel.com, linux-kernel@vger.kernel.org, chang.seok.bae@intel.com, kvm@vger.kernel.org Subject: [PATCH v4 04/22] x86/fpu/xstate: Modify the context restore helper to handle both static and dynamic buffers Date: Sun, 21 Feb 2021 10:56:19 -0800 Message-Id: <20210221185637.19281-5-chang.seok.bae@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210221185637.19281-1-chang.seok.bae@intel.com> References: <20210221185637.19281-1-chang.seok.bae@intel.com> Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org Have the function restoring xstate take a struct fpu * pointer in preparation for dynamic state buffer support. No functional change. Signed-off-by: Chang S. Bae Reviewed-by: Len Brown Cc: x86@kernel.org Cc: linux-kernel@vger.kernel.org Cc: kvm@vger.kernel.org --- Changes from v3: * Updated the changelog. (Borislav Petkov) * Reverted the change on the copy_kernel_to_xregs_err() function as not needed. Changes from v2: * Updated the changelog with task->fpu removed. (Borislav Petkov) --- arch/x86/include/asm/fpu/internal.h | 6 ++++-- arch/x86/kernel/fpu/core.c | 4 ++-- arch/x86/kvm/x86.c | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/arch/x86/include/asm/fpu/internal.h b/arch/x86/include/asm/fpu/internal.h index 0153c4d4ca77..b34d0d29e4b8 100644 --- a/arch/x86/include/asm/fpu/internal.h +++ b/arch/x86/include/asm/fpu/internal.h @@ -425,8 +425,10 @@ static inline void __copy_kernel_to_fpregs(union fpregs_state *fpstate, u64 mask } } -static inline void copy_kernel_to_fpregs(union fpregs_state *fpstate) +static inline void copy_kernel_to_fpregs(struct fpu *fpu) { + union fpregs_state *fpstate = &fpu->state; + /* * AMD K7/K8 CPUs don't save/restore FDP/FIP/FOP unless an exception is * pending. Clear the x87 state here by setting it to fixed values. @@ -511,7 +513,7 @@ static inline void __fpregs_load_activate(void) return; if (!fpregs_state_valid(fpu, cpu)) { - copy_kernel_to_fpregs(&fpu->state); + copy_kernel_to_fpregs(fpu); fpregs_activate(fpu); fpu->last_cpu = cpu; } diff --git a/arch/x86/kernel/fpu/core.c b/arch/x86/kernel/fpu/core.c index d43661d309ab..5775e64b0172 100644 --- a/arch/x86/kernel/fpu/core.c +++ b/arch/x86/kernel/fpu/core.c @@ -173,7 +173,7 @@ void fpu__save(struct fpu *fpu) if (!test_thread_flag(TIF_NEED_FPU_LOAD)) { if (!copy_fpregs_to_fpstate(fpu)) { - copy_kernel_to_fpregs(&fpu->state); + copy_kernel_to_fpregs(fpu); } } @@ -251,7 +251,7 @@ int fpu__copy(struct task_struct *dst, struct task_struct *src) memcpy(&dst_fpu->state, &src_fpu->state, fpu_kernel_xstate_size); else if (!copy_fpregs_to_fpstate(dst_fpu)) - copy_kernel_to_fpregs(&dst_fpu->state); + copy_kernel_to_fpregs(dst_fpu); fpregs_unlock(); diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index cc3b604ddcd2..dd9565d12d81 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -9313,7 +9313,7 @@ static void kvm_put_guest_fpu(struct kvm_vcpu *vcpu) if (vcpu->arch.guest_fpu) kvm_save_current_fpu(vcpu->arch.guest_fpu); - copy_kernel_to_fpregs(&vcpu->arch.user_fpu->state); + copy_kernel_to_fpregs(vcpu->arch.user_fpu); fpregs_mark_activate(); fpregs_unlock(); From patchwork Sun Feb 21 18:56:21 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Chang S. Bae" X-Patchwork-Id: 12097599 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 91A98C4332B for ; Sun, 21 Feb 2021 19:02:51 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 67C8A64EE9 for ; Sun, 21 Feb 2021 19:02:51 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230431AbhBUTCk (ORCPT ); Sun, 21 Feb 2021 14:02:40 -0500 Received: from mga09.intel.com ([134.134.136.24]:2045 "EHLO mga09.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230206AbhBUTCZ (ORCPT ); Sun, 21 Feb 2021 14:02:25 -0500 IronPort-SDR: /kKcnz+YFXJnS56yPr9MS9L3HU0Ea1x0GMN1KVIDUjHw4XRIza1wQaFLdifDP3HUFRUsQvxOlV rIHcBKFE/7Bg== X-IronPort-AV: E=McAfee;i="6000,8403,9902"; a="184382824" X-IronPort-AV: E=Sophos;i="5.81,195,1610438400"; d="scan'208";a="184382824" Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by orsmga102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Feb 2021 11:01:27 -0800 IronPort-SDR: +TZ5FY2bPtSLhvgm1OpabPFyD83SIwsAiejzjqLGQ+Ch+7NCjvMgRhgSIAl0gJnHevLFVsQ/3K Vwwduy7rHi0g== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.81,195,1610438400"; d="scan'208";a="429792096" Received: from chang-linux-3.sc.intel.com ([172.25.66.175]) by FMSMGA003.fm.intel.com with ESMTP; 21 Feb 2021 11:01:26 -0800 From: "Chang S. Bae" To: bp@suse.de, luto@kernel.org, tglx@linutronix.de, mingo@kernel.org, x86@kernel.org Cc: len.brown@intel.com, dave.hansen@intel.com, jing2.liu@intel.com, ravi.v.shankar@intel.com, linux-kernel@vger.kernel.org, chang.seok.bae@intel.com, kvm@vger.kernel.org Subject: [PATCH v4 06/22] x86/fpu/xstate: Add new variables to indicate dynamic xstate buffer size Date: Sun, 21 Feb 2021 10:56:21 -0800 Message-Id: <20210221185637.19281-7-chang.seok.bae@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210221185637.19281-1-chang.seok.bae@intel.com> References: <20210221185637.19281-1-chang.seok.bae@intel.com> Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org The xstate per-task buffer is in preparation to be dynamic for user states. Introduce new size variables to indicate the minimum and maximum size of the buffer. The value is determined at boot-time. Instead of adding them as newly exported, introduce helper functions to access them as well as the user buffer size. No functional change. Those sizes have no difference, as the buffer is not dynamic yet. Signed-off-by: Chang S. Bae Reviewed-by: Len Brown Cc: x86@kernel.org Cc: linux-kernel@vger.kernel.org Cc: kvm@vger.kernel.org --- Changes from v3: * Added as a new patch to add the variables along with new helpers. (Borislav Petkov) --- arch/x86/include/asm/fpu/xstate.h | 9 ++++ arch/x86/include/asm/processor.h | 10 +--- arch/x86/kernel/fpu/core.c | 24 +++++++--- arch/x86/kernel/fpu/init.c | 26 ++++------- arch/x86/kernel/fpu/regset.c | 4 +- arch/x86/kernel/fpu/signal.c | 27 ++++++----- arch/x86/kernel/fpu/xstate.c | 78 ++++++++++++++++++++++++------- arch/x86/kernel/process.c | 7 +++ arch/x86/kvm/x86.c | 5 +- 9 files changed, 129 insertions(+), 61 deletions(-) diff --git a/arch/x86/include/asm/fpu/xstate.h b/arch/x86/include/asm/fpu/xstate.h index 6ce8350672c2..1fba2ca15874 100644 --- a/arch/x86/include/asm/fpu/xstate.h +++ b/arch/x86/include/asm/fpu/xstate.h @@ -102,6 +102,15 @@ extern u64 xstate_fx_sw_bytes[USER_XSTATE_FX_SW_WORDS]; extern void __init update_regset_xstate_info(unsigned int size, u64 xstate_mask); +enum xstate_config { + XSTATE_MIN_SIZE, + XSTATE_MAX_SIZE, + XSTATE_USER_SIZE +}; + +extern unsigned int get_xstate_config(enum xstate_config cfg); +void set_xstate_config(enum xstate_config cfg, unsigned int value); + void *get_xsave_addr(struct fpu *fpu, int xfeature_nr); const void *get_xsave_field_ptr(int xfeature_nr); int using_compacted_format(void); diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index c20a52b5534b..f70228312790 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -477,9 +477,6 @@ DECLARE_PER_CPU_ALIGNED(struct stack_canary, stack_canary); DECLARE_PER_CPU(struct irq_stack *, softirq_stack_ptr); #endif /* X86_64 */ -extern unsigned int fpu_kernel_xstate_size; -extern unsigned int fpu_user_xstate_size; - struct perf_event; struct thread_struct { @@ -545,12 +542,7 @@ struct thread_struct { }; /* Whitelist the FPU state from the task_struct for hardened usercopy. */ -static inline void arch_thread_struct_whitelist(unsigned long *offset, - unsigned long *size) -{ - *offset = offsetof(struct thread_struct, fpu.state); - *size = fpu_kernel_xstate_size; -} +extern void arch_thread_struct_whitelist(unsigned long *offset, unsigned long *size); /* * Thread-synchronous status. diff --git a/arch/x86/kernel/fpu/core.c b/arch/x86/kernel/fpu/core.c index 5775e64b0172..043fdba8431c 100644 --- a/arch/x86/kernel/fpu/core.c +++ b/arch/x86/kernel/fpu/core.c @@ -198,21 +198,30 @@ static inline void fpstate_init_fstate(struct fregs_state *fp) void fpstate_init(struct fpu *fpu) { union fpregs_state *state; + unsigned int size; + u64 mask; - if (fpu) + if (fpu) { state = &fpu->state; - else + /* The dynamic user states are not prepared yet. */ + mask = xfeatures_mask_all & ~xfeatures_mask_user_dynamic; + size = get_xstate_config(XSTATE_MIN_SIZE); + } else { state = &init_fpstate; + mask = xfeatures_mask_all; + size = get_xstate_config(XSTATE_MAX_SIZE); + } if (!static_cpu_has(X86_FEATURE_FPU)) { fpstate_init_soft(&state->soft); return; } - memset(state, 0, fpu_kernel_xstate_size); + memset(state, 0, size); if (static_cpu_has(X86_FEATURE_XSAVES)) - fpstate_init_xstate(&state->xsave, xfeatures_mask_all); + fpstate_init_xstate(&state->xsave, mask); + if (static_cpu_has(X86_FEATURE_FXSR)) fpstate_init_fxstate(&state->fxsave); else @@ -235,8 +244,11 @@ int fpu__copy(struct task_struct *dst, struct task_struct *src) /* * Don't let 'init optimized' areas of the XSAVE area * leak into the child task: + * + * The child does not inherit the dynamic states. So, + * the xstate buffer has the minimum size. */ - memset(&dst_fpu->state.xsave, 0, fpu_kernel_xstate_size); + memset(&dst_fpu->state.xsave, 0, get_xstate_config(XSTATE_MIN_SIZE)); /* * If the FPU registers are not current just memcpy() the state. @@ -248,7 +260,7 @@ int fpu__copy(struct task_struct *dst, struct task_struct *src) */ fpregs_lock(); if (test_thread_flag(TIF_NEED_FPU_LOAD)) - memcpy(&dst_fpu->state, &src_fpu->state, fpu_kernel_xstate_size); + memcpy(&dst_fpu->state, &src_fpu->state, get_xstate_config(XSTATE_MIN_SIZE)); else if (!copy_fpregs_to_fpstate(dst_fpu)) copy_kernel_to_fpregs(dst_fpu); diff --git a/arch/x86/kernel/fpu/init.c b/arch/x86/kernel/fpu/init.c index 74e03e3bc20f..f63765b7a83c 100644 --- a/arch/x86/kernel/fpu/init.c +++ b/arch/x86/kernel/fpu/init.c @@ -129,15 +129,6 @@ static void __init fpu__init_system_generic(void) fpu__init_system_mxcsr(); } -/* - * Size of the FPU context state. All tasks in the system use the - * same context size, regardless of what portion they use. - * This is inherent to the XSAVE architecture which puts all state - * components into a single, continuous memory block: - */ -unsigned int fpu_kernel_xstate_size; -EXPORT_SYMBOL_GPL(fpu_kernel_xstate_size); - /* Get alignment of the TYPE. */ #define TYPE_ALIGN(TYPE) offsetof(struct { char x; TYPE test; }, test) @@ -167,8 +158,10 @@ static void __init fpu__init_task_struct_size(void) /* * Add back the dynamically-calculated register state * size. + * + * Use the minimum size as embedded to task_struct. */ - task_size += fpu_kernel_xstate_size; + task_size += get_xstate_config(XSTATE_MIN_SIZE); /* * We dynamically size 'struct fpu', so we require that @@ -193,6 +186,7 @@ static void __init fpu__init_task_struct_size(void) static void __init fpu__init_system_xstate_size_legacy(void) { static int on_boot_cpu __initdata = 1; + unsigned int size; WARN_ON_FPU(!on_boot_cpu); on_boot_cpu = 0; @@ -203,17 +197,17 @@ static void __init fpu__init_system_xstate_size_legacy(void) */ if (!boot_cpu_has(X86_FEATURE_FPU)) { - fpu_kernel_xstate_size = sizeof(struct swregs_state); + size = sizeof(struct swregs_state); } else { if (boot_cpu_has(X86_FEATURE_FXSR)) - fpu_kernel_xstate_size = - sizeof(struct fxregs_state); + size = sizeof(struct fxregs_state); else - fpu_kernel_xstate_size = - sizeof(struct fregs_state); + size = sizeof(struct fregs_state); } - fpu_user_xstate_size = fpu_kernel_xstate_size; + set_xstate_config(XSTATE_MIN_SIZE, size); + set_xstate_config(XSTATE_MAX_SIZE, size); + set_xstate_config(XSTATE_USER_SIZE, size); } /* diff --git a/arch/x86/kernel/fpu/regset.c b/arch/x86/kernel/fpu/regset.c index 5e13e58d11d4..6a025fa26a7e 100644 --- a/arch/x86/kernel/fpu/regset.c +++ b/arch/x86/kernel/fpu/regset.c @@ -99,7 +99,7 @@ int xstateregs_get(struct task_struct *target, const struct user_regset *regset, /* * Copy the xstate memory layout. */ - return membuf_write(&to, xsave, fpu_user_xstate_size); + return membuf_write(&to, xsave, get_xstate_config(XSTATE_USER_SIZE)); } } @@ -117,7 +117,7 @@ int xstateregs_set(struct task_struct *target, const struct user_regset *regset, /* * A whole standard-format XSAVE buffer is needed: */ - if ((pos != 0) || (count < fpu_user_xstate_size)) + if ((pos != 0) || (count < get_xstate_config(XSTATE_USER_SIZE))) return -EFAULT; xsave = &fpu->state.xsave; diff --git a/arch/x86/kernel/fpu/signal.c b/arch/x86/kernel/fpu/signal.c index 0d6deb75c507..3a2d8665b9a3 100644 --- a/arch/x86/kernel/fpu/signal.c +++ b/arch/x86/kernel/fpu/signal.c @@ -35,7 +35,7 @@ static inline int check_for_xstate(struct fxregs_state __user *buf, /* Check for the first magic field and other error scenarios. */ if (fx_sw->magic1 != FP_XSTATE_MAGIC1 || fx_sw->xstate_size < min_xstate_size || - fx_sw->xstate_size > fpu_user_xstate_size || + fx_sw->xstate_size > get_xstate_config(XSTATE_USER_SIZE) || fx_sw->xstate_size > fx_sw->extended_size) return -1; @@ -98,7 +98,7 @@ static inline int save_xstate_epilog(void __user *buf, int ia32_frame) return err; err |= __put_user(FP_XSTATE_MAGIC2, - (__u32 __user *)(buf + fpu_user_xstate_size)); + (__u32 __user *)(buf + get_xstate_config(XSTATE_USER_SIZE))); /* * Read the xfeatures which we copied (directly from the cpu or @@ -135,7 +135,7 @@ static inline int copy_fpregs_to_sigframe(struct xregs_state __user *buf) else err = copy_fregs_to_user((struct fregs_state __user *) buf); - if (unlikely(err) && __clear_user(buf, fpu_user_xstate_size)) + if (unlikely(err) && __clear_user(buf, get_xstate_config(XSTATE_USER_SIZE))) err = -EFAULT; return err; } @@ -196,7 +196,7 @@ int copy_fpstate_to_sigframe(void __user *buf, void __user *buf_fx, int size) fpregs_unlock(); if (ret) { - if (!fault_in_pages_writeable(buf_fx, fpu_user_xstate_size)) + if (!fault_in_pages_writeable(buf_fx, get_xstate_config(XSTATE_USER_SIZE))) goto retry; return -EFAULT; } @@ -290,13 +290,13 @@ static int copy_user_to_fpregs_zeroing(void __user *buf, u64 xbv, int fx_only) static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size) { struct user_i387_ia32_struct *envp = NULL; - int state_size = fpu_kernel_xstate_size; int ia32_fxstate = (buf != buf_fx); struct task_struct *tsk = current; struct fpu *fpu = &tsk->thread.fpu; struct user_i387_ia32_struct env; u64 user_xfeatures = 0; int fx_only = 0; + int state_size; int ret = 0; ia32_fxstate &= (IS_ENABLED(CONFIG_X86_32) || @@ -330,6 +330,9 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size) state_size = fx_sw_user.xstate_size; user_xfeatures = fx_sw_user.xfeatures; } + } else { + /* The buffer cannot be dynamic without using XSAVE. */ + state_size = get_xstate_config(XSTATE_MIN_SIZE); } if ((unsigned long)buf_fx % 64) @@ -469,8 +472,9 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size) static inline int xstate_sigframe_size(void) { - return use_xsave() ? fpu_user_xstate_size + FP_XSTATE_MAGIC2_SIZE : - fpu_user_xstate_size; + int size = get_xstate_config(XSTATE_USER_SIZE); + + return use_xsave() ? size + FP_XSTATE_MAGIC2_SIZE : size; } /* @@ -514,19 +518,20 @@ fpu__alloc_mathframe(unsigned long sp, int ia32_frame, */ void fpu__init_prepare_fx_sw_frame(void) { - int size = fpu_user_xstate_size + FP_XSTATE_MAGIC2_SIZE; + int xstate_size = get_xstate_config(XSTATE_USER_SIZE); + int ext_size = xstate_size + FP_XSTATE_MAGIC2_SIZE; fx_sw_reserved.magic1 = FP_XSTATE_MAGIC1; - fx_sw_reserved.extended_size = size; + fx_sw_reserved.extended_size = ext_size; fx_sw_reserved.xfeatures = xfeatures_mask_user(); - fx_sw_reserved.xstate_size = fpu_user_xstate_size; + fx_sw_reserved.xstate_size = xstate_size; if (IS_ENABLED(CONFIG_IA32_EMULATION) || IS_ENABLED(CONFIG_X86_32)) { int fsave_header_size = sizeof(struct fregs_state); fx_sw_reserved_ia32 = fx_sw_reserved; - fx_sw_reserved_ia32.extended_size = size + fsave_header_size; + fx_sw_reserved_ia32.extended_size = ext_size + fsave_header_size; } } diff --git a/arch/x86/kernel/fpu/xstate.c b/arch/x86/kernel/fpu/xstate.c index 43940828d1a3..16379c368714 100644 --- a/arch/x86/kernel/fpu/xstate.c +++ b/arch/x86/kernel/fpu/xstate.c @@ -72,12 +72,50 @@ static unsigned int xstate_sizes[XFEATURE_MAX] = { [ 0 ... XFEATURE_MAX - 1] = static unsigned int xstate_comp_offsets[XFEATURE_MAX] = { [ 0 ... XFEATURE_MAX - 1] = -1}; static unsigned int xstate_supervisor_only_offsets[XFEATURE_MAX] = { [ 0 ... XFEATURE_MAX - 1] = -1}; -/* - * The XSAVE area of kernel can be in standard or compacted format; - * it is always in standard format for user mode. This is the user - * mode standard format size used for signal and ptrace frames. +/** + * struct fpu_xstate_buffer_config - xstate per-task buffer configuration + * @min_size, @max_size: The size of the kernel buffer. It is variable with the dynamic user + * states. Every task has the minimum buffer by default. It can be + * expanded to the max size. The two sizes are the same when using the + * standard format. + * @user_size: The size of the userspace buffer. The buffer is always in the + * standard format. It is used for signal and ptrace frames. */ -unsigned int fpu_user_xstate_size; +struct fpu_xstate_buffer_config { + unsigned int min_size, max_size; + unsigned int user_size; +}; + +static struct fpu_xstate_buffer_config buffer_config __read_mostly; + +unsigned int get_xstate_config(enum xstate_config cfg) +{ + switch (cfg) { + case XSTATE_MIN_SIZE: + return buffer_config.min_size; + case XSTATE_MAX_SIZE: + return buffer_config.max_size; + case XSTATE_USER_SIZE: + return buffer_config.user_size; + default: + return 0; + } +} +EXPORT_SYMBOL_GPL(get_xstate_config); + +void set_xstate_config(enum xstate_config cfg, unsigned int value) +{ + switch (cfg) { + case XSTATE_MIN_SIZE: + buffer_config.min_size = value; + break; + case XSTATE_MAX_SIZE: + buffer_config.max_size = value; + break; + case XSTATE_USER_SIZE: + buffer_config.user_size = value; + } +} /* * Return whether the system supports a given xfeature. @@ -659,7 +697,7 @@ static void do_extra_xstate_size_checks(void) */ paranoid_xstate_size += xfeature_size(i); } - XSTATE_WARN_ON(paranoid_xstate_size != fpu_kernel_xstate_size); + XSTATE_WARN_ON(paranoid_xstate_size != get_xstate_config(XSTATE_MAX_SIZE)); } @@ -754,21 +792,29 @@ static int __init init_xstate_size(void) else possible_xstate_size = xsave_size; - /* Ensure we have the space to store all enabled: */ - if (!is_supported_xstate_size(possible_xstate_size)) - return -EINVAL; - /* - * The size is OK, we are definitely going to use xsave, - * make it known to the world that we need more space. + * The size accounts for all the possible states reserved in the + * per-task buffer. Set the maximum with this value. */ - fpu_kernel_xstate_size = possible_xstate_size; + set_xstate_config(XSTATE_MAX_SIZE, possible_xstate_size); + + /* Perform an extra check for the maximum size. */ do_extra_xstate_size_checks(); + /* + * Set the minimum to be the same as the maximum. The dynamic + * user states are not supported yet. + */ + set_xstate_config(XSTATE_MIN_SIZE, possible_xstate_size); + + /* Ensure the minimum size fits in the statically-alocated buffer: */ + if (!is_supported_xstate_size(get_xstate_config(XSTATE_MIN_SIZE))) + return -EINVAL; + /* * User space is always in standard format. */ - fpu_user_xstate_size = xsave_size; + set_xstate_config(XSTATE_USER_SIZE, xsave_size); return 0; } @@ -859,7 +905,7 @@ void __init fpu__init_system_xstate(void) * Update info used for ptrace frames; use standard-format size and no * supervisor xstates: */ - update_regset_xstate_info(fpu_user_xstate_size, xfeatures_mask_user()); + update_regset_xstate_info(get_xstate_config(XSTATE_USER_SIZE), xfeatures_mask_user()); fpu__init_prepare_fx_sw_frame(); setup_init_fpu_buf(); @@ -869,7 +915,7 @@ void __init fpu__init_system_xstate(void) pr_info("x86/fpu: Enabled xstate features 0x%llx, context size is %d bytes, using '%s' format.\n", xfeatures_mask_all, - fpu_kernel_xstate_size, + get_xstate_config(XSTATE_MAX_SIZE), boot_cpu_has(X86_FEATURE_XSAVES) ? "compacted" : "standard"); return; diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index 145a7ac0c19a..2070ae35ccbc 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -96,6 +96,13 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) return fpu__copy(dst, src); } +void arch_thread_struct_whitelist(unsigned long *offset, unsigned long *size) +{ + *offset = offsetof(struct thread_struct, fpu.state); + /* The buffer embedded in thread_struct has the minimum size. */ + *size = get_xstate_config(XSTATE_MIN_SIZE); +} + /* * Free thread data structures etc.. */ diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index dd9565d12d81..5c70a4270157 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -9271,10 +9271,13 @@ static void kvm_save_current_fpu(struct fpu *fpu) /* * If the target FPU state is not resident in the CPU registers, just * memcpy() from current, else save CPU state directly to the target. + * + * KVM does not support dynamic user states yet. Assume the buffer + * always has the minimum size. */ if (test_thread_flag(TIF_NEED_FPU_LOAD)) memcpy(&fpu->state, ¤t->thread.fpu.state, - fpu_kernel_xstate_size); + get_xstate_config(XSTATE_MIN_SIZE)); else copy_fpregs_to_fpstate(fpu); } From patchwork Sun Feb 21 18:56:23 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Chang S. Bae" X-Patchwork-Id: 12097601 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2BF8FC433E9 for ; Sun, 21 Feb 2021 19:03:23 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id E459F64EE9 for ; Sun, 21 Feb 2021 19:03:22 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230507AbhBUTDL (ORCPT ); Sun, 21 Feb 2021 14:03:11 -0500 Received: from mga09.intel.com ([134.134.136.24]:2045 "EHLO mga09.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230469AbhBUTCo (ORCPT ); Sun, 21 Feb 2021 14:02:44 -0500 IronPort-SDR: aGM8miW3VbQUOu7/u5cH/QUaYMNpEMoSFSMQWOa/XaB8LHBmPtnxV2tGPpwe8hkxH7uGwSb8L1 SA675bW3KHHg== X-IronPort-AV: E=McAfee;i="6000,8403,9902"; a="184382827" X-IronPort-AV: E=Sophos;i="5.81,195,1610438400"; d="scan'208";a="184382827" Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by orsmga102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Feb 2021 11:01:28 -0800 IronPort-SDR: IqATZu8D38l3AJo11y1gcfDB4EDG0MF75OYMMTQZNml+9mbwGNmT/FahRKoVTXzXgo2hFJ7fju ijO/QWC+2K9Q== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.81,195,1610438400"; d="scan'208";a="429792103" Received: from chang-linux-3.sc.intel.com ([172.25.66.175]) by FMSMGA003.fm.intel.com with ESMTP; 21 Feb 2021 11:01:27 -0800 From: "Chang S. Bae" To: bp@suse.de, luto@kernel.org, tglx@linutronix.de, mingo@kernel.org, x86@kernel.org Cc: len.brown@intel.com, dave.hansen@intel.com, jing2.liu@intel.com, ravi.v.shankar@intel.com, linux-kernel@vger.kernel.org, chang.seok.bae@intel.com, kvm@vger.kernel.org Subject: [PATCH v4 08/22] x86/fpu/xstate: Convert the struct fpu 'state' field to a pointer Date: Sun, 21 Feb 2021 10:56:23 -0800 Message-Id: <20210221185637.19281-9-chang.seok.bae@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210221185637.19281-1-chang.seok.bae@intel.com> References: <20210221185637.19281-1-chang.seok.bae@intel.com> Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org The xstate per-task buffer is embedded into struct fpu. And the field 'state' represents the buffer. When the dynamic user states in use, the buffer may be dynamically allocated. Convert the 'state' field to point either the embedded buffer or the dynamically-allocated buffer. Add a new field to represent the embedded buffer. Every child process will set the pointer on its creation. And the initial task sets it before dealing with soft FPU. No functional change. Suggested-by: Borislav Petkov Signed-off-by: Chang S. Bae Reviewed-by: Len Brown Cc: x86@kernel.org Cc: linux-kernel@vger.kernel.org Cc: kvm@vger.kernel.org --- Changes from v3: * Added as a new patch to simplify the buffer access. (Borislav Petkov) --- arch/x86/include/asm/fpu/internal.h | 6 +++--- arch/x86/include/asm/fpu/types.h | 27 +++++++++++++++++++++------ arch/x86/include/asm/trace/fpu.h | 4 ++-- arch/x86/kernel/fpu/core.c | 26 ++++++++++++++------------ arch/x86/kernel/fpu/init.c | 6 ++++-- arch/x86/kernel/fpu/regset.c | 22 +++++++++++----------- arch/x86/kernel/fpu/signal.c | 22 +++++++++++----------- arch/x86/kernel/fpu/xstate.c | 18 +++++++++--------- arch/x86/kernel/process.c | 2 +- arch/x86/kvm/x86.c | 18 +++++++++--------- arch/x86/math-emu/fpu_aux.c | 2 +- arch/x86/math-emu/fpu_entry.c | 4 ++-- arch/x86/math-emu/fpu_system.h | 2 +- 13 files changed, 89 insertions(+), 70 deletions(-) diff --git a/arch/x86/include/asm/fpu/internal.h b/arch/x86/include/asm/fpu/internal.h index b34d0d29e4b8..46cb51ef4d17 100644 --- a/arch/x86/include/asm/fpu/internal.h +++ b/arch/x86/include/asm/fpu/internal.h @@ -199,9 +199,9 @@ static inline int copy_user_to_fregs(struct fregs_state __user *fx) static inline void copy_fxregs_to_kernel(struct fpu *fpu) { if (IS_ENABLED(CONFIG_X86_32)) - asm volatile( "fxsave %[fx]" : [fx] "=m" (fpu->state.fxsave)); + asm volatile( "fxsave %[fx]" : [fx] "=m" (fpu->state->fxsave)); else - asm volatile("fxsaveq %[fx]" : [fx] "=m" (fpu->state.fxsave)); + asm volatile("fxsaveq %[fx]" : [fx] "=m" (fpu->state->fxsave)); } /* These macros all use (%edi)/(%rdi) as the single memory argument. */ @@ -427,7 +427,7 @@ static inline void __copy_kernel_to_fpregs(union fpregs_state *fpstate, u64 mask static inline void copy_kernel_to_fpregs(struct fpu *fpu) { - union fpregs_state *fpstate = &fpu->state; + union fpregs_state *fpstate = fpu->state; /* * AMD K7/K8 CPUs don't save/restore FDP/FIP/FOP unless an exception is diff --git a/arch/x86/include/asm/fpu/types.h b/arch/x86/include/asm/fpu/types.h index f5a38a5f3ae1..dcd28a545377 100644 --- a/arch/x86/include/asm/fpu/types.h +++ b/arch/x86/include/asm/fpu/types.h @@ -339,13 +339,28 @@ struct fpu { /* * @state: * - * In-memory copy of all FPU registers that we save/restore - * over context switches. If the task is using the FPU then - * the registers in the FPU are more recent than this state - * copy. If the task context-switches away then they get - * saved here and represent the FPU state. + * A pointer to indicate the in-memory copy of all FPU registers that are + * saved/restored over context switches. + * + * Initially @state points to @__default_state. When dynamic states get + * used, a memory is allocated for the larger state copy and @state is + * updated to point to it. Then, the state in ->state supersedes and + * invalidates the state in @__default_state. + * + * In general, if the task is using the FPU then the registers in the FPU + * are more recent than the state copy. If the task context-switches away + * then they get saved in ->state and represent the FPU state. + */ + union fpregs_state *state; + + /* + * @__default_state: + * + * Initial in-memory copy of all FPU registers that saved/restored + * over context switches. When the task is switched to dynamic states, + * this copy is replaced with the new in-memory copy in ->state. */ - union fpregs_state state; + union fpregs_state __default_state; /* * WARNING: 'state' is dynamically-sized. Do not put * anything after it here. diff --git a/arch/x86/include/asm/trace/fpu.h b/arch/x86/include/asm/trace/fpu.h index 879b77792f94..ef82f4824ce7 100644 --- a/arch/x86/include/asm/trace/fpu.h +++ b/arch/x86/include/asm/trace/fpu.h @@ -22,8 +22,8 @@ DECLARE_EVENT_CLASS(x86_fpu, __entry->fpu = fpu; __entry->load_fpu = test_thread_flag(TIF_NEED_FPU_LOAD); if (boot_cpu_has(X86_FEATURE_OSXSAVE)) { - __entry->xfeatures = fpu->state.xsave.header.xfeatures; - __entry->xcomp_bv = fpu->state.xsave.header.xcomp_bv; + __entry->xfeatures = fpu->state->xsave.header.xfeatures; + __entry->xcomp_bv = fpu->state->xsave.header.xcomp_bv; } ), TP_printk("x86/fpu: %p load: %d xfeatures: %llx xcomp_bv: %llx", diff --git a/arch/x86/kernel/fpu/core.c b/arch/x86/kernel/fpu/core.c index 043fdba8431c..60a581aa0be8 100644 --- a/arch/x86/kernel/fpu/core.c +++ b/arch/x86/kernel/fpu/core.c @@ -95,13 +95,13 @@ EXPORT_SYMBOL(irq_fpu_usable); int copy_fpregs_to_fpstate(struct fpu *fpu) { if (likely(use_xsave())) { - copy_xregs_to_kernel(&fpu->state.xsave); + copy_xregs_to_kernel(&fpu->state->xsave); /* * AVX512 state is tracked here because its use is * known to slow the max clock speed of the core. */ - if (fpu->state.xsave.header.xfeatures & XFEATURE_MASK_AVX512) + if (fpu->state->xsave.header.xfeatures & XFEATURE_MASK_AVX512) fpu->avx512_timestamp = jiffies; return 1; } @@ -115,7 +115,7 @@ int copy_fpregs_to_fpstate(struct fpu *fpu) * Legacy FPU register saving, FNSAVE always clears FPU registers, * so we have to mark them inactive: */ - asm volatile("fnsave %[fp]; fwait" : [fp] "=m" (fpu->state.fsave)); + asm volatile("fnsave %[fp]; fwait" : [fp] "=m" (fpu->state->fsave)); return 0; } @@ -202,7 +202,7 @@ void fpstate_init(struct fpu *fpu) u64 mask; if (fpu) { - state = &fpu->state; + state = fpu->state; /* The dynamic user states are not prepared yet. */ mask = xfeatures_mask_all & ~xfeatures_mask_user_dynamic; size = get_xstate_config(XSTATE_MIN_SIZE); @@ -241,6 +241,8 @@ int fpu__copy(struct task_struct *dst, struct task_struct *src) WARN_ON_FPU(src_fpu != ¤t->thread.fpu); + dst_fpu->state = &dst_fpu->__default_state; + /* * Don't let 'init optimized' areas of the XSAVE area * leak into the child task: @@ -248,7 +250,7 @@ int fpu__copy(struct task_struct *dst, struct task_struct *src) * The child does not inherit the dynamic states. So, * the xstate buffer has the minimum size. */ - memset(&dst_fpu->state.xsave, 0, get_xstate_config(XSTATE_MIN_SIZE)); + memset(&dst_fpu->state->xsave, 0, get_xstate_config(XSTATE_MIN_SIZE)); /* * If the FPU registers are not current just memcpy() the state. @@ -260,7 +262,7 @@ int fpu__copy(struct task_struct *dst, struct task_struct *src) */ fpregs_lock(); if (test_thread_flag(TIF_NEED_FPU_LOAD)) - memcpy(&dst_fpu->state, &src_fpu->state, get_xstate_config(XSTATE_MIN_SIZE)); + memcpy(dst_fpu->state, src_fpu->state, get_xstate_config(XSTATE_MIN_SIZE)); else if (!copy_fpregs_to_fpstate(dst_fpu)) copy_kernel_to_fpregs(dst_fpu); @@ -396,7 +398,7 @@ static void fpu__clear(struct fpu *fpu, bool user_only) if (user_only) { if (!fpregs_state_valid(fpu, smp_processor_id()) && xfeatures_mask_supervisor()) - copy_kernel_to_xregs(&fpu->state.xsave, + copy_kernel_to_xregs(&fpu->state->xsave, xfeatures_mask_supervisor()); copy_init_fpstate_to_fpregs(xfeatures_mask_user()); } else { @@ -478,11 +480,11 @@ int fpu__exception_code(struct fpu *fpu, int trap_nr) * fully reproduce the context of the exception. */ if (boot_cpu_has(X86_FEATURE_FXSR)) { - cwd = fpu->state.fxsave.cwd; - swd = fpu->state.fxsave.swd; + cwd = fpu->state->fxsave.cwd; + swd = fpu->state->fxsave.swd; } else { - cwd = (unsigned short)fpu->state.fsave.cwd; - swd = (unsigned short)fpu->state.fsave.swd; + cwd = (unsigned short)fpu->state->fsave.cwd; + swd = (unsigned short)fpu->state->fsave.swd; } err = swd & ~cwd; @@ -496,7 +498,7 @@ int fpu__exception_code(struct fpu *fpu, int trap_nr) unsigned short mxcsr = MXCSR_DEFAULT; if (boot_cpu_has(X86_FEATURE_XMM)) - mxcsr = fpu->state.fxsave.mxcsr; + mxcsr = fpu->state->fxsave.mxcsr; err = ~(mxcsr >> 7) & mxcsr; } diff --git a/arch/x86/kernel/fpu/init.c b/arch/x86/kernel/fpu/init.c index f63765b7a83c..f2fcdcc979e7 100644 --- a/arch/x86/kernel/fpu/init.c +++ b/arch/x86/kernel/fpu/init.c @@ -31,10 +31,12 @@ static void fpu__init_cpu_generic(void) cr0 |= X86_CR0_EM; write_cr0(cr0); + current->thread.fpu.state = ¤t->thread.fpu.__default_state; + /* Flush out any pending x87 state: */ #ifdef CONFIG_MATH_EMULATION if (!boot_cpu_has(X86_FEATURE_FPU)) - fpstate_init_soft(¤t->thread.fpu.state.soft); + fpstate_init_soft(¤t->thread.fpu.state->soft); else #endif asm volatile ("fninit"); @@ -170,7 +172,7 @@ static void __init fpu__init_task_struct_size(void) * you hit a compile error here, check the structure to * see if something got added to the end. */ - CHECK_MEMBER_AT_END_OF(struct fpu, state); + CHECK_MEMBER_AT_END_OF(struct fpu, __default_state); CHECK_MEMBER_AT_END_OF(struct thread_struct, fpu); CHECK_MEMBER_AT_END_OF(struct task_struct, thread); diff --git a/arch/x86/kernel/fpu/regset.c b/arch/x86/kernel/fpu/regset.c index 6a025fa26a7e..ee27df4caed6 100644 --- a/arch/x86/kernel/fpu/regset.c +++ b/arch/x86/kernel/fpu/regset.c @@ -37,7 +37,7 @@ int xfpregs_get(struct task_struct *target, const struct user_regset *regset, fpu__prepare_read(fpu); fpstate_sanitize_xstate(fpu); - return membuf_write(&to, &fpu->state.fxsave, sizeof(struct fxregs_state)); + return membuf_write(&to, &fpu->state->fxsave, sizeof(struct fxregs_state)); } int xfpregs_set(struct task_struct *target, const struct user_regset *regset, @@ -54,19 +54,19 @@ int xfpregs_set(struct task_struct *target, const struct user_regset *regset, fpstate_sanitize_xstate(fpu); ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, - &fpu->state.fxsave, 0, -1); + &fpu->state->fxsave, 0, -1); /* * mxcsr reserved bits must be masked to zero for security reasons. */ - fpu->state.fxsave.mxcsr &= mxcsr_feature_mask; + fpu->state->fxsave.mxcsr &= mxcsr_feature_mask; /* * update the header bits in the xsave header, indicating the * presence of FP and SSE state. */ if (boot_cpu_has(X86_FEATURE_XSAVE)) - fpu->state.xsave.header.xfeatures |= XFEATURE_MASK_FPSSE; + fpu->state->xsave.header.xfeatures |= XFEATURE_MASK_FPSSE; return ret; } @@ -80,7 +80,7 @@ int xstateregs_get(struct task_struct *target, const struct user_regset *regset, if (!boot_cpu_has(X86_FEATURE_XSAVE)) return -ENODEV; - xsave = &fpu->state.xsave; + xsave = &fpu->state->xsave; fpu__prepare_read(fpu); @@ -120,7 +120,7 @@ int xstateregs_set(struct task_struct *target, const struct user_regset *regset, if ((pos != 0) || (count < get_xstate_config(XSTATE_USER_SIZE))) return -EFAULT; - xsave = &fpu->state.xsave; + xsave = &fpu->state->xsave; fpu__prepare_write(fpu); @@ -224,7 +224,7 @@ static inline u32 twd_fxsr_to_i387(struct fxregs_state *fxsave) void convert_from_fxsr(struct user_i387_ia32_struct *env, struct task_struct *tsk) { - struct fxregs_state *fxsave = &tsk->thread.fpu.state.fxsave; + struct fxregs_state *fxsave = &tsk->thread.fpu.state->fxsave; struct _fpreg *to = (struct _fpreg *) &env->st_space[0]; struct _fpxreg *from = (struct _fpxreg *) &fxsave->st_space[0]; int i; @@ -297,7 +297,7 @@ int fpregs_get(struct task_struct *target, const struct user_regset *regset, return fpregs_soft_get(target, regset, to); if (!boot_cpu_has(X86_FEATURE_FXSR)) { - return membuf_write(&to, &fpu->state.fsave, + return membuf_write(&to, &fpu->state->fsave, sizeof(struct fregs_state)); } @@ -328,7 +328,7 @@ int fpregs_set(struct task_struct *target, const struct user_regset *regset, if (!boot_cpu_has(X86_FEATURE_FXSR)) return user_regset_copyin(&pos, &count, &kbuf, &ubuf, - &fpu->state.fsave, 0, + &fpu->state->fsave, 0, -1); if (pos > 0 || count < sizeof(env)) @@ -336,14 +336,14 @@ int fpregs_set(struct task_struct *target, const struct user_regset *regset, ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &env, 0, -1); if (!ret) - convert_to_fxsr(&target->thread.fpu.state.fxsave, &env); + convert_to_fxsr(&target->thread.fpu.state->fxsave, &env); /* * update the header bit in the xsave header, indicating the * presence of FP. */ if (boot_cpu_has(X86_FEATURE_XSAVE)) - fpu->state.xsave.header.xfeatures |= XFEATURE_MASK_FP; + fpu->state->xsave.header.xfeatures |= XFEATURE_MASK_FP; return ret; } diff --git a/arch/x86/kernel/fpu/signal.c b/arch/x86/kernel/fpu/signal.c index 3a2d8665b9a3..9719241da034 100644 --- a/arch/x86/kernel/fpu/signal.c +++ b/arch/x86/kernel/fpu/signal.c @@ -58,7 +58,7 @@ static inline int check_for_xstate(struct fxregs_state __user *buf, static inline int save_fsave_header(struct task_struct *tsk, void __user *buf) { if (use_fxsr()) { - struct xregs_state *xsave = &tsk->thread.fpu.state.xsave; + struct xregs_state *xsave = &tsk->thread.fpu.state->xsave; struct user_i387_ia32_struct env; struct _fpstate_32 __user *fp = buf; @@ -216,7 +216,7 @@ sanitize_restored_user_xstate(struct fpu *fpu, struct user_i387_ia32_struct *ia32_env, u64 user_xfeatures, int fx_only) { - struct xregs_state *xsave = &fpu->state.xsave; + struct xregs_state *xsave = &fpu->state->xsave; struct xstate_header *header = &xsave->header; if (use_xsave()) { @@ -253,7 +253,7 @@ sanitize_restored_user_xstate(struct fpu *fpu, xsave->i387.mxcsr &= mxcsr_feature_mask; if (ia32_env) - convert_to_fxsr(&fpu->state.fxsave, ia32_env); + convert_to_fxsr(&fpu->state->fxsave, ia32_env); } } @@ -366,7 +366,7 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size) */ if (test_thread_flag(TIF_NEED_FPU_LOAD) && xfeatures_mask_supervisor()) - copy_kernel_to_xregs(&fpu->state.xsave, + copy_kernel_to_xregs(&fpu->state->xsave, xfeatures_mask_supervisor()); fpregs_mark_activate(); fpregs_unlock(); @@ -411,10 +411,10 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size) if (using_compacted_format()) { ret = copy_user_to_xstate(fpu, buf_fx); } else { - ret = __copy_from_user(&fpu->state.xsave, buf_fx, state_size); + ret = __copy_from_user(&fpu->state->xsave, buf_fx, state_size); if (!ret && state_size > offsetof(struct xregs_state, header)) - ret = validate_user_xstate_header(&fpu->state.xsave.header); + ret = validate_user_xstate_header(&fpu->state->xsave.header); } if (ret) goto err_out; @@ -429,11 +429,11 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size) * Restore previously saved supervisor xstates along with * copied-in user xstates. */ - ret = copy_kernel_to_xregs_err(&fpu->state.xsave, + ret = copy_kernel_to_xregs_err(&fpu->state->xsave, user_xfeatures | xfeatures_mask_supervisor()); } else if (use_fxsr()) { - ret = __copy_from_user(&fpu->state.fxsave, buf_fx, state_size); + ret = __copy_from_user(&fpu->state->fxsave, buf_fx, state_size); if (ret) { ret = -EFAULT; goto err_out; @@ -449,14 +449,14 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size) copy_kernel_to_xregs(&init_fpstate.xsave, init_bv); } - ret = copy_kernel_to_fxregs_err(&fpu->state.fxsave); + ret = copy_kernel_to_fxregs_err(&fpu->state->fxsave); } else { - ret = __copy_from_user(&fpu->state.fsave, buf_fx, state_size); + ret = __copy_from_user(&fpu->state->fsave, buf_fx, state_size); if (ret) goto err_out; fpregs_lock(); - ret = copy_kernel_to_fregs_err(&fpu->state.fsave); + ret = copy_kernel_to_fregs_err(&fpu->state->fsave); } if (!ret) fpregs_mark_activate(); diff --git a/arch/x86/kernel/fpu/xstate.c b/arch/x86/kernel/fpu/xstate.c index b7686f107f3a..8c067a7a0eec 100644 --- a/arch/x86/kernel/fpu/xstate.c +++ b/arch/x86/kernel/fpu/xstate.c @@ -185,14 +185,14 @@ static bool xfeature_is_supervisor(int xfeature_nr) */ void fpstate_sanitize_xstate(struct fpu *fpu) { - struct fxregs_state *fx = &fpu->state.fxsave; + struct fxregs_state *fx = &fpu->state->fxsave; int feature_bit; u64 xfeatures; if (!use_xsaveopt()) return; - xfeatures = fpu->state.xsave.header.xfeatures; + xfeatures = fpu->state->xsave.header.xfeatures; /* * None of the feature bits are in init state. So nothing else @@ -976,7 +976,7 @@ static void *__raw_xsave_addr(struct fpu *fpu, int xfeature_nr) } if (fpu) - xsave = &fpu->state.xsave; + xsave = &fpu->state->xsave; else xsave = &init_fpstate.xsave; @@ -1019,7 +1019,7 @@ void *get_xsave_addr(struct fpu *fpu, int xfeature_nr) "get of unsupported state"); if (fpu) - xsave = &fpu->state.xsave; + xsave = &fpu->state->xsave; else xsave = &init_fpstate.xsave; @@ -1167,7 +1167,7 @@ void copy_xstate_to_kernel(struct membuf to, struct fpu *fpu) unsigned last = 0; int i; - xsave = &fpu->state.xsave; + xsave = &fpu->state->xsave; /* * The destination is a ptrace buffer; we put in only user xstates: @@ -1232,7 +1232,7 @@ int copy_kernel_to_xstate(struct fpu *fpu, const void *kbuf) if (validate_user_xstate_header(&hdr)) return -EINVAL; - xsave = &fpu->state.xsave; + xsave = &fpu->state->xsave; for (i = 0; i < XFEATURE_MAX; i++) { u64 mask = ((u64)1 << i); @@ -1289,7 +1289,7 @@ int copy_user_to_xstate(struct fpu *fpu, const void __user *ubuf) if (validate_user_xstate_header(&hdr)) return -EINVAL; - xsave = &fpu->state.xsave; + xsave = &fpu->state->xsave; for (i = 0; i < XFEATURE_MAX; i++) { u64 mask = ((u64)1 << i); @@ -1348,7 +1348,7 @@ void copy_supervisor_to_kernel(struct fpu *fpu) max_bit = __fls(xfeatures_mask_supervisor()); min_bit = __ffs(xfeatures_mask_supervisor()); - xstate = &fpu->state.xsave; + xstate = &fpu->state->xsave; lmask = xfeatures_mask_supervisor(); hmask = xfeatures_mask_supervisor() >> 32; XSTATE_OP(XSAVES, xstate, lmask, hmask, err); @@ -1535,7 +1535,7 @@ void update_pasid(void) * update the PASID state in the memory buffer here. The * PASID MSR will be loaded when returning to user mode. */ - xsave = &fpu->state.xsave; + xsave = &fpu->state->xsave; xsave->header.xfeatures |= XFEATURE_MASK_PASID; ppasid_state = get_xsave_addr(fpu, XFEATURE_PASID); /* diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index 2070ae35ccbc..c41116543a82 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -98,7 +98,7 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src) void arch_thread_struct_whitelist(unsigned long *offset, unsigned long *size) { - *offset = offsetof(struct thread_struct, fpu.state); + *offset = offsetof(struct thread_struct, fpu.__default_state); /* The buffer embedded in thread_struct has the minimum size. */ *size = get_xstate_config(XSTATE_MIN_SIZE); } diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 5c70a4270157..c10122547ecd 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -4439,7 +4439,7 @@ static int kvm_vcpu_ioctl_x86_set_debugregs(struct kvm_vcpu *vcpu, static void fill_xsave(u8 *dest, struct kvm_vcpu *vcpu) { - struct xregs_state *xsave = &vcpu->arch.guest_fpu->state.xsave; + struct xregs_state *xsave = &vcpu->arch.guest_fpu->state->xsave; u64 xstate_bv = xsave->header.xfeatures; u64 valid; @@ -4481,7 +4481,7 @@ static void fill_xsave(u8 *dest, struct kvm_vcpu *vcpu) static void load_xsave(struct kvm_vcpu *vcpu, u8 *src) { - struct xregs_state *xsave = &vcpu->arch.guest_fpu->state.xsave; + struct xregs_state *xsave = &vcpu->arch.guest_fpu->state->xsave; u64 xstate_bv = *(u64 *)(src + XSAVE_HDR_OFFSET); u64 valid; @@ -4532,7 +4532,7 @@ static void kvm_vcpu_ioctl_x86_get_xsave(struct kvm_vcpu *vcpu, fill_xsave((u8 *) guest_xsave->region, vcpu); } else { memcpy(guest_xsave->region, - &vcpu->arch.guest_fpu->state.fxsave, + &vcpu->arch.guest_fpu->state->fxsave, sizeof(struct fxregs_state)); *(u64 *)&guest_xsave->region[XSAVE_HDR_OFFSET / sizeof(u32)] = XFEATURE_MASK_FPSSE; @@ -4566,7 +4566,7 @@ static int kvm_vcpu_ioctl_x86_set_xsave(struct kvm_vcpu *vcpu, if (xstate_bv & ~XFEATURE_MASK_FPSSE || mxcsr & ~mxcsr_feature_mask) return -EINVAL; - memcpy(&vcpu->arch.guest_fpu->state.fxsave, + memcpy(&vcpu->arch.guest_fpu->state->fxsave, guest_xsave->region, sizeof(struct fxregs_state)); } return 0; @@ -9276,7 +9276,7 @@ static void kvm_save_current_fpu(struct fpu *fpu) * always has the minimum size. */ if (test_thread_flag(TIF_NEED_FPU_LOAD)) - memcpy(&fpu->state, ¤t->thread.fpu.state, + memcpy(fpu->state, current->thread.fpu.state, get_xstate_config(XSTATE_MIN_SIZE)); else copy_fpregs_to_fpstate(fpu); @@ -9295,7 +9295,7 @@ static void kvm_load_guest_fpu(struct kvm_vcpu *vcpu) */ if (vcpu->arch.guest_fpu) /* PKRU is separately restored in kvm_x86_ops.run. */ - __copy_kernel_to_fpregs(&vcpu->arch.guest_fpu->state, + __copy_kernel_to_fpregs(vcpu->arch.guest_fpu->state, ~XFEATURE_MASK_PKRU); fpregs_mark_activate(); @@ -9832,7 +9832,7 @@ int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) vcpu_load(vcpu); - fxsave = &vcpu->arch.guest_fpu->state.fxsave; + fxsave = &vcpu->arch.guest_fpu->state->fxsave; memcpy(fpu->fpr, fxsave->st_space, 128); fpu->fcw = fxsave->cwd; fpu->fsw = fxsave->swd; @@ -9855,7 +9855,7 @@ int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) vcpu_load(vcpu); - fxsave = &vcpu->arch.guest_fpu->state.fxsave; + fxsave = &vcpu->arch.guest_fpu->state->fxsave; memcpy(fxsave->st_space, fpu->fpr, 128); fxsave->cwd = fpu->fcw; @@ -9916,7 +9916,7 @@ static void fx_init(struct kvm_vcpu *vcpu) fpstate_init(vcpu->arch.guest_fpu); if (boot_cpu_has(X86_FEATURE_XSAVES)) - vcpu->arch.guest_fpu->state.xsave.header.xcomp_bv = + vcpu->arch.guest_fpu->state->xsave.header.xcomp_bv = host_xcr0 | XSTATE_COMPACTION_ENABLED; /* diff --git a/arch/x86/math-emu/fpu_aux.c b/arch/x86/math-emu/fpu_aux.c index 034748459482..51432a73024c 100644 --- a/arch/x86/math-emu/fpu_aux.c +++ b/arch/x86/math-emu/fpu_aux.c @@ -53,7 +53,7 @@ void fpstate_init_soft(struct swregs_state *soft) void finit(void) { - fpstate_init_soft(¤t->thread.fpu.state.soft); + fpstate_init_soft(¤t->thread.fpu.state->soft); } /* diff --git a/arch/x86/math-emu/fpu_entry.c b/arch/x86/math-emu/fpu_entry.c index 8679a9d6c47f..6ba56632170e 100644 --- a/arch/x86/math-emu/fpu_entry.c +++ b/arch/x86/math-emu/fpu_entry.c @@ -640,7 +640,7 @@ int fpregs_soft_set(struct task_struct *target, unsigned int pos, unsigned int count, const void *kbuf, const void __user *ubuf) { - struct swregs_state *s387 = &target->thread.fpu.state.soft; + struct swregs_state *s387 = &target->thread.fpu.state->soft; void *space = s387->st_space; int ret; int offset, other, i, tags, regnr, tag, newtop; @@ -691,7 +691,7 @@ int fpregs_soft_get(struct task_struct *target, const struct user_regset *regset, struct membuf to) { - struct swregs_state *s387 = &target->thread.fpu.state.soft; + struct swregs_state *s387 = &target->thread.fpu.state->soft; const void *space = s387->st_space; int offset = (S387->ftop & 7) * 10, other = 80 - offset; diff --git a/arch/x86/math-emu/fpu_system.h b/arch/x86/math-emu/fpu_system.h index 9b41391867dc..a6291ddfdda6 100644 --- a/arch/x86/math-emu/fpu_system.h +++ b/arch/x86/math-emu/fpu_system.h @@ -73,7 +73,7 @@ static inline bool seg_writable(struct desc_struct *d) return (d->type & SEG_TYPE_EXECUTE_MASK) == SEG_TYPE_WRITABLE; } -#define I387 (¤t->thread.fpu.state) +#define I387 (current->thread.fpu.state) #define FPU_info (I387->soft.info) #define FPU_CS (*(unsigned short *) &(FPU_info->regs->cs)) From patchwork Sun Feb 21 18:56:26 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Chang S. Bae" X-Patchwork-Id: 12097597 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 69817C433DB for ; Sun, 21 Feb 2021 19:02:51 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 3CC4C64EE0 for ; Sun, 21 Feb 2021 19:02:51 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230402AbhBUTCg (ORCPT ); Sun, 21 Feb 2021 14:02:36 -0500 Received: from mga05.intel.com ([192.55.52.43]:37166 "EHLO mga05.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230367AbhBUTCZ (ORCPT ); Sun, 21 Feb 2021 14:02:25 -0500 IronPort-SDR: 59xFBacYzbb9wdU7IS87r6C8h6Cj3NQLkr6UMX0QPcDiP0DywybOrsT+DtFGsHZ1x8ilvyPe1y TzHWhr9LmkmA== X-IronPort-AV: E=McAfee;i="6000,8403,9902"; a="269192147" X-IronPort-AV: E=Sophos;i="5.81,195,1610438400"; d="scan'208";a="269192147" Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga105.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 21 Feb 2021 11:01:28 -0800 IronPort-SDR: riq+h46S09FTbJHO5p9lO8+QrLt8W77mBhOmjYEuMC7CknxpTiKXsngWDVR6DIPq4DutOMlcc5 glep/+dFJAXg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.81,195,1610438400"; d="scan'208";a="429792111" Received: from chang-linux-3.sc.intel.com ([172.25.66.175]) by FMSMGA003.fm.intel.com with ESMTP; 21 Feb 2021 11:01:27 -0800 From: "Chang S. Bae" To: bp@suse.de, luto@kernel.org, tglx@linutronix.de, mingo@kernel.org, x86@kernel.org Cc: len.brown@intel.com, dave.hansen@intel.com, jing2.liu@intel.com, ravi.v.shankar@intel.com, linux-kernel@vger.kernel.org, chang.seok.bae@intel.com, kvm@vger.kernel.org Subject: [PATCH v4 11/22] x86/fpu/xstate: Update the xstate save function to support dynamic states Date: Sun, 21 Feb 2021 10:56:26 -0800 Message-Id: <20210221185637.19281-12-chang.seok.bae@intel.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20210221185637.19281-1-chang.seok.bae@intel.com> References: <20210221185637.19281-1-chang.seok.bae@intel.com> Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org Extend copy_xregs_to_kernel() to receive a mask argument of which states to save, in preparation for dynamic user state handling. Update KVM to set a valid fpu->state_mask, so it can continue to share with the core code. Signed-off-by: Chang S. Bae Reviewed-by: Len Brown Cc: x86@kernel.org Cc: linux-kernel@vger.kernel.org Cc: kvm@vger.kernel.org --- Changes from v3: * Updated the changelog. (Borislav Petkov) * Made the code change more reviewable. Changes from v2: * Updated the changelog to clarify the KVM code changes. --- arch/x86/include/asm/fpu/internal.h | 3 +-- arch/x86/kernel/fpu/core.c | 2 +- arch/x86/kvm/x86.c | 9 +++++++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/arch/x86/include/asm/fpu/internal.h b/arch/x86/include/asm/fpu/internal.h index e4afc1831e29..f964f3efc92e 100644 --- a/arch/x86/include/asm/fpu/internal.h +++ b/arch/x86/include/asm/fpu/internal.h @@ -317,9 +317,8 @@ static inline void copy_kernel_to_xregs_booting(struct xregs_state *xstate) /* * Save processor xstate to xsave area. */ -static inline void copy_xregs_to_kernel(struct xregs_state *xstate) +static inline void copy_xregs_to_kernel(struct xregs_state *xstate, u64 mask) { - u64 mask = xfeatures_mask_all; u32 lmask = mask; u32 hmask = mask >> 32; int err; diff --git a/arch/x86/kernel/fpu/core.c b/arch/x86/kernel/fpu/core.c index dc20eabb072d..ad1ac80f98ef 100644 --- a/arch/x86/kernel/fpu/core.c +++ b/arch/x86/kernel/fpu/core.c @@ -98,7 +98,7 @@ EXPORT_SYMBOL(irq_fpu_usable); int copy_fpregs_to_fpstate(struct fpu *fpu) { if (likely(use_xsave())) { - copy_xregs_to_kernel(&fpu->state->xsave); + copy_xregs_to_kernel(&fpu->state->xsave, fpu->state_mask); /* * AVX512 state is tracked here because its use is diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index c10122547ecd..ca2c0574acf2 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -9275,11 +9275,16 @@ static void kvm_save_current_fpu(struct fpu *fpu) * KVM does not support dynamic user states yet. Assume the buffer * always has the minimum size. */ - if (test_thread_flag(TIF_NEED_FPU_LOAD)) + if (test_thread_flag(TIF_NEED_FPU_LOAD)) { memcpy(fpu->state, current->thread.fpu.state, get_xstate_config(XSTATE_MIN_SIZE)); - else + } else { + struct fpu *src_fpu = ¤t->thread.fpu; + + if (fpu->state_mask != src_fpu->state_mask) + fpu->state_mask = src_fpu->state_mask; copy_fpregs_to_fpstate(fpu); + } } /* Swap (qemu) user FPU context for the guest FPU context. */