xref: /freebsd/sys/i386/include/cpufunc.h (revision 42821a2fc9aa8656e89d0353ece77c4799e940bb)
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$
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
46 extern void xen_cli(void);
47 extern void xen_sti(void);
48 extern u_int xen_rcr2(void);
49 extern void xen_load_cr3(u_int data);
50 extern void xen_tlb_flush(void);
51 extern void xen_invlpg(u_int addr);
52 extern void write_eflags(u_int eflags);
53 extern u_int read_eflags(void);
54 #endif
55 
56 struct 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 
68 static __inline void
69 breakpoint(void)
70 {
71 	__asm __volatile("int $3");
72 }
73 
74 static __inline u_int
75 bsfl(u_int mask)
76 {
77 	u_int	result;
78 
79 	__asm("bsfl %1,%0" : "=r" (result) : "rm" (mask) : "cc");
80 	return (result);
81 }
82 
83 static __inline u_int
84 bsrl(u_int mask)
85 {
86 	u_int	result;
87 
88 	__asm("bsrl %1,%0" : "=r" (result) : "rm" (mask) : "cc");
89 	return (result);
90 }
91 
92 static __inline void
93 clflush(u_long addr)
94 {
95 
96 	__asm __volatile("clflush %0" : : "m" (*(char *)addr));
97 }
98 
99 static __inline void
100 disable_intr(void)
101 {
102 #ifdef XEN
103 	xen_cli();
104 #else
105 	__asm __volatile("cli" : : : "memory");
106 #endif
107 }
108 
109 static __inline void
110 do_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 
117 static __inline void
118 cpuid_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 
125 static __inline void
126 enable_intr(void)
127 {
128 #ifdef XEN
129 	xen_sti();
130 #else
131 	__asm __volatile("sti");
132 #endif
133 }
134 
135 static __inline void
136 cpu_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 
143 static __inline void
144 cpu_mwait(u_long extensions, u_int hints)
145 {
146 
147 	__asm __volatile("mwait" : : "a" (hints), "c" (extensions));
148 }
149 
150 static __inline void
151 mfence(void)
152 {
153 
154 	__asm __volatile("mfence" : : : "memory");
155 }
156 
157 #ifdef _KERNEL
158 
159 #define	HAVE_INLINE_FFS
160 
161 static __inline int
162 ffs(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 
175 static __inline int
176 fls(int mask)
177 {
178 	return (mask == 0 ? mask : (int)bsrl((u_int)mask) + 1);
179 }
180 
181 #endif /* _KERNEL */
182 
183 static __inline void
184 halt(void)
185 {
186 	__asm __volatile("hlt");
187 }
188 
189 static __inline u_char
190 inb(u_int port)
191 {
192 	u_char	data;
193 
194 	__asm __volatile("inb %w1, %0" : "=a" (data) : "Nd" (port));
195 	return (data);
196 }
197 
198 static __inline u_int
199 inl(u_int port)
200 {
201 	u_int	data;
202 
203 	__asm __volatile("inl %w1, %0" : "=a" (data) : "Nd" (port));
204 	return (data);
205 }
206 
207 static __inline void
208 insb(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 
216 static __inline void
217 insw(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 
225 static __inline void
226 insl(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 
234 static __inline void
235 invd(void)
236 {
237 	__asm __volatile("invd");
238 }
239 
240 static __inline u_short
241 inw(u_int port)
242 {
243 	u_short	data;
244 
245 	__asm __volatile("inw %w1, %0" : "=a" (data) : "Nd" (port));
246 	return (data);
247 }
248 
249 static __inline void
250 outb(u_int port, u_char data)
251 {
252 	__asm __volatile("outb %0, %w1" : : "a" (data), "Nd" (port));
253 }
254 
255 static __inline void
256 outl(u_int port, u_int data)
257 {
258 	__asm __volatile("outl %0, %w1" : : "a" (data), "Nd" (port));
259 }
260 
261 static __inline void
262 outsb(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 
269 static __inline void
270 outsw(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 
277 static __inline void
278 outsl(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 
285 static __inline void
286 outw(u_int port, u_short data)
287 {
288 	__asm __volatile("outw %0, %w1" : : "a" (data), "Nd" (port));
289 }
290 
291 static __inline void
292 ia32_pause(void)
293 {
294 	__asm __volatile("pause");
295 }
296 
297 static __inline u_int
298 #ifdef XEN
299 _read_eflags(void)
300 #else
301 read_eflags(void)
302 #endif
303 {
304 	u_int	ef;
305 
306 	__asm __volatile("pushfl; popl %0" : "=r" (ef));
307 	return (ef);
308 }
309 
310 static __inline uint64_t
311 rdmsr(u_int msr)
312 {
313 	uint64_t rv;
314 
315 	__asm __volatile("rdmsr" : "=A" (rv) : "c" (msr));
316 	return (rv);
317 }
318 
319 static __inline uint64_t
320 rdpmc(u_int pmc)
321 {
322 	uint64_t rv;
323 
324 	__asm __volatile("rdpmc" : "=A" (rv) : "c" (pmc));
325 	return (rv);
326 }
327 
328 static __inline uint64_t
329 rdtsc(void)
330 {
331 	uint64_t rv;
332 
333 	__asm __volatile("rdtsc" : "=A" (rv));
334 	return (rv);
335 }
336 
337 static __inline uint32_t
338 rdtsc32(void)
339 {
340 	uint32_t rv;
341 
342 	__asm __volatile("rdtsc" : "=a" (rv) : : "edx");
343 	return (rv);
344 }
345 
346 static __inline void
347 wbinvd(void)
348 {
349 	__asm __volatile("wbinvd");
350 }
351 
352 static __inline void
353 #ifdef XEN
354 _write_eflags(u_int ef)
355 #else
356 write_eflags(u_int ef)
357 #endif
358 {
359 	__asm __volatile("pushl %0; popfl" : : "r" (ef));
360 }
361 
362 static __inline void
363 wrmsr(u_int msr, uint64_t newval)
364 {
365 	__asm __volatile("wrmsr" : : "A" (newval), "c" (msr));
366 }
367 
368 static __inline void
369 load_cr0(u_int data)
370 {
371 
372 	__asm __volatile("movl %0,%%cr0" : : "r" (data));
373 }
374 
375 static __inline u_int
376 rcr0(void)
377 {
378 	u_int	data;
379 
380 	__asm __volatile("movl %%cr0,%0" : "=r" (data));
381 	return (data);
382 }
383 
384 static __inline u_int
385 rcr2(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 
396 static __inline void
397 load_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 
406 static __inline u_int
407 rcr3(void)
408 {
409 	u_int	data;
410 
411 	__asm __volatile("movl %%cr3,%0" : "=r" (data));
412 	return (data);
413 }
414 
415 static __inline void
416 load_cr4(u_int data)
417 {
418 	__asm __volatile("movl %0,%%cr4" : : "r" (data));
419 }
420 
421 static __inline u_int
422 rcr4(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  */
433 static __inline void
434 invltlb(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  */
447 static __inline void
448 invlpg(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 
458 static __inline u_short
459 rfs(void)
460 {
461 	u_short sel;
462 	__asm __volatile("movw %%fs,%0" : "=rm" (sel));
463 	return (sel);
464 }
465 
466 static __inline uint64_t
467 rgdt(void)
468 {
469 	uint64_t gdtr;
470 	__asm __volatile("sgdt %0" : "=m" (gdtr));
471 	return (gdtr);
472 }
473 
474 static __inline u_short
475 rgs(void)
476 {
477 	u_short sel;
478 	__asm __volatile("movw %%gs,%0" : "=rm" (sel));
479 	return (sel);
480 }
481 
482 static __inline uint64_t
483 ridt(void)
484 {
485 	uint64_t idtr;
486 	__asm __volatile("sidt %0" : "=m" (idtr));
487 	return (idtr);
488 }
489 
490 static __inline u_short
491 rldt(void)
492 {
493 	u_short ldtr;
494 	__asm __volatile("sldt %0" : "=g" (ldtr));
495 	return (ldtr);
496 }
497 
498 static __inline u_short
499 rss(void)
500 {
501 	u_short sel;
502 	__asm __volatile("movw %%ss,%0" : "=rm" (sel));
503 	return (sel);
504 }
505 
506 static __inline u_short
507 rtr(void)
508 {
509 	u_short tr;
510 	__asm __volatile("str %0" : "=g" (tr));
511 	return (tr);
512 }
513 
514 static __inline void
515 load_fs(u_short sel)
516 {
517 	__asm __volatile("movw %0,%%fs" : : "rm" (sel));
518 }
519 
520 static __inline void
521 load_gs(u_short sel)
522 {
523 	__asm __volatile("movw %0,%%gs" : : "rm" (sel));
524 }
525 
526 static __inline void
527 lidt(struct region_descriptor *addr)
528 {
529 	__asm __volatile("lidt (%0)" : : "r" (addr));
530 }
531 
532 static __inline void
533 lldt(u_short sel)
534 {
535 	__asm __volatile("lldt %0" : : "r" (sel));
536 }
537 
538 static __inline void
539 ltr(u_short sel)
540 {
541 	__asm __volatile("ltr %0" : : "r" (sel));
542 }
543 
544 static __inline u_int
545 rdr0(void)
546 {
547 	u_int	data;
548 	__asm __volatile("movl %%dr0,%0" : "=r" (data));
549 	return (data);
550 }
551 
552 static __inline void
553 load_dr0(u_int dr0)
554 {
555 	__asm __volatile("movl %0,%%dr0" : : "r" (dr0));
556 }
557 
558 static __inline u_int
559 rdr1(void)
560 {
561 	u_int	data;
562 	__asm __volatile("movl %%dr1,%0" : "=r" (data));
563 	return (data);
564 }
565 
566 static __inline void
567 load_dr1(u_int dr1)
568 {
569 	__asm __volatile("movl %0,%%dr1" : : "r" (dr1));
570 }
571 
572 static __inline u_int
573 rdr2(void)
574 {
575 	u_int	data;
576 	__asm __volatile("movl %%dr2,%0" : "=r" (data));
577 	return (data);
578 }
579 
580 static __inline void
581 load_dr2(u_int dr2)
582 {
583 	__asm __volatile("movl %0,%%dr2" : : "r" (dr2));
584 }
585 
586 static __inline u_int
587 rdr3(void)
588 {
589 	u_int	data;
590 	__asm __volatile("movl %%dr3,%0" : "=r" (data));
591 	return (data);
592 }
593 
594 static __inline void
595 load_dr3(u_int dr3)
596 {
597 	__asm __volatile("movl %0,%%dr3" : : "r" (dr3));
598 }
599 
600 static __inline u_int
601 rdr4(void)
602 {
603 	u_int	data;
604 	__asm __volatile("movl %%dr4,%0" : "=r" (data));
605 	return (data);
606 }
607 
608 static __inline void
609 load_dr4(u_int dr4)
610 {
611 	__asm __volatile("movl %0,%%dr4" : : "r" (dr4));
612 }
613 
614 static __inline u_int
615 rdr5(void)
616 {
617 	u_int	data;
618 	__asm __volatile("movl %%dr5,%0" : "=r" (data));
619 	return (data);
620 }
621 
622 static __inline void
623 load_dr5(u_int dr5)
624 {
625 	__asm __volatile("movl %0,%%dr5" : : "r" (dr5));
626 }
627 
628 static __inline u_int
629 rdr6(void)
630 {
631 	u_int	data;
632 	__asm __volatile("movl %%dr6,%0" : "=r" (data));
633 	return (data);
634 }
635 
636 static __inline void
637 load_dr6(u_int dr6)
638 {
639 	__asm __volatile("movl %0,%%dr6" : : "r" (dr6));
640 }
641 
642 static __inline u_int
643 rdr7(void)
644 {
645 	u_int	data;
646 	__asm __volatile("movl %%dr7,%0" : "=r" (data));
647 	return (data);
648 }
649 
650 static __inline void
651 load_dr7(u_int dr7)
652 {
653 	__asm __volatile("movl %0,%%dr7" : : "r" (dr7));
654 }
655 
656 static __inline u_char
657 read_cyrix_reg(u_char reg)
658 {
659 	outb(0x22, reg);
660 	return inb(0x23);
661 }
662 
663 static __inline void
664 write_cyrix_reg(u_char reg, u_char data)
665 {
666 	outb(0x22, reg);
667 	outb(0x23, data);
668 }
669 
670 static __inline register_t
671 intr_disable(void)
672 {
673 	register_t eflags;
674 
675 	eflags = read_eflags();
676 	disable_intr();
677 	return (eflags);
678 }
679 
680 static __inline void
681 intr_restore(register_t eflags)
682 {
683 	write_eflags(eflags);
684 }
685 
686 #else /* !(__GNUCLIKE_ASM && __CC_SUPPORTS___INLINE) */
687 
688 int	breakpoint(void);
689 u_int	bsfl(u_int mask);
690 u_int	bsrl(u_int mask);
691 void	disable_intr(void);
692 void	do_cpuid(u_int ax, u_int *p);
693 void	enable_intr(void);
694 void	halt(void);
695 void	ia32_pause(void);
696 u_char	inb(u_int port);
697 u_int	inl(u_int port);
698 void	insb(u_int port, void *addr, size_t count);
699 void	insl(u_int port, void *addr, size_t count);
700 void	insw(u_int port, void *addr, size_t count);
701 register_t	intr_disable(void);
702 void	intr_restore(register_t ef);
703 void	invd(void);
704 void	invlpg(u_int addr);
705 void	invltlb(void);
706 u_short	inw(u_int port);
707 void	lidt(struct region_descriptor *addr);
708 void	lldt(u_short sel);
709 void	load_cr0(u_int cr0);
710 void	load_cr3(u_int cr3);
711 void	load_cr4(u_int cr4);
712 void	load_dr0(u_int dr0);
713 void	load_dr1(u_int dr1);
714 void	load_dr2(u_int dr2);
715 void	load_dr3(u_int dr3);
716 void	load_dr4(u_int dr4);
717 void	load_dr5(u_int dr5);
718 void	load_dr6(u_int dr6);
719 void	load_dr7(u_int dr7);
720 void	load_fs(u_short sel);
721 void	load_gs(u_short sel);
722 void	ltr(u_short sel);
723 void	outb(u_int port, u_char data);
724 void	outl(u_int port, u_int data);
725 void	outsb(u_int port, const void *addr, size_t count);
726 void	outsl(u_int port, const void *addr, size_t count);
727 void	outsw(u_int port, const void *addr, size_t count);
728 void	outw(u_int port, u_short data);
729 u_int	rcr0(void);
730 u_int	rcr2(void);
731 u_int	rcr3(void);
732 u_int	rcr4(void);
733 uint64_t rdmsr(u_int msr);
734 uint64_t rdpmc(u_int pmc);
735 u_int	rdr0(void);
736 u_int	rdr1(void);
737 u_int	rdr2(void);
738 u_int	rdr3(void);
739 u_int	rdr4(void);
740 u_int	rdr5(void);
741 u_int	rdr6(void);
742 u_int	rdr7(void);
743 uint64_t rdtsc(void);
744 u_char	read_cyrix_reg(u_char reg);
745 u_int	read_eflags(void);
746 u_int	rfs(void);
747 uint64_t rgdt(void);
748 u_int	rgs(void);
749 uint64_t ridt(void);
750 u_short	rldt(void);
751 u_short	rtr(void);
752 void	wbinvd(void);
753 void	write_cyrix_reg(u_char reg, u_char data);
754 void	write_eflags(u_int ef);
755 void	wrmsr(u_int msr, uint64_t newval);
756 
757 #endif	/* __GNUCLIKE_ASM && __CC_SUPPORTS___INLINE */
758 
759 void    reset_dbregs(void);
760 
761 #ifdef _KERNEL
762 int	rdmsr_safe(u_int msr, uint64_t *val);
763 int	wrmsr_safe(u_int msr, uint64_t newval);
764 #endif
765 
766 #endif /* !_MACHINE_CPUFUNC_H_ */
767