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