xref: /illumos-gate/usr/src/compat/bhyve/amd64/machine/cpufunc.h (revision a92282e44f968185a6bba094d1e5fece2da819cf)
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