X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;ds=sidebyside;f=lib%2Fi386-io-linux.h;h=a2fd69e502aaee1688e0830ee62382b55ff344e1;hb=f9447371463eb6bb4c001be132a0d7c495df00d0;hp=1e52d73d8e26308bdef9f863f725b88803e1af37;hpb=c57fd4462d844d86c5686e9ce7919616bcab1402;p=pciutils.git diff --git a/lib/i386-io-linux.h b/lib/i386-io-linux.h index 1e52d73..a2fd69e 100644 --- a/lib/i386-io-linux.h +++ b/lib/i386-io-linux.h @@ -7,16 +7,67 @@ */ #include +#include + +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 int +static inline void intel_cleanup_io(struct pci_access *a UNUSED) { - iopl(3); - return -1; + 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) +{ +} + +static inline void intel_io_unlock(void) +{ }