summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Mares <mj@ucw.cz>2022-10-30 13:34:44 +0100
committerMartin Mares <mj@ucw.cz>2022-10-30 13:34:44 +0100
commita165591213039657f65a466ba1762e02a1c6e310 (patch)
tree036bbae9d57447b5929f182109e73e86d58bbcbb
parent3711e86f10643442d13f5e49d0c8ae73d380ab6a (diff)
parent963d7cb7cd7133ba8e4662e69c50177654311cf1 (diff)
downloadpciutils-a165591213039657f65a466ba1762e02a1c6e310.tar.gz
Merge remote-tracking branch 'pali/win32-sysdbg'
-rw-r--r--lib/Makefile5
-rwxr-xr-xlib/configure3
-rw-r--r--lib/init.c6
-rw-r--r--lib/internal.h2
-rw-r--r--lib/pci.h1
-rw-r--r--lib/win32-sysdbg.c304
-rw-r--r--pcilib.man7
7 files changed, 326 insertions, 2 deletions
diff --git a/lib/Makefile b/lib/Makefile
index b29a48f..400c32d 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -59,6 +59,10 @@ OBJS += emulated
OBJS += win32-cfgmgr32
endif
+ifdef PCI_HAVE_PM_WIN32_SYSDBG
+OBJS += win32-sysdbg
+endif
+
all: $(PCILIB) $(PCILIBPC)
ifeq ($(SHARED),no)
@@ -108,6 +112,7 @@ filter.o: filter.c $(INCL)
nbsd-libpci.o: nbsd-libpci.c $(INCL)
hurd.o: hurd.c $(INCL)
win32-cfgmgr32.o: win32-cfgmgr32.c $(INCL)
+win32-sysdbg.o: win32-sysdbg.c $(INCL)
# MinGW32 toolchain has some required Win32 header files in /ddk subdirectory.
# But these header files include another header files from /ddk subdirectory
diff --git a/lib/configure b/lib/configure
index 45a416a..2c74d9d 100755
--- a/lib/configure
+++ b/lib/configure
@@ -145,9 +145,10 @@ case $sys in
EXEEXT=.exe
;;
cygwin|windows)
- echo_n " win32-cfgmgr32"
+ echo_n " win32-cfgmgr32 win32-sysdbg"
echo >>$c '#define PCI_HAVE_64BIT_ADDRESS'
echo >>$c '#define PCI_HAVE_PM_WIN32_CFGMGR32'
+ echo >>$c '#define PCI_HAVE_PM_WIN32_SYSDBG'
# Warning: MinGW-w64 (incorrectly) provides cfgmgr32 functions
# also in other import libraries, not only in libcfgmgr32.a.
# So always set -lcfgmgr32 as a first library parameter which
diff --git a/lib/init.c b/lib/init.c
index f997b2b..de7d6f2 100644
--- a/lib/init.c
+++ b/lib/init.c
@@ -81,6 +81,11 @@ static struct pci_methods *pci_methods[PCI_ACCESS_MAX] = {
#else
NULL,
#endif
+#ifdef PCI_HAVE_PM_WIN32_SYSDBG
+ &pm_win32_sysdbg,
+#else
+ NULL,
+#endif
};
// If PCI_ACCESS_AUTO is selected, we probe the access methods in this order
@@ -96,6 +101,7 @@ static int probe_sequence[] = {
PCI_ACCESS_SYLIXOS_DEVICE,
PCI_ACCESS_HURD,
PCI_ACCESS_WIN32_CFGMGR32,
+ PCI_ACCESS_WIN32_SYSDBG,
// Low-level methods poking the hardware directly
PCI_ACCESS_I386_TYPE1,
PCI_ACCESS_I386_TYPE2,
diff --git a/lib/internal.h b/lib/internal.h
index e0185dd..0a5dce4 100644
--- a/lib/internal.h
+++ b/lib/internal.h
@@ -116,4 +116,4 @@ void pci_free_caps(struct pci_dev *);
extern struct pci_methods pm_intel_conf1, pm_intel_conf2, pm_linux_proc,
pm_fbsd_device, pm_aix_device, pm_nbsd_libpci, pm_obsd_device,
pm_dump, pm_linux_sysfs, pm_darwin, pm_sylixos_device, pm_hurd,
- pm_win32_cfgmgr32;
+ pm_win32_cfgmgr32, pm_win32_sysdbg;
diff --git a/lib/pci.h b/lib/pci.h
index eeb4a55..41a162b 100644
--- a/lib/pci.h
+++ b/lib/pci.h
@@ -44,6 +44,7 @@ enum pci_access_type {
PCI_ACCESS_SYLIXOS_DEVICE, /* SylixOS pci */
PCI_ACCESS_HURD, /* GNU/Hurd */
PCI_ACCESS_WIN32_CFGMGR32, /* Win32 cfgmgr32.dll */
+ PCI_ACCESS_WIN32_SYSDBG, /* Win32 NT SysDbg */
PCI_ACCESS_MAX
};
diff --git a/lib/win32-sysdbg.c b/lib/win32-sysdbg.c
new file mode 100644
index 0000000..5d0c07a
--- /dev/null
+++ b/lib/win32-sysdbg.c
@@ -0,0 +1,304 @@
+/*
+ * The PCI Library -- PCI config space access using NT SysDbg interface
+ *
+ * Copyright (c) 2022 Pali Rohár <pali@kernel.org>
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include <windows.h>
+
+#include "internal.h"
+#include "i386-io-windows.h"
+
+#ifndef NTSTATUS
+#define NTSTATUS LONG
+#endif
+#ifndef STATUS_UNSUCCESSFUL
+#define STATUS_UNSUCCESSFUL (NTSTATUS)0xC0000001
+#endif
+#ifndef STATUS_NOT_IMPLEMENTED
+#define STATUS_NOT_IMPLEMENTED (NTSTATUS)0xC0000002
+#endif
+#ifndef STATUS_INVALID_INFO_CLASS
+#define STATUS_INVALID_INFO_CLASS (NTSTATUS)0xC0000003
+#endif
+#ifndef STATUS_ACCESS_DENIED
+#define STATUS_ACCESS_DENIED (NTSTATUS)0xC0000022
+#endif
+#ifndef STATUS_DEBUGGER_INACTIVE
+#define STATUS_DEBUGGER_INACTIVE (NTSTATUS)0xC0000354
+#endif
+
+#ifndef BUS_DATA_TYPE
+#define BUS_DATA_TYPE LONG
+#endif
+#ifndef PCIConfiguration
+#define PCIConfiguration (BUS_DATA_TYPE)4
+#endif
+
+#ifndef SYSDBG_COMMAND
+#define SYSDBG_COMMAND ULONG
+#endif
+#ifndef SysDbgReadBusData
+#define SysDbgReadBusData (SYSDBG_COMMAND)18
+#endif
+#ifndef SysDbgWriteBusData
+#define SysDbgWriteBusData (SYSDBG_COMMAND)19
+#endif
+
+#ifndef SYSDBG_BUS_DATA
+typedef struct _SYSDBG_BUS_DATA {
+ ULONG Address;
+ PVOID Buffer;
+ ULONG Request;
+ BUS_DATA_TYPE BusDataType;
+ ULONG BusNumber;
+ ULONG SlotNumber;
+} SYSDBG_BUS_DATA, *PSYSDBG_BUS_DATA;
+#define SYSDBG_BUS_DATA SYSDBG_BUS_DATA
+#endif
+
+#ifndef PCI_SLOT_NUMBER
+typedef struct _PCI_SLOT_NUMBER {
+ union {
+ struct {
+ ULONG DeviceNumber:5;
+ ULONG FunctionNumber:3;
+ ULONG Reserved:24;
+ } bits;
+ ULONG AsULONG;
+ } u;
+} PCI_SLOT_NUMBER, *PPCI_SLOT_NUMBER;
+#define PCI_SLOT_NUMBER PCI_SLOT_NUMBER
+#endif
+
+#ifdef NtSystemDebugControl
+#undef NtSystemDebugControl
+#endif
+static NTSTATUS (NTAPI *MyNtSystemDebugControl)(SYSDBG_COMMAND Command, PVOID InputBuffer, ULONG InputBufferLength, PVOID OutputBuffer, ULONG OutputBufferLength, PULONG ReturnLength);
+#define NtSystemDebugControl MyNtSystemDebugControl
+
+static BOOL debug_privilege_enabled;
+static LUID luid_debug_privilege;
+static BOOL revert_only_privilege;
+static HANDLE revert_token;
+static HMODULE ntdll;
+
+static int win32_sysdbg_initialized;
+
+static NTSTATUS
+win32_sysdbg_pci_bus_data(BOOL WriteBusData, BYTE BusNumber, BYTE DeviceNumber, BYTE FunctionNumber, BYTE Address, PVOID Buffer, BYTE BufferSize, PULONG Length)
+{
+ SYSDBG_BUS_DATA sysdbg_cmd;
+ PCI_SLOT_NUMBER pci_slot;
+
+ if (!NtSystemDebugControl)
+ return STATUS_NOT_IMPLEMENTED;
+
+ memset(&pci_slot, 0, sizeof(pci_slot));
+ memset(&sysdbg_cmd, 0, sizeof(sysdbg_cmd));
+
+ sysdbg_cmd.Address = Address;
+ sysdbg_cmd.Buffer = Buffer;
+ sysdbg_cmd.Request = BufferSize;
+ sysdbg_cmd.BusDataType = PCIConfiguration;
+ sysdbg_cmd.BusNumber = BusNumber;
+ pci_slot.u.bits.DeviceNumber = DeviceNumber;
+ pci_slot.u.bits.FunctionNumber = FunctionNumber;
+ sysdbg_cmd.SlotNumber = pci_slot.u.AsULONG;
+
+ *Length = 0;
+ return NtSystemDebugControl(WriteBusData ? SysDbgWriteBusData : SysDbgReadBusData, &sysdbg_cmd, sizeof(sysdbg_cmd), NULL, 0, Length);
+}
+
+static int
+win32_sysdbg_setup(struct pci_access *a)
+{
+ UINT prev_error_mode;
+ NTSTATUS status;
+ ULONG ret_len;
+ DWORD id;
+
+ if (win32_sysdbg_initialized)
+ return 1;
+
+ prev_error_mode = change_error_mode(SEM_FAILCRITICALERRORS);
+ ntdll = LoadLibrary(TEXT("ntdll.dll"));
+ change_error_mode(prev_error_mode);
+ if (!ntdll)
+ {
+ a->debug("Cannot open ntdll.dll library.");
+ return 0;
+ }
+
+ NtSystemDebugControl = (LPVOID)GetProcAddress(ntdll, "NtSystemDebugControl");
+ if (!NtSystemDebugControl)
+ {
+ a->debug("Function NtSystemDebugControl() is not supported.");
+ FreeLibrary(ntdll);
+ ntdll = NULL;
+ return 0;
+ }
+
+ /*
+ * Try to read PCI id register from PCI device 00:00.0.
+ * If this device does not exist and NT SysDbg API is working then
+ * NT SysDbg returns STATUS_UNSUCCESSFUL.
+ */
+ status = win32_sysdbg_pci_bus_data(FALSE, 0, 0, 0, 0, &id, sizeof(id), &ret_len);
+ if ((status >= 0 && ret_len == sizeof(id)) || status == STATUS_UNSUCCESSFUL)
+ {
+ win32_sysdbg_initialized = 1;
+ return 1;
+ }
+ else if (status != STATUS_ACCESS_DENIED)
+ {
+ if (status == STATUS_NOT_IMPLEMENTED || status == STATUS_INVALID_INFO_CLASS)
+ a->debug("NT SysDbg is not supported.");
+ else if (status == STATUS_DEBUGGER_INACTIVE)
+ a->debug("NT SysDbg is disabled.");
+ else
+ a->debug("NT SysDbg returned error 0x%lx.", status);
+ FreeLibrary(ntdll);
+ ntdll = NULL;
+ NtSystemDebugControl = NULL;
+ return 0;
+ }
+
+ a->debug("NT SysDbg returned Access Denied, trying again with Debug privilege...");
+
+ if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid_debug_privilege))
+ {
+ a->debug("Debug privilege is not supported.");
+ FreeLibrary(ntdll);
+ ntdll = NULL;
+ NtSystemDebugControl = NULL;
+ return 0;
+ }
+
+ if (!enable_privilege(luid_debug_privilege, &revert_token, &revert_only_privilege))
+ {
+ a->debug("Cannot enable Debug privilege.");
+ FreeLibrary(ntdll);
+ ntdll = NULL;
+ NtSystemDebugControl = NULL;
+ return 0;
+ }
+
+ status = win32_sysdbg_pci_bus_data(FALSE, 0, 0, 0, 0, &id, sizeof(id), &ret_len);
+ if ((status >= 0 && ret_len == sizeof(id)) || status == STATUS_UNSUCCESSFUL)
+ {
+ a->debug("Succeeded.");
+ debug_privilege_enabled = TRUE;
+ win32_sysdbg_initialized = 1;
+ return 1;
+ }
+
+ revert_privilege(luid_debug_privilege, revert_token, revert_only_privilege);
+ revert_token = NULL;
+ revert_only_privilege = FALSE;
+
+ FreeLibrary(ntdll);
+ ntdll = NULL;
+ NtSystemDebugControl = NULL;
+
+ if (status == STATUS_NOT_IMPLEMENTED || status == STATUS_INVALID_INFO_CLASS)
+ a->debug("NT SysDbg is not supported.");
+ else if (status == STATUS_DEBUGGER_INACTIVE)
+ a->debug("NT SysDbg is disabled.");
+ else if (status == STATUS_ACCESS_DENIED)
+ a->debug("NT SysDbg returned Access Denied.");
+ else
+ a->debug("NT SysDbg returned error 0x%lx.", status);
+
+ return 0;
+}
+
+static int
+win32_sysdbg_detect(struct pci_access *a)
+{
+ if (!win32_sysdbg_setup(a))
+ return 0;
+
+ return 1;
+}
+
+static void
+win32_sysdbg_init(struct pci_access *a)
+{
+ if (!win32_sysdbg_setup(a))
+ {
+ a->debug("\n");
+ a->error("NT SysDbg PCI Bus Data interface cannot be accessed.");
+ }
+}
+
+static void
+win32_sysdbg_cleanup(struct pci_access *a UNUSED)
+{
+ if (!win32_sysdbg_initialized)
+ return;
+
+ if (debug_privilege_enabled)
+ {
+ revert_privilege(luid_debug_privilege, revert_token, revert_only_privilege);
+ revert_token = NULL;
+ revert_only_privilege = FALSE;
+ debug_privilege_enabled = FALSE;
+ }
+
+ FreeLibrary(ntdll);
+ ntdll = NULL;
+ NtSystemDebugControl = NULL;
+
+ win32_sysdbg_initialized = 0;
+}
+
+static int
+win32_sysdbg_read(struct pci_dev *d, int pos, byte *buf, int len)
+{
+ NTSTATUS status;
+ ULONG ret_len;
+
+ if ((unsigned int)d->domain > 0 || (unsigned int)pos > 255 || (unsigned int)(pos+len) > 256)
+ return 0;
+
+ status = win32_sysdbg_pci_bus_data(FALSE, d->bus, d->dev, d->func, pos, buf, len, &ret_len);
+ if (status < 0 || ret_len != (unsigned int)len)
+ return 0;
+
+ return 1;
+}
+
+static int
+win32_sysdbg_write(struct pci_dev *d, int pos, byte *buf, int len)
+{
+ NTSTATUS status;
+ ULONG ret_len;
+
+ if ((unsigned int)d->domain > 0 || (unsigned int)pos > 255 || (unsigned int)(pos+len) > 256)
+ return 0;
+
+ status = win32_sysdbg_pci_bus_data(TRUE, d->bus, d->dev, d->func, pos, buf, len, &ret_len);
+ if (status < 0 || ret_len != (unsigned int)len)
+ return 0;
+
+ return 1;
+}
+
+struct pci_methods pm_win32_sysdbg = {
+ "win32-sysdbg",
+ "Win32 PCI config space access using NT SysDbg Bus Data interface",
+ NULL, /* config */
+ win32_sysdbg_detect,
+ win32_sysdbg_init,
+ win32_sysdbg_cleanup,
+ pci_generic_scan,
+ pci_generic_fill_info,
+ win32_sysdbg_read,
+ win32_sysdbg_write,
+ NULL, /* read_vpd */
+ NULL, /* init_dev */
+ NULL /* cleanup_dev */
+};
diff --git a/pcilib.man b/pcilib.man
index 63e58c8..115f1f3 100644
--- a/pcilib.man
+++ b/pcilib.man
@@ -76,6 +76,13 @@ is no access to the PCI configuration space but libpci provides read-only
virtual emulation based on information from Configuration Manager. Starting
with Windows 8 (NT 6.2) it is not possible to retrieve resources from 32-bit
application or library on 64-bit system.
+.TP
+.B win32-sysdbg
+Access to the PCI configuration space via NT SysDbg interface on Windows
+systems. Process needs to have Debug privilege, which local Administrators
+have by default. Not available on 64-bit systems and neither on recent 32-bit
+systems. Only devices from the first domain are accessible and only first
+256 bytes of the PCI configuration space is accessible via this method.
.SH PARAMETERS