]> git.saurik.com Git - apple/xnu.git/blobdiff - iokit/Kernel/IOCatalogue.cpp
xnu-6153.61.1.tar.gz
[apple/xnu.git] / iokit / Kernel / IOCatalogue.cpp
index 7ca1e8c466a410f28d6c16ed0da5eefaa7719375..7c0201e4df7c2381f379c5e62bde771231810414 100644 (file)
@@ -1,8 +1,8 @@
 /*
- * Copyright (c) 1998-2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 1998-2012 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
- * 
+ *
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
  * unlawful or unlicensed copies of an Apple operating system, or to
  * circumvent, violate, or enable the circumvention or violation of, any
  * terms of an Apple operating system software license agreement.
- * 
+ *
  * Please obtain a copy of the License at
  * http://www.opensource.apple.com/apsl/ and read it before using this file.
- * 
+ *
  * The Original Code and all software distributed under the License are
  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
  * Please see the License for the specific language governing rights and
  * limitations under the License.
- * 
+ *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
  */
 /*
- * Copyright (c) 1998 Apple Computer, Inc.  All rights reserved. 
+ * Copyright (c) 1998 Apple Inc.  All rights reserved.
  *
  * HISTORY
  *
  * 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 );
-/* operates on 32 bit segments */
-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;
+const OSSymbol * gIOModuleIdentifierKernelKey;
+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
 
-#define kModuleKey "CFBundleIdentifier"
+#if PRAGMA_MARK
+#pragma mark IOCatalogue class implementation
+#endif
+/*********************************************************************
+*********************************************************************/
 
 #define super OSObject
 OSDefineMetaClassAndStructors(IOCatalogue, OSObject)
 
-#define CATALOGTEST 0
+static bool isModuleLoadedNoOSKextLock(OSDictionary *theKexts,
+    OSDictionary *theModuleDict);
 
-IOCatalogue    * gIOCatalogue;
-const OSSymbol * gIOClassKey;
-const OSSymbol * gIOProbeScoreKey;
-const OSSymbol * gIOModuleIdentifierKey;
-OSSet *          gIOCatalogModuleRequests;
-OSSet *          gIOCatalogCacheMisses;
-OSSet *                 gIOCatalogROMMkexts;
-IOLock *        gIOCatalogLock;
-IOLock *        gIOKLDLock;
 
 /*********************************************************************
 *********************************************************************/
+void
+IOCatalogue::initialize(void)
+{
+       OSArray              * array;
+       OSString             * errorString;
+       bool                   rc;
 
-OSArray * gIOPrelinkedModules = 0;
+       extern const char * gIOKernelConfigTables;
 
-extern "C" kern_return_t
-kmod_create_internal(
-            kmod_info_t *info,
-            kmod_t *id);
+       array = OSDynamicCast(OSArray, OSUnserialize(gIOKernelConfigTables, &errorString));
+       if (!array && errorString) {
+               IOLog("KernelConfigTables syntax error: %s\n",
+                   errorString->getCStringNoCopy());
+               errorString->release();
+       }
 
-extern "C" kern_return_t
-kmod_destroy_internal(kmod_t id);
+       gIOClassKey                  = OSSymbol::withCStringNoCopy( kIOClassKey );
+       gIOProbeScoreKey             = OSSymbol::withCStringNoCopy( kIOProbeScoreKey );
+       gIOModuleIdentifierKey       = OSSymbol::withCStringNoCopy( kCFBundleIdentifierKey );
+       gIOModuleIdentifierKernelKey = OSSymbol::withCStringNoCopy( kCFBundleIdentifierKernelKey );
 
-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);
+       assert( array && gIOClassKey && gIOProbeScoreKey
+           && gIOModuleIdentifierKey);
 
-#if CONFIG_MACF_KEXT
-/* MAC Framework support */
+       gIOCatalogue = new IOCatalogue;
+       assert(gIOCatalogue);
+       rc = gIOCatalogue->init(array);
+       assert(rc);
+       array->release();
+}
 
-/* 
- * define IOC_DEBUG to display run-time debugging information
- * #define IOC_DEBUG 1
- */
+/*********************************************************************
+* Initialize the IOCatalog object.
+*********************************************************************/
+OSArray *
+IOCatalogue::arrayForPersonality(OSDictionary * dict)
+{
+       const OSSymbol * sym;
 
-#ifdef IOC_DEBUG
-#define DPRINTF(x)     printf x
-#else
-#define IOC_DEBUG
-#define DPRINTF(x)
-#endif
+       sym = OSDynamicCast(OSSymbol, dict->getObject(gIOProviderClassKey));
+       if (!sym) {
+               return NULL;
+       }
 
-static bool
-primitive_type(OSObject *obj)
-{
-    const OSMetaClass *typeID;
-
-    typeID = OSTypeIDInst(obj);
-    if (typeID == OSTypeID(OSString) || typeID == OSTypeID(OSNumber) ||
-        typeID == OSTypeID(OSBoolean) || typeID == OSTypeID(OSData))
-       return(true);
-    else
-       return(false);
+       return (OSArray *) personalities->getObject(sym);
 }
 
-static int
-primitive_type_length(OSObject *obj)
+void
+IOCatalogue::addPersonality(OSDictionary * dict)
 {
-    const OSMetaClass *typeID;
-    int len;
-
-    typeID = OSTypeIDInst(obj);
-    if (typeID == OSTypeID(OSString)) {
-        OSString * stringObj = OSDynamicCast(OSString, obj);
-        len = stringObj->getLength() + 1;
-    }
-    else if (typeID == OSTypeID(OSNumber)) {
-        len = sizeof("4294967295");    /* UINT32_MAX */
-    }
-    else if (typeID == OSTypeID(OSBoolean)) {
-        OSBoolean * boolObj = OSDynamicCast(OSBoolean, obj);
-        len = boolObj->isTrue() ? sizeof("true") : sizeof("false");
-    }
-    else if (typeID == OSTypeID(OSData)) {
-        OSData * dataObj = OSDynamicCast(OSData, obj);
-        len = dataObj->getLength();
-    }
-    else {
-       len = 0;
-    }
-    return(len);
-}
+       const OSSymbol * sym;
+       OSArray * arr;
 
-static void
-primitive_type_collect(struct mac_module_data_element *element, OSObject *value)
-{
-    const OSMetaClass *typeID;
-
-    typeID = OSTypeIDInst(value);
-    if (typeID == OSTypeID(OSString)) {
-        OSString *stringObj = OSDynamicCast(OSString, value);
-        element->value_type = MAC_DATA_TYPE_PRIMITIVE;
-        element->value_size = stringObj->getLength() + 1;
-       DPRINTF(("osdict: string %s size %d\n", 
-           stringObj->getCStringNoCopy(), element->value_size));
-        memcpy(element->value, stringObj->getCStringNoCopy(),
-            element->value_size);
-    } else if (typeID == OSTypeID(OSNumber)) {
-        OSNumber *numberObj = OSDynamicCast(OSNumber, value);
-        element->value_type = MAC_DATA_TYPE_PRIMITIVE;
-        element->value_size = sprintf(element->value, "%u",
-           numberObj->unsigned32BitValue()) + 1;
-    } else if (typeID == OSTypeID(OSBoolean)) {
-        OSBoolean *boolObj = OSDynamicCast(OSBoolean, value);
-        element->value_type = MAC_DATA_TYPE_PRIMITIVE;
-        if (boolObj->isTrue()) {
-            strcpy(element->value, "true");
-            element->value_size = 5;
-        } else {
-            strcpy(element->value, "false");
-            element->value_size = 6;
-        }
-    } else if (typeID == OSTypeID(OSData)) {
-        OSData *dataObj = OSDynamicCast(OSData, value);
-        element->value_type = MAC_DATA_TYPE_PRIMITIVE;
-        element->value_size = dataObj->getLength();
-       DPRINTF(("osdict: data size %d\n", dataObj->getLength()));
-        memcpy(element->value, dataObj->getBytesNoCopy(),
-            element->value_size);
-    }
+       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();
+       }
 }
 
 /*********************************************************************
-* This function takes an OSDictionary and returns a struct mac_module_data
-* list.
+* Initialize the IOCatalog object.
 *********************************************************************/
-struct mac_module_data *
-osdict_encode(OSDictionary *dict)
+bool
+IOCatalogue::init(OSArray * initArray)
 {
-    const OSMetaClass * typeID;                    // don't release
-    OSString * key = NULL;                  // don't release
-    OSCollectionIterator * keyIterator = 0; // must release
-    struct mac_module_data * module_data = 0;
-    struct mac_module_data_element * element;
-    unsigned int strtabsize = 0;
-    unsigned int listtabsize = 0;
-    unsigned int dicttabsize = 0;
-    unsigned int nkeys = 0;
-    unsigned int datalen;
-    char *strtab = NULL;
-    char *listtab = NULL;
-    char *dicttab = NULL;
-    vm_offset_t data_addr;
-
-    keyIterator = OSCollectionIterator::withCollection(dict);
-    if (!keyIterator)
-        goto finish;
-
-    /* Iterate over OSModuleData to figure out total size */
-    while ( (key = OSDynamicCast(OSString, keyIterator->getNextObject())) ) {
-
-       // Get the key's value and determine its type
-        OSObject * value = dict->getObject(key);
-        if (!value)
-            continue;
-
-       typeID = OSTypeIDInst(value);
-       if (primitive_type(value)) {
-           strtabsize += primitive_type_length(value);
-       }
-       else if (typeID == OSTypeID(OSArray)) {
-           unsigned int k, cnt, nents;
-           OSArray *arrayObj = OSDynamicCast(OSArray, value);
-
-           nents = 0;
-           cnt = arrayObj->getCount();
-           for (k = 0; k < cnt; k++) {
-               value = arrayObj->getObject(k);
-               typeID = OSTypeIDInst(value);
-               if (primitive_type(value)) {
-                   listtabsize += primitive_type_length(value);
-                   nents++;
-               }
-               else if (typeID == OSTypeID(OSDictionary)) {
-                   unsigned int dents;
-                   OSDictionary *dictObj;
-                   OSString *dictkey;
-                   OSCollectionIterator *dictIterator;
-
-                   dents = 0;
-                   dictObj = OSDynamicCast(OSDictionary, value);
-                   dictIterator = OSCollectionIterator::withCollection(dictObj);
-                   if (!dictIterator)
-                       goto finish;
-                   while ((dictkey = OSDynamicCast(OSString,
-                                             dictIterator->getNextObject()))) {
-                       OSObject *dictvalue;
-
-                       dictvalue = dictObj->getObject(dictkey);
-                       if (!dictvalue)
-                           continue;
-                       if (primitive_type(dictvalue)) {
-                           strtabsize += primitive_type_length(dictvalue);
-                       }
-                       else {
-                           continue;   /* Only handle primitive types here.  */
-                       }
-                       /*
-                        * Allow for the "arraynnn/" prefix in the key length.
-                        */
-                       strtabsize += dictkey->getLength() + 1;
-                       dents++;
-                   }
-                   dictIterator->release();
-                   if (dents-- > 0) {
-                       dicttabsize += sizeof(struct mac_module_data_list) +
-                           dents * sizeof(struct mac_module_data_element);
-                       nents++;
-                   }
-               }
-               else {
-                   continue;           /* Skip everything else.              */
-               }
-           }
-           if (nents == 0)
-               continue;
-           listtabsize += sizeof(struct mac_module_data_list) +
-               (nents - 1) * sizeof(struct mac_module_data_element);
-       }
-       else {
-           continue;           /* skip anything else */
-       }
-       strtabsize += key->getLength() + 1;
-       nkeys++;
-    }
-    if (nkeys == 0)
-       goto finish;
-
-    /*
-     * Allocate and fill in the module data structures.
-     */
-    datalen = sizeof(struct mac_module_data) +
-       sizeof(mac_module_data_element) * (nkeys - 1) +
-        strtabsize + listtabsize + dicttabsize;
-    DPRINTF(("osdict: datalen %d strtabsize %d listtabsize %d dicttabsize %d\n", 
-           datalen, strtabsize, listtabsize, dicttabsize));
-    if (kmem_alloc(kernel_map, &data_addr, datalen) != KERN_SUCCESS)
-       goto finish;
-    module_data = (mac_module_data *)data_addr;
-    module_data->base_addr = data_addr;
-    module_data->size = datalen;
-    module_data->count = nkeys;
-    strtab = (char *)&module_data->data[nkeys];
-    listtab = strtab + strtabsize;
-    dicttab = listtab + listtabsize;
-    DPRINTF(("osdict: data_addr %p strtab %p listtab %p dicttab %p end %p\n", 
-           data_addr, strtab, listtab, dicttab, data_addr + datalen));
-
-    keyIterator->reset();
-    nkeys = 0;
-    element = &module_data->data[0];
-    DPRINTF(("osdict: element %p\n", element));
-    while ( (key = OSDynamicCast(OSString, keyIterator->getNextObject())) ) {
-
-       // Get the key's value and determine its type
-        OSObject * value = dict->getObject(key);
-        if (!value)
-            continue;
-
-       /* Store key */
-       DPRINTF(("osdict: element @%p\n", element));
-       element->key = strtab;
-       element->key_size = key->getLength() + 1;
-       DPRINTF(("osdict: key %s size %d @%p\n", key->getCStringNoCopy(), element->key_size, strtab));
-       memcpy(element->key, key->getCStringNoCopy(), element->key_size);
-
-       typeID = OSTypeIDInst(value);
-       if (primitive_type(value)) {
-           /* Store value */
-           element->value = element->key + element->key_size;
-           DPRINTF(("osdict: primitive element value %p\n", element->value));
-           primitive_type_collect(element, value);
-           strtab += element->key_size + element->value_size;
-           DPRINTF(("osdict: new strtab %p\n", strtab));
+       OSDictionary         * dict;
+       OSObject * obj;
+
+       if (!super::init()) {
+               return false;
        }
-       else if (typeID == OSTypeID(OSArray)) {
-           unsigned int k, cnt, nents;
-           char *astrtab;
-           struct mac_module_data_list *arrayhd;
-           struct mac_module_data_element *ele;
-           OSArray *arrayObj = OSDynamicCast(OSArray, value);
-
-           element->value = listtab;
-           DPRINTF(("osdict: array element value %p\n", element->value));
-           element->value_type = MAC_DATA_TYPE_ARRAY;
-           arrayhd = (struct mac_module_data_list *)element->value;
-           arrayhd->type = 0;
-           DPRINTF(("osdict: arrayhd %p\n", arrayhd));
-           nents = 0;
-           astrtab = strtab + element->key_size;
-           ele = &(arrayhd->list[0]);
-           cnt = arrayObj->getCount();
-           for (k = 0; k < cnt; k++) {
-               value = arrayObj->getObject(k);
-               DPRINTF(("osdict: array ele %d @%p\n", nents, ele));
-               ele->key = NULL;
-               ele->key_size = 0;
-               typeID = OSTypeIDInst(value);
-               if (primitive_type(value)) {
-                   if (arrayhd->type != 0 &&
-                       arrayhd->type != MAC_DATA_TYPE_PRIMITIVE)
+
+       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;
-                   arrayhd->type = MAC_DATA_TYPE_PRIMITIVE;
-                   ele->value = astrtab;
-                   primitive_type_collect(ele, value);
-                   astrtab += ele->value_size;
-                   DPRINTF(("osdict: array new astrtab %p\n", astrtab));
                }
-               else if (typeID == OSTypeID(OSDictionary)) {
-                   unsigned int dents;
-                   char *dstrtab;
-                   OSDictionary *dictObj;
-                   OSString *dictkey;
-                   OSCollectionIterator *dictIterator;
-                   struct mac_module_data_list *dicthd;
-                   struct mac_module_data_element *dele;
-
-                   if (arrayhd->type != 0 &&
-                       arrayhd->type != MAC_DATA_TYPE_DICT)
-                       continue;
-                   dictObj = OSDynamicCast(OSDictionary, value);
-                   dictIterator = OSCollectionIterator::withCollection(dictObj);
-                   if (!dictIterator)
-                       goto finish;
-                   DPRINTF(("osdict: dict\n"));
-                   ele->value = dicttab;
-                   ele->value_type = MAC_DATA_TYPE_DICT;
-                   dicthd = (struct mac_module_data_list *)ele->value;
-                   DPRINTF(("osdict: dicthd %p\n", dicthd));
-                   dstrtab = astrtab;
-                   dents = 0;
-                   while ((dictkey = OSDynamicCast(OSString,
-                                             dictIterator->getNextObject()))) {
-                       OSObject *dictvalue;
-
-                       dictvalue = dictObj->getObject(dictkey);
-                       if (!dictvalue)
-                           continue;
-                       dele = &(dicthd->list[dents]);
-                       DPRINTF(("osdict: dict ele %d @%p\n", dents, dele));
-                       if (primitive_type(dictvalue)) {
-                           dele->key = dstrtab;
-                           dele->key_size = dictkey->getLength() + 1;
-                           DPRINTF(("osdict: dictkey %s size %d @%p\n",
-                               dictkey->getCStringNoCopy(), dictkey->getLength(), dstrtab));
-                           memcpy(dele->key, dictkey->getCStringNoCopy(),
-                               dele->key_size);
-                           dele->value = dele->key + dele->key_size;
-                           primitive_type_collect(dele, dictvalue);
-                           dstrtab += dele->key_size + dele->value_size;
-                           DPRINTF(("osdict: dict new dstrtab %p\n", dstrtab));
-                       }
-                       else {
-                           continue;   /* Only handle primitive types here.  */
-                       }
-                       dents++;
-                   }
-                   dictIterator->release();
-                   if (dents == 0)
+               OSKext::uniquePersonalityProperties(dict);
+               if (NULL == dict->getObject( gIOClassKey )) {
+                       IOLog("Missing or bad \"%s\" key\n",
+                           gIOClassKey->getCStringNoCopy());
                        continue;
-                   arrayhd->type = MAC_DATA_TYPE_DICT;
-                   ele->value_size = sizeof(struct mac_module_data_list) +
-                       (dents - 1) * sizeof(struct mac_module_data_element);
-                   DPRINTF(("osdict: dict ele size %d ents %d\n", ele->value_size, dents));
-                   dicttab += ele->value_size;
-                   DPRINTF(("osdict: new dicttab %p\n", dicttab));
-                   dicthd->count = dents;
-                   astrtab = dstrtab;
                }
-               else {
-                   continue;           /* Skip everything else.              */
-               }
-               nents++;
-               ele++;
-           }
-           if (nents == 0)
-               continue;
-           element->value_size = sizeof(struct mac_module_data_list) +
-               (nents - 1) * sizeof(struct mac_module_data_element);
-           listtab += element->value_size;
-           DPRINTF(("osdict: new listtab %p\n", listtab));
-           arrayhd->count = nents;
-           strtab = astrtab;
-           DPRINTF(("osdict: new strtab %p\n", strtab));
-       }
-       else {
-           continue;           /* skip anything else */
+               dict->setObject("KernelConfigTable", kOSBooleanTrue);
+               addPersonality(dict);
        }
-       element++;
-    }
-    DPRINTF(("module_data list @%p, key %p value %p\n",
-       module_data, module_data->data[0].key, module_data->data[0].value));
-finish:
-    if (keyIterator)
-       keyIterator->release();
-    return(module_data);
+
+       gIOCatalogLock = IORWLockAlloc();
+       lock = gIOCatalogLock;
+
+       return true;
 }
 
 /*********************************************************************
-* This function takes a plist and looks for an OSModuleData dictionary.
-* If it is found, an encoded copy is returned.
+* Release all resources used by IOCatalogue and deallocate.
+* This will probably never be called.
 *********************************************************************/
-kmod_args_t
-get_module_data(OSDictionary * kextPlist, mach_msg_type_number_t * datalen)
+void
+IOCatalogue::free( void )
 {
-
-    OSDictionary * kextModuleData = 0;      // don't release
-    struct mac_module_data * module_data = 0;
-    vm_map_copy_t copy = 0;
-
-    kextModuleData = OSDynamicCast(OSDictionary,
-       kextPlist->getObject("OSModuleData"));
-    if (!kextModuleData)
-        goto finish;
-
-    module_data = osdict_encode(kextModuleData);
-    if (!module_data)
-        goto finish;
-    *datalen = module_data->size;
-    /*
-     * Make a CoW copy of data and free the original.  The copy is
-     * consumed by a call to vm_map_copyout() in kmod_start_or_stop().
-     */
-    vm_map_copyin(kernel_map, (vm_offset_t)module_data, *datalen, FALSE, &copy);
-    kmem_free(kernel_map, (vm_offset_t)module_data, *datalen);
-    DPRINTF(("get_module_data: copy @ %p\n", copy));
-finish:
-    return (kmod_args_t)copy;
+       panic("");
 }
-#endif /* MAC */
 
-static 
-kern_return_t start_prelink_module(UInt32 moduleIndex)
+/*********************************************************************
+*********************************************************************/
+OSOrderedSet *
+IOCatalogue::findDrivers(
+       IOService * service,
+       SInt32 * generationCount)
 {
-    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;
-
-    togo    = IONew(UInt32, prelinkedModules->getCount());
-    togo[0] = moduleIndex;
-    count   = 1;
-
-    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;
+       OSDictionary         * nextTable;
+       OSOrderedSet         * set;
+       OSArray              * array;
+       const OSMetaClass    * meta;
+       unsigned int           idx;
+
+       set = OSOrderedSet::withCapacity( 1, IOServiceOrdering,
+           (void *)gIOProbeScoreKey );
+       if (!set) {
+               return NULL;
        }
-    }
 
-    if (KERN_SUCCESS != kr)
-       return kr;
+       IORWLockRead(lock);
 
-    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());
+       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();
        }
-       dict->removeObject("OSBundlePrelink");
 
-       if (kmod_info->start)
-           kr = kmod_start_or_stop(kmod_info->id, 1, 0, 0);
-    }
+       *generationCount = getGenerationCount();
 
-    IODelete(togo, UInt32, prelinkedModules->getCount());
+       IORWLockUnlock(lock);
 
-    return kr;
+       return set;
 }
 
 /*********************************************************************
-* This is a function that IOCatalogue calls in order to load a kmod.
+* Is personality already in the catalog?
 *********************************************************************/
-
-static 
-kern_return_t kmod_load_from_cache_sym(const OSSymbol * kmod_name)
+OSOrderedSet *
+IOCatalogue::findDrivers(
+       OSDictionary * matching,
+       SInt32 * generationCount)
 {
-    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;
+       OSCollectionIterator * iter;
+       OSDictionary         * dict;
+       OSOrderedSet         * set;
+       OSArray              * array;
+       const OSSymbol       * key;
+       unsigned int           idx;
+
+       OSKext::uniquePersonalityProperties(matching);
+
+       set = OSOrderedSet::withCapacity( 1, IOServiceOrdering,
+           (void *)gIOProbeScoreKey );
+       if (!set) {
+               return NULL;
+       }
+       iter = OSCollectionIterator::withCollection(personalities);
+       if (!iter) {
+               set->release();
+               return NULL;
        }
-       else
-           result = start_prelink_module(idx);
-    }
 
-    return result;
+       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);
+
+       iter->release();
+       return set;
 }
 
-extern "C" Boolean kmod_load_request(const char * moduleName, Boolean make_request)
+/*********************************************************************
+* 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               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;
+       bool                   result = false;
+       OSCollectionIterator * iter = NULL;   // must release
+       OSOrderedSet         * set = NULL;    // must release
+       OSObject             * object = NULL;   // do not release
+       OSArray              * persons = NULL;// do not release
+
+       persons = OSDynamicCast(OSArray, drivers);
+       if (!persons) {
+               goto finish;
        }
-       sym = OSSymbol::withCString(moduleName);
-       if (!sym) {
-           ret = false;
-           break;
+
+       set = OSOrderedSet::withCapacity( 10, IOServiceOrdering,
+           (void *)gIOProbeScoreKey );
+       if (!set) {
+               goto finish;
        }
 
-       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;
+       iter = OSCollectionIterator::withCollection(persons);
+       if (!iter) {
+               goto finish;
        }
 
-       kr = kmod_load_function((char *)moduleName);
+       /* Start with success; clear it on an error.
+        */
+       result = true;
 
-       if (ret != kIOReturnSuccess) {
-           IOLog("IOCatalogue: %s cannot be loaded.\n", moduleName);
+       IORWLockWrite(lock);
+       while ((object = iter->getNextObject())) {
+               // xxx Deleted OSBundleModuleDemand check; will handle in other ways for SL
 
-           /* 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;
+               OSDictionary * personality = OSDynamicCast(OSDictionary, object);
 
-       } else if (kernelLinkerPresent) {
-           // If kern linker is here, the driver is actually loaded,
-           // so return true.
-           ret = true;
+               SInt count;
 
-       } 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);
+               if (!personality) {
+                       IOLog("IOCatalogue::addDrivers() encountered non-dictionary; bailing.\n");
+                       result = false;
+                       break;
+               }
 
-    IOLockUnlock(gIOKLDLock);
+               OSKext::uniquePersonalityProperties(personality);
+
+               // Add driver personality to catalogue.
+
+               OSArray * array = arrayForPersonality(personality);
+               if (!array) {
+                       addPersonality(personality);
+               } else {
+                       count = array->getCount();
+                       while (count--) {
+                               OSDictionary * driver;
+
+                               // Be sure not to double up on personalities.
+                               driver = (OSDictionary *)array->getObject(count);
+
+                               /* Unlike in other functions, this comparison must be exact!
+                                * The catalogue must be able to contain personalities that
+                                * are proper supersets of others.
+                                * Do not compare just the properties present in one driver
+                                * personality or the other.
+                                */
+                               if (personality->isEqualTo(driver)) {
+                                       break;
+                               }
+                       }
+                       if (count >= 0) {
+                               // its a dup
+                               continue;
+                       }
+                       result = array->setObject(personality);
+                       if (!result) {
+                               break;
+                       }
+               }
+
+               set->setObject(personality);
+       }
+       // Start device matching.
+       if (result && doNubMatching && (set->getCount() > 0)) {
+               IOService::catalogNewDrivers(set);
+               generation++;
+       }
+       IORWLockUnlock(lock);
 
-    if (sym)
-    {
-       IOLockLock(gIOCatalogLock);
-       gIOCatalogModuleRequests->setObject(sym);
-       if (cacheMiss)
-           gIOCatalogCacheMisses->setObject(sym);
-       IOLockUnlock(gIOCatalogLock);
-    }
+finish:
+       if (set) {
+               set->release();
+       }
+       if (iter) {
+               iter->release();
+       }
 
-    return ret;
+       return result;
 }
 
-extern "C" kern_return_t kmod_unload_cache(void)
+/*********************************************************************
+* Remove drivers from the catalog which match the
+* properties in the matching dictionary.
+*********************************************************************/
+bool
+IOCatalogue::removeDrivers(
+       OSDictionary * matching,
+       bool doNubMatching)
 {
-    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);
+       OSOrderedSet         * set;
+       OSCollectionIterator * iter;
+       OSDictionary         * dict;
+       OSArray              * array;
+       const OSSymbol       * key;
+       unsigned int           idx;
+
+       if (!matching) {
+               return false;
+       }
+
+       set = OSOrderedSet::withCapacity(10,
+           IOServiceOrdering,
+           (void *)gIOProbeScoreKey);
+       if (!set) {
+               return false;
+       }
+       iter = OSCollectionIterator::withCollection(personalities);
+       if (!iter) {
+               set->release();
+               return false;
        }
-    }
 
-    gIOPrelinkedModules->release();
-    gIOPrelinkedModules = 0;
+       IORWLockWrite(lock);
+       while ((key = (const OSSymbol *) iter->getNextObject())) {
+               array = (OSArray *) personalities->getObject(key);
+               if (array) {
+                       for (idx = 0; (dict = (OSDictionary *) array->getObject(idx)); idx++) {
+                               /* This comparison must be done with only the keys in the
+                                * "matching" dict to enable general searches.
+                                */
+                               if (dict->isEqualTo(matching, matching)) {
+                                       set->setObject(dict);
+                                       array->removeObject(idx);
+                                       idx--;
+                               }
+                       }
+               }
+               // Start device matching.
+               if (doNubMatching && (set->getCount() > 0)) {
+                       IOService::catalogNewDrivers(set);
+                       generation++;
+               }
+       }
+       IORWLockUnlock(lock);
 
-    IOLockUnlock(gIOKLDLock);
+       set->release();
+       iter->release();
 
-    return result;
+       return true;
 }
 
-extern "C" kern_return_t kmod_load_from_cache(const char * kmod_name)
+// Return the generation count.
+SInt32
+IOCatalogue::getGenerationCount(void) const
 {
-    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;
+       return generation;
 }
 
-/*********************************************************************
-*********************************************************************/
-
-static void UniqueProperties( OSDictionary * dict )
+// Check to see if kernel module has been loaded already, and request its load.
+bool
+IOCatalogue::isModuleLoaded(OSDictionary * driver, OSObject ** kextRef) const
 {
-    OSString             * data;
+       OSString * moduleName = NULL;
+       OSString * publisherName = NULL;
+       OSReturn   ret;
 
-    data = OSDynamicCast( OSString, dict->getObject( gIOClassKey ));
-    if( data) {
-        const OSSymbol *classSymbol = OSSymbol::withString(data);
-
-        dict->setObject( gIOClassKey, (OSSymbol *) classSymbol);
-        classSymbol->release();
-    }
+       if (kextRef) {
+               *kextRef = NULL;
+       }
+       if (!driver) {
+               return false;
+       }
 
-    data = OSDynamicCast( OSString, dict->getObject( gIOMatchCategoryKey ));
-    if( data) {
-        const OSSymbol *classSymbol = OSSymbol::withString(data);
+       /* The personalities of codeless kexts often contain the bundle ID of the
+        * kext they reference, and not the bundle ID of the codeless kext itself.
+        * The prelinked kernel needs to know the bundle ID of the codeless kext
+        * so it can include these personalities, so OSKext stores that bundle ID
+        * in the IOPersonalityPublisher key, and we record it as requested here.
+        */
+       publisherName = OSDynamicCast(OSString,
+           driver->getObject(kIOPersonalityPublisherKey));
+       OSKext::recordIdentifierRequest(publisherName);
+
+       moduleName = OSDynamicCast(OSString, driver->getObject(gIOModuleIdentifierKernelKey));
+       if (moduleName) {
+               ret = OSKext::loadKextWithIdentifier(moduleName, kextRef);
+               if (kOSKextReturnDeferred == ret) {
+                       // a request has been queued but the module isn't necessarily
+                       // loaded yet, so stall.
+                       return false;
+               }
+               OSString *moduleDextName = OSDynamicCast(OSString, driver->getObject(gIOModuleIdentifierKey));
+               if (moduleDextName && !(moduleName->isEqualTo(moduleDextName))) {
+                       OSObject *dextRef = NULL;
+                       ret = OSKext::loadKextWithIdentifier(moduleDextName, &dextRef);
+                       OSSafeReleaseNULL(dextRef);
+               }
+               // module is present or never will be
+               return true;
+       }
 
-        dict->setObject( gIOMatchCategoryKey, (OSSymbol *) classSymbol);
-        classSymbol->release();
-    }
+       /* If a personality doesn't hold the "CFBundleIdentifier" or "CFBundleIdentifierKernel" key
+        * it is assumed to be an "in-kernel" driver.
+        */
+       return true;
 }
 
-void IOCatalogue::initialize( void )
+/* 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)
 {
-    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 );
-    gIOModuleIdentifierKey   = OSSymbol::withCStringNoCopy( kModuleKey );
-    gIOCatalogModuleRequests = OSSet::withCapacity(16);
-    gIOCatalogCacheMisses    = OSSet::withCapacity(16);
-    gIOCatalogROMMkexts      = OSSet::withCapacity(4);
-
-    assert( array && gIOClassKey && gIOProbeScoreKey 
-           && gIOModuleIdentifierKey && gIOCatalogModuleRequests);
-
-    gIOCatalogue = new IOCatalogue;
-    assert(gIOCatalogue);
-    rc = gIOCatalogue->init(array);
-    assert(rc);
-    array->release();
+       startMatching(moduleName);
+
+       (void) OSKext::setDeferredLoadSucceeded();
+       (void) OSKext::considerRebuildOfPrelinkedKernel();
 }
 
-// Initialize the IOCatalog object.
-bool IOCatalogue::init(OSArray * initArray)
+void
+IOCatalogue::moduleHasLoaded(const char * moduleName)
 {
-    OSDictionary         * dict;
-    
-    if ( !super::init() )
-        return false;
-
-    generation = 1;
-    
-    array = initArray;
-    array->retain();
-    kernelTables = OSCollectionIterator::withCollection( array );
-
-    gIOCatalogLock = IOLockAlloc();
-    gIOKLDLock     = IOLockAlloc();
-
-    lock     = gIOCatalogLock;
-    kld_lock = gIOKLDLock;
-
-    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
+       const OSSymbol * name;
 
-    return true;
+       name = OSSymbol::withCString(moduleName);
+       moduleHasLoaded(name);
+       name->release();
 }
 
-// Release all resources used by IOCatalogue and deallocate.
-// This will probably never be called.
-void IOCatalogue::free( void )
+// xxx - return is really OSReturn/kern_return_t
+IOReturn
+IOCatalogue::unloadModule(OSString * moduleName) const
 {
-    if ( array )
-        array->release();
-
-    if ( kernelTables )
-        kernelTables->release();
-    
-    super::free();
+       return OSKext::removeKextWithIdentifier(moduleName->getCStringNoCopy());
 }
 
-#if CATALOGTEST
-
-static int hackLimit;
-
-enum { kDriversPerIter = 4 };
-
-void IOCatalogue::ping( thread_call_param_t arg, thread_call_param_t)
+IOReturn
+IOCatalogue::_terminateDrivers(OSDictionary * matching)
 {
-    IOCatalogue         * self = (IOCatalogue *) arg;
-    OSOrderedSet         * set;
-    OSDictionary         * table;
-    int                           newLimit;
+       OSDictionary         * dict;
+       OSIterator           * iter;
+       IOService            * service;
+       IOReturn               ret;
 
-    set = OSOrderedSet::withCapacity( 1 );
-
-    IOLockLock( &self->lock );
-
-    for( newLimit = 0; newLimit < kDriversPerIter; newLimit++) {
-       table = (OSDictionary *) self->array->getObject(
-                                       hackLimit + newLimit );
-       if( table) {
-           set->setLastObject( table );
-
-           OSSymbol * sym = (OSSymbol *) table->getObject( gIOClassKey );
-           kprintf("enabling %s\n", sym->getCStringNoCopy());
+       if (!matching) {
+               return kIOReturnBadArgument;
+       }
 
-       } else {
-           newLimit--;
-           break;
+       ret = kIOReturnSuccess;
+       dict = NULL;
+       iter = IORegistryIterator::iterateOver(gIOServicePlane,
+           kIORegistryIterateRecursively);
+       if (!iter) {
+               return kIOReturnNoMemory;
        }
-    }
 
-    IOService::catalogNewDrivers( set );
+       OSKext::uniquePersonalityProperties( matching );
+
+       // terminate instances.
+       do {
+               iter->reset();
+               while ((service = (IOService *)iter->getNextObject())) {
+                       dict = service->getPropertyTable();
+                       if (!dict) {
+                               continue;
+                       }
 
-    hackLimit += newLimit;
-    self->generation++;
+                       /* Terminate only for personalities that match the matching dictionary.
+                        * This comparison must be done with only the keys in the
+                        * "matching" dict to enable general matching.
+                        */
+                       if (!dict->isEqualTo(matching, matching)) {
+                               continue;
+                       }
 
-    IOLockUnlock( &self->lock );
+                       if (!service->terminate(kIOServiceRequired | kIOServiceSynchronous)) {
+                               ret = kIOReturnUnsupported;
+                               break;
+                       }
+               }
+       } while (!service && !iter->isValid());
+       iter->release();
 
-    if( kDriversPerIter == newLimit) {
-        AbsoluteTime deadline;
-        clock_interval_to_deadline( 500, kMillisecondScale );
-        thread_call_func_delayed( ping, this, deadline );
-    }
+       return ret;
 }
-#endif
 
-OSOrderedSet * IOCatalogue::findDrivers( IOService * service,
-                                       SInt32 * generationCount )
+IOReturn
+IOCatalogue::_removeDrivers(OSDictionary * matching)
 {
-    OSDictionary         * nextTable;
-    OSOrderedSet         * set;
-    OSString             * imports;
-
-    set = OSOrderedSet::withCapacity( 1, IOServiceOrdering,
-                                      (void *)gIOProbeScoreKey );
-    if( !set )
-       return( 0 );
+       IOReturn               ret = kIOReturnSuccess;
+       OSCollectionIterator * iter;
+       OSDictionary         * dict;
+       OSArray              * array;
+       const OSSymbol       * key;
+       unsigned int           idx;
+
+       // remove configs from catalog.
+
+       iter = OSCollectionIterator::withCollection(personalities);
+       if (!iter) {
+               return kIOReturnNoMemory;
+       }
 
-    IOLockLock( lock );
-    kernelTables->reset();
+       while ((key = (const OSSymbol *) iter->getNextObject())) {
+               array = (OSArray *) personalities->getObject(key);
+               if (array) {
+                       for (idx = 0; (dict = (OSDictionary *) array->getObject(idx)); idx++) {
+                               /* Remove from the catalogue's array any personalities
+                                * that match the matching dictionary.
+                                * This comparison must be done with only the keys in the
+                                * "matching" dict to enable general matching.
+                                */
+                               if (dict->isEqualTo(matching, matching)) {
+                                       array->removeObject(idx);
+                                       idx--;
+                               }
+                       }
+               }
+       }
+       iter->release();
 
-#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 );
-    }
+       return ret;
+}
 
-    *generationCount = getGenerationCount();
+IOReturn
+IOCatalogue::terminateDrivers(OSDictionary * matching)
+{
+       IOReturn ret;
 
-    IOLockUnlock( lock );
+       ret = _terminateDrivers(matching);
+       IORWLockWrite(lock);
+       if (kIOReturnSuccess == ret) {
+               ret = _removeDrivers(matching);
+       }
+       IORWLockUnlock(lock);
 
-    return( set );
+       return ret;
 }
 
-// Is personality already in the catalog?
-OSOrderedSet * IOCatalogue::findDrivers( OSDictionary * matching,
-                                         SInt32 * generationCount)
+IOReturn
+IOCatalogue::terminateDriversForModule(
+       OSString * moduleName,
+       bool unload)
 {
-    OSDictionary         * dict;
-    OSOrderedSet         * set;
+       IOReturn ret;
+       OSDictionary * dict;
+       bool isLoaded = false;
+
+       /* Check first if the kext currently has any linkage dependents;
+        * in such a case the unload would fail so let's not terminate any
+        * IOServices (since doing so typically results in a panic when there
+        * are loaded dependencies). Note that we aren't locking the kext here
+        * so it might lose or gain dependents by the time we call unloadModule();
+        * I think that's ok, our unload can fail if a kext comes in on top of
+        * this one even after we've torn down IOService objects. Conversely,
+        * if we fail the unload here and then lose a library, the autounload
+        * thread will get us in short order.
+        */
+       if (OSKext::isKextWithIdentifierLoaded(moduleName->getCStringNoCopy())) {
+               isLoaded = true;
+
+               if (!OSKext::canUnloadKextWithIdentifier(moduleName,
+                   /* checkClasses */ false)) {
+                       ret = kOSKextReturnInUse;
+                       goto finish;
+               }
+       }
+       dict = OSDictionary::withCapacity(1);
+       if (!dict) {
+               ret = kIOReturnNoMemory;
+               goto finish;
+       }
 
-    UniqueProperties(matching);
+       dict->setObject(gIOModuleIdentifierKey, moduleName);
 
-    set = OSOrderedSet::withCapacity( 1, IOServiceOrdering,
-                                      (void *)gIOProbeScoreKey );
+       ret = _terminateDrivers(dict);
 
-    IOLockLock( lock );
-    kernelTables->reset();
-    while ( (dict = (OSDictionary *) kernelTables->getNextObject()) ) {
+       /* No goto between IOLock calls!
+        */
+       IORWLockWrite(lock);
+       if (kIOReturnSuccess == ret) {
+               ret = _removeDrivers(dict);
+       }
 
-       /* This comparison must be done with only the keys in the
-        * "matching" dict to enable general searches.
-        */
-        if ( dict->isEqualTo(matching, matching) )
-            set->setObject(dict);
-    }
-    *generationCount = getGenerationCount();
-    IOLockUnlock( lock );
+       // Unload the module itself.
+       if (unload && isLoaded && ret == kIOReturnSuccess) {
+               ret = unloadModule(moduleName);
+       }
 
-    return set;
-}
+       IORWLockUnlock(lock);
 
-// 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);
-}
+       dict->release();
 
-// Add driver config tables to catalog and start matching process.
-bool IOCatalogue::addDrivers(OSArray * drivers,
-                              bool doNubMatching )
-{
-    OSCollectionIterator * iter;
-    OSDictionary         * dict;
-    OSOrderedSet         * set;
-    OSArray              * persons;
-    OSString             * moduleName;
-    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;
-    }
-
-    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;
-    
-           AddNewImports( set, dict );
-       }
-    }
-    // Start device matching.
-    if (doNubMatching && (set->getCount() > 0)) {
-        IOService::catalogNewDrivers( set );
-        generation++;
-    }
-    IOLockUnlock( lock );
-
-    set->release();
-    iter->release();
-    
-    return ret;
+finish:
+       return ret;
 }
 
-// Remove drivers from the catalog which match the
-// properties in the matching dictionary.
-bool IOCatalogue::removeDrivers( OSDictionary * matching,
-                                 bool doNubMatching)
+IOReturn
+IOCatalogue::terminateDriversForModule(
+       const char * moduleName,
+       bool unload)
 {
-    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 );
-
-    IOLockLock( lock );
-    kernelTables->reset();
-    arrayCopy->merge(array);
-    array->flushCollection();
-    tables->reset();
-    while ( (dict = (OSDictionary *)tables->getNextObject()) ) {
-
-       /* This comparison must be done with only the keys in the
-        * "matching" dict to enable general searches.
-        */
-        if ( dict->isEqualTo(matching, matching) ) {
-            AddNewImports( set, dict );
-            continue;
-        }
-
-        array->setObject(dict);
-    }
-    // Start device matching.
-    if ( doNubMatching && (set->getCount() > 0) ) {
-        IOService::catalogNewDrivers(set);
-        generation++;
-    }
-    IOLockUnlock( lock );
-    
-    set->release();
-    tables->release();
-    
-    return true;
-}
+       OSString * name;
+       IOReturn ret;
 
-// Return the generation count.
-SInt32 IOCatalogue::getGenerationCount( void ) const
-{
-    return( generation );
-}
+       name = OSString::withCString(moduleName);
+       if (!name) {
+               return kIOReturnNoMemory;
+       }
 
-bool IOCatalogue::isModuleLoaded( OSString * moduleName ) const
-{
-    return isModuleLoaded(moduleName->getCStringNoCopy());
-}
+       ret = terminateDriversForModule(name, unload);
+       name->release();
 
-bool IOCatalogue::isModuleLoaded( const char * moduleName ) const
-{
-    return (kmod_load_request(moduleName, true));
+       return ret;
 }
 
-// Check to see if module has been loaded already.
-bool IOCatalogue::isModuleLoaded( OSDictionary * driver ) const
+#if defined(__i386__) || defined(__x86_64__)
+bool
+IOCatalogue::startMatching( OSDictionary * matching )
 {
-    OSString             * moduleName = NULL;
+       OSOrderedSet         * set;
 
-    if ( !driver )
-        return false;
+       if (!matching) {
+               return false;
+       }
 
-    moduleName = OSDynamicCast(OSString, driver->getObject(gIOModuleIdentifierKey));
-    if ( moduleName )
-        return isModuleLoaded(moduleName);
+       set = OSOrderedSet::withCapacity(10, IOServiceOrdering,
+           (void *)gIOProbeScoreKey);
+       if (!set) {
+               return false;
+       }
 
-   /* If a personality doesn't hold the "CFBundleIdentifier" key
-    * it is assumed to be an "in-kernel" driver.
-    */
-    return true;
-}
+       IORWLockRead(lock);
 
-// This function is called after a module has been loaded.
-void IOCatalogue::moduleHasLoaded( OSString * moduleName )
-{
-    OSDictionary         * dict;
+       personalities->iterateObjects(^bool (const OSSymbol * key, OSObject * value) {
+               OSArray      * array;
+               OSDictionary * dict;
+               unsigned int   idx;
 
-    dict = OSDictionary::withCapacity(2);
-    dict->setObject(gIOModuleIdentifierKey, moduleName);
-    startMatching(dict);
-    dict->release();
-}
+               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;
+       });
 
-void IOCatalogue::moduleHasLoaded( const char * moduleName )
-{
-    OSString             * name;
+       // Start device matching.
+       if (set->getCount() > 0) {
+               IOService::catalogNewDrivers(set);
+               generation++;
+       }
 
-    name = OSString::withCString(moduleName);
-    moduleHasLoaded(name);
-    name->release();
-}
+       IORWLockUnlock(lock);
 
-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) ) {
-            record_kext_unload(k_info->id);
-            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;
-}
+       set->release();
 
-static IOReturn _terminateDrivers( OSDictionary * matching )
-{
-    OSDictionary         * dict;
-    OSIterator           * iter;
-    IOService            * service;
-    IOReturn               ret;
-
-    if ( !matching )
-        return kIOReturnBadArgument;
-
-    ret = kIOReturnSuccess;
-    dict = 0;
-    iter = IORegistryIterator::iterateOver(gIOServicePlane,
-                                kIORegistryIterateRecursively);
-    if ( !iter )
-        return kIOReturnNoMemory;
-
-    UniqueProperties( matching );
-
-    // terminate instances.
-    do {
-        iter->reset();
-        while( (service = (IOService *)iter->getNextObject()) ) {
-            dict = service->getPropertyTable();
-            if ( !dict )
-                continue;
-
-           /* Terminate only for personalities that match the matching dictionary.
-            * This comparison must be done with only the keys in the
-            * "matching" dict to enable general matching.
-            */
-            if ( !dict->isEqualTo(matching, matching) )
-                 continue;
-
-            if ( !service->terminate(kIOServiceRequired|kIOServiceSynchronous) ) {
-                ret = kIOReturnUnsupported;
-                break;
-            }
-        }
-    } while( !service && !iter->isValid());
-    iter->release();
-
-    return ret;
+       return true;
 }
+#endif /* defined(__i386__) || defined(__x86_64__) */
 
-static IOReturn _removeDrivers( OSArray * array, OSDictionary * matching )
+bool
+IOCatalogue::startMatching( const OSSymbol * moduleName )
 {
-    OSCollectionIterator * tables;
-    OSDictionary         * dict;
-    OSArray              * arrayCopy;
-    IOReturn               ret = kIOReturnSuccess;
+       OSOrderedSet         * set;
 
-    // remove configs from catalog.
+       if (!moduleName) {
+               return false;
+       }
 
-    arrayCopy = OSArray::withCapacity(100);
-    if ( !arrayCopy )
-        return kIOReturnNoMemory;
+       set = OSOrderedSet::withCapacity(10, IOServiceOrdering,
+           (void *)gIOProbeScoreKey);
+       if (!set) {
+               return false;
+       }
 
-    tables = OSCollectionIterator::withCollection(arrayCopy);
-    arrayCopy->release();
-    if ( !tables )
-        return kIOReturnNoMemory;
+       IORWLockRead(lock);
 
-    arrayCopy->merge(array);
-    array->flushCollection();
-    tables->reset();
-    while ( (dict = (OSDictionary *)tables->getNextObject()) ) {
+       personalities->iterateObjects(^bool (const OSSymbol * key, OSObject * value) {
+               OSArray      * array;
+               OSDictionary * dict;
+               OSObject     * obj;
+               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;
+               array = (OSArray *) value;
+               for (idx = 0; (dict = (OSDictionary *) array->getObject(idx)); idx++) {
+                       obj = dict->getObject(gIOModuleIdentifierKernelKey);
+                       if (obj && moduleName->isEqualTo(obj)) {
+                               set->setObject(dict);
+                       }
+               }
+               return false;
+       });
+
+       // Start device matching.
+       if (set->getCount() > 0) {
+               IOService::catalogNewDrivers(set);
+               generation++;
+       }
 
-        array->setObject(dict);
-    }
+       IORWLockUnlock(lock);
 
-    tables->release();
+       set->release();
 
-    return ret;
+       return true;
 }
 
-IOReturn IOCatalogue::terminateDrivers( OSDictionary * matching )
+void
+IOCatalogue::reset(void)
 {
-    IOReturn ret;
-
-    ret = _terminateDrivers(matching);
-    IOLockLock( lock );
-    if (kIOReturnSuccess == ret)
-       ret = _removeDrivers(array, matching);
-    kernelTables->reset();
-    IOLockUnlock( lock );
-
-    return ret;
+       IOCatalogue::resetAndAddDrivers(/* no drivers; true reset */ NULL,
+           /* doMatching */ false);
+       return;
 }
 
-IOReturn IOCatalogue::terminateDriversForModule(
-                                      OSString * moduleName,
-                                      bool unload )
+bool
+IOCatalogue::resetAndAddDrivers(OSArray * drivers, bool doNubMatching)
 {
-    IOReturn ret;
-    OSDictionary * dict;
+       bool                   result              = false;
+       OSArray              * newPersonalities    = NULL;// do not release
+       OSCollectionIterator * iter                = NULL;// must release
+       OSOrderedSet         * matchSet            = NULL;// must release
+       const OSSymbol       * key;
+       OSArray              * array;
+       OSDictionary         * thisNewPersonality   = NULL;// do not release
+       OSDictionary         * thisOldPersonality   = NULL;// do not release
+       OSDictionary         * myKexts              = NULL;// must release
+       signed int             idx, newIdx;
+
+       if (drivers) {
+               newPersonalities = OSDynamicCast(OSArray, drivers);
+               if (!newPersonalities) {
+                       goto finish;
+               }
+       }
+       matchSet = OSOrderedSet::withCapacity(10, IOServiceOrdering,
+           (void *)gIOProbeScoreKey);
+       if (!matchSet) {
+               goto finish;
+       }
+       iter = OSCollectionIterator::withCollection(personalities);
+       if (!iter) {
+               goto finish;
+       }
 
-    dict = OSDictionary::withCapacity(1);
-    if ( !dict )
-        return kIOReturnNoMemory;
+       /* 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();
 
-    dict->setObject(gIOModuleIdentifierKey, moduleName);
+       result = true;
 
-    ret = _terminateDrivers(dict);
-    IOLockLock( lock );
-    if (kIOReturnSuccess == ret)
-       ret = _removeDrivers(array, dict);
-    kernelTables->reset();
+       IOLog("Resetting IOCatalogue.\n");
 
-    // Unload the module itself.
-    if ( unload && ret == kIOReturnSuccess ) {
-        // Do kmod stop first.
-        ret = unloadModule(moduleName);
-    }
+       /* No goto finish from here to unlock.
+        */
+       IORWLockWrite(lock);
 
-    IOLockUnlock( lock );
+       while ((key = (const OSSymbol *) iter->getNextObject())) {
+               array = (OSArray *) personalities->getObject(key);
+               if (!array) {
+                       continue;
+               }
 
-    dict->release();
+               for (idx = 0;
+                   (thisOldPersonality = (OSDictionary *) array->getObject(idx));
+                   idx++) {
+                       if (thisOldPersonality->getObject("KernelConfigTable")) {
+                               continue;
+                       }
+                       thisNewPersonality = NULL;
+
+                       if (newPersonalities) {
+                               for (newIdx = 0;
+                                   (thisNewPersonality = (OSDictionary *) newPersonalities->getObject(newIdx));
+                                   newIdx++) {
+                                       /* Unlike in other functions, this comparison must be exact!
+                                        * The catalogue must be able to contain personalities that
+                                        * are proper supersets of others.
+                                        * Do not compare just the properties present in one driver
+                                        * personality or the other.
+                                        */
+                                       if (OSDynamicCast(OSDictionary, thisNewPersonality) == NULL) {
+                                               /* skip thisNewPersonality if it is not an OSDictionary */
+                                               continue;
+                                       }
+                                       if (thisNewPersonality->isEqualTo(thisOldPersonality)) {
+                                               break;
+                                       }
+                               }
+                       }
+                       if (thisNewPersonality) {
+                               // dup, ignore
+                               newPersonalities->removeObject(newIdx);
+                       } else {
+                               // not in new set - remove
+                               // only remove dictionary if this module in not loaded - 9953845
+                               if (isModuleLoadedNoOSKextLock(myKexts, thisOldPersonality) == false) {
+                                       if (matchSet) {
+                                               matchSet->setObject(thisOldPersonality);
+                                       }
+                                       array->removeObject(idx);
+                                       idx--;
+                               }
+                       }
+               } // for...
+       } // while...
+
+       // add new
+       if (newPersonalities) {
+               for (newIdx = 0;
+                   (thisNewPersonality = (OSDictionary *) newPersonalities->getObject(newIdx));
+                   newIdx++) {
+                       if (OSDynamicCast(OSDictionary, thisNewPersonality) == NULL) {
+                               /* skip thisNewPersonality if it is not an OSDictionary */
+                               continue;
+                       }
 
-    return ret;
-}
+                       OSKext::uniquePersonalityProperties(thisNewPersonality);
+                       addPersonality(thisNewPersonality);
+                       matchSet->setObject(thisNewPersonality);
+               }
+       }
 
-IOReturn IOCatalogue::terminateDriversForModule(
-                                      const char * moduleName,
-                                      bool unload )
-{
-    OSString * name;
-    IOReturn ret;
+       /* Finally, start device matching on all new & removed personalities.
+        */
+       if (result && doNubMatching && (matchSet->getCount() > 0)) {
+               IOService::catalogNewDrivers(matchSet);
+               generation++;
+       }
 
-    name = OSString::withCString(moduleName);
-    if ( !name )
-        return kIOReturnNoMemory;
+       IORWLockUnlock(lock);
 
-    ret = terminateDriversForModule(name, unload);
-    name->release();
+finish:
+       if (matchSet) {
+               matchSet->release();
+       }
+       if (iter) {
+               iter->release();
+       }
+       if (myKexts) {
+               myKexts->release();
+       }
 
-    return ret;
+       return result;
 }
 
-bool IOCatalogue::startMatching( OSDictionary * matching )
+bool
+IOCatalogue::serialize(OSSerialize * s) const
 {
-    OSDictionary         * dict;
-    OSOrderedSet         * set;
-    
-    if ( !matching )
-        return false;
-
-    set = OSOrderedSet::withCapacity(10, IOServiceOrdering,
-                                     (void *)gIOProbeScoreKey);
-    if ( !set )
-        return false;
-
-    IOLockLock( lock );
-    kernelTables->reset();
-
-    while ( (dict = (OSDictionary *)kernelTables->getNextObject()) ) {
-
-       /* This comparison must be done with only the keys in the
-        * "matching" dict to enable general matching.
-        */
-        if ( dict->isEqualTo(matching, matching) )
-            AddNewImports(set, dict);
-    }
-    // Start device matching.
-    if ( set->getCount() > 0 ) {
-        IOService::catalogNewDrivers(set);
-        generation++;
-    }
-
-    IOLockUnlock( lock );
-
-    set->release();
-
-    return true;
-}
+       if (!s) {
+               return false;
+       }
 
-void IOCatalogue::reset(void)
-{
-    IOLog("Resetting IOCatalogue.\n");
+       return super::serialize(s);
 }
 
-bool IOCatalogue::serialize(OSSerialize * s) const
+bool
+IOCatalogue::serializeData(IOOptionBits kind, OSSerialize * s) const
 {
-    if ( !s )
-        return false;
+       kern_return_t kr = kIOReturnSuccess;
 
-    return super::serialize(s);
-}
+       switch (kind) {
+       case kIOCatalogGetContents:
+               kr = KERN_NOT_SUPPORTED;
+               break;
 
-bool IOCatalogue::serializeData(IOOptionBits kind, OSSerialize * s) const
-{
-    kern_return_t kr = kIOReturnSuccess;
-
-    switch ( kind )
-    {
-        case kIOCatalogGetContents:
-            if (!array->serialize(s))
-                kr = kIOReturnNoMemory;
-            break;
-
-        case kIOCatalogGetModuleDemandList:
-           IOLockLock( lock );
-            if (!gIOCatalogModuleRequests->serialize(s))
-                kr = kIOReturnNoMemory;
-           IOLockUnlock( lock );
-            break;
-
-        case kIOCatalogGetCacheMissList:
-           IOLockLock( lock );
-            if (!gIOCatalogCacheMisses->serialize(s))
-                kr = kIOReturnNoMemory;
-           IOLockUnlock( lock );
-            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 );
-            break;
-
-        default:
-            kr = kIOReturnBadArgument;
-            break;
-    }
-
-    return kr;
-}
+       case kIOCatalogGetModuleDemandList:
+               kr = KERN_NOT_SUPPORTED;
+               break;
 
+       case kIOCatalogGetCacheMissList:
+               kr = KERN_NOT_SUPPORTED;
+               break;
 
-bool IOCatalogue::recordStartupExtensions(void) {
-    bool result = false;
+       case kIOCatalogGetROMMkextList:
+               kr = KERN_NOT_SUPPORTED;
+               break;
 
-    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);
+       default:
+               kr = kIOReturnBadArgument;
+               break;
+       }
 
-    return result;
+       return kr;
 }
 
-
-/*********************************************************************
-* This function operates on sections retrieved from the currently running
-* 32 bit mach kernel.
-*********************************************************************/
-bool IOCatalogue::addExtensionsFromArchive(OSData * mkext)
+/* 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)
 {
-    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;
+       bool                    myResult = false;
+       const OSString *        myBundleID = NULL;// do not release
+       OSKext *                myKext = NULL;  // do not release
+
+       if (theKexts == NULL || theModuleDict == NULL) {
+               return myResult;
        }
 
-       IOLockUnlock(kld_lock);
+       // gIOModuleIdentifierKey is "CFBundleIdentifier"
+       myBundleID = OSDynamicCast(OSString,
+           theModuleDict->getObject(gIOModuleIdentifierKey));
+       if (myBundleID == NULL) {
+               return myResult;
+       }
 
-       copyData->release();
-    }
+       myKext = OSDynamicCast(OSKext, theKexts->getObject(myBundleID->getCStringNoCopy()));
+       if (myKext) {
+               myResult = myKext->isLoaded();
+       }
 
-    return result;
+       return myResult;
 }
 
-/*********************************************************************
-* 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 * segmentLE, *segmentKLD;
-    boolean_t  keepsyms = FALSE;
-#if __ppc__ || __arm__
-    char * dt_segment_name;
-    void * segment_paddress;
-    int    segment_size;
-#endif
 
-   /* 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;
-    }
-
-    PE_parse_boot_argn("keepsyms", &keepsyms, sizeof (keepsyms));
-    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.
-    */
-    segmentKLD = getsegbyname("__KLD");
-    if (!segmentKLD) {
-        IOLog("error removing kernel linker: can't find __KLD segment\n");
-        result = KERN_FAILURE;
-        goto finish;
-    }
-    OSRuntimeUnloadCPPForSegment(segmentKLD);
-
-#if __ppc__ || __arm__
-   /* 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);
-    }
-#elif __i386__
-    /* On x86, use the mapping data from the segment load command to
-     * unload KLD directly, unless the keepsyms boot-arg was enabled.
-     * This may invalidate any assumptions about  "avail_start"
-     * defining the lower bound for valid physical addresses.
-     */
-    if (!keepsyms && segmentKLD->vmaddr && segmentKLD->vmsize)
-           ml_static_mfree(segmentKLD->vmaddr, segmentKLD->vmsize);
-#else
-#error arch
+#if PRAGMA_MARK
+#pragma mark Obsolete Kext Loading Stuff
 #endif
-
-    struct section * sect;
-    sect = getsectbyname("__PRELINK", "__symtab");
-    if (sect && sect->addr) {
-       ml_static_mfree(sect->addr, 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;
-    }
-
-    IOLockUnlock(gIOKLDLock);
-}
-
-extern "C"
-void jettison_kernel_linker(void)
-{
-    if (gIOCatalogue != NULL)
-       gIOCatalogue->removeKernelLinker();
-}
+ **********************************************************************
+ ***                  BINARY COMPATIBILITY SECTION                  ***
+ **********************************************************************
+ **********************************************************************
+ * These functions are no longer used are necessary for C++ binary
+ * compatibility on i386.
+ **********************************************************************/