Received: by 2002:a05:6a10:c7c6:0:0:0:0 with SMTP id h6csp2962522pxy; Tue, 3 Aug 2021 21:35:57 -0700 (PDT) X-Google-Smtp-Source: ABdhPJxy/QniY4Q0TlcN1PWgvhlWRGfOO9qO8UGBkwy3dCo04XcdCN61nPKGZz3QGELQX39hWyUa X-Received: by 2002:a5d:8b8b:: with SMTP id p11mr477884iol.77.1628051757719; Tue, 03 Aug 2021 21:35:57 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1628051757; cv=none; d=google.com; s=arc-20160816; b=ZYoUNUIkdHKpry90dD0RJsZ8lPxhY+xVoI6TZCaXAkDW31bw0RCxhUOxG/jJbDsjZa VnJaKqfdZaSoXcaqimOEXbgDwXqSk+BgYaoJ76CquAdKVag541MWJPOAIgwlBGntAuvT qqVieoS8WKUaLdUWPipH8eq4jbhlycB7xXzYAdohuD+hpGk2UR/aRjVVdaBcetOgXGJ2 KH5uvtcF0fTAjOYGT/01go7B6SYMipmbKTHCtEZRb5CZs37/xktx5AsCLmUXrbFCvv+l y9ialpNZXmSqFgfNQDkXtw9ofKUB69FxV1WDbGVAypIDtACm9QCTdM3/0LsXzHnYWfOQ YKZw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from; bh=MmdMp2i/ufVSB1wZ0sbmH4xzrOd4IKE2cFMtaZYpz70=; b=WJJkkp3OcdQDbFNu0WEXHjsElf+2+p5YyEBf8xFCrSLAQfTqLI+ttXqmeSmJugD0ZR R1aA1+K8ajKa3MDSy5qX38ddnaD+aMVsit1+ANOGG5DWPUVKWhrlwTzFCVnvCHAr/uS1 6peuK3xwTc6KC8kkSc8vh929C5A/g97S3vbxmJnSGkhIfkItFsVjZJRtp55H3GKjGLvr KyZtXCM8Vf/u1ZM64x0+Uj0kaz66xCAa/i4WmAfOVwc7LMUtnAVQnVy2z4jN+5zeZYbR kASBMItVncoh6fVZ3TNxypiuqYh2rnOpQCUN6l002sc9EPoYGTruVI+l8+aYwVBIQmzY hdVw== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=intel.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id k2si857860iol.39.2021.08.03.21.35.41; Tue, 03 Aug 2021 21:35:57 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=intel.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235062AbhHDEdB (ORCPT + 99 others); Wed, 4 Aug 2021 00:33:01 -0400 Received: from mga14.intel.com ([192.55.52.115]:41725 "EHLO mga14.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234747AbhHDEcs (ORCPT ); Wed, 4 Aug 2021 00:32:48 -0400 X-IronPort-AV: E=McAfee;i="6200,9189,10065"; a="213574613" X-IronPort-AV: E=Sophos;i="5.84,293,1620716400"; d="scan'208";a="213574613" Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by fmsmga103.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Aug 2021 21:32:36 -0700 X-IronPort-AV: E=Sophos;i="5.84,293,1620716400"; d="scan'208";a="511702673" Received: from iweiny-desk2.sc.intel.com (HELO localhost) ([10.3.52.147]) by fmsmga003-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Aug 2021 21:32:36 -0700 From: ira.weiny@intel.com To: Dave Hansen , Dan Williams Cc: Ira Weiny , Peter Zijlstra , Fenghua Yu , "Hansen, Dave" , Thomas Gleixner , Ingo Molnar , Borislav Petkov , Andy Lutomirski , "H. Peter Anvin" , Rick Edgecombe , x86@kernel.org, linux-kernel@vger.kernel.org, nvdimm@lists.linux.dev, linux-mm@kvack.org Subject: [PATCH V7 05/18] x86/pks: Add PKS setup code Date: Tue, 3 Aug 2021 21:32:18 -0700 Message-Id: <20210804043231.2655537-6-ira.weiny@intel.com> X-Mailer: git-send-email 2.28.0.rc0.12.gb6a658bd00c9 In-Reply-To: <20210804043231.2655537-1-ira.weiny@intel.com> References: <20210804043231.2655537-1-ira.weiny@intel.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Ira Weiny Protection Keys for Supervisor pages (PKS) enables fast, hardware thread specific, manipulation of permission restrictions on supervisor page mappings. It uses the same mechanism of Protection Keys as those on User mappings but applies that mechanism to supervisor mappings using a supervisor specific MSR. Add setup code and the lowest level of PKS MSR write support. Pkeys values are allocated statically via the pks_pkey_consumers enumeration. create_initial_pkrs_value() builds the initial protection values for each pkey. Users who need a default value other than Access Disabled should update consumer_defaults[]. The PKRS value is cached per-cpu to avoid the overhead of the MSR write if the value has not changed. That said, it should be noted that the underlying WRMSR(MSR_IA32_PKRS) is not serializing but still maintains ordering properties similar to WRPKRU. The current SDM section on PKRS needs updating but should be the same as that of WRPKRU. So to quote from the WRPKRU text: WRPKRU will never execute transiently. Memory accesses affected by PKRU register will not execute (even transiently) until all prior executions of WRPKRU have completed execution and updated the PKRU register. write_pkrs() contributed by Peter Zijlstra. create_initial_pkrs_value() contributed by Dave Hansen setup_pks() is an internal x86 function call. Introduce asm/pks.h to declare functions and internal structures such as this. Reviewed-by: Dan Williams Co-developed-by: Peter Zijlstra Signed-off-by: Peter Zijlstra Co-developed-by: Fenghua Yu Signed-off-by: Fenghua Yu Co-developed-by: "Hansen, Dave" Signed-off-by: "Hansen, Dave" Signed-off-by: Ira Weiny --- Changes for V7 Create a dynamic pkrs_initial_value in early init code. Clean up comments Add comment to macro guard --- arch/x86/include/asm/msr-index.h | 1 + arch/x86/include/asm/pkeys_common.h | 4 ++ arch/x86/include/asm/pks.h | 15 ++++++ arch/x86/kernel/cpu/common.c | 2 + arch/x86/mm/pkeys.c | 75 +++++++++++++++++++++++++++++ include/linux/pkeys.h | 8 +++ 6 files changed, 105 insertions(+) create mode 100644 arch/x86/include/asm/pks.h diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h index a7c413432b33..c986eb1f36a9 100644 --- a/arch/x86/include/asm/msr-index.h +++ b/arch/x86/include/asm/msr-index.h @@ -767,6 +767,7 @@ #define MSR_IA32_TSC_DEADLINE 0x000006E0 +#define MSR_IA32_PKRS 0x000006E1 #define MSR_TSX_FORCE_ABORT 0x0000010F diff --git a/arch/x86/include/asm/pkeys_common.h b/arch/x86/include/asm/pkeys_common.h index 8a3c6d2e6a8a..079a8be9686b 100644 --- a/arch/x86/include/asm/pkeys_common.h +++ b/arch/x86/include/asm/pkeys_common.h @@ -2,14 +2,18 @@ #ifndef _ASM_X86_PKEYS_COMMON_H #define _ASM_X86_PKEYS_COMMON_H +#define PKR_RW_BIT 0x0 #define PKR_AD_BIT 0x1 #define PKR_WD_BIT 0x2 #define PKR_BITS_PER_PKEY 2 +#define PKS_NUM_PKEYS 16 + #define PKR_PKEY_SHIFT(pkey) (pkey * PKR_BITS_PER_PKEY) #define PKR_PKEY_MASK(pkey) (((1 << PKR_BITS_PER_PKEY) - 1) << PKR_PKEY_SHIFT(pkey)) #define PKR_AD_KEY(pkey) (PKR_AD_BIT << PKR_PKEY_SHIFT(pkey)) #define PKR_WD_KEY(pkey) (PKR_WD_BIT << PKR_PKEY_SHIFT(pkey)) +#define PKR_VALUE(pkey, val) (val << PKR_PKEY_SHIFT(pkey)) #endif /*_ASM_X86_PKEYS_COMMON_H */ diff --git a/arch/x86/include/asm/pks.h b/arch/x86/include/asm/pks.h new file mode 100644 index 000000000000..5d7067ada8fb --- /dev/null +++ b/arch/x86/include/asm/pks.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _ASM_X86_PKS_H +#define _ASM_X86_PKS_H + +#ifdef CONFIG_ARCH_ENABLE_SUPERVISOR_PKEYS + +void setup_pks(void); + +#else /* !CONFIG_ARCH_ENABLE_SUPERVISOR_PKEYS */ + +static inline void setup_pks(void) { } + +#endif /* CONFIG_ARCH_ENABLE_SUPERVISOR_PKEYS */ + +#endif /* _ASM_X86_PKS_H */ diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index 64b805bd6a54..abb32bd32f53 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -59,6 +59,7 @@ #include #include #include +#include #include "cpu.h" @@ -1590,6 +1591,7 @@ static void identify_cpu(struct cpuinfo_x86 *c) x86_init_rdrand(c); setup_pku(c); + setup_pks(); /* * Clear/Set all flags overridden by options, need do it diff --git a/arch/x86/mm/pkeys.c b/arch/x86/mm/pkeys.c index 75437aa8fc56..fbffbced81b5 100644 --- a/arch/x86/mm/pkeys.c +++ b/arch/x86/mm/pkeys.c @@ -211,3 +211,78 @@ u32 update_pkey_val(u32 pk_reg, int pkey, unsigned int flags) return pk_reg; } + +#ifdef CONFIG_ARCH_ENABLE_SUPERVISOR_PKEYS + +static DEFINE_PER_CPU(u32, pkrs_cache); +u32 __read_mostly pkrs_init_value; + +/* + * write_pkrs() optimizes MSR writes by maintaining a per cpu cache which can + * be checked quickly. + * + * It should also be noted that the underlying WRMSR(MSR_IA32_PKRS) is not + * serializing but still maintains ordering properties similar to WRPKRU. + * The current SDM section on PKRS needs updating but should be the same as + * that of WRPKRU. So to quote from the WRPKRU text: + * + * WRPKRU will never execute transiently. Memory accesses + * affected by PKRU register will not execute (even transiently) + * until all prior executions of WRPKRU have completed execution + * and updated the PKRU register. + */ +void write_pkrs(u32 new_pkrs) +{ + u32 *pkrs; + + if (!static_cpu_has(X86_FEATURE_PKS)) + return; + + pkrs = get_cpu_ptr(&pkrs_cache); + if (*pkrs != new_pkrs) { + *pkrs = new_pkrs; + wrmsrl(MSR_IA32_PKRS, new_pkrs); + } + put_cpu_ptr(pkrs); +} + +/* + * Build a default PKRS value from the array specified by consumers + */ +static int __init create_initial_pkrs_value(void) +{ + /* All users get Access Disabled unless changed below */ + u8 consumer_defaults[PKS_NUM_PKEYS] = { + [0 ... PKS_NUM_PKEYS-1] = PKR_AD_BIT + }; + int i; + + consumer_defaults[PKS_KEY_DEFAULT] = PKR_RW_BIT; + + /* Ensure the number of consumers is less than the number of keys */ + BUILD_BUG_ON(PKS_KEY_NR_CONSUMERS > PKS_NUM_PKEYS); + + pkrs_init_value = 0; + + /* Fill the defaults for the consumers */ + for (i = 0; i < PKS_NUM_PKEYS; i++) + pkrs_init_value |= PKR_VALUE(i, consumer_defaults[i]); + + return 0; +} +early_initcall(create_initial_pkrs_value); + +/* + * PKS is independent of PKU and either or both may be supported on a CPU. + * Configure PKS if the CPU supports the feature. + */ +void setup_pks(void) +{ + if (!cpu_feature_enabled(X86_FEATURE_PKS)) + return; + + write_pkrs(pkrs_init_value); + cr4_set_bits(X86_CR4_PKS); +} + +#endif /* CONFIG_ARCH_ENABLE_SUPERVISOR_PKEYS */ diff --git a/include/linux/pkeys.h b/include/linux/pkeys.h index 6beb26b7151d..580238388f0c 100644 --- a/include/linux/pkeys.h +++ b/include/linux/pkeys.h @@ -46,4 +46,12 @@ static inline bool arch_pkeys_enabled(void) #endif /* ! CONFIG_ARCH_HAS_PKEYS */ +#ifdef CONFIG_ARCH_ENABLE_SUPERVISOR_PKEYS +enum pks_pkey_consumers { + PKS_KEY_DEFAULT = 0, /* Must be 0 for default PTE values */ + PKS_KEY_NR_CONSUMERS +}; +extern u32 pkrs_init_value; +#endif + #endif /* _LINUX_PKEYS_H */ -- 2.28.0.rc0.12.gb6a658bd00c9