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