162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 262306a36Sopenharmony_ci 362306a36Sopenharmony_ci#ifndef _PKEYS_X86_H 462306a36Sopenharmony_ci#define _PKEYS_X86_H 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#ifdef __i386__ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#define REG_IP_IDX REG_EIP 962306a36Sopenharmony_ci#define si_pkey_offset 0x14 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#else 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#define REG_IP_IDX REG_RIP 1462306a36Sopenharmony_ci#define si_pkey_offset 0x20 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#endif 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#ifndef PKEY_DISABLE_ACCESS 1962306a36Sopenharmony_ci# define PKEY_DISABLE_ACCESS 0x1 2062306a36Sopenharmony_ci#endif 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#ifndef PKEY_DISABLE_WRITE 2362306a36Sopenharmony_ci# define PKEY_DISABLE_WRITE 0x2 2462306a36Sopenharmony_ci#endif 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#define NR_PKEYS 16 2762306a36Sopenharmony_ci#define NR_RESERVED_PKEYS 2 /* pkey-0 and exec-only-pkey */ 2862306a36Sopenharmony_ci#define PKEY_BITS_PER_PKEY 2 2962306a36Sopenharmony_ci#define HPAGE_SIZE (1UL<<21) 3062306a36Sopenharmony_ci#define PAGE_SIZE 4096 3162306a36Sopenharmony_ci#define MB (1<<20) 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_cistatic inline void __page_o_noops(void) 3462306a36Sopenharmony_ci{ 3562306a36Sopenharmony_ci /* 8-bytes of instruction * 512 bytes = 1 page */ 3662306a36Sopenharmony_ci asm(".rept 512 ; nopl 0x7eeeeeee(%eax) ; .endr"); 3762306a36Sopenharmony_ci} 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistatic inline u64 __read_pkey_reg(void) 4062306a36Sopenharmony_ci{ 4162306a36Sopenharmony_ci unsigned int eax, edx; 4262306a36Sopenharmony_ci unsigned int ecx = 0; 4362306a36Sopenharmony_ci unsigned pkey_reg; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci asm volatile(".byte 0x0f,0x01,0xee\n\t" 4662306a36Sopenharmony_ci : "=a" (eax), "=d" (edx) 4762306a36Sopenharmony_ci : "c" (ecx)); 4862306a36Sopenharmony_ci pkey_reg = eax; 4962306a36Sopenharmony_ci return pkey_reg; 5062306a36Sopenharmony_ci} 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_cistatic inline void __write_pkey_reg(u64 pkey_reg) 5362306a36Sopenharmony_ci{ 5462306a36Sopenharmony_ci unsigned int eax = pkey_reg; 5562306a36Sopenharmony_ci unsigned int ecx = 0; 5662306a36Sopenharmony_ci unsigned int edx = 0; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci dprintf4("%s() changing %016llx to %016llx\n", __func__, 5962306a36Sopenharmony_ci __read_pkey_reg(), pkey_reg); 6062306a36Sopenharmony_ci asm volatile(".byte 0x0f,0x01,0xef\n\t" 6162306a36Sopenharmony_ci : : "a" (eax), "c" (ecx), "d" (edx)); 6262306a36Sopenharmony_ci assert(pkey_reg == __read_pkey_reg()); 6362306a36Sopenharmony_ci} 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci/* Intel-defined CPU features, CPUID level 0x00000007:0 (ecx) */ 6662306a36Sopenharmony_ci#define X86_FEATURE_PKU (1<<3) /* Protection Keys for Userspace */ 6762306a36Sopenharmony_ci#define X86_FEATURE_OSPKE (1<<4) /* OS Protection Keys Enable */ 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cistatic inline int cpu_has_pkeys(void) 7062306a36Sopenharmony_ci{ 7162306a36Sopenharmony_ci unsigned int eax; 7262306a36Sopenharmony_ci unsigned int ebx; 7362306a36Sopenharmony_ci unsigned int ecx; 7462306a36Sopenharmony_ci unsigned int edx; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci __cpuid_count(0x7, 0x0, eax, ebx, ecx, edx); 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci if (!(ecx & X86_FEATURE_PKU)) { 7962306a36Sopenharmony_ci dprintf2("cpu does not have PKU\n"); 8062306a36Sopenharmony_ci return 0; 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ci if (!(ecx & X86_FEATURE_OSPKE)) { 8362306a36Sopenharmony_ci dprintf2("cpu does not have OSPKE\n"); 8462306a36Sopenharmony_ci return 0; 8562306a36Sopenharmony_ci } 8662306a36Sopenharmony_ci return 1; 8762306a36Sopenharmony_ci} 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cistatic inline int cpu_max_xsave_size(void) 9062306a36Sopenharmony_ci{ 9162306a36Sopenharmony_ci unsigned long XSTATE_CPUID = 0xd; 9262306a36Sopenharmony_ci unsigned int eax; 9362306a36Sopenharmony_ci unsigned int ebx; 9462306a36Sopenharmony_ci unsigned int ecx; 9562306a36Sopenharmony_ci unsigned int edx; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci __cpuid_count(XSTATE_CPUID, 0, eax, ebx, ecx, edx); 9862306a36Sopenharmony_ci return ecx; 9962306a36Sopenharmony_ci} 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_cistatic inline u32 pkey_bit_position(int pkey) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci return pkey * PKEY_BITS_PER_PKEY; 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci#define XSTATE_PKEY_BIT (9) 10762306a36Sopenharmony_ci#define XSTATE_PKEY 0x200 10862306a36Sopenharmony_ci#define XSTATE_BV_OFFSET 512 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ciint pkey_reg_xstate_offset(void) 11162306a36Sopenharmony_ci{ 11262306a36Sopenharmony_ci unsigned int eax; 11362306a36Sopenharmony_ci unsigned int ebx; 11462306a36Sopenharmony_ci unsigned int ecx; 11562306a36Sopenharmony_ci unsigned int edx; 11662306a36Sopenharmony_ci int xstate_offset; 11762306a36Sopenharmony_ci int xstate_size = 0; 11862306a36Sopenharmony_ci unsigned long XSTATE_CPUID = 0xd; 11962306a36Sopenharmony_ci int leaf; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci /* assume that XSTATE_PKEY is set in XCR0 */ 12262306a36Sopenharmony_ci leaf = XSTATE_PKEY_BIT; 12362306a36Sopenharmony_ci { 12462306a36Sopenharmony_ci __cpuid_count(XSTATE_CPUID, leaf, eax, ebx, ecx, edx); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci if (leaf == XSTATE_PKEY_BIT) { 12762306a36Sopenharmony_ci xstate_offset = ebx; 12862306a36Sopenharmony_ci xstate_size = eax; 12962306a36Sopenharmony_ci } 13062306a36Sopenharmony_ci } 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci if (xstate_size == 0) { 13362306a36Sopenharmony_ci printf("could not find size/offset of PKEY in xsave state\n"); 13462306a36Sopenharmony_ci return 0; 13562306a36Sopenharmony_ci } 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci return xstate_offset; 13862306a36Sopenharmony_ci} 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_cistatic inline int get_arch_reserved_keys(void) 14162306a36Sopenharmony_ci{ 14262306a36Sopenharmony_ci return NR_RESERVED_PKEYS; 14362306a36Sopenharmony_ci} 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_civoid expect_fault_on_read_execonly_key(void *p1, int pkey) 14662306a36Sopenharmony_ci{ 14762306a36Sopenharmony_ci int ptr_contents; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci ptr_contents = read_ptr(p1); 15062306a36Sopenharmony_ci dprintf2("ptr (%p) contents@%d: %x\n", p1, __LINE__, ptr_contents); 15162306a36Sopenharmony_ci expected_pkey_fault(pkey); 15262306a36Sopenharmony_ci} 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_civoid *malloc_pkey_with_mprotect_subpage(long size, int prot, u16 pkey) 15562306a36Sopenharmony_ci{ 15662306a36Sopenharmony_ci return PTR_ERR_ENOTSUP; 15762306a36Sopenharmony_ci} 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci#endif /* _PKEYS_X86_H */ 160