2 * The PCI Library -- PCI config space access using Kernel Local Debugging Driver
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 <stdio.h> /* for sprintf() */
13 #include <string.h> /* for memset() and memcpy() */
16 #include "i386-io-windows.h"
18 #ifndef ERROR_NOT_FOUND
19 #define ERROR_NOT_FOUND 1168
22 #ifndef LOAD_LIBRARY_AS_IMAGE_RESOURCE
23 #define LOAD_LIBRARY_AS_IMAGE_RESOURCE 0x20
25 #ifndef LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE
26 #define LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE 0x40
30 #define IOCTL_KLDBG CTL_CODE(FILE_DEVICE_UNKNOWN, 0x1, METHOD_NEITHER, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
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_SEGMENT_BUS_NUMBER
63 typedef struct _PCI_SEGMENT_BUS_NUMBER
{
67 ULONG SegmentNumber
:16;
72 } PCI_SEGMENT_BUS_NUMBER
, *PPCI_SEGMENT_BUS_NUMBER
;
73 #define PCI_SEGMENT_BUS_NUMBER PCI_SEGMENT_BUS_NUMBER
76 #ifndef PCI_SLOT_NUMBER
77 typedef struct _PCI_SLOT_NUMBER
{
81 ULONG FunctionNumber
:3;
86 } PCI_SLOT_NUMBER
, *PPCI_SLOT_NUMBER
;
87 #define PCI_SLOT_NUMBER PCI_SLOT_NUMBER
91 typedef struct _KLDBG
{
92 SYSDBG_COMMAND Command
;
99 static BOOL debug_privilege_enabled
;
100 static LUID luid_debug_privilege
;
101 static BOOL revert_only_privilege
;
102 static HANDLE revert_token
;
104 static HANDLE kldbg_dev
= INVALID_HANDLE_VALUE
;
107 win32_kldbg_pci_bus_data(BOOL WriteBusData
, USHORT SegmentNumber
, BYTE BusNumber
, BYTE DeviceNumber
, BYTE FunctionNumber
, USHORT Address
, PVOID Buffer
, ULONG BufferSize
, LPDWORD Length
);
110 win32_strerror(DWORD win32_error_id
)
113 * Use static buffer which is large enough.
114 * Hopefully no Win32 API error message string is longer than 4 kB.
116 static char buffer
[4096];
119 len
= FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM
| FORMAT_MESSAGE_IGNORE_INSERTS
, NULL
, win32_error_id
, MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
), buffer
, sizeof(buffer
), NULL
);
121 /* FormatMessage() automatically appends ".\r\n" to the error message. */
122 if (len
&& buffer
[len
-1] == '\n')
123 buffer
[--len
] = '\0';
124 if (len
&& buffer
[len
-1] == '\r')
125 buffer
[--len
] = '\0';
126 if (len
&& buffer
[len
-1] == '.')
127 buffer
[--len
] = '\0';
130 sprintf(buffer
, "Unknown Win32 error %lu", win32_error_id
);
136 win32_is_32bit_on_64bit_system(void)
138 BOOL (WINAPI
*MyIsWow64Process
)(HANDLE
, PBOOL
);
142 kernel32
= GetModuleHandle(TEXT("kernel32.dll"));
146 MyIsWow64Process
= (void *)GetProcAddress(kernel32
, "IsWow64Process");
147 if (!MyIsWow64Process
)
150 if (!MyIsWow64Process(GetCurrentProcess(), &is_wow64
))
157 win32_get_current_process_machine(void)
159 IMAGE_DOS_HEADER
*dos_header
;
160 IMAGE_NT_HEADERS
*nt_header
;
162 dos_header
= (IMAGE_DOS_HEADER
*)GetModuleHandle(NULL
);
163 if (dos_header
->e_magic
!= IMAGE_DOS_SIGNATURE
)
164 return IMAGE_FILE_MACHINE_UNKNOWN
;
166 nt_header
= (IMAGE_NT_HEADERS
*)((BYTE
*)dos_header
+ dos_header
->e_lfanew
);
167 if (nt_header
->Signature
!= IMAGE_NT_SIGNATURE
)
168 return IMAGE_FILE_MACHINE_UNKNOWN
;
170 return nt_header
->FileHeader
.Machine
;
174 win32_check_driver(BYTE
*driver_data
)
176 IMAGE_DOS_HEADER
*dos_header
;
177 IMAGE_NT_HEADERS
*nt_headers
;
178 WORD current_machine
;
180 current_machine
= win32_get_current_process_machine();
181 if (current_machine
== IMAGE_FILE_MACHINE_UNKNOWN
)
184 dos_header
= (IMAGE_DOS_HEADER
*)driver_data
;
185 if (dos_header
->e_magic
!= IMAGE_DOS_SIGNATURE
)
188 nt_headers
= (IMAGE_NT_HEADERS
*)((BYTE
*)dos_header
+ dos_header
->e_lfanew
);
189 if (nt_headers
->Signature
!= IMAGE_NT_SIGNATURE
)
192 if (nt_headers
->FileHeader
.Machine
!= current_machine
)
195 if (!(nt_headers
->FileHeader
.Characteristics
& IMAGE_FILE_EXECUTABLE_IMAGE
))
199 if (!(nt_headers
->FileHeader
.Characteristics
& IMAGE_FILE_32BIT_MACHINE
))
203 /* IMAGE_NT_OPTIONAL_HDR_MAGIC is alias for the header magic used on the target compiler architecture. */
204 if (nt_headers
->OptionalHeader
.Magic
!= IMAGE_NT_OPTIONAL_HDR_MAGIC
)
207 if (nt_headers
->OptionalHeader
.Subsystem
!= IMAGE_SUBSYSTEM_NATIVE
)
214 win32_kldbg_unpack_driver(struct pci_access
*a
, void *driver_path
)
216 BOOL use_kd_exe
= FALSE
;
217 HMODULE exe_with_driver
= NULL
;
218 HRSRC driver_resource_info
= NULL
;
219 HGLOBAL driver_resource
= NULL
;
220 BYTE
*driver_data
= NULL
;
221 DWORD driver_size
= 0;
222 HANDLE driver_handle
= INVALID_HANDLE_VALUE
;
227 /* Try to find and open windbg.exe or kd.exe file in PATH. */
228 exe_with_driver
= LoadLibraryEx(TEXT("windbg.exe"), NULL
, LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE
| LOAD_LIBRARY_AS_IMAGE_RESOURCE
);
229 if (!exe_with_driver
)
232 exe_with_driver
= LoadLibraryEx(TEXT("kd.exe"), NULL
, LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE
| LOAD_LIBRARY_AS_IMAGE_RESOURCE
);
234 if (!exe_with_driver
)
236 error
= GetLastError();
237 if (error
== ERROR_FILE_NOT_FOUND
||
238 error
== ERROR_MOD_NOT_FOUND
)
239 a
->debug("Cannot find windbg.exe or kd.exe file in PATH");
241 a
->debug("Cannot load %s file: %s.", use_kd_exe
? "kd.exe" : "windbg.exe", win32_strerror(error
));
245 /* kldbgdrv.sys is embedded in windbg.exe/kd.exe as a resource with name id 0x7777 and type id 0x4444. */
246 driver_resource_info
= FindResource(exe_with_driver
, MAKEINTRESOURCE(0x7777), MAKEINTRESOURCE(0x4444));
247 if (!driver_resource_info
)
249 a
->debug("Cannot find kldbgdrv.sys resource in %s file: %s.", use_kd_exe
? "kd.exe" : "windbg.exe", win32_strerror(GetLastError()));
253 driver_resource
= LoadResource(exe_with_driver
, driver_resource_info
);
254 if (!driver_resource
)
256 a
->debug("Cannot load kldbgdrv.sys resource from %s file: %s.", use_kd_exe
? "kd.exe" : "windbg.exe", win32_strerror(GetLastError()));
260 driver_size
= SizeofResource(exe_with_driver
, driver_resource_info
);
263 a
->debug("Cannot determinate size of kldbgdrv.sys resource from %s file: %s.", use_kd_exe
? "kd.exe" : "windbg.exe", win32_strerror(GetLastError()));
267 driver_data
= LockResource(driver_resource
);
270 a
->debug("Cannot load kldbgdrv.sys resouce data from %s file: %s.", use_kd_exe
? "kd.exe" : "windbg.exe", win32_strerror(GetLastError()));
274 if (!win32_check_driver(driver_data
))
276 a
->debug("Cannot use kldbgdrv.sys driver from %s file: Driver is from different architecture.", use_kd_exe
? "kd.exe" : "windbg.exe");
280 driver_handle
= CreateFile(driver_path
, GENERIC_WRITE
, 0, NULL
, CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, NULL
);
281 if (driver_handle
== INVALID_HANDLE_VALUE
)
283 error
= GetLastError();
284 if (error
!= ERROR_FILE_EXISTS
)
286 a
->debug("Cannot create kldbgdrv.sys driver file in system32 directory: %s.", win32_strerror(error
));
289 /* If driver file in system32 directory already exists then treat it as successfull unpack. */
294 if (!WriteFile(driver_handle
, driver_data
, driver_size
, &written
, NULL
) ||
295 written
!= driver_size
)
297 a
->debug("Cannot store kldbgdrv.sys driver file to system32 directory: %s.", win32_strerror(GetLastError()));
298 /* On error, delete file from system32 directory to allow another unpack attempt. */
299 CloseHandle(driver_handle
);
300 driver_handle
= INVALID_HANDLE_VALUE
;
301 DeleteFile(driver_path
);
305 a
->debug("Driver kldbgdrv.sys was successfully unpacked from %s and stored in system32 directory...", use_kd_exe
? "kd.exe" : "windbg.exe");
309 if (driver_handle
!= INVALID_HANDLE_VALUE
)
310 CloseHandle(driver_handle
);
313 FreeResource(driver_resource
);
316 FreeLibrary(exe_with_driver
);
322 win32_kldbg_register_driver(struct pci_access
*a
, SC_HANDLE manager
, SC_HANDLE
*service
)
324 UINT (WINAPI
*get_system_root_path
)(void *buffer
, UINT size
) = NULL
;
327 HANDLE driver_handle
;
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.
336 * Old Windows versions return path to NT SystemRoot namespace via
337 * GetWindowsDirectory() function. New Windows versions via
338 * GetSystemWindowsDirectory(). GetSystemWindowsDirectory() is not
339 * provided in old Windows versions, so use GetProcAddress() for
340 * compatibility with all Windows versions.
343 kernel32
= GetModuleHandle(TEXT("kernel32.dll"));
345 get_system_root_path
= (void *)GetProcAddress(kernel32
, "GetSystemWindowsDirectory"
353 if (!get_system_root_path
)
354 get_system_root_path
= (void *)&GetWindowsDirectory
;
356 systemroot_len
= get_system_root_path(NULL
, 0);
358 systemroot_len
= sizeof(TEXT("C:\\Windows\\"));
360 driver_path
= pci_malloc(a
, systemroot_len
+ sizeof(TEXT("\\system32\\kldbgdrv.sys")));
362 systemroot_len
= get_system_root_path(driver_path
, systemroot_len
+ sizeof(TEXT("")));
365 systemroot_len
= sizeof(TEXT("C:\\Windows\\"));
366 memcpy(driver_path
, TEXT("C:\\Windows\\"), systemroot_len
);
369 if (((char *)driver_path
)[systemroot_len
-sizeof(TEXT(""))+1] != '\\')
371 ((char *)driver_path
)[systemroot_len
-sizeof(TEXT(""))+1] = '\\';
372 systemroot_len
+= sizeof(TEXT(""));
375 memcpy((char *)driver_path
+ systemroot_len
, TEXT("system32\\kldbgdrv.sys"), sizeof(TEXT("system32\\kldbgdrv.sys")));
377 driver_handle
= CreateFile(driver_path
, 0, 0, NULL
, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
378 if (driver_handle
!= INVALID_HANDLE_VALUE
)
379 CloseHandle(driver_handle
);
380 else if (GetLastError() == ERROR_FILE_NOT_FOUND
)
382 a
->debug("Driver kldbgdrv.sys is missing, trying to unpack it from windbg.exe or kd.exe...");
383 if (!win32_kldbg_unpack_driver(a
, driver_path
))
385 pci_mfree(driver_path
);
390 *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
);
393 if (GetLastError() != ERROR_SERVICE_EXISTS
)
395 a
->debug("Cannot create kldbgdrv service: %s.", win32_strerror(GetLastError()));
396 pci_mfree(driver_path
);
400 *service
= OpenService(manager
, TEXT("kldbgdrv"), SERVICE_START
);
403 a
->debug("Cannot open kldbgdrv service: %s.", win32_strerror(GetLastError()));
404 pci_mfree(driver_path
);
409 a
->debug("Service kldbgdrv was successfully registered...");
410 pci_mfree(driver_path
);
415 win32_kldbg_start_driver(struct pci_access
*a
)
417 SC_HANDLE manager
= NULL
;
418 SC_HANDLE service
= NULL
;
422 manager
= OpenSCManager(NULL
, NULL
, SC_MANAGER_CONNECT
| SC_MANAGER_CREATE_SERVICE
);
424 manager
= OpenSCManager(NULL
, NULL
, SC_MANAGER_CONNECT
);
427 a
->debug("Cannot open Service Manager: %s.", win32_strerror(GetLastError()));
431 service
= OpenService(manager
, TEXT("kldbgdrv"), SERVICE_START
);
434 error
= GetLastError();
435 if (error
!= ERROR_SERVICE_DOES_NOT_EXIST
)
437 a
->debug("Cannot open kldbgdrv service: %s.", win32_strerror(error
));
441 a
->debug("Kernel Local Debugging Driver (kldbgdrv.sys) is not registered, trying to register it...");
443 if (win32_is_32bit_on_64bit_system())
446 a
->debug("Registering driver from 32-bit process on 64-bit system is not implemented yet.");
450 if (!win32_kldbg_register_driver(a
, manager
, &service
))
454 if (!StartService(service
, 0, NULL
))
456 error
= GetLastError();
457 if (error
!= ERROR_SERVICE_ALREADY_RUNNING
)
459 a
->debug("Cannot start kldbgdrv service: %s.", win32_strerror(error
));
464 a
->debug("Service kldbgdrv successfully started...");
469 CloseServiceHandle(service
);
472 CloseServiceHandle(manager
);
478 win32_kldbg_setup(struct pci_access
*a
)
480 OSVERSIONINFO version
;
485 if (kldbg_dev
!= INVALID_HANDLE_VALUE
)
488 /* Check for Windows Vista (NT 6.0). */
489 version
.dwOSVersionInfoSize
= sizeof(version
);
490 if (!GetVersionEx(&version
) ||
491 version
.dwPlatformId
!= VER_PLATFORM_WIN32_NT
||
492 version
.dwMajorVersion
< 6)
494 a
->debug("Accessing PCI config space via Kernel Local Debugging Driver requires Windows Vista or higher version.");
498 kldbg_dev
= CreateFile(TEXT("\\\\.\\kldbgdrv"), GENERIC_READ
| GENERIC_WRITE
, 0, NULL
, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
499 if (kldbg_dev
== INVALID_HANDLE_VALUE
)
501 error
= GetLastError();
502 if (error
!= ERROR_FILE_NOT_FOUND
)
504 a
->debug("Cannot open \"\\\\.\\kldbgdrv\" device: %s.", win32_strerror(error
));
508 a
->debug("Kernel Local Debugging Driver (kldbgdrv.sys) is not running, trying to start it...");
510 if (!win32_kldbg_start_driver(a
))
513 kldbg_dev
= CreateFile(TEXT("\\\\.\\kldbgdrv"), GENERIC_READ
| GENERIC_WRITE
, 0, NULL
, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
514 if (kldbg_dev
== INVALID_HANDLE_VALUE
)
516 error
= GetLastError();
517 a
->debug("Cannot open \"\\\\.\\kldbgdrv\" device: %s.", win32_strerror(error
));
523 * Try to read PCI id register from PCI device 0000:00:00.0.
524 * If this device does not exist and kldbg API is working then
525 * kldbg returns success with read value 0xffffffff.
527 if (win32_kldbg_pci_bus_data(FALSE
, 0, 0, 0, 0, 0, &id
, sizeof(id
), &ret_len
) && ret_len
== sizeof(id
))
530 error
= GetLastError();
532 a
->debug("Cannot read PCI config space via Kernel Local Debugging Driver: %s.", win32_strerror(error
));
534 if (error
!= ERROR_ACCESS_DENIED
)
536 CloseHandle(kldbg_dev
);
537 kldbg_dev
= INVALID_HANDLE_VALUE
;
541 a
->debug("..Trying again with Debug privilege...");
543 if (!LookupPrivilegeValue(NULL
, SE_DEBUG_NAME
, &luid_debug_privilege
))
545 a
->debug("Debug privilege is not supported.");
546 CloseHandle(kldbg_dev
);
547 kldbg_dev
= INVALID_HANDLE_VALUE
;
551 if (!enable_privilege(luid_debug_privilege
, &revert_token
, &revert_only_privilege
))
553 a
->debug("Process does not have right to enable Debug privilege.");
554 CloseHandle(kldbg_dev
);
555 kldbg_dev
= INVALID_HANDLE_VALUE
;
559 if (win32_kldbg_pci_bus_data(FALSE
, 0, 0, 0, 0, 0, &id
, sizeof(id
), &ret_len
) && ret_len
== sizeof(id
))
561 a
->debug("Succeeded.");
562 debug_privilege_enabled
= TRUE
;
566 error
= GetLastError();
568 a
->debug("Cannot read PCI config space via Kernel Local Debugging Driver: %s.", win32_strerror(error
));
570 CloseHandle(kldbg_dev
);
571 kldbg_dev
= INVALID_HANDLE_VALUE
;
573 revert_privilege(luid_debug_privilege
, revert_token
, revert_only_privilege
);
575 revert_only_privilege
= FALSE
;
580 win32_kldbg_detect(struct pci_access
*a
)
582 if (!win32_kldbg_setup(a
))
589 win32_kldbg_init(struct pci_access
*a
)
591 if (!win32_kldbg_setup(a
))
594 a
->error("PCI config space via Kernel Local Debugging Driver cannot be accessed.");
599 win32_kldbg_cleanup(struct pci_access
*a UNUSED
)
601 if (kldbg_dev
== INVALID_HANDLE_VALUE
)
604 CloseHandle(kldbg_dev
);
605 kldbg_dev
= INVALID_HANDLE_VALUE
;
607 if (debug_privilege_enabled
)
609 revert_privilege(luid_debug_privilege
, revert_token
, revert_only_privilege
);
611 revert_only_privilege
= FALSE
;
612 debug_privilege_enabled
= FALSE
;
622 char oem_table_id
[8];
624 char asl_compiler_id
[4];
625 u32 asl_compiler_revision
;
637 win32_kldbg_scan(struct pci_access
*a
)
640 * There is no kldbg API to retrieve list of PCI segments. WinDBG pci plugin
641 * kext.dll loads debug symbols from pci.pdb file for kernel module pci.sys.
642 * Then it reads kernel memory which belongs to PciSegmentList local variable
643 * which is the first entry of struct _PCI_SEGMENT linked list. And then it
644 * iterates all entries in linked list and reads SegmentNumber for each entry.
646 * This is extremly ugly hack and does not work on systems without installed
647 * kernel debug symbol files.
649 * Do something less ugly. Retrieve ACPI MCFG table via GetSystemFirmwareTable
650 * and parse all PCI segment numbers from it. ACPI MCFG table contains PCIe
651 * ECAM definitions, so all PCI segment numbers.
654 UINT (*WINAPI MyGetSystemFirmwareTable
)(DWORD FirmwareTableProviderSignature
, DWORD FirmwareTableID
, PVOID pFirmwareTableBuffer
, DWORD BufferSize
);
655 int i
, allocations_count
;
656 struct acpi_mcfg
*mcfg
;
662 /* Always scan PCI segment 0. */
663 pci_generic_scan_domain(a
, 0);
665 kernel32
= GetModuleHandle(TEXT("kernel32.dll"));
669 /* Function GetSystemFirmwareTable() is available since Windows Vista. */
670 MyGetSystemFirmwareTable
= (void *)GetProcAddress(kernel32
, "GetSystemFirmwareTable");
671 if (!MyGetSystemFirmwareTable
)
674 /* 0x41435049 = 'ACPI', 0x4746434D = 'MCFG' */
675 size
= MyGetSystemFirmwareTable(0x41435049, 0x4746434D, NULL
, 0);
678 error
= GetLastError();
679 if (error
== ERROR_INVALID_FUNCTION
) /* ACPI is not present, so only PCI segment 0 is available. */
681 else if (error
== ERROR_NOT_FOUND
) /* MCFG table is not present, so only PCI segment 0 is available. */
683 a
->debug("Cannot retrieve ACPI MCFG table: %s.\n", win32_strerror(error
));
687 mcfg
= pci_malloc(a
, size
);
689 if (MyGetSystemFirmwareTable(0x41435049, 0x4746434D, mcfg
, size
) != size
)
691 error
= GetLastError();
692 a
->debug("Cannot retrieve ACPI MCFG table: %s.\n", win32_strerror(error
));
697 if (size
< sizeof(*mcfg
) || size
< mcfg
->length
)
699 a
->debug("ACPI MCFG table is broken.\n");
704 segments
= pci_malloc(a
, 0xFFFF/8);
705 memset(segments
, 0, 0xFFFF/8);
707 /* Scan all MCFG allocations and set available PCI segments into bit field. */
708 allocations_count
= (mcfg
->length
- ((unsigned char *)&mcfg
->allocations
- (unsigned char *)mcfg
)) / sizeof(mcfg
->allocations
[0]);
709 for (i
= 0; i
< allocations_count
; i
++)
710 segments
[mcfg
->allocations
[i
].pci_segment
/ 8] |= 1 << (mcfg
->allocations
[i
].pci_segment
% 8);
712 /* Skip PCI segment 0 which was already scanned. */
713 for (i
= 1; i
< 0xFFFF; i
++)
714 if (segments
[i
/ 8] & (1 << (i
% 8)))
715 pci_generic_scan_domain(a
, i
);
722 win32_kldbg_pci_bus_data(BOOL WriteBusData
, USHORT SegmentNumber
, BYTE BusNumber
, BYTE DeviceNumber
, BYTE FunctionNumber
, USHORT Address
, PVOID Buffer
, ULONG BufferSize
, LPDWORD Length
)
725 SYSDBG_BUS_DATA sysdbg_cmd
;
726 PCI_SLOT_NUMBER pci_slot
;
727 PCI_SEGMENT_BUS_NUMBER pci_seg_bus
;
729 memset(&pci_slot
, 0, sizeof(pci_slot
));
730 memset(&sysdbg_cmd
, 0, sizeof(sysdbg_cmd
));
731 memset(&pci_seg_bus
, 0, sizeof(pci_seg_bus
));
733 sysdbg_cmd
.Address
= Address
;
734 sysdbg_cmd
.Buffer
= Buffer
;
735 sysdbg_cmd
.Request
= BufferSize
;
736 sysdbg_cmd
.BusDataType
= PCIConfiguration
;
737 pci_seg_bus
.u
.bits
.BusNumber
= BusNumber
;
738 pci_seg_bus
.u
.bits
.SegmentNumber
= SegmentNumber
;
739 sysdbg_cmd
.BusNumber
= pci_seg_bus
.u
.AsULONG
;
740 pci_slot
.u
.bits
.DeviceNumber
= DeviceNumber
;
741 pci_slot
.u
.bits
.FunctionNumber
= FunctionNumber
;
742 sysdbg_cmd
.SlotNumber
= pci_slot
.u
.AsULONG
;
744 kldbg_cmd
.Command
= WriteBusData
? SysDbgWriteBusData
: SysDbgReadBusData
;
745 kldbg_cmd
.Buffer
= &sysdbg_cmd
;
746 kldbg_cmd
.BufferLength
= sizeof(sysdbg_cmd
);
749 return DeviceIoControl(kldbg_dev
, IOCTL_KLDBG
, &kldbg_cmd
, sizeof(kldbg_cmd
), &sysdbg_cmd
, sizeof(sysdbg_cmd
), Length
, NULL
);
753 win32_kldbg_read(struct pci_dev
*d
, int pos
, byte
*buf
, int len
)
757 if ((unsigned int)d
->domain
> 0xffff)
760 if (!win32_kldbg_pci_bus_data(FALSE
, d
->domain
, d
->bus
, d
->dev
, d
->func
, pos
, buf
, len
, &ret_len
))
763 if (ret_len
!= (unsigned int)len
)
770 win32_kldbg_write(struct pci_dev
*d
, int pos
, byte
*buf
, int len
)
774 if ((unsigned int)d
->domain
> 0xffff)
777 if (!win32_kldbg_pci_bus_data(TRUE
, d
->domain
, d
->bus
, d
->dev
, d
->func
, pos
, buf
, len
, &ret_len
))
780 if (ret_len
!= (unsigned int)len
)
786 struct pci_methods pm_win32_kldbg
= {
788 "Win32 PCI config space access using Kernel Local Debugging Driver",
794 pci_generic_fill_info
,
799 NULL
/* cleanup_dev */