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
21static __inline u_long
22bsfq(u_long mask)
23{
24	u_long	result;
25
26	__asm __volatile("bsfq %1,%0" : "=r" (result) : "rm" (mask));
27	return (result);
28}
29
30static __inline u_int
31bsrl(u_int mask)
32{
33	u_int	result;
34
35	__asm __volatile("bsrl %1,%0" : "=r" (result) : "rm" (mask));
36	return (result);
37}
38
39static __inline u_long
40bsrq(u_long mask)
41{
42	u_long	result;
43
44	__asm __volatile("bsrq %1,%0" : "=r" (result) : "rm" (mask));
45	return (result);
46}
47
48static __inline void
49clts(void)
50{
51	__asm __volatile("clts");
52}
53
54static __inline void
55do_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
62static __inline void
63cpuid_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
70static __inline void
71disable_intr(void)
72{
73	__asm __volatile("cli");
74}
75
76static __inline void
77enable_intr(void)
78{
79	__asm __volatile("sti");
80}
81
82static __inline int
83ffsl(long mask)
84{
85	return (mask == 0 ? mask : (int)bsfq((u_long)mask) + 1);
86}
87
88static __inline int
89fls(int mask)
90{
91	return (mask == 0 ? mask : (int)bsrl((u_int)mask) + 1);
92}
93
94static __inline int
95flsl(long mask)
96{
97	return (mask == 0 ? mask : (int)bsrq((u_long)mask) + 1);
98}
99
100static __inline int
101flsll(long long mask)
102{
103	return (flsl((long)mask));
104}
105
106static __inline u_long
107read_rflags(void)
108{
109	u_long  rf;
110
111	__asm __volatile("pushfq; popq %0" : "=r" (rf));
112	return (rf);
113}
114
115static __inline uint64_t
116rdmsr(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
124static __inline uint64_t
125rdtsc(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
133static __inline void
134wrmsr(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
143static __inline void
144load_cr0(u_long data)
145{
146	__asm __volatile("movq %0,%%cr0" : : "r" (data));
147}
148
149static __inline u_long
150rcr0(void)
151{
152	u_long  data;
153
154	__asm __volatile("movq %%cr0,%0" : "=r" (data));
155	return (data);
156}
157
158static __inline u_long
159rcr3(void)
160{
161	u_long  data;
162
163	__asm __volatile("movq %%cr3,%0" : "=r" (data));
164	return (data);
165}
166
167static __inline void
168load_cr4(u_long data)
169{
170	__asm __volatile("movq %0,%%cr4" : : "r" (data));
171}
172
173static __inline u_long
174rcr4(void)
175{
176	u_long  data;
177
178	__asm __volatile("movq %%cr4,%0" : "=r" (data));
179	return (data);
180}
181
182static __inline u_long
183rxcr(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
191static __inline void
192load_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
201static __inline void
202write_rflags(u_long rf)
203{
204	__asm __volatile("pushq %0;  popfq" : : "r" (rf));
205}
206
207static __inline uint64_t
208rdr0(void)
209{
210	uint64_t data;
211	__asm __volatile("movq %%dr0,%0" : "=r" (data));
212	return (data);
213}
214
215static __inline void
216load_dr0(uint64_t dr0)
217{
218	__asm __volatile("movq %0,%%dr0" : : "r" (dr0));
219}
220
221static __inline uint64_t
222rdr1(void)
223{
224	uint64_t data;
225	__asm __volatile("movq %%dr1,%0" : "=r" (data));
226	return (data);
227}
228
229static __inline void
230load_dr1(uint64_t dr1)
231{
232	__asm __volatile("movq %0,%%dr1" : : "r" (dr1));
233}
234
235static __inline uint64_t
236rdr2(void)
237{
238	uint64_t data;
239	__asm __volatile("movq %%dr2,%0" : "=r" (data));
240	return (data);
241}
242
243static __inline void
244load_dr2(uint64_t dr2)
245{
246	__asm __volatile("movq %0,%%dr2" : : "r" (dr2));
247}
248
249static __inline uint64_t
250rdr3(void)
251{
252	uint64_t data;
253	__asm __volatile("movq %%dr3,%0" : "=r" (data));
254	return (data);
255}
256
257static __inline void
258load_dr3(uint64_t dr3)
259{
260	__asm __volatile("movq %0,%%dr3" : : "r" (dr3));
261}
262
263static __inline uint64_t
264rdr6(void)
265{
266	uint64_t data;
267	__asm __volatile("movq %%dr6,%0" : "=r" (data));
268	return (data);
269}
270
271static __inline void
272load_dr6(uint64_t dr6)
273{
274	__asm __volatile("movq %0,%%dr6" : : "r" (dr6));
275}
276
277static __inline uint64_t
278rdr7(void)
279{
280	uint64_t data;
281	__asm __volatile("movq %%dr7,%0" : "=r" (data));
282	return (data);
283}
284
285static __inline void
286load_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
298static __inline void
299lldt(u_short sel)
300{
301	wr_ldtr(sel);
302}
303
304static __inline u_short
305sldt()
306{
307	return (rd_ldtr());
308}
309#endif /* _KERNEL */
310
311#endif	/* _COMPAT_FREEBSD_AMD64_MACHINE_CPUFUNC_H_ */
312