cpufunc.h revision 282274
1/*-
2 * Copyright (c) 1993 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 4. Neither the name of the University nor the names of its contributors
14 *    may be used to endorse or promote products derived from this software
15 *    without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * $FreeBSD: head/sys/i386/include/cpufunc.h 282274 2015-04-30 15:48:48Z jhb $
30 */
31
32/*
33 * Functions to provide access to special i386 instructions.
34 * This in included in sys/systm.h, and that file should be
35 * used in preference to this.
36 */
37
38#ifndef _MACHINE_CPUFUNC_H_
39#define	_MACHINE_CPUFUNC_H_
40
41#ifndef _SYS_CDEFS_H_
42#error this file needs sys/cdefs.h as a prerequisite
43#endif
44
45struct region_descriptor;
46
47#define readb(va)	(*(volatile uint8_t *) (va))
48#define readw(va)	(*(volatile uint16_t *) (va))
49#define readl(va)	(*(volatile uint32_t *) (va))
50
51#define writeb(va, d)	(*(volatile uint8_t *) (va) = (d))
52#define writew(va, d)	(*(volatile uint16_t *) (va) = (d))
53#define writel(va, d)	(*(volatile uint32_t *) (va) = (d))
54
55#if defined(__GNUCLIKE_ASM) && defined(__CC_SUPPORTS___INLINE)
56
57static __inline void
58breakpoint(void)
59{
60	__asm __volatile("int $3");
61}
62
63static __inline u_int
64bsfl(u_int mask)
65{
66	u_int	result;
67
68	__asm("bsfl %1,%0" : "=r" (result) : "rm" (mask) : "cc");
69	return (result);
70}
71
72static __inline u_int
73bsrl(u_int mask)
74{
75	u_int	result;
76
77	__asm("bsrl %1,%0" : "=r" (result) : "rm" (mask) : "cc");
78	return (result);
79}
80
81static __inline void
82clflush(u_long addr)
83{
84
85	__asm __volatile("clflush %0" : : "m" (*(char *)addr));
86}
87
88static __inline void
89clts(void)
90{
91
92	__asm __volatile("clts");
93}
94
95static __inline void
96disable_intr(void)
97{
98
99	__asm __volatile("cli" : : : "memory");
100}
101
102static __inline void
103do_cpuid(u_int ax, u_int *p)
104{
105	__asm __volatile("cpuid"
106			 : "=a" (p[0]), "=b" (p[1]), "=c" (p[2]), "=d" (p[3])
107			 :  "0" (ax));
108}
109
110static __inline void
111cpuid_count(u_int ax, u_int cx, u_int *p)
112{
113	__asm __volatile("cpuid"
114			 : "=a" (p[0]), "=b" (p[1]), "=c" (p[2]), "=d" (p[3])
115			 :  "0" (ax), "c" (cx));
116}
117
118static __inline void
119enable_intr(void)
120{
121
122	__asm __volatile("sti");
123}
124
125static __inline void
126cpu_monitor(const void *addr, u_long extensions, u_int hints)
127{
128
129	__asm __volatile("monitor"
130	    : : "a" (addr), "c" (extensions), "d" (hints));
131}
132
133static __inline void
134cpu_mwait(u_long extensions, u_int hints)
135{
136
137	__asm __volatile("mwait" : : "a" (hints), "c" (extensions));
138}
139
140static __inline void
141lfence(void)
142{
143
144	__asm __volatile("lfence" : : : "memory");
145}
146
147static __inline void
148mfence(void)
149{
150
151	__asm __volatile("mfence" : : : "memory");
152}
153
154#ifdef _KERNEL
155
156#define	HAVE_INLINE_FFS
157
158static __inline int
159ffs(int mask)
160{
161	/*
162	 * Note that gcc-2's builtin ffs would be used if we didn't declare
163	 * this inline or turn off the builtin.  The builtin is faster but
164	 * broken in gcc-2.4.5 and slower but working in gcc-2.5 and later
165	 * versions.
166	 */
167	 return (mask == 0 ? mask : (int)bsfl((u_int)mask) + 1);
168}
169
170#define	HAVE_INLINE_FFSL
171
172static __inline int
173ffsl(long mask)
174{
175	return (ffs((int)mask));
176}
177
178#define	HAVE_INLINE_FLS
179
180static __inline int
181fls(int mask)
182{
183	return (mask == 0 ? mask : (int)bsrl((u_int)mask) + 1);
184}
185
186#define	HAVE_INLINE_FLSL
187
188static __inline int
189flsl(long mask)
190{
191	return (fls((int)mask));
192}
193
194#endif /* _KERNEL */
195
196static __inline void
197halt(void)
198{
199	__asm __volatile("hlt");
200}
201
202static __inline u_char
203inb(u_int port)
204{
205	u_char	data;
206
207	__asm __volatile("inb %w1, %0" : "=a" (data) : "Nd" (port));
208	return (data);
209}
210
211static __inline u_int
212inl(u_int port)
213{
214	u_int	data;
215
216	__asm __volatile("inl %w1, %0" : "=a" (data) : "Nd" (port));
217	return (data);
218}
219
220static __inline void
221insb(u_int port, void *addr, size_t count)
222{
223	__asm __volatile("cld; rep; insb"
224			 : "+D" (addr), "+c" (count)
225			 : "d" (port)
226			 : "memory");
227}
228
229static __inline void
230insw(u_int port, void *addr, size_t count)
231{
232	__asm __volatile("cld; rep; insw"
233			 : "+D" (addr), "+c" (count)
234			 : "d" (port)
235			 : "memory");
236}
237
238static __inline void
239insl(u_int port, void *addr, size_t count)
240{
241	__asm __volatile("cld; rep; insl"
242			 : "+D" (addr), "+c" (count)
243			 : "d" (port)
244			 : "memory");
245}
246
247static __inline void
248invd(void)
249{
250	__asm __volatile("invd");
251}
252
253static __inline u_short
254inw(u_int port)
255{
256	u_short	data;
257
258	__asm __volatile("inw %w1, %0" : "=a" (data) : "Nd" (port));
259	return (data);
260}
261
262static __inline void
263outb(u_int port, u_char data)
264{
265	__asm __volatile("outb %0, %w1" : : "a" (data), "Nd" (port));
266}
267
268static __inline void
269outl(u_int port, u_int data)
270{
271	__asm __volatile("outl %0, %w1" : : "a" (data), "Nd" (port));
272}
273
274static __inline void
275outsb(u_int port, const void *addr, size_t count)
276{
277	__asm __volatile("cld; rep; outsb"
278			 : "+S" (addr), "+c" (count)
279			 : "d" (port));
280}
281
282static __inline void
283outsw(u_int port, const void *addr, size_t count)
284{
285	__asm __volatile("cld; rep; outsw"
286			 : "+S" (addr), "+c" (count)
287			 : "d" (port));
288}
289
290static __inline void
291outsl(u_int port, const void *addr, size_t count)
292{
293	__asm __volatile("cld; rep; outsl"
294			 : "+S" (addr), "+c" (count)
295			 : "d" (port));
296}
297
298static __inline void
299outw(u_int port, u_short data)
300{
301	__asm __volatile("outw %0, %w1" : : "a" (data), "Nd" (port));
302}
303
304static __inline void
305ia32_pause(void)
306{
307	__asm __volatile("pause");
308}
309
310static __inline u_int
311read_eflags(void)
312{
313	u_int	ef;
314
315	__asm __volatile("pushfl; popl %0" : "=r" (ef));
316	return (ef);
317}
318
319static __inline uint64_t
320rdmsr(u_int msr)
321{
322	uint64_t rv;
323
324	__asm __volatile("rdmsr" : "=A" (rv) : "c" (msr));
325	return (rv);
326}
327
328static __inline uint32_t
329rdmsr32(u_int msr)
330{
331	uint32_t low;
332
333	__asm __volatile("rdmsr" : "=a" (low) : "c" (msr) : "edx");
334	return (low);
335}
336
337static __inline uint64_t
338rdpmc(u_int pmc)
339{
340	uint64_t rv;
341
342	__asm __volatile("rdpmc" : "=A" (rv) : "c" (pmc));
343	return (rv);
344}
345
346static __inline uint64_t
347rdtsc(void)
348{
349	uint64_t rv;
350
351	__asm __volatile("rdtsc" : "=A" (rv));
352	return (rv);
353}
354
355static __inline uint32_t
356rdtsc32(void)
357{
358	uint32_t rv;
359
360	__asm __volatile("rdtsc" : "=a" (rv) : : "edx");
361	return (rv);
362}
363
364static __inline void
365wbinvd(void)
366{
367	__asm __volatile("wbinvd");
368}
369
370static __inline void
371write_eflags(u_int ef)
372{
373	__asm __volatile("pushl %0; popfl" : : "r" (ef));
374}
375
376static __inline void
377wrmsr(u_int msr, uint64_t newval)
378{
379	__asm __volatile("wrmsr" : : "A" (newval), "c" (msr));
380}
381
382static __inline void
383load_cr0(u_int data)
384{
385
386	__asm __volatile("movl %0,%%cr0" : : "r" (data));
387}
388
389static __inline u_int
390rcr0(void)
391{
392	u_int	data;
393
394	__asm __volatile("movl %%cr0,%0" : "=r" (data));
395	return (data);
396}
397
398static __inline u_int
399rcr2(void)
400{
401	u_int	data;
402
403	__asm __volatile("movl %%cr2,%0" : "=r" (data));
404	return (data);
405}
406
407static __inline void
408load_cr3(u_int data)
409{
410
411	__asm __volatile("movl %0,%%cr3" : : "r" (data) : "memory");
412}
413
414static __inline u_int
415rcr3(void)
416{
417	u_int	data;
418
419	__asm __volatile("movl %%cr3,%0" : "=r" (data));
420	return (data);
421}
422
423static __inline void
424load_cr4(u_int data)
425{
426	__asm __volatile("movl %0,%%cr4" : : "r" (data));
427}
428
429static __inline u_int
430rcr4(void)
431{
432	u_int	data;
433
434	__asm __volatile("movl %%cr4,%0" : "=r" (data));
435	return (data);
436}
437
438static __inline uint64_t
439rxcr(u_int reg)
440{
441	u_int low, high;
442
443	__asm __volatile("xgetbv" : "=a" (low), "=d" (high) : "c" (reg));
444	return (low | ((uint64_t)high << 32));
445}
446
447static __inline void
448load_xcr(u_int reg, uint64_t val)
449{
450	u_int low, high;
451
452	low = val;
453	high = val >> 32;
454	__asm __volatile("xsetbv" : : "c" (reg), "a" (low), "d" (high));
455}
456
457/*
458 * Global TLB flush (except for thise for pages marked PG_G)
459 */
460static __inline void
461invltlb(void)
462{
463
464	load_cr3(rcr3());
465}
466
467/*
468 * TLB flush for an individual page (even if it has PG_G).
469 * Only works on 486+ CPUs (i386 does not have PG_G).
470 */
471static __inline void
472invlpg(u_int addr)
473{
474
475	__asm __volatile("invlpg %0" : : "m" (*(char *)addr) : "memory");
476}
477
478static __inline u_short
479rfs(void)
480{
481	u_short sel;
482	__asm __volatile("movw %%fs,%0" : "=rm" (sel));
483	return (sel);
484}
485
486static __inline uint64_t
487rgdt(void)
488{
489	uint64_t gdtr;
490	__asm __volatile("sgdt %0" : "=m" (gdtr));
491	return (gdtr);
492}
493
494static __inline u_short
495rgs(void)
496{
497	u_short sel;
498	__asm __volatile("movw %%gs,%0" : "=rm" (sel));
499	return (sel);
500}
501
502static __inline uint64_t
503ridt(void)
504{
505	uint64_t idtr;
506	__asm __volatile("sidt %0" : "=m" (idtr));
507	return (idtr);
508}
509
510static __inline u_short
511rldt(void)
512{
513	u_short ldtr;
514	__asm __volatile("sldt %0" : "=g" (ldtr));
515	return (ldtr);
516}
517
518static __inline u_short
519rss(void)
520{
521	u_short sel;
522	__asm __volatile("movw %%ss,%0" : "=rm" (sel));
523	return (sel);
524}
525
526static __inline u_short
527rtr(void)
528{
529	u_short tr;
530	__asm __volatile("str %0" : "=g" (tr));
531	return (tr);
532}
533
534static __inline void
535load_fs(u_short sel)
536{
537	__asm __volatile("movw %0,%%fs" : : "rm" (sel));
538}
539
540static __inline void
541load_gs(u_short sel)
542{
543	__asm __volatile("movw %0,%%gs" : : "rm" (sel));
544}
545
546static __inline void
547lidt(struct region_descriptor *addr)
548{
549	__asm __volatile("lidt (%0)" : : "r" (addr));
550}
551
552static __inline void
553lldt(u_short sel)
554{
555	__asm __volatile("lldt %0" : : "r" (sel));
556}
557
558static __inline void
559ltr(u_short sel)
560{
561	__asm __volatile("ltr %0" : : "r" (sel));
562}
563
564static __inline u_int
565rdr0(void)
566{
567	u_int	data;
568	__asm __volatile("movl %%dr0,%0" : "=r" (data));
569	return (data);
570}
571
572static __inline void
573load_dr0(u_int dr0)
574{
575	__asm __volatile("movl %0,%%dr0" : : "r" (dr0));
576}
577
578static __inline u_int
579rdr1(void)
580{
581	u_int	data;
582	__asm __volatile("movl %%dr1,%0" : "=r" (data));
583	return (data);
584}
585
586static __inline void
587load_dr1(u_int dr1)
588{
589	__asm __volatile("movl %0,%%dr1" : : "r" (dr1));
590}
591
592static __inline u_int
593rdr2(void)
594{
595	u_int	data;
596	__asm __volatile("movl %%dr2,%0" : "=r" (data));
597	return (data);
598}
599
600static __inline void
601load_dr2(u_int dr2)
602{
603	__asm __volatile("movl %0,%%dr2" : : "r" (dr2));
604}
605
606static __inline u_int
607rdr3(void)
608{
609	u_int	data;
610	__asm __volatile("movl %%dr3,%0" : "=r" (data));
611	return (data);
612}
613
614static __inline void
615load_dr3(u_int dr3)
616{
617	__asm __volatile("movl %0,%%dr3" : : "r" (dr3));
618}
619
620static __inline u_int
621rdr4(void)
622{
623	u_int	data;
624	__asm __volatile("movl %%dr4,%0" : "=r" (data));
625	return (data);
626}
627
628static __inline void
629load_dr4(u_int dr4)
630{
631	__asm __volatile("movl %0,%%dr4" : : "r" (dr4));
632}
633
634static __inline u_int
635rdr5(void)
636{
637	u_int	data;
638	__asm __volatile("movl %%dr5,%0" : "=r" (data));
639	return (data);
640}
641
642static __inline void
643load_dr5(u_int dr5)
644{
645	__asm __volatile("movl %0,%%dr5" : : "r" (dr5));
646}
647
648static __inline u_int
649rdr6(void)
650{
651	u_int	data;
652	__asm __volatile("movl %%dr6,%0" : "=r" (data));
653	return (data);
654}
655
656static __inline void
657load_dr6(u_int dr6)
658{
659	__asm __volatile("movl %0,%%dr6" : : "r" (dr6));
660}
661
662static __inline u_int
663rdr7(void)
664{
665	u_int	data;
666	__asm __volatile("movl %%dr7,%0" : "=r" (data));
667	return (data);
668}
669
670static __inline void
671load_dr7(u_int dr7)
672{
673	__asm __volatile("movl %0,%%dr7" : : "r" (dr7));
674}
675
676static __inline u_char
677read_cyrix_reg(u_char reg)
678{
679	outb(0x22, reg);
680	return inb(0x23);
681}
682
683static __inline void
684write_cyrix_reg(u_char reg, u_char data)
685{
686	outb(0x22, reg);
687	outb(0x23, data);
688}
689
690static __inline register_t
691intr_disable(void)
692{
693	register_t eflags;
694
695	eflags = read_eflags();
696	disable_intr();
697	return (eflags);
698}
699
700static __inline void
701intr_restore(register_t eflags)
702{
703	write_eflags(eflags);
704}
705
706#else /* !(__GNUCLIKE_ASM && __CC_SUPPORTS___INLINE) */
707
708int	breakpoint(void);
709u_int	bsfl(u_int mask);
710u_int	bsrl(u_int mask);
711void	clflush(u_long addr);
712void	clts(void);
713void	cpuid_count(u_int ax, u_int cx, u_int *p);
714void	disable_intr(void);
715void	do_cpuid(u_int ax, u_int *p);
716void	enable_intr(void);
717void	halt(void);
718void	ia32_pause(void);
719u_char	inb(u_int port);
720u_int	inl(u_int port);
721void	insb(u_int port, void *addr, size_t count);
722void	insl(u_int port, void *addr, size_t count);
723void	insw(u_int port, void *addr, size_t count);
724register_t	intr_disable(void);
725void	intr_restore(register_t ef);
726void	invd(void);
727void	invlpg(u_int addr);
728void	invltlb(void);
729u_short	inw(u_int port);
730void	lidt(struct region_descriptor *addr);
731void	lldt(u_short sel);
732void	load_cr0(u_int cr0);
733void	load_cr3(u_int cr3);
734void	load_cr4(u_int cr4);
735void	load_dr0(u_int dr0);
736void	load_dr1(u_int dr1);
737void	load_dr2(u_int dr2);
738void	load_dr3(u_int dr3);
739void	load_dr4(u_int dr4);
740void	load_dr5(u_int dr5);
741void	load_dr6(u_int dr6);
742void	load_dr7(u_int dr7);
743void	load_fs(u_short sel);
744void	load_gs(u_short sel);
745void	ltr(u_short sel);
746void	outb(u_int port, u_char data);
747void	outl(u_int port, u_int data);
748void	outsb(u_int port, const void *addr, size_t count);
749void	outsl(u_int port, const void *addr, size_t count);
750void	outsw(u_int port, const void *addr, size_t count);
751void	outw(u_int port, u_short data);
752u_int	rcr0(void);
753u_int	rcr2(void);
754u_int	rcr3(void);
755u_int	rcr4(void);
756uint64_t rdmsr(u_int msr);
757uint64_t rdpmc(u_int pmc);
758u_int	rdr0(void);
759u_int	rdr1(void);
760u_int	rdr2(void);
761u_int	rdr3(void);
762u_int	rdr4(void);
763u_int	rdr5(void);
764u_int	rdr6(void);
765u_int	rdr7(void);
766uint64_t rdtsc(void);
767u_char	read_cyrix_reg(u_char reg);
768u_int	read_eflags(void);
769u_int	rfs(void);
770uint64_t rgdt(void);
771u_int	rgs(void);
772uint64_t ridt(void);
773u_short	rldt(void);
774u_short	rtr(void);
775void	wbinvd(void);
776void	write_cyrix_reg(u_char reg, u_char data);
777void	write_eflags(u_int ef);
778void	wrmsr(u_int msr, uint64_t newval);
779
780#endif	/* __GNUCLIKE_ASM && __CC_SUPPORTS___INLINE */
781
782void    reset_dbregs(void);
783
784#ifdef _KERNEL
785int	rdmsr_safe(u_int msr, uint64_t *val);
786int	wrmsr_safe(u_int msr, uint64_t newval);
787#endif
788
789#endif /* !_MACHINE_CPUFUNC_H_ */
790