X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/21362eb3e66fd2c787aee132bce100a44d71a99c..0b4c1975fb5e4eccf1012a35081f7e7799b81046:/iokit/Kernel/IOCatalogue.cpp?ds=sidebyside diff --git a/iokit/Kernel/IOCatalogue.cpp b/iokit/Kernel/IOCatalogue.cpp index 73d4bb5ab..8c51eed84 100644 --- a/iokit/Kernel/IOCatalogue.cpp +++ b/iokit/Kernel/IOCatalogue.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2004 Apple Computer, Inc. All rights reserved. + * Copyright (c) 1998-2006 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * @@ -26,65 +26,42 @@ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ /* - * Copyright (c) 1998 Apple Computer, Inc. All rights reserved. + * Copyright (c) 1998 Apple Inc. All rights reserved. * * HISTORY * */ +/* + * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce + * support for mandatory and extensible security protections. This notice + * is included in support of clause 2.2 (b) of the Apple Public License, + * Version 2.0. + */ -#include -#include -#include -#include -#include extern "C" { #include -#include -#include +#include #include +#include }; -#include - -#include - - -extern "C" { -int IODTGetLoaderInfo( char *key, void **infoAddr, int *infoSize ); -extern void IODTFreeLoaderInfo( char *key, void *infoAddr, int infoSize ); -/* operates on 32 bit segments */ -extern void OSRuntimeUnloadCPPForSegment(struct segment_command * segment); -}; - - -/***** - * At startup these function pointers are set to use the libsa in-kernel - * linker for recording and loading kmods. Once the root filesystem - * is available, the kmod_load_function pointer gets switched to point - * at the kmod_load_extension() function built into the kernel, and the - * others are set to zero. Those two functions must *always* be checked - * before being invoked. - */ -extern "C" { -kern_return_t (*kmod_load_function)(char *extension_name) = - &kmod_load_extension; -bool (*record_startup_extensions_function)(void) = 0; -bool (*add_from_mkext_function)(OSData * mkext) = 0; -void (*remove_startup_extension_function)(const char * name) = 0; -}; - +#include +#include +#include +#include -/***** - * A few parts of IOCatalogue require knowledge of - * whether the in-kernel linker is present. This - * variable is set by libsa's bootstrap code. - */ -int kernelLinkerPresent = 0; +#include +#include +#include -#define kModuleKey "CFBundleIdentifier" +#include +#include -#define super OSObject -OSDefineMetaClassAndStructors(IOCatalogue, OSObject) +#if PRAGMA_MARK +#pragma mark Internal Declarations +#endif +/********************************************************************* +*********************************************************************/ #define CATALOGTEST 0 @@ -92,340 +69,60 @@ IOCatalogue * gIOCatalogue; const OSSymbol * gIOClassKey; const OSSymbol * gIOProbeScoreKey; const OSSymbol * gIOModuleIdentifierKey; -OSSet * gIOCatalogModuleRequests; -OSSet * gIOCatalogCacheMisses; -OSSet * gIOCatalogROMMkexts; -IOLock * gIOCatalogLock; -IOLock * gIOKLDLock; +IOLock * gIOCatalogLock; +#if PRAGMA_MARK +#pragma mark Utility functions +#endif /********************************************************************* *********************************************************************/ - -OSArray * gIOPrelinkedModules = 0; - -extern "C" kern_return_t -kmod_create_internal( - kmod_info_t *info, - kmod_t *id); - -extern "C" kern_return_t -kmod_destroy_internal(kmod_t id); - -extern "C" kern_return_t -kmod_start_or_stop( - kmod_t id, - int start, - kmod_args_t *data, - mach_msg_type_number_t *dataCount); - -extern "C" kern_return_t kmod_retain(kmod_t id); -extern "C" kern_return_t kmod_release(kmod_t id); - -static -kern_return_t start_prelink_module(UInt32 moduleIndex) +static void +UniqueProperties(OSDictionary * dict) { - kern_return_t kr = KERN_SUCCESS; - UInt32 * togo; - SInt32 count, where, end; - UInt32 * prelink; - SInt32 next, lastDep; - OSData * data; - OSString * str; - OSDictionary * dict; - - OSArray * - prelinkedModules = gIOPrelinkedModules; + OSString * data; - togo = IONew(UInt32, prelinkedModules->getCount()); - togo[0] = moduleIndex; - count = 1; + data = OSDynamicCast(OSString, dict->getObject(gIOClassKey)); + if (data) { + const OSSymbol *classSymbol = OSSymbol::withString(data); - for (next = 0; next < count; next++) - { - dict = (OSDictionary *) prelinkedModules->getObject(togo[next]); - - data = OSDynamicCast(OSData, dict->getObject("OSBundlePrelink")); - if (!data) - { - // already started or no code - if (togo[next] == moduleIndex) - { - kr = KERN_FAILURE; - break; - } - continue; - } - prelink = (UInt32 *) data->getBytesNoCopy(); - lastDep = OSReadBigInt32(prelink, 12); - for (SInt32 idx = OSReadBigInt32(prelink, 8); idx < lastDep; idx += sizeof(UInt32)) - { - UInt32 depIdx = OSReadBigInt32(prelink, idx) - 1; - - for (where = next + 1; - (where < count) && (togo[where] > depIdx); - where++) {} - - if (where != count) - { - if (togo[where] == depIdx) - continue; - for (end = count; end != where; end--) - togo[end] = togo[end - 1]; - } - count++; - togo[where] = depIdx; - } + dict->setObject( gIOClassKey, (OSSymbol *) classSymbol); + classSymbol->release(); } - if (KERN_SUCCESS != kr) - return kr; - - for (next = (count - 1); next >= 0; next--) - { - dict = (OSDictionary *) prelinkedModules->getObject(togo[next]); - - data = OSDynamicCast(OSData, dict->getObject("OSBundlePrelink")); - if (!data) - continue; - prelink = (UInt32 *) data->getBytesNoCopy(); - - kmod_t id; - kmod_info_t * kmod_info = (kmod_info_t *) OSReadBigInt32(prelink, 0); - - kr = kmod_create_internal(kmod_info, &id); - if (KERN_SUCCESS != kr) - break; - - lastDep = OSReadBigInt32(prelink, 12); - for (SInt32 idx = OSReadBigInt32(prelink, 8); idx < lastDep; idx += sizeof(UInt32)) - { - OSDictionary * depDict; - kmod_info_t * depInfo; - - depDict = (OSDictionary *) prelinkedModules->getObject(OSReadBigInt32(prelink, idx) - 1); - str = OSDynamicCast(OSString, depDict->getObject(kModuleKey)); - depInfo = kmod_lookupbyname_locked(str->getCStringNoCopy()); - if (depInfo) - { - kr = kmod_retain(KMOD_PACK_IDS(id, depInfo->id)); - kfree(depInfo, sizeof(kmod_info_t)); - } else - IOLog("%s: NO DEP %s\n", kmod_info->name, str->getCStringNoCopy()); - } - dict->removeObject("OSBundlePrelink"); + data = OSDynamicCast(OSString, dict->getObject(gIOMatchCategoryKey)); + if (data) { + const OSSymbol *classSymbol = OSSymbol::withString(data); - if (kmod_info->start) - kr = kmod_start_or_stop(kmod_info->id, 1, 0, 0); + dict->setObject(gIOMatchCategoryKey, (OSSymbol *) classSymbol); + classSymbol->release(); } - - IODelete(togo, UInt32, prelinkedModules->getCount()); - - return kr; + return; } /********************************************************************* -* This is a function that IOCatalogue calls in order to load a kmod. +* Add a new personality to the set if it has a unique IOResourceMatchKey value. +* XXX -- svail: This should be optimized. +* esb - There doesn't seem like any reason to do this - it causes problems +* esb - when there are more than one loadable driver matching on the same provider class *********************************************************************/ - -static -kern_return_t kmod_load_from_cache_sym(const OSSymbol * kmod_name) -{ - OSArray * prelinkedModules = gIOPrelinkedModules; - kern_return_t result = KERN_FAILURE; - OSDictionary * dict; - OSObject * ident; - UInt32 idx; - - if (!gIOPrelinkedModules) - return KERN_FAILURE; - - for (idx = 0; - (dict = (OSDictionary *) prelinkedModules->getObject(idx)); - idx++) - { - if ((ident = dict->getObject(kModuleKey)) - && kmod_name->isEqualTo(ident)) - break; - } - if (dict) - { - if (kernelLinkerPresent && dict->getObject("OSBundleDefer")) - { - kmod_load_extension((char *) kmod_name->getCStringNoCopy()); - result = kIOReturnOffline; - } - else - result = start_prelink_module(idx); - } - - return result; -} - -extern "C" Boolean kmod_load_request(const char * moduleName, Boolean make_request) -{ - bool ret, cacheMiss = false; - kern_return_t kr; - const OSSymbol * sym = 0; - kmod_info_t * kmod_info; - - if (!moduleName) - return false; - - /* To make sure this operation completes even if a bad extension needs - * to be removed, take the kld lock for this whole block, spanning the - * kmod_load_function() and remove_startup_extension_function() calls. - */ - IOLockLock(gIOKLDLock); - do - { - // Is the module already loaded? - ret = (0 != (kmod_info = kmod_lookupbyname_locked((char *)moduleName))); - if (ret) { - kfree(kmod_info, sizeof(kmod_info_t)); - break; - } - sym = OSSymbol::withCString(moduleName); - if (!sym) { - ret = false; - break; - } - - kr = kmod_load_from_cache_sym(sym); - ret = (kIOReturnSuccess == kr); - cacheMiss = !ret; - if (ret || !make_request || (kr == kIOReturnOffline)) - break; - - // If the module hasn't been loaded, then load it. - if (!kmod_load_function) { - IOLog("IOCatalogue: %s cannot be loaded " - "(kmod load function not set).\n", - moduleName); - ret = true; - break; - } - - kr = kmod_load_function((char *)moduleName); - - if (ret != kIOReturnSuccess) { - IOLog("IOCatalogue: %s cannot be loaded.\n", moduleName); - - /* If the extension couldn't be loaded this time, - * make it unavailable so that no more requests are - * made in vain. This also enables other matching - * extensions to have a chance. - */ - if (kernelLinkerPresent && remove_startup_extension_function) { - (*remove_startup_extension_function)(moduleName); - } - ret = false; - - } else if (kernelLinkerPresent) { - // If kern linker is here, the driver is actually loaded, - // so return true. - ret = true; - - } else { - // kern linker isn't here, a request has been queued - // but the module isn't necessarily loaded yet, so stall. - ret = false; - } - } - while (false); - - IOLockUnlock(gIOKLDLock); - - if (sym) - { - IOLockLock(gIOCatalogLock); - gIOCatalogModuleRequests->setObject(sym); - if (cacheMiss) - gIOCatalogCacheMisses->setObject(sym); - IOLockUnlock(gIOCatalogLock); - } - - return ret; -} - -extern "C" kern_return_t kmod_unload_cache(void) -{ - OSArray * prelinkedModules = gIOPrelinkedModules; - kern_return_t result = KERN_FAILURE; - OSDictionary * dict; - UInt32 idx; - UInt32 * prelink; - OSData * data; - - if (!gIOPrelinkedModules) - return KERN_SUCCESS; - - IOLockLock(gIOKLDLock); - for (idx = 0; - (dict = (OSDictionary *) prelinkedModules->getObject(idx)); - idx++) - { - data = OSDynamicCast(OSData, dict->getObject("OSBundlePrelink")); - if (!data) - continue; - prelink = (UInt32 *) data->getBytesNoCopy(); - - kmod_info_t * kmod_info = (kmod_info_t *) OSReadBigInt32(prelink, 0); - vm_offset_t - virt = ml_static_ptovirt(kmod_info->address); - if( virt) { - ml_static_mfree(virt, kmod_info->size); - } - } - - gIOPrelinkedModules->release(); - gIOPrelinkedModules = 0; - - IOLockUnlock(gIOKLDLock); - - return result; -} - -extern "C" kern_return_t kmod_load_from_cache(const char * kmod_name) +static void +AddNewImports(OSOrderedSet * set, OSDictionary * dict) { - kern_return_t kr; - const OSSymbol * sym = OSSymbol::withCStringNoCopy(kmod_name); - - if (sym) - { - kr = kmod_load_from_cache_sym(sym); - sym->release(); - } - else - kr = kIOReturnNoMemory; - - return kr; + set->setObject(dict); } +#if PRAGMA_MARK +#pragma mark IOCatalogue class implementation +#endif /********************************************************************* *********************************************************************/ -static void UniqueProperties( OSDictionary * dict ) -{ - OSString * data; - - data = OSDynamicCast( OSString, dict->getObject( gIOClassKey )); - if( data) { - const OSSymbol *classSymbol = OSSymbol::withString(data); - - dict->setObject( gIOClassKey, (OSSymbol *) classSymbol); - classSymbol->release(); - } - - data = OSDynamicCast( OSString, dict->getObject( gIOMatchCategoryKey )); - if( data) { - const OSSymbol *classSymbol = OSSymbol::withString(data); - - dict->setObject( gIOMatchCategoryKey, (OSSymbol *) classSymbol); - classSymbol->release(); - } -} +#define super OSObject +OSDefineMetaClassAndStructors(IOCatalogue, OSObject) -void IOCatalogue::initialize( void ) +/********************************************************************* +*********************************************************************/ +void IOCatalogue::initialize(void) { OSArray * array; OSString * errorString; @@ -435,20 +132,17 @@ void IOCatalogue::initialize( void ) array = OSDynamicCast(OSArray, OSUnserialize(gIOKernelConfigTables, &errorString)); if (!array && errorString) { - IOLog("KernelConfigTables syntax error: %s\n", - errorString->getCStringNoCopy()); - errorString->release(); + IOLog("KernelConfigTables syntax error: %s\n", + errorString->getCStringNoCopy()); + errorString->release(); } gIOClassKey = OSSymbol::withCStringNoCopy( kIOClassKey ); gIOProbeScoreKey = OSSymbol::withCStringNoCopy( kIOProbeScoreKey ); - gIOModuleIdentifierKey = OSSymbol::withCStringNoCopy( kModuleKey ); - gIOCatalogModuleRequests = OSSet::withCapacity(16); - gIOCatalogCacheMisses = OSSet::withCapacity(16); - gIOCatalogROMMkexts = OSSet::withCapacity(4); + gIOModuleIdentifierKey = OSSymbol::withCStringNoCopy( kCFBundleIdentifierKey ); assert( array && gIOClassKey && gIOProbeScoreKey - && gIOModuleIdentifierKey && gIOCatalogModuleRequests); + && gIOModuleIdentifierKey); gIOCatalogue = new IOCatalogue; assert(gIOCatalogue); @@ -457,7 +151,9 @@ void IOCatalogue::initialize( void ) array->release(); } -// Initialize the IOCatalog object. +/********************************************************************* +* Initialize the IOCatalog object. +*********************************************************************/ bool IOCatalogue::init(OSArray * initArray) { OSDictionary * dict; @@ -472,10 +168,11 @@ bool IOCatalogue::init(OSArray * initArray) kernelTables = OSCollectionIterator::withCollection( array ); gIOCatalogLock = IOLockAlloc(); - gIOKLDLock = IOLockAlloc(); lock = gIOCatalogLock; - kld_lock = gIOKLDLock; +#if __ppc__ || __i386__ + kld_lock = NULL; +#endif /* __ppc__ || __i386__ */ kernelTables->reset(); while( (dict = (OSDictionary *) kernelTables->getNextObject())) { @@ -494,8 +191,10 @@ bool IOCatalogue::init(OSArray * initArray) return true; } -// Release all resources used by IOCatalogue and deallocate. -// This will probably never be called. +/********************************************************************* +* Release all resources used by IOCatalogue and deallocate. +* This will probably never be called. +*********************************************************************/ void IOCatalogue::free( void ) { if ( array ) @@ -507,13 +206,15 @@ void IOCatalogue::free( void ) super::free(); } +/********************************************************************* +*********************************************************************/ #if CATALOGTEST static int hackLimit; - enum { kDriversPerIter = 4 }; -void IOCatalogue::ping( thread_call_param_t arg, thread_call_param_t) +void +IOCatalogue::ping(thread_call_param_t arg, thread_call_param_t) { IOCatalogue * self = (IOCatalogue *) arg; OSOrderedSet * set; @@ -530,7 +231,7 @@ void IOCatalogue::ping( thread_call_param_t arg, thread_call_param_t) if( table) { set->setLastObject( table ); - OSSymbol * sym = (OSSymbol *) table->getObject( gIOClassKey ); + OSSymbol * sym = (OSSymbol *) table->getObject(gIOClassKey); kprintf("enabling %s\n", sym->getCStringNoCopy()); } else { @@ -548,14 +249,18 @@ void IOCatalogue::ping( thread_call_param_t arg, thread_call_param_t) if( kDriversPerIter == newLimit) { AbsoluteTime deadline; - clock_interval_to_deadline( 500, kMillisecondScale ); - thread_call_func_delayed( ping, this, deadline ); + clock_interval_to_deadline(500, kMillisecondScale); + thread_call_func_delayed(ping, this, deadline); } } #endif -OSOrderedSet * IOCatalogue::findDrivers( IOService * service, - SInt32 * generationCount ) +/********************************************************************* +*********************************************************************/ +OSOrderedSet * +IOCatalogue::findDrivers( + IOService * service, + SInt32 * generationCount) { OSDictionary * nextTable; OSOrderedSet * set; @@ -566,7 +271,7 @@ OSOrderedSet * IOCatalogue::findDrivers( IOService * service, if( !set ) return( 0 ); - IOLockLock( lock ); + IOLockLock(lock); kernelTables->reset(); #if CATALOGTEST @@ -585,14 +290,18 @@ OSOrderedSet * IOCatalogue::findDrivers( IOService * service, *generationCount = getGenerationCount(); - IOLockUnlock( lock ); + IOLockUnlock(lock); return( set ); } -// Is personality already in the catalog? -OSOrderedSet * IOCatalogue::findDrivers( OSDictionary * matching, - SInt32 * generationCount) +/********************************************************************* +* Is personality already in the catalog? +*********************************************************************/ +OSOrderedSet * +IOCatalogue::findDrivers( + OSDictionary * matching, + SInt32 * generationCount) { OSDictionary * dict; OSOrderedSet * set; @@ -602,7 +311,7 @@ OSOrderedSet * IOCatalogue::findDrivers( OSDictionary * matching, set = OSOrderedSet::withCapacity( 1, IOServiceOrdering, (void *)gIOProbeScoreKey ); - IOLockLock( lock ); + IOLockLock(lock); kernelTables->reset(); while ( (dict = (OSDictionary *) kernelTables->getNextObject()) ) { @@ -613,108 +322,111 @@ OSOrderedSet * IOCatalogue::findDrivers( OSDictionary * matching, set->setObject(dict); } *generationCount = getGenerationCount(); - IOLockUnlock( lock ); + IOLockUnlock(lock); return set; } -// Add a new personality to the set if it has a unique IOResourceMatchKey value. -// XXX -- svail: This should be optimized. -// esb - There doesn't seem like any reason to do this - it causes problems -// esb - when there are more than one loadable driver matching on the same provider class -static void AddNewImports( OSOrderedSet * set, OSDictionary * dict ) -{ - set->setObject(dict); -} - -// Add driver config tables to catalog and start matching process. -bool IOCatalogue::addDrivers(OSArray * drivers, - bool doNubMatching ) +/********************************************************************* +* Add driver config tables to catalog and start matching process. +* +* Important that existing personalities are kept (not replaced) +* if duplicates found. Personalities can come from OSKext objects +* or from userland kext library. We want to minimize distinct +* copies between OSKext & IOCatalogue. +* +* xxx - userlib used to refuse to send personalities with IOKitDebug +* xxx - during safe boot. That would be better implemented here. +*********************************************************************/ +bool IOCatalogue::addDrivers( + OSArray * drivers, + bool doNubMatching) { - OSCollectionIterator * iter; - OSDictionary * dict; - OSOrderedSet * set; - OSArray * persons; - OSString * moduleName; - bool ret; + bool result = false; + OSCollectionIterator * iter = NULL; // must release + OSOrderedSet * set = NULL; // must release + OSDictionary * dict = NULL; // do not release + OSArray * persons = NULL; // do not release - ret = true; persons = OSDynamicCast(OSArray, drivers); - if ( !persons ) - return false; - - iter = OSCollectionIterator::withCollection( persons ); - if (!iter ) - return false; + if (!persons) { + goto finish; + } set = OSOrderedSet::withCapacity( 10, IOServiceOrdering, - (void *)gIOProbeScoreKey ); - if ( !set ) { - iter->release(); - return false; + (void *)gIOProbeScoreKey ); + if (!set) { + goto finish; } - IOLockLock( lock ); - while ( (dict = (OSDictionary *) iter->getNextObject()) ) - { - if ((moduleName = OSDynamicCast(OSString, dict->getObject("OSBundleModuleDemand")))) - { - IOLockUnlock( lock ); - ret = kmod_load_request(moduleName->getCStringNoCopy(), false); - IOLockLock( lock ); - ret = true; - } - else - { - SInt count; - - UniqueProperties( dict ); - - // Add driver personality to catalogue. - count = array->getCount(); - while ( count-- ) { - OSDictionary * driver; - - // Be sure not to double up on personalities. - driver = (OSDictionary *)array->getObject(count); - - /* Unlike in other functions, this comparison must be exact! - * The catalogue must be able to contain personalities that - * are proper supersets of others. - * Do not compare just the properties present in one driver - * pesonality or the other. - */ - if (dict->isEqualTo(driver)) - break; - } - if (count >= 0) - // its a dup - continue; - - ret = array->setObject( dict ); - if (!ret) - break; + iter = OSCollectionIterator::withCollection(persons); + if (!iter) { + goto finish; + } + + result = true; + + IOLockLock(lock); + while ( (dict = (OSDictionary *) iter->getNextObject()) ) { - AddNewImports( set, dict ); - } + // xxx Deleted OSBundleModuleDemand check; will handle in other ways for SL + + SInt count; + + UniqueProperties(dict); + + // Add driver personality to catalogue. + count = array->getCount(); + while (count--) { + OSDictionary * driver; + + // Be sure not to double up on personalities. + driver = (OSDictionary *)array->getObject(count); + + /* Unlike in other functions, this comparison must be exact! + * The catalogue must be able to contain personalities that + * are proper supersets of others. + * Do not compare just the properties present in one driver + * pesonality or the other. + */ + if (dict->isEqualTo(driver)) { + break; + } + } + if (count >= 0) { + // its a dup + continue; + } + + result = array->setObject(dict); + if (!result) { + break; + } + + AddNewImports(set, dict); } // Start device matching. if (doNubMatching && (set->getCount() > 0)) { - IOService::catalogNewDrivers( set ); + IOService::catalogNewDrivers(set); generation++; } - IOLockUnlock( lock ); + IOLockUnlock(lock); - set->release(); - iter->release(); - - return ret; +finish: + if (set) set->release(); + if (iter) iter->release(); + + return result; } -// Remove drivers from the catalog which match the -// properties in the matching dictionary. -bool IOCatalogue::removeDrivers( OSDictionary * matching, - bool doNubMatching) +/********************************************************************* +* Remove drivers from the catalog which match the +* properties in the matching dictionary. +*********************************************************************/ +bool +IOCatalogue::removeDrivers( + OSDictionary * matching, + bool doNubMatching) { OSCollectionIterator * tables; OSDictionary * dict; @@ -745,7 +457,7 @@ bool IOCatalogue::removeDrivers( OSDictionary * matching, UniqueProperties( matching ); - IOLockLock( lock ); + IOLockLock(lock); kernelTables->reset(); arrayCopy->merge(array); array->flushCollection(); @@ -767,7 +479,7 @@ bool IOCatalogue::removeDrivers( OSDictionary * matching, IOService::catalogNewDrivers(set); generation++; } - IOLockUnlock( lock ); + IOLockUnlock(lock); set->release(); tables->release(); @@ -776,29 +488,48 @@ bool IOCatalogue::removeDrivers( OSDictionary * matching, } // Return the generation count. -SInt32 IOCatalogue::getGenerationCount( void ) const +SInt32 IOCatalogue::getGenerationCount(void) const { return( generation ); } -bool IOCatalogue::isModuleLoaded( OSString * moduleName ) const +bool IOCatalogue::isModuleLoaded(OSString * moduleName) const { return isModuleLoaded(moduleName->getCStringNoCopy()); } -bool IOCatalogue::isModuleLoaded( const char * moduleName ) const +bool IOCatalogue::isModuleLoaded(const char * moduleName) const { - return (kmod_load_request(moduleName, true)); + OSReturn ret; + ret = OSKext::loadKextWithIdentifier(moduleName); + if (kOSKextReturnDeferred == ret) { + // a request has been queued but the module isn't necessarily + // loaded yet, so stall. + return false; + } + // module is present or never will be + return true; } // Check to see if module has been loaded already. -bool IOCatalogue::isModuleLoaded( OSDictionary * driver ) const +bool IOCatalogue::isModuleLoaded(OSDictionary * driver) const { OSString * moduleName = NULL; + OSString * publisherName = NULL; if ( !driver ) return false; + /* The personalities of codeless kexts often contain the bundle ID of the + * kext they reference, and not the bundle ID of the codeless kext itself. + * The prelinked kernel needs to know the bundle ID of the codeless kext + * so it can include these personalities, so OSKext stores that bundle ID + * in the IOPersonalityPublisher key, and we record it as requested here. + */ + publisherName = OSDynamicCast(OSString, + driver->getObject(kIOPersonalityPublisherKey)); + OSKext::recordIdentifierRequest(publisherName); + moduleName = OSDynamicCast(OSString, driver->getObject(gIOModuleIdentifierKey)); if ( moduleName ) return isModuleLoaded(moduleName); @@ -809,56 +540,39 @@ bool IOCatalogue::isModuleLoaded( OSDictionary * driver ) const return true; } -// This function is called after a module has been loaded. -void IOCatalogue::moduleHasLoaded( OSString * moduleName ) +/* This function is called after a module has been loaded. + * Is invoked from user client call, ultimately from IOKitLib's + * IOCatalogueModuleLoaded(). Sent from kextd. + */ +void IOCatalogue::moduleHasLoaded(OSString * moduleName) { - OSDictionary * dict; + OSDictionary * dict; dict = OSDictionary::withCapacity(2); dict->setObject(gIOModuleIdentifierKey, moduleName); startMatching(dict); dict->release(); + + (void) OSKext::setDeferredLoadSucceeded(); + (void) OSKext::considerRebuildOfPrelinkedKernel(); } -void IOCatalogue::moduleHasLoaded( const char * moduleName ) +void IOCatalogue::moduleHasLoaded(const char * moduleName) { - OSString * name; + OSString * name; name = OSString::withCString(moduleName); moduleHasLoaded(name); name->release(); } -IOReturn IOCatalogue::unloadModule( OSString * moduleName ) const +// xxx - return is really OSReturn/kern_return_t +IOReturn IOCatalogue::unloadModule(OSString * moduleName) const { - kmod_info_t * k_info = 0; - kern_return_t ret; - const char * name; - - ret = kIOReturnBadArgument; - if ( moduleName ) { - name = moduleName->getCStringNoCopy(); - k_info = kmod_lookupbyname_locked((char *)name); - if ( k_info && (k_info->reference_count < 1) ) { - if ( k_info->stop && - !((ret = k_info->stop(k_info, 0)) == kIOReturnSuccess) ) { - - kfree(k_info, sizeof(kmod_info_t)); - return ret; - } - - ret = kmod_destroy(host_priv_self(), k_info->id); - } - } - - if (k_info) { - kfree(k_info, sizeof(kmod_info_t)); - } - - return ret; + return OSKext::removeKextWithIdentifier(moduleName->getCStringNoCopy()); } -static IOReturn _terminateDrivers( OSDictionary * matching ) +static IOReturn _terminateDrivers(OSDictionary * matching) { OSDictionary * dict; OSIterator * iter; @@ -942,55 +656,82 @@ static IOReturn _removeDrivers( OSArray * array, OSDictionary * matching ) return ret; } -IOReturn IOCatalogue::terminateDrivers( OSDictionary * matching ) +IOReturn IOCatalogue::terminateDrivers(OSDictionary * matching) { IOReturn ret; ret = _terminateDrivers(matching); - IOLockLock( lock ); + IOLockLock(lock); if (kIOReturnSuccess == ret) ret = _removeDrivers(array, matching); kernelTables->reset(); - IOLockUnlock( lock ); + IOLockUnlock(lock); return ret; } IOReturn IOCatalogue::terminateDriversForModule( - OSString * moduleName, - bool unload ) + OSString * moduleName, + bool unload) { IOReturn ret; OSDictionary * dict; + bool isLoaded = false; + + /* Check first if the kext currently has any linkage dependents; + * in such a case the unload would fail so let's not terminate any + * IOServices (since doing so typically results in a panic when there + * are loaded dependencies). Note that we aren't locking the kext here + * so it might lose or gain dependents by the time we call unloadModule(); + * I think that's ok, our unload can fail if a kext comes in on top of + * this one even after we've torn down IOService objects. Conversely, + * if we fail the unload here and then lose a library, the autounload + * thread will get us in short order. + */ + if (OSKext::isKextWithIdentifierLoaded(moduleName->getCStringNoCopy())) { + + isLoaded = true; + if (!OSKext::canUnloadKextWithIdentifier(moduleName, + /* checkClasses */ false)) { + ret = kOSKextReturnInUse; + goto finish; + } + } dict = OSDictionary::withCapacity(1); - if ( !dict ) - return kIOReturnNoMemory; + if (!dict) { + ret = kIOReturnNoMemory; + goto finish; + } dict->setObject(gIOModuleIdentifierKey, moduleName); ret = _terminateDrivers(dict); - IOLockLock( lock ); - if (kIOReturnSuccess == ret) - ret = _removeDrivers(array, dict); + + /* No goto between IOLock calls! + */ + IOLockLock(lock); + if (kIOReturnSuccess == ret) { + ret = _removeDrivers(array, dict); + } kernelTables->reset(); // Unload the module itself. - if ( unload && ret == kIOReturnSuccess ) { - // Do kmod stop first. + if (unload && isLoaded && ret == kIOReturnSuccess) { ret = unloadModule(moduleName); } - IOLockUnlock( lock ); + IOLockUnlock(lock); dict->release(); +finish: return ret; } IOReturn IOCatalogue::terminateDriversForModule( - const char * moduleName, - bool unload ) + const char * moduleName, + bool unload) { OSString * name; IOReturn ret; @@ -1018,7 +759,7 @@ bool IOCatalogue::startMatching( OSDictionary * matching ) if ( !set ) return false; - IOLockLock( lock ); + IOLockLock(lock); kernelTables->reset(); while ( (dict = (OSDictionary *)kernelTables->getNextObject()) ) { @@ -1035,7 +776,7 @@ bool IOCatalogue::startMatching( OSDictionary * matching ) generation++; } - IOLockUnlock( lock ); + IOLockUnlock(lock); set->release(); @@ -1062,39 +803,20 @@ bool IOCatalogue::serializeData(IOOptionBits kind, OSSerialize * s) const switch ( kind ) { case kIOCatalogGetContents: - if (!serialize(s)) + if (!array->serialize(s)) kr = kIOReturnNoMemory; break; case kIOCatalogGetModuleDemandList: - IOLockLock( lock ); - if (!gIOCatalogModuleRequests->serialize(s)) - kr = kIOReturnNoMemory; - IOLockUnlock( lock ); + kr = KERN_NOT_SUPPORTED; break; case kIOCatalogGetCacheMissList: - IOLockLock( lock ); - if (!gIOCatalogCacheMisses->serialize(s)) - kr = kIOReturnNoMemory; - IOLockUnlock( lock ); + kr = KERN_NOT_SUPPORTED; break; case kIOCatalogGetROMMkextList: - IOLockLock( lock ); - - if (!gIOCatalogROMMkexts || !gIOCatalogROMMkexts->getCount()) - kr = kIOReturnNoResources; - else if (!gIOCatalogROMMkexts->serialize(s)) - kr = kIOReturnNoMemory; - - if (gIOCatalogROMMkexts) - { - gIOCatalogROMMkexts->release(); - gIOCatalogROMMkexts = 0; - } - - IOLockUnlock( lock ); + kr = KERN_NOT_SUPPORTED; break; default: @@ -1106,181 +828,26 @@ bool IOCatalogue::serializeData(IOOptionBits kind, OSSerialize * s) const } -bool IOCatalogue::recordStartupExtensions(void) { - bool result = false; - - IOLockLock(kld_lock); - if (kernelLinkerPresent && record_startup_extensions_function) { - result = (*record_startup_extensions_function)(); - } else { - IOLog("Can't record startup extensions; " - "kernel linker is not present.\n"); - result = false; - } - IOLockUnlock(kld_lock); - - return result; -} - - -/********************************************************************* -* This function operates on sections retrieved from the currently running -* 32 bit mach kernel. -*********************************************************************/ -bool IOCatalogue::addExtensionsFromArchive(OSData * mkext) -{ - OSData * copyData; - bool result = false; - bool prelinked; - - /* The mkext we've been handed (or the data it references) can go away, - * so we need to make a local copy to keep around as long as it might - * be needed. - */ - copyData = OSData::withData(mkext); - if (copyData) - { - struct section * infosect; - - infosect = getsectbyname("__PRELINK", "__info"); - prelinked = (infosect && infosect->addr && infosect->size); - - IOLockLock(kld_lock); - - if (gIOCatalogROMMkexts) - gIOCatalogROMMkexts->setObject(copyData); - - if (prelinked) { - result = true; - } else if (kernelLinkerPresent && add_from_mkext_function) { - result = (*add_from_mkext_function)(copyData); - } else { - IOLog("Can't add startup extensions from archive; " - "kernel linker is not present.\n"); - result = false; - } - - IOLockUnlock(kld_lock); - - copyData->release(); - } - - return result; -} - - +#if PRAGMA_MARK +#pragma mark Obsolete Kext Loading Stuff +#endif /********************************************************************* -* This function clears out all references to the in-kernel linker, -* frees the list of startup extensions in extensionDict, and -* deallocates the kernel's __KLD segment to reclaim that memory. -* -* The segments it operates on are strictly 32 bit segments. -*********************************************************************/ -kern_return_t IOCatalogue::removeKernelLinker(void) { - kern_return_t result = KERN_SUCCESS; - struct segment_command * segment; - char * dt_segment_name; - void * segment_paddress; - int segment_size; - - /* This must be the very first thing done by this function. - */ - IOLockLock(kld_lock); - - - /* If the kernel linker isn't here, that's automatically - * a success. - */ - if (!kernelLinkerPresent) { - result = KERN_SUCCESS; - goto finish; - } - - IOLog("Jettisoning kernel linker.\n"); - - kernelLinkerPresent = 0; - - /* Set the kmod_load_extension function as the means for loading - * a kernel extension. - */ - kmod_load_function = &kmod_load_extension; - - record_startup_extensions_function = 0; - add_from_mkext_function = 0; - remove_startup_extension_function = 0; - - - /* Invoke destructors for the __KLD and __LINKEDIT segments. - * Do this for all segments before actually freeing their - * memory so that any cross-dependencies (not that there - * should be any) are handled. - */ - segment = getsegbyname("__KLD"); - if (!segment) { - IOLog("error removing kernel linker: can't find %s segment\n", - "__KLD"); - result = KERN_FAILURE; - goto finish; - } - OSRuntimeUnloadCPPForSegment(segment); - - segment = getsegbyname("__LINKEDIT"); - if (!segment) { - IOLog("error removing kernel linker: can't find %s segment\n", - "__LINKEDIT"); - result = KERN_FAILURE; - goto finish; - } - OSRuntimeUnloadCPPForSegment(segment); - - - /* Free the memory that was set up by bootx. - */ - dt_segment_name = "Kernel-__KLD"; - if (0 == IODTGetLoaderInfo(dt_segment_name, &segment_paddress, &segment_size)) { - IODTFreeLoaderInfo(dt_segment_name, (void *)segment_paddress, - (int)segment_size); - } +********************************************************************** +*** BINARY COMPATIBILITY SECTION *** +********************************************************************** +********************************************************************** +* These functions are no longer used are necessary for C++ binary +* compatibility on ppc/i386. +**********************************************************************/ +#if __ppc__ || __i386__ + +bool IOCatalogue::recordStartupExtensions(void) +{ return false; } - dt_segment_name = "Kernel-__LINKEDIT"; - if (0 == IODTGetLoaderInfo(dt_segment_name, &segment_paddress, &segment_size)) { - IODTFreeLoaderInfo(dt_segment_name, (void *)segment_paddress, - (int)segment_size); - } - - struct section * sect; - sect = getsectbyname("__PRELINK", "__symtab"); - if (sect && sect->addr) - { - vm_offset_t - virt = ml_static_ptovirt(sect->addr); - if( virt) { - ml_static_mfree(virt, sect->size); - } - } - -finish: - - /* This must be the very last thing done before returning. - */ - IOLockUnlock(kld_lock); - - return result; -} - -/********************************************************************* -* This function stops the catalogue from making kextd requests during -* shutdown. -*********************************************************************/ -void IOCatalogue::disableExternalLinker(void) { - IOLockLock(gIOKLDLock); - /* If kmod_load_extension (the kextd requester function) is in use, - * disable new module requests. - */ - if (kmod_load_function == &kmod_load_extension) { - kmod_load_function = NULL; - } +bool IOCatalogue::addExtensionsFromArchive(OSData * mkext) +{ return KERN_NOT_SUPPORTED; } - IOLockUnlock(gIOKLDLock); -} +kern_return_t IOCatalogue::removeKernelLinker(void) +{ return KERN_NOT_SUPPORTED; } +#endif /* __ppc__ || __i386__ */