X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/2d21ac55c334faf3a56e5634905ed6987fc787d4..a991bd8d3e7fe02dbca0644054bab73c5b75324a:/iokit/Kernel/IOCatalogue.cpp diff --git a/iokit/Kernel/IOCatalogue.cpp b/iokit/Kernel/IOCatalogue.cpp index 939c78a3c..958022743 100644 --- a/iokit/Kernel/IOCatalogue.cpp +++ b/iokit/Kernel/IOCatalogue.cpp @@ -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 @@ -11,10 +11,10 @@ * 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, @@ -22,11 +22,11 @@ * 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 * @@ -38,1660 +38,1154 @@ * Version 2.0. */ -#include -#include -#include -#include -#include +#define IOKIT_ENABLE_SHARED_PTR + extern "C" { #include -#include -#include +#include #include #include }; -#include - -#include - +#include +#include +#include +#include +#include +#include -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 +#include +#include +#include +#include +#include -/***** - * 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 +/********************************************************************* +*********************************************************************/ +OSSharedPtr gIOCatalogue; +OSSharedPtr gIOClassKey; +OSSharedPtr gIOProbeScoreKey; +OSSharedPtr gIOModuleIdentifierKey; +OSSharedPtr 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) +{ + OSSharedPtr array; + OSSharedPtr 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 = OSDynamicPtrCast(OSUnserialize(gIOKernelConfigTables, errorString)); + if (!array && errorString) { + IOLog("KernelConfigTables syntax error: %s\n", + errorString->getCStringNoCopy()); + } -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 = OSMakeShared(); + assert(gIOCatalogue); + rc = gIOCatalogue->init(array.get()); + assert(rc); +} -/* - * 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 { + OSSharedPtr sharedArr = OSArray::withObjects((const OSObject **)&dict, 1, 2); + personalities->setObject(sym, sharedArr.get()); + } } /********************************************************************* -* 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) + OSKext::uniquePersonalityProperties(dict); + if (NULL == dict->getObject( gIOClassKey.get())) { + IOLog("Missing or bad \"%s\" key\n", + gIOClassKey->getCStringNoCopy()); 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) - 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, ©); - 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) +/********************************************************************* +*********************************************************************/ +OSPtr +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; + OSDictionary * nextTable; + OSSharedPtr set; + OSArray * array; + const OSMetaClass * meta; + unsigned int idx; + + set = OSOrderedSet::withCapacity( 1, IOServiceOrdering, + (void *)(gIOProbeScoreKey.get())); + if (!set) { + return NULL; } - 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; - } - } - 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) +OSPtr +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; + OSSharedPtr iter; + OSDictionary * dict; + OSSharedPtr set; + OSArray * array; + const OSSymbol * key; + unsigned int idx; + + OSKext::uniquePersonalityProperties(matching); + + set = OSOrderedSet::withCapacity( 1, IOServiceOrdering, + (void *)(gIOProbeScoreKey.get())); + if (!set) { + return NULL; } - else - result = start_prelink_module(idx); - } + iter = OSCollectionIterator::withCollection(personalities.get()); + if (!iter) { + return nullptr; + } + + IORWLockRead(lock); + while ((key = (const OSSymbol *) iter->getNextObject())) { + array = (OSArray *) personalities->getObject(key); + if (array) { + for (idx = 0; (dict = (OSDictionary *) array->getObject(idx)); idx++) { + /* This comparison must be done with only the keys in the + * "matching" dict to enable general searches. + */ + if (dict->isEqualTo(matching, matching)) { + set->setObject(dict); + } + } + } + } + *generationCount = getGenerationCount(); + IORWLockUnlock(lock); - return result; + 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; + OSSharedPtr set; + OSSharedPtr iter; + 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.get())); + 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; + } + + 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; + } + } - IOLockUnlock(gIOKLDLock); + set->setObject(personality); + } + // Start device matching. + if (result && doNubMatching && (set->getCount() > 0)) { + IOService::catalogNewDrivers(set.get()); + generation++; + } + IORWLockUnlock(lock); - if (sym) - { - IOLockLock(gIOCatalogLock); - gIOCatalogModuleRequests->setObject(sym); - if (cacheMiss) - gIOCatalogCacheMisses->setObject(sym); - IOLockUnlock(gIOCatalogLock); - } +finish: - return ret; + return result; } -extern "C" kern_return_t kmod_unload_cache(void) +bool +IOCatalogue::removeDrivers(bool doNubMatching, bool (^shouldRemove)(OSDictionary *personality)) { - 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); + OSSharedPtr set; + OSSharedPtr iter; + OSDictionary * dict; + OSArray * array; + const OSSymbol * key; + unsigned int idx; + + set = OSOrderedSet::withCapacity(10, + IOServiceOrdering, + (void *)(gIOProbeScoreKey.get())); + if (!set) { + return false; + } + iter = OSCollectionIterator::withCollection(personalities.get()); + if (!iter) { + return false; } - } - - gIOPrelinkedModules->release(); - gIOPrelinkedModules = 0; - - IOLockUnlock(gIOKLDLock); - return result; -} + IORWLockWrite(lock); + while ((key = (const OSSymbol *) iter->getNextObject())) { + array = (OSArray *) personalities->getObject(key); + if (array) { + for (idx = 0; (dict = (OSDictionary *) array->getObject(idx)); idx++) { + if (shouldRemove(dict)) { + set->setObject(dict); + array->removeObject(idx); + idx--; + } + } + } + // Start device matching. + if (doNubMatching && (set->getCount() > 0)) { + IOService::catalogNewDrivers(set.get()); + generation++; + } + } + IORWLockUnlock(lock); -extern "C" kern_return_t kmod_load_from_cache(const char * kmod_name) -{ - 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 true; } /********************************************************************* +* Remove drivers from the catalog which match the +* properties in the matching dictionary. *********************************************************************/ +bool +IOCatalogue::removeDrivers( + OSDictionary * matching, + bool doNubMatching) +{ + if (!matching) { + return false; + } + return removeDrivers(doNubMatching, ^(OSDictionary *dict) { + /* This comparison must be done with only the keys in the + * "matching" dict to enable general searches. + */ + return dict->isEqualTo(matching, matching); + }); +} -static void UniqueProperties( OSDictionary * dict ) +// Return the generation count. +SInt32 +IOCatalogue::getGenerationCount(void) const { - OSString * data; + return generation; +} - data = OSDynamicCast( OSString, dict->getObject( gIOClassKey )); - if( data) { - const OSSymbol *classSymbol = OSSymbol::withString(data); +// Check to see if kernel module has been loaded already, and request its load. +bool +IOCatalogue::isModuleLoaded(OSDictionary * driver, OSObject ** kextRef) const +{ + OSString * moduleName = NULL; + OSString * publisherName = NULL; + OSReturn ret; - 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.get())); + if (moduleName) { + ret = OSKext::loadKextWithIdentifier(moduleName, kextRef); + if (kOSKextReturnDeferred == ret) { + // a request has been queued but the module isn't necessarily + // loaded yet, so stall. + return false; + } + OSString *moduleDextName = OSDynamicCast(OSString, driver->getObject(gIOModuleIdentifierKey.get())); + if (moduleDextName && !(moduleName->isEqualTo(moduleDextName))) { + OSSharedPtr dextRef; + ret = OSKext::loadKextWithIdentifier(moduleDextName, 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 ) +bool +IOCatalogue::isModuleLoaded(OSDictionary * driver, OSSharedPtr& kextRef) const { - 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(); + OSObject* kextRefRaw = NULL; + bool result = isModuleLoaded(driver, &kextRefRaw); + kextRef.reset(kextRefRaw, OSNoRetain); + return result; } -// Initialize the IOCatalog object. -bool IOCatalogue::init(OSArray * initArray) +/* 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) { - 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 + startMatching(moduleName); - return true; + (void) OSKext::setDeferredLoadSucceeded(); + (void) OSKext::considerRebuildOfPrelinkedKernel(); } -// Release all resources used by IOCatalogue and deallocate. -// This will probably never be called. -void IOCatalogue::free( void ) +void +IOCatalogue::moduleHasLoaded(const char * moduleName) { - if ( array ) - array->release(); + OSSharedPtr name; - if ( kernelTables ) - kernelTables->release(); - - super::free(); + name = OSSymbol::withCString(moduleName); + moduleHasLoaded(name.get()); } -#if CATALOGTEST - -static int hackLimit; - -enum { kDriversPerIter = 4 }; +// xxx - return is really OSReturn/kern_return_t +IOReturn +IOCatalogue::unloadModule(OSString * moduleName) const +{ + return OSKext::removeKextWithIdentifier(moduleName->getCStringNoCopy()); +} -void IOCatalogue::ping( thread_call_param_t arg, thread_call_param_t) +IOReturn +IOCatalogue::terminateDrivers(OSDictionary * matching, io_name_t className) { - IOCatalogue * self = (IOCatalogue *) arg; - OSOrderedSet * set; - OSDictionary * table; - int newLimit; + OSDictionary * dict; + OSSharedPtr iter; + IOService * service; + IOReturn ret; + + ret = kIOReturnSuccess; + dict = NULL; + iter = IORegistryIterator::iterateOver(gIOServicePlane, + kIORegistryIterateRecursively); + if (!iter) { + return kIOReturnNoMemory; + } - set = OSOrderedSet::withCapacity( 1 ); + if (matching) { + OSKext::uniquePersonalityProperties( matching, false ); + } - IOLockLock( &self->lock ); + // terminate instances. + do { + iter->reset(); + while ((service = (IOService *)iter->getNextObject())) { + if (className && !service->metaCast(className)) { + continue; + } + if (matching) { + /* Terminate only for personalities that match the matching dictionary. + * This comparison must be done with only the keys in the + * "matching" dict to enable general matching. + */ + dict = service->getPropertyTable(); + if (!dict) { + continue; + } + if (!dict->isEqualTo(matching, matching)) { + continue; + } + } - for( newLimit = 0; newLimit < kDriversPerIter; newLimit++) { - table = (OSDictionary *) self->array->getObject( - hackLimit + newLimit ); - if( table) { - set->setLastObject( table ); + OSKext * kext; + OSSharedPtr dextBundleID; + const char * bundleIDStr; + OSObject * prop; + bool okToTerminate; + bool isDext = service->hasUserServer(); + for (okToTerminate = true;;) { + if (isDext) { + dextBundleID = OSDynamicPtrCast(service->copyProperty(gIOModuleIdentifierKey.get())); + if (!dextBundleID) { + break; + } + bundleIDStr = dextBundleID->getCStringNoCopy(); + } else { + kext = service->getMetaClass()->getKext(); + if (!kext) { + break; + } + bundleIDStr = kext->getIdentifierCString(); + prop = kext->getPropertyForHostArch(kOSBundleAllowUserTerminateKey); + if (prop) { + okToTerminate = (kOSBooleanTrue == prop); + break; + } + } + if (!bundleIDStr) { + break; + } + if (!strcmp(kOSKextKernelIdentifier, bundleIDStr)) { + okToTerminate = false; + break; + } + if (!strncmp("com.apple.", bundleIDStr, strlen("com.apple."))) { + okToTerminate = false; + break; + } + break; + } + if (!okToTerminate) { +#if DEVELOPMENT || DEBUG + okToTerminate = true; +#endif /* DEVELOPMENT || DEBUG */ + IOLog("%sallowing kextunload terminate for bundleID %s\n", + okToTerminate ? "" : "dis", bundleIDStr ? bundleIDStr : "?"); + if (!okToTerminate) { + ret = kIOReturnUnsupported; + break; + } + } + IOOptionBits terminateOptions = kIOServiceRequired | kIOServiceSynchronous; + if (isDext) { + terminateOptions |= kIOServiceTerminateNeedWillTerminate; + } + if (!service->terminate(terminateOptions)) { + ret = kIOReturnUnsupported; + break; + } + } + } while (!service && !iter->isValid()); - OSSymbol * sym = (OSSymbol *) table->getObject( gIOClassKey ); - kprintf("enabling %s\n", sym->getCStringNoCopy()); + return ret; +} - } else { - newLimit--; - break; +IOReturn +IOCatalogue::_removeDrivers(OSDictionary * matching) +{ + IOReturn ret = kIOReturnSuccess; + OSSharedPtr iter; + OSDictionary * dict; + OSArray * array; + const OSSymbol * key; + unsigned int idx; + + // remove configs from catalog. + + iter = OSCollectionIterator::withCollection(personalities.get()); + if (!iter) { + return kIOReturnNoMemory; } - } - - IOService::catalogNewDrivers( set ); - hackLimit += newLimit; - self->generation++; - - IOLockUnlock( &self->lock ); + 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--; + } + } + } + } - 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::terminateDrivers(OSDictionary * matching) { - OSDictionary * nextTable; - OSOrderedSet * set; - OSString * imports; - - set = OSOrderedSet::withCapacity( 1, IOServiceOrdering, - (void *)gIOProbeScoreKey ); - if( !set ) - return( 0 ); + IOReturn ret; - IOLockLock( lock ); - kernelTables->reset(); + if (!matching) { + return kIOReturnBadArgument; + } + ret = terminateDrivers(matching, NULL); + IORWLockWrite(lock); + if (kIOReturnSuccess == ret) { + ret = _removeDrivers(matching); + } + IORWLockUnlock(lock); -#if CATALOGTEST - int hackIndex = 0; -#endif - while( (nextTable = (OSDictionary *) kernelTables->getNextObject())) { -#if CATALOGTEST - if( hackIndex++ > hackLimit) - break; -#endif - imports = OSDynamicCast( OSString, - nextTable->getObject( gIOProviderClassKey )); - if( imports && service->metaCast( imports )) - set->setObject( nextTable ); - } + return ret; +} - *generationCount = getGenerationCount(); +IOReturn +IOCatalogue::terminateDriversForUserspaceReboot() +{ + IOReturn ret = kIOReturnSuccess; + +#if !NO_KEXTD + OSSharedPtr iter; + IOService * service; + bool isDeferredMatch; + bool isDext; + IOOptionBits terminateOptions; + + iter = IORegistryIterator::iterateOver(gIOServicePlane, + kIORegistryIterateRecursively); + if (!iter) { + return kIOReturnNoMemory; + } - IOLockUnlock( lock ); + do { + iter->reset(); + while ((service = (IOService *)iter->getNextObject())) { + isDeferredMatch = service->propertyHasValue(gIOMatchDeferKey, kOSBooleanTrue); + isDext = service->hasUserServer(); + if (isDeferredMatch || isDext) { + if (isDext) { + OSSharedPtr name = OSDynamicPtrCast(service->copyProperty(gIOUserServerNameKey)); + const char *userServerName = NULL; + if (name) { + userServerName = name->getCStringNoCopy(); + } + IOLog("terminating service %s-0x%llx [dext %s]\n", service->getName(), service->getRegistryEntryID(), userServerName ? userServerName : "(null)"); + } else { + OSKext *kext = service->getMetaClass()->getKext(); + const char *bundleID = NULL; + if (kext) { + bundleID = kext->getIdentifierCString(); + } + IOLog("terminating service %s-0x%llx [kext %s]\n", service->getName(), service->getRegistryEntryID(), bundleID ? bundleID : "(null)"); + } + terminateOptions = kIOServiceRequired | kIOServiceSynchronous; + if (isDext) { + terminateOptions |= kIOServiceTerminateNeedWillTerminate; + } + if (!service->terminate(terminateOptions)) { + IOLog("failed to terminate service %s-0x%llx\n", service->getName(), service->getRegistryEntryID()); + ret = kIOReturnUnsupported; + break; + } + } + } + } while (!service && !iter->isValid()); +#endif - return( set ); + return ret; } -// Is personality already in the catalog? -OSOrderedSet * IOCatalogue::findDrivers( OSDictionary * matching, - SInt32 * generationCount) +IOReturn +IOCatalogue::resetAfterUserspaceReboot(void) { - OSDictionary * dict; - OSOrderedSet * set; + OSSharedPtr iter; + IOService * service; - UniqueProperties(matching); - - set = OSOrderedSet::withCapacity( 1, IOServiceOrdering, - (void *)gIOProbeScoreKey ); - - IOLockLock( lock ); - kernelTables->reset(); - while ( (dict = (OSDictionary *) kernelTables->getNextObject()) ) { + iter = IORegistryIterator::iterateOver(gIOServicePlane, + kIORegistryIterateRecursively); + if (!iter) { + return kIOReturnNoMemory; + } - /* 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 ); + do { + iter->reset(); + while ((service = (IOService *)iter->getNextObject())) { + service->resetRematchProperties(); + } + } while (!service && !iter->isValid()); - return set; -} + /* Remove all dext personalities */ + removeDrivers(false, ^(OSDictionary *dict) { + return dict->getObject(gIOUserServerNameKey) != NULL; + }); -// 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); + return kIOReturnSuccess; } -// Add driver config tables to catalog and start matching process. -bool IOCatalogue::addDrivers(OSArray * drivers, - bool doNubMatching ) +IOReturn +IOCatalogue::terminateDriversForModule( + OSString * moduleName, + bool unload) { - 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; + IOReturn ret; + OSSharedPtr 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; + } } - 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 ); + dict = OSDictionary::withCapacity(1); + if (!dict) { + ret = kIOReturnNoMemory; + goto finish; } - } - // Start device matching. - if (doNubMatching && (set->getCount() > 0)) { - IOService::catalogNewDrivers( set ); - generation++; - } - IOLockUnlock( lock ); - - set->release(); - iter->release(); - - return ret; -} -// Remove drivers from the catalog which match the -// properties in the matching dictionary. -bool IOCatalogue::removeDrivers( OSDictionary * matching, - bool doNubMatching) -{ - 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; -} + dict->setObject(gIOModuleIdentifierKey.get(), moduleName); -// Return the generation count. -SInt32 IOCatalogue::getGenerationCount( void ) const -{ - return( generation ); -} + ret = terminateDrivers(dict.get(), NULL); -bool IOCatalogue::isModuleLoaded( OSString * moduleName ) const -{ - return isModuleLoaded(moduleName->getCStringNoCopy()); -} + /* No goto between IOLock calls! + */ + IORWLockWrite(lock); + if (kIOReturnSuccess == ret) { + ret = _removeDrivers(dict.get()); + } -bool IOCatalogue::isModuleLoaded( const char * moduleName ) const -{ - return (kmod_load_request(moduleName, true)); + // Unload the module itself. + if (unload && isLoaded && ret == kIOReturnSuccess) { + ret = unloadModule(moduleName); + } + + IORWLockUnlock(lock); + +finish: + return ret; } -// Check to see if module has been loaded already. -bool IOCatalogue::isModuleLoaded( OSDictionary * driver ) const +IOReturn +IOCatalogue::terminateDriversForModule( + const char * moduleName, + bool unload) { - OSString * moduleName = NULL; + OSSharedPtr name; + IOReturn ret; - if ( !driver ) - return false; + name = OSString::withCString(moduleName); + if (!name) { + return kIOReturnNoMemory; + } - moduleName = OSDynamicCast(OSString, driver->getObject(gIOModuleIdentifierKey)); - if ( moduleName ) - return isModuleLoaded(moduleName); + ret = terminateDriversForModule(name.get(), unload); - /* If a personality doesn't hold the "CFBundleIdentifier" key - * it is assumed to be an "in-kernel" driver. - */ - return true; + return ret; } -// This function is called after a module has been loaded. -void IOCatalogue::moduleHasLoaded( OSString * moduleName ) +#if defined(__i386__) || defined(__x86_64__) +bool +IOCatalogue::startMatching( OSDictionary * matching ) { - OSDictionary * dict; + OSSharedPtr set; - dict = OSDictionary::withCapacity(2); - dict->setObject(gIOModuleIdentifierKey, moduleName); - startMatching(dict); - dict->release(); -} + if (!matching) { + return false; + } -void IOCatalogue::moduleHasLoaded( const char * moduleName ) -{ - OSString * name; + set = OSOrderedSet::withCapacity(10, IOServiceOrdering, + (void *)(gIOProbeScoreKey.get())); + if (!set) { + return false; + } - name = OSString::withCString(moduleName); - moduleHasLoaded(name); - name->release(); -} + IORWLockRead(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) ) { - 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; -} + personalities->iterateObjects(^bool (const OSSymbol * key, OSObject * value) { + OSArray * array; + OSDictionary * dict; + unsigned int idx; -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; -} + 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; + }); -static IOReturn _removeDrivers( OSArray * array, OSDictionary * matching ) -{ - OSCollectionIterator * tables; - OSDictionary * dict; - OSArray * arrayCopy; - IOReturn ret = kIOReturnSuccess; + // Start device matching. + if (set->getCount() > 0) { + IOService::catalogNewDrivers(set.get()); + generation++; + } - // remove configs from catalog. + IORWLockUnlock(lock); - arrayCopy = OSArray::withCapacity(100); - if ( !arrayCopy ) - return kIOReturnNoMemory; + return true; +} +#endif /* defined(__i386__) || defined(__x86_64__) */ - tables = OSCollectionIterator::withCollection(arrayCopy); - arrayCopy->release(); - if ( !tables ) - return kIOReturnNoMemory; +bool +IOCatalogue::startMatching( const OSSymbol * moduleName ) +{ + OSSharedPtr set; - arrayCopy->merge(array); - array->flushCollection(); - tables->reset(); - while ( (dict = (OSDictionary *)tables->getNextObject()) ) { + if (!moduleName) { + return false; + } - /* 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; + set = OSOrderedSet::withCapacity(10, IOServiceOrdering, + (void *)(gIOProbeScoreKey.get())); + if (!set) { + return false; + } - array->setObject(dict); - } + IORWLockRead(lock); + + personalities->iterateObjects(^bool (const OSSymbol * key, OSObject * value) { + OSArray * array; + OSDictionary * dict; + OSObject * moduleIdentifierKernel; + OSObject * moduleIdentifier; + unsigned int idx; + + array = (OSArray *) value; + for (idx = 0; (dict = (OSDictionary *) array->getObject(idx)); idx++) { + moduleIdentifierKernel = dict->getObject(gIOModuleIdentifierKernelKey.get()); + moduleIdentifier = dict->getObject(gIOModuleIdentifierKey.get()); + if ((moduleIdentifierKernel && moduleName->isEqualTo(moduleIdentifierKernel)) || + (moduleIdentifier && moduleName->isEqualTo(moduleIdentifier))) { + set->setObject(dict); + } + } + return false; + }); + + // Start device matching. + if (set->getCount() > 0) { + IOService::catalogNewDrivers(set.get()); + generation++; + } - tables->release(); + IORWLockUnlock(lock); - 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 + const OSSymbol * key; + OSArray * array; + OSDictionary * thisNewPersonality = NULL;// do not release + OSDictionary * thisOldPersonality = NULL;// do not release + OSSharedPtr myKexts; + OSSharedPtr iter; + OSSharedPtr matchSet; + signed int idx, newIdx; + + if (drivers) { + newPersonalities = OSDynamicCast(OSArray, drivers); + if (!newPersonalities) { + goto finish; + } + } + matchSet = OSOrderedSet::withCapacity(10, IOServiceOrdering, + (void *)(gIOProbeScoreKey.get())); + if (!matchSet) { + goto finish; + } + iter = OSCollectionIterator::withCollection(personalities.get()); + if (!iter) { + goto finish; + } - 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.get(), thisOldPersonality) == false) { + if (matchSet) { + matchSet->setObject(thisOldPersonality); + } + array->removeObject(idx); + idx--; + } + } + } // for... + } // while... + + // add new + if (newPersonalities) { + for (newIdx = 0; + (thisNewPersonality = (OSDictionary *) newPersonalities->getObject(newIdx)); + newIdx++) { + if (OSDynamicCast(OSDictionary, thisNewPersonality) == NULL) { + /* skip thisNewPersonality if it is not an OSDictionary */ + continue; + } - 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.get()); + generation++; + } - name = OSString::withCString(moduleName); - if ( !name ) - return kIOReturnNoMemory; + IORWLockUnlock(lock); - ret = terminateDriversForModule(name, unload); - name->release(); +finish: - 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.get())); + 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_arg("keepsyms", &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. + **********************************************************************/