1*c2e0c6b5SAndroid Build Coastguard Worker /*
2*c2e0c6b5SAndroid Build Coastguard Worker * The PCI Library -- Access to i386 I/O ports on Windows
3*c2e0c6b5SAndroid Build Coastguard Worker *
4*c2e0c6b5SAndroid Build Coastguard Worker * Copyright (c) 2004 Alexander Stock <[email protected]>
5*c2e0c6b5SAndroid Build Coastguard Worker * Copyright (c) 2006 Martin Mares <[email protected]>
6*c2e0c6b5SAndroid Build Coastguard Worker * Copyright (c) 2021 Pali Rohár <[email protected]>
7*c2e0c6b5SAndroid Build Coastguard Worker *
8*c2e0c6b5SAndroid Build Coastguard Worker * Can be freely distributed and used under the terms of the GNU GPL v2+
9*c2e0c6b5SAndroid Build Coastguard Worker *
10*c2e0c6b5SAndroid Build Coastguard Worker * SPDX-License-Identifier: GPL-2.0-or-later
11*c2e0c6b5SAndroid Build Coastguard Worker */
12*c2e0c6b5SAndroid Build Coastguard Worker
13*c2e0c6b5SAndroid Build Coastguard Worker #include <windows.h>
14*c2e0c6b5SAndroid Build Coastguard Worker #include "win32-helpers.h"
15*c2e0c6b5SAndroid Build Coastguard Worker
16*c2e0c6b5SAndroid Build Coastguard Worker #include "i386-io-access.h"
17*c2e0c6b5SAndroid Build Coastguard Worker
18*c2e0c6b5SAndroid Build Coastguard Worker /*
19*c2e0c6b5SAndroid Build Coastguard Worker * Define __readeflags() for MSVC and GCC compilers.
20*c2e0c6b5SAndroid Build Coastguard Worker * MSVC since version 14.00 included in WDK 6001 and since version 15.00
21*c2e0c6b5SAndroid Build Coastguard Worker * included in VS 2008 provides __readeflags() intrinsic for both 32 and 64-bit
22*c2e0c6b5SAndroid Build Coastguard Worker * modes. WDK 6001 defines macro __BUILDMACHINE__ to value WinDDK. VS 2008 does
23*c2e0c6b5SAndroid Build Coastguard Worker * not define this macro at all. MSVC throws error if name of user defined
24*c2e0c6b5SAndroid Build Coastguard Worker * function conflicts with some MSVC intrinsic.
25*c2e0c6b5SAndroid Build Coastguard Worker * MSVC supports inline assembly via __asm keyword in 32-bit mode only.
26*c2e0c6b5SAndroid Build Coastguard Worker * GCC version 4.9.0 and higher provides __builtin_ia32_readeflags_uXX()
27*c2e0c6b5SAndroid Build Coastguard Worker * builtin for XX-mode. This builtin is also available as __readeflags()
28*c2e0c6b5SAndroid Build Coastguard Worker * function indirectly via <x86intrin.h> header file.
29*c2e0c6b5SAndroid Build Coastguard Worker *
30*c2e0c6b5SAndroid Build Coastguard Worker * CAVEAT: Semicolon in MSVC __asm block means start of the comment, and not
31*c2e0c6b5SAndroid Build Coastguard Worker * end of the __asm statement, like it is for all other C statements. Also
32*c2e0c6b5SAndroid Build Coastguard Worker * function which uses MSVC inline assembly cannot be inlined to another function
33*c2e0c6b5SAndroid Build Coastguard Worker * (compiler reports a warning about it, not a fatal error). So we add explicit
34*c2e0c6b5SAndroid Build Coastguard Worker * curly brackets for __asm blocks, remove misleading semicolons and do not
35*c2e0c6b5SAndroid Build Coastguard Worker * declare functions as inline.
36*c2e0c6b5SAndroid Build Coastguard Worker */
37*c2e0c6b5SAndroid Build Coastguard Worker #if defined(_MSC_VER) && (_MSC_VER >= 1500 || (_MSC_VER >= 1400 && defined(__BUILDMACHINE__)))
38*c2e0c6b5SAndroid Build Coastguard Worker #pragma intrinsic(__readeflags)
39*c2e0c6b5SAndroid Build Coastguard Worker #elif defined(__GNUC__) && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 9) || (__GNUC__ > 4))
40*c2e0c6b5SAndroid Build Coastguard Worker #include <x86intrin.h>
41*c2e0c6b5SAndroid Build Coastguard Worker #elif defined(_MSC_VER) && defined(_M_IX86)
42*c2e0c6b5SAndroid Build Coastguard Worker static unsigned int
__readeflags(void)43*c2e0c6b5SAndroid Build Coastguard Worker __readeflags(void)
44*c2e0c6b5SAndroid Build Coastguard Worker {
45*c2e0c6b5SAndroid Build Coastguard Worker __asm {
46*c2e0c6b5SAndroid Build Coastguard Worker pushfd
47*c2e0c6b5SAndroid Build Coastguard Worker pop eax
48*c2e0c6b5SAndroid Build Coastguard Worker }
49*c2e0c6b5SAndroid Build Coastguard Worker }
50*c2e0c6b5SAndroid Build Coastguard Worker #elif defined(__GNUC__)
51*c2e0c6b5SAndroid Build Coastguard Worker static inline unsigned
52*c2e0c6b5SAndroid Build Coastguard Worker #ifdef __x86_64__
53*c2e0c6b5SAndroid Build Coastguard Worker long long
54*c2e0c6b5SAndroid Build Coastguard Worker #endif
55*c2e0c6b5SAndroid Build Coastguard Worker int
__readeflags(void)56*c2e0c6b5SAndroid Build Coastguard Worker __readeflags(void)
57*c2e0c6b5SAndroid Build Coastguard Worker {
58*c2e0c6b5SAndroid Build Coastguard Worker unsigned
59*c2e0c6b5SAndroid Build Coastguard Worker #ifdef __x86_64__
60*c2e0c6b5SAndroid Build Coastguard Worker long long
61*c2e0c6b5SAndroid Build Coastguard Worker #endif
62*c2e0c6b5SAndroid Build Coastguard Worker int eflags;
63*c2e0c6b5SAndroid Build Coastguard Worker asm volatile ("pushf\n\tpop %0\n" : "=r" (eflags));
64*c2e0c6b5SAndroid Build Coastguard Worker return eflags;
65*c2e0c6b5SAndroid Build Coastguard Worker }
66*c2e0c6b5SAndroid Build Coastguard Worker #else
67*c2e0c6b5SAndroid Build Coastguard Worker #error "Unsupported compiler"
68*c2e0c6b5SAndroid Build Coastguard Worker #endif
69*c2e0c6b5SAndroid Build Coastguard Worker
70*c2e0c6b5SAndroid Build Coastguard Worker /* Read IOPL of the current process, IOPL is stored in eflag bits [13:12]. */
71*c2e0c6b5SAndroid Build Coastguard Worker #define read_iopl() ((__readeflags() >> 12) & 0x3)
72*c2e0c6b5SAndroid Build Coastguard Worker
73*c2e0c6b5SAndroid Build Coastguard Worker /*
74*c2e0c6b5SAndroid Build Coastguard Worker * Unfortunately NtSetInformationProcess() function, ProcessUserModeIOPL
75*c2e0c6b5SAndroid Build Coastguard Worker * constant and all other helpers for its usage are not specified in any
76*c2e0c6b5SAndroid Build Coastguard Worker * standard WinAPI header file. So define all of required constants and types.
77*c2e0c6b5SAndroid Build Coastguard Worker * Function NtSetInformationProcess() is available in ntdll.dll library on all
78*c2e0c6b5SAndroid Build Coastguard Worker * Windows systems but marked as it can be removed in some future version.
79*c2e0c6b5SAndroid Build Coastguard Worker */
80*c2e0c6b5SAndroid Build Coastguard Worker #ifndef NTSTATUS
81*c2e0c6b5SAndroid Build Coastguard Worker #define NTSTATUS LONG
82*c2e0c6b5SAndroid Build Coastguard Worker #endif
83*c2e0c6b5SAndroid Build Coastguard Worker #ifndef STATUS_NOT_IMPLEMENTED
84*c2e0c6b5SAndroid Build Coastguard Worker #define STATUS_NOT_IMPLEMENTED (NTSTATUS)0xC0000002
85*c2e0c6b5SAndroid Build Coastguard Worker #endif
86*c2e0c6b5SAndroid Build Coastguard Worker #ifndef STATUS_PRIVILEGE_NOT_HELD
87*c2e0c6b5SAndroid Build Coastguard Worker #define STATUS_PRIVILEGE_NOT_HELD (NTSTATUS)0xC0000061
88*c2e0c6b5SAndroid Build Coastguard Worker #endif
89*c2e0c6b5SAndroid Build Coastguard Worker #ifndef PROCESSINFOCLASS
90*c2e0c6b5SAndroid Build Coastguard Worker #define PROCESSINFOCLASS DWORD
91*c2e0c6b5SAndroid Build Coastguard Worker #endif
92*c2e0c6b5SAndroid Build Coastguard Worker #ifndef ProcessUserModeIOPL
93*c2e0c6b5SAndroid Build Coastguard Worker #define ProcessUserModeIOPL 16
94*c2e0c6b5SAndroid Build Coastguard Worker #endif
95*c2e0c6b5SAndroid Build Coastguard Worker typedef NTSTATUS (NTAPI *NtSetInformationProcessProt)(HANDLE ProcessHandle, PROCESSINFOCLASS ProcessInformationClass, PVOID ProcessInformation, ULONG ProcessInformationLength);
96*c2e0c6b5SAndroid Build Coastguard Worker typedef ULONG (NTAPI *RtlNtStatusToDosErrorProt)(NTSTATUS Status);
97*c2e0c6b5SAndroid Build Coastguard Worker
98*c2e0c6b5SAndroid Build Coastguard Worker /*
99*c2e0c6b5SAndroid Build Coastguard Worker * ProcessUserModeIOPL is syscall for NT kernel to change x86 IOPL
100*c2e0c6b5SAndroid Build Coastguard Worker * of the current running process to 3.
101*c2e0c6b5SAndroid Build Coastguard Worker *
102*c2e0c6b5SAndroid Build Coastguard Worker * Process handle argument for ProcessUserModeIOPL is ignored and
103*c2e0c6b5SAndroid Build Coastguard Worker * IOPL is always changed for the current running process. So pass
104*c2e0c6b5SAndroid Build Coastguard Worker * GetCurrentProcess() handle for documentation purpose. Process
105*c2e0c6b5SAndroid Build Coastguard Worker * information buffer and length are unused for ProcessUserModeIOPL.
106*c2e0c6b5SAndroid Build Coastguard Worker *
107*c2e0c6b5SAndroid Build Coastguard Worker * ProcessUserModeIOPL may success (return value >= 0) or may fail
108*c2e0c6b5SAndroid Build Coastguard Worker * because it is not implemented or because of missing privilege.
109*c2e0c6b5SAndroid Build Coastguard Worker * Other errors are not defined, so handle them as unknown.
110*c2e0c6b5SAndroid Build Coastguard Worker */
111*c2e0c6b5SAndroid Build Coastguard Worker static BOOL
SetProcessUserModeIOPLFunc(LPVOID Arg)112*c2e0c6b5SAndroid Build Coastguard Worker SetProcessUserModeIOPLFunc(LPVOID Arg)
113*c2e0c6b5SAndroid Build Coastguard Worker {
114*c2e0c6b5SAndroid Build Coastguard Worker RtlNtStatusToDosErrorProt RtlNtStatusToDosErrorPtr = (RtlNtStatusToDosErrorProt)(((LPVOID *)Arg)[1]);
115*c2e0c6b5SAndroid Build Coastguard Worker NtSetInformationProcessProt NtSetInformationProcessPtr = (NtSetInformationProcessProt)(((LPVOID *)Arg)[0]);
116*c2e0c6b5SAndroid Build Coastguard Worker NTSTATUS nt_status = NtSetInformationProcessPtr(GetCurrentProcess(), ProcessUserModeIOPL, NULL, 0);
117*c2e0c6b5SAndroid Build Coastguard Worker if (nt_status >= 0)
118*c2e0c6b5SAndroid Build Coastguard Worker return TRUE;
119*c2e0c6b5SAndroid Build Coastguard Worker
120*c2e0c6b5SAndroid Build Coastguard Worker /*
121*c2e0c6b5SAndroid Build Coastguard Worker * If we have optional RtlNtStatusToDosError() function then use it for
122*c2e0c6b5SAndroid Build Coastguard Worker * translating NT status to Win32 error. If we do not have it then translate
123*c2e0c6b5SAndroid Build Coastguard Worker * two important status codes which we use later STATUS_NOT_IMPLEMENTED and
124*c2e0c6b5SAndroid Build Coastguard Worker * STATUS_PRIVILEGE_NOT_HELD.
125*c2e0c6b5SAndroid Build Coastguard Worker */
126*c2e0c6b5SAndroid Build Coastguard Worker if (RtlNtStatusToDosErrorPtr)
127*c2e0c6b5SAndroid Build Coastguard Worker SetLastError(RtlNtStatusToDosErrorPtr(nt_status));
128*c2e0c6b5SAndroid Build Coastguard Worker else if (nt_status == STATUS_NOT_IMPLEMENTED)
129*c2e0c6b5SAndroid Build Coastguard Worker SetLastError(ERROR_INVALID_FUNCTION);
130*c2e0c6b5SAndroid Build Coastguard Worker else if (nt_status == STATUS_PRIVILEGE_NOT_HELD)
131*c2e0c6b5SAndroid Build Coastguard Worker SetLastError(ERROR_PRIVILEGE_NOT_HELD);
132*c2e0c6b5SAndroid Build Coastguard Worker else
133*c2e0c6b5SAndroid Build Coastguard Worker SetLastError(ERROR_GEN_FAILURE);
134*c2e0c6b5SAndroid Build Coastguard Worker
135*c2e0c6b5SAndroid Build Coastguard Worker return FALSE;
136*c2e0c6b5SAndroid Build Coastguard Worker }
137*c2e0c6b5SAndroid Build Coastguard Worker
138*c2e0c6b5SAndroid Build Coastguard Worker /*
139*c2e0c6b5SAndroid Build Coastguard Worker * Set x86 I/O Privilege Level to 3 for the whole current NT process. Do it via
140*c2e0c6b5SAndroid Build Coastguard Worker * NtSetInformationProcess() call with ProcessUserModeIOPL information class,
141*c2e0c6b5SAndroid Build Coastguard Worker * which is supported by 32-bit Windows NT kernel versions and requires Tcb
142*c2e0c6b5SAndroid Build Coastguard Worker * privilege.
143*c2e0c6b5SAndroid Build Coastguard Worker */
144*c2e0c6b5SAndroid Build Coastguard Worker static BOOL
SetProcessUserModeIOPL(VOID)145*c2e0c6b5SAndroid Build Coastguard Worker SetProcessUserModeIOPL(VOID)
146*c2e0c6b5SAndroid Build Coastguard Worker {
147*c2e0c6b5SAndroid Build Coastguard Worker LPVOID Arg[2];
148*c2e0c6b5SAndroid Build Coastguard Worker UINT prev_error_mode;
149*c2e0c6b5SAndroid Build Coastguard Worker HMODULE ntdll;
150*c2e0c6b5SAndroid Build Coastguard Worker BOOL ret;
151*c2e0c6b5SAndroid Build Coastguard Worker
152*c2e0c6b5SAndroid Build Coastguard Worker /*
153*c2e0c6b5SAndroid Build Coastguard Worker * Load ntdll.dll library with disabled critical-error-handler and
154*c2e0c6b5SAndroid Build Coastguard Worker * file-not-found message box.
155*c2e0c6b5SAndroid Build Coastguard Worker * It means that NT kernel does not show unwanted GUI message box to user
156*c2e0c6b5SAndroid Build Coastguard Worker * when LoadLibrary() function fails.
157*c2e0c6b5SAndroid Build Coastguard Worker */
158*c2e0c6b5SAndroid Build Coastguard Worker prev_error_mode = win32_change_error_mode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
159*c2e0c6b5SAndroid Build Coastguard Worker ntdll = LoadLibrary(TEXT("ntdll.dll"));
160*c2e0c6b5SAndroid Build Coastguard Worker win32_change_error_mode(prev_error_mode);
161*c2e0c6b5SAndroid Build Coastguard Worker if (!ntdll)
162*c2e0c6b5SAndroid Build Coastguard Worker {
163*c2e0c6b5SAndroid Build Coastguard Worker SetLastError(ERROR_INVALID_FUNCTION);
164*c2e0c6b5SAndroid Build Coastguard Worker return FALSE;
165*c2e0c6b5SAndroid Build Coastguard Worker }
166*c2e0c6b5SAndroid Build Coastguard Worker
167*c2e0c6b5SAndroid Build Coastguard Worker /* Retrieve pointer to NtSetInformationProcess() function. */
168*c2e0c6b5SAndroid Build Coastguard Worker Arg[0] = (LPVOID)GetProcAddress(ntdll, "NtSetInformationProcess");
169*c2e0c6b5SAndroid Build Coastguard Worker if (!Arg[0])
170*c2e0c6b5SAndroid Build Coastguard Worker {
171*c2e0c6b5SAndroid Build Coastguard Worker FreeLibrary(ntdll);
172*c2e0c6b5SAndroid Build Coastguard Worker SetLastError(ERROR_INVALID_FUNCTION);
173*c2e0c6b5SAndroid Build Coastguard Worker return FALSE;
174*c2e0c6b5SAndroid Build Coastguard Worker }
175*c2e0c6b5SAndroid Build Coastguard Worker
176*c2e0c6b5SAndroid Build Coastguard Worker /* Retrieve pointer to optional RtlNtStatusToDosError() function, it may be NULL. */
177*c2e0c6b5SAndroid Build Coastguard Worker Arg[1] = (LPVOID)GetProcAddress(ntdll, "RtlNtStatusToDosError");
178*c2e0c6b5SAndroid Build Coastguard Worker
179*c2e0c6b5SAndroid Build Coastguard Worker /* Call ProcessUserModeIOPL with Tcb privilege. */
180*c2e0c6b5SAndroid Build Coastguard Worker ret = win32_call_func_with_tcb_privilege(SetProcessUserModeIOPLFunc, (LPVOID)&Arg);
181*c2e0c6b5SAndroid Build Coastguard Worker
182*c2e0c6b5SAndroid Build Coastguard Worker FreeLibrary(ntdll);
183*c2e0c6b5SAndroid Build Coastguard Worker
184*c2e0c6b5SAndroid Build Coastguard Worker if (!ret)
185*c2e0c6b5SAndroid Build Coastguard Worker return FALSE;
186*c2e0c6b5SAndroid Build Coastguard Worker
187*c2e0c6b5SAndroid Build Coastguard Worker /*
188*c2e0c6b5SAndroid Build Coastguard Worker * Some Windows NT kernel versions (e.g. Windows 2003 x64) do not
189*c2e0c6b5SAndroid Build Coastguard Worker * implement ProcessUserModeIOPL syscall at all but incorrectly
190*c2e0c6b5SAndroid Build Coastguard Worker * returns success when it is called by user process. So always
191*c2e0c6b5SAndroid Build Coastguard Worker * after this call verify that IOPL is set to 3.
192*c2e0c6b5SAndroid Build Coastguard Worker */
193*c2e0c6b5SAndroid Build Coastguard Worker if (read_iopl() != 3)
194*c2e0c6b5SAndroid Build Coastguard Worker {
195*c2e0c6b5SAndroid Build Coastguard Worker SetLastError(ERROR_INVALID_FUNCTION);
196*c2e0c6b5SAndroid Build Coastguard Worker return FALSE;
197*c2e0c6b5SAndroid Build Coastguard Worker }
198*c2e0c6b5SAndroid Build Coastguard Worker
199*c2e0c6b5SAndroid Build Coastguard Worker return TRUE;
200*c2e0c6b5SAndroid Build Coastguard Worker }
201*c2e0c6b5SAndroid Build Coastguard Worker
202*c2e0c6b5SAndroid Build Coastguard Worker static int
intel_setup_io(struct pci_access * a)203*c2e0c6b5SAndroid Build Coastguard Worker intel_setup_io(struct pci_access *a)
204*c2e0c6b5SAndroid Build Coastguard Worker {
205*c2e0c6b5SAndroid Build Coastguard Worker #ifndef _WIN64
206*c2e0c6b5SAndroid Build Coastguard Worker /* 16/32-bit non-NT systems allow applications to access PCI I/O ports without any special setup. */
207*c2e0c6b5SAndroid Build Coastguard Worker if (win32_is_non_nt_system())
208*c2e0c6b5SAndroid Build Coastguard Worker {
209*c2e0c6b5SAndroid Build Coastguard Worker a->debug("Detected 16/32-bit non-NT system, skipping NT setup...");
210*c2e0c6b5SAndroid Build Coastguard Worker return 1;
211*c2e0c6b5SAndroid Build Coastguard Worker }
212*c2e0c6b5SAndroid Build Coastguard Worker #endif
213*c2e0c6b5SAndroid Build Coastguard Worker
214*c2e0c6b5SAndroid Build Coastguard Worker /* Check if we have I/O permission */
215*c2e0c6b5SAndroid Build Coastguard Worker if (read_iopl() == 3)
216*c2e0c6b5SAndroid Build Coastguard Worker {
217*c2e0c6b5SAndroid Build Coastguard Worker a->debug("IOPL is already set to 3, skipping NT setup...");
218*c2e0c6b5SAndroid Build Coastguard Worker return 1;
219*c2e0c6b5SAndroid Build Coastguard Worker }
220*c2e0c6b5SAndroid Build Coastguard Worker
221*c2e0c6b5SAndroid Build Coastguard Worker /* On NT-based systems issue ProcessUserModeIOPL syscall which changes IOPL to 3. */
222*c2e0c6b5SAndroid Build Coastguard Worker if (!SetProcessUserModeIOPL())
223*c2e0c6b5SAndroid Build Coastguard Worker {
224*c2e0c6b5SAndroid Build Coastguard Worker DWORD error = GetLastError();
225*c2e0c6b5SAndroid Build Coastguard Worker a->debug("NT ProcessUserModeIOPL call failed: %s.", error == ERROR_INVALID_FUNCTION ? "Call is not supported" : win32_strerror(error));
226*c2e0c6b5SAndroid Build Coastguard Worker return 0;
227*c2e0c6b5SAndroid Build Coastguard Worker }
228*c2e0c6b5SAndroid Build Coastguard Worker
229*c2e0c6b5SAndroid Build Coastguard Worker a->debug("NT ProcessUserModeIOPL call succeeded...");
230*c2e0c6b5SAndroid Build Coastguard Worker return 1;
231*c2e0c6b5SAndroid Build Coastguard Worker }
232*c2e0c6b5SAndroid Build Coastguard Worker
233*c2e0c6b5SAndroid Build Coastguard Worker static inline void
intel_cleanup_io(struct pci_access * a UNUSED)234*c2e0c6b5SAndroid Build Coastguard Worker intel_cleanup_io(struct pci_access *a UNUSED)
235*c2e0c6b5SAndroid Build Coastguard Worker {
236*c2e0c6b5SAndroid Build Coastguard Worker /*
237*c2e0c6b5SAndroid Build Coastguard Worker * 16/32-bit non-NT systems do not use any special setup and on NT-based
238*c2e0c6b5SAndroid Build Coastguard Worker * systems ProcessUserModeIOPL permanently changes IOPL to 3 for the current
239*c2e0c6b5SAndroid Build Coastguard Worker * NT process, no revert for current process is possible.
240*c2e0c6b5SAndroid Build Coastguard Worker */
241*c2e0c6b5SAndroid Build Coastguard Worker }
242*c2e0c6b5SAndroid Build Coastguard Worker
intel_io_lock(void)243*c2e0c6b5SAndroid Build Coastguard Worker static inline void intel_io_lock(void)
244*c2e0c6b5SAndroid Build Coastguard Worker {
245*c2e0c6b5SAndroid Build Coastguard Worker }
246*c2e0c6b5SAndroid Build Coastguard Worker
intel_io_unlock(void)247*c2e0c6b5SAndroid Build Coastguard Worker static inline void intel_io_unlock(void)
248*c2e0c6b5SAndroid Build Coastguard Worker {
249*c2e0c6b5SAndroid Build Coastguard Worker }
250