1 #ifndef LIBCFLAT_PROCESSOR_H 2 #define LIBCFLAT_PROCESSOR_H 3 4 #include "libcflat.h" 5 #include "msr.h" 6 #include <stdint.h> 7 8 #ifdef __x86_64__ 9 # define R "r" 10 # define W "q" 11 # define S "8" 12 #else 13 # define R "e" 14 # define W "l" 15 # define S "4" 16 #endif 17 18 #define X86_CR0_PE 0x00000001 19 #define X86_CR0_MP 0x00000002 20 #define X86_CR0_TS 0x00000008 21 #define X86_CR0_WP 0x00010000 22 #define X86_CR0_AM 0x00040000 23 #define X86_CR0_PG 0x80000000 24 #define X86_CR4_TSD 0x00000004 25 #define X86_CR4_DE 0x00000008 26 #define X86_CR4_PSE 0x00000010 27 #define X86_CR4_PAE 0x00000020 28 #define X86_CR4_VMXE 0x00002000 29 #define X86_CR4_PCIDE 0x00020000 30 #define X86_CR4_SMAP 0x00200000 31 #define X86_CR4_PKE 0x00400000 32 33 #define X86_EFLAGS_CF 0x00000001 34 #define X86_EFLAGS_ZF 0x00000040 35 #define X86_EFLAGS_AC 0x00040000 36 37 #define X86_IA32_EFER 0xc0000080 38 #define X86_EFER_LMA (1UL << 8) 39 40 struct descriptor_table_ptr { 41 u16 limit; 42 ulong base; 43 } __attribute__((packed)); 44 45 static inline void barrier(void) 46 { 47 asm volatile ("" : : : "memory"); 48 } 49 50 static inline void clac(void) 51 { 52 asm volatile (".byte 0x0f, 0x01, 0xca" : : : "memory"); 53 } 54 55 static inline void stac(void) 56 { 57 asm volatile (".byte 0x0f, 0x01, 0xcb" : : : "memory"); 58 } 59 60 static inline u16 read_cs(void) 61 { 62 unsigned val; 63 64 asm volatile ("mov %%cs, %0" : "=mr"(val)); 65 return val; 66 } 67 68 static inline u16 read_ds(void) 69 { 70 unsigned val; 71 72 asm volatile ("mov %%ds, %0" : "=mr"(val)); 73 return val; 74 } 75 76 static inline u16 read_es(void) 77 { 78 unsigned val; 79 80 asm volatile ("mov %%es, %0" : "=mr"(val)); 81 return val; 82 } 83 84 static inline u16 read_ss(void) 85 { 86 unsigned val; 87 88 asm volatile ("mov %%ss, %0" : "=mr"(val)); 89 return val; 90 } 91 92 static inline u16 read_fs(void) 93 { 94 unsigned val; 95 96 asm volatile ("mov %%fs, %0" : "=mr"(val)); 97 return val; 98 } 99 100 static inline u16 read_gs(void) 101 { 102 unsigned val; 103 104 asm volatile ("mov %%gs, %0" : "=mr"(val)); 105 return val; 106 } 107 108 static inline unsigned long read_rflags(void) 109 { 110 unsigned long f; 111 asm volatile ("pushf; pop %0\n\t" : "=rm"(f)); 112 return f; 113 } 114 115 static inline void write_ds(unsigned val) 116 { 117 asm volatile ("mov %0, %%ds" : : "rm"(val) : "memory"); 118 } 119 120 static inline void write_es(unsigned val) 121 { 122 asm volatile ("mov %0, %%es" : : "rm"(val) : "memory"); 123 } 124 125 static inline void write_ss(unsigned val) 126 { 127 asm volatile ("mov %0, %%ss" : : "rm"(val) : "memory"); 128 } 129 130 static inline void write_fs(unsigned val) 131 { 132 asm volatile ("mov %0, %%fs" : : "rm"(val) : "memory"); 133 } 134 135 static inline void write_gs(unsigned val) 136 { 137 asm volatile ("mov %0, %%gs" : : "rm"(val) : "memory"); 138 } 139 140 static inline void write_rflags(unsigned long f) 141 { 142 asm volatile ("push %0; popf\n\t" : : "rm"(f)); 143 } 144 145 static inline u64 rdmsr(u32 index) 146 { 147 u32 a, d; 148 asm volatile ("rdmsr" : "=a"(a), "=d"(d) : "c"(index) : "memory"); 149 return a | ((u64)d << 32); 150 } 151 152 static inline void wrmsr(u32 index, u64 val) 153 { 154 u32 a = val, d = val >> 32; 155 asm volatile ("wrmsr" : : "a"(a), "d"(d), "c"(index) : "memory"); 156 } 157 158 static inline uint64_t rdpmc(uint32_t index) 159 { 160 uint32_t a, d; 161 asm volatile ("rdpmc" : "=a"(a), "=d"(d) : "c"(index)); 162 return a | ((uint64_t)d << 32); 163 } 164 165 static inline void write_cr0(ulong val) 166 { 167 asm volatile ("mov %0, %%cr0" : : "r"(val) : "memory"); 168 } 169 170 static inline ulong read_cr0(void) 171 { 172 ulong val; 173 asm volatile ("mov %%cr0, %0" : "=r"(val) : : "memory"); 174 return val; 175 } 176 177 static inline void write_cr2(ulong val) 178 { 179 asm volatile ("mov %0, %%cr2" : : "r"(val) : "memory"); 180 } 181 182 static inline ulong read_cr2(void) 183 { 184 ulong val; 185 asm volatile ("mov %%cr2, %0" : "=r"(val) : : "memory"); 186 return val; 187 } 188 189 static inline void write_cr3(ulong val) 190 { 191 asm volatile ("mov %0, %%cr3" : : "r"(val) : "memory"); 192 } 193 194 static inline ulong read_cr3(void) 195 { 196 ulong val; 197 asm volatile ("mov %%cr3, %0" : "=r"(val) : : "memory"); 198 return val; 199 } 200 201 static inline void write_cr4(ulong val) 202 { 203 asm volatile ("mov %0, %%cr4" : : "r"(val) : "memory"); 204 } 205 206 static inline ulong read_cr4(void) 207 { 208 ulong val; 209 asm volatile ("mov %%cr4, %0" : "=r"(val) : : "memory"); 210 return val; 211 } 212 213 static inline void write_cr8(ulong val) 214 { 215 asm volatile ("mov %0, %%cr8" : : "r"(val) : "memory"); 216 } 217 218 static inline ulong read_cr8(void) 219 { 220 ulong val; 221 asm volatile ("mov %%cr8, %0" : "=r"(val) : : "memory"); 222 return val; 223 } 224 225 static inline void lgdt(const struct descriptor_table_ptr *ptr) 226 { 227 asm volatile ("lgdt %0" : : "m"(*ptr)); 228 } 229 230 static inline void sgdt(struct descriptor_table_ptr *ptr) 231 { 232 asm volatile ("sgdt %0" : "=m"(*ptr)); 233 } 234 235 static inline void lidt(const struct descriptor_table_ptr *ptr) 236 { 237 asm volatile ("lidt %0" : : "m"(*ptr)); 238 } 239 240 static inline void sidt(struct descriptor_table_ptr *ptr) 241 { 242 asm volatile ("sidt %0" : "=m"(*ptr)); 243 } 244 245 static inline void lldt(unsigned val) 246 { 247 asm volatile ("lldt %0" : : "rm"(val)); 248 } 249 250 static inline u16 sldt(void) 251 { 252 u16 val; 253 asm volatile ("sldt %0" : "=rm"(val)); 254 return val; 255 } 256 257 static inline void ltr(u16 val) 258 { 259 asm volatile ("ltr %0" : : "rm"(val)); 260 } 261 262 static inline u16 str(void) 263 { 264 u16 val; 265 asm volatile ("str %0" : "=rm"(val)); 266 return val; 267 } 268 269 static inline void write_dr6(ulong val) 270 { 271 asm volatile ("mov %0, %%dr6" : : "r"(val) : "memory"); 272 } 273 274 static inline ulong read_dr6(void) 275 { 276 ulong val; 277 asm volatile ("mov %%dr6, %0" : "=r"(val)); 278 return val; 279 } 280 281 static inline void write_dr7(ulong val) 282 { 283 asm volatile ("mov %0, %%dr7" : : "r"(val) : "memory"); 284 } 285 286 static inline ulong read_dr7(void) 287 { 288 ulong val; 289 asm volatile ("mov %%dr7, %0" : "=r"(val)); 290 return val; 291 } 292 293 struct cpuid { u32 a, b, c, d; }; 294 295 static inline struct cpuid raw_cpuid(u32 function, u32 index) 296 { 297 struct cpuid r; 298 asm volatile ("cpuid" 299 : "=a"(r.a), "=b"(r.b), "=c"(r.c), "=d"(r.d) 300 : "0"(function), "2"(index)); 301 return r; 302 } 303 304 static inline struct cpuid cpuid_indexed(u32 function, u32 index) 305 { 306 u32 level = raw_cpuid(function & 0xf0000000, 0).a; 307 if (level < function) 308 return (struct cpuid) { 0, 0, 0, 0 }; 309 return raw_cpuid(function, index); 310 } 311 312 static inline struct cpuid cpuid(u32 function) 313 { 314 return cpuid_indexed(function, 0); 315 } 316 317 static inline u8 cpuid_maxphyaddr(void) 318 { 319 if (raw_cpuid(0x80000000, 0).a < 0x80000008) 320 return 36; 321 return raw_cpuid(0x80000008, 0).a & 0xff; 322 } 323 324 325 static inline void pause(void) 326 { 327 asm volatile ("pause"); 328 } 329 330 static inline void cli(void) 331 { 332 asm volatile ("cli"); 333 } 334 335 static inline void sti(void) 336 { 337 asm volatile ("sti"); 338 } 339 340 static inline unsigned long long rdtsc() 341 { 342 long long r; 343 344 #ifdef __x86_64__ 345 unsigned a, d; 346 347 asm volatile ("rdtsc" : "=a"(a), "=d"(d)); 348 r = a | ((long long)d << 32); 349 #else 350 asm volatile ("rdtsc" : "=A"(r)); 351 #endif 352 return r; 353 } 354 355 static inline unsigned long long rdtscp(u32 *aux) 356 { 357 long long r; 358 359 #ifdef __x86_64__ 360 unsigned a, d; 361 362 asm volatile ("rdtscp" : "=a"(a), "=d"(d), "=c"(*aux)); 363 r = a | ((long long)d << 32); 364 #else 365 asm volatile ("rdtscp" : "=A"(r), "=c"(*aux)); 366 #endif 367 return r; 368 } 369 370 static inline void wrtsc(u64 tsc) 371 { 372 unsigned a = tsc, d = tsc >> 32; 373 374 asm volatile("wrmsr" : : "a"(a), "d"(d), "c"(0x10)); 375 } 376 377 static inline void irq_disable(void) 378 { 379 asm volatile("cli"); 380 } 381 382 /* Note that irq_enable() does not ensure an interrupt shadow due 383 * to the vagaries of compiler optimizations. If you need the 384 * shadow, use a single asm with "sti" and the instruction after it. 385 */ 386 static inline void irq_enable(void) 387 { 388 asm volatile("sti"); 389 } 390 391 static inline void invlpg(volatile void *va) 392 { 393 asm volatile("invlpg (%0)" ::"r" (va) : "memory"); 394 } 395 396 static inline void safe_halt(void) 397 { 398 asm volatile("sti; hlt"); 399 } 400 401 static inline u32 read_pkru(void) 402 { 403 unsigned int eax, edx; 404 unsigned int ecx = 0; 405 unsigned int pkru; 406 407 asm volatile(".byte 0x0f,0x01,0xee\n\t" 408 : "=a" (eax), "=d" (edx) 409 : "c" (ecx)); 410 pkru = eax; 411 return pkru; 412 } 413 414 static inline void write_pkru(u32 pkru) 415 { 416 unsigned int eax = pkru; 417 unsigned int ecx = 0; 418 unsigned int edx = 0; 419 420 asm volatile(".byte 0x0f,0x01,0xef\n\t" 421 : : "a" (eax), "c" (ecx), "d" (edx)); 422 } 423 424 #endif 425