]> git.ipfire.org Git - thirdparty/pciutils.git/commitdiff
libpci: win32-kldbg: Fix calling IOCTL_KLDBG from 32-bit process on 64-bit system
authorPali Rohár <pali@kernel.org>
Sat, 18 Jan 2025 17:57:05 +0000 (18:57 +0100)
committerMartin Mares <mj@ucw.cz>
Sun, 8 Jun 2025 15:19:58 +0000 (17:19 +0200)
32-bit process on 64-bit system needs to pass all pointers in 64-bit format
for IOCTL_KLDBG call.

So for 32-bit builds (determined by not defined _WIN64 macro) define new
SYSDBG_BUS_DATA64 and KLDBG64 structures with u64 type for pointer members.
Compiler will automatically align all structure members and inserts padding
between members as needed, in the same way as for 64-bit builds. Due to
alignment restrictions, adding just one dummy 32-bit member after each
pointer member does not work.

32-bit code then needs to figure out if the host system is 32-bit or 64-bit
and choose which structure (process native or 64-bit) needs to be passed to
the IOCTL_KLDBG call for successful execution. This is determined by the
win32_is_32bit_on_64bit_system() helper function.

With this change 32-bit i386 lspci.exe binary is working fine on 64-bit
AMD64 system and via win32-kldbg can access PCIe config space if the
AMD64 kldbgdrv.sys driver is registered in the host system.

lib/win32-kldbg.c

index 62e4b7c6966c1c7be6cdc6276a4d8bee51f33e85..ed5b5993d63ada153cc0385282c2bb105f6bfa96 100644 (file)
 #define SysDbgWriteBusData (SYSDBG_COMMAND)19
 #endif
 
+#ifndef _WIN64
+typedef struct _SYSDBG_BUS_DATA64 {
+  ULONG Address;
+  u64 Buffer64; /* 32-bit process has to pass 64-bit wide pointer on 64-bit systems */
+  ULONG Request;
+  BUS_DATA_TYPE BusDataType;
+  ULONG BusNumber;
+  ULONG SlotNumber;
+} SYSDBG_BUS_DATA64, *PSYSDBG_BUS_DATA64;
+#endif
 #ifndef SYSDBG_BUS_DATA
 typedef struct _SYSDBG_BUS_DATA {
   ULONG Address;
@@ -89,6 +99,13 @@ typedef struct _PCI_SLOT_NUMBER {
 #define PCI_SLOT_NUMBER PCI_SLOT_NUMBER
 #endif
 
+#ifndef _WIN64
+typedef struct _KLDBG64 {
+  SYSDBG_COMMAND Command;
+  u64 Buffer64; /* 32-bit process has to pass 64-bit wide pointer on 64-bit systems */
+  DWORD BufferLength;
+} KLDBG64, *PKLDBG64;
+#endif
 #ifndef KLDBG
 typedef struct _KLDBG {
   SYSDBG_COMMAND Command;
@@ -656,32 +673,79 @@ win32_kldbg_scan(struct pci_access *a)
 static BOOL
 win32_kldbg_pci_bus_data(BOOL WriteBusData, USHORT SegmentNumber, BYTE BusNumber, BYTE DeviceNumber, BYTE FunctionNumber, USHORT Address, PVOID Buffer, ULONG BufferSize, LPDWORD Length)
 {
-  KLDBG kldbg_cmd;
-  SYSDBG_BUS_DATA sysdbg_cmd;
+  union {
+    KLDBG native;
+#ifndef _WIN64
+    KLDBG64 ext64;
+#endif
+  } kldbg_cmd;
+  union {
+    SYSDBG_BUS_DATA native;
+#ifndef _WIN64
+    SYSDBG_BUS_DATA64 ext64;
+#endif
+  } sysdbg_cmd;
   PCI_SLOT_NUMBER pci_slot;
   PCI_SEGMENT_BUS_NUMBER pci_seg_bus;
+  DWORD kldbg_cmd_size;
+  DWORD sysdbg_cmd_size;
+#ifndef _WIN64
+  BOOL is_32bit_on_64bit_system = win32_is_32bit_on_64bit_system();
+#endif
 
   memset(&pci_slot, 0, sizeof(pci_slot));
+  memset(&kldbg_cmd, 0, sizeof(kldbg_cmd));
   memset(&sysdbg_cmd, 0, sizeof(sysdbg_cmd));
   memset(&pci_seg_bus, 0, sizeof(pci_seg_bus));
 
-  sysdbg_cmd.Address = Address;
-  sysdbg_cmd.Buffer = Buffer;
-  sysdbg_cmd.Request = BufferSize;
-  sysdbg_cmd.BusDataType = PCIConfiguration;
   pci_seg_bus.u.bits.BusNumber = BusNumber;
   pci_seg_bus.u.bits.SegmentNumber = SegmentNumber;
-  sysdbg_cmd.BusNumber = pci_seg_bus.u.AsULONG;
+
   pci_slot.u.bits.DeviceNumber = DeviceNumber;
   pci_slot.u.bits.FunctionNumber = FunctionNumber;
-  sysdbg_cmd.SlotNumber = pci_slot.u.AsULONG;
 
-  kldbg_cmd.Command = WriteBusData ? SysDbgWriteBusData : SysDbgReadBusData;
-  kldbg_cmd.Buffer = &sysdbg_cmd;
-  kldbg_cmd.BufferLength = sizeof(sysdbg_cmd);
+#ifndef _WIN64
+  if (is_32bit_on_64bit_system)
+    {
+      sysdbg_cmd.ext64.Address = Address;
+      sysdbg_cmd.ext64.Buffer64 = (u64)(ULONG)Buffer; /* extend 32-bit pointer to 64-bit */
+      sysdbg_cmd.ext64.Request = BufferSize;
+      sysdbg_cmd.ext64.BusDataType = PCIConfiguration;
+      sysdbg_cmd.ext64.BusNumber = pci_seg_bus.u.AsULONG;
+      sysdbg_cmd.ext64.SlotNumber = pci_slot.u.AsULONG;
+      sysdbg_cmd_size = sizeof(sysdbg_cmd.ext64);
+    }
+  else
+#endif
+    {
+      sysdbg_cmd.native.Address = Address;
+      sysdbg_cmd.native.Buffer = Buffer;
+      sysdbg_cmd.native.Request = BufferSize;
+      sysdbg_cmd.native.BusDataType = PCIConfiguration;
+      sysdbg_cmd.native.BusNumber = pci_seg_bus.u.AsULONG;
+      sysdbg_cmd.native.SlotNumber = pci_slot.u.AsULONG;
+      sysdbg_cmd_size = sizeof(sysdbg_cmd.native);
+    }
+
+#ifndef _WIN64
+  if (is_32bit_on_64bit_system)
+    {
+      kldbg_cmd.ext64.Command = WriteBusData ? SysDbgWriteBusData : SysDbgReadBusData;
+      kldbg_cmd.ext64.Buffer64 = (u64)(ULONG)&sysdbg_cmd; /* extend 32-bit pointer to 64-bit */
+      kldbg_cmd.ext64.BufferLength = sysdbg_cmd_size;
+      kldbg_cmd_size = sizeof(kldbg_cmd.ext64);
+    }
+  else
+#endif
+    {
+      kldbg_cmd.native.Command = WriteBusData ? SysDbgWriteBusData : SysDbgReadBusData;
+      kldbg_cmd.native.Buffer = &sysdbg_cmd;
+      kldbg_cmd.native.BufferLength = sysdbg_cmd_size;
+      kldbg_cmd_size = sizeof(kldbg_cmd.native);
+    }
 
   *Length = 0;
-  return DeviceIoControl(kldbg_dev, IOCTL_KLDBG, &kldbg_cmd, sizeof(kldbg_cmd), &sysdbg_cmd, sizeof(sysdbg_cmd), Length, NULL);
+  return DeviceIoControl(kldbg_dev, IOCTL_KLDBG, &kldbg_cmd, kldbg_cmd_size, &sysdbg_cmd, sysdbg_cmd_size, Length, NULL);
 }
 
 static int