X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/e5568f75972dfc723778653c11cb6b4dc825716a..8f6c56a50524aa785f7e596d52dddfb331e18961:/iokit/Kernel/IOService.cpp diff --git a/iokit/Kernel/IOService.cpp b/iokit/Kernel/IOService.cpp index 1ea83079b..7feca38f6 100644 --- a/iokit/Kernel/IOService.cpp +++ b/iokit/Kernel/IOService.cpp @@ -1,23 +1,29 @@ /* * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * @APPLE_OSREFERENCE_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 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. * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. + * 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_LICENSE_HEADER_END@ + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ #include @@ -26,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -98,6 +105,8 @@ const OSSymbol * gIOCommandPoolSizeKey; const OSSymbol * gIOConsoleUsersKey; const OSSymbol * gIOConsoleSessionUIDKey; const OSSymbol * gIOConsoleUsersSeedKey; +const OSSymbol * gIOConsoleSessionOnConsoleKey; +const OSSymbol * gIOConsoleSessionSecureInputPIDKey; static int gIOResourceGenerationCount; @@ -158,6 +167,19 @@ static OSData * gIOConsoleUsersSeedValue; /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +#define queue_element(entry, element, type, field) do { \ + vm_address_t __ele = (vm_address_t) (entry); \ + __ele -= -4 + ((size_t)(&((type) 4)->field)); \ + (element) = (type) __ele; \ + } while(0) + +#define iterqueue(que, elt) \ + for (queue_entry_t elt = queue_first(que); \ + !queue_end(que, elt); \ + elt = queue_next(elt)) + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + struct ArbitrationLockQueueElement { queue_chain_t link; IOThread thread; @@ -234,6 +256,8 @@ void IOService::initialize( void ) gIOConsoleUsersKey = OSSymbol::withCStringNoCopy( kIOConsoleUsersKey); gIOConsoleSessionUIDKey = OSSymbol::withCStringNoCopy( kIOConsoleSessionUIDKey); gIOConsoleUsersSeedKey = OSSymbol::withCStringNoCopy( kIOConsoleUsersSeedKey); + gIOConsoleSessionOnConsoleKey = OSSymbol::withCStringNoCopy( kIOConsoleSessionOnConsoleKey); + gIOConsoleSessionSecureInputPIDKey = OSSymbol::withCStringNoCopy( kIOConsoleSessionSecureInputPIDKey); gIOConsoleUsersSeedValue = OSData::withBytesNoCopy(&gIOConsoleUsersSeed, sizeof(gIOConsoleUsersSeed)); gNotificationLock = IORecursiveLockAlloc(); @@ -246,6 +270,7 @@ void IOService::initialize( void ) && gIOPublishNotification && gIOMatchedNotification && gIOTerminatedNotification && gIOServiceKey && gIOConsoleUsersKey && gIOConsoleSessionUIDKey + && gIOConsoleSessionOnConsoleKey && gIOConsoleSessionSecureInputPIDKey && gIOConsoleUsersSeedKey && gIOConsoleUsersSeedValue); gJobsLock = IOLockAlloc(); @@ -512,7 +537,7 @@ void IOService::startMatching( IOOptionBits options ) lockForArbitration(); IOLockLock( gIOServiceBusyLock ); - waitAgain = (prevBusy != (__state[1] & kIOServiceBusyStateMask)); + waitAgain = (prevBusy < (__state[1] & kIOServiceBusyStateMask)); if( waitAgain) __state[1] |= kIOServiceSyncPubState | kIOServiceBusyWaiterState; else @@ -534,7 +559,8 @@ void IOService::startMatching( IOOptionBits options ) IOReturn IOService::catalogNewDrivers( OSOrderedSet * newTables ) { OSDictionary * table; - OSIterator * iter; + OSSet * set; + OSSet * allSet = 0; IOService * service; #if IOMATCHDEBUG SInt32 count = 0; @@ -545,18 +571,23 @@ IOReturn IOService::catalogNewDrivers( OSOrderedSet * newTables ) while( (table = (OSDictionary *) newTables->getFirstObject())) { LOCKWRITENOTIFY(); - iter = (OSIterator *) getExistingServices( table, - kIOServiceRegisteredState ); + set = (OSSet *) getExistingServices( table, + kIOServiceRegisteredState, + kIOServiceExistingSet); UNLOCKNOTIFY(); - if( iter) { - while( (service = (IOService *) iter->getNextObject())) { - service->startMatching(kIOServiceAsynchronous); + if( set) { + #if IOMATCHDEBUG - count++; + count += set->getCount(); #endif + if (allSet) { + allSet->merge((const OSSet *) set); + set->release(); } - iter->release(); + else + allSet = set; } + #if IOMATCHDEBUG if( getDebugFlags( table ) & kIOLogMatch) LOG("Matching service count = %ld\n", count); @@ -564,6 +595,14 @@ IOReturn IOService::catalogNewDrivers( OSOrderedSet * newTables ) newTables->removeObject(table); } + if (allSet) { + while( (service = (IOService *) allSet->getAnyObject())) { + service->startMatching(kIOServiceAsynchronous); + allSet->removeObject(service); + } + allSet->release(); + } + newTables->release(); return( kIOReturnSuccess ); @@ -1250,32 +1289,48 @@ IOReturn IOService::messageClient( UInt32 type, OSObject * client, return( ret ); } +static void +applyToInterestNotifiers(const IORegistryEntry *target, + const OSSymbol * typeOfInterest, + OSObjectApplierFunction applier, + void * context ) +{ + OSArray * copyArray = 0; + + LOCKREADNOTIFY(); + + IOCommand *notifyList = + OSDynamicCast( IOCommand, target->getProperty( typeOfInterest )); + + if( notifyList) { + copyArray = OSArray::withCapacity(1); + + // iterate over queue, entry is set to each element in the list + iterqueue(¬ifyList->fCommandChain, entry) { + _IOServiceInterestNotifier * notify; + + queue_element(entry, notify, _IOServiceInterestNotifier *, chain); + copyArray->setObject(notify); + } + } + UNLOCKNOTIFY(); + + if( copyArray) { + unsigned int index; + OSObject * next; + + for( index = 0; (next = copyArray->getObject( index )); index++) + (*applier)(next, context); + copyArray->release(); + } +} + void IOService::applyToInterested( const OSSymbol * typeOfInterest, OSObjectApplierFunction applier, void * context ) { - OSArray * array; - unsigned int index; - OSObject * next; - OSArray * copyArray; - applyToClients( (IOServiceApplierFunction) applier, context ); - - LOCKREADNOTIFY(); - array = OSDynamicCast( OSArray, getProperty( typeOfInterest )); - if( array) { - copyArray = OSArray::withArray( array ); - UNLOCKNOTIFY(); - if( copyArray) { - for( index = 0; - (next = copyArray->getObject( index )); - index++) { - (*applier)(next, context); - } - copyArray->release(); - } - } else - UNLOCKNOTIFY(); + applyToInterestNotifiers(this, typeOfInterest, applier, context); } struct MessageClientsContext { @@ -1325,7 +1380,6 @@ IONotifier * IOService::registerInterest( const OSSymbol * typeOfInterest, IOServiceInterestHandler handler, void * target, void * ref ) { _IOServiceInterestNotifier * notify = 0; - OSArray * set; if( (typeOfInterest != gIOGeneralInterest) && (typeOfInterest != gIOBusyInterest) @@ -1352,16 +1406,23 @@ IONotifier * IOService::registerInterest( const OSSymbol * typeOfInterest, ////// queue LOCKWRITENOTIFY(); - if( 0 == (set = (OSArray *) getProperty( typeOfInterest ))) { - set = OSArray::withCapacity( 1 ); - if( set) { - setProperty( typeOfInterest, set ); - set->release(); - } - } - notify->whence = set; - if( set) - set->setObject( notify ); + + // Get the head of the notifier linked list + IOCommand *notifyList = (IOCommand *) getProperty( typeOfInterest ); + if (!notifyList || !OSDynamicCast(IOCommand, notifyList)) { + notifyList = OSTypeAlloc(IOCommand); + if (notifyList) { + notifyList->init(); + setProperty( typeOfInterest, notifyList); + notifyList->release(); + } + } + + if (notifyList) { + enqueue(¬ifyList->fCommandChain, ¬ify->chain); + notify->retain(); // ref'ed while in list + } + UNLOCKNOTIFY(); } } @@ -1370,30 +1431,30 @@ IONotifier * IOService::registerInterest( const OSSymbol * typeOfInterest, return( notify ); } -static void cleanInterestArray( OSObject * object ) +static void cleanInterestList( OSObject * head ) { - OSArray * array; - unsigned int index; - _IOServiceInterestNotifier * next; - - if( (array = OSDynamicCast( OSArray, object))) { - LOCKWRITENOTIFY(); - for( index = 0; - (next = (_IOServiceInterestNotifier *) - array->getObject( index )); - index++) { - next->whence = 0; - } - UNLOCKNOTIFY(); + IOCommand *notifyHead = OSDynamicCast(IOCommand, head); + if (!notifyHead) + return; + + LOCKWRITENOTIFY(); + while ( queue_entry_t entry = dequeue(¬ifyHead->fCommandChain) ) { + queue_next(entry) = queue_prev(entry) = 0; + + _IOServiceInterestNotifier * notify; + + queue_element(entry, notify, _IOServiceInterestNotifier *, chain); + notify->release(); } + UNLOCKNOTIFY(); } void IOService::unregisterAllInterest( void ) { - cleanInterestArray( getProperty( gIOGeneralInterest )); - cleanInterestArray( getProperty( gIOBusyInterest )); - cleanInterestArray( getProperty( gIOAppPowerStateInterest )); - cleanInterestArray( getProperty( gIOPriorityPowerStateInterest )); + cleanInterestList( getProperty( gIOGeneralInterest )); + cleanInterestList( getProperty( gIOBusyInterest )); + cleanInterestList( getProperty( gIOAppPowerStateInterest )); + cleanInterestList( getProperty( gIOPriorityPowerStateInterest )); } /* @@ -1435,10 +1496,10 @@ void _IOServiceInterestNotifier::remove() { LOCKWRITENOTIFY(); - if( whence) { - whence->removeObject(whence->getNextIndexOfObject( - (OSObject *) this, 0 )); - whence = 0; + if( queue_next( &chain )) { + remqueue( 0, &chain); + queue_next( &chain) = queue_prev( &chain) = 0; + release(); } state &= ~kIOServiceNotifyEnable; @@ -1563,7 +1624,6 @@ bool IOService::terminatePhase1( IOOptionBits options ) victim->deliverNotification( gIOTerminatedNotification, 0, 0xffffffff ); IOUserClient::destroyUserReferences( victim ); - victim->unregisterAllInterest(); iter = victim->getClientIterator(); if( iter) { @@ -1598,7 +1658,7 @@ bool IOService::terminatePhase1( IOOptionBits options ) void IOService::scheduleTerminatePhase2( IOOptionBits options ) { AbsoluteTime deadline; - int waitResult; + int waitResult = THREAD_AWAKENED; bool wait, haveDeadline = false; options |= kIOServiceRequired; @@ -1636,8 +1696,7 @@ void IOService::scheduleTerminatePhase2( IOOptionBits options ) deadline, THREAD_UNINT ); if( waitResult == THREAD_TIMED_OUT) { TLOG("%s::terminate(kIOServiceSynchronous) timeout", getName()); - } else - thread_cancel_timer(); + } } } while(gIOTerminateWork || (wait && (waitResult != THREAD_TIMED_OUT))); @@ -2548,11 +2607,15 @@ bool IOService::startCandidate( IOService * service ) ok = service->attach( this ); - if( ok) { - // stall for any nub resources - checkResources(); - // stall for any driver resources - service->checkResources(); + if( ok) + { + if (this != gIOResources) + { + // stall for any nub resources + checkResources(); + // stall for any driver resources + service->checkResources(); + } AbsoluteTime startTime; AbsoluteTime endTime; @@ -2612,22 +2675,22 @@ void IOService::publishResource( const OSSymbol * key, OSObject * value ) bool IOService::addNeededResource( const char * key ) { - OSObject * resources; + OSObject * resourcesProp; OSSet * set; OSString * newKey; bool ret; - resources = getProperty( gIOResourceMatchKey ); + resourcesProp = getProperty( gIOResourceMatchKey ); newKey = OSString::withCString( key ); - if( (0 == resources) || (0 == newKey)) + if( (0 == resourcesProp) || (0 == newKey)) return( false); - set = OSDynamicCast( OSSet, resources ); + set = OSDynamicCast( OSSet, resourcesProp ); if( !set) { set = OSSet::withCapacity( 1 ); if( set) - set->setObject( resources ); + set->setObject( resourcesProp ); } else set->retain(); @@ -2674,32 +2737,32 @@ bool IOService::checkResource( OSObject * matching ) bool IOService::checkResources( void ) { - OSObject * resources; + OSObject * resourcesProp; OSSet * set; OSIterator * iter; bool ok; - resources = getProperty( gIOResourceMatchKey ); - if( 0 == resources) + resourcesProp = getProperty( gIOResourceMatchKey ); + if( 0 == resourcesProp) return( true ); - if( (set = OSDynamicCast( OSSet, resources ))) { + if( (set = OSDynamicCast( OSSet, resourcesProp ))) { iter = OSCollectionIterator::withCollection( set ); ok = (0 != iter); - while( ok && (resources = iter->getNextObject()) ) - ok = checkResource( resources ); + while( ok && (resourcesProp = iter->getNextObject()) ) + ok = checkResource( resourcesProp ); if( iter) iter->release(); } else - ok = checkResource( resources ); + ok = checkResource( resourcesProp ); return( ok ); } -_IOConfigThread * _IOConfigThread::configThread( void ) +void _IOConfigThread::configThread( void ) { _IOConfigThread * inst; @@ -2708,18 +2771,17 @@ _IOConfigThread * _IOConfigThread::configThread( void ) continue; if( !inst->init()) continue; - if( !(inst->thread = IOCreateThread - ( (IOThreadFunc) &_IOConfigThread::main, inst ))) + if( !(IOCreateThread((IOThreadFunc) &_IOConfigThread::main, inst ))) continue; - return( inst ); + return; } while( false); if( inst) inst->release(); - return( 0 ); + return; } void _IOConfigThread::free( void ) @@ -2838,21 +2900,15 @@ UInt32 IOService::_adjustBusy( SInt32 delta ) next->unlockForArbitration(); if( (wasQuiet || nowQuiet) ) { - OSArray * array; - unsigned int index; - OSObject * interested; - - array = OSDynamicCast( OSArray, next->getProperty( gIOBusyInterest )); - if( array) { - LOCKREADNOTIFY(); - for( index = 0; - (interested = array->getObject( index )); - index++) { - next->messageClient(kIOMessageServiceBusyStateChange, - interested, (void *) wasQuiet /* busy now */); - } - UNLOCKNOTIFY(); - } + MessageClientsContext context; + + context.service = next; + context.type = kIOMessageServiceBusyStateChange; + context.argument = (void *) wasQuiet; // busy now + context.argSize = 0; + + applyToInterestNotifiers( next, gIOBusyInterest, + &messageClientsApplier, &context ); if( nowQuiet && (next == gIOServiceRoot)) OSMetaClass::considerUnloads(); @@ -2892,7 +2948,6 @@ IOReturn IOService::waitForState( UInt32 mask, UInt32 value, if( wait) { __state[1] |= kIOServiceBusyWaiterState; unlockForArbitration(); - assert_wait( (event_t) this, THREAD_UNINT ); if( timeout ) { if( computeDeadline ) { AbsoluteTime nsinterval; @@ -2905,16 +2960,16 @@ IOReturn IOService::waitForState( UInt32 mask, UInt32 value, abstime, &abstime ); computeDeadline = false; } - thread_set_timer_deadline( abstime ); + + assert_wait_deadline((event_t)this, THREAD_UNINT, __OSAbsoluteTime(abstime)); } + else + assert_wait((event_t)this, THREAD_UNINT ); } else unlockForArbitration(); IOLockUnlock( gIOServiceBusyLock ); - if( wait) { + if( wait) waitResult = thread_block(THREAD_CONTINUE_NULL); - if( timeout && (waitResult != THREAD_TIMED_OUT)) - thread_cancel_timer(); - } } while( wait && (waitResult != THREAD_TIMED_OUT)); @@ -3077,7 +3132,6 @@ void _IOServiceJob::pingConfig( _IOServiceJob * job ) semaphore_signal( gJobsSemaphore ); } - // internal - call with gNotificationLock OSObject * IOService::getExistingServices( OSDictionary * matching, IOOptionBits inState, IOOptionBits options ) @@ -3085,36 +3139,57 @@ OSObject * IOService::getExistingServices( OSDictionary * matching, OSObject * current = 0; OSIterator * iter; IOService * service; + OSObject * obj; if( !matching) return( 0 ); - iter = IORegistryIterator::iterateOver( gIOServicePlane, - kIORegistryIterateRecursively ); - if( iter) { - do { - iter->reset(); - while( (service = (IOService *) iter->getNextObject())) { - if( (inState == (service->__state[0] & inState)) - && (0 == (service->__state[0] & kIOServiceInactiveState)) - && service->passiveMatch( matching )) { - - if( options & kIONotifyOnce) { - current = service; - break; - } - if( current) - ((OSSet *)current)->setObject( service ); - else - current = OSSet::withObjects( - (const OSObject **) &service, 1, 1 ); - } - } - } while( !service && !iter->isValid()); - iter->release(); + if(true + && (obj = matching->getObject(gIOProviderClassKey)) + && gIOResourcesKey + && gIOResourcesKey->isEqualTo(obj) + && (service = gIOResources)) + { + if( (inState == (service->__state[0] & inState)) + && (0 == (service->__state[0] & kIOServiceInactiveState)) + && service->passiveMatch( matching )) + { + if( options & kIONotifyOnce) + current = service; + else + current = OSSet::withObjects( + (const OSObject **) &service, 1, 1 ); + } + } + else + { + iter = IORegistryIterator::iterateOver( gIOServicePlane, + kIORegistryIterateRecursively ); + if( iter) { + do { + iter->reset(); + while( (service = (IOService *) iter->getNextObject())) { + if( (inState == (service->__state[0] & inState)) + && (0 == (service->__state[0] & kIOServiceInactiveState)) + && service->passiveMatch( matching )) { + + if( options & kIONotifyOnce) { + current = service; + break; + } + if( current) + ((OSSet *)current)->setObject( service ); + else + current = OSSet::withObjects( + (const OSObject **) &service, 1, 1 ); + } + } + } while( !service && !iter->isValid()); + iter->release(); + } } - if( current && (0 == (options & kIONotifyOnce))) { + if( current && (0 == (options & (kIONotifyOnce | kIOServiceExistingSet)))) { iter = OSCollectionIterator::withCollection( (OSSet *)current ); current->release(); current = iter; @@ -4098,7 +4173,7 @@ int IOService::errnoFromReturn( IOReturn rtn ) case kIOReturnBadArgument: return(EINVAL); case kIOReturnUnsupported: - return(EOPNOTSUPP); + return(ENOTSUP); case kIOReturnBusy: return(EBUSY); case kIOReturnNoPower: @@ -4393,8 +4468,8 @@ IOReturn IOService::causeInterrupt(int source) OSMetaClassDefineReservedUsed(IOService, 0); OSMetaClassDefineReservedUsed(IOService, 1); OSMetaClassDefineReservedUsed(IOService, 2); +OSMetaClassDefineReservedUsed(IOService, 3); -OSMetaClassDefineReservedUnused(IOService, 3); OSMetaClassDefineReservedUnused(IOService, 4); OSMetaClassDefineReservedUnused(IOService, 5); OSMetaClassDefineReservedUnused(IOService, 6);