1 /* 2 * Copyright (c) 1998-2006 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_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. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28 29 #include <IOKit/IODeviceTreeSupport.h> 30 #include <libkern/c++/OSContainers.h> 31 #include <libkern/c++/OSSharedPtr.h> 32 #include <IOKit/IODeviceMemory.h> 33 #include <IOKit/IOService.h> 34 #include <IOKit/IOCatalogue.h> 35 36 #include <IOKit/IOLib.h> 37 #include <IOKit/IOKitKeys.h> 38 39 #include <pexpert/device_tree.h> 40 41 #if __arm64__ 42 typedef UInt64 dtptr_t; 43 #else 44 typedef UInt32 dtptr_t; 45 #endif 46 47 #include <machine/machine_routines.h> 48 49 extern "C" { 50 int IODTGetLoaderInfo( const char *key, void **infoAddr, int *infosize ); 51 void IODTFreeLoaderInfo( const char *key, void *infoAddr, int infoSize ); 52 int IODTGetDefault(const char *key, void *infoAddr, unsigned int infoSize ); 53 } 54 55 #include <IOKit/assert.h> 56 57 #define IODTSUPPORTDEBUG 0 58 59 struct IODTPersistent { 60 IODTCompareAddressCellFunc compareFunc; 61 }; 62 63 struct IODTResolvers { 64 unsigned int alloc; 65 unsigned int count; 66 IOLock * lock; 67 IODTPersistent * resolvers; 68 }; 69 70 const IORegistryPlane * gIODTPlane; 71 72 static OSArray * gIODTPHandles; 73 static OSArray * gIODTPHandleMap; 74 75 static IODTResolvers * gIODTResolvers; 76 77 const OSSymbol * gIODTNameKey; 78 const OSSymbol * gIODTUnitKey; 79 const OSSymbol * gIODTCompatibleKey; 80 const OSSymbol * gIODTTypeKey; 81 const OSSymbol * gIODTModelKey; 82 const OSSymbol * gIODTBridgeModelKey; 83 const OSSymbol * gIODTTargetTypeKey; 84 85 const OSSymbol * gIODTSizeCellKey; 86 const OSSymbol * gIODTAddressCellKey; 87 const OSSymbol * gIODTRangeKey; 88 89 const OSSymbol * gIODTPersistKey; 90 91 const OSSymbol * gIODTDefaultInterruptController; 92 const OSSymbol * gIODTAAPLInterruptsKey; 93 const OSSymbol * gIODTPHandleKey; 94 const OSSymbol * gIODTInterruptCellKey; 95 const OSSymbol * gIODTInterruptParentKey; 96 const OSSymbol * gIODTNWInterruptMappingKey; 97 98 const OSData * gIODTAssociatedServiceKey; 99 100 OSDictionary * gIODTSharedInterrupts; 101 102 static IORegistryEntry * MakeReferenceTable( DTEntry dtEntry, bool copy ); 103 static void AddPHandle( IORegistryEntry * regEntry ); 104 static void FreePhysicalMemory( vm_offset_t * range ); 105 static bool IODTMapInterruptsSharing( IORegistryEntry * regEntry, OSDictionary * allInts ); 106 107 // FIXME: Implementation of this function is hidden from the static analyzer. 108 // The analyzer doesn't know that the registry holds retains, and gets confused 109 // about releases after calls to 'attachToParent'. 110 // Feel free to remove the #ifndef and address the warning! 111 #ifndef __clang_analyzer__ 112 IORegistryEntry * 113 IODeviceTreeAlloc( void * dtTop ) 114 { 115 IORegistryEntry * parent; 116 IORegistryEntry * child; 117 IORegistryIterator * regIter; 118 OpaqueDTEntryIterator iter; 119 DTEntry dtChild; 120 DTEntry mapEntry; 121 OSArray * stack; 122 OSData * prop; 123 OSDictionary * allInts; 124 vm_offset_t * dtMap; 125 unsigned int propSize; 126 bool intMap; 127 bool foundDTNode; 128 bool freeDT; 129 char exBootArg[64]; 130 const char * found; 131 132 gIODTPlane = IORegistryEntry::makePlane( kIODeviceTreePlane ); 133 134 gIODTNameKey = OSSymbol::withCStringNoCopy( "name" ); 135 gIODTUnitKey = OSSymbol::withCStringNoCopy( "AAPL,unit-string" ); 136 gIODTCompatibleKey = OSSymbol::withCStringNoCopy( "compatible" ); 137 gIODTTypeKey = OSSymbol::withCStringNoCopy( "device_type" ); 138 gIODTModelKey = OSSymbol::withCStringNoCopy( "model" ); 139 gIODTBridgeModelKey = OSSymbol::withCStringNoCopy( "bridge-model" ); 140 gIODTTargetTypeKey = OSSymbol::withCStringNoCopy( "target-type" ); 141 gIODTSizeCellKey = OSSymbol::withCStringNoCopy( "#size-cells" ); 142 gIODTAddressCellKey = OSSymbol::withCStringNoCopy( "#address-cells" ); 143 gIODTRangeKey = OSSymbol::withCStringNoCopy( "ranges" ); 144 gIODTPersistKey = OSSymbol::withCStringNoCopy( "IODTPersist" ); 145 gIODTAssociatedServiceKey = OSData::withBytesNoCopy((void *) kIODTAssociatedServiceKey, sizeof(kIODTAssociatedServiceKey)); 146 147 148 assert( gIODTPlane && gIODTCompatibleKey 149 && gIODTTypeKey && gIODTModelKey 150 && gIODTSizeCellKey && gIODTAddressCellKey && gIODTRangeKey 151 && gIODTPersistKey ); 152 153 gIODTDefaultInterruptController 154 = OSSymbol::withCStringNoCopy("IOPrimaryInterruptController"); 155 gIODTNWInterruptMappingKey 156 = OSSymbol::withCStringNoCopy("IONWInterrupts"); 157 158 gIODTAAPLInterruptsKey 159 = OSSymbol::withCStringNoCopy("AAPL,interrupts"); 160 gIODTPHandleKey 161 = OSSymbol::withCStringNoCopy("AAPL,phandle"); 162 163 gIODTInterruptParentKey 164 = OSSymbol::withCStringNoCopy("interrupt-parent"); 165 166 gIODTPHandles = OSArray::withCapacity( 1 ); 167 gIODTPHandleMap = OSArray::withCapacity( 1 ); 168 169 gIODTResolvers = zalloc_permanent_type(IODTResolvers); 170 gIODTResolvers->count = 0; 171 gIODTResolvers->alloc = 2; 172 gIODTResolvers->resolvers = IONewZero(IODTPersistent, gIODTResolvers->alloc); 173 gIODTResolvers->lock = IOLockAlloc(); 174 175 if (!PE_parse_boot_argn("exp", exBootArg, sizeof(exBootArg))) { 176 exBootArg[0] = '\0'; 177 } 178 179 gIODTInterruptCellKey 180 = OSSymbol::withCStringNoCopy("#interrupt-cells"); 181 182 assert( gIODTDefaultInterruptController && gIODTNWInterruptMappingKey 183 && gIODTAAPLInterruptsKey 184 && gIODTPHandleKey && gIODTInterruptParentKey 185 && gIODTPHandles && gIODTPHandleMap && gIODTInterruptCellKey 186 && gIODTResolvers && gIODTResolvers->lock && gIODTResolvers->resolvers 187 ); 188 189 foundDTNode = (kSuccess == SecureDTLookupEntry( NULL, "/chosen/memory-map", &mapEntry )) 190 && (kSuccess == SecureDTGetProperty( mapEntry, 191 "DeviceTree", (void const **) &dtMap, &propSize )) 192 && ((2 * sizeof(uint32_t)) == propSize); 193 194 freeDT = foundDTNode && !SecureDTIsLockedDown(); 195 196 parent = MakeReferenceTable((DTEntry)dtTop, freeDT ); 197 198 stack = OSArray::withObjects((const OSObject **) &parent, 1, 10 ); 199 SecureDTInitEntryIterator((DTEntry)dtTop, &iter ); 200 201 do { 202 parent = (IORegistryEntry *)stack->getObject( stack->getCount() - 1); 203 //parent->release(); 204 stack->removeObject( stack->getCount() - 1); 205 206 while (kSuccess == SecureDTIterateEntries( &iter, &dtChild)) { 207 child = MakeReferenceTable( dtChild, freeDT ); 208 child->attachToParent( parent, gIODTPlane); 209 210 AddPHandle( child ); 211 // E.g. exp=sgx:3 or exp=sgx:3,5 212 if ((found = strnstr(exBootArg, child->getName(), sizeof(exBootArg)))) { 213 child->setProperty(gIOExclaveAssignedKey, kOSBooleanTrue); 214 uint32_t ep = 0; 215 uint32_t edk_ep = 0; 216 found += strlen(child->getName()); 217 if (':' == *found) { 218 char *end; 219 ep = (uint32_t) strtol(found + 1, &end, 0); 220 // Check for optional edk endpoint 221 if (',' == *end) { 222 edk_ep = (uint32_t) strtol(end + 1, &end, 0); 223 child->setProperty("exclave-edk-endpoint", &edk_ep, sizeof(edk_ep)); 224 } 225 } 226 child->setProperty("exclave-endpoint", &ep, sizeof(ep)); 227 } 228 229 if (kSuccess == SecureDTEnterEntry( &iter, dtChild)) { 230 stack->setObject( parent); 231 parent = child; 232 } 233 // only registry holds retain 234 child->release(); 235 } 236 } while (stack->getCount() 237 && (kSuccess == SecureDTExitEntry( &iter, &dtChild))); 238 239 stack->release(); 240 assert(kSuccess != SecureDTExitEntry(&iter, &dtChild)); 241 242 // parent is now root of the created tree 243 244 // make root name first compatible entry (purely cosmetic) 245 if ((prop = (OSData *) parent->getProperty( gIODTCompatibleKey))) { 246 parent->setName( parent->getName(), gIODTPlane ); 247 parent->setName((const char *) prop->getBytesNoCopy()); 248 } 249 250 // attach tree to meta root 251 parent->attachToParent( IORegistryEntry::getRegistryRoot(), gIODTPlane); 252 parent->release(); 253 254 if (freeDT) { 255 // free original device tree 256 SecureDTInit(NULL, 0); 257 IODTFreeLoaderInfo( "DeviceTree", 258 (void *)dtMap[0], (int) round_page(dtMap[1])); 259 } 260 261 // adjust tree 262 263 gIODTSharedInterrupts = OSDictionary::withCapacity(4); 264 allInts = OSDictionary::withCapacity(4); 265 intMap = false; 266 regIter = IORegistryIterator::iterateOver( gIODTPlane, 267 kIORegistryIterateRecursively ); 268 assert( regIter && allInts && gIODTSharedInterrupts ); 269 if (regIter && allInts && gIODTSharedInterrupts) { 270 while ((child = regIter->getNextObject())) { 271 IODTMapInterruptsSharing( child, allInts ); 272 if (!intMap && child->getProperty( gIODTInterruptParentKey)) { 273 intMap = true; 274 } 275 if (!strcmp("sep", child->getName()) 276 || !strcmp("aop", child->getName()) 277 || !strcmp("disp0", child->getName())) { 278 uint32_t aotFlags = 1; 279 child->setProperty("aot-power", &aotFlags, sizeof(aotFlags)); 280 } 281 } 282 regIter->release(); 283 } 284 285 #if IODTSUPPORTDEBUG 286 parent->setProperty("allInts", allInts); 287 parent->setProperty("sharedInts", gIODTSharedInterrupts); 288 289 regIter = IORegistryIterator::iterateOver( gIODTPlane, 290 kIORegistryIterateRecursively ); 291 if (regIter) { 292 while ((child = regIter->getNextObject())) { 293 OSArray * 294 array = OSDynamicCast(OSArray, child->getProperty( gIOInterruptSpecifiersKey )); 295 for (UInt32 i = 0; array && (i < array->getCount()); i++) { 296 IOOptionBits options; 297 IOReturn ret = IODTGetInterruptOptions( child, i, &options ); 298 if ((ret != kIOReturnSuccess) || options) { 299 IOLog("%s[%ld] %ld (%x)\n", child->getName(), i, options, ret); 300 } 301 } 302 } 303 regIter->release(); 304 } 305 #endif 306 307 allInts->release(); 308 309 if (intMap) { 310 // set a key in the root to indicate we found NW interrupt mapping 311 parent->setProperty( gIODTNWInterruptMappingKey, 312 (OSObject *) gIODTNWInterruptMappingKey ); 313 } 314 315 return parent; 316 } 317 #endif 318 319 int 320 IODTGetLoaderInfo( const char *key, void **infoAddr, int *infoSize ) 321 { 322 IORegistryEntry *chosen; 323 OSData *propObj; 324 dtptr_t *propPtr; 325 unsigned int propSize; 326 int ret = -1; 327 328 chosen = IORegistryEntry::fromPath( "/chosen/memory-map", gIODTPlane ); 329 if (chosen == NULL) { 330 return -1; 331 } 332 333 propObj = OSDynamicCast( OSData, chosen->getProperty(key)); 334 if (propObj == NULL) { 335 goto cleanup; 336 } 337 338 propSize = propObj->getLength(); 339 if (propSize != (2 * sizeof(dtptr_t))) { 340 goto cleanup; 341 } 342 343 propPtr = (dtptr_t *)propObj->getBytesNoCopy(); 344 if (propPtr == NULL) { 345 goto cleanup; 346 } 347 348 *infoAddr = (void *)(uintptr_t) (propPtr[0]); 349 *infoSize = (int) (propPtr[1]); 350 351 ret = 0; 352 353 cleanup: 354 chosen->release(); 355 356 return ret; 357 } 358 359 void 360 IODTFreeLoaderInfo( const char *key, void *infoAddr, int infoSize ) 361 { 362 vm_offset_t range[2]; 363 IORegistryEntry *chosen; 364 365 range[0] = (vm_offset_t)infoAddr; 366 range[1] = (vm_offset_t)infoSize; 367 FreePhysicalMemory( range ); 368 369 if (key != NULL) { 370 chosen = IORegistryEntry::fromPath( "/chosen/memory-map", gIODTPlane ); 371 if (chosen != NULL) { 372 chosen->removeProperty(key); 373 chosen->release(); 374 } 375 } 376 } 377 378 int 379 IODTGetDefault(const char *key, void *infoAddr, unsigned int infoSize ) 380 { 381 IORegistryEntry *defaults; 382 OSData *defaultObj; 383 unsigned int defaultSize; 384 385 defaults = IORegistryEntry::fromPath( "/defaults", gIODTPlane ); 386 if (defaults == NULL) { 387 return -1; 388 } 389 390 defaultObj = OSDynamicCast( OSData, defaults->getProperty(key)); 391 392 if (defaultObj == NULL) { 393 defaults->release(); 394 return -1; 395 } 396 397 defaultSize = defaultObj->getLength(); 398 if (defaultSize > infoSize) { 399 defaults->release(); 400 return -1; 401 } 402 403 memcpy( infoAddr, defaultObj->getBytesNoCopy(), defaultSize ); 404 405 defaults->release(); 406 return 0; 407 } 408 409 static void 410 FreePhysicalMemory( vm_offset_t * range ) 411 { 412 vm_offset_t virt; 413 414 virt = ml_static_ptovirt( range[0] ); 415 if (virt) { 416 ml_static_mfree( virt, range[1] ); 417 } 418 } 419 420 static IORegistryEntry * 421 MakeReferenceTable( DTEntry dtEntry, bool copy ) 422 { 423 IORegistryEntry *regEntry; 424 OSDictionary *propTable; 425 const OSSymbol *nameKey; 426 OSData *data; 427 const OSSymbol *sym; 428 OpaqueDTPropertyIterator dtIter; 429 void const *prop; 430 unsigned int propSize; 431 char const *name; 432 char location[32]; 433 bool noLocation = true; 434 bool kernelOnly; 435 436 regEntry = new IOService; 437 438 if (regEntry && (false == regEntry->init())) { 439 regEntry->release(); 440 regEntry = NULL; 441 } 442 443 if (regEntry && 444 (kSuccess == SecureDTInitPropertyIterator( dtEntry, &dtIter))) { 445 kernelOnly = (kSuccess == SecureDTGetProperty(dtEntry, "kernel-only", &prop, &propSize)); 446 propTable = regEntry->getPropertyTable(); 447 448 while (kSuccess == SecureDTIterateProperties( &dtIter, &name)) { 449 if (kSuccess != SecureDTGetProperty( dtEntry, name, &prop, &propSize )) { 450 continue; 451 } 452 453 if (copy) { 454 nameKey = OSSymbol::withCString(name); 455 data = OSData::withBytes(prop, propSize); 456 } else { 457 nameKey = OSSymbol::withCStringNoCopy(name); 458 /* There is no OSDataConst or other way to indicate 459 * that the OSData is actually immutable. But CTRR 460 * will catch any write attempts. */ 461 data = OSData::withBytesNoCopy((void**)(uintptr_t)prop, propSize); 462 } 463 assert( nameKey && data ); 464 465 #if DEVELOPMENT || DEBUG 466 #pragma unused(kernelOnly) 467 #else 468 if (kernelOnly) { 469 data->setSerializable(false); 470 } 471 #endif 472 473 propTable->setObject( nameKey, data); 474 data->release(); 475 nameKey->release(); 476 477 if (nameKey == gIODTNameKey) { 478 if (copy) { 479 sym = OSSymbol::withCString((const char *) prop); 480 } else { 481 sym = OSSymbol::withCStringNoCopy((const char *) prop); 482 } 483 regEntry->setName( sym ); 484 sym->release(); 485 } else if (nameKey == gIODTUnitKey) { 486 // all OF strings are null terminated... except this one 487 if (propSize >= (int) sizeof(location)) { 488 propSize = sizeof(location) - 1; 489 } 490 strncpy( location, (const char *) prop, propSize ); 491 location[propSize] = 0; 492 regEntry->setLocation( location ); 493 propTable->removeObject( gIODTUnitKey ); 494 noLocation = false; 495 } else if (noLocation && (!strncmp(name, "reg", sizeof("reg")))) { 496 // default location - override later 497 snprintf(location, sizeof(location), "%X", *((uint32_t *) prop)); 498 regEntry->setLocation( location ); 499 } 500 } 501 } 502 503 return regEntry; 504 } 505 506 static void 507 AddPHandle( IORegistryEntry * regEntry ) 508 { 509 OSData * data; 510 511 if (regEntry->getProperty( gIODTInterruptCellKey) 512 && (data = OSDynamicCast( OSData, regEntry->getProperty( gIODTPHandleKey )))) { 513 // a possible interrupt-parent 514 gIODTPHandles->setObject( data ); 515 gIODTPHandleMap->setObject( regEntry ); 516 } 517 } 518 519 static LIBKERN_RETURNS_NOT_RETAINED IORegistryEntry * 520 FindPHandle( UInt32 phandle ) 521 { 522 OSData *data; 523 IORegistryEntry *regEntry = NULL; 524 int i; 525 526 for (i = 0; (data = (OSData *)gIODTPHandles->getObject( i )); i++) { 527 if (phandle == *((UInt32 *)data->getBytesNoCopy())) { 528 regEntry = (IORegistryEntry *) 529 gIODTPHandleMap->getObject( i ); 530 break; 531 } 532 } 533 534 return regEntry; 535 } 536 537 static bool 538 GetUInt32( IORegistryEntry * regEntry, const OSSymbol * name, 539 UInt32 * value ) 540 { 541 OSObject * obj; 542 OSData * data; 543 bool result; 544 545 if (!(obj = regEntry->copyProperty(name))) { 546 return false; 547 } 548 549 result = ((data = OSDynamicCast(OSData, obj)) && (sizeof(UInt32) == data->getLength())); 550 if (result) { 551 *value = *((UInt32 *) data->getBytesNoCopy()); 552 } 553 554 obj->release(); 555 return result; 556 } 557 558 static IORegistryEntry * 559 IODTFindInterruptParent( IORegistryEntry * regEntry, IOItemCount index ) 560 { 561 IORegistryEntry * parent; 562 UInt32 phandle; 563 OSData * data; 564 unsigned int len; 565 566 if ((data = OSDynamicCast( OSData, regEntry->getProperty( gIODTInterruptParentKey ))) 567 && (sizeof(UInt32) <= (len = data->getLength()))) { 568 if (((index + 1) * sizeof(UInt32)) > len) { 569 index = 0; 570 } 571 phandle = ((UInt32 *) data->getBytesNoCopy())[index]; 572 parent = FindPHandle( phandle ); 573 } else if (NULL == regEntry->getProperty( "interrupt-controller")) { 574 parent = regEntry->getParentEntry( gIODTPlane); 575 } else { 576 parent = NULL; 577 } 578 579 return parent; 580 } 581 582 const OSSymbol * 583 IODTInterruptControllerName( IORegistryEntry * regEntry ) 584 { 585 const OSSymbol *sym; 586 UInt32 phandle; 587 bool ok; 588 char buf[48]; 589 590 ok = GetUInt32( regEntry, gIODTPHandleKey, &phandle); 591 assert( ok ); 592 593 if (ok) { 594 snprintf(buf, sizeof(buf), "IOInterruptController%08X", (uint32_t)phandle); 595 sym = OSSymbol::withCString( buf ); 596 } else { 597 sym = NULL; 598 } 599 600 return sym; 601 } 602 603 #define unexpected(a) { kprintf("unexpected %s:%d\n", __FILE__, __LINE__); a; } 604 605 static void 606 IODTGetICellCounts( IORegistryEntry * regEntry, 607 UInt32 * iCellCount, UInt32 * aCellCount) 608 { 609 if (!GetUInt32( regEntry, gIODTInterruptCellKey, iCellCount)) { 610 unexpected( *iCellCount = 1 ); 611 } 612 if (!GetUInt32( regEntry, gIODTAddressCellKey, aCellCount)) { 613 *aCellCount = 0; 614 } 615 } 616 617 static UInt32 618 IODTMapOneInterrupt( IORegistryEntry * regEntry, UInt32 * intSpec, UInt32 index, 619 LIBKERN_RETURNS_RETAINED OSData ** spec, 620 LIBKERN_RETURNS_RETAINED const OSSymbol ** controller ) 621 { 622 IORegistryEntry *parent = NULL; 623 OSData *data; 624 UInt32 *addrCmp; 625 UInt32 *maskCmp; 626 UInt32 *map; 627 UInt32 *endMap; 628 UInt32 acells, icells, pacells, picells, cell; 629 UInt32 i, original_icells; 630 bool cmp, ok = false; 631 632 parent = IODTFindInterruptParent( regEntry, index ); 633 IODTGetICellCounts( parent, &icells, &acells ); 634 addrCmp = NULL; 635 if (acells) { 636 data = OSDynamicCast( OSData, regEntry->getProperty( "reg" )); 637 if (data && (data->getLength() >= (acells * sizeof(UInt32)))) { 638 addrCmp = (UInt32 *) data->getBytesNoCopy(); 639 } 640 } 641 original_icells = icells; 642 regEntry = parent; 643 644 do { 645 #if IODTSUPPORTDEBUG 646 kprintf("IODTMapOneInterrupt: current regEntry name %s\n", regEntry->getName()); 647 kprintf("acells - icells: "); 648 for (i = 0; i < acells; i++) { 649 kprintf("0x%08X ", addrCmp[i]); 650 } 651 kprintf("- "); 652 for (i = 0; i < icells; i++) { 653 kprintf("0x%08X ", intSpec[i]); 654 } 655 kprintf("\n"); 656 #endif 657 658 if (parent && (data = OSDynamicCast( OSData, 659 regEntry->getProperty( "interrupt-controller")))) { 660 // found a controller - don't want to follow cascaded controllers 661 parent = NULL; 662 *spec = OSData::withBytesNoCopy((void *) intSpec, 663 icells * sizeof(UInt32)); 664 *controller = IODTInterruptControllerName( regEntry ); 665 ok = (*spec && *controller); 666 } else if (parent && (data = OSDynamicCast( OSData, 667 regEntry->getProperty( "interrupt-map")))) { 668 // interrupt-map 669 map = (UInt32 *) data->getBytesNoCopy(); 670 endMap = map + (data->getLength() / sizeof(UInt32)); 671 data = OSDynamicCast( OSData, regEntry->getProperty( "interrupt-map-mask" )); 672 if (data && (data->getLength() >= ((acells + icells) * sizeof(UInt32)))) { 673 maskCmp = (UInt32 *) data->getBytesNoCopy(); 674 } else { 675 maskCmp = NULL; 676 } 677 678 #if IODTSUPPORTDEBUG 679 if (maskCmp) { 680 kprintf(" maskCmp: "); 681 for (i = 0; i < acells + icells; i++) { 682 if (i == acells) { 683 kprintf("- "); 684 } 685 kprintf("0x%08X ", maskCmp[i]); 686 } 687 kprintf("\n"); 688 kprintf(" masked: "); 689 for (i = 0; i < acells + icells; i++) { 690 if (i == acells) { 691 kprintf("- "); 692 } 693 kprintf("0x%08X ", ((i < acells) ? addrCmp[i] : intSpec[i - acells]) & maskCmp[i]); 694 } 695 kprintf("\n"); 696 } else { 697 kprintf("no maskCmp\n"); 698 } 699 #endif 700 do { 701 #if IODTSUPPORTDEBUG 702 kprintf(" map: "); 703 for (i = 0; i < acells + icells; i++) { 704 if (i == acells) { 705 kprintf("- "); 706 } 707 kprintf("0x%08X ", map[i]); 708 } 709 kprintf("\n"); 710 #endif 711 for (i = 0, cmp = true; cmp && (i < (acells + icells)); i++) { 712 cell = (i < acells) ? addrCmp[i] : intSpec[i - acells]; 713 if (maskCmp) { 714 cell &= maskCmp[i]; 715 } 716 cmp = (cell == map[i]); 717 } 718 719 map += acells + icells; 720 if (NULL == (parent = FindPHandle( *(map++)))) { 721 unexpected(break); 722 } 723 724 IODTGetICellCounts( parent, &picells, &pacells ); 725 if (cmp) { 726 addrCmp = map; 727 intSpec = map + pacells; 728 regEntry = parent; 729 } else { 730 map += pacells + picells; 731 } 732 } while (!cmp && (map < endMap)); 733 if (!cmp) { 734 parent = NULL; 735 } 736 } 737 738 if (parent) { 739 IODTGetICellCounts( parent, &icells, &acells ); 740 regEntry = parent; 741 } 742 } while (parent); 743 744 return ok ? original_icells : 0; 745 } 746 747 IOReturn 748 IODTGetInterruptOptions( IORegistryEntry * regEntry, int source, IOOptionBits * options ) 749 { 750 OSArray * controllers; 751 OSArray * specifiers; 752 OSArray * shared; 753 OSObject * spec; 754 OSObject * oneSpec; 755 756 *options = 0; 757 758 controllers = OSDynamicCast(OSArray, regEntry->getProperty(gIOInterruptControllersKey)); 759 specifiers = OSDynamicCast(OSArray, regEntry->getProperty(gIOInterruptSpecifiersKey)); 760 761 if (!controllers || !specifiers) { 762 return kIOReturnNoInterrupt; 763 } 764 765 shared = (OSArray *) gIODTSharedInterrupts->getObject( 766 (const OSSymbol *) controllers->getObject(source)); 767 if (!shared) { 768 return kIOReturnSuccess; 769 } 770 771 spec = specifiers->getObject(source); 772 if (!spec) { 773 return kIOReturnNoInterrupt; 774 } 775 776 for (unsigned int i = 0; 777 (oneSpec = shared->getObject(i)) 778 && (!oneSpec->isEqualTo(spec)); 779 i++) { 780 } 781 782 if (oneSpec) { 783 *options = kIODTInterruptShared; 784 } 785 786 return kIOReturnSuccess; 787 } 788 789 static bool 790 IODTMapInterruptsSharing( IORegistryEntry * regEntry, OSDictionary * allInts ) 791 { 792 IORegistryEntry * parent; 793 OSData * local; 794 OSData * local2; 795 UInt32 * localBits; 796 UInt32 * localEnd; 797 IOItemCount index; 798 OSData * map = NULL; 799 OSObject * oneMap; 800 OSArray * mapped; 801 OSArray * controllerInts; 802 const OSSymbol * controller = NULL; 803 OSArray * controllers; 804 UInt32 skip = 1; 805 bool ok, nw; 806 807 nw = (NULL == (local = OSDynamicCast( OSData, 808 regEntry->getProperty( gIODTAAPLInterruptsKey)))); 809 if (nw && (NULL == (local = OSDynamicCast( OSData, 810 regEntry->getProperty( "interrupts"))))) { 811 return true; // nothing to see here 812 } 813 if (nw && (parent = regEntry->getParentEntry( gIODTPlane))) { 814 // check for bridges on old world 815 if ((local2 = OSDynamicCast( OSData, 816 parent->getProperty( gIODTAAPLInterruptsKey)))) { 817 local = local2; 818 nw = false; 819 } 820 } 821 822 localBits = (UInt32 *) local->getBytesNoCopy(); 823 localEnd = localBits + (local->getLength() / sizeof(UInt32)); 824 index = 0; 825 mapped = OSArray::withCapacity( 1 ); 826 controllers = OSArray::withCapacity( 1 ); 827 828 ok = (mapped && controllers); 829 830 if (ok) { 831 do { 832 if (nw) { 833 skip = IODTMapOneInterrupt( regEntry, localBits, index, &map, &controller ); 834 if (0 == skip) { 835 IOLog("%s: error mapping interrupt[%d]\n", 836 regEntry->getName(), mapped->getCount()); 837 OSSafeReleaseNULL(map); 838 OSSafeReleaseNULL(controller); 839 break; 840 } 841 } else { 842 map = OSData::withData( local, mapped->getCount() * sizeof(UInt32), 843 sizeof(UInt32)); 844 controller = gIODTDefaultInterruptController; 845 controller->retain(); 846 } 847 848 index++; 849 localBits += skip; 850 mapped->setObject( map ); 851 controllers->setObject( controller ); 852 853 if (allInts) { 854 controllerInts = (OSArray *) allInts->getObject( controller ); 855 if (controllerInts) { 856 for (unsigned int i = 0; (oneMap = controllerInts->getObject(i)); i++) { 857 if (map->isEqualTo(oneMap)) { 858 controllerInts = (OSArray *) gIODTSharedInterrupts->getObject( controller ); 859 if (controllerInts) { 860 controllerInts->setObject(map); 861 } else { 862 controllerInts = OSArray::withObjects((const OSObject **) &map, 1, 4 ); 863 if (controllerInts) { 864 gIODTSharedInterrupts->setObject( controller, controllerInts ); 865 controllerInts->release(); 866 } 867 } 868 break; 869 } 870 } 871 if (!oneMap) { 872 controllerInts->setObject(map); 873 } 874 } else { 875 controllerInts = OSArray::withObjects((const OSObject **) &map, 1, 16 ); 876 if (controllerInts) { 877 allInts->setObject( controller, controllerInts ); 878 controllerInts->release(); 879 } 880 } 881 } 882 883 OSSafeReleaseNULL(map); 884 OSSafeReleaseNULL(controller); 885 } while (localBits < localEnd); 886 } 887 888 ok &= (localBits == localEnd); 889 890 if (ok) { 891 // store results 892 ok = regEntry->setProperty( gIOInterruptControllersKey, controllers); 893 ok &= regEntry->setProperty( gIOInterruptSpecifiersKey, mapped); 894 } 895 896 if (controllers) { 897 controllers->release(); 898 } 899 if (mapped) { 900 mapped->release(); 901 } 902 903 return ok; 904 } 905 906 bool 907 IODTMapInterrupts( IORegistryEntry * regEntry ) 908 { 909 return IODTMapInterruptsSharing( regEntry, NULL ); 910 } 911 912 /* 913 */ 914 915 static bool 916 CompareKey( OSString * key, 917 const IORegistryEntry * table, const OSSymbol * propName, 918 LIBKERN_RETURNS_RETAINED OSString ** matchingName ) 919 { 920 OSObject *prop; 921 OSData *data; 922 OSString *string; 923 const char *ckey; 924 UInt32 keyLen; 925 UInt32 nlen; 926 const char *names; 927 const char *lastName; 928 bool wild; 929 bool matched; 930 const char *result = NULL; 931 932 if (NULL == (prop = table->copyProperty( propName ))) { 933 return 0; 934 } 935 936 if ((data = OSDynamicCast( OSData, prop ))) { 937 names = (const char *) data->getBytesNoCopy(); 938 lastName = names + data->getLength(); 939 } else if ((string = OSDynamicCast( OSString, prop ))) { 940 names = string->getCStringNoCopy(); 941 lastName = names + string->getLength() + 1; 942 } else { 943 names = NULL; 944 } 945 946 if (names) { 947 ckey = key->getCStringNoCopy(); 948 keyLen = key->getLength(); 949 wild = ('*' == key->getChar( keyLen - 1 )); 950 951 do { 952 // for each name in the property 953 nlen = (unsigned int) strnlen(names, lastName - names); 954 if (wild) { 955 matched = ((nlen >= (keyLen - 1)) && (0 == strncmp(ckey, names, keyLen - 1))); 956 } else { 957 matched = (keyLen == nlen) && (0 == strncmp(ckey, names, keyLen)); 958 } 959 960 if (matched) { 961 result = names; 962 } 963 964 names = names + nlen + 1; 965 } while ((names < lastName) && (false == matched)); 966 } 967 968 if (result && matchingName) { 969 *matchingName = OSString::withCString( result ); 970 } 971 972 if (prop) { 973 prop->release(); 974 } 975 976 return result != NULL; 977 } 978 979 980 bool 981 IODTCompareNubName( const IORegistryEntry * regEntry, 982 OSString * name, OSString ** matchingName ) 983 { 984 bool matched; 985 986 matched = CompareKey( name, regEntry, gIODTNameKey, matchingName) 987 || CompareKey( name, regEntry, gIODTCompatibleKey, matchingName) 988 || CompareKey( name, regEntry, gIODTTypeKey, matchingName) 989 || CompareKey( name, regEntry, gIODTModelKey, matchingName); 990 991 return matched; 992 } 993 994 bool 995 IODTCompareNubName( const IORegistryEntry * regEntry, 996 OSString * name, OSSharedPtr<OSString>& matchingName ) 997 { 998 OSString* matchingNameRaw = NULL; 999 bool result = IODTCompareNubName(regEntry, name, &matchingNameRaw); 1000 matchingName.reset(matchingNameRaw, OSNoRetain); 1001 return result; 1002 } 1003 1004 bool 1005 IODTMatchNubWithKeys( IORegistryEntry * regEntry, 1006 const char * keys ) 1007 { 1008 OSObject *obj; 1009 bool result = false; 1010 1011 obj = OSUnserialize( keys, NULL ); 1012 1013 if (obj) { 1014 result = regEntry->compareNames( obj ); 1015 obj->release(); 1016 } 1017 #if DEBUG 1018 else { 1019 IOLog("Couldn't unserialize %s\n", keys ); 1020 } 1021 #endif 1022 1023 return result; 1024 } 1025 1026 LIBKERN_RETURNS_RETAINED OSCollectionIterator * 1027 IODTFindMatchingEntries( IORegistryEntry * from, 1028 IOOptionBits options, const char * keys ) 1029 { 1030 OSSet *result = NULL; 1031 IORegistryEntry *next; 1032 IORegistryIterator *iter; 1033 OSCollectionIterator *cIter; 1034 bool cmp; 1035 bool minus = options & kIODTExclusive; 1036 1037 1038 iter = IORegistryIterator::iterateOver( from, gIODTPlane, 1039 (options & kIODTRecursive) ? kIORegistryIterateRecursively : 0 ); 1040 if (iter) { 1041 do { 1042 if (result) { 1043 result->release(); 1044 } 1045 result = OSSet::withCapacity( 3 ); 1046 if (!result) { 1047 break; 1048 } 1049 1050 iter->reset(); 1051 while ((next = iter->getNextObject())) { 1052 // Look for existence of a debug property to skip 1053 if (next->propertyExists("AAPL,ignore")) { 1054 continue; 1055 } 1056 if (next->propertyHasValue(gIODTTypeKey, gIODTAssociatedServiceKey)) { 1057 continue; 1058 } 1059 if (keys) { 1060 cmp = IODTMatchNubWithKeys( next, keys ); 1061 if ((minus && (false == cmp)) 1062 || ((false == minus) && (false != cmp))) { 1063 result->setObject( next); 1064 } 1065 } else { 1066 result->setObject( next); 1067 } 1068 } 1069 } while (!iter->isValid()); 1070 1071 iter->release(); 1072 } 1073 1074 cIter = OSCollectionIterator::withCollection( result); 1075 if (result) { 1076 result->release(); 1077 } 1078 1079 return cIter; 1080 } 1081 1082 1083 void 1084 IODTSetResolving( IORegistryEntry * regEntry, 1085 IODTCompareAddressCellFunc compareFunc, 1086 IODTNVLocationFunc locationFunc __unused ) 1087 { 1088 IODTPersistent * entry; 1089 IODTPersistent * newResolvers; 1090 OSNumber * num; 1091 unsigned int index; 1092 1093 IOLockLock(gIODTResolvers->lock); 1094 1095 entry = gIODTResolvers->resolvers; 1096 for (index = 0; index < gIODTResolvers->count; index++) { 1097 if (compareFunc == entry->compareFunc) { 1098 break; 1099 } 1100 entry++; 1101 } 1102 1103 if (index == gIODTResolvers->count) { 1104 if (gIODTResolvers->alloc == gIODTResolvers->count) { 1105 if (__improbable(os_mul_overflow(gIODTResolvers->alloc, 2, 1106 &gIODTResolvers->alloc))) { 1107 panic("IODTSetResolving - gIODTResolvers alloc overflows"); 1108 } 1109 1110 newResolvers = IONewZero(IODTPersistent, gIODTResolvers->alloc); 1111 if (__improbable(!newResolvers)) { 1112 panic("IODTSetResolving - could not allocate new resolvers"); 1113 } 1114 1115 bcopy(gIODTResolvers->resolvers, newResolvers, 1116 sizeof(gIODTResolvers->resolvers[0]) * gIODTResolvers->count); 1117 1118 IODelete(gIODTResolvers->resolvers, IODTPersistent, 1119 gIODTResolvers->count); 1120 gIODTResolvers->resolvers = newResolvers; 1121 } 1122 1123 entry = &gIODTResolvers->resolvers[gIODTResolvers->count]; 1124 entry->compareFunc = compareFunc; 1125 gIODTResolvers->count++; 1126 } 1127 1128 IOLockUnlock(gIODTResolvers->lock); 1129 1130 num = OSNumber::withNumber(index, 32); 1131 regEntry->setProperty(gIODTPersistKey, num); 1132 OSSafeReleaseNULL(num); 1133 1134 return; 1135 } 1136 1137 #if defined(__arm64__) 1138 static SInt64 1139 DefaultCompare( UInt32 cellCount, UInt32 left[], UInt32 right[] ) 1140 { 1141 SInt64 diff = 0; 1142 1143 if (cellCount == 2) { 1144 diff = IOPhysical32(left[1], left[0]) - IOPhysical32(right[1], right[0]); 1145 } else if (cellCount == 1) { 1146 diff = (left[0] - right[0]); 1147 } else { 1148 panic("DefaultCompare only knows how to handle 1 or 2 cells."); 1149 } 1150 1151 return diff; 1152 } 1153 #elif defined(__i386__) || defined(__x86_64__) 1154 static SInt32 1155 DefaultCompare( UInt32 cellCount, UInt32 left[], UInt32 right[] ) 1156 { 1157 cellCount--; 1158 return left[cellCount] - right[cellCount]; 1159 } 1160 #else 1161 #error Unknown architecture. 1162 #endif 1163 1164 static void 1165 AddLengthToCells( UInt32 numCells, UInt32 *cells, UInt64 offset) 1166 { 1167 if (numCells == 1) { 1168 cells[0] += (UInt32)offset; 1169 } else { 1170 #if defined(__arm64__) 1171 UInt64 sum = cells[numCells - 2] + offset; 1172 cells[numCells - 2] = (UInt32)sum; 1173 if (sum > UINT32_MAX) { 1174 cells[numCells - 1] += (UInt32)(sum >> 32); 1175 } 1176 #else 1177 UInt64 sum = cells[numCells - 1] + offset; 1178 cells[numCells - 1] = (UInt32)sum; 1179 if (sum > UINT32_MAX) { 1180 cells[numCells - 2] += (UInt32)(sum >> 32); 1181 } 1182 #endif 1183 } 1184 } 1185 1186 static IOPhysicalAddress 1187 CellsValue( UInt32 numCells, UInt32 *cells) 1188 { 1189 if (numCells == 1) { 1190 return IOPhysical32( 0, cells[0] ); 1191 } else { 1192 #if defined(__arm64__) || defined(arm) 1193 return IOPhysical32( cells[numCells - 1], cells[numCells - 2] ); 1194 #else 1195 return IOPhysical32( cells[numCells - 2], cells[numCells - 1] ); 1196 #endif 1197 } 1198 } 1199 1200 void 1201 IODTGetCellCounts( IORegistryEntry * regEntry, 1202 UInt32 * sizeCount, UInt32 * addressCount) 1203 { 1204 if (!GetUInt32( regEntry, gIODTSizeCellKey, sizeCount)) { 1205 *sizeCount = 1; 1206 } 1207 if (!GetUInt32( regEntry, gIODTAddressCellKey, addressCount)) { 1208 *addressCount = 2; 1209 } 1210 return; 1211 } 1212 1213 // Given addr & len cells from our child, find it in our ranges property, then 1214 // look in our parent to resolve the base of the range for us. 1215 1216 // Range[]: child-addr our-addr child-len 1217 // #cells: child ours child 1218 1219 bool 1220 IODTResolveAddressCell( IORegistryEntry * startEntry, 1221 UInt32 cellsIn[], 1222 IOPhysicalAddress * phys, IOPhysicalLength * lenOut ) 1223 { 1224 IORegistryEntry * parent = NULL; 1225 IORegistryEntry * regEntry; 1226 OSData * prop; 1227 OSNumber * num; 1228 unsigned int index; 1229 // cells in addresses at regEntry 1230 UInt32 sizeCells, addressCells; 1231 // cells in addresses below regEntry 1232 UInt32 childSizeCells, childAddressCells; 1233 UInt32 childCells; 1234 UInt32 cell[8], propLen; 1235 UInt64 offset = 0; 1236 UInt32 endCell[8]; 1237 UInt32 *range; 1238 UInt32 *lookRange; 1239 UInt32 *startRange; 1240 UInt32 *endRanges; 1241 bool ok = true; 1242 SInt64 diff, diff2, endDiff; 1243 UInt64 len, rangeLen; 1244 1245 IODTCompareAddressCellFunc compare; 1246 1247 regEntry = startEntry; 1248 regEntry->retain(); 1249 IODTGetCellCounts( regEntry, &childSizeCells, &childAddressCells ); 1250 childCells = childAddressCells + childSizeCells; 1251 1252 if (childCells > sizeof(cell) / sizeof(cell[0])) { 1253 panic("IODTResolveAddressCell: Invalid device tree (%u,%u)", (uint32_t)childAddressCells, (uint32_t)childSizeCells); 1254 } 1255 1256 bcopy( cellsIn, cell, sizeof(UInt32) * childCells ); 1257 *lenOut = CellsValue( childSizeCells, cellsIn + childAddressCells ); 1258 1259 do{ 1260 prop = OSDynamicCast( OSData, regEntry->getProperty( gIODTRangeKey )); 1261 if (NULL == prop) { 1262 /* end of the road */ 1263 *phys = CellsValue( childAddressCells, cell ); 1264 *phys += offset; 1265 break; 1266 } 1267 1268 parent = regEntry->copyParentEntry( gIODTPlane ); 1269 IODTGetCellCounts( parent, &sizeCells, &addressCells ); 1270 1271 if ((propLen = prop->getLength())) { 1272 // search 1273 startRange = (UInt32 *) prop->getBytesNoCopy(); 1274 range = startRange; 1275 endRanges = range + (propLen / sizeof(UInt32)); 1276 1277 compare = NULL; 1278 num = OSDynamicCast(OSNumber, regEntry->getProperty(gIODTPersistKey)); 1279 if (num) { 1280 IOLockLock(gIODTResolvers->lock); 1281 index = num->unsigned32BitValue(); 1282 if (index < gIODTResolvers->count) { 1283 compare = gIODTResolvers->resolvers[index].compareFunc; 1284 } 1285 IOLockUnlock(gIODTResolvers->lock); 1286 } 1287 1288 if (!compare && (addressCells == childAddressCells)) { 1289 compare = DefaultCompare; 1290 } 1291 if (!compare) { 1292 panic("There is no mixed comparison function yet..."); 1293 } 1294 1295 for (ok = false; 1296 range < endRanges; 1297 range += (childCells + addressCells)) { 1298 // is cell start within range? 1299 diff = (*compare)( childAddressCells, cell, range ); 1300 1301 if (childAddressCells > sizeof(endCell) / sizeof(endCell[0])) { 1302 panic("IODTResolveAddressCell: Invalid device tree (%u)", (uint32_t)childAddressCells); 1303 } 1304 1305 bcopy(range, endCell, childAddressCells * sizeof(UInt32)); 1306 1307 rangeLen = CellsValue(childSizeCells, range + childAddressCells + addressCells); 1308 AddLengthToCells(childAddressCells, endCell, rangeLen); 1309 1310 diff2 = (*compare)( childAddressCells, cell, endCell ); 1311 1312 // if start of cell < start of range, or end of range >= start of cell, skip 1313 if ((diff < 0) || (diff2 >= 0)) { 1314 continue; 1315 } 1316 1317 len = CellsValue(childSizeCells, cell + childAddressCells); 1318 ok = (0 == len); 1319 1320 if (!ok) { 1321 // search for cell end 1322 bcopy(cell, endCell, childAddressCells * sizeof(UInt32)); 1323 1324 AddLengthToCells(childAddressCells, endCell, len - 1); 1325 1326 for (lookRange = startRange; 1327 lookRange < endRanges; 1328 lookRange += (childCells + addressCells)) { 1329 // make sure end of cell >= range start 1330 endDiff = (*compare)( childAddressCells, endCell, lookRange ); 1331 if (endDiff < 0) { 1332 continue; 1333 } 1334 1335 UInt64 rangeStart = CellsValue(addressCells, range + childAddressCells); 1336 UInt64 lookRangeStart = CellsValue(addressCells, lookRange + childAddressCells); 1337 if ((endDiff - len + 1 + lookRangeStart) == (diff + rangeStart)) { 1338 ok = true; 1339 break; 1340 } 1341 } 1342 if (!ok) { 1343 continue; 1344 } 1345 } 1346 offset += diff; 1347 break; 1348 } 1349 1350 if (addressCells + sizeCells > sizeof(cell) / sizeof(cell[0])) { 1351 panic("IODTResolveAddressCell: Invalid device tree (%u, %u)", (uint32_t)addressCells, (uint32_t)sizeCells); 1352 } 1353 1354 // Get the physical start of the range from our parent 1355 bcopy( range + childAddressCells, cell, sizeof(UInt32) * addressCells ); 1356 bzero( cell + addressCells, sizeof(UInt32) * sizeCells ); 1357 } /* else zero length range => pass thru to parent */ 1358 1359 OSSafeReleaseNULL(regEntry); 1360 regEntry = parent; 1361 parent = NULL; 1362 childSizeCells = sizeCells; 1363 childAddressCells = addressCells; 1364 childCells = childAddressCells + childSizeCells; 1365 }while (ok && regEntry); 1366 1367 OSSafeReleaseNULL(regEntry); 1368 1369 return ok; 1370 } 1371 1372 1373 OSArray * 1374 IODTResolveAddressing( IORegistryEntry * regEntry, 1375 const char * addressPropertyName, 1376 IODeviceMemory * parent ) 1377 { 1378 IORegistryEntry *parentEntry; 1379 OSData *addressProperty; 1380 UInt32 sizeCells, addressCells, cells; 1381 int i, num; 1382 UInt32 *reg; 1383 IOPhysicalAddress phys; 1384 IOPhysicalLength len; 1385 OSArray *array; 1386 1387 array = NULL; 1388 do{ 1389 parentEntry = regEntry->copyParentEntry( gIODTPlane ); 1390 addressProperty = (OSData *) regEntry->getProperty( addressPropertyName ); 1391 if ((NULL == addressProperty) || (NULL == parentEntry)) { 1392 break; 1393 } 1394 1395 IODTGetCellCounts( parentEntry, &sizeCells, &addressCells ); 1396 if (0 == sizeCells) { 1397 break; 1398 } 1399 1400 cells = sizeCells + addressCells; 1401 reg = (UInt32 *) addressProperty->getBytesNoCopy(); 1402 num = addressProperty->getLength() / (4 * cells); 1403 1404 array = OSArray::withCapacity( 1 ); 1405 if (NULL == array) { 1406 break; 1407 } 1408 1409 for (i = 0; i < num; i++) { 1410 if (IODTResolveAddressCell( parentEntry, reg, &phys, &len )) { 1411 IODeviceMemory *range; 1412 range = NULL; 1413 if (parent) { 1414 range = IODeviceMemory::withSubRange( parent, 1415 phys - parent->getPhysicalSegment(0, NULL, kIOMemoryMapperNone), len ); 1416 } 1417 if (NULL == range) { 1418 range = IODeviceMemory::withRange( phys, len ); 1419 } 1420 if (range) { 1421 array->setObject( range ); 1422 OSSafeReleaseNULL(range); 1423 } 1424 } 1425 reg += cells; 1426 } 1427 1428 regEntry->setProperty( gIODeviceMemoryKey, array); 1429 array->release(); /* ??? */ 1430 }while (false); 1431 1432 OSSafeReleaseNULL(parentEntry); 1433 1434 return array; 1435 } 1436 1437 OSData * 1438 IODTFindSlotName( IORegistryEntry * regEntry, UInt32 deviceNumber ) 1439 { 1440 IORegistryEntry *parent; 1441 OSData *data; 1442 OSData *ret = NULL; 1443 UInt32 *bits; 1444 UInt32 i; 1445 UInt32 nlen; 1446 char *names; 1447 char *lastName; 1448 UInt32 mask; 1449 1450 data = (OSData *) regEntry->getProperty("AAPL,slot-name"); 1451 if (data) { 1452 return data; 1453 } 1454 1455 do{ 1456 parent = regEntry->copyParentEntry( gIODTPlane ); 1457 if (!parent) { 1458 break; 1459 } 1460 1461 data = OSDynamicCast( OSData, parent->getProperty("slot-names")); 1462 if (!data) { 1463 break; 1464 } 1465 if (data->getLength() <= 4) { 1466 break; 1467 } 1468 1469 bits = (UInt32 *) data->getBytesNoCopy(); 1470 mask = *bits; 1471 if ((0 == (mask & (1 << deviceNumber)))) { 1472 break; 1473 } 1474 1475 names = (char *)(bits + 1); 1476 lastName = names + (data->getLength() - 4); 1477 1478 for (i = 0; (i <= deviceNumber) && (names < lastName); i++) { 1479 if (mask & (1 << i)) { 1480 nlen = 1 + ((unsigned int) strnlen(names, lastName - names)); 1481 if (i == deviceNumber) { 1482 data = OSData::withBytesNoCopy(names, nlen); 1483 if (data) { 1484 regEntry->setProperty("AAPL,slot-name", data); 1485 ret = data; 1486 data->release(); 1487 } 1488 } else { 1489 names += nlen; 1490 } 1491 } 1492 } 1493 }while (false); 1494 1495 OSSafeReleaseNULL(parent); 1496 1497 return ret; 1498 } 1499 1500 extern "C" IOReturn 1501 IONDRVLibrariesInitialize( IOService * provider ) 1502 { 1503 return kIOReturnUnsupported; 1504 } 1505