<sys/io.h>: add inb()/inw()/inl() and outb()/outw()/outl().
Needed to compile libpciaccess without local modifications, even though
this fallback path isn't used for kernels >= 2.6 from 2003.
There's no obvious way to test these (though on the bright side, they're
inline-only, so there's no real down side to getting them wrong).
See https://www.felixcloutier.com/x86/in and
https://www.felixcloutier.com/x86/out for instruction documentation (but
remember that the compiler uses backwards AT&T syntax rather than the
more sensible Intel syntax on those pages). The constraints are 'a' for
the al/ax/eax register, 'd' for the dx register, and 'N' for the imm8
encoding of the port number.
"Tested" by adding a [not checked in] test and looking at the resulting
assembler.
Bug: http://b/394369994
Change-Id: I2917b920983d55bed2bb14f110484e5cf7a00d21
diff --git a/libc/include/sys/io.h b/libc/include/sys/io.h
index 11f3f3a..472a744 100644
--- a/libc/include/sys/io.h
+++ b/libc/include/sys/io.h
@@ -30,7 +30,7 @@
/**
* @file sys/io.h
- * @brief The x86/x86-64 I/O port functions iopl() and ioperm().
+ * @brief The x86/x86-64 I/O port functions.
*/
#include <sys/cdefs.h>
@@ -72,4 +72,82 @@
}
#endif
+/**
+ * [inb(2)](https://man7.org/linux/man-pages/man2/inb.2.html)
+ * reads a byte from the given x86/x86-64 I/O port.
+ *
+ * Only available for x86/x86-64.
+ */
+#if defined(__i386__) || defined(__x86_64__)
+static __inline unsigned char inb(unsigned short __port) {
+ unsigned char __value;
+ __asm__ __volatile__("inb %1, %0" : "=a"(__value) : "dN"(__port));
+ return __value;
+}
+#endif
+
+/**
+ * [inw(2)](https://man7.org/linux/man-pages/man2/inw.2.html)
+ * reads a 16-bit "word" from the given x86/x86-64 I/O port.
+ *
+ * Only available for x86/x86-64.
+ */
+#if defined(__i386__) || defined(__x86_64__)
+static __inline unsigned short inw(unsigned short __port) {
+ unsigned short __value;
+ __asm__ __volatile__("inw %1, %0" : "=a"(__value) : "dN"(__port));
+ return __value;
+}
+#endif
+
+/**
+ * [inl(2)](https://man7.org/linux/man-pages/man2/inl.2.html)
+ * reads a 32-bit "long word" from the given x86/x86-64 I/O port.
+ *
+ * Only available for x86/x86-64.
+ */
+#if defined(__i386__) || defined(__x86_64__)
+static __inline unsigned int inl(unsigned short __port) {
+ unsigned int __value;
+ __asm__ __volatile__("inl %1, %0" : "=a"(__value) : "dN"(__port));
+ return __value;
+}
+#endif
+
+/**
+ * [outb(2)](https://man7.org/linux/man-pages/man2/outb.2.html)
+ * writes the given byte to the given x86/x86-64 I/O port.
+ *
+ * Only available for x86/x86-64.
+ */
+#if defined(__i386__) || defined(__x86_64__)
+static __inline void outb(unsigned char __value, unsigned short __port) {
+ __asm__ __volatile__("outb %0, %1" : : "a"(__value), "dN"(__port));
+}
+#endif
+
+/**
+ * [outw(2)](https://man7.org/linux/man-pages/man2/outw.2.html)
+ * writes the given 16-bit "word" to the given x86/x86-64 I/O port.
+ *
+ * Only available for x86/x86-64.
+ */
+#if defined(__i386__) || defined(__x86_64__)
+static __inline void outw(unsigned short __value, unsigned short __port) {
+ __asm__ __volatile__("outw %0, %1" : : "a"(__value), "dN"(__port));
+}
+#endif
+
+/**
+ * [outl(2)](https://man7.org/linux/man-pages/man2/outl.2.html)
+ * writes the given 32-bit "long word" to the given x86/x86-64 I/O port.
+ *
+ * Only available for x86/x86-64.
+ */
+#if defined(__i386__) || defined(__x86_64__)
+static __inline void outl(unsigned int __value, unsigned short __port) {
+ __asm__ __volatile__("outl %0, %1" : : "a"(__value), "dN"(__port));
+}
+#endif
+
__END_DECLS