1/* 2 * Copyright (c) 1998-2014 Apple Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28 29#include <IOKit/system.h> 30 31#include <IOKit/IOService.h> 32#include <libkern/OSDebug.h> 33#include <libkern/c++/OSContainers.h> 34#include <libkern/c++/OSKext.h> 35#include <libkern/c++/OSUnserialize.h> 36#include <IOKit/IOCatalogue.h> 37#include <IOKit/IOCommand.h> 38#include <IOKit/IODeviceTreeSupport.h> 39#include <IOKit/IODeviceMemory.h> 40#include <IOKit/IOInterrupts.h> 41#include <IOKit/IOInterruptController.h> 42#include <IOKit/IOPlatformExpert.h> 43#include <IOKit/IOMessage.h> 44#include <IOKit/IOLib.h> 45#include <IOKit/IOKitKeysPrivate.h> 46#include <IOKit/IOBSD.h> 47#include <IOKit/IOUserClient.h> 48#include <IOKit/IOWorkLoop.h> 49#include <IOKit/IOTimeStamp.h> 50#include <IOKit/IOHibernatePrivate.h> 51#include <IOKit/IOInterruptAccountingPrivate.h> 52#include <IOKit/IOKernelReporters.h> 53#include <mach/sync_policy.h> 54#include <IOKit/assert.h> 55#include <sys/errno.h> 56 57#include <machine/pal_routines.h> 58 59#define LOG kprintf 60//#define LOG IOLog 61#define MATCH_DEBUG 0 62#define OBFUSCATE(x) ((void *)(VM_KERNEL_ADDRPERM(x))) 63 64#include "IOServicePrivate.h" 65#include "IOKitKernelInternal.h" 66 67// take lockForArbitration before LOCKNOTIFY 68 69/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 70 71#define super IORegistryEntry 72 73OSDefineMetaClassAndStructors(IOService, IORegistryEntry) 74 75OSDefineMetaClassAndStructors(_IOServiceNotifier, IONotifier) 76 77OSDefineMetaClassAndStructors(_IOServiceInterestNotifier, IONotifier) 78 79OSDefineMetaClassAndStructors(_IOConfigThread, OSObject) 80 81OSDefineMetaClassAndStructors(_IOServiceJob, OSObject) 82 83OSDefineMetaClassAndStructors(IOResources, IOService) 84 85OSDefineMetaClassAndStructors(_IOOpenServiceIterator, OSIterator) 86 87OSDefineMetaClassAndAbstractStructors(IONotifier, OSObject) 88 89/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 90 91static IOPlatformExpert * gIOPlatform; 92static class IOPMrootDomain * gIOPMRootDomain; 93const IORegistryPlane * gIOServicePlane; 94const IORegistryPlane * gIOPowerPlane; 95const OSSymbol * gIODeviceMemoryKey; 96const OSSymbol * gIOInterruptControllersKey; 97const OSSymbol * gIOInterruptSpecifiersKey; 98 99const OSSymbol * gIOResourcesKey; 100const OSSymbol * gIOResourceMatchKey; 101const OSSymbol * gIOProviderClassKey; 102const OSSymbol * gIONameMatchKey; 103const OSSymbol * gIONameMatchedKey; 104const OSSymbol * gIOPropertyMatchKey; 105const OSSymbol * gIOLocationMatchKey; 106const OSSymbol * gIOParentMatchKey; 107const OSSymbol * gIOPathMatchKey; 108const OSSymbol * gIOMatchCategoryKey; 109const OSSymbol * gIODefaultMatchCategoryKey; 110const OSSymbol * gIOMatchedServiceCountKey; 111 112const OSSymbol * gIOMapperIDKey; 113const OSSymbol * gIOUserClientClassKey; 114const OSSymbol * gIOKitDebugKey; 115 116const OSSymbol * gIOCommandPoolSizeKey; 117 118const OSSymbol * gIOConsoleLockedKey; 119const OSSymbol * gIOConsoleUsersKey; 120const OSSymbol * gIOConsoleSessionUIDKey; 121const OSSymbol * gIOConsoleSessionAuditIDKey; 122const OSSymbol * gIOConsoleUsersSeedKey; 123const OSSymbol * gIOConsoleSessionOnConsoleKey; 124const OSSymbol * gIOConsoleSessionLoginDoneKey; 125const OSSymbol * gIOConsoleSessionSecureInputPIDKey; 126const OSSymbol * gIOConsoleSessionScreenLockedTimeKey; 127 128clock_sec_t gIOConsoleLockTime; 129static bool gIOConsoleLoggedIn; 130#if HIBERNATION 131static uint32_t gIOScreenLockState; 132#endif 133static IORegistryEntry * gIOChosenEntry; 134 135static int gIOResourceGenerationCount; 136 137const OSSymbol * gIOServiceKey; 138const OSSymbol * gIOPublishNotification; 139const OSSymbol * gIOFirstPublishNotification; 140const OSSymbol * gIOMatchedNotification; 141const OSSymbol * gIOFirstMatchNotification; 142const OSSymbol * gIOTerminatedNotification; 143 144const OSSymbol * gIOGeneralInterest; 145const OSSymbol * gIOBusyInterest; 146const OSSymbol * gIOAppPowerStateInterest; 147const OSSymbol * gIOPriorityPowerStateInterest; 148const OSSymbol * gIOConsoleSecurityInterest; 149 150static OSDictionary * gNotifications; 151static IORecursiveLock * gNotificationLock; 152 153static IOService * gIOResources; 154static IOService * gIOServiceRoot; 155 156static OSOrderedSet * gJobs; 157static semaphore_port_t gJobsSemaphore; 158static IOLock * gJobsLock; 159static int gOutstandingJobs; 160static int gNumConfigThreads; 161static int gNumWaitingThreads; 162static IOLock * gIOServiceBusyLock; 163 164static thread_t gIOTerminateThread; 165static UInt32 gIOTerminateWork; 166static OSArray * gIOTerminatePhase2List; 167static OSArray * gIOStopList; 168static OSArray * gIOStopProviderList; 169static OSArray * gIOFinalizeList; 170 171static SInt32 gIOConsoleUsersSeed; 172static OSData * gIOConsoleUsersSeedValue; 173 174extern const OSSymbol * gIODTPHandleKey; 175 176const OSSymbol * gIOPlatformSleepActionKey; 177const OSSymbol * gIOPlatformWakeActionKey; 178const OSSymbol * gIOPlatformQuiesceActionKey; 179const OSSymbol * gIOPlatformActiveActionKey; 180const OSSymbol * gIOPlatformHaltRestartActionKey; 181 182const OSSymbol * gIOPlatformFunctionHandlerSet; 183 184static IOLock * gIOConsoleUsersLock; 185static thread_call_t gIOConsoleLockCallout; 186 187/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 188 189#define LOCKREADNOTIFY() \ 190 IORecursiveLockLock( gNotificationLock ) 191#define LOCKWRITENOTIFY() \ 192 IORecursiveLockLock( gNotificationLock ) 193#define LOCKWRITE2READNOTIFY() 194#define UNLOCKNOTIFY() \ 195 IORecursiveLockUnlock( gNotificationLock ) 196#define SLEEPNOTIFY(event) \ 197 IORecursiveLockSleep( gNotificationLock, (void *)(event), THREAD_UNINT ) 198#define SLEEPNOTIFYTO(event, deadline) \ 199 IORecursiveLockSleepDeadline( gNotificationLock, (void *)(event), deadline, THREAD_UNINT ) 200#define WAKEUPNOTIFY(event) \ 201 IORecursiveLockWakeup( gNotificationLock, (void *)(event), /* wake one */ false ) 202 203#define randomDelay() \ 204 int del = read_processor_clock(); \ 205 del = (((int)IOThreadSelf()) ^ del ^ (del >> 10)) & 0x3ff; \ 206 IOSleep( del ); 207 208/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 209 210#define queue_element(entry, element, type, field) do { \ 211 vm_address_t __ele = (vm_address_t) (entry); \ 212 __ele -= -4 + ((size_t)(&((type) 4)->field)); \ 213 (element) = (type) __ele; \ 214 } while(0) 215 216#define iterqueue(que, elt) \ 217 for (queue_entry_t elt = queue_first(que); \ 218 !queue_end(que, elt); \ 219 elt = queue_next(elt)) 220 221/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 222 223struct IOInterruptAccountingReporter { 224 IOSimpleReporter * reporter; /* Reporter responsible for communicating the statistics */ 225 IOInterruptAccountingData * statistics; /* The live statistics values, if any */ 226}; 227 228struct ArbitrationLockQueueElement { 229 queue_chain_t link; 230 IOThread thread; 231 IOService * service; 232 unsigned count; 233 bool required; 234 bool aborted; 235}; 236 237static queue_head_t gArbitrationLockQueueActive; 238static queue_head_t gArbitrationLockQueueWaiting; 239static queue_head_t gArbitrationLockQueueFree; 240static IOLock * gArbitrationLockQueueLock; 241 242bool IOService::isInactive( void ) const 243 { return( 0 != (kIOServiceInactiveState & getState())); } 244 245/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 246 247#if defined(__i386__) || defined(__x86_64__) 248 249// Only used by the intel implementation of 250// IOService::requireMaxBusStall(UInt32 ns) 251// IOService::requireMaxInterruptDelay(uint32_t ns) 252struct CpuDelayEntry 253{ 254 IOService * fService; 255 UInt32 fMaxDelay; 256 UInt32 fDelayType; 257}; 258 259enum { 260 kCpuDelayBusStall, kCpuDelayInterrupt, 261 kCpuNumDelayTypes 262}; 263 264static OSData *sCpuDelayData = OSData::withCapacity(8 * sizeof(CpuDelayEntry)); 265static IORecursiveLock *sCpuDelayLock = IORecursiveLockAlloc(); 266static OSArray *sCpuLatencyHandlers[kCpuNumDelayTypes]; 267const OSSymbol *sCPULatencyFunctionName[kCpuNumDelayTypes]; 268static OSNumber * sCPULatencyHolder[kCpuNumDelayTypes]; 269static OSNumber * sCPULatencySet[kCpuNumDelayTypes]; 270 271static void 272requireMaxCpuDelay(IOService * service, UInt32 ns, UInt32 delayType); 273static IOReturn 274setLatencyHandler(UInt32 delayType, IOService * target, bool enable); 275 276#endif /* defined(__i386__) || defined(__x86_64__) */ 277 278/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 279 280void IOService::initialize( void ) 281{ 282 kern_return_t err; 283 284 gIOServicePlane = IORegistryEntry::makePlane( kIOServicePlane ); 285 gIOPowerPlane = IORegistryEntry::makePlane( kIOPowerPlane ); 286 287 gIOProviderClassKey = OSSymbol::withCStringNoCopy( kIOProviderClassKey ); 288 gIONameMatchKey = OSSymbol::withCStringNoCopy( kIONameMatchKey ); 289 gIONameMatchedKey = OSSymbol::withCStringNoCopy( kIONameMatchedKey ); 290 gIOPropertyMatchKey = OSSymbol::withCStringNoCopy( kIOPropertyMatchKey ); 291 gIOPathMatchKey = OSSymbol::withCStringNoCopy( kIOPathMatchKey ); 292 gIOLocationMatchKey = OSSymbol::withCStringNoCopy( kIOLocationMatchKey ); 293 gIOParentMatchKey = OSSymbol::withCStringNoCopy( kIOParentMatchKey ); 294 295 gIOMatchCategoryKey = OSSymbol::withCStringNoCopy( kIOMatchCategoryKey ); 296 gIODefaultMatchCategoryKey = OSSymbol::withCStringNoCopy( 297 kIODefaultMatchCategoryKey ); 298 gIOMatchedServiceCountKey = OSSymbol::withCStringNoCopy( 299 kIOMatchedServiceCountKey ); 300 301 gIOUserClientClassKey = OSSymbol::withCStringNoCopy( kIOUserClientClassKey ); 302 303 gIOResourcesKey = OSSymbol::withCStringNoCopy( kIOResourcesClass ); 304 gIOResourceMatchKey = OSSymbol::withCStringNoCopy( kIOResourceMatchKey ); 305 306 gIODeviceMemoryKey = OSSymbol::withCStringNoCopy( "IODeviceMemory" ); 307 gIOInterruptControllersKey 308 = OSSymbol::withCStringNoCopy("IOInterruptControllers"); 309 gIOInterruptSpecifiersKey 310 = OSSymbol::withCStringNoCopy("IOInterruptSpecifiers"); 311 312 gIOMapperIDKey = OSSymbol::withCStringNoCopy(kIOMapperIDKey); 313 314 gIOKitDebugKey = OSSymbol::withCStringNoCopy( kIOKitDebugKey ); 315 316 gIOCommandPoolSizeKey = OSSymbol::withCStringNoCopy( kIOCommandPoolSizeKey ); 317 318 gIOGeneralInterest = OSSymbol::withCStringNoCopy( kIOGeneralInterest ); 319 gIOBusyInterest = OSSymbol::withCStringNoCopy( kIOBusyInterest ); 320 gIOAppPowerStateInterest = OSSymbol::withCStringNoCopy( kIOAppPowerStateInterest ); 321 gIOPriorityPowerStateInterest = OSSymbol::withCStringNoCopy( kIOPriorityPowerStateInterest ); 322 gIOConsoleSecurityInterest = OSSymbol::withCStringNoCopy( kIOConsoleSecurityInterest ); 323 324 gNotifications = OSDictionary::withCapacity( 1 ); 325 gIOPublishNotification = OSSymbol::withCStringNoCopy( 326 kIOPublishNotification ); 327 gIOFirstPublishNotification = OSSymbol::withCStringNoCopy( 328 kIOFirstPublishNotification ); 329 gIOMatchedNotification = OSSymbol::withCStringNoCopy( 330 kIOMatchedNotification ); 331 gIOFirstMatchNotification = OSSymbol::withCStringNoCopy( 332 kIOFirstMatchNotification ); 333 gIOTerminatedNotification = OSSymbol::withCStringNoCopy( 334 kIOTerminatedNotification ); 335 gIOServiceKey = OSSymbol::withCStringNoCopy( kIOServiceClass); 336 337 gIOConsoleLockedKey = OSSymbol::withCStringNoCopy( kIOConsoleLockedKey); 338 gIOConsoleUsersKey = OSSymbol::withCStringNoCopy( kIOConsoleUsersKey); 339 gIOConsoleSessionUIDKey = OSSymbol::withCStringNoCopy( kIOConsoleSessionUIDKey); 340 gIOConsoleSessionAuditIDKey = OSSymbol::withCStringNoCopy( kIOConsoleSessionAuditIDKey); 341 342 gIOConsoleUsersSeedKey = OSSymbol::withCStringNoCopy(kIOConsoleUsersSeedKey); 343 gIOConsoleSessionOnConsoleKey = OSSymbol::withCStringNoCopy(kIOConsoleSessionOnConsoleKey); 344 gIOConsoleSessionLoginDoneKey = OSSymbol::withCStringNoCopy(kIOConsoleSessionLoginDoneKey); 345 gIOConsoleSessionSecureInputPIDKey = OSSymbol::withCStringNoCopy(kIOConsoleSessionSecureInputPIDKey); 346 gIOConsoleSessionScreenLockedTimeKey = OSSymbol::withCStringNoCopy(kIOConsoleSessionScreenLockedTimeKey); 347 348 gIOConsoleUsersSeedValue = OSData::withBytesNoCopy(&gIOConsoleUsersSeed, sizeof(gIOConsoleUsersSeed)); 349 350 gIOPlatformSleepActionKey = OSSymbol::withCStringNoCopy(kIOPlatformSleepActionKey); 351 gIOPlatformWakeActionKey = OSSymbol::withCStringNoCopy(kIOPlatformWakeActionKey); 352 gIOPlatformQuiesceActionKey = OSSymbol::withCStringNoCopy(kIOPlatformQuiesceActionKey); 353 gIOPlatformActiveActionKey = OSSymbol::withCStringNoCopy(kIOPlatformActiveActionKey); 354 gIOPlatformHaltRestartActionKey = OSSymbol::withCStringNoCopy(kIOPlatformHaltRestartActionKey); 355 356 gIOPlatformFunctionHandlerSet = OSSymbol::withCStringNoCopy(kIOPlatformFunctionHandlerSet); 357#if defined(__i386__) || defined(__x86_64__) 358 sCPULatencyFunctionName[kCpuDelayBusStall] = OSSymbol::withCStringNoCopy(kIOPlatformFunctionHandlerMaxBusDelay); 359 sCPULatencyFunctionName[kCpuDelayInterrupt] = OSSymbol::withCStringNoCopy(kIOPlatformFunctionHandlerMaxInterruptDelay); 360 uint32_t idx; 361 for (idx = 0; idx < kCpuNumDelayTypes; idx++) 362 { 363 sCPULatencySet[idx] = OSNumber::withNumber(-1U, 32); 364 sCPULatencyHolder[idx] = OSNumber::withNumber(0ULL, 64); 365 assert(sCPULatencySet[idx] && sCPULatencyHolder[idx]); 366 } 367#endif 368 gNotificationLock = IORecursiveLockAlloc(); 369 370 assert( gIOServicePlane && gIODeviceMemoryKey 371 && gIOInterruptControllersKey && gIOInterruptSpecifiersKey 372 && gIOResourcesKey && gNotifications && gNotificationLock 373 && gIOProviderClassKey && gIONameMatchKey && gIONameMatchedKey 374 && gIOMatchCategoryKey && gIODefaultMatchCategoryKey 375 && gIOPublishNotification && gIOMatchedNotification 376 && gIOTerminatedNotification && gIOServiceKey 377 && gIOConsoleUsersKey && gIOConsoleSessionUIDKey 378 && gIOConsoleSessionOnConsoleKey && gIOConsoleSessionSecureInputPIDKey 379 && gIOConsoleUsersSeedKey && gIOConsoleUsersSeedValue); 380 381 gJobsLock = IOLockAlloc(); 382 gJobs = OSOrderedSet::withCapacity( 10 ); 383 384 gIOServiceBusyLock = IOLockAlloc(); 385 386 gIOConsoleUsersLock = IOLockAlloc(); 387 388 err = semaphore_create(kernel_task, &gJobsSemaphore, SYNC_POLICY_FIFO, 0); 389 390 gIOConsoleLockCallout = thread_call_allocate(&IOService::consoleLockTimer, NULL); 391 392 IORegistryEntry::getRegistryRoot()->setProperty(gIOConsoleLockedKey, kOSBooleanTrue); 393 394 assert( gIOServiceBusyLock && gJobs && gJobsLock && gIOConsoleUsersLock 395 && gIOConsoleLockCallout && (err == KERN_SUCCESS) ); 396 397 gIOResources = IOResources::resources(); 398 assert( gIOResources ); 399 400 gArbitrationLockQueueLock = IOLockAlloc(); 401 queue_init(&gArbitrationLockQueueActive); 402 queue_init(&gArbitrationLockQueueWaiting); 403 queue_init(&gArbitrationLockQueueFree); 404 405 assert( gArbitrationLockQueueLock ); 406 407 gIOTerminatePhase2List = OSArray::withCapacity( 2 ); 408 gIOStopList = OSArray::withCapacity( 16 ); 409 gIOStopProviderList = OSArray::withCapacity( 16 ); 410 gIOFinalizeList = OSArray::withCapacity( 16 ); 411 assert( gIOTerminatePhase2List && gIOStopList && gIOStopProviderList && gIOFinalizeList ); 412} 413 414/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 415 416#if IOMATCHDEBUG 417static UInt64 getDebugFlags( OSDictionary * props ) 418{ 419 OSNumber * debugProp; 420 UInt64 debugFlags; 421 422 debugProp = OSDynamicCast( OSNumber, 423 props->getObject( gIOKitDebugKey )); 424 if( debugProp) 425 debugFlags = debugProp->unsigned64BitValue(); 426 else 427 debugFlags = gIOKitDebug; 428 429 return( debugFlags ); 430} 431#endif 432 433/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 434 435// Probe a matched service and return an instance to be started. 436// The default score is from the property table, & may be altered 437// during probe to change the start order. 438 439IOService * IOService::probe( IOService * provider, 440 SInt32 * score ) 441{ 442 return( this ); 443} 444 445bool IOService::start( IOService * provider ) 446{ 447 return( true ); 448} 449 450void IOService::stop( IOService * provider ) 451{ 452} 453 454bool IOService::init( OSDictionary * dictionary ) 455{ 456 bool ret = false; 457 458 ret = super::init(dictionary); 459 460 if (!ret) 461 goto done; 462 463 reserved = IONew(ExpansionData, 1); 464 465 if (!reserved) { 466 ret = false; 467 goto done; 468 } 469 470 bzero(reserved, sizeof(*reserved)); 471 472 /* 473 * TODO: Improve on this. Previous efforts to more lazily allocate this 474 * lock based on the presence of specifiers ran into issues as some 475 * platforms set up the specifiers after IOService initialization. 476 * 477 * We may be able to get away with a global lock, as this should only be 478 * contended by IOReporting clients and driver start/stop (unless a 479 * driver wants to remove/add handlers in the course of normal operation, 480 * which should be unlikely). 481 */ 482 reserved->interruptStatisticsLock = IOLockAlloc(); 483 484 if (!reserved->interruptStatisticsLock) { 485 ret = false; 486 goto done; 487 } 488 489done: 490 return ret; 491} 492 493bool IOService::init( IORegistryEntry * from, 494 const IORegistryPlane * inPlane ) 495{ 496 bool ret = false; 497 498 ret = super::init(from, inPlane); 499 500 if (!ret) 501 goto done; 502 503 reserved = IONew(ExpansionData, 1); 504 505 if (!reserved) { 506 ret = false; 507 goto done; 508 } 509 510 bzero(reserved, sizeof(*reserved)); 511 512 /* 513 * TODO: Improve on this. Previous efforts to more lazily allocate this 514 * lock based on the presence of specifiers ran into issues as some 515 * platforms set up the specifiers after IOService initialization. 516 * 517 * We may be able to get away with a global lock, as this should only be 518 * contended by IOReporting clients and driver start/stop (unless a 519 * driver wants to remove/add handlers in the course of normal operation, 520 * which should be unlikely). 521 */ 522 reserved->interruptStatisticsLock = IOLockAlloc(); 523 524 if (!reserved->interruptStatisticsLock) { 525 ret = false; 526 goto done; 527 } 528 529done: 530 return ret; 531} 532 533void IOService::free( void ) 534{ 535 int i = 0; 536 requireMaxBusStall(0); 537 requireMaxInterruptDelay(0); 538 if( getPropertyTable()) 539 unregisterAllInterest(); 540 PMfree(); 541 542 if (reserved) { 543 if (reserved->interruptStatisticsArray) { 544 for (i = 0; i < reserved->interruptStatisticsArrayCount; i++) { 545 if (reserved->interruptStatisticsArray[i].reporter) 546 reserved->interruptStatisticsArray[i].reporter->release(); 547 } 548 549 IODelete(reserved->interruptStatisticsArray, IOInterruptAccountingReporter, reserved->interruptStatisticsArrayCount); 550 } 551 552 if (reserved->interruptStatisticsLock) 553 IOLockFree(reserved->interruptStatisticsLock); 554 IODelete(reserved, ExpansionData, 1); 555 } 556 557 super::free(); 558} 559 560/* 561 * Attach in service plane 562 */ 563bool IOService::attach( IOService * provider ) 564{ 565 bool ok; 566 567 if( provider) { 568 569 if( gIOKitDebug & kIOLogAttach) 570 LOG( "%s::attach(%s)\n", getName(), 571 provider->getName()); 572 573 provider->lockForArbitration(); 574 if( provider->__state[0] & kIOServiceInactiveState) 575 ok = false; 576 else 577 ok = attachToParent( provider, gIOServicePlane); 578 provider->unlockForArbitration(); 579 580 } else { 581 gIOServiceRoot = this; 582 ok = attachToParent( getRegistryRoot(), gIOServicePlane); 583 } 584 585 if (ok && !__provider) (void) getProvider(); 586 587 return( ok ); 588} 589 590IOService * IOService::getServiceRoot( void ) 591{ 592 return( gIOServiceRoot ); 593} 594 595void IOService::detach( IOService * provider ) 596{ 597 IOService * newProvider = 0; 598 SInt32 busy; 599 bool adjParent; 600 601 if( gIOKitDebug & kIOLogAttach) 602 LOG("%s::detach(%s)\n", getName(), provider->getName()); 603 604 lockForArbitration(); 605 606 adjParent = ((busy = (__state[1] & kIOServiceBusyStateMask)) 607 && (provider == getProvider())); 608 609 detachFromParent( provider, gIOServicePlane ); 610 611 if( busy) { 612 newProvider = getProvider(); 613 if( busy && (__state[1] & kIOServiceTermPhase3State) && (0 == newProvider)) 614 _adjustBusy( -busy ); 615 } 616 617 if (kIOServiceInactiveState & __state[0]) { 618 getMetaClass()->removeInstance(this); 619 } 620 621 unlockForArbitration(); 622 623 if( newProvider) { 624 newProvider->lockForArbitration(); 625 newProvider->_adjustBusy(1); 626 newProvider->unlockForArbitration(); 627 } 628 629 // check for last client detach from a terminated service 630 if( provider->lockForArbitration( true )) 631 { 632 if (kIOServiceStartState & __state[1]) 633 { 634 provider->scheduleTerminatePhase2(); 635 } 636 if( adjParent) provider->_adjustBusy( -1 ); 637 if( (provider->__state[1] & kIOServiceTermPhase3State) 638 && (0 == provider->getClient())) { 639 provider->scheduleFinalize(); 640 } 641 provider->unlockForArbitration(); 642 } 643} 644 645/* 646 * Register instance - publish it for matching 647 */ 648 649void IOService::registerService( IOOptionBits options ) 650{ 651 char * pathBuf; 652 const char * path; 653 char * skip; 654 int len; 655 enum { kMaxPathLen = 256 }; 656 enum { kMaxChars = 63 }; 657 658 IORegistryEntry * parent = this; 659 IORegistryEntry * root = getRegistryRoot(); 660 while( parent && (parent != root)) 661 parent = parent->getParentEntry( gIOServicePlane); 662 663 if( parent != root) { 664 IOLog("%s: not registry member at registerService()\n", getName()); 665 return; 666 } 667 668 // Allow the Platform Expert to adjust this node. 669 if( gIOPlatform && (!gIOPlatform->platformAdjustService(this))) 670 return; 671 672 if( (this != gIOResources) 673 && (kIOLogRegister & gIOKitDebug)) { 674 675 pathBuf = (char *) IOMalloc( kMaxPathLen ); 676 677 IOLog( "Registering: " ); 678 679 len = kMaxPathLen; 680 if( pathBuf && getPath( pathBuf, &len, gIOServicePlane)) { 681 682 path = pathBuf; 683 if( len > kMaxChars) { 684 IOLog(".."); 685 len -= kMaxChars; 686 path += len; 687 if( (skip = strchr( path, '/'))) 688 path = skip; 689 } 690 } else 691 path = getName(); 692 693 IOLog( "%s\n", path ); 694 695 if( pathBuf) 696 IOFree( pathBuf, kMaxPathLen ); 697 } 698 699 startMatching( options ); 700} 701 702void IOService::startMatching( IOOptionBits options ) 703{ 704 IOService * provider; 705 UInt32 prevBusy = 0; 706 bool needConfig; 707 bool needWake = false; 708 bool ok; 709 bool sync; 710 bool waitAgain; 711 712 lockForArbitration(); 713 714 sync = (options & kIOServiceSynchronous) 715 || ((provider = getProvider()) 716 && (provider->__state[1] & kIOServiceSynchronousState)); 717 718 if ( options & kIOServiceAsynchronous ) 719 sync = false; 720 721 needConfig = (0 == (__state[1] & (kIOServiceNeedConfigState | kIOServiceConfigState))) 722 && (0 == (__state[0] & kIOServiceInactiveState)); 723 724 __state[1] |= kIOServiceNeedConfigState; 725 726// __state[0] &= ~kIOServiceInactiveState; 727 728// if( sync) LOG("OSKernelStackRemaining = %08x @ %s\n", 729// OSKernelStackRemaining(), getName()); 730 731 if( needConfig) { 732 needWake = (0 != (kIOServiceSyncPubState & __state[1])); 733 } 734 735 if( sync) 736 __state[1] |= kIOServiceSynchronousState; 737 else 738 __state[1] &= ~kIOServiceSynchronousState; 739 740 if( needConfig) prevBusy = _adjustBusy( 1 ); 741 742 unlockForArbitration(); 743 744 if( needConfig) { 745 746 if( needWake) { 747 IOLockLock( gIOServiceBusyLock ); 748 thread_wakeup( (event_t) this/*&__state[1]*/ ); 749 IOLockUnlock( gIOServiceBusyLock ); 750 751 } else if( !sync || (kIOServiceAsynchronous & options)) { 752 753 ok = (0 != _IOServiceJob::startJob( this, kMatchNubJob, options )); 754 755 } else do { 756 757 if( (__state[1] & kIOServiceNeedConfigState)) 758 doServiceMatch( options ); 759 760 lockForArbitration(); 761 IOLockLock( gIOServiceBusyLock ); 762 763 waitAgain = ((prevBusy < (__state[1] & kIOServiceBusyStateMask)) 764 && (0 == (__state[0] & kIOServiceInactiveState))); 765 766 if( waitAgain) 767 __state[1] |= kIOServiceSyncPubState | kIOServiceBusyWaiterState; 768 else 769 __state[1] &= ~kIOServiceSyncPubState; 770 771 unlockForArbitration(); 772 773 if( waitAgain) 774 assert_wait( (event_t) this/*&__state[1]*/, THREAD_UNINT); 775 776 IOLockUnlock( gIOServiceBusyLock ); 777 if( waitAgain) 778 thread_block(THREAD_CONTINUE_NULL); 779 780 } while( waitAgain ); 781 } 782} 783 784IOReturn IOService::catalogNewDrivers( OSOrderedSet * newTables ) 785{ 786 OSDictionary * table; 787 OSSet * set; 788 OSSet * allSet = 0; 789 IOService * service; 790#if IOMATCHDEBUG 791 SInt32 count = 0; 792#endif 793 794 newTables->retain(); 795 796 while( (table = (OSDictionary *) newTables->getFirstObject())) { 797 798 LOCKWRITENOTIFY(); 799 set = (OSSet *) copyExistingServices( table, 800 kIOServiceRegisteredState, 801 kIOServiceExistingSet); 802 UNLOCKNOTIFY(); 803 if( set) { 804 805#if IOMATCHDEBUG 806 count += set->getCount(); 807#endif 808 if (allSet) { 809 allSet->merge((const OSSet *) set); 810 set->release(); 811 } 812 else 813 allSet = set; 814 } 815 816#if IOMATCHDEBUG 817 if( getDebugFlags( table ) & kIOLogMatch) 818 LOG("Matching service count = %ld\n", (long)count); 819#endif 820 newTables->removeObject(table); 821 } 822 823 if (allSet) { 824 while( (service = (IOService *) allSet->getAnyObject())) { 825 service->startMatching(kIOServiceAsynchronous); 826 allSet->removeObject(service); 827 } 828 allSet->release(); 829 } 830 831 newTables->release(); 832 833 return( kIOReturnSuccess ); 834} 835 836 _IOServiceJob * _IOServiceJob::startJob( IOService * nub, int type, 837 IOOptionBits options ) 838{ 839 _IOServiceJob * job; 840 841 job = new _IOServiceJob; 842 if( job && !job->init()) { 843 job->release(); 844 job = 0; 845 } 846 847 if( job) { 848 job->type = type; 849 job->nub = nub; 850 job->options = options; 851 nub->retain(); // thread will release() 852 pingConfig( job ); 853 } 854 855 return( job ); 856} 857 858/* 859 * Called on a registered service to see if it matches 860 * a property table. 861 */ 862 863bool IOService::matchPropertyTable( OSDictionary * table, SInt32 * score ) 864{ 865 return( matchPropertyTable(table) ); 866} 867 868bool IOService::matchPropertyTable( OSDictionary * table ) 869{ 870 return( true ); 871} 872 873/* 874 * Called on a matched service to allocate resources 875 * before first driver is attached. 876 */ 877 878IOReturn IOService::getResources( void ) 879{ 880 return( kIOReturnSuccess); 881} 882 883/* 884 * Client/provider accessors 885 */ 886 887IOService * IOService::getProvider( void ) const 888{ 889 IOService * self = (IOService *) this; 890 IOService * parent; 891 SInt32 generation; 892 893 generation = getGenerationCount(); 894 if( __providerGeneration == generation) 895 return( __provider ); 896 897 parent = (IOService *) getParentEntry( gIOServicePlane); 898 if( parent == IORegistryEntry::getRegistryRoot()) 899 /* root is not an IOService */ 900 parent = 0; 901 902 self->__provider = parent; 903 OSMemoryBarrier(); 904 // save the count from before call to getParentEntry() 905 self->__providerGeneration = generation; 906 907 return( parent ); 908} 909 910IOWorkLoop * IOService::getWorkLoop() const 911{ 912 IOService *provider = getProvider(); 913 914 if (provider) 915 return provider->getWorkLoop(); 916 else 917 return 0; 918} 919 920OSIterator * IOService::getProviderIterator( void ) const 921{ 922 return( getParentIterator( gIOServicePlane)); 923} 924 925IOService * IOService::getClient( void ) const 926{ 927 return( (IOService *) getChildEntry( gIOServicePlane)); 928} 929 930OSIterator * IOService::getClientIterator( void ) const 931{ 932 return( getChildIterator( gIOServicePlane)); 933} 934 935OSIterator * _IOOpenServiceIterator::iterator( OSIterator * _iter, 936 const IOService * client, 937 const IOService * provider ) 938{ 939 _IOOpenServiceIterator * inst; 940 941 if( !_iter) 942 return( 0 ); 943 944 inst = new _IOOpenServiceIterator; 945 946 if( inst && !inst->init()) { 947 inst->release(); 948 inst = 0; 949 } 950 if( inst) { 951 inst->iter = _iter; 952 inst->client = client; 953 inst->provider = provider; 954 } 955 956 return( inst ); 957} 958 959void _IOOpenServiceIterator::free() 960{ 961 iter->release(); 962 if( last) 963 last->unlockForArbitration(); 964 OSIterator::free(); 965} 966 967OSObject * _IOOpenServiceIterator::getNextObject() 968{ 969 IOService * next; 970 971 if( last) 972 last->unlockForArbitration(); 973 974 while( (next = (IOService *) iter->getNextObject())) { 975 976 next->lockForArbitration(); 977 if( (client && (next->isOpen( client ))) 978 || (provider && (provider->isOpen( next ))) ) 979 break; 980 next->unlockForArbitration(); 981 } 982 983 last = next; 984 985 return( next ); 986} 987 988bool _IOOpenServiceIterator::isValid() 989{ 990 return( iter->isValid() ); 991} 992 993void _IOOpenServiceIterator::reset() 994{ 995 if( last) { 996 last->unlockForArbitration(); 997 last = 0; 998 } 999 iter->reset(); 1000} 1001 1002OSIterator * IOService::getOpenProviderIterator( void ) const 1003{ 1004 return( _IOOpenServiceIterator::iterator( getProviderIterator(), this, 0 )); 1005} 1006 1007OSIterator * IOService::getOpenClientIterator( void ) const 1008{ 1009 return( _IOOpenServiceIterator::iterator( getClientIterator(), 0, this )); 1010} 1011 1012 1013IOReturn IOService::callPlatformFunction( const OSSymbol * functionName, 1014 bool waitForFunction, 1015 void *param1, void *param2, 1016 void *param3, void *param4 ) 1017{ 1018 IOReturn result = kIOReturnUnsupported; 1019 IOService *provider; 1020 1021 if (gIOPlatformFunctionHandlerSet == functionName) 1022 { 1023#if defined(__i386__) || defined(__x86_64__) 1024 const OSSymbol * functionHandlerName = (const OSSymbol *) param1; 1025 IOService * target = (IOService *) param2; 1026 bool enable = (param3 != 0); 1027 1028 if (sCPULatencyFunctionName[kCpuDelayBusStall] == functionHandlerName) 1029 result = setLatencyHandler(kCpuDelayBusStall, target, enable); 1030 else if (sCPULatencyFunctionName[kCpuDelayInterrupt] == param1) 1031 result = setLatencyHandler(kCpuDelayInterrupt, target, enable); 1032#endif /* defined(__i386__) || defined(__x86_64__) */ 1033 } 1034 1035 if ((kIOReturnUnsupported == result) && (provider = getProvider())) { 1036 result = provider->callPlatformFunction(functionName, waitForFunction, 1037 param1, param2, param3, param4); 1038 } 1039 1040 return result; 1041} 1042 1043IOReturn IOService::callPlatformFunction( const char * functionName, 1044 bool waitForFunction, 1045 void *param1, void *param2, 1046 void *param3, void *param4 ) 1047{ 1048 IOReturn result = kIOReturnNoMemory; 1049 const OSSymbol *functionSymbol = OSSymbol::withCString(functionName); 1050 1051 if (functionSymbol != 0) { 1052 result = callPlatformFunction(functionSymbol, waitForFunction, 1053 param1, param2, param3, param4); 1054 functionSymbol->release(); 1055 } 1056 1057 return result; 1058} 1059 1060 1061/* 1062 * Accessors for global services 1063 */ 1064 1065IOPlatformExpert * IOService::getPlatform( void ) 1066{ 1067 return( gIOPlatform); 1068} 1069 1070class IOPMrootDomain * IOService::getPMRootDomain( void ) 1071{ 1072 return( gIOPMRootDomain); 1073} 1074 1075IOService * IOService::getResourceService( void ) 1076{ 1077 return( gIOResources ); 1078} 1079 1080void IOService::setPlatform( IOPlatformExpert * platform) 1081{ 1082 gIOPlatform = platform; 1083 gIOResources->attachToParent( gIOServiceRoot, gIOServicePlane ); 1084 1085#if defined(__i386__) || defined(__x86_64__) 1086 1087 static const char * keys[kCpuNumDelayTypes] = { 1088 kIOPlatformMaxBusDelay, kIOPlatformMaxInterruptDelay }; 1089 const OSObject * objs[2]; 1090 OSArray * array; 1091 uint32_t idx; 1092 1093 for (idx = 0; idx < kCpuNumDelayTypes; idx++) 1094 { 1095 objs[0] = sCPULatencySet[idx]; 1096 objs[1] = sCPULatencyHolder[idx]; 1097 array = OSArray::withObjects(objs, 2); 1098 if (!array) break; 1099 platform->setProperty(keys[idx], array); 1100 array->release(); 1101 } 1102#endif /* defined(__i386__) || defined(__x86_64__) */ 1103} 1104 1105void IOService::setPMRootDomain( class IOPMrootDomain * rootDomain) 1106{ 1107 gIOPMRootDomain = rootDomain; 1108 publishResource("IOKit"); 1109} 1110 1111/* 1112 * Stacking change 1113 */ 1114 1115bool IOService::lockForArbitration( bool isSuccessRequired ) 1116{ 1117 bool found; 1118 bool success; 1119 ArbitrationLockQueueElement * element; 1120 ArbitrationLockQueueElement * active; 1121 ArbitrationLockQueueElement * waiting; 1122 1123 enum { kPutOnFreeQueue, kPutOnActiveQueue, kPutOnWaitingQueue } action; 1124 1125 // lock global access 1126 IOTakeLock( gArbitrationLockQueueLock ); 1127 1128 // obtain an unused queue element 1129 if( !queue_empty( &gArbitrationLockQueueFree )) { 1130 queue_remove_first( &gArbitrationLockQueueFree, 1131 element, 1132 ArbitrationLockQueueElement *, 1133 link ); 1134 } else { 1135 element = IONew( ArbitrationLockQueueElement, 1 ); 1136 assert( element ); 1137 } 1138 1139 // prepare the queue element 1140 element->thread = IOThreadSelf(); 1141 element->service = this; 1142 element->count = 1; 1143 element->required = isSuccessRequired; 1144 element->aborted = false; 1145 1146 // determine whether this object is already locked (ie. on active queue) 1147 found = false; 1148 queue_iterate( &gArbitrationLockQueueActive, 1149 active, 1150 ArbitrationLockQueueElement *, 1151 link ) 1152 { 1153 if( active->service == element->service ) { 1154 found = true; 1155 break; 1156 } 1157 } 1158 1159 if( found ) { // this object is already locked 1160 1161 // determine whether it is the same or a different thread trying to lock 1162 if( active->thread != element->thread ) { // it is a different thread 1163 1164 ArbitrationLockQueueElement * victim = 0; 1165 1166 // before placing this new thread on the waiting queue, we look for 1167 // a deadlock cycle... 1168 1169 while( 1 ) { 1170 // determine whether the active thread holding the object we 1171 // want is waiting for another object to be unlocked 1172 found = false; 1173 queue_iterate( &gArbitrationLockQueueWaiting, 1174 waiting, 1175 ArbitrationLockQueueElement *, 1176 link ) 1177 { 1178 if( waiting->thread == active->thread ) { 1179 assert( false == waiting->aborted ); 1180 found = true; 1181 break; 1182 } 1183 } 1184 1185 if( found ) { // yes, active thread waiting for another object 1186 1187 // this may be a candidate for rejection if the required 1188 // flag is not set, should we detect a deadlock later on 1189 if( false == waiting->required ) 1190 victim = waiting; 1191 1192 // find the thread that is holding this other object, that 1193 // is blocking the active thread from proceeding (fun :-) 1194 found = false; 1195 queue_iterate( &gArbitrationLockQueueActive, 1196 active, // (reuse active queue element) 1197 ArbitrationLockQueueElement *, 1198 link ) 1199 { 1200 if( active->service == waiting->service ) { 1201 found = true; 1202 break; 1203 } 1204 } 1205 1206 // someone must be holding it or it wouldn't be waiting 1207 assert( found ); 1208 1209 if( active->thread == element->thread ) { 1210 1211 // doh, it's waiting for the thread that originated 1212 // this whole lock (ie. current thread) -> deadlock 1213 if( false == element->required ) { // willing to fail? 1214 1215 // the originating thread doesn't have the required 1216 // flag, so it can fail 1217 success = false; // (fail originating lock request) 1218 break; // (out of while) 1219 1220 } else { // originating thread is not willing to fail 1221 1222 // see if we came across a waiting thread that did 1223 // not have the 'required' flag set: we'll fail it 1224 if( victim ) { 1225 1226 // we do have a willing victim, fail it's lock 1227 victim->aborted = true; 1228 1229 // take the victim off the waiting queue 1230 queue_remove( &gArbitrationLockQueueWaiting, 1231 victim, 1232 ArbitrationLockQueueElement *, 1233 link ); 1234 1235 // wake the victim 1236 IOLockWakeup( gArbitrationLockQueueLock, 1237 victim, 1238 /* one thread */ true ); 1239 1240 // allow this thread to proceed (ie. wait) 1241 success = true; // (put request on wait queue) 1242 break; // (out of while) 1243 } else { 1244 1245 // all the waiting threads we came across in 1246 // finding this loop had the 'required' flag 1247 // set, so we've got a deadlock we can't avoid 1248 panic("I/O Kit: Unrecoverable deadlock."); 1249 } 1250 } 1251 } else { 1252 // repeat while loop, redefining active thread to be the 1253 // thread holding "this other object" (see above), and 1254 // looking for threads waiting on it; note the active 1255 // variable points to "this other object" already... so 1256 // there nothing to do in this else clause. 1257 } 1258 } else { // no, active thread is not waiting for another object 1259 1260 success = true; // (put request on wait queue) 1261 break; // (out of while) 1262 } 1263 } // while forever 1264 1265 if( success ) { // put the request on the waiting queue? 1266 kern_return_t wait_result; 1267 1268 // place this thread on the waiting queue and put it to sleep; 1269 // we place it at the tail of the queue... 1270 queue_enter( &gArbitrationLockQueueWaiting, 1271 element, 1272 ArbitrationLockQueueElement *, 1273 link ); 1274 1275 // declare that this thread will wait for a given event 1276restart_sleep: wait_result = assert_wait( element, 1277 element->required ? THREAD_UNINT 1278 : THREAD_INTERRUPTIBLE ); 1279 1280 // unlock global access 1281 IOUnlock( gArbitrationLockQueueLock ); 1282 1283 // put thread to sleep, waiting for our event to fire... 1284 if (wait_result == THREAD_WAITING) 1285 wait_result = thread_block(THREAD_CONTINUE_NULL); 1286 1287 1288 // ...and we've been woken up; we might be in one of two states: 1289 // (a) we've been aborted and our queue element is not on 1290 // any of the three queues, but is floating around 1291 // (b) we're allowed to proceed with the lock and we have 1292 // already been moved from the waiting queue to the 1293 // active queue. 1294 // ...plus a 3rd state, should the thread have been interrupted: 1295 // (c) we're still on the waiting queue 1296 1297 // determine whether we were interrupted out of our sleep 1298 if( THREAD_INTERRUPTED == wait_result ) { 1299 1300 // re-lock global access 1301 IOTakeLock( gArbitrationLockQueueLock ); 1302 1303 // determine whether we're still on the waiting queue 1304 found = false; 1305 queue_iterate( &gArbitrationLockQueueWaiting, 1306 waiting, // (reuse waiting queue element) 1307 ArbitrationLockQueueElement *, 1308 link ) 1309 { 1310 if( waiting == element ) { 1311 found = true; 1312 break; 1313 } 1314 } 1315 1316 if( found ) { // yes, we're still on the waiting queue 1317 1318 // determine whether we're willing to fail 1319 if( false == element->required ) { 1320 1321 // mark us as aborted 1322 element->aborted = true; 1323 1324 // take us off the waiting queue 1325 queue_remove( &gArbitrationLockQueueWaiting, 1326 element, 1327 ArbitrationLockQueueElement *, 1328 link ); 1329 } else { // we are not willing to fail 1330 1331 // ignore interruption, go back to sleep 1332 goto restart_sleep; 1333 } 1334 } 1335 1336 // unlock global access 1337 IOUnlock( gArbitrationLockQueueLock ); 1338 1339 // proceed as though this were a normal wake up 1340 wait_result = THREAD_AWAKENED; 1341 } 1342 1343 assert( THREAD_AWAKENED == wait_result ); 1344 1345 // determine whether we've been aborted while we were asleep 1346 if( element->aborted ) { 1347 assert( false == element->required ); 1348 1349 // re-lock global access 1350 IOTakeLock( gArbitrationLockQueueLock ); 1351 1352 action = kPutOnFreeQueue; 1353 success = false; 1354 } else { // we weren't aborted, so we must be ready to go :-) 1355 1356 // we've already been moved from waiting to active queue 1357 return true; 1358 } 1359 1360 } else { // the lock request is to be failed 1361 1362 // return unused queue element to queue 1363 action = kPutOnFreeQueue; 1364 } 1365 } else { // it is the same thread, recursive access is allowed 1366 1367 // add one level of recursion 1368 active->count++; 1369 1370 // return unused queue element to queue 1371 action = kPutOnFreeQueue; 1372 success = true; 1373 } 1374 } else { // this object is not already locked, so let this thread through 1375 action = kPutOnActiveQueue; 1376 success = true; 1377 } 1378 1379 // put the new element on a queue 1380 if( kPutOnActiveQueue == action ) { 1381 queue_enter( &gArbitrationLockQueueActive, 1382 element, 1383 ArbitrationLockQueueElement *, 1384 link ); 1385 } else if( kPutOnFreeQueue == action ) { 1386 queue_enter( &gArbitrationLockQueueFree, 1387 element, 1388 ArbitrationLockQueueElement *, 1389 link ); 1390 } else { 1391 assert( 0 ); // kPutOnWaitingQueue never occurs, handled specially above 1392 } 1393 1394 // unlock global access 1395 IOUnlock( gArbitrationLockQueueLock ); 1396 1397 return( success ); 1398} 1399 1400void IOService::unlockForArbitration( void ) 1401{ 1402 bool found; 1403 ArbitrationLockQueueElement * element; 1404 1405 // lock global access 1406 IOTakeLock( gArbitrationLockQueueLock ); 1407 1408 // find the lock element for this object (ie. on active queue) 1409 found = false; 1410 queue_iterate( &gArbitrationLockQueueActive, 1411 element, 1412 ArbitrationLockQueueElement *, 1413 link ) 1414 { 1415 if( element->service == this ) { 1416 found = true; 1417 break; 1418 } 1419 } 1420 1421 assert( found ); 1422 1423 // determine whether the lock has been taken recursively 1424 if( element->count > 1 ) { 1425 // undo one level of recursion 1426 element->count--; 1427 1428 } else { 1429 1430 // remove it from the active queue 1431 queue_remove( &gArbitrationLockQueueActive, 1432 element, 1433 ArbitrationLockQueueElement *, 1434 link ); 1435 1436 // put it on the free queue 1437 queue_enter( &gArbitrationLockQueueFree, 1438 element, 1439 ArbitrationLockQueueElement *, 1440 link ); 1441 1442 // determine whether a thread is waiting for object (head to tail scan) 1443 found = false; 1444 queue_iterate( &gArbitrationLockQueueWaiting, 1445 element, 1446 ArbitrationLockQueueElement *, 1447 link ) 1448 { 1449 if( element->service == this ) { 1450 found = true; 1451 break; 1452 } 1453 } 1454 1455 if ( found ) { // we found an interested thread on waiting queue 1456 1457 // remove it from the waiting queue 1458 queue_remove( &gArbitrationLockQueueWaiting, 1459 element, 1460 ArbitrationLockQueueElement *, 1461 link ); 1462 1463 // put it on the active queue 1464 queue_enter( &gArbitrationLockQueueActive, 1465 element, 1466 ArbitrationLockQueueElement *, 1467 link ); 1468 1469 // wake the waiting thread 1470 IOLockWakeup( gArbitrationLockQueueLock, 1471 element, 1472 /* one thread */ true ); 1473 } 1474 } 1475 1476 // unlock global access 1477 IOUnlock( gArbitrationLockQueueLock ); 1478} 1479 1480void IOService::applyToProviders( IOServiceApplierFunction applier, 1481 void * context ) 1482{ 1483 applyToParents( (IORegistryEntryApplierFunction) applier, 1484 context, gIOServicePlane ); 1485} 1486 1487void IOService::applyToClients( IOServiceApplierFunction applier, 1488 void * context ) 1489{ 1490 applyToChildren( (IORegistryEntryApplierFunction) applier, 1491 context, gIOServicePlane ); 1492} 1493 1494 1495/* 1496 * Client messages 1497 */ 1498 1499 1500// send a message to a client or interested party of this service 1501IOReturn IOService::messageClient( UInt32 type, OSObject * client, 1502 void * argument, vm_size_t argSize ) 1503{ 1504 IOReturn ret; 1505 IOService * service; 1506 _IOServiceInterestNotifier * notify; 1507 1508 if( (service = OSDynamicCast( IOService, client))) 1509 ret = service->message( type, this, argument ); 1510 1511 else if( (notify = OSDynamicCast( _IOServiceInterestNotifier, client))) { 1512 1513 _IOServiceNotifierInvocation invocation; 1514 bool willNotify; 1515 1516 invocation.thread = current_thread(); 1517 1518 LOCKWRITENOTIFY(); 1519 willNotify = (0 != (kIOServiceNotifyEnable & notify->state)); 1520 1521 if( willNotify) { 1522 queue_enter( ¬ify->handlerInvocations, &invocation, 1523 _IOServiceNotifierInvocation *, link ); 1524 } 1525 UNLOCKNOTIFY(); 1526 1527 if( willNotify) { 1528 1529 ret = (*notify->handler)( notify->target, notify->ref, 1530 type, this, argument, argSize ); 1531 1532 LOCKWRITENOTIFY(); 1533 queue_remove( ¬ify->handlerInvocations, &invocation, 1534 _IOServiceNotifierInvocation *, link ); 1535 if( kIOServiceNotifyWaiter & notify->state) { 1536 notify->state &= ~kIOServiceNotifyWaiter; 1537 WAKEUPNOTIFY( notify ); 1538 } 1539 UNLOCKNOTIFY(); 1540 1541 } else 1542 ret = kIOReturnSuccess; 1543 1544 } else 1545 ret = kIOReturnBadArgument; 1546 1547 return( ret ); 1548} 1549 1550static void 1551applyToInterestNotifiers(const IORegistryEntry *target, 1552 const OSSymbol * typeOfInterest, 1553 OSObjectApplierFunction applier, 1554 void * context ) 1555{ 1556 OSArray * copyArray = 0; 1557 1558 LOCKREADNOTIFY(); 1559 1560 IOCommand *notifyList = 1561 OSDynamicCast( IOCommand, target->getProperty( typeOfInterest )); 1562 1563 if( notifyList) { 1564 copyArray = OSArray::withCapacity(1); 1565 1566 // iterate over queue, entry is set to each element in the list 1567 iterqueue(¬ifyList->fCommandChain, entry) { 1568 _IOServiceInterestNotifier * notify; 1569 1570 queue_element(entry, notify, _IOServiceInterestNotifier *, chain); 1571 copyArray->setObject(notify); 1572 } 1573 } 1574 UNLOCKNOTIFY(); 1575 1576 if( copyArray) { 1577 unsigned int index; 1578 OSObject * next; 1579 1580 for( index = 0; (next = copyArray->getObject( index )); index++) 1581 (*applier)(next, context); 1582 copyArray->release(); 1583 } 1584} 1585 1586void IOService::applyToInterested( const OSSymbol * typeOfInterest, 1587 OSObjectApplierFunction applier, 1588 void * context ) 1589{ 1590 if (gIOGeneralInterest == typeOfInterest) 1591 applyToClients( (IOServiceApplierFunction) applier, context ); 1592 applyToInterestNotifiers(this, typeOfInterest, applier, context); 1593} 1594 1595struct MessageClientsContext { 1596 IOService * service; 1597 UInt32 type; 1598 void * argument; 1599 vm_size_t argSize; 1600 IOReturn ret; 1601}; 1602 1603static void messageClientsApplier( OSObject * object, void * ctx ) 1604{ 1605 IOReturn ret; 1606 MessageClientsContext * context = (MessageClientsContext *) ctx; 1607 1608 ret = context->service->messageClient( context->type, 1609 object, context->argument, context->argSize ); 1610 if( kIOReturnSuccess != ret) 1611 context->ret = ret; 1612} 1613 1614// send a message to all clients 1615IOReturn IOService::messageClients( UInt32 type, 1616 void * argument, vm_size_t argSize ) 1617{ 1618 MessageClientsContext context; 1619 1620 context.service = this; 1621 context.type = type; 1622 context.argument = argument; 1623 context.argSize = argSize; 1624 context.ret = kIOReturnSuccess; 1625 1626 applyToInterested( gIOGeneralInterest, 1627 &messageClientsApplier, &context ); 1628 1629 return( context.ret ); 1630} 1631 1632IOReturn IOService::acknowledgeNotification( IONotificationRef notification, 1633 IOOptionBits response ) 1634{ 1635 return( kIOReturnUnsupported ); 1636} 1637 1638IONotifier * IOService::registerInterest( const OSSymbol * typeOfInterest, 1639 IOServiceInterestHandler handler, void * target, void * ref ) 1640{ 1641 _IOServiceInterestNotifier * notify = 0; 1642 IOReturn rc = kIOReturnError; 1643 1644 notify = new _IOServiceInterestNotifier; 1645 if (!notify) return NULL; 1646 1647 if(notify->init()) { 1648 rc = registerInterestForNotifer(notify, typeOfInterest, 1649 handler, target, ref); 1650 } 1651 1652 if (rc != kIOReturnSuccess) { 1653 notify->release(); 1654 notify = 0; 1655 } 1656 1657 return( notify ); 1658} 1659 1660IOReturn IOService::registerInterestForNotifer( IONotifier *svcNotify, const OSSymbol * typeOfInterest, 1661 IOServiceInterestHandler handler, void * target, void * ref ) 1662{ 1663 IOReturn rc = kIOReturnSuccess; 1664 _IOServiceInterestNotifier *notify = 0; 1665 1666 if( (typeOfInterest != gIOGeneralInterest) 1667 && (typeOfInterest != gIOBusyInterest) 1668 && (typeOfInterest != gIOAppPowerStateInterest) 1669 && (typeOfInterest != gIOConsoleSecurityInterest) 1670 && (typeOfInterest != gIOPriorityPowerStateInterest)) 1671 return( kIOReturnBadArgument ); 1672 1673 if (!svcNotify || !(notify = OSDynamicCast(_IOServiceInterestNotifier, svcNotify))) 1674 return( kIOReturnBadArgument ); 1675 1676 lockForArbitration(); 1677 if( 0 == (__state[0] & kIOServiceInactiveState)) { 1678 1679 notify->handler = handler; 1680 notify->target = target; 1681 notify->ref = ref; 1682 notify->state = kIOServiceNotifyEnable; 1683 1684 ////// queue 1685 1686 LOCKWRITENOTIFY(); 1687 1688 // Get the head of the notifier linked list 1689 IOCommand *notifyList = (IOCommand *) getProperty( typeOfInterest ); 1690 if (!notifyList || !OSDynamicCast(IOCommand, notifyList)) { 1691 notifyList = OSTypeAlloc(IOCommand); 1692 if (notifyList) { 1693 notifyList->init(); 1694 setProperty( typeOfInterest, notifyList); 1695 notifyList->release(); 1696 } 1697 } 1698 1699 if (notifyList) { 1700 enqueue(¬ifyList->fCommandChain, ¬ify->chain); 1701 notify->retain(); // ref'ed while in list 1702 } 1703 1704 UNLOCKNOTIFY(); 1705 } 1706 else { 1707 rc = kIOReturnNotReady; 1708 } 1709 unlockForArbitration(); 1710 1711 return rc; 1712} 1713 1714static void cleanInterestList( OSObject * head ) 1715{ 1716 IOCommand *notifyHead = OSDynamicCast(IOCommand, head); 1717 if (!notifyHead) 1718 return; 1719 1720 LOCKWRITENOTIFY(); 1721 while ( queue_entry_t entry = dequeue(¬ifyHead->fCommandChain) ) { 1722 queue_next(entry) = queue_prev(entry) = 0; 1723 1724 _IOServiceInterestNotifier * notify; 1725 1726 queue_element(entry, notify, _IOServiceInterestNotifier *, chain); 1727 notify->release(); 1728 } 1729 UNLOCKNOTIFY(); 1730} 1731 1732void IOService::unregisterAllInterest( void ) 1733{ 1734 cleanInterestList( getProperty( gIOGeneralInterest )); 1735 cleanInterestList( getProperty( gIOBusyInterest )); 1736 cleanInterestList( getProperty( gIOAppPowerStateInterest )); 1737 cleanInterestList( getProperty( gIOPriorityPowerStateInterest )); 1738 cleanInterestList( getProperty( gIOConsoleSecurityInterest )); 1739} 1740 1741/* 1742 * _IOServiceInterestNotifier 1743 */ 1744 1745// wait for all threads, other than the current one, 1746// to exit the handler 1747 1748void _IOServiceInterestNotifier::wait() 1749{ 1750 _IOServiceNotifierInvocation * next; 1751 bool doWait; 1752 1753 do { 1754 doWait = false; 1755 queue_iterate( &handlerInvocations, next, 1756 _IOServiceNotifierInvocation *, link) { 1757 if( next->thread != current_thread() ) { 1758 doWait = true; 1759 break; 1760 } 1761 } 1762 if( doWait) { 1763 state |= kIOServiceNotifyWaiter; 1764 SLEEPNOTIFY(this); 1765 } 1766 1767 } while( doWait ); 1768} 1769 1770void _IOServiceInterestNotifier::free() 1771{ 1772 assert( queue_empty( &handlerInvocations )); 1773 OSObject::free(); 1774} 1775 1776void _IOServiceInterestNotifier::remove() 1777{ 1778 LOCKWRITENOTIFY(); 1779 1780 if( queue_next( &chain )) { 1781 remqueue(&chain); 1782 queue_next( &chain) = queue_prev( &chain) = 0; 1783 release(); 1784 } 1785 1786 state &= ~kIOServiceNotifyEnable; 1787 1788 wait(); 1789 1790 UNLOCKNOTIFY(); 1791 1792 release(); 1793} 1794 1795bool _IOServiceInterestNotifier::disable() 1796{ 1797 bool ret; 1798 1799 LOCKWRITENOTIFY(); 1800 1801 ret = (0 != (kIOServiceNotifyEnable & state)); 1802 state &= ~kIOServiceNotifyEnable; 1803 if( ret) 1804 wait(); 1805 1806 UNLOCKNOTIFY(); 1807 1808 return( ret ); 1809} 1810 1811void _IOServiceInterestNotifier::enable( bool was ) 1812{ 1813 LOCKWRITENOTIFY(); 1814 if( was) 1815 state |= kIOServiceNotifyEnable; 1816 else 1817 state &= ~kIOServiceNotifyEnable; 1818 UNLOCKNOTIFY(); 1819} 1820 1821bool _IOServiceInterestNotifier::init() 1822{ 1823 queue_init( &handlerInvocations ); 1824 return (OSObject::init()); 1825} 1826/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 1827 1828/* 1829 * Termination 1830 */ 1831 1832#define tailQ(o) setObject(o) 1833#define headQ(o) setObject(0, o) 1834#define TLOG(fmt, args...) { if(kIOLogYield & gIOKitDebug) { IOLog("[%llx] ", thread_tid(current_thread())); IOLog(fmt, ## args); }} 1835 1836static void _workLoopAction( IOWorkLoop::Action action, 1837 IOService * service, 1838 void * p0 = 0, void * p1 = 0, 1839 void * p2 = 0, void * p3 = 0 ) 1840{ 1841 IOWorkLoop * wl; 1842 1843 if( (wl = service->getWorkLoop())) { 1844 wl->retain(); 1845 wl->runAction( action, service, p0, p1, p2, p3 ); 1846 wl->release(); 1847 } else 1848 (*action)( service, p0, p1, p2, p3 ); 1849} 1850 1851bool IOService::requestTerminate( IOService * provider, IOOptionBits options ) 1852{ 1853 bool ok; 1854 1855 // if its our only provider 1856 ok = isParent( provider, gIOServicePlane, true); 1857 1858 // -- compat 1859 if( ok) { 1860 provider->terminateClient( this, options | kIOServiceRecursing ); 1861 ok = (0 != (__state[1] & kIOServiceRecursing)); 1862 } 1863 // -- 1864 1865 return( ok ); 1866} 1867 1868bool IOService::terminatePhase1( IOOptionBits options ) 1869{ 1870 IOService * victim; 1871 IOService * client; 1872 OSIterator * iter; 1873 OSArray * makeInactive; 1874 int waitResult = THREAD_AWAKENED; 1875 bool wait; 1876 bool ok; 1877 bool didInactive; 1878 bool startPhase2 = false; 1879 1880 TLOG("%s[0x%qx]::terminatePhase1(%08llx)\n", getName(), getRegistryEntryID(), (long long)options); 1881 1882 uint64_t regID = getRegistryEntryID(); 1883 IOServiceTrace( 1884 IOSERVICE_TERMINATE_PHASE1, 1885 (uintptr_t) regID, 1886 (uintptr_t) (regID >> 32), 1887 (uintptr_t) this, 1888 (uintptr_t) options); 1889 1890 // -- compat 1891 if( options & kIOServiceRecursing) { 1892 lockForArbitration(); 1893 __state[0] |= kIOServiceInactiveState; 1894 __state[1] |= kIOServiceRecursing; 1895 unlockForArbitration(); 1896 1897 return( true ); 1898 } 1899 // -- 1900 1901 makeInactive = OSArray::withCapacity( 16 ); 1902 if( !makeInactive) 1903 return( false ); 1904 1905 victim = this; 1906 victim->retain(); 1907 1908 while( victim ) { 1909 1910 didInactive = victim->lockForArbitration( true ); 1911 if( didInactive) { 1912 didInactive = (0 == (victim->__state[0] & kIOServiceInactiveState)) 1913 || (victim->__state[1] & kIOServiceRecursing); 1914 if( didInactive) { 1915 victim->__state[0] |= kIOServiceInactiveState; 1916 victim->__state[0] &= ~(kIOServiceRegisteredState | kIOServiceMatchedState 1917 | kIOServiceFirstPublishState | kIOServiceFirstMatchState); 1918 victim->__state[1] &= ~kIOServiceRecursing; 1919 1920 if (victim == this) 1921 { 1922 victim->__state[1] |= kIOServiceTermPhase1State; 1923 if (kIOServiceTerminateNeedWillTerminate & options) 1924 { 1925 victim->__state[1] |= kIOServiceNeedWillTerminate; 1926 } 1927 } 1928 1929 victim->_adjustBusy( 1 ); 1930 1931 } else if (victim != this) do { 1932 1933 IOLockLock(gIOServiceBusyLock); 1934 wait = (victim->__state[1] & kIOServiceTermPhase1State); 1935 if( wait) { 1936 TLOG("%s[0x%qx]::waitPhase1(%s[0x%qx])\n", 1937 getName(), getRegistryEntryID(), victim->getName(), victim->getRegistryEntryID()); 1938 victim->__state[1] |= kIOServiceTerm1WaiterState; 1939 victim->unlockForArbitration(); 1940 assert_wait((event_t)&victim->__state[1], THREAD_UNINT); 1941 } 1942 IOLockUnlock(gIOServiceBusyLock); 1943 if( wait) { 1944 waitResult = thread_block(THREAD_CONTINUE_NULL); 1945 TLOG("%s[0x%qx]::did waitPhase1(%s[0x%qx])\n", 1946 getName(), getRegistryEntryID(), victim->getName(), victim->getRegistryEntryID()); 1947 victim->lockForArbitration(); 1948 } 1949 } while( wait && (waitResult != THREAD_TIMED_OUT)); 1950 1951 victim->unlockForArbitration(); 1952 } 1953 if( victim == this) 1954 startPhase2 = didInactive; 1955 if( didInactive) { 1956 1957 victim->deliverNotification( gIOTerminatedNotification, 0, 0xffffffff ); 1958 IOUserClient::destroyUserReferences( victim ); 1959 1960 iter = victim->getClientIterator(); 1961 if( iter) { 1962 while( (client = (IOService *) iter->getNextObject())) { 1963 TLOG("%s[0x%qx]::requestTerminate(%s[0x%qx], %08llx)\n", 1964 client->getName(), client->getRegistryEntryID(), 1965 victim->getName(), victim->getRegistryEntryID(), (long long)options); 1966 ok = client->requestTerminate( victim, options ); 1967 TLOG("%s[0x%qx]::requestTerminate(%s[0x%qx], ok = %d)\n", 1968 client->getName(), client->getRegistryEntryID(), 1969 victim->getName(), victim->getRegistryEntryID(), ok); 1970 1971 uint64_t regID1 = client->getRegistryEntryID(); 1972 uint64_t regID2 = victim->getRegistryEntryID(); 1973 IOServiceTrace( 1974 (ok ? IOSERVICE_TERMINATE_REQUEST_OK 1975 : IOSERVICE_TERMINATE_REQUEST_FAIL), 1976 (uintptr_t) regID1, 1977 (uintptr_t) (regID1 >> 32), 1978 (uintptr_t) regID2, 1979 (uintptr_t) (regID2 >> 32)); 1980 1981 if( ok) 1982 makeInactive->setObject( client ); 1983 } 1984 iter->release(); 1985 } 1986 } 1987 victim->release(); 1988 victim = (IOService *) makeInactive->getObject(0); 1989 if( victim) { 1990 victim->retain(); 1991 makeInactive->removeObject(0); 1992 } 1993 } 1994 1995 makeInactive->release(); 1996 1997 if( startPhase2) 1998 { 1999 lockForArbitration(); 2000 __state[1] &= ~kIOServiceTermPhase1State; 2001 if (kIOServiceTerm1WaiterState & __state[1]) 2002 { 2003 __state[1] &= ~kIOServiceTerm1WaiterState; 2004 TLOG("%s[0x%qx]::wakePhase1\n", getName(), getRegistryEntryID()); 2005 IOLockLock( gIOServiceBusyLock ); 2006 thread_wakeup( (event_t) &__state[1]); 2007 IOLockUnlock( gIOServiceBusyLock ); 2008 } 2009 unlockForArbitration(); 2010 scheduleTerminatePhase2( options ); 2011 } 2012 2013 return( true ); 2014} 2015 2016void IOService::setTerminateDefer(IOService * provider, bool defer) 2017{ 2018 lockForArbitration(); 2019 if (defer) __state[1] |= kIOServiceStartState; 2020 else __state[1] &= ~kIOServiceStartState; 2021 unlockForArbitration(); 2022 2023 if (provider && !defer) 2024 { 2025 provider->lockForArbitration(); 2026 provider->scheduleTerminatePhase2(); 2027 provider->unlockForArbitration(); 2028 } 2029} 2030 2031// call with lockForArbitration 2032void IOService::scheduleTerminatePhase2( IOOptionBits options ) 2033{ 2034 AbsoluteTime deadline; 2035 int waitResult = THREAD_AWAKENED; 2036 bool wait, haveDeadline = false; 2037 2038 if (!(__state[0] & kIOServiceInactiveState) 2039 || (__state[1] & kIOServiceTermPhase1State)) return; 2040 2041 options |= kIOServiceRequired; 2042 2043 retain(); 2044 2045 IOLockLock( gJobsLock ); 2046 2047 if( (options & kIOServiceSynchronous) 2048 && (current_thread() != gIOTerminateThread)) { 2049 2050 do { 2051 wait = (gIOTerminateThread != 0); 2052 if( wait) { 2053 // wait to become the terminate thread 2054 IOLockSleep( gJobsLock, &gIOTerminateThread, THREAD_UNINT); 2055 } 2056 } while( wait ); 2057 2058 gIOTerminateThread = current_thread(); 2059 gIOTerminatePhase2List->setObject( this ); 2060 gIOTerminateWork++; 2061 2062 do { 2063 while( gIOTerminateWork ) 2064 terminateWorker( options ); 2065 wait = (0 != (__state[1] & kIOServiceBusyStateMask)); 2066 if( wait) { 2067 // wait for the victim to go non-busy 2068 if( !haveDeadline) { 2069 clock_interval_to_deadline( 15, kSecondScale, &deadline ); 2070 haveDeadline = true; 2071 } 2072 waitResult = IOLockSleepDeadline( gJobsLock, &gIOTerminateWork, 2073 deadline, THREAD_UNINT ); 2074 if( waitResult == THREAD_TIMED_OUT) { 2075 IOLog("%s[0x%qx]::terminate(kIOServiceSynchronous) timeout\n", getName(), getRegistryEntryID()); 2076 } 2077 } 2078 } while(gIOTerminateWork || (wait && (waitResult != THREAD_TIMED_OUT))); 2079 2080 gIOTerminateThread = 0; 2081 IOLockWakeup( gJobsLock, (event_t) &gIOTerminateThread, /* one-thread */ false); 2082 2083 } else { 2084 // ! kIOServiceSynchronous 2085 2086 gIOTerminatePhase2List->setObject( this ); 2087 if( 0 == gIOTerminateWork++) { 2088 if( !gIOTerminateThread) 2089 kernel_thread_start(&terminateThread, (void *)(uintptr_t) options, &gIOTerminateThread); 2090 else 2091 IOLockWakeup(gJobsLock, (event_t) &gIOTerminateWork, /* one-thread */ false ); 2092 } 2093 } 2094 2095 IOLockUnlock( gJobsLock ); 2096 2097 release(); 2098} 2099 2100void IOService::terminateThread( void * arg, wait_result_t waitResult ) 2101{ 2102 IOLockLock( gJobsLock ); 2103 2104 while (gIOTerminateWork) 2105 terminateWorker( (uintptr_t) arg ); 2106 2107 thread_deallocate(gIOTerminateThread); 2108 gIOTerminateThread = 0; 2109 IOLockWakeup( gJobsLock, (event_t) &gIOTerminateThread, /* one-thread */ false); 2110 2111 IOLockUnlock( gJobsLock ); 2112} 2113 2114void IOService::scheduleStop( IOService * provider ) 2115{ 2116 uint64_t regID1 = getRegistryEntryID(); 2117 uint64_t regID2 = provider->getRegistryEntryID(); 2118 2119 TLOG("%s[0x%qx]::scheduleStop(%s[0x%qx])\n", getName(), regID1, provider->getName(), regID2); 2120 IOServiceTrace( 2121 IOSERVICE_TERMINATE_SCHEDULE_STOP, 2122 (uintptr_t) regID1, 2123 (uintptr_t) (regID1 >> 32), 2124 (uintptr_t) regID2, 2125 (uintptr_t) (regID2 >> 32)); 2126 2127 IOLockLock( gJobsLock ); 2128 gIOStopList->tailQ( this ); 2129 gIOStopProviderList->tailQ( provider ); 2130 2131 if( 0 == gIOTerminateWork++) { 2132 if( !gIOTerminateThread) 2133 kernel_thread_start(&terminateThread, (void *) 0, &gIOTerminateThread); 2134 else 2135 IOLockWakeup(gJobsLock, (event_t) &gIOTerminateWork, /* one-thread */ false ); 2136 } 2137 2138 IOLockUnlock( gJobsLock ); 2139} 2140 2141void IOService::scheduleFinalize( void ) 2142{ 2143 uint64_t regID1 = getRegistryEntryID(); 2144 2145 TLOG("%s[0x%qx]::scheduleFinalize\n", getName(), regID1); 2146 IOServiceTrace( 2147 IOSERVICE_TERMINATE_SCHEDULE_FINALIZE, 2148 (uintptr_t) regID1, 2149 (uintptr_t) (regID1 >> 32), 2150 0, 0); 2151 2152 IOLockLock( gJobsLock ); 2153 gIOFinalizeList->tailQ( this ); 2154 2155 if( 0 == gIOTerminateWork++) { 2156 if( !gIOTerminateThread) 2157 kernel_thread_start(&terminateThread, (void *) 0, &gIOTerminateThread); 2158 else 2159 IOLockWakeup(gJobsLock, (event_t) &gIOTerminateWork, /* one-thread */ false ); 2160 } 2161 2162 IOLockUnlock( gJobsLock ); 2163} 2164 2165bool IOService::willTerminate( IOService * provider, IOOptionBits options ) 2166{ 2167 return( true ); 2168} 2169 2170bool IOService::didTerminate( IOService * provider, IOOptionBits options, bool * defer ) 2171{ 2172 if( false == *defer) { 2173 2174 if( lockForArbitration( true )) { 2175 if( false == provider->handleIsOpen( this )) 2176 scheduleStop( provider ); 2177 // -- compat 2178 else { 2179 message( kIOMessageServiceIsRequestingClose, provider, (void *)(uintptr_t) options ); 2180 if( false == provider->handleIsOpen( this )) 2181 scheduleStop( provider ); 2182 } 2183 // -- 2184 unlockForArbitration(); 2185 } 2186 } 2187 2188 return( true ); 2189} 2190 2191void IOService::actionWillTerminate( IOService * victim, IOOptionBits options, 2192 OSArray * doPhase2List, 2193 void *unused2 __unused, 2194 void *unused3 __unused ) 2195{ 2196 OSIterator * iter; 2197 IOService * client; 2198 bool ok; 2199 uint64_t regID1, regID2 = victim->getRegistryEntryID(); 2200 2201 iter = victim->getClientIterator(); 2202 if( iter) { 2203 while( (client = (IOService *) iter->getNextObject())) { 2204 2205 regID1 = client->getRegistryEntryID(); 2206 TLOG("%s[0x%qx]::willTerminate(%s[0x%qx], %08llx)\n", 2207 client->getName(), regID1, 2208 victim->getName(), regID2, (long long)options); 2209 IOServiceTrace( 2210 IOSERVICE_TERMINATE_WILL, 2211 (uintptr_t) regID1, 2212 (uintptr_t) (regID1 >> 32), 2213 (uintptr_t) regID2, 2214 (uintptr_t) (regID2 >> 32)); 2215 2216 ok = client->willTerminate( victim, options ); 2217 doPhase2List->tailQ( client ); 2218 } 2219 iter->release(); 2220 } 2221} 2222 2223void IOService::actionDidTerminate( IOService * victim, IOOptionBits options, 2224 void *unused1 __unused, void *unused2 __unused, 2225 void *unused3 __unused ) 2226{ 2227 OSIterator * iter; 2228 IOService * client; 2229 bool defer = false; 2230 uint64_t regID1, regID2 = victim->getRegistryEntryID(); 2231 2232 victim->messageClients( kIOMessageServiceIsTerminated, (void *)(uintptr_t) options ); 2233 2234 iter = victim->getClientIterator(); 2235 if( iter) { 2236 while( (client = (IOService *) iter->getNextObject())) { 2237 2238 regID1 = client->getRegistryEntryID(); 2239 TLOG("%s[0x%qx]::didTerminate(%s[0x%qx], %08llx)\n", 2240 client->getName(), regID1, 2241 victim->getName(), regID2, (long long)options); 2242 client->didTerminate( victim, options, &defer ); 2243 2244 IOServiceTrace( 2245 (defer ? IOSERVICE_TERMINATE_DID_DEFER 2246 : IOSERVICE_TERMINATE_DID), 2247 (uintptr_t) regID1, 2248 (uintptr_t) (regID1 >> 32), 2249 (uintptr_t) regID2, 2250 (uintptr_t) (regID2 >> 32)); 2251 2252 TLOG("%s[0x%qx]::didTerminate(%s[0x%qx], defer %d)\n", 2253 client->getName(), regID1, 2254 victim->getName(), regID2, defer); 2255 } 2256 iter->release(); 2257 } 2258} 2259 2260 2261void IOService::actionWillStop( IOService * victim, IOOptionBits options, 2262 void *unused1 __unused, void *unused2 __unused, 2263 void *unused3 __unused ) 2264{ 2265 OSIterator * iter; 2266 IOService * provider; 2267 bool ok; 2268 uint64_t regID1, regID2 = victim->getRegistryEntryID(); 2269 2270 iter = victim->getProviderIterator(); 2271 if( iter) { 2272 while( (provider = (IOService *) iter->getNextObject())) { 2273 2274 regID1 = provider->getRegistryEntryID(); 2275 TLOG("%s[0x%qx]::willTerminate(%s[0x%qx], %08llx)\n", 2276 victim->getName(), regID2, 2277 provider->getName(), regID1, (long long)options); 2278 IOServiceTrace( 2279 IOSERVICE_TERMINATE_WILL, 2280 (uintptr_t) regID2, 2281 (uintptr_t) (regID2 >> 32), 2282 (uintptr_t) regID1, 2283 (uintptr_t) (regID1 >> 32)); 2284 2285 ok = victim->willTerminate( provider, options ); 2286 } 2287 iter->release(); 2288 } 2289} 2290 2291void IOService::actionDidStop( IOService * victim, IOOptionBits options, 2292 void *unused1 __unused, void *unused2 __unused, 2293 void *unused3 __unused ) 2294{ 2295 OSIterator * iter; 2296 IOService * provider; 2297 bool defer = false; 2298 uint64_t regID1, regID2 = victim->getRegistryEntryID(); 2299 2300 iter = victim->getProviderIterator(); 2301 if( iter) { 2302 while( (provider = (IOService *) iter->getNextObject())) { 2303 2304 regID1 = provider->getRegistryEntryID(); 2305 TLOG("%s[0x%qx]::didTerminate(%s[0x%qx], %08llx)\n", 2306 victim->getName(), regID2, 2307 provider->getName(), regID1, (long long)options); 2308 victim->didTerminate( provider, options, &defer ); 2309 2310 IOServiceTrace( 2311 (defer ? IOSERVICE_TERMINATE_DID_DEFER 2312 : IOSERVICE_TERMINATE_DID), 2313 (uintptr_t) regID2, 2314 (uintptr_t) (regID2 >> 32), 2315 (uintptr_t) regID1, 2316 (uintptr_t) (regID1 >> 32)); 2317 2318 TLOG("%s[0x%qx]::didTerminate(%s[0x%qx], defer %d)\n", 2319 victim->getName(), regID2, 2320 provider->getName(), regID1, defer); 2321 } 2322 iter->release(); 2323 } 2324} 2325 2326 2327void IOService::actionFinalize( IOService * victim, IOOptionBits options, 2328 void *unused1 __unused, void *unused2 __unused, 2329 void *unused3 __unused ) 2330{ 2331 uint64_t regID1 = victim->getRegistryEntryID(); 2332 TLOG("%s[0x%qx]::finalize(%08llx)\n", victim->getName(), regID1, (long long)options); 2333 IOServiceTrace( 2334 IOSERVICE_TERMINATE_FINALIZE, 2335 (uintptr_t) regID1, 2336 (uintptr_t) (regID1 >> 32), 2337 0, 0); 2338 2339 victim->finalize( options ); 2340} 2341 2342void IOService::actionStop( IOService * provider, IOService * client, 2343 void *unused1 __unused, void *unused2 __unused, 2344 void *unused3 __unused ) 2345{ 2346 uint64_t regID1 = provider->getRegistryEntryID(); 2347 uint64_t regID2 = client->getRegistryEntryID(); 2348 2349 TLOG("%s[0x%qx]::stop(%s[0x%qx])\n", client->getName(), regID2, provider->getName(), regID1); 2350 IOServiceTrace( 2351 IOSERVICE_TERMINATE_STOP, 2352 (uintptr_t) regID1, 2353 (uintptr_t) (regID1 >> 32), 2354 (uintptr_t) regID2, 2355 (uintptr_t) (regID2 >> 32)); 2356 2357 client->stop( provider ); 2358 if( provider->isOpen( client )) 2359 provider->close( client ); 2360 2361 TLOG("%s[0x%qx]::detach(%s[0x%qx])\n", client->getName(), regID2, provider->getName(), regID1); 2362 client->detach( provider ); 2363} 2364 2365void IOService::terminateWorker( IOOptionBits options ) 2366{ 2367 OSArray * doPhase2List; 2368 OSArray * didPhase2List; 2369 OSSet * freeList; 2370 OSIterator * iter; 2371 UInt32 workDone; 2372 IOService * victim; 2373 IOService * client; 2374 IOService * provider; 2375 unsigned int idx; 2376 bool moreToDo; 2377 bool doPhase2; 2378 bool doPhase3; 2379 2380 options |= kIOServiceRequired; 2381 2382 doPhase2List = OSArray::withCapacity( 16 ); 2383 didPhase2List = OSArray::withCapacity( 16 ); 2384 freeList = OSSet::withCapacity( 16 ); 2385 if( (0 == doPhase2List) || (0 == didPhase2List) || (0 == freeList)) 2386 return; 2387 2388 do { 2389 workDone = gIOTerminateWork; 2390 2391 while( (victim = (IOService *) gIOTerminatePhase2List->getObject(0) )) { 2392 2393 victim->retain(); 2394 gIOTerminatePhase2List->removeObject(0); 2395 IOLockUnlock( gJobsLock ); 2396 2397 while( victim ) { 2398 2399 doPhase2 = victim->lockForArbitration( true ); 2400 if( doPhase2) { 2401 doPhase2 = (0 != (kIOServiceInactiveState & victim->__state[0])); 2402 if( doPhase2) { 2403 doPhase2 = (0 == (victim->__state[1] & kIOServiceTermPhase2State)) 2404 && (0 == (victim->__state[1] & kIOServiceConfigState)); 2405 2406 if (doPhase2 && (iter = victim->getClientIterator())) { 2407 while (doPhase2 && (client = (IOService *) iter->getNextObject())) { 2408 doPhase2 = (0 == (client->__state[1] & kIOServiceStartState)); 2409 2410 if (!doPhase2) TLOG("%s[0x%qx]::defer phase2(%s[0x%qx])\n", 2411 victim->getName(), victim->getRegistryEntryID(), 2412 client->getName(), client->getRegistryEntryID()); 2413 } 2414 iter->release(); 2415 } 2416 if( doPhase2) 2417 victim->__state[1] |= kIOServiceTermPhase2State; 2418 } 2419 victim->unlockForArbitration(); 2420 } 2421 if( doPhase2) { 2422 2423 if (kIOServiceNeedWillTerminate & victim->__state[1]) { 2424 _workLoopAction( (IOWorkLoop::Action) &actionWillStop, 2425 victim, (void *)(uintptr_t) options, NULL ); 2426 } 2427 2428 if( 0 == victim->getClient()) { 2429 // no clients - will go to finalize 2430 IOLockLock( gJobsLock ); 2431 gIOFinalizeList->tailQ( victim ); 2432 IOLockUnlock( gJobsLock ); 2433 } else { 2434 _workLoopAction( (IOWorkLoop::Action) &actionWillTerminate, 2435 victim, (void *)(uintptr_t) options, (void *)(uintptr_t) doPhase2List ); 2436 } 2437 didPhase2List->headQ( victim ); 2438 } 2439 victim->release(); 2440 victim = (IOService *) doPhase2List->getObject(0); 2441 if( victim) { 2442 victim->retain(); 2443 doPhase2List->removeObject(0); 2444 } 2445 } 2446 2447 while( (victim = (IOService *) didPhase2List->getObject(0)) ) { 2448 2449 if( victim->lockForArbitration( true )) { 2450 victim->__state[1] |= kIOServiceTermPhase3State; 2451 victim->unlockForArbitration(); 2452 } 2453 _workLoopAction( (IOWorkLoop::Action) &actionDidTerminate, 2454 victim, (void *)(uintptr_t) options ); 2455 if (kIOServiceNeedWillTerminate & victim->__state[1]) { 2456 _workLoopAction( (IOWorkLoop::Action) &actionDidStop, 2457 victim, (void *)(uintptr_t) options, NULL ); 2458 } 2459 didPhase2List->removeObject(0); 2460 } 2461 IOLockLock( gJobsLock ); 2462 } 2463 2464 // phase 3 2465 do { 2466 doPhase3 = false; 2467 // finalize leaves 2468 while( (victim = (IOService *) gIOFinalizeList->getObject(0))) { 2469 2470 IOLockUnlock( gJobsLock ); 2471 _workLoopAction( (IOWorkLoop::Action) &actionFinalize, 2472 victim, (void *)(uintptr_t) options ); 2473 IOLockLock( gJobsLock ); 2474 // hold off free 2475 freeList->setObject( victim ); 2476 // safe if finalize list is append only 2477 gIOFinalizeList->removeObject(0); 2478 } 2479 2480 for( idx = 0; 2481 (!doPhase3) && (client = (IOService *) gIOStopList->getObject(idx)); ) { 2482 2483 provider = (IOService *) gIOStopProviderList->getObject(idx); 2484 assert( provider ); 2485 2486 uint64_t regID1 = provider->getRegistryEntryID(); 2487 uint64_t regID2 = client->getRegistryEntryID(); 2488 2489 if( !provider->isChild( client, gIOServicePlane )) { 2490 // may be multiply queued - nop it 2491 TLOG("%s[0x%qx]::nop stop(%s[0x%qx])\n", client->getName(), regID2, provider->getName(), regID1); 2492 IOServiceTrace( 2493 IOSERVICE_TERMINATE_STOP_NOP, 2494 (uintptr_t) regID1, 2495 (uintptr_t) (regID1 >> 32), 2496 (uintptr_t) regID2, 2497 (uintptr_t) (regID2 >> 32)); 2498 2499 } else { 2500 // a terminated client is not ready for stop if it has clients, skip it 2501 if( (kIOServiceInactiveState & client->__state[0]) && client->getClient()) { 2502 TLOG("%s[0x%qx]::defer stop(%s[0x%qx])\n", 2503 client->getName(), regID2, 2504 client->getClient()->getName(), client->getClient()->getRegistryEntryID()); 2505 IOServiceTrace( 2506 IOSERVICE_TERMINATE_STOP_DEFER, 2507 (uintptr_t) regID1, 2508 (uintptr_t) (regID1 >> 32), 2509 (uintptr_t) regID2, 2510 (uintptr_t) (regID2 >> 32)); 2511 2512 idx++; 2513 continue; 2514 } 2515 2516 IOLockUnlock( gJobsLock ); 2517 _workLoopAction( (IOWorkLoop::Action) &actionStop, 2518 provider, (void *) client ); 2519 IOLockLock( gJobsLock ); 2520 // check the finalize list now 2521 doPhase3 = true; 2522 } 2523 // hold off free 2524 freeList->setObject( client ); 2525 freeList->setObject( provider ); 2526 2527 // safe if stop list is append only 2528 gIOStopList->removeObject( idx ); 2529 gIOStopProviderList->removeObject( idx ); 2530 idx = 0; 2531 } 2532 2533 } while( doPhase3 ); 2534 2535 gIOTerminateWork -= workDone; 2536 moreToDo = (gIOTerminateWork != 0); 2537 2538 if( !moreToDo) { 2539 TLOG("iokit terminate done, %d stops remain\n", gIOStopList->getCount()); 2540 IOServiceTrace( 2541 IOSERVICE_TERMINATE_DONE, 2542 (uintptr_t) gIOStopList->getCount(), 0, 0, 0); 2543 } 2544 2545 } while( moreToDo ); 2546 2547 IOLockUnlock( gJobsLock ); 2548 2549 freeList->release(); 2550 doPhase2List->release(); 2551 didPhase2List->release(); 2552 2553 IOLockLock( gJobsLock ); 2554} 2555 2556bool IOService::finalize( IOOptionBits options ) 2557{ 2558 OSIterator * iter; 2559 IOService * provider; 2560 uint64_t regID1, regID2 = getRegistryEntryID(); 2561 2562 iter = getProviderIterator(); 2563 assert( iter ); 2564 2565 if( iter) { 2566 while( (provider = (IOService *) iter->getNextObject())) { 2567 2568 // -- compat 2569 if( 0 == (__state[1] & kIOServiceTermPhase3State)) { 2570 /* we come down here on programmatic terminate */ 2571 2572 regID1 = provider->getRegistryEntryID(); 2573 TLOG("%s[0x%qx]::stop1(%s[0x%qx])\n", getName(), regID2, provider->getName(), regID1); 2574 IOServiceTrace( 2575 IOSERVICE_TERMINATE_STOP, 2576 (uintptr_t) regID1, 2577 (uintptr_t) (regID1 >> 32), 2578 (uintptr_t) regID2, 2579 (uintptr_t) (regID2 >> 32)); 2580 2581 stop( provider ); 2582 if( provider->isOpen( this )) 2583 provider->close( this ); 2584 detach( provider ); 2585 } else { 2586 //-- 2587 if( provider->lockForArbitration( true )) { 2588 if( 0 == (provider->__state[1] & kIOServiceTermPhase3State)) 2589 scheduleStop( provider ); 2590 provider->unlockForArbitration(); 2591 } 2592 } 2593 } 2594 iter->release(); 2595 } 2596 2597 return( true ); 2598} 2599 2600#undef tailQ 2601#undef headQ 2602 2603/* 2604 * Terminate 2605 */ 2606 2607void IOService::doServiceTerminate( IOOptionBits options ) 2608{ 2609} 2610 2611// a method in case someone needs to override it 2612bool IOService::terminateClient( IOService * client, IOOptionBits options ) 2613{ 2614 bool ok; 2615 2616 if( client->isParent( this, gIOServicePlane, true)) 2617 // we are the clients only provider 2618 ok = client->terminate( options ); 2619 else 2620 ok = true; 2621 2622 return( ok ); 2623} 2624 2625bool IOService::terminate( IOOptionBits options ) 2626{ 2627 options |= kIOServiceTerminate; 2628 2629 return( terminatePhase1( options )); 2630} 2631 2632/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 2633 2634/* 2635 * Open & close 2636 */ 2637 2638struct ServiceOpenMessageContext 2639{ 2640 IOService * service; 2641 UInt32 type; 2642 IOService * excludeClient; 2643 IOOptionBits options; 2644}; 2645 2646static void serviceOpenMessageApplier( OSObject * object, void * ctx ) 2647{ 2648 ServiceOpenMessageContext * context = (ServiceOpenMessageContext *) ctx; 2649 2650 if( object != context->excludeClient) 2651 context->service->messageClient( context->type, object, (void *)(uintptr_t) context->options ); 2652} 2653 2654bool IOService::open( IOService * forClient, 2655 IOOptionBits options, 2656 void * arg ) 2657{ 2658 bool ok; 2659 ServiceOpenMessageContext context; 2660 2661 context.service = this; 2662 context.type = kIOMessageServiceIsAttemptingOpen; 2663 context.excludeClient = forClient; 2664 context.options = options; 2665 2666 applyToInterested( gIOGeneralInterest, 2667 &serviceOpenMessageApplier, &context ); 2668 2669 if( false == lockForArbitration(false) ) 2670 return false; 2671 2672 ok = (0 == (__state[0] & kIOServiceInactiveState)); 2673 if( ok) 2674 ok = handleOpen( forClient, options, arg ); 2675 2676 unlockForArbitration(); 2677 2678 return( ok ); 2679} 2680 2681void IOService::close( IOService * forClient, 2682 IOOptionBits options ) 2683{ 2684 bool wasClosed; 2685 bool last = false; 2686 2687 lockForArbitration(); 2688 2689 wasClosed = handleIsOpen( forClient ); 2690 if( wasClosed) { 2691 handleClose( forClient, options ); 2692 last = (__state[1] & kIOServiceTermPhase3State); 2693 } 2694 2695 unlockForArbitration(); 2696 2697 if( last) 2698 forClient->scheduleStop( this ); 2699 2700 else if( wasClosed) { 2701 2702 ServiceOpenMessageContext context; 2703 2704 context.service = this; 2705 context.type = kIOMessageServiceWasClosed; 2706 context.excludeClient = forClient; 2707 context.options = options; 2708 2709 applyToInterested( gIOGeneralInterest, 2710 &serviceOpenMessageApplier, &context ); 2711 } 2712} 2713 2714bool IOService::isOpen( const IOService * forClient ) const 2715{ 2716 IOService * self = (IOService *) this; 2717 bool ok; 2718 2719 self->lockForArbitration(); 2720 2721 ok = handleIsOpen( forClient ); 2722 2723 self->unlockForArbitration(); 2724 2725 return( ok ); 2726} 2727 2728bool IOService::handleOpen( IOService * forClient, 2729 IOOptionBits options, 2730 void * arg ) 2731{ 2732 bool ok; 2733 2734 ok = (0 == __owner); 2735 if( ok ) 2736 __owner = forClient; 2737 2738 else if( options & kIOServiceSeize ) { 2739 ok = (kIOReturnSuccess == messageClient( kIOMessageServiceIsRequestingClose, 2740 __owner, (void *)(uintptr_t) options )); 2741 if( ok && (0 == __owner )) 2742 __owner = forClient; 2743 else 2744 ok = false; 2745 } 2746 return( ok ); 2747} 2748 2749void IOService::handleClose( IOService * forClient, 2750 IOOptionBits options ) 2751{ 2752 if( __owner == forClient) 2753 __owner = 0; 2754} 2755 2756bool IOService::handleIsOpen( const IOService * forClient ) const 2757{ 2758 if( forClient) 2759 return( __owner == forClient ); 2760 else 2761 return( __owner != forClient ); 2762} 2763 2764/* 2765 * Probing & starting 2766 */ 2767static SInt32 IONotifyOrdering( const OSMetaClassBase * inObj1, const OSMetaClassBase * inObj2, void * ref ) 2768{ 2769 const _IOServiceNotifier * obj1 = (const _IOServiceNotifier *) inObj1; 2770 const _IOServiceNotifier * obj2 = (const _IOServiceNotifier *) inObj2; 2771 SInt32 val1; 2772 SInt32 val2; 2773 2774 val1 = 0; 2775 val2 = 0; 2776 2777 if ( obj1 ) 2778 val1 = obj1->priority; 2779 2780 if ( obj2 ) 2781 val2 = obj2->priority; 2782 2783 return ( val1 - val2 ); 2784} 2785 2786static SInt32 IOServiceObjectOrder( const OSObject * entry, void * ref) 2787{ 2788 OSDictionary * dict; 2789 IOService * service; 2790 _IOServiceNotifier * notify; 2791 OSSymbol * key = (OSSymbol *) ref; 2792 OSNumber * offset; 2793 2794 if( (dict = OSDynamicCast( OSDictionary, entry))) 2795 offset = OSDynamicCast(OSNumber, dict->getObject( key )); 2796 else if( (notify = OSDynamicCast( _IOServiceNotifier, entry))) 2797 return( notify->priority ); 2798 2799 else if( (service = OSDynamicCast( IOService, entry))) 2800 offset = OSDynamicCast(OSNumber, service->getProperty( key )); 2801 else { 2802 assert( false ); 2803 offset = 0; 2804 } 2805 2806 if( offset) 2807 return( (SInt32) offset->unsigned32BitValue()); 2808 else 2809 return( kIODefaultProbeScore ); 2810} 2811 2812SInt32 IOServiceOrdering( const OSMetaClassBase * inObj1, const OSMetaClassBase * inObj2, void * ref ) 2813{ 2814 const OSObject * obj1 = (const OSObject *) inObj1; 2815 const OSObject * obj2 = (const OSObject *) inObj2; 2816 SInt32 val1; 2817 SInt32 val2; 2818 2819 val1 = 0; 2820 val2 = 0; 2821 2822 if ( obj1 ) 2823 val1 = IOServiceObjectOrder( obj1, ref ); 2824 2825 if ( obj2 ) 2826 val2 = IOServiceObjectOrder( obj2, ref ); 2827 2828 return ( val1 - val2 ); 2829} 2830 2831IOService * IOService::copyClientWithCategory( const OSSymbol * category ) 2832{ 2833 IOService * service = 0; 2834 OSIterator * iter; 2835 const OSSymbol * nextCat; 2836 2837 iter = getClientIterator(); 2838 if( iter) { 2839 while( (service = (IOService *) iter->getNextObject())) { 2840 if( kIOServiceInactiveState & service->__state[0]) 2841 continue; 2842 nextCat = (const OSSymbol *) OSDynamicCast( OSSymbol, 2843 service->getProperty( gIOMatchCategoryKey )); 2844 if( category == nextCat) 2845 { 2846 service->retain(); 2847 break; 2848 } 2849 } 2850 iter->release(); 2851 } 2852 return( service ); 2853} 2854 2855IOService * IOService::getClientWithCategory( const OSSymbol * category ) 2856{ 2857 IOService * 2858 service = copyClientWithCategory(category); 2859 if (service) 2860 service->release(); 2861 return (service); 2862} 2863 2864bool IOService::invokeNotifer( _IOServiceNotifier * notify ) 2865{ 2866 _IOServiceNotifierInvocation invocation; 2867 bool willNotify; 2868 bool ret = true; 2869 2870 invocation.thread = current_thread(); 2871 2872 LOCKWRITENOTIFY(); 2873 willNotify = (0 != (kIOServiceNotifyEnable & notify->state)); 2874 2875 if( willNotify) { 2876 queue_enter( ¬ify->handlerInvocations, &invocation, 2877 _IOServiceNotifierInvocation *, link ); 2878 } 2879 UNLOCKNOTIFY(); 2880 2881 if( willNotify) { 2882 2883 ret = (*notify->handler)(notify->target, notify->ref, this, notify); 2884 2885 LOCKWRITENOTIFY(); 2886 queue_remove( ¬ify->handlerInvocations, &invocation, 2887 _IOServiceNotifierInvocation *, link ); 2888 if( kIOServiceNotifyWaiter & notify->state) { 2889 notify->state &= ~kIOServiceNotifyWaiter; 2890 WAKEUPNOTIFY( notify ); 2891 } 2892 UNLOCKNOTIFY(); 2893 } 2894 2895 return( ret ); 2896} 2897 2898/* 2899 * Alloc and probe matching classes, 2900 * called on the provider instance 2901 */ 2902 2903void IOService::probeCandidates( OSOrderedSet * matches ) 2904{ 2905 OSDictionary * match = 0; 2906 OSSymbol * symbol; 2907 IOService * inst; 2908 IOService * newInst; 2909 OSDictionary * props; 2910 SInt32 score; 2911 OSNumber * newPri; 2912 OSOrderedSet * familyMatches = 0; 2913 OSOrderedSet * startList; 2914 OSDictionary * startDict = 0; 2915 const OSSymbol * category; 2916 OSIterator * iter; 2917 _IOServiceNotifier * notify; 2918 OSObject * nextMatch = 0; 2919 bool started; 2920 bool needReloc = false; 2921#if IOMATCHDEBUG 2922 SInt64 debugFlags; 2923#endif 2924 IOService * client = NULL; 2925 2926 2927 assert( matches ); 2928 while( !needReloc && (nextMatch = matches->getFirstObject())) { 2929 2930 nextMatch->retain(); 2931 matches->removeObject(nextMatch); 2932 2933 if( (notify = OSDynamicCast( _IOServiceNotifier, nextMatch ))) { 2934 2935 lockForArbitration(); 2936 if( 0 == (__state[0] & kIOServiceInactiveState)) 2937 invokeNotifer( notify ); 2938 unlockForArbitration(); 2939 nextMatch->release(); 2940 nextMatch = 0; 2941 continue; 2942 2943 } else if( !(match = OSDynamicCast( OSDictionary, nextMatch ))) { 2944 nextMatch->release(); 2945 nextMatch = 0; 2946 continue; 2947 } 2948 2949 props = 0; 2950#if IOMATCHDEBUG 2951 debugFlags = getDebugFlags( match ); 2952#endif 2953 2954 do { 2955 category = OSDynamicCast( OSSymbol, 2956 match->getObject( gIOMatchCategoryKey )); 2957 if( 0 == category) 2958 category = gIODefaultMatchCategoryKey; 2959 2960 if( (client = copyClientWithCategory(category)) ) { 2961#if IOMATCHDEBUG 2962 if( (debugFlags & kIOLogMatch) && (this != gIOResources)) 2963 LOG("%s: match category %s exists\n", getName(), 2964 category->getCStringNoCopy()); 2965#endif 2966 nextMatch->release(); 2967 nextMatch = 0; 2968 2969 client->release(); 2970 client = NULL; 2971 2972 continue; 2973 } 2974 2975 // create a copy now in case its modified during matching 2976 props = OSDictionary::withDictionary( match, match->getCount()); 2977 if( 0 == props) 2978 continue; 2979 props->setCapacityIncrement(1); 2980 2981 // check the nub matches 2982 if( false == matchPassive(props, kIOServiceChangesOK | kIOServiceClassDone)) 2983 continue; 2984 2985 // Check to see if driver reloc has been loaded. 2986 needReloc = (false == gIOCatalogue->isModuleLoaded( match )); 2987 if( needReloc) { 2988#if IOMATCHDEBUG 2989 if( debugFlags & kIOLogCatalogue) 2990 LOG("%s: stalling for module\n", getName()); 2991#endif 2992 // If reloc hasn't been loaded, exit; 2993 // reprobing will occur after reloc has been loaded. 2994 continue; 2995 } 2996 2997 // reorder on family matchPropertyTable score. 2998 if( 0 == familyMatches) 2999 familyMatches = OSOrderedSet::withCapacity( 1, 3000 IOServiceOrdering, (void *) gIOProbeScoreKey ); 3001 if( familyMatches) 3002 familyMatches->setObject( props ); 3003 3004 } while( false ); 3005 3006 if (nextMatch) { 3007 nextMatch->release(); 3008 nextMatch = 0; 3009 } 3010 if( props) 3011 props->release(); 3012 } 3013 matches->release(); 3014 matches = 0; 3015 3016 if( familyMatches) { 3017 3018 while( !needReloc 3019 && (props = (OSDictionary *) familyMatches->getFirstObject())) { 3020 3021 props->retain(); 3022 familyMatches->removeObject( props ); 3023 3024 inst = 0; 3025 newInst = 0; 3026#if IOMATCHDEBUG 3027 debugFlags = getDebugFlags( props ); 3028#endif 3029 do { 3030 symbol = OSDynamicCast( OSSymbol, 3031 props->getObject( gIOClassKey)); 3032 if( !symbol) 3033 continue; 3034 3035 //IOLog("%s alloc (symbol %p props %p)\n", symbol->getCStringNoCopy(), OBFUSCATE(symbol), OBFUSCATE(props)); 3036 3037 // alloc the driver instance 3038 inst = (IOService *) OSMetaClass::allocClassWithName( symbol); 3039 3040 if( !inst) { 3041 IOLog("Couldn't alloc class \"%s\"\n", 3042 symbol->getCStringNoCopy()); 3043 continue; 3044 } 3045 3046 // init driver instance 3047 if( !(inst->init( props ))) { 3048#if IOMATCHDEBUG 3049 if( debugFlags & kIOLogStart) 3050 IOLog("%s::init fails\n", symbol->getCStringNoCopy()); 3051#endif 3052 continue; 3053 } 3054 if( __state[1] & kIOServiceSynchronousState) 3055 inst->__state[1] |= kIOServiceSynchronousState; 3056 3057 // give the driver the default match category if not specified 3058 category = OSDynamicCast( OSSymbol, 3059 props->getObject( gIOMatchCategoryKey )); 3060 if( 0 == category) 3061 category = gIODefaultMatchCategoryKey; 3062 inst->setProperty( gIOMatchCategoryKey, (OSObject *) category ); 3063 // attach driver instance 3064 if( !(inst->attach( this ))) 3065 continue; 3066 3067 // pass in score from property table 3068 score = familyMatches->orderObject( props ); 3069 3070 // & probe the new driver instance 3071#if IOMATCHDEBUG 3072 if( debugFlags & kIOLogProbe) 3073 LOG("%s::probe(%s)\n", 3074 inst->getMetaClass()->getClassName(), getName()); 3075#endif 3076 3077 newInst = inst->probe( this, &score ); 3078 inst->detach( this ); 3079 if( 0 == newInst) { 3080#if IOMATCHDEBUG 3081 if( debugFlags & kIOLogProbe) 3082 IOLog("%s::probe fails\n", symbol->getCStringNoCopy()); 3083#endif 3084 continue; 3085 } 3086 3087 // save the score 3088 newPri = OSNumber::withNumber( score, 32 ); 3089 if( newPri) { 3090 newInst->setProperty( gIOProbeScoreKey, newPri ); 3091 newPri->release(); 3092 } 3093 3094 // add to start list for the match category 3095 if( 0 == startDict) 3096 startDict = OSDictionary::withCapacity( 1 ); 3097 assert( startDict ); 3098 startList = (OSOrderedSet *) 3099 startDict->getObject( category ); 3100 if( 0 == startList) { 3101 startList = OSOrderedSet::withCapacity( 1, 3102 IOServiceOrdering, (void *) gIOProbeScoreKey ); 3103 if( startDict && startList) { 3104 startDict->setObject( category, startList ); 3105 startList->release(); 3106 } 3107 } 3108 assert( startList ); 3109 if( startList) 3110 startList->setObject( newInst ); 3111 3112 } while( false ); 3113 3114 props->release(); 3115 if( inst) 3116 inst->release(); 3117 } 3118 familyMatches->release(); 3119 familyMatches = 0; 3120 } 3121 3122 // start the best (until success) of each category 3123 3124 iter = OSCollectionIterator::withCollection( startDict ); 3125 if( iter) { 3126 while( (category = (const OSSymbol *) iter->getNextObject())) { 3127 3128 startList = (OSOrderedSet *) startDict->getObject( category ); 3129 assert( startList ); 3130 if( !startList) 3131 continue; 3132 3133 started = false; 3134 while( true // (!started) 3135 && (inst = (IOService *)startList->getFirstObject())) { 3136 3137 inst->retain(); 3138 startList->removeObject(inst); 3139 3140#if IOMATCHDEBUG 3141 debugFlags = getDebugFlags( inst->getPropertyTable() ); 3142 3143 if( debugFlags & kIOLogStart) { 3144 if( started) 3145 LOG( "match category exists, skipping " ); 3146 LOG( "%s::start(%s) <%d>\n", inst->getName(), 3147 getName(), inst->getRetainCount()); 3148 } 3149#endif 3150 if( false == started) 3151 started = startCandidate( inst ); 3152#if IOMATCHDEBUG 3153 if( (debugFlags & kIOLogStart) && (false == started)) 3154 LOG( "%s::start(%s) <%d> failed\n", inst->getName(), getName(), 3155 inst->getRetainCount()); 3156#endif 3157 inst->release(); 3158 } 3159 } 3160 iter->release(); 3161 } 3162 3163 3164 // adjust the busy count by +1 if matching is stalled for a module, 3165 // or -1 if a previously stalled matching is complete. 3166 lockForArbitration(); 3167 SInt32 adjBusy = 0; 3168 uint64_t regID = getRegistryEntryID(); 3169 3170 if( needReloc) { 3171 adjBusy = (__state[1] & kIOServiceModuleStallState) ? 0 : 1; 3172 if( adjBusy) { 3173 3174 IOServiceTrace( 3175 IOSERVICE_MODULESTALL, 3176 (uintptr_t) regID, 3177 (uintptr_t) (regID >> 32), 3178 (uintptr_t) this, 3179 0); 3180 3181 __state[1] |= kIOServiceModuleStallState; 3182 } 3183 3184 } else if( __state[1] & kIOServiceModuleStallState) { 3185 3186 IOServiceTrace( 3187 IOSERVICE_MODULEUNSTALL, 3188 (uintptr_t) regID, 3189 (uintptr_t) (regID >> 32), 3190 (uintptr_t) this, 3191 0); 3192 3193 __state[1] &= ~kIOServiceModuleStallState; 3194 adjBusy = -1; 3195 } 3196 if( adjBusy) 3197 _adjustBusy( adjBusy ); 3198 unlockForArbitration(); 3199 3200 if( startDict) 3201 startDict->release(); 3202} 3203 3204/* 3205 * Start a previously attached & probed instance, 3206 * called on exporting object instance 3207 */ 3208 3209bool IOService::startCandidate( IOService * service ) 3210{ 3211 bool ok; 3212 3213 ok = service->attach( this ); 3214 3215 if( ok) 3216 { 3217 if (this != gIOResources) 3218 { 3219 // stall for any nub resources 3220 checkResources(); 3221 // stall for any driver resources 3222 service->checkResources(); 3223 } 3224 3225 AbsoluteTime startTime; 3226 AbsoluteTime endTime; 3227 UInt64 nano; 3228 3229 if (kIOLogStart & gIOKitDebug) 3230 clock_get_uptime(&startTime); 3231 3232 ok = service->start(this); 3233 3234 if (kIOLogStart & gIOKitDebug) 3235 { 3236 clock_get_uptime(&endTime); 3237 3238 if (CMP_ABSOLUTETIME(&endTime, &startTime) > 0) 3239 { 3240 SUB_ABSOLUTETIME(&endTime, &startTime); 3241 absolutetime_to_nanoseconds(endTime, &nano); 3242 if (nano > 500000000ULL) 3243 IOLog("%s::start took %ld ms\n", service->getName(), (long)(UInt32)(nano / 1000000ULL)); 3244 } 3245 } 3246 if( !ok) 3247 service->detach( this ); 3248 } 3249 return( ok ); 3250} 3251 3252void IOService::publishResource( const char * key, OSObject * value ) 3253{ 3254 const OSSymbol * sym; 3255 3256 if( (sym = OSSymbol::withCString( key))) { 3257 publishResource( sym, value); 3258 sym->release(); 3259 } 3260} 3261 3262void IOService::publishResource( const OSSymbol * key, OSObject * value ) 3263{ 3264 if( 0 == value) 3265 value = (OSObject *) gIOServiceKey; 3266 3267 gIOResources->setProperty( key, value); 3268 3269 if( IORecursiveLockHaveLock( gNotificationLock)) 3270 return; 3271 3272 gIOResourceGenerationCount++; 3273 gIOResources->registerService(); 3274} 3275 3276bool IOService::addNeededResource( const char * key ) 3277{ 3278 OSObject * resourcesProp; 3279 OSSet * set; 3280 OSString * newKey; 3281 bool ret; 3282 3283 resourcesProp = getProperty( gIOResourceMatchKey ); 3284 3285 newKey = OSString::withCString( key ); 3286 if( (0 == resourcesProp) || (0 == newKey)) 3287 return( false); 3288 3289 set = OSDynamicCast( OSSet, resourcesProp ); 3290 if( !set) { 3291 set = OSSet::withCapacity( 1 ); 3292 if( set) 3293 set->setObject( resourcesProp ); 3294 } 3295 else 3296 set->retain(); 3297 3298 set->setObject( newKey ); 3299 newKey->release(); 3300 ret = setProperty( gIOResourceMatchKey, set ); 3301 set->release(); 3302 3303 return( ret ); 3304} 3305 3306bool IOService::checkResource( OSObject * matching ) 3307{ 3308 OSString * str; 3309 OSDictionary * table; 3310 3311 if( (str = OSDynamicCast( OSString, matching ))) { 3312 if( gIOResources->getProperty( str )) 3313 return( true ); 3314 } 3315 3316 if( str) 3317 table = resourceMatching( str ); 3318 else if( (table = OSDynamicCast( OSDictionary, matching ))) 3319 table->retain(); 3320 else { 3321 IOLog("%s: Can't match using: %s\n", getName(), 3322 matching->getMetaClass()->getClassName()); 3323 /* false would stall forever */ 3324 return( true ); 3325 } 3326 3327 if( gIOKitDebug & kIOLogConfig) 3328 LOG("config(%p): stalling %s\n", OBFUSCATE(IOThreadSelf()), getName()); 3329 3330 waitForService( table ); 3331 3332 if( gIOKitDebug & kIOLogConfig) 3333 LOG("config(%p): waking\n", OBFUSCATE(IOThreadSelf()) ); 3334 3335 return( true ); 3336} 3337 3338bool IOService::checkResources( void ) 3339{ 3340 OSObject * resourcesProp; 3341 OSSet * set; 3342 OSIterator * iter; 3343 bool ok; 3344 3345 resourcesProp = getProperty( gIOResourceMatchKey ); 3346 if( 0 == resourcesProp) 3347 return( true ); 3348 3349 if( (set = OSDynamicCast( OSSet, resourcesProp ))) { 3350 3351 iter = OSCollectionIterator::withCollection( set ); 3352 ok = (0 != iter); 3353 while( ok && (resourcesProp = iter->getNextObject()) ) 3354 ok = checkResource( resourcesProp ); 3355 if( iter) 3356 iter->release(); 3357 3358 } else 3359 ok = checkResource( resourcesProp ); 3360 3361 return( ok ); 3362} 3363 3364 3365void _IOConfigThread::configThread( void ) 3366{ 3367 _IOConfigThread * inst; 3368 3369 do { 3370 if( !(inst = new _IOConfigThread)) 3371 continue; 3372 if( !inst->init()) 3373 continue; 3374 thread_t unused; 3375 if (KERN_SUCCESS != kernel_thread_start(&_IOConfigThread::main, inst, &unused)) 3376 continue; 3377 3378 return; 3379 3380 } while( false); 3381 3382 if( inst) 3383 inst->release(); 3384 3385 return; 3386} 3387 3388void _IOConfigThread::free( void ) 3389{ 3390 thread_deallocate(current_thread()); 3391 OSObject::free(); 3392} 3393 3394void IOService::doServiceMatch( IOOptionBits options ) 3395{ 3396 _IOServiceNotifier * notify; 3397 OSIterator * iter; 3398 OSOrderedSet * matches; 3399 SInt32 catalogGeneration; 3400 bool keepGuessing = true; 3401 bool reRegistered = true; 3402 bool didRegister; 3403 3404// job->nub->deliverNotification( gIOPublishNotification, 3405// kIOServiceRegisteredState, 0xffffffff ); 3406 3407 while( keepGuessing ) { 3408 3409 matches = gIOCatalogue->findDrivers( this, &catalogGeneration ); 3410 // the matches list should always be created by findDrivers() 3411 if( matches) { 3412 3413 lockForArbitration(); 3414 if( 0 == (__state[0] & kIOServiceFirstPublishState)) { 3415 getMetaClass()->addInstance(this); 3416 deliverNotification( gIOFirstPublishNotification, 3417 kIOServiceFirstPublishState, 0xffffffff ); 3418 } 3419 LOCKREADNOTIFY(); 3420 __state[1] &= ~kIOServiceNeedConfigState; 3421 __state[1] |= kIOServiceConfigState; 3422 didRegister = (0 == (kIOServiceRegisteredState & __state[0])); 3423 __state[0] |= kIOServiceRegisteredState; 3424 3425 keepGuessing &= (0 == (__state[0] & kIOServiceInactiveState)); 3426 if (reRegistered && keepGuessing) { 3427 iter = OSCollectionIterator::withCollection( (OSOrderedSet *) 3428 gNotifications->getObject( gIOPublishNotification ) ); 3429 if( iter) { 3430 while((notify = (_IOServiceNotifier *) 3431 iter->getNextObject())) { 3432 3433 if( matchPassive(notify->matching, 0) 3434 && (kIOServiceNotifyEnable & notify->state)) 3435 matches->setObject( notify ); 3436 } 3437 iter->release(); 3438 } 3439 } 3440 3441 UNLOCKNOTIFY(); 3442 unlockForArbitration(); 3443 3444 if (keepGuessing && matches->getCount() && (kIOReturnSuccess == getResources())) 3445 probeCandidates( matches ); 3446 else 3447 matches->release(); 3448 } 3449 3450 lockForArbitration(); 3451 reRegistered = (0 != (__state[1] & kIOServiceNeedConfigState)); 3452 keepGuessing = 3453 (reRegistered || (catalogGeneration != 3454 gIOCatalogue->getGenerationCount())) 3455 && (0 == (__state[0] & kIOServiceInactiveState)); 3456 3457 if( keepGuessing) 3458 unlockForArbitration(); 3459 } 3460 3461 if( (0 == (__state[0] & kIOServiceInactiveState)) 3462 && (0 == (__state[1] & kIOServiceModuleStallState)) ) { 3463 deliverNotification( gIOMatchedNotification, 3464 kIOServiceMatchedState, 0xffffffff ); 3465 if( 0 == (__state[0] & kIOServiceFirstMatchState)) 3466 deliverNotification( gIOFirstMatchNotification, 3467 kIOServiceFirstMatchState, 0xffffffff ); 3468 } 3469 3470 __state[1] &= ~kIOServiceConfigState; 3471 scheduleTerminatePhase2(); 3472 3473 _adjustBusy( -1 ); 3474 unlockForArbitration(); 3475} 3476 3477UInt32 IOService::_adjustBusy( SInt32 delta ) 3478{ 3479 IOService * next; 3480 UInt32 count; 3481 UInt32 result; 3482 bool wasQuiet, nowQuiet, needWake; 3483 3484 next = this; 3485 result = __state[1] & kIOServiceBusyStateMask; 3486 3487 if( delta) do { 3488 if( next != this) 3489 next->lockForArbitration(); 3490 count = next->__state[1] & kIOServiceBusyStateMask; 3491 wasQuiet = (0 == count); 3492 if (((delta < 0) && wasQuiet) || ((delta > 0) && (kIOServiceBusyMax == count))) 3493 OSReportWithBacktrace("%s: bad busy count (%d,%d)\n", next->getName(), count, delta); 3494 else 3495 count += delta; 3496 next->__state[1] = (next->__state[1] & ~kIOServiceBusyStateMask) | count; 3497 nowQuiet = (0 == count); 3498 needWake = (0 != (kIOServiceBusyWaiterState & next->__state[1])); 3499 3500 if( needWake) { 3501 next->__state[1] &= ~kIOServiceBusyWaiterState; 3502 IOLockLock( gIOServiceBusyLock ); 3503 thread_wakeup( (event_t) next); 3504 IOLockUnlock( gIOServiceBusyLock ); 3505 } 3506 if( next != this) 3507 next->unlockForArbitration(); 3508 3509 if( (wasQuiet || nowQuiet) ) { 3510 uint64_t regID = next->getRegistryEntryID(); 3511 3512 IOServiceTrace( 3513 ((wasQuiet/*nowBusy*/) ? IOSERVICE_BUSY : IOSERVICE_NONBUSY), 3514 (uintptr_t) regID, 3515 (uintptr_t) (regID >> 32), 3516 (uintptr_t) next, 3517 0); 3518 3519 if (wasQuiet) 3520 { 3521 next->__timeBusy = mach_absolute_time(); 3522 } 3523 else 3524 { 3525 next->__accumBusy += mach_absolute_time() - next->__timeBusy; 3526 next->__timeBusy = 0; 3527 } 3528 3529 MessageClientsContext context; 3530 3531 context.service = next; 3532 context.type = kIOMessageServiceBusyStateChange; 3533 context.argument = (void *) wasQuiet; /*nowBusy*/ 3534 context.argSize = 0; 3535 3536 applyToInterestNotifiers( next, gIOBusyInterest, 3537 &messageClientsApplier, &context ); 3538 3539#if !NO_KEXTD 3540 if( nowQuiet && (next == gIOServiceRoot)) { 3541 OSKext::considerUnloads(); 3542 IOServiceTrace(IOSERVICE_REGISTRY_QUIET, 0, 0, 0, 0); 3543 } 3544#endif 3545 } 3546 3547 delta = nowQuiet ? -1 : +1; 3548 3549 } while( (wasQuiet || nowQuiet) && (next = next->getProvider())); 3550 3551 return( result ); 3552} 3553 3554void IOService::adjustBusy( SInt32 delta ) 3555{ 3556 lockForArbitration(); 3557 _adjustBusy( delta ); 3558 unlockForArbitration(); 3559} 3560 3561uint64_t IOService::getAccumulatedBusyTime( void ) 3562{ 3563 uint64_t accumBusy = __accumBusy; 3564 uint64_t timeBusy = __timeBusy; 3565 uint64_t nano; 3566 3567 do 3568 { 3569 accumBusy = __accumBusy; 3570 timeBusy = __timeBusy; 3571 if (timeBusy) 3572 accumBusy += mach_absolute_time() - timeBusy; 3573 } 3574 while (timeBusy != __timeBusy); 3575 3576 absolutetime_to_nanoseconds(*(AbsoluteTime *)&accumBusy, &nano); 3577 3578 return (nano); 3579} 3580 3581UInt32 IOService::getBusyState( void ) 3582{ 3583 return( __state[1] & kIOServiceBusyStateMask ); 3584} 3585 3586IOReturn IOService::waitForState( UInt32 mask, UInt32 value, 3587 mach_timespec_t * timeout ) 3588{ 3589 panic("waitForState"); 3590 return (kIOReturnUnsupported); 3591} 3592 3593IOReturn IOService::waitForState( UInt32 mask, UInt32 value, 3594 uint64_t timeout ) 3595{ 3596 bool wait; 3597 int waitResult = THREAD_AWAKENED; 3598 bool computeDeadline = true; 3599 AbsoluteTime abstime; 3600 3601 do { 3602 lockForArbitration(); 3603 IOLockLock( gIOServiceBusyLock ); 3604 wait = (value != (__state[1] & mask)); 3605 if( wait) { 3606 __state[1] |= kIOServiceBusyWaiterState; 3607 unlockForArbitration(); 3608 if( timeout != UINT64_MAX ) { 3609 if( computeDeadline ) { 3610 AbsoluteTime nsinterval; 3611 nanoseconds_to_absolutetime(timeout, &nsinterval ); 3612 clock_absolutetime_interval_to_deadline(nsinterval, &abstime); 3613 computeDeadline = false; 3614 } 3615 assert_wait_deadline((event_t)this, THREAD_UNINT, __OSAbsoluteTime(abstime)); 3616 } 3617 else 3618 assert_wait((event_t)this, THREAD_UNINT ); 3619 } else 3620 unlockForArbitration(); 3621 IOLockUnlock( gIOServiceBusyLock ); 3622 if( wait) 3623 waitResult = thread_block(THREAD_CONTINUE_NULL); 3624 3625 } while( wait && (waitResult != THREAD_TIMED_OUT)); 3626 3627 if( waitResult == THREAD_TIMED_OUT) 3628 return( kIOReturnTimeout ); 3629 else 3630 return( kIOReturnSuccess ); 3631} 3632 3633IOReturn IOService::waitQuiet( uint64_t timeout ) 3634{ 3635 IOReturn ret; 3636 ret = waitForState( kIOServiceBusyStateMask, 0, timeout ); 3637 if ((kIOReturnTimeout == ret) && (timeout >= 30000000000) && (kIOWaitQuietPanics & gIOKitDebug)) 3638 { 3639 panic("IOService 0x%llx (%s) busy timeout", getRegistryEntryID(), getName()); 3640 } 3641 return (ret); 3642} 3643 3644IOReturn IOService::waitQuiet( mach_timespec_t * timeout ) 3645{ 3646 uint64_t timeoutNS; 3647 3648 if (timeout) 3649 { 3650 timeoutNS = timeout->tv_sec; 3651 timeoutNS *= kSecondScale; 3652 timeoutNS += timeout->tv_nsec; 3653 } 3654 else 3655 timeoutNS = UINT64_MAX; 3656 3657 return (waitQuiet(timeoutNS)); 3658} 3659 3660bool IOService::serializeProperties( OSSerialize * s ) const 3661{ 3662#if 0 3663 ((IOService *)this)->setProperty( ((IOService *)this)->__state, 3664 sizeof( __state), "__state"); 3665#endif 3666 return( super::serializeProperties(s) ); 3667} 3668 3669 3670void _IOConfigThread::main(void * arg, wait_result_t result) 3671{ 3672 _IOConfigThread * self = (_IOConfigThread *) arg; 3673 _IOServiceJob * job; 3674 IOService * nub; 3675 bool alive = true; 3676 kern_return_t kr; 3677 thread_precedence_policy_data_t precedence = { -1 }; 3678 3679 kr = thread_policy_set(current_thread(), 3680 THREAD_PRECEDENCE_POLICY, 3681 (thread_policy_t) &precedence, 3682 THREAD_PRECEDENCE_POLICY_COUNT); 3683 if (KERN_SUCCESS != kr) 3684 IOLog("thread_policy_set(%d)\n", kr); 3685 3686 do { 3687 3688// randomDelay(); 3689 3690 semaphore_wait( gJobsSemaphore ); 3691 3692 IOTakeLock( gJobsLock ); 3693 job = (_IOServiceJob *) gJobs->getFirstObject(); 3694 job->retain(); 3695 gJobs->removeObject(job); 3696 if( job) { 3697 gOutstandingJobs--; 3698// gNumConfigThreads--; // we're out of service 3699 gNumWaitingThreads--; // we're out of service 3700 } 3701 IOUnlock( gJobsLock ); 3702 3703 if( job) { 3704 3705 nub = job->nub; 3706 3707 if( gIOKitDebug & kIOLogConfig) 3708 LOG("config(%p): starting on %s, %d\n", 3709 OBFUSCATE(IOThreadSelf()), job->nub->getName(), job->type); 3710 3711 switch( job->type) { 3712 3713 case kMatchNubJob: 3714 nub->doServiceMatch( job->options ); 3715 break; 3716 3717 default: 3718 LOG("config(%p): strange type (%d)\n", 3719 OBFUSCATE(IOThreadSelf()), job->type ); 3720 break; 3721 } 3722 3723 nub->release(); 3724 job->release(); 3725 3726 IOTakeLock( gJobsLock ); 3727 alive = (gOutstandingJobs > gNumWaitingThreads); 3728 if( alive) 3729 gNumWaitingThreads++; // back in service 3730// gNumConfigThreads++; 3731 else { 3732 if( 0 == --gNumConfigThreads) { 3733// IOLog("MATCH IDLE\n"); 3734 IOLockWakeup( gJobsLock, (event_t) &gNumConfigThreads, /* one-thread */ false ); 3735 } 3736 } 3737 IOUnlock( gJobsLock ); 3738 } 3739 3740 } while( alive ); 3741 3742 if( gIOKitDebug & kIOLogConfig) 3743 LOG("config(%p): terminating\n", OBFUSCATE(IOThreadSelf()) ); 3744 3745 self->release(); 3746} 3747 3748IOReturn IOService::waitMatchIdle( UInt32 msToWait ) 3749{ 3750 bool wait; 3751 int waitResult = THREAD_AWAKENED; 3752 bool computeDeadline = true; 3753 AbsoluteTime deadline; 3754 3755 IOLockLock( gJobsLock ); 3756 do { 3757 wait = (0 != gNumConfigThreads); 3758 if( wait) { 3759 if( msToWait) { 3760 if( computeDeadline ) { 3761 clock_interval_to_deadline( 3762 msToWait, kMillisecondScale, &deadline ); 3763 computeDeadline = false; 3764 } 3765 waitResult = IOLockSleepDeadline( gJobsLock, &gNumConfigThreads, 3766 deadline, THREAD_UNINT ); 3767 } else { 3768 waitResult = IOLockSleep( gJobsLock, &gNumConfigThreads, 3769 THREAD_UNINT ); 3770 } 3771 } 3772 } while( wait && (waitResult != THREAD_TIMED_OUT)); 3773 IOLockUnlock( gJobsLock ); 3774 3775 if( waitResult == THREAD_TIMED_OUT) 3776 return( kIOReturnTimeout ); 3777 else 3778 return( kIOReturnSuccess ); 3779} 3780 3781void _IOServiceJob::pingConfig( _IOServiceJob * job ) 3782{ 3783 int count; 3784 bool create; 3785 3786 assert( job ); 3787 3788 IOTakeLock( gJobsLock ); 3789 3790 gOutstandingJobs++; 3791 gJobs->setLastObject( job ); 3792 3793 count = gNumWaitingThreads; 3794// if( gNumConfigThreads) count++;// assume we're called from a config thread 3795 3796 create = ( (gOutstandingJobs > count) 3797 && (gNumConfigThreads < kMaxConfigThreads) ); 3798 if( create) { 3799 gNumConfigThreads++; 3800 gNumWaitingThreads++; 3801 } 3802 3803 IOUnlock( gJobsLock ); 3804 3805 job->release(); 3806 3807 if( create) { 3808 if( gIOKitDebug & kIOLogConfig) 3809 LOG("config(%d): creating\n", gNumConfigThreads - 1); 3810 _IOConfigThread::configThread(); 3811 } 3812 3813 semaphore_signal( gJobsSemaphore ); 3814} 3815 3816struct IOServiceMatchContext 3817{ 3818 OSDictionary * table; 3819 OSObject * result; 3820 uint32_t options; 3821 uint32_t state; 3822 uint32_t count; 3823 uint32_t done; 3824}; 3825 3826bool IOService::instanceMatch(const OSObject * entry, void * context) 3827{ 3828 IOServiceMatchContext * ctx = (typeof(ctx)) context; 3829 IOService * service = (typeof(service)) entry; 3830 OSDictionary * table = ctx->table; 3831 uint32_t options = ctx->options; 3832 uint32_t state = ctx->state; 3833 uint32_t done; 3834 bool match; 3835 3836 done = 0; 3837 do 3838 { 3839 match = ((state == (state & service->__state[0])) 3840 && (0 == (service->__state[0] & kIOServiceInactiveState))); 3841 if (!match) break; 3842 ctx->count += table->getCount(); 3843 match = service->matchInternal(table, options, &done); 3844 ctx->done += done; 3845 } 3846 while (false); 3847 if (!match) 3848 return (false); 3849 3850 if ((kIONotifyOnce & options) && (ctx->done == ctx->count)) 3851 { 3852 service->retain(); 3853 ctx->result = service; 3854 return (true); 3855 } 3856 else if (!ctx->result) 3857 { 3858 ctx->result = OSSet::withObjects((const OSObject **) &service, 1, 1); 3859 } 3860 else 3861 { 3862 ((OSSet *)ctx->result)->setObject(service); 3863 } 3864 return (false); 3865} 3866 3867// internal - call with gNotificationLock 3868OSObject * IOService::copyExistingServices( OSDictionary * matching, 3869 IOOptionBits inState, IOOptionBits options ) 3870{ 3871 OSObject * current = 0; 3872 OSIterator * iter; 3873 IOService * service; 3874 OSObject * obj; 3875 OSString * str; 3876 3877 if( !matching) 3878 return( 0 ); 3879 3880#if MATCH_DEBUG 3881 OSSerialize * s = OSSerialize::withCapacity(128); 3882 matching->serialize(s); 3883#endif 3884 3885 if((obj = matching->getObject(gIOProviderClassKey)) 3886 && gIOResourcesKey 3887 && gIOResourcesKey->isEqualTo(obj) 3888 && (service = gIOResources)) 3889 { 3890 if( (inState == (service->__state[0] & inState)) 3891 && (0 == (service->__state[0] & kIOServiceInactiveState)) 3892 && service->matchPassive(matching, options)) 3893 { 3894 if( options & kIONotifyOnce) 3895 { 3896 service->retain(); 3897 current = service; 3898 } 3899 else 3900 current = OSSet::withObjects((const OSObject **) &service, 1, 1 ); 3901 } 3902 } 3903 else 3904 { 3905 IOServiceMatchContext ctx; 3906 ctx.table = matching; 3907 ctx.state = inState; 3908 ctx.count = 0; 3909 ctx.done = 0; 3910 ctx.options = options; 3911 ctx.result = 0; 3912 3913 if ((str = OSDynamicCast(OSString, obj))) 3914 { 3915 const OSSymbol * sym = OSSymbol::withString(str); 3916 OSMetaClass::applyToInstancesOfClassName(sym, instanceMatch, &ctx); 3917 sym->release(); 3918 } 3919 else 3920 { 3921 IOService::gMetaClass.applyToInstances(instanceMatch, &ctx); 3922 } 3923 3924 3925 current = ctx.result; 3926 3927 options |= kIOServiceInternalDone | kIOServiceClassDone; 3928 if (current && (ctx.done != ctx.count)) 3929 { 3930 OSSet * 3931 source = OSDynamicCast(OSSet, current); 3932 current = 0; 3933 while ((service = (IOService *) source->getAnyObject())) 3934 { 3935 if (service->matchPassive(matching, options)) 3936 { 3937 if( options & kIONotifyOnce) 3938 { 3939 service->retain(); 3940 current = service; 3941 break; 3942 } 3943 if( current) 3944 { 3945 ((OSSet *)current)->setObject( service ); 3946 } 3947 else 3948 { 3949 current = OSSet::withObjects( 3950 (const OSObject **) &service, 1, 1 ); 3951 } 3952 } 3953 source->removeObject(service); 3954 } 3955 source->release(); 3956 } 3957 } 3958 3959#if MATCH_DEBUG 3960 { 3961 OSObject * _current = 0; 3962 3963 iter = IORegistryIterator::iterateOver( gIOServicePlane, 3964 kIORegistryIterateRecursively ); 3965 if( iter) { 3966 do { 3967 iter->reset(); 3968 while( (service = (IOService *) iter->getNextObject())) { 3969 if( (inState == (service->__state[0] & inState)) 3970 && (0 == (service->__state[0] & kIOServiceInactiveState)) 3971 && service->matchPassive(matching, 0)) { 3972 3973 if( options & kIONotifyOnce) { 3974 service->retain(); 3975 _current = service; 3976 break; 3977 } 3978 if( _current) 3979 ((OSSet *)_current)->setObject( service ); 3980 else 3981 _current = OSSet::withObjects( 3982 (const OSObject **) &service, 1, 1 ); 3983 } 3984 } 3985 } while( !service && !iter->isValid()); 3986 iter->release(); 3987 } 3988 3989 3990 if ( ((current != 0) != (_current != 0)) 3991 || (current && _current && !current->isEqualTo(_current))) 3992 { 3993 OSSerialize * s1 = OSSerialize::withCapacity(128); 3994 OSSerialize * s2 = OSSerialize::withCapacity(128); 3995 current->serialize(s1); 3996 _current->serialize(s2); 3997 kprintf("**mismatch** %p %p\n%s\n%s\n%s\n", OBFUSCATE(current), 3998 OBFUSCATE(_current), s->text(), s1->text(), s2->text()); 3999 s1->release(); 4000 s2->release(); 4001 } 4002 4003 if (_current) _current->release(); 4004 } 4005 4006 s->release(); 4007#endif 4008 4009 if( current && (0 == (options & (kIONotifyOnce | kIOServiceExistingSet)))) { 4010 iter = OSCollectionIterator::withCollection( (OSSet *)current ); 4011 current->release(); 4012 current = iter; 4013 } 4014 4015 return( current ); 4016} 4017 4018// public version 4019OSIterator * IOService::getMatchingServices( OSDictionary * matching ) 4020{ 4021 OSIterator * iter; 4022 4023 // is a lock even needed? 4024 LOCKWRITENOTIFY(); 4025 4026 iter = (OSIterator *) copyExistingServices( matching, 4027 kIOServiceMatchedState ); 4028 4029 UNLOCKNOTIFY(); 4030 4031 return( iter ); 4032} 4033 4034IOService * IOService::copyMatchingService( OSDictionary * matching ) 4035{ 4036 IOService * service; 4037 4038 // is a lock even needed? 4039 LOCKWRITENOTIFY(); 4040 4041 service = (IOService *) copyExistingServices( matching, 4042 kIOServiceMatchedState, kIONotifyOnce ); 4043 4044 UNLOCKNOTIFY(); 4045 4046 return( service ); 4047} 4048 4049struct _IOServiceMatchingNotificationHandlerRef 4050{ 4051 IOServiceNotificationHandler handler; 4052 void * ref; 4053}; 4054 4055static bool _IOServiceMatchingNotificationHandler( void * target, void * refCon, 4056 IOService * newService, 4057 IONotifier * notifier ) 4058{ 4059 return ((*((_IOServiceNotifier *) notifier)->compatHandler)(target, refCon, newService)); 4060} 4061 4062// internal - call with gNotificationLock 4063IONotifier * IOService::setNotification( 4064 const OSSymbol * type, OSDictionary * matching, 4065 IOServiceMatchingNotificationHandler handler, void * target, void * ref, 4066 SInt32 priority ) 4067{ 4068 _IOServiceNotifier * notify = 0; 4069 OSOrderedSet * set; 4070 4071 if( !matching) 4072 return( 0 ); 4073 4074 notify = new _IOServiceNotifier; 4075 if( notify && !notify->init()) { 4076 notify->release(); 4077 notify = 0; 4078 } 4079 4080 if( notify) { 4081 notify->handler = handler; 4082 notify->target = target; 4083 notify->matching = matching; 4084 matching->retain(); 4085 if (handler == &_IOServiceMatchingNotificationHandler) 4086 { 4087 notify->compatHandler = ((_IOServiceMatchingNotificationHandlerRef *)ref)->handler; 4088 notify->ref = ((_IOServiceMatchingNotificationHandlerRef *)ref)->ref; 4089 } 4090 else 4091 notify->ref = ref; 4092 notify->priority = priority; 4093 notify->state = kIOServiceNotifyEnable; 4094 queue_init( ¬ify->handlerInvocations ); 4095 4096 ////// queue 4097 4098 if( 0 == (set = (OSOrderedSet *) gNotifications->getObject( type ))) { 4099 set = OSOrderedSet::withCapacity( 1, 4100 IONotifyOrdering, 0 ); 4101 if( set) { 4102 gNotifications->setObject( type, set ); 4103 set->release(); 4104 } 4105 } 4106 notify->whence = set; 4107 if( set) 4108 set->setObject( notify ); 4109 } 4110 4111 return( notify ); 4112} 4113 4114// internal - call with gNotificationLock 4115IONotifier * IOService::doInstallNotification( 4116 const OSSymbol * type, OSDictionary * matching, 4117 IOServiceMatchingNotificationHandler handler, 4118 void * target, void * ref, 4119 SInt32 priority, OSIterator ** existing ) 4120{ 4121 OSIterator * exist; 4122 IONotifier * notify; 4123 IOOptionBits inState; 4124 4125 if( !matching) 4126 return( 0 ); 4127 4128 if( type == gIOPublishNotification) 4129 inState = kIOServiceRegisteredState; 4130 4131 else if( type == gIOFirstPublishNotification) 4132 inState = kIOServiceFirstPublishState; 4133 4134 else if( (type == gIOMatchedNotification) 4135 || (type == gIOFirstMatchNotification)) 4136 inState = kIOServiceMatchedState; 4137 else if( type == gIOTerminatedNotification) 4138 inState = 0; 4139 else 4140 return( 0 ); 4141 4142 notify = setNotification( type, matching, handler, target, ref, priority ); 4143 4144 if( inState) 4145 // get the current set 4146 exist = (OSIterator *) copyExistingServices( matching, inState ); 4147 else 4148 exist = 0; 4149 4150 *existing = exist; 4151 4152 return( notify ); 4153} 4154 4155#if !defined(__LP64__) 4156IONotifier * IOService::installNotification(const OSSymbol * type, OSDictionary * matching, 4157 IOServiceNotificationHandler handler, 4158 void * target, void * refCon, 4159 SInt32 priority, OSIterator ** existing ) 4160{ 4161 IONotifier * result; 4162 _IOServiceMatchingNotificationHandlerRef ref; 4163 ref.handler = handler; 4164 ref.ref = refCon; 4165 4166 result = (_IOServiceNotifier *) installNotification( type, matching, 4167 &_IOServiceMatchingNotificationHandler, 4168 target, &ref, priority, existing ); 4169 if (result) 4170 matching->release(); 4171 4172 return (result); 4173} 4174#endif /* !defined(__LP64__) */ 4175 4176 4177IONotifier * IOService::installNotification( 4178 const OSSymbol * type, OSDictionary * matching, 4179 IOServiceMatchingNotificationHandler handler, 4180 void * target, void * ref, 4181 SInt32 priority, OSIterator ** existing ) 4182{ 4183 IONotifier * notify; 4184 4185 LOCKWRITENOTIFY(); 4186 4187 notify = doInstallNotification( type, matching, handler, target, ref, 4188 priority, existing ); 4189 4190 UNLOCKNOTIFY(); 4191 4192 return( notify ); 4193} 4194 4195IONotifier * IOService::addNotification( 4196 const OSSymbol * type, OSDictionary * matching, 4197 IOServiceNotificationHandler handler, 4198 void * target, void * refCon, 4199 SInt32 priority ) 4200{ 4201 IONotifier * result; 4202 _IOServiceMatchingNotificationHandlerRef ref; 4203 4204 ref.handler = handler; 4205 ref.ref = refCon; 4206 4207 result = addMatchingNotification(type, matching, &_IOServiceMatchingNotificationHandler, 4208 target, &ref, priority); 4209 4210 if (result) 4211 matching->release(); 4212 4213 return (result); 4214} 4215 4216IONotifier * IOService::addMatchingNotification( 4217 const OSSymbol * type, OSDictionary * matching, 4218 IOServiceMatchingNotificationHandler handler, 4219 void * target, void * ref, 4220 SInt32 priority ) 4221{ 4222 OSIterator * existing = NULL; 4223 _IOServiceNotifier * notify; 4224 IOService * next; 4225 4226 notify = (_IOServiceNotifier *) installNotification( type, matching, 4227 handler, target, ref, priority, &existing ); 4228 4229 // send notifications for existing set 4230 if( existing) { 4231 4232 notify->retain(); // in case handler remove()s 4233 while( (next = (IOService *) existing->getNextObject())) { 4234 4235 next->lockForArbitration(); 4236 if( 0 == (next->__state[0] & kIOServiceInactiveState)) 4237 next->invokeNotifer( notify ); 4238 next->unlockForArbitration(); 4239 } 4240 notify->release(); 4241 existing->release(); 4242 } 4243 4244 return( notify ); 4245} 4246 4247bool IOService::syncNotificationHandler( 4248 void * /* target */, void * ref, 4249 IOService * newService, 4250 IONotifier * notifier ) 4251{ 4252 4253 LOCKWRITENOTIFY(); 4254 if (!*((IOService **) ref)) 4255 { 4256 newService->retain(); 4257 (*(IOService **) ref) = newService; 4258 WAKEUPNOTIFY(ref); 4259 } 4260 UNLOCKNOTIFY(); 4261 4262 return( false ); 4263} 4264 4265IOService * IOService::waitForMatchingService( OSDictionary * matching, 4266 uint64_t timeout) 4267{ 4268 IONotifier * notify = 0; 4269 // priority doesn't help us much since we need a thread wakeup 4270 SInt32 priority = 0; 4271 IOService * result; 4272 4273 if (!matching) 4274 return( 0 ); 4275 4276 result = NULL; 4277 4278 LOCKWRITENOTIFY(); 4279 do 4280 { 4281 result = (IOService *) copyExistingServices( matching, 4282 kIOServiceMatchedState, kIONotifyOnce ); 4283 if (result) 4284 break; 4285 notify = IOService::setNotification( gIOMatchedNotification, matching, 4286 &IOService::syncNotificationHandler, (void *) 0, 4287 &result, priority ); 4288 if (!notify) 4289 break; 4290 if (UINT64_MAX != timeout) 4291 { 4292 AbsoluteTime deadline; 4293 nanoseconds_to_absolutetime(timeout, &deadline); 4294 clock_absolutetime_interval_to_deadline(deadline, &deadline); 4295 SLEEPNOTIFYTO(&result, deadline); 4296 } 4297 else 4298 { 4299 SLEEPNOTIFY(&result); 4300 } 4301 } 4302 while( false ); 4303 4304 UNLOCKNOTIFY(); 4305 4306 if (notify) 4307 notify->remove(); // dequeues 4308 4309 return( result ); 4310} 4311 4312IOService * IOService::waitForService( OSDictionary * matching, 4313 mach_timespec_t * timeout ) 4314{ 4315 IOService * result; 4316 uint64_t timeoutNS; 4317 4318 if (timeout) 4319 { 4320 timeoutNS = timeout->tv_sec; 4321 timeoutNS *= kSecondScale; 4322 timeoutNS += timeout->tv_nsec; 4323 } 4324 else 4325 timeoutNS = UINT64_MAX; 4326 4327 result = waitForMatchingService(matching, timeoutNS); 4328 4329 matching->release(); 4330 if (result) 4331 result->release(); 4332 4333 return (result); 4334} 4335 4336void IOService::deliverNotification( const OSSymbol * type, 4337 IOOptionBits orNewState, IOOptionBits andNewState ) 4338{ 4339 _IOServiceNotifier * notify; 4340 OSIterator * iter; 4341 OSArray * willSend = 0; 4342 4343 lockForArbitration(); 4344 4345 if( (0 == (__state[0] & kIOServiceInactiveState)) 4346 || (type == gIOTerminatedNotification)) { 4347 4348 LOCKREADNOTIFY(); 4349 4350 iter = OSCollectionIterator::withCollection( (OSOrderedSet *) 4351 gNotifications->getObject( type ) ); 4352 4353 if( iter) { 4354 while( (notify = (_IOServiceNotifier *) iter->getNextObject())) { 4355 4356 if( matchPassive(notify->matching, 0) 4357 && (kIOServiceNotifyEnable & notify->state)) { 4358 if( 0 == willSend) 4359 willSend = OSArray::withCapacity(8); 4360 if( willSend) 4361 willSend->setObject( notify ); 4362 } 4363 } 4364 iter->release(); 4365 } 4366 4367 __state[0] = (__state[0] | orNewState) & andNewState; 4368 4369 UNLOCKNOTIFY(); 4370 } 4371 4372 if( willSend) { 4373 for( unsigned int idx = 0; 4374 (notify = (_IOServiceNotifier *) willSend->getObject(idx)); 4375 idx++) { 4376 invokeNotifer( notify ); 4377 } 4378 willSend->release(); 4379 } 4380 unlockForArbitration(); 4381} 4382 4383IOOptionBits IOService::getState( void ) const 4384{ 4385 return( __state[0] ); 4386} 4387 4388/* 4389 * Helpers to make matching objects for simple cases 4390 */ 4391 4392OSDictionary * IOService::serviceMatching( const OSString * name, 4393 OSDictionary * table ) 4394{ 4395 4396 const OSString * str; 4397 4398 str = OSSymbol::withString(name); 4399 if( !str) 4400 return( 0 ); 4401 4402 if( !table) 4403 table = OSDictionary::withCapacity( 2 ); 4404 if( table) 4405 table->setObject(gIOProviderClassKey, (OSObject *)str ); 4406 str->release(); 4407 4408 return( table ); 4409} 4410 4411OSDictionary * IOService::serviceMatching( const char * name, 4412 OSDictionary * table ) 4413{ 4414 const OSString * str; 4415 4416 str = OSSymbol::withCString( name ); 4417 if( !str) 4418 return( 0 ); 4419 4420 table = serviceMatching( str, table ); 4421 str->release(); 4422 return( table ); 4423} 4424 4425OSDictionary * IOService::nameMatching( const OSString * name, 4426 OSDictionary * table ) 4427{ 4428 if( !table) 4429 table = OSDictionary::withCapacity( 2 ); 4430 if( table) 4431 table->setObject( gIONameMatchKey, (OSObject *)name ); 4432 4433 return( table ); 4434} 4435 4436OSDictionary * IOService::nameMatching( const char * name, 4437 OSDictionary * table ) 4438{ 4439 const OSString * str; 4440 4441 str = OSSymbol::withCString( name ); 4442 if( !str) 4443 return( 0 ); 4444 4445 table = nameMatching( str, table ); 4446 str->release(); 4447 return( table ); 4448} 4449 4450OSDictionary * IOService::resourceMatching( const OSString * str, 4451 OSDictionary * table ) 4452{ 4453 table = serviceMatching( gIOResourcesKey, table ); 4454 if( table) 4455 table->setObject( gIOResourceMatchKey, (OSObject *) str ); 4456 4457 return( table ); 4458} 4459 4460OSDictionary * IOService::resourceMatching( const char * name, 4461 OSDictionary * table ) 4462{ 4463 const OSSymbol * str; 4464 4465 str = OSSymbol::withCString( name ); 4466 if( !str) 4467 return( 0 ); 4468 4469 table = resourceMatching( str, table ); 4470 str->release(); 4471 4472 return( table ); 4473} 4474 4475OSDictionary * IOService::propertyMatching( const OSSymbol * key, const OSObject * value, 4476 OSDictionary * table ) 4477{ 4478 OSDictionary * properties; 4479 4480 properties = OSDictionary::withCapacity( 2 ); 4481 if( !properties) 4482 return( 0 ); 4483 properties->setObject( key, value ); 4484 4485 if( !table) 4486 table = OSDictionary::withCapacity( 2 ); 4487 if( table) 4488 table->setObject( gIOPropertyMatchKey, properties ); 4489 4490 properties->release(); 4491 4492 return( table ); 4493} 4494 4495OSDictionary * IOService::registryEntryIDMatching( uint64_t entryID, 4496 OSDictionary * table ) 4497{ 4498 OSNumber * num; 4499 4500 num = OSNumber::withNumber( entryID, 64 ); 4501 if( !num) 4502 return( 0 ); 4503 4504 if( !table) 4505 table = OSDictionary::withCapacity( 2 ); 4506 if( table) 4507 table->setObject( gIORegistryEntryIDKey, num ); 4508 4509 if (num) 4510 num->release(); 4511 4512 return( table ); 4513} 4514 4515 4516/* 4517 * _IOServiceNotifier 4518 */ 4519 4520// wait for all threads, other than the current one, 4521// to exit the handler 4522 4523void _IOServiceNotifier::wait() 4524{ 4525 _IOServiceNotifierInvocation * next; 4526 bool doWait; 4527 4528 do { 4529 doWait = false; 4530 queue_iterate( &handlerInvocations, next, 4531 _IOServiceNotifierInvocation *, link) { 4532 if( next->thread != current_thread() ) { 4533 doWait = true; 4534 break; 4535 } 4536 } 4537 if( doWait) { 4538 state |= kIOServiceNotifyWaiter; 4539 SLEEPNOTIFY(this); 4540 } 4541 4542 } while( doWait ); 4543} 4544 4545void _IOServiceNotifier::free() 4546{ 4547 assert( queue_empty( &handlerInvocations )); 4548 OSObject::free(); 4549} 4550 4551void _IOServiceNotifier::remove() 4552{ 4553 LOCKWRITENOTIFY(); 4554 4555 if( whence) { 4556 whence->removeObject( (OSObject *) this ); 4557 whence = 0; 4558 } 4559 if( matching) { 4560 matching->release(); 4561 matching = 0; 4562 } 4563 4564 state &= ~kIOServiceNotifyEnable; 4565 4566 wait(); 4567 4568 UNLOCKNOTIFY(); 4569 4570 release(); 4571} 4572 4573bool _IOServiceNotifier::disable() 4574{ 4575 bool ret; 4576 4577 LOCKWRITENOTIFY(); 4578 4579 ret = (0 != (kIOServiceNotifyEnable & state)); 4580 state &= ~kIOServiceNotifyEnable; 4581 if( ret) 4582 wait(); 4583 4584 UNLOCKNOTIFY(); 4585 4586 return( ret ); 4587} 4588 4589void _IOServiceNotifier::enable( bool was ) 4590{ 4591 LOCKWRITENOTIFY(); 4592 if( was) 4593 state |= kIOServiceNotifyEnable; 4594 else 4595 state &= ~kIOServiceNotifyEnable; 4596 UNLOCKNOTIFY(); 4597} 4598 4599/* 4600 * IOResources 4601 */ 4602 4603IOService * IOResources::resources( void ) 4604{ 4605 IOResources * inst; 4606 4607 inst = new IOResources; 4608 if( inst && !inst->init()) { 4609 inst->release(); 4610 inst = 0; 4611 } 4612 4613 return( inst ); 4614} 4615 4616bool IOResources::init( OSDictionary * dictionary ) 4617{ 4618 // Do super init first 4619 if ( !super::init() ) 4620 return false; 4621 4622 // Allow PAL layer to publish a value 4623 const char *property_name; 4624 int property_value; 4625 4626 pal_get_resource_property( &property_name, &property_value ); 4627 4628 if( property_name ) { 4629 OSNumber *num; 4630 const OSSymbol * sym; 4631 4632 if( (num = OSNumber::withNumber(property_value, 32)) != 0 ) { 4633 if( (sym = OSSymbol::withCString( property_name)) != 0 ) { 4634 this->setProperty( sym, num ); 4635 sym->release(); 4636 } 4637 num->release(); 4638 } 4639 } 4640 4641 return true; 4642} 4643 4644IOWorkLoop * IOResources::getWorkLoop() const 4645{ 4646 // If we are the resource root 4647 // then use the platform's workloop 4648 if (this == (IOResources *) gIOResources) 4649 return getPlatform()->getWorkLoop(); 4650 else 4651 return IOService::getWorkLoop(); 4652} 4653 4654bool IOResources::matchPropertyTable( OSDictionary * table ) 4655{ 4656 OSObject * prop; 4657 OSString * str; 4658 OSSet * set; 4659 OSIterator * iter; 4660 bool ok = true; 4661 4662 prop = table->getObject( gIOResourceMatchKey ); 4663 str = OSDynamicCast( OSString, prop ); 4664 if( str) 4665 ok = (0 != getProperty( str )); 4666 4667 else if( (set = OSDynamicCast( OSSet, prop))) { 4668 4669 iter = OSCollectionIterator::withCollection( set ); 4670 ok = (iter != 0); 4671 while( ok && (str = OSDynamicCast( OSString, iter->getNextObject()) )) 4672 ok = (0 != getProperty( str )); 4673 4674 if( iter) 4675 iter->release(); 4676 } 4677 4678 return( ok ); 4679} 4680 4681void IOService::consoleLockTimer(thread_call_param_t p0, thread_call_param_t p1) 4682{ 4683 IOService::updateConsoleUsers(NULL, 0); 4684} 4685 4686void IOService::updateConsoleUsers(OSArray * consoleUsers, IOMessage systemMessage) 4687{ 4688 IORegistryEntry * regEntry; 4689 OSObject * locked = kOSBooleanFalse; 4690 uint32_t idx; 4691 bool publish; 4692 OSDictionary * user; 4693 static IOMessage sSystemPower; 4694 4695 regEntry = IORegistryEntry::getRegistryRoot(); 4696 4697 if (!gIOChosenEntry) 4698 gIOChosenEntry = IORegistryEntry::fromPath("/chosen", gIODTPlane); 4699 4700 IOLockLock(gIOConsoleUsersLock); 4701 4702 if (systemMessage) 4703 { 4704 sSystemPower = systemMessage; 4705#if HIBERNATION 4706 if ((kIOMessageSystemHasPoweredOn == systemMessage) && IOHibernateWasScreenLocked()) 4707 { 4708 locked = kOSBooleanTrue; 4709 } 4710#endif /* HIBERNATION */ 4711 } 4712 4713 if (consoleUsers) 4714 { 4715 OSNumber * num = 0; 4716 gIOConsoleLoggedIn = false; 4717 for (idx = 0; 4718 (user = OSDynamicCast(OSDictionary, consoleUsers->getObject(idx))); 4719 idx++) 4720 { 4721 gIOConsoleLoggedIn |= ((kOSBooleanTrue == user->getObject(gIOConsoleSessionOnConsoleKey)) 4722 && (kOSBooleanTrue == user->getObject(gIOConsoleSessionLoginDoneKey))); 4723 if (!num) 4724 { 4725 num = OSDynamicCast(OSNumber, user->getObject(gIOConsoleSessionScreenLockedTimeKey)); 4726 } 4727 } 4728 gIOConsoleLockTime = num ? num->unsigned32BitValue() : 0; 4729 } 4730 4731 if (!gIOConsoleLoggedIn 4732 || (kIOMessageSystemWillSleep == sSystemPower) 4733 || (kIOMessageSystemPagingOff == sSystemPower)) 4734 { 4735 locked = kOSBooleanTrue; 4736 } 4737 else if (gIOConsoleLockTime) 4738 { 4739 clock_sec_t now; 4740 clock_usec_t microsecs; 4741 4742 clock_get_calendar_microtime(&now, µsecs); 4743 if (gIOConsoleLockTime > now) 4744 { 4745 AbsoluteTime deadline; 4746 clock_interval_to_deadline(gIOConsoleLockTime - now, kSecondScale, &deadline); 4747 thread_call_enter_delayed(gIOConsoleLockCallout, deadline); 4748 } 4749 else 4750 { 4751 locked = kOSBooleanTrue; 4752 } 4753 } 4754 4755 publish = (consoleUsers || (locked != regEntry->getProperty(gIOConsoleLockedKey))); 4756 if (publish) 4757 { 4758 regEntry->setProperty(gIOConsoleLockedKey, locked); 4759 if (consoleUsers) 4760 { 4761 regEntry->setProperty(gIOConsoleUsersKey, consoleUsers); 4762 } 4763 OSIncrementAtomic( &gIOConsoleUsersSeed ); 4764 } 4765 4766#if HIBERNATION 4767 if (gIOChosenEntry) 4768 { 4769 if (locked == kOSBooleanTrue) gIOScreenLockState = kIOScreenLockLocked; 4770 else if (gIOConsoleLockTime) gIOScreenLockState = kIOScreenLockUnlocked; 4771 else gIOScreenLockState = kIOScreenLockNoLock; 4772 gIOChosenEntry->setProperty(kIOScreenLockStateKey, &gIOScreenLockState, sizeof(gIOScreenLockState)); 4773 } 4774#endif /* HIBERNATION */ 4775 4776 IOLockUnlock(gIOConsoleUsersLock); 4777 4778 if (publish) 4779 { 4780 publishResource( gIOConsoleUsersSeedKey, gIOConsoleUsersSeedValue ); 4781 4782 MessageClientsContext context; 4783 4784 context.service = getServiceRoot(); 4785 context.type = kIOMessageConsoleSecurityChange; 4786 context.argument = (void *) regEntry; 4787 context.argSize = 0; 4788 4789 applyToInterestNotifiers(getServiceRoot(), gIOConsoleSecurityInterest, 4790 &messageClientsApplier, &context ); 4791 } 4792} 4793 4794IOReturn IOResources::setProperties( OSObject * properties ) 4795{ 4796 IOReturn err; 4797 const OSSymbol * key; 4798 OSDictionary * dict; 4799 OSCollectionIterator * iter; 4800 4801 err = IOUserClient::clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator); 4802 if ( kIOReturnSuccess != err) 4803 return( err ); 4804 4805 dict = OSDynamicCast(OSDictionary, properties); 4806 if( 0 == dict) 4807 return( kIOReturnBadArgument); 4808 4809 iter = OSCollectionIterator::withCollection( dict); 4810 if( 0 == iter) 4811 return( kIOReturnBadArgument); 4812 4813 while( (key = OSDynamicCast(OSSymbol, iter->getNextObject()))) 4814 { 4815 if (gIOConsoleUsersKey == key) do 4816 { 4817 OSArray * consoleUsers; 4818 consoleUsers = OSDynamicCast(OSArray, dict->getObject(key)); 4819 if (!consoleUsers) 4820 continue; 4821 IOService::updateConsoleUsers(consoleUsers, 0); 4822 } 4823 while (false); 4824 4825 publishResource( key, dict->getObject(key) ); 4826 } 4827 4828 iter->release(); 4829 4830 return( kIOReturnSuccess ); 4831} 4832 4833/* 4834 * Helpers for matching dictionaries. 4835 * Keys existing in matching are checked in properties. 4836 * Keys may be a string or OSCollection of IOStrings 4837 */ 4838 4839bool IOService::compareProperty( OSDictionary * matching, 4840 const char * key ) 4841{ 4842 OSObject * value; 4843 bool ok; 4844 4845 value = matching->getObject( key ); 4846 if( value) 4847 ok = value->isEqualTo( getProperty( key )); 4848 else 4849 ok = true; 4850 4851 return( ok ); 4852} 4853 4854 4855bool IOService::compareProperty( OSDictionary * matching, 4856 const OSString * key ) 4857{ 4858 OSObject * value; 4859 bool ok; 4860 4861 value = matching->getObject( key ); 4862 if( value) 4863 ok = value->isEqualTo( getProperty( key )); 4864 else 4865 ok = true; 4866 4867 return( ok ); 4868} 4869 4870bool IOService::compareProperties( OSDictionary * matching, 4871 OSCollection * keys ) 4872{ 4873 OSCollectionIterator * iter; 4874 const OSString * key; 4875 bool ok = true; 4876 4877 if( !matching || !keys) 4878 return( false ); 4879 4880 iter = OSCollectionIterator::withCollection( keys ); 4881 4882 if( iter) { 4883 while( ok && (key = OSDynamicCast( OSString, iter->getNextObject()))) 4884 ok = compareProperty( matching, key ); 4885 4886 iter->release(); 4887 } 4888 keys->release(); // !! consume a ref !! 4889 4890 return( ok ); 4891} 4892 4893/* Helper to add a location matching dict to the table */ 4894 4895OSDictionary * IOService::addLocation( OSDictionary * table ) 4896{ 4897 OSDictionary * dict; 4898 4899 if( !table) 4900 return( 0 ); 4901 4902 dict = OSDictionary::withCapacity( 1 ); 4903 if( dict) { 4904 table->setObject( gIOLocationMatchKey, dict ); 4905 dict->release(); 4906 } 4907 4908 return( dict ); 4909} 4910 4911/* 4912 * Go looking for a provider to match a location dict. 4913 */ 4914 4915IOService * IOService::matchLocation( IOService * /* client */ ) 4916{ 4917 IOService * parent; 4918 4919 parent = getProvider(); 4920 4921 if( parent) 4922 parent = parent->matchLocation( this ); 4923 4924 return( parent ); 4925} 4926 4927bool IOService::matchInternal(OSDictionary * table, uint32_t options, uint32_t * did) 4928{ 4929 OSString * matched; 4930 OSObject * obj; 4931 OSString * str; 4932 IORegistryEntry * entry; 4933 OSNumber * num; 4934 bool match = true; 4935 bool changesOK = (0 != (kIOServiceChangesOK & options)); 4936 uint32_t count; 4937 uint32_t done; 4938 4939 do 4940 { 4941 count = table->getCount(); 4942 done = 0; 4943 str = OSDynamicCast(OSString, table->getObject(gIOProviderClassKey)); 4944 if (str) { 4945 done++; 4946 match = ((kIOServiceClassDone & options) || (0 != metaCast(str))); 4947#if MATCH_DEBUG 4948 match = (0 != metaCast( str )); 4949 if ((kIOServiceClassDone & options) && !match) panic("classDone"); 4950#endif 4951 if ((!match) || (done == count)) break; 4952 } 4953 4954 obj = table->getObject( gIONameMatchKey ); 4955 if( obj) { 4956 done++; 4957 match = compareNames( obj, changesOK ? &matched : 0 ); 4958 if (!match) break; 4959 if( changesOK && matched) { 4960 // leave a hint as to which name matched 4961 table->setObject( gIONameMatchedKey, matched ); 4962 matched->release(); 4963 } 4964 if (done == count) break; 4965 } 4966 4967 str = OSDynamicCast( OSString, table->getObject( gIOLocationMatchKey )); 4968 if (str) 4969 { 4970 const OSSymbol * sym; 4971 done++; 4972 match = false; 4973 sym = copyLocation(); 4974 if (sym) { 4975 match = sym->isEqualTo( str ); 4976 sym->release(); 4977 } 4978 if ((!match) || (done == count)) break; 4979 } 4980 4981 obj = table->getObject( gIOPropertyMatchKey ); 4982 if( obj) 4983 { 4984 OSDictionary * dict; 4985 OSDictionary * nextDict; 4986 OSIterator * iter; 4987 done++; 4988 match = false; 4989 dict = dictionaryWithProperties(); 4990 if( dict) { 4991 nextDict = OSDynamicCast( OSDictionary, obj); 4992 if( nextDict) 4993 iter = 0; 4994 else 4995 iter = OSCollectionIterator::withCollection( 4996 OSDynamicCast(OSCollection, obj)); 4997 4998 while( nextDict 4999 || (iter && (0 != (nextDict = OSDynamicCast(OSDictionary, 5000 iter->getNextObject()))))) { 5001 match = dict->isEqualTo( nextDict, nextDict); 5002 if( match) 5003 break; 5004 nextDict = 0; 5005 } 5006 dict->release(); 5007 if( iter) 5008 iter->release(); 5009 } 5010 if ((!match) || (done == count)) break; 5011 } 5012 5013 str = OSDynamicCast( OSString, table->getObject( gIOPathMatchKey )); 5014 if( str) { 5015 done++; 5016 entry = IORegistryEntry::fromPath( str->getCStringNoCopy() ); 5017 match = (this == entry); 5018 if( entry) 5019 entry->release(); 5020 if ((!match) || (done == count)) break; 5021 } 5022 5023 num = OSDynamicCast( OSNumber, table->getObject( gIORegistryEntryIDKey )); 5024 if (num) { 5025 done++; 5026 match = (getRegistryEntryID() == num->unsigned64BitValue()); 5027 if ((!match) || (done == count)) break; 5028 } 5029 5030 num = OSDynamicCast( OSNumber, table->getObject( gIOMatchedServiceCountKey )); 5031 if( num) 5032 { 5033 OSIterator * iter; 5034 IOService * service = 0; 5035 UInt32 serviceCount = 0; 5036 5037 done++; 5038 iter = getClientIterator(); 5039 if( iter) { 5040 while( (service = (IOService *) iter->getNextObject())) { 5041 if( kIOServiceInactiveState & service->__state[0]) 5042 continue; 5043 if( 0 == service->getProperty( gIOMatchCategoryKey )) 5044 continue; 5045 ++serviceCount; 5046 } 5047 iter->release(); 5048 } 5049 match = (serviceCount == num->unsigned32BitValue()); 5050 if ((!match) || (done == count)) break; 5051 } 5052 5053#define propMatch(key) \ 5054 obj = table->getObject(key); \ 5055 if (obj) \ 5056 { \ 5057 OSObject * prop; \ 5058 done++; \ 5059 prop = copyProperty(key); \ 5060 match = obj->isEqualTo(prop); \ 5061 if (prop) prop->release(); \ 5062 if ((!match) || (done == count)) break; \ 5063 } 5064 propMatch(kIOBSDNameKey) 5065 propMatch(kIOBSDMajorKey) 5066 propMatch(kIOBSDMinorKey) 5067 propMatch(kIOBSDUnitKey) 5068#undef propMatch 5069 } 5070 while (false); 5071 5072 if (did) *did = done; 5073 return (match); 5074} 5075 5076bool IOService::passiveMatch( OSDictionary * table, bool changesOK ) 5077{ 5078 return (matchPassive(table, changesOK ? kIOServiceChangesOK : 0)); 5079} 5080 5081bool IOService::matchPassive(OSDictionary * table, uint32_t options) 5082{ 5083 IOService * where; 5084 OSDictionary * nextTable; 5085 SInt32 score; 5086 OSNumber * newPri; 5087 bool match = true; 5088 bool matchParent = false; 5089 uint32_t count; 5090 uint32_t done; 5091 5092 assert( table ); 5093 5094#if MATCH_DEBUG 5095 OSDictionary * root = table; 5096#endif 5097 5098 where = this; 5099 do 5100 { 5101 do 5102 { 5103 count = table->getCount(); 5104 if (!(kIOServiceInternalDone & options)) 5105 { 5106 match = where->matchInternal(table, options, &done); 5107 // don't call family if we've done all the entries in the table 5108 if ((!match) || (done == count)) break; 5109 } 5110 5111 // pass in score from property table 5112 score = IOServiceObjectOrder( table, (void *) gIOProbeScoreKey); 5113 5114 // do family specific matching 5115 match = where->matchPropertyTable( table, &score ); 5116 5117 if( !match) { 5118#if IOMATCHDEBUG 5119 if( kIOLogMatch & getDebugFlags( table )) 5120 LOG("%s: family specific matching fails\n", where->getName()); 5121#endif 5122 break; 5123 } 5124 5125 if (kIOServiceChangesOK & options) { 5126 // save the score 5127 newPri = OSNumber::withNumber( score, 32 ); 5128 if( newPri) { 5129 table->setObject( gIOProbeScoreKey, newPri ); 5130 newPri->release(); 5131 } 5132 } 5133 5134 options = 0; 5135 matchParent = false; 5136 5137 nextTable = OSDynamicCast(OSDictionary, 5138 table->getObject( gIOParentMatchKey )); 5139 if( nextTable) { 5140 // look for a matching entry anywhere up to root 5141 match = false; 5142 matchParent = true; 5143 table = nextTable; 5144 break; 5145 } 5146 5147 table = OSDynamicCast(OSDictionary, 5148 table->getObject( gIOLocationMatchKey )); 5149 if (table) { 5150 // look for a matching entry at matchLocation() 5151 match = false; 5152 where = where->getProvider(); 5153 if (where && (where = where->matchLocation(where))) continue; 5154 } 5155 break; 5156 } 5157 while (true); 5158 } 5159 while( matchParent && (!match) && (where = where->getProvider()) ); 5160 5161#if MATCH_DEBUG 5162 if (where != this) 5163 { 5164 OSSerialize * s = OSSerialize::withCapacity(128); 5165 root->serialize(s); 5166 kprintf("parent match 0x%llx, %d,\n%s\n", getRegistryEntryID(), match, s->text()); 5167 s->release(); 5168 } 5169#endif 5170 5171 return( match ); 5172} 5173 5174 5175IOReturn IOService::newUserClient( task_t owningTask, void * securityID, 5176 UInt32 type, OSDictionary * properties, 5177 IOUserClient ** handler ) 5178{ 5179 const OSSymbol *userClientClass = 0; 5180 IOUserClient *client; 5181 OSObject *temp; 5182 5183 if (kIOReturnSuccess == newUserClient( owningTask, securityID, type, handler )) 5184 return kIOReturnSuccess; 5185 5186 // First try my own properties for a user client class name 5187 temp = getProperty(gIOUserClientClassKey); 5188 if (temp) { 5189 if (OSDynamicCast(OSSymbol, temp)) 5190 userClientClass = (const OSSymbol *) temp; 5191 else if (OSDynamicCast(OSString, temp)) { 5192 userClientClass = OSSymbol::withString((OSString *) temp); 5193 if (userClientClass) 5194 setProperty(kIOUserClientClassKey, 5195 (OSObject *) userClientClass); 5196 } 5197 } 5198 5199 // Didn't find one so lets just bomb out now without further ado. 5200 if (!userClientClass) 5201 return kIOReturnUnsupported; 5202 5203 // This reference is consumed by the IOServiceOpen call 5204 temp = OSMetaClass::allocClassWithName(userClientClass); 5205 if (!temp) 5206 return kIOReturnNoMemory; 5207 5208 if (OSDynamicCast(IOUserClient, temp)) 5209 client = (IOUserClient *) temp; 5210 else { 5211 temp->release(); 5212 return kIOReturnUnsupported; 5213 } 5214 5215 if ( !client->initWithTask(owningTask, securityID, type, properties) ) { 5216 client->release(); 5217 return kIOReturnBadArgument; 5218 } 5219 5220 if ( !client->attach(this) ) { 5221 client->release(); 5222 return kIOReturnUnsupported; 5223 } 5224 5225 if ( !client->start(this) ) { 5226 client->detach(this); 5227 client->release(); 5228 return kIOReturnUnsupported; 5229 } 5230 5231 *handler = client; 5232 return kIOReturnSuccess; 5233} 5234 5235IOReturn IOService::newUserClient( task_t owningTask, void * securityID, 5236 UInt32 type, IOUserClient ** handler ) 5237{ 5238 return( kIOReturnUnsupported ); 5239} 5240 5241IOReturn IOService::requestProbe( IOOptionBits options ) 5242{ 5243 return( kIOReturnUnsupported); 5244} 5245 5246/* 5247 * Convert an IOReturn to text. Subclasses which add additional 5248 * IOReturn's should override this method and call 5249 * super::stringFromReturn if the desired value is not found. 5250 */ 5251 5252const char * IOService::stringFromReturn( IOReturn rtn ) 5253{ 5254 static const IONamedValue IOReturn_values[] = { 5255 {kIOReturnSuccess, "success" }, 5256 {kIOReturnError, "general error" }, 5257 {kIOReturnNoMemory, "memory allocation error" }, 5258 {kIOReturnNoResources, "resource shortage" }, 5259 {kIOReturnIPCError, "Mach IPC failure" }, 5260 {kIOReturnNoDevice, "no such device" }, 5261 {kIOReturnNotPrivileged, "privilege violation" }, 5262 {kIOReturnBadArgument, "invalid argument" }, 5263 {kIOReturnLockedRead, "device is read locked" }, 5264 {kIOReturnLockedWrite, "device is write locked" }, 5265 {kIOReturnExclusiveAccess, "device is exclusive access" }, 5266 {kIOReturnBadMessageID, "bad IPC message ID" }, 5267 {kIOReturnUnsupported, "unsupported function" }, 5268 {kIOReturnVMError, "virtual memory error" }, 5269 {kIOReturnInternalError, "internal driver error" }, 5270 {kIOReturnIOError, "I/O error" }, 5271 {kIOReturnCannotLock, "cannot acquire lock" }, 5272 {kIOReturnNotOpen, "device is not open" }, 5273 {kIOReturnNotReadable, "device is not readable" }, 5274 {kIOReturnNotWritable, "device is not writeable" }, 5275 {kIOReturnNotAligned, "alignment error" }, 5276 {kIOReturnBadMedia, "media error" }, 5277 {kIOReturnStillOpen, "device is still open" }, 5278 {kIOReturnRLDError, "rld failure" }, 5279 {kIOReturnDMAError, "DMA failure" }, 5280 {kIOReturnBusy, "device is busy" }, 5281 {kIOReturnTimeout, "I/O timeout" }, 5282 {kIOReturnOffline, "device is offline" }, 5283 {kIOReturnNotReady, "device is not ready" }, 5284 {kIOReturnNotAttached, "device/channel is not attached" }, 5285 {kIOReturnNoChannels, "no DMA channels available" }, 5286 {kIOReturnNoSpace, "no space for data" }, 5287 {kIOReturnPortExists, "device port already exists" }, 5288 {kIOReturnCannotWire, "cannot wire physical memory" }, 5289 {kIOReturnNoInterrupt, "no interrupt attached" }, 5290 {kIOReturnNoFrames, "no DMA frames enqueued" }, 5291 {kIOReturnMessageTooLarge, "message is too large" }, 5292 {kIOReturnNotPermitted, "operation is not permitted" }, 5293 {kIOReturnNoPower, "device is without power" }, 5294 {kIOReturnNoMedia, "media is not present" }, 5295 {kIOReturnUnformattedMedia, "media is not formatted" }, 5296 {kIOReturnUnsupportedMode, "unsupported mode" }, 5297 {kIOReturnUnderrun, "data underrun" }, 5298 {kIOReturnOverrun, "data overrun" }, 5299 {kIOReturnDeviceError, "device error" }, 5300 {kIOReturnNoCompletion, "no completion routine" }, 5301 {kIOReturnAborted, "operation was aborted" }, 5302 {kIOReturnNoBandwidth, "bus bandwidth would be exceeded" }, 5303 {kIOReturnNotResponding, "device is not responding" }, 5304 {kIOReturnInvalid, "unanticipated driver error" }, 5305 {0, NULL } 5306 }; 5307 5308 return IOFindNameForValue(rtn, IOReturn_values); 5309} 5310 5311/* 5312 * Convert an IOReturn to an errno. 5313 */ 5314int IOService::errnoFromReturn( IOReturn rtn ) 5315{ 5316 if (unix_err(err_get_code(rtn)) == rtn) 5317 return err_get_code(rtn); 5318 5319 switch(rtn) { 5320 // (obvious match) 5321 case kIOReturnSuccess: 5322 return(0); 5323 case kIOReturnNoMemory: 5324 return(ENOMEM); 5325 case kIOReturnNoDevice: 5326 return(ENXIO); 5327 case kIOReturnVMError: 5328 return(EFAULT); 5329 case kIOReturnNotPermitted: 5330 return(EPERM); 5331 case kIOReturnNotPrivileged: 5332 return(EACCES); 5333 case kIOReturnIOError: 5334 return(EIO); 5335 case kIOReturnNotWritable: 5336 return(EROFS); 5337 case kIOReturnBadArgument: 5338 return(EINVAL); 5339 case kIOReturnUnsupported: 5340 return(ENOTSUP); 5341 case kIOReturnBusy: 5342 return(EBUSY); 5343 case kIOReturnNoPower: 5344 return(EPWROFF); 5345 case kIOReturnDeviceError: 5346 return(EDEVERR); 5347 case kIOReturnTimeout: 5348 return(ETIMEDOUT); 5349 case kIOReturnMessageTooLarge: 5350 return(EMSGSIZE); 5351 case kIOReturnNoSpace: 5352 return(ENOSPC); 5353 case kIOReturnCannotLock: 5354 return(ENOLCK); 5355 5356 // (best match) 5357 case kIOReturnBadMessageID: 5358 case kIOReturnNoCompletion: 5359 case kIOReturnNotAligned: 5360 return(EINVAL); 5361 case kIOReturnNotReady: 5362 return(EBUSY); 5363 case kIOReturnRLDError: 5364 return(EBADMACHO); 5365 case kIOReturnPortExists: 5366 case kIOReturnStillOpen: 5367 return(EEXIST); 5368 case kIOReturnExclusiveAccess: 5369 case kIOReturnLockedRead: 5370 case kIOReturnLockedWrite: 5371 case kIOReturnNotOpen: 5372 case kIOReturnNotReadable: 5373 return(EACCES); 5374 case kIOReturnCannotWire: 5375 case kIOReturnNoResources: 5376 return(ENOMEM); 5377 case kIOReturnAborted: 5378 case kIOReturnOffline: 5379 case kIOReturnNotResponding: 5380 return(EBUSY); 5381 case kIOReturnBadMedia: 5382 case kIOReturnNoMedia: 5383 case kIOReturnNotAttached: 5384 case kIOReturnUnformattedMedia: 5385 return(ENXIO); // (media error) 5386 case kIOReturnDMAError: 5387 case kIOReturnOverrun: 5388 case kIOReturnUnderrun: 5389 return(EIO); // (transfer error) 5390 case kIOReturnNoBandwidth: 5391 case kIOReturnNoChannels: 5392 case kIOReturnNoFrames: 5393 case kIOReturnNoInterrupt: 5394 return(EIO); // (hardware error) 5395 case kIOReturnError: 5396 case kIOReturnInternalError: 5397 case kIOReturnInvalid: 5398 return(EIO); // (generic error) 5399 case kIOReturnIPCError: 5400 return(EIO); // (ipc error) 5401 default: 5402 return(EIO); // (all other errors) 5403 } 5404} 5405 5406IOReturn IOService::message( UInt32 type, IOService * provider, 5407 void * argument ) 5408{ 5409 /* 5410 * Generic entry point for calls from the provider. A return value of 5411 * kIOReturnSuccess indicates that the message was received, and where 5412 * applicable, that it was successful. 5413 */ 5414 5415 return kIOReturnUnsupported; 5416} 5417 5418/* 5419 * Device memory 5420 */ 5421 5422IOItemCount IOService::getDeviceMemoryCount( void ) 5423{ 5424 OSArray * array; 5425 IOItemCount count; 5426 5427 array = OSDynamicCast( OSArray, getProperty( gIODeviceMemoryKey)); 5428 if( array) 5429 count = array->getCount(); 5430 else 5431 count = 0; 5432 5433 return( count); 5434} 5435 5436IODeviceMemory * IOService::getDeviceMemoryWithIndex( unsigned int index ) 5437{ 5438 OSArray * array; 5439 IODeviceMemory * range; 5440 5441 array = OSDynamicCast( OSArray, getProperty( gIODeviceMemoryKey)); 5442 if( array) 5443 range = (IODeviceMemory *) array->getObject( index ); 5444 else 5445 range = 0; 5446 5447 return( range); 5448} 5449 5450IOMemoryMap * IOService::mapDeviceMemoryWithIndex( unsigned int index, 5451 IOOptionBits options ) 5452{ 5453 IODeviceMemory * range; 5454 IOMemoryMap * map; 5455 5456 range = getDeviceMemoryWithIndex( index ); 5457 if( range) 5458 map = range->map( options ); 5459 else 5460 map = 0; 5461 5462 return( map ); 5463} 5464 5465OSArray * IOService::getDeviceMemory( void ) 5466{ 5467 return( OSDynamicCast( OSArray, getProperty( gIODeviceMemoryKey))); 5468} 5469 5470 5471void IOService::setDeviceMemory( OSArray * array ) 5472{ 5473 setProperty( gIODeviceMemoryKey, array); 5474} 5475 5476/* 5477 * For machines where the transfers on an I/O bus can stall because 5478 * the CPU is in an idle mode, These APIs allow a driver to specify 5479 * the maximum bus stall that they can handle. 0 indicates no limit. 5480 */ 5481void IOService:: 5482setCPUSnoopDelay(UInt32 __unused ns) 5483{ 5484#if defined(__i386__) || defined(__x86_64__) 5485 ml_set_maxsnoop(ns); 5486#endif /* defined(__i386__) || defined(__x86_64__) */ 5487} 5488 5489UInt32 IOService:: 5490getCPUSnoopDelay() 5491{ 5492#if defined(__i386__) || defined(__x86_64__) 5493 return ml_get_maxsnoop(); 5494#else 5495 return 0; 5496#endif /* defined(__i386__) || defined(__x86_64__) */ 5497} 5498 5499#if defined(__i386__) || defined(__x86_64__) 5500static void 5501requireMaxCpuDelay(IOService * service, UInt32 ns, UInt32 delayType) 5502{ 5503 static const UInt kNoReplace = -1U; // Must be an illegal index 5504 UInt replace = kNoReplace; 5505 bool setCpuDelay = false; 5506 5507 IORecursiveLockLock(sCpuDelayLock); 5508 5509 UInt count = sCpuDelayData->getLength() / sizeof(CpuDelayEntry); 5510 CpuDelayEntry *entries = (CpuDelayEntry *) sCpuDelayData->getBytesNoCopy(); 5511 IOService * holder = NULL; 5512 5513 if (ns) { 5514 const CpuDelayEntry ne = {service, ns, delayType}; 5515 holder = service; 5516 // Set maximum delay. 5517 for (UInt i = 0; i < count; i++) { 5518 IOService *thisService = entries[i].fService; 5519 bool sameType = (delayType == entries[i].fDelayType); 5520 if ((service == thisService) && sameType) 5521 replace = i; 5522 else if (!thisService) { 5523 if (kNoReplace == replace) 5524 replace = i; 5525 } 5526 else if (sameType) { 5527 const UInt32 thisMax = entries[i].fMaxDelay; 5528 if (thisMax < ns) 5529 { 5530 ns = thisMax; 5531 holder = thisService; 5532 } 5533 } 5534 } 5535 5536 setCpuDelay = true; 5537 if (kNoReplace == replace) 5538 sCpuDelayData->appendBytes(&ne, sizeof(ne)); 5539 else 5540 entries[replace] = ne; 5541 } 5542 else { 5543 ns = -1U; // Set to max unsigned, i.e. no restriction 5544 5545 for (UInt i = 0; i < count; i++) { 5546 // Clear a maximum delay. 5547 IOService *thisService = entries[i].fService; 5548 if (thisService && (delayType == entries[i].fDelayType)) { 5549 UInt32 thisMax = entries[i].fMaxDelay; 5550 if (service == thisService) 5551 replace = i; 5552 else if (thisMax < ns) { 5553 ns = thisMax; 5554 holder = thisService; 5555 } 5556 } 5557 } 5558 5559 // Check if entry found 5560 if (kNoReplace != replace) { 5561 entries[replace].fService = 0; // Null the entry 5562 setCpuDelay = true; 5563 } 5564 } 5565 5566 if (setCpuDelay) 5567 { 5568 // Must be safe to call from locked context 5569 if (delayType == kCpuDelayBusStall) 5570 { 5571 ml_set_maxbusdelay(ns); 5572 } 5573 else if (delayType == kCpuDelayInterrupt) 5574 { 5575 ml_set_maxintdelay(ns); 5576 } 5577 sCPULatencyHolder[delayType]->setValue(holder ? holder->getRegistryEntryID() : 0); 5578 sCPULatencySet [delayType]->setValue(ns); 5579 5580 OSArray * handlers = sCpuLatencyHandlers[delayType]; 5581 IOService * target; 5582 if (handlers) for (unsigned int idx = 0; 5583 (target = (IOService *) handlers->getObject(idx)); 5584 idx++) 5585 { 5586 target->callPlatformFunction(sCPULatencyFunctionName[delayType], false, 5587 (void *) (uintptr_t) ns, holder, 5588 NULL, NULL); 5589 } 5590 } 5591 5592 IORecursiveLockUnlock(sCpuDelayLock); 5593} 5594 5595static IOReturn 5596setLatencyHandler(UInt32 delayType, IOService * target, bool enable) 5597{ 5598 IOReturn result = kIOReturnNotFound; 5599 OSArray * array; 5600 unsigned int idx; 5601 5602 IORecursiveLockLock(sCpuDelayLock); 5603 5604 do 5605 { 5606 if (enable && !sCpuLatencyHandlers[delayType]) 5607 sCpuLatencyHandlers[delayType] = OSArray::withCapacity(4); 5608 array = sCpuLatencyHandlers[delayType]; 5609 if (!array) 5610 break; 5611 idx = array->getNextIndexOfObject(target, 0); 5612 if (!enable) 5613 { 5614 if (-1U != idx) 5615 { 5616 array->removeObject(idx); 5617 result = kIOReturnSuccess; 5618 } 5619 } 5620 else 5621 { 5622 if (-1U != idx) { 5623 result = kIOReturnExclusiveAccess; 5624 break; 5625 } 5626 array->setObject(target); 5627 5628 UInt count = sCpuDelayData->getLength() / sizeof(CpuDelayEntry); 5629 CpuDelayEntry *entries = (CpuDelayEntry *) sCpuDelayData->getBytesNoCopy(); 5630 UInt32 ns = -1U; // Set to max unsigned, i.e. no restriction 5631 IOService * holder = NULL; 5632 5633 for (UInt i = 0; i < count; i++) { 5634 if (entries[i].fService 5635 && (delayType == entries[i].fDelayType) 5636 && (entries[i].fMaxDelay < ns)) { 5637 ns = entries[i].fMaxDelay; 5638 holder = entries[i].fService; 5639 } 5640 } 5641 target->callPlatformFunction(sCPULatencyFunctionName[delayType], false, 5642 (void *) (uintptr_t) ns, holder, 5643 NULL, NULL); 5644 result = kIOReturnSuccess; 5645 } 5646 } 5647 while (false); 5648 5649 IORecursiveLockUnlock(sCpuDelayLock); 5650 5651 return (result); 5652} 5653 5654#endif /* defined(__i386__) || defined(__x86_64__) */ 5655 5656void IOService:: 5657requireMaxBusStall(UInt32 __unused ns) 5658{ 5659#if defined(__i386__) || defined(__x86_64__) 5660 requireMaxCpuDelay(this, ns, kCpuDelayBusStall); 5661#endif 5662} 5663 5664void IOService:: 5665requireMaxInterruptDelay(uint32_t __unused ns) 5666{ 5667#if defined(__i386__) || defined(__x86_64__) 5668 requireMaxCpuDelay(this, ns, kCpuDelayInterrupt); 5669#endif 5670} 5671 5672/* 5673 * Device interrupts 5674 */ 5675 5676IOReturn IOService::resolveInterrupt(IOService *nub, int source) 5677{ 5678 IOInterruptController *interruptController; 5679 OSArray *array; 5680 OSData *data; 5681 OSSymbol *interruptControllerName; 5682 long numSources; 5683 IOInterruptSource *interruptSources; 5684 5685 // Get the parents list from the nub. 5686 array = OSDynamicCast(OSArray, nub->getProperty(gIOInterruptControllersKey)); 5687 if (array == 0) return kIOReturnNoResources; 5688 5689 // Allocate space for the IOInterruptSources if needed... then return early. 5690 if (nub->_interruptSources == 0) { 5691 numSources = array->getCount(); 5692 interruptSources = (IOInterruptSource *)IOMalloc(numSources * sizeof(IOInterruptSource)); 5693 if (interruptSources == 0) return kIOReturnNoMemory; 5694 5695 bzero(interruptSources, numSources * sizeof(IOInterruptSource)); 5696 5697 nub->_numInterruptSources = numSources; 5698 nub->_interruptSources = interruptSources; 5699 return kIOReturnSuccess; 5700 } 5701 5702 interruptControllerName = OSDynamicCast(OSSymbol,array->getObject(source)); 5703 if (interruptControllerName == 0) return kIOReturnNoResources; 5704 5705 interruptController = getPlatform()->lookUpInterruptController(interruptControllerName); 5706 if (interruptController == 0) return kIOReturnNoResources; 5707 5708 // Get the interrupt numbers from the nub. 5709 array = OSDynamicCast(OSArray, nub->getProperty(gIOInterruptSpecifiersKey)); 5710 if (array == 0) return kIOReturnNoResources; 5711 data = OSDynamicCast(OSData, array->getObject(source)); 5712 if (data == 0) return kIOReturnNoResources; 5713 5714 // Set the interruptController and interruptSource in the nub's table. 5715 interruptSources = nub->_interruptSources; 5716 interruptSources[source].interruptController = interruptController; 5717 interruptSources[source].vectorData = data; 5718 5719 return kIOReturnSuccess; 5720} 5721 5722IOReturn IOService::lookupInterrupt(int source, bool resolve, IOInterruptController **interruptController) 5723{ 5724 IOReturn ret; 5725 5726 /* Make sure the _interruptSources are set */ 5727 if (_interruptSources == 0) { 5728 ret = resolveInterrupt(this, source); 5729 if (ret != kIOReturnSuccess) return ret; 5730 } 5731 5732 /* Make sure the local source number is valid */ 5733 if ((source < 0) || (source >= _numInterruptSources)) 5734 return kIOReturnNoInterrupt; 5735 5736 /* Look up the contoller for the local source */ 5737 *interruptController = _interruptSources[source].interruptController; 5738 5739 if (*interruptController == NULL) { 5740 if (!resolve) return kIOReturnNoInterrupt; 5741 5742 /* Try to reslove the interrupt */ 5743 ret = resolveInterrupt(this, source); 5744 if (ret != kIOReturnSuccess) return ret; 5745 5746 *interruptController = _interruptSources[source].interruptController; 5747 } 5748 5749 return kIOReturnSuccess; 5750} 5751 5752IOReturn IOService::registerInterrupt(int source, OSObject *target, 5753 IOInterruptAction handler, 5754 void *refCon) 5755{ 5756 IOInterruptController *interruptController; 5757 IOReturn ret; 5758 5759 ret = lookupInterrupt(source, true, &interruptController); 5760 if (ret != kIOReturnSuccess) return ret; 5761 5762 /* Register the source */ 5763 return interruptController->registerInterrupt(this, source, target, 5764 (IOInterruptHandler)handler, 5765 refCon); 5766} 5767 5768IOReturn IOService::unregisterInterrupt(int source) 5769{ 5770 IOInterruptController *interruptController; 5771 IOReturn ret; 5772 5773 ret = lookupInterrupt(source, false, &interruptController); 5774 if (ret != kIOReturnSuccess) return ret; 5775 5776 /* Unregister the source */ 5777 return interruptController->unregisterInterrupt(this, source); 5778} 5779 5780IOReturn IOService::addInterruptStatistics(IOInterruptAccountingData * statistics, int source) 5781{ 5782 IOReportLegend * legend = NULL; 5783 IOInterruptAccountingData * oldValue = NULL; 5784 IOInterruptAccountingReporter * newArray = NULL; 5785 int newArraySize = 0; 5786 int i = 0; 5787 5788 if (source < 0) { 5789 return kIOReturnBadArgument; 5790 } 5791 5792 /* 5793 * We support statistics on a maximum of 256 interrupts per nub; if a nub 5794 * has more than 256 interrupt specifiers associated with it, and tries 5795 * to register a high interrupt index with interrupt accounting, panic. 5796 * Having more than 256 interrupts associated with a single nub is 5797 * probably a sign that something fishy is going on. 5798 */ 5799 if (source > IA_INDEX_MAX) { 5800 panic("addInterruptStatistics called for an excessively large index (%d)", source); 5801 } 5802 5803 /* 5804 * TODO: This is ugly (wrapping a lock around an allocation). I'm only 5805 * leaving it as is because the likelihood of contention where we are 5806 * actually growing the array is minimal (we would realistically need 5807 * to be starting a driver for the first time, with an IOReporting 5808 * client already in place). Nonetheless, cleanup that can be done 5809 * to adhere to best practices; it'll make the code more complicated, 5810 * unfortunately. 5811 */ 5812 IOLockLock(reserved->interruptStatisticsLock); 5813 5814 /* 5815 * Lazily allocate the statistics array. 5816 */ 5817 if (!reserved->interruptStatisticsArray) { 5818 reserved->interruptStatisticsArray = IONew(IOInterruptAccountingReporter, 1); 5819 assert(reserved->interruptStatisticsArray); 5820 reserved->interruptStatisticsArrayCount = 1; 5821 bzero(reserved->interruptStatisticsArray, sizeof(*reserved->interruptStatisticsArray)); 5822 } 5823 5824 if (source >= reserved->interruptStatisticsArrayCount) { 5825 /* 5826 * We're still within the range of supported indices, but we are out 5827 * of space in the current array. Do a nasty realloc (because 5828 * IORealloc isn't a thing) here. We'll double the size with each 5829 * reallocation. 5830 * 5831 * Yes, the "next power of 2" could be more efficient; but this will 5832 * be invoked incredibly rarely. Who cares. 5833 */ 5834 newArraySize = (reserved->interruptStatisticsArrayCount << 1); 5835 5836 while (newArraySize <= source) 5837 newArraySize = (newArraySize << 1); 5838 newArray = IONew(IOInterruptAccountingReporter, newArraySize); 5839 5840 assert(newArray); 5841 5842 /* 5843 * TODO: This even zeroes the memory it is about to overwrite. 5844 * Shameful; fix it. Not particularly high impact, however. 5845 */ 5846 bzero(newArray, newArraySize * sizeof(*newArray)); 5847 memcpy(newArray, reserved->interruptStatisticsArray, reserved->interruptStatisticsArrayCount * sizeof(*newArray)); 5848 IODelete(reserved->interruptStatisticsArray, IOInterruptAccountingReporter, reserved->interruptStatisticsArrayCount); 5849 reserved->interruptStatisticsArray = newArray; 5850 reserved->interruptStatisticsArrayCount = newArraySize; 5851 } 5852 5853 if (!reserved->interruptStatisticsArray[source].reporter) { 5854 /* 5855 * We don't have a reporter associated with this index yet, so we 5856 * need to create one. 5857 */ 5858 /* 5859 * TODO: Some statistics do in fact have common units (time); should this be 5860 * split into separate reporters to communicate this? 5861 */ 5862 reserved->interruptStatisticsArray[source].reporter = IOSimpleReporter::with(this, kIOReportCategoryInterrupt, kIOReportUnitNone); 5863 5864 /* 5865 * Each statistic is given an identifier based on the interrupt index (which 5866 * should be unique relative to any single nub) and the statistic involved. 5867 * We should now have a sane (small and positive) index, so start 5868 * constructing the channels for statistics. 5869 */ 5870 for (i = 0; i < IA_NUM_INTERRUPT_ACCOUNTING_STATISTICS; i++) { 5871 /* 5872 * TODO: Currently, this does not add channels for disabled statistics. 5873 * Will this be confusing for clients? If so, we should just add the 5874 * channels; we can avoid updating the channels even if they exist. 5875 */ 5876 if (IA_GET_STATISTIC_ENABLED(i)) 5877 reserved->interruptStatisticsArray[source].reporter->addChannel(IA_GET_CHANNEL_ID(source, i), kInterruptAccountingStatisticNameArray[i]); 5878 } 5879 5880 /* 5881 * We now need to add the legend for this reporter to the registry. 5882 */ 5883 legend = IOReportLegend::with(OSDynamicCast(OSArray, getProperty(kIOReportLegendKey))); 5884 5885 if ((source >= IA_MAX_SUBGROUP_NAME) || (source < 0)) { 5886 /* 5887 * Either we're using a nonsensical index (should never happen), or the 5888 * index is larger than anticipated (may happen, almost certainly won't). 5889 * This may move to live generation of the names in the future, but for 5890 * now, point both cases to a generic subgroup name (this will confuse 5891 * clients, unfortunately). 5892 */ 5893 legend->addReporterLegend(reserved->interruptStatisticsArray[source].reporter, kInterruptAccountingGroupName, kInterruptAccountingGenericSubgroupName); 5894 } else { 5895 legend->addReporterLegend(reserved->interruptStatisticsArray[source].reporter, kInterruptAccountingGroupName, kInterruptAccountingSubgroupNames[source]); 5896 } 5897 5898 setProperty(kIOReportLegendKey, legend->getLegend()); 5899 legend->release(); 5900 5901 /* 5902 * TODO: Is this a good idea? Probably not; my assumption is it opts 5903 * all entities who register interrupts into public disclosure of all 5904 * IOReporting channels. Unfortunately, this appears to be as fine 5905 * grain as it gets. 5906 */ 5907 setProperty(kIOReportLegendPublicKey, true); 5908 } 5909 5910 /* 5911 * Don't stomp existing entries. If we are about to, panic; this 5912 * probably means we failed to tear down our old interrupt source 5913 * correctly. 5914 */ 5915 oldValue = reserved->interruptStatisticsArray[source].statistics; 5916 5917 if (oldValue) { 5918 panic("addInterruptStatistics call for index %d would have clobbered existing statistics", source); 5919 } 5920 5921 reserved->interruptStatisticsArray[source].statistics = statistics; 5922 5923 /* 5924 * Inherit the reporter values for each statistic. The target may 5925 * be torn down as part of the runtime of the service (especially 5926 * for sleep/wake), so we inherit in order to avoid having values 5927 * reset for no apparent reason. Our statistics are ultimately 5928 * tied to the index and the sevice, not to an individual target, 5929 * so we should maintain them accordingly. 5930 */ 5931 interruptAccountingDataInheritChannels(reserved->interruptStatisticsArray[source].statistics, reserved->interruptStatisticsArray[source].reporter); 5932 5933 IOLockUnlock(reserved->interruptStatisticsLock); 5934 5935 return kIOReturnSuccess; 5936} 5937 5938IOReturn IOService::removeInterruptStatistics(int source) 5939{ 5940 IOInterruptAccountingData * value = NULL; 5941 5942 if (source < 0) { 5943 return kIOReturnBadArgument; 5944 } 5945 5946 IOLockLock(reserved->interruptStatisticsLock); 5947 5948 /* 5949 * We dynamically grow the statistics array, so an excessively 5950 * large index value has NEVER been registered. This either 5951 * means our cap on the array size is too small (unlikely), or 5952 * that we have been passed a corrupt index (this must be passed 5953 * the plain index into the interrupt specifier list). 5954 */ 5955 if (source >= reserved->interruptStatisticsArrayCount) { 5956 panic("removeInterruptStatistics called for index %d, which was never registered", source); 5957 } 5958 5959 assert(reserved->interruptStatisticsArray); 5960 5961 /* 5962 * If there is no existing entry, we are most likely trying to 5963 * free an interrupt owner twice, or we have corrupted the 5964 * index value. 5965 */ 5966 value = reserved->interruptStatisticsArray[source].statistics; 5967 5968 if (!value) { 5969 panic("removeInterruptStatistics called for empty index %d", source); 5970 } 5971 5972 /* 5973 * We update the statistics, so that any delta with the reporter 5974 * state is not lost. 5975 */ 5976 interruptAccountingDataUpdateChannels(reserved->interruptStatisticsArray[source].statistics, reserved->interruptStatisticsArray[source].reporter); 5977 reserved->interruptStatisticsArray[source].statistics = NULL; 5978 IOLockUnlock(reserved->interruptStatisticsLock); 5979 5980 return kIOReturnSuccess; 5981} 5982 5983IOReturn IOService::getInterruptType(int source, int *interruptType) 5984{ 5985 IOInterruptController *interruptController; 5986 IOReturn ret; 5987 5988 ret = lookupInterrupt(source, true, &interruptController); 5989 if (ret != kIOReturnSuccess) return ret; 5990 5991 /* Return the type */ 5992 return interruptController->getInterruptType(this, source, interruptType); 5993} 5994 5995IOReturn IOService::enableInterrupt(int source) 5996{ 5997 IOInterruptController *interruptController; 5998 IOReturn ret; 5999 6000 ret = lookupInterrupt(source, false, &interruptController); 6001 if (ret != kIOReturnSuccess) return ret; 6002 6003 /* Enable the source */ 6004 return interruptController->enableInterrupt(this, source); 6005} 6006 6007IOReturn IOService::disableInterrupt(int source) 6008{ 6009 IOInterruptController *interruptController; 6010 IOReturn ret; 6011 6012 ret = lookupInterrupt(source, false, &interruptController); 6013 if (ret != kIOReturnSuccess) return ret; 6014 6015 /* Disable the source */ 6016 return interruptController->disableInterrupt(this, source); 6017} 6018 6019IOReturn IOService::causeInterrupt(int source) 6020{ 6021 IOInterruptController *interruptController; 6022 IOReturn ret; 6023 6024 ret = lookupInterrupt(source, false, &interruptController); 6025 if (ret != kIOReturnSuccess) return ret; 6026 6027 /* Cause an interrupt for the source */ 6028 return interruptController->causeInterrupt(this, source); 6029} 6030 6031IOReturn IOService::configureReport(IOReportChannelList *channelList, 6032 IOReportConfigureAction action, 6033 void *result, 6034 void *destination) 6035{ 6036 unsigned cnt; 6037 6038 for (cnt = 0; cnt < channelList->nchannels; cnt++) { 6039 if ( channelList->channels[cnt].channel_id == kPMPowerStatesChID ) { 6040 if (pwrMgt) configurePowerStatesReport(action, result); 6041 else return kIOReturnUnsupported; 6042 } 6043 else if ( channelList->channels[cnt].channel_id == kPMCurrStateChID ) { 6044 if (pwrMgt) configureSimplePowerReport(action, result); 6045 else return kIOReturnUnsupported; 6046 } 6047 } 6048 6049 IOLockLock(reserved->interruptStatisticsLock); 6050 6051 /* The array count is signed (because the interrupt indices are signed), hence the cast */ 6052 for (cnt = 0; cnt < (unsigned) reserved->interruptStatisticsArrayCount; cnt++) { 6053 if (reserved->interruptStatisticsArray[cnt].reporter) { 6054 /* 6055 * If the reporter is currently associated with the statistics 6056 * for an event source, we may need to update the reporter. 6057 */ 6058 if (reserved->interruptStatisticsArray[cnt].statistics) 6059 interruptAccountingDataUpdateChannels(reserved->interruptStatisticsArray[cnt].statistics, reserved->interruptStatisticsArray[cnt].reporter); 6060 6061 reserved->interruptStatisticsArray[cnt].reporter->configureReport(channelList, action, result, destination); 6062 } 6063 } 6064 6065 IOLockUnlock(reserved->interruptStatisticsLock); 6066 6067 return kIOReturnSuccess; 6068} 6069 6070IOReturn IOService::updateReport(IOReportChannelList *channelList, 6071 IOReportUpdateAction action, 6072 void *result, 6073 void *destination) 6074{ 6075 unsigned cnt; 6076 6077 for (cnt = 0; cnt < channelList->nchannels; cnt++) { 6078 if ( channelList->channels[cnt].channel_id == kPMPowerStatesChID ) { 6079 if (pwrMgt) updatePowerStatesReport(action, result, destination); 6080 else return kIOReturnUnsupported; 6081 } 6082 else if ( channelList->channels[cnt].channel_id == kPMCurrStateChID ) { 6083 if (pwrMgt) updateSimplePowerReport(action, result, destination); 6084 else return kIOReturnUnsupported; 6085 } 6086 } 6087 6088 IOLockLock(reserved->interruptStatisticsLock); 6089 6090 /* The array count is signed (because the interrupt indices are signed), hence the cast */ 6091 for (cnt = 0; cnt < (unsigned) reserved->interruptStatisticsArrayCount; cnt++) { 6092 if (reserved->interruptStatisticsArray[cnt].reporter) { 6093 /* 6094 * If the reporter is currently associated with the statistics 6095 * for an event source, we need to update the reporter. 6096 */ 6097 if (reserved->interruptStatisticsArray[cnt].statistics) 6098 interruptAccountingDataUpdateChannels(reserved->interruptStatisticsArray[cnt].statistics, reserved->interruptStatisticsArray[cnt].reporter); 6099 6100 reserved->interruptStatisticsArray[cnt].reporter->updateReport(channelList, action, result, destination); 6101 } 6102 } 6103 6104 IOLockUnlock(reserved->interruptStatisticsLock); 6105 6106 return kIOReturnSuccess; 6107} 6108 6109uint64_t IOService::getAuthorizationID( void ) 6110{ 6111 return reserved->authorizationID; 6112} 6113 6114IOReturn IOService::setAuthorizationID( uint64_t authorizationID ) 6115{ 6116 OSObject * entitlement; 6117 IOReturn status; 6118 6119 entitlement = IOUserClient::copyClientEntitlement( current_task( ), "com.apple.private.iokit.IOServiceSetAuthorizationID" ); 6120 6121 if ( entitlement ) 6122 { 6123 if ( entitlement == kOSBooleanTrue ) 6124 { 6125 reserved->authorizationID = authorizationID; 6126 6127 status = kIOReturnSuccess; 6128 } 6129 else 6130 { 6131 status = kIOReturnNotPrivileged; 6132 } 6133 6134 entitlement->release( ); 6135 } 6136 else 6137 { 6138 status = kIOReturnNotPrivileged; 6139 } 6140 6141 return status; 6142} 6143 6144#if __LP64__ 6145OSMetaClassDefineReservedUsed(IOService, 0); 6146OSMetaClassDefineReservedUsed(IOService, 1); 6147OSMetaClassDefineReservedUnused(IOService, 2); 6148OSMetaClassDefineReservedUnused(IOService, 3); 6149OSMetaClassDefineReservedUnused(IOService, 4); 6150OSMetaClassDefineReservedUnused(IOService, 5); 6151OSMetaClassDefineReservedUnused(IOService, 6); 6152OSMetaClassDefineReservedUnused(IOService, 7); 6153#else 6154OSMetaClassDefineReservedUsed(IOService, 0); 6155OSMetaClassDefineReservedUsed(IOService, 1); 6156OSMetaClassDefineReservedUsed(IOService, 2); 6157OSMetaClassDefineReservedUsed(IOService, 3); 6158OSMetaClassDefineReservedUsed(IOService, 4); 6159OSMetaClassDefineReservedUsed(IOService, 5); 6160OSMetaClassDefineReservedUsed(IOService, 6); 6161OSMetaClassDefineReservedUsed(IOService, 7); 6162#endif 6163OSMetaClassDefineReservedUnused(IOService, 8); 6164OSMetaClassDefineReservedUnused(IOService, 9); 6165OSMetaClassDefineReservedUnused(IOService, 10); 6166OSMetaClassDefineReservedUnused(IOService, 11); 6167OSMetaClassDefineReservedUnused(IOService, 12); 6168OSMetaClassDefineReservedUnused(IOService, 13); 6169OSMetaClassDefineReservedUnused(IOService, 14); 6170OSMetaClassDefineReservedUnused(IOService, 15); 6171OSMetaClassDefineReservedUnused(IOService, 16); 6172OSMetaClassDefineReservedUnused(IOService, 17); 6173OSMetaClassDefineReservedUnused(IOService, 18); 6174OSMetaClassDefineReservedUnused(IOService, 19); 6175OSMetaClassDefineReservedUnused(IOService, 20); 6176OSMetaClassDefineReservedUnused(IOService, 21); 6177OSMetaClassDefineReservedUnused(IOService, 22); 6178OSMetaClassDefineReservedUnused(IOService, 23); 6179OSMetaClassDefineReservedUnused(IOService, 24); 6180OSMetaClassDefineReservedUnused(IOService, 25); 6181OSMetaClassDefineReservedUnused(IOService, 26); 6182OSMetaClassDefineReservedUnused(IOService, 27); 6183OSMetaClassDefineReservedUnused(IOService, 28); 6184OSMetaClassDefineReservedUnused(IOService, 29); 6185OSMetaClassDefineReservedUnused(IOService, 30); 6186OSMetaClassDefineReservedUnused(IOService, 31); 6187OSMetaClassDefineReservedUnused(IOService, 32); 6188OSMetaClassDefineReservedUnused(IOService, 33); 6189OSMetaClassDefineReservedUnused(IOService, 34); 6190OSMetaClassDefineReservedUnused(IOService, 35); 6191OSMetaClassDefineReservedUnused(IOService, 36); 6192OSMetaClassDefineReservedUnused(IOService, 37); 6193OSMetaClassDefineReservedUnused(IOService, 38); 6194OSMetaClassDefineReservedUnused(IOService, 39); 6195OSMetaClassDefineReservedUnused(IOService, 40); 6196OSMetaClassDefineReservedUnused(IOService, 41); 6197OSMetaClassDefineReservedUnused(IOService, 42); 6198OSMetaClassDefineReservedUnused(IOService, 43); 6199OSMetaClassDefineReservedUnused(IOService, 44); 6200OSMetaClassDefineReservedUnused(IOService, 45); 6201OSMetaClassDefineReservedUnused(IOService, 46); 6202OSMetaClassDefineReservedUnused(IOService, 47); 6203