]> git.saurik.com Git - apple/xnu.git/blobdiff - iokit/Kernel/IOCatalogue.cpp
xnu-7195.101.1.tar.gz
[apple/xnu.git] / iokit / Kernel / IOCatalogue.cpp
index 6f8f07890de39d3a1daf4ca263a1c16f20168d0f..a57b083a7213be51dda569145d995fb69856bce8 100644 (file)
@@ -38,6 +38,8 @@
  * Version 2.0.
  */
 
+#define IOKIT_ENABLE_SHARED_PTR
+
 extern "C" {
 #include <machine/machine_routines.h>
 #include <libkern/kernel_mach_header.h>
@@ -48,6 +50,7 @@ extern "C" {
 #include <libkern/c++/OSContainers.h>
 #include <libkern/c++/OSUnserialize.h>
 #include <libkern/c++/OSKext.h>
+#include <libkern/c++/OSSharedPtr.h>
 #include <libkern/OSKextLibPrivate.h>
 #include <libkern/OSDebug.h>
 
@@ -57,6 +60,7 @@ extern "C" {
 
 #include <IOKit/IOLib.h>
 #include <IOKit/assert.h>
+#include <IOKit/IOKitKeysPrivate.h>
 
 #if PRAGMA_MARK
 #pragma mark Internal Declarations
@@ -64,11 +68,12 @@ extern "C" {
 /*********************************************************************
 *********************************************************************/
 
-IOCatalogue    * gIOCatalogue;
-const OSSymbol * gIOClassKey;
-const OSSymbol * gIOProbeScoreKey;
-const OSSymbol * gIOModuleIdentifierKey;
-const OSSymbol * gIOModuleIdentifierKernelKey;
+OSSharedPtr<IOCatalogue> gIOCatalogue;
+OSSharedPtr<const OSSymbol> gIOClassKey;
+OSSharedPtr<const OSSymbol> gIOProbeScoreKey;
+OSSharedPtr<const OSSymbol> gIOModuleIdentifierKey;
+OSSharedPtr<const OSSymbol> gIOModuleIdentifierKernelKey;
+OSSharedPtr<const OSSymbol> gIOHIDInterfaceClassName;
 IORWLock       * gIOCatalogLock;
 
 #if PRAGMA_MARK
@@ -93,33 +98,32 @@ static bool isModuleLoadedNoOSKextLock(OSDictionary *theKexts,
 void
 IOCatalogue::initialize(void)
 {
-       OSArray              * array;
-       OSString             * errorString;
+       OSSharedPtr<OSArray> array;
+       OSSharedPtr<OSString> errorString;
        bool                   rc;
 
        extern const char * gIOKernelConfigTables;
 
-       array = OSDynamicCast(OSArray, OSUnserialize(gIOKernelConfigTables, &errorString));
+       array = OSDynamicPtrCast<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 );
+       gIOHIDInterfaceClassName     = OSSymbol::withCStringNoCopy( "IOHIDInterface" );
 
 
        assert( array && gIOClassKey && gIOProbeScoreKey
            && gIOModuleIdentifierKey);
 
-       gIOCatalogue = new IOCatalogue;
+       gIOCatalogue = OSMakeShared<IOCatalogue>();
        assert(gIOCatalogue);
-       rc = gIOCatalogue->init(array);
+       rc = gIOCatalogue->init(array.get());
        assert(rc);
-       array->release();
 }
 
 /*********************************************************************
@@ -152,9 +156,8 @@ IOCatalogue::addPersonality(OSDictionary * dict)
        if (arr) {
                arr->setObject(dict);
        } else {
-               arr = OSArray::withObjects((const OSObject **)&dict, 1, 2);
-               personalities->setObject(sym, arr);
-               arr->release();
+               OSSharedPtr<OSArray> sharedArr = OSArray::withObjects((const OSObject **)&dict, 1, 2);
+               personalities->setObject(sym, sharedArr.get());
        }
 }
 
@@ -181,7 +184,7 @@ IOCatalogue::init(OSArray * initArray)
                        continue;
                }
                OSKext::uniquePersonalityProperties(dict);
-               if (NULL == dict->getObject( gIOClassKey )) {
+               if (NULL == dict->getObject( gIOClassKey.get())) {
                        IOLog("Missing or bad \"%s\" key\n",
                            gIOClassKey->getCStringNoCopy());
                        continue;
@@ -208,19 +211,19 @@ IOCatalogue::free( void )
 
 /*********************************************************************
 *********************************************************************/
-OSOrderedSet *
+OSPtr<OSOrderedSet>
 IOCatalogue::findDrivers(
        IOService * service,
        SInt32 * generationCount)
 {
        OSDictionary         * nextTable;
-       OSOrderedSet         * set;
+       OSSharedPtr<OSOrderedSet> set;
        OSArray              * array;
        const OSMetaClass    * meta;
        unsigned int           idx;
 
        set = OSOrderedSet::withCapacity( 1, IOServiceOrdering,
-           (void *)gIOProbeScoreKey );
+           (void *)(gIOProbeScoreKey.get()));
        if (!set) {
                return NULL;
        }
@@ -251,14 +254,14 @@ IOCatalogue::findDrivers(
 /*********************************************************************
 * Is personality already in the catalog?
 *********************************************************************/
-OSOrderedSet *
+OSPtr<OSOrderedSet>
 IOCatalogue::findDrivers(
        OSDictionary * matching,
        SInt32 * generationCount)
 {
-       OSCollectionIterator * iter;
+       OSSharedPtr<OSCollectionIterator> iter;
        OSDictionary         * dict;
-       OSOrderedSet         * set;
+       OSSharedPtr<OSOrderedSet> set;
        OSArray              * array;
        const OSSymbol       * key;
        unsigned int           idx;
@@ -266,14 +269,13 @@ IOCatalogue::findDrivers(
        OSKext::uniquePersonalityProperties(matching);
 
        set = OSOrderedSet::withCapacity( 1, IOServiceOrdering,
-           (void *)gIOProbeScoreKey );
+           (void *)(gIOProbeScoreKey.get()));
        if (!set) {
                return NULL;
        }
-       iter = OSCollectionIterator::withCollection(personalities);
+       iter = OSCollectionIterator::withCollection(personalities.get());
        if (!iter) {
-               set->release();
-               return NULL;
+               return nullptr;
        }
 
        IORWLockRead(lock);
@@ -293,7 +295,6 @@ IOCatalogue::findDrivers(
        *generationCount = getGenerationCount();
        IORWLockUnlock(lock);
 
-       iter->release();
        return set;
 }
 
@@ -315,8 +316,8 @@ IOCatalogue::addDrivers(
        bool doNubMatching)
 {
        bool                   result = false;
-       OSCollectionIterator * iter = NULL;   // must release
-       OSOrderedSet         * set = NULL;    // must release
+       OSSharedPtr<OSOrderedSet> set;
+       OSSharedPtr<OSCollectionIterator> iter;
        OSObject             * object = NULL;   // do not release
        OSArray              * persons = NULL;// do not release
 
@@ -326,7 +327,7 @@ IOCatalogue::addDrivers(
        }
 
        set = OSOrderedSet::withCapacity( 10, IOServiceOrdering,
-           (void *)gIOProbeScoreKey );
+           (void *)(gIOProbeScoreKey.get()));
        if (!set) {
                goto finish;
        }
@@ -393,51 +394,34 @@ IOCatalogue::addDrivers(
        }
        // Start device matching.
        if (result && doNubMatching && (set->getCount() > 0)) {
-               IOService::catalogNewDrivers(set);
+               IOService::catalogNewDrivers(set.get());
                generation++;
        }
        IORWLockUnlock(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)
+IOCatalogue::removeDrivers(bool doNubMatching, bool (^shouldRemove)(OSDictionary *personality))
 {
-       OSOrderedSet         * set;
-       OSCollectionIterator * iter;
+       OSSharedPtr<OSOrderedSet> set;
+       OSSharedPtr<OSCollectionIterator> iter;
        OSDictionary         * dict;
        OSArray              * array;
        const OSSymbol       * key;
        unsigned int           idx;
 
-       if (!matching) {
-               return false;
-       }
-
        set = OSOrderedSet::withCapacity(10,
            IOServiceOrdering,
-           (void *)gIOProbeScoreKey);
+           (void *)(gIOProbeScoreKey.get()));
        if (!set) {
                return false;
        }
-       iter = OSCollectionIterator::withCollection(personalities);
+       iter = OSCollectionIterator::withCollection(personalities.get());
        if (!iter) {
-               set->release();
                return false;
        }
 
@@ -446,10 +430,7 @@ IOCatalogue::removeDrivers(
                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)) {
+                               if (shouldRemove(dict)) {
                                        set->setObject(dict);
                                        array->removeObject(idx);
                                        idx--;
@@ -458,18 +439,35 @@ IOCatalogue::removeDrivers(
                }
                // Start device matching.
                if (doNubMatching && (set->getCount() > 0)) {
-                       IOService::catalogNewDrivers(set);
+                       IOService::catalogNewDrivers(set.get());
                        generation++;
                }
        }
        IORWLockUnlock(lock);
 
-       set->release();
-       iter->release();
-
        return true;
 }
 
+/*********************************************************************
+* Remove drivers from the catalog which match the
+* properties in the matching dictionary.
+*********************************************************************/
+bool
+IOCatalogue::removeDrivers(
+       OSDictionary * matching,
+       bool doNubMatching)
+{
+       if (!matching) {
+               return false;
+       }
+       return removeDrivers(doNubMatching, ^(OSDictionary *dict) {
+               /* This comparison must be done with only the keys in the
+                * "matching" dict to enable general searches.
+                */
+               return dict->isEqualTo(matching, matching);
+       });
+}
+
 // Return the generation count.
 SInt32
 IOCatalogue::getGenerationCount(void) const
@@ -502,7 +500,7 @@ IOCatalogue::isModuleLoaded(OSDictionary * driver, OSObject ** kextRef) const
            driver->getObject(kIOPersonalityPublisherKey));
        OSKext::recordIdentifierRequest(publisherName);
 
-       moduleName = OSDynamicCast(OSString, driver->getObject(gIOModuleIdentifierKernelKey));
+       moduleName = OSDynamicCast(OSString, driver->getObject(gIOModuleIdentifierKernelKey.get()));
        if (moduleName) {
                ret = OSKext::loadKextWithIdentifier(moduleName, kextRef);
                if (kOSKextReturnDeferred == ret) {
@@ -510,11 +508,10 @@ IOCatalogue::isModuleLoaded(OSDictionary * driver, OSObject ** kextRef) const
                        // loaded yet, so stall.
                        return false;
                }
-               OSString *moduleDextName = OSDynamicCast(OSString, driver->getObject(gIOModuleIdentifierKey));
+               OSString *moduleDextName = OSDynamicCast(OSString, driver->getObject(gIOModuleIdentifierKey.get()));
                if (moduleDextName && !(moduleName->isEqualTo(moduleDextName))) {
-                       OSObject *dextRef = NULL;
-                       ret = OSKext::loadKextWithIdentifier(moduleDextName, &dextRef);
-                       OSSafeReleaseNULL(dextRef);
+                       OSSharedPtr<OSObject> dextRef;
+                       ret = OSKext::loadKextWithIdentifier(moduleDextName, dextRef);
                }
                // module is present or never will be
                return true;
@@ -526,6 +523,15 @@ IOCatalogue::isModuleLoaded(OSDictionary * driver, OSObject ** kextRef) const
        return true;
 }
 
+bool
+IOCatalogue::isModuleLoaded(OSDictionary * driver, OSSharedPtr<OSObject>& kextRef) const
+{
+       OSObject* kextRefRaw = NULL;
+       bool result = isModuleLoaded(driver, &kextRefRaw);
+       kextRef.reset(kextRefRaw, OSNoRetain);
+       return result;
+}
+
 /* This function is called after a module has been loaded.
  * Is invoked from user client call, ultimately from IOKitLib's
  * IOCatalogueModuleLoaded(). Sent from kextd.
@@ -542,11 +548,10 @@ IOCatalogue::moduleHasLoaded(const OSSymbol * moduleName)
 void
 IOCatalogue::moduleHasLoaded(const char * moduleName)
 {
-       const OSSymbol * name;
+       OSSharedPtr<const OSSymbol> name;
 
        name = OSSymbol::withCString(moduleName);
-       moduleHasLoaded(name);
-       name->release();
+       moduleHasLoaded(name.get());
 }
 
 // xxx - return is really OSReturn/kern_return_t
@@ -560,7 +565,7 @@ IOReturn
 IOCatalogue::terminateDrivers(OSDictionary * matching, io_name_t className)
 {
        OSDictionary         * dict;
-       OSIterator           * iter;
+       OSSharedPtr<OSIterator> iter;
        IOService            * service;
        IOReturn               ret;
 
@@ -573,7 +578,7 @@ IOCatalogue::terminateDrivers(OSDictionary * matching, io_name_t className)
        }
 
        if (matching) {
-               OSKext::uniquePersonalityProperties( matching );
+               OSKext::uniquePersonalityProperties( matching, false );
        }
 
        // terminate instances.
@@ -598,23 +603,33 @@ IOCatalogue::terminateDrivers(OSDictionary * matching, io_name_t className)
                        }
 
                        OSKext     * kext;
+                       OSSharedPtr<OSString> dextBundleID;
                        const char * bundleIDStr;
                        OSObject   * prop;
                        bool         okToTerminate;
+                       bool         isDext = service->hasUserServer();
                        for (okToTerminate = true;;) {
-                               kext = service->getMetaClass()->getKext();
-                               if (!kext) {
-                                       break;
+                               if (isDext) {
+                                       dextBundleID = OSDynamicPtrCast<OSString>(service->copyProperty(gIOModuleIdentifierKey.get()));
+                                       if (!dextBundleID) {
+                                               break;
+                                       }
+                                       bundleIDStr = dextBundleID->getCStringNoCopy();
+                               } else {
+                                       kext = service->getMetaClass()->getKext();
+                                       if (!kext) {
+                                               break;
+                                       }
+                                       bundleIDStr = kext->getIdentifierCString();
+                                       prop = kext->getPropertyForHostArch(kOSBundleAllowUserTerminateKey);
+                                       if (prop) {
+                                               okToTerminate = (kOSBooleanTrue == prop);
+                                               break;
+                                       }
                                }
-                               bundleIDStr = kext->getIdentifierCString();
                                if (!bundleIDStr) {
                                        break;
                                }
-                               prop = kext->getPropertyForHostArch(kOSBundleAllowUserTerminateKey);
-                               if (prop) {
-                                       okToTerminate = (kOSBooleanTrue == prop);
-                                       break;
-                               }
                                if (!strcmp(kOSKextKernelIdentifier, bundleIDStr)) {
                                        okToTerminate = false;
                                        break;
@@ -636,13 +651,16 @@ IOCatalogue::terminateDrivers(OSDictionary * matching, io_name_t className)
                                        break;
                                }
                        }
-                       if (!service->terminate(kIOServiceRequired | kIOServiceSynchronous)) {
+                       IOOptionBits terminateOptions = kIOServiceRequired | kIOServiceSynchronous;
+                       if (isDext) {
+                               terminateOptions |= kIOServiceTerminateNeedWillTerminate;
+                       }
+                       if (!service->terminate(terminateOptions)) {
                                ret = kIOReturnUnsupported;
                                break;
                        }
                }
        } while (!service && !iter->isValid());
-       iter->release();
 
        return ret;
 }
@@ -651,7 +669,7 @@ IOReturn
 IOCatalogue::_removeDrivers(OSDictionary * matching)
 {
        IOReturn               ret = kIOReturnSuccess;
-       OSCollectionIterator * iter;
+       OSSharedPtr<OSCollectionIterator> iter;
        OSDictionary         * dict;
        OSArray              * array;
        const OSSymbol       * key;
@@ -659,7 +677,7 @@ IOCatalogue::_removeDrivers(OSDictionary * matching)
 
        // remove configs from catalog.
 
-       iter = OSCollectionIterator::withCollection(personalities);
+       iter = OSCollectionIterator::withCollection(personalities.get());
        if (!iter) {
                return kIOReturnNoMemory;
        }
@@ -680,7 +698,6 @@ IOCatalogue::_removeDrivers(OSDictionary * matching)
                        }
                }
        }
-       iter->release();
 
        return ret;
 }
@@ -703,14 +720,99 @@ IOCatalogue::terminateDrivers(OSDictionary * matching)
        return ret;
 }
 
+IOReturn
+IOCatalogue::terminateDriversForUserspaceReboot()
+{
+       IOReturn                ret = kIOReturnSuccess;
+
+#if !NO_KEXTD
+       OSSharedPtr<OSIterator> iter;
+       IOService             * service;
+       bool                    isDeferredMatch;
+       bool                    isDext;
+       IOOptionBits            terminateOptions;
+
+       iter = IORegistryIterator::iterateOver(gIOServicePlane,
+           kIORegistryIterateRecursively);
+       if (!iter) {
+               return kIOReturnNoMemory;
+       }
+
+       do {
+               iter->reset();
+               while ((service = (IOService *)iter->getNextObject())) {
+                       isDeferredMatch = service->propertyHasValue(gIOMatchDeferKey, kOSBooleanTrue);
+                       isDext = service->hasUserServer();
+                       if (isDeferredMatch || isDext) {
+                               if (isDext) {
+                                       OSSharedPtr<OSString> name = OSDynamicPtrCast<OSString>(service->copyProperty(gIOUserServerNameKey));
+                                       const char *userServerName = NULL;
+                                       if (name) {
+                                               userServerName = name->getCStringNoCopy();
+                                       }
+                                       IOLog("terminating service %s-0x%llx [dext %s]\n", service->getName(), service->getRegistryEntryID(), userServerName ? userServerName : "(null)");
+                               } else {
+                                       OSKext *kext = service->getMetaClass()->getKext();
+                                       const char *bundleID = NULL;
+                                       if (kext) {
+                                               bundleID = kext->getIdentifierCString();
+                                       }
+                                       IOLog("terminating service %s-0x%llx [kext %s]\n", service->getName(), service->getRegistryEntryID(), bundleID ? bundleID : "(null)");
+                               }
+                               terminateOptions = kIOServiceRequired | kIOServiceSynchronous;
+                               if (isDext) {
+                                       terminateOptions |= kIOServiceTerminateNeedWillTerminate;
+                               }
+                               if (!service->terminate(terminateOptions)) {
+                                       IOLog("failed to terminate service %s-0x%llx\n", service->getName(), service->getRegistryEntryID());
+                                       ret = kIOReturnUnsupported;
+                                       break;
+                               }
+                       }
+               }
+       } while (!service && !iter->isValid());
+#endif
+
+       return ret;
+}
+
+IOReturn
+IOCatalogue::resetAfterUserspaceReboot(void)
+{
+       OSSharedPtr<OSIterator> iter;
+       IOService             * service;
+
+       iter = IORegistryIterator::iterateOver(gIOServicePlane,
+           kIORegistryIterateRecursively);
+       if (!iter) {
+               return kIOReturnNoMemory;
+       }
+
+       do {
+               iter->reset();
+               while ((service = (IOService *)iter->getNextObject())) {
+                       service->resetRematchProperties();
+               }
+       } while (!service && !iter->isValid());
+
+       /* Remove all dext personalities */
+       removeDrivers(false, ^(OSDictionary *dict) {
+               return dict->getObject(gIOUserServerNameKey) != NULL;
+       });
+
+       return kIOReturnSuccess;
+}
+
 IOReturn
 IOCatalogue::terminateDriversForModule(
        OSString * moduleName,
        bool unload)
 {
        IOReturn ret;
-       OSDictionary * dict;
+       OSSharedPtr<OSDictionary> dict;
+       OSSharedPtr<OSKext> kext;
        bool isLoaded = false;
+       bool isDext = 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
@@ -731,32 +833,40 @@ IOCatalogue::terminateDriversForModule(
                        goto finish;
                }
        }
+       kext = OSKext::lookupKextWithIdentifier(moduleName->getCStringNoCopy());
+       if (kext) {
+               isDext = kext->isDriverKit();
+       }
+
        dict = OSDictionary::withCapacity(1);
        if (!dict) {
                ret = kIOReturnNoMemory;
                goto finish;
        }
 
-       dict->setObject(gIOModuleIdentifierKey, moduleName);
+       dict->setObject(gIOModuleIdentifierKey.get(), moduleName);
 
-       ret = terminateDrivers(dict, NULL);
+       ret = terminateDrivers(dict.get(), NULL);
 
-       /* No goto between IOLock calls!
-        */
-       IORWLockWrite(lock);
-       if (kIOReturnSuccess == ret) {
-               ret = _removeDrivers(dict);
-       }
+       if (isDext) {
+               /* Force rematching after removing personalities. Dexts are never considered to be "loaded" (from OSKext),
+                * so we can't call unloadModule() to remove personalities and start rematching. */
+               removeDrivers(dict.get(), true);
+       } else {
+               /* No goto between IOLock calls!
+                */
+               IORWLockWrite(lock);
+               if (kIOReturnSuccess == ret) {
+                       ret = _removeDrivers(dict.get());
+               }
 
-       // Unload the module itself.
-       if (unload && isLoaded && ret == kIOReturnSuccess) {
-               ret = unloadModule(moduleName);
+               // Unload the module itself.
+               if (unload && isLoaded && ret == kIOReturnSuccess) {
+                       ret = unloadModule(moduleName);
+               }
+               IORWLockUnlock(lock);
        }
 
-       IORWLockUnlock(lock);
-
-       dict->release();
-
 finish:
        return ret;
 }
@@ -766,7 +876,7 @@ IOCatalogue::terminateDriversForModule(
        const char * moduleName,
        bool unload)
 {
-       OSString * name;
+       OSSharedPtr<OSString> name;
        IOReturn ret;
 
        name = OSString::withCString(moduleName);
@@ -774,8 +884,7 @@ IOCatalogue::terminateDriversForModule(
                return kIOReturnNoMemory;
        }
 
-       ret = terminateDriversForModule(name, unload);
-       name->release();
+       ret = terminateDriversForModule(name.get(), unload);
 
        return ret;
 }
@@ -784,14 +893,14 @@ IOCatalogue::terminateDriversForModule(
 bool
 IOCatalogue::startMatching( OSDictionary * matching )
 {
-       OSOrderedSet         * set;
+       OSSharedPtr<OSOrderedSet> set;
 
        if (!matching) {
                return false;
        }
 
        set = OSOrderedSet::withCapacity(10, IOServiceOrdering,
-           (void *)gIOProbeScoreKey);
+           (void *)(gIOProbeScoreKey.get()));
        if (!set) {
                return false;
        }
@@ -817,14 +926,12 @@ IOCatalogue::startMatching( OSDictionary * matching )
 
        // Start device matching.
        if (set->getCount() > 0) {
-               IOService::catalogNewDrivers(set);
+               IOService::catalogNewDrivers(set.get());
                generation++;
        }
 
        IORWLockUnlock(lock);
 
-       set->release();
-
        return true;
 }
 #endif /* defined(__i386__) || defined(__x86_64__) */
@@ -832,46 +939,112 @@ IOCatalogue::startMatching( OSDictionary * matching )
 bool
 IOCatalogue::startMatching( const OSSymbol * moduleName )
 {
-       OSOrderedSet         * set;
+       OSSharedPtr<OSOrderedSet> set;
+       OSSharedPtr<OSKext>       kext;
+       OSSharedPtr<OSArray>      servicesToTerminate;
 
        if (!moduleName) {
                return false;
        }
 
        set = OSOrderedSet::withCapacity(10, IOServiceOrdering,
-           (void *)gIOProbeScoreKey);
+           (void *)(gIOProbeScoreKey.get()));
        if (!set) {
                return false;
        }
 
        IORWLockRead(lock);
 
+       kext = OSKext::lookupKextWithIdentifier(moduleName->getCStringNoCopy());
+       if (kext && kext->isDriverKit()) {
+               /* We're here because kernelmanagerd called IOCatalogueModuleLoaded after launching a dext.
+                * Determine what providers the dext would match against. If there's something already attached
+                * to the provider, terminate it.
+                *
+                * This is only safe to do for HID dexts.
+                */
+               OSSharedPtr<OSArray> dextPersonalities = kext->copyPersonalitiesArray();
+
+               if (!dextPersonalities) {
+                       return false;
+               }
+
+               servicesToTerminate = OSArray::withCapacity(1);
+               if (!servicesToTerminate) {
+                       return false;
+               }
+
+               dextPersonalities->iterateObjects(^bool (OSObject * obj) {
+                       OSDictionary * personality = OSDynamicCast(OSDictionary, obj);
+                       OSSharedPtr<OSIterator> iter;
+                       IOService * provider;
+                       OSSharedPtr<IOService> service;
+                       const OSSymbol * category;
+
+                       if (personality) {
+                               category = OSDynamicCast(OSSymbol, personality->getObject(gIOMatchCategoryKey));
+                               if (!category) {
+                                       category = gIODefaultMatchCategoryKey;
+                               }
+                               iter = IOService::getMatchingServices(personality);
+
+                               while (iter && (provider = OSDynamicCast(IOService, iter->getNextObject()))) {
+                                       if (provider->metaCast(gIOHIDInterfaceClassName.get()) != NULL) {
+                                               service.reset(provider->copyClientWithCategory(category), OSNoRetain);
+                                               if (service) {
+                                                       servicesToTerminate->setObject(service);
+                                               }
+                                       }
+                               }
+                       }
+
+                       return false;
+               });
+       }
+
        personalities->iterateObjects(^bool (const OSSymbol * key, OSObject * value) {
                OSArray      * array;
                OSDictionary * dict;
-               OSObject     * obj;
+               OSObject     * moduleIdentifierKernel;
+               OSObject     * moduleIdentifier;
                unsigned int   idx;
 
                array = (OSArray *) value;
                for (idx = 0; (dict = (OSDictionary *) array->getObject(idx)); idx++) {
-                       obj = dict->getObject(gIOModuleIdentifierKernelKey);
-                       if (obj && moduleName->isEqualTo(obj)) {
+                       moduleIdentifierKernel = dict->getObject(gIOModuleIdentifierKernelKey.get());
+                       moduleIdentifier = dict->getObject(gIOModuleIdentifierKey.get());
+                       if ((moduleIdentifierKernel && moduleName->isEqualTo(moduleIdentifierKernel)) ||
+                       (moduleIdentifier && moduleName->isEqualTo(moduleIdentifier))) {
                                set->setObject(dict);
                        }
                }
                return false;
        });
 
+       if (servicesToTerminate) {
+               servicesToTerminate->iterateObjects(^bool (OSObject * obj) {
+                       IOService * service = OSDynamicCast(IOService, obj);
+                       if (service) {
+                               IOOptionBits terminateOptions = kIOServiceRequired;
+                               if (service->hasUserServer()) {
+                                       terminateOptions |= kIOServiceTerminateNeedWillTerminate;
+                               }
+                               if (!service->terminate(terminateOptions)) {
+                                       IOLog("%s: failed to terminate service %s-0x%qx with options %08llx for new dext %s\n", __FUNCTION__, service->getName(), service->getRegistryEntryID(), (long long)terminateOptions, moduleName->getCStringNoCopy());
+                               }
+                       }
+                       return false;
+               });
+       }
+
        // Start device matching.
        if (set->getCount() > 0) {
-               IOService::catalogNewDrivers(set);
+               IOService::catalogNewDrivers(set.get());
                generation++;
        }
 
        IORWLockUnlock(lock);
 
-       set->release();
-
        return true;
 }
 
@@ -888,13 +1061,13 @@ IOCatalogue::resetAndAddDrivers(OSArray * drivers, bool doNubMatching)
 {
        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
+       OSSharedPtr<OSDictionary> myKexts;
+       OSSharedPtr<OSCollectionIterator> iter;
+       OSSharedPtr<OSOrderedSet> matchSet;
        signed int             idx, newIdx;
 
        if (drivers) {
@@ -904,11 +1077,11 @@ IOCatalogue::resetAndAddDrivers(OSArray * drivers, bool doNubMatching)
                }
        }
        matchSet = OSOrderedSet::withCapacity(10, IOServiceOrdering,
-           (void *)gIOProbeScoreKey);
+           (void *)(gIOProbeScoreKey.get()));
        if (!matchSet) {
                goto finish;
        }
-       iter = OSCollectionIterator::withCollection(personalities);
+       iter = OSCollectionIterator::withCollection(personalities.get());
        if (!iter) {
                goto finish;
        }
@@ -966,7 +1139,7 @@ IOCatalogue::resetAndAddDrivers(OSArray * drivers, bool doNubMatching)
                        } else {
                                // not in new set - remove
                                // only remove dictionary if this module in not loaded - 9953845
-                               if (isModuleLoadedNoOSKextLock(myKexts, thisOldPersonality) == false) {
+                               if (isModuleLoadedNoOSKextLock(myKexts.get(), thisOldPersonality) == false) {
                                        if (matchSet) {
                                                matchSet->setObject(thisOldPersonality);
                                        }
@@ -996,22 +1169,13 @@ IOCatalogue::resetAndAddDrivers(OSArray * drivers, bool doNubMatching)
        /* Finally, start device matching on all new & removed personalities.
         */
        if (result && doNubMatching && (matchSet->getCount() > 0)) {
-               IOService::catalogNewDrivers(matchSet);
+               IOService::catalogNewDrivers(matchSet.get());
                generation++;
        }
 
        IORWLockUnlock(lock);
 
 finish:
-       if (matchSet) {
-               matchSet->release();
-       }
-       if (iter) {
-               iter->release();
-       }
-       if (myKexts) {
-               myKexts->release();
-       }
 
        return result;
 }
@@ -1079,7 +1243,7 @@ isModuleLoadedNoOSKextLock(OSDictionary *theKexts,
 
        // gIOModuleIdentifierKey is "CFBundleIdentifier"
        myBundleID = OSDynamicCast(OSString,
-           theModuleDict->getObject(gIOModuleIdentifierKey));
+           theModuleDict->getObject(gIOModuleIdentifierKey.get()));
        if (myBundleID == NULL) {
                return myResult;
        }