1 /*
2 * The PCI Library -- Access to i386 I/O ports on Linux
3 *
4 * Copyright (c) 1997--2006 Martin Mares <[email protected]>
5 *
6 * Can be freely distributed and used under the terms of the GNU GPL v2+
7 *
8 * SPDX-License-Identifier: GPL-2.0-or-later
9 */
10
11 #include <sys/io.h>
12 #include <errno.h>
13
14 #include "i386-io-access.h"
15
16 static int ioperm_enabled;
17 static int iopl_enabled;
18
19 static int
intel_setup_io(struct pci_access * a UNUSED)20 intel_setup_io(struct pci_access *a UNUSED)
21 {
22 if (ioperm_enabled || iopl_enabled)
23 return 1;
24
25 /*
26 * Before Linux 2.6.8, only the first 0x3ff I/O ports permissions can be
27 * modified via ioperm(). Since 2.6.8 all ports are supported.
28 * Since Linux 5.5, EFLAGS-based iopl() implementation was removed and
29 * replaced by new TSS-IOPB-map-all-based emulator. Before Linux 5.5,
30 * EFLAGS-based iopl() allowed userspace to enable/disable interrupts,
31 * which is dangerous. So prefer usage of ioperm() and fallback to iopl().
32 */
33 if (ioperm(0xcf8, 8, 1) < 0) /* conf1 + conf2 ports */
34 {
35 if (errno == EINVAL) /* ioperm() unsupported */
36 {
37 if (iopl(3) < 0)
38 return 0;
39 iopl_enabled = 1;
40 return 1;
41 }
42 return 0;
43 }
44 if (ioperm(0xc000, 0xfff, 1) < 0) /* remaining conf2 ports */
45 {
46 ioperm(0xcf8, 8, 0);
47 return 0;
48 }
49
50 ioperm_enabled = 1;
51 return 1;
52 }
53
54 static inline void
intel_cleanup_io(struct pci_access * a UNUSED)55 intel_cleanup_io(struct pci_access *a UNUSED)
56 {
57 if (ioperm_enabled)
58 {
59 ioperm(0xcf8, 8, 0);
60 ioperm(0xc000, 0xfff, 0);
61 ioperm_enabled = 0;
62 }
63
64 if (iopl_enabled)
65 {
66 iopl(0);
67 iopl_enabled = 0;
68 }
69 }
70
intel_io_lock(void)71 static inline void intel_io_lock(void)
72 {
73 }
74
intel_io_unlock(void)75 static inline void intel_io_unlock(void)
76 {
77 }
78