cpufunc.h revision 6367
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 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * $Id: cpufunc.h,v 1.31 1995/01/04 20:42:25 davidg Exp $ 34 */ 35 36/* 37 * Functions to provide access to special i386 instructions. 38 */ 39 40#ifndef _MACHINE_CPUFUNC_H_ 41#define _MACHINE_CPUFUNC_H_ 42 43#include <sys/cdefs.h> 44#include <sys/types.h> 45 46#include <machine/spl.h> /* XXX belongs elsewhere */ 47 48#ifdef __GNUC__ 49 50#ifdef BDE_DEBUGGER 51extern int bdb_exists; 52 53static __inline int 54bdb(void) 55{ 56 if (!bdb_exists) 57 return (0); 58 __asm __volatile("int $3"); 59 return (1); 60} 61#endif /* BDE_DEBUGGER */ 62 63static __inline void 64disable_intr(void) 65{ 66 __asm __volatile("cli"); 67} 68 69static __inline void 70enable_intr(void) 71{ 72 __asm __volatile("sti"); 73} 74 75#define HAVE_INLINE_FFS 76 77static __inline int 78ffs(int mask) 79{ 80 int result; 81 /* 82 * bsfl turns out to be not all that slow on 486's. It can beaten 83 * using a binary search to reduce to 4 bits and then a table lookup, 84 * but only if the code is inlined and in the cache, and the code 85 * is quite large so inlining it probably busts the cache. 86 * 87 * Note that gcc-2's builtin ffs would be used if we didn't declare 88 * this inline or turn off the builtin. The builtin is faster but 89 * broken in gcc-2.4.5 and slower but working in gcc-2.5 and 2.6. 90 */ 91 __asm __volatile("testl %0,%0; je 1f; bsfl %0,%0; incl %0; 1:" 92 : "=r" (result) : "0" (mask)); 93 return (result); 94} 95 96#if __GNUC__ < 2 97 98#define inb(port) inbv(port) 99#define outb(port, data) outbv(port, data) 100 101#else /* __GNUC >= 2 */ 102 103/* 104 * Use an expression-statement instead of a conditional expression 105 * because gcc-2.6.0 would promote the operands of the conditional 106 * and produce poor code for "if ((inb(var) & const1) == const2)". 107 */ 108#define inb(port) ({ \ 109 u_char _data; \ 110 if (__builtin_constant_p((int) (port)) && (port) < 256ul) \ 111 _data = inbc(port); \ 112 else \ 113 _data = inbv(port); \ 114 _data; }) 115 116#define outb(port, data) \ 117 (__builtin_constant_p((int) (port)) && (port) < 256ul \ 118 ? outbc(port, data) : outbv(port, data)) 119 120static __inline u_char 121inbc(u_int port) 122{ 123 u_char data; 124 125 __asm __volatile("inb %1,%0" : "=a" (data) : "i" (port)); 126 return (data); 127} 128 129static __inline void 130outbc(u_int port, u_char data) 131{ 132 __asm __volatile("outb %0,%1" : : "a" (data), "i" (port)); 133} 134 135#endif /* __GNUC <= 2 */ 136 137static __inline u_char 138inbv(u_int port) 139{ 140 u_char data; 141 /* 142 * We use %%dx and not %1 here because i/o is done at %dx and not at 143 * %edx, while gcc generates inferior code (movw instead of movl) 144 * if we tell it to load (u_short) port. 145 */ 146 __asm __volatile("inb %%dx,%0" : "=a" (data) : "d" (port)); 147 return (data); 148} 149 150static __inline u_long 151inl(u_int port) 152{ 153 u_long data; 154 155 __asm __volatile("inl %%dx,%0" : "=a" (data) : "d" (port)); 156 return (data); 157} 158 159static __inline void 160insb(u_int port, void *addr, size_t cnt) 161{ 162 __asm __volatile("cld; rep; insb" 163 : : "d" (port), "D" (addr), "c" (cnt) 164 : "di", "cx", "memory"); 165} 166 167static __inline void 168insw(u_int port, void *addr, size_t cnt) 169{ 170 __asm __volatile("cld; rep; insw" 171 : : "d" (port), "D" (addr), "c" (cnt) 172 : "di", "cx", "memory"); 173} 174 175static __inline void 176insl(u_int port, void *addr, size_t cnt) 177{ 178 __asm __volatile("cld; rep; insl" 179 : : "d" (port), "D" (addr), "c" (cnt) 180 : "di", "cx", "memory"); 181} 182 183static __inline u_short 184inw(u_int port) 185{ 186 u_short data; 187 188 __asm __volatile("inw %%dx,%0" : "=a" (data) : "d" (port)); 189 return (data); 190} 191 192static __inline void 193outbv(u_int port, u_char data) 194{ 195 u_char al; 196 /* 197 * Use an unnecessary assignment to help gcc's register allocator. 198 * This make a large difference for gcc-1.40 and a tiny difference 199 * for gcc-2.6.0. For gcc-1.40, al had to be ``asm("ax")'' for 200 * best results. gcc-2.6.0 can't handle this. 201 */ 202 al = data; 203 __asm __volatile("outb %0,%%dx" : : "a" (al), "d" (port)); 204} 205 206static __inline void 207outl(u_int port, u_long data) 208{ 209 /* 210 * outl() and outw() aren't used much so we haven't looked at 211 * possible micro-optimizations such as the unnecessary 212 * assignment for them. 213 */ 214 __asm __volatile("outl %0,%%dx" : : "a" (data), "d" (port)); 215} 216 217static __inline void 218outsb(u_int port, void *addr, size_t cnt) 219{ 220 __asm __volatile("cld; rep; outsb" 221 : : "d" (port), "S" (addr), "c" (cnt) 222 : "si", "cx"); 223} 224 225static __inline void 226outsw(u_int port, void *addr, size_t cnt) 227{ 228 __asm __volatile("cld; rep; outsw" 229 : : "d" (port), "S" (addr), "c" (cnt) 230 : "si", "cx"); 231} 232 233static __inline void 234outsl(u_int port, void *addr, size_t cnt) 235{ 236 __asm __volatile("cld; rep; outsl" 237 : : "d" (port), "S" (addr), "c" (cnt) 238 : "si", "cx"); 239} 240 241static __inline void 242outw(u_int port, u_short data) 243{ 244 __asm __volatile("outw %0,%%dx" : : "a" (data), "d" (port)); 245} 246 247static __inline void 248pmap_update(void) 249{ 250 u_long temp; 251 /* 252 * This should be implemented as load_cr3(rcr3()) when load_cr3() 253 * is inlined. 254 */ 255 __asm __volatile("movl %%cr3, %0; movl %0, %%cr3" : "=r" (temp)); 256} 257 258static __inline u_long 259rcr2(void) 260{ 261 u_long data; 262 263 __asm __volatile("movl %%cr2,%0" : "=r" (data)); 264 return (data); 265} 266 267static __inline u_long 268read_eflags(void) 269{ 270 u_long ef; 271 272 __asm __volatile("pushfl; popl %0" : "=r" (ef)); 273 return (ef); 274} 275 276static __inline void 277write_eflags(u_long ef) 278{ 279 __asm __volatile("pushl %0; popfl" : : "r" (ef)); 280} 281 282/* 283 * XXX queue stuff belongs elsewhere. 284 */ 285struct quehead { 286 struct quehead *qh_link; 287 struct quehead *qh_rlink; 288}; 289 290static __inline void 291insque(void *a, void *b) 292{ 293 struct quehead *element = a, *head = b; 294 295 element->qh_link = head->qh_link; 296 head->qh_link = element; 297 element->qh_rlink = head; 298 element->qh_link->qh_rlink = element; 299} 300 301static __inline void 302remque(void *a) 303{ 304 struct quehead *element = a; 305 306 element->qh_link->qh_rlink = element->qh_rlink; 307 element->qh_rlink->qh_link = element->qh_link; 308 element->qh_rlink = 0; 309} 310 311#else /* !__GNUC__ */ 312 313int bdb __P((void)); 314void disable_intr __P((void)); 315void enable_intr __P((void)); 316u_char inb __P((u_int port)); 317u_long inl __P((u_int port)); 318void insb __P((u_int port, void *addr, size_t cnt)); 319void insl __P((u_int port, void *addr, size_t cnt)); 320void insw __P((u_int port, void *addr, size_t cnt)); 321u_short inw __P((u_int port)); 322void outb __P((u_int port, u_char data)); 323void outl __P((u_int port, u_long data)); 324void outsb __P((u_int port, void *addr, size_t cnt)); 325void outsl __P((u_int port, void *addr, size_t cnt)); 326void outsw __P((u_int port, void *addr, size_t cnt)); 327void outw __P((u_int port, u_short data)); 328void void pmap_update __P((void)); 329u_long read_eflags __P((void)); 330u_long rcr2 __P((void)); 331void write_eflags __P((u_long ef)); 332 333void insque __P((void *a, void *b)); 334void remque __P((void *a)) 335 336#endif /* __GNUC__ */ 337 338/* 339 * XXX the following declarations document garbage in support.s. 340 * gcc hasn't needed _divsi* for years. 341 * bcopy[bwx]() was used by pccons but isn't used now. 342 */ 343int __divsi3 __P((int factor1, int factor2)); 344u_int __udivsi3 __P((u_int factor1, u_int factor2)); 345void bcopyb __P((const void *from, void *to, size_t len)); 346void bcopyw __P((const void *from, void *to, size_t len)); 347void bcopyx __P((const void *from, void *to, size_t len, 348 int stride)); 349 350#if 0 351/* 352 * These functions in support.s are declared elsewhere. 353 */ 354void bcopy __P((const void *from, void *to, size_t len)); 355void blkclr __P((void *buf, size_t len)); 356void bzero __P((void *buf, size_t len)); 357int copyin __P((void *udaddr, void *kaddr, size_t len)); 358int copyinstr __P((void *udaddr, void *kaddr, size_t len, 359 size_t *lencopied)); 360int copyout __P((void *kaddr, void *udaddr, size_t len)); 361int copystr __P((void *kfaddr, void *kdaddr, size_t len, 362 size_t *lencopied)); 363int fubyte __P((void *base)); 364int fuswintr __P((void *base)); 365int fuibyte __P((void *base)); 366int fuword __P((void *base)); 367struct region_descriptor; 368void lgdt __P((struct region_descriptor *rdp)); 369void lidt __P((struct region_descriptor *rdp)); 370void lldt __P((u_short sel)); 371/* 372 * longjmp() and setjmp() are only used by ddb. They probably shouldn't 373 * shouldn't be supported in the kernel. 374 */ 375#include <setjmp.h> 376void longjmp __P((jmp_buf jb, int rv)); 377void ovbcopy __P((const void *from, void *to, size_t len); 378int setjmp __P((jmp_buf jb)); 379struct soft_segment_descriptor; 380union descriptor; 381int ssdtosd __P((struct soft_segment_descriptor *ssdp, 382 union descriptor *sdp)); 383int subyte __P((void *base, int byte)); 384int suibyte __P((void *base, int byte)); 385int suswintr __P((void *base, int word)); 386int suword __P((void *base, int word)); 387 388/* 389 * These functions in support.s are declared elsewhere, but never used. 390 * A silly amount of effort went into copyoutstr(). It's not worth 391 * maintaining, since the string length is usually known so copyout 392 * works better, or is easy to find so copyout() can be used. 393 */ 394int copyoutstr __P((void *kaddr, void *udaddr, size_t len, 395 size_t *lencopied)); 396int fuiword __P((void *base)); 397int suiword __P((void *base, int word)); 398 399/* 400 * These functions in support.s are also in libkern.a and are declared in 401 * libkern.h. 402 * ffs() is built in to gcc-2 and was buggy in gcc-2.4.5 so we may may the 403 * buggy version if we don't replace it by an inline. 404 */ 405int bcmp __P((const void *b1, const void *b2, size_t length)); 406int ffs __P((int mask)); 407#endif /* 0 */ 408 409/* 410 * These variables and functions in support.s are used. 411 */ 412extern u_int atdevbase; /* offset in virtual memory of ISA io mem */ 413 414void filli __P((int pat, void *base, size_t cnt)); 415void fillw __P((int /*u_short*/ pat, void *base, size_t cnt)); 416int fusword __P((void *base)); 417void load_cr0 __P((u_long cr0)); 418void load_cr3 __P((u_long cr3)); 419void ltr __P((u_short sel)); 420u_int rcr0 __P((void)); 421u_long rcr3 __P((void)); 422int rtcin __P((int val)); 423 424/* 425 * These functions are NOT in support.s and should be declared elsewhere. 426 */ 427void Debugger __P((const char *msg)); 428u_long kvtop __P((void *addr)); 429typedef void alias_for_inthand_t __P((u_int cs, u_int ef, u_int esp, 430 u_int ss)); 431void setidt __P((int idx, alias_for_inthand_t *func, int typ, 432 int dpl)); 433 434#endif /* !_MACHINE_CPUFUNC_H_ */ 435