diff options
author | Martin Mares <mj@ucw.cz> | 2022-11-13 17:05:19 +0100 |
---|---|---|
committer | Martin Mares <mj@ucw.cz> | 2022-11-13 17:05:19 +0100 |
commit | 43c7706c2f233b63c40bb5a4d9c3536310192e0f (patch) | |
tree | 3f1829cfde3688382226c72b87e11f29b9b1a3cb | |
parent | 97c4e9a9433962c18595c53a41a6f361c0ef27b0 (diff) | |
parent | ebd12ed869fd62fcd1cfeaaaed406a80cd1c7ae5 (diff) | |
download | pciutils-43c7706c2f233b63c40bb5a4d9c3536310192e0f.tar.gz |
Merge remote-tracking branch 'pali/linux-ioperm'
-rw-r--r-- | lib/i386-io-linux.h | 48 |
1 files changed, 46 insertions, 2 deletions
diff --git a/lib/i386-io-linux.h b/lib/i386-io-linux.h index 731e8e3..a2fd69e 100644 --- a/lib/i386-io-linux.h +++ b/lib/i386-io-linux.h @@ -7,17 +7,61 @@ */ #include <sys/io.h> +#include <errno.h> + +static int ioperm_enabled; +static int iopl_enabled; static int intel_setup_io(struct pci_access *a UNUSED) { - return (iopl(3) < 0) ? 0 : 1; + if (ioperm_enabled || iopl_enabled) + return 1; + + /* + * Before Linux 2.6.8, only the first 0x3ff I/O ports permissions can be + * modified via ioperm(). Since 2.6.8 all ports are supported. + * Since Linux 5.5, EFLAGS-based iopl() implementation was removed and + * replaced by new TSS-IOPB-map-all-based emulator. Before Linux 5.5, + * EFLAGS-based iopl() allowed userspace to enable/disable interrupts, + * which is dangerous. So prefer usage of ioperm() and fallback to iopl(). + */ + if (ioperm(0xcf8, 8, 1) < 0) /* conf1 + conf2 ports */ + { + if (errno == EINVAL) /* ioperm() unsupported */ + { + if (iopl(3) < 0) + return 0; + iopl_enabled = 1; + return 1; + } + return 0; + } + if (ioperm(0xc000, 0xfff, 1) < 0) /* remaining conf2 ports */ + { + ioperm(0xcf8, 8, 0); + return 0; + } + + ioperm_enabled = 1; + return 1; } static inline void intel_cleanup_io(struct pci_access *a UNUSED) { - iopl(0); + if (ioperm_enabled) + { + ioperm(0xcf8, 8, 0); + ioperm(0xc000, 0xfff, 0); + ioperm_enabled = 0; + } + + if (iopl_enabled) + { + iopl(0); + iopl_enabled = 0; + } } static inline void intel_io_lock(void) |