cpufunc.h revision 8521
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.35 1995/05/11 07:24:35 bde 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 unsigned 193loadandclear(u_int *addr) 194{ 195 u_int result; 196 197 __asm __volatile("xorl %0,%0; xchgl %1,%0" 198 : "=&r" (result) : "m" (*addr)); 199 return (result); 200} 201 202static __inline void 203outbv(u_int port, u_char data) 204{ 205 u_char al; 206 /* 207 * Use an unnecessary assignment to help gcc's register allocator. 208 * This make a large difference for gcc-1.40 and a tiny difference 209 * for gcc-2.6.0. For gcc-1.40, al had to be ``asm("ax")'' for 210 * best results. gcc-2.6.0 can't handle this. 211 */ 212 al = data; 213 __asm __volatile("outb %0,%%dx" : : "a" (al), "d" (port)); 214} 215 216static __inline void 217outl(u_int port, u_long data) 218{ 219 /* 220 * outl() and outw() aren't used much so we haven't looked at 221 * possible micro-optimizations such as the unnecessary 222 * assignment for them. 223 */ 224 __asm __volatile("outl %0,%%dx" : : "a" (data), "d" (port)); 225} 226 227static __inline void 228outsb(u_int port, void *addr, size_t cnt) 229{ 230 __asm __volatile("cld; rep; outsb" 231 : : "d" (port), "S" (addr), "c" (cnt) 232 : "si", "cx"); 233} 234 235static __inline void 236outsw(u_int port, void *addr, size_t cnt) 237{ 238 __asm __volatile("cld; rep; outsw" 239 : : "d" (port), "S" (addr), "c" (cnt) 240 : "si", "cx"); 241} 242 243static __inline void 244outsl(u_int port, void *addr, size_t cnt) 245{ 246 __asm __volatile("cld; rep; outsl" 247 : : "d" (port), "S" (addr), "c" (cnt) 248 : "si", "cx"); 249} 250 251static __inline void 252outw(u_int port, u_short data) 253{ 254 __asm __volatile("outw %0,%%dx" : : "a" (data), "d" (port)); 255} 256 257static __inline void 258pmap_update(void) 259{ 260 u_long temp; 261 /* 262 * This should be implemented as load_cr3(rcr3()) when load_cr3() 263 * is inlined. 264 */ 265 __asm __volatile("movl %%cr3, %0; movl %0, %%cr3" : "=r" (temp)); 266} 267 268static __inline u_long 269rcr2(void) 270{ 271 u_long data; 272 273 __asm __volatile("movl %%cr2,%0" : "=r" (data)); 274 return (data); 275} 276 277static __inline u_long 278read_eflags(void) 279{ 280 u_long ef; 281 282 __asm __volatile("pushfl; popl %0" : "=r" (ef)); 283 return (ef); 284} 285 286static __inline void 287write_eflags(u_long ef) 288{ 289 __asm __volatile("pushl %0; popfl" : : "r" (ef)); 290} 291 292/* 293 * XXX queue stuff belongs elsewhere. 294 */ 295struct quehead { 296 struct quehead *qh_link; 297 struct quehead *qh_rlink; 298}; 299 300static __inline void 301insque(void *a, void *b) 302{ 303 struct quehead *element = a, *head = b; 304 305 element->qh_link = head->qh_link; 306 element->qh_rlink = head; 307 head->qh_link = element; 308 element->qh_link->qh_rlink = element; 309} 310 311static __inline void 312remque(void *a) 313{ 314 struct quehead *element = a; 315 316 element->qh_link->qh_rlink = element->qh_rlink; 317 element->qh_rlink->qh_link = element->qh_link; 318 element->qh_rlink = 0; 319} 320 321#else /* !__GNUC__ */ 322 323int bdb __P((void)); 324void disable_intr __P((void)); 325void enable_intr __P((void)); 326u_char inb __P((u_int port)); 327u_long inl __P((u_int port)); 328void insb __P((u_int port, void *addr, size_t cnt)); 329void insl __P((u_int port, void *addr, size_t cnt)); 330void insw __P((u_int port, void *addr, size_t cnt)); 331u_short inw __P((u_int port)); 332u_int loadandclear __P((u_int *addr)); 333void outb __P((u_int port, u_char data)); 334void outl __P((u_int port, u_long data)); 335void outsb __P((u_int port, void *addr, size_t cnt)); 336void outsl __P((u_int port, void *addr, size_t cnt)); 337void outsw __P((u_int port, void *addr, size_t cnt)); 338void outw __P((u_int port, u_short data)); 339void pmap_update __P((void)); 340u_long read_eflags __P((void)); 341u_long rcr2 __P((void)); 342void write_eflags __P((u_long ef)); 343 344void insque __P((void *a, void *b)); 345void remque __P((void *a)); 346 347#endif /* __GNUC__ */ 348 349/* 350 * XXX the following declarations document garbage in support.s. 351 * gcc hasn't needed _divsi* for years. 352 * bcopy[bwx]() was used by pccons but isn't used now. 353 */ 354int __divsi3 __P((int factor1, int factor2)); 355u_int __udivsi3 __P((u_int factor1, u_int factor2)); 356void bcopyb __P((const void *from, void *to, size_t len)); 357void bcopyw __P((const void *from, void *to, size_t len)); 358void bcopyx __P((const void *from, void *to, size_t len, 359 int stride)); 360 361#if 0 362/* 363 * These functions in support.s are declared elsewhere. 364 */ 365void bcopy __P((const void *from, void *to, size_t len)); 366void blkclr __P((void *buf, size_t len)); 367void bzero __P((void *buf, size_t len)); 368int copyin __P((void *udaddr, void *kaddr, size_t len)); 369int copyinstr __P((void *udaddr, void *kaddr, size_t len, 370 size_t *lencopied)); 371int copyout __P((void *kaddr, void *udaddr, size_t len)); 372int copystr __P((void *kfaddr, void *kdaddr, size_t len, 373 size_t *lencopied)); 374int fubyte __P((void *base)); 375int fuswintr __P((void *base)); 376int fuibyte __P((void *base)); 377int fuword __P((void *base)); 378struct region_descriptor; 379void lgdt __P((struct region_descriptor *rdp)); 380void lidt __P((struct region_descriptor *rdp)); 381void lldt __P((u_short sel)); 382/* 383 * longjmp() and setjmp() are only used by ddb. They probably shouldn't 384 * shouldn't be supported in the kernel. 385 */ 386#include <setjmp.h> 387void longjmp __P((jmp_buf jb, int rv)); 388void ovbcopy __P((const void *from, void *to, size_t len); 389int setjmp __P((jmp_buf jb)); 390struct soft_segment_descriptor; 391union descriptor; 392int ssdtosd __P((struct soft_segment_descriptor *ssdp, 393 union descriptor *sdp)); 394int subyte __P((void *base, int byte)); 395int suibyte __P((void *base, int byte)); 396int suswintr __P((void *base, int word)); 397int suword __P((void *base, int word)); 398 399/* 400 * These functions in support.s are declared elsewhere, but never used. 401 * A silly amount of effort went into copyoutstr(). It's not worth 402 * maintaining, since the string length is usually known so copyout 403 * works better, or is easy to find so copyout() can be used. 404 */ 405int copyoutstr __P((void *kaddr, void *udaddr, size_t len, 406 size_t *lencopied)); 407int fuiword __P((void *base)); 408int suiword __P((void *base, int word)); 409 410/* 411 * These functions in support.s are also in libkern.a and are declared in 412 * libkern.h. 413 * ffs() is built in to gcc-2 and was buggy in gcc-2.4.5 so we may may the 414 * buggy version if we don't replace it by an inline. 415 */ 416int bcmp __P((const void *b1, const void *b2, size_t length)); 417int ffs __P((int mask)); 418#endif /* 0 */ 419 420/* 421 * These variables and functions in support.s are used. 422 */ 423extern u_int atdevbase; /* offset in virtual memory of ISA io mem */ 424 425void filli __P((int pat, void *base, size_t cnt)); 426void fillw __P((int /*u_short*/ pat, void *base, size_t cnt)); 427int fusword __P((void *base)); 428void load_cr0 __P((u_long cr0)); 429void load_cr3 __P((u_long cr3)); 430void ltr __P((u_short sel)); 431u_int rcr0 __P((void)); 432u_long rcr3 __P((void)); 433int rtcin __P((int val)); 434 435/* 436 * These functions are NOT in support.s and should be declared elsewhere. 437 */ 438void Debugger __P((const char *msg)); 439u_long kvtop __P((void *addr)); 440typedef void alias_for_inthand_t __P((u_int cs, u_int ef, u_int esp, 441 u_int ss)); 442void setidt __P((int idx, alias_for_inthand_t *func, int typ, 443 int dpl)); 444 445#endif /* !_MACHINE_CPUFUNC_H_ */ 446