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