cpufunc.h revision 238142
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 238142 2012-07-05 18:19:35Z jhb $
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 u_long
277popcntq(u_long mask)
278{
279	u_long result;
280
281	__asm __volatile("popcntq %1,%0" : "=r" (result) : "rm" (mask));
282	return (result);
283}
284
285static __inline void
286mfence(void)
287{
288
289	__asm __volatile("mfence" : : : "memory");
290}
291
292static __inline void
293ia32_pause(void)
294{
295	__asm __volatile("pause");
296}
297
298static __inline u_long
299read_rflags(void)
300{
301	u_long	rf;
302
303	__asm __volatile("pushfq; popq %0" : "=r" (rf));
304	return (rf);
305}
306
307static __inline uint64_t
308rdmsr(u_int msr)
309{
310	uint32_t low, high;
311
312	__asm __volatile("rdmsr" : "=a" (low), "=d" (high) : "c" (msr));
313	return (low | ((uint64_t)high << 32));
314}
315
316static __inline uint64_t
317rdpmc(u_int pmc)
318{
319	uint32_t low, high;
320
321	__asm __volatile("rdpmc" : "=a" (low), "=d" (high) : "c" (pmc));
322	return (low | ((uint64_t)high << 32));
323}
324
325static __inline uint64_t
326rdtsc(void)
327{
328	uint32_t low, high;
329
330	__asm __volatile("rdtsc" : "=a" (low), "=d" (high));
331	return (low | ((uint64_t)high << 32));
332}
333
334static __inline uint32_t
335rdtsc32(void)
336{
337	uint32_t rv;
338
339	__asm __volatile("rdtsc" : "=a" (rv) : : "edx");
340	return (rv);
341}
342
343static __inline void
344wbinvd(void)
345{
346	__asm __volatile("wbinvd");
347}
348
349static __inline void
350write_rflags(u_long rf)
351{
352	__asm __volatile("pushq %0;  popfq" : : "r" (rf));
353}
354
355static __inline void
356wrmsr(u_int msr, uint64_t newval)
357{
358	uint32_t low, high;
359
360	low = newval;
361	high = newval >> 32;
362	__asm __volatile("wrmsr" : : "a" (low), "d" (high), "c" (msr));
363}
364
365static __inline void
366load_cr0(u_long data)
367{
368
369	__asm __volatile("movq %0,%%cr0" : : "r" (data));
370}
371
372static __inline u_long
373rcr0(void)
374{
375	u_long	data;
376
377	__asm __volatile("movq %%cr0,%0" : "=r" (data));
378	return (data);
379}
380
381static __inline u_long
382rcr2(void)
383{
384	u_long	data;
385
386	__asm __volatile("movq %%cr2,%0" : "=r" (data));
387	return (data);
388}
389
390static __inline void
391load_cr3(u_long data)
392{
393
394	__asm __volatile("movq %0,%%cr3" : : "r" (data) : "memory");
395}
396
397static __inline u_long
398rcr3(void)
399{
400	u_long	data;
401
402	__asm __volatile("movq %%cr3,%0" : "=r" (data));
403	return (data);
404}
405
406static __inline void
407load_cr4(u_long data)
408{
409	__asm __volatile("movq %0,%%cr4" : : "r" (data));
410}
411
412static __inline u_long
413rcr4(void)
414{
415	u_long	data;
416
417	__asm __volatile("movq %%cr4,%0" : "=r" (data));
418	return (data);
419}
420
421static __inline u_long
422rxcr(u_int reg)
423{
424	u_int low, high;
425
426	__asm __volatile("xgetbv" : "=a" (low), "=d" (high) : "c" (reg));
427	return (low | ((uint64_t)high << 32));
428}
429
430static __inline void
431load_xcr(u_int reg, u_long val)
432{
433	u_int low, high;
434
435	low = val;
436	high = val >> 32;
437	__asm __volatile("xsetbv" : : "c" (reg), "a" (low), "d" (high));
438}
439
440/*
441 * Global TLB flush (except for thise for pages marked PG_G)
442 */
443static __inline void
444invltlb(void)
445{
446
447	load_cr3(rcr3());
448}
449
450/*
451 * TLB flush for an individual page (even if it has PG_G).
452 * Only works on 486+ CPUs (i386 does not have PG_G).
453 */
454static __inline void
455invlpg(u_long addr)
456{
457
458	__asm __volatile("invlpg %0" : : "m" (*(char *)addr) : "memory");
459}
460
461static __inline u_short
462rfs(void)
463{
464	u_short sel;
465	__asm __volatile("movw %%fs,%0" : "=rm" (sel));
466	return (sel);
467}
468
469static __inline u_short
470rgs(void)
471{
472	u_short sel;
473	__asm __volatile("movw %%gs,%0" : "=rm" (sel));
474	return (sel);
475}
476
477static __inline u_short
478rss(void)
479{
480	u_short sel;
481	__asm __volatile("movw %%ss,%0" : "=rm" (sel));
482	return (sel);
483}
484
485static __inline void
486load_ds(u_short sel)
487{
488	__asm __volatile("movw %0,%%ds" : : "rm" (sel));
489}
490
491static __inline void
492load_es(u_short sel)
493{
494	__asm __volatile("movw %0,%%es" : : "rm" (sel));
495}
496
497static __inline void
498cpu_monitor(const void *addr, u_long extensions, u_int hints)
499{
500
501	__asm __volatile("monitor"
502	    : : "a" (addr), "c" (extensions), "d" (hints));
503}
504
505static __inline void
506cpu_mwait(u_long extensions, u_int hints)
507{
508
509	__asm __volatile("mwait" : : "a" (hints), "c" (extensions));
510}
511
512#ifdef _KERNEL
513/* This is defined in <machine/specialreg.h> but is too painful to get to */
514#ifndef	MSR_FSBASE
515#define	MSR_FSBASE	0xc0000100
516#endif
517static __inline void
518load_fs(u_short sel)
519{
520	/* Preserve the fsbase value across the selector load */
521	__asm __volatile("rdmsr; movw %0,%%fs; wrmsr"
522	    : : "rm" (sel), "c" (MSR_FSBASE) : "eax", "edx");
523}
524
525#ifndef	MSR_GSBASE
526#define	MSR_GSBASE	0xc0000101
527#endif
528static __inline void
529load_gs(u_short sel)
530{
531	/*
532	 * Preserve the gsbase value across the selector load.
533	 * Note that we have to disable interrupts because the gsbase
534	 * being trashed happens to be the kernel gsbase at the time.
535	 */
536	__asm __volatile("pushfq; cli; rdmsr; movw %0,%%gs; wrmsr; popfq"
537	    : : "rm" (sel), "c" (MSR_GSBASE) : "eax", "edx");
538}
539#else
540/* Usable by userland */
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#endif
553
554static __inline void
555lidt(struct region_descriptor *addr)
556{
557	__asm __volatile("lidt (%0)" : : "r" (addr));
558}
559
560static __inline void
561lldt(u_short sel)
562{
563	__asm __volatile("lldt %0" : : "r" (sel));
564}
565
566static __inline void
567ltr(u_short sel)
568{
569	__asm __volatile("ltr %0" : : "r" (sel));
570}
571
572static __inline uint64_t
573rdr0(void)
574{
575	uint64_t data;
576	__asm __volatile("movq %%dr0,%0" : "=r" (data));
577	return (data);
578}
579
580static __inline void
581load_dr0(uint64_t dr0)
582{
583	__asm __volatile("movq %0,%%dr0" : : "r" (dr0));
584}
585
586static __inline uint64_t
587rdr1(void)
588{
589	uint64_t data;
590	__asm __volatile("movq %%dr1,%0" : "=r" (data));
591	return (data);
592}
593
594static __inline void
595load_dr1(uint64_t dr1)
596{
597	__asm __volatile("movq %0,%%dr1" : : "r" (dr1));
598}
599
600static __inline uint64_t
601rdr2(void)
602{
603	uint64_t data;
604	__asm __volatile("movq %%dr2,%0" : "=r" (data));
605	return (data);
606}
607
608static __inline void
609load_dr2(uint64_t dr2)
610{
611	__asm __volatile("movq %0,%%dr2" : : "r" (dr2));
612}
613
614static __inline uint64_t
615rdr3(void)
616{
617	uint64_t data;
618	__asm __volatile("movq %%dr3,%0" : "=r" (data));
619	return (data);
620}
621
622static __inline void
623load_dr3(uint64_t dr3)
624{
625	__asm __volatile("movq %0,%%dr3" : : "r" (dr3));
626}
627
628static __inline uint64_t
629rdr4(void)
630{
631	uint64_t data;
632	__asm __volatile("movq %%dr4,%0" : "=r" (data));
633	return (data);
634}
635
636static __inline void
637load_dr4(uint64_t dr4)
638{
639	__asm __volatile("movq %0,%%dr4" : : "r" (dr4));
640}
641
642static __inline uint64_t
643rdr5(void)
644{
645	uint64_t data;
646	__asm __volatile("movq %%dr5,%0" : "=r" (data));
647	return (data);
648}
649
650static __inline void
651load_dr5(uint64_t dr5)
652{
653	__asm __volatile("movq %0,%%dr5" : : "r" (dr5));
654}
655
656static __inline uint64_t
657rdr6(void)
658{
659	uint64_t data;
660	__asm __volatile("movq %%dr6,%0" : "=r" (data));
661	return (data);
662}
663
664static __inline void
665load_dr6(uint64_t dr6)
666{
667	__asm __volatile("movq %0,%%dr6" : : "r" (dr6));
668}
669
670static __inline uint64_t
671rdr7(void)
672{
673	uint64_t data;
674	__asm __volatile("movq %%dr7,%0" : "=r" (data));
675	return (data);
676}
677
678static __inline void
679load_dr7(uint64_t dr7)
680{
681	__asm __volatile("movq %0,%%dr7" : : "r" (dr7));
682}
683
684static __inline register_t
685intr_disable(void)
686{
687	register_t rflags;
688
689	rflags = read_rflags();
690	disable_intr();
691	return (rflags);
692}
693
694static __inline void
695intr_restore(register_t rflags)
696{
697	write_rflags(rflags);
698}
699
700#else /* !(__GNUCLIKE_ASM && __CC_SUPPORTS___INLINE) */
701
702int	breakpoint(void);
703u_int	bsfl(u_int mask);
704u_int	bsrl(u_int mask);
705void	disable_intr(void);
706void	do_cpuid(u_int ax, u_int *p);
707void	enable_intr(void);
708void	halt(void);
709void	ia32_pause(void);
710u_char	inb(u_int port);
711u_int	inl(u_int port);
712void	insb(u_int port, void *addr, size_t count);
713void	insl(u_int port, void *addr, size_t count);
714void	insw(u_int port, void *addr, size_t count);
715register_t	intr_disable(void);
716void	intr_restore(register_t rf);
717void	invd(void);
718void	invlpg(u_int addr);
719void	invltlb(void);
720u_short	inw(u_int port);
721void	lidt(struct region_descriptor *addr);
722void	lldt(u_short sel);
723void	load_cr0(u_long cr0);
724void	load_cr3(u_long cr3);
725void	load_cr4(u_long cr4);
726void	load_dr0(uint64_t dr0);
727void	load_dr1(uint64_t dr1);
728void	load_dr2(uint64_t dr2);
729void	load_dr3(uint64_t dr3);
730void	load_dr4(uint64_t dr4);
731void	load_dr5(uint64_t dr5);
732void	load_dr6(uint64_t dr6);
733void	load_dr7(uint64_t dr7);
734void	load_fs(u_short sel);
735void	load_gs(u_short sel);
736void	ltr(u_short sel);
737void	outb(u_int port, u_char data);
738void	outl(u_int port, u_int data);
739void	outsb(u_int port, const void *addr, size_t count);
740void	outsl(u_int port, const void *addr, size_t count);
741void	outsw(u_int port, const void *addr, size_t count);
742void	outw(u_int port, u_short data);
743u_long	rcr0(void);
744u_long	rcr2(void);
745u_long	rcr3(void);
746u_long	rcr4(void);
747uint64_t rdmsr(u_int msr);
748uint64_t rdpmc(u_int pmc);
749uint64_t rdr0(void);
750uint64_t rdr1(void);
751uint64_t rdr2(void);
752uint64_t rdr3(void);
753uint64_t rdr4(void);
754uint64_t rdr5(void);
755uint64_t rdr6(void);
756uint64_t rdr7(void);
757uint64_t rdtsc(void);
758u_long	read_rflags(void);
759u_int	rfs(void);
760u_int	rgs(void);
761void	wbinvd(void);
762void	write_rflags(u_int rf);
763void	wrmsr(u_int msr, uint64_t newval);
764
765#endif	/* __GNUCLIKE_ASM && __CC_SUPPORTS___INLINE */
766
767void	reset_dbregs(void);
768
769#ifdef _KERNEL
770int	rdmsr_safe(u_int msr, uint64_t *val);
771int	wrmsr_safe(u_int msr, uint64_t newval);
772#endif
773
774#endif /* !_MACHINE_CPUFUNC_H_ */
775