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.
12 #include "i386-io-windows.h"
17 #ifndef STATUS_UNSUCCESSFUL
18 #define STATUS_UNSUCCESSFUL (NTSTATUS)0xC0000001
20 #ifndef STATUS_NOT_IMPLEMENTED
21 #define STATUS_NOT_IMPLEMENTED (NTSTATUS)0xC0000002
23 #ifndef STATUS_INVALID_INFO_CLASS
24 #define STATUS_INVALID_INFO_CLASS (NTSTATUS)0xC0000003
26 #ifndef STATUS_ACCESS_DENIED
27 #define STATUS_ACCESS_DENIED (NTSTATUS)0xC0000022
29 #ifndef STATUS_DEBUGGER_INACTIVE
30 #define STATUS_DEBUGGER_INACTIVE (NTSTATUS)0xC0000354
34 #define BUS_DATA_TYPE LONG
36 #ifndef PCIConfiguration
37 #define PCIConfiguration (BUS_DATA_TYPE)4
40 #ifndef SYSDBG_COMMAND
41 #define SYSDBG_COMMAND ULONG
43 #ifndef SysDbgReadBusData
44 #define SysDbgReadBusData (SYSDBG_COMMAND)18
46 #ifndef SysDbgWriteBusData
47 #define SysDbgWriteBusData (SYSDBG_COMMAND)19
50 #ifndef SYSDBG_BUS_DATA
51 typedef struct _SYSDBG_BUS_DATA {
55 BUS_DATA_TYPE BusDataType;
58 } SYSDBG_BUS_DATA, *PSYSDBG_BUS_DATA;
59 #define SYSDBG_BUS_DATA SYSDBG_BUS_DATA
62 #ifndef PCI_SLOT_NUMBER
63 typedef struct _PCI_SLOT_NUMBER {
67 ULONG FunctionNumber:3;
72 } PCI_SLOT_NUMBER, *PPCI_SLOT_NUMBER;
73 #define PCI_SLOT_NUMBER PCI_SLOT_NUMBER
76 #ifdef NtSystemDebugControl
77 #undef NtSystemDebugControl
79 static NTSTATUS (NTAPI *MyNtSystemDebugControl)(SYSDBG_COMMAND Command, PVOID InputBuffer, ULONG InputBufferLength, PVOID OutputBuffer, ULONG OutputBufferLength, PULONG ReturnLength);
80 #define NtSystemDebugControl MyNtSystemDebugControl
82 static BOOL debug_privilege_enabled;
83 static LUID luid_debug_privilege;
84 static BOOL revert_only_privilege;
85 static HANDLE revert_token;
88 static int win32_sysdbg_initialized;
91 win32_sysdbg_pci_bus_data(BOOL WriteBusData, BYTE BusNumber, BYTE DeviceNumber, BYTE FunctionNumber, BYTE Address, PVOID Buffer, BYTE BufferSize, PULONG Length)
93 SYSDBG_BUS_DATA sysdbg_cmd;
94 PCI_SLOT_NUMBER pci_slot;
96 if (!NtSystemDebugControl)
97 return STATUS_NOT_IMPLEMENTED;
99 memset(&pci_slot, 0, sizeof(pci_slot));
100 memset(&sysdbg_cmd, 0, sizeof(sysdbg_cmd));
102 sysdbg_cmd.Address = Address;
103 sysdbg_cmd.Buffer = Buffer;
104 sysdbg_cmd.Request = BufferSize;
105 sysdbg_cmd.BusDataType = PCIConfiguration;
106 sysdbg_cmd.BusNumber = BusNumber;
107 pci_slot.u.bits.DeviceNumber = DeviceNumber;
108 pci_slot.u.bits.FunctionNumber = FunctionNumber;
109 sysdbg_cmd.SlotNumber = pci_slot.u.AsULONG;
112 return NtSystemDebugControl(WriteBusData ? SysDbgWriteBusData : SysDbgReadBusData, &sysdbg_cmd, sizeof(sysdbg_cmd), NULL, 0, Length);
116 win32_sysdbg_setup(struct pci_access *a)
118 UINT prev_error_mode;
123 if (win32_sysdbg_initialized)
126 prev_error_mode = change_error_mode(SEM_FAILCRITICALERRORS);
127 ntdll = LoadLibrary(TEXT("ntdll.dll"));
128 change_error_mode(prev_error_mode);
131 a->debug("Cannot open ntdll.dll library.");
135 NtSystemDebugControl = (LPVOID)GetProcAddress(ntdll, "NtSystemDebugControl");
136 if (!NtSystemDebugControl)
138 a->debug("Function NtSystemDebugControl() is not supported.");
145 * Try to read PCI id register from PCI device 00:00.0.
146 * If this device does not exist and NT SysDbg API is working then
147 * NT SysDbg returns STATUS_UNSUCCESSFUL.
149 status = win32_sysdbg_pci_bus_data(FALSE, 0, 0, 0, 0, &id, sizeof(id), &ret_len);
150 if ((status >= 0 && ret_len == sizeof(id)) || status == STATUS_UNSUCCESSFUL)
152 win32_sysdbg_initialized = 1;
155 else if (status != STATUS_ACCESS_DENIED)
157 if (status == STATUS_NOT_IMPLEMENTED || status == STATUS_INVALID_INFO_CLASS)
158 a->debug("NT SysDbg is not supported.");
159 else if (status == STATUS_DEBUGGER_INACTIVE)
160 a->debug("NT SysDbg is disabled.");
162 a->debug("NT SysDbg returned error 0x%lx.", status);
165 NtSystemDebugControl = NULL;
169 a->debug("NT SysDbg returned Access Denied, trying again with Debug privilege...");
171 if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid_debug_privilege))
173 a->debug("Debug privilege is not supported.");
176 NtSystemDebugControl = NULL;
180 if (!enable_privilege(luid_debug_privilege, &revert_token, &revert_only_privilege))
182 a->debug("Cannot enable Debug privilege.");
185 NtSystemDebugControl = NULL;
189 status = win32_sysdbg_pci_bus_data(FALSE, 0, 0, 0, 0, &id, sizeof(id), &ret_len);
190 if ((status >= 0 && ret_len == sizeof(id)) || status == STATUS_UNSUCCESSFUL)
192 a->debug("Succeeded.");
193 debug_privilege_enabled = TRUE;
194 win32_sysdbg_initialized = 1;
198 revert_privilege(luid_debug_privilege, revert_token, revert_only_privilege);
200 revert_only_privilege = FALSE;
204 NtSystemDebugControl = NULL;
206 if (status == STATUS_NOT_IMPLEMENTED || status == STATUS_INVALID_INFO_CLASS)
207 a->debug("NT SysDbg is not supported.");
208 else if (status == STATUS_DEBUGGER_INACTIVE)
209 a->debug("NT SysDbg is disabled.");
210 else if (status == STATUS_ACCESS_DENIED)
211 a->debug("NT SysDbg returned Access Denied.");
213 a->debug("NT SysDbg returned error 0x%lx.", status);
219 win32_sysdbg_detect(struct pci_access *a)
221 if (!win32_sysdbg_setup(a))
228 win32_sysdbg_init(struct pci_access *a)
230 if (!win32_sysdbg_setup(a))
233 a->error("NT SysDbg PCI Bus Data interface cannot be accessed.");
238 win32_sysdbg_cleanup(struct pci_access *a UNUSED)
240 if (!win32_sysdbg_initialized)
243 if (debug_privilege_enabled)
245 revert_privilege(luid_debug_privilege, revert_token, revert_only_privilege);
247 revert_only_privilege = FALSE;
248 debug_privilege_enabled = FALSE;
253 NtSystemDebugControl = NULL;
255 win32_sysdbg_initialized = 0;
259 win32_sysdbg_read(struct pci_dev *d, int pos, byte *buf, int len)
264 if ((unsigned int)d->domain > 0 || (unsigned int)pos > 255 || (unsigned int)(pos+len) > 256)
267 status = win32_sysdbg_pci_bus_data(FALSE, d->bus, d->dev, d->func, pos, buf, len, &ret_len);
268 if (status < 0 || ret_len != (unsigned int)len)
275 win32_sysdbg_write(struct pci_dev *d, int pos, byte *buf, int len)
280 if ((unsigned int)d->domain > 0 || (unsigned int)pos > 255 || (unsigned int)(pos+len) > 256)
283 status = win32_sysdbg_pci_bus_data(TRUE, d->bus, d->dev, d->func, pos, buf, len, &ret_len);
284 if (status < 0 || ret_len != (unsigned int)len)
290 struct pci_methods pm_win32_sysdbg = {
292 "Win32 PCI config space access using NT SysDbg Bus Data interface",
296 win32_sysdbg_cleanup,
298 pci_generic_fill_info,
303 NULL /* cleanup_dev */