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 /* Equivalent to the FreeBSD rdtsc(), but with any necessary per-cpu offset */ 116 uint64_t rdtsc_offset(void); 117 118 static __inline uint64_t 119 rdmsr(u_int msr) 120 { 121 uint32_t low, high; 122 123 __asm __volatile("rdmsr" : "=a" (low), "=d" (high) : "c" (msr)); 124 return (low | ((uint64_t)high << 32)); 125 } 126 127 static __inline void 128 wrmsr(u_int msr, uint64_t newval) 129 { 130 uint32_t low, high; 131 132 low = newval; 133 high = newval >> 32; 134 __asm __volatile("wrmsr" : : "a" (low), "d" (high), "c" (msr)); 135 } 136 137 static __inline void 138 load_cr0(u_long data) 139 { 140 __asm __volatile("movq %0,%%cr0" : : "r" (data)); 141 } 142 143 static __inline u_long 144 rcr0(void) 145 { 146 u_long data; 147 148 __asm __volatile("movq %%cr0,%0" : "=r" (data)); 149 return (data); 150 } 151 152 static __inline u_long 153 rcr3(void) 154 { 155 u_long data; 156 157 __asm __volatile("movq %%cr3,%0" : "=r" (data)); 158 return (data); 159 } 160 161 static __inline void 162 load_cr4(u_long data) 163 { 164 __asm __volatile("movq %0,%%cr4" : : "r" (data)); 165 } 166 167 static __inline u_long 168 rcr4(void) 169 { 170 u_long data; 171 172 __asm __volatile("movq %%cr4,%0" : "=r" (data)); 173 return (data); 174 } 175 176 static __inline u_long 177 rxcr(u_int reg) 178 { 179 u_int low, high; 180 181 __asm __volatile("xgetbv" : "=a" (low), "=d" (high) : "c" (reg)); 182 return (low | ((uint64_t)high << 32)); 183 } 184 185 static __inline void 186 load_xcr(u_int reg, u_long val) 187 { 188 u_int low, high; 189 190 low = val; 191 high = val >> 32; 192 __asm __volatile("xsetbv" : : "c" (reg), "a" (low), "d" (high)); 193 } 194 195 static __inline void 196 write_rflags(u_long rf) 197 { 198 __asm __volatile("pushq %0; popfq" : : "r" (rf)); 199 } 200 201 static __inline uint64_t 202 rdr0(void) 203 { 204 uint64_t data; 205 __asm __volatile("movq %%dr0,%0" : "=r" (data)); 206 return (data); 207 } 208 209 static __inline void 210 load_dr0(uint64_t dr0) 211 { 212 __asm __volatile("movq %0,%%dr0" : : "r" (dr0)); 213 } 214 215 static __inline uint64_t 216 rdr1(void) 217 { 218 uint64_t data; 219 __asm __volatile("movq %%dr1,%0" : "=r" (data)); 220 return (data); 221 } 222 223 static __inline void 224 load_dr1(uint64_t dr1) 225 { 226 __asm __volatile("movq %0,%%dr1" : : "r" (dr1)); 227 } 228 229 static __inline uint64_t 230 rdr2(void) 231 { 232 uint64_t data; 233 __asm __volatile("movq %%dr2,%0" : "=r" (data)); 234 return (data); 235 } 236 237 static __inline void 238 load_dr2(uint64_t dr2) 239 { 240 __asm __volatile("movq %0,%%dr2" : : "r" (dr2)); 241 } 242 243 static __inline uint64_t 244 rdr3(void) 245 { 246 uint64_t data; 247 __asm __volatile("movq %%dr3,%0" : "=r" (data)); 248 return (data); 249 } 250 251 static __inline void 252 load_dr3(uint64_t dr3) 253 { 254 __asm __volatile("movq %0,%%dr3" : : "r" (dr3)); 255 } 256 257 static __inline uint64_t 258 rdr6(void) 259 { 260 uint64_t data; 261 __asm __volatile("movq %%dr6,%0" : "=r" (data)); 262 return (data); 263 } 264 265 static __inline void 266 load_dr6(uint64_t dr6) 267 { 268 __asm __volatile("movq %0,%%dr6" : : "r" (dr6)); 269 } 270 271 static __inline uint64_t 272 rdr7(void) 273 { 274 uint64_t data; 275 __asm __volatile("movq %%dr7,%0" : "=r" (data)); 276 return (data); 277 } 278 279 static __inline void 280 load_dr7(uint64_t dr7) 281 { 282 __asm __volatile("movq %0,%%dr7" : : "r" (dr7)); 283 } 284 285 #ifdef _KERNEL 286 /* 287 * Including the native sys/segments.h in userspace seriously conflicts with 288 * the FreeBSD compat/contrib headers. 289 */ 290 #include <sys/segments.h> 291 292 static __inline void 293 lldt(u_short sel) 294 { 295 wr_ldtr(sel); 296 } 297 298 static __inline u_short 299 sldt() 300 { 301 return (rd_ldtr()); 302 } 303 #endif /* _KERNEL */ 304 305 #endif /* _COMPAT_FREEBSD_AMD64_MACHINE_CPUFUNC_H_ */ 306