X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/4bd07ac2140668789aa3ee8ec4dde4a3e0a3bba5..cc8bc92ae4a8e9f1a1ab61bf83d34ad8150b3405:/iokit/Kernel/IOService.cpp diff --git a/iokit/Kernel/IOService.cpp b/iokit/Kernel/IOService.cpp index 6ff5f289d..40055c5c9 100644 --- a/iokit/Kernel/IOService.cpp +++ b/iokit/Kernel/IOService.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2014 Apple Inc. All rights reserved. + * Copyright (c) 1998-2016 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * @@ -51,6 +51,7 @@ #include #include #include +#include #include #include #include @@ -63,7 +64,10 @@ #define LOG kprintf //#define LOG IOLog #define MATCH_DEBUG 0 -#define OBFUSCATE(x) ((void *)(VM_KERNEL_ADDRPERM(x))) +#define IOSERVICE_OBFUSCATE(x) ((void *)(VM_KERNEL_ADDRPERM(x))) + +// disabled since lockForArbitration() can be held externally +#define DEBUG_NOTIFIER_LOCKED 0 #include "IOServicePrivate.h" #include "IOKitKernelInternal.h" @@ -77,6 +81,7 @@ OSDefineMetaClassAndStructors(IOService, IORegistryEntry) OSDefineMetaClassAndStructors(_IOServiceNotifier, IONotifier) +OSDefineMetaClassAndStructors(_IOServiceNullNotifier, IONotifier) OSDefineMetaClassAndStructors(_IOServiceInterestNotifier, IONotifier) @@ -102,16 +107,21 @@ const OSSymbol * gIOInterruptSpecifiersKey; const OSSymbol * gIOResourcesKey; const OSSymbol * gIOResourceMatchKey; +const OSSymbol * gIOResourceMatchedKey; const OSSymbol * gIOProviderClassKey; const OSSymbol * gIONameMatchKey; const OSSymbol * gIONameMatchedKey; const OSSymbol * gIOPropertyMatchKey; +const OSSymbol * gIOPropertyExistsMatchKey; const OSSymbol * gIOLocationMatchKey; const OSSymbol * gIOParentMatchKey; const OSSymbol * gIOPathMatchKey; const OSSymbol * gIOMatchCategoryKey; const OSSymbol * gIODefaultMatchCategoryKey; const OSSymbol * gIOMatchedServiceCountKey; +#if !CONFIG_EMBEDDED +const OSSymbol * gIOServiceLegacyMatchingRegistryIDKey; +#endif const OSSymbol * gIOMapperIDKey; const OSSymbol * gIOUserClientClassKey; @@ -128,10 +138,11 @@ const OSSymbol * gIOConsoleSessionOnConsoleKey; const OSSymbol * gIOConsoleSessionLoginDoneKey; const OSSymbol * gIOConsoleSessionSecureInputPIDKey; const OSSymbol * gIOConsoleSessionScreenLockedTimeKey; - +const OSSymbol * gIOConsoleSessionScreenIsLockedKey; clock_sec_t gIOConsoleLockTime; static bool gIOConsoleLoggedIn; #if HIBERNATION +static OSBoolean * gIOConsoleBooterLockState; static uint32_t gIOScreenLockState; #endif static IORegistryEntry * gIOChosenEntry; @@ -144,6 +155,7 @@ const OSSymbol * gIOFirstPublishNotification; const OSSymbol * gIOMatchedNotification; const OSSymbol * gIOFirstMatchNotification; const OSSymbol * gIOTerminatedNotification; +const OSSymbol * gIOWillTerminateNotification; const OSSymbol * gIOGeneralInterest; const OSSymbol * gIOBusyInterest; @@ -151,6 +163,12 @@ const OSSymbol * gIOAppPowerStateInterest; const OSSymbol * gIOPriorityPowerStateInterest; const OSSymbol * gIOConsoleSecurityInterest; +const OSSymbol * gIOBSDKey; +const OSSymbol * gIOBSDNameKey; +const OSSymbol * gIOBSDMajorKey; +const OSSymbol * gIOBSDMinorKey; +const OSSymbol * gIOBSDUnitKey; + const OSSymbol * gAKSGetKey; #if defined(__i386__) || defined(__x86_64__) const OSSymbol * gIOCreateEFIDevicePathSymbol; @@ -169,7 +187,7 @@ static int gOutstandingJobs; static int gNumConfigThreads; static int gNumWaitingThreads; static IOLock * gIOServiceBusyLock; -static bool gCPUsRunning; +bool gCPUsRunning; static thread_t gIOTerminateThread; static UInt32 gIOTerminateWork; @@ -187,6 +205,7 @@ const OSSymbol * gIOPlatformFunctionHandlerSet; static IOLock * gIOConsoleUsersLock; static thread_call_t gIOConsoleLockCallout; +static IONotifier * gIOServiceNullNotifier; /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ @@ -293,6 +312,7 @@ void IOService::initialize( void ) gIONameMatchKey = OSSymbol::withCStringNoCopy( kIONameMatchKey ); gIONameMatchedKey = OSSymbol::withCStringNoCopy( kIONameMatchedKey ); gIOPropertyMatchKey = OSSymbol::withCStringNoCopy( kIOPropertyMatchKey ); + gIOPropertyExistsMatchKey = OSSymbol::withCStringNoCopy( kIOPropertyExistsMatchKey ); gIOPathMatchKey = OSSymbol::withCStringNoCopy( kIOPathMatchKey ); gIOLocationMatchKey = OSSymbol::withCStringNoCopy( kIOLocationMatchKey ); gIOParentMatchKey = OSSymbol::withCStringNoCopy( kIOParentMatchKey ); @@ -302,11 +322,16 @@ void IOService::initialize( void ) kIODefaultMatchCategoryKey ); gIOMatchedServiceCountKey = OSSymbol::withCStringNoCopy( kIOMatchedServiceCountKey ); +#if !CONFIG_EMBEDDED + gIOServiceLegacyMatchingRegistryIDKey = OSSymbol::withCStringNoCopy( + kIOServiceLegacyMatchingRegistryIDKey ); +#endif gIOUserClientClassKey = OSSymbol::withCStringNoCopy( kIOUserClientClassKey ); - gIOResourcesKey = OSSymbol::withCStringNoCopy( kIOResourcesClass ); - gIOResourceMatchKey = OSSymbol::withCStringNoCopy( kIOResourceMatchKey ); + gIOResourcesKey = OSSymbol::withCStringNoCopy( kIOResourcesClass ); + gIOResourceMatchKey = OSSymbol::withCStringNoCopy( kIOResourceMatchKey ); + gIOResourceMatchedKey = OSSymbol::withCStringNoCopy( kIOResourceMatchedKey ); gIODeviceMemoryKey = OSSymbol::withCStringNoCopy( "IODeviceMemory" ); gIOInterruptControllersKey @@ -326,6 +351,12 @@ void IOService::initialize( void ) gIOPriorityPowerStateInterest = OSSymbol::withCStringNoCopy( kIOPriorityPowerStateInterest ); gIOConsoleSecurityInterest = OSSymbol::withCStringNoCopy( kIOConsoleSecurityInterest ); + gIOBSDKey = OSSymbol::withCStringNoCopy(kIOBSDKey); + gIOBSDNameKey = OSSymbol::withCStringNoCopy(kIOBSDNameKey); + gIOBSDMajorKey = OSSymbol::withCStringNoCopy(kIOBSDMajorKey); + gIOBSDMinorKey = OSSymbol::withCStringNoCopy(kIOBSDMinorKey); + gIOBSDUnitKey = OSSymbol::withCStringNoCopy(kIOBSDUnitKey); + gNotifications = OSDictionary::withCapacity( 1 ); gIOPublishNotification = OSSymbol::withCStringNoCopy( kIOPublishNotification ); @@ -337,6 +368,8 @@ void IOService::initialize( void ) kIOFirstMatchNotification ); gIOTerminatedNotification = OSSymbol::withCStringNoCopy( kIOTerminatedNotification ); + gIOWillTerminateNotification = OSSymbol::withCStringNoCopy( + kIOWillTerminateNotification ); gIOServiceKey = OSSymbol::withCStringNoCopy( kIOServiceClass); gIOConsoleLockedKey = OSSymbol::withCStringNoCopy( kIOConsoleLockedKey); @@ -349,6 +382,7 @@ void IOService::initialize( void ) gIOConsoleSessionLoginDoneKey = OSSymbol::withCStringNoCopy(kIOConsoleSessionLoginDoneKey); gIOConsoleSessionSecureInputPIDKey = OSSymbol::withCStringNoCopy(kIOConsoleSessionSecureInputPIDKey); gIOConsoleSessionScreenLockedTimeKey = OSSymbol::withCStringNoCopy(kIOConsoleSessionScreenLockedTimeKey); + gIOConsoleSessionScreenIsLockedKey = OSSymbol::withCStringNoCopy(kIOConsoleSessionScreenIsLockedKey); gIOConsoleUsersSeedValue = OSData::withBytesNoCopy(&gIOConsoleUsersSeed, sizeof(gIOConsoleUsersSeed)); @@ -399,6 +433,9 @@ void IOService::initialize( void ) gIOResources = IOResources::resources(); assert( gIOResources ); + gIOServiceNullNotifier = OSTypeAlloc(_IOServiceNullNotifier); + assert(gIOServiceNullNotifier); + gArbitrationLockQueueLock = IOLockAlloc(); queue_init(&gArbitrationLockQueueActive); queue_init(&gArbitrationLockQueueWaiting); @@ -411,7 +448,6 @@ void IOService::initialize( void ) gIOStopProviderList = OSArray::withCapacity( 16 ); gIOFinalizeList = OSArray::withCapacity( 16 ); assert( gIOTerminatePhase2List && gIOStopList && gIOStopProviderList && gIOFinalizeList ); - } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ @@ -419,6 +455,7 @@ void IOService::initialize( void ) #if defined(__i386__) || defined(__x86_64__) extern "C" { +const char *getCpuDelayBusStallHolderName(void); const char *getCpuDelayBusStallHolderName(void) { return sCPULatencyHolderName[kCpuDelayBusStall]; } @@ -441,6 +478,24 @@ static UInt64 getDebugFlags( OSDictionary * props ) return( debugFlags ); } + +static UInt64 getDebugFlags( IOService * inst ) +{ + OSObject * prop; + OSNumber * debugProp; + UInt64 debugFlags; + + prop = inst->copyProperty(gIOKitDebugKey); + debugProp = OSDynamicCast(OSNumber, prop); + if( debugProp) + debugFlags = debugProp->unsigned64BitValue(); + else + debugFlags = gIOKitDebug; + + OSSafeReleaseNULL(prop); + + return( debugFlags ); +} #endif /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ @@ -559,7 +614,11 @@ void IOService::free( void ) */ bool IOService::attach( IOService * provider ) { - bool ok; + bool ok; + uint32_t count; + AbsoluteTime deadline; + int waitResult = THREAD_AWAKENED; + bool wait, computeDeadline = true; if( provider) { @@ -567,12 +626,39 @@ bool IOService::attach( IOService * provider ) LOG( "%s::attach(%s)\n", getName(), provider->getName()); - provider->lockForArbitration(); - if( provider->__state[0] & kIOServiceInactiveState) - ok = false; - else - ok = attachToParent( provider, gIOServicePlane); - provider->unlockForArbitration(); + ok = false; + do + { + wait = false; + provider->lockForArbitration(); + if (provider->__state[0] & kIOServiceInactiveState) ok = false; + else + { + count = provider->getChildCount(gIOServicePlane); + wait = (count > (kIOServiceBusyMax - 4)); + if (!wait) ok = attachToParent(provider, gIOServicePlane); + else + { + IOLog("stalling for detach from %s\n", provider->getName()); + IOLockLock( gIOServiceBusyLock ); + provider->__state[1] |= kIOServiceWaitDetachState; + } + } + provider->unlockForArbitration(); + if (wait) + { + if (computeDeadline) + { + clock_interval_to_deadline(15, kSecondScale, &deadline); + computeDeadline = false; + } + assert_wait_deadline((event_t)&provider->__provider, THREAD_UNINT, deadline); + IOLockUnlock( gIOServiceBusyLock ); + waitResult = thread_block(THREAD_CONTINUE_NULL); + wait = (waitResult != THREAD_TIMED_OUT); + } + } + while (wait); } else { gIOServiceRoot = this; @@ -643,8 +729,17 @@ void IOService::detach( IOService * provider ) if( adjParent) provider->_adjustBusy( -1 ); if( (provider->__state[1] & kIOServiceTermPhase3State) && (0 == provider->getClient())) { - provider->scheduleFinalize(); + provider->scheduleFinalize(false); } + + IOLockLock( gIOServiceBusyLock ); + if (kIOServiceWaitDetachState & provider->__state[1]) + { + provider->__state[1] &= ~kIOServiceWaitDetachState; + thread_wakeup(&provider->__provider); + } + IOLockUnlock( gIOServiceBusyLock ); + provider->unlockForArbitration(); } } @@ -727,7 +822,7 @@ void IOService::startMatching( IOOptionBits options ) if ( options & kIOServiceAsynchronous ) sync = false; - needConfig = (0 == (__state[1] & (kIOServiceNeedConfigState | kIOServiceConfigState))) + needConfig = (0 == (__state[1] & (kIOServiceNeedConfigState | kIOServiceConfigRunning))) && (0 == (__state[0] & kIOServiceInactiveState)); __state[1] |= kIOServiceNeedConfigState; @@ -899,7 +994,7 @@ IOService * IOService::getProvider( void ) const IOService * parent; SInt32 generation; - generation = getGenerationCount(); + generation = getRegistryEntryGenerationCount(); if( __providerGeneration == generation) return( __provider ); @@ -1486,6 +1581,41 @@ void IOService::unlockForArbitration( void ) IOUnlock( gArbitrationLockQueueLock ); } +uint32_t IOService::isLockedForArbitration(IOService * service) +{ +#if DEBUG_NOTIFIER_LOCKED + uint32_t count; + ArbitrationLockQueueElement * active; + + // lock global access + IOLockLock(gArbitrationLockQueueLock); + + // determine whether this object is already locked (ie. on active queue) + count = 0; + queue_iterate(&gArbitrationLockQueueActive, + active, + ArbitrationLockQueueElement *, + link) + { + if ((active->thread == IOThreadSelf()) + && (!service || (active->service == service))) + { + count += 0x10000; + count += active->count; + } + } + + IOLockUnlock(gArbitrationLockQueueLock); + + return (count); + +#else /* DEBUG_NOTIFIER_LOCKED */ + + return (0); + +#endif /* DEBUG_NOTIFIER_LOCKED */ +} + void IOService::applyToProviders( IOServiceApplierFunction applier, void * context ) { @@ -1562,12 +1692,13 @@ applyToInterestNotifiers(const IORegistryEntry *target, OSObjectApplierFunction applier, void * context ) { - OSArray * copyArray = 0; + OSArray * copyArray = 0; + OSObject * prop; LOCKREADNOTIFY(); - IOCommand *notifyList = - OSDynamicCast( IOCommand, target->getProperty( typeOfInterest )); + prop = target->copyProperty(typeOfInterest); + IOCommand *notifyList = OSDynamicCast(IOCommand, prop); if( notifyList) { copyArray = OSArray::withCapacity(1); @@ -1590,6 +1721,8 @@ applyToInterestNotifiers(const IORegistryEntry *target, (*applier)(next, context); copyArray->release(); } + + OSSafeReleaseNULL(prop); } void IOService::applyToInterested( const OSSymbol * typeOfInterest, @@ -1654,7 +1787,7 @@ IONotifier * IOService::registerInterest( const OSSymbol * typeOfInterest, if (!notify) return NULL; if(notify->init()) { - rc = registerInterestForNotifer(notify, typeOfInterest, + rc = registerInterestForNotifier(notify, typeOfInterest, handler, target, ref); } @@ -1666,7 +1799,7 @@ IONotifier * IOService::registerInterest( const OSSymbol * typeOfInterest, return( notify ); } -IOReturn IOService::registerInterestForNotifer( IONotifier *svcNotify, const OSSymbol * typeOfInterest, +IOReturn IOService::registerInterestForNotifier( IONotifier *svcNotify, const OSSymbol * typeOfInterest, IOServiceInterestHandler handler, void * target, void * ref ) { IOReturn rc = kIOReturnSuccess; @@ -1743,11 +1876,27 @@ static void cleanInterestList( OSObject * head ) void IOService::unregisterAllInterest( void ) { - cleanInterestList( getProperty( gIOGeneralInterest )); - cleanInterestList( getProperty( gIOBusyInterest )); - cleanInterestList( getProperty( gIOAppPowerStateInterest )); - cleanInterestList( getProperty( gIOPriorityPowerStateInterest )); - cleanInterestList( getProperty( gIOConsoleSecurityInterest )); + OSObject * prop; + + prop = copyProperty(gIOGeneralInterest); + cleanInterestList(prop); + OSSafeReleaseNULL(prop); + + prop = copyProperty(gIOBusyInterest); + cleanInterestList(prop); + OSSafeReleaseNULL(prop); + + prop = copyProperty(gIOAppPowerStateInterest); + cleanInterestList(prop); + OSSafeReleaseNULL(prop); + + prop = copyProperty(gIOPriorityPowerStateInterest); + cleanInterestList(prop); + OSSafeReleaseNULL(prop); + + prop = copyProperty(gIOConsoleSecurityInterest); + cleanInterestList(prop); + OSSafeReleaseNULL(prop); } /* @@ -1983,7 +2132,10 @@ bool IOService::terminatePhase1( IOOptionBits options ) if( victim == this) startPhase2 = didInactive; if (didInactive) { - victim->deliverNotification( gIOTerminatedNotification, 0, 0xffffffff ); + OSArray * notifiers; + notifiers = victim->copyNotifiers(gIOTerminatedNotification, 0, 0xffffffff); + victim->invokeNotifiers(¬ifiers); + IOUserClient::destroyUserReferences( victim ); iter = victim->getClientIterator(); @@ -2188,7 +2340,7 @@ void IOService::scheduleStop( IOService * provider ) IOLockUnlock( gJobsLock ); } -void IOService::scheduleFinalize( void ) +void IOService::scheduleFinalize(bool now) { uint64_t regID1 = getRegistryEntryID(); @@ -2199,17 +2351,19 @@ void IOService::scheduleFinalize( void ) (uintptr_t) (regID1 >> 32), 0, 0); - IOLockLock( gJobsLock ); - gIOFinalizeList->tailQ( this ); - - if( 0 == gIOTerminateWork++) { - if( !gIOTerminateThread) - kernel_thread_start(&terminateThread, (void *) 0, &gIOTerminateThread); - else - IOLockWakeup(gJobsLock, (event_t) &gIOTerminateWork, /* one-thread */ false ); + if (now || IOUserClient::finalizeUserReferences(this)) + { + IOLockLock( gJobsLock ); + gIOFinalizeList->tailQ(this); + if( 0 == gIOTerminateWork++) + { + if( !gIOTerminateThread) + kernel_thread_start(&terminateThread, (void *) 0, &gIOTerminateThread); + else + IOLockWakeup(gJobsLock, (event_t) &gIOTerminateWork, /* one-thread */ false ); + } + IOLockUnlock( gJobsLock ); } - - IOLockUnlock( gJobsLock ); } bool IOService::willTerminate( IOService * provider, IOOptionBits options ) @@ -2468,8 +2622,10 @@ void IOService::terminateWorker( IOOptionBits options ) (uintptr_t) victim->__state[1], (uintptr_t) 0); - doPhase2 = (0 == (victim->__state[1] & kIOServiceTermPhase2State)) - && (0 == (victim->__state[1] & kIOServiceConfigState)); + doPhase2 = (0 == (victim->__state[1] & + (kIOServiceTermPhase1State + | kIOServiceTermPhase2State + | kIOServiceConfigState))); if (doPhase2 && (iter = victim->getClientIterator())) { while (doPhase2 && (client = (IOService *) iter->getNextObject())) { @@ -2502,11 +2658,15 @@ void IOService::terminateWorker( IOOptionBits options ) victim, (void *)(uintptr_t) options, NULL ); } + OSArray * notifiers; + notifiers = victim->copyNotifiers(gIOWillTerminateNotification, 0, 0xffffffff); + victim->invokeNotifiers(¬ifiers); + if( 0 == victim->getClient()) { + // no clients - will go to finalize - IOLockLock( gJobsLock ); - gIOFinalizeList->tailQ( victim ); - IOLockUnlock( gJobsLock ); + victim->scheduleFinalize(false); + } else { _workLoopAction( (IOWorkLoop::Action) &actionWillTerminate, victim, (void *)(uintptr_t) options, (void *)(uintptr_t) doPhase2List ); @@ -2867,23 +3027,30 @@ static SInt32 IOServiceObjectOrder( const OSObject * entry, void * ref) _IOServiceNotifier * notify; OSSymbol * key = (OSSymbol *) ref; OSNumber * offset; + OSObject * prop; + SInt32 result; + prop = 0; + result = kIODefaultProbeScore; if( (dict = OSDynamicCast( OSDictionary, entry))) offset = OSDynamicCast(OSNumber, dict->getObject( key )); else if( (notify = OSDynamicCast( _IOServiceNotifier, entry))) return( notify->priority ); - else if( (service = OSDynamicCast( IOService, entry))) - offset = OSDynamicCast(OSNumber, service->getProperty( key )); + { + prop = service->copyProperty(key); + offset = OSDynamicCast(OSNumber, prop); + } else { assert( false ); offset = 0; } - if( offset) - return( (SInt32) offset->unsigned32BitValue()); - else - return( kIODefaultProbeScore ); + if (offset) result = offset->unsigned32BitValue(); + + OSSafeReleaseNULL(prop); + + return (result); } SInt32 IOServiceOrdering( const OSMetaClassBase * inObj1, const OSMetaClassBase * inObj2, void * ref ) @@ -2938,14 +3105,22 @@ IOService * IOService::getClientWithCategory( const OSSymbol * category ) return (service); } -bool IOService::invokeNotifer( _IOServiceNotifier * notify ) +bool IOService::invokeNotifier( _IOServiceNotifier * notify ) { _IOServiceNotifierInvocation invocation; bool willNotify; bool ret = true; - invocation.thread = current_thread(); +#if DEBUG_NOTIFIER_LOCKED + uint32_t count; + if ((count = isLockedForArbitration(0))) + { + IOLog("[%s, 0x%x]\n", notify->type->getCStringNoCopy(), count); + panic("[%s, 0x%x]\n", notify->type->getCStringNoCopy(), count); + } +#endif /* DEBUG_NOTIFIER_LOCKED */ + LOCKWRITENOTIFY(); willNotify = (0 != (kIOServiceNotifyEnable & notify->state)); @@ -2972,6 +3147,27 @@ bool IOService::invokeNotifer( _IOServiceNotifier * notify ) return( ret ); } +bool IOService::invokeNotifiers(OSArray ** willSend) +{ + OSArray * array; + _IOServiceNotifier * notify; + bool ret = true; + + array = *willSend; + if (!array) return (true); + *willSend = 0; + + for( unsigned int idx = 0; + (notify = (_IOServiceNotifier *) array->getObject(idx)); + idx++) { + ret &= invokeNotifier(notify); + } + array->release(); + + return (ret); +} + + /* * Alloc and probe matching classes, * called on the provider instance @@ -3009,10 +3205,7 @@ void IOService::probeCandidates( OSOrderedSet * matches ) if( (notify = OSDynamicCast( _IOServiceNotifier, nextMatch ))) { - lockForArbitration(); - if( 0 == (__state[0] & kIOServiceInactiveState)) - invokeNotifer( notify ); - unlockForArbitration(); + if (0 == (__state[0] & kIOServiceInactiveState)) invokeNotifier( notify ); nextMatch->release(); nextMatch = 0; continue; @@ -3109,12 +3302,12 @@ void IOService::probeCandidates( OSOrderedSet * matches ) if( !symbol) continue; - //IOLog("%s alloc (symbol %p props %p)\n", symbol->getCStringNoCopy(), OBFUSCATE(symbol), OBFUSCATE(props)); + //IOLog("%s alloc (symbol %p props %p)\n", symbol->getCStringNoCopy(), IOSERVICE_OBFUSCATE(symbol), IOSERVICE_OBFUSCATE(props)); // alloc the driver instance inst = (IOService *) OSMetaClass::allocClassWithName( symbol); - if( !inst) { + if( !inst || !OSDynamicCast(IOService, inst)) { IOLog("Couldn't alloc class \"%s\"\n", symbol->getCStringNoCopy()); continue; @@ -3215,7 +3408,7 @@ void IOService::probeCandidates( OSOrderedSet * matches ) startList->removeObject(inst); #if IOMATCHDEBUG - debugFlags = getDebugFlags( inst->getPropertyTable() ); + debugFlags = getDebugFlags( inst ); if( debugFlags & kIOLogStart) { if( started) @@ -3357,11 +3550,15 @@ bool IOService::addNeededResource( const char * key ) OSString * newKey; bool ret; - resourcesProp = getProperty( gIOResourceMatchKey ); + resourcesProp = copyProperty( gIOResourceMatchKey ); + if (!resourcesProp) return(false); newKey = OSString::withCString( key ); - if( (0 == resourcesProp) || (0 == newKey)) + if (!newKey) + { + resourcesProp->release(); return( false); + } set = OSDynamicCast( OSSet, resourcesProp ); if( !set) { @@ -3376,6 +3573,7 @@ bool IOService::addNeededResource( const char * key ) newKey->release(); ret = setProperty( gIOResourceMatchKey, set ); set->release(); + resourcesProp->release(); return( ret ); } @@ -3402,12 +3600,12 @@ bool IOService::checkResource( OSObject * matching ) } if( gIOKitDebug & kIOLogConfig) - LOG("config(%p): stalling %s\n", OBFUSCATE(IOThreadSelf()), getName()); + LOG("config(%p): stalling %s\n", IOSERVICE_OBFUSCATE(IOThreadSelf()), getName()); waitForService( table ); if( gIOKitDebug & kIOLogConfig) - LOG("config(%p): waking\n", OBFUSCATE(IOThreadSelf()) ); + LOG("config(%p): waking\n", IOSERVICE_OBFUSCATE(IOThreadSelf()) ); return( true ); } @@ -3419,7 +3617,7 @@ bool IOService::checkResources( void ) OSIterator * iter; bool ok; - resourcesProp = getProperty( gIOResourceMatchKey ); + resourcesProp = copyProperty( gIOResourceMatchKey ); if( 0 == resourcesProp) return( true ); @@ -3435,6 +3633,8 @@ bool IOService::checkResources( void ) } else ok = checkResource( resourcesProp ); + OSSafeReleaseNULL(resourcesProp); + return( ok ); } @@ -3473,10 +3673,12 @@ void IOService::doServiceMatch( IOOptionBits options ) _IOServiceNotifier * notify; OSIterator * iter; OSOrderedSet * matches; + OSArray * resourceKeys = 0; SInt32 catalogGeneration; bool keepGuessing = true; bool reRegistered = true; bool didRegister; + OSArray * notifiers[2] = {0}; // job->nub->deliverNotification( gIOPublishNotification, // kIOServiceRegisteredState, 0xffffffff ); @@ -3490,12 +3692,12 @@ void IOService::doServiceMatch( IOOptionBits options ) lockForArbitration(); if( 0 == (__state[0] & kIOServiceFirstPublishState)) { getMetaClass()->addInstance(this); - deliverNotification( gIOFirstPublishNotification, + notifiers[0] = copyNotifiers(gIOFirstPublishNotification, kIOServiceFirstPublishState, 0xffffffff ); } LOCKREADNOTIFY(); __state[1] &= ~kIOServiceNeedConfigState; - __state[1] |= kIOServiceConfigState; + __state[1] |= kIOServiceConfigState | kIOServiceConfigRunning; didRegister = (0 == (kIOServiceRegisteredState & __state[0])); __state[0] |= kIOServiceRegisteredState; @@ -3517,9 +3719,17 @@ void IOService::doServiceMatch( IOOptionBits options ) UNLOCKNOTIFY(); unlockForArbitration(); + invokeNotifiers(¬ifiers[0]); if (keepGuessing && matches->getCount() && (kIOReturnSuccess == getResources())) + { + if (this == gIOResources) + { + if (resourceKeys) resourceKeys->release(); + resourceKeys = copyPropertyKeys(); + } probeCandidates( matches ); + } else matches->release(); } @@ -3537,13 +3747,25 @@ void IOService::doServiceMatch( IOOptionBits options ) if( (0 == (__state[0] & kIOServiceInactiveState)) && (0 == (__state[1] & kIOServiceModuleStallState)) ) { - deliverNotification( gIOMatchedNotification, - kIOServiceMatchedState, 0xffffffff ); + + if (resourceKeys) setProperty(gIOResourceMatchedKey, resourceKeys); + + notifiers[0] = copyNotifiers(gIOMatchedNotification, + kIOServiceMatchedState, 0xffffffff); if( 0 == (__state[0] & kIOServiceFirstMatchState)) - deliverNotification( gIOFirstMatchNotification, - kIOServiceFirstMatchState, 0xffffffff ); + notifiers[1] = copyNotifiers(gIOFirstMatchNotification, + kIOServiceFirstMatchState, 0xffffffff); } + __state[1] &= ~kIOServiceConfigRunning; + unlockForArbitration(); + + if (resourceKeys) resourceKeys->release(); + + invokeNotifiers(¬ifiers[0]); + invokeNotifiers(¬ifiers[1]); + + lockForArbitration(); __state[1] &= ~kIOServiceConfigState; scheduleTerminatePhase2(); @@ -3710,52 +3932,101 @@ IOReturn IOService::waitForState( UInt32 mask, UInt32 value, IOReturn IOService::waitQuiet( uint64_t timeout ) { IOReturn ret; - ret = waitForState( kIOServiceBusyStateMask, 0, timeout ); - if ((kIOReturnTimeout == ret) && (timeout >= 41000000000) && (kIOWaitQuietPanics & gIOKitDebug)) + uint32_t loops; + char * string = NULL; + char * panicString = NULL; + size_t len; + size_t panicStringLen; + uint64_t time; + uint64_t nano; + bool kextdWait; + bool dopanic; + + enum { kTimeoutExtensions = 4 }; + + time = mach_absolute_time(); + kextdWait = false; + for (loops = 0; loops < kTimeoutExtensions; loops++) { - IORegistryIterator * iter; - OSOrderedSet * set; - OSOrderedSet * leaves; - IOService * next; - IOService * nextParent; - char * string; - char * s; - size_t len, l; - - len = 256; - string = IONew(char, len); - set = NULL; - iter = IORegistryIterator::iterateOver(this, gIOServicePlane, kIORegistryIterateRecursively); - leaves = OSOrderedSet::withCapacity(4); - if (iter) set = iter->iterateAll(); - if (string && leaves && set) - { - while ((next = (IOService *) set->getLastObject())) - { - if (next->getBusyState()) - { - leaves->setObject(next); - nextParent = next; - while ((nextParent = nextParent->getProvider())) - { - set->removeObject(nextParent); - leaves->removeObject(nextParent); - } - } - set->removeObject(next); - } - s = string; - while ((next = (IOService *) leaves->getLastObject())) - { - l = snprintf(s, len, "%s'%s'", ((s == string) ? "" : ", "), next->getName()); - if (l >= len) break; - s += l; - len -= l; - leaves->removeObject(next); - } - } - panic("busy timeout(%llds): %s", timeout / 1000000000ULL, string ? string : ""); + ret = waitForState( kIOServiceBusyStateMask, 0, timeout ); + + if (loops && (kIOReturnSuccess == ret)) + { + time = mach_absolute_time() - time; + absolutetime_to_nanoseconds(*(AbsoluteTime *)&time, &nano); + IOLog("busy extended ok[%d], (%llds, %llds)\n", + loops, timeout / 1000000000ULL, nano / 1000000000ULL); + break; + } + else if (kIOReturnTimeout != ret) break; + else if (timeout < 41000000000) break; + + { + IORegistryIterator * iter; + OSOrderedSet * set; + OSOrderedSet * leaves; + IOService * next; + IOService * nextParent; + char * s; + size_t l; + + len = 256; + panicStringLen = 256; + if (!string) string = IONew(char, len); + if (!panicString) panicString = IONew(char, panicStringLen); + set = NULL; + kextdWait = OSKext::isWaitingKextd(); + iter = IORegistryIterator::iterateOver(this, gIOServicePlane, kIORegistryIterateRecursively); + leaves = OSOrderedSet::withCapacity(4); + if (iter) set = iter->iterateAll(); + if (string && panicString && leaves && set) + { + string[0] = panicString[0] = 0; + set->setObject(this); + while ((next = (IOService *) set->getLastObject())) + { + if (next->getBusyState()) + { + if (kIOServiceModuleStallState & next->__state[1]) kextdWait = true; + leaves->setObject(next); + nextParent = next; + while ((nextParent = nextParent->getProvider())) + { + set->removeObject(nextParent); + leaves->removeObject(nextParent); + } + } + set->removeObject(next); + } + s = string; + while ((next = (IOService *) leaves->getLastObject())) + { + l = snprintf(s, len, "%s'%s'", ((s == string) ? "" : ", "), next->getName()); + if (l >= len) break; + s += l; + len -= l; + leaves->removeObject(next); + } + } + OSSafeReleaseNULL(leaves); + OSSafeReleaseNULL(set); + OSSafeReleaseNULL(iter); + } + + dopanic = ((loops >= (kTimeoutExtensions - 1)) && (kIOWaitQuietPanics & gIOKitDebug)); + snprintf(panicString, panicStringLen, + "%s[%d], (%llds): %s", + kextdWait ? "kextd stall" : "busy timeout", + loops, timeout / 1000000000ULL, + string ? string : ""); + IOLog("%s\n", panicString); + if (dopanic) panic("%s", panicString); + else if (!loops) getPMRootDomain()->startSpinDump(1); } + + if (string) IODelete(string, char, 256); + if (panicString) IODelete(panicString, char, panicStringLen); + return (ret); } @@ -3824,7 +4095,7 @@ void _IOConfigThread::main(void * arg, wait_result_t result) if( gIOKitDebug & kIOLogConfig) LOG("config(%p): starting on %s, %d\n", - OBFUSCATE(IOThreadSelf()), job->nub->getName(), job->type); + IOSERVICE_OBFUSCATE(IOThreadSelf()), job->nub->getName(), job->type); switch( job->type) { @@ -3834,7 +4105,7 @@ void _IOConfigThread::main(void * arg, wait_result_t result) default: LOG("config(%p): strange type (%d)\n", - OBFUSCATE(IOThreadSelf()), job->type ); + IOSERVICE_OBFUSCATE(IOThreadSelf()), job->type ); break; } @@ -3858,7 +4129,7 @@ void _IOConfigThread::main(void * arg, wait_result_t result) } while( alive ); if( gIOKitDebug & kIOLogConfig) - LOG("config(%p): terminating\n", OBFUSCATE(IOThreadSelf()) ); + LOG("config(%p): terminating\n", IOSERVICE_OBFUSCATE(IOThreadSelf()) ); self->release(); } @@ -4040,7 +4311,6 @@ OSObject * IOService::copyExistingServices( OSDictionary * matching, const OSSymbol * sym = OSSymbol::withString(str); OSMetaClass::applyToInstancesOfClassName(sym, instanceMatch, &ctx); sym->release(); - } else { @@ -4120,8 +4390,8 @@ OSObject * IOService::copyExistingServices( OSDictionary * matching, OSSerialize * s2 = OSSerialize::withCapacity(128); current->serialize(s1); _current->serialize(s2); - kprintf("**mismatch** %p %p\n%s\n%s\n%s\n", OBFUSCATE(current), - OBFUSCATE(_current), s->text(), s1->text(), s2->text()); + kprintf("**mismatch** %p %p\n%s\n%s\n%s\n", IOSERVICE_OBFUSCATE(current), + IOSERVICE_OBFUSCATE(_current), s->text(), s1->text(), s2->text()); s1->release(); s2->release(); } @@ -4206,6 +4476,7 @@ IONotifier * IOService::setNotification( if( notify) { notify->handler = handler; notify->target = target; + notify->type = type; notify->matching = matching; matching->retain(); if (handler == &_IOServiceMatchingNotificationHandler) @@ -4257,10 +4528,13 @@ IONotifier * IOService::doInstallNotification( else if( type == gIOFirstPublishNotification) inState = kIOServiceFirstPublishState; - else if( (type == gIOMatchedNotification) - || (type == gIOFirstMatchNotification)) + else if (type == gIOMatchedNotification) inState = kIOServiceMatchedState; - else if( type == gIOTerminatedNotification) + + else if (type == gIOFirstMatchNotification) + inState = kIOServiceFirstMatchState; + + else if ((type == gIOTerminatedNotification) || (type == gIOWillTerminateNotification)) inState = 0; else return( 0 ); @@ -4313,6 +4587,9 @@ IONotifier * IOService::installNotification( notify = doInstallNotification( type, matching, handler, target, ref, priority, existing ); + // in case handler remove()s + if (notify) notify->retain(); + UNLOCKNOTIFY(); return( notify ); @@ -4346,28 +4623,34 @@ IONotifier * IOService::addMatchingNotification( SInt32 priority ) { OSIterator * existing = NULL; + IONotifier * ret; _IOServiceNotifier * notify; IOService * next; - notify = (_IOServiceNotifier *) installNotification( type, matching, + ret = notify = (_IOServiceNotifier *) installNotification( type, matching, handler, target, ref, priority, &existing ); + if (!ret) return (0); // send notifications for existing set - if( existing) { - - notify->retain(); // in case handler remove()s - while( (next = (IOService *) existing->getNextObject())) { - - next->lockForArbitration(); + if (existing) + { + while( (next = (IOService *) existing->getNextObject())) + { if( 0 == (next->__state[0] & kIOServiceInactiveState)) - next->invokeNotifer( notify ); - next->unlockForArbitration(); + { + next->invokeNotifier( notify ); + } } - notify->release(); existing->release(); } - return( notify ); + LOCKWRITENOTIFY(); + bool removed = (0 == notify->whence); + notify->release(); + if (removed) ret = gIOServiceNullNotifier; + UNLOCKNOTIFY(); + + return( ret ); } bool IOService::syncNotificationHandler( @@ -4461,6 +4744,12 @@ IOService * IOService::waitForService( OSDictionary * matching, void IOService::deliverNotification( const OSSymbol * type, IOOptionBits orNewState, IOOptionBits andNewState ) +{ + panic("deliverNotification"); +} + +OSArray * IOService::copyNotifiers(const OSSymbol * type, + IOOptionBits orNewState, IOOptionBits andNewState ) { _IOServiceNotifier * notify; OSIterator * iter; @@ -4469,7 +4758,8 @@ void IOService::deliverNotification( const OSSymbol * type, lockForArbitration(); if( (0 == (__state[0] & kIOServiceInactiveState)) - || (type == gIOTerminatedNotification)) { + || (type == gIOTerminatedNotification) + || (type == gIOWillTerminateNotification)) { LOCKREADNOTIFY(); @@ -4489,21 +4779,14 @@ void IOService::deliverNotification( const OSSymbol * type, } iter->release(); } - __state[0] = (__state[0] | orNewState) & andNewState; - UNLOCKNOTIFY(); } - if( willSend) { - for( unsigned int idx = 0; - (notify = (_IOServiceNotifier *) willSend->getObject(idx)); - idx++) { - invokeNotifer( notify ); - } - willSend->release(); - } unlockForArbitration(); + + return (willSend); + } IOOptionBits IOService::getState( void ) const @@ -4722,6 +5005,19 @@ void _IOServiceNotifier::enable( bool was ) UNLOCKNOTIFY(); } + +/* + * _IOServiceNullNotifier + */ + +void _IOServiceNullNotifier::taggedRetain(const void *tag) const {} +void _IOServiceNullNotifier::taggedRelease(const void *tag, const int when) const {} +void _IOServiceNullNotifier::free() {} +void _IOServiceNullNotifier::wait() {} +void _IOServiceNullNotifier::remove() {} +void _IOServiceNullNotifier::enable(bool was) {} +bool _IOServiceNullNotifier::disable() { return(false); } + /* * IOResources */ @@ -4742,7 +5038,7 @@ IOService * IOResources::resources( void ) bool IOResources::init( OSDictionary * dictionary ) { // Do super init first - if ( !super::init() ) + if ( !IOService::init() ) return false; // Allow PAL layer to publish a value @@ -4790,6 +5086,7 @@ bool IOResources::matchPropertyTable( OSDictionary * table ) OSString * str; OSSet * set; OSIterator * iter; + OSArray * keys; bool ok = true; prop = table->getObject( gIOResourceMatchKey ); @@ -4807,6 +5104,17 @@ bool IOResources::matchPropertyTable( OSDictionary * table ) if( iter) iter->release(); } + else if ((prop = table->getObject(gIOResourceMatchedKey))) + { + keys = (OSArray *) copyProperty(gIOResourceMatchedKey); + ok = false; + if (keys) + { + // assuming OSSymbol + ok = ((-1U) != keys->getNextIndexOfObject(prop, 0)); + keys->release(); + } + } return( ok ); } @@ -4824,6 +5132,8 @@ void IOService::updateConsoleUsers(OSArray * consoleUsers, IOMessage systemMessa bool publish; OSDictionary * user; static IOMessage sSystemPower; + clock_sec_t now = 0; + clock_usec_t microsecs; regEntry = IORegistryEntry::getRegistryRoot(); @@ -4836,9 +5146,25 @@ void IOService::updateConsoleUsers(OSArray * consoleUsers, IOMessage systemMessa { sSystemPower = systemMessage; #if HIBERNATION - if ((kIOMessageSystemHasPoweredOn == systemMessage) && IOHibernateWasScreenLocked()) + if (kIOMessageSystemHasPoweredOn == systemMessage) { - locked = kOSBooleanTrue; + uint32_t lockState = IOHibernateWasScreenLocked(); + switch (lockState) + { + case 0: + break; + case kIOScreenLockLocked: + case kIOScreenLockFileVaultDialog: + gIOConsoleBooterLockState = kOSBooleanTrue; + break; + case kIOScreenLockNoLock: + gIOConsoleBooterLockState = 0; + break; + case kIOScreenLockUnlocked: + default: + gIOConsoleBooterLockState = kOSBooleanFalse; + break; + } } #endif /* HIBERNATION */ } @@ -4846,6 +5172,8 @@ void IOService::updateConsoleUsers(OSArray * consoleUsers, IOMessage systemMessa if (consoleUsers) { OSNumber * num = 0; + bool loginLocked = true; + gIOConsoleLoggedIn = false; for (idx = 0; (user = OSDynamicCast(OSDictionary, consoleUsers->getObject(idx))); @@ -4853,11 +5181,19 @@ void IOService::updateConsoleUsers(OSArray * consoleUsers, IOMessage systemMessa { gIOConsoleLoggedIn |= ((kOSBooleanTrue == user->getObject(gIOConsoleSessionOnConsoleKey)) && (kOSBooleanTrue == user->getObject(gIOConsoleSessionLoginDoneKey))); + + loginLocked &= (kOSBooleanTrue == user->getObject(gIOConsoleSessionScreenIsLockedKey)); if (!num) { num = OSDynamicCast(OSNumber, user->getObject(gIOConsoleSessionScreenLockedTimeKey)); } } +#if HIBERNATION + if (!loginLocked) gIOConsoleBooterLockState = 0; + IOLog("IOConsoleUsers: time(%d) %ld->%d, lin %d, llk %d, \n", + (num != 0), gIOConsoleLockTime, (num ? num->unsigned32BitValue() : 0), + gIOConsoleLoggedIn, loginLocked); +#endif /* HIBERNATION */ gIOConsoleLockTime = num ? num->unsigned32BitValue() : 0; } @@ -4867,11 +5203,14 @@ void IOService::updateConsoleUsers(OSArray * consoleUsers, IOMessage systemMessa { locked = kOSBooleanTrue; } +#if HIBERNATION + else if (gIOConsoleBooterLockState) + { + locked = gIOConsoleBooterLockState; + } +#endif /* HIBERNATION */ else if (gIOConsoleLockTime) { - clock_sec_t now; - clock_usec_t microsecs; - clock_get_calendar_microtime(&now, µsecs); if (gIOConsoleLockTime > now) { @@ -4903,6 +5242,9 @@ void IOService::updateConsoleUsers(OSArray * consoleUsers, IOMessage systemMessa else if (gIOConsoleLockTime) gIOScreenLockState = kIOScreenLockUnlocked; else gIOScreenLockState = kIOScreenLockNoLock; gIOChosenEntry->setProperty(kIOScreenLockStateKey, &gIOScreenLockState, sizeof(gIOScreenLockState)); + + IOLog("IOConsoleUsers: gIOScreenLockState %d, hs %d, bs %d, now %ld, sm 0x%x\n", + gIOScreenLockState, gIOHibernateState, (gIOConsoleBooterLockState != 0), now, systemMessage); } #endif /* HIBERNATION */ @@ -4973,11 +5315,16 @@ bool IOService::compareProperty( OSDictionary * matching, const char * key ) { OSObject * value; + OSObject * prop; bool ok; value = matching->getObject( key ); if( value) - ok = value->isEqualTo( getProperty( key )); + { + prop = copyProperty(key); + ok = value->isEqualTo(prop); + if (prop) prop->release(); + } else ok = true; @@ -4989,11 +5336,16 @@ bool IOService::compareProperty( OSDictionary * matching, const OSString * key ) { OSObject * value; + OSObject * prop; bool ok; value = matching->getObject( key ); if( value) - ok = value->isEqualTo( getProperty( key )); + { + prop = copyProperty(key); + ok = value->isEqualTo(prop); + if (prop) prop->release(); + } else ok = true; @@ -5075,7 +5427,6 @@ bool IOService::matchInternal(OSDictionary * table, uint32_t options, uint32_t * done = 0; str = OSDynamicCast(OSString, table->getObject(gIOProviderClassKey)); - if (str) { done++; match = ((kIOServiceClassDone & options) || (0 != metaCast(str))); @@ -5145,6 +5496,38 @@ bool IOService::matchInternal(OSDictionary * table, uint32_t options, uint32_t * if ((!match) || (done == count)) break; } + obj = table->getObject( gIOPropertyExistsMatchKey ); + if( obj) + { + OSDictionary * dict; + OSString * nextKey; + OSIterator * iter; + done++; + match = false; + dict = dictionaryWithProperties(); + if( dict) { + nextKey = OSDynamicCast( OSString, obj); + if( nextKey) + iter = 0; + else + iter = OSCollectionIterator::withCollection( + OSDynamicCast(OSCollection, obj)); + + while( nextKey + || (iter && (0 != (nextKey = OSDynamicCast(OSString, + iter->getNextObject()))))) { + match = (0 != dict->getObject(nextKey)); + if( match) + break; + nextKey = 0; + } + dict->release(); + if( iter) + iter->release(); + } + if ((!match) || (done == count)) break; + } + str = OSDynamicCast( OSString, table->getObject( gIOPathMatchKey )); if( str) { done++; @@ -5196,10 +5579,10 @@ bool IOService::matchInternal(OSDictionary * table, uint32_t options, uint32_t * if (prop) prop->release(); \ if ((!match) || (done == count)) break; \ } - propMatch(kIOBSDNameKey) - propMatch(kIOBSDMajorKey) - propMatch(kIOBSDMinorKey) - propMatch(kIOBSDUnitKey) + propMatch(gIOBSDNameKey) + propMatch(gIOBSDMajorKey) + propMatch(gIOBSDMinorKey) + propMatch(gIOBSDUnitKey) #undef propMatch } while (false); @@ -5226,7 +5609,12 @@ bool IOService::matchPassive(OSDictionary * table, uint32_t options) assert( table ); -#if MATCH_DEBUG +#if !CONFIG_EMBEDDED + OSArray* aliasServiceRegIds = NULL; + IOService* foundAlternateService = NULL; +#endif + +#if MATCH_DEBUG OSDictionary * root = table; #endif @@ -5236,7 +5624,6 @@ bool IOService::matchPassive(OSDictionary * table, uint32_t options) do { count = table->getCount(); - if (!(kIOServiceInternalDone & options)) { match = where->matchInternal(table, options, &done); @@ -5249,7 +5636,7 @@ bool IOService::matchPassive(OSDictionary * table, uint32_t options) // do family specific matching match = where->matchPropertyTable( table, &score ); - + if( !match) { #if IOMATCHDEBUG if( kIOLogMatch & getDebugFlags( table )) @@ -5272,8 +5659,7 @@ bool IOService::matchPassive(OSDictionary * table, uint32_t options) nextTable = OSDynamicCast(OSDictionary, table->getObject( gIOParentMatchKey )); - if(nextTable) { - + if( nextTable) { // look for a matching entry anywhere up to root match = false; matchParent = true; @@ -5292,8 +5678,61 @@ bool IOService::matchPassive(OSDictionary * table, uint32_t options) break; } while (true); + + if(match == true) { + break; + } + + if(matchParent == true) { +#if !CONFIG_EMBEDDED + // check if service has an alias to search its other "parents" if a parent match isn't found + OSObject * prop = where->copyProperty(gIOServiceLegacyMatchingRegistryIDKey); + OSNumber * alternateRegistryID = OSDynamicCast(OSNumber, prop); + if(alternateRegistryID != NULL) { + if(aliasServiceRegIds == NULL) + { + aliasServiceRegIds = OSArray::withCapacity(sizeof(alternateRegistryID)); + } + aliasServiceRegIds->setObject(alternateRegistryID); + } + OSSafeReleaseNULL(prop); +#endif + } + else { + break; + } + + where = where->getProvider(); +#if !CONFIG_EMBEDDED + if(where == NULL) { + // there were no matching parent services, check to see if there are aliased services that have a matching parent + if(aliasServiceRegIds != NULL) { + unsigned int numAliasedServices = aliasServiceRegIds->getCount(); + if(numAliasedServices != 0) { + OSNumber* alternateRegistryID = OSDynamicCast(OSNumber, aliasServiceRegIds->getObject(numAliasedServices - 1)); + if(alternateRegistryID != NULL) { + OSDictionary* alternateMatchingDict = IOService::registryEntryIDMatching(alternateRegistryID->unsigned64BitValue()); + aliasServiceRegIds->removeObject(numAliasedServices - 1); + if(alternateMatchingDict != NULL) { + OSSafeReleaseNULL(foundAlternateService); + foundAlternateService = IOService::copyMatchingService(alternateMatchingDict); + alternateMatchingDict->release(); + if(foundAlternateService != NULL) { + where = foundAlternateService; + } + } + } + } + } + } +#endif } - while( matchParent && (!match) && (where = where->getProvider()) ); + while( where != NULL ); + +#if !CONFIG_EMBEDDED + OSSafeReleaseNULL(foundAlternateService); + OSSafeReleaseNULL(aliasServiceRegIds); +#endif #if MATCH_DEBUG if (where != this) @@ -5315,30 +5754,35 @@ IOReturn IOService::newUserClient( task_t owningTask, void * securityID, { const OSSymbol *userClientClass = 0; IOUserClient *client; + OSObject *prop; OSObject *temp; if (kIOReturnSuccess == newUserClient( owningTask, securityID, type, handler )) return kIOReturnSuccess; // First try my own properties for a user client class name - temp = getProperty(gIOUserClientClassKey); - if (temp) { - if (OSDynamicCast(OSSymbol, temp)) - userClientClass = (const OSSymbol *) temp; - else if (OSDynamicCast(OSString, temp)) { - userClientClass = OSSymbol::withString((OSString *) temp); + prop = copyProperty(gIOUserClientClassKey); + if (prop) { + if (OSDynamicCast(OSSymbol, prop)) + userClientClass = (const OSSymbol *) prop; + else if (OSDynamicCast(OSString, prop)) { + userClientClass = OSSymbol::withString((OSString *) prop); if (userClientClass) - setProperty(kIOUserClientClassKey, + setProperty(gIOUserClientClassKey, (OSObject *) userClientClass); } } // Didn't find one so lets just bomb out now without further ado. if (!userClientClass) + { + OSSafeReleaseNULL(prop); return kIOReturnUnsupported; + } // This reference is consumed by the IOServiceOpen call temp = OSMetaClass::allocClassWithName(userClientClass); + OSSafeReleaseNULL(prop); if (!temp) return kIOReturnNoMemory; @@ -6022,7 +6466,9 @@ IOReturn IOService::addInterruptStatistics(IOInterruptAccountingData * statistic /* * We now need to add the legend for this reporter to the registry. */ - legend = IOReportLegend::with(OSDynamicCast(OSArray, getProperty(kIOReportLegendKey))); + OSObject * prop = copyProperty(kIOReportLegendKey); + legend = IOReportLegend::with(OSDynamicCast(OSArray, prop)); + OSSafeReleaseNULL(prop); /* * Note that while we compose the subgroup name, we do not need to