OBJS += win32-cfgmgr32
endif
+ifdef PCI_HAVE_PM_WIN32_SYSDBG
+OBJS += win32-sysdbg
+endif
+
all: $(PCILIB) $(PCILIBPC)
ifeq ($(SHARED),no)
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
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
// (their positions in struct pci_filter were declared as RFU).
STATIC_ALIAS(void pci_filter_init(struct pci_access *a, struct pci_filter *f), pci_filter_init_v38(a, f));
+DEFINE_ALIAS(void pci_filter_init_v33(struct pci_access *a, struct pci_filter *f), pci_filter_init_v38);
SYMBOL_VERSION(pci_filter_init_v30, pci_filter_init@LIBPCI_3.0);
-SYMBOL_VERSION(pci_filter_init_v38, pci_filter_init@LIBPCI_3.3);
+SYMBOL_VERSION(pci_filter_init_v33, pci_filter_init@LIBPCI_3.3);
SYMBOL_VERSION(pci_filter_init_v38, pci_filter_init@@LIBPCI_3.8);
STATIC_ALIAS(char *pci_filter_parse_slot(struct pci_filter *f, char *str), pci_filter_parse_slot_v38(f, str));
+DEFINE_ALIAS(char *pci_filter_parse_slot_v33(struct pci_filter *f, char *str), pci_filter_parse_slot_v38);
SYMBOL_VERSION(pci_filter_parse_slot_v30, pci_filter_parse_slot@LIBPCI_3.0);
-SYMBOL_VERSION(pci_filter_parse_slot_v38, pci_filter_parse_slot@LIBPCI_3.3);
+SYMBOL_VERSION(pci_filter_parse_slot_v33, pci_filter_parse_slot@LIBPCI_3.3);
SYMBOL_VERSION(pci_filter_parse_slot_v38, pci_filter_parse_slot@@LIBPCI_3.8);
STATIC_ALIAS(char *pci_filter_parse_id(struct pci_filter *f, char *str), pci_filter_parse_id_v38(f, str));
+DEFINE_ALIAS(char *pci_filter_parse_id_v33(struct pci_filter *f, char *str), pci_filter_parse_id_v38);
SYMBOL_VERSION(pci_filter_parse_id_v30, pci_filter_parse_id@LIBPCI_3.0);
-SYMBOL_VERSION(pci_filter_parse_id_v38, pci_filter_parse_id@LIBPCI_3.3);
+SYMBOL_VERSION(pci_filter_parse_id_v33, pci_filter_parse_id@LIBPCI_3.3);
SYMBOL_VERSION(pci_filter_parse_id_v38, pci_filter_parse_id@@LIBPCI_3.8);
STATIC_ALIAS(int pci_filter_match(struct pci_filter *f, struct pci_dev *d), pci_filter_match_v38(f, d));
+DEFINE_ALIAS(int pci_filter_match_v33(struct pci_filter *f, struct pci_dev *d), pci_filter_match_v38);
SYMBOL_VERSION(pci_filter_match_v30, pci_filter_match@LIBPCI_3.0);
-SYMBOL_VERSION(pci_filter_match_v38, pci_filter_match@LIBPCI_3.3);
+SYMBOL_VERSION(pci_filter_match_v33, pci_filter_match@LIBPCI_3.3);
SYMBOL_VERSION(pci_filter_match_v38, pci_filter_match@@LIBPCI_3.8);
#define PCI_HT_SEC_CMD 2 /* Command Register */
#define PCI_HT_SEC_CMD_WR 0x0001 /* Warm Reset */
#define PCI_HT_SEC_CMD_DE 0x0002 /* Double-Ended */
-#define PCI_HT_SEC_CMD_DN 0x0076 /* Device Number */
+#define PCI_HT_SEC_CMD_DN 0x007c /* Device Number */
#define PCI_HT_SEC_CMD_CS 0x0080 /* Chain Side */
#define PCI_HT_SEC_CMD_HH 0x0100 /* Host Hide */
#define PCI_HT_SEC_CMD_AS 0x0400 /* Act as Slave */
#define PCI_DVSEC_VENDOR_ID_CXL 0x1e98 /* Designated Vendor-Specific Vendor ID for CXL */
#define PCI_DVSEC_ID_CXL 0 /* Designated Vendor-Specific ID for Intel CXL */
-/* PCIe CXL Designated Vendor-Specific Capabilities, Control, Status */
-#define PCI_CXL_CAP 0x0a /* CXL Capability Register */
-#define PCI_CXL_CAP_CACHE 0x0001 /* CXL.cache Protocol Support */
-#define PCI_CXL_CAP_IO 0x0002 /* CXL.io Protocol Support */
-#define PCI_CXL_CAP_MEM 0x0004 /* CXL.mem Protocol Support */
-#define PCI_CXL_CAP_MEM_HWINIT 0x0008 /* CXL.mem Initializes with HW/FW Support */
-#define PCI_CXL_CAP_HDM_CNT(x) (((x) & (3 << 4)) >> 4) /* CXL Number of HDM ranges */
-#define PCI_CXL_CAP_VIRAL 0x4000 /* CXL Viral Handling Support */
-#define PCI_CXL_CTRL 0x0c /* CXL Control Register */
-#define PCI_CXL_CTRL_CACHE 0x0001 /* CXL.cache Protocol Enable */
-#define PCI_CXL_CTRL_IO 0x0002 /* CXL.io Protocol Enable */
-#define PCI_CXL_CTRL_MEM 0x0004 /* CXL.mem Protocol Enable */
-#define PCI_CXL_CTRL_CACHE_SF_COV(x) (((x) & (0x1f << 3)) >> 3) /* Snoop Filter Coverage */
-#define PCI_CXL_CTRL_CACHE_SF_GRAN(x) (((x) & (0x7 << 8)) >> 8) /* Snoop Filter Granularity */
-#define PCI_CXL_CTRL_CACHE_CLN 0x0800 /* CXL.cache Performance Hint on Clean Evictions */
-#define PCI_CXL_CTRL_VIRAL 0x4000 /* CXL Viral Handling Enable */
-#define PCI_CXL_STATUS 0x0e /* CXL Status Register */
-#define PCI_CXL_STATUS_VIRAL 0x4000 /* CXL Viral Handling Status */
+/* PCIe CXL Designated Vendor-Specific Capabilities for Devices: Control, Status */
+#define PCI_CXL_DEV_LEN 0x38 /* CXL Device DVSEC Length */
+#define PCI_CXL_DEV_CAP 0x0a /* CXL Capability Register */
+#define PCI_CXL_DEV_CAP_CACHE 0x0001 /* CXL.cache Protocol Support */
+#define PCI_CXL_DEV_CAP_IO 0x0002 /* CXL.io Protocol Support */
+#define PCI_CXL_DEV_CAP_MEM 0x0004 /* CXL.mem Protocol Support */
+#define PCI_CXL_DEV_CAP_MEM_HWINIT 0x0008 /* CXL.mem Initializes with HW/FW Support */
+#define PCI_CXL_DEV_CAP_HDM_CNT(x) (((x) & (3 << 4)) >> 4) /* CXL Number of HDM ranges */
+#define PCI_CXL_DEV_CAP_VIRAL 0x4000 /* CXL Viral Handling Support */
+#define PCI_CXL_DEV_CTRL 0x0c /* CXL Control Register */
+#define PCI_CXL_DEV_CTRL_CACHE 0x0001 /* CXL.cache Protocol Enable */
+#define PCI_CXL_DEV_CTRL_IO 0x0002 /* CXL.io Protocol Enable */
+#define PCI_CXL_DEV_CTRL_MEM 0x0004 /* CXL.mem Protocol Enable */
+#define PCI_CXL_DEV_CTRL_CACHE_SF_COV(x) (((x) & (0x1f << 3)) >> 3) /* Snoop Filter Coverage */
+#define PCI_CXL_DEV_CTRL_CACHE_SF_GRAN(x) (((x) & (0x7 << 8)) >> 8) /* Snoop Filter Granularity */
+#define PCI_CXL_DEV_CTRL_CACHE_CLN 0x0800 /* CXL.cache Performance Hint on Clean Evictions */
+#define PCI_CXL_DEV_CTRL_VIRAL 0x4000 /* CXL Viral Handling Enable */
+#define PCI_CXL_DEV_STATUS 0x0e /* CXL Status Register */
+#define PCI_CXL_DEV_STATUS_VIRAL 0x4000 /* CXL Viral Handling Status */
+#define PCI_CXL_DEV_STATUS2 0x12
+#define PCI_CXL_DEV_STATUS_CACHE_INV 0x0001
+#define PCI_CXL_DEV_STATUS_RC 0x0002 /* Device Reset Complete */
+#define PCI_CXL_DEV_STATUS_RE 0x0004 /* Device Reset Error */
+#define PCI_CXL_DEV_STATUS_PMC 0x8000 /* Power Management Init Complete */
+#define PCI_CXL_DEV_CAP2 0x16
+#define PCI_CXL_DEV_CAP2_CACHE_UNK 0x0000 /* Cache Size Isn't Reported */
+#define PCI_CXL_DEV_CAP2_CACHE_64K 0x0001 /* Unit Size 64K */
+#define PCI_CXL_DEV_CAP2_CACHE_1M 0x0002 /* Unit Size 1M */
+#define PCI_CXL_DEV_RANGE1_SIZE_HI 0x18
+#define PCI_CXL_DEV_RANGE1_SIZE_LO 0x1c
+#define PCI_CXL_RANGE_VALID 0x0001
+#define PCI_CXL_RANGE_ACTIVE 0x0002
+#define PCI_CXL_RANGE_TYPE(x) (((x) >> 2) & 0x7)
+#define PCI_CXL_RANGE_CLASS(x) (((x) >> 5) & 0x7)
+#define PCI_CXL_RANGE_INTERLEAVE(x) (((x) >> 8) & 0x1f)
+#define PCI_CXL_RANGE_TIMEOUT(x) (((x) >> 13) & 0x7)
+#define PCI_CXL_DEV_RANGE1_BASE_HI 0x20
+#define PCI_CXL_DEV_RANGE1_BASE_LO 0x24
+#define PCI_CXL_DEV_RANGE2_SIZE_HI 0x28
+#define PCI_CXL_DEV_RANGE2_SIZE_LO 0x2c
+#define PCI_CXL_DEV_RANGE2_BASE_HI 0x30
+#define PCI_CXL_DEV_RANGE2_BASE_LO 0x34
+
+/* PCIe CXL 2.0 Designated Vendor-Specific Capabilities for Ports */
+#define PCI_CXL_PORT_EXT_LEN 0x28 /* CXL Extensions DVSEC for Ports Length */
+#define PCI_CXL_PORT_EXT_STATUS 0x0a /* Port Extension Status */
+#define PCI_CXL_PORT_PM_INIT_COMPLETE 0x1 /* Port Power Management Initialization Complete */
+#define PCI_CXL_PORT_CTRL 0x0c /* Port Control Override */
+#define PCI_CXL_PORT_UNMASK_SBR 0x0001 /* Unmask SBR */
+#define PCI_CXL_PORT_UNMASK_LINK 0x0002 /* Unmask Link Disable */
+#define PCI_CXL_PORT_ALT_MEMORY 0x0004 /* Alt Memory and ID Space Enable */
+#define PCI_CXL_PORT_ALT_BME 0x0008 /* Alt BME */
+#define PCI_CXL_PORT_VIRAL_EN 0x4000 /* Viral Enable */
+#define PCI_CXL_PORT_ALT_BUS_BASE 0xe
+#define PCI_CXL_PORT_ALT_BUS_LIMIT 0xf
+#define PCI_CXL_PORT_ALT_MEM_BASE 0x10
+#define PCI_CXL_PORT_ALT_MEM_LIMIT 0x12
+
+/* PCIe CXL 2.0 Designated Vendor-Specific Capabilities for Register Locator */
+#define PCI_CXL_RL_BASE0_LO 0x0c
+#define PCI_CXL_RL_BASE0_HI 0x10
+#define PCI_CXL_RL_BASE1_LO 0x14
+#define PCI_CXL_RL_BASE1_HI 0x18
+#define PCI_CXL_RL_BASE2_LO 0x1c
+#define PCI_CXL_RL_BASE2_HI 0x20
/* Access Control Services */
#define PCI_ACS_CAP 0x04 /* ACS Capability Register */
#define PCI_L1PM_SUBSTAT_CAP_PM_L11 0x2 /* PCI-PM L1.1 Supported */
#define PCI_L1PM_SUBSTAT_CAP_ASPM_L12 0x4 /* ASPM L1.2 Supported */
#define PCI_L1PM_SUBSTAT_CAP_ASPM_L11 0x8 /* ASPM L1.1 Supported */
-#define PCI_L1PM_SUBSTAT_CAP_L1PM_SUPP 0x16 /* L1 PM Substates supported */
+#define PCI_L1PM_SUBSTAT_CAP_L1PM_SUPP 0x10 /* L1 PM Substates supported */
#define PCI_L1PM_SUBSTAT_CTL1 0x8 /* L1 PM Substate Control 1 */
#define PCI_L1PM_SUBSTAT_CTL1_PM_L12 0x1 /* PCI-PM L1.2 Enable */
#define PCI_L1PM_SUBSTAT_CTL1_PM_L11 0x2 /* PCI-PM L1.1 Enable */
/* Get requested info from the server */
-static void
+static int
hurd_fill_regions(struct pci_dev *d)
{
mach_port_t device_port = device_port_lookup(d);
int err = pci_get_dev_regions(device_port, &buf, &size);
if (err)
- return;
+ return 0;
if ((char *) ®ions != buf)
{
if (size > sizeof(regions))
{
vm_deallocate(mach_task_self(), (vm_address_t) buf, size);
- return;
+ return 0;
}
memcpy(®ions, buf, size);
d->size[i] = regions[i].size;
}
+
+ return 1;
}
-static void
+static int
hurd_fill_rom(struct pci_dev *d)
{
struct pci_xrom_bar rom;
int err = pci_get_dev_rom(device_port, &buf, &size);
if (err)
- return;
+ return 0;
if ((char *) &rom != buf)
{
if (size > sizeof(rom))
{
vm_deallocate(mach_task_self(), (vm_address_t) buf, size);
- return;
+ return 0;
}
memcpy(&rom, buf, size);
d->rom_base_addr = rom.base_addr;
d->rom_size = rom.size;
+
+ return 1;
}
static void
if (!d->access->buscentric)
{
if (want_fill(d, flags, PCI_FILL_BASES | PCI_FILL_SIZES))
- hurd_fill_regions(d);
+ {
+ if (hurd_fill_regions(d))
+ clear_fill(d, PCI_FILL_BASES | PCI_FILL_SIZES);
+ }
if (want_fill(d, flags, PCI_FILL_ROM_BASE))
- hurd_fill_rom(d);
+ {
+ if (hurd_fill_rom(d))
+ clear_fill(d, PCI_FILL_ROM_BASE);
+ }
}
+
+ pci_generic_fill_info(d, flags);
}
struct pci_methods pm_hurd = {
#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
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,
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;
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
};
--- /dev/null
+/*
+ * 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 */
+};
/*
* The PCI Utilities -- Show Extended Capabilities
*
- * Copyright (c) 1997--2020 Martin Mares <mj@ucw.cz>
+ * Copyright (c) 1997--2022 Martin Mares <mj@ucw.cz>
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
pat_pos = BITS(rcap, 24, 8);
printf("Caps:\tPATOffset=%02x MaxTimeSlots=%d RejSnoopTrans%c\n",
pat_pos,
- BITS(rcap, 16, 6) + 1,
+ BITS(rcap, 16, 7) + 1,
FLAG(rcap, 1 << 15));
printf("\t\t\tArb:");
}
static void
-cap_dvsec_cxl(struct device *d, int where)
+cxl_range(u64 base, u64 size, int n)
{
- u16 l;
+ u32 interleave[] = { 0, 256, 4096, 512, 1024, 2048, 8192, 16384 };
+ const char *type[] = { "Volatile", "Non-volatile", "CDAT" };
+ const char *class[] = { "DRAM", "Storage", "CDAT" };
+ u16 w;
- printf(": CXL\n");
- if (verbose < 2)
+ w = (u16) size;
+
+ size &= ~0x0fffffffULL;
+
+ printf("\t\tRange%d: %016"PCI_U64_FMT_X"-%016"PCI_U64_FMT_X"\n", n, base, base + size - 1);
+ printf("\t\t\tValid%c Active%c Type=%s Class=%s interleave=%d timeout=%ds\n",
+ FLAG(w, PCI_CXL_RANGE_VALID), FLAG(w, PCI_CXL_RANGE_ACTIVE),
+ type[PCI_CXL_RANGE_TYPE(w)], class[PCI_CXL_RANGE_CLASS(w)],
+ interleave[PCI_CXL_RANGE_INTERLEAVE(w)],
+ 1 << (PCI_CXL_RANGE_TIMEOUT(w) * 2));
+}
+
+static void
+dvsec_cxl_device(struct device *d, int rev, int where, int len)
+{
+ u32 cache_size, cache_unit_size;
+ u64 range_base, range_size;
+ u16 w;
+
+ if (len < PCI_CXL_DEV_LEN)
return;
- if (!config_fetch(d, where + PCI_CXL_CAP, 12))
+ /* Legacy 1.1 revs aren't handled */
+ if (rev < 1)
return;
- l = get_conf_word(d, where + PCI_CXL_CAP);
+ w = get_conf_word(d, where + PCI_CXL_DEV_CAP);
printf("\t\tCXLCap:\tCache%c IO%c Mem%c Mem HW Init%c HDMCount %d Viral%c\n",
- FLAG(l, PCI_CXL_CAP_CACHE), FLAG(l, PCI_CXL_CAP_IO), FLAG(l, PCI_CXL_CAP_MEM),
- FLAG(l, PCI_CXL_CAP_MEM_HWINIT), PCI_CXL_CAP_HDM_CNT(l), FLAG(l, PCI_CXL_CAP_VIRAL));
+ FLAG(w, PCI_CXL_DEV_CAP_CACHE), FLAG(w, PCI_CXL_DEV_CAP_IO), FLAG(w, PCI_CXL_DEV_CAP_MEM),
+ FLAG(w, PCI_CXL_DEV_CAP_MEM_HWINIT), PCI_CXL_DEV_CAP_HDM_CNT(w), FLAG(w, PCI_CXL_DEV_CAP_VIRAL));
- l = get_conf_word(d, where + PCI_CXL_CTRL);
+ w = get_conf_word(d, where + PCI_CXL_DEV_CTRL);
printf("\t\tCXLCtl:\tCache%c IO%c Mem%c Cache SF Cov %d Cache SF Gran %d Cache Clean%c Viral%c\n",
- FLAG(l, PCI_CXL_CTRL_CACHE), FLAG(l, PCI_CXL_CTRL_IO), FLAG(l, PCI_CXL_CTRL_MEM),
- PCI_CXL_CTRL_CACHE_SF_COV(l), PCI_CXL_CTRL_CACHE_SF_GRAN(l), FLAG(l, PCI_CXL_CTRL_CACHE_CLN),
- FLAG(l, PCI_CXL_CTRL_VIRAL));
+ FLAG(w, PCI_CXL_DEV_CTRL_CACHE), FLAG(w, PCI_CXL_DEV_CTRL_IO), FLAG(w, PCI_CXL_DEV_CTRL_MEM),
+ PCI_CXL_DEV_CTRL_CACHE_SF_COV(w), PCI_CXL_DEV_CTRL_CACHE_SF_GRAN(w), FLAG(w, PCI_CXL_DEV_CTRL_CACHE_CLN),
+ FLAG(w, PCI_CXL_DEV_CTRL_VIRAL));
+
+ w = get_conf_word(d, where + PCI_CXL_DEV_STATUS);
+ printf("\t\tCXLSta:\tViral%c\n", FLAG(w, PCI_CXL_DEV_STATUS_VIRAL));
+
+ w = get_conf_word(d, where + PCI_CXL_DEV_STATUS2);
+ printf("\t\tCXLSta2:\tResetComplete%c ResetError%c PMComplete%c\n",
+ FLAG(w, PCI_CXL_DEV_STATUS_RC), FLAG(w,PCI_CXL_DEV_STATUS_RE), FLAG(w, PCI_CXL_DEV_STATUS_PMC));
- l = get_conf_word(d, where + PCI_CXL_STATUS);
- printf("\t\tCXLSta:\tViral%c\n", FLAG(l, PCI_CXL_STATUS_VIRAL));
+ w = get_conf_word(d, where + PCI_CXL_DEV_CAP2);
+ cache_unit_size = BITS(w, 0, 4);
+ cache_size = BITS(w, 8, 8);
+ switch (cache_unit_size)
+ {
+ case PCI_CXL_DEV_CAP2_CACHE_1M:
+ printf("\t\tCache Size: %08x\n", cache_size * (1<<20));
+ break;
+ case PCI_CXL_DEV_CAP2_CACHE_64K:
+ printf("\t\tCache Size: %08x\n", cache_size * (64<<10));
+ break;
+ case PCI_CXL_DEV_CAP2_CACHE_UNK:
+ printf("\t\tCache Size Not Reported\n");
+ break;
+ default:
+ printf("\t\tCache Size: %d of unknown unit size (%d)\n", cache_size, cache_unit_size);
+ break;
+ }
+
+ range_size = (u64) get_conf_long(d, where + PCI_CXL_DEV_RANGE1_SIZE_HI) << 32;
+ range_size |= get_conf_long(d, where + PCI_CXL_DEV_RANGE1_SIZE_LO);
+ range_base = (u64) get_conf_long(d, where + PCI_CXL_DEV_RANGE1_BASE_HI) << 32;
+ range_base |= get_conf_long(d, where + PCI_CXL_DEV_RANGE1_BASE_LO);
+ cxl_range(range_base, range_size, 1);
+
+ range_size = (u64) get_conf_long(d, where + PCI_CXL_DEV_RANGE2_SIZE_HI) << 32;
+ range_size |= get_conf_long(d, where + PCI_CXL_DEV_RANGE2_SIZE_LO);
+ range_base = (u64) get_conf_long(d, where + PCI_CXL_DEV_RANGE2_BASE_HI) << 32;
+ range_base |= get_conf_long(d, where + PCI_CXL_DEV_RANGE2_BASE_LO);
+ cxl_range(range_base, range_size, 2);
+}
+
+static void
+dvsec_cxl_port(struct device *d, int where, int len)
+{
+ u16 w, m1, m2;
+ u8 b1, b2;
+
+ if (len < PCI_CXL_PORT_EXT_LEN)
+ return;
+
+ w = get_conf_word(d, where + PCI_CXL_PORT_EXT_STATUS);
+ printf("\t\tCXLPortSta:\tPMComplete%c\n", FLAG(w, PCI_CXL_PORT_EXT_STATUS));
+
+ w = get_conf_word(d, where + PCI_CXL_PORT_CTRL);
+ printf("\t\tCXLPortCtl:\tUnmaskSBR%c UnmaskLinkDisable%c AltMem%c AltBME%c ViralEnable%c\n",
+ FLAG(w, PCI_CXL_PORT_UNMASK_SBR), FLAG(w, PCI_CXL_PORT_UNMASK_LINK),
+ FLAG(w, PCI_CXL_PORT_ALT_MEMORY), FLAG(w, PCI_CXL_PORT_ALT_BME),
+ FLAG(w, PCI_CXL_PORT_VIRAL_EN));
+
+ b1 = get_conf_byte(d, where + PCI_CXL_PORT_ALT_BUS_BASE);
+ b2 = get_conf_byte(d, where + PCI_CXL_PORT_ALT_BUS_LIMIT);
+ printf("\t\tAlternateBus:\t%02x-%02x\n", b1, b2);
+ m1 = get_conf_word(d, where + PCI_CXL_PORT_ALT_MEM_BASE);
+ m2 = get_conf_word(d, where + PCI_CXL_PORT_ALT_MEM_LIMIT);
+ printf("\t\tAlternateBus:\t%04x-%04x\n", m1, m2);
+}
+
+static void
+dvsec_cxl_register_locator(struct device *d, int where, int len)
+{
+ static const char * const id_names[] = {
+ "empty",
+ "component registers",
+ "BAR virtualization",
+ "CXL device registers",
+ "CPMU registers",
+ };
+
+ for (int i=0; ; i++)
+ {
+ int pos = where + 8*i;
+ if (pos + 7 >= len)
+ break;
+
+ u32 lo = get_conf_long(d, pos);
+ u32 hi = get_conf_long(d, pos + 4);
+
+ unsigned int bir = BITS(lo, 0, 3);
+ unsigned int block_id = BITS(lo, 8, 8);
+ u64 base = (BITS(lo, 16, 16) << 16) | ((u64) hi << 32);
+
+ if (!block_id)
+ continue;
+
+ const char *id_name;
+ if (block_id < sizeof(id_names) / sizeof(*id_names))
+ id_name = id_names[block_id];
+ else if (block_id == 0xff)
+ id_name = "vendor-specific";
+ else
+ id_name = "<?>";
+
+ printf("\t\tBlock%d: BIR: bar%d, ID: %s, offset: %016" PCI_U64_FMT_X "\n", i, bir, id_name, base);
+ }
+}
+
+static void
+cap_dvsec_cxl(struct device *d, int id, int rev, int where, int len)
+{
+ printf(": CXL\n");
+ if (verbose < 2)
+ return;
+
+ if (!config_fetch(d, where, len))
+ return;
+
+ switch (id)
+ {
+ case 0:
+ dvsec_cxl_device(d, rev, where, len);
+ break;
+ case 2:
+ printf("\t\tNon-CXL Function Map DVSEC\n");
+ break;
+ case 3:
+ dvsec_cxl_port(d, where, len);
+ break;
+ case 4:
+ printf("\t\tGPF DVSEC for Port\n");
+ break;
+ case 5:
+ printf("\t\tGPF DVSEC for Device\n");
+ break;
+ case 7:
+ printf("\t\tPCIe DVSEC Flex Bus Port\n");
+ break;
+ case 8:
+ dvsec_cxl_register_locator(d, where, len);
+ break;
+ case 9:
+ printf("\t\tMLD DVSEC\n");
+ break;
+ default:
+ printf("\t\tUnknown ID %04x\n", id);
+ }
}
static void
u16 id = get_conf_long(d, where + PCI_DVSEC_HEADER2);
printf("Vendor=%04x ID=%04x Rev=%d Len=%d", vendor, id, rev, len);
- if (vendor == PCI_DVSEC_VENDOR_ID_CXL && id == PCI_DVSEC_ID_CXL && len >= 16)
- cap_dvsec_cxl(d, where);
+ if (vendor == PCI_DVSEC_VENDOR_ID_CXL && len >= 16)
+ cap_dvsec_cxl(d, id, rev, where, len);
else
printf(" <?>\n");
}
*p = ' ';
}
-static void show_tree_bridge(struct bridge *, char *, char *);
+static void show_tree_bridge(struct pci_filter *filter, struct bridge *, char *, char *);
static char * FORMAT_CHECK(printf, 3, 4)
tree_printf(char *line, char *p, char *fmt, ...)
}
static void
-show_tree_dev(struct device *d, char *line, char *p)
+show_tree_dev(struct pci_filter *filter, struct device *d, char *line, char *p)
{
struct pci_dev *q = d->dev;
struct bridge *b;
p = tree_printf(line, p, "-[%02x]-", b->secondary);
else
p = tree_printf(line, p, "-[%02x-%02x]-", b->secondary, b->subordinate);
- show_tree_bridge(b, line, p);
+ show_tree_bridge(filter, b, line, p);
return;
}
if (verbose)
print_it(line, p);
}
+static int
+check_bus_filter(struct pci_filter *filter, struct bus *b);
+
+static int
+check_dev_filter(struct pci_filter *filter, struct device *d)
+{
+ struct bridge *br;
+ struct bus *b;
+
+ if (!filter)
+ return 1;
+
+ if (pci_filter_match(filter, d->dev))
+ return 1;
+
+ for (br = &host_bridge; br; br = br->chain)
+ if (br->br_dev == d)
+ {
+ for (b = br->first_bus; b; b = b->sibling)
+ if (check_bus_filter(filter, b))
+ return 1;
+ break;
+ }
+
+ return 0;
+}
+
+static int
+check_bus_filter(struct pci_filter *filter, struct bus *b)
+{
+ struct device *d;
+
+ if (!filter)
+ return 1;
+
+ for (d = b->first_dev; d; d = d->bus_next)
+ if (check_dev_filter(filter, d))
+ return 1;
+
+ return 0;
+}
+
static void
-show_tree_bus(struct bus *b, char *line, char *p)
+show_tree_bus(struct pci_filter *filter, struct bus *b, char *line, char *p)
{
if (!b->first_dev)
print_it(line, p);
else if (!b->first_dev->bus_next)
{
- p = tree_printf(line, p, "--");
- show_tree_dev(b->first_dev, line, p);
+ if (check_dev_filter(filter, b->first_dev))
+ {
+ p = tree_printf(line, p, "--");
+ show_tree_dev(filter, b->first_dev, line, p);
+ }
+ else
+ print_it(line, p);
}
else
{
+ int empty = 1;
struct device *d = b->first_dev;
while (d->bus_next)
{
- char *p2 = tree_printf(line, p, "+-");
- show_tree_dev(d, line, p2);
+ if (check_dev_filter(filter, d))
+ {
+ char *p2 = tree_printf(line, p, "+-");
+ show_tree_dev(filter, d, line, p2);
+ empty = 0;
+ }
d = d->bus_next;
}
- p = tree_printf(line, p, "\\-");
- show_tree_dev(d, line, p);
+ if (check_dev_filter(filter, d))
+ {
+ p = tree_printf(line, p, "\\-");
+ show_tree_dev(filter, d, line, p);
+ empty = 0;
+ }
+ if (empty)
+ print_it(line, p);
}
}
static void
-show_tree_bridge(struct bridge *b, char *line, char *p)
+show_tree_bridge(struct pci_filter *filter, struct bridge *b, char *line, char *p)
{
*p++ = '-';
if (!b->first_bus->sibling)
{
- if (b == &host_bridge)
- p = tree_printf(line, p, "[%04x:%02x]-", b->domain, b->first_bus->number);
- show_tree_bus(b->first_bus, line, p);
+ if (check_bus_filter(filter, b->first_bus))
+ {
+ if (b == &host_bridge)
+ p = tree_printf(line, p, "[%04x:%02x]-", b->domain, b->first_bus->number);
+ show_tree_bus(filter, b->first_bus, line, p);
+ }
+ else
+ print_it(line, p);
}
else
{
+ int empty = 1;
struct bus *u = b->first_bus;
char *k;
while (u->sibling)
{
- k = tree_printf(line, p, "+-[%04x:%02x]-", u->domain, u->number);
- show_tree_bus(u, line, k);
+ if (check_bus_filter(filter, u))
+ {
+ k = tree_printf(line, p, "+-[%04x:%02x]-", u->domain, u->number);
+ show_tree_bus(filter, u, line, k);
+ empty = 0;
+ }
u = u->sibling;
}
- k = tree_printf(line, p, "\\-[%04x:%02x]-", u->domain, u->number);
- show_tree_bus(u, line, k);
+ if (check_bus_filter(filter, u))
+ {
+ k = tree_printf(line, p, "\\-[%04x:%02x]-", u->domain, u->number);
+ show_tree_bus(filter, u, line, k);
+ empty = 0;
+ }
+ if (empty)
+ print_it(line, p);
}
}
show_forest(struct pci_filter *filter)
{
char line[LINE_BUF_SIZE];
- if (filter == NULL)
- show_tree_bridge(&host_bridge, line, line);
- else
- {
- struct bridge *b;
- for (b=&host_bridge; b; b=b->chain)
- {
- if (b->br_dev && pci_filter_match(filter, b->br_dev->dev))
- {
- struct pci_dev *d = b->br_dev->dev;
- char *p = line;
- p = tree_printf(line, p, "%04x:%02x:", d->domain_16, d->bus);
- show_tree_dev(b->br_dev, line, p);
- }
- }
- }
+ show_tree_bridge(filter, &host_bridge, line, line);
}
echo >&2 'Usage: tag-release vX.Y.Z'
exit 1
fi
-git tag -u ED70F82D $1
+git tag -u 1F3D0761D9B65F0B $1
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