1/* 2 * Copyright (c) 2000-2013 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24#include <CoreFoundation/CoreFoundation.h> // (CFDictionary, ...) 25#include <IOKit/IOCFSerialize.h> // (IOCFSerialize, ...) 26#include <IOKit/IOKitLib.h> // (IOMasterPort, ...) 27#include <IOKit/IOKitLibPrivate.h> // (IOServiceGetState, ...) 28#include <sys/ioctl.h> // (TIOCGWINSZ, ...) 29#include <term.h> // (tputs, ...) 30#include <unistd.h> // (getopt, ...) 31 32// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 33 34#define assertion(e, message) ((void) (__builtin_expect(!(e), 0) ? fprintf(stderr, "ioreg: error: %s.\n", message), exit(1) : 0)) 35 36// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 37 38struct options 39{ 40 UInt32 archive:1; // (-a option) 41 UInt32 bold:1; // (-b option) 42 UInt32 format:1; // (-f option) 43 UInt32 hex:1; // (-x option) 44 UInt32 inheritance:1; // (-i option) 45 UInt32 list:1; // (-l option) 46 UInt32 root:1; // (-r option) 47 UInt32 tree:1; // (-t option) 48 49 char * class; // (-c option) 50 UInt32 depth; // (-d option) 51 char * key; // (-k option) 52 char * name; // (-n option) 53 char * plane; // (-p option) 54 UInt32 width; // (-w option) 55}; 56 57struct context 58{ 59 io_registry_entry_t service; 60 UInt32 serviceDepth; 61 UInt64 stackOfBits; 62 struct options options; 63}; 64 65// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 66 67static void boldinit(); 68static void boldon(); 69static void boldoff(); 70static void printinit(int width); 71static void print(const char * format, ...); 72static void println(const char * format, ...); 73 74static void cfshowinit(Boolean hex); 75static void cfshow(CFTypeRef object); 76static void cfarrayshow(CFArrayRef object); 77static void cfbooleanshow(CFBooleanRef object); 78static void cfdatashow(CFDataRef object); 79static void cfdictionaryshow(CFDictionaryRef object); 80static void cfnumbershow(CFNumberRef object); 81static void cfsetshow(CFSetRef object); 82static void cfstringshow(CFStringRef object); 83 84static CFStringRef createInheritanceStringForIORegistryClassName(CFStringRef name); 85 86static void printProp(CFStringRef key, CFTypeRef value, struct context * context); 87static void printPhysAddr(CFTypeRef value, struct context * context); 88static void printSlotNames(CFTypeRef value, struct context * context); 89static void printPCIRanges(CFTypeRef value, struct context * context); 90static void printInterruptMap(CFTypeRef value, struct context * context); 91static void printInterrupts(CFTypeRef value, struct context * context); 92static void printInterruptParent( CFTypeRef value, struct context * context ); 93static void printData(CFTypeRef value, struct context * context); 94 95// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 96 97static CFMutableDictionaryRef archive( io_registry_entry_t service, 98 struct options options ) CF_RETURNS_RETAINED; 99 100static CFMutableDictionaryRef archive_scan( io_registry_entry_t service, 101 UInt32 serviceDepth, 102 struct options options ) CF_RETURNS_RETAINED; 103 104static CFMutableArrayRef archive_search( io_registry_entry_t service, 105 UInt32 serviceHasMatchedDepth, 106 UInt32 serviceDepth, 107 io_registry_entry_t stackOfObjects[], 108 struct options options ) CF_RETURNS_RETAINED; 109 110static Boolean compare( io_registry_entry_t service, 111 struct options options ); 112 113static void indent( Boolean isNode, 114 UInt32 serviceDepth, 115 UInt64 stackOfBits ); 116 117static void scan( io_registry_entry_t service, 118 Boolean serviceHasMoreSiblings, 119 UInt32 serviceDepth, 120 UInt64 stackOfBits, 121 struct options options ); 122 123static void search( io_registry_entry_t service, 124 UInt32 serviceHasMatchedDepth, 125 UInt32 serviceDepth, 126 io_registry_entry_t stackOfObjects[], 127 struct options options ); 128 129static void show( io_registry_entry_t service, 130 UInt32 serviceDepth, 131 UInt64 stackOfBits, 132 struct options options ); 133 134static void showitem( const void * key, 135 const void * value, 136 void * parameter ); 137 138static void usage(); 139 140// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 141 142int main(int argc, char ** argv) 143{ 144 int argument = 0; 145 CFWriteStreamRef file = 0; // (needs release) 146 CFTypeRef object = 0; // (needs release) 147 struct options options; 148 CFURLRef path = 0; // (needs release) 149 io_registry_entry_t service = 0; // (needs release) 150 io_registry_entry_t stackOfObjects[64]; 151 Boolean success = FALSE; 152 struct winsize winsize; 153 154 // Initialize our minimal state. 155 156 options.archive = FALSE; 157 options.bold = FALSE; 158 options.format = FALSE; 159 options.hex = FALSE; 160 options.inheritance = FALSE; 161 options.list = FALSE; 162 options.root = FALSE; 163 options.tree = FALSE; 164 165 options.class = 0; 166 options.depth = 0; 167 options.key = 0; 168 options.name = 0; 169 options.plane = kIOServicePlane; 170 options.root = 0; 171 options.width = 0; 172 173 // Obtain the screen width. 174 175 if (isatty(fileno(stdout))) 176 { 177 if (ioctl(fileno(stdout), TIOCGWINSZ, &winsize) == 0) 178 { 179 options.width = winsize.ws_col; 180 } 181 } 182 183 // Obtain the command-line arguments. 184 185 while ( (argument = getopt(argc, argv, ":abc:d:fik:ln:p:rsStw:x")) != -1 ) 186 { 187 switch (argument) 188 { 189 case 'a': 190 options.archive = TRUE; 191 break; 192 case 'b': 193 options.bold = TRUE; 194 break; 195 case 'c': 196 options.class = optarg; 197 break; 198 case 'd': 199 options.depth = atoi(optarg); 200 break; 201 case 'f': 202 options.format = TRUE; 203 break; 204 case 'i': 205 options.inheritance = TRUE; 206 break; 207 case 'k': 208 options.key = optarg; 209 break; 210 case 'l': 211 options.list = TRUE; 212 break; 213 case 'n': 214 options.name = optarg; 215 break; 216 case 'p': 217 options.plane = optarg; 218 break; 219 case 'r': 220 options.root = TRUE; 221 break; 222 case 's': 223 break; 224 case 'S': 225 break; 226 case 't': 227 options.tree = TRUE; 228 break; 229 case 'w': 230 options.width = atoi(optarg); 231 break; 232 case 'x': 233 options.hex = TRUE; 234 break; 235 default: 236 usage(); 237 break; 238 } 239 } 240 241 // Initialize text output functions. 242 243 cfshowinit(options.hex); 244 245 printinit(options.width); 246 247 if (options.bold) boldinit(); 248 249 // Obtain the I/O Kit root service. 250 251 service = IORegistryGetRootEntry(kIOMasterPortDefault); 252 assertion(service, "can't obtain I/O Kit's root service"); 253 254 // Traverse over all the I/O Kit services. 255 256 if (options.archive) 257 { 258 if (options.root) 259 { 260 object = archive_search( /* service */ service, 261 /* serviceHasMatchedDepth */ 0, 262 /* serviceDepth */ 0, 263 /* stackOfObjects */ stackOfObjects, 264 /* options */ options ); 265 } 266 else 267 { 268 object = archive_scan( /* service */ service, 269 /* serviceDepth */ 0, 270 /* options */ options ); 271 } 272 273 if (object) 274 { 275 path = CFURLCreateWithFileSystemPath( /* allocator */ kCFAllocatorDefault, 276 /* filePath */ CFSTR("/dev/stdout"), 277 /* pathStyle */ kCFURLPOSIXPathStyle, 278 /* isDirectory */ FALSE ); 279 assertion(path != NULL, "can't create path"); 280 281 file = CFWriteStreamCreateWithFile(kCFAllocatorDefault, path); 282 assertion(file != NULL, "can't create file"); 283 284 success = CFWriteStreamOpen(file); 285 assertion(success, "can't open file"); 286 287 CFPropertyListWrite( /* propertyList */ object, 288 /* stream */ file, 289 /* format */ kCFPropertyListXMLFormat_v1_0, 290 /* options */ 0, 291 /* error */ NULL ); 292 293 CFWriteStreamClose(file); 294 295 CFRelease(file); 296 CFRelease(path); 297 CFRelease(object); 298 } 299 } 300 else 301 { 302 if (options.root) 303 { 304 search( /* service */ service, 305 /* serviceHasMatchedDepth */ 0, 306 /* serviceDepth */ 0, 307 /* stackOfObjects */ stackOfObjects, 308 /* options */ options ); 309 } 310 else 311 { 312 scan( /* service */ service, 313 /* serviceHasMoreSiblings */ FALSE, 314 /* serviceDepth */ 0, 315 /* stackOfBits */ 0, 316 /* options */ options ); 317 } 318 } 319 320 // Release resources. 321 322 IOObjectRelease(service); 323 324 // Quit. 325 326 exit(0); 327} 328 329// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 330 331static CFMutableDictionaryRef archive( io_registry_entry_t service, 332 struct options options ) 333{ 334 io_name_t class; // (don't release) 335 uint32_t count = 0; 336 CFMutableDictionaryRef dictionary = 0; // (needs release) 337 uint64_t identifier = 0; 338 io_name_t location; // (don't release) 339 io_name_t name; // (don't release) 340 CFTypeRef object = 0; // (needs release) 341 uint64_t state = 0; 342 kern_return_t status = KERN_SUCCESS; 343 uint64_t time = 0; 344 345 // Determine whether the service is a match. 346 347 if (options.list || compare(service, options)) 348 { 349 // Obtain the service's properties. 350 351 status = IORegistryEntryCreateCFProperties( service, 352 &dictionary, 353 kCFAllocatorDefault, 354 kNilOptions ); 355 assertion(status == KERN_SUCCESS, "can't obtain properties"); 356 } 357 else 358 { 359 dictionary = CFDictionaryCreateMutable( kCFAllocatorDefault, 360 0, 361 &kCFTypeDictionaryKeyCallBacks, 362 &kCFTypeDictionaryValueCallBacks ); 363 assertion(dictionary != NULL, "can't create dictionary"); 364 } 365 366 // Obtain the name of the service. 367 368 status = IORegistryEntryGetNameInPlane(service, options.plane, name); 369 assertion(status == KERN_SUCCESS, "can't obtain name"); 370 371 object = CFStringCreateWithCString(kCFAllocatorDefault, name, kCFStringEncodingUTF8); 372 assertion(object != NULL, "can't create name"); 373 374 CFDictionarySetValue(dictionary, CFSTR("IORegistryEntryName"), object); 375 CFRelease(object); 376 377 // Obtain the location of the service. 378 379 status = IORegistryEntryGetLocationInPlane(service, options.plane, location); 380 if (status == KERN_SUCCESS) 381 { 382 object = CFStringCreateWithCString(kCFAllocatorDefault, location, kCFStringEncodingUTF8); 383 assertion(object != NULL, "can't create location"); 384 385 CFDictionarySetValue(dictionary, CFSTR("IORegistryEntryLocation"), object); 386 CFRelease(object); 387 } 388 389 // Obtain the ID of the service. 390 391 status = IORegistryEntryGetRegistryEntryID(service, &identifier); 392 assertion(status == KERN_SUCCESS, "can't obtain identifier"); 393 394 object = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt64Type, &identifier); 395 assertion(object != NULL, "can't create identifier"); 396 397 CFDictionarySetValue(dictionary, CFSTR("IORegistryEntryID"), object); 398 CFRelease(object); 399 400 // Obtain the class of the service. 401 402 status = IOObjectGetClass(service, class); 403 assertion(status == KERN_SUCCESS, "can't obtain class"); 404 405 object = CFStringCreateWithCString(kCFAllocatorDefault, name, kCFStringEncodingUTF8); 406 assertion(object != NULL, "can't create class"); 407 408 CFDictionarySetValue(dictionary, CFSTR("IOObjectClass"), object); 409 CFRelease(object); 410 411 // Obtain the retain count of the service. 412 413 count = IOObjectGetKernelRetainCount(service); 414 415 object = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &count); 416 assertion(object != NULL, "can't create retain count"); 417 418 CFDictionarySetValue(dictionary, CFSTR("IOObjectRetainCount"), object); 419 CFRelease(object); 420 421 // Obtain the busy state of the service (for IOService objects). 422 423 if (IOObjectConformsTo(service, "IOService")) 424 { 425 status = IOServiceGetBusyStateAndTime(service, &state, &count, &time); 426 assertion(status == KERN_SUCCESS, "can't obtain state"); 427 428 object = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt64Type, &state); 429 assertion(object != NULL, "can't create state"); 430 431 CFDictionarySetValue(dictionary, CFSTR("IOServiceState"), object); 432 CFRelease(object); 433 434 object = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &count); 435 assertion(object != NULL, "can't create busy state"); 436 437 CFDictionarySetValue(dictionary, CFSTR("IOServiceBusyState"), object); 438 CFRelease(object); 439 440 object = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt64Type, &time); 441 assertion(object != NULL, "can't create busy time"); 442 443 CFDictionarySetValue(dictionary, CFSTR("IOServiceBusyTime"), object); 444 CFRelease(object); 445 } 446 447 return dictionary; 448} 449 450// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 451 452static CFMutableDictionaryRef archive_scan( io_registry_entry_t service, 453 UInt32 serviceDepth, 454 struct options options ) 455{ 456 CFMutableArrayRef array = 0; // (needs release) 457 io_registry_entry_t child = 0; // (needs release) 458 io_registry_entry_t childUpNext = 0; // (don't release) 459 io_iterator_t children = 0; // (needs release) 460 CFMutableDictionaryRef dictionary = 0; // (needs release) 461 CFTypeRef object = 0; // (needs release) 462 kern_return_t status = KERN_SUCCESS; 463 464 // Obtain the service's children. 465 466 status = IORegistryEntryGetChildIterator(service, options.plane, &children); 467 if (status == KERN_SUCCESS) 468 { 469 childUpNext = IOIteratorNext(children); 470 471 // Obtain the relevant service information. 472 473 dictionary = archive(service, options); 474 475 // Traverse over the children of this service. 476 477 if (options.depth == 0 || options.depth > serviceDepth + 1) 478 { 479 if (childUpNext) 480 { 481 array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); 482 assertion(array != NULL, "can't create array"); 483 484 while (childUpNext) 485 { 486 child = childUpNext; 487 childUpNext = IOIteratorNext(children); 488 489 object = archive_scan( /* service */ child, 490 /* serviceDepth */ serviceDepth + 1, 491 /* options */ options ); 492 assertion(object != NULL, "can't obtain child"); 493 494 CFArrayAppendValue(array, object); 495 CFRelease(object); 496 497 IOObjectRelease(child); 498 } 499 500 CFDictionarySetValue(dictionary, CFSTR("IORegistryEntryChildren"), array); 501 CFRelease(array); 502 } 503 } 504 505 IOObjectRelease(children); 506 } 507 508 return dictionary; 509} 510 511// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 512 513static CFMutableArrayRef archive_search( io_registry_entry_t service, 514 UInt32 serviceHasMatchedDepth, 515 UInt32 serviceDepth, 516 io_registry_entry_t stackOfObjects[], 517 struct options options ) 518{ 519 CFMutableArrayRef array = 0; // (needs release) 520 CFMutableArrayRef array2 = 0; // (needs release) 521 io_registry_entry_t child = 0; // (needs release) 522 io_registry_entry_t childUpNext = 0; // (don't release) 523 io_iterator_t children = 0; // (needs release) 524 CFMutableDictionaryRef dictionary = 0; // (needs release) 525 CFMutableDictionaryRef dictionary2 = 0; // (needs release) 526 UInt32 index = 0; 527 kern_return_t status = KERN_SUCCESS; 528 529 // Determine whether the service is a match. 530 531 if (serviceHasMatchedDepth < serviceDepth + 1 && compare(service, options)) 532 { 533 if (options.depth) 534 { 535 serviceHasMatchedDepth = serviceDepth + options.depth; 536 } 537 else 538 { 539 serviceHasMatchedDepth = UINT32_MAX; 540 } 541 542 if (options.tree) 543 { 544 if (options.depth) options.depth += serviceDepth; 545 546 dictionary = archive_scan( /* service */ service, 547 /* serviceDepth */ serviceDepth, 548 /* options */ options ); 549 550 if (options.depth) options.depth -= serviceDepth; 551 552 for (index = serviceDepth; index > 0; index--) 553 { 554 dictionary2 = archive(stackOfObjects[index - 1], options); 555 assertion(dictionary2 != NULL, "can't obtain parent"); 556 557 CFDictionarySetValue(dictionary2, CFSTR("IORegistryEntryChildren"), dictionary); 558 CFRelease(dictionary); 559 560 dictionary = dictionary2; 561 } 562 } 563 else 564 { 565 dictionary = archive_scan( /* service */ service, 566 /* serviceDepth */ 0, 567 /* options */ options ); 568 } 569 570 array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); 571 assertion(array != NULL, "can't create array"); 572 573 CFArrayAppendValue(array, dictionary); 574 CFRelease(dictionary); 575 } 576 577 // Save service into stackOfObjects for this depth. 578 579 stackOfObjects[serviceDepth] = service; 580 581 // Obtain the service's children. 582 583 status = IORegistryEntryGetChildIterator(service, options.plane, &children); 584 if (status == KERN_SUCCESS) 585 { 586 childUpNext = IOIteratorNext(children); 587 588 // Traverse over the children of this service. 589 590 while (childUpNext) 591 { 592 child = childUpNext; 593 childUpNext = IOIteratorNext(children); 594 595 array2 = archive_search( /* service */ child, 596 /* serviceHasMatchedDepth */ serviceHasMatchedDepth, 597 /* serviceDepth */ serviceDepth + 1, 598 /* stackOfObjects */ stackOfObjects, 599 /* options */ options ); 600 if (array2) 601 { 602 if (array) 603 { 604 CFArrayAppendArray(array, array2, CFRangeMake(0, CFArrayGetCount(array2))); 605 CFRelease(array2); 606 } 607 else 608 { 609 array = array2; 610 } 611 } 612 613 IOObjectRelease(child); 614 } 615 616 IOObjectRelease(children); 617 } 618 619 return array; 620} 621 622// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 623 624static Boolean compare( io_registry_entry_t service, 625 struct options options ) 626{ 627 CFStringRef key = 0; // (needs release) 628 io_name_t location; // (don't release) 629 Boolean match = FALSE; 630 io_name_t name; // (don't release) 631 kern_return_t status = KERN_SUCCESS; 632 CFTypeRef value = 0; // (needs release) 633 634 // Determine whether the class of the service is a match. 635 636 if (options.class) 637 { 638 if (IOObjectConformsTo(service, options.class) == FALSE) 639 { 640 return FALSE; 641 } 642 643 match = TRUE; 644 } 645 646 // Determine whether the key of the service is a match. 647 648 if (options.key) 649 { 650 key = CFStringCreateWithCString( kCFAllocatorDefault, 651 options.key, 652 kCFStringEncodingUTF8 ); 653 assertion(key != NULL, "can't create key"); 654 655 value = IORegistryEntryCreateCFProperty( service, 656 key, 657 kCFAllocatorDefault, 658 kNilOptions ); 659 660 CFRelease(key); 661 662 if (value == NULL) 663 { 664 return FALSE; 665 } 666 667 CFRelease(value); 668 669 match = TRUE; 670 } 671 672 // Determine whether the name of the service is a match. 673 674 if (options.name) 675 { 676 // Obtain the name of the service. 677 678 status = IORegistryEntryGetNameInPlane(service, options.plane, name); 679 assertion(status == KERN_SUCCESS, "can't obtain name"); 680 681 if (strchr(options.name, '@')) 682 { 683 strlcat(name, "@", sizeof(name)); 684 685 // Obtain the location of the service. 686 687 status = IORegistryEntryGetLocationInPlane(service, options.plane, location); 688 if (status == KERN_SUCCESS) strlcat(name, location, sizeof(name)); 689 } 690 691 if (strcmp(options.name, name)) 692 { 693 return FALSE; 694 } 695 696 match = TRUE; 697 } 698 699 return match; 700} 701 702// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 703 704static void scan( io_registry_entry_t service, 705 Boolean serviceHasMoreSiblings, 706 UInt32 serviceDepth, 707 UInt64 stackOfBits, 708 struct options options ) 709{ 710 io_registry_entry_t child = 0; // (needs release) 711 io_registry_entry_t childUpNext = 0; // (don't release) 712 io_iterator_t children = 0; // (needs release) 713 kern_return_t status = KERN_SUCCESS; 714 715 // Obtain the service's children. 716 717 status = IORegistryEntryGetChildIterator(service, options.plane, &children); 718 if (status == KERN_SUCCESS) 719 { 720 childUpNext = IOIteratorNext(children); 721 722 // Save has-more-siblings state into stackOfBits for this depth. 723 724 if (serviceHasMoreSiblings) 725 stackOfBits |= (1 << serviceDepth); 726 else 727 stackOfBits &= ~(1 << serviceDepth); 728 729 // Save has-children state into stackOfBits for this depth. 730 731 if (options.depth == 0 || options.depth > serviceDepth + 1) 732 { 733 if (childUpNext) 734 stackOfBits |= (2 << serviceDepth); 735 else 736 stackOfBits &= ~(2 << serviceDepth); 737 } 738 739 // Print out the relevant service information. 740 741 show(service, serviceDepth, stackOfBits, options); 742 743 // Traverse over the children of this service. 744 745 if (options.depth == 0 || options.depth > serviceDepth + 1) 746 { 747 while (childUpNext) 748 { 749 child = childUpNext; 750 childUpNext = IOIteratorNext(children); 751 752 scan( /* service */ child, 753 /* serviceHasMoreSiblings */ (childUpNext) ? TRUE : FALSE, 754 /* serviceDepth */ serviceDepth + 1, 755 /* stackOfBits */ stackOfBits, 756 /* options */ options ); 757 758 IOObjectRelease(child); 759 } 760 } 761 762 IOObjectRelease(children); 763 } 764} 765 766// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 767 768static void search( io_registry_entry_t service, 769 UInt32 serviceHasMatchedDepth, 770 UInt32 serviceDepth, 771 io_registry_entry_t stackOfObjects[], 772 struct options options ) 773{ 774 io_registry_entry_t child = 0; // (needs release) 775 io_registry_entry_t childUpNext = 0; // (don't release) 776 io_iterator_t children = 0; // (needs release) 777 UInt32 index = 0; 778 kern_return_t status = KERN_SUCCESS; 779 780 // Determine whether the service is a match. 781 782 if (serviceHasMatchedDepth < serviceDepth + 1 && compare(service, options)) 783 { 784 if (options.depth) 785 { 786 serviceHasMatchedDepth = serviceDepth + options.depth; 787 } 788 else 789 { 790 serviceHasMatchedDepth = UINT32_MAX; 791 } 792 793 if (options.tree) 794 { 795 for (index = 0; index < serviceDepth; index++) 796 { 797 show(stackOfObjects[index], index, (2 << index), options); 798 } 799 800 if (options.depth) options.depth += serviceDepth; 801 802 scan( /* service */ service, 803 /* serviceHasMoreSiblings */ FALSE, 804 /* serviceDepth */ serviceDepth, 805 /* stackOfBits */ 0, 806 /* options */ options ); 807 808 if (options.depth) options.depth -= serviceDepth; 809 } 810 else 811 { 812 scan( /* service */ service, 813 /* serviceHasMoreSiblings */ FALSE, 814 /* serviceDepth */ 0, 815 /* stackOfBits */ 0, 816 /* options */ options ); 817 } 818 819 println(""); 820 } 821 822 // Save service into stackOfObjects for this depth. 823 824 stackOfObjects[serviceDepth] = service; 825 826 // Obtain the service's children. 827 828 status = IORegistryEntryGetChildIterator(service, options.plane, &children); 829 if (status == KERN_SUCCESS) 830 { 831 childUpNext = IOIteratorNext(children); 832 833 // Traverse over the children of this service. 834 835 while (childUpNext) 836 { 837 child = childUpNext; 838 childUpNext = IOIteratorNext(children); 839 840 search( /* service */ child, 841 /* serviceHasMatchedDepth */ serviceHasMatchedDepth, 842 /* serviceDepth */ serviceDepth + 1, 843 /* stackOfObjects */ stackOfObjects, 844 /* options */ options ); 845 846 IOObjectRelease(child); 847 } 848 849 IOObjectRelease(children); 850 } 851} 852 853// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 854 855static void show( io_registry_entry_t service, 856 UInt32 serviceDepth, 857 UInt64 stackOfBits, 858 struct options options ) 859{ 860 io_name_t class; // (don't release) 861 struct context context = { service, serviceDepth, stackOfBits, options }; 862 uint32_t integer = 0; 863 uint64_t state = 0; 864 uint64_t accumulated_busy_time; 865 io_name_t location; // (don't release) 866 io_name_t name; // (don't release) 867 CFMutableDictionaryRef properties = 0; // (needs release) 868 kern_return_t status = KERN_SUCCESS; 869 870 // Print out the name of the service. 871 872 status = IORegistryEntryGetNameInPlane(service, options.plane, name); 873 assertion(status == KERN_SUCCESS, "can't obtain name"); 874 875 indent(TRUE, serviceDepth, stackOfBits); 876 877 if (options.bold) boldon(); 878 879 print("%s", name); 880 881 if (options.bold) boldoff(); 882 883 // Print out the location of the service. 884 885 status = IORegistryEntryGetLocationInPlane(service, options.plane, location); 886 if (status == KERN_SUCCESS) print("@%s", location); 887 888 // Print out the class of the service. 889 890 print(" <class "); 891 892 if (options.inheritance) 893 { 894 CFStringRef classCFStr; 895 CFStringRef ancestryCFStr; 896 char * aCStr; 897 898 classCFStr = IOObjectCopyClass (service); 899 ancestryCFStr = createInheritanceStringForIORegistryClassName (classCFStr); 900 901 aCStr = (char *) CFStringGetCStringPtr (ancestryCFStr, kCFStringEncodingMacRoman); 902 if (NULL != aCStr) 903 { 904 print(aCStr); 905 } 906 907 CFRelease (classCFStr); 908 CFRelease (ancestryCFStr); 909 } 910 else 911 { 912 status = IOObjectGetClass(service, class); 913 assertion(status == KERN_SUCCESS, "can't obtain class"); 914 915 print("%s", class); 916 } 917 918 // Prepare to print out the service's useful debug information. 919 920 uint64_t entryID; 921 922 status = IORegistryEntryGetRegistryEntryID(service, &entryID); 923 if (status == KERN_SUCCESS) 924 { 925 print(", id 0x%llx", entryID); 926 } 927 928 // Print out the busy state of the service (for IOService objects). 929 930 if (IOObjectConformsTo(service, "IOService")) 931 { 932 status = IOServiceGetBusyStateAndTime(service, &state, &integer, &accumulated_busy_time); 933 assertion(status == KERN_SUCCESS, "can't obtain state"); 934 935 print( ", %sregistered, %smatched, %sactive", 936 state & kIOServiceRegisteredState ? "" : "!", 937 state & kIOServiceMatchedState ? "" : "!", 938 state & kIOServiceInactiveState ? "in" : "" ); 939 940 print(", busy %ld", 941 (unsigned long)integer); 942 943 if (accumulated_busy_time) 944 { 945 print(" (%lld ms)", 946 accumulated_busy_time / kMillisecondScale); 947 } 948 } 949 950 // Print out the retain count of the service. 951 952 integer = IOObjectGetKernelRetainCount(service); 953 954 print(", retain %ld", (unsigned long)integer); 955 956 println(">"); 957 958 // Determine whether the service is a match. 959 960 if (options.list || compare(service, options)) 961 { 962 indent(FALSE, serviceDepth, stackOfBits); 963 println("{"); 964 965 // Obtain the service's properties. 966 967 status = IORegistryEntryCreateCFProperties( service, 968 &properties, 969 kCFAllocatorDefault, 970 kNilOptions ); 971 assertion(status == KERN_SUCCESS, "can't obtain properties"); 972 973 // Print out the service's properties. 974 975 CFDictionaryApplyFunction(properties, showitem, &context); 976 977 indent(FALSE, serviceDepth, stackOfBits); 978 println("}"); 979 indent(FALSE, serviceDepth, stackOfBits); 980 println(""); 981 982 // Release resources. 983 984 CFRelease(properties); 985 } 986} 987 988// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 989 990static void showitem(const void * key, const void * value, void * parameter) 991{ 992 struct context * context = parameter; // (don't release) 993 994 // Print out one of the service's properties. 995 996 indent(FALSE, context->serviceDepth, context->stackOfBits); 997 print(" "); 998 cfshow(key); 999 print(" = "); 1000 1001 if (context->options.format) 1002 { 1003 printProp(key, value, context); 1004 } 1005 else 1006 { 1007 cfshow(value); 1008 println(""); 1009 } 1010} 1011 1012// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1013 1014static void indent(Boolean isNode, UInt32 serviceDepth, UInt64 stackOfBits) 1015{ 1016 // stackOfBits representation, given current zero-based depth is n: 1017 // bit n+1 = does depth n have children? 1=yes, 0=no 1018 // bit [n, .. i .., 0] = does depth i have more siblings? 1=yes, 0=no 1019 1020 UInt32 index; 1021 1022 if (isNode) 1023 { 1024 for (index = 0; index < serviceDepth; index++) 1025 print( (stackOfBits & (1 << index)) ? "| " : " " ); 1026 1027 print("+-o "); 1028 } 1029 else // if (!isNode) 1030 { 1031 for (index = 0; index <= serviceDepth + 1; index++) 1032 print( (stackOfBits & (1 << index)) ? "| " : " " ); 1033 } 1034} 1035 1036// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1037 1038void usage() 1039{ 1040 fprintf( stderr, 1041 "usage: ioreg [-abfilrtx] [-c class] [-d depth] [-k key] [-n name] [-p plane] [-w width]\n" 1042 "where options are:\n" 1043 "\t-a archive output\n" 1044 "\t-b show object name in bold\n" 1045 "\t-c list properties of objects with the given class\n" 1046 "\t-d limit tree to the given depth\n" 1047 "\t-f enable smart formatting\n" 1048 "\t-i show object inheritance\n" 1049 "\t-k list properties of objects with the given key\n" 1050 "\t-l list properties of all objects\n" 1051 "\t-n list properties of objects with the given name\n" 1052 "\t-p traverse registry over the given plane (IOService is default)\n" 1053 "\t-r show subtrees rooted by the given criteria\n" 1054 "\t-t show location of each subtree\n" 1055 "\t-w clip output to the given line width (0 is unlimited)\n" 1056 "\t-x show data and numbers as hexadecimal\n" 1057 ); 1058 exit(1); 1059} 1060 1061// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1062 1063static char * termcapstr_boldon = 0; 1064static char * termcapstr_boldoff = 0; 1065 1066static int termcapstr_outc(int c) 1067{ 1068 return putchar(c); 1069} 1070 1071static void boldinit() 1072{ 1073 char * term; 1074 static char termcapbuf[64]; 1075 char * termcapbufptr = termcapbuf; 1076 1077 term = getenv("TERM"); 1078 1079 if (term) 1080 { 1081 if (tgetent(NULL, term) > 0) 1082 { 1083 termcapstr_boldon = tgetstr("md", &termcapbufptr); 1084 termcapstr_boldoff = tgetstr("me", &termcapbufptr); 1085 1086 assertion(termcapbufptr - termcapbuf <= sizeof(termcapbuf), "can't obtain terminfo"); 1087 } 1088 } 1089 1090 if (termcapstr_boldon == 0) termcapstr_boldon = ""; 1091 if (termcapstr_boldoff == 0) termcapstr_boldoff = ""; 1092} 1093 1094static void boldon() 1095{ 1096 tputs(termcapstr_boldon, 1, termcapstr_outc); 1097} 1098 1099static void boldoff() 1100{ 1101 tputs(termcapstr_boldoff, 1, termcapstr_outc); 1102} 1103 1104// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1105 1106static char * printbuf = 0; 1107static int printbufclip = FALSE; 1108static int printbufleft = 0; 1109static int printbufsize = 0; 1110 1111static void printinit(int width) 1112{ 1113 if (width) 1114 { 1115 printbuf = malloc(width); 1116 printbufleft = width; 1117 printbufsize = width; 1118 1119 assertion(printbuf != NULL, "can't allocate buffer"); 1120 } 1121} 1122 1123static void printva(const char * format, va_list arguments) 1124{ 1125 if (printbufsize) 1126 { 1127 char * c; 1128 int count = vsnprintf(printbuf, printbufleft, format, arguments); 1129 1130 while ( (c = strchr(printbuf, '\n')) ) *c = ' '; // (strip newlines) 1131 1132 printf("%s", printbuf); 1133 1134 if (count >= printbufleft) 1135 { 1136 count = printbufleft - 1; 1137 printbufclip = TRUE; 1138 } 1139 1140 printbufleft -= count; // (printbufleft never hits zero, stops at one) 1141 } 1142 else 1143 { 1144 vprintf(format, arguments); 1145 } 1146} 1147 1148static void print(const char * format, ...) 1149{ 1150 va_list arguments; 1151 va_start(arguments, format); 1152 printva(format, arguments); 1153 va_end(arguments); 1154} 1155 1156static void println(const char * format, ...) 1157{ 1158 va_list arguments; 1159 va_start(arguments, format); 1160 printva(format, arguments); 1161 va_end(arguments); 1162 1163 if (printbufclip) printf("$"); 1164 1165 printf("\n"); 1166 1167 printbufclip = FALSE; 1168 printbufleft = printbufsize; 1169} 1170 1171// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1172 1173static Boolean cfshowhex; 1174 1175static void cfshowinit(Boolean hex) 1176{ 1177 cfshowhex = hex; 1178} 1179 1180static void cfshow(CFTypeRef object) 1181{ 1182 CFTypeID type = CFGetTypeID(object); 1183 1184 if ( type == CFArrayGetTypeID() ) cfarrayshow(object); 1185 else if ( type == CFBooleanGetTypeID() ) cfbooleanshow(object); 1186 else if ( type == CFDataGetTypeID() ) cfdatashow(object); 1187 else if ( type == CFDictionaryGetTypeID() ) cfdictionaryshow(object); 1188 else if ( type == CFNumberGetTypeID() ) cfnumbershow(object); 1189 else if ( type == CFSetGetTypeID() ) cfsetshow(object); 1190 else if ( type == CFStringGetTypeID() ) cfstringshow(object); 1191 else print("<unknown object>"); 1192} 1193 1194static void cfarrayshowapplier(const void * value, void * parameter) 1195{ 1196 Boolean * first = (Boolean *) parameter; 1197 1198 if (*first) 1199 *first = FALSE; 1200 else 1201 print(","); 1202 1203 cfshow(value); 1204} 1205 1206static void cfarrayshow(CFArrayRef object) 1207{ 1208 Boolean first = TRUE; 1209 CFRange range = { 0, CFArrayGetCount(object) }; 1210 1211 print("("); 1212 CFArrayApplyFunction(object, range, cfarrayshowapplier, &first); 1213 print(")"); 1214} 1215 1216static void cfbooleanshow(CFBooleanRef object) 1217{ 1218 print(CFBooleanGetValue(object) ? "Yes" : "No"); 1219} 1220 1221static void cfdatashow(CFDataRef object) 1222{ 1223 UInt32 asciiNormalCount = 0; 1224 UInt32 asciiSymbolCount = 0; 1225 const UInt8 * bytes; 1226 CFIndex index; 1227 CFIndex length; 1228 1229 print("<"); 1230 length = CFDataGetLength(object); 1231 bytes = CFDataGetBytePtr(object); 1232 1233 // 1234 // This algorithm detects ascii strings, or a set of ascii strings, inside a 1235 // stream of bytes. The string, or last string if in a set, needn't be null 1236 // terminated. High-order symbol characters are accepted, unless they occur 1237 // too often (80% of characters must be normal). Zero padding at the end of 1238 // the string(s) is valid. If the data stream is only one byte, it is never 1239 // considered to be a string. 1240 // 1241 1242 for (index = 0; index < length; index++) // (scan for ascii string/strings) 1243 { 1244 if (bytes[index] == 0) // (detected null in place of a new string, 1245 { // ensure remainder of the string is null) 1246 break; // (either end of data or a non-null byte in stream) 1247 } 1248 else // (scan along this potential ascii string) 1249 { 1250 for (; index < length; index++) 1251 { 1252 if (isprint(bytes[index])) 1253 asciiNormalCount++; 1254 else if (bytes[index] >= 128 && bytes[index] <= 254) 1255 asciiSymbolCount++; 1256 else 1257 break; 1258 } 1259 1260 if (index < length && bytes[index] == 0) // (end of string) 1261 continue; 1262 else // (either end of data or an unprintable character) 1263 break; 1264 } 1265 } 1266 1267 if ((asciiNormalCount >> 2) < asciiSymbolCount) // (is 80% normal ascii?) 1268 index = 0; 1269 else if (length == 1) // (is just one byte?) 1270 index = 0; 1271 else if (cfshowhex) 1272 index = 0; 1273 1274 if (index >= length && asciiNormalCount) // (is a string or set of strings?) 1275 { 1276 Boolean quoted = FALSE; 1277 1278 for (index = 0; index < length; index++) 1279 { 1280 if (bytes[index]) 1281 { 1282 if (quoted == FALSE) 1283 { 1284 quoted = TRUE; 1285 if (index) 1286 print(",\""); 1287 else 1288 print("\""); 1289 } 1290 print("%c", bytes[index]); 1291 } 1292 else 1293 { 1294 if (quoted == TRUE) 1295 { 1296 quoted = FALSE; 1297 print("\""); 1298 } 1299 else 1300 break; 1301 } 1302 } 1303 if (quoted == TRUE) 1304 print("\""); 1305 } 1306 else // (is not a string or set of strings) 1307 { 1308 for (index = 0; index < length; index++) print("%02x", bytes[index]); 1309 } 1310 1311 print(">"); 1312} 1313 1314static void cfdictionaryshowapplier( const void * key, 1315 const void * value, 1316 void * parameter ) 1317{ 1318 Boolean * first = (Boolean *) parameter; 1319 1320 if (*first) 1321 *first = FALSE; 1322 else 1323 print(","); 1324 1325 cfshow(key); 1326 print("="); 1327 cfshow(value); 1328} 1329 1330static void cfdictionaryshow(CFDictionaryRef object) 1331{ 1332 Boolean first = TRUE; 1333 1334 print("{"); 1335 CFDictionaryApplyFunction(object, cfdictionaryshowapplier, &first); 1336 print("}"); 1337} 1338 1339static void cfnumbershow(CFNumberRef object) 1340{ 1341 long long number; 1342 1343 if (CFNumberGetValue(object, kCFNumberLongLongType, &number)) 1344 { 1345 if (cfshowhex) 1346 print("0x%qx", (unsigned long long)number); 1347 else 1348 print("%qu", (unsigned long long)number); 1349 } 1350} 1351 1352static void cfsetshowapplier(const void * value, void * parameter) 1353{ 1354 Boolean * first = (Boolean *) parameter; 1355 1356 if (*first) 1357 *first = FALSE; 1358 else 1359 print(","); 1360 1361 cfshow(value); 1362} 1363 1364static void cfsetshow(CFSetRef object) 1365{ 1366 Boolean first = TRUE; 1367 print("["); 1368 CFSetApplyFunction(object, cfsetshowapplier, &first); 1369 print("]"); 1370} 1371 1372static void cfstringshow(CFStringRef object) 1373{ 1374 const char * c = CFStringGetCStringPtr(object, kCFStringEncodingMacRoman); 1375 1376 if (c) 1377 print("\"%s\"", c); 1378 else 1379 { 1380 CFIndex bufferSize = CFStringGetLength(object) + 1; 1381 char * buffer = malloc(bufferSize); 1382 1383 if (buffer) 1384 { 1385 if ( CFStringGetCString( 1386 /* string */ object, 1387 /* buffer */ buffer, 1388 /* bufferSize */ bufferSize, 1389 /* encoding */ kCFStringEncodingMacRoman ) ) 1390 print("\"%s\"", buffer); 1391 1392 free(buffer); 1393 } 1394 } 1395} 1396 1397// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1398 1399static CFStringRef createInheritanceStringForIORegistryClassName(CFStringRef name) 1400{ 1401 CFStringRef curClassCFStr; 1402 CFStringRef oldClassCFStr; 1403 CFMutableStringRef outCFStr; 1404 1405 outCFStr = CFStringCreateMutable (NULL, 512); 1406 CFStringInsert (outCFStr, 0, name); 1407 1408 curClassCFStr = CFStringCreateCopy (NULL, name); 1409 1410 for (;;) 1411 { 1412 oldClassCFStr = curClassCFStr; 1413 curClassCFStr = IOObjectCopySuperclassForClass (curClassCFStr); 1414 CFRelease (oldClassCFStr); 1415 1416 if (FALSE == CFEqual (curClassCFStr, CFSTR ("OSObject"))) 1417 { 1418 CFStringInsert (outCFStr, 0, CFSTR (":")); 1419 CFStringInsert (outCFStr, 0, curClassCFStr); 1420 } 1421 else 1422 { 1423 break; 1424 } 1425 } 1426 1427 if (curClassCFStr) CFRelease(curClassCFStr); 1428 1429 // Return the CFMutableStringRef as a CFStringRef because it is derived and compatible: 1430 return (CFStringRef) outCFStr; 1431} 1432 1433// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1434 1435static void printProp(CFStringRef key, CFTypeRef value, struct context * context) 1436{ 1437 kern_return_t status = KERN_SUCCESS; 1438 Boolean valueShown = FALSE; // Flag is set when property is printed 1439 io_registry_entry_t thisObj; 1440 1441 thisObj = context->service; 1442 1443 // Match "reg" property for PCI devices. 1444 if (CFStringCompare(key, CFSTR("reg"), 0 ) == 0) 1445 { 1446 io_registry_entry_t parentObj; // (needs release) 1447 io_name_t parentName; 1448 1449 // If the parent entry in the IODeviceTree plane is "pci", 1450 // then we've found what we're looking for. 1451 1452 status = IORegistryEntryGetParentEntry( thisObj, 1453 kIODeviceTreePlane, 1454 &parentObj ); 1455 if (status == KERN_SUCCESS) 1456 { 1457 status = IORegistryEntryGetNameInPlane( parentObj, 1458 kIODeviceTreePlane, 1459 parentName ); 1460 assertion(status == KERN_SUCCESS, "could not get name of parent"); 1461 1462 IOObjectRelease(parentObj); 1463 1464 if (strncmp(parentName, "pci", 3) == 0) 1465 { 1466 printPhysAddr(value, context); 1467 valueShown = TRUE; 1468 } 1469 } 1470 } 1471 1472 // Match "assigned-addresses" property. 1473 else if (CFStringCompare(key, CFSTR("assigned-addresses"), 0) == 0) 1474 { 1475 printPhysAddr(value, context); 1476 valueShown = TRUE; 1477 } 1478 1479 // Match "slot-names" property. 1480 else if (CFStringCompare(key, CFSTR("slot-names"), 0) == 0) 1481 { 1482 printSlotNames(value, context); 1483 valueShown = TRUE; 1484 } 1485 1486 // Match "ranges" property. 1487 else if (CFStringCompare(key, CFSTR("ranges"), 0) == 0) 1488 { 1489 printPCIRanges(value, context); 1490 valueShown = TRUE; 1491 } 1492 1493 // Match "interrupt-map" property. 1494 else if (CFStringCompare(key, CFSTR("interrupt-map"), 0) == 0) 1495 { 1496 printInterruptMap(value, context); 1497 valueShown = TRUE; 1498 } 1499 1500 // Match "interrupts" property. 1501 else if ( CFStringCompare( key, CFSTR("interrupts"), 0) == 0 ) 1502 { 1503 printInterrupts( value, context ); 1504 valueShown = TRUE; 1505 } 1506 1507 // Match "interrupt-parent" property. 1508 else if ( CFStringCompare( key, CFSTR("interrupt-parent"), 0) == 0 ) 1509 { 1510 printInterruptParent( value, context ); 1511 valueShown = TRUE; 1512 } 1513 1514 // Print the value if it doesn't have a formatter. 1515 if (valueShown == FALSE) 1516 { 1517 if (CFGetTypeID(value) == CFDataGetTypeID()) 1518 { 1519 printData(value, context); 1520 } 1521 else 1522 { 1523 cfshow(value); 1524 println(""); 1525 } 1526 } 1527} 1528 1529/* The following data structures, masks and shift values are used to decode 1530 * physical address properties as defined by IEEE 1275-1994. The format is 1531 * used in 'reg' and 'assigned-address' properties. 1532 * 1533 * The format of the physHi word is as follows: 1534 * 1535 * npt000ss bbbbbbbb dddddfff rrrrrrrr 1536 * 1537 * n 1 = Relocatable, 0 = Absolute (1 bit) 1538 * p 1 = Prefetchable (1 bit) 1539 * t 1 = Alias (1 bit) 1540 * ss Space code (Config, I/O, Mem, 64-bit Mem) (2 bits) 1541 * bbbbbbbb Bus number (8 bits) 1542 * ddddd Device number (5 bits) 1543 * fff Function number (3 bits) 1544 * rrrrrrrr Register number (8 bits) 1545 */ 1546 1547struct physAddrProperty { 1548 UInt32 physHi; 1549 UInt32 physMid; 1550 UInt32 physLo; 1551 UInt32 sizeHi; 1552 UInt32 sizeLo; 1553}; 1554 1555#define kPhysAbsoluteMask 0x80000000 1556#define kPhysPrefetchMask 0x40000000 1557#define kPhysAliasMask 0x20000000 1558#define kPhysSpaceMask 0x03000000 1559#define kPhysSpaceShift 24 1560#define kPhysBusMask 0x00FF0000 1561#define kPhysBusShift 16 1562#define kPhysDeviceMask 0x0000F800 1563#define kPhysDeviceShift 11 1564#define kPhysFunctionMask 0x00000700 1565#define kPhysFunctionShift 8 1566#define kPhysRegisterMask 0x000000FF 1567#define kPhysRegisterShift 0 1568 1569static SInt32 1570getRecursivePropValue( io_registry_entry_t thisRegEntry, CFStringRef propertyNameToLookFor ) 1571{ 1572 SInt32 returnValue; 1573 CFTypeRef ptr; 1574 1575 ptr = IORegistryEntrySearchCFProperty(thisRegEntry, 1576 kIODeviceTreePlane, 1577 propertyNameToLookFor, 1578 kCFAllocatorDefault, 1579 kIORegistryIterateParents | kIORegistryIterateRecursively); 1580 assertion( ptr != NULL, "unable to get properties" ); 1581 1582 returnValue = *(SInt32 *)CFDataGetBytePtr( (CFDataRef) ptr ); 1583 1584 CFRelease( ptr ); 1585 return( returnValue ); 1586} 1587 1588static void printPhysAddr(CFTypeRef value, struct context * context) 1589{ 1590 CFIndex length; // stores total byte count in this prop. 1591 struct physAddrProperty *physAddr; // points to current physAddr property 1592 UInt64 numPhysAddr, // how many physAddr's to decode? 1593 count; // loop counter variable 1594 UInt32 tmpCell; // temp storage for a single word 1595 1596 UInt32 busNumber, // temp storage for decoded values 1597 deviceNumber, 1598 functionNumber, 1599 registerNumber; 1600 const char *addressType, 1601 *isPrefetch, 1602 *isAlias, 1603 *isAbsolute; 1604 1605 // Ensure that the object passed in is in fact a CFData object. 1606 1607 assertion(CFGetTypeID(value) == CFDataGetTypeID(), "invalid phys addr"); 1608 1609 // Make sure there is actually data in the object. 1610 length = CFDataGetLength((CFDataRef)value); 1611 1612 if (length == 0) 1613 { 1614 println("<>"); 1615 return; 1616 } 1617 1618 numPhysAddr = length / sizeof(struct physAddrProperty); 1619 physAddr = (struct physAddrProperty *)CFDataGetBytePtr((CFDataRef)value); 1620 1621 println(""); 1622 1623 for (count = 0; count < numPhysAddr; count++) 1624 { 1625 tmpCell = physAddr[count].physHi; // copy physHi word to a temp var 1626 1627 // Decode the fields in the physHi word. 1628 1629 busNumber = (tmpCell & kPhysBusMask) >> kPhysBusShift; 1630 deviceNumber = (tmpCell & kPhysDeviceMask) >> kPhysDeviceShift; 1631 functionNumber = (tmpCell & kPhysFunctionMask) >> kPhysFunctionShift; 1632 registerNumber = (tmpCell & kPhysRegisterMask) >> kPhysRegisterShift; 1633 isAbsolute = ((tmpCell & kPhysAbsoluteMask) != 0) ? "abs" : "rel"; 1634 isPrefetch = ((tmpCell & kPhysPrefetchMask) != 0) ? ", prefetch" : ""; 1635 isAlias = ((tmpCell & kPhysAliasMask) != 0) ? ", alias" : ""; 1636 switch ((tmpCell & kPhysSpaceMask) >> kPhysSpaceShift) 1637 { 1638 case 0: addressType = "Config"; break; 1639 case 1: addressType = "I/O"; break; 1640 case 2: addressType = "Mem"; break; 1641 case 3: addressType = "64-bit"; break; 1642 default: addressType = "?"; break; 1643 } 1644 1645 // Format and print the information for this entry. 1646 1647 indent(FALSE, context->serviceDepth, context->stackOfBits); 1648 println(" %02lu: phys.hi: %08lx phys.mid: %08lx phys.lo: %08lx", 1649 (unsigned long)count, 1650 (unsigned long)physAddr[count].physHi, 1651 (unsigned long)physAddr[count].physMid, 1652 (unsigned long)physAddr[count].physLo ); 1653 1654 indent(FALSE, context->serviceDepth, context->stackOfBits); 1655 println(" size.hi: %08lx size.lo: %08lx", 1656 (unsigned long)physAddr[count].sizeHi, 1657 (unsigned long)physAddr[count].sizeLo ); 1658 1659 indent(FALSE, context->serviceDepth, context->stackOfBits); 1660 println(" bus: %lu dev: %lu func: %lu reg: %lu", 1661 (unsigned long)busNumber, 1662 (unsigned long)deviceNumber, 1663 (unsigned long)functionNumber, 1664 (unsigned long)registerNumber ); 1665 1666 indent(FALSE, context->serviceDepth, context->stackOfBits); 1667 println(" type: %s flags: %s%s%s", 1668 addressType, 1669 isAbsolute, 1670 isPrefetch, 1671 isAlias ); 1672 } 1673} 1674 1675static void printSlotNames(CFTypeRef value, struct context * context) 1676{ 1677 CFIndex length; 1678 char * bytePtr; 1679 UInt32 count; 1680 UInt32 * avail_slots; 1681 1682 // Ensure that the object passed in is in fact a CFData object. 1683 1684 assertion(CFGetTypeID(value) == CFDataGetTypeID(), "invalid phys addr"); 1685 1686 // Make sure there is actually data in the object. 1687 1688 length = CFDataGetLength((CFDataRef)value); 1689 1690 if (length == 0) 1691 { 1692 println("<>"); 1693 return; 1694 } 1695 1696 avail_slots = (UInt32 *)CFDataGetBytePtr((CFDataRef)value); 1697 bytePtr = (char *)avail_slots + sizeof(UInt32); 1698 1699 // Ignore entries that have no named slots. 1700 1701 if (*avail_slots == 0) 1702 { 1703 println("<>"); 1704 return; 1705 } 1706 1707 println(""); 1708 1709 // Cycle through all 32 bit positions and print slot names. 1710 1711 for (count = 0; count < 32; count++) 1712 { 1713 if ((*avail_slots & (1 << count)) != 0) 1714 { 1715 indent(FALSE, context->serviceDepth, context->stackOfBits); 1716 println(" %02lu: %s", (unsigned long)count, bytePtr); 1717 bytePtr += strlen(bytePtr) + 1; // advance to next string 1718 } 1719 } 1720} 1721 1722static void printPCIRanges(CFTypeRef value, struct context * context) 1723{ 1724 kern_return_t status = KERN_SUCCESS; 1725 CFIndex length; 1726 UInt32 *quadletPtr; 1727 SInt32 parentACells, childACells, childSCells, elemSize; 1728 io_registry_entry_t parentObj; // must be released 1729 UInt64 i,j,nRanges; 1730 SInt32 counts[3]; 1731 const char *titles[] = {"-child--", "-parent-", "-size---"}; 1732 1733 // Ensure that the object passed in is in fact a CFData object. 1734 assertion(CFGetTypeID(value) == CFDataGetTypeID(), "invalid ranges"); 1735 1736 // Make sure there is actually data in the object. 1737 length = CFDataGetLength((CFDataRef)value); 1738 1739 if (length == 0) 1740 { 1741 println("<>"); 1742 return; 1743 } 1744 1745 quadletPtr = (UInt32 *)CFDataGetBytePtr((CFDataRef)value); 1746 1747 // Get #address-cells of device-tree parent 1748 status = IORegistryEntryGetParentEntry( context->service, kIODeviceTreePlane, &parentObj ); 1749 assertion(status == KERN_SUCCESS, "unable to get device tree parent"); 1750 1751 parentACells = getRecursivePropValue( parentObj, CFSTR( "#address-cells" ) ); 1752 1753 IOObjectRelease( parentObj ); 1754 1755 // Get #address-cells and #size-cells for owner 1756 childACells = getRecursivePropValue( context->service, CFSTR( "#address-cells" ) ); 1757 childSCells = getRecursivePropValue( context->service, CFSTR( "#size-cells" ) ); 1758 1759 // ranges property is a list of [[child addr][parent addr][size]] 1760 elemSize = childACells + parentACells + childSCells; 1761 1762 // print a title line 1763 println(""); 1764 indent(FALSE, context->serviceDepth, context->stackOfBits); 1765 print(" "); 1766 1767 // set up array of cell counts (only used to print title) 1768 counts[0] = childACells; 1769 counts[1] = parentACells; 1770 counts[2] = childSCells; 1771 1772 for (j = 0; j < 3; j++) 1773 { 1774 print("%s", titles[j]); // titles is init'ed at start of func. 1775 if (counts[j] > 1) 1776 { 1777 print("-"); 1778 for( i = 2; i <= counts[j]; i++) 1779 { 1780 if(i == counts[j]) 1781 print("-------- "); 1782 else 1783 print("---------"); 1784 } 1785 } 1786 else 1787 print(" "); 1788 } 1789 println(""); 1790 1791 nRanges = length/(elemSize * sizeof(UInt32)); 1792 1793 for(j = 0; j < nRanges; j++) 1794 { 1795 indent(FALSE, context->serviceDepth, context->stackOfBits); 1796 print(" "); 1797 for(i = 0; i < elemSize; i++) print("%08lx ", (unsigned long)*quadletPtr++); 1798 println(""); 1799 } 1800} 1801 1802// constructs a path string for a node in the device tree 1803static void makepath(io_registry_entry_t target, io_string_t path) 1804{ 1805 kern_return_t status = KERN_SUCCESS; 1806 1807 status = IORegistryEntryGetPath(target, kIODeviceTreePlane, path); 1808 assertion(status == KERN_SUCCESS, "unable to get path"); 1809 1810 strlcpy(path, strchr(path, ':') + 1, sizeof(io_string_t)); 1811} 1812 1813static Boolean lookupPHandle(UInt32 phandle, io_registry_entry_t * device) 1814{ 1815 CFDictionaryRef props; 1816 Boolean ret = FALSE; // pre-set to failure 1817 CFStringRef key = CFSTR(kIOPropertyMatchKey); 1818 CFDictionaryRef value; 1819 CFStringRef phandleKey = CFSTR("AAPL,phandle"); 1820 CFDataRef data; 1821 1822 data = CFDataCreate(NULL, (void *)&phandle, sizeof(UInt32)); 1823 1824 props = CFDictionaryCreate( NULL, 1825 (void *)&phandleKey, 1826 (void *)&data, 1827 1, 1828 &kCFCopyStringDictionaryKeyCallBacks, 1829 &kCFTypeDictionaryValueCallBacks ); 1830 1831 value = CFDictionaryCreate( NULL, 1832 (void *)&key, 1833 (void *)&props, 1834 1, 1835 &kCFCopyStringDictionaryKeyCallBacks, 1836 &kCFTypeDictionaryValueCallBacks ); 1837 1838 /* This call consumes 'value', so do not release it. 1839 */ 1840 *device = IOServiceGetMatchingService(kIOMasterPortDefault, value); 1841 1842 if (*device) 1843 ret = TRUE; 1844 1845 CFRelease(props); 1846 CFRelease(data); 1847 1848 return(ret); 1849} 1850 1851static void printInterruptMap(CFTypeRef value, struct context * context) 1852{ 1853 io_registry_entry_t intParent; 1854 io_string_t path; 1855 SInt32 childCells, parentCells; 1856 UInt32 *position, *end; 1857 CFIndex length, count, index; 1858 1859 // Get #address-cells and #interrupt-cells for owner 1860 childCells = getRecursivePropValue( context->service, CFSTR("#address-cells" ) ) 1861 + getRecursivePropValue( context->service, CFSTR("#interrupt-cells" ) ); 1862 1863 // Walk through each table entry. 1864 position = (UInt32 *)CFDataGetBytePtr((CFDataRef)value); 1865 length = CFDataGetLength((CFDataRef)value)/sizeof(UInt32); 1866 end = position + length; 1867 count = 0; 1868 1869 println(""); 1870 1871 while (position < end) 1872 { 1873 indent(FALSE, context->serviceDepth, context->stackOfBits); 1874 print(" %02ld: ", (unsigned long)count); 1875 1876 // Display the child's unit interrupt specifier. 1877 print(" child: "); 1878 for (index = 0; index < childCells; index++) { 1879 print("%08lx ", (unsigned long)*position++); 1880 } 1881 println(""); 1882 1883 // Lookup the phandle and retreive needed info. 1884 assertion( lookupPHandle(*position, &intParent), "error looking up phandle" ); 1885 1886 parentCells = getRecursivePropValue( intParent, CFSTR( "#address-cells" ) ) 1887 + getRecursivePropValue( intParent, CFSTR( "#interrupt-cells" ) ); 1888 1889 *path = '\0'; 1890 makepath(intParent, path); 1891 1892 IOObjectRelease(intParent); 1893 1894 // Display the phandle, corresponding device path, and 1895 // the parent interrupt specifier. 1896 indent(FALSE, context->serviceDepth, context->stackOfBits); 1897 println(" phandle: %08lx (%s)", (unsigned long)*position++, path); 1898 1899 indent(FALSE, context->serviceDepth, context->stackOfBits); 1900 print(" parent: "); 1901 for (index = 0; index < parentCells; index++) { 1902 print("%08lx ", (unsigned long)*position++); 1903 } 1904 println(""); 1905 1906 count++; 1907 } 1908} 1909 1910static void printInterrupts(CFTypeRef value, struct context * context) 1911{ 1912 UInt32 *position, *end; 1913 CFIndex length, count, index; 1914 1915 // Walk through each table entry. 1916 position = (UInt32 *)CFDataGetBytePtr((CFDataRef)value); 1917 length = CFDataGetLength((CFDataRef)value) / sizeof(UInt32); 1918 end = position + length; 1919 count = 0; 1920 index = 0; 1921 1922 println(""); 1923 1924 while (position < end) 1925 { 1926 indent(FALSE, context->serviceDepth, context->stackOfBits); 1927 print(" %02ld: ", (unsigned long)index); 1928 1929 if ( count < (length-1) ) 1930 { 1931 print("specifier: %08lx (vector: %02lx) sense: %08lx (", 1932 (unsigned long)*position, 1933 (unsigned long)((*position) & 0x000000FF), 1934 (unsigned long)*(position+1) ); 1935 position ++; 1936 count ++; 1937 if ( (*position & 0x00000002 ) ) // HyperTransport 1938 { 1939 print( "HyperTransport vector: %04lx, ", 1940 (unsigned long)((*position >> 16) & 0x0000FFFF)); 1941 } 1942 1943 println( "%s)", (*position & 1)? "level" : "edge" ); 1944 } 1945 else 1946 { 1947 println("parent interrupt-map entry: %08lx", 1948 (unsigned long)*position ); 1949 } 1950 1951 position ++; 1952 count ++; 1953 index ++; 1954 } 1955} 1956 1957static void printInterruptParent( CFTypeRef value, struct context * context ) 1958{ 1959io_registry_entry_t parentRegEntry; 1960io_string_t path; 1961UInt32 * pHandleValue = (UInt32 *) CFDataGetBytePtr( (CFDataRef) value ); 1962 1963 if ( lookupPHandle( *pHandleValue, &parentRegEntry ) ) 1964 { 1965 *path = '\0'; 1966 makepath( parentRegEntry, path ); 1967 1968 print( "<%08lx>", (unsigned long)*pHandleValue ); 1969 if ( *path != '\0' ) 1970 print( " (%s)", path ); 1971 println( "" ); 1972 1973 IOObjectRelease( parentRegEntry ); 1974 } 1975} 1976 1977static char ToAscii(UInt32 nibble) 1978{ 1979 nibble &= 0x0F; 1980 1981 if (nibble <= 9) 1982 return((char)nibble + '0'); 1983 else 1984 return((char)nibble - 10 + 'A'); 1985} 1986 1987static void printData(CFTypeRef value, struct context * context) 1988{ 1989 UInt32 asciiNormalCount = 0; 1990 UInt32 asciiSymbolCount = 0; 1991 const UInt8 * bytes; 1992 CFIndex index; 1993 CFIndex length; 1994 1995 length = CFDataGetLength(value); 1996 bytes = CFDataGetBytePtr(value); 1997 1998 // 1999 // This algorithm detects ascii strings, or a set of ascii strings, inside a 2000 // stream of bytes. The string, or last string if in a set, needn't be null 2001 // terminated. High-order symbol characters are accepted, unless they occur 2002 // too often (80% of characters must be normal). Zero padding at the end of 2003 // the string(s) is valid. If the data stream is only one byte, it is never 2004 // considered to be a string. 2005 // 2006 2007 for (index = 0; index < length; index++) // (scan for ascii string/strings) 2008 { 2009 if (bytes[index] == 0) // (detected null in place of a new string, 2010 { // ensure remainder of the string is null) 2011 for (; index < length && bytes[index] == 0; index++) { } 2012 2013 break; // (either end of data or a non-null byte in stream) 2014 } 2015 else // (scan along this potential ascii string) 2016 { 2017 for (; index < length; index++) 2018 { 2019 if (isprint(bytes[index])) 2020 asciiNormalCount++; 2021 else if (bytes[index] >= 128 && bytes[index] <= 254) 2022 asciiSymbolCount++; 2023 else 2024 break; 2025 } 2026 2027 if (index < length && bytes[index] == 0) // (end of string) 2028 continue; 2029 else // (either end of data or an unprintable character) 2030 break; 2031 } 2032 } 2033 2034 if ((asciiNormalCount >> 2) < asciiSymbolCount) // (is 80% normal ascii?) 2035 index = 0; 2036 else if (length == 1) // (is just one byte?) 2037 index = 0; 2038 else if (cfshowhex) 2039 index = 0; 2040 2041 if (index >= length && asciiNormalCount) // (is a string or set of strings?) 2042 { 2043 Boolean quoted = FALSE; 2044 2045 print("<"); 2046 2047 for (index = 0; index < length; index++) 2048 { 2049 if (bytes[index]) 2050 { 2051 if (quoted == FALSE) 2052 { 2053 quoted = TRUE; 2054 if (index) 2055 print(",\""); 2056 else 2057 print("\""); 2058 } 2059 print("%c", bytes[index]); 2060 } 2061 else 2062 { 2063 if (quoted == TRUE) 2064 { 2065 quoted = FALSE; 2066 print("\""); 2067 } 2068 else 2069 break; 2070 } 2071 } 2072 if (quoted == TRUE) 2073 print("\""); 2074 2075 print(">"); 2076 } 2077 2078 else if (length > 8) // (is not a string or set of strings) 2079 { 2080 SInt8 work[ 256 ]; 2081 SInt8* p; 2082 UInt32 i; 2083 UInt32 offset; 2084 CFIndex totalBytes; 2085 CFIndex nBytesToDraw; 2086 UInt32 bytesPerLine; 2087 UInt8 c; 2088 2089 totalBytes = length; // assume length is greater than zero 2090 2091 // Calculate number of bytes per line to print, use as much screen 2092 // as possible. The numbers used are derived by counting the number 2093 // of characters that are always printed (data address offset, white 2094 // space, etc ~= 20), indentation from the tree structure (2*depth) 2095 // and 4 characters printed per byte (two hex digits, one space, and 2096 // one ascii char). 2097 2098 bytesPerLine = (context->options.width - 20 - (2*context->serviceDepth))/4; 2099 2100 // Make sure we don't overflow the work buffer (256 bytes) 2101 bytesPerLine = bytesPerLine > 32 ? 32 : bytesPerLine; 2102 2103 for ( offset = 0; offset < totalBytes; offset += bytesPerLine ) 2104 { 2105 UInt32 offsetCopy; 2106 UInt16 text; 2107 2108 println(""); 2109 2110 if ( ( offset + bytesPerLine ) <= totalBytes ) 2111 nBytesToDraw = bytesPerLine; 2112 else 2113 nBytesToDraw = totalBytes - offset; 2114 2115 offsetCopy = offset; 2116 2117 // Convert offset to ASCII. 2118 work[ 8 ] = ':'; 2119 p = &work[ 7 ]; 2120 2121 while ( offsetCopy != 0 ) 2122 { 2123 *p-- = ToAscii( offsetCopy & 0x0F ); 2124 offsetCopy >>= 4; 2125 } 2126 2127 // Insert leading zeros. 2128 while ( p >= work ) 2129 *p-- = '0'; 2130 2131 // Add kBytesPerLine bytes of data. 2132 p = &work[ 9 ]; 2133 for ( i = 0; i < nBytesToDraw; i++ ) 2134 { 2135 c = bytes[ offset + i ]; 2136 *p++ = ' '; 2137 *p++ = ToAscii( ( c & 0xF0 ) >> 4 ); 2138 *p++ = ToAscii( c & 0x0F ); 2139 } 2140 2141 // Add padding spaces. 2142 for ( ; i < bytesPerLine; i++ ) 2143 { 2144 text = ( ( ' ' << 8 ) | ' ' ); 2145 *( UInt16 * ) p = text; 2146 p[ 2 ] = ' '; 2147 p += 3; 2148 } 2149 2150 *p++ = ' '; 2151 2152 // Insert ASCII representation of data. 2153 for ( i = 0; i < nBytesToDraw; i++ ) 2154 { 2155 c = bytes[ offset + i ]; 2156 if ( ( c < ' ' ) || ( c > '~' ) ) 2157 c = '.'; 2158 2159 *p++ = c; 2160 } 2161 2162 *p = 0; 2163 2164 // Print this line. 2165 indent(FALSE, context->serviceDepth, context->stackOfBits); 2166 print(" %s", work); 2167 2168 } // for 2169 2170 } // else if (length > 32) 2171 else 2172 { 2173 print("<"); 2174 for (index = 0; index < length; index++) print("%02x", bytes[index]); 2175 print(">"); 2176 } 2177 2178 println(""); 2179} 2180