]> mj.ucw.cz Git - pciutils.git/blob - lib/win32-kldbg.c
libpci: Add constants for Lane Margining at the Receiver Extended Capability
[pciutils.git] / lib / win32-kldbg.c
1 /*
2  *      The PCI Library -- PCI config space access using Kernel Local Debugging Driver
3  *
4  *      Copyright (c) 2022 Pali Rohár <pali@kernel.org>
5  *
6  *      Can be freely distributed and used under the terms of the GNU GPL v2+.
7  *
8  *      SPDX-License-Identifier: GPL-2.0-or-later
9  */
10
11 #include <windows.h>
12 #include <winioctl.h>
13
14 #include <stdio.h> /* for sprintf() */
15 #include <string.h> /* for memset() and memcpy() */
16
17 #include "internal.h"
18 #include "i386-io-windows.h"
19
20 #ifndef ERROR_NOT_FOUND
21 #define ERROR_NOT_FOUND 1168
22 #endif
23
24 #ifndef LOAD_LIBRARY_AS_IMAGE_RESOURCE
25 #define LOAD_LIBRARY_AS_IMAGE_RESOURCE 0x20
26 #endif
27 #ifndef LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE
28 #define LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE 0x40
29 #endif
30
31 #ifndef IOCTL_KLDBG
32 #define IOCTL_KLDBG CTL_CODE(FILE_DEVICE_UNKNOWN, 0x1, METHOD_NEITHER, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
33 #endif
34
35 #ifndef BUS_DATA_TYPE
36 #define BUS_DATA_TYPE LONG
37 #endif
38 #ifndef PCIConfiguration
39 #define PCIConfiguration (BUS_DATA_TYPE)4
40 #endif
41
42 #ifndef SYSDBG_COMMAND
43 #define SYSDBG_COMMAND ULONG
44 #endif
45 #ifndef SysDbgReadBusData
46 #define SysDbgReadBusData (SYSDBG_COMMAND)18
47 #endif
48 #ifndef SysDbgWriteBusData
49 #define SysDbgWriteBusData (SYSDBG_COMMAND)19
50 #endif
51
52 #ifndef SYSDBG_BUS_DATA
53 typedef struct _SYSDBG_BUS_DATA {
54   ULONG Address;
55   PVOID Buffer;
56   ULONG Request;
57   BUS_DATA_TYPE BusDataType;
58   ULONG BusNumber;
59   ULONG SlotNumber;
60 } SYSDBG_BUS_DATA, *PSYSDBG_BUS_DATA;
61 #define SYSDBG_BUS_DATA SYSDBG_BUS_DATA
62 #endif
63
64 #ifndef PCI_SEGMENT_BUS_NUMBER
65 typedef struct _PCI_SEGMENT_BUS_NUMBER {
66   union {
67     struct {
68       ULONG BusNumber:8;
69       ULONG SegmentNumber:16;
70       ULONG Reserved:8;
71     } bits;
72     ULONG AsULONG;
73   } u;
74 } PCI_SEGMENT_BUS_NUMBER, *PPCI_SEGMENT_BUS_NUMBER;
75 #define PCI_SEGMENT_BUS_NUMBER PCI_SEGMENT_BUS_NUMBER
76 #endif
77
78 #ifndef PCI_SLOT_NUMBER
79 typedef struct _PCI_SLOT_NUMBER {
80   union {
81     struct {
82       ULONG DeviceNumber:5;
83       ULONG FunctionNumber:3;
84       ULONG Reserved:24;
85     } bits;
86     ULONG AsULONG;
87   } u;
88 } PCI_SLOT_NUMBER, *PPCI_SLOT_NUMBER;
89 #define PCI_SLOT_NUMBER PCI_SLOT_NUMBER
90 #endif
91
92 #ifndef KLDBG
93 typedef struct _KLDBG {
94   SYSDBG_COMMAND Command;
95   PVOID Buffer;
96   DWORD BufferLength;
97 } KLDBG, *PKLDBG;
98 #define KLDBG KLDBG
99 #endif
100
101 static BOOL debug_privilege_enabled;
102 static LUID luid_debug_privilege;
103 static BOOL revert_only_privilege;
104 static HANDLE revert_token;
105
106 static HANDLE kldbg_dev = INVALID_HANDLE_VALUE;
107
108 static BOOL
109 win32_kldbg_pci_bus_data(BOOL WriteBusData, USHORT SegmentNumber, BYTE BusNumber, BYTE DeviceNumber, BYTE FunctionNumber, USHORT Address, PVOID Buffer, ULONG BufferSize, LPDWORD Length);
110
111 static const char *
112 win32_strerror(DWORD win32_error_id)
113 {
114   /*
115    * Use static buffer which is large enough.
116    * Hopefully no Win32 API error message string is longer than 4 kB.
117    */
118   static char buffer[4096];
119   DWORD len;
120
121   len = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, win32_error_id, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buffer, sizeof(buffer), NULL);
122
123   /* FormatMessage() automatically appends ".\r\n" to the error message. */
124   if (len && buffer[len-1] == '\n')
125     buffer[--len] = '\0';
126   if (len && buffer[len-1] == '\r')
127     buffer[--len] = '\0';
128   if (len && buffer[len-1] == '.')
129     buffer[--len] = '\0';
130
131   if (!len)
132     sprintf(buffer, "Unknown Win32 error %lu", win32_error_id);
133
134   return buffer;
135 }
136
137 static BOOL
138 win32_is_32bit_on_64bit_system(void)
139 {
140   BOOL (WINAPI *MyIsWow64Process)(HANDLE, PBOOL);
141   HMODULE kernel32;
142   BOOL is_wow64;
143
144   kernel32 = GetModuleHandle(TEXT("kernel32.dll"));
145   if (!kernel32)
146     return FALSE;
147
148   MyIsWow64Process = (void *)GetProcAddress(kernel32, "IsWow64Process");
149   if (!MyIsWow64Process)
150     return FALSE;
151
152   if (!MyIsWow64Process(GetCurrentProcess(), &is_wow64))
153     return FALSE;
154
155   return is_wow64;
156 }
157
158 static WORD
159 win32_get_current_process_machine(void)
160 {
161   IMAGE_DOS_HEADER *dos_header;
162   IMAGE_NT_HEADERS *nt_header;
163
164   dos_header = (IMAGE_DOS_HEADER *)GetModuleHandle(NULL);
165   if (dos_header->e_magic != IMAGE_DOS_SIGNATURE)
166     return IMAGE_FILE_MACHINE_UNKNOWN;
167
168   nt_header = (IMAGE_NT_HEADERS *)((BYTE *)dos_header + dos_header->e_lfanew);
169   if (nt_header->Signature != IMAGE_NT_SIGNATURE)
170     return IMAGE_FILE_MACHINE_UNKNOWN;
171
172   return nt_header->FileHeader.Machine;
173 }
174
175 static BOOL
176 win32_check_driver(BYTE *driver_data)
177 {
178   IMAGE_DOS_HEADER *dos_header;
179   IMAGE_NT_HEADERS *nt_headers;
180   WORD current_machine;
181
182   current_machine = win32_get_current_process_machine();
183   if (current_machine == IMAGE_FILE_MACHINE_UNKNOWN)
184     return FALSE;
185
186   dos_header = (IMAGE_DOS_HEADER *)driver_data;
187   if (dos_header->e_magic != IMAGE_DOS_SIGNATURE)
188     return FALSE;
189
190   nt_headers = (IMAGE_NT_HEADERS *)((BYTE *)dos_header + dos_header->e_lfanew);
191   if (nt_headers->Signature != IMAGE_NT_SIGNATURE)
192     return FALSE;
193
194   if (nt_headers->FileHeader.Machine != current_machine)
195     return FALSE;
196
197   if (!(nt_headers->FileHeader.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE))
198     return FALSE;
199
200 #ifndef _WIN64
201   if (!(nt_headers->FileHeader.Characteristics & IMAGE_FILE_32BIT_MACHINE))
202     return FALSE;
203 #endif
204
205   /* IMAGE_NT_OPTIONAL_HDR_MAGIC is alias for the header magic used on the target compiler architecture. */
206   if (nt_headers->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC)
207     return FALSE;
208
209   if (nt_headers->OptionalHeader.Subsystem != IMAGE_SUBSYSTEM_NATIVE)
210     return FALSE;
211
212   return TRUE;
213 }
214
215 static int
216 win32_kldbg_unpack_driver(struct pci_access *a, LPTSTR driver_path)
217 {
218   BOOL use_kd_exe = FALSE;
219   HMODULE exe_with_driver = NULL;
220   HRSRC driver_resource_info = NULL;
221   HGLOBAL driver_resource = NULL;
222   BYTE *driver_data = NULL;
223   DWORD driver_size = 0;
224   HANDLE driver_handle = INVALID_HANDLE_VALUE;
225   DWORD written = 0;
226   DWORD error = 0;
227   int ret = 0;
228
229   /* Try to find and open windbg.exe or kd.exe file in PATH. */
230   exe_with_driver = LoadLibraryEx(TEXT("windbg.exe"), NULL, LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE | LOAD_LIBRARY_AS_IMAGE_RESOURCE);
231   if (!exe_with_driver)
232     {
233       use_kd_exe = TRUE;
234       exe_with_driver = LoadLibraryEx(TEXT("kd.exe"), NULL, LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE | LOAD_LIBRARY_AS_IMAGE_RESOURCE);
235     }
236   if (!exe_with_driver)
237     {
238       error = GetLastError();
239       if (error == ERROR_FILE_NOT_FOUND ||
240           error == ERROR_MOD_NOT_FOUND)
241         a->debug("Cannot find windbg.exe or kd.exe file in PATH");
242       else
243         a->debug("Cannot load %s file: %s.", use_kd_exe ? "kd.exe" : "windbg.exe", win32_strerror(error));
244       goto out;
245     }
246
247   /* kldbgdrv.sys is embedded in windbg.exe/kd.exe as a resource with name id 0x7777 and type id 0x4444. */
248   driver_resource_info = FindResource(exe_with_driver, MAKEINTRESOURCE(0x7777), MAKEINTRESOURCE(0x4444));
249   if (!driver_resource_info)
250     {
251       a->debug("Cannot find kldbgdrv.sys resource in %s file: %s.", use_kd_exe ? "kd.exe" : "windbg.exe", win32_strerror(GetLastError()));
252       goto out;
253     }
254
255   driver_resource = LoadResource(exe_with_driver, driver_resource_info);
256   if (!driver_resource)
257     {
258       a->debug("Cannot load kldbgdrv.sys resource from %s file: %s.", use_kd_exe ? "kd.exe" : "windbg.exe", win32_strerror(GetLastError()));
259       goto out;
260     }
261
262   driver_size = SizeofResource(exe_with_driver, driver_resource_info);
263   if (!driver_size)
264     {
265       a->debug("Cannot determinate size of kldbgdrv.sys resource from %s file: %s.", use_kd_exe ? "kd.exe" : "windbg.exe", win32_strerror(GetLastError()));
266       goto out;
267     }
268
269   driver_data = LockResource(driver_resource);
270   if (!driver_data)
271     {
272       a->debug("Cannot load kldbgdrv.sys resouce data from %s file: %s.", use_kd_exe ? "kd.exe" : "windbg.exe", win32_strerror(GetLastError()));
273       goto out;
274     }
275
276   if (!win32_check_driver(driver_data))
277     {
278       a->debug("Cannot use kldbgdrv.sys driver from %s file: Driver is from different architecture.", use_kd_exe ? "kd.exe" : "windbg.exe");
279       goto out;
280     }
281
282   driver_handle = CreateFile(driver_path, GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
283   if (driver_handle == INVALID_HANDLE_VALUE)
284     {
285       error = GetLastError();
286       if (error != ERROR_FILE_EXISTS)
287         {
288           a->debug("Cannot create kldbgdrv.sys driver file in system32 directory: %s.", win32_strerror(error));
289           goto out;
290         }
291       /* If driver file in system32 directory already exists then treat it as successfull unpack. */
292       ret = 1;
293       goto out;
294     }
295
296   if (!WriteFile(driver_handle, driver_data, driver_size, &written, NULL) ||
297       written != driver_size)
298     {
299       a->debug("Cannot store kldbgdrv.sys driver file to system32 directory: %s.", win32_strerror(GetLastError()));
300       /* On error, delete file from system32 directory to allow another unpack attempt. */
301       CloseHandle(driver_handle);
302       driver_handle = INVALID_HANDLE_VALUE;
303       DeleteFile(driver_path);
304       goto out;
305     }
306
307   a->debug("Driver kldbgdrv.sys was successfully unpacked from %s and stored in system32 directory...", use_kd_exe ? "kd.exe" : "windbg.exe");
308   ret = 1;
309
310 out:
311   if (driver_handle != INVALID_HANDLE_VALUE)
312     CloseHandle(driver_handle);
313
314   if (driver_resource)
315     FreeResource(driver_resource);
316
317   if (exe_with_driver)
318     FreeLibrary(exe_with_driver);
319
320   return ret;
321 }
322
323 static int
324 win32_kldbg_register_driver(struct pci_access *a, SC_HANDLE manager, SC_HANDLE *service)
325 {
326   UINT system32_len;
327   LPTSTR driver_path;
328   HANDLE driver_handle;
329
330   /*
331    * COM library dbgeng.dll unpacks kldbg driver to file "\\system32\\kldbgdrv.sys"
332    * and register this driver with service name kldbgdrv. Implement same behavior.
333    * GetSystemDirectory() returns path to "\\system32" directory on all Windows versions.
334    */
335
336   system32_len = GetSystemDirectory(NULL, 0); /* Returns number of TCHARs plus 1 for nul-term. */
337   if (!system32_len)
338     system32_len = sizeof("C:\\Windows\\System32");
339
340   driver_path = pci_malloc(a, (system32_len + sizeof("\\kldbgdrv.sys")-1) * sizeof(TCHAR));
341
342   system32_len = GetSystemDirectory(driver_path, system32_len); /* Now it returns number of TCHARs without nul-term. */
343   if (!system32_len)
344     {
345       system32_len = sizeof("C:\\Windows\\System32")-1;
346       memcpy(driver_path, TEXT("C:\\Windows\\System32"), system32_len);
347     }
348
349   /* GetSystemDirectory returns path without backslash unless the system directory is the root directory. */
350   if (driver_path[system32_len-1] != '\\')
351     driver_path[system32_len++] = '\\';
352
353   memcpy(driver_path + system32_len, TEXT("kldbgdrv.sys"), sizeof(TEXT("kldbgdrv.sys")));
354
355   driver_handle = CreateFile(driver_path, 0, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
356   if (driver_handle != INVALID_HANDLE_VALUE)
357     CloseHandle(driver_handle);
358   else if (GetLastError() == ERROR_FILE_NOT_FOUND)
359     {
360       a->debug("Driver kldbgdrv.sys is missing, trying to unpack it from windbg.exe or kd.exe...");
361       if (!win32_kldbg_unpack_driver(a, driver_path))
362         {
363           pci_mfree(driver_path);
364           return 0;
365         }
366     }
367
368   *service = CreateService(manager, TEXT("kldbgdrv"), TEXT("kldbgdrv"), SERVICE_START, SERVICE_KERNEL_DRIVER, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, driver_path, NULL, NULL, NULL, NULL, NULL);
369   if (!*service)
370     {
371       if (GetLastError() != ERROR_SERVICE_EXISTS)
372         {
373           a->debug("Cannot create kldbgdrv service: %s.", win32_strerror(GetLastError()));
374           pci_mfree(driver_path);
375           return 0;
376         }
377
378       *service = OpenService(manager, TEXT("kldbgdrv"), SERVICE_START);
379       if (!*service)
380         {
381           a->debug("Cannot open kldbgdrv service: %s.", win32_strerror(GetLastError()));
382           pci_mfree(driver_path);
383           return 0;
384         }
385     }
386
387   a->debug("Service kldbgdrv was successfully registered...");
388   pci_mfree(driver_path);
389   return 1;
390 }
391
392 static int
393 win32_kldbg_start_driver(struct pci_access *a)
394 {
395   SC_HANDLE manager = NULL;
396   SC_HANDLE service = NULL;
397   DWORD error = 0;
398   int ret = 0;
399
400   manager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE);
401   if (!manager)
402     manager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
403   if (!manager)
404     {
405       a->debug("Cannot open Service Manager: %s.", win32_strerror(GetLastError()));
406       return 0;
407     }
408
409   service = OpenService(manager, TEXT("kldbgdrv"), SERVICE_START);
410   if (!service)
411     {
412       error = GetLastError();
413       if (error != ERROR_SERVICE_DOES_NOT_EXIST)
414         {
415           a->debug("Cannot open kldbgdrv service: %s.", win32_strerror(error));
416           goto out;
417         }
418
419       a->debug("Kernel Local Debugging Driver (kldbgdrv.sys) is not registered, trying to register it...");
420
421       if (win32_is_32bit_on_64bit_system())
422         {
423           /* TODO */
424           a->debug("Registering driver from 32-bit process on 64-bit system is not implemented yet.");
425           goto out;
426         }
427
428       if (!win32_kldbg_register_driver(a, manager, &service))
429         goto out;
430     }
431
432   if (!StartService(service, 0, NULL))
433     {
434       error = GetLastError();
435       if (error != ERROR_SERVICE_ALREADY_RUNNING)
436         {
437           a->debug("Cannot start kldbgdrv service: %s.", win32_strerror(error));
438           goto out;
439         }
440     }
441
442   a->debug("Service kldbgdrv successfully started...");
443   ret = 1;
444
445 out:
446   if (service)
447     CloseServiceHandle(service);
448
449   if (manager)
450     CloseServiceHandle(manager);
451
452   return ret;
453 }
454
455 static int
456 win32_kldbg_setup(struct pci_access *a)
457 {
458   OSVERSIONINFO version;
459   DWORD ret_len;
460   DWORD error;
461   DWORD id;
462
463   if (kldbg_dev != INVALID_HANDLE_VALUE)
464     return 1;
465
466   /* Check for Windows Vista (NT 6.0). */
467   version.dwOSVersionInfoSize = sizeof(version);
468   if (!GetVersionEx(&version) ||
469       version.dwPlatformId != VER_PLATFORM_WIN32_NT ||
470       version.dwMajorVersion < 6)
471     {
472       a->debug("Accessing PCI config space via Kernel Local Debugging Driver requires Windows Vista or higher version.");
473       return 0;
474     }
475
476   kldbg_dev = CreateFile(TEXT("\\\\.\\kldbgdrv"), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
477   if (kldbg_dev == INVALID_HANDLE_VALUE)
478     {
479       error = GetLastError();
480       if (error != ERROR_FILE_NOT_FOUND)
481         {
482           a->debug("Cannot open \"\\\\.\\kldbgdrv\" device: %s.", win32_strerror(error));
483           return 0;
484         }
485
486       a->debug("Kernel Local Debugging Driver (kldbgdrv.sys) is not running, trying to start it...");
487
488       if (!win32_kldbg_start_driver(a))
489         return 0;
490
491       kldbg_dev = CreateFile(TEXT("\\\\.\\kldbgdrv"), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
492       if (kldbg_dev == INVALID_HANDLE_VALUE)
493         {
494           error = GetLastError();
495           a->debug("Cannot open \"\\\\.\\kldbgdrv\" device: %s.", win32_strerror(error));
496           return 0;
497         }
498     }
499
500   /*
501    * Try to read PCI id register from PCI device 0000:00:00.0.
502    * If this device does not exist and kldbg API is working then
503    * kldbg returns success with read value 0xffffffff.
504    */
505   if (win32_kldbg_pci_bus_data(FALSE, 0, 0, 0, 0, 0, &id, sizeof(id), &ret_len) && ret_len == sizeof(id))
506     return 1;
507
508   error = GetLastError();
509
510   a->debug("Cannot read PCI config space via Kernel Local Debugging Driver: %s.", win32_strerror(error));
511
512   if (error != ERROR_ACCESS_DENIED)
513     {
514       CloseHandle(kldbg_dev);
515       kldbg_dev = INVALID_HANDLE_VALUE;
516       return 0;
517     }
518
519   a->debug("..Trying again with Debug privilege...");
520
521   if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid_debug_privilege))
522     {
523       a->debug("Debug privilege is not supported.");
524       CloseHandle(kldbg_dev);
525       kldbg_dev = INVALID_HANDLE_VALUE;
526       return 0;
527     }
528
529   if (!enable_privilege(luid_debug_privilege, &revert_token, &revert_only_privilege))
530     {
531       a->debug("Process does not have right to enable Debug privilege.");
532       CloseHandle(kldbg_dev);
533       kldbg_dev = INVALID_HANDLE_VALUE;
534       return 0;
535     }
536
537   if (win32_kldbg_pci_bus_data(FALSE, 0, 0, 0, 0, 0, &id, sizeof(id), &ret_len) && ret_len == sizeof(id))
538     {
539       a->debug("Succeeded.");
540       debug_privilege_enabled = TRUE;
541       return 1;
542     }
543
544   error = GetLastError();
545
546   a->debug("Cannot read PCI config space via Kernel Local Debugging Driver: %s.", win32_strerror(error));
547
548   CloseHandle(kldbg_dev);
549   kldbg_dev = INVALID_HANDLE_VALUE;
550
551   revert_privilege(luid_debug_privilege, revert_token, revert_only_privilege);
552   revert_token = NULL;
553   revert_only_privilege = FALSE;
554   return 0;
555 }
556
557 static int
558 win32_kldbg_detect(struct pci_access *a)
559 {
560   if (!win32_kldbg_setup(a))
561     return 0;
562
563   return 1;
564 }
565
566 static void
567 win32_kldbg_init(struct pci_access *a)
568 {
569   if (!win32_kldbg_setup(a))
570     {
571       a->debug("\n");
572       a->error("PCI config space via Kernel Local Debugging Driver cannot be accessed.");
573     }
574 }
575
576 static void
577 win32_kldbg_cleanup(struct pci_access *a UNUSED)
578 {
579   if (kldbg_dev == INVALID_HANDLE_VALUE)
580     return;
581
582   CloseHandle(kldbg_dev);
583   kldbg_dev = INVALID_HANDLE_VALUE;
584
585   if (debug_privilege_enabled)
586     {
587       revert_privilege(luid_debug_privilege, revert_token, revert_only_privilege);
588       revert_token = NULL;
589       revert_only_privilege = FALSE;
590       debug_privilege_enabled = FALSE;
591     }
592 }
593
594 struct acpi_mcfg {
595   char signature[4];
596   u32 length;
597   u8 revision;
598   u8 checksum;
599   char oem_id[6];
600   char oem_table_id[8];
601   u32 oem_revision;
602   char asl_compiler_id[4];
603   u32 asl_compiler_revision;
604   u64 reserved;
605   struct {
606     u64 address;
607     u16 pci_segment;
608     u8 start_bus_number;
609     u8 end_bus_number;
610     u32 reserved;
611   } allocations[0];
612 } PCI_PACKED;
613
614 static void
615 win32_kldbg_scan(struct pci_access *a)
616 {
617   /*
618    * There is no kldbg API to retrieve list of PCI segments. WinDBG pci plugin
619    * kext.dll loads debug symbols from pci.pdb file for kernel module pci.sys.
620    * Then it reads kernel memory which belongs to PciSegmentList local variable
621    * which is the first entry of struct _PCI_SEGMENT linked list. And then it
622    * iterates all entries in linked list and reads SegmentNumber for each entry.
623    *
624    * This is extremly ugly hack and does not work on systems without installed
625    * kernel debug symbol files.
626    *
627    * Do something less ugly. Retrieve ACPI MCFG table via GetSystemFirmwareTable
628    * and parse all PCI segment numbers from it. ACPI MCFG table contains PCIe
629    * ECAM definitions, so all PCI segment numbers.
630    */
631
632   UINT (*WINAPI MyGetSystemFirmwareTable)(DWORD FirmwareTableProviderSignature, DWORD FirmwareTableID, PVOID pFirmwareTableBuffer, DWORD BufferSize);
633   int i, allocations_count;
634   struct acpi_mcfg *mcfg;
635   HMODULE kernel32;
636   byte *segments;
637   DWORD error;
638   DWORD size;
639
640   /* Always scan PCI segment 0. */
641   pci_generic_scan_domain(a, 0);
642
643   kernel32 = GetModuleHandle(TEXT("kernel32.dll"));
644   if (!kernel32)
645     return;
646
647   /* Function GetSystemFirmwareTable() is available since Windows Vista. */
648   MyGetSystemFirmwareTable = (void *)GetProcAddress(kernel32, "GetSystemFirmwareTable");
649   if (!MyGetSystemFirmwareTable)
650     return;
651
652   /* 0x41435049 = 'ACPI', 0x4746434D = 'MCFG' */
653   size = MyGetSystemFirmwareTable(0x41435049, 0x4746434D, NULL, 0);
654   if (size == 0)
655     {
656       error = GetLastError();
657       if (error == ERROR_INVALID_FUNCTION) /* ACPI is not present, so only PCI segment 0 is available. */
658         return;
659       else if (error == ERROR_NOT_FOUND) /* MCFG table is not present, so only PCI segment 0 is available. */
660         return;
661       a->debug("Cannot retrieve ACPI MCFG table: %s.\n", win32_strerror(error));
662       return;
663     }
664
665   mcfg = pci_malloc(a, size);
666
667   if (MyGetSystemFirmwareTable(0x41435049, 0x4746434D, mcfg, size) != size)
668     {
669       error = GetLastError();
670       a->debug("Cannot retrieve ACPI MCFG table: %s.\n", win32_strerror(error));
671       pci_mfree(mcfg);
672       return;
673     }
674
675   if (size < sizeof(*mcfg) || size < mcfg->length)
676     {
677       a->debug("ACPI MCFG table is broken.\n");
678       pci_mfree(mcfg);
679       return;
680     }
681
682   segments = pci_malloc(a, 0xFFFF/8);
683   memset(segments, 0, 0xFFFF/8);
684
685   /* Scan all MCFG allocations and set available PCI segments into bit field. */
686   allocations_count = (mcfg->length - ((unsigned char *)&mcfg->allocations - (unsigned char *)mcfg)) / sizeof(mcfg->allocations[0]);
687   for (i = 0; i < allocations_count; i++)
688     segments[mcfg->allocations[i].pci_segment / 8] |= 1 << (mcfg->allocations[i].pci_segment % 8);
689
690   /* Skip PCI segment 0 which was already scanned. */
691   for (i = 1; i < 0xFFFF; i++)
692     if (segments[i / 8] & (1 << (i % 8)))
693       pci_generic_scan_domain(a, i);
694
695   pci_mfree(segments);
696   pci_mfree(mcfg);
697 }
698
699 static BOOL
700 win32_kldbg_pci_bus_data(BOOL WriteBusData, USHORT SegmentNumber, BYTE BusNumber, BYTE DeviceNumber, BYTE FunctionNumber, USHORT Address, PVOID Buffer, ULONG BufferSize, LPDWORD Length)
701 {
702   KLDBG kldbg_cmd;
703   SYSDBG_BUS_DATA sysdbg_cmd;
704   PCI_SLOT_NUMBER pci_slot;
705   PCI_SEGMENT_BUS_NUMBER pci_seg_bus;
706
707   memset(&pci_slot, 0, sizeof(pci_slot));
708   memset(&sysdbg_cmd, 0, sizeof(sysdbg_cmd));
709   memset(&pci_seg_bus, 0, sizeof(pci_seg_bus));
710
711   sysdbg_cmd.Address = Address;
712   sysdbg_cmd.Buffer = Buffer;
713   sysdbg_cmd.Request = BufferSize;
714   sysdbg_cmd.BusDataType = PCIConfiguration;
715   pci_seg_bus.u.bits.BusNumber = BusNumber;
716   pci_seg_bus.u.bits.SegmentNumber = SegmentNumber;
717   sysdbg_cmd.BusNumber = pci_seg_bus.u.AsULONG;
718   pci_slot.u.bits.DeviceNumber = DeviceNumber;
719   pci_slot.u.bits.FunctionNumber = FunctionNumber;
720   sysdbg_cmd.SlotNumber = pci_slot.u.AsULONG;
721
722   kldbg_cmd.Command = WriteBusData ? SysDbgWriteBusData : SysDbgReadBusData;
723   kldbg_cmd.Buffer = &sysdbg_cmd;
724   kldbg_cmd.BufferLength = sizeof(sysdbg_cmd);
725
726   *Length = 0;
727   return DeviceIoControl(kldbg_dev, IOCTL_KLDBG, &kldbg_cmd, sizeof(kldbg_cmd), &sysdbg_cmd, sizeof(sysdbg_cmd), Length, NULL);
728 }
729
730 static int
731 win32_kldbg_read(struct pci_dev *d, int pos, byte *buf, int len)
732 {
733   DWORD ret_len;
734
735   if ((unsigned int)d->domain > 0xffff)
736     return 0;
737
738   if (!win32_kldbg_pci_bus_data(FALSE, d->domain, d->bus, d->dev, d->func, pos, buf, len, &ret_len))
739     return 0;
740
741   if (ret_len != (unsigned int)len)
742     return 0;
743
744   return 1;
745 }
746
747 static int
748 win32_kldbg_write(struct pci_dev *d, int pos, byte *buf, int len)
749 {
750   DWORD ret_len;
751
752   if ((unsigned int)d->domain > 0xffff)
753     return 0;
754
755   if (!win32_kldbg_pci_bus_data(TRUE, d->domain, d->bus, d->dev, d->func, pos, buf, len, &ret_len))
756     return 0;
757
758   if (ret_len != (unsigned int)len)
759     return 0;
760
761   return 1;
762 }
763
764 struct pci_methods pm_win32_kldbg = {
765   "win32-kldbg",
766   "Win32 PCI config space access using Kernel Local Debugging Driver",
767   NULL,                                 /* config */
768   win32_kldbg_detect,
769   win32_kldbg_init,
770   win32_kldbg_cleanup,
771   win32_kldbg_scan,
772   pci_generic_fill_info,
773   win32_kldbg_read,
774   win32_kldbg_write,
775   NULL,                                 /* read_vpd */
776   NULL,                                 /* init_dev */
777   NULL                                  /* cleanup_dev */
778 };