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