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