+ 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;