1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2014 Pluribus Networks Inc. 14 */ 15 16 #ifndef _COMPAT_FREEBSD_AMD64_MACHINE_CPUFUNC_H_ 17 #define _COMPAT_FREEBSD_AMD64_MACHINE_CPUFUNC_H_ 18 19 #include <sys/types.h> 20 21 static __inline u_long 22 bsfq(u_long mask) 23 { 24 u_long result; 25 26 __asm __volatile("bsfq %1,%0" : "=r" (result) : "rm" (mask)); 27 return (result); 28 } 29 30 static __inline u_int 31 bsrl(u_int mask) 32 { 33 u_int result; 34 35 __asm __volatile("bsrl %1,%0" : "=r" (result) : "rm" (mask)); 36 return (result); 37 } 38 39 static __inline u_long 40 bsrq(u_long mask) 41 { 42 u_long result; 43 44 __asm __volatile("bsrq %1,%0" : "=r" (result) : "rm" (mask)); 45 return (result); 46 } 47 48 static __inline void 49 clts(void) 50 { 51 __asm __volatile("clts"); 52 } 53 54 static __inline void 55 do_cpuid(u_int ax, u_int *p) 56 { 57 __asm __volatile("cpuid" 58 : "=a" (p[0]), "=b" (p[1]), "=c" (p[2]), "=d" (p[3]) 59 : "0" (ax)); 60 } 61 62 static __inline void 63 cpuid_count(u_int ax, u_int cx, u_int *p) 64 { 65 __asm __volatile("cpuid" 66 : "=a" (p[0]), "=b" (p[1]), "=c" (p[2]), "=d" (p[3]) 67 : "0" (ax), "c" (cx)); 68 } 69 70 static __inline void 71 disable_intr(void) 72 { 73 __asm __volatile("cli"); 74 } 75 76 static __inline void 77 enable_intr(void) 78 { 79 __asm __volatile("sti"); 80 } 81 82 static __inline int 83 ffsl(long mask) 84 { 85 return (mask == 0 ? mask : (int)bsfq((u_long)mask) + 1); 86 } 87 88 static __inline int 89 fls(int mask) 90 { 91 return (mask == 0 ? mask : (int)bsrl((u_int)mask) + 1); 92 } 93 94 static __inline int 95 flsl(long mask) 96 { 97 return (mask == 0 ? mask : (int)bsrq((u_long)mask) + 1); 98 } 99 100 static __inline int 101 flsll(long long mask) 102 { 103 return (flsl((long)mask)); 104 } 105 106 static __inline u_long 107 read_rflags(void) 108 { 109 u_long rf; 110 111 __asm __volatile("pushfq; popq %0" : "=r" (rf)); 112 return (rf); 113 } 114 115 static __inline uint64_t 116 rdmsr(u_int msr) 117 { 118 uint32_t low, high; 119 120 __asm __volatile("rdmsr" : "=a" (low), "=d" (high) : "c" (msr)); 121 return (low | ((uint64_t)high << 32)); 122 } 123 124 static __inline uint64_t 125 rdtsc(void) 126 { 127 extern hrtime_t tsc_gethrtimeunscaled_delta(void); 128 129 /* Get the TSC reading with any needed synch offset applied */ 130 return ((uint64_t)tsc_gethrtimeunscaled_delta()); 131 } 132 133 static __inline void 134 wrmsr(u_int msr, uint64_t newval) 135 { 136 uint32_t low, high; 137 138 low = newval; 139 high = newval >> 32; 140 __asm __volatile("wrmsr" : : "a" (low), "d" (high), "c" (msr)); 141 } 142 143 static __inline void 144 load_cr0(u_long data) 145 { 146 __asm __volatile("movq %0,%%cr0" : : "r" (data)); 147 } 148 149 static __inline u_long 150 rcr0(void) 151 { 152 u_long data; 153 154 __asm __volatile("movq %%cr0,%0" : "=r" (data)); 155 return (data); 156 } 157 158 static __inline u_long 159 rcr3(void) 160 { 161 u_long data; 162 163 __asm __volatile("movq %%cr3,%0" : "=r" (data)); 164 return (data); 165 } 166 167 static __inline void 168 load_cr4(u_long data) 169 { 170 __asm __volatile("movq %0,%%cr4" : : "r" (data)); 171 } 172 173 static __inline u_long 174 rcr4(void) 175 { 176 u_long data; 177 178 __asm __volatile("movq %%cr4,%0" : "=r" (data)); 179 return (data); 180 } 181 182 static __inline u_long 183 rxcr(u_int reg) 184 { 185 u_int low, high; 186 187 __asm __volatile("xgetbv" : "=a" (low), "=d" (high) : "c" (reg)); 188 return (low | ((uint64_t)high << 32)); 189 } 190 191 static __inline void 192 load_xcr(u_int reg, u_long val) 193 { 194 u_int low, high; 195 196 low = val; 197 high = val >> 32; 198 __asm __volatile("xsetbv" : : "c" (reg), "a" (low), "d" (high)); 199 } 200 201 static __inline void 202 write_rflags(u_long rf) 203 { 204 __asm __volatile("pushq %0; popfq" : : "r" (rf)); 205 } 206 207 static __inline uint64_t 208 rdr0(void) 209 { 210 uint64_t data; 211 __asm __volatile("movq %%dr0,%0" : "=r" (data)); 212 return (data); 213 } 214 215 static __inline void 216 load_dr0(uint64_t dr0) 217 { 218 __asm __volatile("movq %0,%%dr0" : : "r" (dr0)); 219 } 220 221 static __inline uint64_t 222 rdr1(void) 223 { 224 uint64_t data; 225 __asm __volatile("movq %%dr1,%0" : "=r" (data)); 226 return (data); 227 } 228 229 static __inline void 230 load_dr1(uint64_t dr1) 231 { 232 __asm __volatile("movq %0,%%dr1" : : "r" (dr1)); 233 } 234 235 static __inline uint64_t 236 rdr2(void) 237 { 238 uint64_t data; 239 __asm __volatile("movq %%dr2,%0" : "=r" (data)); 240 return (data); 241 } 242 243 static __inline void 244 load_dr2(uint64_t dr2) 245 { 246 __asm __volatile("movq %0,%%dr2" : : "r" (dr2)); 247 } 248 249 static __inline uint64_t 250 rdr3(void) 251 { 252 uint64_t data; 253 __asm __volatile("movq %%dr3,%0" : "=r" (data)); 254 return (data); 255 } 256 257 static __inline void 258 load_dr3(uint64_t dr3) 259 { 260 __asm __volatile("movq %0,%%dr3" : : "r" (dr3)); 261 } 262 263 static __inline uint64_t 264 rdr6(void) 265 { 266 uint64_t data; 267 __asm __volatile("movq %%dr6,%0" : "=r" (data)); 268 return (data); 269 } 270 271 static __inline void 272 load_dr6(uint64_t dr6) 273 { 274 __asm __volatile("movq %0,%%dr6" : : "r" (dr6)); 275 } 276 277 static __inline uint64_t 278 rdr7(void) 279 { 280 uint64_t data; 281 __asm __volatile("movq %%dr7,%0" : "=r" (data)); 282 return (data); 283 } 284 285 static __inline void 286 load_dr7(uint64_t dr7) 287 { 288 __asm __volatile("movq %0,%%dr7" : : "r" (dr7)); 289 } 290 291 #ifdef _KERNEL 292 /* 293 * Including the native sys/segments.h in userspace seriously conflicts with 294 * the FreeBSD compat/contrib headers. 295 */ 296 #include <sys/segments.h> 297 298 static __inline void 299 lldt(u_short sel) 300 { 301 wr_ldtr(sel); 302 } 303 304 static __inline u_short 305 sldt() 306 { 307 return (rd_ldtr()); 308 } 309 #endif /* _KERNEL */ 310 311 #endif /* _COMPAT_FREEBSD_AMD64_MACHINE_CPUFUNC_H_ */ 312