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