]> git.saurik.com Git - apple/xnu.git/blobdiff - iokit/Kernel/IOCatalogue.cpp
xnu-1504.9.17.tar.gz
[apple/xnu.git] / iokit / Kernel / IOCatalogue.cpp
index 73d4bb5ab27f96a5f1f7c44ba7b40672bb9d043c..8c51eed8472570af85d563a859785dffc1ebf317 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998-2004 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 1998-2006 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  * 
  * @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>
-
-
-extern "C" {
-int IODTGetLoaderInfo( char *key, void **infoAddr, int *infoSize );
-extern void IODTFreeLoaderInfo( char *key, void *infoAddr, int infoSize );
-/* operates on 32 bit segments */
-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;
-};
-
+#include <libkern/c++/OSContainers.h>
+#include <libkern/c++/OSUnserialize.h>
+#include <libkern/c++/OSKext.h>
+#include <libkern/OSKextLibPrivate.h>
 
-/*****
- * 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;
+#include <IOKit/IODeviceTreeSupport.h>
+#include <IOKit/IOService.h>
+#include <IOKit/IOCatalogue.h>
 
-#define kModuleKey "CFBundleIdentifier"
+#include <IOKit/IOLib.h>
+#include <IOKit/assert.h>
 
-#define super OSObject
-OSDefineMetaClassAndStructors(IOCatalogue, OSObject)
+#if PRAGMA_MARK
+#pragma mark Internal Declarations
+#endif
+/*********************************************************************
+*********************************************************************/
 
 #define CATALOGTEST 0
 
@@ -92,340 +69,60 @@ IOCatalogue    * gIOCatalogue;
 const OSSymbol * gIOClassKey;
 const OSSymbol * gIOProbeScoreKey;
 const OSSymbol * gIOModuleIdentifierKey;
-OSSet *          gIOCatalogModuleRequests;
-OSSet *          gIOCatalogCacheMisses;
-OSSet *                 gIOCatalogROMMkexts;
-IOLock *        gIOCatalogLock;
-IOLock *        gIOKLDLock;
+IOLock         * gIOCatalogLock;
 
+#if PRAGMA_MARK
+#pragma mark Utility functions
+#endif
 /*********************************************************************
 *********************************************************************/
-
-OSArray * gIOPrelinkedModules = 0;
-
-extern "C" kern_return_t
-kmod_create_internal(
-            kmod_info_t *info,
-            kmod_t *id);
-
-extern "C" kern_return_t
-kmod_destroy_internal(kmod_t id);
-
-extern "C" kern_return_t
-kmod_start_or_stop(
-    kmod_t id,
-    int start,
-    kmod_args_t *data,
-    mach_msg_type_number_t *dataCount);
-
-extern "C" kern_return_t kmod_retain(kmod_t id);
-extern "C" kern_return_t kmod_release(kmod_t id);
-
-static 
-kern_return_t start_prelink_module(UInt32 moduleIndex)
+static void
+UniqueProperties(OSDictionary * dict)
 {
-    kern_return_t  kr = KERN_SUCCESS;
-    UInt32 *       togo;
-    SInt32        count, where, end;
-    UInt32 *       prelink;
-    SInt32        next, lastDep;
-    OSData *       data;
-    OSString *     str;
-    OSDictionary * dict;
-
-    OSArray *
-    prelinkedModules = gIOPrelinkedModules;
+    OSString * data;
 
-    togo    = IONew(UInt32, prelinkedModules->getCount());
-    togo[0] = moduleIndex;
-    count   = 1;
+    data = OSDynamicCast(OSString, dict->getObject(gIOClassKey));
+    if (data) {
+        const OSSymbol *classSymbol = OSSymbol::withString(data);
 
-    for (next = 0; next < count; next++)
-    {
-       dict = (OSDictionary *) prelinkedModules->getObject(togo[next]);
-
-       data = OSDynamicCast(OSData, dict->getObject("OSBundlePrelink"));
-       if (!data)
-       {
-           // already started or no code
-           if (togo[next] == moduleIndex)
-           {
-               kr = KERN_FAILURE;
-               break;
-           }
-           continue;
-       }
-       prelink = (UInt32 *) data->getBytesNoCopy();
-       lastDep = OSReadBigInt32(prelink, 12);
-       for (SInt32 idx = OSReadBigInt32(prelink, 8); idx < lastDep; idx += sizeof(UInt32))
-       {
-           UInt32 depIdx = OSReadBigInt32(prelink, idx) - 1;
-
-           for (where = next + 1;
-                (where < count) && (togo[where] > depIdx);
-                where++)       {}
-
-           if (where != count)
-           {
-               if (togo[where] == depIdx)
-                   continue;
-               for (end = count; end != where; end--)
-                   togo[end] = togo[end - 1];
-           }
-           count++;
-           togo[where] = depIdx;
-       }
+        dict->setObject( gIOClassKey, (OSSymbol *) classSymbol);
+        classSymbol->release();
     }
 
-    if (KERN_SUCCESS != kr)
-       return kr;
-
-    for (next = (count - 1); next >= 0; next--)
-    {
-       dict = (OSDictionary *) prelinkedModules->getObject(togo[next]);
-
-       data = OSDynamicCast(OSData, dict->getObject("OSBundlePrelink"));
-       if (!data)
-           continue;
-       prelink = (UInt32 *) data->getBytesNoCopy();
-    
-       kmod_t id;
-       kmod_info_t * kmod_info = (kmod_info_t *) OSReadBigInt32(prelink, 0);
-
-       kr = kmod_create_internal(kmod_info, &id);
-       if (KERN_SUCCESS != kr)
-           break;
-
-       lastDep = OSReadBigInt32(prelink, 12);
-       for (SInt32 idx = OSReadBigInt32(prelink, 8); idx < lastDep; idx += sizeof(UInt32))
-       {
-           OSDictionary * depDict;
-           kmod_info_t *  depInfo;
-
-           depDict = (OSDictionary *) prelinkedModules->getObject(OSReadBigInt32(prelink, idx) - 1);
-           str = OSDynamicCast(OSString, depDict->getObject(kModuleKey));
-           depInfo = kmod_lookupbyname_locked(str->getCStringNoCopy());
-           if (depInfo)
-           {
-               kr = kmod_retain(KMOD_PACK_IDS(id, depInfo->id));
-               kfree(depInfo, sizeof(kmod_info_t));
-           } else
-               IOLog("%s: NO DEP %s\n", kmod_info->name, str->getCStringNoCopy());
-       }
-       dict->removeObject("OSBundlePrelink");
+    data = OSDynamicCast(OSString, dict->getObject(gIOMatchCategoryKey));
+    if (data) {
+        const OSSymbol *classSymbol = OSSymbol::withString(data);
 
-       if (kmod_info->start)
-           kr = kmod_start_or_stop(kmod_info->id, 1, 0, 0);
+        dict->setObject(gIOMatchCategoryKey, (OSSymbol *) classSymbol);
+        classSymbol->release();
     }
-
-    IODelete(togo, UInt32, prelinkedModules->getCount());
-
-    return kr;
+    return;
 }
 
 /*********************************************************************
-* This is a function that IOCatalogue calls in order to load a kmod.
+* 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 
-kern_return_t kmod_load_from_cache_sym(const OSSymbol * kmod_name)
-{
-    OSArray *      prelinkedModules = gIOPrelinkedModules;
-    kern_return_t  result = KERN_FAILURE;
-    OSDictionary * dict;
-    OSObject *     ident;
-    UInt32        idx;
-
-    if (!gIOPrelinkedModules)
-       return KERN_FAILURE;
-
-    for (idx = 0; 
-        (dict = (OSDictionary *) prelinkedModules->getObject(idx));
-        idx++)
-    {
-       if ((ident = dict->getObject(kModuleKey))
-        && kmod_name->isEqualTo(ident))
-           break;
-    }
-    if (dict) 
-    {
-       if (kernelLinkerPresent && dict->getObject("OSBundleDefer"))
-       {
-           kmod_load_extension((char *) kmod_name->getCStringNoCopy());
-           result = kIOReturnOffline;
-       }
-       else
-           result = start_prelink_module(idx);
-    }
-
-    return result;
-}
-
-extern "C" Boolean kmod_load_request(const char * moduleName, Boolean make_request)
-{
-    bool               ret, cacheMiss = false;
-    kern_return_t      kr;
-    const OSSymbol *   sym = 0;
-    kmod_info_t *      kmod_info;
-
-    if (!moduleName)
-        return false;
-
-    /* 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(gIOKLDLock);
-    do
-    {
-       // Is the module already loaded?
-       ret = (0 != (kmod_info = kmod_lookupbyname_locked((char *)moduleName)));
-       if (ret) {
-           kfree(kmod_info, sizeof(kmod_info_t));
-           break;
-       }
-       sym = OSSymbol::withCString(moduleName);
-       if (!sym) {
-           ret = false;
-           break;
-       }
-
-       kr = kmod_load_from_cache_sym(sym);
-       ret = (kIOReturnSuccess == kr);
-       cacheMiss = !ret;
-       if (ret || !make_request || (kr == kIOReturnOffline))
-           break;
-
-        // If the module hasn't been loaded, then load it.
-        if (!kmod_load_function) {
-            IOLog("IOCatalogue: %s cannot be loaded "
-                "(kmod load function not set).\n",
-                moduleName);
-           ret = true;
-           break;
-       }
-
-       kr = 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);
-           }
-           ret = false;
-
-       } else if (kernelLinkerPresent) {
-           // If kern linker is here, the driver is actually loaded,
-           // so return true.
-           ret = true;
-
-       } else {
-           // kern linker isn't here, a request has been queued
-           // but the module isn't necessarily loaded yet, so stall.
-           ret = false;
-       }
-    }
-    while (false);
-
-    IOLockUnlock(gIOKLDLock);
-
-    if (sym)
-    {
-       IOLockLock(gIOCatalogLock);
-       gIOCatalogModuleRequests->setObject(sym);
-       if (cacheMiss)
-           gIOCatalogCacheMisses->setObject(sym);
-       IOLockUnlock(gIOCatalogLock);
-    }
-
-    return ret;
-}
-
-extern "C" kern_return_t kmod_unload_cache(void)
-{
-    OSArray *      prelinkedModules = gIOPrelinkedModules;
-    kern_return_t  result = KERN_FAILURE;
-    OSDictionary * dict;
-    UInt32        idx;
-    UInt32 *       prelink;
-    OSData *       data;
-
-    if (!gIOPrelinkedModules)
-       return KERN_SUCCESS;
-
-    IOLockLock(gIOKLDLock);
-    for (idx = 0; 
-        (dict = (OSDictionary *) prelinkedModules->getObject(idx));
-        idx++)
-    {
-       data = OSDynamicCast(OSData, dict->getObject("OSBundlePrelink"));
-       if (!data)
-           continue;
-       prelink = (UInt32 *) data->getBytesNoCopy();
-    
-       kmod_info_t * kmod_info = (kmod_info_t *) OSReadBigInt32(prelink, 0);
-       vm_offset_t
-       virt = ml_static_ptovirt(kmod_info->address);
-       if( virt) {
-           ml_static_mfree(virt, kmod_info->size);
-       }
-    }
-
-    gIOPrelinkedModules->release();
-    gIOPrelinkedModules = 0;
-
-    IOLockUnlock(gIOKLDLock);
-
-    return result;
-}
-
-extern "C" kern_return_t kmod_load_from_cache(const char * kmod_name)
+static void
+AddNewImports(OSOrderedSet * set, OSDictionary * dict)
 {
-    kern_return_t kr;
-    const OSSymbol * sym = OSSymbol::withCStringNoCopy(kmod_name);
-
-    if (sym)
-    {
-       kr = kmod_load_from_cache_sym(sym);
-       sym->release();
-    }
-    else
-       kr = kIOReturnNoMemory;
-
-    return kr;
+    set->setObject(dict);
 }
 
+#if PRAGMA_MARK
+#pragma mark IOCatalogue class implementation
+#endif
 /*********************************************************************
 *********************************************************************/
 
-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();
-    }
-}
+#define super OSObject
+OSDefineMetaClassAndStructors(IOCatalogue, OSObject)
 
-void IOCatalogue::initialize( void )
+/*********************************************************************
+*********************************************************************/
+void IOCatalogue::initialize(void)
 {
     OSArray              * array;
     OSString             * errorString;
@@ -435,20 +132,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 );
-    gIOModuleIdentifierKey   = OSSymbol::withCStringNoCopy( kModuleKey );
-    gIOCatalogModuleRequests = OSSet::withCapacity(16);
-    gIOCatalogCacheMisses    = OSSet::withCapacity(16);
-    gIOCatalogROMMkexts      = OSSet::withCapacity(4);
+    gIOModuleIdentifierKey   = OSSymbol::withCStringNoCopy( kCFBundleIdentifierKey );
 
     assert( array && gIOClassKey && gIOProbeScoreKey 
-           && gIOModuleIdentifierKey && gIOCatalogModuleRequests);
+           && gIOModuleIdentifierKey);
 
     gIOCatalogue = new IOCatalogue;
     assert(gIOCatalogue);
@@ -457,7 +151,9 @@ void IOCatalogue::initialize( void )
     array->release();
 }
 
-// Initialize the IOCatalog object.
+/*********************************************************************
+* Initialize the IOCatalog object.
+*********************************************************************/
 bool IOCatalogue::init(OSArray * initArray)
 {
     OSDictionary         * dict;
@@ -472,10 +168,11 @@ bool IOCatalogue::init(OSArray * initArray)
     kernelTables = OSCollectionIterator::withCollection( array );
 
     gIOCatalogLock = IOLockAlloc();
-    gIOKLDLock     = IOLockAlloc();
 
     lock     = gIOCatalogLock;
-    kld_lock = gIOKLDLock;
+#if __ppc__ || __i386__
+    kld_lock = NULL;
+#endif /* __ppc__ || __i386__ */
 
     kernelTables->reset();
     while( (dict = (OSDictionary *) kernelTables->getNextObject())) {
@@ -494,8 +191,10 @@ bool IOCatalogue::init(OSArray * initArray)
     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 )
@@ -507,13 +206,15 @@ void IOCatalogue::free( void )
     super::free();
 }
 
+/*********************************************************************
+*********************************************************************/
 #if CATALOGTEST
 
 static int hackLimit;
-
 enum { kDriversPerIter = 4 };
 
-void IOCatalogue::ping( thread_call_param_t arg, thread_call_param_t)
+void
+IOCatalogue::ping(thread_call_param_t arg, thread_call_param_t)
 {
     IOCatalogue         * self = (IOCatalogue *) arg;
     OSOrderedSet         * set;
@@ -530,7 +231,7 @@ void IOCatalogue::ping( thread_call_param_t arg, thread_call_param_t)
        if( table) {
            set->setLastObject( table );
 
-           OSSymbol * sym = (OSSymbol *) table->getObject( gIOClassKey );
+           OSSymbol * sym = (OSSymbol *) table->getObject(gIOClassKey);
            kprintf("enabling %s\n", sym->getCStringNoCopy());
 
        } else {
@@ -548,14 +249,18 @@ void IOCatalogue::ping( thread_call_param_t arg, thread_call_param_t)
 
     if( kDriversPerIter == newLimit) {
         AbsoluteTime deadline;
-        clock_interval_to_deadline( 500, kMillisecondScale );
-        thread_call_func_delayed( ping, this, deadline );
+        clock_interval_to_deadline(500, kMillisecondScale);
+        thread_call_func_delayed(ping, this, deadline);
     }
 }
 #endif
 
-OSOrderedSet * IOCatalogue::findDrivers( IOService * service,
-                                       SInt32 * generationCount )
+/*********************************************************************
+*********************************************************************/
+OSOrderedSet *
+IOCatalogue::findDrivers(
+    IOService * service,
+    SInt32 * generationCount)
 {
     OSDictionary         * nextTable;
     OSOrderedSet         * set;
@@ -566,7 +271,7 @@ OSOrderedSet * IOCatalogue::findDrivers( IOService * service,
     if( !set )
        return( 0 );
 
-    IOLockLock( lock );
+    IOLockLock(lock);
     kernelTables->reset();
 
 #if CATALOGTEST
@@ -585,14 +290,18 @@ OSOrderedSet * IOCatalogue::findDrivers( IOService * service,
 
     *generationCount = getGenerationCount();
 
-    IOLockUnlock( lock );
+    IOLockUnlock(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)
 {
     OSDictionary         * dict;
     OSOrderedSet         * set;
@@ -602,7 +311,7 @@ OSOrderedSet * IOCatalogue::findDrivers( OSDictionary * matching,
     set = OSOrderedSet::withCapacity( 1, IOServiceOrdering,
                                       (void *)gIOProbeScoreKey );
 
-    IOLockLock( lock );
+    IOLockLock(lock);
     kernelTables->reset();
     while ( (dict = (OSDictionary *) kernelTables->getNextObject()) ) {
 
@@ -613,108 +322,111 @@ OSOrderedSet * IOCatalogue::findDrivers( OSDictionary * matching,
             set->setObject(dict);
     }
     *generationCount = getGenerationCount();
-    IOLockUnlock( lock );
+    IOLockUnlock(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 )
+/*********************************************************************
+* 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)
 {
-    OSCollectionIterator * iter;
-    OSDictionary         * dict;
-    OSOrderedSet         * set;
-    OSArray              * persons;
-    OSString             * moduleName;
-    bool                   ret;
+    bool                   result = false;
+    OSCollectionIterator * iter = NULL;       // must release
+    OSOrderedSet         * set = NULL;        // must release
+    OSDictionary         * dict = NULL;       // do not release
+    OSArray              * persons = NULL;    // do not release
 
-    ret = true;
     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;
     }
 
-    IOLockLock( lock );
-    while ( (dict = (OSDictionary *) iter->getNextObject()) )
-    {
-       if ((moduleName = OSDynamicCast(OSString, dict->getObject("OSBundleModuleDemand"))))
-       {
-           IOLockUnlock( lock );
-           ret = kmod_load_request(moduleName->getCStringNoCopy(), false);
-           IOLockLock( lock );
-           ret = true;
-       }
-       else
-       {
-           SInt count;
-           
-           UniqueProperties( dict );
-    
-           // Add driver personality to catalogue.
-           count = array->getCount();
-           while ( count-- ) {
-               OSDictionary * driver;
-    
-               // Be sure not to double up on personalities.
-               driver = (OSDictionary *)array->getObject(count);
-    
-           /* Unlike in other functions, this comparison must be exact!
-               * The catalogue must be able to contain personalities that
-               * are proper supersets of others.
-               * Do not compare just the properties present in one driver
-               * pesonality or the other.
-               */
-               if (dict->isEqualTo(driver))
-                   break;
-           }
-           if (count >= 0)
-               // its a dup
-               continue;
-           
-           ret = array->setObject( dict );
-           if (!ret)
-               break;
+    iter = OSCollectionIterator::withCollection(persons);
+    if (!iter) {
+        goto finish;
+    }
+
+    result = true;
+
+    IOLockLock(lock);
+    while ( (dict = (OSDictionary *) iter->getNextObject()) ) {
     
-           AddNewImports( set, dict );
-       }
+        // xxx Deleted OSBundleModuleDemand check; will handle in other ways for SL
+
+        SInt count;
+        
+        UniqueProperties(dict);
+        
+        // Add driver personality to catalogue.
+        count = array->getCount();
+        while (count--) {
+            OSDictionary * driver;
+            
+            // Be sure not to double up on personalities.
+            driver = (OSDictionary *)array->getObject(count);
+            
+           /* Unlike in other functions, this comparison must be exact!
+            * The catalogue must be able to contain personalities that
+            * are proper supersets of others.
+            * Do not compare just the properties present in one driver
+            * pesonality or the other.
+            */
+            if (dict->isEqualTo(driver)) {
+                break;
+            }
+        }
+        if (count >= 0) {
+            // its a dup
+            continue;
+        }
+        
+        result = array->setObject(dict);
+        if (!result) {
+            break;
+        }
+        
+        AddNewImports(set, dict);
     }
     // Start device matching.
     if (doNubMatching && (set->getCount() > 0)) {
-        IOService::catalogNewDrivers( set );
+        IOService::catalogNewDrivers(set);
         generation++;
     }
-    IOLockUnlock( lock );
+    IOLockUnlock(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)
+/*********************************************************************
+* Remove drivers from the catalog which match the
+* properties in the matching dictionary.
+*********************************************************************/
+bool
+IOCatalogue::removeDrivers(
+    OSDictionary * matching,
+    bool doNubMatching)
 {
     OSCollectionIterator * tables;
     OSDictionary         * dict;
@@ -745,7 +457,7 @@ bool IOCatalogue::removeDrivers( OSDictionary * matching,
 
     UniqueProperties( matching );
 
-    IOLockLock( lock );
+    IOLockLock(lock);
     kernelTables->reset();
     arrayCopy->merge(array);
     array->flushCollection();
@@ -767,7 +479,7 @@ bool IOCatalogue::removeDrivers( OSDictionary * matching,
         IOService::catalogNewDrivers(set);
         generation++;
     }
-    IOLockUnlock( lock );
+    IOLockUnlock(lock);
     
     set->release();
     tables->release();
@@ -776,29 +488,48 @@ bool IOCatalogue::removeDrivers( OSDictionary * matching,
 }
 
 // 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
 {
-    return (kmod_load_request(moduleName, true));
+    OSReturn ret;
+    ret = OSKext::loadKextWithIdentifier(moduleName);
+    if (kOSKextReturnDeferred == ret) {
+        // a request has been queued but the module isn't necessarily 
+        // loaded yet, so stall.
+        return false;
+    }
+    // module is present or never will be 
+    return true;
 }
 
 // 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;
 
+    /* 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);
@@ -809,56 +540,39 @@ 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(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( OSDictionary * matching )
+static IOReturn _terminateDrivers(OSDictionary * matching)
 {
     OSDictionary         * dict;
     OSIterator           * iter;
@@ -942,55 +656,82 @@ static IOReturn _removeDrivers( OSArray * array, OSDictionary * matching )
     return ret;
 }
 
-IOReturn IOCatalogue::terminateDrivers( OSDictionary * matching )
+IOReturn IOCatalogue::terminateDrivers(OSDictionary * matching)
 {
     IOReturn ret;
 
     ret = _terminateDrivers(matching);
-    IOLockLock( lock );
+    IOLockLock(lock);
     if (kIOReturnSuccess == ret)
        ret = _removeDrivers(array, matching);
     kernelTables->reset();
-    IOLockUnlock( lock );
+    IOLockUnlock(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;
+    if (!dict) {
+        ret = kIOReturnNoMemory;
+        goto finish;
+    }
 
     dict->setObject(gIOModuleIdentifierKey, moduleName);
 
     ret = _terminateDrivers(dict);
-    IOLockLock( lock );
-    if (kIOReturnSuccess == ret)
-       ret = _removeDrivers(array, dict);
+    
+   /* No goto between IOLock calls!
+    */
+    IOLockLock(lock);
+    if (kIOReturnSuccess == ret) {
+        ret = _removeDrivers(array, dict);
+    }
     kernelTables->reset();
 
     // Unload the module itself.
-    if ( unload && ret == kIOReturnSuccess ) {
-        // Do kmod stop first.
+    if (unload && isLoaded && ret == kIOReturnSuccess) {
         ret = unloadModule(moduleName);
     }
 
-    IOLockUnlock( lock );
+    IOLockUnlock(lock);
 
     dict->release();
 
+finish:
     return ret;
 }
 
 IOReturn IOCatalogue::terminateDriversForModule(
-                                      const char * moduleName,
-                                      bool unload )
+    const char * moduleName,
+    bool unload)
 {
     OSString * name;
     IOReturn ret;
@@ -1018,7 +759,7 @@ bool IOCatalogue::startMatching( OSDictionary * matching )
     if ( !set )
         return false;
 
-    IOLockLock( lock );
+    IOLockLock(lock);
     kernelTables->reset();
 
     while ( (dict = (OSDictionary *)kernelTables->getNextObject()) ) {
@@ -1035,7 +776,7 @@ bool IOCatalogue::startMatching( OSDictionary * matching )
         generation++;
     }
 
-    IOLockUnlock( lock );
+    IOLockUnlock(lock);
 
     set->release();
 
@@ -1062,39 +803,20 @@ bool IOCatalogue::serializeData(IOOptionBits kind, OSSerialize * s) const
     switch ( kind )
     {
         case kIOCatalogGetContents:
-            if (!serialize(s))
+            if (!array->serialize(s))
                 kr = kIOReturnNoMemory;
             break;
 
         case kIOCatalogGetModuleDemandList:
-           IOLockLock( lock );
-            if (!gIOCatalogModuleRequests->serialize(s))
-                kr = kIOReturnNoMemory;
-           IOLockUnlock( lock );
+            kr = KERN_NOT_SUPPORTED;
             break;
 
         case kIOCatalogGetCacheMissList:
-           IOLockLock( lock );
-            if (!gIOCatalogCacheMisses->serialize(s))
-                kr = kIOReturnNoMemory;
-           IOLockUnlock( lock );
+            kr = KERN_NOT_SUPPORTED;
             break;
 
         case kIOCatalogGetROMMkextList:
-           IOLockLock( lock );
-
-           if (!gIOCatalogROMMkexts || !gIOCatalogROMMkexts->getCount())
-               kr = kIOReturnNoResources;
-            else if (!gIOCatalogROMMkexts->serialize(s))
-                kr = kIOReturnNoMemory;
-
-           if (gIOCatalogROMMkexts)
-           {
-               gIOCatalogROMMkexts->release();
-               gIOCatalogROMMkexts = 0;
-           }
-
-           IOLockUnlock( lock );
+            kr = KERN_NOT_SUPPORTED;
             break;
 
         default:
@@ -1106,181 +828,26 @@ bool IOCatalogue::serializeData(IOOptionBits kind, OSSerialize * s) const
 }
 
 
-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;
-}
-
-
-/*********************************************************************
-* This function operates on sections retrieved from the currently running
-* 32 bit mach kernel.
-*********************************************************************/
-bool IOCatalogue::addExtensionsFromArchive(OSData * mkext)
-{
-    OSData * copyData;
-    bool result = false;
-    bool prelinked;
-
-   /* The mkext we've been handed (or the data it references) can go away,
-    * so we need to make a local copy to keep around as long as it might
-    * be needed.
-    */
-    copyData = OSData::withData(mkext);
-    if (copyData)
-    {
-       struct section * infosect;
-    
-       infosect  = getsectbyname("__PRELINK", "__info");
-       prelinked = (infosect && infosect->addr && infosect->size);
-
-       IOLockLock(kld_lock);
-
-       if (gIOCatalogROMMkexts)
-           gIOCatalogROMMkexts->setObject(copyData);
-
-       if (prelinked) {
-           result = true;
-       } else if (kernelLinkerPresent && add_from_mkext_function) {
-           result = (*add_from_mkext_function)(copyData);
-       } else {
-           IOLog("Can't add startup extensions from archive; "
-               "kernel linker is not present.\n");
-           result = false;
-       }
-
-       IOLockUnlock(kld_lock);
-
-       copyData->release();
-    }
-
-    return result;
-}
-
-
+#if PRAGMA_MARK
+#pragma mark Obsolete Kext Loading Stuff
+#endif
 /*********************************************************************
-* 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.
-*
-* The segments it operates on are strictly 32 bit segments.
-*********************************************************************/
-kern_return_t IOCatalogue::removeKernelLinker(void) {
-    kern_return_t result = KERN_SUCCESS;
-    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 = getsegbyname("__KLD");
-    if (!segment) {
-        IOLog("error removing kernel linker: can't find %s segment\n",
-            "__KLD");
-        result = KERN_FAILURE;
-        goto finish;
-    }
-    OSRuntimeUnloadCPPForSegment(segment);
-
-    segment = getsegbyname("__LINKEDIT");
-    if (!segment) {
-        IOLog("error removing kernel linker: can't find %s segment\n",
-            "__LINKEDIT");
-        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);
-    }
+**********************************************************************
+***                  BINARY COMPATIBILITY SECTION                  ***
+**********************************************************************
+**********************************************************************
+* These functions are no longer used are necessary for C++ binary
+* compatibility on ppc/i386.
+**********************************************************************/
+#if __ppc__ || __i386__
+
+bool IOCatalogue::recordStartupExtensions(void)
+{  return false;  }
 
-    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);
-    }
-
-    struct section * sect;
-    sect = getsectbyname("__PRELINK", "__symtab");
-    if (sect && sect->addr)
-    {
-       vm_offset_t
-       virt = ml_static_ptovirt(sect->addr);
-       if( virt) {
-           ml_static_mfree(virt, sect->size);
-       }
-    }
-
-finish:
-
-   /* This must be the very last thing done before returning.
-    */
-    IOLockUnlock(kld_lock);
-
-    return result;
-}
-
-/*********************************************************************
-* This function stops the catalogue from making kextd requests during
-* shutdown.
-*********************************************************************/
-void IOCatalogue::disableExternalLinker(void) {
-    IOLockLock(gIOKLDLock);
-   /* If kmod_load_extension (the kextd requester function) is in use,
-    * disable new module requests.
-    */
-    if (kmod_load_function == &kmod_load_extension) {
-       kmod_load_function = NULL;
-    }
+bool IOCatalogue::addExtensionsFromArchive(OSData * mkext)
+{  return KERN_NOT_SUPPORTED;  }
 
-    IOLockUnlock(gIOKLDLock);
-}
+kern_return_t IOCatalogue::removeKernelLinker(void)
+{  return KERN_NOT_SUPPORTED;  }
 
+#endif /* __ppc__ || __i386__ */