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