]> git.saurik.com Git - apple/xnu.git/blobdiff - iokit/Kernel/IOCatalogue.cpp
xnu-2050.18.24.tar.gz
[apple/xnu.git] / iokit / Kernel / IOCatalogue.cpp
index 4c8e3b1b563b2b63c504106dc32be060ae4bc767..ee193c0277aaa8879ee295eec975d6a3686f1ac3 100644 (file)
@@ -1,16 +1,19 @@
 /*
- * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 1998-2006 Apple Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * Copyright (c) 1999-2003 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. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * 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
  * Please see the License for the specific language governing rights and
  * limitations under the License.
  * 
- * @APPLE_LICENSE_HEADER_END@
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
  */
 /*
- * Copyright (c) 1998 Apple Computer, Inc.  All rights reserved. 
+ * Copyright (c) 1998 Apple 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.
+ */
 
-#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 <libkern/kernel_mach_header.h>
 #include <kern/host.h>
+#include <security/mac_data.h>
 };
 
-#include <IOKit/IOLib.h>
-
-#include <IOKit/assert.h>
-
+#include <libkern/c++/OSContainers.h>
+#include <libkern/c++/OSUnserialize.h>
+#include <libkern/c++/OSKext.h>
+#include <libkern/OSKextLibPrivate.h>
+#include <libkern/OSDebug.h>
 
-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);
-};
+#include <IOKit/IODeviceTreeSupport.h>
+#include <IOKit/IOService.h>
+#include <IOKit/IOCatalogue.h>
 
+#include <IOKit/IOLib.h>
+#include <IOKit/assert.h>
 
-/*****
- * 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;
-};
+#if PRAGMA_MARK
+#pragma mark Internal Declarations
+#endif
+/*********************************************************************
+*********************************************************************/
 
+IOCatalogue    * gIOCatalogue;
+const OSSymbol * gIOClassKey;
+const OSSymbol * gIOProbeScoreKey;
+const OSSymbol * gIOModuleIdentifierKey;
+IORWLock         * gIOCatalogLock;
 
-/*****
- * 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;
+#if PRAGMA_MARK
+#pragma mark Utility functions
+#endif
 
+#if PRAGMA_MARK
+#pragma mark IOCatalogue class implementation
+#endif
+/*********************************************************************
+*********************************************************************/
 
 #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 )
+/*********************************************************************
+*********************************************************************/
+void IOCatalogue::initialize(void)
 {
     OSArray              * array;
     OSString             * errorString;
@@ -121,14 +95,17 @@ void IOCatalogue::initialize( void )
 
     array = OSDynamicCast(OSArray, OSUnserialize(gIOKernelConfigTables, &errorString));
     if (!array && errorString) {
-       IOLog("KernelConfigTables syntax error: %s\n",
-               errorString->getCStringNoCopy());
-       errorString->release();
+        IOLog("KernelConfigTables syntax error: %s\n",
+            errorString->getCStringNoCopy());
+        errorString->release();
     }
 
-    gIOClassKey = OSSymbol::withCStringNoCopy( kIOClassKey );
-    gIOProbeScoreKey = OSSymbol::withCStringNoCopy( kIOProbeScoreKey );
-    assert( array && gIOClassKey && gIOProbeScoreKey);
+    gIOClassKey              = OSSymbol::withCStringNoCopy( kIOClassKey );
+    gIOProbeScoreKey        = OSSymbol::withCStringNoCopy( kIOProbeScoreKey );
+    gIOModuleIdentifierKey   = OSSymbol::withCStringNoCopy( kCFBundleIdentifierKey );
+
+    assert( array && gIOClassKey && gIOProbeScoreKey 
+           && gIOModuleIdentifierKey);
 
     gIOCatalogue = new IOCatalogue;
     assert(gIOCatalogue);
@@ -137,398 +114,379 @@ void IOCatalogue::initialize( void )
     array->release();
 }
 
-// Initialize the IOCatalog object.
+/*********************************************************************
+* Initialize the IOCatalog object.
+*********************************************************************/
+OSArray * IOCatalogue::arrayForPersonality(OSDictionary * dict)
+{
+    const OSSymbol * sym;
+
+    sym = OSDynamicCast(OSSymbol, dict->getObject(gIOProviderClassKey));
+    if (!sym)  return (0);
+
+    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
+    {
+        arr = OSArray::withObjects((const OSObject **)&dict, 1, 2);
+        personalities->setObject(sym, arr);
+        arr->release();
+    }
+}
+
+/*********************************************************************
+* Initialize the IOCatalog object.
+*********************************************************************/
 bool IOCatalogue::init(OSArray * initArray)
 {
-    IORegistryEntry      * entry;
     OSDictionary         * dict;
-    
+    OSObject * obj;
+
     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);
+    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( 0 == dict->getObject( gIOClassKey ))
+        {
             IOLog("Missing or bad \"%s\" key\n",
                     gIOClassKey->getCStringNoCopy());
+           continue;
+       }
+       dict->setObject("KernelConfigTable", kOSBooleanTrue);
+        addPersonality(dict);
     }
 
-#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);
+    gIOCatalogLock = IORWLockAlloc();
+    lock = gIOCatalogLock;
 
     return true;
 }
 
-// Release all resources used by IOCatalogue and deallocate.
-// This will probably never be called.
+/*********************************************************************
+* 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 );
-    }
+    panic("");
 }
-#endif
 
-OSOrderedSet * IOCatalogue::findDrivers( IOService * service,
-                                       SInt32 * generationCount )
+/*********************************************************************
+*********************************************************************/
+OSOrderedSet *
+IOCatalogue::findDrivers(
+    IOService * service,
+    SInt32 * generationCount)
 {
     OSDictionary         * nextTable;
     OSOrderedSet         * set;
-    OSString             * imports;
+    OSArray              * array;
+    const OSMetaClass    * meta;
+    unsigned int           idx;
 
     set = OSOrderedSet::withCapacity( 1, IOServiceOrdering,
                                       (void *)gIOProbeScoreKey );
     if( !set )
        return( 0 );
 
-    IOTakeLock( lock );
-    kernelTables->reset();
+    IORWLockRead(lock);
 
-#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 );
+    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();
 
-    IOUnlock( lock );
+    IORWLockUnlock(lock);
 
     return( set );
 }
 
-// Is personality already in the catalog?
-OSOrderedSet * IOCatalogue::findDrivers( OSDictionary * matching,
-                                         SInt32 * generationCount)
+/*********************************************************************
+* Is personality already in the catalog?
+*********************************************************************/
+OSOrderedSet *
+IOCatalogue::findDrivers(
+    OSDictionary * matching,
+    SInt32 * generationCount)
 {
+    OSCollectionIterator * iter;
     OSDictionary         * dict;
     OSOrderedSet         * set;
+    OSArray              * array;
+    const OSSymbol       * key;
+    unsigned int           idx;
 
-    UniqueProperties(matching);
+    OSKext::uniquePersonalityProperties(matching);
 
     set = OSOrderedSet::withCapacity( 1, IOServiceOrdering,
                                       (void *)gIOProbeScoreKey );
+    if (!set) return (0);
+    iter = OSCollectionIterator::withCollection(personalities);
+    if (!iter) 
+    {
+       set->release();
+       return (0);
+    }
 
-    IOTakeLock( lock );
-    kernelTables->reset();
-    while ( (dict = (OSDictionary *) kernelTables->getNextObject()) ) {
-
-       /* 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);
+    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();
-    IOUnlock( lock );
+    IORWLockUnlock(lock);
 
+    iter->release();
     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.
+*
+* 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.
+*********************************************************************/
 
-// Add driver config tables to catalog and start matching process.
-bool IOCatalogue::addDrivers(OSArray * drivers,
-                              bool doNubMatching = true )
+bool IOCatalogue::addDrivers(
+    OSArray * drivers,
+    bool doNubMatching)
 {
-    OSCollectionIterator * iter;
-    OSDictionary         * dict;
-    OSOrderedSet         * set;
-    OSArray              * persons;
-    bool                   ret;
-
-    ret = true;
+    bool                   result = false;
+    OSCollectionIterator * iter = NULL;       // must release
+    OSOrderedSet         * set = NULL;        // must release
+    OSObject             * object = NULL;       // do not release
+    OSArray              * persons = NULL;    // do not release
+    
     persons = OSDynamicCast(OSArray, drivers);
-    if ( !persons )
-        return false;
-
-    iter = OSCollectionIterator::withCollection( persons );
-    if (!iter )
-        return false;
+    if (!persons) {
+        goto finish;
+    }
     
     set = OSOrderedSet::withCapacity( 10, IOServiceOrdering,
-                                      (void *)gIOProbeScoreKey );
-    if ( !set ) {
-        iter->release();
-        return false;
+        (void *)gIOProbeScoreKey );
+    if (!set) {
+        goto finish;
     }
 
-    IOTakeLock( lock );
-    while ( (dict = (OSDictionary *) iter->getNextObject()) ) {
-        UInt count;
-        
-        UniqueProperties( dict );
+    iter = OSCollectionIterator::withCollection(persons);
+    if (!iter) {
+        goto finish;
+    }
 
-        // Add driver personality to catalogue.
-        count = array->getCount();
-        while ( count-- ) {
-            OSDictionary         * driver;
+   /* Start with success; clear it on an error.
+    */
+    result = true;
 
-            // Be sure not to double up on personalities.
-            driver = (OSDictionary *)array->getObject(count);
+    IORWLockWrite(lock);
+    while ( (object = iter->getNextObject()) ) {
+    
+        // xxx Deleted OSBundleModuleDemand check; will handle in other ways for SL
 
-           /* Unlike in other functions, this comparison must be exact!
-            * The catalogue must be able to contain personalities that
-            * are proper supersets of others.
-            * Do not compare just the properties present in one driver
-            * pesonality or the other.
-            */
-            if ( dict->isEqualTo(driver) ) {
-                array->removeObject(count);
-                break;
-            }
-        }
-        
-        ret = array->setObject( dict );
-        if ( !ret )
+        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
+               * pesonality or the other.
+               */
+               if (personality->isEqualTo(driver)) {
+                   break;
+               }
+           }
+           if (count >= 0) {
+               // its a dup
+               continue;
+           }
+           result = array->setObject(personality);
+           if (!result) {
+               break;
+           }
+        }
 
-        AddNewImports( set, dict );
+       set->setObject(personality);        
     }
     // Start device matching.
-    if ( doNubMatching && (set->getCount() > 0) ) {
-        IOService::catalogNewDrivers( set );
+    if (result && doNubMatching && (set->getCount() > 0)) {
+        IOService::catalogNewDrivers(set);
         generation++;
     }
-    IOUnlock( lock );
+    IORWLockUnlock(lock);
 
-    set->release();
-    iter->release();
-    
-    return ret;
+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 = true)
+/*********************************************************************
+* Remove drivers from the catalog which match the
+* properties in the matching dictionary.
+*********************************************************************/
+bool
+IOCatalogue::removeDrivers(
+    OSDictionary * matching,
+    bool doNubMatching)
 {
-    OSCollectionIterator * tables;
-    OSDictionary         * dict;
     OSOrderedSet         * set;
-    OSArray              * arrayCopy;
+    OSCollectionIterator * iter;
+    OSDictionary         * dict;
+    OSArray              * array;
+    const OSSymbol       * key;
+    unsigned int           idx;
 
     if ( !matching )
         return false;
-
+    
     set = OSOrderedSet::withCapacity(10,
                                      IOServiceOrdering,
                                      (void *)gIOProbeScoreKey);
     if ( !set )
         return false;
-
-    arrayCopy = OSArray::withCapacity(100);
-    if ( !arrayCopy ) {
-        set->release();
-        return false;
-    }
-    
-    tables = OSCollectionIterator::withCollection(arrayCopy);
-    arrayCopy->release();
-    if ( !tables ) {
-        set->release();
-        return false;
+    iter = OSCollectionIterator::withCollection(personalities);
+    if (!iter) 
+    {
+       set->release();
+       return (false);
     }
 
-    UniqueProperties( matching );
-
-    IOTakeLock( lock );
-    kernelTables->reset();
-    arrayCopy->merge(array);
-    array->flushCollection();
-    tables->reset();
-    while ( (dict = (OSDictionary *)tables->getNextObject()) ) {
-
-       /* This comparison must be done with only the keys in the
-        * "matching" dict to enable general searches.
-        */
-        if ( dict->isEqualTo(matching, matching) ) {
-            AddNewImports( set, dict );
-            continue;
+    IORWLockWrite(lock);
+    while ((key = (const OSSymbol *) iter->getNextObject()))
+    {
+        array = (OSArray *) personalities->getObject(key);
+        if (array) for (idx = 0; (dict = (OSDictionary *) array->getObject(idx)); idx++)
+        {
+           /* This comparison must be done with only the keys in the
+            * "matching" dict to enable general searches.
+            */
+            if ( dict->isEqualTo(matching, matching) ) {
+                set->setObject(dict);        
+                array->removeObject(idx);
+                idx--;
+            }
+        }
+        // Start device matching.
+        if ( doNubMatching && (set->getCount() > 0) ) {
+            IOService::catalogNewDrivers(set);
+            generation++;
         }
-
-        array->setObject(dict);
-    }
-    // Start device matching.
-    if ( doNubMatching && (set->getCount() > 0) ) {
-        IOService::catalogNewDrivers(set);
-        generation++;
     }
-    IOUnlock( lock );
-    
+    IORWLockUnlock(lock);
+   
     set->release();
-    tables->release();
+    iter->release();
     
     return true;
 }
 
 // Return the generation count.
-SInt32 IOCatalogue::getGenerationCount( void ) const
+SInt32 IOCatalogue::getGenerationCount(void) const
 {
     return( generation );
 }
 
-bool IOCatalogue::isModuleLoaded( OSString * moduleName ) const
+bool IOCatalogue::isModuleLoaded(OSString * moduleName) const
 {
     return isModuleLoaded(moduleName->getCStringNoCopy());
 }
 
-bool IOCatalogue::isModuleLoaded( const char * moduleName ) const
+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_locked((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);
+    OSReturn ret;
+    ret = OSKext::loadKextWithIdentifier(moduleName);
+    if (kOSKextReturnDeferred == ret) {
+        // a request has been queued but the module isn't necessarily 
+        // loaded yet, so stall.
         return false;
     }
-
-    if (k_info) {
-        kfree(k_info, sizeof(kmod_info_t));
-    }
-
-    /* Lock wasn't taken if we get here. */
+    // module is present or never will be 
     return true;
 }
 
 // Check to see if module has been loaded already.
-bool IOCatalogue::isModuleLoaded( OSDictionary * driver ) const
+bool IOCatalogue::isModuleLoaded(OSDictionary * driver) const
 {
     OSString             * moduleName = NULL;
+    OSString             * publisherName = NULL;
 
     if ( !driver )
         return false;
 
-    moduleName = OSDynamicCast(OSString, driver->getObject(kModuleKey));
+    /* The personalities of codeless kexts often contain the bundle ID of the
+     * kext they reference, and not the bundle ID of the codeless kext itself.
+     * The prelinked kernel needs to know the bundle ID of the codeless kext
+     * so it can include these personalities, so OSKext stores that bundle ID
+     * in the IOPersonalityPublisher key, and we record it as requested here.
+     */
+    publisherName = OSDynamicCast(OSString, 
+        driver->getObject(kIOPersonalityPublisherKey));
+    OSKext::recordIdentifierRequest(publisherName);
+
+    moduleName = OSDynamicCast(OSString, driver->getObject(gIOModuleIdentifierKey));
     if ( moduleName )
         return isModuleLoaded(moduleName);
 
@@ -538,61 +496,42 @@ bool IOCatalogue::isModuleLoaded( OSDictionary * driver ) const
     return true;
 }
 
-// This function is called after a module has been loaded.
-void IOCatalogue::moduleHasLoaded( OSString * moduleName )
+/* This function is called after a module has been loaded.
+ * Is invoked from user client call, ultimately from IOKitLib's
+ * IOCatalogueModuleLoaded(). Sent from kextd.
+ */
+void IOCatalogue::moduleHasLoaded(OSString * moduleName)
 {
-    OSDictionary         * dict;
+    OSDictionary * dict;
 
     dict = OSDictionary::withCapacity(2);
-    dict->setObject(kModuleKey, moduleName);
+    dict->setObject(gIOModuleIdentifierKey, moduleName);
     startMatching(dict);
     dict->release();
+
+    (void) OSKext::setDeferredLoadSucceeded();
+    (void) OSKext::considerRebuildOfPrelinkedKernel();
 }
 
-void IOCatalogue::moduleHasLoaded( const char * moduleName )
+void IOCatalogue::moduleHasLoaded(const char * moduleName)
 {
-    OSString             * name;
+    OSString * name;
 
     name = OSString::withCString(moduleName);
     moduleHasLoaded(name);
     name->release();
 }
 
-IOReturn IOCatalogue::unloadModule( OSString * moduleName ) const
+// xxx - return is really OSReturn/kern_return_t
+IOReturn IOCatalogue::unloadModule(OSString * moduleName) const
 {
-    kmod_info_t          * k_info = 0;
-    kern_return_t          ret;
-    const char           * name;
-
-    ret = kIOReturnBadArgument;
-    if ( moduleName ) {
-        name = moduleName->getCStringNoCopy();
-        k_info = kmod_lookupbyname_locked((char *)name);
-        if ( k_info && (k_info->reference_count < 1) ) {
-            if ( k_info->stop &&
-                 !((ret = k_info->stop(k_info, 0)) == kIOReturnSuccess) ) {
-
-                kfree(k_info, sizeof(kmod_info_t));
-                return ret;
-           }
-            
-           ret = kmod_destroy(host_priv_self(), k_info->id);
-        }
-    }
-    if (k_info) {
-        kfree(k_info, sizeof(kmod_info_t));
-    }
-
-    return ret;
+    return OSKext::removeKextWithIdentifier(moduleName->getCStringNoCopy());
 }
 
-static IOReturn _terminateDrivers( OSArray * array, OSDictionary * matching )
+IOReturn IOCatalogue::_terminateDrivers(OSDictionary * matching)
 {
-    OSCollectionIterator * tables;
     OSDictionary         * dict;
     OSIterator           * iter;
-    OSArray              * arrayCopy;
     IOService            * service;
     IOReturn               ret;
 
@@ -606,7 +545,7 @@ static IOReturn _terminateDrivers( OSArray * array, OSDictionary * matching )
     if ( !iter )
         return kIOReturnNoMemory;
 
-    UniqueProperties( matching );
+    OSKext::uniquePersonalityProperties( matching );
 
     // terminate instances.
     do {
@@ -631,87 +570,120 @@ static IOReturn _terminateDrivers( OSArray * array, OSDictionary * matching )
     } 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;
+    return ret;
+}
 
-    arrayCopy->merge(array);
-    array->flushCollection();
-    tables->reset();
-    while ( (dict = (OSDictionary *)tables->getNextObject()) ) {
+IOReturn IOCatalogue::_removeDrivers(OSDictionary * matching)
+{
+    IOReturn               ret = kIOReturnSuccess;
+    OSCollectionIterator * iter;
+    OSDictionary         * dict;
+    OSArray              * array;
+    const OSSymbol       * key;
+    unsigned int           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) )
-            continue;
+    // remove configs from catalog.
 
-        array->setObject(dict);
+    iter = OSCollectionIterator::withCollection(personalities);
+    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--;
+            }
+        }
     }
-
-    tables->release();
+    iter->release();
 
     return ret;
 }
 
-IOReturn IOCatalogue::terminateDrivers( OSDictionary * matching )
+IOReturn IOCatalogue::terminateDrivers(OSDictionary * matching)
 {
     IOReturn ret;
 
-    ret = kIOReturnSuccess;
-    IOTakeLock( lock );
-    ret = _terminateDrivers(array, matching);
-    kernelTables->reset();
-    IOUnlock( lock );
+    ret = _terminateDrivers(matching);
+    IORWLockWrite(lock);
+    if (kIOReturnSuccess == ret)
+       ret = _removeDrivers(matching);
+    IORWLockUnlock(lock);
 
     return ret;
 }
 
 IOReturn IOCatalogue::terminateDriversForModule(
-                                      OSString * moduleName,
-                                      bool unload )
+    OSString * moduleName,
+    bool unload)
 {
     IOReturn ret;
     OSDictionary * dict;
+    bool isLoaded = false;
+
+   /* Check first if the kext currently has any linkage dependents;
+    * in such a case the unload would fail so let's not terminate any
+    * IOServices (since doing so typically results in a panic when there
+    * are loaded dependencies). Note that we aren't locking the kext here
+    * so it might lose or gain dependents by the time we call unloadModule();
+    * I think that's ok, our unload can fail if a kext comes in on top of
+    * this one even after we've torn down IOService objects. Conversely,
+    * if we fail the unload here and then lose a library, the autounload
+    * thread will get us in short order.
+    */
+    if (OSKext::isKextWithIdentifierLoaded(moduleName->getCStringNoCopy())) {
+    
+        isLoaded = true;
 
+        if (!OSKext::canUnloadKextWithIdentifier(moduleName,
+            /* checkClasses */ false)) {
+            ret = kOSKextReturnInUse;
+            goto finish;
+        }
+    }
     dict = OSDictionary::withCapacity(1);
-    if ( !dict )
-        return kIOReturnNoMemory;
-
-    dict->setObject(kModuleKey, moduleName);
+    if (!dict) {
+        ret = kIOReturnNoMemory;
+        goto finish;
+    }
 
-    IOTakeLock( lock );
+    dict->setObject(gIOModuleIdentifierKey, moduleName);
 
-    ret = _terminateDrivers(array, dict);
-    kernelTables->reset();
+    ret = _terminateDrivers(dict);
+    
+   /* No goto between IOLock calls!
+    */
+    IORWLockWrite(lock);
+    if (kIOReturnSuccess == ret) {
+        ret = _removeDrivers(dict);
+    }
 
     // Unload the module itself.
-    if ( unload && ret == kIOReturnSuccess ) {
-        // Do kmod stop first.
+    if (unload && isLoaded && ret == kIOReturnSuccess) {
         ret = unloadModule(moduleName);
     }
 
-    IOUnlock( lock );
+    IORWLockUnlock(lock);
 
     dict->release();
 
+finish:
     return ret;
 }
 
 IOReturn IOCatalogue::terminateDriversForModule(
-                                      const char * moduleName,
-                                      bool unload )
+    const char * moduleName,
+    bool unload)
 {
     OSString * name;
     IOReturn ret;
@@ -728,8 +700,12 @@ IOReturn IOCatalogue::terminateDriversForModule(
 
 bool IOCatalogue::startMatching( OSDictionary * matching )
 {
+    OSCollectionIterator * iter;
     OSDictionary         * dict;
     OSOrderedSet         * set;
+    OSArray              * array;
+    const OSSymbol *       key;
+    unsigned int           idx;
     
     if ( !matching )
         return false;
@@ -739,191 +715,210 @@ bool IOCatalogue::startMatching( OSDictionary * matching )
     if ( !set )
         return false;
 
-    IOTakeLock( lock );
-    kernelTables->reset();
-
-    while ( (dict = (OSDictionary *)kernelTables->getNextObject()) ) {
+    iter = OSCollectionIterator::withCollection(personalities);
+    if (!iter) 
+    {
+       set->release();
+        return false;
+    }
 
-       /* This comparison must be done with only the keys in the
-        * "matching" dict to enable general matching.
-        */
-        if ( dict->isEqualTo(matching, matching) )
-            AddNewImports(set, dict);
+    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 matching.
+           */
+            if (dict->isEqualTo(matching, matching)) {
+                set->setObject(dict);
+            }        
+        }
     }
+
     // Start device matching.
     if ( set->getCount() > 0 ) {
         IOService::catalogNewDrivers(set);
         generation++;
     }
 
-    IOUnlock( lock );
+    IORWLockUnlock(lock);
 
     set->release();
+    iter->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();
+    IOCatalogue::resetAndAddDrivers(/* no drivers; true reset */ NULL,
+        /* doMatching */ false);
+    return;
 }
 
-bool IOCatalogue::serialize(OSSerialize * s) const
+bool IOCatalogue::resetAndAddDrivers(OSArray * drivers, bool doNubMatching)
 {
-    bool                   ret;
-    
-    if ( !s )
-        return false;
-
-    IOTakeLock( lock );
-    ret = array->serialize(s);
-    IOUnlock( lock );
-
-    return ret;
-}
+    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
+    signed int             idx, newIdx;
+
+    if (drivers) {
+        newPersonalities = OSDynamicCast(OSArray, drivers);
+        if (!newPersonalities) {
+            goto finish;
+        }
+        
+        matchSet = OSOrderedSet::withCapacity(10, IOServiceOrdering,
+            (void *)gIOProbeScoreKey);
+        if (!matchSet) {
+            goto finish;
+        }
+        iter = OSCollectionIterator::withCollection(personalities);
+        if (!iter) {
+            goto finish;
+        }
+    }
 
+    result = true;
 
-bool IOCatalogue::recordStartupExtensions(void) {
-    bool result = false;
+    IOLog("Resetting IOCatalogue.\n");
 
-    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;
+   /* 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;
+            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
+            * pesonality or the other.
+            */
+                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 ( isModuleLoaded(thisOldPersonality) == false ) 
+                {
+                    if (matchSet)  matchSet->setObject(thisOldPersonality);
+                    array->removeObject(idx);
+                    idx--;
+                }
+            }
+        }
     }
-    IOLockUnlock(kld_lock);
 
-    return result;
-}
+     // add new
+     for (newIdx = 0;
+          (thisNewPersonality = (OSDictionary *) newPersonalities->getObject(newIdx)); 
+          newIdx++)
+     {
+         OSKext::uniquePersonalityProperties(thisNewPersonality);
+         addPersonality(thisNewPersonality);
+         matchSet->setObject(thisNewPersonality);
+     }
+
+   /* Finally, start device matching on all new & removed personalities.
+    */
+    if (result && doNubMatching && (matchSet->getCount() > 0)) {
+        IOService::catalogNewDrivers(matchSet);
+        generation++;
+    }
 
+    IORWLockUnlock(lock);
 
-/*********************************************************************
-*********************************************************************/
-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);
+finish:
+    if (matchSet) matchSet->release();
+    if (iter)     iter->release();
 
     return result;
 }
 
+bool IOCatalogue::serialize(OSSerialize * s) const
+{
+    if ( !s )
+        return false;
 
-/*********************************************************************
-* 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.
-*********************************************************************/
-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");
+    return super::serialize(s);
+}
 
-    kernelLinkerPresent = 0;
+bool IOCatalogue::serializeData(IOOptionBits kind, OSSerialize * s) const
+{
+    kern_return_t kr = kIOReturnSuccess;
 
-   /* Set the kmod_load_extension function as the means for loading
-    * a kernel extension.
-    */
-    kmod_load_function = &kmod_load_extension;
+    switch ( kind )
+    {
+        case kIOCatalogGetContents:
+            kr = KERN_NOT_SUPPORTED;
+            break;
 
-    record_startup_extensions_function = 0;
-    add_from_mkext_function = 0;
-    remove_startup_extension_function = 0;
+        case kIOCatalogGetModuleDemandList:
+            kr = KERN_NOT_SUPPORTED;
+            break;
 
+        case kIOCatalogGetCacheMissList:
+            kr = KERN_NOT_SUPPORTED;
+            break;
 
-   /* 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) {
-        IOLog("error removing kernel linker: can't find __KLD segment\n");
-        result = KERN_FAILURE;
-        goto finish;
-    }
-    OSRuntimeUnloadCPPForSegment(segment);
+        case kIOCatalogGetROMMkextList:
+            kr = KERN_NOT_SUPPORTED;
+            break;
 
-    segment = getsegbynamefromheader(
-        &_mh_execute_header, "__LINKEDIT");
-    if (!segment) {
-        IOLog("error removing kernel linker: can't find __LINKEDIT segment\n");
-        result = KERN_FAILURE;
-        goto finish;
+        default:
+            kr = kIOReturnBadArgument;
+            break;
     }
-    OSRuntimeUnloadCPPForSegment(segment);
 
+    return kr;
+}
 
-   /* 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);
-    }
+#if PRAGMA_MARK
+#pragma mark Obsolete Kext Loading Stuff
+#endif
+/*********************************************************************
+**********************************************************************
+***                  BINARY COMPATIBILITY SECTION                  ***
+**********************************************************************
+**********************************************************************
+* These functions are no longer used are necessary for C++ binary
+* compatibility on i386.
+**********************************************************************/
+#if __i386__
 
+bool IOCatalogue::recordStartupExtensions(void)
+{  return false;  }
 
-finish:
+bool IOCatalogue::addExtensionsFromArchive(OSData * mkext)
+{  return KERN_NOT_SUPPORTED;  }
 
-   /* This must be the very last thing done before returning.
-    */
-    IOLockUnlock(kld_lock);
+kern_return_t IOCatalogue::removeKernelLinker(void)
+{  return KERN_NOT_SUPPORTED;  }
 
-    return result;
-}
+#endif /* __i386__ */