cpufunc.h revision 290188
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 290188 2015-10-30 09:53:33Z kib $
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
89clflushopt(u_long addr)
90{
91
92	__asm __volatile(".byte 0x66;clflush %0" : : "m" (*(char *)addr));
93}
94
95static __inline void
96clts(void)
97{
98
99	__asm __volatile("clts");
100}
101
102static __inline void
103disable_intr(void)
104{
105
106	__asm __volatile("cli" : : : "memory");
107}
108
109static __inline void
110do_cpuid(u_int ax, u_int *p)
111{
112	__asm __volatile("cpuid"
113			 : "=a" (p[0]), "=b" (p[1]), "=c" (p[2]), "=d" (p[3])
114			 :  "0" (ax));
115}
116
117static __inline void
118cpuid_count(u_int ax, u_int cx, u_int *p)
119{
120	__asm __volatile("cpuid"
121			 : "=a" (p[0]), "=b" (p[1]), "=c" (p[2]), "=d" (p[3])
122			 :  "0" (ax), "c" (cx));
123}
124
125static __inline void
126enable_intr(void)
127{
128
129	__asm __volatile("sti");
130}
131
132static __inline void
133cpu_monitor(const void *addr, u_long extensions, u_int hints)
134{
135
136	__asm __volatile("monitor"
137	    : : "a" (addr), "c" (extensions), "d" (hints));
138}
139
140static __inline void
141cpu_mwait(u_long extensions, u_int hints)
142{
143
144	__asm __volatile("mwait" : : "a" (hints), "c" (extensions));
145}
146
147static __inline void
148lfence(void)
149{
150
151	__asm __volatile("lfence" : : : "memory");
152}
153
154static __inline void
155mfence(void)
156{
157
158	__asm __volatile("mfence" : : : "memory");
159}
160
161#ifdef _KERNEL
162
163#define	HAVE_INLINE_FFS
164
165static __inline int
166ffs(int mask)
167{
168	/*
169	 * Note that gcc-2's builtin ffs would be used if we didn't declare
170	 * this inline or turn off the builtin.  The builtin is faster but
171	 * broken in gcc-2.4.5 and slower but working in gcc-2.5 and later
172	 * versions.
173	 */
174	 return (mask == 0 ? mask : (int)bsfl((u_int)mask) + 1);
175}
176
177#define	HAVE_INLINE_FFSL
178
179static __inline int
180ffsl(long mask)
181{
182	return (ffs((int)mask));
183}
184
185#define	HAVE_INLINE_FLS
186
187static __inline int
188fls(int mask)
189{
190	return (mask == 0 ? mask : (int)bsrl((u_int)mask) + 1);
191}
192
193#define	HAVE_INLINE_FLSL
194
195static __inline int
196flsl(long mask)
197{
198	return (fls((int)mask));
199}
200
201#endif /* _KERNEL */
202
203static __inline void
204halt(void)
205{
206	__asm __volatile("hlt");
207}
208
209static __inline u_char
210inb(u_int port)
211{
212	u_char	data;
213
214	__asm __volatile("inb %w1, %0" : "=a" (data) : "Nd" (port));
215	return (data);
216}
217
218static __inline u_int
219inl(u_int port)
220{
221	u_int	data;
222
223	__asm __volatile("inl %w1, %0" : "=a" (data) : "Nd" (port));
224	return (data);
225}
226
227static __inline void
228insb(u_int port, void *addr, size_t count)
229{
230	__asm __volatile("cld; rep; insb"
231			 : "+D" (addr), "+c" (count)
232			 : "d" (port)
233			 : "memory");
234}
235
236static __inline void
237insw(u_int port, void *addr, size_t count)
238{
239	__asm __volatile("cld; rep; insw"
240			 : "+D" (addr), "+c" (count)
241			 : "d" (port)
242			 : "memory");
243}
244
245static __inline void
246insl(u_int port, void *addr, size_t count)
247{
248	__asm __volatile("cld; rep; insl"
249			 : "+D" (addr), "+c" (count)
250			 : "d" (port)
251			 : "memory");
252}
253
254static __inline void
255invd(void)
256{
257	__asm __volatile("invd");
258}
259
260static __inline u_short
261inw(u_int port)
262{
263	u_short	data;
264
265	__asm __volatile("inw %w1, %0" : "=a" (data) : "Nd" (port));
266	return (data);
267}
268
269static __inline void
270outb(u_int port, u_char data)
271{
272	__asm __volatile("outb %0, %w1" : : "a" (data), "Nd" (port));
273}
274
275static __inline void
276outl(u_int port, u_int data)
277{
278	__asm __volatile("outl %0, %w1" : : "a" (data), "Nd" (port));
279}
280
281static __inline void
282outsb(u_int port, const void *addr, size_t count)
283{
284	__asm __volatile("cld; rep; outsb"
285			 : "+S" (addr), "+c" (count)
286			 : "d" (port));
287}
288
289static __inline void
290outsw(u_int port, const void *addr, size_t count)
291{
292	__asm __volatile("cld; rep; outsw"
293			 : "+S" (addr), "+c" (count)
294			 : "d" (port));
295}
296
297static __inline void
298outsl(u_int port, const void *addr, size_t count)
299{
300	__asm __volatile("cld; rep; outsl"
301			 : "+S" (addr), "+c" (count)
302			 : "d" (port));
303}
304
305static __inline void
306outw(u_int port, u_short data)
307{
308	__asm __volatile("outw %0, %w1" : : "a" (data), "Nd" (port));
309}
310
311static __inline void
312ia32_pause(void)
313{
314	__asm __volatile("pause");
315}
316
317static __inline u_int
318read_eflags(void)
319{
320	u_int	ef;
321
322	__asm __volatile("pushfl; popl %0" : "=r" (ef));
323	return (ef);
324}
325
326static __inline uint64_t
327rdmsr(u_int msr)
328{
329	uint64_t rv;
330
331	__asm __volatile("rdmsr" : "=A" (rv) : "c" (msr));
332	return (rv);
333}
334
335static __inline uint32_t
336rdmsr32(u_int msr)
337{
338	uint32_t low;
339
340	__asm __volatile("rdmsr" : "=a" (low) : "c" (msr) : "edx");
341	return (low);
342}
343
344static __inline uint64_t
345rdpmc(u_int pmc)
346{
347	uint64_t rv;
348
349	__asm __volatile("rdpmc" : "=A" (rv) : "c" (pmc));
350	return (rv);
351}
352
353static __inline uint64_t
354rdtsc(void)
355{
356	uint64_t rv;
357
358	__asm __volatile("rdtsc" : "=A" (rv));
359	return (rv);
360}
361
362static __inline uint32_t
363rdtsc32(void)
364{
365	uint32_t rv;
366
367	__asm __volatile("rdtsc" : "=a" (rv) : : "edx");
368	return (rv);
369}
370
371static __inline void
372wbinvd(void)
373{
374	__asm __volatile("wbinvd");
375}
376
377static __inline void
378write_eflags(u_int ef)
379{
380	__asm __volatile("pushl %0; popfl" : : "r" (ef));
381}
382
383static __inline void
384wrmsr(u_int msr, uint64_t newval)
385{
386	__asm __volatile("wrmsr" : : "A" (newval), "c" (msr));
387}
388
389static __inline void
390load_cr0(u_int data)
391{
392
393	__asm __volatile("movl %0,%%cr0" : : "r" (data));
394}
395
396static __inline u_int
397rcr0(void)
398{
399	u_int	data;
400
401	__asm __volatile("movl %%cr0,%0" : "=r" (data));
402	return (data);
403}
404
405static __inline u_int
406rcr2(void)
407{
408	u_int	data;
409
410	__asm __volatile("movl %%cr2,%0" : "=r" (data));
411	return (data);
412}
413
414static __inline void
415load_cr3(u_int data)
416{
417
418	__asm __volatile("movl %0,%%cr3" : : "r" (data) : "memory");
419}
420
421static __inline u_int
422rcr3(void)
423{
424	u_int	data;
425
426	__asm __volatile("movl %%cr3,%0" : "=r" (data));
427	return (data);
428}
429
430static __inline void
431load_cr4(u_int data)
432{
433	__asm __volatile("movl %0,%%cr4" : : "r" (data));
434}
435
436static __inline u_int
437rcr4(void)
438{
439	u_int	data;
440
441	__asm __volatile("movl %%cr4,%0" : "=r" (data));
442	return (data);
443}
444
445static __inline uint64_t
446rxcr(u_int reg)
447{
448	u_int low, high;
449
450	__asm __volatile("xgetbv" : "=a" (low), "=d" (high) : "c" (reg));
451	return (low | ((uint64_t)high << 32));
452}
453
454static __inline void
455load_xcr(u_int reg, uint64_t val)
456{
457	u_int low, high;
458
459	low = val;
460	high = val >> 32;
461	__asm __volatile("xsetbv" : : "c" (reg), "a" (low), "d" (high));
462}
463
464/*
465 * Global TLB flush (except for thise for pages marked PG_G)
466 */
467static __inline void
468invltlb(void)
469{
470
471	load_cr3(rcr3());
472}
473
474/*
475 * TLB flush for an individual page (even if it has PG_G).
476 * Only works on 486+ CPUs (i386 does not have PG_G).
477 */
478static __inline void
479invlpg(u_int addr)
480{
481
482	__asm __volatile("invlpg %0" : : "m" (*(char *)addr) : "memory");
483}
484
485static __inline u_short
486rfs(void)
487{
488	u_short sel;
489	__asm __volatile("movw %%fs,%0" : "=rm" (sel));
490	return (sel);
491}
492
493static __inline uint64_t
494rgdt(void)
495{
496	uint64_t gdtr;
497	__asm __volatile("sgdt %0" : "=m" (gdtr));
498	return (gdtr);
499}
500
501static __inline u_short
502rgs(void)
503{
504	u_short sel;
505	__asm __volatile("movw %%gs,%0" : "=rm" (sel));
506	return (sel);
507}
508
509static __inline uint64_t
510ridt(void)
511{
512	uint64_t idtr;
513	__asm __volatile("sidt %0" : "=m" (idtr));
514	return (idtr);
515}
516
517static __inline u_short
518rldt(void)
519{
520	u_short ldtr;
521	__asm __volatile("sldt %0" : "=g" (ldtr));
522	return (ldtr);
523}
524
525static __inline u_short
526rss(void)
527{
528	u_short sel;
529	__asm __volatile("movw %%ss,%0" : "=rm" (sel));
530	return (sel);
531}
532
533static __inline u_short
534rtr(void)
535{
536	u_short tr;
537	__asm __volatile("str %0" : "=g" (tr));
538	return (tr);
539}
540
541static __inline void
542load_fs(u_short sel)
543{
544	__asm __volatile("movw %0,%%fs" : : "rm" (sel));
545}
546
547static __inline void
548load_gs(u_short sel)
549{
550	__asm __volatile("movw %0,%%gs" : : "rm" (sel));
551}
552
553static __inline void
554lidt(struct region_descriptor *addr)
555{
556	__asm __volatile("lidt (%0)" : : "r" (addr));
557}
558
559static __inline void
560lldt(u_short sel)
561{
562	__asm __volatile("lldt %0" : : "r" (sel));
563}
564
565static __inline void
566ltr(u_short sel)
567{
568	__asm __volatile("ltr %0" : : "r" (sel));
569}
570
571static __inline u_int
572rdr0(void)
573{
574	u_int	data;
575	__asm __volatile("movl %%dr0,%0" : "=r" (data));
576	return (data);
577}
578
579static __inline void
580load_dr0(u_int dr0)
581{
582	__asm __volatile("movl %0,%%dr0" : : "r" (dr0));
583}
584
585static __inline u_int
586rdr1(void)
587{
588	u_int	data;
589	__asm __volatile("movl %%dr1,%0" : "=r" (data));
590	return (data);
591}
592
593static __inline void
594load_dr1(u_int dr1)
595{
596	__asm __volatile("movl %0,%%dr1" : : "r" (dr1));
597}
598
599static __inline u_int
600rdr2(void)
601{
602	u_int	data;
603	__asm __volatile("movl %%dr2,%0" : "=r" (data));
604	return (data);
605}
606
607static __inline void
608load_dr2(u_int dr2)
609{
610	__asm __volatile("movl %0,%%dr2" : : "r" (dr2));
611}
612
613static __inline u_int
614rdr3(void)
615{
616	u_int	data;
617	__asm __volatile("movl %%dr3,%0" : "=r" (data));
618	return (data);
619}
620
621static __inline void
622load_dr3(u_int dr3)
623{
624	__asm __volatile("movl %0,%%dr3" : : "r" (dr3));
625}
626
627static __inline u_int
628rdr4(void)
629{
630	u_int	data;
631	__asm __volatile("movl %%dr4,%0" : "=r" (data));
632	return (data);
633}
634
635static __inline void
636load_dr4(u_int dr4)
637{
638	__asm __volatile("movl %0,%%dr4" : : "r" (dr4));
639}
640
641static __inline u_int
642rdr5(void)
643{
644	u_int	data;
645	__asm __volatile("movl %%dr5,%0" : "=r" (data));
646	return (data);
647}
648
649static __inline void
650load_dr5(u_int dr5)
651{
652	__asm __volatile("movl %0,%%dr5" : : "r" (dr5));
653}
654
655static __inline u_int
656rdr6(void)
657{
658	u_int	data;
659	__asm __volatile("movl %%dr6,%0" : "=r" (data));
660	return (data);
661}
662
663static __inline void
664load_dr6(u_int dr6)
665{
666	__asm __volatile("movl %0,%%dr6" : : "r" (dr6));
667}
668
669static __inline u_int
670rdr7(void)
671{
672	u_int	data;
673	__asm __volatile("movl %%dr7,%0" : "=r" (data));
674	return (data);
675}
676
677static __inline void
678load_dr7(u_int dr7)
679{
680	__asm __volatile("movl %0,%%dr7" : : "r" (dr7));
681}
682
683static __inline u_char
684read_cyrix_reg(u_char reg)
685{
686	outb(0x22, reg);
687	return inb(0x23);
688}
689
690static __inline void
691write_cyrix_reg(u_char reg, u_char data)
692{
693	outb(0x22, reg);
694	outb(0x23, data);
695}
696
697static __inline register_t
698intr_disable(void)
699{
700	register_t eflags;
701
702	eflags = read_eflags();
703	disable_intr();
704	return (eflags);
705}
706
707static __inline void
708intr_restore(register_t eflags)
709{
710	write_eflags(eflags);
711}
712
713#else /* !(__GNUCLIKE_ASM && __CC_SUPPORTS___INLINE) */
714
715int	breakpoint(void);
716u_int	bsfl(u_int mask);
717u_int	bsrl(u_int mask);
718void	clflush(u_long addr);
719void	clts(void);
720void	cpuid_count(u_int ax, u_int cx, u_int *p);
721void	disable_intr(void);
722void	do_cpuid(u_int ax, u_int *p);
723void	enable_intr(void);
724void	halt(void);
725void	ia32_pause(void);
726u_char	inb(u_int port);
727u_int	inl(u_int port);
728void	insb(u_int port, void *addr, size_t count);
729void	insl(u_int port, void *addr, size_t count);
730void	insw(u_int port, void *addr, size_t count);
731register_t	intr_disable(void);
732void	intr_restore(register_t ef);
733void	invd(void);
734void	invlpg(u_int addr);
735void	invltlb(void);
736u_short	inw(u_int port);
737void	lidt(struct region_descriptor *addr);
738void	lldt(u_short sel);
739void	load_cr0(u_int cr0);
740void	load_cr3(u_int cr3);
741void	load_cr4(u_int cr4);
742void	load_dr0(u_int dr0);
743void	load_dr1(u_int dr1);
744void	load_dr2(u_int dr2);
745void	load_dr3(u_int dr3);
746void	load_dr4(u_int dr4);
747void	load_dr5(u_int dr5);
748void	load_dr6(u_int dr6);
749void	load_dr7(u_int dr7);
750void	load_fs(u_short sel);
751void	load_gs(u_short sel);
752void	ltr(u_short sel);
753void	outb(u_int port, u_char data);
754void	outl(u_int port, u_int data);
755void	outsb(u_int port, const void *addr, size_t count);
756void	outsl(u_int port, const void *addr, size_t count);
757void	outsw(u_int port, const void *addr, size_t count);
758void	outw(u_int port, u_short data);
759u_int	rcr0(void);
760u_int	rcr2(void);
761u_int	rcr3(void);
762u_int	rcr4(void);
763uint64_t rdmsr(u_int msr);
764uint64_t rdpmc(u_int pmc);
765u_int	rdr0(void);
766u_int	rdr1(void);
767u_int	rdr2(void);
768u_int	rdr3(void);
769u_int	rdr4(void);
770u_int	rdr5(void);
771u_int	rdr6(void);
772u_int	rdr7(void);
773uint64_t rdtsc(void);
774u_char	read_cyrix_reg(u_char reg);
775u_int	read_eflags(void);
776u_int	rfs(void);
777uint64_t rgdt(void);
778u_int	rgs(void);
779uint64_t ridt(void);
780u_short	rldt(void);
781u_short	rtr(void);
782void	wbinvd(void);
783void	write_cyrix_reg(u_char reg, u_char data);
784void	write_eflags(u_int ef);
785void	wrmsr(u_int msr, uint64_t newval);
786
787#endif	/* __GNUCLIKE_ASM && __CC_SUPPORTS___INLINE */
788
789void    reset_dbregs(void);
790
791#ifdef _KERNEL
792int	rdmsr_safe(u_int msr, uint64_t *val);
793int	wrmsr_safe(u_int msr, uint64_t newval);
794#endif
795
796#endif /* !_MACHINE_CPUFUNC_H_ */
797