cpufunc.h revision 13086
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.43 1995/12/19 14:30:42 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" : : : "memory"); 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 * The following complications are to get around gcc not having a 105 * constraint letter for the range 0..255. We still put "d" in the 106 * constraint because "i" isn't a valid constraint when the port 107 * isn't constant. This only matters for -O0 because otherwise 108 * the non-working version gets optimized away. 109 * 110 * Use an expression-statement instead of a conditional expression 111 * because gcc-2.6.0 would promote the operands of the conditional 112 * and produce poor code for "if ((inb(var) & const1) == const2)". 113 */ 114#define inb(port) ({ \ 115 u_char _data; \ 116 if (__builtin_constant_p((int) (port)) && (port) < 256ul) \ 117 _data = inbc(port); \ 118 else \ 119 _data = inbv(port); \ 120 _data; }) 121 122#define outb(port, data) \ 123 (__builtin_constant_p((int) (port)) && (port) < 256ul \ 124 ? outbc(port, data) : outbv(port, data)) 125 126static __inline u_char 127inbc(u_int port) 128{ 129 u_char data; 130 131 __asm __volatile("inb %1,%0" : "=a" (data) : "id" ((u_short)(port))); 132 return (data); 133} 134 135static __inline void 136outbc(u_int port, u_char data) 137{ 138 __asm __volatile("outb %0,%1" : : "a" (data), "id" ((u_short)(port))); 139} 140 141#endif /* __GNUC <= 2 */ 142 143static __inline u_char 144inbv(u_int port) 145{ 146 u_char data; 147 /* 148 * We use %%dx and not %1 here because i/o is done at %dx and not at 149 * %edx, while gcc generates inferior code (movw instead of movl) 150 * if we tell it to load (u_short) port. 151 */ 152 __asm __volatile("inb %%dx,%0" : "=a" (data) : "d" (port)); 153 return (data); 154} 155 156static __inline u_long 157inl(u_int port) 158{ 159 u_long data; 160 161 __asm __volatile("inl %%dx,%0" : "=a" (data) : "d" (port)); 162 return (data); 163} 164 165static __inline void 166insb(u_int port, void *addr, size_t cnt) 167{ 168 __asm __volatile("cld; rep; insb" 169 : : "d" (port), "D" (addr), "c" (cnt) 170 : "di", "cx", "memory"); 171} 172 173static __inline void 174insw(u_int port, void *addr, size_t cnt) 175{ 176 __asm __volatile("cld; rep; insw" 177 : : "d" (port), "D" (addr), "c" (cnt) 178 : "di", "cx", "memory"); 179} 180 181static __inline void 182insl(u_int port, void *addr, size_t cnt) 183{ 184 __asm __volatile("cld; rep; insl" 185 : : "d" (port), "D" (addr), "c" (cnt) 186 : "di", "cx", "memory"); 187} 188 189static __inline u_short 190inw(u_int port) 191{ 192 u_short data; 193 194 __asm __volatile("inw %%dx,%0" : "=a" (data) : "d" (port)); 195 return (data); 196} 197 198static __inline unsigned 199loadandclear(u_int *addr) 200{ 201 u_int result; 202 203 __asm __volatile("xorl %0,%0; xchgl %1,%0" 204 : "=&r" (result) : "m" (*addr)); 205 return (result); 206} 207 208static __inline void 209outbv(u_int port, u_char data) 210{ 211 u_char al; 212 /* 213 * Use an unnecessary assignment to help gcc's register allocator. 214 * This make a large difference for gcc-1.40 and a tiny difference 215 * for gcc-2.6.0. For gcc-1.40, al had to be ``asm("ax")'' for 216 * best results. gcc-2.6.0 can't handle this. 217 */ 218 al = data; 219 __asm __volatile("outb %0,%%dx" : : "a" (al), "d" (port)); 220} 221 222static __inline void 223outl(u_int port, u_long data) 224{ 225 /* 226 * outl() and outw() aren't used much so we haven't looked at 227 * possible micro-optimizations such as the unnecessary 228 * assignment for them. 229 */ 230 __asm __volatile("outl %0,%%dx" : : "a" (data), "d" (port)); 231} 232 233static __inline void 234outsb(u_int port, void *addr, size_t cnt) 235{ 236 __asm __volatile("cld; rep; outsb" 237 : : "d" (port), "S" (addr), "c" (cnt) 238 : "si", "cx"); 239} 240 241static __inline void 242outsw(u_int port, void *addr, size_t cnt) 243{ 244 __asm __volatile("cld; rep; outsw" 245 : : "d" (port), "S" (addr), "c" (cnt) 246 : "si", "cx"); 247} 248 249static __inline void 250outsl(u_int port, void *addr, size_t cnt) 251{ 252 __asm __volatile("cld; rep; outsl" 253 : : "d" (port), "S" (addr), "c" (cnt) 254 : "si", "cx"); 255} 256 257static __inline void 258outw(u_int port, u_short data) 259{ 260 __asm __volatile("outw %0,%%dx" : : "a" (data), "d" (port)); 261} 262 263static __inline void 264pmap_update(void) 265{ 266 u_long temp; 267 /* 268 * This should be implemented as load_cr3(rcr3()) when load_cr3() 269 * is inlined. 270 */ 271 __asm __volatile("movl %%cr3, %0; movl %0, %%cr3" : "=r" (temp) 272 : : "memory"); 273} 274 275static __inline u_long 276rcr2(void) 277{ 278 u_long data; 279 280 __asm __volatile("movl %%cr2,%0" : "=r" (data)); 281 return (data); 282} 283 284static __inline u_long 285read_eflags(void) 286{ 287 u_long ef; 288 289 __asm __volatile("pushfl; popl %0" : "=r" (ef)); 290 return (ef); 291} 292 293static __inline void 294write_eflags(u_long ef) 295{ 296 __asm __volatile("pushl %0; popfl" : : "r" (ef)); 297} 298 299#else /* !__GNUC__ */ 300 301int bdb __P((void)); 302void disable_intr __P((void)); 303void enable_intr __P((void)); 304u_char inb __P((u_int port)); 305u_long inl __P((u_int port)); 306void insb __P((u_int port, void *addr, size_t cnt)); 307void insl __P((u_int port, void *addr, size_t cnt)); 308void insw __P((u_int port, void *addr, size_t cnt)); 309u_short inw __P((u_int port)); 310u_int loadandclear __P((u_int *addr)); 311void outb __P((u_int port, u_char data)); 312void outl __P((u_int port, u_long data)); 313void outsb __P((u_int port, void *addr, size_t cnt)); 314void outsl __P((u_int port, void *addr, size_t cnt)); 315void outsw __P((u_int port, void *addr, size_t cnt)); 316void outw __P((u_int port, u_short data)); 317void pmap_update __P((void)); 318u_long read_eflags __P((void)); 319u_long rcr2 __P((void)); 320void write_eflags __P((u_long ef)); 321 322#endif /* __GNUC__ */ 323 324/* 325 * XXX the following declarations document garbage in support.s. 326 * bcopy[bwx]() was used by pccons but isn't used now. 327 */ 328void bcopyb __P((const void *from, void *to, size_t len)); 329void bcopyw __P((const void *from, void *to, size_t len)); 330void bcopyx __P((const void *from, void *to, size_t len, 331 int stride)); 332/* 333 * These variables and functions in support.s are used. 334 */ 335extern u_int atdevbase; /* offset in virtual memory of ISA io mem */ 336 337void filli __P((int pat, void *base, size_t cnt)); 338void fillw __P((int /*u_short*/ pat, void *base, size_t cnt)); 339int fusword __P((void *base)); 340void load_cr0 __P((u_long cr0)); 341void load_cr3 __P((u_long cr3)); 342void ltr __P((u_short sel)); 343u_int rcr0 __P((void)); 344u_long rcr3 __P((void)); 345int rtcin __P((int val)); 346 347/* 348 * These functions are NOT in support.s and should be declared elsewhere. 349 */ 350void Debugger __P((const char *msg)); 351u_long kvtop __P((void *addr)); 352typedef void alias_for_inthand_t __P((u_int cs, u_int ef, u_int esp, 353 u_int ss)); 354void setidt __P((int idx, alias_for_inthand_t *func, int typ, 355 int dpl, int selec)); 356 357#endif /* !_MACHINE_CPUFUNC_H_ */ 358