| 1 | /* SPDX-License-Identifier: GPL-2.0 */ | 
|---|
| 2 | #ifndef _ASM_X86_SPECIAL_INSNS_H | 
|---|
| 3 | #define _ASM_X86_SPECIAL_INSNS_H | 
|---|
| 4 |  | 
|---|
| 5 | #ifdef __KERNEL__ | 
|---|
| 6 | #include <asm/nops.h> | 
|---|
| 7 | #include <asm/processor-flags.h> | 
|---|
| 8 |  | 
|---|
| 9 | #include <linux/errno.h> | 
|---|
| 10 | #include <linux/irqflags.h> | 
|---|
| 11 | #include <linux/jump_label.h> | 
|---|
| 12 |  | 
|---|
| 13 | void native_write_cr0(unsigned long val); | 
|---|
| 14 |  | 
|---|
| 15 | static inline unsigned long native_read_cr0(void) | 
|---|
| 16 | { | 
|---|
| 17 | unsigned long val; | 
|---|
| 18 | asm volatile( "mov %%cr0,%0": "=r"(val)); | 
|---|
| 19 | return val; | 
|---|
| 20 | } | 
|---|
| 21 |  | 
|---|
| 22 | static __always_inline unsigned long native_read_cr2(void) | 
|---|
| 23 | { | 
|---|
| 24 | unsigned long val; | 
|---|
| 25 | asm volatile( "mov %%cr2,%0": "=r"(val)); | 
|---|
| 26 | return val; | 
|---|
| 27 | } | 
|---|
| 28 |  | 
|---|
| 29 | static __always_inline void native_write_cr2(unsigned long val) | 
|---|
| 30 | { | 
|---|
| 31 | asm volatile( "mov %0,%%cr2": : "r"(val) : "memory"); | 
|---|
| 32 | } | 
|---|
| 33 |  | 
|---|
| 34 | static __always_inline unsigned long __native_read_cr3(void) | 
|---|
| 35 | { | 
|---|
| 36 | unsigned long val; | 
|---|
| 37 | asm volatile( "mov %%cr3,%0": "=r"(val)); | 
|---|
| 38 | return val; | 
|---|
| 39 | } | 
|---|
| 40 |  | 
|---|
| 41 | static __always_inline void native_write_cr3(unsigned long val) | 
|---|
| 42 | { | 
|---|
| 43 | asm volatile( "mov %0,%%cr3": : "r"(val) : "memory"); | 
|---|
| 44 | } | 
|---|
| 45 |  | 
|---|
| 46 | static inline unsigned long native_read_cr4(void) | 
|---|
| 47 | { | 
|---|
| 48 | unsigned long val; | 
|---|
| 49 | #ifdef CONFIG_X86_32 | 
|---|
| 50 | /* | 
|---|
| 51 | * This could fault if CR4 does not exist.  Non-existent CR4 | 
|---|
| 52 | * is functionally equivalent to CR4 == 0.  Keep it simple and pretend | 
|---|
| 53 | * that CR4 == 0 on CPUs that don't have CR4. | 
|---|
| 54 | */ | 
|---|
| 55 | asm volatile( "1: mov %%cr4, %0\n" | 
|---|
| 56 | "2:\n" | 
|---|
| 57 | _ASM_EXTABLE(1b, 2b) | 
|---|
| 58 | : "=r"(val) : "0"(0)); | 
|---|
| 59 | #else | 
|---|
| 60 | /* CR4 always exists on x86_64. */ | 
|---|
| 61 | asm volatile( "mov %%cr4,%0": "=r"(val)); | 
|---|
| 62 | #endif | 
|---|
| 63 | return val; | 
|---|
| 64 | } | 
|---|
| 65 |  | 
|---|
| 66 | void native_write_cr4(unsigned long val); | 
|---|
| 67 |  | 
|---|
| 68 | #ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS | 
|---|
| 69 | static inline u32 rdpkru(void) | 
|---|
| 70 | { | 
|---|
| 71 | u32 ecx = 0; | 
|---|
| 72 | u32 edx, pkru; | 
|---|
| 73 |  | 
|---|
| 74 | /* | 
|---|
| 75 | * "rdpkru" instruction.  Places PKRU contents in to EAX, | 
|---|
| 76 | * clears EDX and requires that ecx=0. | 
|---|
| 77 | */ | 
|---|
| 78 | asm volatile( "rdpkru": "=a"(pkru), "=d"(edx) : "c"(ecx)); | 
|---|
| 79 | return pkru; | 
|---|
| 80 | } | 
|---|
| 81 |  | 
|---|
| 82 | static inline void wrpkru(u32 pkru) | 
|---|
| 83 | { | 
|---|
| 84 | u32 ecx = 0, edx = 0; | 
|---|
| 85 |  | 
|---|
| 86 | /* | 
|---|
| 87 | * "wrpkru" instruction.  Loads contents in EAX to PKRU, | 
|---|
| 88 | * requires that ecx = edx = 0. | 
|---|
| 89 | */ | 
|---|
| 90 | asm volatile( "wrpkru": : "a"(pkru), "c"(ecx), "d"(edx)); | 
|---|
| 91 | } | 
|---|
| 92 |  | 
|---|
| 93 | #else | 
|---|
| 94 | static inline u32 rdpkru(void) | 
|---|
| 95 | { | 
|---|
| 96 | return 0; | 
|---|
| 97 | } | 
|---|
| 98 |  | 
|---|
| 99 | static inline void wrpkru(u32 pkru) | 
|---|
| 100 | { | 
|---|
| 101 | } | 
|---|
| 102 | #endif | 
|---|
| 103 |  | 
|---|
| 104 | /* | 
|---|
| 105 | * Write back all modified lines in all levels of cache associated with this | 
|---|
| 106 | * logical processor to main memory, and then invalidate all caches.  Depending | 
|---|
| 107 | * on the micro-architecture, WBINVD (and WBNOINVD below) may or may not affect | 
|---|
| 108 | * lower level caches associated with another logical processor that shares any | 
|---|
| 109 | * level of this processor's cache hierarchy. | 
|---|
| 110 | */ | 
|---|
| 111 | static __always_inline void wbinvd(void) | 
|---|
| 112 | { | 
|---|
| 113 | asm volatile( "wbinvd": : : "memory"); | 
|---|
| 114 | } | 
|---|
| 115 |  | 
|---|
| 116 | /* Instruction encoding provided for binutils backwards compatibility. */ | 
|---|
| 117 | #define ASM_WBNOINVD _ASM_BYTES(0xf3,0x0f,0x09) | 
|---|
| 118 |  | 
|---|
| 119 | /* | 
|---|
| 120 | * Write back all modified lines in all levels of cache associated with this | 
|---|
| 121 | * logical processor to main memory, but do NOT explicitly invalidate caches, | 
|---|
| 122 | * i.e. leave all/most cache lines in the hierarchy in non-modified state. | 
|---|
| 123 | */ | 
|---|
| 124 | static __always_inline void wbnoinvd(void) | 
|---|
| 125 | { | 
|---|
| 126 | /* | 
|---|
| 127 | * Explicitly encode WBINVD if X86_FEATURE_WBNOINVD is unavailable even | 
|---|
| 128 | * though WBNOINVD is backwards compatible (it's simply WBINVD with an | 
|---|
| 129 | * ignored REP prefix), to guarantee that WBNOINVD isn't used if it | 
|---|
| 130 | * needs to be avoided for any reason.  For all supported usage in the | 
|---|
| 131 | * kernel, WBINVD is functionally a superset of WBNOINVD. | 
|---|
| 132 | */ | 
|---|
| 133 | alternative( "wbinvd", ASM_WBNOINVD, X86_FEATURE_WBNOINVD); | 
|---|
| 134 | } | 
|---|
| 135 |  | 
|---|
| 136 | static inline unsigned long __read_cr4(void) | 
|---|
| 137 | { | 
|---|
| 138 | return native_read_cr4(); | 
|---|
| 139 | } | 
|---|
| 140 |  | 
|---|
| 141 | #ifdef CONFIG_PARAVIRT_XXL | 
|---|
| 142 | #include <asm/paravirt.h> | 
|---|
| 143 | #else | 
|---|
| 144 |  | 
|---|
| 145 | static inline unsigned long read_cr0(void) | 
|---|
| 146 | { | 
|---|
| 147 | return native_read_cr0(); | 
|---|
| 148 | } | 
|---|
| 149 |  | 
|---|
| 150 | static inline void write_cr0(unsigned long x) | 
|---|
| 151 | { | 
|---|
| 152 | native_write_cr0(val: x); | 
|---|
| 153 | } | 
|---|
| 154 |  | 
|---|
| 155 | static __always_inline unsigned long read_cr2(void) | 
|---|
| 156 | { | 
|---|
| 157 | return native_read_cr2(); | 
|---|
| 158 | } | 
|---|
| 159 |  | 
|---|
| 160 | static __always_inline void write_cr2(unsigned long x) | 
|---|
| 161 | { | 
|---|
| 162 | native_write_cr2(val: x); | 
|---|
| 163 | } | 
|---|
| 164 |  | 
|---|
| 165 | /* | 
|---|
| 166 | * Careful!  CR3 contains more than just an address.  You probably want | 
|---|
| 167 | * read_cr3_pa() instead. | 
|---|
| 168 | */ | 
|---|
| 169 | static inline unsigned long __read_cr3(void) | 
|---|
| 170 | { | 
|---|
| 171 | return __native_read_cr3(); | 
|---|
| 172 | } | 
|---|
| 173 |  | 
|---|
| 174 | static inline void write_cr3(unsigned long x) | 
|---|
| 175 | { | 
|---|
| 176 | native_write_cr3(val: x); | 
|---|
| 177 | } | 
|---|
| 178 |  | 
|---|
| 179 | static inline void __write_cr4(unsigned long x) | 
|---|
| 180 | { | 
|---|
| 181 | native_write_cr4(val: x); | 
|---|
| 182 | } | 
|---|
| 183 | #endif /* CONFIG_PARAVIRT_XXL */ | 
|---|
| 184 |  | 
|---|
| 185 | static __always_inline void clflush(volatile void *__p) | 
|---|
| 186 | { | 
|---|
| 187 | asm volatile( "clflush %0": "+m"(*(volatile char __force *)__p)); | 
|---|
| 188 | } | 
|---|
| 189 |  | 
|---|
| 190 | static inline void clflushopt(volatile void *__p) | 
|---|
| 191 | { | 
|---|
| 192 | alternative_io( "ds clflush %0", | 
|---|
| 193 | "clflushopt %0", X86_FEATURE_CLFLUSHOPT, | 
|---|
| 194 | "+m"(*(volatile char __force *)__p)); | 
|---|
| 195 | } | 
|---|
| 196 |  | 
|---|
| 197 | static inline void clwb(volatile void *__p) | 
|---|
| 198 | { | 
|---|
| 199 | volatile struct { char x[64]; } *p = __p; | 
|---|
| 200 |  | 
|---|
| 201 | asm_inline volatile(ALTERNATIVE_2( | 
|---|
| 202 | "ds clflush %0", | 
|---|
| 203 | "clflushopt %0", X86_FEATURE_CLFLUSHOPT, | 
|---|
| 204 | "clwb %0", X86_FEATURE_CLWB) | 
|---|
| 205 | : "+m"(*p)); | 
|---|
| 206 | } | 
|---|
| 207 |  | 
|---|
| 208 | #ifdef CONFIG_X86_USER_SHADOW_STACK | 
|---|
| 209 | static inline int write_user_shstk_64(u64 __user *addr, u64 val) | 
|---|
| 210 | { | 
|---|
| 211 | asm goto( "1: wrussq %[val], %[addr]\n" | 
|---|
| 212 | _ASM_EXTABLE(1b, %l[fail]) | 
|---|
| 213 | :: [addr] "m"(*addr), [val] "r"(val) | 
|---|
| 214 | :: fail); | 
|---|
| 215 | return 0; | 
|---|
| 216 | fail: | 
|---|
| 217 | return -EFAULT; | 
|---|
| 218 | } | 
|---|
| 219 | #endif /* CONFIG_X86_USER_SHADOW_STACK */ | 
|---|
| 220 |  | 
|---|
| 221 | #define nop() asm volatile ("nop") | 
|---|
| 222 |  | 
|---|
| 223 | static __always_inline void serialize(void) | 
|---|
| 224 | { | 
|---|
| 225 | /* Instruction opcode for SERIALIZE; supported in binutils >= 2.35. */ | 
|---|
| 226 | asm volatile( ".byte 0xf, 0x1, 0xe8"::: "memory"); | 
|---|
| 227 | } | 
|---|
| 228 |  | 
|---|
| 229 | /* The dst parameter must be 64-bytes aligned */ | 
|---|
| 230 | static inline void movdir64b(void *dst, const void *src) | 
|---|
| 231 | { | 
|---|
| 232 | const struct { char _[64]; } *__src = src; | 
|---|
| 233 | struct { char _[64]; } *__dst = dst; | 
|---|
| 234 |  | 
|---|
| 235 | /* | 
|---|
| 236 | * MOVDIR64B %(rdx), rax. | 
|---|
| 237 | * | 
|---|
| 238 | * Both __src and __dst must be memory constraints in order to tell the | 
|---|
| 239 | * compiler that no other memory accesses should be reordered around | 
|---|
| 240 | * this one. | 
|---|
| 241 | * | 
|---|
| 242 | * Also, both must be supplied as lvalues because this tells | 
|---|
| 243 | * the compiler what the object is (its size) the instruction accesses. | 
|---|
| 244 | * I.e., not the pointers but what they point to, thus the deref'ing '*'. | 
|---|
| 245 | */ | 
|---|
| 246 | asm volatile( ".byte 0x66, 0x0f, 0x38, 0xf8, 0x02" | 
|---|
| 247 | : "+m"(*__dst) | 
|---|
| 248 | : "m"(*__src), "a"(__dst), "d"(__src)); | 
|---|
| 249 | } | 
|---|
| 250 |  | 
|---|
| 251 | static inline void movdir64b_io(void __iomem *dst, const void *src) | 
|---|
| 252 | { | 
|---|
| 253 | movdir64b(dst: (void __force *)dst, src); | 
|---|
| 254 | } | 
|---|
| 255 |  | 
|---|
| 256 | /** | 
|---|
| 257 | * enqcmds - Enqueue a command in supervisor (CPL0) mode | 
|---|
| 258 | * @dst: destination, in MMIO space (must be 512-bit aligned) | 
|---|
| 259 | * @src: 512 bits memory operand | 
|---|
| 260 | * | 
|---|
| 261 | * The ENQCMDS instruction allows software to write a 512-bit command to | 
|---|
| 262 | * a 512-bit-aligned special MMIO region that supports the instruction. | 
|---|
| 263 | * A return status is loaded into the ZF flag in the RFLAGS register. | 
|---|
| 264 | * ZF = 0 equates to success, and ZF = 1 indicates retry or error. | 
|---|
| 265 | * | 
|---|
| 266 | * This function issues the ENQCMDS instruction to submit data from | 
|---|
| 267 | * kernel space to MMIO space, in a unit of 512 bits. Order of data access | 
|---|
| 268 | * is not guaranteed, nor is a memory barrier performed afterwards. It | 
|---|
| 269 | * returns 0 on success and -EAGAIN on failure. | 
|---|
| 270 | * | 
|---|
| 271 | * Warning: Do not use this helper unless your driver has checked that the | 
|---|
| 272 | * ENQCMDS instruction is supported on the platform and the device accepts | 
|---|
| 273 | * ENQCMDS. | 
|---|
| 274 | */ | 
|---|
| 275 | static inline int enqcmds(void __iomem *dst, const void *src) | 
|---|
| 276 | { | 
|---|
| 277 | const struct { char _[64]; } *__src = src; | 
|---|
| 278 | struct { char _[64]; } __iomem *__dst = dst; | 
|---|
| 279 | bool zf; | 
|---|
| 280 |  | 
|---|
| 281 | /* | 
|---|
| 282 | * ENQCMDS %(rdx), rax | 
|---|
| 283 | * | 
|---|
| 284 | * See movdir64b()'s comment on operand specification. | 
|---|
| 285 | */ | 
|---|
| 286 | asm volatile( ".byte 0xf3, 0x0f, 0x38, 0xf8, 0x02, 0x66, 0x90" | 
|---|
| 287 | : "=@ccz"(zf), "+m"(*__dst) | 
|---|
| 288 | : "m"(*__src), "a"(__dst), "d"(__src)); | 
|---|
| 289 |  | 
|---|
| 290 | /* Submission failure is indicated via EFLAGS.ZF=1 */ | 
|---|
| 291 | if (zf) | 
|---|
| 292 | return -EAGAIN; | 
|---|
| 293 |  | 
|---|
| 294 | return 0; | 
|---|
| 295 | } | 
|---|
| 296 |  | 
|---|
| 297 | static __always_inline void tile_release(void) | 
|---|
| 298 | { | 
|---|
| 299 | /* | 
|---|
| 300 | * Instruction opcode for TILERELEASE; supported in binutils | 
|---|
| 301 | * version >= 2.36. | 
|---|
| 302 | */ | 
|---|
| 303 | asm volatile( ".byte 0xc4, 0xe2, 0x78, 0x49, 0xc0"); | 
|---|
| 304 | } | 
|---|
| 305 |  | 
|---|
| 306 | #endif /* __KERNEL__ */ | 
|---|
| 307 |  | 
|---|
| 308 | #endif /* _ASM_X86_SPECIAL_INSNS_H */ | 
|---|
| 309 |  | 
|---|