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