bool IOCatalogue::startMatching( OSDictionary * matching ) { OSDictionary * dict; OSOrderedSet * set; if ( !matching ) return false; set = OSOrderedSet::withCapacity(10, IOServiceOrdering, (void *)gIOProbeScoreKey); if ( !set ) return false; IOLockLock(lock); kernelTables->reset(); while ( (dict = (OSDictionary *)kernelTables->getNextObject()) ) { /* This comparison must be done with only the keys in the * "matching" dict to enable general matching. */ if ( dict->isEqualTo(matching, matching) ) AddNewImports(set, dict); } // Start device matching. if ( set->getCount() > 0 ) { IOService::catalogNewDrivers(set); generation++; } IOLockUnlock(lock); set->release(); return true; }
/********************************************************************* * Add driver config tables to catalog and start matching process. * * Important that existing personalities are kept (not replaced) * if duplicates found. Personalities can come from OSKext objects * or from userland kext library. We want to minimize distinct * copies between OSKext & IOCatalogue. * * xxx - userlib used to refuse to send personalities with IOKitDebug * xxx - during safe boot. That would be better implemented here. *********************************************************************/ bool IOCatalogue::addDrivers( OSArray * drivers, bool doNubMatching) { bool result = false; OSCollectionIterator * iter = NULL; // must release OSOrderedSet * set = NULL; // must release OSDictionary * dict = NULL; // do not release OSArray * persons = NULL; // do not release persons = OSDynamicCast(OSArray, drivers); if (!persons) { goto finish; } set = OSOrderedSet::withCapacity( 10, IOServiceOrdering, (void *)gIOProbeScoreKey ); if (!set) { goto finish; } iter = OSCollectionIterator::withCollection(persons); if (!iter) { goto finish; } result = true; IOLockLock(lock); while ( (dict = (OSDictionary *) iter->getNextObject()) ) { // xxx Deleted OSBundleModuleDemand check; will handle in other ways for SL SInt count; UniqueProperties(dict); // Add driver personality to catalogue. count = array->getCount(); while (count--) { OSDictionary * driver; // Be sure not to double up on personalities. driver = (OSDictionary *)array->getObject(count); /* Unlike in other functions, this comparison must be exact! * The catalogue must be able to contain personalities that * are proper supersets of others. * Do not compare just the properties present in one driver * pesonality or the other. */ if (dict->isEqualTo(driver)) { break; } } if (count >= 0) { // its a dup continue; } result = array->setObject(dict); if (!result) { break; } AddNewImports(set, dict); } // Start device matching. if (doNubMatching && (set->getCount() > 0)) { IOService::catalogNewDrivers(set); generation++; } IOLockUnlock(lock); finish: if (set) set->release(); if (iter) iter->release(); return result; }
/********************************************************************* * Remove drivers from the catalog which match the * properties in the matching dictionary. *********************************************************************/ bool IOCatalogue::removeDrivers( OSDictionary * matching, bool doNubMatching) { OSCollectionIterator * tables; OSDictionary * dict; OSOrderedSet * set; OSArray * arrayCopy; if ( !matching ) return false; set = OSOrderedSet::withCapacity(10, IOServiceOrdering, (void *)gIOProbeScoreKey); if ( !set ) return false; arrayCopy = OSArray::withCapacity(100); if ( !arrayCopy ) { set->release(); return false; } tables = OSCollectionIterator::withCollection(arrayCopy); arrayCopy->release(); if ( !tables ) { set->release(); return false; } UniqueProperties( matching ); IOLockLock(lock); kernelTables->reset(); arrayCopy->merge(array); array->flushCollection(); tables->reset(); while ( (dict = (OSDictionary *)tables->getNextObject()) ) { /* This comparison must be done with only the keys in the * "matching" dict to enable general searches. */ if ( dict->isEqualTo(matching, matching) ) { AddNewImports( set, dict ); continue; } array->setObject(dict); } // Start device matching. if ( doNubMatching && (set->getCount() > 0) ) { IOService::catalogNewDrivers(set); generation++; } IOLockUnlock(lock); set->release(); tables->release(); return true; }
bool IOCatalogue::resetAndAddDrivers(OSArray * drivers, bool doNubMatching) { bool result = false; OSArray * newPersonalities = NULL; // do not release OSCollectionIterator * newPIterator = NULL; // must release OSOrderedSet * matchSet = NULL; // must release OSArray * oldPersonalities = NULL; // must release OSArray * kernelPersonalities = NULL; // must release OSString * errorString = NULL; // must release OSObject * object = NULL; // do not release OSDictionary * thisNewPersonality = NULL; // do not release signed int count, i; extern const char * gIOKernelConfigTables; if (drivers) { newPersonalities = OSDynamicCast(OSArray, drivers); if (!newPersonalities) { goto finish; } newPIterator = OSCollectionIterator::withCollection(newPersonalities); if (!newPIterator) { goto finish; } matchSet = OSOrderedSet::withCapacity(10, IOServiceOrdering, (void *)gIOProbeScoreKey); if (!matchSet) { goto finish; } } /* Read personalities for the built-in kernel driver classes. * We don't have many any more. */ kernelPersonalities = OSDynamicCast(OSArray, OSUnserialize(gIOKernelConfigTables, &errorString)); if (!kernelPersonalities && errorString) { IOLog("KernelConfigTables syntax error: %s\n", errorString->getCStringNoCopy()); goto finish; } /* Now copy the current array of personalities so we can reuse them * if the new list contains any duplicates. This saves on memory * consumption. */ oldPersonalities = OSDynamicCast(OSArray, array->copyCollection()); if (!oldPersonalities) { goto finish; } result = true; IOLog("Resetting IOCatalogue.\n"); /* No goto finish from here to unlock. */ IOLockLock(lock); array->flushCollection(); /* Add back the kernel personalities and remove them from the old * array so we don't try to match on them again. Go forward through * the arrays as this causes the least iteration since kernel personalities * should always be first. */ count = kernelPersonalities->getCount(); for (i = 0; i < count; i++) { /* Static cast here, as the data is coming from within the kernel image. */ OSDictionary * thisNewPersonality = (OSDictionary *) kernelPersonalities->getObject(i); array->setObject(thisNewPersonality); signed int oldPCount = oldPersonalities->getCount(); for (signed int oldPIndex = 0; oldPIndex < oldPCount; oldPIndex++) { if (thisNewPersonality->isEqualTo(oldPersonalities->getObject(oldPIndex))) { oldPersonalities->removeObject(oldPIndex); break; } } } /* Now add the new set of personalities passed in, using existing * copies if we had them in kernel memory already. */ if (newPIterator) { OSDictionary * thisOldPersonality = NULL; // do not release while ( (object = newPIterator->getNextObject()) ) { thisNewPersonality = OSDynamicCast(OSDictionary, object); if (!thisNewPersonality) { IOLog("IOCatalogue::resetAndAddDrivers() encountered non-dictionary; bailing.\n"); result = false; break; } /* Convert common OSString property values to OSSymbols. */ OSKext::uniquePersonalityProperties(thisNewPersonality); /* Add driver personality to catalogue, but if we had a copy already * use that instead so we don't have multiple copies from OSKext instances. */ count = oldPersonalities->getCount(); thisOldPersonality = NULL; while (count--) { thisOldPersonality = (OSDictionary *)oldPersonalities->getObject(count); /* Unlike in other functions, this comparison must be exact! * The catalogue must be able to contain personalities that * are proper supersets of others. * Do not compare just the properties present in one driver * pesonality or the other. */ if (thisNewPersonality->isEqualTo(thisOldPersonality)) { break; } } /* If we found a dup, add the *original* back to the catalogue, * remove it from our bookkeeping list, and continue. * Don't worry about matching on personalities we already had. */ if (count >= 0) { array->setObject(thisOldPersonality); oldPersonalities->removeObject(count); continue; } /* Otherwise add the new personality and mark it for matching. */ array->setObject(thisNewPersonality); AddNewImports(matchSet, thisNewPersonality); } /***** * Now, go through remaining old personalities, which have effectively * been removed, and add them to the match set as necessary. */ count = oldPersonalities->getCount(); while (count--) { /* Static cast here is ok as these dictionaries were already in the catalogue. */ thisOldPersonality = (OSDictionary *)oldPersonalities->getObject(count); AddNewImports(matchSet, thisOldPersonality); } /* Finally, start device matching on all new & removed personalities. */ if (result && doNubMatching && (matchSet->getCount() > 0)) { IOService::catalogNewDrivers(matchSet); generation++; } } IOLockUnlock(lock); finish: if (newPIterator) newPIterator->release(); if (matchSet) matchSet->release(); if (oldPersonalities) oldPersonalities->release(); if (kernelPersonalities) kernelPersonalities->release(); if (errorString) errorString->release(); return result; }