1/* 2cc tools/pcidump.c -o /tmp/pcidump -Wall -framework IOKit -framework CoreFoundation 3 */ 4 5#include <assert.h> 6#include <CoreFoundation/CoreFoundation.h> 7#include <IOKit/IOKitLib.h> 8#include <IOKit/IOKitKeys.h> 9#include <IOKit/pci/IOPCIDevice.h> 10#include <IOKit/pci/IOPCIPrivate.h> 11 12static uint32_t configRead32(io_connect_t connect, uint32_t segment, 13 uint32_t bus, uint32_t device, uint32_t function, 14 uint32_t offset) 15{ 16 IOPCIDiagnosticsParameters param; 17 kern_return_t status; 18 19 param.spaceType = kIOPCIConfigSpace; 20 param.bitWidth = 32; 21 param.options = 0; 22 23 param.address.pci.offset = offset; 24 param.address.pci.function = function; 25 param.address.pci.device = device; 26 param.address.pci.bus = bus; 27 param.address.pci.segment = segment; 28 param.address.pci.reserved = 0; 29 param.value = -1ULL; 30 31 size_t outSize = sizeof(param); 32 status = IOConnectCallStructMethod(connect, kIOPCIDiagnosticsMethodRead, 33 ¶m, sizeof(param), 34 ¶m, &outSize); 35 assert(kIOReturnSuccess == status); 36 return ((uint32_t) param.value); 37} 38 39 40static void configWrite32(io_connect_t connect, uint32_t segment, 41 uint32_t bus, uint32_t device, uint32_t function, 42 uint32_t offset, 43 uint32_t data) 44{ 45 IOPCIDiagnosticsParameters param; 46 kern_return_t status; 47 48 param.spaceType = kIOPCIConfigSpace; 49 param.bitWidth = 32; 50 param.options = 0; 51 52 param.address.pci.offset = offset; 53 param.address.pci.function = function; 54 param.address.pci.device = device; 55 param.address.pci.bus = bus; 56 param.address.pci.segment = segment; 57 param.address.pci.reserved = 0; 58 param.value = data; 59 60 size_t outSize = 0; 61 status = IOConnectCallStructMethod(connect, kIOPCIDiagnosticsMethodWrite, 62 ¶m, sizeof(param), 63 NULL, &outSize); 64 assert(kIOReturnSuccess == status); 65} 66 67static void physWrite32(io_connect_t connect, uint64_t offset, uint32_t data) 68{ 69 IOPCIDiagnosticsParameters param; 70 kern_return_t status; 71 72 param.spaceType = kIOPCI64BitMemorySpace; 73 param.bitWidth = 32; 74 param.options = 0; 75 76 param.address.addr64 = offset; 77 param.value = data; 78 79 size_t outSize = 0; 80 status = IOConnectCallStructMethod(connect, kIOPCIDiagnosticsMethodWrite, 81 ¶m, sizeof(param), 82 NULL, &outSize); 83 assert(kIOReturnSuccess == status); 84} 85 86static uint32_t physRead32(io_connect_t connect, uint64_t offset) 87{ 88 IOPCIDiagnosticsParameters param; 89 kern_return_t status; 90 91 param.spaceType = kIOPCI64BitMemorySpace; 92 param.bitWidth = 32; 93 param.options = 0; 94 95 param.address.addr64 = offset; 96 param.value = -1ULL; 97 98 size_t outSize = sizeof(param); 99 status = IOConnectCallStructMethod(connect, kIOPCIDiagnosticsMethodRead, 100 ¶m, sizeof(param), 101 ¶m, &outSize); 102 assert(kIOReturnSuccess == status); 103 104 return ((uint32_t) param.value); 105} 106 107static uint32_t ioRead32(io_connect_t connect, uint64_t offset) 108{ 109 IOPCIDiagnosticsParameters param; 110 kern_return_t status; 111 112 param.spaceType = kIOPCIIOSpace; 113 param.bitWidth = 16; 114 param.options = 0; 115 116 param.address.addr64 = offset; 117 param.value = -1ULL; 118 119 size_t outSize = sizeof(param); 120 status = IOConnectCallStructMethod(connect, kIOPCIDiagnosticsMethodRead, 121 ¶m, sizeof(param), 122 ¶m, &outSize); 123 assert(kIOReturnSuccess == status); 124 125 return ((uint32_t) param.value); 126} 127 128io_registry_entry_t lookService(uint32_t segment, 129 uint32_t bus, uint32_t device, uint32_t function) 130{ 131 kern_return_t status; 132 io_iterator_t iter; 133 io_service_t service; 134 135 IOPCIAddressSpace space; 136 space.bits = 0; 137 space.es.busNum = bus; 138 space.es.deviceNum = device; 139 space.es.functionNum = function; 140 141 status = IOServiceGetMatchingServices(kIOMasterPortDefault, 142 IOServiceMatching("IOPCIDevice"), &iter); 143 assert(kIOReturnSuccess == status); 144 145 while ((service = IOIteratorNext(iter))) 146 { 147 CFDataRef reg; 148 UInt32 bits; 149 150 reg = IORegistryEntryCreateCFProperty(service, CFSTR("reg"), 151 kCFAllocatorDefault, kNilOptions); 152 bits = 0; 153 154 if (reg) 155 { 156 if (CFDataGetTypeID() == CFGetTypeID(reg)) 157 bits = ((UInt32 *)CFDataGetBytePtr(reg))[0]; 158 CFRelease(reg); 159 } 160 if (bits == space.bits) 161 { 162 IOObjectRetain(service); 163 break; 164 } 165 } 166 IOObjectRelease(iter); 167 168 return (service); 169} 170 171static void dump( const uint8_t * bytes, size_t len ) 172{ 173 int i; 174 175 printf(" 0 1 2 3 4 5 6 7 8 9 A B C D E F"); 176 for (i = 0; i < len; i++) 177 { 178 if( 0 == (i & 15)) 179 printf("\n %02X:", i); 180 printf(" %02x", bytes[i]); 181 } 182 printf("\n"); 183} 184 185static void 186dumpDevice(io_connect_t connect, uint32_t segment, 187 uint32_t bus, uint32_t device, uint32_t fn, 188 uint32_t * maxBus, uint32_t * maxFn) 189{ 190 io_registry_entry_t service; 191 kern_return_t status; 192 io_name_t name; 193 uint64_t entryID; 194 uint32_t off; 195 uint32_t vendProd; 196 uint32_t vend; 197 uint32_t prod; 198 uint32_t headerType; 199 uint32_t priBusNum; 200 uint32_t secBusNum; 201 uint32_t subBusNum; 202 uint32_t data[256/sizeof(uint32_t)]; 203 uint8_t *bytes = (uint8_t *)&data[0]; 204 205 for(off = 0; off < 256; off += 4) 206 data[off >> 2] = configRead32(connect, segment, bus, device, fn, off); 207 208 vendProd = data[0]; 209 vend = vendProd & 0xffff; 210 prod = vendProd >> 16; 211 printf("[%d, %d, %d] 0x%04x, 0x%04x - ", bus, device, fn, vend, prod); 212 213 service = lookService(segment, bus, device, fn); 214 if (service) 215 { 216 status = IORegistryEntryGetName(service, name); 217 assert(kIOReturnSuccess == status); 218 status = IORegistryEntryGetRegistryEntryID(service, &entryID); 219 assert(kIOReturnSuccess == status); 220 printf("\"%s\", 0x%qx - ", name, entryID); 221 IOObjectRelease(service); 222 } 223 224 headerType = bytes[kIOPCIConfigHeaderType]; 225 if (maxFn && (0x80 & headerType)) 226 *maxFn = 7; 227 headerType &= 0x7f; 228 if (!headerType) 229 { 230 // device dump 231 printf("class: 0x%x, 0x%x, 0x%x\n", 232 bytes[kIOPCIConfigRevisionID + 3], 233 bytes[kIOPCIConfigRevisionID + 2], 234 bytes[kIOPCIConfigRevisionID + 1]); 235 } 236 else 237 { 238 priBusNum = bytes[kPCI2PCIPrimaryBus]; 239 secBusNum = bytes[kPCI2PCISecondaryBus]; 240 subBusNum = bytes[kPCI2PCISubordinateBus]; 241 printf("bridge: [%d, %d, %d]\n", priBusNum, secBusNum, subBusNum); 242 if (maxBus && (subBusNum > *maxBus)) 243 *maxBus = subBusNum; 244 } 245 246 dump(bytes, sizeof(data)); 247 printf("\n"); 248} 249 250 251int main(int argc, char **argv) 252{ 253 io_registry_entry_t service; 254 io_connect_t connect; 255 kern_return_t status; 256 257 service = IOServiceGetMatchingService(kIOMasterPortDefault, 258 IOServiceMatching("IOPCIBridge")); 259 assert(service); 260 if (service) 261 { 262 status = IOServiceOpen(service, mach_task_self(), kIOPCIDiagnosticsClientType, &connect); 263 IOObjectRelease(service); 264 assert(kIOReturnSuccess == status); 265 } 266 267 uint32_t count = 0; 268 uint32_t segment = 0; 269 uint32_t maxBus = 0; 270 uint32_t bus, device, fn, maxFn; 271 uint32_t vendProd; 272 273 if (argc > 3) 274 { 275 bus = strtoul(argv[1], NULL, 0); 276 device = strtoul(argv[2], NULL, 0); 277 fn = strtoul(argv[3], NULL, 0); 278 if (argc == 4) 279 { 280 dumpDevice(connect, segment, bus, device, fn, NULL, NULL); 281 count++; 282 } 283 if (argc > 5) 284 { 285 uint32_t offs; 286 uint32_t data; 287 offs = strtoul(argv[4], NULL, 0); 288 data = strtoul(argv[5], NULL, 0); 289 configWrite32(connect, segment, bus, device, fn, offs, data); 290 printf("wrote 0x%08x to [%d, %d, %d]:0x%X\n", data, bus, device, fn, offs); 291 } 292 else if (argc > 4) 293 { 294 uint32_t offs; 295 uint32_t data; 296 offs = strtoul(argv[4], NULL, 0); 297 data = configRead32(connect, segment, bus, device, fn, offs); 298 printf("read 0x%08x from [%d, %d, %d]:0x%X\n", data, bus, device, fn, offs); 299 } 300 } 301 else if (argc > 2) 302 { 303 uint64_t offs; 304 uint32_t data; 305 offs = strtoull(argv[1], NULL, 0); 306 data = strtoul(argv[2], NULL, 0); 307 physWrite32(connect, offs, data); 308 printf("wrote 0x%08x to 0x%llX\n", data, offs); 309 } 310 else if (argc > 1) 311 { 312 uint64_t offs; 313 uint32_t data; 314 offs = strtoull(argv[1], NULL, 0); 315 if (true || (offs > 0x10000ULL)) 316 { 317 data = physRead32(connect, offs); 318 printf("read 0x%08x from mem 0x%llX\n", data, offs); 319 } 320 else 321 { 322 data = ioRead32(connect, offs); 323 printf("read 0x%08x from i/o 0x%llX\n", data, offs); 324 } 325 } 326 else for (bus = 0; bus <= maxBus; bus++) 327 { 328 for (device = 0; device < 32; device++) 329 { 330 maxFn = 0; 331 for (fn = 0; fn <= maxFn; fn++) 332 { 333 vendProd = configRead32(connect, segment, bus, device, fn, kIOPCIConfigVendorID); 334 if ((0xFFFFFFFF == vendProd) || !vendProd) 335 continue; 336 count++; 337 dumpDevice(connect, segment, bus, device, fn, &maxBus, &maxFn); 338 } 339 } 340 } 341 342 printf("total: %d\n", count); 343 exit(0); 344} 345