FILE
special_insns.h
File preview with syntax highlighting.
linux-6.19.14/arch/x86/include/asm/special_insns.h
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 13void native_write_cr0(unsigned long val); 14 15static 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 22static __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 29static __always_inline void native_write_cr2(unsigned long val) 30{ 31 asm volatile("mov %0,%%cr2": : "r" (val) : "memory"); 32} 33 34static __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 41static __always_inline void native_write_cr3(unsigned long val) 42{ 43 asm volatile("mov %0,%%cr3": : "r" (val) : "memory"); 44} 45 46static 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 66void native_write_cr4(unsigned long val); 67 68#ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS 69static 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 82static 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 94static inline u32 rdpkru(void) 95{ 96 return 0; 97} 98 99static 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 */ 111static __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 */ 124static __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 136static 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 145static inline unsigned long read_cr0(void) 146{ 147 return native_read_cr0(); 148} 149 150static inline void write_cr0(unsigned long x) 151{ 152 native_write_cr0(x); 153} 154 155static __always_inline unsigned long read_cr2(void) 156{ 157 return native_read_cr2(); 158} 159 160static __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 */ 169static inline unsigned long __read_cr3(void) 170{ 171 return __native_read_cr3(); 172} 173 174static inline void write_cr3(unsigned long x) 175{ 176 native_write_cr3(x); 177} 178 179static inline void __write_cr4(unsigned long x) 180{ 181 native_write_cr4(x); 182} 183#endif /* CONFIG_PARAVIRT_XXL */ 184 185static __always_inline void clflush(volatile void *__p) 186{ 187 asm volatile("clflush %0" : "+m" (*(volatile char __force *)__p)); 188} 189 190static 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 197static 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 209static 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; 216fail: 217 return -EFAULT; 218} 219#endif /* CONFIG_X86_USER_SHADOW_STACK */ 220 221#define nop() asm volatile ("nop") 222 223static __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 */ 230static 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 251static 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 */ 275static 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 297static __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 */
~/
Read-only file preview.