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