]> git.saurik.com Git - apple/xnu.git/blobdiff - iokit/Kernel/IOCatalogue.cpp
xnu-6153.81.5.tar.gz
[apple/xnu.git] / iokit / Kernel / IOCatalogue.cpp
index c6de3b56c0a9b02bf2e25b3967df639bbfe8e01b..7c0201e4df7c2381f379c5e62bde771231810414 100644 (file)
@@ -1,8 +1,8 @@
 /*
- * Copyright (c) 1998-2006 Apple Inc. All rights reserved.
+ * Copyright (c) 1998-2012 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
- * 
+ *
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
  * unlawful or unlicensed copies of an Apple operating system, or to
  * circumvent, violate, or enable the circumvention or violation of, any
  * terms of an Apple operating system software license agreement.
- * 
+ *
  * Please obtain a copy of the License at
  * http://www.opensource.apple.com/apsl/ and read it before using this file.
- * 
+ *
  * The Original Code and all software distributed under the License are
  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
  * Please see the License for the specific language governing rights and
  * limitations under the License.
- * 
+ *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
  */
 /*
- * Copyright (c) 1998 Apple Inc.  All rights reserved. 
+ * Copyright (c) 1998 Apple Inc.  All rights reserved.
  *
  * HISTORY
  *
@@ -49,6 +49,7 @@ extern "C" {
 #include <libkern/c++/OSUnserialize.h>
 #include <libkern/c++/OSKext.h>
 #include <libkern/OSKextLibPrivate.h>
+#include <libkern/OSDebug.h>
 
 #include <IOKit/IODeviceTreeSupport.h>
 #include <IOKit/IOService.h>
@@ -63,28 +64,16 @@ extern "C" {
 /*********************************************************************
 *********************************************************************/
 
-#define CATALOGTEST 0
-
 IOCatalogue    * gIOCatalogue;
 const OSSymbol * gIOClassKey;
 const OSSymbol * gIOProbeScoreKey;
 const OSSymbol * gIOModuleIdentifierKey;
-IOLock         * gIOCatalogLock;
+const OSSymbol * gIOModuleIdentifierKernelKey;
+IORWLock       * gIOCatalogLock;
 
 #if PRAGMA_MARK
 #pragma mark Utility functions
 #endif
-/*********************************************************************
-* Add a new personality to the set if it has a unique IOResourceMatchKey value.
-* XXX -- svail: This should be optimized.
-* esb - There doesn't seem like any reason to do this - it causes problems
-* esb - when there are more than one loadable driver matching on the same provider class
-*********************************************************************/
-static void
-AddNewImports(OSOrderedSet * set, OSDictionary * dict)
-{
-    set->setObject(dict);
-}
 
 #if PRAGMA_MARK
 #pragma mark IOCatalogue class implementation
@@ -95,179 +84,168 @@ AddNewImports(OSOrderedSet * set, OSDictionary * dict)
 #define super OSObject
 OSDefineMetaClassAndStructors(IOCatalogue, OSObject)
 
+static bool isModuleLoadedNoOSKextLock(OSDictionary *theKexts,
+    OSDictionary *theModuleDict);
+
+
 /*********************************************************************
 *********************************************************************/
-void IOCatalogue::initialize(void)
+void
+IOCatalogue::initialize(void)
 {
-    OSArray              * array;
-    OSString             * errorString;
-    bool                  rc;
+       OSArray              * array;
+       OSString             * errorString;
+       bool                   rc;
+
+       extern const char * gIOKernelConfigTables;
 
-    extern const char * gIOKernelConfigTables;
+       array = OSDynamicCast(OSArray, OSUnserialize(gIOKernelConfigTables, &errorString));
+       if (!array && errorString) {
+               IOLog("KernelConfigTables syntax error: %s\n",
+                   errorString->getCStringNoCopy());
+               errorString->release();
+       }
 
-    array = OSDynamicCast(OSArray, OSUnserialize(gIOKernelConfigTables, &errorString));
-    if (!array && errorString) {
-        IOLog("KernelConfigTables syntax error: %s\n",
-            errorString->getCStringNoCopy());
-        errorString->release();
-    }
+       gIOClassKey                  = OSSymbol::withCStringNoCopy( kIOClassKey );
+       gIOProbeScoreKey             = OSSymbol::withCStringNoCopy( kIOProbeScoreKey );
+       gIOModuleIdentifierKey       = OSSymbol::withCStringNoCopy( kCFBundleIdentifierKey );
+       gIOModuleIdentifierKernelKey = OSSymbol::withCStringNoCopy( kCFBundleIdentifierKernelKey );
 
-    gIOClassKey              = OSSymbol::withCStringNoCopy( kIOClassKey );
-    gIOProbeScoreKey        = OSSymbol::withCStringNoCopy( kIOProbeScoreKey );
-    gIOModuleIdentifierKey   = OSSymbol::withCStringNoCopy( kCFBundleIdentifierKey );
 
-    assert( array && gIOClassKey && gIOProbeScoreKey 
+       assert( array && gIOClassKey && gIOProbeScoreKey
            && gIOModuleIdentifierKey);
 
-    gIOCatalogue = new IOCatalogue;
-    assert(gIOCatalogue);
-    rc = gIOCatalogue->init(array);
-    assert(rc);
-    array->release();
+       gIOCatalogue = new IOCatalogue;
+       assert(gIOCatalogue);
+       rc = gIOCatalogue->init(array);
+       assert(rc);
+       array->release();
 }
 
 /*********************************************************************
 * Initialize the IOCatalog object.
 *********************************************************************/
-bool IOCatalogue::init(OSArray * initArray)
+OSArray *
+IOCatalogue::arrayForPersonality(OSDictionary * dict)
 {
-    OSDictionary         * dict;
-    
-    if ( !super::init() )
-        return false;
-
-    generation = 1;
-    
-    array = initArray;
-    array->retain();
-    kernelTables = OSCollectionIterator::withCollection( array );
-
-    gIOCatalogLock = IOLockAlloc();
-
-    lock     = gIOCatalogLock;
-#if __i386__
-    kld_lock = NULL;
-#endif /* __i386__ */
-
-    kernelTables->reset();
-    while( (dict = (OSDictionary *) kernelTables->getNextObject())) {
-        OSKext::uniquePersonalityProperties(dict);
-        if( 0 == dict->getObject( gIOClassKey ))
-            IOLog("Missing or bad \"%s\" key\n",
-                    gIOClassKey->getCStringNoCopy());
-    }
-
-#if CATALOGTEST
-    AbsoluteTime deadline;
-    clock_interval_to_deadline( 1000, kMillisecondScale );
-    thread_call_func_delayed( ping, this, deadline );
-#endif
+       const OSSymbol * sym;
+
+       sym = OSDynamicCast(OSSymbol, dict->getObject(gIOProviderClassKey));
+       if (!sym) {
+               return NULL;
+       }
 
-    return true;
+       return (OSArray *) personalities->getObject(sym);
 }
 
-/*********************************************************************
-* Release all resources used by IOCatalogue and deallocate.
-* This will probably never be called.
-*********************************************************************/
-void IOCatalogue::free( void )
+void
+IOCatalogue::addPersonality(OSDictionary * dict)
 {
-    if ( array )
-        array->release();
+       const OSSymbol * sym;
+       OSArray * arr;
 
-    if ( kernelTables )
-        kernelTables->release();
-    
-    super::free();
+       sym = OSDynamicCast(OSSymbol, dict->getObject(gIOProviderClassKey));
+       if (!sym) {
+               return;
+       }
+       arr = (OSArray *) personalities->getObject(sym);
+       if (arr) {
+               arr->setObject(dict);
+       } else {
+               arr = OSArray::withObjects((const OSObject **)&dict, 1, 2);
+               personalities->setObject(sym, arr);
+               arr->release();
+       }
 }
 
 /*********************************************************************
+* Initialize the IOCatalog object.
 *********************************************************************/
-#if CATALOGTEST
-
-static int hackLimit;
-enum { kDriversPerIter = 4 };
-
-void
-IOCatalogue::ping(thread_call_param_t arg, thread_call_param_t)
+bool
+IOCatalogue::init(OSArray * initArray)
 {
-    IOCatalogue         * self = (IOCatalogue *) arg;
-    OSOrderedSet         * set;
-    OSDictionary         * table;
-    int                           newLimit;
-
-    set = OSOrderedSet::withCapacity( 1 );
+       OSDictionary         * dict;
+       OSObject * obj;
 
-    IOLockLock( &self->lock );
-
-    for( newLimit = 0; newLimit < kDriversPerIter; newLimit++) {
-       table = (OSDictionary *) self->array->getObject(
-                                       hackLimit + newLimit );
-       if( table) {
-           set->setLastObject( table );
-
-           OSSymbol * sym = (OSSymbol *) table->getObject(gIOClassKey);
-           kprintf("enabling %s\n", sym->getCStringNoCopy());
-
-       } else {
-           newLimit--;
-           break;
+       if (!super::init()) {
+               return false;
        }
-    }
 
-    IOService::catalogNewDrivers( set );
+       generation = 1;
+
+       personalities = OSDictionary::withCapacity(32);
+       personalities->setOptions(OSCollection::kSort, OSCollection::kSort);
+       for (unsigned int idx = 0; (obj = initArray->getObject(idx)); idx++) {
+               dict = OSDynamicCast(OSDictionary, obj);
+               if (!dict) {
+                       continue;
+               }
+               OSKext::uniquePersonalityProperties(dict);
+               if (NULL == dict->getObject( gIOClassKey )) {
+                       IOLog("Missing or bad \"%s\" key\n",
+                           gIOClassKey->getCStringNoCopy());
+                       continue;
+               }
+               dict->setObject("KernelConfigTable", kOSBooleanTrue);
+               addPersonality(dict);
+       }
 
-    hackLimit += newLimit;
-    self->generation++;
+       gIOCatalogLock = IORWLockAlloc();
+       lock = gIOCatalogLock;
 
-    IOLockUnlock( &self->lock );
+       return true;
+}
 
-    if( kDriversPerIter == newLimit) {
-        AbsoluteTime deadline;
-        clock_interval_to_deadline(500, kMillisecondScale);
-        thread_call_func_delayed(ping, this, deadline);
-    }
+/*********************************************************************
+* Release all resources used by IOCatalogue and deallocate.
+* This will probably never be called.
+*********************************************************************/
+void
+IOCatalogue::free( void )
+{
+       panic("");
 }
-#endif
 
 /*********************************************************************
 *********************************************************************/
 OSOrderedSet *
 IOCatalogue::findDrivers(
-    IOService * service,
-    SInt32 * generationCount)
+       IOService * service,
+       SInt32 * generationCount)
 {
-    OSDictionary         * nextTable;
-    OSOrderedSet         * set;
-    OSString             * imports;
-
-    set = OSOrderedSet::withCapacity( 1, IOServiceOrdering,
-                                      (void *)gIOProbeScoreKey );
-    if( !set )
-       return( 0 );
-
-    IOLockLock(lock);
-    kernelTables->reset();
+       OSDictionary         * nextTable;
+       OSOrderedSet         * set;
+       OSArray              * array;
+       const OSMetaClass    * meta;
+       unsigned int           idx;
+
+       set = OSOrderedSet::withCapacity( 1, IOServiceOrdering,
+           (void *)gIOProbeScoreKey );
+       if (!set) {
+               return NULL;
+       }
 
-#if CATALOGTEST
-    int hackIndex = 0;
-#endif
-    while( (nextTable = (OSDictionary *) kernelTables->getNextObject())) {
-#if CATALOGTEST
-       if( hackIndex++ > hackLimit)
-           break;
-#endif
-        imports = OSDynamicCast( OSString,
-                       nextTable->getObject( gIOProviderClassKey ));
-       if( imports && service->metaCast( imports ))
-            set->setObject( nextTable );
-    }
+       IORWLockRead(lock);
+
+       meta = service->getMetaClass();
+       while (meta) {
+               array = (OSArray *) personalities->getObject(meta->getClassNameSymbol());
+               if (array) {
+                       for (idx = 0; (nextTable = (OSDictionary *) array->getObject(idx)); idx++) {
+                               set->setObject(nextTable);
+                       }
+               }
+               if (meta == &IOService::gMetaClass) {
+                       break;
+               }
+               meta = meta->getSuperClass();
+       }
 
-    *generationCount = getGenerationCount();
+       *generationCount = getGenerationCount();
 
-    IOLockUnlock(lock);
+       IORWLockUnlock(lock);
 
-    return( set );
+       return set;
 }
 
 /*********************************************************************
@@ -275,31 +253,48 @@ IOCatalogue::findDrivers(
 *********************************************************************/
 OSOrderedSet *
 IOCatalogue::findDrivers(
-    OSDictionary * matching,
-    SInt32 * generationCount)
+       OSDictionary * matching,
+       SInt32 * generationCount)
 {
-    OSDictionary         * dict;
-    OSOrderedSet         * set;
-
-    OSKext::uniquePersonalityProperties(matching);
-
-    set = OSOrderedSet::withCapacity( 1, IOServiceOrdering,
-                                      (void *)gIOProbeScoreKey );
-
-    IOLockLock(lock);
-    kernelTables->reset();
-    while ( (dict = (OSDictionary *) kernelTables->getNextObject()) ) {
+       OSCollectionIterator * iter;
+       OSDictionary         * dict;
+       OSOrderedSet         * set;
+       OSArray              * array;
+       const OSSymbol       * key;
+       unsigned int           idx;
+
+       OSKext::uniquePersonalityProperties(matching);
+
+       set = OSOrderedSet::withCapacity( 1, IOServiceOrdering,
+           (void *)gIOProbeScoreKey );
+       if (!set) {
+               return NULL;
+       }
+       iter = OSCollectionIterator::withCollection(personalities);
+       if (!iter) {
+               set->release();
+               return NULL;
+       }
 
-       /* This comparison must be done with only the keys in the
-        * "matching" dict to enable general searches.
-        */
-        if ( dict->isEqualTo(matching, matching) )
-            set->setObject(dict);
-    }
-    *generationCount = getGenerationCount();
-    IOLockUnlock(lock);
+       IORWLockRead(lock);
+       while ((key = (const OSSymbol *) iter->getNextObject())) {
+               array = (OSArray *) personalities->getObject(key);
+               if (array) {
+                       for (idx = 0; (dict = (OSDictionary *) array->getObject(idx)); idx++) {
+                               /* This comparison must be done with only the keys in the
+                                * "matching" dict to enable general searches.
+                                */
+                               if (dict->isEqualTo(matching, matching)) {
+                                       set->setObject(dict);
+                               }
+                       }
+               }
+       }
+       *generationCount = getGenerationCount();
+       IORWLockUnlock(lock);
 
-    return set;
+       iter->release();
+       return set;
 }
 
 /*********************************************************************
@@ -313,95 +308,105 @@ IOCatalogue::findDrivers(
 * 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
+IOCatalogue::addDrivers(
+       OSArray * drivers,
+       bool doNubMatching)
 {
-    bool                   result = false;
-    OSCollectionIterator * iter = NULL;       // must release
-    OSOrderedSet         * set = NULL;        // must release
-    OSObject             * object = 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;
-    }
-
-   /* Start with success; clear it on an error.
-    */
-    result = true;
-
-    IOLockLock(lock);
-    while ( (object = iter->getNextObject()) ) {
-    
-        // xxx Deleted OSBundleModuleDemand check; will handle in other ways for SL
-
-        OSDictionary * personality = OSDynamicCast(OSDictionary, object);
-
-        SInt count;
-
-        if (!personality) {
-            IOLog("IOCatalogue::addDrivers() encountered non-dictionary; bailing.\n");
-            result = false;
-            break;
-        }
-
-        OSKext::uniquePersonalityProperties(personality);
-        
-        // 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 (personality->isEqualTo(driver)) {
-                break;
-            }
-        }
-        if (count >= 0) {
-            // its a dup
-            continue;
-        }
-        
-        result = array->setObject(personality);
-        if (!result) {
-            break;
-        }
-        
-        AddNewImports(set, personality);
-    }
-    // Start device matching.
-    if (result && doNubMatching && (set->getCount() > 0)) {
-        IOService::catalogNewDrivers(set);
-        generation++;
-    }
-    IOLockUnlock(lock);
+       bool                   result = false;
+       OSCollectionIterator * iter = NULL;   // must release
+       OSOrderedSet         * set = NULL;    // must release
+       OSObject             * object = 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;
+       }
+
+       /* Start with success; clear it on an error.
+        */
+       result = true;
+
+       IORWLockWrite(lock);
+       while ((object = iter->getNextObject())) {
+               // xxx Deleted OSBundleModuleDemand check; will handle in other ways for SL
+
+               OSDictionary * personality = OSDynamicCast(OSDictionary, object);
+
+               SInt count;
+
+               if (!personality) {
+                       IOLog("IOCatalogue::addDrivers() encountered non-dictionary; bailing.\n");
+                       result = false;
+                       break;
+               }
+
+               OSKext::uniquePersonalityProperties(personality);
+
+               // Add driver personality to catalogue.
+
+               OSArray * array = arrayForPersonality(personality);
+               if (!array) {
+                       addPersonality(personality);
+               } else {
+                       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
+                                * personality or the other.
+                                */
+                               if (personality->isEqualTo(driver)) {
+                                       break;
+                               }
+                       }
+                       if (count >= 0) {
+                               // its a dup
+                               continue;
+                       }
+                       result = array->setObject(personality);
+                       if (!result) {
+                               break;
+                       }
+               }
+
+               set->setObject(personality);
+       }
+       // Start device matching.
+       if (result && doNubMatching && (set->getCount() > 0)) {
+               IOService::catalogNewDrivers(set);
+               generation++;
+       }
+       IORWLockUnlock(lock);
 
 finish:
-    if (set)  set->release();
-    if (iter) iter->release();
+       if (set) {
+               set->release();
+       }
+       if (iter) {
+               iter->release();
+       }
 
-    return result;
+       return result;
 }
 
 /*********************************************************************
@@ -410,604 +415,648 @@ finish:
 *********************************************************************/
 bool
 IOCatalogue::removeDrivers(
-    OSDictionary * matching,
-    bool doNubMatching)
+       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;
-    }
-
-    OSKext::uniquePersonalityProperties( 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;
+       OSOrderedSet         * set;
+       OSCollectionIterator * iter;
+       OSDictionary         * dict;
+       OSArray              * array;
+       const OSSymbol       * key;
+       unsigned int           idx;
+
+       if (!matching) {
+               return false;
+       }
+
+       set = OSOrderedSet::withCapacity(10,
+           IOServiceOrdering,
+           (void *)gIOProbeScoreKey);
+       if (!set) {
+               return false;
+       }
+       iter = OSCollectionIterator::withCollection(personalities);
+       if (!iter) {
+               set->release();
+               return false;
+       }
+
+       IORWLockWrite(lock);
+       while ((key = (const OSSymbol *) iter->getNextObject())) {
+               array = (OSArray *) personalities->getObject(key);
+               if (array) {
+                       for (idx = 0; (dict = (OSDictionary *) array->getObject(idx)); idx++) {
+                               /* This comparison must be done with only the keys in the
+                                * "matching" dict to enable general searches.
+                                */
+                               if (dict->isEqualTo(matching, matching)) {
+                                       set->setObject(dict);
+                                       array->removeObject(idx);
+                                       idx--;
+                               }
+                       }
+               }
+               // Start device matching.
+               if (doNubMatching && (set->getCount() > 0)) {
+                       IOService::catalogNewDrivers(set);
+                       generation++;
+               }
+       }
+       IORWLockUnlock(lock);
+
+       set->release();
+       iter->release();
+
+       return true;
 }
 
 // Return the generation count.
-SInt32 IOCatalogue::getGenerationCount(void) const
+SInt32
+IOCatalogue::getGenerationCount(void) const
 {
-    return( generation );
+       return generation;
 }
 
-bool IOCatalogue::isModuleLoaded(OSString * moduleName) const
+// Check to see if kernel module has been loaded already, and request its load.
+bool
+IOCatalogue::isModuleLoaded(OSDictionary * driver, OSObject ** kextRef) const
 {
-    return isModuleLoaded(moduleName->getCStringNoCopy());
-}
+       OSString * moduleName = NULL;
+       OSString * publisherName = NULL;
+       OSReturn   ret;
 
-bool IOCatalogue::isModuleLoaded(const char * moduleName) const
-{
-    OSReturn ret;
-    ret = OSKext::loadKextWithIdentifier(moduleName);
-    if (kOSKextReturnDeferred == ret) {
-        // a request has been queued but the module isn't necessarily 
-        // loaded yet, so stall.
-        return false;
-    }
-    // module is present or never will be 
-    return true;
-}
+       if (kextRef) {
+               *kextRef = NULL;
+       }
+       if (!driver) {
+               return false;
+       }
 
-// Check to see if module has been loaded already.
-bool IOCatalogue::isModuleLoaded(OSDictionary * driver) const
-{
-    OSString             * moduleName = NULL;
-    OSString             * publisherName = NULL;
-
-    if ( !driver )
-        return false;
-
-    /* The personalities of codeless kexts often contain the bundle ID of the
-     * kext they reference, and not the bundle ID of the codeless kext itself.
-     * The prelinked kernel needs to know the bundle ID of the codeless kext
-     * so it can include these personalities, so OSKext stores that bundle ID
-     * in the IOPersonalityPublisher key, and we record it as requested here.
-     */
-    publisherName = OSDynamicCast(OSString, 
-        driver->getObject(kIOPersonalityPublisherKey));
-    OSKext::recordIdentifierRequest(publisherName);
-
-    moduleName = OSDynamicCast(OSString, driver->getObject(gIOModuleIdentifierKey));
-    if ( moduleName )
-        return isModuleLoaded(moduleName);
-
-   /* If a personality doesn't hold the "CFBundleIdentifier" key
-    * it is assumed to be an "in-kernel" driver.
-    */
-    return true;
+       /* The personalities of codeless kexts often contain the bundle ID of the
+        * kext they reference, and not the bundle ID of the codeless kext itself.
+        * The prelinked kernel needs to know the bundle ID of the codeless kext
+        * so it can include these personalities, so OSKext stores that bundle ID
+        * in the IOPersonalityPublisher key, and we record it as requested here.
+        */
+       publisherName = OSDynamicCast(OSString,
+           driver->getObject(kIOPersonalityPublisherKey));
+       OSKext::recordIdentifierRequest(publisherName);
+
+       moduleName = OSDynamicCast(OSString, driver->getObject(gIOModuleIdentifierKernelKey));
+       if (moduleName) {
+               ret = OSKext::loadKextWithIdentifier(moduleName, kextRef);
+               if (kOSKextReturnDeferred == ret) {
+                       // a request has been queued but the module isn't necessarily
+                       // loaded yet, so stall.
+                       return false;
+               }
+               OSString *moduleDextName = OSDynamicCast(OSString, driver->getObject(gIOModuleIdentifierKey));
+               if (moduleDextName && !(moduleName->isEqualTo(moduleDextName))) {
+                       OSObject *dextRef = NULL;
+                       ret = OSKext::loadKextWithIdentifier(moduleDextName, &dextRef);
+                       OSSafeReleaseNULL(dextRef);
+               }
+               // module is present or never will be
+               return true;
+       }
+
+       /* If a personality doesn't hold the "CFBundleIdentifier" or "CFBundleIdentifierKernel" key
+        * it is assumed to be an "in-kernel" driver.
+        */
+       return true;
 }
 
 /* This function is called after a module has been loaded.
  * Is invoked from user client call, ultimately from IOKitLib's
  * IOCatalogueModuleLoaded(). Sent from kextd.
  */
-void IOCatalogue::moduleHasLoaded(OSString * moduleName)
+void
+IOCatalogue::moduleHasLoaded(const OSSymbol * moduleName)
 {
-    OSDictionary * dict;
-
-    dict = OSDictionary::withCapacity(2);
-    dict->setObject(gIOModuleIdentifierKey, moduleName);
-    startMatching(dict);
-    dict->release();
+       startMatching(moduleName);
 
-    (void) OSKext::considerRebuildOfPrelinkedKernel(moduleName);
+       (void) OSKext::setDeferredLoadSucceeded();
+       (void) OSKext::considerRebuildOfPrelinkedKernel();
 }
 
-void IOCatalogue::moduleHasLoaded(const char * moduleName)
+void
+IOCatalogue::moduleHasLoaded(const char * moduleName)
 {
-    OSString * name;
+       const OSSymbol * name;
 
-    name = OSString::withCString(moduleName);
-    moduleHasLoaded(name);
-    name->release();
+       name = OSSymbol::withCString(moduleName);
+       moduleHasLoaded(name);
+       name->release();
 }
 
 // xxx - return is really OSReturn/kern_return_t
-IOReturn IOCatalogue::unloadModule(OSString * moduleName) const
+IOReturn
+IOCatalogue::unloadModule(OSString * moduleName) const
 {
-    return OSKext::removeKextWithIdentifier(moduleName->getCStringNoCopy());
+       return OSKext::removeKextWithIdentifier(moduleName->getCStringNoCopy());
 }
 
-static IOReturn _terminateDrivers(OSDictionary * matching)
+IOReturn
+IOCatalogue::_terminateDrivers(OSDictionary * matching)
 {
-    OSDictionary         * dict;
-    OSIterator           * iter;
-    IOService            * service;
-    IOReturn               ret;
-
-    if ( !matching )
-        return kIOReturnBadArgument;
-
-    ret = kIOReturnSuccess;
-    dict = 0;
-    iter = IORegistryIterator::iterateOver(gIOServicePlane,
-                                kIORegistryIterateRecursively);
-    if ( !iter )
-        return kIOReturnNoMemory;
-
-    OSKext::uniquePersonalityProperties( matching );
-
-    // terminate instances.
-    do {
-        iter->reset();
-        while( (service = (IOService *)iter->getNextObject()) ) {
-            dict = service->getPropertyTable();
-            if ( !dict )
-                continue;
-
-           /* Terminate only for personalities that match the matching dictionary.
-            * This comparison must be done with only the keys in the
-            * "matching" dict to enable general matching.
-            */
-            if ( !dict->isEqualTo(matching, matching) )
-                 continue;
-
-            if ( !service->terminate(kIOServiceRequired|kIOServiceSynchronous) ) {
-                ret = kIOReturnUnsupported;
-                break;
-            }
-        }
-    } while( !service && !iter->isValid());
-    iter->release();
-
-    return ret;
-}
+       OSDictionary         * dict;
+       OSIterator           * iter;
+       IOService            * service;
+       IOReturn               ret;
 
-static IOReturn _removeDrivers( OSArray * array, OSDictionary * matching )
-{
-    OSCollectionIterator * tables;
-    OSDictionary         * dict;
-    OSArray              * arrayCopy;
-    IOReturn               ret = kIOReturnSuccess;
+       if (!matching) {
+               return kIOReturnBadArgument;
+       }
 
-    // remove configs from catalog.
+       ret = kIOReturnSuccess;
+       dict = NULL;
+       iter = IORegistryIterator::iterateOver(gIOServicePlane,
+           kIORegistryIterateRecursively);
+       if (!iter) {
+               return kIOReturnNoMemory;
+       }
 
-    arrayCopy = OSArray::withCapacity(100);
-    if ( !arrayCopy )
-        return kIOReturnNoMemory;
+       OSKext::uniquePersonalityProperties( matching );
+
+       // terminate instances.
+       do {
+               iter->reset();
+               while ((service = (IOService *)iter->getNextObject())) {
+                       dict = service->getPropertyTable();
+                       if (!dict) {
+                               continue;
+                       }
+
+                       /* Terminate only for personalities that match the matching dictionary.
+                        * This comparison must be done with only the keys in the
+                        * "matching" dict to enable general matching.
+                        */
+                       if (!dict->isEqualTo(matching, matching)) {
+                               continue;
+                       }
+
+                       if (!service->terminate(kIOServiceRequired | kIOServiceSynchronous)) {
+                               ret = kIOReturnUnsupported;
+                               break;
+                       }
+               }
+       } while (!service && !iter->isValid());
+       iter->release();
+
+       return ret;
+}
 
-    tables = OSCollectionIterator::withCollection(arrayCopy);
-    arrayCopy->release();
-    if ( !tables )
-        return kIOReturnNoMemory;
+IOReturn
+IOCatalogue::_removeDrivers(OSDictionary * matching)
+{
+       IOReturn               ret = kIOReturnSuccess;
+       OSCollectionIterator * iter;
+       OSDictionary         * dict;
+       OSArray              * array;
+       const OSSymbol       * key;
+       unsigned int           idx;
+
+       // remove configs from catalog.
+
+       iter = OSCollectionIterator::withCollection(personalities);
+       if (!iter) {
+               return kIOReturnNoMemory;
+       }
 
-    arrayCopy->merge(array);
-    array->flushCollection();
-    tables->reset();
-    while ( (dict = (OSDictionary *)tables->getNextObject()) ) {
+       while ((key = (const OSSymbol *) iter->getNextObject())) {
+               array = (OSArray *) personalities->getObject(key);
+               if (array) {
+                       for (idx = 0; (dict = (OSDictionary *) array->getObject(idx)); idx++) {
+                               /* Remove from the catalogue's array any personalities
+                                * that match the matching dictionary.
+                                * This comparison must be done with only the keys in the
+                                * "matching" dict to enable general matching.
+                                */
+                               if (dict->isEqualTo(matching, matching)) {
+                                       array->removeObject(idx);
+                                       idx--;
+                               }
+                       }
+               }
+       }
+       iter->release();
 
-       /* Remove from the catalogue's array any personalities
-        * that match the matching dictionary.
-        * This comparison must be done with only the keys in the
-        * "matching" dict to enable general matching.
-        */
-        if ( dict->isEqualTo(matching, matching) )
-            continue;
+       return ret;
+}
 
-        array->setObject(dict);
-    }
+IOReturn
+IOCatalogue::terminateDrivers(OSDictionary * matching)
+{
+       IOReturn ret;
 
-    tables->release();
+       ret = _terminateDrivers(matching);
+       IORWLockWrite(lock);
+       if (kIOReturnSuccess == ret) {
+               ret = _removeDrivers(matching);
+       }
+       IORWLockUnlock(lock);
 
-    return ret;
+       return ret;
 }
 
-IOReturn IOCatalogue::terminateDrivers(OSDictionary * matching)
+IOReturn
+IOCatalogue::terminateDriversForModule(
+       OSString * moduleName,
+       bool unload)
 {
-    IOReturn ret;
+       IOReturn ret;
+       OSDictionary * dict;
+       bool isLoaded = false;
+
+       /* Check first if the kext currently has any linkage dependents;
+        * in such a case the unload would fail so let's not terminate any
+        * IOServices (since doing so typically results in a panic when there
+        * are loaded dependencies). Note that we aren't locking the kext here
+        * so it might lose or gain dependents by the time we call unloadModule();
+        * I think that's ok, our unload can fail if a kext comes in on top of
+        * this one even after we've torn down IOService objects. Conversely,
+        * if we fail the unload here and then lose a library, the autounload
+        * thread will get us in short order.
+        */
+       if (OSKext::isKextWithIdentifierLoaded(moduleName->getCStringNoCopy())) {
+               isLoaded = true;
+
+               if (!OSKext::canUnloadKextWithIdentifier(moduleName,
+                   /* checkClasses */ false)) {
+                       ret = kOSKextReturnInUse;
+                       goto finish;
+               }
+       }
+       dict = OSDictionary::withCapacity(1);
+       if (!dict) {
+               ret = kIOReturnNoMemory;
+               goto finish;
+       }
 
-    ret = _terminateDrivers(matching);
-    IOLockLock(lock);
-    if (kIOReturnSuccess == ret)
-       ret = _removeDrivers(array, matching);
-    kernelTables->reset();
-    IOLockUnlock(lock);
+       dict->setObject(gIOModuleIdentifierKey, moduleName);
 
-    return ret;
+       ret = _terminateDrivers(dict);
+
+       /* No goto between IOLock calls!
+        */
+       IORWLockWrite(lock);
+       if (kIOReturnSuccess == ret) {
+               ret = _removeDrivers(dict);
+       }
+
+       // Unload the module itself.
+       if (unload && isLoaded && ret == kIOReturnSuccess) {
+               ret = unloadModule(moduleName);
+       }
+
+       IORWLockUnlock(lock);
+
+       dict->release();
+
+finish:
+       return ret;
 }
 
-IOReturn IOCatalogue::terminateDriversForModule(
-    OSString * moduleName,
-    bool unload)
+IOReturn
+IOCatalogue::terminateDriversForModule(
+       const char * moduleName,
+       bool unload)
 {
-    IOReturn ret;
-    OSDictionary * dict;
-    bool isLoaded = false;
-
-   /* Check first if the kext currently has any linkage dependents;
-    * in such a case the unload would fail so let's not terminate any
-    * IOServices (since doing so typically results in a panic when there
-    * are loaded dependencies). Note that we aren't locking the kext here
-    * so it might lose or gain dependents by the time we call unloadModule();
-    * I think that's ok, our unload can fail if a kext comes in on top of
-    * this one even after we've torn down IOService objects. Conversely,
-    * if we fail the unload here and then lose a library, the autounload
-    * thread will get us in short order.
-    */
-    if (OSKext::isKextWithIdentifierLoaded(moduleName->getCStringNoCopy())) {
-    
-        isLoaded = true;
-
-        if (!OSKext::canUnloadKextWithIdentifier(moduleName,
-            /* checkClasses */ false)) {
-            ret = kOSKextReturnInUse;
-            goto finish;
-        }
-    }
-    dict = OSDictionary::withCapacity(1);
-    if (!dict) {
-        ret = kIOReturnNoMemory;
-        goto finish;
-    }
-
-    dict->setObject(gIOModuleIdentifierKey, moduleName);
-
-    ret = _terminateDrivers(dict);
-    
-   /* No goto between IOLock calls!
-    */
-    IOLockLock(lock);
-    if (kIOReturnSuccess == ret) {
-        ret = _removeDrivers(array, dict);
-    }
-    kernelTables->reset();
-
-    // Unload the module itself.
-    if (unload && isLoaded && ret == kIOReturnSuccess) {
-        ret = unloadModule(moduleName);
-    }
-
-    IOLockUnlock(lock);
-
-    dict->release();
+       OSString * name;
+       IOReturn ret;
 
-finish:
-    return ret;
+       name = OSString::withCString(moduleName);
+       if (!name) {
+               return kIOReturnNoMemory;
+       }
+
+       ret = terminateDriversForModule(name, unload);
+       name->release();
+
+       return ret;
 }
 
-IOReturn IOCatalogue::terminateDriversForModule(
-    const char * moduleName,
-    bool unload)
+#if defined(__i386__) || defined(__x86_64__)
+bool
+IOCatalogue::startMatching( OSDictionary * matching )
 {
-    OSString * name;
-    IOReturn ret;
+       OSOrderedSet         * set;
+
+       if (!matching) {
+               return false;
+       }
+
+       set = OSOrderedSet::withCapacity(10, IOServiceOrdering,
+           (void *)gIOProbeScoreKey);
+       if (!set) {
+               return false;
+       }
 
-    name = OSString::withCString(moduleName);
-    if ( !name )
-        return kIOReturnNoMemory;
+       IORWLockRead(lock);
+
+       personalities->iterateObjects(^bool (const OSSymbol * key, OSObject * value) {
+               OSArray      * array;
+               OSDictionary * dict;
+               unsigned int   idx;
+
+               array = (OSArray *) value;
+               for (idx = 0; (dict = (OSDictionary *) array->getObject(idx)); idx++) {
+                       /* This comparison must be done with only the keys in the
+                        * "matching" dict to enable general matching.
+                        */
+                       if (dict->isEqualTo(matching, matching)) {
+                               set->setObject(dict);
+                       }
+               }
+               return false;
+       });
+
+       // Start device matching.
+       if (set->getCount() > 0) {
+               IOService::catalogNewDrivers(set);
+               generation++;
+       }
+
+       IORWLockUnlock(lock);
 
-    ret = terminateDriversForModule(name, unload);
-    name->release();
+       set->release();
 
-    return ret;
+       return true;
 }
+#endif /* defined(__i386__) || defined(__x86_64__) */
 
-bool IOCatalogue::startMatching( OSDictionary * matching )
+bool
+IOCatalogue::startMatching( const OSSymbol * moduleName )
 {
-    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;
+       OSOrderedSet         * set;
+
+       if (!moduleName) {
+               return false;
+       }
+
+       set = OSOrderedSet::withCapacity(10, IOServiceOrdering,
+           (void *)gIOProbeScoreKey);
+       if (!set) {
+               return false;
+       }
+
+       IORWLockRead(lock);
+
+       personalities->iterateObjects(^bool (const OSSymbol * key, OSObject * value) {
+               OSArray      * array;
+               OSDictionary * dict;
+               OSObject     * obj;
+               unsigned int   idx;
+
+               array = (OSArray *) value;
+               for (idx = 0; (dict = (OSDictionary *) array->getObject(idx)); idx++) {
+                       obj = dict->getObject(gIOModuleIdentifierKernelKey);
+                       if (obj && moduleName->isEqualTo(obj)) {
+                               set->setObject(dict);
+                       }
+               }
+               return false;
+       });
+
+       // Start device matching.
+       if (set->getCount() > 0) {
+               IOService::catalogNewDrivers(set);
+               generation++;
+       }
+
+       IORWLockUnlock(lock);
+
+       set->release();
+
+       return true;
 }
 
-void IOCatalogue::reset(void)
+void
+IOCatalogue::reset(void)
 {
-    IOCatalogue::resetAndAddDrivers(/* no drivers; true reset */ NULL,
-        /* doMatching */ false);
-    return;
+       IOCatalogue::resetAndAddDrivers(/* no drivers; true reset */ NULL,
+           /* doMatching */ false);
+       return;
 }
 
-bool IOCatalogue::resetAndAddDrivers(OSArray * drivers, bool doNubMatching)
+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);
+       bool                   result              = false;
+       OSArray              * newPersonalities    = NULL;// do not release
+       OSCollectionIterator * iter                = NULL;// must release
+       OSOrderedSet         * matchSet            = NULL;// must release
+       const OSSymbol       * key;
+       OSArray              * array;
+       OSDictionary         * thisNewPersonality   = NULL;// do not release
+       OSDictionary         * thisOldPersonality   = NULL;// do not release
+       OSDictionary         * myKexts              = NULL;// must release
+       signed int             idx, newIdx;
+
+       if (drivers) {
+               newPersonalities = OSDynamicCast(OSArray, drivers);
+               if (!newPersonalities) {
+                       goto finish;
+               }
+       }
+       matchSet = OSOrderedSet::withCapacity(10, IOServiceOrdering,
+           (void *)gIOProbeScoreKey);
+       if (!matchSet) {
+               goto finish;
+       }
+       iter = OSCollectionIterator::withCollection(personalities);
+       if (!iter) {
+               goto finish;
+       }
+
+       /* need copy of loaded kexts so we can check if for loaded modules without
+        * taking the OSKext lock.  There is a potential of deadlocking if we get
+        * an OSKext via the normal path.  See 14672140.
+        */
+       myKexts = OSKext::copyKexts();
+
+       result = true;
+
+       IOLog("Resetting IOCatalogue.\n");
+
+       /* No goto finish from here to unlock.
+        */
+       IORWLockWrite(lock);
+
+       while ((key = (const OSSymbol *) iter->getNextObject())) {
+               array = (OSArray *) personalities->getObject(key);
+               if (!array) {
+                       continue;
+               }
+
+               for (idx = 0;
+                   (thisOldPersonality = (OSDictionary *) array->getObject(idx));
+                   idx++) {
+                       if (thisOldPersonality->getObject("KernelConfigTable")) {
+                               continue;
+                       }
+                       thisNewPersonality = NULL;
+
+                       if (newPersonalities) {
+                               for (newIdx = 0;
+                                   (thisNewPersonality = (OSDictionary *) newPersonalities->getObject(newIdx));
+                                   newIdx++) {
+                                       /* 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
+                                        * personality or the other.
+                                        */
+                                       if (OSDynamicCast(OSDictionary, thisNewPersonality) == NULL) {
+                                               /* skip thisNewPersonality if it is not an OSDictionary */
+                                               continue;
+                                       }
+                                       if (thisNewPersonality->isEqualTo(thisOldPersonality)) {
+                                               break;
+                                       }
+                               }
+                       }
+                       if (thisNewPersonality) {
+                               // dup, ignore
+                               newPersonalities->removeObject(newIdx);
+                       } else {
+                               // not in new set - remove
+                               // only remove dictionary if this module in not loaded - 9953845
+                               if (isModuleLoadedNoOSKextLock(myKexts, thisOldPersonality) == false) {
+                                       if (matchSet) {
+                                               matchSet->setObject(thisOldPersonality);
+                                       }
+                                       array->removeObject(idx);
+                                       idx--;
+                               }
+                       }
+               } // for...
+       } // while...
+
+       // add new
+       if (newPersonalities) {
+               for (newIdx = 0;
+                   (thisNewPersonality = (OSDictionary *) newPersonalities->getObject(newIdx));
+                   newIdx++) {
+                       if (OSDynamicCast(OSDictionary, thisNewPersonality) == NULL) {
+                               /* skip thisNewPersonality if it is not an OSDictionary */
+                               continue;
+                       }
+
+                       OSKext::uniquePersonalityProperties(thisNewPersonality);
+                       addPersonality(thisNewPersonality);
+                       matchSet->setObject(thisNewPersonality);
+               }
+       }
+
+       /* Finally, start device matching on all new & removed personalities.
+        */
+       if (result && doNubMatching && (matchSet->getCount() > 0)) {
+               IOService::catalogNewDrivers(matchSet);
+               generation++;
+       }
+
+       IORWLockUnlock(lock);
 
 finish:
-    if (newPIterator) newPIterator->release();
-    if (matchSet) matchSet->release();
-    if (oldPersonalities) oldPersonalities->release();
-    if (kernelPersonalities) kernelPersonalities->release();
-    if (errorString) errorString->release();
+       if (matchSet) {
+               matchSet->release();
+       }
+       if (iter) {
+               iter->release();
+       }
+       if (myKexts) {
+               myKexts->release();
+       }
 
-    return result;
+       return result;
 }
 
-bool IOCatalogue::serialize(OSSerialize * s) const
+bool
+IOCatalogue::serialize(OSSerialize * s) const
 {
-    if ( !s )
-        return false;
+       if (!s) {
+               return false;
+       }
 
-    return super::serialize(s);
+       return super::serialize(s);
 }
 
-bool IOCatalogue::serializeData(IOOptionBits kind, OSSerialize * s) const
+bool
+IOCatalogue::serializeData(IOOptionBits kind, OSSerialize * s) const
 {
-    kern_return_t kr = kIOReturnSuccess;
+       kern_return_t kr = kIOReturnSuccess;
 
-    switch ( kind )
-    {
-        case kIOCatalogGetContents:
-            if (!array->serialize(s))
-                kr = kIOReturnNoMemory;
-            break;
+       switch (kind) {
+       case kIOCatalogGetContents:
+               kr = KERN_NOT_SUPPORTED;
+               break;
 
-        case kIOCatalogGetModuleDemandList:
-            kr = KERN_NOT_SUPPORTED;
-            break;
+       case kIOCatalogGetModuleDemandList:
+               kr = KERN_NOT_SUPPORTED;
+               break;
 
-        case kIOCatalogGetCacheMissList:
-            kr = KERN_NOT_SUPPORTED;
-            break;
+       case kIOCatalogGetCacheMissList:
+               kr = KERN_NOT_SUPPORTED;
+               break;
 
-        case kIOCatalogGetROMMkextList:
-            kr = KERN_NOT_SUPPORTED;
-            break;
+       case kIOCatalogGetROMMkextList:
+               kr = KERN_NOT_SUPPORTED;
+               break;
 
-        default:
-            kr = kIOReturnBadArgument;
-            break;
-    }
+       default:
+               kr = kIOReturnBadArgument;
+               break;
+       }
 
-    return kr;
+       return kr;
 }
 
+/* isModuleLoadedNoOSKextLock - used to check to see if a kext is loaded
+ * without taking the OSKext lock.  We use this to avoid the problem
+ * where taking the IOCatalog lock then the OSKext lock will dealock when
+ * a kext load or unload is happening at the same time as IOCatalog changing.
+ *
+ * theKexts - is a dictionary of current kexts (from OSKext::copyKexts) with
+ *      key set to the kext bundle ID and value set to an OSKext object
+ * theModuleDict - is an IOKit personality dictionary for a given module (kext)
+ */
+static bool
+isModuleLoadedNoOSKextLock(OSDictionary *theKexts,
+    OSDictionary *theModuleDict)
+{
+       bool                    myResult = false;
+       const OSString *        myBundleID = NULL;// do not release
+       OSKext *                myKext = NULL;  // do not release
 
-#if PRAGMA_MARK
-#pragma mark Obsolete Kext Loading Stuff
-#endif
-/*********************************************************************
-**********************************************************************
-***                  BINARY COMPATIBILITY SECTION                  ***
-**********************************************************************
-**********************************************************************
-* These functions are no longer used are necessary for C++ binary
-* compatibility on i386.
-**********************************************************************/
-#if __i386__
+       if (theKexts == NULL || theModuleDict == NULL) {
+               return myResult;
+       }
 
-bool IOCatalogue::recordStartupExtensions(void)
-{  return false;  }
+       // gIOModuleIdentifierKey is "CFBundleIdentifier"
+       myBundleID = OSDynamicCast(OSString,
+           theModuleDict->getObject(gIOModuleIdentifierKey));
+       if (myBundleID == NULL) {
+               return myResult;
+       }
+
+       myKext = OSDynamicCast(OSKext, theKexts->getObject(myBundleID->getCStringNoCopy()));
+       if (myKext) {
+               myResult = myKext->isLoaded();
+       }
 
-bool IOCatalogue::addExtensionsFromArchive(OSData * mkext)
-{  return KERN_NOT_SUPPORTED;  }
+       return myResult;
+}
 
-kern_return_t IOCatalogue::removeKernelLinker(void)
-{  return KERN_NOT_SUPPORTED;  }
 
-#endif /* __i386__ */
+#if PRAGMA_MARK
+#pragma mark Obsolete Kext Loading Stuff
+#endif
+/*********************************************************************
+ **********************************************************************
+ ***                  BINARY COMPATIBILITY SECTION                  ***
+ **********************************************************************
+ **********************************************************************
+ * These functions are no longer used are necessary for C++ binary
+ * compatibility on i386.
+ **********************************************************************/