aboutsummaryrefslogtreecommitdiff
path: root/sys/amd64/include
diff options
context:
space:
mode:
authorBruce Evans <bde@FreeBSD.org>1994-11-14 15:04:06 +0000
committerBruce Evans <bde@FreeBSD.org>1994-11-14 15:04:06 +0000
commit004bedeb68174a591553291cc84a3753aec4cdac (patch)
tree89377e8c7a2a7f6a05c325f10e4fa2e3d86c54e2 /sys/amd64/include
parent663f148514e167ab452351a757b007a17a0dc871 (diff)
Notes
Diffstat (limited to 'sys/amd64/include')
-rw-r--r--sys/amd64/include/cpufunc.h433
1 files changed, 300 insertions, 133 deletions
diff --git a/sys/amd64/include/cpufunc.h b/sys/amd64/include/cpufunc.h
index 60586a439d12c..cc6f9de62e158 100644
--- a/sys/amd64/include/cpufunc.h
+++ b/sys/amd64/include/cpufunc.h
@@ -30,238 +30,405 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- *
- * Portions:
- * Copyright (c) 1993 Charles Hannum.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Charles Hannum.
- * 4. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *
- * $Id: cpufunc.h,v 1.27 1994/09/25 21:31:55 davidg Exp $
+ * $Id: cpufunc.h,v 1.28 1994/11/09 00:51:38 bde Exp $
*/
-
/*
* Functions to provide access to special i386 instructions.
- * XXX - bezillions more are defined in locore.s but are not declared anywhere.
*/
#ifndef _MACHINE_CPUFUNC_H_
-#define _MACHINE_CPUFUNC_H_ 1
+#define _MACHINE_CPUFUNC_H_
#include <sys/cdefs.h>
#include <sys/types.h>
-#include <machine/spl.h>
+#include <machine/spl.h> /* XXX belongs elsewhere */
#ifdef __GNUC__
-static __inline void
-insb(u_short port, void *addr, int cnt)
+#ifdef BDE_DEBUGGER
+extern int bdb_exists;
+
+static __inline int
+bdb(void)
{
- __asm __volatile("cld;repne;insb" :
- : "d" (port), "D" (addr), "c" (cnt) : "%edi", "%ecx", "memory");
+ if (!bdb_exists)
+ return (0);
+ __asm __volatile("int $3");
+ return (1);
}
+#endif /* BDE_DEBUGGER */
static __inline void
-insw(u_short port, void *addr, int cnt)
+disable_intr(void)
{
- __asm __volatile("cld;repne;insw" :
- : "d" (port), "D" (addr), "c" (cnt) : "%edi", "%ecx", "memory");
+ __asm __volatile("cli");
}
static __inline void
-insl(u_short port, void *addr, int cnt)
+enable_intr(void)
{
- __asm __volatile("cld;repne;insl" :
- : "d" (port), "D" (addr), "c" (cnt) : "%edi", "%ecx", "memory");
+ __asm __volatile("sti");
}
-static __inline void
-outsb(u_short port, void *addr, int cnt)
+#define HAVE_INLINE_FFS
+
+static __inline int
+ffs(int mask)
{
- __asm __volatile("cld;repne;outsb" :
- : "d" (port), "S" (addr), "c" (cnt) : "%esi", "%ecx");
+ int result;
+ /*
+ * bsfl turns out to be not all that slow on 486's. It can beaten
+ * using a binary search to reduce to 4 bits and then a table lookup,
+ * but only if the code is inlined and in the cache, and the code
+ * is quite large so inlining it probably busts the cache.
+ *
+ * Note that gcc-2's builtin ffs would be used if we didn't declare
+ * this inline or turn off the builtin. The builtin is faster but
+ * broken in gcc-2.4.5 and slower but working in gcc-2.5 and 2.6.
+ */
+ __asm __volatile("testl %0,%0; je 1f; bsfl %0,%0; incl %0; 1:"
+ : "=r" (result) : "0" (mask));
+ return (result);
}
-static __inline void
-outsw(u_short port, void *addr, int cnt)
+#if __GNUC__ < 2
+
+#define inb(port) inbv(port)
+#define outb(port, data) outbv(port, data)
+
+#else /* __GNUC >= 2 */
+
+/*
+ * Use an expression-statement instead of a conditional expression
+ * because gcc-2.6.0 would promote the operands of the conditional
+ * and produce poor code for "if ((inb(var) & const1) == const2)".
+ */
+#define inb(port) ({ \
+ u_char _data; \
+ if (__builtin_constant_p((int) (port)) && (port) < 256ul) \
+ _data = inbc(port); \
+ else \
+ _data = inbv(port); \
+ _data; })
+
+#define outb(port, data) \
+ (__builtin_constant_p((int) (port)) && (port) < 256ul \
+ ? outbc(port, data) : outbv(port, data))
+
+static __inline u_char
+inbc(u_int port)
{
- __asm __volatile("cld;repne;outsw" :
- : "d" (port), "S" (addr), "c" (cnt) : "%esi", "%ecx");
+ u_char data;
+
+ __asm __volatile("inb %1,%0" : "=a" (data) : "i" (port));
+ return (data);
}
static __inline void
-outsl(u_short port, void *addr, int cnt)
+outbc(u_int port, u_char data)
{
- __asm __volatile("cld;repne;outsl" :
- : "d" (port), "S" (addr), "c" (cnt) : "%esi", "%ecx");
+ __asm __volatile("outb %0,%1" : : "a" (data), "i" (port));
}
-static inline u_char
-inb(u_short port)
-{
- u_char data;
+#endif /* __GNUC <= 2 */
- __asm __volatile("inb %1,%0" : "=a" (data) : "d" (port));
- return data;
+static __inline u_char
+inbv(u_int port)
+{
+ u_char data;
+ /*
+ * We use %%dx and not %1 here because i/o is done at %dx and not at
+ * %edx, while gcc generates inferior code (movw instead of movl)
+ * if we tell it to load (u_short) port.
+ */
+ __asm __volatile("inb %%dx,%0" : "=a" (data) : "d" (port));
+ return (data);
}
-static inline u_short
-inw(u_short port)
+static __inline u_long
+inl(u_int port)
{
- u_short data;
+ u_long data;
- __asm __volatile("inw %1,%0" : "=a" (data) : "d" (port));
- return data;
+ __asm __volatile("inl %%dx,%0" : "=a" (data) : "d" (port));
+ return (data);
}
-static inline u_long
-inl(u_short port)
+static __inline void
+insb(u_int port, void *addr, size_t cnt)
{
- u_long data;
-
- __asm __volatile("inl %1,%0" : "=a" (data) : "d" (port));
- return data;
+ __asm __volatile("cld; rep; insb"
+ : : "d" (port), "D" (addr), "c" (cnt)
+ : "di", "cx", "memory");
}
-static inline void
-outb(u_short port, u_char val)
+static __inline void
+insw(u_int port, void *addr, size_t cnt)
{
- __asm __volatile("outb %0,%1" : :"a" (val), "d" (port));
+ __asm __volatile("cld; rep; insw"
+ : : "d" (port), "D" (addr), "c" (cnt)
+ : "di", "cx", "memory");
}
-static inline void
-outw(u_short port, u_short val)
+static __inline void
+insl(u_int port, void *addr, size_t cnt)
{
- __asm __volatile("outw %0,%1" : :"a" (val), "d" (port));
+ __asm __volatile("cld; rep; insl"
+ : : "d" (port), "D" (addr), "c" (cnt)
+ : "di", "cx", "memory");
}
-static inline void
-outl(u_short port, u_long val)
+static __inline u_short
+inw(u_int port)
{
- __asm __volatile("outl %0,%1" : :"a" (val), "d" (port));
+ u_short data;
+
+ __asm __volatile("inw %%dx,%0" : "=a" (data) : "d" (port));
+ return (data);
}
-static inline int bdb(void)
+static __inline void
+outbv(u_int port, u_char data)
{
- extern int bdb_exists;
+ u_char al;
+ /*
+ * Use an unnecessary assignment to help gcc's register allocator.
+ * This make a large difference for gcc-1.40 and a tiny difference
+ * for gcc-2.6.0. For gcc-1.40, al had to be ``asm("ax")'' for
+ * best results. gcc-2.6.0 can't handle this.
+ */
+ al = data;
+ __asm __volatile("outb %0,%%dx" : : "a" (al), "d" (port));
+}
- if (!bdb_exists)
- return (0);
- __asm("int $3");
- return (1);
+static __inline void
+outl(u_int port, u_long data)
+{
+ /*
+ * outl() and outw() aren't used much so we haven't looked at
+ * possible micro-optimizations such as the unnecessary
+ * assignment for them.
+ */
+ __asm __volatile("outl %0,%%dx" : : "a" (data), "d" (port));
}
-static inline void
-disable_intr(void)
+static __inline void
+outsb(u_int port, void *addr, size_t cnt)
{
- __asm __volatile("cli");
+ __asm __volatile("cld; rep; outsb"
+ : : "d" (port), "S" (addr), "c" (cnt)
+ : "di", "cx");
}
-static inline void
-enable_intr(void)
+static __inline void
+outsw(u_int port, void *addr, size_t cnt)
{
- __asm __volatile("sti");
+ __asm __volatile("cld; rep; outsw"
+ : : "d" (port), "S" (addr), "c" (cnt)
+ : "di", "cx");
}
-static inline u_long
-read_eflags()
+static __inline void
+outsl(u_int port, void *addr, size_t cnt)
{
- u_long ef;
- __asm __volatile("pushf; popl %0" : "=a" (ef));
- return(ef);
+ __asm __volatile("cld; rep; outsl"
+ : : "d" (port), "S" (addr), "c" (cnt)
+ : "di", "cx");
}
-static inline void
-write_eflags(u_long ef)
+static __inline void
+outw(u_int port, u_short data)
{
- __asm __volatile("pushl %0; popf" : : "a" ((u_long) ef));
+ __asm __volatile("outw %0,%%dx" : : "a" (data), "d" (port));
}
-static inline void
-pmap_update()
+static __inline void
+pmap_update(void)
{
- __asm __volatile("movl %%cr3, %%eax; movl %%eax, %%cr3" : : : "ax");
+ u_long temp;
+ /*
+ * This should be implemented as load_cr3(rcr3()) when load_cr3()
+ * is inlined.
+ */
+ __asm __volatile("movl %%cr3, %0; movl %0, %%cr3" : "=r" (temp));
}
-static inline u_long
-rcr2()
+static __inline u_long
+rcr2(void)
{
u_long data;
- __asm __volatile("movl %%cr2,%%eax" : "=a" (data));
- return data;
+
+ __asm __volatile("movl %%cr2,%0" : "=r" (data));
+ return (data);
+}
+
+static __inline u_long
+read_eflags(void)
+{
+ u_long ef;
+
+ __asm __volatile("pushfl; popl %0" : "=r" (ef));
+ return (ef);
+}
+
+static __inline void
+write_eflags(u_long ef)
+{
+ __asm __volatile("pushl %0; popfl" : : "r" (ef));
}
+/*
+ * XXX queue stuff belongs elsewhere.
+ */
struct quehead {
struct quehead *qh_link;
struct quehead *qh_rlink;
};
-static inline void
+static __inline void
insque(void *a, void *b)
{
- register struct quehead *element = a, *head = b;
+ struct quehead *element = a, *head = b;
+
element->qh_link = head->qh_link;
- head->qh_link = (struct quehead *)element;
- element->qh_rlink = (struct quehead *)head;
- ((struct quehead *)(element->qh_link))->qh_rlink
- = (struct quehead *)element;
+ head->qh_link = element;
+ element->qh_rlink = head;
+ element->qh_link->qh_rlink = element;
}
-static inline void
+static __inline void
remque(void *a)
{
- register struct quehead *element = a;
- ((struct quehead *)(element->qh_link))->qh_rlink = element->qh_rlink;
- ((struct quehead *)(element->qh_rlink))->qh_link = element->qh_link;
+ struct quehead *element = a;
+
+ element->qh_link->qh_rlink = element->qh_rlink;
+ element->qh_rlink->qh_link = element->qh_link;
element->qh_rlink = 0;
}
-#else /* not __GNUC__ */
-extern void insque __P((void *, void *));
-extern void remque __P((void *));
+#else /* !__GNUC__ */
int bdb __P((void));
void disable_intr __P((void));
void enable_intr __P((void));
u_char inb __P((u_int port));
-void outb __P((u_int port, u_int data)); /* XXX - incompat */
+u_long inl __P((u_int port));
+void insb __P((u_int port, void *addr, size_t cnt));
+void insl __P((u_int port, void *addr, size_t cnt));
+void insw __P((u_int port, void *addr, size_t cnt));
+u_short inw __P((u_int port));
+void outb __P((u_int port, u_char data));
+void outl __P((u_int port, u_long data));
+void outsb __P((u_int port, void *addr, size_t cnt));
+void outsl __P((u_int port, void *addr, size_t cnt));
+void outsw __P((u_int port, void *addr, size_t cnt));
+void outw __P((u_int port, u_short data));
+void void pmap_update __P((void));
+u_long read_eflags __P((void));
+u_long rcr2 __P((void));
+void write_eflags __P((u_long ef));
+
+void insque __P((void *a, void *b));
+void remque __P((void *a))
#endif /* __GNUC__ */
-void load_cr0 __P((u_int cr0));
-u_int rcr0 __P((void));
-void load_cr3(u_long);
-u_long rcr3(void);
+/*
+ * XXX the following declarations document garbage in support.s.
+ * gcc hasn't needed _divsi* for years.
+ * bcopy[bwx]() was used by pccons but isn't used now.
+ */
+int __divsi3 __P((int factor1, int factor2));
+u_int __udivsi3 __P((u_int factor1, u_int factor2));
+void bcopyb __P((const void *from, void *to, size_t len));
+void bcopyw __P((const void *from, void *to, size_t len));
+void bcopyx __P((const void *from, void *to, size_t len,
+ int stride));
+
+#if 0
+/*
+ * These functions in support.s are declared elsewhere.
+ */
+void bcopy __P((const void *from, void *to, size_t len));
+void blkclr __P((void *buf, size_t len));
+void bzero __P((void *buf, size_t len));
+int copyin __P((void *udaddr, void *kaddr, size_t len));
+int copyinstr __P((void *udaddr, void *kaddr, size_t len,
+ size_t *lencopied));
+int copyout __P((void *kaddr, void *udaddr, size_t len));
+int copystr __P((void *kfaddr, void *kdaddr, size_t len,
+ size_t *lencopied));
+int fubyte __P((void *base));
+int fuswintr __P((void *base));
+int fuibyte __P((void *base));
+int fuword __P((void *base));
+struct region_descriptor;
+void lgdt __P((struct region_descriptor *rdp));
+void lidt __P((struct region_descriptor *rdp));
+void lldt __P((u_short sel));
+/*
+ * longjmp() and setjmp() are only used by ddb. They probably shouldn't
+ * shouldn't be supported in the kernel.
+ */
+#include <setjmp.h>
+void longjmp __P((jmp_buf jb, int rv));
+void ovbcopy __P((const void *from, void *to, size_t len);
+int setjmp __P((jmp_buf jb));
+struct soft_segment_descriptor;
+union descriptor;
+int ssdtosd __P((struct soft_segment_descriptor *ssdp,
+ union descriptor *sdp));
+int subyte __P((void *base, int byte));
+int suibyte __P((void *base, int byte));
+int suswintr __P((void *base, int word));
+int suword __P((void *base, int word));
+
+/*
+ * These functions in support.s are declared elsewhere, but never used.
+ * A silly amount of effort went into copyoutstr(). It's not worth
+ * maintaining, since the string length is usually known so copyout
+ * works better, or is easy to find so copyout() can be used.
+ */
+int copyoutstr __P((void *kaddr, void *udaddr, size_t len,
+ size_t *lencopied));
+int fuiword __P((void *base));
+int suiword __P((void *base, int word));
+
+/*
+ * These functions in support.s are also in libkern.a and are declared in
+ * libkern.h.
+ * ffs() is built in to gcc-2 and was buggy in gcc-2.4.5 so we may may the
+ * buggy version if we don't replace it by an inline.
+ */
+int bcmp __P((const void *b1, const void *b2, size_t length));
+int ffs __P((int mask));
+#endif /* 0 */
+
+/*
+ * These variables and functions in support.s are used.
+ */
+extern u_int atdevbase; /* offset in virtual memory of ISA io mem */
+
+void filli __P((int pat, void *base, size_t cnt));
+void fillw __P((int /*u_short*/ pat, void *base, size_t cnt));
+int fusword __P((void *base));
+void load_cr0 __P((u_long cr0));
+void load_cr3 __P((u_long cr3));
+void ltr __P((u_short sel));
+u_int rcr0 __P((void));
+u_long rcr3 __P((void));
+int rtcin __P((int val));
+int susword __P((void *base, int word));
-void setidt __P((int, void (*)(), int, int));
-extern u_long kvtop(void *);
-extern void fillw(int /*u_short*/, void *, size_t);
-extern void filli(int, void *, size_t);
+/*
+ * These functions are NOT in support.s and should be declared elsewhere.
+ */
+u_long kvtop __P((void *addr));
+typedef void alias_for_inthand_t __P((u_int cs, u_int ef, u_int esp,
+ u_int ss));
+void setidt __P((int idx, alias_for_inthand_t *func, int typ,
+ int dpl));
-#endif /* _MACHINE_CPUFUNC_H_ */
+#endif /* !_MACHINE_CPUFUNC_H_ */