1/* SPDX-License-Identifier: GPL-2.0 */
2
3#ifndef _PKEYS_X86_H
4#define _PKEYS_X86_H
5
6#ifdef __i386__
7
8#ifndef SYS_mprotect_key
9# define SYS_mprotect_key	380
10#endif
11
12#ifndef SYS_pkey_alloc
13# define SYS_pkey_alloc		381
14# define SYS_pkey_free		382
15#endif
16
17#define REG_IP_IDX		REG_EIP
18#define si_pkey_offset		0x14
19
20#else
21
22#ifndef SYS_mprotect_key
23# define SYS_mprotect_key	329
24#endif
25
26#ifndef SYS_pkey_alloc
27# define SYS_pkey_alloc		330
28# define SYS_pkey_free		331
29#endif
30
31#define REG_IP_IDX		REG_RIP
32#define si_pkey_offset		0x20
33
34#endif
35
36#ifndef PKEY_DISABLE_ACCESS
37# define PKEY_DISABLE_ACCESS	0x1
38#endif
39
40#ifndef PKEY_DISABLE_WRITE
41# define PKEY_DISABLE_WRITE	0x2
42#endif
43
44#define NR_PKEYS		16
45#define NR_RESERVED_PKEYS	2 /* pkey-0 and exec-only-pkey */
46#define PKEY_BITS_PER_PKEY	2
47#define HPAGE_SIZE		(1UL<<21)
48#define PAGE_SIZE		4096
49#define MB			(1<<20)
50
51static inline void __page_o_noops(void)
52{
53	/* 8-bytes of instruction * 512 bytes = 1 page */
54	asm(".rept 512 ; nopl 0x7eeeeeee(%eax) ; .endr");
55}
56
57static inline u64 __read_pkey_reg(void)
58{
59	unsigned int eax, edx;
60	unsigned int ecx = 0;
61	unsigned pkey_reg;
62
63	asm volatile(".byte 0x0f,0x01,0xee\n\t"
64		     : "=a" (eax), "=d" (edx)
65		     : "c" (ecx));
66	pkey_reg = eax;
67	return pkey_reg;
68}
69
70static inline void __write_pkey_reg(u64 pkey_reg)
71{
72	unsigned int eax = pkey_reg;
73	unsigned int ecx = 0;
74	unsigned int edx = 0;
75
76	dprintf4("%s() changing %016llx to %016llx\n", __func__,
77			__read_pkey_reg(), pkey_reg);
78	asm volatile(".byte 0x0f,0x01,0xef\n\t"
79		     : : "a" (eax), "c" (ecx), "d" (edx));
80	assert(pkey_reg == __read_pkey_reg());
81}
82
83static inline void __cpuid(unsigned int *eax, unsigned int *ebx,
84		unsigned int *ecx, unsigned int *edx)
85{
86	/* ecx is often an input as well as an output. */
87	asm volatile(
88		"cpuid;"
89		: "=a" (*eax),
90		  "=b" (*ebx),
91		  "=c" (*ecx),
92		  "=d" (*edx)
93		: "0" (*eax), "2" (*ecx));
94}
95
96/* Intel-defined CPU features, CPUID level 0x00000007:0 (ecx) */
97#define X86_FEATURE_PKU        (1<<3) /* Protection Keys for Userspace */
98#define X86_FEATURE_OSPKE      (1<<4) /* OS Protection Keys Enable */
99
100static inline int cpu_has_pkeys(void)
101{
102	unsigned int eax;
103	unsigned int ebx;
104	unsigned int ecx;
105	unsigned int edx;
106
107	eax = 0x7;
108	ecx = 0x0;
109	__cpuid(&eax, &ebx, &ecx, &edx);
110
111	if (!(ecx & X86_FEATURE_PKU)) {
112		dprintf2("cpu does not have PKU\n");
113		return 0;
114	}
115	if (!(ecx & X86_FEATURE_OSPKE)) {
116		dprintf2("cpu does not have OSPKE\n");
117		return 0;
118	}
119	return 1;
120}
121
122static inline u32 pkey_bit_position(int pkey)
123{
124	return pkey * PKEY_BITS_PER_PKEY;
125}
126
127#define XSTATE_PKEY_BIT	(9)
128#define XSTATE_PKEY	0x200
129
130int pkey_reg_xstate_offset(void)
131{
132	unsigned int eax;
133	unsigned int ebx;
134	unsigned int ecx;
135	unsigned int edx;
136	int xstate_offset;
137	int xstate_size;
138	unsigned long XSTATE_CPUID = 0xd;
139	int leaf;
140
141	/* assume that XSTATE_PKEY is set in XCR0 */
142	leaf = XSTATE_PKEY_BIT;
143	{
144		eax = XSTATE_CPUID;
145		ecx = leaf;
146		__cpuid(&eax, &ebx, &ecx, &edx);
147
148		if (leaf == XSTATE_PKEY_BIT) {
149			xstate_offset = ebx;
150			xstate_size = eax;
151		}
152	}
153
154	if (xstate_size == 0) {
155		printf("could not find size/offset of PKEY in xsave state\n");
156		return 0;
157	}
158
159	return xstate_offset;
160}
161
162static inline int get_arch_reserved_keys(void)
163{
164	return NR_RESERVED_PKEYS;
165}
166
167void expect_fault_on_read_execonly_key(void *p1, int pkey)
168{
169	int ptr_contents;
170
171	ptr_contents = read_ptr(p1);
172	dprintf2("ptr (%p) contents@%d: %x\n", p1, __LINE__, ptr_contents);
173	expected_pkey_fault(pkey);
174}
175
176void *malloc_pkey_with_mprotect_subpage(long size, int prot, u16 pkey)
177{
178	return PTR_ERR_ENOTSUP;
179}
180
181#endif /* _PKEYS_X86_H */
182