aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPali Rohár <pali@kernel.org>2023-10-08 15:10:12 +0200
committerGrant Pannell <300992+DigitalDJ@users.noreply.github.com>2023-12-31 01:56:49 +1030
commitcf930fa5ec551e2842a607cd299dd3c061b69d63 (patch)
treefcd120f3f422987f199eaba6c46bee9492a6d04f
parent3d2d69cbc55016c4850ab7333de8e3884ec9d498 (diff)
downloadpciutils-cf930fa5ec551e2842a607cd299dd3c061b69d63.tar.gz
lib: Refactor access to x86 I/O ports
On all systems except BeOS and Haiku are x86 I/O ports accessed in the standard way by the x86 in/out instructions. On more systems there are wrapper functions for x86 in/out instructions but under different names and sometimes even for same system those names depends on user version of toolchain/compiler. And also some systems have same function names but switched order of arguments. Simplify this code, define own wrapper functions for x86 in/out instructions in new header file i386-io-access.h and use it for every platform except BeOS and Haiku. This change simplifies Windows port, duplicated code between SunOS and Windows and also tons of redefined port functions in every port. To not conlict with possible system functions included from some header file, add intel_ prefix for every function included from the file lib/i386-io-access.h into lib/i386-ports.c
-rw-r--r--lib/i386-io-access.h75
-rw-r--r--lib/i386-io-beos.h12
-rw-r--r--lib/i386-io-cygwin.h2
-rw-r--r--lib/i386-io-djgpp.h8
-rw-r--r--lib/i386-io-haiku.h21
-rw-r--r--lib/i386-io-hurd.h2
-rw-r--r--lib/i386-io-linux.h2
-rw-r--r--lib/i386-io-sunos.h44
-rw-r--r--lib/i386-io-windows.h87
-rw-r--r--lib/i386-ports.c58
10 files changed, 135 insertions, 176 deletions
diff --git a/lib/i386-io-access.h b/lib/i386-io-access.h
new file mode 100644
index 0000000..8b1ad5f
--- /dev/null
+++ b/lib/i386-io-access.h
@@ -0,0 +1,75 @@
+/*
+ * The PCI Library -- Compiler-specific wrappers around x86 I/O port access instructions
+ *
+ * Copyright (c) 2023 Pali Rohár <pali@kernel.org>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL v2+
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#if defined(__GNUC__)
+
+static inline unsigned char
+intel_inb(unsigned short int port)
+{
+ unsigned char value;
+ asm volatile ("inb %w1, %0" : "=a" (value) : "Nd" (port));
+ return value;
+}
+
+static inline unsigned short int
+intel_inw(unsigned short int port)
+{
+ unsigned short value;
+ asm volatile ("inw %w1, %0" : "=a" (value) : "Nd" (port));
+ return value;
+}
+
+static inline unsigned int
+intel_inl(unsigned short int port)
+{
+ u32 value;
+ asm volatile ("inl %w1, %0" : "=a" (value) : "Nd" (port));
+ return value;
+}
+
+static inline void
+intel_outb(unsigned char value, unsigned short int port)
+{
+ asm volatile ("outb %b0, %w1" : : "a" (value), "Nd" (port));
+}
+
+static inline void
+intel_outw(unsigned short int value, unsigned short int port)
+{
+ asm volatile ("outw %w0, %w1" : : "a" (value), "Nd" (port));
+}
+
+static inline void
+intel_outl(u32 value, unsigned short int port)
+{
+ asm volatile ("outl %0, %w1" : : "a" (value), "Nd" (port));
+}
+
+#elif defined(_MSC_VER)
+
+#pragma intrinsic(_outp)
+#pragma intrinsic(_outpw)
+#pragma intrinsic(_outpd)
+#pragma intrinsic(_inp)
+#pragma intrinsic(_inpw)
+#pragma intrinsic(_inpd)
+
+#define intel_outb(x, y) _outp(y, x)
+#define intel_outw(x, y) _outpw(y, x)
+#define intel_outl(x, y) _outpd(y, x)
+#define intel_inb(x) _inp(x)
+#define intel_inw(x) _inpw(x)
+#define intel_inl(x) _inpd(x)
+
+#else
+
+#error Do not know how to access I/O ports on this compiler
+
+#endif
diff --git a/lib/i386-io-beos.h b/lib/i386-io-beos.h
index 49b7094..dac0e4b 100644
--- a/lib/i386-io-beos.h
+++ b/lib/i386-io-beos.h
@@ -24,37 +24,37 @@ intel_cleanup_io(struct pci_access *a UNUSED)
}
static inline u8
-inb (u16 port)
+intel_inb (u16 port)
{
return (u8)read_isa_io(0, (void *)(u32)port, sizeof(u8));
}
static inline u16
-inw (u16 port)
+intel_inw (u16 port)
{
return (u16)read_isa_io(0, (void *)(u32)port, sizeof(u16));
}
static inline u32
-inl (u16 port)
+intel_inl (u16 port)
{
return (u32)read_isa_io(0, (void *)(u32)port, sizeof(u32));
}
static inline void
-outb (u8 value, u16 port)
+intel_outb (u8 value, u16 port)
{
write_isa_io(0, (void *)(u32)port, sizeof(value), value);
}
static inline void
-outw (u16 value, u16 port)
+intel_outw (u16 value, u16 port)
{
write_isa_io(0, (void *)(u32)port, sizeof(value), value);
}
static inline void
-outl (u32 value, u16 port)
+intel_outl (u32 value, u16 port)
{
write_isa_io(0, (void *)(u32)port, sizeof(value), value);
}
diff --git a/lib/i386-io-cygwin.h b/lib/i386-io-cygwin.h
index 0b71d16..4118057 100644
--- a/lib/i386-io-cygwin.h
+++ b/lib/i386-io-cygwin.h
@@ -10,6 +10,8 @@
#include <sys/io.h>
+#include "i386-io-access.h"
+
static int
intel_setup_io(struct pci_access *a UNUSED)
{
diff --git a/lib/i386-io-djgpp.h b/lib/i386-io-djgpp.h
index bb29526..1afb00e 100644
--- a/lib/i386-io-djgpp.h
+++ b/lib/i386-io-djgpp.h
@@ -8,15 +8,9 @@
* SPDX-License-Identifier: GPL-2.0-or-later
*/
-#include <pc.h>
#include <dos.h>
-#define outb(x,y) outportb(y, x)
-#define outw(x,y) outportw(y, x)
-#define outl(x,y) outportl(y, x)
-#define inb inportb
-#define inw inportw
-#define inl inportl
+#include "i386-io-access.h"
static int irq_enabled;
diff --git a/lib/i386-io-haiku.h b/lib/i386-io-haiku.h
index ce5362b..23843ea 100644
--- a/lib/i386-io-haiku.h
+++ b/lib/i386-io-haiku.h
@@ -66,6 +66,15 @@ static int poke_driver_fd;
static int
intel_setup_io(struct pci_access *a UNUSED)
{
+ /*
+ * Opening poke device on systems with the linked change below
+ * automatically changes process IOPL to 3 and closing its file
+ * descriptor changes process IOPL back to 0, which give access
+ * to all x86 IO ports via x86 in/out instructions for this
+ * userspace process. To support also older systems without this
+ * change, access IO ports via ioctl() instead of x86 in/out.
+ * https://review.haiku-os.org/c/haiku/+/1077
+ */
poke_driver_fd = open(POKE_DEVICE_FULLNAME, O_RDWR);
return (poke_driver_fd < 0) ? 0 : 1;
}
@@ -77,7 +86,7 @@ intel_cleanup_io(struct pci_access *a UNUSED)
}
static inline u8
-inb (u16 port)
+intel_inb (u16 port)
{
port_io_args args = { POKE_SIGNATURE, port, sizeof(u8), 0 };
if (ioctl(poke_driver_fd, POKE_PORT_READ, &args, sizeof(args)) < 0)
@@ -86,7 +95,7 @@ inb (u16 port)
}
static inline u16
-inw (u16 port)
+intel_inw (u16 port)
{
port_io_args args = { POKE_SIGNATURE, port, sizeof(u16), 0 };
if (ioctl(poke_driver_fd, POKE_PORT_READ, &args, sizeof(args)) < 0)
@@ -95,7 +104,7 @@ inw (u16 port)
}
static inline u32
-inl (u16 port)
+intel_inl (u16 port)
{
port_io_args args = { POKE_SIGNATURE, port, sizeof(u32), 0 };
if (ioctl(poke_driver_fd, POKE_PORT_READ, &args, sizeof(args)) < 0)
@@ -104,21 +113,21 @@ inl (u16 port)
}
static inline void
-outb (u8 value, u16 port)
+intel_outb (u8 value, u16 port)
{
port_io_args args = { POKE_SIGNATURE, port, sizeof(u8), value };
ioctl(poke_driver_fd, POKE_PORT_WRITE, &args, sizeof(args));
}
static inline void
-outw (u16 value, u16 port)
+intel_outw (u16 value, u16 port)
{
port_io_args args = { POKE_SIGNATURE, port, sizeof(u16), value };
ioctl(poke_driver_fd, POKE_PORT_WRITE, &args, sizeof(args));
}
static inline void
-outl (u32 value, u16 port)
+intel_outl (u32 value, u16 port)
{
port_io_args args = { POKE_SIGNATURE, port, sizeof(u32), value };
ioctl(poke_driver_fd, POKE_PORT_WRITE, &args, sizeof(args));
diff --git a/lib/i386-io-hurd.h b/lib/i386-io-hurd.h
index d44b2f5..01d684e 100644
--- a/lib/i386-io-hurd.h
+++ b/lib/i386-io-hurd.h
@@ -14,6 +14,8 @@
#include <sys/io.h>
+#include "i386-io-access.h"
+
static inline int
intel_setup_io(struct pci_access *a UNUSED)
{
diff --git a/lib/i386-io-linux.h b/lib/i386-io-linux.h
index e6bb9b6..317f079 100644
--- a/lib/i386-io-linux.h
+++ b/lib/i386-io-linux.h
@@ -11,6 +11,8 @@
#include <sys/io.h>
#include <errno.h>
+#include "i386-io-access.h"
+
static int ioperm_enabled;
static int iopl_enabled;
diff --git a/lib/i386-io-sunos.h b/lib/i386-io-sunos.h
index 86948d9..99fd576 100644
--- a/lib/i386-io-sunos.h
+++ b/lib/i386-io-sunos.h
@@ -12,6 +12,8 @@
#include <sys/sysi86.h>
#include <sys/psw.h>
+#include "i386-io-access.h"
+
static int
intel_setup_io(struct pci_access *a UNUSED)
{
@@ -24,48 +26,6 @@ intel_cleanup_io(struct pci_access *a UNUSED)
/* FIXME: How to switch off I/O port access? */
}
-static inline u8
-inb (u16 port)
-{
- u8 v;
- __asm__ __volatile__ ("inb (%w1)":"=a" (v):"Nd" (port));
- return v;
-}
-
-static inline u16
-inw (u16 port)
-{
- u16 v;
- __asm__ __volatile__ ("inw (%w1)":"=a" (v):"Nd" (port));
- return v;
-}
-
-static inline u32
-inl (u16 port)
-{
- u32 v;
- __asm__ __volatile__ ("inl (%w1)":"=a" (v):"Nd" (port));
- return v;
-}
-
-static inline void
-outb (u8 value, u16 port)
-{
- __asm__ __volatile__ ("outb (%w1)": :"a" (value), "Nd" (port));
-}
-
-static inline void
-outw (u16 value, u16 port)
-{
- __asm__ __volatile__ ("outw (%w1)": :"a" (value), "Nd" (port));
-}
-
-static inline void
-outl (u32 value, u16 port)
-{
- __asm__ __volatile__ ("outl (%w1)": :"a" (value), "Nd" (port));
-}
-
static inline void intel_io_lock(void)
{
}
diff --git a/lib/i386-io-windows.h b/lib/i386-io-windows.h
index fd1a54e..ef011b1 100644
--- a/lib/i386-io-windows.h
+++ b/lib/i386-io-windows.h
@@ -10,95 +10,10 @@
* SPDX-License-Identifier: GPL-2.0-or-later
*/
-#include <io.h>
#include <windows.h>
#include <aclapi.h>
-#ifdef _MSC_VER
-/* MSVC compiler provides I/O port intrinsics for both 32 and 64-bit modes. */
-#pragma intrinsic(_outp)
-#pragma intrinsic(_outpw)
-#pragma intrinsic(_outpd)
-#pragma intrinsic(_inp)
-#pragma intrinsic(_inpw)
-#pragma intrinsic(_inpd)
-#elif defined(_WIN64) || defined(_UCRT)
-/*
- * For other compilers I/O port intrinsics are available in <intrin.h> header
- * file either as inline/external functions or macros. Beware that <intrin.h>
- * names are different than MSVC intrinsics names and glibc function names.
- * Usage of <intrin.h> is also the prefered way for 64-bit mode or when using
- * new UCRT library.
- */
-#include <intrin.h>
-#define _outp(x,y) __outbyte(x,y)
-#define _outpw(x,y) __outword(x,y)
-#define _outpd(x,y) __outdword(x,y)
-#define _inp(x) __inbyte(x)
-#define _inpw(x) __inword(x)
-#define _inpd(x) __indword(x)
-#elif defined(__CRTDLL__) || (defined(__MSVCRT_VERSION__) && __MSVCRT_VERSION__ < 0x400)
-/*
- * Old 32-bit CRTDLL library and pre-4.00 MSVCRT library do not provide I/O
- * port functions. As these libraries exist only in 32-bit mode variant,
- * implement I/O port functions via 32-bit inline assembly.
- */
-static inline int _outp(unsigned short port, int databyte)
-{
- asm volatile ("outb %b0, %w1" : : "a" (databyte), "Nd" (port));
- return databyte;
-}
-static inline unsigned short _outpw(unsigned short port, unsigned short dataword)
-{
- asm volatile ("outw %w0, %w1" : : "a" (dataword), "Nd" (port));
- return dataword;
-}
-static inline unsigned long _outpd(unsigned short port, unsigned long dataword)
-{
- asm volatile ("outl %0, %w1" : : "a" (dataword), "Nd" (port));
- return dataword;
-}
-static inline int _inp(unsigned short port)
-{
- unsigned char ret;
- asm volatile ("inb %w1, %0" : "=a" (ret) : "Nd" (port));
- return ret;
-}
-static inline unsigned short _inpw(unsigned short port)
-{
- unsigned short ret;
- asm volatile ("inw %w1, %0" : "=a" (ret) : "Nd" (port));
- return ret;
-}
-static inline unsigned long _inpd(unsigned short port)
-{
- unsigned long ret;
- asm volatile ("inl %w1, %0" : "=a" (ret) : "Nd" (port));
- return ret;
-}
-#elif !defined(__GNUC__)
-/*
- * Old 32-bit MSVCRT (non-UCRT) library provides I/O port functions. Function
- * prototypes are defined in <conio.h> header file but they are missing in
- * some MinGW toolchains. So for GCC compiler define them manually.
- */
-#include <conio.h>
-#else
-int _outp(unsigned short port, int databyte);
-unsigned short _outpw(unsigned short port, unsigned short dataword);
-unsigned long _outpd(unsigned short port, unsigned long dataword);
-int _inp(unsigned short port);
-unsigned short _inpw(unsigned short port);
-unsigned long _inpd(unsigned short port);
-#endif
-
-#define outb(x,y) _outp(y,x)
-#define outw(x,y) _outpw(y,x)
-#define outl(x,y) _outpd(y,x)
-
-#define inb(x) _inp(x)
-#define inw(x) _inpw(x)
-#define inl(x) _inpd(x)
+#include "i386-io-access.h"
/*
* Define __readeflags() for MSVC and GCC compilers.
diff --git a/lib/i386-ports.c b/lib/i386-ports.c
index 1e2c402..687dd48 100644
--- a/lib/i386-ports.c
+++ b/lib/i386-ports.c
@@ -116,12 +116,12 @@ conf1_detect(struct pci_access *a)
}
intel_io_lock();
- outb (0x01, 0xCFB);
- tmp = inl (0xCF8);
- outl (0x80000000, 0xCF8);
- if (inl (0xCF8) == 0x80000000)
+ intel_outb (0x01, 0xCFB);
+ tmp = intel_inl (0xCF8);
+ intel_outl (0x80000000, 0xCF8);
+ if (intel_inl (0xCF8) == 0x80000000)
res = 1;
- outl (tmp, 0xCF8);
+ intel_outl (tmp, 0xCF8);
intel_io_unlock();
if (res)
@@ -142,18 +142,18 @@ conf1_read(struct pci_dev *d, int pos, byte *buf, int len)
return pci_generic_block_read(d, pos, buf, len);
intel_io_lock();
- outl(0x80000000 | ((d->bus & 0xff) << 16) | (PCI_DEVFN(d->dev, d->func) << 8) | (pos&~3), 0xcf8);
+ intel_outl(0x80000000 | ((d->bus & 0xff) << 16) | (PCI_DEVFN(d->dev, d->func) << 8) | (pos&~3), 0xcf8);
switch (len)
{
case 1:
- buf[0] = inb(addr);
+ buf[0] = intel_inb(addr);
break;
case 2:
- ((u16 *) buf)[0] = cpu_to_le16(inw(addr));
+ ((u16 *) buf)[0] = cpu_to_le16(intel_inw(addr));
break;
case 4:
- ((u32 *) buf)[0] = cpu_to_le32(inl(addr));
+ ((u32 *) buf)[0] = cpu_to_le32(intel_inl(addr));
break;
}
@@ -174,18 +174,18 @@ conf1_write(struct pci_dev *d, int pos, byte *buf, int len)
return pci_generic_block_write(d, pos, buf, len);
intel_io_lock();
- outl(0x80000000 | ((d->bus & 0xff) << 16) | (PCI_DEVFN(d->dev, d->func) << 8) | (pos&~3), 0xcf8);
+ intel_outl(0x80000000 | ((d->bus & 0xff) << 16) | (PCI_DEVFN(d->dev, d->func) << 8) | (pos&~3), 0xcf8);
switch (len)
{
case 1:
- outb(buf[0], addr);
+ intel_outb(buf[0], addr);
break;
case 2:
- outw(le16_to_cpu(((u16 *) buf)[0]), addr);
+ intel_outw(le16_to_cpu(((u16 *) buf)[0]), addr);
break;
case 4:
- outl(le32_to_cpu(((u32 *) buf)[0]), addr);
+ intel_outl(le32_to_cpu(((u32 *) buf)[0]), addr);
break;
}
intel_io_unlock();
@@ -210,10 +210,10 @@ conf2_detect(struct pci_access *a)
/* This is ugly and tends to produce false positives. Beware. */
intel_io_lock();
- outb(0x00, 0xCFB);
- outb(0x00, 0xCF8);
- outb(0x00, 0xCFA);
- if (inb(0xCF8) == 0x00 && inb(0xCFA) == 0x00)
+ intel_outb(0x00, 0xCFB);
+ intel_outb(0x00, 0xCF8);
+ intel_outb(0x00, 0xCFA);
+ if (intel_inb(0xCF8) == 0x00 && intel_inb(0xCFA) == 0x00)
res = intel_sanity_check(a, &pm_intel_conf2);
intel_io_unlock();
return res;
@@ -236,21 +236,21 @@ conf2_read(struct pci_dev *d, int pos, byte *buf, int len)
return pci_generic_block_read(d, pos, buf, len);
intel_io_lock();
- outb((d->func << 1) | 0xf0, 0xcf8);
- outb(d->bus, 0xcfa);
+ intel_outb((d->func << 1) | 0xf0, 0xcf8);
+ intel_outb(d->bus, 0xcfa);
switch (len)
{
case 1:
- buf[0] = inb(addr);
+ buf[0] = intel_inb(addr);
break;
case 2:
- ((u16 *) buf)[0] = cpu_to_le16(inw(addr));
+ ((u16 *) buf)[0] = cpu_to_le16(intel_inw(addr));
break;
case 4:
- ((u32 *) buf)[0] = cpu_to_le32(inl(addr));
+ ((u32 *) buf)[0] = cpu_to_le32(intel_inl(addr));
break;
}
- outb(0, 0xcf8);
+ intel_outb(0, 0xcf8);
intel_io_unlock();
return res;
}
@@ -272,22 +272,22 @@ conf2_write(struct pci_dev *d, int pos, byte *buf, int len)
return pci_generic_block_write(d, pos, buf, len);
intel_io_lock();
- outb((d->func << 1) | 0xf0, 0xcf8);
- outb(d->bus, 0xcfa);
+ intel_outb((d->func << 1) | 0xf0, 0xcf8);
+ intel_outb(d->bus, 0xcfa);
switch (len)
{
case 1:
- outb(buf[0], addr);
+ intel_outb(buf[0], addr);
break;
case 2:
- outw(le16_to_cpu(* (u16 *) buf), addr);
+ intel_outw(le16_to_cpu(* (u16 *) buf), addr);
break;
case 4:
- outl(le32_to_cpu(* (u32 *) buf), addr);
+ intel_outl(le32_to_cpu(* (u32 *) buf), addr);
break;
}
- outb(0, 0xcf8);
+ intel_outb(0, 0xcf8);
intel_io_unlock();
return res;
}