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