Loading...
iokit/Kernel/IOCatalogue.cpp xnu-12377.101.15 xnu-201.19
--- xnu/xnu-12377.101.15/iokit/Kernel/IOCatalogue.cpp
+++ xnu/xnu-201.19/iokit/Kernel/IOCatalogue.cpp
@@ -1,1422 +1,890 @@
 /*
- * Copyright (c) 1998-2012 Apple Inc. All rights reserved.
+ * Copyright (c) 1998-2000 Apple Computer, 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
- * compliance with the License. The rights granted to you under the License
- * may not be used to create, or enable the creation or redistribution of,
- * 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
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License").  You may not use this file except in compliance with the
+ * License.  Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ * 
+ * This 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,
  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * 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@
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
  */
 /*
- * Copyright (c) 1998 Apple Inc.  All rights reserved.
+ * Copyright (c) 1998 Apple Computer, Inc.  All rights reserved. 
  *
  * HISTORY
  *
  */
-/*
- * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce
- * support for mandatory and extensible security protections.  This notice
- * is included in support of clause 2.2 (b) of the Apple Public License,
- * Version 2.0.
- */
-
-#define IOKIT_ENABLE_SHARED_PTR
-
-extern "C" {
-#include <libkern/kernel_mach_header.h>
-#include <kern/host.h>
-#include <security/mac_data.h>
-};
-
-#include <machine/machine_routines.h>
-#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>
 
 #include <IOKit/IODeviceTreeSupport.h>
 #include <IOKit/IOService.h>
+#include <libkern/c++/OSContainers.h>
 #include <IOKit/IOCatalogue.h>
+#include <libkern/c++/OSUnserialize.h>
+extern "C" {
+#include <machine/machine_routines.h>
+#include <mach/kmod.h>
+#include <mach-o/mach_header.h>
+};
 
 #include <IOKit/IOLib.h>
+
 #include <IOKit/assert.h>
-#include <IOKit/IOKitKeysPrivate.h>
-
-#if PRAGMA_MARK
-#pragma mark Internal Declarations
+
+
+extern "C" {
+int IODTGetLoaderInfo( char *key, void **infoAddr, int *infoSize );
+extern void IODTFreeLoaderInfo( char *key, void *infoAddr, int infoSize );
+extern void OSRuntimeUnloadCPPForSegment(
+    struct segment_command * segment);
+};
+
+
+/*****
+ * At startup these function pointers are set to use the libsa in-kernel
+ * linker for recording and loading kmods. Once the root filesystem
+ * is available, the kmod_load_function pointer gets switched to point
+ * at the kmod_load_extension() function built into the kernel, and the
+ * others are set to zero. Those two functions must *always* be checked
+ * before being invoked.
+ */
+extern "C" {
+kern_return_t (*kmod_load_function)(char *extension_name) =
+    &kmod_load_extension;
+bool (*record_startup_extensions_function)(void) = 0;
+bool (*add_from_mkext_function)(OSData * mkext) = 0;
+void (*remove_startup_extension_function)(const char * name) = 0;
+};
+
+
+/*****
+ * A few parts of IOCatalogue require knowledge of
+ * whether the in-kernel linker is present. This
+ * variable is set by libsa's bootstrap code.
+ */
+int kernelLinkerPresent = 0;
+
+
+#define super OSObject
+#define kModuleKey "CFBundleIdentifier"
+
+OSDefineMetaClassAndStructors(IOCatalogue, OSObject)
+
+#define CATALOGTEST 0
+
+IOCatalogue                   * gIOCatalogue;
+const OSSymbol                * gIOClassKey;
+const OSSymbol                * gIOProbeScoreKey;
+
+static void UniqueProperties( OSDictionary * dict )
+{
+    OSString             * data;
+
+    data = OSDynamicCast( OSString, dict->getObject( gIOClassKey ));
+    if( data) {
+        const OSSymbol *classSymbol = OSSymbol::withString(data);
+
+        dict->setObject( gIOClassKey, (OSSymbol *) classSymbol);
+        classSymbol->release();
+    }
+
+    data = OSDynamicCast( OSString, dict->getObject( gIOMatchCategoryKey ));
+    if( data) {
+        const OSSymbol *classSymbol = OSSymbol::withString(data);
+
+        dict->setObject( gIOMatchCategoryKey, (OSSymbol *) classSymbol);
+        classSymbol->release();
+    }
+}
+
+void IOCatalogue::initialize( void )
+{
+    OSArray              * array;
+    OSString             * errorString;
+    bool		   rc;
+
+    extern const char * gIOKernelConfigTables;
+
+    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 );
+    assert( array && gIOClassKey && gIOProbeScoreKey);
+
+    gIOCatalogue = new IOCatalogue;
+    assert(gIOCatalogue);
+    rc = gIOCatalogue->init(array);
+    assert(rc);
+    array->release();
+}
+
+// Initialize the IOCatalog object.
+bool IOCatalogue::init(OSArray * initArray)
+{
+    IORegistryEntry      * entry;
+    OSDictionary         * dict;
+    
+    if ( !super::init() )
+        return false;
+
+    generation = 1;
+    
+    array = initArray;
+    array->retain();
+    kernelTables = OSCollectionIterator::withCollection( array );
+
+    lock = IOLockAlloc();
+    kld_lock = IOLockAlloc();
+
+    kernelTables->reset();
+    while( (dict = (OSDictionary *) kernelTables->getNextObject())) {
+        UniqueProperties(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
+
+    entry = IORegistryEntry::getRegistryRoot();
+    if ( entry )
+        entry->setProperty(kIOCatalogueKey, this);
+
+    return true;
+}
+
+// Release all resources used by IOCatalogue and deallocate.
+// This will probably never be called.
+void IOCatalogue::free( void )
+{
+    if ( array )
+        array->release();
+
+    if ( kernelTables )
+        kernelTables->release();
+    
+    super::free();
+}
+
+#if CATALOGTEST
+
+static int hackLimit;
+
+enum { kDriversPerIter = 4 };
+
+void IOCatalogue::ping( thread_call_param_t arg, thread_call_param_t)
+{
+    IOCatalogue 	 * self = (IOCatalogue *) arg;
+    OSOrderedSet         * set;
+    OSDictionary         * table;
+    int	                   newLimit;
+
+    set = OSOrderedSet::withCapacity( 1 );
+
+    IOTakeLock( &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;
+	}
+    }
+
+    IOService::catalogNewDrivers( set );
+
+    hackLimit += newLimit;
+    self->generation++;
+
+    IOUnlock( &self->lock );
+
+    if( kDriversPerIter == newLimit) {
+        AbsoluteTime deadline;
+        clock_interval_to_deadline( 500, kMillisecondScale );
+        thread_call_func_delayed( ping, this, deadline );
+    }
+}
+#endif
+
+OSOrderedSet * IOCatalogue::findDrivers( IOService * service,
+					SInt32 * generationCount )
+{
+    OSDictionary         * nextTable;
+    OSOrderedSet         * set;
+    OSString             * imports;
+
+    set = OSOrderedSet::withCapacity( 1, IOServiceOrdering,
+                                      (void *)gIOProbeScoreKey );
+    if( !set )
+	return( 0 );
+
+    IOTakeLock( lock );
+    kernelTables->reset();
+
+#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 );
+    }
+
+    *generationCount = getGenerationCount();
+
+    IOUnlock( lock );
+
+    return( set );
+}
+
+// Is personality already in the catalog?
+OSOrderedSet * IOCatalogue::findDrivers( OSDictionary * matching,
+                                         SInt32 * generationCount)
+{
+    OSDictionary         * dict;
+    OSOrderedSet         * set;
+
+    UniqueProperties(matching);
+
+    set = OSOrderedSet::withCapacity( 1, IOServiceOrdering,
+                                      (void *)gIOProbeScoreKey );
+
+    IOTakeLock( lock );
+    kernelTables->reset();
+    while ( (dict = (OSDictionary *) kernelTables->getNextObject()) ) {
+        if ( dict->isEqualTo(matching, matching) )
+            set->setObject(dict);
+    }
+    *generationCount = getGenerationCount();
+    IOUnlock( lock );
+
+    return set;
+}
+
+// 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);
+}
+
+// Add driver config tables to catalog and start matching process.
+bool IOCatalogue::addDrivers(OSArray * drivers,
+                              bool doNubMatching = true )
+{
+    OSCollectionIterator * iter;
+    OSDictionary         * dict;
+    OSOrderedSet         * set;
+    OSArray              * persons;
+    bool                   ret;
+
+    ret = true;
+    persons = OSDynamicCast(OSArray, drivers);
+    if ( !persons )
+        return false;
+
+    iter = OSCollectionIterator::withCollection( persons );
+    if (!iter )
+        return false;
+    
+    set = OSOrderedSet::withCapacity( 10, IOServiceOrdering,
+                                      (void *)gIOProbeScoreKey );
+    if ( !set ) {
+        iter->release();
+        return false;
+    }
+
+    IOTakeLock( lock );
+    while ( (dict = (OSDictionary *) iter->getNextObject()) ) {
+        UInt count;
+        
+        UniqueProperties( dict );
+
+        // Add driver personality to catalogue.
+        count = array->getCount();
+        while ( count-- ) {
+            OSDictionary         * driver;
+
+            // Be sure not to double up on personalities.
+            driver = (OSDictionary *)array->getObject(count);
+            if ( dict->isEqualTo(driver, driver) ) {
+                array->removeObject(count);
+                break;
+            }
+        }
+        
+        ret = array->setObject( dict );
+        if ( !ret )
+            break;
+
+        AddNewImports( set, dict );
+    }
+    // Start device matching.
+    if ( doNubMatching && (set->getCount() > 0) ) {
+        IOService::catalogNewDrivers( set );
+        generation++;
+    }
+    IOUnlock( lock );
+
+    set->release();
+    iter->release();
+    
+    return ret;
+}
+
+// Remove drivers from the catalog which match the
+// properties in the matching dictionary.
+bool IOCatalogue::removeDrivers( OSDictionary * matching,
+                                 bool doNubMatching = true)
+{
+    OSCollectionIterator * tables;
+    OSDictionary         * dict;
+    OSOrderedSet         * set;
+    OSArray              * arrayCopy;
+
+    if ( !matching )
+        return false;
+
+    set = OSOrderedSet::withCapacity(10,
+                                     IOServiceOrdering,
+                                     (void *)gIOProbeScoreKey);
+    if ( !set )
+        return false;
+
+    arrayCopy = OSArray::withCapacity(100);
+    if ( !arrayCopy ) {
+        set->release();
+        return false;
+    }
+    
+    tables = OSCollectionIterator::withCollection(arrayCopy);
+    arrayCopy->release();
+    if ( !tables ) {
+        set->release();
+        return false;
+    }
+
+    UniqueProperties( matching );
+
+    IOTakeLock( lock );
+    kernelTables->reset();
+    arrayCopy->merge(array);
+    array->flushCollection();
+    tables->reset();
+    while ( (dict = (OSDictionary *)tables->getNextObject()) ) {
+        if ( dict->isEqualTo(matching, matching) ) {
+            AddNewImports( set, dict );
+            continue;
+        }
+
+        array->setObject(dict);
+    }
+    // Start device matching.
+    if ( doNubMatching && (set->getCount() > 0) ) {
+        IOService::catalogNewDrivers(set);
+        generation++;
+    }
+    IOUnlock( lock );
+    
+    set->release();
+    tables->release();
+    
+    return true;
+}
+
+// Return the generation count.
+SInt32 IOCatalogue::getGenerationCount( void ) const
+{
+    return( generation );
+}
+
+bool IOCatalogue::isModuleLoaded( OSString * moduleName ) const
+{
+    return isModuleLoaded(moduleName->getCStringNoCopy());
+}
+
+bool IOCatalogue::isModuleLoaded( const char * moduleName ) const
+{
+    kmod_info_t          * k_info;
+
+    if ( !moduleName )
+        return false;
+
+    // Is the module already loaded?
+    k_info = kmod_lookupbyname((char *)moduleName);
+    if ( !k_info ) {
+        kern_return_t            ret;
+
+       /* To make sure this operation completes even if a bad extension needs
+        * to be removed, take the kld lock for this whole block, spanning the
+        * kmod_load_function() and remove_startup_extension_function() calls.
+        */
+        IOLockLock(kld_lock);
+
+        // If the module hasn't been loaded, then load it.
+        if (kmod_load_function != 0) {
+
+            ret = kmod_load_function((char *)moduleName);
+
+            if  ( ret != kIOReturnSuccess ) {
+                IOLog("IOCatalogue: %s cannot be loaded.\n", moduleName);
+
+               /* If the extension couldn't be loaded this time,
+                * make it unavailable so that no more requests are
+                * made in vain. This also enables other matching
+                * extensions to have a chance.
+                */
+                if (kernelLinkerPresent && remove_startup_extension_function) {
+                    (*remove_startup_extension_function)(moduleName);
+                }
+                IOLockUnlock(kld_lock);
+                return false;
+            } else if (kernelLinkerPresent) {
+                // If kern linker is here, the driver is actually loaded,
+                // so return true.
+                IOLockUnlock(kld_lock);
+                return true;
+            } else {
+                // kern linker isn't here, a request has been queued
+                // but the module isn't necessarily loaded yet, so stall.
+                IOLockUnlock(kld_lock);
+                return false;
+            }
+        } else {
+            IOLog("IOCatalogue: %s cannot be loaded "
+                "(kmod load function not set).\n",
+                moduleName);
+        }
+
+        IOLockUnlock(kld_lock);
+        return false;
+    }
+
+    /* Lock wasn't taken if we get here. */
+    return true;
+}
+
+// Check to see if module has been loaded already.
+bool IOCatalogue::isModuleLoaded( OSDictionary * driver ) const
+{
+    OSString             * moduleName = NULL;
+
+    if ( !driver )
+        return false;
+
+    moduleName = OSDynamicCast(OSString, driver->getObject(kModuleKey));
+    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;
+}
+
+// This function is called after a module has been loaded.
+void IOCatalogue::moduleHasLoaded( OSString * moduleName )
+{
+    OSDictionary         * dict;
+
+    dict = OSDictionary::withCapacity(2);
+    dict->setObject(kModuleKey, moduleName);
+    startMatching(dict);
+    dict->release();
+}
+
+void IOCatalogue::moduleHasLoaded( const char * moduleName )
+{
+    OSString             * name;
+
+    name = OSString::withCString(moduleName);
+    moduleHasLoaded(name);
+    name->release();
+}
+
+IOReturn IOCatalogue::unloadModule( OSString * moduleName ) const
+{
+    kmod_info_t          * k_info;
+    kern_return_t          ret;
+    const char           * name;
+
+    ret = kIOReturnBadArgument;
+    if ( moduleName ) {
+        name = moduleName->getCStringNoCopy();
+        k_info = kmod_lookupbyname((char *)name);
+        if ( k_info && (k_info->reference_count < 1) ) {
+            if ( k_info->stop &&
+                 !((ret = k_info->stop(k_info, 0)) == kIOReturnSuccess) )
+                return ret;
+            
+           ret = kmod_destroy(host_priv_self(), k_info->id);
+        }
+    }
+
+    return ret;
+}
+
+static IOReturn _terminateDrivers( OSArray * array, OSDictionary * matching )
+{
+    OSCollectionIterator * tables;
+    OSCollectionIterator * props;
+    OSDictionary         * dict;
+    OSIterator           * iter;
+    OSArray              * arrayCopy;
+    IOService            * service;
+    IOReturn               ret;
+
+    if ( !matching )
+        return kIOReturnBadArgument;
+
+    ret = kIOReturnSuccess;
+    dict = 0;
+    iter = IORegistryIterator::iterateOver(gIOServicePlane,
+                                kIORegistryIterateRecursively);
+    if ( !iter )
+        return kIOReturnNoMemory;
+
+    UniqueProperties( matching );
+
+    props = OSCollectionIterator::withCollection(matching);
+    if ( !props ) {
+        iter->release();
+        return kIOReturnNoMemory;
+    }
+
+    // terminate instances.
+    do {
+        iter->reset();
+        while( (service = (IOService *)iter->getNextObject()) ) {
+            dict = service->getPropertyTable();
+            if ( !dict )
+                continue;
+
+            if ( !dict->isEqualTo(matching, matching) )
+                 continue;
+
+            if ( !service->terminate(kIOServiceRequired|kIOServiceSynchronous) ) {
+                ret = kIOReturnUnsupported;
+                break;
+            }
+        }
+    } while( !service && !iter->isValid());
+    iter->release();
+
+    // remove configs from catalog.
+    if ( ret != kIOReturnSuccess ) 
+        return ret;
+
+    arrayCopy = OSArray::withCapacity(100);
+    if ( !arrayCopy )
+        return kIOReturnNoMemory;
+
+    tables = OSCollectionIterator::withCollection(arrayCopy);
+    arrayCopy->release();
+    if ( !tables )
+        return kIOReturnNoMemory;
+
+    arrayCopy->merge(array);
+    array->flushCollection();
+    tables->reset();
+    while ( (dict = (OSDictionary *)tables->getNextObject()) ) {
+        if ( dict->isEqualTo(matching, matching) )
+            continue;
+
+        array->setObject(dict);
+    }
+
+    tables->release();
+
+    return ret;
+}
+
+IOReturn IOCatalogue::terminateDrivers( OSDictionary * matching )
+{
+    IOReturn ret;
+
+    ret = kIOReturnSuccess;
+    IOTakeLock( lock );
+    ret = _terminateDrivers(array, matching);
+    kernelTables->reset();
+    IOUnlock( lock );
+
+    return ret;
+}
+
+IOReturn IOCatalogue::terminateDriversForModule(
+                                      OSString * moduleName,
+                                      bool unload )
+{
+    IOReturn ret;
+    OSDictionary * dict;
+
+    dict = OSDictionary::withCapacity(1);
+    if ( !dict )
+        return kIOReturnNoMemory;
+
+    dict->setObject(kModuleKey, moduleName);
+    
+    IOTakeLock( lock );
+
+    ret = _terminateDrivers(array, dict);
+    kernelTables->reset();
+
+    // Unload the module itself.
+    if ( unload && ret == kIOReturnSuccess ) {
+        // Do kmod stop first.
+        ret = unloadModule(moduleName);
+    }
+
+    IOUnlock( lock );
+
+    dict->release();
+
+    return ret;
+}
+
+IOReturn IOCatalogue::terminateDriversForModule(
+                                      const char * moduleName,
+                                      bool unload )
+{
+    OSString * name;
+    IOReturn ret;
+
+    name = OSString::withCString(moduleName);
+    if ( !name )
+        return kIOReturnNoMemory;
+
+    ret = terminateDriversForModule(name, unload);
+    name->release();
+    
+    return ret;
+}
+
+bool IOCatalogue::startMatching( OSDictionary * matching )
+{
+    OSDictionary         * dict;
+    OSOrderedSet         * set;
+    
+    if ( !matching )
+        return false;
+
+    set = OSOrderedSet::withCapacity(10, IOServiceOrdering,
+                                     (void *)gIOProbeScoreKey);
+    if ( !set )
+        return false;
+
+    IOTakeLock( lock );
+    kernelTables->reset();
+
+    while ( (dict = (OSDictionary *)kernelTables->getNextObject()) ) {
+        if ( dict->isEqualTo(matching, matching) )
+            AddNewImports(set, dict);
+    }
+    // Start device matching.
+    if ( set->getCount() > 0 ) {
+        IOService::catalogNewDrivers(set);
+        generation++;
+    }
+
+    IOUnlock( lock );
+
+    set->release();
+
+    return true;
+}
+
+void IOCatalogue::reset(void)
+{
+    OSArray              * tables;
+    OSDictionary         * entry;
+    unsigned int           count;
+
+    IOLog("Resetting IOCatalogue.\n");
+    
+    IOTakeLock( lock );
+    tables = OSArray::withArray(array);
+    array->flushCollection();
+    
+    count = tables->getCount();
+    while ( count-- ) {
+        entry = (OSDictionary *)tables->getObject(count);
+        if ( entry && !entry->getObject(kModuleKey) ) {
+            array->setObject(entry);
+        }
+    }
+    
+    kernelTables->reset();
+    IOUnlock( lock );
+    
+    tables->release();
+}
+
+bool IOCatalogue::serialize(OSSerialize * s) const
+{
+    bool                   ret;
+    
+    if ( !s )
+        return false;
+
+    IOTakeLock( lock );
+    ret = array->serialize(s);
+    IOUnlock( lock );
+
+    return ret;
+}
+
+
+bool IOCatalogue::recordStartupExtensions(void) {
+    bool result = false;
+
+    IOLockLock(kld_lock);
+    if (kernelLinkerPresent && record_startup_extensions_function) {
+        result = (*record_startup_extensions_function)();
+    } else {
+        IOLog("Can't record startup extensions; "
+            "kernel linker is not present.\n");
+        result = false;
+    }
+    IOLockUnlock(kld_lock);
+
+    return result;
+}
+
+
 /*********************************************************************
 *********************************************************************/
-
-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
-#pragma mark Utility functions
-#endif
-
-#if PRAGMA_MARK
-#pragma mark IOCatalogue class implementation
-#endif
+bool IOCatalogue::addExtensionsFromArchive(OSData * mkext) {
+    bool result = false;
+
+    IOLockLock(kld_lock);
+    if (kernelLinkerPresent && add_from_mkext_function) {
+        result = (*add_from_mkext_function)(mkext);
+    } else {
+        IOLog("Can't add startup extensions from archive; "
+            "kernel linker is not present.\n");
+        result = false;
+    }
+    IOLockUnlock(kld_lock);
+
+    return result;
+}
+
+
 /*********************************************************************
+* This function clears out all references to the in-kernel linker,
+* frees the list of startup extensions in extensionDict, and
+* deallocates the kernel's __KLD segment to reclaim that memory.
 *********************************************************************/
-
-#define super OSObject
-OSDefineMetaClassAndStructors(IOCatalogue, OSObject)
-
-static bool isModuleLoadedNoOSKextLock(OSDictionary *theKexts,
-    OSDictionary *theModuleDict);
-
-
-/*********************************************************************
-*********************************************************************/
-void
-IOCatalogue::initialize(void)
-{
-	OSSharedPtr<OSArray> array;
-	OSSharedPtr<OSString> errorString;
-	bool                   rc;
-
-	extern const char * gIOKernelConfigTables;
-
-	array = OSDynamicPtrCast<OSArray>(OSUnserialize(gIOKernelConfigTables, errorString));
-	if (!array && errorString) {
-		IOLog("KernelConfigTables syntax error: %s\n",
-		    errorString->getCStringNoCopy());
-	}
-
-	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 = OSMakeShared<IOCatalogue>();
-	assert(gIOCatalogue);
-	rc = gIOCatalogue->init(array.get());
-	assert(rc);
-}
-
-/*********************************************************************
-* Initialize the IOCatalog object.
-*********************************************************************/
-OSArray *
-IOCatalogue::arrayForPersonality(OSDictionary * dict)
-{
-	const OSSymbol * sym;
-
-	sym = OSDynamicCast(OSSymbol, dict->getObject(gIOProviderClassKey));
-	if (!sym) {
-		return NULL;
-	}
-
-	return (OSArray *) personalities->getObject(sym);
-}
-
-void
-IOCatalogue::addPersonality(OSDictionary * dict)
-{
-	const OSSymbol * sym;
-	OSArray * arr;
-
-	sym = OSDynamicCast(OSSymbol, dict->getObject(gIOProviderClassKey));
-	if (!sym) {
-		return;
-	}
-	arr = (OSArray *) personalities->getObject(sym);
-	if (arr) {
-		arr->setObject(dict);
-	} else {
-		OSSharedPtr<OSArray> sharedArr = OSArray::withObjects((const OSObject **)&dict, 1, 2);
-		personalities->setObject(sym, sharedArr.get());
-	}
-}
-
-/*********************************************************************
-* Initialize the IOCatalog object.
-*********************************************************************/
-bool
-IOCatalogue::init(OSArray * initArray)
-{
-	OSDictionary         * dict;
-	OSObject * obj;
-
-	if (!super::init()) {
-		return false;
-	}
-
-	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.get())) {
-			IOLog("Missing or bad \"%s\" key\n",
-			    gIOClassKey->getCStringNoCopy());
-			continue;
-		}
-		dict->setObject("KernelConfigTable", kOSBooleanTrue);
-		addPersonality(dict);
-	}
-
-	gIOCatalogLock = IORWLockAlloc();
-	lock = gIOCatalogLock;
-
-	return true;
-}
-
-/*********************************************************************
-* Release all resources used by IOCatalogue and deallocate.
-* This will probably never be called.
-*********************************************************************/
-void
-IOCatalogue::free( void )
-{
-	panic("");
-}
-
-/*********************************************************************
-*********************************************************************/
-OSPtr<OSOrderedSet>
-IOCatalogue::findDrivers(
-	IOService * service,
-	SInt32 * generationCount)
-{
-	OSDictionary         * nextTable;
-	OSSharedPtr<OSOrderedSet> set;
-	OSArray              * array;
-	const OSMetaClass    * meta;
-	unsigned int           idx;
-
-	set = OSOrderedSet::withCapacity( 1, IOServiceOrdering,
-	    (void *)(gIOProbeScoreKey.get()));
-	if (!set) {
-		return NULL;
-	}
-
-	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();
-
-	IORWLockUnlock(lock);
-
-	return set;
-}
-
-/*********************************************************************
-* Is personality already in the catalog?
-*********************************************************************/
-OSPtr<OSOrderedSet>
-IOCatalogue::findDrivers(
-	OSDictionary * matching,
-	SInt32 * generationCount)
-{
-	OSSharedPtr<OSCollectionIterator> iter;
-	OSDictionary         * dict;
-	OSSharedPtr<OSOrderedSet> set;
-	OSArray              * array;
-	const OSSymbol       * key;
-	unsigned int           idx;
-
-	OSKext::uniquePersonalityProperties(matching);
-
-	set = OSOrderedSet::withCapacity( 1, IOServiceOrdering,
-	    (void *)(gIOProbeScoreKey.get()));
-	if (!set) {
-		return NULL;
-	}
-	iter = OSCollectionIterator::withCollection(personalities.get());
-	if (!iter) {
-		return nullptr;
-	}
-
-	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;
-}
-
-bool
-IOCatalogue::exchangeDrivers(
-	OSDictionary *matchingForRemove,
-	OSArray *personalitiesToAdd,
-	bool doNubMatching)
-{
-	OSSharedPtr<OSOrderedSet> set;
-	OSSharedPtr<OSCollectionIterator> iter_new, iter_all_personalities;
-
-	set = OSOrderedSet::withCapacity(10, IOServiceOrdering,
-	    (void *)(gIOProbeScoreKey.get()));
-	if (!set) {
-		goto finish;
-	}
-
-	iter_new = OSCollectionIterator::withCollection(personalitiesToAdd);
-	if (!iter_new) {
-		goto finish;
-	}
-
-	IORWLockWrite(lock);
-
-	iter_all_personalities = OSCollectionIterator::withCollection(personalities.get());
-	if (!iter_all_personalities) {
-		IORWLockUnlock(lock);
-		goto finish;
-	}
-
-	/*
-	 * Remove personalities first.
-	 * We get a dictionary that has only some keys that could belong to a personality.
-	 * Every personality that will match those keys will be removed.
-	 */
-	const OSSymbol * key;
-	while ((key = (const OSSymbol *) iter_all_personalities->getNextObject())) {
-		OSArray *array = (OSArray *) personalities->getObject(key);
-		if (array) {
-			unsigned int idx;
-			OSDictionary *dict;
-			for (idx = 0; (dict = (OSDictionary *) array->getObject(idx)); idx++) {
-				if (dict->isEqualTo(matchingForRemove, matchingForRemove)) {
-					set->setObject(dict);
-					array->removeObject(idx);
-					idx--;
-				}
-			}
-		}
-	}
-
-	/*
-	 * Add new personalities.
-	 */
-	OSObject *object;
-	while ((object = iter_new->getNextObject())) {
-		OSDictionary * personality = OSDynamicCast(OSDictionary, object);
-		if (personality) {
-			OSKext::uniquePersonalityProperties(personality);
-			OSArray * array = arrayForPersonality(personality);
-			if (!array) {
-				addPersonality(personality);
-			} else {
-				SInt 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;
-				}
-				array->setObject(personality);
-			}
-			set->setObject(personality);
-		}
-	}
-
-	if (doNubMatching && (set->getCount() > 0)) {
-		IOService::catalogNewDrivers(set.get());
-		generation++;
-	}
-
-	IORWLockUnlock(lock);
+kern_return_t IOCatalogue::removeKernelLinker(void) {
+    kern_return_t result = KERN_SUCCESS;
+    extern struct mach_header _mh_execute_header;
+    struct segment_command * segment;
+    char * dt_segment_name;
+    void * segment_paddress;
+    int    segment_size;
+
+   /* This must be the very first thing done by this function.
+    */
+    IOLockLock(kld_lock);
+
+
+   /* If the kernel linker isn't here, that's automatically
+    * a success.
+    */
+    if (!kernelLinkerPresent) {
+        result = KERN_SUCCESS;
+        goto finish;
+    }
+
+    IOLog("Jettisoning kernel linker.\n");
+
+    kernelLinkerPresent = 0;
+
+   /* Set the kmod_load_extension function as the means for loading
+    * a kernel extension.
+    */
+    kmod_load_function = &kmod_load_extension;
+
+    record_startup_extensions_function = 0;
+    add_from_mkext_function = 0;
+    remove_startup_extension_function = 0;
+
+
+   /* Invoke destructors for the __KLD and __LINKEDIT segments.
+    * Do this for all segments before actually freeing their
+    * memory so that any cross-dependencies (not that there
+    * should be any) are handled.
+    */
+    segment = getsegbynamefromheader(
+        &_mh_execute_header, "__KLD");
+    if (!segment) {
+        result = KERN_FAILURE;
+        goto finish;
+    }
+    OSRuntimeUnloadCPPForSegment(segment);
+
+    segment = getsegbynamefromheader(
+        &_mh_execute_header, "__LINKEDIT");
+    if (!segment) {
+        result = KERN_FAILURE;
+        goto finish;
+    }
+    OSRuntimeUnloadCPPForSegment(segment);
+
+
+   /* Free the memory that was set up by bootx.
+    */
+    dt_segment_name = "Kernel-__KLD";
+    if (0 == IODTGetLoaderInfo(dt_segment_name, &segment_paddress, &segment_size)) {
+        IODTFreeLoaderInfo(dt_segment_name, (void *)segment_paddress,
+            (int)segment_size);
+    }
+
+    dt_segment_name = "Kernel-__LINKEDIT";
+    if (0 == IODTGetLoaderInfo(dt_segment_name, &segment_paddress, &segment_size)) {
+        IODTFreeLoaderInfo(dt_segment_name, (void *)segment_paddress,
+            (int)segment_size);
+    }
+
 
 finish:
-	return true;
-}
-
-/*********************************************************************
-* Add driver config tables to catalog and start matching process.
-*
-* Important that existing personalities are kept (not replaced)
-* if duplicates found. Personalities can come from OSKext objects
-* or from userland kext library. We want to minimize distinct
-* copies between OSKext & IOCatalogue.
-*
-* xxx - userlib used to refuse to send personalities with IOKitDebug
-* xxx - during safe boot. That would be better implemented here.
-*********************************************************************/
-
-bool
-IOCatalogue::addDrivers(
-	OSArray * drivers,
-	bool doNubMatching)
-{
-	bool                   result = false;
-	OSSharedPtr<OSOrderedSet> set;
-	OSSharedPtr<OSCollectionIterator> iter;
-	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.get()));
-	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.get());
-		generation++;
-	}
-	IORWLockUnlock(lock);
-
-finish:
-
-	return result;
-}
-
-bool
-IOCatalogue::removeDrivers(bool doNubMatching, bool (^shouldRemove)(OSDictionary *personality))
-{
-	OSSharedPtr<OSOrderedSet> set;
-	OSSharedPtr<OSCollectionIterator> iter;
-	OSDictionary         * dict;
-	OSArray              * array;
-	const OSSymbol       * key;
-	unsigned int           idx;
-
-	set = OSOrderedSet::withCapacity(10,
-	    IOServiceOrdering,
-	    (void *)(gIOProbeScoreKey.get()));
-	if (!set) {
-		return false;
-	}
-	iter = OSCollectionIterator::withCollection(personalities.get());
-	if (!iter) {
-		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++) {
-				if (shouldRemove(dict)) {
-					set->setObject(dict);
-					array->removeObject(idx);
-					idx--;
-				}
-			}
-		}
-		// Start device matching.
-		if (doNubMatching && (set->getCount() > 0)) {
-			IOService::catalogNewDrivers(set.get());
-			generation++;
-		}
-	}
-	IORWLockUnlock(lock);
-
-	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
-{
-	return generation;
-}
-/*********************************************************************
-*********************************************************************/
-/* static */
-
-bool
-IOCatalogue::personalityIsBoot(OSDictionary * match)
-{
-	OSString * moduleName;
-	OSSharedPtr<OSKext> theKext;
-
-	moduleName = OSDynamicCast(OSString, match->getObject(gIOModuleIdentifierKey.get()));
-	if (!moduleName) {
-		return true;
-	}
-	theKext = OSKext::lookupKextWithIdentifier(moduleName->getCStringNoCopy());
-	if (!theKext) {
-		return true;
-	}
-	switch (theKext->kc_type) {
-	case KCKindPrimary:
-		return true;
-	case KCKindUnknown:
-		return true;
-	case KCKindNone:
-		return false;
-	case KCKindAuxiliary:
-		return false;
-	case KCKindPageable:
-		return false;
-	default:
-		assert(false);
-		return false;
-	}
-}
-
-// Check to see if kernel module has been loaded already, and request its load.
-bool
-IOCatalogue::isModuleLoaded(OSDictionary * driver, OSObject ** kextRef) const
-{
-	OSString * moduleName = NULL;
-	OSString * publisherName = NULL;
-	OSReturn   ret;
-
-	if (kextRef) {
-		*kextRef = 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(gIOModuleIdentifierKernelKey.get()));
-	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.get()));
-		if (moduleDextName && !(moduleName->isEqualTo(moduleDextName))) {
-			OSSharedPtr<OSObject> dextRef;
-			ret = OSKext::loadKextWithIdentifier(moduleDextName, 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;
-}
-
-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.
- */
-void
-IOCatalogue::moduleHasLoaded(const OSSymbol * moduleName)
-{
-	startMatching(moduleName);
-
-	(void) OSKext::setDeferredLoadSucceeded();
-	(void) OSKext::considerRebuildOfPrelinkedKernel();
-}
-
-void
-IOCatalogue::moduleHasLoaded(const char * moduleName)
-{
-	OSSharedPtr<const OSSymbol> name;
-
-	name = OSSymbol::withCString(moduleName);
-	moduleHasLoaded(name.get());
-}
-
-// xxx - return is really OSReturn/kern_return_t
-IOReturn
-IOCatalogue::unloadModule(OSString * moduleName) const
-{
-	return OSKext::removeKextWithIdentifier(moduleName->getCStringNoCopy());
-}
-
-IOReturn
-IOCatalogue::terminateDrivers(OSDictionary * matching, io_name_t className, bool asynchronous)
-{
-	OSDictionary         * dict;
-	OSSharedPtr<OSIterator> iter;
-	IOService            * service;
-	IOReturn               ret;
-
-	ret = kIOReturnSuccess;
-	dict = NULL;
-	iter = IORegistryIterator::iterateOver(gIOServicePlane,
-	    kIORegistryIterateRecursively);
-	if (!iter) {
-		return kIOReturnNoMemory;
-	}
-
-	if (matching) {
-		OSKext::uniquePersonalityProperties( matching, false );
-	}
-
-	// terminate instances.
-	do {
-		iter->reset();
-		while ((service = (IOService *)iter->getNextObject())) {
-			if (className && !service->metaCast(className)) {
-				continue;
-			}
-			if (matching) {
-				/* 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.
-				 */
-				dict = service->getPropertyTable();
-				if (!dict) {
-					continue;
-				}
-				if (!dict->isEqualTo(matching, matching)) {
-					continue;
-				}
-			}
-
-			OSKext     * kext;
-			OSSharedPtr<OSString> dextBundleID;
-			const char * bundleIDStr;
-			OSObject   * prop;
-			bool         okToTerminate;
-			bool         isDext = service->hasUserServer();
-			for (okToTerminate = true;;) {
-				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;
-					}
-				}
-				if (!bundleIDStr) {
-					break;
-				}
-				if (!strcmp(kOSKextKernelIdentifier, bundleIDStr)) {
-					okToTerminate = false;
-					break;
-				}
-				if (!strncmp("com.apple.", bundleIDStr, strlen("com.apple."))) {
-					okToTerminate = false;
-					break;
-				}
-				break;
-			}
-			if (!okToTerminate) {
-#if DEVELOPMENT || DEBUG
-				okToTerminate = true;
-#endif /* DEVELOPMENT || DEBUG */
-				IOLog("%sallowing kextunload terminate for bundleID %s\n",
-				    okToTerminate ? "" : "dis", bundleIDStr ? bundleIDStr : "?");
-				if (!okToTerminate) {
-					ret = kIOReturnUnsupported;
-					break;
-				}
-			}
-			IOOptionBits terminateOptions = kIOServiceRequired;
-			if (!asynchronous) {
-				terminateOptions |= kIOServiceSynchronous;
-			}
-			if (isDext) {
-				terminateOptions |= kIOServiceTerminateNeedWillTerminate;
-			}
-			if (!service->terminate(terminateOptions)) {
-				ret = kIOReturnUnsupported;
-				break;
-			}
-		}
-	} while (!service && !iter->isValid());
-
-	return ret;
-}
-
-IOReturn
-IOCatalogue::_removeDrivers(OSDictionary * matching)
-{
-	IOReturn               ret = kIOReturnSuccess;
-	OSSharedPtr<OSCollectionIterator> iter;
-	OSDictionary         * dict;
-	OSArray              * array;
-	const OSSymbol       * key;
-	unsigned int           idx;
-
-	// remove configs from catalog.
-
-	iter = OSCollectionIterator::withCollection(personalities.get());
-	if (!iter) {
-		return kIOReturnNoMemory;
-	}
-
-	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--;
-				}
-			}
-		}
-	}
-
-	return ret;
-}
-
-IOReturn
-IOCatalogue::terminateDrivers(OSDictionary * matching)
-{
-	IOReturn ret;
-
-	if (!matching) {
-		return kIOReturnBadArgument;
-	}
-	ret = terminateDrivers(matching, NULL, false);
-	IORWLockWrite(lock);
-	if (kIOReturnSuccess == ret) {
-		ret = _removeDrivers(matching);
-	}
-	IORWLockUnlock(lock);
-
-	return ret;
-}
-
-IOReturn
-IOCatalogue::terminateDriversForUserspaceReboot()
-{
-	IOReturn                ret = kIOReturnSuccess;
-
-#if !NO_KEXTD
-	OSSharedPtr<OSIterator> iter;
-	IOService             * service;
-	bool                    isDeferredMatch;
-	bool                    isDext;
-	bool                    preserveDuringUserspaceReboot;
-	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) {
-				OSSharedPtr<OSObject> prop = service->copyProperty(gIOUserServerPreserveUserspaceRebootKey, gIOServicePlane, kIORegistryIterateRecursively | kIORegistryIterateParents);
-				preserveDuringUserspaceReboot = prop == kOSBooleanTrue;
-				if (preserveDuringUserspaceReboot) {
-					IOLog("preserving service %s-0x%llx during userspace reboot\n", service->getName(), service->getRegistryEntryID());
-					continue;
-				}
-
-				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,
-	bool asynchronous)
-{
-	IOReturn ret;
-	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
-	 * 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;
-		}
-	}
-	kext = OSKext::lookupKextWithIdentifier(moduleName->getCStringNoCopy());
-	if (kext) {
-		isDext = kext->isDriverKit();
-	}
-
-	dict = OSDictionary::withCapacity(1);
-	if (!dict) {
-		ret = kIOReturnNoMemory;
-		goto finish;
-	}
-
-	dict->setObject(gIOModuleIdentifierKey.get(), moduleName);
-
-	ret = terminateDrivers(dict.get(), NULL, asynchronous);
-
-	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);
-		}
-		IORWLockUnlock(lock);
-	}
-
-finish:
-	return ret;
-}
-
-IOReturn
-IOCatalogue::terminateDriversForModule(
-	const char * moduleName,
-	bool unload,
-	bool asynchronous)
-{
-	OSSharedPtr<OSString> name;
-	IOReturn ret;
-
-	name = OSString::withCString(moduleName);
-	if (!name) {
-		return kIOReturnNoMemory;
-	}
-
-	ret = terminateDriversForModule(name.get(), unload, asynchronous);
-
-	return ret;
-}
-
-#if defined(__i386__) || defined(__x86_64__)
-bool
-IOCatalogue::startMatching( OSDictionary * matching )
-{
-	OSSharedPtr<OSOrderedSet> set;
-
-	if (!matching) {
-		return false;
-	}
-
-	set = OSOrderedSet::withCapacity(10, IOServiceOrdering,
-	    (void *)(gIOProbeScoreKey.get()));
-	if (!set) {
-		return false;
-	}
-
-	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.get());
-		generation++;
-	}
-
-	IORWLockUnlock(lock);
-
-	return true;
-}
-#endif /* defined(__i386__) || defined(__x86_64__) */
-
-bool
-IOCatalogue::startMatching( const OSSymbol * moduleName )
-{
-	OSSharedPtr<OSOrderedSet> set;
-	OSSharedPtr<OSKext>       kext;
-	OSSharedPtr<OSArray>      servicesToTerminate;
-
-	if (!moduleName) {
-		return false;
-	}
-
-	set = OSOrderedSet::withCapacity(10, IOServiceOrdering,
-	    (void *)(gIOProbeScoreKey.get()));
-	if (!set) {
-		return false;
-	}
-
-	/*
-	 * Be sure to call into OSKext outside of
-	 * IORWLock, otherwise it can trigger a lock
-	 * inversion.
-	 */
-	kext = OSKext::lookupKextWithIdentifier(moduleName->getCStringNoCopy());
-
-	IORWLockRead(lock);
-
-	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) {
-			IORWLockUnlock(lock);
-			return false;
-		}
-
-		servicesToTerminate = OSArray::withCapacity(1);
-		if (!servicesToTerminate) {
-			IORWLockUnlock(lock);
-			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     * moduleIdentifierKernel;
-		OSObject     * moduleIdentifier;
-		unsigned int   idx;
-
-		array = (OSArray *) value;
-		for (idx = 0; (dict = (OSDictionary *) array->getObject(idx)); idx++) {
-		        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.get());
-		generation++;
-	}
-
-	IORWLockUnlock(lock);
-
-	return true;
-}
-
-void
-IOCatalogue::reset(void)
-{
-	IOCatalogue::resetAndAddDrivers(/* no drivers; true reset */ NULL,
-	    /* doMatching */ false);
-	return;
-}
-
-bool
-IOCatalogue::resetAndAddDrivers(OSArray * drivers, bool doNubMatching)
-{
-	bool                   result              = false;
-	OSArray              * newPersonalities    = NULL;// do not release
-	const OSSymbol       * key;
-	OSArray              * array;
-	OSDictionary         * thisNewPersonality   = NULL;// do not release
-	OSDictionary         * thisOldPersonality   = NULL;// do not release
-	OSSharedPtr<OSDictionary> myKexts;
-	OSSharedPtr<OSCollectionIterator> iter;
-	OSSharedPtr<OSOrderedSet> matchSet;
-	signed int             idx, newIdx;
-
-	if (drivers) {
-		newPersonalities = OSDynamicCast(OSArray, drivers);
-		if (!newPersonalities) {
-			goto finish;
-		}
-	}
-	matchSet = OSOrderedSet::withCapacity(10, IOServiceOrdering,
-	    (void *)(gIOProbeScoreKey.get()));
-	if (!matchSet) {
-		goto finish;
-	}
-	iter = OSCollectionIterator::withCollection(personalities.get());
-	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.get(), 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.get());
-		generation++;
-	}
-
-	IORWLockUnlock(lock);
-
-finish:
-
-	return result;
-}
-
-bool
-IOCatalogue::serialize(OSSerialize * s) const
-{
-	if (!s) {
-		return false;
-	}
-
-	return super::serialize(s);
-}
-
-bool
-IOCatalogue::serializeData(IOOptionBits kind, OSSerialize * s) const
-{
-	kern_return_t kr = kIOReturnSuccess;
-
-	switch (kind) {
-	case kIOCatalogGetContents:
-		kr = KERN_NOT_SUPPORTED;
-		break;
-
-	case kIOCatalogGetModuleDemandList:
-		kr = KERN_NOT_SUPPORTED;
-		break;
-
-	case kIOCatalogGetCacheMissList:
-		kr = KERN_NOT_SUPPORTED;
-		break;
-
-	case kIOCatalogGetROMMkextList:
-		kr = KERN_NOT_SUPPORTED;
-		break;
-
-	default:
-		kr = kIOReturnBadArgument;
-		break;
-	}
-
-	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 (theKexts == NULL || theModuleDict == NULL) {
-		return myResult;
-	}
-
-	// gIOModuleIdentifierKey is "CFBundleIdentifier"
-	myBundleID = OSDynamicCast(OSString,
-	    theModuleDict->getObject(gIOModuleIdentifierKey.get()));
-	if (myBundleID == NULL) {
-		return myResult;
-	}
-
-	myKext = OSDynamicCast(OSKext, theKexts->getObject(myBundleID->getCStringNoCopy()));
-	if (myKext) {
-		myResult = myKext->isLoaded();
-	}
-
-	return myResult;
-}
-
-
-#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.
- **********************************************************************/
+
+   /* This must be the very last thing done before returning.
+    */
+    IOLockUnlock(kld_lock);
+
+    return result;
+}