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
bsfq(u_long mask)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
bsrl(u_int mask)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
bsrq(u_long mask)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
clts(void)49 clts(void)
50 {
51 __asm __volatile("clts");
52 }
53
54 static __inline void
do_cpuid(u_int ax,u_int * p)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
cpuid_count(u_int ax,u_int cx,u_int * p)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
disable_intr(void)71 disable_intr(void)
72 {
73 __asm __volatile("cli");
74 }
75
76 static __inline void
enable_intr(void)77 enable_intr(void)
78 {
79 __asm __volatile("sti");
80 }
81
82 static __inline int
ffsl(long mask)83 ffsl(long mask)
84 {
85 return (mask == 0 ? mask : (int)bsfq((u_long)mask) + 1);
86 }
87
88 static __inline int
fls(int mask)89 fls(int mask)
90 {
91 return (mask == 0 ? mask : (int)bsrl((u_int)mask) + 1);
92 }
93
94 static __inline int
flsl(long mask)95 flsl(long mask)
96 {
97 return (mask == 0 ? mask : (int)bsrq((u_long)mask) + 1);
98 }
99
100 static __inline int
flsll(long long mask)101 flsll(long long mask)
102 {
103 return (flsl((long)mask));
104 }
105
106 static __inline u_long
read_rflags(void)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
rdmsr(u_int msr)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
wrmsr(u_int msr,uint64_t newval)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
load_cr0(u_long data)138 load_cr0(u_long data)
139 {
140 __asm __volatile("movq %0,%%cr0" : : "r" (data));
141 }
142
143 static __inline u_long
rcr0(void)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
rcr3(void)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
load_cr4(u_long data)162 load_cr4(u_long data)
163 {
164 __asm __volatile("movq %0,%%cr4" : : "r" (data));
165 }
166
167 static __inline u_long
rcr4(void)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
rxcr(u_int reg)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
load_xcr(u_int reg,u_long val)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
write_rflags(u_long rf)196 write_rflags(u_long rf)
197 {
198 __asm __volatile("pushq %0; popfq" : : "r" (rf));
199 }
200
201 static __inline uint64_t
rdr0(void)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
load_dr0(uint64_t dr0)210 load_dr0(uint64_t dr0)
211 {
212 __asm __volatile("movq %0,%%dr0" : : "r" (dr0));
213 }
214
215 static __inline uint64_t
rdr1(void)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
load_dr1(uint64_t dr1)224 load_dr1(uint64_t dr1)
225 {
226 __asm __volatile("movq %0,%%dr1" : : "r" (dr1));
227 }
228
229 static __inline uint64_t
rdr2(void)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
load_dr2(uint64_t dr2)238 load_dr2(uint64_t dr2)
239 {
240 __asm __volatile("movq %0,%%dr2" : : "r" (dr2));
241 }
242
243 static __inline uint64_t
rdr3(void)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
load_dr3(uint64_t dr3)252 load_dr3(uint64_t dr3)
253 {
254 __asm __volatile("movq %0,%%dr3" : : "r" (dr3));
255 }
256
257 static __inline uint64_t
rdr6(void)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
load_dr6(uint64_t dr6)266 load_dr6(uint64_t dr6)
267 {
268 __asm __volatile("movq %0,%%dr6" : : "r" (dr6));
269 }
270
271 static __inline uint64_t
rdr7(void)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
load_dr7(uint64_t dr7)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
lldt(u_short sel)293 lldt(u_short sel)
294 {
295 wr_ldtr(sel);
296 }
297
298 static __inline u_short
sldt()299 sldt()
300 {
301 return (rd_ldtr());
302 }
303 #endif /* _KERNEL */
304
305 #endif /* _COMPAT_FREEBSD_AMD64_MACHINE_CPUFUNC_H_ */
306