Loading...
--- xnu/xnu-12377.101.15/iokit/Kernel/IOCatalogue.cpp
+++ xnu/xnu-792.2.4/iokit/Kernel/IOCatalogue.cpp
@@ -1,1422 +1,1280 @@
/*
- * Copyright (c) 1998-2012 Apple Inc. All rights reserved.
+ * Copyright (c) 1998-2004 Apple Computer, Inc. All rights reserved.
*
- * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. The rights granted to you under the License
- * may not be used to create, or enable the creation or redistribution of,
- * unlawful or unlicensed copies of an Apple operating system, or to
- * circumvent, violate, or enable the circumvention or violation of, any
- * terms of an Apple operating system software license agreement.
- *
- * Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This 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,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * 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@
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
*/
/*
- * Copyright (c) 1998 Apple Inc. All rights reserved.
+ * Copyright (c) 1998 Apple Computer, Inc. All rights reserved.
*
* HISTORY
*
*/
-/*
- * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce
- * support for mandatory and extensible security protections. This notice
- * is included in support of clause 2.2 (b) of the Apple Public License,
- * Version 2.0.
- */
-
-#define IOKIT_ENABLE_SHARED_PTR
-
-extern "C" {
-#include <libkern/kernel_mach_header.h>
-#include <kern/host.h>
-#include <security/mac_data.h>
-};
-
-#include <machine/machine_routines.h>
-#include <libkern/c++/OSContainers.h>
-#include <libkern/c++/OSUnserialize.h>
-#include <libkern/c++/OSKext.h>
-#include <libkern/c++/OSSharedPtr.h>
-#include <libkern/OSKextLibPrivate.h>
-#include <libkern/OSDebug.h>
#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 <kern/host.h>
+};
#include <IOKit/IOLib.h>
+
#include <IOKit/assert.h>
-#include <IOKit/IOKitKeysPrivate.h>
-
-#if PRAGMA_MARK
-#pragma mark Internal Declarations
-#endif
+
+
+extern "C" {
+int IODTGetLoaderInfo( char *key, void **infoAddr, int *infoSize );
+extern void IODTFreeLoaderInfo( char *key, void *infoAddr, int infoSize );
+/* operates on 32 bit segments */
+extern void OSRuntimeUnloadCPPForSegment(struct segment_command * segment);
+};
+
+
+/*****
+ * At startup these function pointers are set to use the libsa in-kernel
+ * linker for recording and loading kmods. Once the root filesystem
+ * is available, the kmod_load_function pointer gets switched to point
+ * at the kmod_load_extension() function built into the kernel, and the
+ * others are set to zero. Those two functions must *always* be checked
+ * before being invoked.
+ */
+extern "C" {
+kern_return_t (*kmod_load_function)(char *extension_name) =
+ &kmod_load_extension;
+bool (*record_startup_extensions_function)(void) = 0;
+bool (*add_from_mkext_function)(OSData * mkext) = 0;
+void (*remove_startup_extension_function)(const char * name) = 0;
+};
+
+
+/*****
+ * 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;
+
+#define kModuleKey "CFBundleIdentifier"
+
+#define super OSObject
+OSDefineMetaClassAndStructors(IOCatalogue, OSObject)
+
+#define CATALOGTEST 0
+
+IOCatalogue * gIOCatalogue;
+const OSSymbol * gIOClassKey;
+const OSSymbol * gIOProbeScoreKey;
+const OSSymbol * gIOModuleIdentifierKey;
+OSSet * gIOCatalogModuleRequests;
+OSSet * gIOCatalogCacheMisses;
+OSSet * gIOCatalogROMMkexts;
+IOLock * gIOCatalogLock;
+IOLock * gIOKLDLock;
+
/*********************************************************************
*********************************************************************/
-OSSharedPtr<IOCatalogue> gIOCatalogue;
-OSSharedPtr<const OSSymbol> gIOClassKey;
-OSSharedPtr<const OSSymbol> gIOProbeScoreKey;
-OSSharedPtr<const OSSymbol> gIOModuleIdentifierKey;
-OSSharedPtr<const OSSymbol> gIOModuleIdentifierKernelKey;
-OSSharedPtr<const OSSymbol> gIOHIDInterfaceClassName;
-IORWLock * gIOCatalogLock;
-
-#if PRAGMA_MARK
-#pragma mark Utility functions
-#endif
-
-#if PRAGMA_MARK
-#pragma mark IOCatalogue class implementation
-#endif
+OSArray * gIOPrelinkedModules = 0;
+
+extern "C" kern_return_t
+kmod_create_internal(
+ kmod_info_t *info,
+ kmod_t *id);
+
+extern "C" kern_return_t
+kmod_destroy_internal(kmod_t id);
+
+extern "C" kern_return_t
+kmod_start_or_stop(
+ kmod_t id,
+ int start,
+ kmod_args_t *data,
+ mach_msg_type_number_t *dataCount);
+
+extern "C" kern_return_t kmod_retain(kmod_t id);
+extern "C" kern_return_t kmod_release(kmod_t id);
+
+static
+kern_return_t start_prelink_module(UInt32 moduleIndex)
+{
+ 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;
+ }
+ }
+
+ if (KERN_SUCCESS != kr)
+ return kr;
+
+ for (next = (count - 1); next >= 0; next--)
+ {
+ dict = (OSDictionary *) prelinkedModules->getObject(togo[next]);
+
+ data = OSDynamicCast(OSData, dict->getObject("OSBundlePrelink"));
+ if (!data)
+ continue;
+ prelink = (UInt32 *) data->getBytesNoCopy();
+
+ kmod_t id;
+ kmod_info_t * kmod_info = (kmod_info_t *) OSReadBigInt32(prelink, 0);
+
+ kr = kmod_create_internal(kmod_info, &id);
+ if (KERN_SUCCESS != kr)
+ break;
+
+ lastDep = OSReadBigInt32(prelink, 12);
+ for (SInt32 idx = OSReadBigInt32(prelink, 8); idx < lastDep; idx += sizeof(UInt32))
+ {
+ OSDictionary * depDict;
+ kmod_info_t * depInfo;
+
+ depDict = (OSDictionary *) prelinkedModules->getObject(OSReadBigInt32(prelink, idx) - 1);
+ str = OSDynamicCast(OSString, depDict->getObject(kModuleKey));
+ depInfo = kmod_lookupbyname_locked(str->getCStringNoCopy());
+ if (depInfo)
+ {
+ kr = kmod_retain(KMOD_PACK_IDS(id, depInfo->id));
+ kfree(depInfo, sizeof(kmod_info_t));
+ } else
+ IOLog("%s: NO DEP %s\n", kmod_info->name, str->getCStringNoCopy());
+ }
+ dict->removeObject("OSBundlePrelink");
+
+ if (kmod_info->start)
+ kr = kmod_start_or_stop(kmod_info->id, 1, 0, 0);
+ }
+
+ IODelete(togo, UInt32, prelinkedModules->getCount());
+
+ return kr;
+}
+
+/*********************************************************************
+* This is a function that IOCatalogue calls in order to load a kmod.
+*********************************************************************/
+
+static
+kern_return_t kmod_load_from_cache_sym(const OSSymbol * kmod_name)
+{
+ OSArray * prelinkedModules = gIOPrelinkedModules;
+ kern_return_t result = KERN_FAILURE;
+ OSDictionary * dict;
+ OSObject * ident;
+ UInt32 idx;
+
+ if (!gIOPrelinkedModules)
+ return KERN_FAILURE;
+
+ for (idx = 0;
+ (dict = (OSDictionary *) prelinkedModules->getObject(idx));
+ idx++)
+ {
+ if ((ident = dict->getObject(kModuleKey))
+ && kmod_name->isEqualTo(ident))
+ break;
+ }
+ if (dict)
+ {
+ if (kernelLinkerPresent && dict->getObject("OSBundleDefer"))
+ {
+ kmod_load_extension((char *) kmod_name->getCStringNoCopy());
+ result = kIOReturnOffline;
+ }
+ else
+ result = start_prelink_module(idx);
+ }
+
+ return result;
+}
+
+extern "C" Boolean kmod_load_request(const char * moduleName, Boolean make_request)
+{
+ bool ret, cacheMiss = false;
+ kern_return_t kr;
+ const OSSymbol * sym = 0;
+ kmod_info_t * kmod_info;
+
+ if (!moduleName)
+ return false;
+
+ /* To make sure this operation completes even if a bad extension needs
+ * to be removed, take the kld lock for this whole block, spanning the
+ * kmod_load_function() and remove_startup_extension_function() calls.
+ */
+ IOLockLock(gIOKLDLock);
+ do
+ {
+ // Is the module already loaded?
+ ret = (0 != (kmod_info = kmod_lookupbyname_locked((char *)moduleName)));
+ if (ret) {
+ kfree(kmod_info, sizeof(kmod_info_t));
+ break;
+ }
+ sym = OSSymbol::withCString(moduleName);
+ if (!sym) {
+ ret = false;
+ break;
+ }
+
+ kr = kmod_load_from_cache_sym(sym);
+ ret = (kIOReturnSuccess == kr);
+ cacheMiss = !ret;
+ if (ret || !make_request || (kr == kIOReturnOffline))
+ break;
+
+ // If the module hasn't been loaded, then load it.
+ if (!kmod_load_function) {
+ IOLog("IOCatalogue: %s cannot be loaded "
+ "(kmod load function not set).\n",
+ moduleName);
+ ret = true;
+ break;
+ }
+
+ kr = kmod_load_function((char *)moduleName);
+
+ if (ret != kIOReturnSuccess) {
+ IOLog("IOCatalogue: %s cannot be loaded.\n", moduleName);
+
+ /* If the extension couldn't be loaded this time,
+ * make it unavailable so that no more requests are
+ * made in vain. This also enables other matching
+ * extensions to have a chance.
+ */
+ if (kernelLinkerPresent && remove_startup_extension_function) {
+ (*remove_startup_extension_function)(moduleName);
+ }
+ ret = false;
+
+ } else if (kernelLinkerPresent) {
+ // If kern linker is here, the driver is actually loaded,
+ // so return true.
+ ret = true;
+
+ } else {
+ // kern linker isn't here, a request has been queued
+ // but the module isn't necessarily loaded yet, so stall.
+ ret = false;
+ }
+ }
+ while (false);
+
+ IOLockUnlock(gIOKLDLock);
+
+ if (sym)
+ {
+ IOLockLock(gIOCatalogLock);
+ gIOCatalogModuleRequests->setObject(sym);
+ if (cacheMiss)
+ gIOCatalogCacheMisses->setObject(sym);
+ IOLockUnlock(gIOCatalogLock);
+ }
+
+ return ret;
+}
+
+extern "C" kern_return_t kmod_unload_cache(void)
+{
+ OSArray * prelinkedModules = gIOPrelinkedModules;
+ kern_return_t result = KERN_FAILURE;
+ OSDictionary * dict;
+ UInt32 idx;
+ UInt32 * prelink;
+ OSData * data;
+
+ if (!gIOPrelinkedModules)
+ return KERN_SUCCESS;
+
+ IOLockLock(gIOKLDLock);
+ for (idx = 0;
+ (dict = (OSDictionary *) prelinkedModules->getObject(idx));
+ idx++)
+ {
+ data = OSDynamicCast(OSData, dict->getObject("OSBundlePrelink"));
+ if (!data)
+ continue;
+ prelink = (UInt32 *) data->getBytesNoCopy();
+
+ kmod_info_t * kmod_info = (kmod_info_t *) OSReadBigInt32(prelink, 0);
+ vm_offset_t
+ virt = ml_static_ptovirt(kmod_info->address);
+ if( virt) {
+ ml_static_mfree(virt, kmod_info->size);
+ }
+ }
+
+ gIOPrelinkedModules->release();
+ gIOPrelinkedModules = 0;
+
+ IOLockUnlock(gIOKLDLock);
+
+ return result;
+}
+
+extern "C" kern_return_t kmod_load_from_cache(const char * kmod_name)
+{
+ 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;
+}
+
/*********************************************************************
*********************************************************************/
-#define super OSObject
-OSDefineMetaClassAndStructors(IOCatalogue, OSObject)
-
-static bool isModuleLoadedNoOSKextLock(OSDictionary *theKexts,
- OSDictionary *theModuleDict);
+static void UniqueProperties( OSDictionary * dict )
+{
+ OSString * data;
+
+ data = OSDynamicCast( OSString, dict->getObject( gIOClassKey ));
+ if( data) {
+ const OSSymbol *classSymbol = OSSymbol::withString(data);
+
+ dict->setObject( gIOClassKey, (OSSymbol *) classSymbol);
+ classSymbol->release();
+ }
+
+ data = OSDynamicCast( OSString, dict->getObject( gIOMatchCategoryKey ));
+ if( data) {
+ const OSSymbol *classSymbol = OSSymbol::withString(data);
+
+ dict->setObject( gIOMatchCategoryKey, (OSSymbol *) classSymbol);
+ classSymbol->release();
+ }
+}
+
+void IOCatalogue::initialize( void )
+{
+ 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();
+}
+
+// Initialize the IOCatalog object.
+bool IOCatalogue::init(OSArray * initArray)
+{
+ 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
+
+ return true;
+}
+
+// Release all resources used by IOCatalogue and deallocate.
+// This will probably never be called.
+void IOCatalogue::free( void )
+{
+ if ( array )
+ array->release();
+
+ if ( kernelTables )
+ kernelTables->release();
+
+ super::free();
+}
+
+#if CATALOGTEST
+
+static int hackLimit;
+
+enum { kDriversPerIter = 4 };
+
+void IOCatalogue::ping( thread_call_param_t arg, thread_call_param_t)
+{
+ IOCatalogue * self = (IOCatalogue *) arg;
+ OSOrderedSet * set;
+ OSDictionary * table;
+ int newLimit;
+
+ set = OSOrderedSet::withCapacity( 1 );
+
+ 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());
+
+ } else {
+ newLimit--;
+ break;
+ }
+ }
+
+ IOService::catalogNewDrivers( set );
+
+ hackLimit += newLimit;
+ self->generation++;
+
+ IOLockUnlock( &self->lock );
+
+ if( kDriversPerIter == newLimit) {
+ AbsoluteTime deadline;
+ clock_interval_to_deadline( 500, kMillisecondScale );
+ thread_call_func_delayed( ping, this, deadline );
+ }
+}
+#endif
+
+OSOrderedSet * IOCatalogue::findDrivers( IOService * service,
+ SInt32 * generationCount )
+{
+ OSDictionary * nextTable;
+ OSOrderedSet * set;
+ OSString * imports;
+
+ set = OSOrderedSet::withCapacity( 1, IOServiceOrdering,
+ (void *)gIOProbeScoreKey );
+ if( !set )
+ return( 0 );
+
+ IOLockLock( lock );
+ kernelTables->reset();
+
+#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 );
+ }
+
+ *generationCount = getGenerationCount();
+
+ IOLockUnlock( lock );
+
+ return( set );
+}
+
+// Is personality already in the catalog?
+OSOrderedSet * IOCatalogue::findDrivers( OSDictionary * matching,
+ SInt32 * generationCount)
+{
+ OSDictionary * dict;
+ OSOrderedSet * set;
+
+ UniqueProperties(matching);
+
+ set = OSOrderedSet::withCapacity( 1, IOServiceOrdering,
+ (void *)gIOProbeScoreKey );
+
+ 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 searches.
+ */
+ if ( dict->isEqualTo(matching, matching) )
+ set->setObject(dict);
+ }
+ *generationCount = getGenerationCount();
+ IOLockUnlock( lock );
+
+ return set;
+}
+
+// Add a new personality to the set if it has a unique IOResourceMatchKey value.
+// XXX -- svail: This should be optimized.
+// esb - There doesn't seem like any reason to do this - it causes problems
+// esb - when there are more than one loadable driver matching on the same provider class
+static void AddNewImports( OSOrderedSet * set, OSDictionary * dict )
+{
+ set->setObject(dict);
+}
+
+// Add driver config tables to catalog and start matching process.
+bool IOCatalogue::addDrivers(OSArray * drivers,
+ bool doNubMatching )
+{
+ 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;
+}
+
+// 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;
+}
+
+// Return the generation count.
+SInt32 IOCatalogue::getGenerationCount( void ) const
+{
+ return( generation );
+}
+
+bool IOCatalogue::isModuleLoaded( OSString * moduleName ) const
+{
+ return isModuleLoaded(moduleName->getCStringNoCopy());
+}
+
+bool IOCatalogue::isModuleLoaded( const char * moduleName ) const
+{
+ return (kmod_load_request(moduleName, true));
+}
+
+// Check to see if module has been loaded already.
+bool IOCatalogue::isModuleLoaded( OSDictionary * driver ) const
+{
+ OSString * moduleName = NULL;
+
+ if ( !driver )
+ return false;
+
+ moduleName = OSDynamicCast(OSString, driver->getObject(gIOModuleIdentifierKey));
+ if ( moduleName )
+ return isModuleLoaded(moduleName);
+
+ /* If a personality doesn't hold the "CFBundleIdentifier" key
+ * it is assumed to be an "in-kernel" driver.
+ */
+ return true;
+}
+
+// This function is called after a module has been loaded.
+void IOCatalogue::moduleHasLoaded( OSString * moduleName )
+{
+ OSDictionary * dict;
+
+ dict = OSDictionary::withCapacity(2);
+ dict->setObject(gIOModuleIdentifierKey, moduleName);
+ startMatching(dict);
+ dict->release();
+}
+
+void IOCatalogue::moduleHasLoaded( const char * moduleName )
+{
+ OSString * name;
+
+ name = OSString::withCString(moduleName);
+ moduleHasLoaded(name);
+ name->release();
+}
+
+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;
+}
+
+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;
+}
+
+static IOReturn _removeDrivers( OSArray * array, OSDictionary * matching )
+{
+ OSCollectionIterator * tables;
+ OSDictionary * dict;
+ OSArray * arrayCopy;
+ IOReturn ret = kIOReturnSuccess;
+
+ // remove configs from catalog.
+
+ arrayCopy = OSArray::withCapacity(100);
+ if ( !arrayCopy )
+ return kIOReturnNoMemory;
+
+ tables = OSCollectionIterator::withCollection(arrayCopy);
+ arrayCopy->release();
+ if ( !tables )
+ return kIOReturnNoMemory;
+
+ arrayCopy->merge(array);
+ array->flushCollection();
+ tables->reset();
+ while ( (dict = (OSDictionary *)tables->getNextObject()) ) {
+
+ /* 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->setObject(dict);
+ }
+
+ tables->release();
+
+ return ret;
+}
+
+IOReturn IOCatalogue::terminateDrivers( OSDictionary * matching )
+{
+ IOReturn ret;
+
+ ret = _terminateDrivers(matching);
+ IOLockLock( lock );
+ if (kIOReturnSuccess == ret)
+ ret = _removeDrivers(array, matching);
+ kernelTables->reset();
+ IOLockUnlock( lock );
+
+ return ret;
+}
+
+IOReturn IOCatalogue::terminateDriversForModule(
+ OSString * moduleName,
+ bool unload )
+{
+ IOReturn ret;
+ OSDictionary * dict;
+
+ dict = OSDictionary::withCapacity(1);
+ if ( !dict )
+ return kIOReturnNoMemory;
+
+ dict->setObject(gIOModuleIdentifierKey, moduleName);
+
+ ret = _terminateDrivers(dict);
+ IOLockLock( lock );
+ if (kIOReturnSuccess == ret)
+ ret = _removeDrivers(array, dict);
+ kernelTables->reset();
+
+ // Unload the module itself.
+ if ( unload && ret == kIOReturnSuccess ) {
+ // Do kmod stop first.
+ ret = unloadModule(moduleName);
+ }
+
+ IOLockUnlock( lock );
+
+ dict->release();
+
+ return ret;
+}
+
+IOReturn IOCatalogue::terminateDriversForModule(
+ const char * moduleName,
+ bool unload )
+{
+ OSString * name;
+ IOReturn ret;
+
+ name = OSString::withCString(moduleName);
+ if ( !name )
+ return kIOReturnNoMemory;
+
+ ret = terminateDriversForModule(name, unload);
+ name->release();
+
+ return ret;
+}
+
+bool IOCatalogue::startMatching( OSDictionary * matching )
+{
+ 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;
+}
+
+void IOCatalogue::reset(void)
+{
+ IOLog("Resetting IOCatalogue.\n");
+}
+
+bool IOCatalogue::serialize(OSSerialize * s) const
+{
+ if ( !s )
+ return false;
+
+ return super::serialize(s);
+}
+
+bool IOCatalogue::serializeData(IOOptionBits kind, OSSerialize * s) const
+{
+ kern_return_t kr = kIOReturnSuccess;
+
+ switch ( kind )
+ {
+ case kIOCatalogGetContents:
+ if (!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;
+}
+
+
+bool IOCatalogue::recordStartupExtensions(void) {
+ bool result = false;
+
+ IOLockLock(kld_lock);
+ if (kernelLinkerPresent && record_startup_extensions_function) {
+ result = (*record_startup_extensions_function)();
+ } else {
+ IOLog("Can't record startup extensions; "
+ "kernel linker is not present.\n");
+ result = false;
+ }
+ IOLockUnlock(kld_lock);
+
+ return result;
+}
/*********************************************************************
+* This function operates on sections retrieved from the currently running
+* 32 bit mach kernel.
*********************************************************************/
-void
-IOCatalogue::initialize(void)
-{
- OSSharedPtr<OSArray> array;
- OSSharedPtr<OSString> errorString;
- bool rc;
-
- extern const char * gIOKernelConfigTables;
-
- array = OSDynamicPtrCast<OSArray>(OSUnserialize(gIOKernelConfigTables, errorString));
- if (!array && errorString) {
- IOLog("KernelConfigTables syntax error: %s\n",
- errorString->getCStringNoCopy());
- }
-
- gIOClassKey = OSSymbol::withCStringNoCopy( kIOClassKey );
- gIOProbeScoreKey = OSSymbol::withCStringNoCopy( kIOProbeScoreKey );
- gIOModuleIdentifierKey = OSSymbol::withCStringNoCopy( kCFBundleIdentifierKey );
- gIOModuleIdentifierKernelKey = OSSymbol::withCStringNoCopy( kCFBundleIdentifierKernelKey );
- gIOHIDInterfaceClassName = OSSymbol::withCStringNoCopy( "IOHIDInterface" );
-
-
- assert( array && gIOClassKey && gIOProbeScoreKey
- && gIOModuleIdentifierKey);
-
- gIOCatalogue = OSMakeShared<IOCatalogue>();
- assert(gIOCatalogue);
- rc = gIOCatalogue->init(array.get());
- assert(rc);
-}
+bool IOCatalogue::addExtensionsFromArchive(OSData * mkext)
+{
+ OSData * copyData;
+ bool result = false;
+ bool prelinked;
+
+ /* The mkext we've been handed (or the data it references) can go away,
+ * so we need to make a local copy to keep around as long as it might
+ * be needed.
+ */
+ copyData = OSData::withData(mkext);
+ if (copyData)
+ {
+ struct section * infosect;
+
+ infosect = getsectbyname("__PRELINK", "__info");
+ prelinked = (infosect && infosect->addr && infosect->size);
+
+ IOLockLock(kld_lock);
+
+ if (gIOCatalogROMMkexts)
+ gIOCatalogROMMkexts->setObject(copyData);
+
+ if (prelinked) {
+ result = true;
+ } else if (kernelLinkerPresent && add_from_mkext_function) {
+ result = (*add_from_mkext_function)(copyData);
+ } else {
+ IOLog("Can't add startup extensions from archive; "
+ "kernel linker is not present.\n");
+ result = false;
+ }
+
+ IOLockUnlock(kld_lock);
+
+ copyData->release();
+ }
+
+ return result;
+}
+
/*********************************************************************
-* Initialize the IOCatalog object.
+* 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.
*********************************************************************/
-OSArray *
-IOCatalogue::arrayForPersonality(OSDictionary * dict)
-{
- const OSSymbol * sym;
-
- sym = OSDynamicCast(OSSymbol, dict->getObject(gIOProviderClassKey));
- if (!sym) {
- return NULL;
- }
-
- return (OSArray *) personalities->getObject(sym);
-}
-
-void
-IOCatalogue::addPersonality(OSDictionary * dict)
-{
- const OSSymbol * sym;
- OSArray * arr;
-
- sym = OSDynamicCast(OSSymbol, dict->getObject(gIOProviderClassKey));
- if (!sym) {
- return;
- }
- arr = (OSArray *) personalities->getObject(sym);
- if (arr) {
- arr->setObject(dict);
- } else {
- OSSharedPtr<OSArray> sharedArr = OSArray::withObjects((const OSObject **)&dict, 1, 2);
- personalities->setObject(sym, sharedArr.get());
- }
+kern_return_t IOCatalogue::removeKernelLinker(void) {
+ kern_return_t result = KERN_SUCCESS;
+ struct segment_command * segment;
+ char * dt_segment_name;
+ void * segment_paddress;
+ int segment_size;
+
+ /* This must be the very first thing done by this function.
+ */
+ IOLockLock(kld_lock);
+
+
+ /* If the kernel linker isn't here, that's automatically
+ * a success.
+ */
+ if (!kernelLinkerPresent) {
+ result = KERN_SUCCESS;
+ goto finish;
+ }
+
+ IOLog("Jettisoning kernel linker.\n");
+
+ kernelLinkerPresent = 0;
+
+ /* Set the kmod_load_extension function as the means for loading
+ * a kernel extension.
+ */
+ kmod_load_function = &kmod_load_extension;
+
+ record_startup_extensions_function = 0;
+ add_from_mkext_function = 0;
+ remove_startup_extension_function = 0;
+
+
+ /* Invoke destructors for the __KLD and __LINKEDIT segments.
+ * Do this for all segments before actually freeing their
+ * memory so that any cross-dependencies (not that there
+ * should be any) are handled.
+ */
+ segment = getsegbyname("__KLD");
+ if (!segment) {
+ IOLog("error removing kernel linker: can't find %s segment\n",
+ "__KLD");
+ result = KERN_FAILURE;
+ goto finish;
+ }
+ OSRuntimeUnloadCPPForSegment(segment);
+
+ segment = getsegbyname("__LINKEDIT");
+ if (!segment) {
+ IOLog("error removing kernel linker: can't find %s segment\n",
+ "__LINKEDIT");
+ result = KERN_FAILURE;
+ goto finish;
+ }
+ OSRuntimeUnloadCPPForSegment(segment);
+
+
+ /* Free the memory that was set up by bootx.
+ */
+ dt_segment_name = "Kernel-__KLD";
+ if (0 == IODTGetLoaderInfo(dt_segment_name, &segment_paddress, &segment_size)) {
+ IODTFreeLoaderInfo(dt_segment_name, (void *)segment_paddress,
+ (int)segment_size);
+ }
+
+ dt_segment_name = "Kernel-__LINKEDIT";
+ if (0 == IODTGetLoaderInfo(dt_segment_name, &segment_paddress, &segment_size)) {
+ IODTFreeLoaderInfo(dt_segment_name, (void *)segment_paddress,
+ (int)segment_size);
+ }
+
+ struct section * sect;
+ sect = getsectbyname("__PRELINK", "__symtab");
+ if (sect && sect->addr)
+ {
+ vm_offset_t
+ virt = ml_static_ptovirt(sect->addr);
+ if( virt) {
+ ml_static_mfree(virt, sect->size);
+ }
+ }
+
+finish:
+
+ /* This must be the very last thing done before returning.
+ */
+ IOLockUnlock(kld_lock);
+
+ return result;
}
/*********************************************************************
-* Initialize the IOCatalog object.
+* This function stops the catalogue from making kextd requests during
+* shutdown.
*********************************************************************/
-bool
-IOCatalogue::init(OSArray * initArray)
-{
- OSDictionary * dict;
- OSObject * obj;
-
- if (!super::init()) {
- return false;
- }
-
- 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;
- }
- OSKext::uniquePersonalityProperties(dict);
- if (NULL == dict->getObject( gIOClassKey.get())) {
- IOLog("Missing or bad \"%s\" key\n",
- gIOClassKey->getCStringNoCopy());
- continue;
- }
- dict->setObject("KernelConfigTable", kOSBooleanTrue);
- addPersonality(dict);
- }
-
- gIOCatalogLock = IORWLockAlloc();
- lock = gIOCatalogLock;
-
- return true;
-}
-
-/*********************************************************************
-* Release all resources used by IOCatalogue and deallocate.
-* This will probably never be called.
-*********************************************************************/
-void
-IOCatalogue::free( void )
-{
- panic("");
-}
-
-/*********************************************************************
-*********************************************************************/
-OSPtr<OSOrderedSet>
-IOCatalogue::findDrivers(
- IOService * service,
- SInt32 * generationCount)
-{
- OSDictionary * nextTable;
- OSSharedPtr<OSOrderedSet> set;
- OSArray * array;
- const OSMetaClass * meta;
- unsigned int idx;
-
- set = OSOrderedSet::withCapacity( 1, IOServiceOrdering,
- (void *)(gIOProbeScoreKey.get()));
- if (!set) {
- return NULL;
- }
-
- IORWLockRead(lock);
-
- meta = service->getMetaClass();
- while (meta) {
- array = (OSArray *) personalities->getObject(meta->getClassNameSymbol());
- if (array) {
- for (idx = 0; (nextTable = (OSDictionary *) array->getObject(idx)); idx++) {
- set->setObject(nextTable);
- }
- }
- if (meta == &IOService::gMetaClass) {
- break;
- }
- meta = meta->getSuperClass();
- }
-
- *generationCount = getGenerationCount();
-
- IORWLockUnlock(lock);
-
- return set;
-}
-
-/*********************************************************************
-* Is personality already in the catalog?
-*********************************************************************/
-OSPtr<OSOrderedSet>
-IOCatalogue::findDrivers(
- OSDictionary * matching,
- SInt32 * generationCount)
-{
- OSSharedPtr<OSCollectionIterator> iter;
- OSDictionary * dict;
- OSSharedPtr<OSOrderedSet> set;
- OSArray * array;
- const OSSymbol * key;
- unsigned int idx;
-
- OSKext::uniquePersonalityProperties(matching);
-
- set = OSOrderedSet::withCapacity( 1, IOServiceOrdering,
- (void *)(gIOProbeScoreKey.get()));
- if (!set) {
- return NULL;
- }
- 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 set;
-}
-
-bool
-IOCatalogue::exchangeDrivers(
- OSDictionary *matchingForRemove,
- OSArray *personalitiesToAdd,
- bool doNubMatching)
-{
- OSSharedPtr<OSOrderedSet> set;
- OSSharedPtr<OSCollectionIterator> iter_new, iter_all_personalities;
-
- set = OSOrderedSet::withCapacity(10, IOServiceOrdering,
- (void *)(gIOProbeScoreKey.get()));
- if (!set) {
- goto finish;
- }
-
- iter_new = OSCollectionIterator::withCollection(personalitiesToAdd);
- if (!iter_new) {
- goto finish;
- }
-
- IORWLockWrite(lock);
-
- iter_all_personalities = OSCollectionIterator::withCollection(personalities.get());
- if (!iter_all_personalities) {
- IORWLockUnlock(lock);
- goto finish;
- }
-
- /*
- * Remove personalities first.
- * We get a dictionary that has only some keys that could belong to a personality.
- * Every personality that will match those keys will be removed.
- */
- const OSSymbol * key;
- while ((key = (const OSSymbol *) iter_all_personalities->getNextObject())) {
- OSArray *array = (OSArray *) personalities->getObject(key);
- if (array) {
- unsigned int idx;
- OSDictionary *dict;
- for (idx = 0; (dict = (OSDictionary *) array->getObject(idx)); idx++) {
- if (dict->isEqualTo(matchingForRemove, matchingForRemove)) {
- set->setObject(dict);
- array->removeObject(idx);
- idx--;
- }
- }
- }
- }
-
- /*
- * Add new personalities.
- */
- OSObject *object;
- while ((object = iter_new->getNextObject())) {
- OSDictionary * personality = OSDynamicCast(OSDictionary, object);
- if (personality) {
- OSKext::uniquePersonalityProperties(personality);
- OSArray * array = arrayForPersonality(personality);
- if (!array) {
- addPersonality(personality);
- } else {
- SInt 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;
- }
- array->setObject(personality);
- }
- set->setObject(personality);
- }
- }
-
- if (doNubMatching && (set->getCount() > 0)) {
- IOService::catalogNewDrivers(set.get());
- generation++;
- }
-
- IORWLockUnlock(lock);
-
-finish:
- return true;
-}
-
-/*********************************************************************
-* 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 result = false;
- OSSharedPtr<OSOrderedSet> set;
- OSSharedPtr<OSCollectionIterator> iter;
- OSObject * object = NULL; // do not release
- OSArray * persons = NULL;// do not release
-
- persons = OSDynamicCast(OSArray, drivers);
- if (!persons) {
- goto finish;
- }
-
- set = OSOrderedSet::withCapacity( 10, IOServiceOrdering,
- (void *)(gIOProbeScoreKey.get()));
- if (!set) {
- goto finish;
- }
-
- iter = OSCollectionIterator::withCollection(persons);
- if (!iter) {
- goto finish;
- }
-
- /* Start with success; clear it on an error.
- */
- result = true;
-
- IORWLockWrite(lock);
- while ((object = iter->getNextObject())) {
- // xxx Deleted OSBundleModuleDemand check; will handle in other ways for SL
-
- OSDictionary * personality = OSDynamicCast(OSDictionary, object);
-
- SInt count;
-
- if (!personality) {
- IOLog("IOCatalogue::addDrivers() encountered non-dictionary; bailing.\n");
- result = false;
- break;
- }
-
- OSKext::uniquePersonalityProperties(personality);
-
- // Add driver personality to catalogue.
-
- OSArray * array = arrayForPersonality(personality);
- if (!array) {
- addPersonality(personality);
- } else {
- count = array->getCount();
- while (count--) {
- OSDictionary * driver;
-
- // Be sure not to double up on personalities.
- driver = (OSDictionary *)array->getObject(count);
-
- /* Unlike in other functions, this comparison must be exact!
- * The catalogue must be able to contain personalities that
- * are proper supersets of others.
- * Do not compare just the properties present in one driver
- * 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.get());
- generation++;
- }
- IORWLockUnlock(lock);
-
-finish:
-
- return result;
-}
-
-bool
-IOCatalogue::removeDrivers(bool doNubMatching, bool (^shouldRemove)(OSDictionary *personality))
-{
- OSSharedPtr<OSOrderedSet> set;
- OSSharedPtr<OSCollectionIterator> 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;
- }
-
- 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);
-
- 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);
- });
-}
-
-// Return the generation count.
-SInt32
-IOCatalogue::getGenerationCount(void) const
-{
- return generation;
-}
-/*********************************************************************
-*********************************************************************/
-/* static */
-
-bool
-IOCatalogue::personalityIsBoot(OSDictionary * match)
-{
- OSString * moduleName;
- OSSharedPtr<OSKext> theKext;
-
- moduleName = OSDynamicCast(OSString, match->getObject(gIOModuleIdentifierKey.get()));
- if (!moduleName) {
- return true;
- }
- theKext = OSKext::lookupKextWithIdentifier(moduleName->getCStringNoCopy());
- if (!theKext) {
- return true;
- }
- switch (theKext->kc_type) {
- case KCKindPrimary:
- return true;
- case KCKindUnknown:
- return true;
- case KCKindNone:
- return false;
- case KCKindAuxiliary:
- return false;
- case KCKindPageable:
- return false;
- default:
- assert(false);
- return false;
- }
-}
-
-// 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;
-
- if (kextRef) {
- *kextRef = NULL;
- }
- if (!driver) {
- return false;
- }
-
- /* The personalities of codeless kexts often contain the bundle ID of the
- * kext they reference, and not the bundle ID of the codeless kext itself.
- * The prelinked kernel needs to know the bundle ID of the codeless kext
- * so it can include these personalities, so OSKext stores that bundle ID
- * in the IOPersonalityPublisher key, and we record it as requested here.
- */
- publisherName = OSDynamicCast(OSString,
- driver->getObject(kIOPersonalityPublisherKey));
- OSKext::recordIdentifierRequest(publisherName);
-
- moduleName = OSDynamicCast(OSString, driver->getObject(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<OSObject> dextRef;
- ret = OSKext::loadKextWithIdentifier(moduleDextName, dextRef);
- }
- // module is present or never will be
- return true;
- }
-
- /* If a personality doesn't hold the "CFBundleIdentifier" or "CFBundleIdentifierKernel" key
- * it is assumed to be an "in-kernel" driver.
- */
- return true;
-}
-
-bool
-IOCatalogue::isModuleLoaded(OSDictionary * driver, OSSharedPtr<OSObject>& kextRef) const
-{
- OSObject* kextRefRaw = NULL;
- bool result = isModuleLoaded(driver, &kextRefRaw);
- kextRef.reset(kextRefRaw, OSNoRetain);
- return result;
-}
-
-/* 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)
-{
- startMatching(moduleName);
-
- (void) OSKext::setDeferredLoadSucceeded();
- (void) OSKext::considerRebuildOfPrelinkedKernel();
-}
-
-void
-IOCatalogue::moduleHasLoaded(const char * moduleName)
-{
- OSSharedPtr<const OSSymbol> name;
-
- name = OSSymbol::withCString(moduleName);
- moduleHasLoaded(name.get());
-}
-
-// xxx - return is really OSReturn/kern_return_t
-IOReturn
-IOCatalogue::unloadModule(OSString * moduleName) const
-{
- return OSKext::removeKextWithIdentifier(moduleName->getCStringNoCopy());
-}
-
-IOReturn
-IOCatalogue::terminateDrivers(OSDictionary * matching, io_name_t className, bool asynchronous)
-{
- OSDictionary * dict;
- OSSharedPtr<OSIterator> iter;
- IOService * service;
- IOReturn ret;
-
- ret = kIOReturnSuccess;
- dict = NULL;
- iter = IORegistryIterator::iterateOver(gIOServicePlane,
- kIORegistryIterateRecursively);
- if (!iter) {
- return kIOReturnNoMemory;
- }
-
- if (matching) {
- OSKext::uniquePersonalityProperties( matching, false );
- }
-
- // 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;
- }
- }
-
- OSKext * kext;
- OSSharedPtr<OSString> dextBundleID;
- const char * bundleIDStr;
- OSObject * prop;
- bool okToTerminate;
- bool isDext = service->hasUserServer();
- for (okToTerminate = true;;) {
- if (isDext) {
- dextBundleID = OSDynamicPtrCast<OSString>(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;
- if (!asynchronous) {
- terminateOptions |= kIOServiceSynchronous;
- }
- if (isDext) {
- terminateOptions |= kIOServiceTerminateNeedWillTerminate;
- }
- if (!service->terminate(terminateOptions)) {
- ret = kIOReturnUnsupported;
- break;
- }
- }
- } while (!service && !iter->isValid());
-
- return ret;
-}
-
-IOReturn
-IOCatalogue::_removeDrivers(OSDictionary * matching)
-{
- IOReturn ret = kIOReturnSuccess;
- OSSharedPtr<OSCollectionIterator> iter;
- OSDictionary * dict;
- OSArray * array;
- const OSSymbol * key;
- unsigned int idx;
-
- // remove configs from catalog.
-
- iter = OSCollectionIterator::withCollection(personalities.get());
- if (!iter) {
- return kIOReturnNoMemory;
- }
-
- while ((key = (const OSSymbol *) iter->getNextObject())) {
- array = (OSArray *) personalities->getObject(key);
- if (array) {
- for (idx = 0; (dict = (OSDictionary *) array->getObject(idx)); idx++) {
- /* Remove from the catalogue's array any personalities
- * that match the matching dictionary.
- * This comparison must be done with only the keys in the
- * "matching" dict to enable general matching.
- */
- if (dict->isEqualTo(matching, matching)) {
- array->removeObject(idx);
- idx--;
- }
- }
- }
- }
-
- return ret;
-}
-
-IOReturn
-IOCatalogue::terminateDrivers(OSDictionary * matching)
-{
- IOReturn ret;
-
- if (!matching) {
- return kIOReturnBadArgument;
- }
- ret = terminateDrivers(matching, NULL, false);
- IORWLockWrite(lock);
- if (kIOReturnSuccess == ret) {
- ret = _removeDrivers(matching);
- }
- IORWLockUnlock(lock);
-
- return ret;
-}
-
-IOReturn
-IOCatalogue::terminateDriversForUserspaceReboot()
-{
- IOReturn ret = kIOReturnSuccess;
-
-#if !NO_KEXTD
- OSSharedPtr<OSIterator> iter;
- IOService * service;
- bool isDeferredMatch;
- bool isDext;
- bool preserveDuringUserspaceReboot;
- IOOptionBits terminateOptions;
-
- iter = IORegistryIterator::iterateOver(gIOServicePlane,
- kIORegistryIterateRecursively);
- if (!iter) {
- return kIOReturnNoMemory;
- }
-
- do {
- iter->reset();
- while ((service = (IOService *)iter->getNextObject())) {
- isDeferredMatch = service->propertyHasValue(gIOMatchDeferKey, kOSBooleanTrue);
- isDext = service->hasUserServer();
- if (isDeferredMatch || isDext) {
- OSSharedPtr<OSObject> prop = service->copyProperty(gIOUserServerPreserveUserspaceRebootKey, gIOServicePlane, kIORegistryIterateRecursively | kIORegistryIterateParents);
- preserveDuringUserspaceReboot = prop == kOSBooleanTrue;
- if (preserveDuringUserspaceReboot) {
- IOLog("preserving service %s-0x%llx during userspace reboot\n", service->getName(), service->getRegistryEntryID());
- continue;
- }
-
- if (isDext) {
- OSSharedPtr<OSString> name = OSDynamicPtrCast<OSString>(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 ret;
-}
-
-IOReturn
-IOCatalogue::resetAfterUserspaceReboot(void)
-{
- OSSharedPtr<OSIterator> iter;
- IOService * service;
-
- iter = IORegistryIterator::iterateOver(gIOServicePlane,
- kIORegistryIterateRecursively);
- if (!iter) {
- return kIOReturnNoMemory;
- }
-
- do {
- iter->reset();
- while ((service = (IOService *)iter->getNextObject())) {
- service->resetRematchProperties();
- }
- } while (!service && !iter->isValid());
-
- /* Remove all dext personalities */
- removeDrivers(false, ^(OSDictionary *dict) {
- return dict->getObject(gIOUserServerNameKey) != NULL;
- });
-
- return kIOReturnSuccess;
-}
-
-IOReturn
-IOCatalogue::terminateDriversForModule(
- OSString * moduleName,
- bool unload,
- bool asynchronous)
-{
- IOReturn ret;
- OSSharedPtr<OSDictionary> dict;
- OSSharedPtr<OSKext> kext;
- bool isLoaded = false;
- bool isDext = 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;
- }
- }
- kext = OSKext::lookupKextWithIdentifier(moduleName->getCStringNoCopy());
- if (kext) {
- isDext = kext->isDriverKit();
- }
-
- dict = OSDictionary::withCapacity(1);
- if (!dict) {
- ret = kIOReturnNoMemory;
- goto finish;
- }
-
- dict->setObject(gIOModuleIdentifierKey.get(), moduleName);
-
- ret = terminateDrivers(dict.get(), NULL, asynchronous);
-
- if (isDext) {
- /* Force rematching after removing personalities. Dexts are never considered to be "loaded" (from OSKext),
- * so we can't call unloadModule() to remove personalities and start rematching. */
- removeDrivers(dict.get(), true);
- } else {
- /* No goto between IOLock calls!
- */
- IORWLockWrite(lock);
- if (kIOReturnSuccess == ret) {
- ret = _removeDrivers(dict.get());
- }
-
- // Unload the module itself.
- if (unload && isLoaded && ret == kIOReturnSuccess) {
- ret = unloadModule(moduleName);
- }
- IORWLockUnlock(lock);
- }
-
-finish:
- return ret;
-}
-
-IOReturn
-IOCatalogue::terminateDriversForModule(
- const char * moduleName,
- bool unload,
- bool asynchronous)
-{
- OSSharedPtr<OSString> name;
- IOReturn ret;
-
- name = OSString::withCString(moduleName);
- if (!name) {
- return kIOReturnNoMemory;
- }
-
- ret = terminateDriversForModule(name.get(), unload, asynchronous);
-
- return ret;
-}
-
-#if defined(__i386__) || defined(__x86_64__)
-bool
-IOCatalogue::startMatching( OSDictionary * matching )
-{
- OSSharedPtr<OSOrderedSet> set;
-
- if (!matching) {
- return false;
- }
-
- set = OSOrderedSet::withCapacity(10, IOServiceOrdering,
- (void *)(gIOProbeScoreKey.get()));
- if (!set) {
- return false;
- }
-
- IORWLockRead(lock);
-
- personalities->iterateObjects(^bool (const OSSymbol * key, OSObject * value) {
- OSArray * array;
- OSDictionary * dict;
- unsigned int idx;
-
- 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;
- });
-
- // Start device matching.
- if (set->getCount() > 0) {
- IOService::catalogNewDrivers(set.get());
- generation++;
- }
-
- IORWLockUnlock(lock);
-
- return true;
-}
-#endif /* defined(__i386__) || defined(__x86_64__) */
-
-bool
-IOCatalogue::startMatching( const OSSymbol * moduleName )
-{
- OSSharedPtr<OSOrderedSet> set;
- OSSharedPtr<OSKext> kext;
- OSSharedPtr<OSArray> servicesToTerminate;
-
- if (!moduleName) {
- return false;
- }
-
- set = OSOrderedSet::withCapacity(10, IOServiceOrdering,
- (void *)(gIOProbeScoreKey.get()));
- if (!set) {
- return false;
- }
-
- /*
- * Be sure to call into OSKext outside of
- * IORWLock, otherwise it can trigger a lock
- * inversion.
- */
- kext = OSKext::lookupKextWithIdentifier(moduleName->getCStringNoCopy());
-
- IORWLockRead(lock);
-
- if (kext && kext->isDriverKit()) {
- /* We're here because kernelmanagerd called IOCatalogueModuleLoaded after launching a dext.
- * Determine what providers the dext would match against. If there's something already attached
- * to the provider, terminate it.
- *
- * This is only safe to do for HID dexts.
- */
- OSSharedPtr<OSArray> dextPersonalities = kext->copyPersonalitiesArray();
-
- if (!dextPersonalities) {
- IORWLockUnlock(lock);
- return false;
- }
-
- servicesToTerminate = OSArray::withCapacity(1);
- if (!servicesToTerminate) {
- IORWLockUnlock(lock);
- return false;
- }
-
- dextPersonalities->iterateObjects(^bool (OSObject * obj) {
- OSDictionary * personality = OSDynamicCast(OSDictionary, obj);
- OSSharedPtr<OSIterator> iter;
- IOService * provider;
- OSSharedPtr<IOService> service;
- const OSSymbol * category;
-
- if (personality) {
- category = OSDynamicCast(OSSymbol, personality->getObject(gIOMatchCategoryKey));
- if (!category) {
- category = gIODefaultMatchCategoryKey;
- }
- iter = IOService::getMatchingServices(personality);
-
- while (iter && (provider = OSDynamicCast(IOService, iter->getNextObject()))) {
- if (provider->metaCast(gIOHIDInterfaceClassName.get()) != NULL) {
- service.reset(provider->copyClientWithCategory(category), OSNoRetain);
- if (service) {
- servicesToTerminate->setObject(service);
- }
- }
- }
- }
-
- return false;
- });
- }
-
- 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;
- });
-
- if (servicesToTerminate) {
- servicesToTerminate->iterateObjects(^bool (OSObject * obj) {
- IOService * service = OSDynamicCast(IOService, obj);
- if (service) {
- IOOptionBits terminateOptions = kIOServiceRequired;
- if (service->hasUserServer()) {
- terminateOptions |= kIOServiceTerminateNeedWillTerminate;
- }
- if (!service->terminate(terminateOptions)) {
- IOLog("%s: failed to terminate service %s-0x%qx with options %08llx for new dext %s\n", __FUNCTION__, service->getName(), service->getRegistryEntryID(), (long long)terminateOptions, moduleName->getCStringNoCopy());
- }
- }
- return false;
- });
- }
-
- // Start device matching.
- if (set->getCount() > 0) {
- IOService::catalogNewDrivers(set.get());
- generation++;
- }
-
- IORWLockUnlock(lock);
-
- return true;
-}
-
-void
-IOCatalogue::reset(void)
-{
- IOCatalogue::resetAndAddDrivers(/* no drivers; true reset */ NULL,
- /* doMatching */ false);
- return;
-}
-
-bool
-IOCatalogue::resetAndAddDrivers(OSArray * drivers, bool doNubMatching)
-{
- 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<OSDictionary> myKexts;
- OSSharedPtr<OSCollectionIterator> iter;
- OSSharedPtr<OSOrderedSet> 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;
- }
-
- /* 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();
-
- result = true;
-
- IOLog("Resetting IOCatalogue.\n");
-
- /* No goto finish from here to unlock.
- */
- IORWLockWrite(lock);
-
- while ((key = (const OSSymbol *) iter->getNextObject())) {
- array = (OSArray *) personalities->getObject(key);
- if (!array) {
- continue;
- }
-
- for (idx = 0;
- (thisOldPersonality = (OSDictionary *) array->getObject(idx));
- idx++) {
- if (thisOldPersonality->getObject("KernelConfigTable")) {
- continue;
- }
- 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;
- }
-
- OSKext::uniquePersonalityProperties(thisNewPersonality);
- addPersonality(thisNewPersonality);
- matchSet->setObject(thisNewPersonality);
- }
- }
-
- /* Finally, start device matching on all new & removed personalities.
- */
- if (result && doNubMatching && (matchSet->getCount() > 0)) {
- IOService::catalogNewDrivers(matchSet.get());
- generation++;
- }
-
- IORWLockUnlock(lock);
-
-finish:
-
- return result;
-}
-
-bool
-IOCatalogue::serialize(OSSerialize * s) const
-{
- if (!s) {
- return false;
- }
-
- return super::serialize(s);
-}
-
-bool
-IOCatalogue::serializeData(IOOptionBits kind, OSSerialize * s) const
-{
- kern_return_t kr = kIOReturnSuccess;
-
- switch (kind) {
- case kIOCatalogGetContents:
- kr = KERN_NOT_SUPPORTED;
- break;
-
- case kIOCatalogGetModuleDemandList:
- kr = KERN_NOT_SUPPORTED;
- break;
-
- case kIOCatalogGetCacheMissList:
- kr = KERN_NOT_SUPPORTED;
- break;
-
- case kIOCatalogGetROMMkextList:
- kr = KERN_NOT_SUPPORTED;
- break;
-
- default:
- kr = kIOReturnBadArgument;
- break;
- }
-
- return kr;
-}
-
-/* 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)
-{
- bool myResult = false;
- const OSString * myBundleID = NULL;// do not release
- OSKext * myKext = NULL; // do not release
-
- if (theKexts == NULL || theModuleDict == NULL) {
- return myResult;
- }
-
- // gIOModuleIdentifierKey is "CFBundleIdentifier"
- myBundleID = OSDynamicCast(OSString,
- theModuleDict->getObject(gIOModuleIdentifierKey.get()));
- if (myBundleID == NULL) {
- return myResult;
- }
-
- myKext = OSDynamicCast(OSKext, theKexts->getObject(myBundleID->getCStringNoCopy()));
- if (myKext) {
- myResult = myKext->isLoaded();
- }
-
- return myResult;
-}
-
-
-#if PRAGMA_MARK
-#pragma mark Obsolete Kext Loading Stuff
-#endif
-/*********************************************************************
- **********************************************************************
- *** BINARY COMPATIBILITY SECTION ***
- **********************************************************************
- **********************************************************************
- * These functions are no longer used are necessary for C++ binary
- * compatibility on i386.
- **********************************************************************/
+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);
+}
+