Commit | Line | Data |
---|---|---|
53555e2b TJB |
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 | |
604c496b | 45 | #define NR_RESERVED_PKEYS 2 /* pkey-0 and exec-only-pkey */ |
53555e2b TJB |
46 | #define PKEY_BITS_PER_PKEY 2 |
47 | #define HPAGE_SIZE (1UL<<21) | |
48 | #define PAGE_SIZE 4096 | |
49 | #define MB (1<<20) | |
50 | ||
51 | static 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 | ||
4dbdd947 | 57 | static inline u64 __read_pkey_reg(void) |
53555e2b TJB |
58 | { |
59 | unsigned int eax, edx; | |
60 | unsigned int ecx = 0; | |
4dbdd947 | 61 | unsigned pkey_reg; |
53555e2b TJB |
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 | ||
4dbdd947 | 70 | static inline void __write_pkey_reg(u64 pkey_reg) |
53555e2b TJB |
71 | { |
72 | unsigned int eax = pkey_reg; | |
73 | unsigned int ecx = 0; | |
74 | unsigned int edx = 0; | |
75 | ||
4dbdd947 | 76 | dprintf4("%s() changing %016llx to %016llx\n", __func__, |
53555e2b TJB |
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 | ||
53555e2b TJB |
83 | /* Intel-defined CPU features, CPUID level 0x00000007:0 (ecx) */ |
84 | #define X86_FEATURE_PKU (1<<3) /* Protection Keys for Userspace */ | |
85 | #define X86_FEATURE_OSPKE (1<<4) /* OS Protection Keys Enable */ | |
86 | ||
94c8a223 | 87 | static inline int cpu_has_pkeys(void) |
53555e2b TJB |
88 | { |
89 | unsigned int eax; | |
90 | unsigned int ebx; | |
91 | unsigned int ecx; | |
92 | unsigned int edx; | |
93 | ||
0dba8dae | 94 | __cpuid_count(0x7, 0x0, eax, ebx, ecx, edx); |
53555e2b TJB |
95 | |
96 | if (!(ecx & X86_FEATURE_PKU)) { | |
97 | dprintf2("cpu does not have PKU\n"); | |
98 | return 0; | |
99 | } | |
100 | if (!(ecx & X86_FEATURE_OSPKE)) { | |
101 | dprintf2("cpu does not have OSPKE\n"); | |
102 | return 0; | |
103 | } | |
104 | return 1; | |
105 | } | |
106 | ||
6ea25770 KH |
107 | static inline int cpu_max_xsave_size(void) |
108 | { | |
109 | unsigned long XSTATE_CPUID = 0xd; | |
110 | unsigned int eax; | |
111 | unsigned int ebx; | |
112 | unsigned int ecx; | |
113 | unsigned int edx; | |
114 | ||
115 | __cpuid_count(XSTATE_CPUID, 0, eax, ebx, ecx, edx); | |
116 | return ecx; | |
117 | } | |
118 | ||
0c416bca SD |
119 | static inline u32 pkey_bit_position(int pkey) |
120 | { | |
121 | return pkey * PKEY_BITS_PER_PKEY; | |
122 | } | |
123 | ||
53555e2b TJB |
124 | #define XSTATE_PKEY_BIT (9) |
125 | #define XSTATE_PKEY 0x200 | |
d892454b | 126 | #define XSTATE_BV_OFFSET 512 |
53555e2b TJB |
127 | |
128 | int pkey_reg_xstate_offset(void) | |
129 | { | |
130 | unsigned int eax; | |
131 | unsigned int ebx; | |
132 | unsigned int ecx; | |
133 | unsigned int edx; | |
134 | int xstate_offset; | |
135 | int xstate_size; | |
136 | unsigned long XSTATE_CPUID = 0xd; | |
137 | int leaf; | |
138 | ||
139 | /* assume that XSTATE_PKEY is set in XCR0 */ | |
140 | leaf = XSTATE_PKEY_BIT; | |
141 | { | |
0dba8dae | 142 | __cpuid_count(XSTATE_CPUID, leaf, eax, ebx, ecx, edx); |
53555e2b TJB |
143 | |
144 | if (leaf == XSTATE_PKEY_BIT) { | |
145 | xstate_offset = ebx; | |
146 | xstate_size = eax; | |
147 | } | |
148 | } | |
149 | ||
150 | if (xstate_size == 0) { | |
151 | printf("could not find size/offset of PKEY in xsave state\n"); | |
152 | return 0; | |
153 | } | |
154 | ||
155 | return xstate_offset; | |
156 | } | |
157 | ||
604c496b RP |
158 | static inline int get_arch_reserved_keys(void) |
159 | { | |
160 | return NR_RESERVED_PKEYS; | |
161 | } | |
162 | ||
163 | void expect_fault_on_read_execonly_key(void *p1, int pkey) | |
164 | { | |
165 | int ptr_contents; | |
166 | ||
167 | ptr_contents = read_ptr(p1); | |
168 | dprintf2("ptr (%p) contents@%d: %x\n", p1, __LINE__, ptr_contents); | |
169 | expected_pkey_fault(pkey); | |
170 | } | |
171 | ||
6e2c2d0f RP |
172 | void *malloc_pkey_with_mprotect_subpage(long size, int prot, u16 pkey) |
173 | { | |
174 | return PTR_ERR_ENOTSUP; | |
175 | } | |
176 | ||
53555e2b | 177 | #endif /* _PKEYS_X86_H */ |