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: releng/5.3/sys/i386/include/cpufunc.h 146167 2005-05-13 00:02:47Z nectar $
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 struct region_descriptor;
42
43 #define readb(va) (*(volatile u_int8_t *) (va))
44 #define readw(va) (*(volatile u_int16_t *) (va))
45 #define readl(va) (*(volatile u_int32_t *) (va))
46
47 #define writeb(va, d) (*(volatile u_int8_t *) (va) = (d))
48 #define writew(va, d) (*(volatile u_int16_t *) (va) = (d))
49 #define writel(va, d) (*(volatile u_int32_t *) (va) = (d))
50
51 #if defined(__GNUC__) || defined(__INTEL_COMPILER)
52
53 static __inline void
54 breakpoint(void)
55 {
56 __asm __volatile("int $3");
57 }
58
59 static __inline u_int
60 bsfl(u_int mask)
61 {
62 u_int result;
63
64 __asm __volatile("bsfl %1,%0" : "=r" (result) : "rm" (mask));
65 return (result);
66 }
67
68 static __inline u_int
69 bsrl(u_int mask)
70 {
71 u_int result;
72
73 __asm __volatile("bsrl %1,%0" : "=r" (result) : "rm" (mask));
74 return (result);
75 }
76
77 static __inline void
78 disable_intr(void)
79 {
80 __asm __volatile("cli" : : : "memory");
81 }
82
83 static __inline void
84 do_cpuid(u_int ax, u_int *p)
85 {
86 __asm __volatile("cpuid"
87 : "=a" (p[0]), "=b" (p[1]), "=c" (p[2]), "=d" (p[3])
88 : "" (ax));
89 }
90
91 static __inline void
92 cpuid_count(u_int ax, u_int cx, u_int *p)
93 {
94 __asm __volatile("cpuid"
95 : "=a" (p[0]), "=b" (p[1]), "=c" (p[2]), "=d" (p[3])
96 : "" (ax), "c" (cx));
97 }
98
99 static __inline void
100 enable_intr(void)
101 {
102 __asm __volatile("sti");
103 }
104
105 #ifdef _KERNEL
106
107 #define HAVE_INLINE_FFS
108
109 static __inline int
110 ffs(int mask)
111 {
112 /*
113 * Note that gcc-2's builtin ffs would be used if we didn't declare
114 * this inline or turn off the builtin. The builtin is faster but
115 * broken in gcc-2.4.5 and slower but working in gcc-2.5 and later
116 * versions.
117 */
118 return (mask == 0 ? mask : (int)bsfl((u_int)mask) + 1);
119 }
120
121 #define HAVE_INLINE_FLS
122
123 static __inline int
124 fls(int mask)
125 {
126 return (mask == 0 ? mask : (int)bsrl((u_int)mask) + 1);
127 }
128
129 #endif /* _KERNEL */
130
131 static __inline void
132 halt(void)
133 {
134 __asm __volatile("hlt");
135 }
136
137 #if __GNUC__ < 2
138
139 #define inb(port) inbv(port)
140 #define outb(port, data) outbv(port, data)
141
142 #else /* __GNUC >= 2 */
143
144 /*
145 * The following complications are to get around gcc not having a
146 * constraint letter for the range 0..255. We still put "d" in the
147 * constraint because "i" isn't a valid constraint when the port
148 * isn't constant. This only matters for -O0 because otherwise
149 * the non-working version gets optimized away.
150 *
151 * Use an expression-statement instead of a conditional expression
152 * because gcc-2.6.0 would promote the operands of the conditional
153 * and produce poor code for "if ((inb(var) & const1) == const2)".
154 *
155 * The unnecessary test `(port) < 0x10000' is to generate a warning if
156 * the `port' has type u_short or smaller. Such types are pessimal.
157 * This actually only works for signed types. The range check is
158 * careful to avoid generating warnings.
159 */
160 #define inb(port) __extension__ ({ \
161 u_char _data; \
162 if (__builtin_constant_p(port) && ((port) & 0xffff) < 0x100 \
163 && (port) < 0x10000) \
164 _data = inbc(port); \
165 else \
166 _data = inbv(port); \
167 _data; })
168
169 #define outb(port, data) ( \
170 __builtin_constant_p(port) && ((port) & 0xffff) < 0x100 \
171 && (port) < 0x10000 \
172 ? outbc(port, data) : outbv(port, data))
173
174 static __inline u_char
175 inbc(u_int port)
176 {
177 u_char data;
178
179 __asm __volatile("inb %1,%0" : "=a" (data) : "id" ((u_short)(port)));
180 return (data);
181 }
182
183 static __inline void
184 outbc(u_int port, u_char data)
185 {
186 __asm __volatile("outb %0,%1" : : "a" (data), "id" ((u_short)(port)));
187 }
188
189 #endif /* __GNUC <= 2 */
190
191 static __inline u_char
192 inbv(u_int port)
193 {
194 u_char data;
195 /*
196 * We use %%dx and not %1 here because i/o is done at %dx and not at
197 * %edx, while gcc generates inferior code (movw instead of movl)
198 * if we tell it to load (u_short) port.
199 */
200 __asm __volatile("inb %%dx,%0" : "=a" (data) : "d" (port));
201 return (data);
202 }
203
204 static __inline u_int
205 inl(u_int port)
206 {
207 u_int data;
208
209 __asm __volatile("inl %%dx,%0" : "=a" (data) : "d" (port));
210 return (data);
211 }
212
213 static __inline void
214 insb(u_int port, void *addr, size_t cnt)
215 {
216 __asm __volatile("cld; rep; insb"
217 : "+D" (addr), "+c" (cnt)
218 : "d" (port)
219 : "memory");
220 }
221
222 static __inline void
223 insw(u_int port, void *addr, size_t cnt)
224 {
225 __asm __volatile("cld; rep; insw"
226 : "+D" (addr), "+c" (cnt)
227 : "d" (port)
228 : "memory");
229 }
230
231 static __inline void
232 insl(u_int port, void *addr, size_t cnt)
233 {
234 __asm __volatile("cld; rep; insl"
235 : "+D" (addr), "+c" (cnt)
236 : "d" (port)
237 : "memory");
238 }
239
240 static __inline void
241 invd(void)
242 {
243 __asm __volatile("invd");
244 }
245
246 static __inline u_short
247 inw(u_int port)
248 {
249 u_short data;
250
251 __asm __volatile("inw %%dx,%0" : "=a" (data) : "d" (port));
252 return (data);
253 }
254
255 static __inline void
256 outbv(u_int port, u_char data)
257 {
258 u_char al;
259 /*
260 * Use an unnecessary assignment to help gcc's register allocator.
261 * This make a large difference for gcc-1.40 and a tiny difference
262 * for gcc-2.6.0. For gcc-1.40, al had to be ``asm("ax")'' for
263 * best results. gcc-2.6.0 can't handle this.
264 */
265 al = data;
266 __asm __volatile("outb %0,%%dx" : : "a" (al), "d" (port));
267 }
268
269 static __inline void
270 outl(u_int port, u_int data)
271 {
272 /*
273 * outl() and outw() aren't used much so we haven't looked at
274 * possible micro-optimizations such as the unnecessary
275 * assignment for them.
276 */
277 __asm __volatile("outl %0,%%dx" : : "a" (data), "d" (port));
278 }
279
280 static __inline void
281 outsb(u_int port, const void *addr, size_t cnt)
282 {
283 __asm __volatile("cld; rep; outsb"
284 : "+S" (addr), "+c" (cnt)
285 : "d" (port));
286 }
287
288 static __inline void
289 outsw(u_int port, const void *addr, size_t cnt)
290 {
291 __asm __volatile("cld; rep; outsw"
292 : "+S" (addr), "+c" (cnt)
293 : "d" (port));
294 }
295
296 static __inline void
297 outsl(u_int port, const void *addr, size_t cnt)
298 {
299 __asm __volatile("cld; rep; outsl"
300 : "+S" (addr), "+c" (cnt)
301 : "d" (port));
302 }
303
304 static __inline void
305 outw(u_int port, u_short data)
306 {
307 __asm __volatile("outw %0,%%dx" : : "a" (data), "d" (port));
308 }
309
310 static __inline void
311 ia32_pause(void)
312 {
313 __asm __volatile("pause");
314 }
315
316 static __inline u_int
317 read_eflags(void)
318 {
319 u_int ef;
320
321 __asm __volatile("pushfl; popl %0" : "=r" (ef));
322 return (ef);
323 }
324
325 static __inline u_int64_t
326 rdmsr(u_int msr)
327 {
328 u_int64_t rv;
329
330 __asm __volatile("rdmsr" : "=A" (rv) : "c" (msr));
331 return (rv);
332 }
333
334 static __inline u_int64_t
335 rdpmc(u_int pmc)
336 {
337 u_int64_t rv;
338
339 __asm __volatile("rdpmc" : "=A" (rv) : "c" (pmc));
340 return (rv);
341 }
342
343 static __inline u_int64_t
344 rdtsc(void)
345 {
346 u_int64_t rv;
347
348 __asm __volatile("rdtsc" : "=A" (rv));
349 return (rv);
350 }
351
352 static __inline void
353 wbinvd(void)
354 {
355 __asm __volatile("wbinvd");
356 }
357
358 static __inline void
359 write_eflags(u_int ef)
360 {
361 __asm __volatile("pushl %0; popfl" : : "r" (ef));
362 }
363
364 static __inline void
365 wrmsr(u_int msr, u_int64_t newval)
366 {
367 __asm __volatile("wrmsr" : : "A" (newval), "c" (msr));
368 }
369
370 static __inline void
371 load_cr0(u_int data)
372 {
373
374 __asm __volatile("movl %0,%%cr0" : : "r" (data));
375 }
376
377 static __inline u_int
378 rcr0(void)
379 {
380 u_int data;
381
382 __asm __volatile("movl %%cr0,%0" : "=r" (data));
383 return (data);
384 }
385
386 static __inline u_int
387 rcr2(void)
388 {
389 u_int data;
390
391 __asm __volatile("movl %%cr2,%0" : "=r" (data));
392 return (data);
393 }
394
395 static __inline void
396 load_cr3(u_int data)
397 {
398
399 __asm __volatile("movl %0,%%cr3" : : "r" (data) : "memory");
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
433 load_cr3(rcr3());
434 }
435
436 /*
437 * TLB flush for an individual page (even if it has PG_G).
438 * Only works on 486+ CPUs (i386 does not have PG_G).
439 */
440 static __inline void
441 invlpg(u_int addr)
442 {
443
444 __asm __volatile("invlpg %0" : : "m" (*(char *)addr) : "memory");
445 }
446
447 static __inline u_int
448 rfs(void)
449 {
450 u_int sel;
451 __asm __volatile("movl %%fs,%0" : "=rm" (sel));
452 return (sel);
453 }
454
455 static __inline u_int
456 rgs(void)
457 {
458 u_int sel;
459 __asm __volatile("movl %%gs,%0" : "=rm" (sel));
460 return (sel);
461 }
462
463 static __inline u_int
464 rss(void)
465 {
466 u_int sel;
467 __asm __volatile("movl %%ss,%0" : "=rm" (sel));
468 return (sel);
469 }
470
471 static __inline void
472 load_fs(u_int sel)
473 {
474 __asm __volatile("movl %0,%%fs" : : "rm" (sel));
475 }
476
477 static __inline void
478 load_gs(u_int sel)
479 {
480 __asm __volatile("movl %0,%%gs" : : "rm" (sel));
481 }
482
483 static __inline void
484 lidt(struct region_descriptor *addr)
485 {
486 __asm __volatile("lidt (%0)" : : "r" (addr));
487 }
488
489 static __inline void
490 lldt(u_short sel)
491 {
492 __asm __volatile("lldt %0" : : "r" (sel));
493 }
494
495 static __inline void
496 ltr(u_short sel)
497 {
498 __asm __volatile("ltr %0" : : "r" (sel));
499 }
500
501 static __inline u_int
502 rdr0(void)
503 {
504 u_int data;
505 __asm __volatile("movl %%dr0,%0" : "=r" (data));
506 return (data);
507 }
508
509 static __inline void
510 load_dr0(u_int dr0)
511 {
512 __asm __volatile("movl %0,%%dr0" : : "r" (dr0));
513 }
514
515 static __inline u_int
516 rdr1(void)
517 {
518 u_int data;
519 __asm __volatile("movl %%dr1,%0" : "=r" (data));
520 return (data);
521 }
522
523 static __inline void
524 load_dr1(u_int dr1)
525 {
526 __asm __volatile("movl %0,%%dr1" : : "r" (dr1));
527 }
528
529 static __inline u_int
530 rdr2(void)
531 {
532 u_int data;
533 __asm __volatile("movl %%dr2,%0" : "=r" (data));
534 return (data);
535 }
536
537 static __inline void
538 load_dr2(u_int dr2)
539 {
540 __asm __volatile("movl %0,%%dr2" : : "r" (dr2));
541 }
542
543 static __inline u_int
544 rdr3(void)
545 {
546 u_int data;
547 __asm __volatile("movl %%dr3,%0" : "=r" (data));
548 return (data);
549 }
550
551 static __inline void
552 load_dr3(u_int dr3)
553 {
554 __asm __volatile("movl %0,%%dr3" : : "r" (dr3));
555 }
556
557 static __inline u_int
558 rdr4(void)
559 {
560 u_int data;
561 __asm __volatile("movl %%dr4,%0" : "=r" (data));
562 return (data);
563 }
564
565 static __inline void
566 load_dr4(u_int dr4)
567 {
568 __asm __volatile("movl %0,%%dr4" : : "r" (dr4));
569 }
570
571 static __inline u_int
572 rdr5(void)
573 {
574 u_int data;
575 __asm __volatile("movl %%dr5,%0" : "=r" (data));
576 return (data);
577 }
578
579 static __inline void
580 load_dr5(u_int dr5)
581 {
582 __asm __volatile("movl %0,%%dr5" : : "r" (dr5));
583 }
584
585 static __inline u_int
586 rdr6(void)
587 {
588 u_int data;
589 __asm __volatile("movl %%dr6,%0" : "=r" (data));
590 return (data);
591 }
592
593 static __inline void
594 load_dr6(u_int dr6)
595 {
596 __asm __volatile("movl %0,%%dr6" : : "r" (dr6));
597 }
598
599 static __inline u_int
600 rdr7(void)
601 {
602 u_int data;
603 __asm __volatile("movl %%dr7,%0" : "=r" (data));
604 return (data);
605 }
606
607 static __inline void
608 load_dr7(u_int dr7)
609 {
610 __asm __volatile("movl %0,%%dr7" : : "r" (dr7));
611 }
612
613 static __inline register_t
614 intr_disable(void)
615 {
616 register_t eflags;
617
618 eflags = read_eflags();
619 disable_intr();
620 return (eflags);
621 }
622
623 static __inline void
624 intr_restore(register_t eflags)
625 {
626 write_eflags(eflags);
627 }
628
629 #else /* !(__GNUC__ || __INTEL_COMPILER) */
630
631 int breakpoint(void);
632 u_int bsfl(u_int mask);
633 u_int bsrl(u_int mask);
634 void disable_intr(void);
635 void do_cpuid(u_int ax, u_int *p);
636 void enable_intr(void);
637 void halt(void);
638 void ia32_pause(void);
639 u_char inb(u_int port);
640 u_int inl(u_int port);
641 void insb(u_int port, void *addr, size_t cnt);
642 void insl(u_int port, void *addr, size_t cnt);
643 void insw(u_int port, void *addr, size_t cnt);
644 register_t intr_disable(void);
645 void intr_restore(register_t ef);
646 void invd(void);
647 void invlpg(u_int addr);
648 void invltlb(void);
649 u_short inw(u_int port);
650 void lidt(struct region_descriptor *addr);
651 void lldt(u_short sel);
652 void load_cr0(u_int cr0);
653 void load_cr3(u_int cr3);
654 void load_cr4(u_int cr4);
655 void load_dr0(u_int dr0);
656 void load_dr1(u_int dr1);
657 void load_dr2(u_int dr2);
658 void load_dr3(u_int dr3);
659 void load_dr4(u_int dr4);
660 void load_dr5(u_int dr5);
661 void load_dr6(u_int dr6);
662 void load_dr7(u_int dr7);
663 void load_fs(u_int sel);
664 void load_gs(u_int sel);
665 void ltr(u_short sel);
666 void outb(u_int port, u_char data);
667 void outl(u_int port, u_int data);
668 void outsb(u_int port, const void *addr, size_t cnt);
669 void outsl(u_int port, const void *addr, size_t cnt);
670 void outsw(u_int port, const void *addr, size_t cnt);
671 void outw(u_int port, u_short data);
672 u_int rcr0(void);
673 u_int rcr2(void);
674 u_int rcr3(void);
675 u_int rcr4(void);
676 u_int64_t rdmsr(u_int msr);
677 u_int64_t rdpmc(u_int pmc);
678 u_int rdr0(void);
679 u_int rdr1(void);
680 u_int rdr2(void);
681 u_int rdr3(void);
682 u_int rdr4(void);
683 u_int rdr5(void);
684 u_int rdr6(void);
685 u_int rdr7(void);
686 u_int64_t rdtsc(void);
687 u_int read_eflags(void);
688 u_int rfs(void);
689 u_int rgs(void);
690 void wbinvd(void);
691 void write_eflags(u_int ef);
692 void wrmsr(u_int msr, u_int64_t newval);
693
694 #endif /* __GNUC__ || __INTEL_COMPILER */
695
696 void reset_dbregs(void);
697
698 #endif /* !_MACHINE_CPUFUNC_H_ */
Cache object: 74a2abaf75f1996a8f09b579fe422734
|