|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* ! 23: * Copyright (c) 1998 Apple Computer, Inc. All rights reserved. ! 24: * ! 25: * HISTORY ! 26: * ! 27: */ ! 28: ! 29: #include <IOKit/IOService.h> ! 30: #include <libkern/c++/OSContainers.h> ! 31: #include <IOKit/IOCatalogue.h> ! 32: #include <libkern/c++/OSUnserialize.h> ! 33: #include <mach/kmod.h> ! 34: ! 35: #include <IOKit/IOLib.h> ! 36: ! 37: #include <IOKit/assert.h> ! 38: ! 39: ! 40: #define super OSObject ! 41: #define kModuleKey "Module" ! 42: ! 43: OSDefineMetaClassAndStructors(IOCatalogue, OSObject) ! 44: ! 45: #define CATALOGTEST 0 ! 46: ! 47: IOCatalogue * gIOCatalogue; ! 48: const OSSymbol * gIOClassKey; ! 49: const OSSymbol * gIOProbeScoreKey; ! 50: ! 51: static void UniqueProperties( OSDictionary * dict ) ! 52: { ! 53: OSString * data; ! 54: ! 55: data = OSDynamicCast( OSString, dict->getObject( gIOClassKey )); ! 56: if( data) { ! 57: const OSSymbol *classSymbol = OSSymbol::withString(data); ! 58: ! 59: dict->setObject( gIOClassKey, (OSSymbol *) classSymbol); ! 60: classSymbol->release(); ! 61: } else ! 62: IOLog("Missing or bad \"%s\" key\n", ! 63: gIOClassKey->getCStringNoCopy()); ! 64: ! 65: data = OSDynamicCast( OSString, dict->getObject( gIOMatchCategoryKey )); ! 66: if( data) { ! 67: const OSSymbol *classSymbol = OSSymbol::withString(data); ! 68: ! 69: dict->setObject( gIOMatchCategoryKey, (OSSymbol *) classSymbol); ! 70: classSymbol->release(); ! 71: } ! 72: } ! 73: ! 74: void IOCatalogue::initialize( void ) ! 75: { ! 76: OSArray * array; ! 77: OSString * errorString; ! 78: bool rc; ! 79: ! 80: extern const char * gIOKernelConfigTables; ! 81: ! 82: array = OSDynamicCast(OSArray, OSUnserialize(gIOKernelConfigTables, &errorString)); ! 83: if (!array && errorString) { ! 84: IOLog("KernelConfigTables syntax error: %s\n", ! 85: errorString->getCStringNoCopy()); ! 86: errorString->release(); ! 87: } ! 88: ! 89: gIOClassKey = OSSymbol::withCStringNoCopy( kIOClassKey ); ! 90: gIOProbeScoreKey = OSSymbol::withCStringNoCopy( kIOProbeScoreKey ); ! 91: assert( array && gIOClassKey && gIOProbeScoreKey); ! 92: ! 93: gIOCatalogue = new IOCatalogue; ! 94: assert(gIOCatalogue); ! 95: rc = gIOCatalogue->init(array); ! 96: assert(rc); ! 97: array->release(); ! 98: } ! 99: ! 100: // Initialize the IOCatalog object. ! 101: bool IOCatalogue::init(OSArray * initArray) ! 102: { ! 103: IORegistryEntry * entry; ! 104: OSDictionary * dict; ! 105: ! 106: if ( !super::init() ) ! 107: return false; ! 108: ! 109: generation = 1; ! 110: ! 111: array = initArray; ! 112: array->retain(); ! 113: kernelTables = OSCollectionIterator::withCollection( array ); ! 114: ! 115: lock = IOLockAlloc(); ! 116: ! 117: kernelTables->reset(); ! 118: while( (dict = (OSDictionary *) kernelTables->getNextObject())) { ! 119: UniqueProperties(dict); ! 120: } ! 121: ! 122: #if CATALOGTEST ! 123: AbsoluteTime deadline; ! 124: clock_interval_to_deadline( 1000, kMillisecondScale ); ! 125: thread_call_func_delayed( ping, this, deadline ); ! 126: #endif ! 127: ! 128: entry = IORegistryEntry::getRegistryRoot(); ! 129: if ( entry ) ! 130: entry->setProperty(kIOCatalogueKey, this); ! 131: ! 132: return true; ! 133: } ! 134: ! 135: // Release all resources used by IOCatalogue and deallocate. ! 136: // This will probably never be called. ! 137: void IOCatalogue::free( void ) ! 138: { ! 139: if ( array ) ! 140: array->release(); ! 141: ! 142: if ( kernelTables ) ! 143: kernelTables->release(); ! 144: ! 145: super::free(); ! 146: } ! 147: ! 148: #if CATALOGTEST ! 149: ! 150: static int hackLimit; ! 151: ! 152: enum { kDriversPerIter = 4 }; ! 153: ! 154: void IOCatalogue::ping( thread_call_param_t arg, thread_call_param_t) ! 155: { ! 156: IOCatalogue * self = (IOCatalogue *) arg; ! 157: OSOrderedSet * set; ! 158: OSDictionary * table; ! 159: int newLimit; ! 160: ! 161: set = OSOrderedSet::withCapacity( 1 ); ! 162: ! 163: IOTakeLock( &self->lock ); ! 164: ! 165: for( newLimit = 0; newLimit < kDriversPerIter; newLimit++) { ! 166: table = (OSDictionary *) self->array->getObject( ! 167: hackLimit + newLimit ); ! 168: if( table) { ! 169: set->setLastObject( table ); ! 170: ! 171: OSSymbol * sym = (OSSymbol *) table->getObject( gIOClassKey ); ! 172: kprintf("enabling %s\n", sym->getCStringNoCopy()); ! 173: ! 174: } else { ! 175: newLimit--; ! 176: break; ! 177: } ! 178: } ! 179: ! 180: IOService::catalogNewDrivers( set ); ! 181: ! 182: hackLimit += newLimit; ! 183: self->generation++; ! 184: ! 185: IOUnlock( &self->lock ); ! 186: ! 187: if( kDriversPerIter == newLimit) { ! 188: AbsoluteTime deadline; ! 189: clock_interval_to_deadline( 500, kMillisecondScale ); ! 190: thread_call_func_delayed( ping, this, deadline ); ! 191: } ! 192: } ! 193: #endif ! 194: ! 195: OSOrderedSet * IOCatalogue::findDrivers( IOService * service, ! 196: SInt32 * generationCount ) ! 197: { ! 198: OSDictionary * nextTable; ! 199: OSOrderedSet * set; ! 200: OSString * imports; ! 201: ! 202: set = OSOrderedSet::withCapacity( 1, IOServiceOrdering, ! 203: (void *)gIOProbeScoreKey ); ! 204: if( !set ) ! 205: return( 0 ); ! 206: ! 207: IOTakeLock( lock ); ! 208: kernelTables->reset(); ! 209: ! 210: #if CATALOGTEST ! 211: int hackIndex = 0; ! 212: #endif ! 213: while( (nextTable = (OSDictionary *) kernelTables->getNextObject())) { ! 214: #if CATALOGTEST ! 215: if( hackIndex++ > hackLimit) ! 216: break; ! 217: #endif ! 218: imports = OSDynamicCast( OSString, ! 219: nextTable->getObject( gIOProviderClassKey )); ! 220: if( imports && service->metaCast( imports )) ! 221: set->setObject( nextTable ); ! 222: } ! 223: ! 224: *generationCount = getGenerationCount(); ! 225: ! 226: IOUnlock( lock ); ! 227: ! 228: return( set ); ! 229: } ! 230: ! 231: // Is personality already in the catalog? ! 232: OSOrderedSet * IOCatalogue::findDrivers( OSDictionary * matching, ! 233: SInt32 * generationCount) ! 234: { ! 235: OSDictionary * dict; ! 236: OSOrderedSet * set; ! 237: ! 238: UniqueProperties(matching); ! 239: ! 240: set = OSOrderedSet::withCapacity( 1, IOServiceOrdering, ! 241: (void *)gIOProbeScoreKey ); ! 242: ! 243: IOTakeLock( lock ); ! 244: kernelTables->reset(); ! 245: while ( (dict = (OSDictionary *) kernelTables->getNextObject()) ) { ! 246: if ( dict->isEqualTo(matching, matching) ) ! 247: set->setObject(dict); ! 248: } ! 249: *generationCount = getGenerationCount(); ! 250: IOUnlock( lock ); ! 251: ! 252: return set; ! 253: } ! 254: ! 255: // Add a new personality to the set if it has a unique IOResourceMatchKey value. ! 256: // XXX -- svail: This should be optimized. ! 257: static void AddNewImports( OSOrderedSet * set, OSDictionary * dict ) ! 258: { ! 259: OSCollectionIterator * iter; ! 260: OSDictionary * entry; ! 261: OSString * imports1; ! 262: OSString * imports2; ! 263: bool foundMatch; ! 264: ! 265: imports1 = (OSString *)OSDynamicCast(OSString, ! 266: dict->getObject(gIOProviderClassKey)); ! 267: if ( !imports1 ) ! 268: return; ! 269: ! 270: foundMatch = false; ! 271: iter = OSCollectionIterator::withCollection(set); ! 272: if ( !iter ) ! 273: return; ! 274: ! 275: while ( (entry = (OSDictionary *)iter->getNextObject()) ) { ! 276: imports2 = (OSString *)OSDynamicCast(OSString, ! 277: entry->getObject(gIOProviderClassKey)); ! 278: if ( !imports2 ) ! 279: continue; ! 280: ! 281: if ( imports1->isEqualTo(imports2) ) { ! 282: foundMatch = true; ! 283: break; ! 284: } ! 285: } ! 286: iter->release(); ! 287: ! 288: if ( !foundMatch ) ! 289: set->setObject(dict); ! 290: } ! 291: ! 292: // Add driver config tables to catalog and start matching process. ! 293: bool IOCatalogue::addDrivers( OSArray * drivers, ! 294: bool doNubMatching = true ) ! 295: { ! 296: OSCollectionIterator * iter; ! 297: OSDictionary * dict; ! 298: OSOrderedSet * set; ! 299: OSArray * persons; ! 300: bool ret; ! 301: ! 302: ret = true; ! 303: persons = OSDynamicCast(OSArray, drivers); ! 304: if ( !persons ) ! 305: return false; ! 306: ! 307: iter = OSCollectionIterator::withCollection( persons ); ! 308: if (!iter ) ! 309: return false; ! 310: ! 311: set = OSOrderedSet::withCapacity( 10, IOServiceOrdering, ! 312: (void *)gIOProbeScoreKey ); ! 313: if ( !set ) { ! 314: iter->release(); ! 315: return false; ! 316: } ! 317: ! 318: IOTakeLock( lock ); ! 319: while ( (dict = (OSDictionary *) iter->getNextObject()) ) { ! 320: UInt count; ! 321: ! 322: UniqueProperties( dict ); ! 323: ! 324: // Add driver personality to catalogue. ! 325: count = array->getCount(); ! 326: while ( count-- ) { ! 327: OSDictionary * driver; ! 328: ! 329: // Be sure not to double up on personalities. ! 330: driver = (OSDictionary *)array->getObject(count); ! 331: if ( dict->isEqualTo(driver, driver) ) { ! 332: array->removeObject(count); ! 333: break; ! 334: } ! 335: } ! 336: ! 337: ret = array->setObject( dict ); ! 338: if ( !ret ) ! 339: break; ! 340: ! 341: AddNewImports( set, dict ); ! 342: } ! 343: // Start device matching. ! 344: if ( doNubMatching && (set->getCount() > 0) ) { ! 345: IOService::catalogNewDrivers( set ); ! 346: generation++; ! 347: } ! 348: IOUnlock( lock ); ! 349: ! 350: set->release(); ! 351: iter->release(); ! 352: ! 353: return ret; ! 354: } ! 355: ! 356: // Remove drivers from the catalog which match the ! 357: // properties in the matching dictionary. ! 358: bool IOCatalogue::removeDrivers( OSDictionary * matching, ! 359: bool doNubMatching = true) ! 360: { ! 361: OSCollectionIterator * tables; ! 362: OSDictionary * dict; ! 363: OSOrderedSet * set; ! 364: OSArray * arrayCopy; ! 365: ! 366: if ( !matching ) ! 367: return false; ! 368: ! 369: set = OSOrderedSet::withCapacity(10, ! 370: IOServiceOrdering, ! 371: (void *)gIOProbeScoreKey); ! 372: if ( !set ) ! 373: return false; ! 374: ! 375: arrayCopy = OSArray::withCapacity(100); ! 376: if ( !arrayCopy ) ! 377: return false; ! 378: ! 379: tables = OSCollectionIterator::withCollection(arrayCopy); ! 380: arrayCopy->release(); ! 381: if ( !tables ) ! 382: return false; ! 383: ! 384: UniqueProperties( matching ); ! 385: ! 386: IOTakeLock( lock ); ! 387: kernelTables->reset(); ! 388: arrayCopy->merge(array); ! 389: array->flushCollection(); ! 390: tables->reset(); ! 391: while ( (dict = (OSDictionary *)tables->getNextObject()) ) { ! 392: if ( dict->isEqualTo(matching, matching) ) { ! 393: AddNewImports( set, dict ); ! 394: continue; ! 395: } ! 396: ! 397: array->setObject(dict); ! 398: } ! 399: // Start device matching. ! 400: if ( doNubMatching && (set->getCount() > 0) ) { ! 401: IOService::catalogNewDrivers(set); ! 402: generation++; ! 403: } ! 404: IOUnlock( lock ); ! 405: ! 406: set->release(); ! 407: tables->release(); ! 408: ! 409: return true; ! 410: } ! 411: ! 412: // Return the generation count. ! 413: SInt32 IOCatalogue::getGenerationCount( void ) const ! 414: { ! 415: return( generation ); ! 416: } ! 417: ! 418: bool IOCatalogue::isModuleLoaded( OSString * moduleName ) const ! 419: { ! 420: return isModuleLoaded(moduleName->getCStringNoCopy()); ! 421: } ! 422: ! 423: bool IOCatalogue::isModuleLoaded( const char * moduleName ) const ! 424: { ! 425: kmod_info_t * k_info; ! 426: ! 427: if ( !moduleName ) ! 428: return false; ! 429: ! 430: // Is the module already loaded? ! 431: k_info = kmod_lookupbyname((char *)moduleName); ! 432: if ( !k_info ) { ! 433: kern_return_t ret; ! 434: ! 435: // If the module hasn't been loaded, then load it. ! 436: ret = kmod_load_extension((char *)moduleName); ! 437: if ( ret != kIOReturnSuccess ) { ! 438: IOLog("IOCatalogue: %s cannot be loaded.\n", moduleName); ! 439: } ! 440: ! 441: return false; ! 442: } ! 443: ! 444: return true; ! 445: } ! 446: ! 447: // Check to see if module has been loaded already. ! 448: bool IOCatalogue::isModuleLoaded( OSDictionary * driver ) const ! 449: { ! 450: OSString * moduleName; ! 451: ! 452: if ( !driver ) ! 453: return false; ! 454: ! 455: // If a personality doesn't have a module key, it is assumed to ! 456: // be an "in-kernel" driver. ! 457: moduleName = OSDynamicCast(OSString, driver->getObject(kModuleKey)); ! 458: if ( moduleName ) ! 459: return isModuleLoaded(moduleName); ! 460: ! 461: return true; ! 462: } ! 463: ! 464: // This function is called after a module has been loaded. ! 465: void IOCatalogue::moduleHasLoaded( OSString * moduleName ) ! 466: { ! 467: OSDictionary * dict; ! 468: ! 469: dict = OSDictionary::withCapacity(2); ! 470: dict->setObject(kModuleKey, moduleName); ! 471: startMatching(dict); ! 472: dict->release(); ! 473: } ! 474: ! 475: void IOCatalogue::moduleHasLoaded( const char * moduleName ) ! 476: { ! 477: OSString * name; ! 478: ! 479: name = OSString::withCString(moduleName); ! 480: moduleHasLoaded(name); ! 481: name->release(); ! 482: } ! 483: ! 484: IOReturn IOCatalogue::unloadModule( OSString * moduleName ) const ! 485: { ! 486: kmod_info_t * k_info; ! 487: kern_return_t ret; ! 488: const char * name; ! 489: ! 490: ret = kIOReturnBadArgument; ! 491: if ( moduleName ) { ! 492: name = moduleName->getCStringNoCopy(); ! 493: k_info = kmod_lookupbyname((char *)name); ! 494: if ( k_info && (k_info->reference_count < 1) ) { ! 495: if ( k_info->stop && ! 496: !((ret = k_info->stop(k_info, 0)) == kIOReturnSuccess) ) ! 497: return ret; ! 498: ! 499: ret = kmod_destroy((host_t) 1, k_info->id); ! 500: } ! 501: } ! 502: ! 503: return ret; ! 504: } ! 505: ! 506: static IOReturn _terminateDrivers( OSArray * array, OSDictionary * matching ) ! 507: { ! 508: OSCollectionIterator * tables; ! 509: OSCollectionIterator * props; ! 510: OSDictionary * dict; ! 511: OSIterator * iter; ! 512: OSArray * arrayCopy; ! 513: IOService * service; ! 514: IOReturn ret; ! 515: ! 516: if ( !matching ) ! 517: return kIOReturnBadArgument; ! 518: ! 519: ret = kIOReturnSuccess; ! 520: dict = 0; ! 521: iter = IORegistryIterator::iterateOver(gIOServicePlane, ! 522: kIORegistryIterateRecursively); ! 523: if ( !iter ) ! 524: return kIOReturnNoMemory; ! 525: ! 526: UniqueProperties( matching ); ! 527: ! 528: props = OSCollectionIterator::withCollection(matching); ! 529: if ( !props ) { ! 530: iter->release(); ! 531: return kIOReturnNoMemory; ! 532: } ! 533: ! 534: // terminate instances. ! 535: do { ! 536: iter->reset(); ! 537: while( (service = (IOService *)iter->getNextObject()) ) { ! 538: dict = service->getPropertyTable(); ! 539: if ( !dict ) ! 540: continue; ! 541: ! 542: if ( !dict->isEqualTo(matching, matching) ) ! 543: continue; ! 544: ! 545: if ( !service->terminate(kIOServiceRequired|kIOServiceSynchronous) ) { ! 546: ret = kIOReturnUnsupported; ! 547: break; ! 548: } ! 549: } ! 550: } while( !service && !iter->isValid()); ! 551: iter->release(); ! 552: ! 553: // remove configs from catalog. ! 554: if ( ret != kIOReturnSuccess ) ! 555: return ret; ! 556: ! 557: arrayCopy = OSArray::withCapacity(100); ! 558: if ( !arrayCopy ) ! 559: return kIOReturnNoMemory; ! 560: ! 561: tables = OSCollectionIterator::withCollection(arrayCopy); ! 562: arrayCopy->release(); ! 563: if ( !tables ) ! 564: return kIOReturnNoMemory; ! 565: ! 566: arrayCopy->merge(array); ! 567: array->flushCollection(); ! 568: tables->reset(); ! 569: while ( (dict = (OSDictionary *)tables->getNextObject()) ) { ! 570: if ( dict->isEqualTo(matching, matching) ) ! 571: continue; ! 572: ! 573: array->setObject(dict); ! 574: } ! 575: ! 576: tables->release(); ! 577: ! 578: return ret; ! 579: } ! 580: ! 581: IOReturn IOCatalogue::terminateDrivers( OSDictionary * matching ) ! 582: { ! 583: IOReturn ret; ! 584: ! 585: ret = kIOReturnSuccess; ! 586: IOTakeLock( lock ); ! 587: ret = _terminateDrivers(array, matching); ! 588: kernelTables->reset(); ! 589: IOUnlock( lock ); ! 590: ! 591: return ret; ! 592: } ! 593: ! 594: IOReturn IOCatalogue::terminateDriversForModule( ! 595: OSString * moduleName, ! 596: bool unload ) ! 597: { ! 598: IOReturn ret; ! 599: OSDictionary * dict; ! 600: ! 601: dict = OSDictionary::withCapacity(1); ! 602: if ( !dict ) ! 603: return kIOReturnNoMemory; ! 604: ! 605: dict->setObject(kModuleKey, moduleName); ! 606: ! 607: IOTakeLock( lock ); ! 608: ! 609: ret = _terminateDrivers(array, dict); ! 610: kernelTables->reset(); ! 611: ! 612: // Unload the module itself. ! 613: if ( unload && ret == kIOReturnSuccess ) { ! 614: // Do kmod stop first. ! 615: ret = unloadModule(moduleName); ! 616: } ! 617: ! 618: IOUnlock( lock ); ! 619: ! 620: dict->release(); ! 621: ! 622: return ret; ! 623: } ! 624: ! 625: IOReturn IOCatalogue::terminateDriversForModule( ! 626: const char * moduleName, ! 627: bool unload ) ! 628: { ! 629: OSString * name; ! 630: IOReturn ret; ! 631: ! 632: name = OSString::withCString(moduleName); ! 633: if ( !name ) ! 634: return kIOReturnNoMemory; ! 635: ! 636: ret = terminateDriversForModule(name, unload); ! 637: name->release(); ! 638: ! 639: return ret; ! 640: } ! 641: ! 642: bool IOCatalogue::startMatching( OSDictionary * matching ) ! 643: { ! 644: OSDictionary * dict; ! 645: OSOrderedSet * set; ! 646: ! 647: if ( !matching ) ! 648: return false; ! 649: ! 650: set = OSOrderedSet::withCapacity(10, IOServiceOrdering, ! 651: (void *)gIOProbeScoreKey); ! 652: if ( !set ) ! 653: return false; ! 654: ! 655: IOTakeLock( lock ); ! 656: kernelTables->reset(); ! 657: ! 658: while ( (dict = (OSDictionary *)kernelTables->getNextObject()) ) { ! 659: if ( dict->isEqualTo(matching, matching) ) ! 660: AddNewImports(set, dict); ! 661: } ! 662: // Start device matching. ! 663: if ( set->getCount() > 0 ) { ! 664: IOService::catalogNewDrivers(set); ! 665: generation++; ! 666: } ! 667: ! 668: IOUnlock( lock ); ! 669: ! 670: set->release(); ! 671: ! 672: return true; ! 673: } ! 674: ! 675: void IOCatalogue::reset(void) ! 676: { ! 677: OSArray * tables; ! 678: OSDictionary * entry; ! 679: unsigned int count; ! 680: ! 681: IOLog("Resetting IOCatalogue.\n"); ! 682: ! 683: IOTakeLock( lock ); ! 684: tables = OSArray::withArray(array); ! 685: array->flushCollection(); ! 686: ! 687: count = tables->getCount(); ! 688: while ( count-- ) { ! 689: entry = (OSDictionary *)tables->getObject(count); ! 690: if ( entry && !entry->getObject(kModuleKey) ) { ! 691: array->setObject(entry); ! 692: } ! 693: } ! 694: ! 695: kernelTables->reset(); ! 696: IOUnlock( lock ); ! 697: ! 698: tables->release(); ! 699: } ! 700: ! 701: bool IOCatalogue::serialize(OSSerialize * s) const ! 702: { ! 703: bool ret; ! 704: ! 705: if ( !s ) ! 706: return false; ! 707: ! 708: IOTakeLock( lock ); ! 709: ret = array->serialize(s); ! 710: IOUnlock( lock ); ! 711: ! 712: return ret; ! 713: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.