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(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(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(x); 177 } 178 179 static inline void __write_cr4(unsigned long x) 180 { 181 native_write_cr4(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((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