/*
- * 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, ©);
- 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.
+ **********************************************************************/