2 * The PCI Library -- PCI config space access using NT SysDbg interface
4 * Copyright (c) 2022 Pali Rohár <pali@kernel.org>
6 * Can be freely distributed and used under the terms of the GNU GPL v2+.
8 * SPDX-License-Identifier: GPL-2.0-or-later
14 #include "i386-io-windows.h"
15 #include "win32-helpers.h"
20 #ifndef STATUS_UNSUCCESSFUL
21 #define STATUS_UNSUCCESSFUL (NTSTATUS)0xC0000001
23 #ifndef STATUS_NOT_IMPLEMENTED
24 #define STATUS_NOT_IMPLEMENTED (NTSTATUS)0xC0000002
26 #ifndef STATUS_INVALID_INFO_CLASS
27 #define STATUS_INVALID_INFO_CLASS (NTSTATUS)0xC0000003
29 #ifndef STATUS_ACCESS_DENIED
30 #define STATUS_ACCESS_DENIED (NTSTATUS)0xC0000022
32 #ifndef STATUS_DEBUGGER_INACTIVE
33 #define STATUS_DEBUGGER_INACTIVE (NTSTATUS)0xC0000354
37 #define BUS_DATA_TYPE LONG
39 #ifndef PCIConfiguration
40 #define PCIConfiguration (BUS_DATA_TYPE)4
43 #ifndef SYSDBG_COMMAND
44 #define SYSDBG_COMMAND ULONG
46 #ifndef SysDbgReadBusData
47 #define SysDbgReadBusData (SYSDBG_COMMAND)18
49 #ifndef SysDbgWriteBusData
50 #define SysDbgWriteBusData (SYSDBG_COMMAND)19
53 #ifndef SYSDBG_BUS_DATA
54 typedef struct _SYSDBG_BUS_DATA {
58 BUS_DATA_TYPE BusDataType;
61 } SYSDBG_BUS_DATA, *PSYSDBG_BUS_DATA;
62 #define SYSDBG_BUS_DATA SYSDBG_BUS_DATA
65 #ifndef PCI_SLOT_NUMBER
66 typedef struct _PCI_SLOT_NUMBER {
70 ULONG FunctionNumber:3;
75 } PCI_SLOT_NUMBER, *PPCI_SLOT_NUMBER;
76 #define PCI_SLOT_NUMBER PCI_SLOT_NUMBER
79 #ifdef NtSystemDebugControl
80 #undef NtSystemDebugControl
82 static NTSTATUS (NTAPI *MyNtSystemDebugControl)(SYSDBG_COMMAND Command, PVOID InputBuffer, ULONG InputBufferLength, PVOID OutputBuffer, ULONG OutputBufferLength, PULONG ReturnLength);
83 #define NtSystemDebugControl MyNtSystemDebugControl
85 static BOOL debug_privilege_enabled;
86 static LUID luid_debug_privilege;
87 static BOOL revert_only_privilege;
88 static HANDLE revert_token;
91 static int win32_sysdbg_initialized;
94 win32_sysdbg_pci_bus_data(BOOL WriteBusData, BYTE BusNumber, BYTE DeviceNumber, BYTE FunctionNumber, BYTE Address, PVOID Buffer, BYTE BufferSize, PULONG Length)
96 SYSDBG_BUS_DATA sysdbg_cmd;
97 PCI_SLOT_NUMBER pci_slot;
99 if (!NtSystemDebugControl)
100 return STATUS_NOT_IMPLEMENTED;
102 memset(&pci_slot, 0, sizeof(pci_slot));
103 memset(&sysdbg_cmd, 0, sizeof(sysdbg_cmd));
105 sysdbg_cmd.Address = Address;
106 sysdbg_cmd.Buffer = Buffer;
107 sysdbg_cmd.Request = BufferSize;
108 sysdbg_cmd.BusDataType = PCIConfiguration;
109 sysdbg_cmd.BusNumber = BusNumber;
110 pci_slot.u.bits.DeviceNumber = DeviceNumber;
111 pci_slot.u.bits.FunctionNumber = FunctionNumber;
112 sysdbg_cmd.SlotNumber = pci_slot.u.AsULONG;
115 return NtSystemDebugControl(WriteBusData ? SysDbgWriteBusData : SysDbgReadBusData, &sysdbg_cmd, sizeof(sysdbg_cmd), NULL, 0, Length);
119 win32_sysdbg_setup(struct pci_access *a)
121 UINT prev_error_mode;
126 if (win32_sysdbg_initialized)
129 prev_error_mode = change_error_mode(SEM_FAILCRITICALERRORS);
130 ntdll = LoadLibrary(TEXT("ntdll.dll"));
131 change_error_mode(prev_error_mode);
134 a->debug("Cannot open ntdll.dll library.");
138 NtSystemDebugControl = (LPVOID)GetProcAddress(ntdll, "NtSystemDebugControl");
139 if (!NtSystemDebugControl)
141 a->debug("Function NtSystemDebugControl() is not supported.");
148 * Try to read PCI id register from PCI device 00:00.0.
149 * If this device does not exist and NT SysDbg API is working then
150 * NT SysDbg returns STATUS_UNSUCCESSFUL.
152 status = win32_sysdbg_pci_bus_data(FALSE, 0, 0, 0, 0, &id, sizeof(id), &ret_len);
153 if ((status >= 0 && ret_len == sizeof(id)) || status == STATUS_UNSUCCESSFUL)
155 win32_sysdbg_initialized = 1;
158 else if (status != STATUS_ACCESS_DENIED)
160 if (status == STATUS_NOT_IMPLEMENTED || status == STATUS_INVALID_INFO_CLASS)
161 a->debug("NT SysDbg is not supported.");
162 else if (status == STATUS_DEBUGGER_INACTIVE)
163 a->debug("NT SysDbg is disabled.");
165 a->debug("NT SysDbg returned error 0x%lx.", status);
168 NtSystemDebugControl = NULL;
172 a->debug("NT SysDbg returned Access Denied, trying again with Debug privilege...");
174 if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid_debug_privilege))
176 a->debug("Debug privilege is not supported.");
179 NtSystemDebugControl = NULL;
183 if (!enable_privilege(luid_debug_privilege, &revert_token, &revert_only_privilege))
185 a->debug("Cannot enable Debug privilege.");
188 NtSystemDebugControl = NULL;
192 status = win32_sysdbg_pci_bus_data(FALSE, 0, 0, 0, 0, &id, sizeof(id), &ret_len);
193 if ((status >= 0 && ret_len == sizeof(id)) || status == STATUS_UNSUCCESSFUL)
195 a->debug("Succeeded.");
196 debug_privilege_enabled = TRUE;
197 win32_sysdbg_initialized = 1;
201 revert_privilege(luid_debug_privilege, revert_token, revert_only_privilege);
203 revert_only_privilege = FALSE;
207 NtSystemDebugControl = NULL;
209 if (status == STATUS_NOT_IMPLEMENTED || status == STATUS_INVALID_INFO_CLASS)
210 a->debug("NT SysDbg is not supported.");
211 else if (status == STATUS_DEBUGGER_INACTIVE)
212 a->debug("NT SysDbg is disabled.");
213 else if (status == STATUS_ACCESS_DENIED)
214 a->debug("NT SysDbg returned Access Denied.");
216 a->debug("NT SysDbg returned error 0x%lx.", status);
222 win32_sysdbg_detect(struct pci_access *a)
224 if (!win32_sysdbg_setup(a))
231 win32_sysdbg_init(struct pci_access *a)
233 if (!win32_sysdbg_setup(a))
236 a->error("NT SysDbg PCI Bus Data interface cannot be accessed.");
241 win32_sysdbg_cleanup(struct pci_access *a UNUSED)
243 if (!win32_sysdbg_initialized)
246 if (debug_privilege_enabled)
248 revert_privilege(luid_debug_privilege, revert_token, revert_only_privilege);
250 revert_only_privilege = FALSE;
251 debug_privilege_enabled = FALSE;
256 NtSystemDebugControl = NULL;
258 win32_sysdbg_initialized = 0;
262 win32_sysdbg_read(struct pci_dev *d, int pos, byte *buf, int len)
267 if ((unsigned int)d->domain > 0 || (unsigned int)pos > 255 || (unsigned int)(pos+len) > 256)
270 status = win32_sysdbg_pci_bus_data(FALSE, d->bus, d->dev, d->func, pos, buf, len, &ret_len);
271 if (status < 0 || ret_len != (unsigned int)len)
278 win32_sysdbg_write(struct pci_dev *d, int pos, byte *buf, int len)
283 if ((unsigned int)d->domain > 0 || (unsigned int)pos > 255 || (unsigned int)(pos+len) > 256)
286 status = win32_sysdbg_pci_bus_data(TRUE, d->bus, d->dev, d->func, pos, buf, len, &ret_len);
287 if (status < 0 || ret_len != (unsigned int)len)
293 struct pci_methods pm_win32_sysdbg = {
295 "Win32 PCI config space access using NT SysDbg Bus Data interface",
299 win32_sysdbg_cleanup,
301 pci_generic_fill_info,
306 NULL /* cleanup_dev */