162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci#ifndef _ASM_X86_PKRU_H
362306a36Sopenharmony_ci#define _ASM_X86_PKRU_H
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci#include <asm/cpufeature.h>
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#define PKRU_AD_BIT 0x1u
862306a36Sopenharmony_ci#define PKRU_WD_BIT 0x2u
962306a36Sopenharmony_ci#define PKRU_BITS_PER_PKEY 2
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS
1262306a36Sopenharmony_ciextern u32 init_pkru_value;
1362306a36Sopenharmony_ci#define pkru_get_init_value()	READ_ONCE(init_pkru_value)
1462306a36Sopenharmony_ci#else
1562306a36Sopenharmony_ci#define init_pkru_value	0
1662306a36Sopenharmony_ci#define pkru_get_init_value()	0
1762306a36Sopenharmony_ci#endif
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_cistatic inline bool __pkru_allows_read(u32 pkru, u16 pkey)
2062306a36Sopenharmony_ci{
2162306a36Sopenharmony_ci	int pkru_pkey_bits = pkey * PKRU_BITS_PER_PKEY;
2262306a36Sopenharmony_ci	return !(pkru & (PKRU_AD_BIT << pkru_pkey_bits));
2362306a36Sopenharmony_ci}
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_cistatic inline bool __pkru_allows_write(u32 pkru, u16 pkey)
2662306a36Sopenharmony_ci{
2762306a36Sopenharmony_ci	int pkru_pkey_bits = pkey * PKRU_BITS_PER_PKEY;
2862306a36Sopenharmony_ci	/*
2962306a36Sopenharmony_ci	 * Access-disable disables writes too so we need to check
3062306a36Sopenharmony_ci	 * both bits here.
3162306a36Sopenharmony_ci	 */
3262306a36Sopenharmony_ci	return !(pkru & ((PKRU_AD_BIT|PKRU_WD_BIT) << pkru_pkey_bits));
3362306a36Sopenharmony_ci}
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_cistatic inline u32 read_pkru(void)
3662306a36Sopenharmony_ci{
3762306a36Sopenharmony_ci	if (cpu_feature_enabled(X86_FEATURE_OSPKE))
3862306a36Sopenharmony_ci		return rdpkru();
3962306a36Sopenharmony_ci	return 0;
4062306a36Sopenharmony_ci}
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_cistatic inline void write_pkru(u32 pkru)
4362306a36Sopenharmony_ci{
4462306a36Sopenharmony_ci	if (!cpu_feature_enabled(X86_FEATURE_OSPKE))
4562306a36Sopenharmony_ci		return;
4662306a36Sopenharmony_ci	/*
4762306a36Sopenharmony_ci	 * WRPKRU is relatively expensive compared to RDPKRU.
4862306a36Sopenharmony_ci	 * Avoid WRPKRU when it would not change the value.
4962306a36Sopenharmony_ci	 */
5062306a36Sopenharmony_ci	if (pkru != rdpkru())
5162306a36Sopenharmony_ci		wrpkru(pkru);
5262306a36Sopenharmony_ci}
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_cistatic inline void pkru_write_default(void)
5562306a36Sopenharmony_ci{
5662306a36Sopenharmony_ci	if (!cpu_feature_enabled(X86_FEATURE_OSPKE))
5762306a36Sopenharmony_ci		return;
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	wrpkru(pkru_get_init_value());
6062306a36Sopenharmony_ci}
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci#endif
63