2 * Copyright (c) 1998-2016 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 #include <IOKit/system.h>
30 #include <IOKit/IOService.h>
31 #include <libkern/OSDebug.h>
32 #include <libkern/c++/OSContainers.h>
33 #include <libkern/c++/OSKext.h>
34 #include <libkern/c++/OSUnserialize.h>
35 #include <libkern/c++/OSKext.h>
36 #include <libkern/c++/OSSharedPtr.h>
37 #include <libkern/Block.h>
38 #include <IOKit/IOCatalogue.h>
39 #include <IOKit/IOCommand.h>
40 #include <IOKit/IODeviceTreeSupport.h>
41 #include <IOKit/IODeviceMemory.h>
42 #include <IOKit/IOInterrupts.h>
43 #include <IOKit/IOInterruptController.h>
44 #include <IOKit/IOPlatformExpert.h>
45 #include <IOKit/IOMessage.h>
46 #include <IOKit/IOLib.h>
47 #include <IOKit/IOKitKeysPrivate.h>
48 #include <IOKit/IOBSD.h>
49 #include <IOKit/IOUserClient.h>
50 #include <IOKit/IOUserServer.h>
51 #include <IOKit/IOWorkLoop.h>
52 #include <IOKit/IOTimeStamp.h>
53 #include <IOKit/IOHibernatePrivate.h>
54 #include <IOKit/IOInterruptAccountingPrivate.h>
55 #include <IOKit/IOKernelReporters.h>
56 #include <IOKit/AppleKeyStoreInterface.h>
57 #include <IOKit/pwr_mgt/RootDomain.h>
58 #include <IOKit/IOCPU.h>
59 #include <mach/sync_policy.h>
60 #include <mach/thread_info.h>
61 #include <IOKit/assert.h>
62 #include <sys/errno.h>
63 #include <sys/kdebug.h>
66 #include <machine/pal_routines.h>
71 #define IOSERVICE_OBFUSCATE(x) ((void *)(VM_KERNEL_ADDRPERM(x)))
73 // disabled since lockForArbitration() can be held externally
74 #define DEBUG_NOTIFIER_LOCKED 0
77 kIOUserServerCheckInTimeoutSecs
= 120ULL
80 #include "IOServicePrivate.h"
81 #include "IOKitKernelInternal.h"
83 // take lockForArbitration before LOCKNOTIFY
85 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
87 #define super IORegistryEntry
89 OSDefineMetaClassAndStructors(IOService
, IORegistryEntry
)
91 OSDefineMetaClassAndStructors(_IOServiceNotifier
, IONotifier
)
92 OSDefineMetaClassAndStructors(_IOServiceNullNotifier
, IONotifier
)
94 OSDefineMetaClassAndStructors(_IOServiceInterestNotifier
, IONotifier
)
96 OSDefineMetaClassAndStructors(_IOConfigThread
, OSObject
)
98 OSDefineMetaClassAndStructors(_IOServiceJob
, OSObject
)
100 OSDefineMetaClassAndStructors(IOResources
, IOService
)
101 OSDefineMetaClassAndStructors(IOUserResources
, IOService
)
103 OSDefineMetaClassAndStructors(_IOOpenServiceIterator
, OSIterator
)
105 OSDefineMetaClassAndAbstractStructors(IONotifier
, OSObject
)
107 OSDefineMetaClassAndStructors(IOServiceCompatibility
, IOService
)
109 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
111 static IOPlatformExpert
* gIOPlatform
;
112 static class IOPMrootDomain
* gIOPMRootDomain
;
113 const IORegistryPlane
* gIOServicePlane
;
114 const IORegistryPlane
* gIOPowerPlane
;
115 const OSSymbol
* gIODeviceMemoryKey
;
116 const OSSymbol
* gIOInterruptControllersKey
;
117 const OSSymbol
* gIOInterruptSpecifiersKey
;
119 const OSSymbol
* gIOResourcesKey
;
120 const OSSymbol
* gIOUserResourcesKey
;
121 const OSSymbol
* gIOResourceMatchKey
;
122 const OSSymbol
* gIOResourceMatchedKey
;
123 const OSSymbol
* gIOResourceIOKitKey
;
125 const OSSymbol
* gIOProviderClassKey
;
126 const OSSymbol
* gIONameMatchKey
;
127 const OSSymbol
* gIONameMatchedKey
;
128 const OSSymbol
* gIOPropertyMatchKey
;
129 const OSSymbol
* gIOPropertyExistsMatchKey
;
130 const OSSymbol
* gIOLocationMatchKey
;
131 const OSSymbol
* gIOParentMatchKey
;
132 const OSSymbol
* gIOPathMatchKey
;
133 const OSSymbol
* gIOMatchCategoryKey
;
134 const OSSymbol
* gIODefaultMatchCategoryKey
;
135 const OSSymbol
* gIOMatchedServiceCountKey
;
136 const OSSymbol
* gIOMatchedPersonalityKey
;
137 const OSSymbol
* gIORematchPersonalityKey
;
138 const OSSymbol
* gIORematchCountKey
;
139 const OSSymbol
* gIODEXTMatchCountKey
;
140 const OSSymbol
* gIOSupportedPropertiesKey
;
141 const OSSymbol
* gIOUserServicePropertiesKey
;
142 #if defined(XNU_TARGET_OS_OSX)
143 const OSSymbol
* gIOServiceLegacyMatchingRegistryIDKey
;
144 #endif /* defined(XNU_TARGET_OS_OSX) */
146 const OSSymbol
* gIOCompatibilityMatchKey
;
147 const OSSymbol
* gIOCompatibilityPropertiesKey
;
148 const OSSymbol
* gIOPathKey
;
150 const OSSymbol
* gIOMapperIDKey
;
151 const OSSymbol
* gIOUserClientClassKey
;
153 const OSSymbol
* gIOUserClassKey
;
154 const OSSymbol
* gIOUserServerClassKey
;
155 const OSSymbol
* gIOUserServerNameKey
;
156 const OSSymbol
* gIOUserServerTagKey
;
157 const OSSymbol
* gIOUserUserClientKey
;
159 const OSSymbol
* gIOKitDebugKey
;
161 const OSSymbol
* gIOCommandPoolSizeKey
;
163 const OSSymbol
* gIOConsoleLockedKey
;
164 const OSSymbol
* gIOConsoleUsersKey
;
165 const OSSymbol
* gIOConsoleSessionUIDKey
;
166 const OSSymbol
* gIOConsoleSessionAuditIDKey
;
167 const OSSymbol
* gIOConsoleUsersSeedKey
;
168 const OSSymbol
* gIOConsoleSessionOnConsoleKey
;
169 const OSSymbol
* gIOConsoleSessionLoginDoneKey
;
170 const OSSymbol
* gIOConsoleSessionSecureInputPIDKey
;
171 const OSSymbol
* gIOConsoleSessionScreenLockedTimeKey
;
172 const OSSymbol
* gIOConsoleSessionScreenIsLockedKey
;
173 clock_sec_t gIOConsoleLockTime
;
174 static bool gIOConsoleLoggedIn
;
176 static OSBoolean
* gIOConsoleBooterLockState
;
177 static uint32_t gIOScreenLockState
;
179 static IORegistryEntry
* gIOChosenEntry
;
181 static int gIOResourceGenerationCount
;
183 const OSSymbol
* gIOServiceKey
;
184 const OSSymbol
* gIOPublishNotification
;
185 const OSSymbol
* gIOFirstPublishNotification
;
186 const OSSymbol
* gIOMatchedNotification
;
187 const OSSymbol
* gIOFirstMatchNotification
;
188 const OSSymbol
* gIOTerminatedNotification
;
189 const OSSymbol
* gIOWillTerminateNotification
;
191 const OSSymbol
* gIOServiceDEXTEntitlementsKey
;
192 const OSSymbol
* gIODriverKitEntitlementKey
;
193 const OSSymbol
* gIODriverKitUserClientEntitlementsKey
;
194 const OSSymbol
* gIODriverKitUserClientEntitlementAllowAnyKey
;
195 const OSSymbol
* gIOMatchDeferKey
;
196 const OSSymbol
* gIOAllCPUInitializedKey
;
198 const OSSymbol
* gIOGeneralInterest
;
199 const OSSymbol
* gIOBusyInterest
;
200 const OSSymbol
* gIOAppPowerStateInterest
;
201 const OSSymbol
* gIOPriorityPowerStateInterest
;
202 const OSSymbol
* gIOConsoleSecurityInterest
;
204 const OSSymbol
* gIOBSDKey
;
205 const OSSymbol
* gIOBSDNameKey
;
206 const OSSymbol
* gIOBSDMajorKey
;
207 const OSSymbol
* gIOBSDMinorKey
;
208 const OSSymbol
* gIOBSDUnitKey
;
210 const OSSymbol
* gAKSGetKey
;
211 #if defined(__i386__) || defined(__x86_64__)
212 const OSSymbol
* gIOCreateEFIDevicePathSymbol
;
215 static OSDictionary
* gNotifications
;
216 static IORecursiveLock
* gNotificationLock
;
218 static IOService
* gIOResources
;
219 static IOService
* gIOUserResources
;
220 static IOService
* gIOServiceRoot
;
222 static OSOrderedSet
* gJobs
;
223 static semaphore_port_t gJobsSemaphore
;
224 static IOLock
* gJobsLock
;
225 static int gOutstandingJobs
;
226 static int gNumConfigThreads
;
227 static int gHighNumConfigThreads
;
228 static int gMaxConfigThreads
= kMaxConfigThreads
;
229 static int gNumWaitingThreads
;
230 static IOLock
* gIOServiceBusyLock
;
232 bool gIOKitWillTerminate
;
233 bool gInUserspaceReboot
;
235 static thread_t gIOTerminateThread
;
236 static thread_t gIOTerminateWorkerThread
;
237 static UInt32 gIOTerminateWork
;
238 static OSArray
* gIOTerminatePhase2List
;
239 static OSArray
* gIOStopList
;
240 static OSArray
* gIOStopProviderList
;
241 static OSArray
* gIOFinalizeList
;
244 static OSArray
* gIOMatchDeferList
;
247 static SInt32 gIOConsoleUsersSeed
;
248 static OSData
* gIOConsoleUsersSeedValue
;
250 extern const OSSymbol
* gIODTPHandleKey
;
252 const OSSymbol
* gIOPlatformFunctionHandlerSet
;
255 static IOLock
* gIOConsoleUsersLock
;
256 static thread_call_t gIOConsoleLockCallout
;
257 static IONotifier
* gIOServiceNullNotifier
;
259 static uint32_t gIODextRelaunchMax
= 1000;
261 #if DEVELOPMENT || DEBUG
262 uint64_t driverkit_checkin_timed_out
= 0;
265 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
267 #define LOCKREADNOTIFY() \
268 IORecursiveLockLock( gNotificationLock )
269 #define LOCKWRITENOTIFY() \
270 IORecursiveLockLock( gNotificationLock )
271 #define LOCKWRITE2READNOTIFY()
272 #define UNLOCKNOTIFY() \
273 IORecursiveLockUnlock( gNotificationLock )
274 #define SLEEPNOTIFY(event) \
275 IORecursiveLockSleep( gNotificationLock, (void *)(event), THREAD_UNINT )
276 #define SLEEPNOTIFYTO(event, deadline) \
277 IORecursiveLockSleepDeadline( gNotificationLock, (void *)(event), deadline, THREAD_UNINT )
278 #define WAKEUPNOTIFY(event) \
279 IORecursiveLockWakeup( gNotificationLock, (void *)(event), /* wake one */ false )
281 #define randomDelay() \
282 int del = read_processor_clock(); \
283 del = (((int)IOThreadSelf()) ^ del ^ (del >> 10)) & 0x3ff; \
286 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
288 #define queue_element(entry, element, type, field) do { \
289 vm_address_t __ele = (vm_address_t) (entry); \
290 __ele -= -4 + ((size_t)(&((type) 4)->field)); \
291 (element) = (type) __ele; \
294 #define iterqueue(que, elt) \
295 for (queue_entry_t elt = queue_first(que); \
296 !queue_end(que, elt); \
297 elt = queue_next(elt))
299 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
301 struct IOInterruptAccountingReporter
{
302 IOSimpleReporter
* reporter
; /* Reporter responsible for communicating the statistics */
303 IOInterruptAccountingData
* statistics
; /* The live statistics values, if any */
306 struct ArbitrationLockQueueElement
{
315 static queue_head_t gArbitrationLockQueueActive
;
316 static queue_head_t gArbitrationLockQueueWaiting
;
317 static queue_head_t gArbitrationLockQueueFree
;
318 static IOLock
* gArbitrationLockQueueLock
;
321 IOService::isInactive( void ) const
323 return 0 != (kIOServiceInactiveState
& getState());
326 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
328 // Only used by the intel implementation of
329 // IOService::requireMaxBusStall(UInt32 ns)
330 // IOService::requireMaxInterruptDelay(uint32_t ns)
331 struct CpuDelayEntry
{
332 IOService
* fService
;
339 #if defined(__x86_64__)
341 #endif /* defined(__x86_64__) */
345 static OSData
*sCpuDelayData
= OSData::withCapacity(8 * sizeof(CpuDelayEntry
));
346 static IORecursiveLock
*sCpuDelayLock
= IORecursiveLockAlloc();
347 static OSArray
*sCpuLatencyHandlers
[kCpuNumDelayTypes
];
348 const OSSymbol
*sCPULatencyFunctionName
[kCpuNumDelayTypes
];
349 static OSNumber
* sCPULatencyHolder
[kCpuNumDelayTypes
];
350 static char sCPULatencyHolderName
[kCpuNumDelayTypes
][128];
351 static OSNumber
* sCPULatencySet
[kCpuNumDelayTypes
];
354 requireMaxCpuDelay(IOService
* service
, UInt32 ns
, UInt32 delayType
);
356 setLatencyHandler(UInt32 delayType
, IOService
* target
, bool enable
);
358 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
360 static IOMessage sSystemPower
;
362 namespace IOServicePH
364 IONotifier
* fRootNotifier
;
365 OSArray
* fUserServers
;
366 OSArray
* fUserServersWait
;
367 OSArray
* fMatchingWork
;
368 OSArray
* fMatchingDelayed
;
369 IOService
* fSystemPowerAckTo
;
370 uint32_t fSystemPowerAckRef
;
372 uint8_t fUserServerOff
;
377 void init(IOPMrootDomain
* root
);
379 IOReturn
systemPowerChange(
382 UInt32 messageType
, IOService
* service
,
383 void * messageArgument
, vm_size_t argSize
);
385 bool matchingStart(IOService
* service
);
386 void matchingEnd(IOService
* service
);
389 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
392 IOService::initialize( void )
396 gIOServicePlane
= IORegistryEntry::makePlane( kIOServicePlane
);
397 gIOPowerPlane
= IORegistryEntry::makePlane( kIOPowerPlane
);
399 gIOProviderClassKey
= OSSymbol::withCStringNoCopy( kIOProviderClassKey
);
400 gIONameMatchKey
= OSSymbol::withCStringNoCopy( kIONameMatchKey
);
401 gIONameMatchedKey
= OSSymbol::withCStringNoCopy( kIONameMatchedKey
);
402 gIOPropertyMatchKey
= OSSymbol::withCStringNoCopy( kIOPropertyMatchKey
);
403 gIOPropertyExistsMatchKey
= OSSymbol::withCStringNoCopy( kIOPropertyExistsMatchKey
);
404 gIOPathMatchKey
= OSSymbol::withCStringNoCopy( kIOPathMatchKey
);
405 gIOLocationMatchKey
= OSSymbol::withCStringNoCopy( kIOLocationMatchKey
);
406 gIOParentMatchKey
= OSSymbol::withCStringNoCopy( kIOParentMatchKey
);
408 gIOMatchCategoryKey
= OSSymbol::withCStringNoCopy( kIOMatchCategoryKey
);
409 gIODefaultMatchCategoryKey
= OSSymbol::withCStringNoCopy(
410 kIODefaultMatchCategoryKey
);
411 gIOMatchedServiceCountKey
= OSSymbol::withCStringNoCopy(
412 kIOMatchedServiceCountKey
);
413 gIOMatchedPersonalityKey
= OSSymbol::withCStringNoCopy(
414 kIOMatchedPersonalityKey
);
415 gIORematchPersonalityKey
= OSSymbol::withCStringNoCopy(
416 kIORematchPersonalityKey
);
417 gIORematchCountKey
= OSSymbol::withCStringNoCopy(
418 kIORematchCountKey
);
419 gIODEXTMatchCountKey
= OSSymbol::withCStringNoCopy(
420 kIODEXTMatchCountKey
);
422 #if defined(XNU_TARGET_OS_OSX)
423 gIOServiceLegacyMatchingRegistryIDKey
= OSSymbol::withCStringNoCopy(
424 kIOServiceLegacyMatchingRegistryIDKey
);
425 #endif /* defined(XNU_TARGET_OS_OSX) */
427 PE_parse_boot_argn("dextrelaunch", &gIODextRelaunchMax
, sizeof(gIODextRelaunchMax
));
428 PE_parse_boot_argn("iocthreads", &gMaxConfigThreads
, sizeof(gMaxConfigThreads
));
430 gIOUserClientClassKey
= OSSymbol::withCStringNoCopy( kIOUserClientClassKey
);
432 gIOUserClassKey
= OSSymbol::withCStringNoCopy(kIOUserClassKey
);
434 gIOUserServerClassKey
= OSSymbol::withCStringNoCopy(kIOUserServerClassKey
);
435 gIOUserServerNameKey
= OSSymbol::withCStringNoCopy(kIOUserServerNameKey
);
436 gIOUserServerTagKey
= OSSymbol::withCStringNoCopy(kIOUserServerTagKey
);
437 gIOUserUserClientKey
= OSSymbol::withCStringNoCopy(kIOUserUserClientKey
);
439 gIOResourcesKey
= OSSymbol::withCStringNoCopy( kIOResourcesClass
);
440 gIOResourceMatchKey
= OSSymbol::withCStringNoCopy( kIOResourceMatchKey
);
441 gIOResourceMatchedKey
= OSSymbol::withCStringNoCopy( kIOResourceMatchedKey
);
442 gIOResourceIOKitKey
= OSSymbol::withCStringNoCopy("IOKit");
444 gIODeviceMemoryKey
= OSSymbol::withCStringNoCopy( "IODeviceMemory" );
445 gIOInterruptControllersKey
446 = OSSymbol::withCStringNoCopy("IOInterruptControllers");
447 gIOInterruptSpecifiersKey
448 = OSSymbol::withCStringNoCopy("IOInterruptSpecifiers");
450 gIOCompatibilityMatchKey
= OSSymbol::withCStringNoCopy(kIOCompatibilityMatchKey
);
451 gIOCompatibilityPropertiesKey
= OSSymbol::withCStringNoCopy(kIOCompatibilityPropertiesKey
);
452 gIOPathKey
= OSSymbol::withCStringNoCopy(kIOPathKey
);
453 gIOSupportedPropertiesKey
= OSSymbol::withCStringNoCopy(kIOSupportedPropertiesKey
);
454 gIOUserServicePropertiesKey
= OSSymbol::withCStringNoCopy(kIOUserServicePropertiesKey
);
456 gIOMapperIDKey
= OSSymbol::withCStringNoCopy(kIOMapperIDKey
);
458 gIOKitDebugKey
= OSSymbol::withCStringNoCopy( kIOKitDebugKey
);
460 gIOCommandPoolSizeKey
= OSSymbol::withCStringNoCopy( kIOCommandPoolSizeKey
);
462 gIOGeneralInterest
= OSSymbol::withCStringNoCopy( kIOGeneralInterest
);
463 gIOBusyInterest
= OSSymbol::withCStringNoCopy( kIOBusyInterest
);
464 gIOAppPowerStateInterest
= OSSymbol::withCStringNoCopy( kIOAppPowerStateInterest
);
465 gIOPriorityPowerStateInterest
= OSSymbol::withCStringNoCopy( kIOPriorityPowerStateInterest
);
466 gIOConsoleSecurityInterest
= OSSymbol::withCStringNoCopy( kIOConsoleSecurityInterest
);
468 gIOBSDKey
= OSSymbol::withCStringNoCopy(kIOBSDKey
);
469 gIOBSDNameKey
= OSSymbol::withCStringNoCopy(kIOBSDNameKey
);
470 gIOBSDMajorKey
= OSSymbol::withCStringNoCopy(kIOBSDMajorKey
);
471 gIOBSDMinorKey
= OSSymbol::withCStringNoCopy(kIOBSDMinorKey
);
472 gIOBSDUnitKey
= OSSymbol::withCStringNoCopy(kIOBSDUnitKey
);
474 gNotifications
= OSDictionary::withCapacity( 1 );
475 gIOPublishNotification
= OSSymbol::withCStringNoCopy(
476 kIOPublishNotification
);
477 gIOFirstPublishNotification
= OSSymbol::withCStringNoCopy(
478 kIOFirstPublishNotification
);
479 gIOMatchedNotification
= OSSymbol::withCStringNoCopy(
480 kIOMatchedNotification
);
481 gIOFirstMatchNotification
= OSSymbol::withCStringNoCopy(
482 kIOFirstMatchNotification
);
483 gIOTerminatedNotification
= OSSymbol::withCStringNoCopy(
484 kIOTerminatedNotification
);
485 gIOWillTerminateNotification
= OSSymbol::withCStringNoCopy(
486 kIOWillTerminateNotification
);
487 gIOServiceKey
= OSSymbol::withCStringNoCopy( kIOServiceClass
);
490 gIOConsoleLockedKey
= OSSymbol::withCStringNoCopy( kIOConsoleLockedKey
);
491 gIOConsoleUsersKey
= OSSymbol::withCStringNoCopy( kIOConsoleUsersKey
);
492 gIOConsoleSessionUIDKey
= OSSymbol::withCStringNoCopy( kIOConsoleSessionUIDKey
);
493 gIOConsoleSessionAuditIDKey
= OSSymbol::withCStringNoCopy( kIOConsoleSessionAuditIDKey
);
495 gIOConsoleUsersSeedKey
= OSSymbol::withCStringNoCopy(kIOConsoleUsersSeedKey
);
496 gIOConsoleSessionOnConsoleKey
= OSSymbol::withCStringNoCopy(kIOConsoleSessionOnConsoleKey
);
497 gIOConsoleSessionLoginDoneKey
= OSSymbol::withCStringNoCopy(kIOConsoleSessionLoginDoneKey
);
498 gIOConsoleSessionSecureInputPIDKey
= OSSymbol::withCStringNoCopy(kIOConsoleSessionSecureInputPIDKey
);
499 gIOConsoleSessionScreenLockedTimeKey
= OSSymbol::withCStringNoCopy(kIOConsoleSessionScreenLockedTimeKey
);
500 gIOConsoleSessionScreenIsLockedKey
= OSSymbol::withCStringNoCopy(kIOConsoleSessionScreenIsLockedKey
);
502 gIOConsoleUsersSeedValue
= OSData::withBytesNoCopy(&gIOConsoleUsersSeed
, sizeof(gIOConsoleUsersSeed
));
504 gIOServiceDEXTEntitlementsKey
= OSSymbol::withCStringNoCopy( kIOServiceDEXTEntitlementsKey
);
505 gIODriverKitEntitlementKey
= OSSymbol::withCStringNoCopy( kIODriverKitEntitlementKey
);
506 gIODriverKitUserClientEntitlementsKey
= OSSymbol::withCStringNoCopy( kIODriverKitUserClientEntitlementsKey
);
507 gIODriverKitUserClientEntitlementAllowAnyKey
= OSSymbol::withCStringNoCopy( kIODriverKitUserClientEntitlementAllowAnyKey
);
508 gIOMatchDeferKey
= OSSymbol::withCStringNoCopy( kIOMatchDeferKey
);
509 gIOAllCPUInitializedKey
= OSSymbol::withCStringNoCopy( kIOAllCPUInitializedKey
);
511 gIOPlatformFunctionHandlerSet
= OSSymbol::withCStringNoCopy(kIOPlatformFunctionHandlerSet
);
512 sCPULatencyFunctionName
[kCpuDelayBusStall
] = OSSymbol::withCStringNoCopy(kIOPlatformFunctionHandlerMaxBusDelay
);
513 #if defined(__x86_64__)
514 sCPULatencyFunctionName
[kCpuDelayInterrupt
] = OSSymbol::withCStringNoCopy(kIOPlatformFunctionHandlerMaxInterruptDelay
);
515 #endif /* defined(__x86_64__) */
517 for (idx
= 0; idx
< kCpuNumDelayTypes
; idx
++) {
518 sCPULatencySet
[idx
] = OSNumber::withNumber(UINT_MAX
, 32);
519 sCPULatencyHolder
[idx
] = OSNumber::withNumber(0ULL, 64);
520 assert(sCPULatencySet
[idx
] && sCPULatencyHolder
[idx
]);
523 #if defined(__x86_64__)
524 gIOCreateEFIDevicePathSymbol
= OSSymbol::withCString("CreateEFIDevicePath");
525 #endif /* defined(__x86_64__) */
527 gNotificationLock
= IORecursiveLockAlloc();
529 gAKSGetKey
= OSSymbol::withCStringNoCopy(AKS_PLATFORM_FUNCTION_GETKEY
);
531 assert( gIOServicePlane
&& gIODeviceMemoryKey
532 && gIOInterruptControllersKey
&& gIOInterruptSpecifiersKey
533 && gIOResourcesKey
&& gNotifications
&& gNotificationLock
534 && gIOProviderClassKey
&& gIONameMatchKey
&& gIONameMatchedKey
535 && gIOMatchCategoryKey
&& gIODefaultMatchCategoryKey
536 && gIOPublishNotification
&& gIOMatchedNotification
537 && gIOTerminatedNotification
&& gIOServiceKey
538 && gIOConsoleUsersKey
&& gIOConsoleSessionUIDKey
539 && gIOConsoleSessionOnConsoleKey
&& gIOConsoleSessionSecureInputPIDKey
540 && gIOConsoleUsersSeedKey
&& gIOConsoleUsersSeedValue
);
542 gJobsLock
= IOLockAlloc();
543 gJobs
= OSOrderedSet::withCapacity( 10 );
545 gIOServiceBusyLock
= IOLockAlloc();
547 gIOConsoleUsersLock
= IOLockAlloc();
549 err
= semaphore_create(kernel_task
, &gJobsSemaphore
, SYNC_POLICY_FIFO
, 0);
551 gIOConsoleLockCallout
= thread_call_allocate(&IOService::consoleLockTimer
, NULL
);
553 IORegistryEntry::getRegistryRoot()->setProperty(gIOConsoleLockedKey
, kOSBooleanTrue
);
555 assert( gIOServiceBusyLock
&& gJobs
&& gJobsLock
&& gIOConsoleUsersLock
556 && gIOConsoleLockCallout
&& (err
== KERN_SUCCESS
));
558 gIOResources
= IOResources::resources();
559 gIOUserResources
= IOUserResources::resources();
560 assert( gIOResources
&& gIOUserResources
);
562 gIOServiceNullNotifier
= OSTypeAlloc(_IOServiceNullNotifier
);
563 assert(gIOServiceNullNotifier
);
565 gArbitrationLockQueueLock
= IOLockAlloc();
566 queue_init(&gArbitrationLockQueueActive
);
567 queue_init(&gArbitrationLockQueueWaiting
);
568 queue_init(&gArbitrationLockQueueFree
);
570 assert( gArbitrationLockQueueLock
);
572 gIOTerminatePhase2List
= OSArray::withCapacity( 2 );
573 gIOStopList
= OSArray::withCapacity( 16 );
574 gIOStopProviderList
= OSArray::withCapacity( 16 );
575 gIOFinalizeList
= OSArray::withCapacity( 16 );
577 gIOMatchDeferList
= OSArray::withCapacity( 16 );
579 assert( gIOTerminatePhase2List
&& gIOStopList
&& gIOStopProviderList
&& gIOFinalizeList
);
581 // worker thread that is responsible for terminating / cleaning up threads
582 kernel_thread_start(&terminateThread
, NULL
, &gIOTerminateWorkerThread
);
583 assert(gIOTerminateWorkerThread
);
584 thread_set_thread_name(gIOTerminateWorkerThread
, "IOServiceTerminateThread");
587 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
589 #if defined(__x86_64__)
591 const char *getCpuDelayBusStallHolderName(void);
593 getCpuDelayBusStallHolderName(void)
595 return sCPULatencyHolderName
[kCpuDelayBusStall
];
598 const char *getCpuInterruptDelayHolderName(void);
600 getCpuInterruptDelayHolderName(void)
602 return sCPULatencyHolderName
[kCpuDelayInterrupt
];
605 #endif /* defined(__x86_64__) */
611 getDebugFlags( OSDictionary
* props
)
613 OSNumber
* debugProp
;
616 debugProp
= OSDynamicCast( OSNumber
,
617 props
->getObject( gIOKitDebugKey
));
619 debugFlags
= debugProp
->unsigned64BitValue();
621 debugFlags
= gIOKitDebug
;
628 getDebugFlags( IOService
* inst
)
631 OSNumber
* debugProp
;
634 prop
= inst
->copyProperty(gIOKitDebugKey
);
635 debugProp
= OSDynamicCast(OSNumber
, prop
);
637 debugFlags
= debugProp
->unsigned64BitValue();
639 debugFlags
= gIOKitDebug
;
642 OSSafeReleaseNULL(prop
);
648 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
650 // Probe a matched service and return an instance to be started.
651 // The default score is from the property table, & may be altered
652 // during probe to change the start order.
655 IOService::probe( IOService
* provider
,
662 IOService::start( IOService
* provider
)
668 IOService::stop( IOService
* provider
)
670 if (reserved
->uvars
&& reserved
->uvars
->started
&& reserved
->uvars
->userServer
) {
671 reserved
->uvars
->userServer
->serviceStop(this, provider
);
676 IOService::init( OSDictionary
* dictionary
)
680 ret
= super::init(dictionary
);
688 reserved
= IONew(ExpansionData
, 1);
692 bzero(reserved
, sizeof(*reserved
));
695 * TODO: Improve on this. Previous efforts to more lazily allocate this
696 * lock based on the presence of specifiers ran into issues as some
697 * platforms set up the specifiers after IOService initialization.
699 * We may be able to get away with a global lock, as this should only be
700 * contended by IOReporting clients and driver start/stop (unless a
701 * driver wants to remove/add handlers in the course of normal operation,
702 * which should be unlikely).
704 reserved
->interruptStatisticsLock
= IOLockAlloc();
705 if (!reserved
->interruptStatisticsLock
) {
713 IOService::init( IORegistryEntry
* from
,
714 const IORegistryPlane
* inPlane
)
718 ret
= super::init(from
, inPlane
);
726 reserved
= IONew(ExpansionData
, 1);
730 bzero(reserved
, sizeof(*reserved
));
733 * TODO: Improve on this. Previous efforts to more lazily allocate this
734 * lock based on the presence of specifiers ran into issues as some
735 * platforms set up the specifiers after IOService initialization.
737 * We may be able to get away with a global lock, as this should only be
738 * contended by IOReporting clients and driver start/stop (unless a
739 * driver wants to remove/add handlers in the course of normal operation,
740 * which should be unlikely).
742 reserved
->interruptStatisticsLock
= IOLockAlloc();
743 if (!reserved
->interruptStatisticsLock
) {
751 IOService::free( void )
754 requireMaxBusStall(0);
755 #if defined(__x86_64__)
756 requireMaxInterruptDelay(0);
757 #endif /* defined(__x86_64__) */
758 if (getPropertyTable()) {
759 unregisterAllInterest();
764 if (reserved
->interruptStatisticsArray
) {
765 for (i
= 0; i
< reserved
->interruptStatisticsArrayCount
; i
++) {
766 if (reserved
->interruptStatisticsArray
[i
].reporter
) {
767 reserved
->interruptStatisticsArray
[i
].reporter
->release();
771 IODelete(reserved
->interruptStatisticsArray
, IOInterruptAccountingReporter
, reserved
->interruptStatisticsArrayCount
);
774 if (reserved
->interruptStatisticsLock
) {
775 IOLockFree(reserved
->interruptStatisticsLock
);
777 if (reserved
->uvars
&& reserved
->uvars
->userServer
) {
778 reserved
->uvars
->userServer
->serviceFree(this);
780 IODelete(reserved
, ExpansionData
, 1);
783 if (_numInterruptSources
&& _interruptSources
) {
784 for (i
= 0; i
< _numInterruptSources
; i
++) {
785 void * block
= _interruptSourcesPrivate(this)[i
].vectorBlock
;
787 Block_release(block
);
790 IOFree(_interruptSources
,
791 _numInterruptSources
* sizeofAllIOInterruptSource
);
792 _interruptSources
= NULL
;
799 * Attach in service plane
802 IOService::attach( IOService
* provider
)
806 AbsoluteTime deadline
;
807 int waitResult
= THREAD_AWAKENED
;
808 bool wait
, computeDeadline
= true;
811 if (gIOKitDebug
& kIOLogAttach
) {
812 LOG( "%s::attach(%s)\n", getName(),
813 provider
->getName());
819 provider
->lockForArbitration();
820 if (provider
->__state
[0] & kIOServiceInactiveState
) {
823 count
= provider
->getChildCount(gIOServicePlane
);
824 wait
= (count
> (kIOServiceBusyMax
- 4));
826 ok
= attachToParent(provider
, gIOServicePlane
);
828 IOLog("stalling for detach from %s\n", provider
->getName());
829 IOLockLock( gIOServiceBusyLock
);
830 provider
->__state
[1] |= kIOServiceWaitDetachState
;
833 provider
->unlockForArbitration();
835 if (computeDeadline
) {
836 clock_interval_to_deadline(15, kSecondScale
, &deadline
);
837 computeDeadline
= false;
839 assert_wait_deadline((event_t
)&provider
->__provider
, THREAD_UNINT
, deadline
);
840 IOLockUnlock( gIOServiceBusyLock
);
841 waitResult
= thread_block(THREAD_CONTINUE_NULL
);
842 wait
= (waitResult
!= THREAD_TIMED_OUT
);
846 gIOServiceRoot
= this;
847 ok
= attachToParent( getRegistryRoot(), gIOServicePlane
);
850 if (ok
&& !__provider
) {
851 (void) getProvider();
858 IOService::getServiceRoot( void )
860 return gIOServiceRoot
;
864 IOService::detach( IOService
* provider
)
866 IOService
* newProvider
= NULL
;
870 if (gIOKitDebug
& kIOLogAttach
) {
871 LOG("%s::detach(%s)\n", getName(), provider
->getName());
875 IOLockLock(gJobsLock
);
876 if (gIOMatchDeferList
) {
877 auto idx
= gIOMatchDeferList
->getNextIndexOfObject(this, 0);
879 gIOMatchDeferList
->removeObject(idx
);
882 if (IOServicePH::fMatchingDelayed
) {
883 auto idx
= IOServicePH::fMatchingDelayed
->getNextIndexOfObject(this, 0);
885 IOServicePH::fMatchingDelayed
->removeObject(idx
);
888 IOLockUnlock(gJobsLock
);
889 #endif /* NO_KEXTD */
891 lockForArbitration();
893 uint64_t regID1
= provider
->getRegistryEntryID();
894 uint64_t regID2
= getRegistryEntryID();
898 (uintptr_t) (regID1
>> 32),
900 (uintptr_t) (regID2
>> 32));
902 adjParent
= ((busy
= (__state
[1] & kIOServiceBusyStateMask
))
903 && (provider
== getProvider()));
905 detachFromParent( provider
, gIOServicePlane
);
908 newProvider
= getProvider();
909 if (busy
&& (__state
[1] & kIOServiceTermPhase3State
) && (NULL
== newProvider
)) {
910 _adjustBusy( -busy
);
914 if (kIOServiceInactiveState
& __state
[0]) {
915 getMetaClass()->removeInstance(this);
916 IORemoveServicePlatformActions(this);
919 unlockForArbitration();
921 if (newProvider
&& adjParent
) {
922 newProvider
->lockForArbitration();
923 newProvider
->_adjustBusy(1);
924 newProvider
->unlockForArbitration();
927 // check for last client detach from a terminated service
928 if (provider
->lockForArbitration( true )) {
929 if (kIOServiceStartState
& __state
[1]) {
930 provider
->scheduleTerminatePhase2();
933 provider
->_adjustBusy( -1 );
935 if ((provider
->__state
[1] & kIOServiceTermPhase3State
)
936 && (NULL
== provider
->getClient())) {
937 provider
->scheduleFinalize(false);
940 IOLockLock( gIOServiceBusyLock
);
941 if (kIOServiceWaitDetachState
& provider
->__state
[1]) {
942 provider
->__state
[1] &= ~kIOServiceWaitDetachState
;
943 thread_wakeup(&provider
->__provider
);
945 IOLockUnlock( gIOServiceBusyLock
);
947 provider
->unlockForArbitration();
952 * Register instance - publish it for matching
956 IOService::registerService( IOOptionBits options
)
962 enum { kMaxPathLen
= 256 };
963 enum { kMaxChars
= 63 };
965 IORegistryEntry
* parent
= this;
966 IORegistryEntry
* root
= getRegistryRoot();
967 while (parent
&& (parent
!= root
)) {
968 parent
= parent
->getParentEntry( gIOServicePlane
);
971 if (parent
!= root
) {
972 IOLog("%s: not registry member at registerService()\n", getName());
976 // Allow the Platform Expert to adjust this node.
977 if (gIOPlatform
&& (!gIOPlatform
->platformAdjustService(this))) {
981 IOInstallServicePlatformActions(this);
982 IOInstallServiceSleepPlatformActions(this);
984 if ((this != gIOResources
)
985 && (kIOLogRegister
& gIOKitDebug
)) {
986 pathBuf
= (char *) IOMalloc( kMaxPathLen
);
988 IOLog( "Registering: " );
991 if (pathBuf
&& getPath( pathBuf
, &len
, gIOServicePlane
)) {
993 if (len
> kMaxChars
) {
997 if ((skip
= strchr( path
, '/'))) {
1005 IOLog( "%s\n", path
);
1008 IOFree( pathBuf
, kMaxPathLen
);
1012 startMatching( options
);
1016 IOService::startMatching( IOOptionBits options
)
1018 IOService
* provider
;
1019 UInt32 prevBusy
= 0;
1021 bool needWake
= false;
1026 lockForArbitration();
1028 sync
= (options
& kIOServiceSynchronous
)
1029 || ((provider
= getProvider())
1030 && (provider
->__state
[1] & kIOServiceSynchronousState
));
1032 if (options
& kIOServiceAsynchronous
) {
1036 needConfig
= (0 == (__state
[1] & (kIOServiceNeedConfigState
| kIOServiceConfigRunning
)))
1037 && (0 == (__state
[0] & kIOServiceInactiveState
));
1039 __state
[1] |= kIOServiceNeedConfigState
;
1041 // __state[0] &= ~kIOServiceInactiveState;
1043 // if( sync) LOG("OSKernelStackRemaining = %08x @ %s\n",
1044 // OSKernelStackRemaining(), getName());
1047 needWake
= (0 != (kIOServiceSyncPubState
& __state
[1]));
1051 __state
[1] |= kIOServiceSynchronousState
;
1053 __state
[1] &= ~kIOServiceSynchronousState
;
1057 prevBusy
= _adjustBusy( 1 );
1060 unlockForArbitration();
1064 IOLockLock( gIOServiceBusyLock
);
1065 thread_wakeup((event_t
) this /*&__state[1]*/ );
1066 IOLockUnlock( gIOServiceBusyLock
);
1067 } else if (!sync
|| (kIOServiceAsynchronous
& options
)) {
1068 ok
= (NULL
!= _IOServiceJob::startJob( this, kMatchNubJob
, options
));
1071 if ((__state
[1] & kIOServiceNeedConfigState
)) {
1072 doServiceMatch( options
);
1075 lockForArbitration();
1076 IOLockLock( gIOServiceBusyLock
);
1078 waitAgain
= ((prevBusy
< (__state
[1] & kIOServiceBusyStateMask
))
1079 && (0 == (__state
[0] & kIOServiceInactiveState
)));
1082 __state
[1] |= kIOServiceSyncPubState
| kIOServiceBusyWaiterState
;
1084 __state
[1] &= ~kIOServiceSyncPubState
;
1087 unlockForArbitration();
1090 assert_wait((event_t
) this /*&__state[1]*/, THREAD_UNINT
);
1093 IOLockUnlock( gIOServiceBusyLock
);
1095 thread_block(THREAD_CONTINUE_NULL
);
1097 } while (waitAgain
);
1104 IOService::startDeferredMatches(void)
1109 IOLockLock(gJobsLock
);
1110 array
= gIOMatchDeferList
;
1111 gIOMatchDeferList
= NULL
;
1112 IOLockUnlock(gJobsLock
);
1115 IOLog("deferred rematching count %d\n", array
->getCount());
1116 array
->iterateObjects(^bool (OSObject
* obj
)
1118 ((IOService
*)obj
)->startMatching(kIOServiceAsynchronous
);
1123 #endif /* !NO_KEXTD */
1127 IOService::iokitDaemonLaunched(void)
1130 IOServiceTrace(IOSERVICE_KEXTD_READY
, 0, 0, 0, 0);
1131 startDeferredMatches();
1132 getServiceRoot()->adjustBusy(-1);
1133 IOService::publishUserResource(gIOResourceIOKitKey
);
1134 #endif /* !NO_KEXTD */
1138 IOService::catalogNewDrivers( OSOrderedSet
* newTables
)
1140 OSDictionary
* table
;
1142 OSSet
* allSet
= NULL
;
1143 IOService
* service
;
1148 newTables
->retain();
1150 while ((table
= (OSDictionary
*) newTables
->getFirstObject())) {
1152 set
= (OSSet
*) copyExistingServices( table
,
1153 kIOServiceRegisteredState
,
1154 kIOServiceExistingSet
);
1158 count
+= set
->getCount();
1161 allSet
->merge((const OSSet
*) set
);
1169 if (getDebugFlags( table
) & kIOLogMatch
) {
1170 LOG("Matching service count = %ld\n", (long)count
);
1173 newTables
->removeObject(table
);
1177 while ((service
= (IOService
*) allSet
->getAnyObject())) {
1178 service
->startMatching(kIOServiceAsynchronous
);
1179 allSet
->removeObject(service
);
1184 newTables
->release();
1186 return kIOReturnSuccess
;
1190 _IOServiceJob::startJob( IOService
* nub
, int type
,
1191 IOOptionBits options
)
1193 _IOServiceJob
* job
;
1195 job
= new _IOServiceJob
;
1196 if (job
&& !job
->init()) {
1204 job
->options
= options
;
1205 nub
->retain(); // thread will release()
1213 * Called on a registered service to see if it matches
1218 IOService::matchPropertyTable( OSDictionary
* table
, SInt32
* score
)
1220 return matchPropertyTable(table
);
1224 IOService::matchPropertyTable( OSDictionary
* table
)
1230 * Called on a matched service to allocate resources
1231 * before first driver is attached.
1235 IOService::getResources( void )
1237 return kIOReturnSuccess
;
1241 * Client/provider accessors
1245 IOService::getProvider( void ) const
1247 IOService
* self
= (IOService
*) this;
1251 generation
= getRegistryEntryGenerationCount();
1252 if (__providerGeneration
== generation
) {
1256 parent
= (IOService
*) getParentEntry( gIOServicePlane
);
1257 if (parent
== IORegistryEntry::getRegistryRoot()) {
1258 /* root is not an IOService */
1262 self
->__provider
= parent
;
1264 // save the count from before call to getParentEntry()
1265 self
->__providerGeneration
= generation
;
1271 IOService::getWorkLoop() const
1273 IOService
*provider
= getProvider();
1276 return provider
->getWorkLoop();
1283 IOService::getProviderIterator( void ) const
1285 return getParentIterator( gIOServicePlane
);
1289 IOService::getClient( void ) const
1291 return (IOService
*) getChildEntry( gIOServicePlane
);
1295 IOService::getClientIterator( void ) const
1297 return getChildIterator( gIOServicePlane
);
1301 _IOOpenServiceIterator::iterator( OSIterator
* _iter
,
1302 const IOService
* client
,
1303 const IOService
* provider
)
1305 _IOOpenServiceIterator
* inst
;
1311 inst
= new _IOOpenServiceIterator
;
1313 if (inst
&& !inst
->init()) {
1319 inst
->client
= client
;
1320 inst
->provider
= provider
;
1327 _IOOpenServiceIterator::free()
1331 last
->unlockForArbitration();
1337 _IOOpenServiceIterator::getNextObject()
1342 last
->unlockForArbitration();
1345 while ((next
= (IOService
*) iter
->getNextObject())) {
1346 next
->lockForArbitration();
1347 if ((client
&& (next
->isOpen( client
)))
1348 || (provider
&& (provider
->isOpen( next
)))) {
1351 next
->unlockForArbitration();
1360 _IOOpenServiceIterator::isValid()
1362 return iter
->isValid();
1366 _IOOpenServiceIterator::reset()
1369 last
->unlockForArbitration();
1376 IOService::getOpenProviderIterator( void ) const
1378 return _IOOpenServiceIterator::iterator( getProviderIterator(), this, NULL
);
1382 IOService::getOpenClientIterator( void ) const
1384 return _IOOpenServiceIterator::iterator( getClientIterator(), NULL
, this );
1389 IOService::callPlatformFunction( const OSSymbol
* functionName
,
1390 bool waitForFunction
,
1391 void *param1
, void *param2
,
1392 void *param3
, void *param4
)
1394 IOReturn result
= kIOReturnUnsupported
;
1395 IOService
*provider
;
1397 if (functionName
== gIOPlatformQuiesceActionKey
||
1398 functionName
== gIOPlatformActiveActionKey
) {
1400 * Services which register for IOPlatformQuiesceAction / IOPlatformActiveAction
1401 * must consume that event themselves, without passing it up to super/IOService.
1403 if (gEnforceQuiesceSafety
) {
1404 panic("Class %s passed the quiesce/active action to IOService",
1405 getMetaClass()->getClassName());
1409 if (gIOPlatformFunctionHandlerSet
== functionName
) {
1410 const OSSymbol
* functionHandlerName
= (const OSSymbol
*) param1
;
1411 IOService
* target
= (IOService
*) param2
;
1412 bool enable
= (param3
!= NULL
);
1414 if (sCPULatencyFunctionName
[kCpuDelayBusStall
] == functionHandlerName
) {
1415 result
= setLatencyHandler(kCpuDelayBusStall
, target
, enable
);
1417 #if defined(__x86_64__)
1418 else if (sCPULatencyFunctionName
[kCpuDelayInterrupt
] == param1
) {
1419 result
= setLatencyHandler(kCpuDelayInterrupt
, target
, enable
);
1421 #endif /* defined(__x86_64__) */
1424 if ((kIOReturnUnsupported
== result
) && (provider
= getProvider())) {
1425 result
= provider
->callPlatformFunction(functionName
, waitForFunction
,
1426 param1
, param2
, param3
, param4
);
1433 IOService::callPlatformFunction( const char * functionName
,
1434 bool waitForFunction
,
1435 void *param1
, void *param2
,
1436 void *param3
, void *param4
)
1438 IOReturn result
= kIOReturnNoMemory
;
1439 const OSSymbol
*functionSymbol
= OSSymbol::withCString(functionName
);
1441 if (functionSymbol
!= NULL
) {
1442 result
= callPlatformFunction(functionSymbol
, waitForFunction
,
1443 param1
, param2
, param3
, param4
);
1444 functionSymbol
->release();
1452 * Accessors for global services
1456 IOService::getPlatform( void )
1461 class IOPMrootDomain
*
1462 IOService::getPMRootDomain( void )
1464 return gIOPMRootDomain
;
1468 IOService::getResourceService( void )
1470 return gIOResources
;
1474 IOService::setPlatform( IOPlatformExpert
* platform
)
1476 gIOPlatform
= platform
;
1477 gIOResources
->attachToParent( gIOServiceRoot
, gIOServicePlane
);
1478 gIOUserResources
->attachToParent( gIOServiceRoot
, gIOServicePlane
);
1480 static const char * keys
[kCpuNumDelayTypes
] = {
1481 kIOPlatformMaxBusDelay
,
1482 #if defined(__x86_64__)
1483 kIOPlatformMaxInterruptDelay
1484 #endif /* defined(__x86_64__) */
1486 const OSObject
* objs
[2];
1490 for (idx
= 0; idx
< kCpuNumDelayTypes
; idx
++) {
1491 objs
[0] = sCPULatencySet
[idx
];
1492 objs
[1] = sCPULatencyHolder
[idx
];
1493 array
= OSArray::withObjects(objs
, 2);
1497 platform
->setProperty(keys
[idx
], array
);
1503 IOService::setPMRootDomain( class IOPMrootDomain
* rootDomain
)
1505 gIOPMRootDomain
= rootDomain
;
1506 publishResource(gIOResourceIOKitKey
);
1507 IOServicePH::init(rootDomain
);
1515 IOService::lockForArbitration( bool isSuccessRequired
)
1519 ArbitrationLockQueueElement
* element
;
1520 ArbitrationLockQueueElement
* active
;
1521 ArbitrationLockQueueElement
* waiting
;
1523 enum { kPutOnFreeQueue
, kPutOnActiveQueue
, kPutOnWaitingQueue
} action
;
1525 // lock global access
1526 IOTakeLock( gArbitrationLockQueueLock
);
1528 // obtain an unused queue element
1529 if (!queue_empty( &gArbitrationLockQueueFree
)) {
1530 queue_remove_first( &gArbitrationLockQueueFree
,
1532 ArbitrationLockQueueElement
*,
1535 element
= IONew( ArbitrationLockQueueElement
, 1 );
1539 // prepare the queue element
1540 element
->thread
= IOThreadSelf();
1541 element
->service
= this;
1543 element
->required
= isSuccessRequired
;
1544 element
->aborted
= false;
1546 // determine whether this object is already locked (ie. on active queue)
1548 queue_iterate( &gArbitrationLockQueueActive
,
1550 ArbitrationLockQueueElement
*,
1553 if (active
->service
== element
->service
) {
1559 if (found
) { // this object is already locked
1560 // determine whether it is the same or a different thread trying to lock
1561 if (active
->thread
!= element
->thread
) { // it is a different thread
1562 ArbitrationLockQueueElement
* victim
= NULL
;
1564 // before placing this new thread on the waiting queue, we look for
1565 // a deadlock cycle...
1568 // determine whether the active thread holding the object we
1569 // want is waiting for another object to be unlocked
1571 queue_iterate( &gArbitrationLockQueueWaiting
,
1573 ArbitrationLockQueueElement
*,
1576 if (waiting
->thread
== active
->thread
) {
1577 assert( false == waiting
->aborted
);
1583 if (found
) { // yes, active thread waiting for another object
1584 // this may be a candidate for rejection if the required
1585 // flag is not set, should we detect a deadlock later on
1586 if (false == waiting
->required
) {
1590 // find the thread that is holding this other object, that
1591 // is blocking the active thread from proceeding (fun :-)
1593 queue_iterate( &gArbitrationLockQueueActive
,
1594 active
, // (reuse active queue element)
1595 ArbitrationLockQueueElement
*,
1598 if (active
->service
== waiting
->service
) {
1604 // someone must be holding it or it wouldn't be waiting
1607 if (active
->thread
== element
->thread
) {
1608 // doh, it's waiting for the thread that originated
1609 // this whole lock (ie. current thread) -> deadlock
1610 if (false == element
->required
) { // willing to fail?
1611 // the originating thread doesn't have the required
1612 // flag, so it can fail
1613 success
= false; // (fail originating lock request)
1614 break; // (out of while)
1615 } else { // originating thread is not willing to fail
1616 // see if we came across a waiting thread that did
1617 // not have the 'required' flag set: we'll fail it
1619 // we do have a willing victim, fail it's lock
1620 victim
->aborted
= true;
1622 // take the victim off the waiting queue
1623 queue_remove( &gArbitrationLockQueueWaiting
,
1625 ArbitrationLockQueueElement
*,
1629 IOLockWakeup( gArbitrationLockQueueLock
,
1631 /* one thread */ true );
1633 // allow this thread to proceed (ie. wait)
1634 success
= true; // (put request on wait queue)
1635 break; // (out of while)
1637 // all the waiting threads we came across in
1638 // finding this loop had the 'required' flag
1639 // set, so we've got a deadlock we can't avoid
1640 panic("I/O Kit: Unrecoverable deadlock.");
1644 // repeat while loop, redefining active thread to be the
1645 // thread holding "this other object" (see above), and
1646 // looking for threads waiting on it; note the active
1647 // variable points to "this other object" already... so
1648 // there nothing to do in this else clause.
1650 } else { // no, active thread is not waiting for another object
1651 success
= true; // (put request on wait queue)
1652 break; // (out of while)
1656 if (success
) { // put the request on the waiting queue?
1657 kern_return_t wait_result
;
1659 // place this thread on the waiting queue and put it to sleep;
1660 // we place it at the tail of the queue...
1661 queue_enter( &gArbitrationLockQueueWaiting
,
1663 ArbitrationLockQueueElement
*,
1666 // declare that this thread will wait for a given event
1667 restart_sleep
: wait_result
= assert_wait( element
,
1668 element
->required
? THREAD_UNINT
1669 : THREAD_INTERRUPTIBLE
);
1671 // unlock global access
1672 IOUnlock( gArbitrationLockQueueLock
);
1674 // put thread to sleep, waiting for our event to fire...
1675 if (wait_result
== THREAD_WAITING
) {
1676 wait_result
= thread_block(THREAD_CONTINUE_NULL
);
1680 // ...and we've been woken up; we might be in one of two states:
1681 // (a) we've been aborted and our queue element is not on
1682 // any of the three queues, but is floating around
1683 // (b) we're allowed to proceed with the lock and we have
1684 // already been moved from the waiting queue to the
1686 // ...plus a 3rd state, should the thread have been interrupted:
1687 // (c) we're still on the waiting queue
1689 // determine whether we were interrupted out of our sleep
1690 if (THREAD_INTERRUPTED
== wait_result
) {
1691 // re-lock global access
1692 IOTakeLock( gArbitrationLockQueueLock
);
1694 // determine whether we're still on the waiting queue
1696 queue_iterate( &gArbitrationLockQueueWaiting
,
1697 waiting
, // (reuse waiting queue element)
1698 ArbitrationLockQueueElement
*,
1701 if (waiting
== element
) {
1707 if (found
) { // yes, we're still on the waiting queue
1708 // determine whether we're willing to fail
1709 if (false == element
->required
) {
1710 // mark us as aborted
1711 element
->aborted
= true;
1713 // take us off the waiting queue
1714 queue_remove( &gArbitrationLockQueueWaiting
,
1716 ArbitrationLockQueueElement
*,
1718 } else { // we are not willing to fail
1719 // ignore interruption, go back to sleep
1724 // unlock global access
1725 IOUnlock( gArbitrationLockQueueLock
);
1727 // proceed as though this were a normal wake up
1728 wait_result
= THREAD_AWAKENED
;
1731 assert( THREAD_AWAKENED
== wait_result
);
1733 // determine whether we've been aborted while we were asleep
1734 if (element
->aborted
) {
1735 assert( false == element
->required
);
1737 // re-lock global access
1738 IOTakeLock( gArbitrationLockQueueLock
);
1740 action
= kPutOnFreeQueue
;
1742 } else { // we weren't aborted, so we must be ready to go :-)
1743 // we've already been moved from waiting to active queue
1746 } else { // the lock request is to be failed
1747 // return unused queue element to queue
1748 action
= kPutOnFreeQueue
;
1750 } else { // it is the same thread, recursive access is allowed
1751 // add one level of recursion
1754 // return unused queue element to queue
1755 action
= kPutOnFreeQueue
;
1758 } else { // this object is not already locked, so let this thread through
1759 action
= kPutOnActiveQueue
;
1763 // put the new element on a queue
1764 if (kPutOnActiveQueue
== action
) {
1765 queue_enter( &gArbitrationLockQueueActive
,
1767 ArbitrationLockQueueElement
*,
1769 } else if (kPutOnFreeQueue
== action
) {
1770 queue_enter( &gArbitrationLockQueueFree
,
1772 ArbitrationLockQueueElement
*,
1775 assert( 0 ); // kPutOnWaitingQueue never occurs, handled specially above
1778 // unlock global access
1779 IOUnlock( gArbitrationLockQueueLock
);
1785 IOService::unlockForArbitration( void )
1788 ArbitrationLockQueueElement
* element
;
1790 // lock global access
1791 IOTakeLock( gArbitrationLockQueueLock
);
1793 // find the lock element for this object (ie. on active queue)
1795 queue_iterate( &gArbitrationLockQueueActive
,
1797 ArbitrationLockQueueElement
*,
1800 if (element
->service
== this) {
1808 // determine whether the lock has been taken recursively
1809 if (element
->count
> 1) {
1810 // undo one level of recursion
1813 // remove it from the active queue
1814 queue_remove( &gArbitrationLockQueueActive
,
1816 ArbitrationLockQueueElement
*,
1819 // put it on the free queue
1820 queue_enter( &gArbitrationLockQueueFree
,
1822 ArbitrationLockQueueElement
*,
1825 // determine whether a thread is waiting for object (head to tail scan)
1827 queue_iterate( &gArbitrationLockQueueWaiting
,
1829 ArbitrationLockQueueElement
*,
1832 if (element
->service
== this) {
1838 if (found
) { // we found an interested thread on waiting queue
1839 // remove it from the waiting queue
1840 queue_remove( &gArbitrationLockQueueWaiting
,
1842 ArbitrationLockQueueElement
*,
1845 // put it on the active queue
1846 queue_enter( &gArbitrationLockQueueActive
,
1848 ArbitrationLockQueueElement
*,
1851 // wake the waiting thread
1852 IOLockWakeup( gArbitrationLockQueueLock
,
1854 /* one thread */ true );
1858 // unlock global access
1859 IOUnlock( gArbitrationLockQueueLock
);
1863 IOService::isLockedForArbitration(IOService
* service
)
1865 #if DEBUG_NOTIFIER_LOCKED
1867 ArbitrationLockQueueElement
* active
;
1869 // lock global access
1870 IOLockLock(gArbitrationLockQueueLock
);
1872 // determine whether this object is already locked (ie. on active queue)
1874 queue_iterate(&gArbitrationLockQueueActive
,
1876 ArbitrationLockQueueElement
*,
1879 if ((active
->thread
== IOThreadSelf())
1880 && (!service
|| (active
->service
== service
))) {
1882 count
+= active
->count
;
1886 IOLockUnlock(gArbitrationLockQueueLock
);
1890 #else /* DEBUG_NOTIFIER_LOCKED */
1894 #endif /* DEBUG_NOTIFIER_LOCKED */
1898 IOService::applyToProviders( IOServiceApplierFunction applier
,
1901 applyToParents((IORegistryEntryApplierFunction
) applier
,
1902 context
, gIOServicePlane
);
1906 IOService::applyToClients( IOServiceApplierFunction applier
,
1909 applyToChildren((IORegistryEntryApplierFunction
) applier
,
1910 context
, gIOServicePlane
);
1915 IOServiceApplierToBlock(IOService
* next
, void * context
)
1917 IOServiceApplierBlock block
= (IOServiceApplierBlock
) context
;
1922 IOService::applyToProviders(IOServiceApplierBlock applier
)
1924 applyToProviders(&IOServiceApplierToBlock
, applier
);
1928 IOService::applyToClients(IOServiceApplierBlock applier
)
1930 applyToClients(&IOServiceApplierToBlock
, applier
);
1938 // send a message to a client or interested party of this service
1940 IOService::messageClient( UInt32 type
, OSObject
* client
,
1941 void * argument
, vm_size_t argSize
)
1944 IOService
* service
;
1945 _IOServiceInterestNotifier
* notify
;
1947 if ((service
= OSDynamicCast( IOService
, client
))) {
1948 ret
= service
->message( type
, this, argument
);
1949 } else if ((notify
= OSDynamicCast( _IOServiceInterestNotifier
, client
))) {
1950 _IOServiceNotifierInvocation invocation
;
1953 invocation
.thread
= current_thread();
1956 willNotify
= (0 != (kIOServiceNotifyEnable
& notify
->state
));
1959 queue_enter( ¬ify
->handlerInvocations
, &invocation
,
1960 _IOServiceNotifierInvocation
*, link
);
1965 ret
= (*notify
->handler
)( notify
->target
, notify
->ref
,
1966 type
, this, argument
, argSize
);
1969 queue_remove( ¬ify
->handlerInvocations
, &invocation
,
1970 _IOServiceNotifierInvocation
*, link
);
1971 if (kIOServiceNotifyWaiter
& notify
->state
) {
1972 notify
->state
&= ~kIOServiceNotifyWaiter
;
1973 WAKEUPNOTIFY( notify
);
1977 ret
= kIOReturnSuccess
;
1980 ret
= kIOReturnBadArgument
;
1987 applyToInterestNotifiers(const IORegistryEntry
*target
,
1988 const OSSymbol
* typeOfInterest
,
1989 OSObjectApplierFunction applier
,
1992 OSArray
* copyArray
= NULL
;
1997 prop
= target
->copyProperty(typeOfInterest
);
1998 IOCommand
*notifyList
= OSDynamicCast(IOCommand
, prop
);
2001 copyArray
= OSArray::withCapacity(1);
2003 // iterate over queue, entry is set to each element in the list
2004 iterqueue(¬ifyList
->fCommandChain
, entry
) {
2005 _IOServiceInterestNotifier
* notify
;
2007 queue_element(entry
, notify
, _IOServiceInterestNotifier
*, chain
);
2008 copyArray
->setObject(notify
);
2017 for (index
= 0; (next
= copyArray
->getObject( index
)); index
++) {
2018 (*applier
)(next
, context
);
2020 copyArray
->release();
2023 OSSafeReleaseNULL(prop
);
2027 IOService::applyToInterested( const OSSymbol
* typeOfInterest
,
2028 OSObjectApplierFunction applier
,
2031 if (gIOGeneralInterest
== typeOfInterest
) {
2032 applyToClients((IOServiceApplierFunction
) applier
, context
);
2034 applyToInterestNotifiers(this, typeOfInterest
, applier
, context
);
2037 struct MessageClientsContext
{
2038 IOService
* service
;
2046 messageClientsApplier( OSObject
* object
, void * ctx
)
2049 MessageClientsContext
* context
= (MessageClientsContext
*) ctx
;
2051 ret
= context
->service
->messageClient( context
->type
,
2052 object
, context
->argument
, context
->argSize
);
2053 if (kIOReturnSuccess
!= ret
) {
2058 // send a message to all clients
2060 IOService::messageClients( UInt32 type
,
2061 void * argument
, vm_size_t argSize
)
2063 MessageClientsContext context
;
2065 context
.service
= this;
2066 context
.type
= type
;
2067 context
.argument
= argument
;
2068 context
.argSize
= argSize
;
2069 context
.ret
= kIOReturnSuccess
;
2071 applyToInterested( gIOGeneralInterest
,
2072 &messageClientsApplier
, &context
);
2078 IOService::acknowledgeNotification( IONotificationRef notification
,
2079 IOOptionBits response
)
2081 return kIOReturnUnsupported
;
2085 IOService::registerInterest( const OSSymbol
* typeOfInterest
,
2086 IOServiceInterestHandler handler
, void * target
, void * ref
)
2088 _IOServiceInterestNotifier
* notify
= NULL
;
2089 IOReturn rc
= kIOReturnError
;
2091 notify
= new _IOServiceInterestNotifier
;
2096 if (notify
->init()) {
2097 rc
= registerInterestForNotifier(notify
, typeOfInterest
,
2098 handler
, target
, ref
);
2101 if (rc
!= kIOReturnSuccess
) {
2112 IOServiceInterestHandlerToBlock( void * target __unused
, void * refCon
,
2113 UInt32 messageType
, IOService
* provider
,
2114 void * messageArgument
, vm_size_t argSize
)
2116 return ((IOServiceInterestHandlerBlock
) refCon
)(messageType
, provider
, messageArgument
, argSize
);
2120 IOService::registerInterest(const OSSymbol
* typeOfInterest
,
2121 IOServiceInterestHandlerBlock handler
)
2123 IONotifier
* notify
;
2126 block
= Block_copy(handler
);
2131 notify
= registerInterest(typeOfInterest
, &IOServiceInterestHandlerToBlock
, NULL
, block
);
2134 Block_release(block
);
2141 IOService::registerInterestForNotifier( IONotifier
*svcNotify
, const OSSymbol
* typeOfInterest
,
2142 IOServiceInterestHandler handler
, void * target
, void * ref
)
2144 IOReturn rc
= kIOReturnSuccess
;
2145 _IOServiceInterestNotifier
*notify
= NULL
;
2147 if (!svcNotify
|| !(notify
= OSDynamicCast(_IOServiceInterestNotifier
, svcNotify
))) {
2148 return kIOReturnBadArgument
;
2151 notify
->handler
= handler
;
2152 notify
->target
= target
;
2155 if ((typeOfInterest
!= gIOGeneralInterest
)
2156 && (typeOfInterest
!= gIOBusyInterest
)
2157 && (typeOfInterest
!= gIOAppPowerStateInterest
)
2158 && (typeOfInterest
!= gIOConsoleSecurityInterest
)
2159 && (typeOfInterest
!= gIOPriorityPowerStateInterest
)) {
2160 return kIOReturnBadArgument
;
2163 lockForArbitration();
2164 if (0 == (__state
[0] & kIOServiceInactiveState
)) {
2165 notify
->state
= kIOServiceNotifyEnable
;
2171 // Get the head of the notifier linked list
2172 IOCommand
* notifyList
;
2173 OSObject
* obj
= copyProperty( typeOfInterest
);
2174 if (!(notifyList
= OSDynamicCast(IOCommand
, obj
))) {
2175 notifyList
= OSTypeAlloc(IOCommand
);
2178 bool ok
= setProperty( typeOfInterest
, notifyList
);
2179 notifyList
->release();
2190 enqueue(¬ifyList
->fCommandChain
, ¬ify
->chain
);
2191 notify
->retain(); // ref'ed while in list
2196 rc
= kIOReturnNotReady
;
2198 unlockForArbitration();
2204 cleanInterestList( OSObject
* head
)
2206 IOCommand
*notifyHead
= OSDynamicCast(IOCommand
, head
);
2212 while (queue_entry_t entry
= dequeue(¬ifyHead
->fCommandChain
)) {
2213 queue_next(entry
) = queue_prev(entry
) = NULL
;
2215 _IOServiceInterestNotifier
* notify
;
2217 queue_element(entry
, notify
, _IOServiceInterestNotifier
*, chain
);
2224 IOService::unregisterAllInterest( void )
2228 prop
= copyProperty(gIOGeneralInterest
);
2229 cleanInterestList(prop
);
2230 OSSafeReleaseNULL(prop
);
2232 prop
= copyProperty(gIOBusyInterest
);
2233 cleanInterestList(prop
);
2234 OSSafeReleaseNULL(prop
);
2236 prop
= copyProperty(gIOAppPowerStateInterest
);
2237 cleanInterestList(prop
);
2238 OSSafeReleaseNULL(prop
);
2240 prop
= copyProperty(gIOPriorityPowerStateInterest
);
2241 cleanInterestList(prop
);
2242 OSSafeReleaseNULL(prop
);
2244 prop
= copyProperty(gIOConsoleSecurityInterest
);
2245 cleanInterestList(prop
);
2246 OSSafeReleaseNULL(prop
);
2250 * _IOServiceInterestNotifier
2253 // wait for all threads, other than the current one,
2254 // to exit the handler
2257 _IOServiceInterestNotifier::wait()
2259 _IOServiceNotifierInvocation
* next
;
2264 queue_iterate( &handlerInvocations
, next
,
2265 _IOServiceNotifierInvocation
*, link
) {
2266 if (next
->thread
!= current_thread()) {
2272 state
|= kIOServiceNotifyWaiter
;
2279 _IOServiceInterestNotifier::free()
2281 assert( queue_empty( &handlerInvocations
));
2283 if (handler
== &IOServiceInterestHandlerToBlock
) {
2291 _IOServiceInterestNotifier::remove()
2295 if (queue_next( &chain
)) {
2297 queue_next( &chain
) = queue_prev( &chain
) = NULL
;
2301 state
&= ~kIOServiceNotifyEnable
;
2311 _IOServiceInterestNotifier::disable()
2317 ret
= (0 != (kIOServiceNotifyEnable
& state
));
2318 state
&= ~kIOServiceNotifyEnable
;
2329 _IOServiceInterestNotifier::enable( bool was
)
2333 state
|= kIOServiceNotifyEnable
;
2335 state
&= ~kIOServiceNotifyEnable
;
2341 _IOServiceInterestNotifier::init()
2343 queue_init( &handlerInvocations
);
2344 return OSObject::init();
2346 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2352 #define tailQ(o) setObject(o)
2353 #define headQ(o) setObject(0, o)
2354 #define TLOG(fmt, args...) { if(kIOLogYield & gIOKitDebug) { IOLog("[%llx] ", thread_tid(current_thread())); IOLog(fmt, ## args); }}
2357 _workLoopAction( IOWorkLoop::Action action
,
2358 IOService
* service
,
2359 void * p0
= NULL
, void * p1
= NULL
,
2360 void * p2
= NULL
, void * p3
= NULL
)
2364 if ((wl
= service
->getWorkLoop())) {
2366 wl
->runAction( action
, service
, p0
, p1
, p2
, p3
);
2369 (*action
)( service
, p0
, p1
, p2
, p3
);
2374 IOService::requestTerminate( IOService
* provider
, IOOptionBits options
)
2378 // if its our only provider
2379 ok
= isParent( provider
, gIOServicePlane
, true);
2383 provider
->terminateClient( this, options
| kIOServiceRecursing
);
2384 ok
= (0 != (kIOServiceInactiveState
& __state
[0]));
2392 IOService::terminatePhase1( IOOptionBits options
)
2396 IOService
* rematchProvider
;
2398 OSArray
* makeInactive
;
2399 OSArray
* waitingInactive
;
2400 IOOptionBits callerOptions
;
2401 int waitResult
= THREAD_AWAKENED
;
2405 bool startPhase2
= false;
2407 TLOG("%s[0x%qx]::terminatePhase1(%08llx)\n", getName(), getRegistryEntryID(), (long long)options
);
2409 callerOptions
= options
;
2410 rematchProvider
= NULL
;
2411 uint64_t regID
= getRegistryEntryID();
2413 IOSERVICE_TERMINATE_PHASE1
,
2415 (uintptr_t) (regID
>> 32),
2417 (uintptr_t) options
);
2420 if (options
& kIOServiceRecursing
) {
2421 lockForArbitration();
2422 if (0 == (kIOServiceInactiveState
& __state
[0])) {
2423 __state
[0] |= kIOServiceInactiveState
;
2424 __state
[1] |= kIOServiceRecursing
| kIOServiceTermPhase1State
;
2426 unlockForArbitration();
2432 makeInactive
= OSArray::withCapacity( 16 );
2433 waitingInactive
= OSArray::withCapacity( 16 );
2434 if (!makeInactive
|| !waitingInactive
) {
2442 didInactive
= victim
->lockForArbitration( true );
2444 uint64_t regID1
= victim
->getRegistryEntryID();
2445 IOServiceTrace(IOSERVICE_TERM_SET_INACTIVE
,
2447 (uintptr_t) (regID1
>> 32),
2448 (uintptr_t) victim
->__state
[1],
2451 enum { kRP1
= kIOServiceRecursing
| kIOServiceTermPhase1State
};
2452 didInactive
= (kRP1
== (victim
->__state
[1] & kRP1
))
2453 || (0 == (victim
->__state
[0] & kIOServiceInactiveState
));
2456 // a multiply attached IOService can be visited twice
2457 if (-1U == waitingInactive
->getNextIndexOfObject(victim
, 0)) {
2459 IOLockLock(gIOServiceBusyLock
);
2460 wait
= (victim
->__state
[1] & kIOServiceTermPhase1State
);
2462 TLOG("%s[0x%qx]::waitPhase1(%s[0x%qx])\n",
2463 getName(), getRegistryEntryID(), victim
->getName(), victim
->getRegistryEntryID());
2464 victim
->__state
[1] |= kIOServiceTerm1WaiterState
;
2465 victim
->unlockForArbitration();
2466 assert_wait((event_t
)&victim
->__state
[1], THREAD_UNINT
);
2468 IOLockUnlock(gIOServiceBusyLock
);
2470 waitResult
= thread_block(THREAD_CONTINUE_NULL
);
2471 TLOG("%s[0x%qx]::did waitPhase1(%s[0x%qx])\n",
2472 getName(), getRegistryEntryID(), victim
->getName(), victim
->getRegistryEntryID());
2473 victim
->lockForArbitration();
2475 }while (wait
&& (waitResult
!= THREAD_TIMED_OUT
));
2478 victim
->__state
[0] |= kIOServiceInactiveState
;
2479 victim
->__state
[0] &= ~(kIOServiceRegisteredState
| kIOServiceMatchedState
2480 | kIOServiceFirstPublishState
| kIOServiceFirstMatchState
);
2481 victim
->__state
[1] &= ~kIOServiceRecursing
;
2482 victim
->__state
[1] |= kIOServiceTermPhase1State
;
2483 waitingInactive
->headQ(victim
);
2484 if (victim
== this) {
2485 if (kIOServiceTerminateNeedWillTerminate
& options
) {
2486 victim
->__state
[1] |= kIOServiceNeedWillTerminate
;
2489 victim
->_adjustBusy( 1 );
2491 if ((options
& kIOServiceTerminateWithRematch
) && (victim
== this)) {
2493 OSObject
* rematchProps
;
2497 rematchProvider
= getProvider();
2498 if (rematchProvider
) {
2499 obj
= rematchProvider
->copyProperty(gIORematchCountKey
);
2500 num
= OSDynamicCast(OSNumber
, obj
);
2503 count
= num
->unsigned32BitValue();
2506 num
= OSNumber::withNumber(count
, 32);
2507 rematchProvider
->setProperty(gIORematchCountKey
, num
);
2508 rematchProps
= copyProperty(gIOMatchedPersonalityKey
);
2509 rematchProvider
->setProperty(gIORematchPersonalityKey
, rematchProps
);
2510 OSSafeReleaseNULL(num
);
2511 OSSafeReleaseNULL(rematchProps
);
2512 OSSafeReleaseNULL(obj
);
2516 victim
->unlockForArbitration();
2518 if (victim
== this) {
2519 options
&= ~kIOServiceTerminateWithRematch
;
2520 startPhase2
= didInactive
;
2523 OSArray
* notifiers
;
2524 notifiers
= victim
->copyNotifiers(gIOTerminatedNotification
, 0, 0xffffffff);
2525 victim
->invokeNotifiers(¬ifiers
);
2527 IOUserClient::destroyUserReferences( victim
);
2529 iter
= victim
->getClientIterator();
2531 while ((client
= (IOService
*) iter
->getNextObject())) {
2532 TLOG("%s[0x%qx]::requestTerminate(%s[0x%qx], %08llx)\n",
2533 client
->getName(), client
->getRegistryEntryID(),
2534 victim
->getName(), victim
->getRegistryEntryID(), (long long)options
);
2535 ok
= client
->requestTerminate( victim
, options
);
2536 TLOG("%s[0x%qx]::requestTerminate(%s[0x%qx], ok = %d)\n",
2537 client
->getName(), client
->getRegistryEntryID(),
2538 victim
->getName(), victim
->getRegistryEntryID(), ok
);
2540 uint64_t regID1
= client
->getRegistryEntryID();
2541 uint64_t regID2
= victim
->getRegistryEntryID();
2543 (ok
? IOSERVICE_TERMINATE_REQUEST_OK
2544 : IOSERVICE_TERMINATE_REQUEST_FAIL
),
2546 (uintptr_t) (regID1
>> 32),
2548 (uintptr_t) (regID2
>> 32));
2551 makeInactive
->setObject( client
);
2558 victim
= (IOService
*) makeInactive
->getObject(0);
2561 makeInactive
->removeObject(0);
2564 makeInactive
->release();
2566 while ((victim
= (IOService
*) waitingInactive
->getObject(0))) {
2568 waitingInactive
->removeObject(0);
2570 victim
->lockForArbitration();
2571 victim
->__state
[1] &= ~kIOServiceTermPhase1State
;
2572 if (kIOServiceTerm1WaiterState
& victim
->__state
[1]) {
2573 victim
->__state
[1] &= ~kIOServiceTerm1WaiterState
;
2574 TLOG("%s[0x%qx]::wakePhase1\n", victim
->getName(), victim
->getRegistryEntryID());
2575 IOLockLock( gIOServiceBusyLock
);
2576 thread_wakeup((event_t
) &victim
->__state
[1]);
2577 IOLockUnlock( gIOServiceBusyLock
);
2579 victim
->unlockForArbitration();
2582 waitingInactive
->release();
2586 lockForArbitration();
2587 scheduleTerminatePhase2(options
);
2588 unlockForArbitration();
2592 if (rematchProvider
) {
2593 DKLOG(DKS
" rematching after dext crash\n", DKN(rematchProvider
));
2594 rematchProvider
->registerService();
2601 IOService::setTerminateDefer(IOService
* provider
, bool defer
)
2603 lockForArbitration();
2605 __state
[1] |= kIOServiceStartState
;
2607 __state
[1] &= ~kIOServiceStartState
;
2609 unlockForArbitration();
2611 if (provider
&& !defer
) {
2612 provider
->lockForArbitration();
2613 provider
->scheduleTerminatePhase2();
2614 provider
->unlockForArbitration();
2618 // Must call this while holding gJobsLock
2620 IOService::waitToBecomeTerminateThread(void)
2622 IOLockAssert(gJobsLock
, kIOLockAssertOwned
);
2625 wait
= (gIOTerminateThread
!= THREAD_NULL
);
2627 IOLockSleep(gJobsLock
, &gIOTerminateThread
, THREAD_UNINT
);
2630 gIOTerminateThread
= current_thread();
2633 // call with lockForArbitration
2635 IOService::scheduleTerminatePhase2( IOOptionBits options
)
2637 AbsoluteTime deadline
;
2639 int waitResult
= THREAD_AWAKENED
;
2640 bool wait
= false, haveDeadline
= false;
2642 if (!(__state
[0] & kIOServiceInactiveState
)) {
2646 regID1
= getRegistryEntryID();
2648 IOSERVICE_TERM_SCHED_PHASE2
,
2650 (uintptr_t) (regID1
>> 32),
2651 (uintptr_t) __state
[1],
2652 (uintptr_t) options
);
2654 if (__state
[1] & kIOServiceTermPhase1State
) {
2659 unlockForArbitration();
2660 options
|= kIOServiceRequired
;
2661 IOLockLock( gJobsLock
);
2663 if ((options
& kIOServiceSynchronous
)
2664 && (current_thread() != gIOTerminateThread
)) {
2665 waitToBecomeTerminateThread();
2666 gIOTerminatePhase2List
->setObject( this );
2670 while (gIOTerminateWork
) {
2671 terminateWorker( options
);
2673 wait
= (0 != (__state
[1] & kIOServiceBusyStateMask
));
2675 /* wait for the victim to go non-busy */
2676 if (!haveDeadline
) {
2677 clock_interval_to_deadline( 15, kSecondScale
, &deadline
);
2678 haveDeadline
= true;
2680 /* let others do work while we wait */
2681 gIOTerminateThread
= NULL
;
2682 IOLockWakeup( gJobsLock
, (event_t
) &gIOTerminateThread
, /* one-thread */ false);
2683 waitResult
= IOLockSleepDeadline( gJobsLock
, &gIOTerminateWork
,
2684 deadline
, THREAD_UNINT
);
2685 if (__improbable(waitResult
== THREAD_TIMED_OUT
)) {
2686 IOLog("%s[0x%qx]::terminate(kIOServiceSynchronous): THREAD_TIMED_OUT. "
2687 "Attempting to auto-resolve your deadlock. PLEASE FIX!\n", getName(), getRegistryEntryID());
2689 waitToBecomeTerminateThread();
2691 } while (gIOTerminateWork
|| (wait
&& (waitResult
!= THREAD_TIMED_OUT
)));
2693 gIOTerminateThread
= NULL
;
2694 IOLockWakeup( gJobsLock
, (event_t
) &gIOTerminateThread
, /* one-thread */ false);
2696 // ! kIOServiceSynchronous
2698 gIOTerminatePhase2List
->setObject( this );
2699 if (0 == gIOTerminateWork
++) {
2700 assert(gIOTerminateWorkerThread
);
2701 IOLockWakeup(gJobsLock
, (event_t
)&gIOTerminateWork
, /* one-thread */ false );
2705 IOLockUnlock( gJobsLock
);
2706 lockForArbitration();
2710 __attribute__((__noreturn__
))
2712 IOService::terminateThread( void * arg
, wait_result_t waitResult
)
2714 // IOLockSleep re-acquires the lock on wakeup, so we only need to do this once
2715 IOLockLock(gJobsLock
);
2717 if (gIOTerminateThread
!= gIOTerminateWorkerThread
) {
2718 waitToBecomeTerminateThread();
2721 while (gIOTerminateWork
) {
2722 terminateWorker((IOOptionBits
)(uintptr_t)arg
);
2725 gIOTerminateThread
= NULL
;
2726 IOLockWakeup( gJobsLock
, (event_t
) &gIOTerminateThread
, /* one-thread */ false);
2727 IOLockSleep(gJobsLock
, &gIOTerminateWork
, THREAD_UNINT
);
2732 IOService::scheduleStop( IOService
* provider
)
2734 uint64_t regID1
= getRegistryEntryID();
2735 uint64_t regID2
= provider
->getRegistryEntryID();
2737 TLOG("%s[0x%qx]::scheduleStop(%s[0x%qx])\n", getName(), regID1
, provider
->getName(), regID2
);
2739 IOSERVICE_TERMINATE_SCHEDULE_STOP
,
2741 (uintptr_t) (regID1
>> 32),
2743 (uintptr_t) (regID2
>> 32));
2745 IOLockLock( gJobsLock
);
2746 gIOStopList
->tailQ( this );
2747 gIOStopProviderList
->tailQ( provider
);
2749 if (0 == gIOTerminateWork
++) {
2750 assert(gIOTerminateWorkerThread
);
2751 IOLockWakeup(gJobsLock
, (event_t
)&gIOTerminateWork
, /* one-thread */ false );
2754 IOLockUnlock( gJobsLock
);
2758 IOService::scheduleFinalize(bool now
)
2760 uint64_t regID1
= getRegistryEntryID();
2762 TLOG("%s[0x%qx]::scheduleFinalize\n", getName(), regID1
);
2764 IOSERVICE_TERMINATE_SCHEDULE_FINALIZE
,
2766 (uintptr_t) (regID1
>> 32),
2769 if (now
|| IOUserClient::finalizeUserReferences(this)) {
2770 IOLockLock( gJobsLock
);
2771 gIOFinalizeList
->tailQ(this);
2772 if (0 == gIOTerminateWork
++) {
2773 assert(gIOTerminateWorkerThread
);
2774 IOLockWakeup(gJobsLock
, (event_t
)&gIOTerminateWork
, /* one-thread */ false );
2776 IOLockUnlock( gJobsLock
);
2781 IOService::willTerminate( IOService
* provider
, IOOptionBits options
)
2783 if (reserved
->uvars
) {
2784 IOUserServer::serviceWillTerminate(this, provider
, options
);
2790 IOService::didTerminate( IOService
* provider
, IOOptionBits options
, bool * defer
)
2792 if (reserved
->uvars
) {
2793 IOUserServer::serviceDidTerminate(this, provider
, options
, defer
);
2796 if (false == *defer
) {
2797 if (lockForArbitration( true )) {
2798 if (false == provider
->handleIsOpen( this )) {
2799 scheduleStop( provider
);
2803 message( kIOMessageServiceIsRequestingClose
, provider
, (void *)(uintptr_t) options
);
2804 if (false == provider
->handleIsOpen( this )) {
2805 scheduleStop( provider
);
2809 unlockForArbitration();
2817 IOService::actionWillTerminate( IOService
* victim
, IOOptionBits options
,
2818 OSArray
* doPhase2List
,
2820 void *unused3 __unused
)
2825 uint64_t regID1
, regID2
= victim
->getRegistryEntryID();
2827 iter
= victim
->getClientIterator();
2829 while ((client
= (IOService
*) iter
->getNextObject())) {
2830 if (user
!= (NULL
!= client
->reserved
->uvars
)) {
2833 regID1
= client
->getRegistryEntryID();
2834 TLOG("%s[0x%qx]::willTerminate(%s[0x%qx], %08llx)\n",
2835 client
->getName(), regID1
,
2836 victim
->getName(), regID2
, (long long)options
);
2838 IOSERVICE_TERMINATE_WILL
,
2840 (uintptr_t) (regID1
>> 32),
2842 (uintptr_t) (regID2
>> 32));
2844 ok
= client
->willTerminate( victim
, options
);
2845 doPhase2List
->tailQ( client
);
2852 IOService::actionDidTerminate( IOService
* victim
, IOOptionBits options
,
2853 void *unused1 __unused
, void *unused2 __unused
,
2854 void *unused3 __unused
)
2859 uint64_t regID1
, regID2
= victim
->getRegistryEntryID();
2861 victim
->messageClients( kIOMessageServiceIsTerminated
, (void *)(uintptr_t) options
);
2863 iter
= victim
->getClientIterator();
2865 while ((client
= (IOService
*) iter
->getNextObject())) {
2866 regID1
= client
->getRegistryEntryID();
2867 TLOG("%s[0x%qx]::didTerminate(%s[0x%qx], %08llx)\n",
2868 client
->getName(), regID1
,
2869 victim
->getName(), regID2
, (long long)options
);
2871 client
->didTerminate( victim
, options
, &defer
);
2874 (defer
? IOSERVICE_TERMINATE_DID_DEFER
2875 : IOSERVICE_TERMINATE_DID
),
2877 (uintptr_t) (regID1
>> 32),
2879 (uintptr_t) (regID2
>> 32));
2881 TLOG("%s[0x%qx]::didTerminate(%s[0x%qx], defer %d)\n",
2882 client
->getName(), regID1
,
2883 victim
->getName(), regID2
, defer
);
2891 IOService::actionWillStop( IOService
* victim
, IOOptionBits options
,
2892 void *unused1 __unused
, void *unused2 __unused
,
2893 void *unused3 __unused
)
2896 IOService
* provider
;
2898 uint64_t regID1
, regID2
= victim
->getRegistryEntryID();
2900 iter
= victim
->getProviderIterator();
2902 while ((provider
= (IOService
*) iter
->getNextObject())) {
2903 regID1
= provider
->getRegistryEntryID();
2904 TLOG("%s[0x%qx]::willTerminate(%s[0x%qx], %08llx)\n",
2905 victim
->getName(), regID2
,
2906 provider
->getName(), regID1
, (long long)options
);
2908 IOSERVICE_TERMINATE_WILL
,
2910 (uintptr_t) (regID2
>> 32),
2912 (uintptr_t) (regID1
>> 32));
2914 ok
= victim
->willTerminate( provider
, options
);
2921 IOService::actionDidStop( IOService
* victim
, IOOptionBits options
,
2922 void *unused1 __unused
, void *unused2 __unused
,
2923 void *unused3 __unused
)
2926 IOService
* provider
;
2928 uint64_t regID1
, regID2
= victim
->getRegistryEntryID();
2930 iter
= victim
->getProviderIterator();
2932 while ((provider
= (IOService
*) iter
->getNextObject())) {
2933 regID1
= provider
->getRegistryEntryID();
2934 TLOG("%s[0x%qx]::didTerminate(%s[0x%qx], %08llx)\n",
2935 victim
->getName(), regID2
,
2936 provider
->getName(), regID1
, (long long)options
);
2937 victim
->didTerminate( provider
, options
, &defer
);
2940 (defer
? IOSERVICE_TERMINATE_DID_DEFER
2941 : IOSERVICE_TERMINATE_DID
),
2943 (uintptr_t) (regID2
>> 32),
2945 (uintptr_t) (regID1
>> 32));
2947 TLOG("%s[0x%qx]::didTerminate(%s[0x%qx], defer %d)\n",
2948 victim
->getName(), regID2
,
2949 provider
->getName(), regID1
, defer
);
2957 IOService::actionFinalize( IOService
* victim
, IOOptionBits options
,
2958 void *unused1 __unused
, void *unused2 __unused
,
2959 void *unused3 __unused
)
2961 uint64_t regID1
= victim
->getRegistryEntryID();
2962 TLOG("%s[0x%qx]::finalize(%08llx)\n", victim
->getName(), regID1
, (long long)options
);
2964 IOSERVICE_TERMINATE_FINALIZE
,
2966 (uintptr_t) (regID1
>> 32),
2969 victim
->finalize( options
);
2973 IOService::actionStop( IOService
* provider
, IOService
* client
,
2974 void *unused1 __unused
, void *unused2 __unused
,
2975 void *unused3 __unused
)
2977 uint64_t regID1
= provider
->getRegistryEntryID();
2978 uint64_t regID2
= client
->getRegistryEntryID();
2980 TLOG("%s[0x%qx]::stop(%s[0x%qx])\n", client
->getName(), regID2
, provider
->getName(), regID1
);
2982 IOSERVICE_TERMINATE_STOP
,
2984 (uintptr_t) (regID1
>> 32),
2986 (uintptr_t) (regID2
>> 32));
2988 client
->stop( provider
);
2989 if (provider
->isOpen( client
)) {
2990 provider
->close( client
);
2993 TLOG("%s[0x%qx]::detach(%s[0x%qx])\n", client
->getName(), regID2
, provider
->getName(), regID1
);
2994 client
->detach( provider
);
2998 IOService::terminateWorker( IOOptionBits options
)
3000 OSArray
* doPhase2List
;
3001 OSArray
* didPhase2List
;
3007 IOService
* provider
;
3013 options
|= kIOServiceRequired
;
3015 doPhase2List
= OSArray::withCapacity( 16 );
3016 didPhase2List
= OSArray::withCapacity( 16 );
3017 freeList
= OSSet::withCapacity( 16 );
3018 if ((NULL
== doPhase2List
) || (NULL
== didPhase2List
) || (NULL
== freeList
)) {
3023 workDone
= gIOTerminateWork
;
3025 while ((victim
= (IOService
*) gIOTerminatePhase2List
->getObject(0))) {
3027 gIOTerminatePhase2List
->removeObject(0);
3028 IOLockUnlock( gJobsLock
);
3030 uint64_t regID1
= victim
->getRegistryEntryID();
3032 IOSERVICE_TERM_START_PHASE2
,
3034 (uintptr_t) (regID1
>> 32),
3039 doPhase2
= victim
->lockForArbitration( true );
3041 doPhase2
= (0 != (kIOServiceInactiveState
& victim
->__state
[0]));
3043 uint64_t regID1
= victim
->getRegistryEntryID();
3045 IOSERVICE_TERM_TRY_PHASE2
,
3047 (uintptr_t) (regID1
>> 32),
3048 (uintptr_t) victim
->__state
[1],
3051 doPhase2
= (0 == (victim
->__state
[1] &
3052 (kIOServiceTermPhase1State
3053 | kIOServiceTermPhase2State
3054 | kIOServiceConfigState
)));
3056 if (doPhase2
&& (iter
= victim
->getClientIterator())) {
3057 while (doPhase2
&& (client
= (IOService
*) iter
->getNextObject())) {
3058 doPhase2
= (0 == (client
->__state
[1] & kIOServiceStartState
));
3060 uint64_t regID1
= client
->getRegistryEntryID();
3062 IOSERVICE_TERM_UC_DEFER
,
3064 (uintptr_t) (regID1
>> 32),
3065 (uintptr_t) client
->__state
[1],
3067 TLOG("%s[0x%qx]::defer phase2(%s[0x%qx])\n",
3068 victim
->getName(), victim
->getRegistryEntryID(),
3069 client
->getName(), client
->getRegistryEntryID());
3075 victim
->__state
[1] |= kIOServiceTermPhase2State
;
3078 victim
->unlockForArbitration();
3081 if (kIOServiceNeedWillTerminate
& victim
->__state
[1]) {
3082 if (NULL
== victim
->reserved
->uvars
) {
3083 _workLoopAction((IOWorkLoop::Action
) &actionWillStop
,
3084 victim
, (void *)(uintptr_t) options
);
3086 actionWillStop(victim
, options
, NULL
, NULL
, NULL
);
3090 OSArray
* notifiers
;
3091 notifiers
= victim
->copyNotifiers(gIOWillTerminateNotification
, 0, 0xffffffff);
3092 victim
->invokeNotifiers(¬ifiers
);
3094 _workLoopAction((IOWorkLoop::Action
) &actionWillTerminate
,
3096 (void *)(uintptr_t) options
,
3097 (void *)(uintptr_t) doPhase2List
,
3098 (void *)(uintptr_t) false);
3100 actionWillTerminate(
3101 victim
, options
, doPhase2List
, true, NULL
);
3103 didPhase2List
->headQ( victim
);
3106 victim
= (IOService
*) doPhase2List
->getObject(0);
3109 doPhase2List
->removeObject(0);
3113 while ((victim
= (IOService
*) didPhase2List
->getObject(0))) {
3114 bool scheduleFinalize
= false;
3115 if (victim
->lockForArbitration( true )) {
3116 victim
->__state
[1] |= kIOServiceTermPhase3State
;
3117 scheduleFinalize
= (NULL
== victim
->getClient());
3118 victim
->unlockForArbitration();
3120 _workLoopAction((IOWorkLoop::Action
) &actionDidTerminate
,
3121 victim
, (void *)(uintptr_t) options
);
3122 if (kIOServiceNeedWillTerminate
& victim
->__state
[1]) {
3123 _workLoopAction((IOWorkLoop::Action
) &actionDidStop
,
3124 victim
, (void *)(uintptr_t) options
, NULL
);
3126 // no clients - will go to finalize
3127 if (scheduleFinalize
) {
3128 victim
->scheduleFinalize(false);
3130 didPhase2List
->removeObject(0);
3132 IOLockLock( gJobsLock
);
3139 while ((victim
= (IOService
*) gIOFinalizeList
->getObject(0))) {
3140 bool sendFinal
= false;
3141 IOLockUnlock( gJobsLock
);
3142 if (victim
->lockForArbitration(true)) {
3143 sendFinal
= (0 == (victim
->__state
[1] & kIOServiceFinalized
));
3145 victim
->__state
[1] |= kIOServiceFinalized
;
3147 victim
->unlockForArbitration();
3150 _workLoopAction((IOWorkLoop::Action
) &actionFinalize
,
3151 victim
, (void *)(uintptr_t) options
);
3153 IOLockLock( gJobsLock
);
3155 freeList
->setObject( victim
);
3156 // safe if finalize list is append only
3157 gIOFinalizeList
->removeObject(0);
3161 (!doPhase3
) && (client
= (IOService
*) gIOStopList
->getObject(idx
));) {
3162 provider
= (IOService
*) gIOStopProviderList
->getObject(idx
);
3165 uint64_t regID1
= provider
->getRegistryEntryID();
3166 uint64_t regID2
= client
->getRegistryEntryID();
3168 if (!provider
->isChild( client
, gIOServicePlane
)) {
3169 // may be multiply queued - nop it
3170 TLOG("%s[0x%qx]::nop stop(%s[0x%qx])\n", client
->getName(), regID2
, provider
->getName(), regID1
);
3172 IOSERVICE_TERMINATE_STOP_NOP
,
3174 (uintptr_t) (regID1
>> 32),
3176 (uintptr_t) (regID2
>> 32));
3178 // a terminated client is not ready for stop if it has clients, skip it
3179 bool deferStop
= (0 != (kIOServiceInactiveState
& client
->__state
[0]));
3180 IOLockUnlock( gJobsLock
);
3181 if (deferStop
&& client
->lockForArbitration(true)) {
3182 deferStop
= (0 == (client
->__state
[1] & kIOServiceFinalized
));
3183 //deferStop = (!deferStop && (0 != client->getClient()));
3184 //deferStop = (0 != client->getClient());
3185 client
->unlockForArbitration();
3187 TLOG("%s[0x%qx]::defer stop()\n", client
->getName(), regID2
);
3188 IOServiceTrace(IOSERVICE_TERMINATE_STOP_DEFER
,
3190 (uintptr_t) (regID1
>> 32),
3192 (uintptr_t) (regID2
>> 32));
3195 IOLockLock( gJobsLock
);
3199 _workLoopAction((IOWorkLoop::Action
) &actionStop
,
3200 provider
, (void *) client
);
3201 IOLockLock( gJobsLock
);
3202 // check the finalize list now
3206 freeList
->setObject( client
);
3207 freeList
->setObject( provider
);
3209 // safe if stop list is append only
3210 gIOStopList
->removeObject( idx
);
3211 gIOStopProviderList
->removeObject( idx
);
3216 gIOTerminateWork
-= workDone
;
3217 moreToDo
= (gIOTerminateWork
!= 0);
3220 TLOG("iokit terminate done, %d stops remain\n", gIOStopList
->getCount());
3222 IOSERVICE_TERMINATE_DONE
,
3223 (uintptr_t) gIOStopList
->getCount(), 0, 0, 0);
3227 IOLockUnlock( gJobsLock
);
3229 freeList
->release();
3230 doPhase2List
->release();
3231 didPhase2List
->release();
3233 IOLockLock( gJobsLock
);
3237 IOService::finalize( IOOptionBits options
)
3240 IOService
* provider
;
3241 uint64_t regID1
, regID2
= getRegistryEntryID();
3243 iter
= getProviderIterator();
3247 while ((provider
= (IOService
*) iter
->getNextObject())) {
3249 if (0 == (__state
[1] & kIOServiceTermPhase3State
)) {
3250 /* we come down here on programmatic terminate */
3252 regID1
= provider
->getRegistryEntryID();
3253 TLOG("%s[0x%qx]::stop1(%s[0x%qx])\n", getName(), regID2
, provider
->getName(), regID1
);
3255 IOSERVICE_TERMINATE_STOP
,
3257 (uintptr_t) (regID1
>> 32),
3259 (uintptr_t) (regID2
>> 32));
3262 if (provider
->isOpen( this )) {
3263 provider
->close( this );
3268 if (provider
->lockForArbitration( true )) {
3269 if (0 == (provider
->__state
[1] & kIOServiceTermPhase3State
)) {
3270 scheduleStop( provider
);
3272 provider
->unlockForArbitration();
3290 IOService::doServiceTerminate( IOOptionBits options
)
3294 // a method in case someone needs to override it
3296 IOService::terminateClient( IOService
* client
, IOOptionBits options
)
3300 if (client
->isParent( this, gIOServicePlane
, true)) {
3301 // we are the clients only provider
3302 ok
= client
->terminate( options
);
3311 IOService::terminate( IOOptionBits options
)
3313 options
|= kIOServiceTerminate
;
3315 return terminatePhase1( options
);
3318 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3324 struct ServiceOpenMessageContext
{
3325 IOService
* service
;
3327 IOService
* excludeClient
;
3328 IOOptionBits options
;
3332 serviceOpenMessageApplier( OSObject
* object
, void * ctx
)
3334 ServiceOpenMessageContext
* context
= (ServiceOpenMessageContext
*) ctx
;
3336 if (object
!= context
->excludeClient
) {
3337 context
->service
->messageClient( context
->type
, object
, (void *)(uintptr_t) context
->options
);
3342 IOService::open( IOService
* forClient
,
3343 IOOptionBits options
,
3347 ServiceOpenMessageContext context
;
3349 context
.service
= this;
3350 context
.type
= kIOMessageServiceIsAttemptingOpen
;
3351 context
.excludeClient
= forClient
;
3352 context
.options
= options
;
3354 applyToInterested( gIOGeneralInterest
,
3355 &serviceOpenMessageApplier
, &context
);
3357 if (false == lockForArbitration(false)) {
3361 ok
= (0 == (__state
[0] & kIOServiceInactiveState
));
3363 ok
= handleOpen( forClient
, options
, arg
);
3366 if (ok
&& forClient
&& forClient
->reserved
->uvars
&& forClient
->reserved
->uvars
->userServer
) {
3367 forClient
->reserved
->uvars
->userServer
->serviceOpen(this, forClient
);
3370 unlockForArbitration();
3376 IOService::close( IOService
* forClient
,
3377 IOOptionBits options
)
3382 lockForArbitration();
3384 wasClosed
= handleIsOpen( forClient
);
3386 handleClose( forClient
, options
);
3387 last
= (__state
[1] & kIOServiceTermPhase3State
);
3389 if (forClient
&& forClient
->reserved
->uvars
&& forClient
->reserved
->uvars
->userServer
) {
3390 forClient
->reserved
->uvars
->userServer
->serviceClose(this, forClient
);
3394 unlockForArbitration();
3397 forClient
->scheduleStop( this );
3398 } else if (wasClosed
) {
3399 ServiceOpenMessageContext context
;
3401 context
.service
= this;
3402 context
.type
= kIOMessageServiceWasClosed
;
3403 context
.excludeClient
= forClient
;
3404 context
.options
= options
;
3406 applyToInterested( gIOGeneralInterest
,
3407 &serviceOpenMessageApplier
, &context
);
3412 IOService::isOpen( const IOService
* forClient
) const
3414 IOService
* self
= (IOService
*) this;
3417 self
->lockForArbitration();
3419 ok
= handleIsOpen( forClient
);
3421 self
->unlockForArbitration();
3427 IOService::handleOpen( IOService
* forClient
,
3428 IOOptionBits options
,
3433 ok
= (NULL
== __owner
);
3435 __owner
= forClient
;
3436 } else if (options
& kIOServiceSeize
) {
3437 ok
= (kIOReturnSuccess
== messageClient( kIOMessageServiceIsRequestingClose
,
3438 __owner
, (void *)(uintptr_t) options
));
3439 if (ok
&& (NULL
== __owner
)) {
3440 __owner
= forClient
;
3449 IOService::handleClose( IOService
* forClient
,
3450 IOOptionBits options
)
3452 if (__owner
== forClient
) {
3458 IOService::handleIsOpen( const IOService
* forClient
) const
3461 return __owner
== forClient
;
3463 return __owner
!= forClient
;
3468 * Probing & starting
3471 IONotifyOrdering( const OSMetaClassBase
* inObj1
, const OSMetaClassBase
* inObj2
, void * ref
)
3473 const _IOServiceNotifier
* obj1
= (const _IOServiceNotifier
*) inObj1
;
3474 const _IOServiceNotifier
* obj2
= (const _IOServiceNotifier
*) inObj2
;
3481 val1
= obj1
->priority
;
3484 val2
= obj2
->priority
;
3496 IOServiceObjectOrder( const OSObject
* entry
, void * ref
)
3498 OSDictionary
* dict
;
3499 IOService
* service
;
3500 _IOServiceNotifier
* notify
;
3501 OSSymbol
* key
= (OSSymbol
*) ref
;
3507 result
= kIODefaultProbeScore
;
3508 if ((dict
= OSDynamicCast( OSDictionary
, entry
))) {
3509 offset
= OSDynamicCast(OSNumber
, dict
->getObject( key
));
3510 } else if ((notify
= OSDynamicCast( _IOServiceNotifier
, entry
))) {
3511 return notify
->priority
;
3512 } else if ((service
= OSDynamicCast( IOService
, entry
))) {
3513 prop
= service
->copyProperty(key
);
3514 offset
= OSDynamicCast(OSNumber
, prop
);
3521 result
= offset
->unsigned32BitValue();
3524 OSSafeReleaseNULL(prop
);
3530 IOServiceOrdering( const OSMetaClassBase
* inObj1
, const OSMetaClassBase
* inObj2
, void * ref
)
3532 const OSObject
* obj1
= (const OSObject
*) inObj1
;
3533 const OSObject
* obj2
= (const OSObject
*) inObj2
;
3541 val1
= IOServiceObjectOrder( obj1
, ref
);
3545 val2
= IOServiceObjectOrder( obj2
, ref
);
3552 IOService::copyClientWithCategory( const OSSymbol
* category
)
3554 IOService
* service
= NULL
;
3556 const OSSymbol
* nextCat
;
3558 iter
= getClientIterator();
3560 while ((service
= (IOService
*) iter
->getNextObject())) {
3561 if (kIOServiceInactiveState
& service
->__state
[0]) {
3564 nextCat
= (const OSSymbol
*) OSDynamicCast( OSSymbol
,
3565 service
->getProperty( gIOMatchCategoryKey
));
3566 if (category
== nextCat
) {
3577 IOService::getClientWithCategory( const OSSymbol
* category
)
3580 service
= copyClientWithCategory(category
);
3588 IOService::invokeNotifier( _IOServiceNotifier
* notify
)
3590 _IOServiceNotifierInvocation invocation
;
3593 invocation
.thread
= current_thread();
3595 #if DEBUG_NOTIFIER_LOCKED
3597 if ((count
= isLockedForArbitration(0))) {
3598 IOLog("[%s, 0x%x]\n", notify
->type
->getCStringNoCopy(), count
);
3599 panic("[%s, 0x%x]\n", notify
->type
->getCStringNoCopy(), count
);
3601 #endif /* DEBUG_NOTIFIER_LOCKED */
3604 willNotify
= (0 != (kIOServiceNotifyEnable
& notify
->state
));
3607 queue_enter( ¬ify
->handlerInvocations
, &invocation
,
3608 _IOServiceNotifierInvocation
*, link
);
3613 ret
= (*notify
->handler
)(notify
->target
, notify
->ref
, this, notify
);
3616 queue_remove( ¬ify
->handlerInvocations
, &invocation
,
3617 _IOServiceNotifierInvocation
*, link
);
3618 if (kIOServiceNotifyWaiter
& notify
->state
) {
3619 notify
->state
&= ~kIOServiceNotifyWaiter
;
3620 WAKEUPNOTIFY( notify
);
3629 IOService::invokeNotifiers(OSArray
* willSend
[])
3632 _IOServiceNotifier
* notify
;
3641 for (unsigned int idx
= 0;
3642 (notify
= (_IOServiceNotifier
*) array
->getObject(idx
));
3644 ret
&= invokeNotifier(notify
);
3652 * Alloc and probe matching classes,
3653 * called on the provider instance
3657 IOService::probeCandidates( OSOrderedSet
* matches
)
3659 OSDictionary
* match
= NULL
;
3662 IOService
* newInst
;
3663 OSDictionary
* props
;
3666 OSOrderedSet
* familyMatches
= NULL
;
3667 OSOrderedSet
* startList
;
3668 OSSet
* kexts
= NULL
;
3671 OSDictionary
* startDict
= NULL
;
3672 const OSSymbol
* category
;
3674 _IOServiceNotifier
* notify
;
3675 OSObject
* nextMatch
= NULL
;
3677 bool needReloc
= false;
3678 bool matchDeferred
= false;
3682 IOService
* client
= NULL
;
3685 OSDictionary
* rematchPersonality
;
3690 bool categoryConsumed
;
3694 prop1
= copyProperty(gIORematchPersonalityKey
);
3695 rematchPersonality
= OSDynamicCast(OSDictionary
, prop1
);
3696 if (rematchPersonality
) {
3697 prop2
= copyProperty(gIORematchCountKey
);
3698 num
= OSDynamicCast(OSNumber
, prop2
);
3700 count
= num
->unsigned32BitValue();
3702 OSSafeReleaseNULL(prop2
);
3708 && (nextMatch
= matches
->getFirstObject())) {
3709 nextMatch
->retain();
3710 matches
->removeObject(nextMatch
);
3712 if ((notify
= OSDynamicCast( _IOServiceNotifier
, nextMatch
))) {
3713 if (0 == (__state
[0] & kIOServiceInactiveState
)) {
3714 invokeNotifier( notify
);
3716 nextMatch
->release();
3719 } else if (!(match
= OSDynamicCast( OSDictionary
, nextMatch
))) {
3720 nextMatch
->release();
3727 debugFlags
= getDebugFlags( match
);
3731 isDext
= (NULL
!= match
->getObject(gIOUserServerNameKey
));
3732 if (isDext
&& !(kIODKEnable
& gIODKDebug
)) {
3736 category
= OSDynamicCast( OSSymbol
,
3737 match
->getObject( gIOMatchCategoryKey
));
3738 if (NULL
== category
) {
3739 category
= gIODefaultMatchCategoryKey
;
3741 client
= copyClientWithCategory(category
);
3743 categoryConsumed
= (client
!= NULL
);
3744 if (categoryConsumed
) {
3746 if ((debugFlags
& kIOLogMatch
) && (this != gIOResources
)) {
3747 LOG("%s: match category %s exists\n", getName(),
3748 category
->getCStringNoCopy());
3751 OSSafeReleaseNULL(client
);
3757 // create a copy now in case its modified during matching
3758 props
= OSDictionary::withDictionary(match
, match
->getCount());
3759 if (NULL
== props
) {
3762 props
->setCapacityIncrement(1);
3764 // check the nub matches
3765 if (false == matchPassive(props
, kIOServiceChangesOK
| kIOServiceClassDone
)) {
3770 if (categoryConsumed
) {
3775 if (rematchPersonality
) {
3776 bool personalityMatch
= match
->isEqualTo(rematchPersonality
);
3777 if (count
> gIODextRelaunchMax
) {
3778 personalityMatch
= !personalityMatch
;
3780 if (!personalityMatch
) {
3785 // Check to see if driver reloc has been loaded.
3786 needReloc
= (false == gIOCatalogue
->isModuleLoaded( match
, &kextRef
));
3789 if (debugFlags
& kIOLogCatalogue
) {
3790 LOG("%s: stalling for module\n", getName());
3793 // If reloc hasn't been loaded, exit;
3794 // reprobing will occur after reloc has been loaded.
3798 if (NULL
== kexts
) {
3799 kexts
= OSSet::withCapacity(1);
3802 kexts
->setObject(kextRef
);
3807 // copy saved for rematchng
3808 props
->setObject(gIOMatchedPersonalityKey
, match
);
3810 // reorder on family matchPropertyTable score.
3811 if (NULL
== familyMatches
) {
3812 familyMatches
= OSOrderedSet::withCapacity( 1,
3813 IOServiceOrdering
, (void *) gIOProbeScoreKey
);
3815 if (familyMatches
) {
3816 familyMatches
->setObject( props
);
3820 OSSafeReleaseNULL(nextMatch
);
3821 OSSafeReleaseNULL(props
);
3826 if (familyMatches
) {
3828 && (props
= (OSDictionary
*) familyMatches
->getFirstObject())) {
3830 familyMatches
->removeObject( props
);
3835 debugFlags
= getDebugFlags( props
);
3838 symbol
= OSDynamicCast( OSSymbol
,
3839 props
->getObject( gIOClassKey
));
3844 //IOLog("%s alloc (symbol %p props %p)\n", symbol->getCStringNoCopy(), IOSERVICE_OBFUSCATE(symbol), IOSERVICE_OBFUSCATE(props));
3846 // alloc the driver instance
3847 inst
= (IOService
*) OSMetaClass::allocClassWithName( symbol
);
3849 if (!inst
|| !OSDynamicCast(IOService
, inst
)) {
3850 IOLog("Couldn't alloc class \"%s\"\n",
3851 symbol
->getCStringNoCopy());
3855 // init driver instance
3856 if (!(inst
->init( props
))) {
3858 if (debugFlags
& kIOLogStart
) {
3859 IOLog("%s::init fails\n", symbol
->getCStringNoCopy());
3864 if (__state
[1] & kIOServiceSynchronousState
) {
3865 inst
->__state
[1] |= kIOServiceSynchronousState
;
3868 // give the driver the default match category if not specified
3869 category
= OSDynamicCast( OSSymbol
,
3870 props
->getObject( gIOMatchCategoryKey
));
3871 if (NULL
== category
) {
3872 category
= gIODefaultMatchCategoryKey
;
3874 inst
->setProperty( gIOMatchCategoryKey
, (OSObject
*) category
);
3875 // attach driver instance
3876 if (!(inst
->attach( this ))) {
3880 // pass in score from property table
3881 score
= familyMatches
->orderObject( props
);
3883 // & probe the new driver instance
3885 if (debugFlags
& kIOLogProbe
) {
3886 LOG("%s::probe(%s)\n",
3887 inst
->getMetaClass()->getClassName(), getName());
3891 newInst
= inst
->probe( this, &score
);
3892 inst
->detach( this );
3893 if (NULL
== newInst
) {
3895 if (debugFlags
& kIOLogProbe
) {
3896 IOLog("%s::probe fails\n", symbol
->getCStringNoCopy());
3903 newPri
= OSNumber::withNumber( score
, 32 );
3905 newInst
->setProperty( gIOProbeScoreKey
, newPri
);
3909 // add to start list for the match category
3910 if (NULL
== startDict
) {
3911 startDict
= OSDictionary::withCapacity( 1 );
3913 assert( startDict
);
3914 startList
= (OSOrderedSet
*)
3915 startDict
->getObject( category
);
3916 if (NULL
== startList
) {
3917 startList
= OSOrderedSet::withCapacity( 1,
3918 IOServiceOrdering
, (void *) gIOProbeScoreKey
);
3919 if (startDict
&& startList
) {
3920 startDict
->setObject( category
, startList
);
3921 startList
->release();
3924 assert( startList
);
3926 startList
->setObject( newInst
);
3935 familyMatches
->release();
3936 familyMatches
= NULL
;
3939 // start the best (until success) of each category
3941 iter
= OSCollectionIterator::withCollection( startDict
);
3943 while ((category
= (const OSSymbol
*) iter
->getNextObject())) {
3944 startList
= (OSOrderedSet
*) startDict
->getObject( category
);
3945 assert( startList
);
3951 while (true // (!started)
3953 && (inst
= (IOService
*)startList
->getFirstObject())) {
3955 startList
->removeObject(inst
);
3958 debugFlags
= getDebugFlags( inst
);
3960 if (debugFlags
& kIOLogStart
) {
3962 LOG( "match category exists, skipping " );
3964 LOG( "%s::start(%s) <%d>\n", inst
->getName(),
3965 getName(), inst
->getRetainCount());
3968 if (false == started
) {
3970 IOLockLock(gJobsLock
);
3971 matchDeferred
= (gIOMatchDeferList
3972 && (kOSBooleanTrue
== inst
->getProperty(gIOMatchDeferKey
) || gInUserspaceReboot
));
3973 if (matchDeferred
&& (-1U == gIOMatchDeferList
->getNextIndexOfObject(this, 0))) {
3974 gIOMatchDeferList
->setObject(this);
3976 IOLockUnlock(gJobsLock
);
3977 if (matchDeferred
) {
3978 symbol
= OSDynamicCast(OSSymbol
, inst
->getProperty(gIOClassKey
));
3979 IOLog("%s(0x%qx): matching deferred by %s\n",
3980 getName(), getRegistryEntryID(),
3981 symbol
? symbol
->getCStringNoCopy() : "");
3982 // rematching will occur after the IOKit daemon loads all plists
3985 if (!matchDeferred
) {
3986 started
= startCandidate( inst
);
3988 if ((debugFlags
& kIOLogStart
) && (false == started
)) {
3989 LOG( "%s::start(%s) <%d> failed\n", inst
->getName(), getName(),
3990 inst
->getRetainCount());
4001 OSSafeReleaseNULL(prop1
);
4004 num
= OSNumber::withNumber(dextCount
, 32);
4005 setProperty(gIODEXTMatchCountKey
, num
);
4006 OSSafeReleaseNULL(num
);
4007 } else if (rematchPersonality
) {
4008 removeProperty(gIODEXTMatchCountKey
);
4011 // now that instances are created, drop the refs on any kexts allowing unload
4013 OSKext::dropMatchingReferences(kexts
);
4014 OSSafeReleaseNULL(kexts
);
4017 // adjust the busy count by +1 if matching is stalled for a module,
4018 // or -1 if a previously stalled matching is complete.
4019 lockForArbitration();
4021 uint64_t regID
= getRegistryEntryID();
4024 adjBusy
= (__state
[1] & kIOServiceModuleStallState
) ? 0 : 1;
4027 IOSERVICE_MODULESTALL
,
4029 (uintptr_t) (regID
>> 32),
4033 __state
[1] |= kIOServiceModuleStallState
;
4035 } else if (__state
[1] & kIOServiceModuleStallState
) {
4037 IOSERVICE_MODULEUNSTALL
,
4039 (uintptr_t) (regID
>> 32),
4043 __state
[1] &= ~kIOServiceModuleStallState
;
4047 _adjustBusy( adjBusy
);
4049 unlockForArbitration();
4052 startDict
->release();
4057 * Wait for a IOUserServer to check in
4061 __attribute__((noinline
, not_tail_called
))
4063 __WAITING_FOR_USER_SERVER__(OSDictionary
* matching
, IOUserServerCheckInToken
* token
)
4066 server
= IOService::waitForMatchingServiceWithToken(matching
, kIOUserServerCheckInTimeoutSecs
* NSEC_PER_SEC
, token
);
4071 IOService::willShutdown()
4073 gIOKitWillTerminate
= true;
4075 getPlatform()->waitQuiet(30 * NSEC_PER_SEC
);
4077 OSKext::willShutdown();
4081 IOService::userSpaceWillReboot()
4083 IOLockLock(gJobsLock
);
4085 // Recreate the defer list if it does not exist
4086 if (!gIOMatchDeferList
) {
4087 gIOMatchDeferList
= OSArray::withCapacity( 16 );
4090 gInUserspaceReboot
= true;
4091 IOLockUnlock(gJobsLock
);
4095 IOService::userSpaceDidReboot()
4097 IOLockLock(gJobsLock
);
4098 gInUserspaceReboot
= false;
4099 IOLockUnlock(gJobsLock
);
4102 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
4105 IOServicePH::init(IOPMrootDomain
* root
)
4107 fUserServers
= OSArray::withCapacity(4);
4108 fMatchingWork
= OSArray::withCapacity(4);
4110 assert(fUserServers
&& fMatchingWork
);
4112 fRootNotifier
= root
->registerInterest(
4113 gIOPriorityPowerStateInterest
, &IOServicePH::systemPowerChange
, NULL
, NULL
);
4115 assert(fRootNotifier
);
4121 IOLockLock(gJobsLock
);
4125 IOServicePH::unlock()
4127 IOLockUnlock(gJobsLock
);
4131 IOServicePH::serverAdd(IOUserServer
* server
)
4136 idx
= fUserServers
->getNextIndexOfObject(server
, 0);
4138 fUserServers
->setObject(server
);
4144 IOServicePH::serverRemove(IOUserServer
* server
)
4149 idx
= fUserServers
->getNextIndexOfObject(server
, 0);
4151 fUserServers
->removeObject(idx
);
4157 IOServicePH::serverAck(IOUserServer
* server
)
4165 if (server
&& fUserServersWait
) {
4166 idx
= fUserServersWait
->getNextIndexOfObject(server
, 0);
4168 fUserServersWait
->removeObject(idx
);
4169 if (0 == fUserServersWait
->getCount()) {
4170 OSSafeReleaseNULL(fUserServersWait
);
4174 if (!fUserServersWait
&& !fMatchingWork
->getCount()) {
4175 ackTo
= fSystemPowerAckTo
;
4176 ackToRef
= fSystemPowerAckRef
;
4177 fSystemPowerAckTo
= NULL
;
4182 DKLOG("allowPowerChange\n");
4183 ackTo
->allowPowerChange((uintptr_t) ackToRef
);
4188 IOServicePH::matchingStart(IOService
* service
)
4196 idx
= fMatchingWork
->getNextIndexOfObject(service
, 0);
4198 fMatchingWork
->setObject(service
);
4201 if (!fMatchingDelayed
) {
4202 fMatchingDelayed
= OSArray::withObjects((const OSObject
**) &service
, 1, 1);
4204 idx
= fMatchingDelayed
->getNextIndexOfObject(service
, 0);
4206 fMatchingDelayed
->setObject(service
);
4216 IOServicePH::matchingEnd(IOService
* service
)
4219 OSArray
* notifyServers
;
4220 OSArray
* deferredMatches
;
4222 notifyServers
= NULL
;
4223 deferredMatches
= NULL
;
4228 idx
= fMatchingWork
->getNextIndexOfObject(service
, 0);
4230 fMatchingWork
->removeObject(idx
);
4235 if ((fUserServerOff
!= fSystemOff
) && fUserServers
->getCount()) {
4237 if (0 == fMatchingWork
->getCount()) {
4238 fUserServersWait
= OSArray::withArray(fUserServers
);
4239 notifyServers
= OSArray::withArray(fUserServers
);
4240 fUserServerOff
= fSystemOff
;
4243 notifyServers
= OSArray::withArray(fUserServers
);
4244 fUserServerOff
= fSystemOff
;
4248 if (!fSystemOff
&& fMatchingDelayed
) {
4249 deferredMatches
= fMatchingDelayed
;
4250 fMatchingDelayed
= NULL
;
4255 if (notifyServers
) {
4256 notifyServers
->iterateObjects(^bool (OSObject
* obj
) {
4258 us
= (typeof(us
))obj
;
4259 us
->systemPower(fSystemOff
);
4262 OSSafeReleaseNULL(notifyServers
);
4265 if (deferredMatches
) {
4266 DKLOG("sleep deferred rematching count %d\n", deferredMatches
->getCount());
4267 deferredMatches
->iterateObjects(^bool (OSObject
* obj
)
4269 ((IOService
*)obj
)->startMatching(kIOServiceAsynchronous
);
4272 deferredMatches
->release();
4279 IOServicePH::serverSlept(void)
4284 ret
= (kIOMessageSystemWillSleep
== sSystemPower
)
4285 || (kIOMessageSystemPagingOff
== sSystemPower
);
4292 IOServicePH::systemPowerChange(
4295 UInt32 messageType
, IOService
* service
,
4296 void * messageArgument
, vm_size_t argSize
)
4300 IOPMSystemCapabilityChangeParameters
* params
;
4304 switch (messageType
) {
4305 case kIOMessageSystemCapabilityChange
:
4307 params
= (typeof params
)messageArgument
;
4309 if (kIODKLogPM
& gIODKDebug
) {
4310 IOLog("IOServicePH::kIOMessageSystemCapabilityChange: %s%s 0x%x->0x%x\n",
4311 params
->changeFlags
& kIOPMSystemCapabilityWillChange
? "will" : "",
4312 params
->changeFlags
& kIOPMSystemCapabilityDidChange
? "did" : "",
4313 params
->fromCapabilities
,
4314 params
->toCapabilities
);
4317 if ((params
->changeFlags
& kIOPMSystemCapabilityWillChange
) &&
4318 (params
->fromCapabilities
& kIOPMSystemCapabilityCPU
) &&
4319 ((params
->toCapabilities
& kIOPMSystemCapabilityCPU
) == 0)) {
4322 fSystemPowerAckRef
= params
->notifyRef
;
4323 fSystemPowerAckTo
= service
;
4328 params
->maxWaitForReply
= 60 * 1000 * 1000;
4329 ret
= kIOReturnSuccess
;
4330 } else if ((params
->changeFlags
& kIOPMSystemCapabilityWillChange
) &&
4331 ((params
->fromCapabilities
& kIOPMSystemCapabilityCPU
) == 0) &&
4332 (params
->toCapabilities
& kIOPMSystemCapabilityCPU
)) {
4339 params
->maxWaitForReply
= 0;
4340 ret
= kIOReturnSuccess
;
4342 params
->maxWaitForReply
= 0;
4343 ret
= kIOReturnSuccess
;
4348 ret
= kIOReturnUnsupported
;
4355 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
4358 * Start a previously attached & probed instance,
4359 * called on exporting object instance
4363 IOService::startCandidate( IOService
* service
)
4368 IOUserServer
* userServer
;
4372 obj
= service
->copyProperty(gIOUserServerNameKey
);
4374 if (obj
&& (this == gIOResources
)) {
4377 ok
= service
->attach( this );
4383 if ((this != gIOResources
) && (this != gIOUserResources
)) {
4384 // stall for any nub resources
4386 // stall for any driver resources
4387 service
->checkResources();
4391 OSString
* bundleID
;
4392 OSString
* serverName
;
4394 const OSSymbol
* sym
;
4395 OSDictionary
* matching
;
4397 OSNumber
* serverTag
;
4399 IOUserServerCheckInToken
* token
;
4401 if ((serverName
= OSDynamicCast(OSString
, obj
))) {
4402 obj
= service
->copyProperty(gIOModuleIdentifierKey
);
4403 bundleID
= OSDynamicCast(OSString
, obj
);
4404 entryID
= service
->getRegistryEntryID();
4405 serverTag
= OSNumber::withNumber(entryID
, 64);
4408 if (gIOKitWillTerminate
) {
4409 DKLOG("%s disabled in shutdown\n", serverName
->getCStringNoCopy());
4410 service
->detach(this);
4411 OSSafeReleaseNULL(obj
);
4415 ph
= IOServicePH::matchingStart(this);
4417 DKLOG("%s deferred in sleep\n", serverName
->getCStringNoCopy());
4418 service
->detach(this);
4419 OSSafeReleaseNULL(obj
);
4423 prop
= service
->copyProperty(gIOUserClassKey
);
4424 str
= OSDynamicCast(OSString
, prop
);
4426 service
->setName(str
);
4428 OSSafeReleaseNULL(prop
);
4430 if (!(kIODKDisableDextLaunch
& gIODKDebug
)) {
4431 OSKext::requestDaemonLaunch(bundleID
, serverName
, serverTag
, &token
);
4434 DKLOG("%s failed to create check in token\n", serverName
->getCStringNoCopy());
4435 service
->detach(this);
4436 OSSafeReleaseNULL(obj
);
4439 sym
= OSSymbol::withString(serverName
);
4440 matching
= serviceMatching(gIOUserServerClassKey
);
4441 propertyMatching(gIOUserServerNameKey
, sym
, matching
);
4442 if (!(kIODKDisableDextTag
& gIODKDebug
)) {
4443 propertyMatching(gIOUserServerTagKey
, serverTag
, matching
);
4446 server
= __WAITING_FOR_USER_SERVER__(matching
, token
);
4447 matching
->release();
4448 OSSafeReleaseNULL(serverTag
);
4449 OSSafeReleaseNULL(serverName
);
4451 userServer
= OSDynamicCast(IOUserServer
, server
);
4454 service
->detach(this);
4455 IOServicePH::matchingEnd(this);
4456 OSSafeReleaseNULL(obj
);
4457 DKLOG(DKS
" user server timeout\n", DKN(service
));
4458 #if DEVELOPMENT || DEBUG
4459 driverkit_checkin_timed_out
= mach_absolute_time();
4464 if (!(kIODKDisableCheckInTokenVerification
& gIODKDebug
)) {
4465 if (!userServer
->serviceMatchesCheckInToken(token
)) {
4467 service
->detach(this);
4468 IOServicePH::matchingEnd(this);
4469 OSSafeReleaseNULL(obj
);
4470 userServer
->exit("Check In Token verification failed");
4471 userServer
->release();
4477 OSKext
*kext
= OSKext::lookupKextWithIdentifier(bundleID
);
4479 const char *name
= bundleID
->getCStringNoCopy();
4480 IOLog("%s Could not find OSKext for %s\n", __func__
, name
);
4487 userServer
->setTaskLoadTag(kext
);
4488 userServer
->setDriverKitUUID(kext
);
4489 OSKext::OSKextLogDriverKitInfoLoad(kext
);
4491 OSSafeReleaseNULL(bundleID
);
4492 OSSafeReleaseNULL(kext
);
4494 if (!(kIODKDisableEntitlementChecking
& gIODKDebug
)) {
4495 if (!userServer
->checkEntitlements(this, service
)) {
4496 service
->detach(this);
4497 IOServicePH::matchingEnd(this);
4498 userServer
->exit("Entitlements check failed");
4499 userServer
->release();
4504 userServer
->serviceAttach(service
, this);
4508 AbsoluteTime startTime
;
4509 AbsoluteTime endTime
;
4512 if (kIOLogStart
& gIOKitDebug
) {
4513 clock_get_uptime(&startTime
);
4516 ok
= service
->start(this);
4518 if (kIOLogStart
& gIOKitDebug
) {
4519 clock_get_uptime(&endTime
);
4521 if (CMP_ABSOLUTETIME(&endTime
, &startTime
) > 0) {
4522 SUB_ABSOLUTETIME(&endTime
, &startTime
);
4523 absolutetime_to_nanoseconds(endTime
, &nano
);
4524 if (nano
> 500000000ULL) {
4525 IOLog("%s::start took %ld ms\n", service
->getName(), (long)(UInt32
)(nano
/ 1000000ULL));
4530 userServer
->serviceStarted(service
, this, ok
);
4531 userServer
->release();
4535 IOInstallServiceSleepPlatformActions(service
);
4539 service
->detach( this );
4543 IOServicePH::matchingEnd(this);
4550 IOService::publishResource( const char * key
, OSObject
* value
)
4552 const OSSymbol
* sym
;
4554 if ((sym
= OSSymbol::withCString( key
))) {
4555 publishResource( sym
, value
);
4561 IOService::publishResource( const OSSymbol
* key
, OSObject
* value
)
4563 if (NULL
== value
) {
4564 value
= (OSObject
*) gIOServiceKey
;
4567 gIOResources
->setProperty( key
, value
);
4569 if (IORecursiveLockHaveLock( gNotificationLock
)) {
4573 gIOResourceGenerationCount
++;
4574 gIOResources
->registerService();
4578 IOService::publishUserResource( const OSSymbol
* key
, OSObject
* value
)
4580 if (NULL
== value
) {
4581 value
= (OSObject
*) gIOServiceKey
;
4584 gIOUserResources
->setProperty( key
, value
);
4586 if (IORecursiveLockHaveLock( gNotificationLock
)) {
4590 gIOResourceGenerationCount
++;
4591 gIOUserResources
->registerService();
4595 IOService::addNeededResource( const char * key
)
4597 OSObject
* resourcesProp
;
4602 resourcesProp
= copyProperty( gIOResourceMatchKey
);
4603 if (!resourcesProp
) {
4607 newKey
= OSString::withCString( key
);
4609 resourcesProp
->release();
4613 set
= OSDynamicCast( OSSet
, resourcesProp
);
4615 set
= OSSet::withCapacity( 1 );
4617 set
->setObject( resourcesProp
);
4623 set
->setObject( newKey
);
4625 ret
= setProperty( gIOResourceMatchKey
, set
);
4627 resourcesProp
->release();
4633 IOService::checkResource( OSObject
* matching
)
4636 OSDictionary
* table
;
4638 if ((str
= OSDynamicCast( OSString
, matching
))) {
4639 if (gIOResources
->getProperty( str
)) {
4645 table
= resourceMatching( str
);
4646 } else if ((table
= OSDynamicCast( OSDictionary
, matching
))) {
4649 IOLog("%s: Can't match using: %s\n", getName(),
4650 matching
->getMetaClass()->getClassName());
4651 /* false would stall forever */
4655 if (gIOKitDebug
& kIOLogConfig
) {
4656 LOG("config(%p): stalling %s\n", IOSERVICE_OBFUSCATE(IOThreadSelf()), getName());
4659 waitForService( table
);
4661 if (gIOKitDebug
& kIOLogConfig
) {
4662 LOG("config(%p): waking\n", IOSERVICE_OBFUSCATE(IOThreadSelf()));
4669 IOService::checkResources( void )
4671 OSObject
* resourcesProp
;
4677 resourcesProp
= copyProperty( gIOResourceMatchKey
);
4678 if (NULL
== resourcesProp
) {
4682 if ((set
= OSDynamicCast( OSSet
, resourcesProp
))) {
4683 iter
= OSCollectionIterator::withCollection( set
);
4684 ok
= (NULL
!= iter
);
4685 while (ok
&& (obj
= iter
->getNextObject())) {
4686 ok
= checkResource( obj
);
4692 ok
= checkResource( resourcesProp
);
4695 OSSafeReleaseNULL(resourcesProp
);
4702 _IOConfigThread::configThread( const char * name
)
4704 _IOConfigThread
* inst
;
4707 if (!(inst
= new _IOConfigThread
)) {
4710 if (!inst
->init()) {
4714 if (KERN_SUCCESS
!= kernel_thread_start(&_IOConfigThread::main
, inst
, &thread
)) {
4718 char threadName
[MAXTHREADNAMESIZE
];
4719 snprintf(threadName
, sizeof(threadName
), "IOConfigThread_'%s'", name
);
4720 thread_set_thread_name(thread
, threadName
);
4721 thread_deallocate(thread
);
4734 IOService::doServiceMatch( IOOptionBits options
)
4736 _IOServiceNotifier
* notify
;
4738 OSOrderedSet
* matches
;
4739 OSArray
* resourceKeys
= NULL
;
4740 SInt32 catalogGeneration
;
4741 bool keepGuessing
= true;
4742 bool reRegistered
= true;
4744 OSArray
* notifiers
[2] = {NULL
};
4746 // job->nub->deliverNotification( gIOPublishNotification,
4747 // kIOServiceRegisteredState, 0xffffffff );
4749 while (keepGuessing
) {
4750 matches
= gIOCatalogue
->findDrivers( this, &catalogGeneration
);
4751 // the matches list should always be created by findDrivers()
4753 lockForArbitration();
4754 if (0 == (__state
[0] & kIOServiceFirstPublishState
)) {
4755 getMetaClass()->addInstance(this);
4756 notifiers
[0] = copyNotifiers(gIOFirstPublishNotification
,
4757 kIOServiceFirstPublishState
, 0xffffffff );
4760 __state
[1] &= ~kIOServiceNeedConfigState
;
4761 __state
[1] |= kIOServiceConfigState
| kIOServiceConfigRunning
;
4762 didRegister
= (0 == (kIOServiceRegisteredState
& __state
[0]));
4763 __state
[0] |= kIOServiceRegisteredState
;
4765 keepGuessing
&= (0 == (__state
[0] & kIOServiceInactiveState
));
4766 if (reRegistered
&& keepGuessing
) {
4767 iter
= OSCollectionIterator::withCollection((OSOrderedSet
*)
4768 gNotifications
->getObject( gIOPublishNotification
));
4770 while ((notify
= (_IOServiceNotifier
*)
4771 iter
->getNextObject())) {
4772 if (matchPassive(notify
->matching
, 0)
4773 && (kIOServiceNotifyEnable
& notify
->state
)) {
4774 matches
->setObject( notify
);
4782 unlockForArbitration();
4783 invokeNotifiers(¬ifiers
[0]);
4785 if (keepGuessing
&& matches
->getCount() && (kIOReturnSuccess
== getResources())) {
4786 if ((this == gIOResources
) || (this == gIOUserResources
)) {
4788 resourceKeys
->release();
4790 resourceKeys
= copyPropertyKeys();
4792 probeCandidates( matches
);
4798 lockForArbitration();
4799 reRegistered
= (0 != (__state
[1] & kIOServiceNeedConfigState
));
4801 (reRegistered
|| (catalogGeneration
!=
4802 gIOCatalogue
->getGenerationCount()))
4803 && (0 == (__state
[0] & kIOServiceInactiveState
));
4806 unlockForArbitration();
4810 if ((0 == (__state
[0] & kIOServiceInactiveState
))
4811 && (0 == (__state
[1] & kIOServiceModuleStallState
))) {
4813 setProperty(gIOResourceMatchedKey
, resourceKeys
);
4816 notifiers
[0] = copyNotifiers(gIOMatchedNotification
,
4817 kIOServiceMatchedState
, 0xffffffff);
4818 if (0 == (__state
[0] & kIOServiceFirstMatchState
)) {
4819 notifiers
[1] = copyNotifiers(gIOFirstMatchNotification
,
4820 kIOServiceFirstMatchState
, 0xffffffff);
4824 __state
[1] &= ~kIOServiceConfigRunning
;
4825 unlockForArbitration();
4828 resourceKeys
->release();
4831 invokeNotifiers(¬ifiers
[0]);
4832 invokeNotifiers(¬ifiers
[1]);
4834 lockForArbitration();
4835 __state
[1] &= ~kIOServiceConfigState
;
4836 scheduleTerminatePhase2();
4839 unlockForArbitration();
4843 IOService::_adjustBusy( SInt32 delta
)
4848 bool wasQuiet
, nowQuiet
, needWake
;
4851 result
= __state
[1] & kIOServiceBusyStateMask
;
4856 next
->lockForArbitration();
4858 count
= next
->__state
[1] & kIOServiceBusyStateMask
;
4859 wasQuiet
= (0 == count
);
4860 if (((delta
< 0) && wasQuiet
) || ((delta
> 0) && (kIOServiceBusyMax
== count
))) {
4861 OSReportWithBacktrace("%s: bad busy count (%d,%d)\n", next
->getName(), count
, delta
);
4865 next
->__state
[1] = (next
->__state
[1] & ~kIOServiceBusyStateMask
) | count
;
4866 nowQuiet
= (0 == count
);
4867 needWake
= (0 != (kIOServiceBusyWaiterState
& next
->__state
[1]));
4870 next
->__state
[1] &= ~kIOServiceBusyWaiterState
;
4871 IOLockLock( gIOServiceBusyLock
);
4872 thread_wakeup((event_t
) next
);
4873 IOLockUnlock( gIOServiceBusyLock
);
4876 next
->unlockForArbitration();
4879 if ((wasQuiet
|| nowQuiet
)) {
4880 uint64_t regID
= next
->getRegistryEntryID();
4882 ((wasQuiet
/*nowBusy*/) ? IOSERVICE_BUSY
: IOSERVICE_NONBUSY
),
4884 (uintptr_t) (regID
>> 32),
4889 next
->__timeBusy
= mach_absolute_time();
4891 next
->__accumBusy
+= mach_absolute_time() - next
->__timeBusy
;
4892 next
->__timeBusy
= 0;
4895 MessageClientsContext context
;
4897 context
.service
= next
;
4898 context
.type
= kIOMessageServiceBusyStateChange
;
4899 context
.argument
= (void *) wasQuiet
; /*nowBusy*/
4900 context
.argSize
= 0;
4902 applyToInterestNotifiers( next
, gIOBusyInterest
,
4903 &messageClientsApplier
, &context
);
4906 if (nowQuiet
&& (next
== gIOServiceRoot
)) {
4907 OSKext::considerUnloads();
4908 IOServiceTrace(IOSERVICE_REGISTRY_QUIET
, 0, 0, 0, 0);
4913 delta
= nowQuiet
? -1 : +1;
4914 } while ((wasQuiet
|| nowQuiet
) && (next
= next
->getProvider()));
4921 IOService::adjustBusy( SInt32 delta
)
4923 lockForArbitration();
4924 _adjustBusy( delta
);
4925 unlockForArbitration();
4929 IOService::getAccumulatedBusyTime( void )
4931 uint64_t accumBusy
= __accumBusy
;
4932 uint64_t timeBusy
= __timeBusy
;
4936 accumBusy
= __accumBusy
;
4937 timeBusy
= __timeBusy
;
4939 accumBusy
+= mach_absolute_time() - timeBusy
;
4941 }while (timeBusy
!= __timeBusy
);
4943 absolutetime_to_nanoseconds(*(AbsoluteTime
*)&accumBusy
, &nano
);
4949 IOService::getBusyState( void )
4951 return __state
[1] & kIOServiceBusyStateMask
;
4955 IOService::waitForState( UInt32 mask
, UInt32 value
,
4956 mach_timespec_t
* timeout
)
4958 panic("waitForState");
4959 return kIOReturnUnsupported
;
4963 IOService::waitForState( UInt32 mask
, UInt32 value
,
4967 int waitResult
= THREAD_AWAKENED
;
4968 bool computeDeadline
= true;
4969 AbsoluteTime abstime
;
4972 lockForArbitration();
4973 IOLockLock( gIOServiceBusyLock
);
4974 wait
= (value
!= (__state
[1] & mask
));
4976 __state
[1] |= kIOServiceBusyWaiterState
;
4977 unlockForArbitration();
4978 if (timeout
!= UINT64_MAX
) {
4979 if (computeDeadline
) {
4980 AbsoluteTime nsinterval
;
4981 nanoseconds_to_absolutetime(timeout
, &nsinterval
);
4982 clock_absolutetime_interval_to_deadline(nsinterval
, &abstime
);
4983 computeDeadline
= false;
4985 assert_wait_deadline((event_t
)this, THREAD_UNINT
, __OSAbsoluteTime(abstime
));
4987 assert_wait((event_t
)this, THREAD_UNINT
);
4990 unlockForArbitration();
4992 IOLockUnlock( gIOServiceBusyLock
);
4994 waitResult
= thread_block(THREAD_CONTINUE_NULL
);
4996 } while (wait
&& (waitResult
!= THREAD_TIMED_OUT
));
4998 if (waitResult
== THREAD_TIMED_OUT
) {
4999 return kIOReturnTimeout
;
5001 return kIOReturnSuccess
;
5006 IOService::waitQuiet( uint64_t timeout
)
5010 char * string
= NULL
;
5011 char * panicString
= NULL
;
5013 size_t panicStringLen
;
5016 bool pendingRequests
;
5017 bool dopanic
= false;
5021 * On kasan kernels, everything takes longer, so double the number of
5022 * timeout extensions. This should help with issues like 41259215
5023 * where WindowServer was timing out waiting for kextd to get all the
5024 * kasan kexts loaded and started.
5026 enum { kTimeoutExtensions
= 8 };
5027 #define WITH_IOWAITQUIET_EXTENSIONS 1
5028 #elif XNU_TARGET_OS_OSX && defined(__arm64__)
5029 enum { kTimeoutExtensions
= 1 };
5030 #define WITH_IOWAITQUIET_EXTENSIONS 0
5032 enum { kTimeoutExtensions
= 4 };
5033 #define WITH_IOWAITQUIET_EXTENSIONS 1
5036 time
= mach_absolute_time();
5037 pendingRequests
= false;
5038 for (loops
= 0; loops
< kTimeoutExtensions
; loops
++) {
5039 ret
= waitForState( kIOServiceBusyStateMask
, 0, timeout
);
5041 if (loops
&& (kIOReturnSuccess
== ret
)) {
5042 time
= mach_absolute_time() - time
;
5043 absolutetime_to_nanoseconds(*(AbsoluteTime
*)&time
, &nano
);
5044 IOLog("busy extended ok[%d], (%llds, %llds)\n",
5045 loops
, timeout
/ 1000000000ULL, nano
/ 1000000000ULL);
5047 } else if (kIOReturnTimeout
!= ret
) {
5049 } else if (timeout
< (41ull * NSEC_PER_SEC
)) {
5054 IORegistryIterator
* iter
;
5056 OSOrderedSet
* leaves
;
5058 IOService
* nextParent
;
5063 panicStringLen
= 256;
5065 string
= IONew(char, len
);
5068 panicString
= IONew(char, panicStringLen
);
5071 pendingRequests
= OSKext::pendingIOKitDaemonRequests();
5072 iter
= IORegistryIterator::iterateOver(this, gIOServicePlane
, kIORegistryIterateRecursively
);
5073 leaves
= OSOrderedSet::withCapacity(4);
5075 set
= iter
->iterateAll();
5077 if (string
&& panicString
&& leaves
&& set
) {
5078 string
[0] = panicString
[0] = 0;
5079 set
->setObject(this);
5080 while ((next
= (IOService
*) set
->getLastObject())) {
5081 if (next
->getBusyState()) {
5082 if (kIOServiceModuleStallState
& next
->__state
[1]) {
5083 pendingRequests
= true;
5085 leaves
->setObject(next
);
5087 while ((nextParent
= nextParent
->getProvider())) {
5088 set
->removeObject(nextParent
);
5089 leaves
->removeObject(nextParent
);
5092 set
->removeObject(next
);
5095 while ((next
= (IOService
*) leaves
->getLastObject())) {
5096 l
= snprintf(s
, len
, "%s'%s'", ((s
== string
) ? "" : ", "), next
->getName());
5102 leaves
->removeObject(next
);
5105 OSSafeReleaseNULL(leaves
);
5106 OSSafeReleaseNULL(set
);
5107 OSSafeReleaseNULL(iter
);
5110 dopanic
= (kIOWaitQuietPanics
& gIOKitDebug
);
5111 #if WITH_IOWAITQUIET_EXTENSIONS
5112 dopanic
= (dopanic
&& (loops
>= (kTimeoutExtensions
- 1)));
5114 snprintf(panicString
, panicStringLen
,
5115 "%s[%d], (%llds): %s",
5116 pendingRequests
? "IOKit Daemon (" kIOKitDaemonName
") stall" : "busy timeout",
5117 loops
, timeout
/ 1000000000ULL,
5118 string
? string
: "");
5119 IOLog("%s\n", panicString
);
5121 panic("%s", panicString
);
5122 } else if (!loops
) {
5123 getPMRootDomain()->startSpinDump(1);
5128 IODelete(string
, char, 256);
5131 IODelete(panicString
, char, panicStringLen
);
5138 IOService::waitQuiet( mach_timespec_t
* timeout
)
5143 timeoutNS
= timeout
->tv_sec
;
5144 timeoutNS
*= kSecondScale
;
5145 timeoutNS
+= timeout
->tv_nsec
;
5147 timeoutNS
= UINT64_MAX
;
5150 return waitQuiet(timeoutNS
);
5154 IOService::serializeProperties( OSSerialize
* s
) const
5157 ((IOService
*)this)->setProperty(((IOService
*)this)->__state
,
5158 sizeof(__state
), "__state");
5160 return super::serializeProperties(s
);
5164 IOService::resetRematchProperties()
5166 removeProperty(gIORematchCountKey
);
5167 removeProperty(gIORematchPersonalityKey
);
5172 _IOConfigThread::main(void * arg
, wait_result_t result
)
5174 _IOConfigThread
* self
= (_IOConfigThread
*) arg
;
5175 _IOServiceJob
* job
;
5179 thread_precedence_policy_data_t precedence
= { -1 };
5181 kr
= thread_policy_set(current_thread(),
5182 THREAD_PRECEDENCE_POLICY
,
5183 (thread_policy_t
) &precedence
,
5184 THREAD_PRECEDENCE_POLICY_COUNT
);
5185 if (KERN_SUCCESS
!= kr
) {
5186 IOLog("thread_policy_set(%d)\n", kr
);
5192 semaphore_wait( gJobsSemaphore
);
5194 IOTakeLock( gJobsLock
);
5195 job
= (_IOServiceJob
*) gJobs
->getFirstObject();
5197 gJobs
->removeObject(job
);
5200 // gNumConfigThreads--; // we're out of service
5201 gNumWaitingThreads
--; // we're out of service
5203 IOUnlock( gJobsLock
);
5208 if (gIOKitDebug
& kIOLogConfig
) {
5209 LOG("config(%p): starting on %s, %d\n",
5210 IOSERVICE_OBFUSCATE(IOThreadSelf()), job
->nub
->getName(), job
->type
);
5213 switch (job
->type
) {
5215 nub
->doServiceMatch( job
->options
);
5219 LOG("config(%p): strange type (%d)\n",
5220 IOSERVICE_OBFUSCATE(IOThreadSelf()), job
->type
);
5227 IOTakeLock( gJobsLock
);
5228 alive
= (gOutstandingJobs
> gNumWaitingThreads
);
5230 gNumWaitingThreads
++; // back in service
5232 // gNumConfigThreads++;
5234 if (0 == --gNumConfigThreads
) {
5235 // IOLog("MATCH IDLE\n");
5236 IOLockWakeup( gJobsLock
, (event_t
) &gNumConfigThreads
, /* one-thread */ false );
5239 IOUnlock( gJobsLock
);
5243 if (gIOKitDebug
& kIOLogConfig
) {
5244 LOG("config(%p): terminating\n", IOSERVICE_OBFUSCATE(IOThreadSelf()));
5251 IOService::waitMatchIdle( UInt32 msToWait
)
5254 int waitResult
= THREAD_AWAKENED
;
5255 bool computeDeadline
= true;
5256 AbsoluteTime deadline
;
5258 IOLockLock( gJobsLock
);
5260 wait
= (0 != gNumConfigThreads
);
5263 if (computeDeadline
) {
5264 clock_interval_to_deadline(
5265 msToWait
, kMillisecondScale
, &deadline
);
5266 computeDeadline
= false;
5268 waitResult
= IOLockSleepDeadline( gJobsLock
, &gNumConfigThreads
,
5269 deadline
, THREAD_UNINT
);
5271 waitResult
= IOLockSleep( gJobsLock
, &gNumConfigThreads
,
5275 } while (wait
&& (waitResult
!= THREAD_TIMED_OUT
));
5276 IOLockUnlock( gJobsLock
);
5278 if (waitResult
== THREAD_TIMED_OUT
) {
5279 return kIOReturnTimeout
;
5281 return kIOReturnSuccess
;
5286 IOService::cpusRunning(void)
5288 gCPUsRunning
= true;
5292 _IOServiceJob::pingConfig( _IOServiceJob
* job
)
5301 IOTakeLock( gJobsLock
);
5304 if (nub
== gIOResources
) {
5305 gJobs
->setFirstObject( job
);
5307 gJobs
->setLastObject( job
);
5310 count
= gNumWaitingThreads
;
5311 // if( gNumConfigThreads) count++;// assume we're called from a config thread
5313 create
= ((gOutstandingJobs
> count
)
5314 && ((gNumConfigThreads
< gMaxConfigThreads
)
5315 || (nub
== gIOResources
)
5318 gNumConfigThreads
++;
5319 gNumWaitingThreads
++;
5320 if (gNumConfigThreads
> gHighNumConfigThreads
) {
5321 gHighNumConfigThreads
= gNumConfigThreads
;
5325 IOUnlock( gJobsLock
);
5330 if (gIOKitDebug
& kIOLogConfig
) {
5331 LOG("config(%d): creating\n", gNumConfigThreads
- 1);
5333 _IOConfigThread::configThread(nub
->getName());
5336 semaphore_signal( gJobsSemaphore
);
5339 struct IOServiceMatchContext
{
5340 OSDictionary
* table
;
5349 IOService::instanceMatch(const OSObject
* entry
, void * context
)
5351 IOServiceMatchContext
* ctx
= (typeof(ctx
))context
;
5352 IOService
* service
= (typeof(service
))entry
;
5353 OSDictionary
* table
= ctx
->table
;
5354 uint32_t options
= ctx
->options
;
5355 uint32_t state
= ctx
->state
;
5361 match
= ((state
== (state
& service
->__state
[0]))
5362 && (0 == (service
->__state
[0] & kIOServiceInactiveState
)));
5366 match
= service
->matchInternal(table
, options
, &done
);
5368 ctx
->count
+= table
->getCount();
5376 if ((kIONotifyOnce
& options
) && (ctx
->done
== ctx
->count
)) {
5378 ctx
->result
= service
;
5380 } else if (!ctx
->result
) {
5381 ctx
->result
= OSSet::withObjects((const OSObject
**) &service
, 1, 1);
5383 ((OSSet
*)ctx
->result
)->setObject(service
);
5388 // internal - call with gNotificationLock
5390 IOService::copyExistingServices( OSDictionary
* matching
,
5391 IOOptionBits inState
, IOOptionBits options
)
5393 OSObject
* current
= NULL
;
5395 IOService
* service
;
5404 OSSerialize
* s
= OSSerialize::withCapacity(128);
5405 matching
->serialize(s
);
5408 if ((obj
= matching
->getObject(gIOProviderClassKey
))
5410 && gIOResourcesKey
->isEqualTo(obj
)
5411 && (service
= gIOResources
)) {
5412 if ((inState
== (service
->__state
[0] & inState
))
5413 && (0 == (service
->__state
[0] & kIOServiceInactiveState
))
5414 && service
->matchPassive(matching
, options
)) {
5415 if (options
& kIONotifyOnce
) {
5419 current
= OSSet::withObjects((const OSObject
**) &service
, 1, 1 );
5423 IOServiceMatchContext ctx
;
5425 options
|= kIOServiceClassDone
;
5426 ctx
.table
= matching
;
5427 ctx
.state
= inState
;
5430 ctx
.options
= options
;
5433 if ((str
= OSDynamicCast(OSString
, obj
))) {
5434 const OSSymbol
* sym
= OSSymbol::withString(str
);
5435 OSMetaClass::applyToInstancesOfClassName(sym
, instanceMatch
, &ctx
);
5438 IOService::gMetaClass
.applyToInstances(instanceMatch
, &ctx
);
5441 if (((!(options
& kIONotifyOnce
) || !ctx
.result
))
5442 && matching
->getObject(gIOCompatibilityMatchKey
)) {
5443 IOServiceCompatibility::gMetaClass
.applyToInstances(instanceMatch
, &ctx
);
5446 current
= ctx
.result
;
5447 options
|= kIOServiceInternalDone
;
5448 if (current
&& (ctx
.done
!= ctx
.count
)) {
5449 OSSet
* source
= OSDynamicCast(OSSet
, current
);
5451 while ((service
= (IOService
*) source
->getAnyObject())) {
5452 if (service
->matchPassive(matching
, options
)) {
5453 if (options
& kIONotifyOnce
) {
5459 ((OSSet
*)current
)->setObject( service
);
5461 current
= OSSet::withObjects(
5462 (const OSObject
**) &service
, 1, 1 );
5465 source
->removeObject(service
);
5473 OSObject
* _current
= 0;
5475 iter
= IORegistryIterator::iterateOver( gIOServicePlane
,
5476 kIORegistryIterateRecursively
);
5480 while ((service
= (IOService
*) iter
->getNextObject())) {
5481 if ((inState
== (service
->__state
[0] & inState
))
5482 && (0 == (service
->__state
[0] & kIOServiceInactiveState
))
5483 && service
->matchPassive(matching
, 0)) {
5484 if (options
& kIONotifyOnce
) {
5490 ((OSSet
*)_current
)->setObject( service
);
5492 _current
= OSSet::withObjects(
5493 (const OSObject
**) &service
, 1, 1 );
5497 } while (!service
&& !iter
->isValid());
5501 if (((current
!= 0) != (_current
!= 0))
5502 || (current
&& _current
&& !current
->isEqualTo(_current
))) {
5503 OSSerialize
* s1
= OSSerialize::withCapacity(128);
5504 OSSerialize
* s2
= OSSerialize::withCapacity(128);
5505 current
->serialize(s1
);
5506 _current
->serialize(s2
);
5507 kprintf("**mismatch** %p %p\n%s\n%s\n%s\n", IOSERVICE_OBFUSCATE(current
),
5508 IOSERVICE_OBFUSCATE(_current
), s
->text(), s1
->text(), s2
->text());
5514 _current
->release();
5521 if (current
&& (0 == (options
& (kIONotifyOnce
| kIOServiceExistingSet
)))) {
5522 iter
= OSCollectionIterator::withCollection((OSSet
*)current
);
5532 IOService::getMatchingServices( OSDictionary
* matching
)
5536 // is a lock even needed?
5539 iter
= (OSIterator
*) copyExistingServices( matching
,
5540 kIOServiceMatchedState
);
5548 IOService::copyMatchingService( OSDictionary
* matching
)
5550 IOService
* service
;
5552 // is a lock even needed?
5555 service
= (IOService
*) copyExistingServices( matching
,
5556 kIOServiceMatchedState
, kIONotifyOnce
);
5563 struct _IOServiceMatchingNotificationHandlerRef
{
5564 IOServiceNotificationHandler handler
;
5569 _IOServiceMatchingNotificationHandler( void * target
, void * refCon
,
5570 IOService
* newService
,
5571 IONotifier
* notifier
)
5573 return (*((_IOServiceNotifier
*) notifier
)->compatHandler
)(target
, refCon
, newService
);
5576 // internal - call with gNotificationLock
5578 IOService::setNotification(
5579 const OSSymbol
* type
, OSDictionary
* matching
,
5580 IOServiceMatchingNotificationHandler handler
, void * target
, void * ref
,
5583 _IOServiceNotifier
* notify
= NULL
;
5590 notify
= new _IOServiceNotifier
;
5591 if (notify
&& !notify
->init()) {
5597 notify
->handler
= handler
;
5598 notify
->target
= target
;
5599 notify
->type
= type
;
5600 notify
->matching
= matching
;
5602 if (handler
== &_IOServiceMatchingNotificationHandler
) {
5603 notify
->compatHandler
= ((_IOServiceMatchingNotificationHandlerRef
*)ref
)->handler
;
5604 notify
->ref
= ((_IOServiceMatchingNotificationHandlerRef
*)ref
)->ref
;
5608 notify
->priority
= priority
;
5609 notify
->state
= kIOServiceNotifyEnable
;
5610 queue_init( ¬ify
->handlerInvocations
);
5614 if (NULL
== (set
= (OSOrderedSet
*) gNotifications
->getObject( type
))) {
5615 set
= OSOrderedSet::withCapacity( 1,
5616 IONotifyOrdering
, NULL
);
5618 gNotifications
->setObject( type
, set
);
5622 notify
->whence
= set
;
5624 set
->setObject( notify
);
5631 // internal - call with gNotificationLock
5633 IOService::doInstallNotification(
5634 const OSSymbol
* type
, OSDictionary
* matching
,
5635 IOServiceMatchingNotificationHandler handler
,
5636 void * target
, void * ref
,
5637 SInt32 priority
, OSIterator
** existing
)
5640 IONotifier
* notify
;
5641 IOOptionBits inState
;
5647 if (type
== gIOPublishNotification
) {
5648 inState
= kIOServiceRegisteredState
;
5649 } else if (type
== gIOFirstPublishNotification
) {
5650 inState
= kIOServiceFirstPublishState
;
5651 } else if (type
== gIOMatchedNotification
) {
5652 inState
= kIOServiceMatchedState
;
5653 } else if (type
== gIOFirstMatchNotification
) {
5654 inState
= kIOServiceFirstMatchState
;
5655 } else if ((type
== gIOTerminatedNotification
) || (type
== gIOWillTerminateNotification
)) {
5661 notify
= setNotification( type
, matching
, handler
, target
, ref
, priority
);
5664 // get the current set
5665 exist
= (OSIterator
*) copyExistingServices( matching
, inState
);
5675 #if !defined(__LP64__)
5677 IOService::installNotification(const OSSymbol
* type
, OSDictionary
* matching
,
5678 IOServiceNotificationHandler handler
,
5679 void * target
, void * refCon
,
5680 SInt32 priority
, OSIterator
** existing
)
5682 IONotifier
* result
;
5683 _IOServiceMatchingNotificationHandlerRef ref
;
5684 ref
.handler
= handler
;
5687 result
= (_IOServiceNotifier
*) installNotification( type
, matching
,
5688 &_IOServiceMatchingNotificationHandler
,
5689 target
, &ref
, priority
, existing
);
5691 matching
->release();
5697 #endif /* !defined(__LP64__) */
5701 IOService::installNotification(
5702 const OSSymbol
* type
, OSDictionary
* matching
,
5703 IOServiceMatchingNotificationHandler handler
,
5704 void * target
, void * ref
,
5705 SInt32 priority
, OSIterator
** existing
)
5707 IONotifier
* notify
;
5711 notify
= doInstallNotification( type
, matching
, handler
, target
, ref
,
5712 priority
, existing
);
5714 // in case handler remove()s
5725 IOService::addNotification(
5726 const OSSymbol
* type
, OSDictionary
* matching
,
5727 IOServiceNotificationHandler handler
,
5728 void * target
, void * refCon
,
5731 IONotifier
* result
;
5732 _IOServiceMatchingNotificationHandlerRef ref
;
5734 ref
.handler
= handler
;
5737 result
= addMatchingNotification(type
, matching
, &_IOServiceMatchingNotificationHandler
,
5738 target
, &ref
, priority
);
5741 matching
->release();
5748 IOService::addMatchingNotification(
5749 const OSSymbol
* type
, OSDictionary
* matching
,
5750 IOServiceMatchingNotificationHandler handler
,
5751 void * target
, void * ref
,
5754 OSIterator
* existing
= NULL
;
5756 _IOServiceNotifier
* notify
;
5759 ret
= notify
= (_IOServiceNotifier
*) installNotification( type
, matching
,
5760 handler
, target
, ref
, priority
, &existing
);
5765 // send notifications for existing set
5767 while ((next
= (IOService
*) existing
->getNextObject())) {
5768 if (0 == (next
->__state
[0] & kIOServiceInactiveState
)) {
5769 next
->invokeNotifier( notify
);
5772 existing
->release();
5776 bool removed
= (NULL
== notify
->whence
);
5779 ret
= gIOServiceNullNotifier
;
5787 IOServiceMatchingNotificationHandlerToBlock( void * target __unused
, void * refCon
,
5788 IOService
* newService
,
5789 IONotifier
* notifier
)
5791 return ((IOServiceMatchingNotificationHandlerBlock
) refCon
)(newService
, notifier
);
5795 IOService::addMatchingNotification(
5796 const OSSymbol
* type
, OSDictionary
* matching
,
5798 IOServiceMatchingNotificationHandlerBlock handler
)
5800 IONotifier
* notify
;
5803 block
= Block_copy(handler
);
5808 notify
= addMatchingNotification(type
, matching
,
5809 &IOServiceMatchingNotificationHandlerToBlock
, NULL
, block
, priority
);
5812 Block_release(block
);
5819 IOService::userServerCheckInTokenNotificationHandler(
5820 __unused IOUserServerCheckInToken
*token
,
5829 IOService::syncNotificationHandler(
5830 void * /* target */, void * ref
,
5831 IOService
* newService
,
5832 IONotifier
* notifier
)
5835 if (!*((IOService
**) ref
)) {
5836 newService
->retain();
5837 (*(IOService
**) ref
) = newService
;
5846 IOService::waitForMatchingServiceWithToken( OSDictionary
* matching
,
5848 IOUserServerCheckInToken
* checkInToken
)
5850 IONotifier
* notify
= NULL
;
5851 // priority doesn't help us much since we need a thread wakeup
5852 SInt32 priority
= 0;
5861 #if DEBUG || DEVELOPMENT
5862 char currentName
[MAXTHREADNAMESIZE
];
5863 char newName
[MAXTHREADNAMESIZE
];
5866 OSDictionary
* dict
;
5868 currentName
[0] = '\0';
5869 if (thread_has_thread_name(current_thread())) {
5871 obj
= matching
->getObject(gIOPropertyMatchKey
);
5872 if ((dict
= OSDynamicCast(OSDictionary
, obj
))) {
5873 OSObject
* result __block
= NULL
;
5874 dict
->iterateObjects(^bool (const OSSymbol
* sym
, OSObject
* value
) {
5875 result
= __DECONST(OSObject
*, sym
);
5881 obj
= matching
->getObject(gIOResourceMatchKey
);
5884 obj
= matching
->getObject(gIONameMatchKey
);
5887 obj
= matching
->getObject(gIOProviderClassKey
);
5889 if ((str
= OSDynamicCast(OSString
, obj
))) {
5890 thread_get_thread_name(current_thread(), currentName
);
5891 snprintf(newName
, sizeof(newName
), "Waiting_'%s'", str
->getCStringNoCopy());
5892 thread_set_thread_name(current_thread(), newName
);
5895 #endif /* DEBUG || DEVELOPMENT */
5900 checkInToken
->setNoSendersNotification(&IOService::userServerCheckInTokenNotificationHandler
,
5903 result
= (IOService
*) copyExistingServices( matching
,
5904 kIOServiceMatchedState
, kIONotifyOnce
);
5908 notify
= IOService::setNotification( gIOMatchedNotification
, matching
,
5909 &IOService::syncNotificationHandler
, (void *) NULL
,
5910 &result
, priority
);
5914 if (UINT64_MAX
!= timeout
) {
5915 AbsoluteTime deadline
;
5916 nanoseconds_to_absolutetime(timeout
, &deadline
);
5917 clock_absolutetime_interval_to_deadline(deadline
, &deadline
);
5918 SLEEPNOTIFYTO(&result
, deadline
);
5920 SLEEPNOTIFY(&result
);
5926 #if DEBUG || DEVELOPMENT
5927 if (currentName
[0]) {
5928 thread_set_thread_name(current_thread(), currentName
);
5930 #endif /* DEBUG || DEVELOPMENT */
5933 notify
->remove(); // dequeues
5937 checkInToken
->clearNotification();
5944 IOService::waitForMatchingService( OSDictionary
* matching
,
5947 return IOService::waitForMatchingServiceWithToken(matching
, timeout
, NULL
);
5951 IOService::waitForService( OSDictionary
* matching
,
5952 mach_timespec_t
* timeout
)
5958 timeoutNS
= timeout
->tv_sec
;
5959 timeoutNS
*= kSecondScale
;
5960 timeoutNS
+= timeout
->tv_nsec
;
5962 timeoutNS
= UINT64_MAX
;
5965 result
= waitForMatchingService(matching
, timeoutNS
);
5967 matching
->release();
5977 IOService::deliverNotification( const OSSymbol
* type
,
5978 IOOptionBits orNewState
, IOOptionBits andNewState
)
5980 panic("deliverNotification");
5984 IOService::copyNotifiers(const OSSymbol
* type
,
5985 IOOptionBits orNewState
, IOOptionBits andNewState
)
5987 _IOServiceNotifier
* notify
;
5989 OSArray
* willSend
= NULL
;
5991 lockForArbitration();
5993 if ((0 == (__state
[0] & kIOServiceInactiveState
))
5994 || (type
== gIOTerminatedNotification
)
5995 || (type
== gIOWillTerminateNotification
)) {
5998 iter
= OSCollectionIterator::withCollection((OSOrderedSet
*)
5999 gNotifications
->getObject( type
));
6002 while ((notify
= (_IOServiceNotifier
*) iter
->getNextObject())) {
6003 if (matchPassive(notify
->matching
, 0)
6004 && (kIOServiceNotifyEnable
& notify
->state
)) {
6005 if (NULL
== willSend
) {
6006 willSend
= OSArray::withCapacity(8);
6009 willSend
->setObject( notify
);
6015 __state
[0] = (__state
[0] | orNewState
) & andNewState
;
6019 unlockForArbitration();
6025 IOService::getState( void ) const
6031 * Helpers to make matching objects for simple cases
6035 IOService::serviceMatching( const OSString
* name
,
6036 OSDictionary
* table
)
6038 const OSString
* str
;
6040 str
= OSSymbol::withString(name
);
6046 table
= OSDictionary::withCapacity( 2 );
6049 table
->setObject(gIOProviderClassKey
, (OSObject
*)str
);
6057 IOService::serviceMatching( const char * name
,
6058 OSDictionary
* table
)
6060 const OSString
* str
;
6062 str
= OSSymbol::withCString( name
);
6067 table
= serviceMatching( str
, table
);
6073 IOService::nameMatching( const OSString
* name
,
6074 OSDictionary
* table
)
6077 table
= OSDictionary::withCapacity( 2 );
6080 table
->setObject( gIONameMatchKey
, (OSObject
*)name
);
6087 IOService::nameMatching( const char * name
,
6088 OSDictionary
* table
)
6090 const OSString
* str
;
6092 str
= OSSymbol::withCString( name
);
6097 table
= nameMatching( str
, table
);
6103 IOService::resourceMatching( const OSString
* str
,
6104 OSDictionary
* table
)
6106 table
= serviceMatching( gIOResourcesKey
, table
);
6108 table
->setObject( gIOResourceMatchKey
, (OSObject
*) str
);
6115 IOService::resourceMatching( const char * name
,
6116 OSDictionary
* table
)
6118 const OSSymbol
* str
;
6120 str
= OSSymbol::withCString( name
);
6125 table
= resourceMatching( str
, table
);
6132 IOService::propertyMatching( const OSSymbol
* key
, const OSObject
* value
,
6133 OSDictionary
* table
)
6135 OSDictionary
* properties
;
6137 properties
= OSDictionary::withCapacity( 2 );
6141 properties
->setObject( key
, value
);
6144 table
= OSDictionary::withCapacity( 2 );
6147 table
->setObject( gIOPropertyMatchKey
, properties
);
6150 properties
->release();
6156 IOService::registryEntryIDMatching( uint64_t entryID
,
6157 OSDictionary
* table
)
6161 num
= OSNumber::withNumber( entryID
, 64 );
6167 table
= OSDictionary::withCapacity( 2 );
6170 table
->setObject( gIORegistryEntryIDKey
, num
);
6182 * _IOServiceNotifier
6185 // wait for all threads, other than the current one,
6186 // to exit the handler
6189 _IOServiceNotifier::wait()
6191 _IOServiceNotifierInvocation
* next
;
6196 queue_iterate( &handlerInvocations
, next
,
6197 _IOServiceNotifierInvocation
*, link
) {
6198 if (next
->thread
!= current_thread()) {
6204 state
|= kIOServiceNotifyWaiter
;
6211 _IOServiceNotifier::free()
6213 assert( queue_empty( &handlerInvocations
));
6215 if (handler
== &IOServiceMatchingNotificationHandlerToBlock
) {
6223 _IOServiceNotifier::remove()
6228 whence
->removeObject((OSObject
*) this );
6232 matching
->release();
6236 state
&= ~kIOServiceNotifyEnable
;
6246 _IOServiceNotifier::disable()
6252 ret
= (0 != (kIOServiceNotifyEnable
& state
));
6253 state
&= ~kIOServiceNotifyEnable
;
6264 _IOServiceNotifier::enable( bool was
)
6268 state
|= kIOServiceNotifyEnable
;
6270 state
&= ~kIOServiceNotifyEnable
;
6277 * _IOServiceNullNotifier
6281 _IOServiceNullNotifier::taggedRetain(const void *tag
) const
6285 _IOServiceNullNotifier::taggedRelease(const void *tag
, const int when
) const
6289 _IOServiceNullNotifier::free()
6293 _IOServiceNullNotifier::wait()
6297 _IOServiceNullNotifier::remove()
6301 _IOServiceNullNotifier::enable(bool was
)
6305 _IOServiceNullNotifier::disable()
6315 IOResources::resources( void )
6319 inst
= new IOResources
;
6320 if (inst
&& !inst
->init()) {
6329 IOResources::init( OSDictionary
* dictionary
)
6331 // Do super init first
6332 if (!IOService::init()) {
6336 // Allow PAL layer to publish a value
6337 const char *property_name
;
6340 pal_get_resource_property( &property_name
, &property_value
);
6342 if (property_name
) {
6344 const OSSymbol
* sym
;
6346 if ((num
= OSNumber::withNumber(property_value
, 32)) != NULL
) {
6347 if ((sym
= OSSymbol::withCString( property_name
)) != NULL
) {
6348 this->setProperty( sym
, num
);
6359 IOResources::newUserClient(task_t owningTask
, void * securityID
,
6360 UInt32 type
, OSDictionary
* properties
,
6361 IOUserClient
** handler
)
6363 return kIOReturnUnsupported
;
6367 IOResources::getWorkLoop() const
6369 // If we are the resource root
6370 // then use the platform's workloop
6371 if (this == (IOResources
*) gIOResources
) {
6372 return getPlatform()->getWorkLoop();
6374 return IOService::getWorkLoop();
6379 IOResourcesMatchPropertyTable(IOService
* resources
, OSDictionary
* table
)
6389 prop
= table
->getObject( gIOResourceMatchKey
);
6390 str
= OSDynamicCast( OSString
, prop
);
6392 ok
= (NULL
!= resources
->getProperty( str
));
6393 } else if ((set
= OSDynamicCast( OSSet
, prop
))) {
6394 iter
= OSCollectionIterator::withCollection( set
);
6395 ok
= (iter
!= NULL
);
6396 while (ok
&& (str
= OSDynamicCast( OSString
, iter
->getNextObject()))) {
6397 ok
= (NULL
!= resources
->getProperty( str
));
6403 } else if ((prop
= table
->getObject(gIOResourceMatchedKey
))) {
6404 obj
= resources
->copyProperty(gIOResourceMatchedKey
);
6405 keys
= OSDynamicCast(OSArray
, obj
);
6408 // assuming OSSymbol
6409 ok
= ((-1U) != keys
->getNextIndexOfObject(prop
, 0));
6411 OSSafeReleaseNULL(obj
);
6418 IOResources::matchPropertyTable( OSDictionary
* table
)
6420 return IOResourcesMatchPropertyTable(this, table
);
6428 IOUserResources::resources( void )
6430 IOUserResources
* inst
;
6432 inst
= OSTypeAlloc(IOUserResources
);
6433 if (inst
&& !inst
->init()) {
6442 IOUserResources::init( OSDictionary
* dictionary
)
6444 // Do super init first
6445 if (!IOService::init()) {
6452 IOUserResources::newUserClient(task_t owningTask
, void * securityID
,
6453 UInt32 type
, OSDictionary
* properties
,
6454 IOUserClient
** handler
)
6456 return kIOReturnUnsupported
;
6460 IOUserResources::getWorkLoop() const
6462 return getPlatform()->getWorkLoop();
6466 IOUserResources::matchPropertyTable( OSDictionary
* table
)
6468 return IOResourcesMatchPropertyTable(this, table
);
6474 IOService::consoleLockTimer(thread_call_param_t p0
, thread_call_param_t p1
)
6476 IOService::updateConsoleUsers(NULL
, 0);
6480 IOService::updateConsoleUsers(OSArray
* consoleUsers
, IOMessage systemMessage
, bool afterUserspaceReboot
)
6482 IORegistryEntry
* regEntry
;
6483 OSObject
* locked
= kOSBooleanFalse
;
6486 OSDictionary
* user
;
6487 clock_sec_t now
= 0;
6488 clock_usec_t microsecs
;
6490 regEntry
= IORegistryEntry::getRegistryRoot();
6492 if (!gIOChosenEntry
) {
6493 gIOChosenEntry
= IORegistryEntry::fromPath("/chosen", gIODTPlane
);
6496 IOLockLock(gIOConsoleUsersLock
);
6498 if (systemMessage
) {
6499 sSystemPower
= systemMessage
;
6501 if (kIOMessageSystemHasPoweredOn
== systemMessage
) {
6502 uint32_t lockState
= IOHibernateWasScreenLocked();
6503 switch (lockState
) {
6506 case kIOScreenLockLocked
:
6507 case kIOScreenLockFileVaultDialog
:
6508 gIOConsoleBooterLockState
= kOSBooleanTrue
;
6510 case kIOScreenLockNoLock
:
6511 gIOConsoleBooterLockState
= NULL
;
6513 case kIOScreenLockUnlocked
:
6515 gIOConsoleBooterLockState
= kOSBooleanFalse
;
6519 #endif /* HIBERNATION */
6523 OSNumber
* num
= NULL
;
6524 bool loginLocked
= true;
6526 gIOConsoleLoggedIn
= false;
6528 (user
= OSDynamicCast(OSDictionary
, consoleUsers
->getObject(idx
)));
6530 gIOConsoleLoggedIn
|= ((kOSBooleanTrue
== user
->getObject(gIOConsoleSessionOnConsoleKey
))
6531 && (kOSBooleanTrue
== user
->getObject(gIOConsoleSessionLoginDoneKey
)));
6533 loginLocked
&= (kOSBooleanTrue
== user
->getObject(gIOConsoleSessionScreenIsLockedKey
));
6535 num
= OSDynamicCast(OSNumber
, user
->getObject(gIOConsoleSessionScreenLockedTimeKey
));
6539 if (!loginLocked
|| afterUserspaceReboot
) {
6540 gIOConsoleBooterLockState
= NULL
;
6542 IOLog("IOConsoleUsers: time(%d) %ld->%d, lin %d, llk %d, \n",
6543 (num
!= NULL
), gIOConsoleLockTime
, (num
? num
->unsigned32BitValue() : 0),
6544 gIOConsoleLoggedIn
, loginLocked
);
6545 #endif /* HIBERNATION */
6546 gIOConsoleLockTime
= num
? num
->unsigned32BitValue() : 0;
6549 if (!gIOConsoleLoggedIn
6550 || (kIOMessageSystemWillSleep
== sSystemPower
)
6551 || (kIOMessageSystemPagingOff
== sSystemPower
)) {
6552 if (afterUserspaceReboot
) {
6553 // set "locked" to false after a user space reboot
6554 // because the reboot happens directly after a user
6555 // logs into the machine via fvunlock mode.
6556 locked
= kOSBooleanFalse
;
6558 locked
= kOSBooleanTrue
;
6562 else if (gIOConsoleBooterLockState
) {
6563 locked
= gIOConsoleBooterLockState
;
6565 #endif /* HIBERNATION */
6566 else if (gIOConsoleLockTime
) {
6567 clock_get_calendar_microtime(&now
, µsecs
);
6568 if (gIOConsoleLockTime
> now
) {
6569 AbsoluteTime deadline
;
6570 clock_sec_t interval
;
6571 uint32_t interval32
;
6573 interval
= (gIOConsoleLockTime
- now
);
6574 interval32
= (uint32_t) interval
;
6575 if (interval32
!= interval
) {
6576 interval32
= UINT_MAX
;
6578 clock_interval_to_deadline(interval32
, kSecondScale
, &deadline
);
6579 thread_call_enter_delayed(gIOConsoleLockCallout
, deadline
);
6581 locked
= kOSBooleanTrue
;
6585 publish
= (consoleUsers
|| (locked
!= regEntry
->getProperty(gIOConsoleLockedKey
)));
6587 regEntry
->setProperty(gIOConsoleLockedKey
, locked
);
6589 regEntry
->setProperty(gIOConsoleUsersKey
, consoleUsers
);
6591 OSIncrementAtomic( &gIOConsoleUsersSeed
);
6595 if (gIOChosenEntry
) {
6596 if (locked
== kOSBooleanTrue
) {
6597 gIOScreenLockState
= kIOScreenLockLocked
;
6598 } else if (gIOConsoleLockTime
) {
6599 gIOScreenLockState
= kIOScreenLockUnlocked
;
6601 gIOScreenLockState
= kIOScreenLockNoLock
;
6603 gIOChosenEntry
->setProperty(kIOScreenLockStateKey
, &gIOScreenLockState
, sizeof(gIOScreenLockState
));
6605 IOLog("IOConsoleUsers: gIOScreenLockState %d, hs %d, bs %d, now %ld, sm 0x%x\n",
6606 gIOScreenLockState
, gIOHibernateState
, (gIOConsoleBooterLockState
!= NULL
), now
, systemMessage
);
6608 #endif /* HIBERNATION */
6610 IOLockUnlock(gIOConsoleUsersLock
);
6613 publishResource( gIOConsoleUsersSeedKey
, gIOConsoleUsersSeedValue
);
6615 MessageClientsContext context
;
6617 context
.service
= getServiceRoot();
6618 context
.type
= kIOMessageConsoleSecurityChange
;
6619 context
.argument
= (void *) regEntry
;
6620 context
.argSize
= 0;
6622 applyToInterestNotifiers(getServiceRoot(), gIOConsoleSecurityInterest
,
6623 &messageClientsApplier
, &context
);
6628 IOResources::setProperties( OSObject
* properties
)
6631 const OSSymbol
* key
;
6632 OSDictionary
* dict
;
6633 OSCollectionIterator
* iter
;
6635 if (!IOTaskHasEntitlement(current_task(), kIOResourcesSetPropertyKey
)) {
6636 err
= IOUserClient::clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator
);
6637 if (kIOReturnSuccess
!= err
) {
6642 dict
= OSDynamicCast(OSDictionary
, properties
);
6644 return kIOReturnBadArgument
;
6647 iter
= OSCollectionIterator::withCollection( dict
);
6649 return kIOReturnBadArgument
;
6652 while ((key
= OSDynamicCast(OSSymbol
, iter
->getNextObject()))) {
6653 if (gIOConsoleUsersKey
== key
) {
6655 OSArray
* consoleUsers
;
6656 consoleUsers
= OSDynamicCast(OSArray
, dict
->getObject(key
));
6657 if (!consoleUsers
) {
6660 IOService::updateConsoleUsers(consoleUsers
, 0);
6664 publishResource( key
, dict
->getObject(key
));
6669 return kIOReturnSuccess
;
6673 * Helpers for matching dictionaries.
6674 * Keys existing in matching are checked in properties.
6675 * Keys may be a string or OSCollection of IOStrings
6679 IOService::compareProperty( OSDictionary
* matching
,
6686 value
= matching
->getObject( key
);
6688 prop
= copyProperty(key
);
6689 ok
= value
->isEqualTo(prop
);
6702 IOService::compareProperty( OSDictionary
* matching
,
6703 const OSString
* key
)
6709 value
= matching
->getObject( key
);
6711 prop
= copyProperty(key
);
6712 ok
= value
->isEqualTo(prop
);
6723 #ifndef __clang_analyzer__
6724 // Implementation of this function is hidden from the static analyzer.
6725 // The analyzer was worried about this function's confusing contract over
6726 // the 'keys' parameter. The contract is to either release it or not release it
6727 // depending on whether 'matching' is non-null. Such contracts are discouraged
6728 // but changing it now would break compatibility.
6730 IOService::compareProperties( OSDictionary
* matching
,
6731 OSCollection
* keys
)
6733 OSCollectionIterator
* iter
;
6734 const OSString
* key
;
6737 if (!matching
|| !keys
) {
6741 iter
= OSCollectionIterator::withCollection( keys
);
6744 while (ok
&& (key
= OSDynamicCast( OSString
, iter
->getNextObject()))) {
6745 ok
= compareProperty( matching
, key
);
6750 keys
->release(); // !! consume a ref !!
6754 #endif // __clang_analyzer__
6756 /* Helper to add a location matching dict to the table */
6759 IOService::addLocation( OSDictionary
* table
)
6761 OSDictionary
* dict
;
6767 dict
= OSDictionary::withCapacity( 1 );
6769 bool ok
= table
->setObject( gIOLocationMatchKey
, dict
);
6780 * Go looking for a provider to match a location dict.
6784 IOService::matchLocation( IOService
* /* client */ )
6788 parent
= getProvider();
6791 parent
= parent
->matchLocation( this );
6798 IOService::matchInternal(OSDictionary
* table
, uint32_t options
, uint32_t * did
)
6803 OSDictionary
* matchProps
;
6804 IORegistryEntry
* entry
;
6807 bool changesOK
= (0 != (kIOServiceChangesOK
& options
));
6812 count
= table
->getCount();
6816 if (table
->getObject(gIOCompatibilityMatchKey
)) {
6818 obj
= copyProperty(gIOCompatibilityPropertiesKey
);
6819 matchProps
= OSDynamicCast(OSDictionary
, obj
);
6821 OSSafeReleaseNULL(obj
);
6825 str
= OSDynamicCast(OSString
, table
->getObject(gIOProviderClassKey
));
6828 if (matchProps
&& (obj
= matchProps
->getObject(gIOClassKey
))) {
6829 match
= str
->isEqualTo(obj
);
6831 match
= ((kIOServiceClassDone
& options
) || (NULL
!= metaCast(str
)));
6835 match
= (0 != metaCast( str
));
6836 if ((kIOServiceClassDone
& options
) && !match
) {
6840 if ((!match
) || (done
== count
)) {
6845 obj
= table
->getObject( gIONameMatchKey
);
6848 match
= compareNames( obj
, changesOK
? &matched
: NULL
);
6852 if (changesOK
&& matched
) {
6853 // leave a hint as to which name matched
6854 table
->setObject( gIONameMatchedKey
, matched
);
6857 if (done
== count
) {
6862 str
= OSDynamicCast( OSString
, table
->getObject( gIOLocationMatchKey
));
6864 const OSSymbol
* sym
;
6867 sym
= copyLocation();
6869 match
= sym
->isEqualTo( str
);
6872 if ((!match
) || (done
== count
)) {
6877 obj
= table
->getObject( gIOPropertyMatchKey
);
6879 OSDictionary
* nextDict
;
6884 matchProps
= dictionaryWithProperties();
6887 nextDict
= OSDynamicCast( OSDictionary
, obj
);
6891 iter
= OSCollectionIterator::withCollection(
6892 OSDynamicCast(OSCollection
, obj
));
6896 || (iter
&& (NULL
!= (nextDict
= OSDynamicCast(OSDictionary
,
6897 iter
->getNextObject()))))) {
6898 match
= matchProps
->isEqualTo( nextDict
, nextDict
);
6908 if ((!match
) || (done
== count
)) {
6913 obj
= table
->getObject( gIOPropertyExistsMatchKey
);
6920 matchProps
= dictionaryWithProperties();
6923 nextKey
= OSDynamicCast( OSString
, obj
);
6927 iter
= OSCollectionIterator::withCollection(
6928 OSDynamicCast(OSCollection
, obj
));
6932 || (iter
&& (NULL
!= (nextKey
= OSDynamicCast(OSString
,
6933 iter
->getNextObject()))))) {
6934 match
= (NULL
!= matchProps
->getObject(nextKey
));
6944 if ((!match
) || (done
== count
)) {
6949 str
= OSDynamicCast( OSString
, table
->getObject( gIOPathMatchKey
));
6952 entry
= IORegistryEntry::fromPath( str
->getCStringNoCopy());
6953 match
= (this == entry
);
6957 if (!match
&& matchProps
&& (obj
= matchProps
->getObject(gIOPathKey
))) {
6958 match
= str
->isEqualTo(obj
);
6960 if ((!match
) || (done
== count
)) {
6965 num
= OSDynamicCast( OSNumber
, table
->getObject( gIORegistryEntryIDKey
));
6968 match
= (getRegistryEntryID() == num
->unsigned64BitValue());
6969 if ((!match
) || (done
== count
)) {
6974 num
= OSDynamicCast( OSNumber
, table
->getObject( gIOMatchedServiceCountKey
));
6977 IOService
* service
= NULL
;
6978 UInt32 serviceCount
= 0;
6981 iter
= getClientIterator();
6983 while ((service
= (IOService
*) iter
->getNextObject())) {
6984 if (kIOServiceInactiveState
& service
->__state
[0]) {
6987 if (NULL
== service
->getProperty( gIOMatchCategoryKey
)) {
6994 match
= (serviceCount
== num
->unsigned32BitValue());
6995 if ((!match
) || (done
== count
)) {
7000 #define propMatch(key) \
7001 obj = table->getObject(key); \
7006 prop = copyProperty(key); \
7007 match = obj->isEqualTo(prop); \
7008 if (prop) prop->release(); \
7009 if ((!match) || (done == count)) break; \
7011 propMatch(gIOBSDNameKey
)
7012 propMatch(gIOBSDMajorKey
)
7013 propMatch(gIOBSDMinorKey
)
7014 propMatch(gIOBSDUnitKey
)
7018 OSSafeReleaseNULL(matchProps
);
7027 IOService::passiveMatch( OSDictionary
* table
, bool changesOK
)
7029 return matchPassive(table
, changesOK
? kIOServiceChangesOK
: 0);
7033 IOService::matchPassive(OSDictionary
* table
, uint32_t options
)
7036 OSDictionary
* nextTable
;
7040 bool matchParent
= false;
7046 #if defined(XNU_TARGET_OS_OSX)
7047 OSArray
* aliasServiceRegIds
= NULL
;
7048 IOService
* foundAlternateService
= NULL
;
7049 #endif /* defined(XNU_TARGET_OS_OSX) */
7052 OSDictionary
* root
= table
;
7058 count
= table
->getCount();
7059 if (!(kIOServiceInternalDone
& options
)) {
7060 match
= where
->matchInternal(table
, options
, &done
);
7061 // don't call family if we've done all the entries in the table
7062 if ((!match
) || (done
== count
)) {
7067 // pass in score from property table
7068 score
= IOServiceObjectOrder( table
, (void *) gIOProbeScoreKey
);
7070 // do family specific matching
7071 match
= where
->matchPropertyTable( table
, &score
);
7075 if (kIOLogMatch
& getDebugFlags( table
)) {
7076 LOG("%s: family specific matching fails\n", where
->getName());
7082 if (kIOServiceChangesOK
& options
) {
7084 newPri
= OSNumber::withNumber( score
, 32 );
7086 table
->setObject( gIOProbeScoreKey
, newPri
);
7092 matchParent
= false;
7094 nextTable
= OSDynamicCast(OSDictionary
,
7095 table
->getObject( gIOParentMatchKey
));
7097 // look for a matching entry anywhere up to root
7104 table
= OSDynamicCast(OSDictionary
,
7105 table
->getObject( gIOLocationMatchKey
));
7107 // look for a matching entry at matchLocation()
7109 where
= where
->getProvider();
7110 if (where
&& (where
= where
->matchLocation(where
))) {
7117 if (match
== true) {
7121 if (matchParent
== true) {
7122 #if defined(XNU_TARGET_OS_OSX)
7123 // check if service has an alias to search its other "parents" if a parent match isn't found
7124 OSObject
* prop
= where
->copyProperty(gIOServiceLegacyMatchingRegistryIDKey
);
7125 OSNumber
* alternateRegistryID
= OSDynamicCast(OSNumber
, prop
);
7126 if (alternateRegistryID
!= NULL
) {
7127 if (aliasServiceRegIds
== NULL
) {
7128 aliasServiceRegIds
= OSArray::withCapacity(sizeof(alternateRegistryID
));
7130 aliasServiceRegIds
->setObject(alternateRegistryID
);
7132 OSSafeReleaseNULL(prop
);
7133 #endif /* defined(XNU_TARGET_OS_OSX) */
7138 where
= where
->getProvider();
7139 #if defined(XNU_TARGET_OS_OSX)
7140 if (where
== NULL
) {
7141 // there were no matching parent services, check to see if there are aliased services that have a matching parent
7142 if (aliasServiceRegIds
!= NULL
) {
7143 unsigned int numAliasedServices
= aliasServiceRegIds
->getCount();
7144 if (numAliasedServices
!= 0) {
7145 OSNumber
* alternateRegistryID
= OSDynamicCast(OSNumber
, aliasServiceRegIds
->getObject(numAliasedServices
- 1));
7146 if (alternateRegistryID
!= NULL
) {
7147 OSDictionary
* alternateMatchingDict
= IOService::registryEntryIDMatching(alternateRegistryID
->unsigned64BitValue());
7148 aliasServiceRegIds
->removeObject(numAliasedServices
- 1);
7149 if (alternateMatchingDict
!= NULL
) {
7150 OSSafeReleaseNULL(foundAlternateService
);
7151 foundAlternateService
= IOService::copyMatchingService(alternateMatchingDict
);
7152 alternateMatchingDict
->release();
7153 if (foundAlternateService
!= NULL
) {
7154 where
= foundAlternateService
;
7161 #endif /* defined(XNU_TARGET_OS_OSX) */
7162 }while (where
!= NULL
);
7164 #if defined(XNU_TARGET_OS_OSX)
7165 OSSafeReleaseNULL(foundAlternateService
);
7166 OSSafeReleaseNULL(aliasServiceRegIds
);
7167 #endif /* defined(XNU_TARGET_OS_OSX) */
7170 if (where
!= this) {
7171 OSSerialize
* s
= OSSerialize::withCapacity(128);
7173 kprintf("parent match 0x%llx, %d,\n%s\n", getRegistryEntryID(), match
, s
->text());
7183 IOService::newUserClient( task_t owningTask
, void * securityID
,
7184 UInt32 type
, OSDictionary
* properties
,
7185 IOUserClient
** handler
)
7187 const OSSymbol
*userClientClass
= NULL
;
7188 IOUserClient
*client
;
7192 if (reserved
&& reserved
->uvars
&& reserved
->uvars
->userServer
) {
7193 return reserved
->uvars
->userServer
->serviceNewUserClient(this, owningTask
, securityID
, type
, properties
, handler
);
7196 if (kIOReturnSuccess
== newUserClient( owningTask
, securityID
, type
, handler
)) {
7197 return kIOReturnSuccess
;
7200 // First try my own properties for a user client class name
7201 prop
= copyProperty(gIOUserClientClassKey
);
7203 if (OSDynamicCast(OSSymbol
, prop
)) {
7204 userClientClass
= (const OSSymbol
*) prop
;
7205 } else if (OSDynamicCast(OSString
, prop
)) {
7206 userClientClass
= OSSymbol::withString((OSString
*) prop
);
7207 if (userClientClass
) {
7208 setProperty(gIOUserClientClassKey
,
7209 (OSObject
*) userClientClass
);
7214 // Didn't find one so lets just bomb out now without further ado.
7215 if (!userClientClass
) {
7216 OSSafeReleaseNULL(prop
);
7217 return kIOReturnUnsupported
;
7220 // This reference is consumed by the IOServiceOpen call
7221 temp
= OSMetaClass::allocClassWithName(userClientClass
);
7222 OSSafeReleaseNULL(prop
);
7224 return kIOReturnNoMemory
;
7227 if (OSDynamicCast(IOUserClient
, temp
)) {
7228 client
= (IOUserClient
*) temp
;
7231 return kIOReturnUnsupported
;
7234 if (!client
->initWithTask(owningTask
, securityID
, type
, properties
)) {
7236 return kIOReturnBadArgument
;
7239 if (!client
->attach(this)) {
7241 return kIOReturnUnsupported
;
7244 if (!client
->start(this)) {
7245 client
->detach(this);
7247 return kIOReturnUnsupported
;
7251 return kIOReturnSuccess
;
7255 IOService::newUserClient( task_t owningTask
, void * securityID
,
7256 UInt32 type
, OSDictionary
* properties
,
7257 OSSharedPtr
<IOUserClient
>& handler
)
7259 IOUserClient
* handlerRaw
= NULL
;
7260 IOReturn result
= newUserClient(owningTask
, securityID
, type
, properties
, &handlerRaw
);
7261 handler
.reset(handlerRaw
, OSNoRetain
);
7266 IOService::newUserClient( task_t owningTask
, void * securityID
,
7267 UInt32 type
, IOUserClient
** handler
)
7269 return kIOReturnUnsupported
;
7273 IOService::newUserClient( task_t owningTask
, void * securityID
,
7274 UInt32 type
, OSSharedPtr
<IOUserClient
>& handler
)
7276 IOUserClient
* handlerRaw
= nullptr;
7277 IOReturn result
= IOService::newUserClient(owningTask
, securityID
, type
, &handlerRaw
);
7278 handler
.reset(handlerRaw
, OSNoRetain
);
7284 IOService::requestProbe( IOOptionBits options
)
7286 return kIOReturnUnsupported
;
7290 IOService::hasUserServer() const
7292 return reserved
&& reserved
->uvars
&& reserved
->uvars
->userServer
;
7296 * Convert an IOReturn to text. Subclasses which add additional
7297 * IOReturn's should override this method and call
7298 * super::stringFromReturn if the desired value is not found.
7302 IOService::stringFromReturn( IOReturn rtn
)
7304 static const IONamedValue IOReturn_values
[] = {
7305 {kIOReturnSuccess
, "success" },
7306 {kIOReturnError
, "general error" },
7307 {kIOReturnNoMemory
, "memory allocation error" },
7308 {kIOReturnNoResources
, "resource shortage" },
7309 {kIOReturnIPCError
, "Mach IPC failure" },
7310 {kIOReturnNoDevice
, "no such device" },
7311 {kIOReturnNotPrivileged
, "privilege violation" },
7312 {kIOReturnBadArgument
, "invalid argument" },
7313 {kIOReturnLockedRead
, "device is read locked" },
7314 {kIOReturnLockedWrite
, "device is write locked" },
7315 {kIOReturnExclusiveAccess
, "device is exclusive access" },
7316 {kIOReturnBadMessageID
, "bad IPC message ID" },
7317 {kIOReturnUnsupported
, "unsupported function" },
7318 {kIOReturnVMError
, "virtual memory error" },
7319 {kIOReturnInternalError
, "internal driver error" },
7320 {kIOReturnIOError
, "I/O error" },
7321 {kIOReturnCannotLock
, "cannot acquire lock" },
7322 {kIOReturnNotOpen
, "device is not open" },
7323 {kIOReturnNotReadable
, "device is not readable" },
7324 {kIOReturnNotWritable
, "device is not writeable" },
7325 {kIOReturnNotAligned
, "alignment error" },
7326 {kIOReturnBadMedia
, "media error" },
7327 {kIOReturnStillOpen
, "device is still open" },
7328 {kIOReturnRLDError
, "rld failure" },
7329 {kIOReturnDMAError
, "DMA failure" },
7330 {kIOReturnBusy
, "device is busy" },
7331 {kIOReturnTimeout
, "I/O timeout" },
7332 {kIOReturnOffline
, "device is offline" },
7333 {kIOReturnNotReady
, "device is not ready" },
7334 {kIOReturnNotAttached
, "device/channel is not attached" },
7335 {kIOReturnNoChannels
, "no DMA channels available" },
7336 {kIOReturnNoSpace
, "no space for data" },
7337 {kIOReturnPortExists
, "device port already exists" },
7338 {kIOReturnCannotWire
, "cannot wire physical memory" },
7339 {kIOReturnNoInterrupt
, "no interrupt attached" },
7340 {kIOReturnNoFrames
, "no DMA frames enqueued" },
7341 {kIOReturnMessageTooLarge
, "message is too large" },
7342 {kIOReturnNotPermitted
, "operation is not permitted" },
7343 {kIOReturnNoPower
, "device is without power" },
7344 {kIOReturnNoMedia
, "media is not present" },
7345 {kIOReturnUnformattedMedia
, "media is not formatted" },
7346 {kIOReturnUnsupportedMode
, "unsupported mode" },
7347 {kIOReturnUnderrun
, "data underrun" },
7348 {kIOReturnOverrun
, "data overrun" },
7349 {kIOReturnDeviceError
, "device error" },
7350 {kIOReturnNoCompletion
, "no completion routine" },
7351 {kIOReturnAborted
, "operation was aborted" },
7352 {kIOReturnNoBandwidth
, "bus bandwidth would be exceeded" },
7353 {kIOReturnNotResponding
, "device is not responding" },
7354 {kIOReturnInvalid
, "unanticipated driver error" },
7358 return IOFindNameForValue(rtn
, IOReturn_values
);
7362 * Convert an IOReturn to an errno.
7365 IOService::errnoFromReturn( IOReturn rtn
)
7367 if (unix_err(err_get_code(rtn
)) == rtn
) {
7368 return err_get_code(rtn
);
7373 case kIOReturnSuccess
:
7375 case kIOReturnNoMemory
:
7377 case kIOReturnNoDevice
:
7379 case kIOReturnVMError
:
7381 case kIOReturnNotPermitted
:
7383 case kIOReturnNotPrivileged
:
7385 case kIOReturnIOError
:
7387 case kIOReturnNotWritable
:
7389 case kIOReturnBadArgument
:
7391 case kIOReturnUnsupported
:
7395 case kIOReturnNoPower
:
7397 case kIOReturnDeviceError
:
7399 case kIOReturnTimeout
:
7401 case kIOReturnMessageTooLarge
:
7403 case kIOReturnNoSpace
:
7405 case kIOReturnCannotLock
:
7409 case kIOReturnBadMessageID
:
7410 case kIOReturnNoCompletion
:
7411 case kIOReturnNotAligned
:
7413 case kIOReturnNotReady
:
7415 case kIOReturnRLDError
:
7417 case kIOReturnPortExists
:
7418 case kIOReturnStillOpen
:
7420 case kIOReturnExclusiveAccess
:
7421 case kIOReturnLockedRead
:
7422 case kIOReturnLockedWrite
:
7423 case kIOReturnNotOpen
:
7424 case kIOReturnNotReadable
:
7426 case kIOReturnCannotWire
:
7427 case kIOReturnNoResources
:
7429 case kIOReturnAborted
:
7430 case kIOReturnOffline
:
7431 case kIOReturnNotResponding
:
7433 case kIOReturnBadMedia
:
7434 case kIOReturnNoMedia
:
7435 case kIOReturnNotAttached
:
7436 case kIOReturnUnformattedMedia
:
7437 return ENXIO
; // (media error)
7438 case kIOReturnDMAError
:
7439 case kIOReturnOverrun
:
7440 case kIOReturnUnderrun
:
7441 return EIO
; // (transfer error)
7442 case kIOReturnNoBandwidth
:
7443 case kIOReturnNoChannels
:
7444 case kIOReturnNoFrames
:
7445 case kIOReturnNoInterrupt
:
7446 return EIO
; // (hardware error)
7447 case kIOReturnError
:
7448 case kIOReturnInternalError
:
7449 case kIOReturnInvalid
:
7450 return EIO
; // (generic error)
7451 case kIOReturnIPCError
:
7452 return EIO
; // (ipc error)
7454 return EIO
; // (all other errors)
7459 IOService::message( UInt32 type
, IOService
* provider
,
7463 * Generic entry point for calls from the provider. A return value of
7464 * kIOReturnSuccess indicates that the message was received, and where
7465 * applicable, that it was successful.
7468 return kIOReturnUnsupported
;
7476 IOService::getDeviceMemoryCount( void )
7481 array
= OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
));
7483 count
= array
->getCount();
7492 IOService::getDeviceMemoryWithIndex( unsigned int index
)
7495 IODeviceMemory
* range
;
7497 array
= OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
));
7499 range
= (IODeviceMemory
*) array
->getObject( index
);
7508 IOService::mapDeviceMemoryWithIndex( unsigned int index
,
7509 IOOptionBits options
)
7511 IODeviceMemory
* range
;
7514 range
= getDeviceMemoryWithIndex( index
);
7516 map
= range
->map( options
);
7525 IOService::getDeviceMemory( void )
7527 return OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
));
7532 IOService::setDeviceMemory( OSArray
* array
)
7534 setProperty( gIODeviceMemoryKey
, array
);
7538 requireMaxCpuDelay(IOService
* service
, UInt32 ns
, UInt32 delayType
)
7540 static const UInt kNoReplace
= -1U; // Must be an illegal index
7541 UInt replace
= kNoReplace
;
7542 bool setCpuDelay
= false;
7544 IORecursiveLockLock(sCpuDelayLock
);
7546 UInt count
= sCpuDelayData
->getLength() / sizeof(CpuDelayEntry
);
7547 CpuDelayEntry
*entries
= (CpuDelayEntry
*) sCpuDelayData
->getBytesNoCopy();
7548 IOService
* holder
= NULL
;
7551 const CpuDelayEntry ne
= {service
, ns
, delayType
};
7553 // Set maximum delay.
7554 for (UInt i
= 0; i
< count
; i
++) {
7555 IOService
*thisService
= entries
[i
].fService
;
7556 bool sameType
= (delayType
== entries
[i
].fDelayType
);
7557 if ((service
== thisService
) && sameType
) {
7559 } else if (!thisService
) {
7560 if (kNoReplace
== replace
) {
7563 } else if (sameType
) {
7564 const UInt32 thisMax
= entries
[i
].fMaxDelay
;
7567 holder
= thisService
;
7573 if (kNoReplace
== replace
) {
7574 sCpuDelayData
->appendBytes(&ne
, sizeof(ne
));
7576 entries
[replace
] = ne
;
7579 ns
= -1U; // Set to max unsigned, i.e. no restriction
7581 for (UInt i
= 0; i
< count
; i
++) {
7582 // Clear a maximum delay.
7583 IOService
*thisService
= entries
[i
].fService
;
7584 if (thisService
&& (delayType
== entries
[i
].fDelayType
)) {
7585 UInt32 thisMax
= entries
[i
].fMaxDelay
;
7586 if (service
== thisService
) {
7588 } else if (thisMax
< ns
) {
7590 holder
= thisService
;
7595 // Check if entry found
7596 if (kNoReplace
!= replace
) {
7597 entries
[replace
].fService
= NULL
; // Null the entry
7603 if (holder
&& debug_boot_arg
) {
7604 strlcpy(sCPULatencyHolderName
[delayType
], holder
->getName(), sizeof(sCPULatencyHolderName
[delayType
]));
7607 // Must be safe to call from locked context
7608 if (delayType
== kCpuDelayBusStall
) {
7609 #if defined(__x86_64__)
7610 ml_set_maxbusdelay(ns
);
7611 #endif /* defined(__x86_64__) */
7613 #if defined(__x86_64__)
7614 else if (delayType
== kCpuDelayInterrupt
) {
7615 ml_set_maxintdelay(ns
);
7617 #endif /* defined(__x86_64__) */
7618 sCPULatencyHolder
[delayType
]->setValue(holder
? holder
->getRegistryEntryID() : 0);
7619 sCPULatencySet
[delayType
]->setValue(ns
);
7621 OSArray
* handlers
= sCpuLatencyHandlers
[delayType
];
7624 for (unsigned int idx
= 0;
7625 (target
= (IOService
*) handlers
->getObject(idx
));
7627 target
->callPlatformFunction(sCPULatencyFunctionName
[delayType
], false,
7628 (void *) (uintptr_t) ns
, holder
,
7634 IORecursiveLockUnlock(sCpuDelayLock
);
7638 setLatencyHandler(UInt32 delayType
, IOService
* target
, bool enable
)
7640 IOReturn result
= kIOReturnNotFound
;
7644 IORecursiveLockLock(sCpuDelayLock
);
7647 if (enable
&& !sCpuLatencyHandlers
[delayType
]) {
7648 sCpuLatencyHandlers
[delayType
] = OSArray::withCapacity(4);
7650 array
= sCpuLatencyHandlers
[delayType
];
7654 idx
= array
->getNextIndexOfObject(target
, 0);
7657 array
->removeObject(idx
);
7658 result
= kIOReturnSuccess
;
7662 result
= kIOReturnExclusiveAccess
;
7665 array
->setObject(target
);
7667 UInt count
= sCpuDelayData
->getLength() / sizeof(CpuDelayEntry
);
7668 CpuDelayEntry
*entries
= (CpuDelayEntry
*) sCpuDelayData
->getBytesNoCopy();
7669 UInt32 ns
= -1U; // Set to max unsigned, i.e. no restriction
7670 IOService
* holder
= NULL
;
7672 for (UInt i
= 0; i
< count
; i
++) {
7673 if (entries
[i
].fService
7674 && (delayType
== entries
[i
].fDelayType
)
7675 && (entries
[i
].fMaxDelay
< ns
)) {
7676 ns
= entries
[i
].fMaxDelay
;
7677 holder
= entries
[i
].fService
;
7680 target
->callPlatformFunction(sCPULatencyFunctionName
[delayType
], false,
7681 (void *) (uintptr_t) ns
, holder
,
7683 result
= kIOReturnSuccess
;
7687 IORecursiveLockUnlock(sCpuDelayLock
);
7693 IOService::requireMaxBusStall(UInt32 ns
)
7695 #if !defined(__x86_64__)
7697 case kIOMaxBusStall40usec
:
7698 case kIOMaxBusStall30usec
:
7699 case kIOMaxBusStall25usec
:
7700 case kIOMaxBusStall20usec
:
7701 case kIOMaxBusStall10usec
:
7702 case kIOMaxBusStall5usec
:
7703 case kIOMaxBusStallNone
:
7706 return kIOReturnBadArgument
;
7708 #endif /* !defined(__x86_64__) */
7709 requireMaxCpuDelay(this, ns
, kCpuDelayBusStall
);
7710 return kIOReturnSuccess
;
7714 IOService::requireMaxInterruptDelay(uint32_t ns
)
7716 #if defined(__x86_64__)
7717 requireMaxCpuDelay(this, ns
, kCpuDelayInterrupt
);
7718 return kIOReturnSuccess
;
7719 #else /* defined(__x86_64__) */
7720 return kIOReturnUnsupported
;
7721 #endif /* defined(__x86_64__) */
7729 IOService::resolveInterrupt(IOService
*nub
, int source
)
7731 IOInterruptController
*interruptController
;
7734 OSSymbol
*interruptControllerName
;
7735 unsigned int numSources
;
7736 IOInterruptSource
*interruptSources
;
7738 // Get the parents list from the nub.
7739 array
= OSDynamicCast(OSArray
, nub
->getProperty(gIOInterruptControllersKey
));
7740 if (array
== NULL
) {
7741 return kIOReturnNoResources
;
7744 // Allocate space for the IOInterruptSources if needed... then return early.
7745 if (nub
->_interruptSources
== NULL
) {
7746 numSources
= array
->getCount();
7747 interruptSources
= (IOInterruptSource
*)IOMalloc(
7748 numSources
* sizeofAllIOInterruptSource
);
7749 if (interruptSources
== NULL
) {
7750 return kIOReturnNoMemory
;
7753 bzero(interruptSources
, numSources
* sizeofAllIOInterruptSource
);
7755 nub
->_numInterruptSources
= numSources
;
7756 nub
->_interruptSources
= interruptSources
;
7757 return kIOReturnSuccess
;
7760 interruptControllerName
= OSDynamicCast(OSSymbol
, array
->getObject(source
));
7761 if (interruptControllerName
== NULL
) {
7762 return kIOReturnNoResources
;
7765 interruptController
= getPlatform()->lookUpInterruptController(interruptControllerName
);
7766 if (interruptController
== NULL
) {
7767 return kIOReturnNoResources
;
7770 // Get the interrupt numbers from the nub.
7771 array
= OSDynamicCast(OSArray
, nub
->getProperty(gIOInterruptSpecifiersKey
));
7772 if (array
== NULL
) {
7773 return kIOReturnNoResources
;
7775 data
= OSDynamicCast(OSData
, array
->getObject(source
));
7777 return kIOReturnNoResources
;
7780 // Set the interruptController and interruptSource in the nub's table.
7781 interruptSources
= nub
->_interruptSources
;
7782 interruptSources
[source
].interruptController
= interruptController
;
7783 interruptSources
[source
].vectorData
= data
;
7785 return kIOReturnSuccess
;
7789 IOService::lookupInterrupt(int source
, bool resolve
, IOInterruptController
**interruptController
)
7793 /* Make sure the _interruptSources are set */
7794 if (_interruptSources
== NULL
) {
7795 ret
= resolveInterrupt(this, source
);
7796 if (ret
!= kIOReturnSuccess
) {
7801 /* Make sure the local source number is valid */
7802 if ((source
< 0) || (source
>= _numInterruptSources
)) {
7803 return kIOReturnNoInterrupt
;
7806 /* Look up the contoller for the local source */
7807 *interruptController
= _interruptSources
[source
].interruptController
;
7809 if (*interruptController
== NULL
) {
7811 return kIOReturnNoInterrupt
;
7814 /* Try to resolve the interrupt */
7815 ret
= resolveInterrupt(this, source
);
7816 if (ret
!= kIOReturnSuccess
) {
7820 *interruptController
= _interruptSources
[source
].interruptController
;
7823 return kIOReturnSuccess
;
7827 IOService::registerInterrupt(int source
, OSObject
*target
,
7828 IOInterruptAction handler
,
7831 IOInterruptController
*interruptController
;
7834 ret
= lookupInterrupt(source
, true, &interruptController
);
7835 if (ret
!= kIOReturnSuccess
) {
7839 /* Register the source */
7840 return interruptController
->registerInterrupt(this, source
, target
,
7841 (IOInterruptHandler
)handler
,
7846 IOServiceInterruptActionToBlock( OSObject
* target
, void * refCon
,
7847 IOService
* nub
, int source
)
7849 ((IOInterruptActionBlock
)(refCon
))(nub
, source
);
7853 IOService::registerInterruptBlock(int source
, OSObject
*target
,
7854 IOInterruptActionBlock handler
)
7859 block
= Block_copy(handler
);
7861 return kIOReturnNoMemory
;
7864 ret
= registerInterrupt(source
, target
, &IOServiceInterruptActionToBlock
, block
);
7865 if (kIOReturnSuccess
!= ret
) {
7866 Block_release(block
);
7869 _interruptSourcesPrivate(this)[source
].vectorBlock
= block
;
7875 IOService::unregisterInterrupt(int source
)
7878 IOInterruptController
*interruptController
;
7881 ret
= lookupInterrupt(source
, false, &interruptController
);
7882 if (ret
!= kIOReturnSuccess
) {
7886 /* Unregister the source */
7887 block
= _interruptSourcesPrivate(this)[source
].vectorBlock
;
7888 ret
= interruptController
->unregisterInterrupt(this, source
);
7889 if ((kIOReturnSuccess
== ret
) && (block
= _interruptSourcesPrivate(this)[source
].vectorBlock
)) {
7890 _interruptSourcesPrivate(this)[source
].vectorBlock
= NULL
;
7891 Block_release(block
);
7898 IOService::addInterruptStatistics(IOInterruptAccountingData
* statistics
, int source
)
7900 IOReportLegend
* legend
= NULL
;
7901 IOInterruptAccountingData
* oldValue
= NULL
;
7902 IOInterruptAccountingReporter
* newArray
= NULL
;
7903 char subgroupName
[64];
7904 int newArraySize
= 0;
7908 return kIOReturnBadArgument
;
7912 * We support statistics on a maximum of 256 interrupts per nub; if a nub
7913 * has more than 256 interrupt specifiers associated with it, and tries
7914 * to register a high interrupt index with interrupt accounting, panic.
7915 * Having more than 256 interrupts associated with a single nub is
7916 * probably a sign that something fishy is going on.
7918 if (source
> IA_INDEX_MAX
) {
7919 panic("addInterruptStatistics called for an excessively large index (%d)", source
);
7923 * TODO: This is ugly (wrapping a lock around an allocation). I'm only
7924 * leaving it as is because the likelihood of contention where we are
7925 * actually growing the array is minimal (we would realistically need
7926 * to be starting a driver for the first time, with an IOReporting
7927 * client already in place). Nonetheless, cleanup that can be done
7928 * to adhere to best practices; it'll make the code more complicated,
7931 IOLockLock(reserved
->interruptStatisticsLock
);
7934 * Lazily allocate the statistics array.
7936 if (!reserved
->interruptStatisticsArray
) {
7937 reserved
->interruptStatisticsArray
= IONew(IOInterruptAccountingReporter
, 1);
7938 assert(reserved
->interruptStatisticsArray
);
7939 reserved
->interruptStatisticsArrayCount
= 1;
7940 bzero(reserved
->interruptStatisticsArray
, sizeof(*reserved
->interruptStatisticsArray
));
7943 if (source
>= reserved
->interruptStatisticsArrayCount
) {
7945 * We're still within the range of supported indices, but we are out
7946 * of space in the current array. Do a nasty realloc (because
7947 * IORealloc isn't a thing) here. We'll double the size with each
7950 * Yes, the "next power of 2" could be more efficient; but this will
7951 * be invoked incredibly rarely. Who cares.
7953 newArraySize
= (reserved
->interruptStatisticsArrayCount
<< 1);
7955 while (newArraySize
<= source
) {
7956 newArraySize
= (newArraySize
<< 1);
7958 newArray
= IONew(IOInterruptAccountingReporter
, newArraySize
);
7963 * TODO: This even zeroes the memory it is about to overwrite.
7964 * Shameful; fix it. Not particularly high impact, however.
7966 bzero(newArray
, newArraySize
* sizeof(*newArray
));
7967 memcpy(newArray
, reserved
->interruptStatisticsArray
, reserved
->interruptStatisticsArrayCount
* sizeof(*newArray
));
7968 IODelete(reserved
->interruptStatisticsArray
, IOInterruptAccountingReporter
, reserved
->interruptStatisticsArrayCount
);
7969 reserved
->interruptStatisticsArray
= newArray
;
7970 reserved
->interruptStatisticsArrayCount
= newArraySize
;
7973 if (!reserved
->interruptStatisticsArray
[source
].reporter
) {
7975 * We don't have a reporter associated with this index yet, so we
7976 * need to create one.
7979 * TODO: Some statistics do in fact have common units (time); should this be
7980 * split into separate reporters to communicate this?
7982 reserved
->interruptStatisticsArray
[source
].reporter
= IOSimpleReporter::with(this, kIOReportCategoryPower
, kIOReportUnitNone
);
7985 * Each statistic is given an identifier based on the interrupt index (which
7986 * should be unique relative to any single nub) and the statistic involved.
7987 * We should now have a sane (small and positive) index, so start
7988 * constructing the channels for statistics.
7990 for (i
= 0; i
< IA_NUM_INTERRUPT_ACCOUNTING_STATISTICS
; i
++) {
7992 * TODO: Currently, this does not add channels for disabled statistics.
7993 * Will this be confusing for clients? If so, we should just add the
7994 * channels; we can avoid updating the channels even if they exist.
7996 if (IA_GET_STATISTIC_ENABLED(i
)) {
7997 reserved
->interruptStatisticsArray
[source
].reporter
->addChannel(IA_GET_CHANNEL_ID(source
, i
), kInterruptAccountingStatisticNameArray
[i
]);
8002 * We now need to add the legend for this reporter to the registry.
8004 OSObject
* prop
= copyProperty(kIOReportLegendKey
);
8005 legend
= IOReportLegend::with(OSDynamicCast(OSArray
, prop
));
8006 OSSafeReleaseNULL(prop
);
8009 * Note that while we compose the subgroup name, we do not need to
8010 * manage its lifecycle (the reporter will handle this).
8012 snprintf(subgroupName
, sizeof(subgroupName
), "%s %d", getName(), source
);
8013 subgroupName
[sizeof(subgroupName
) - 1] = 0;
8014 legend
->addReporterLegend(reserved
->interruptStatisticsArray
[source
].reporter
, kInterruptAccountingGroupName
, subgroupName
);
8015 setProperty(kIOReportLegendKey
, legend
->getLegend());
8019 * TODO: Is this a good idea? Probably not; my assumption is it opts
8020 * all entities who register interrupts into public disclosure of all
8021 * IOReporting channels. Unfortunately, this appears to be as fine
8024 setProperty(kIOReportLegendPublicKey
, true);
8028 * Don't stomp existing entries. If we are about to, panic; this
8029 * probably means we failed to tear down our old interrupt source
8032 oldValue
= reserved
->interruptStatisticsArray
[source
].statistics
;
8035 panic("addInterruptStatistics call for index %d would have clobbered existing statistics", source
);
8038 reserved
->interruptStatisticsArray
[source
].statistics
= statistics
;
8041 * Inherit the reporter values for each statistic. The target may
8042 * be torn down as part of the runtime of the service (especially
8043 * for sleep/wake), so we inherit in order to avoid having values
8044 * reset for no apparent reason. Our statistics are ultimately
8045 * tied to the index and the sevice, not to an individual target,
8046 * so we should maintain them accordingly.
8048 interruptAccountingDataInheritChannels(reserved
->interruptStatisticsArray
[source
].statistics
, reserved
->interruptStatisticsArray
[source
].reporter
);
8050 IOLockUnlock(reserved
->interruptStatisticsLock
);
8052 return kIOReturnSuccess
;
8056 IOService::removeInterruptStatistics(int source
)
8058 IOInterruptAccountingData
* value
= NULL
;
8061 return kIOReturnBadArgument
;
8064 IOLockLock(reserved
->interruptStatisticsLock
);
8067 * We dynamically grow the statistics array, so an excessively
8068 * large index value has NEVER been registered. This either
8069 * means our cap on the array size is too small (unlikely), or
8070 * that we have been passed a corrupt index (this must be passed
8071 * the plain index into the interrupt specifier list).
8073 if (source
>= reserved
->interruptStatisticsArrayCount
) {
8074 panic("removeInterruptStatistics called for index %d, which was never registered", source
);
8077 assert(reserved
->interruptStatisticsArray
);
8080 * If there is no existing entry, we are most likely trying to
8081 * free an interrupt owner twice, or we have corrupted the
8084 value
= reserved
->interruptStatisticsArray
[source
].statistics
;
8087 panic("removeInterruptStatistics called for empty index %d", source
);
8091 * We update the statistics, so that any delta with the reporter
8092 * state is not lost.
8094 interruptAccountingDataUpdateChannels(reserved
->interruptStatisticsArray
[source
].statistics
, reserved
->interruptStatisticsArray
[source
].reporter
);
8095 reserved
->interruptStatisticsArray
[source
].statistics
= NULL
;
8096 IOLockUnlock(reserved
->interruptStatisticsLock
);
8098 return kIOReturnSuccess
;
8102 IOService::getInterruptType(int source
, int *interruptType
)
8104 IOInterruptController
*interruptController
;
8107 ret
= lookupInterrupt(source
, true, &interruptController
);
8108 if (ret
!= kIOReturnSuccess
) {
8112 /* Return the type */
8113 return interruptController
->getInterruptType(this, source
, interruptType
);
8117 IOService::enableInterrupt(int source
)
8119 IOInterruptController
*interruptController
;
8122 ret
= lookupInterrupt(source
, false, &interruptController
);
8123 if (ret
!= kIOReturnSuccess
) {
8127 /* Enable the source */
8128 return interruptController
->enableInterrupt(this, source
);
8132 IOService::disableInterrupt(int source
)
8134 IOInterruptController
*interruptController
;
8137 ret
= lookupInterrupt(source
, false, &interruptController
);
8138 if (ret
!= kIOReturnSuccess
) {
8142 /* Disable the source */
8143 return interruptController
->disableInterrupt(this, source
);
8147 IOService::causeInterrupt(int source
)
8149 IOInterruptController
*interruptController
;
8152 ret
= lookupInterrupt(source
, false, &interruptController
);
8153 if (ret
!= kIOReturnSuccess
) {
8157 /* Cause an interrupt for the source */
8158 return interruptController
->causeInterrupt(this, source
);
8162 IOService::configureReport(IOReportChannelList
*channelList
,
8163 IOReportConfigureAction action
,
8169 for (cnt
= 0; cnt
< channelList
->nchannels
; cnt
++) {
8170 if (channelList
->channels
[cnt
].channel_id
== kPMPowerStatesChID
) {
8172 configurePowerStatesReport(action
, result
);
8174 return kIOReturnUnsupported
;
8176 } else if (channelList
->channels
[cnt
].channel_id
== kPMCurrStateChID
) {
8178 configureSimplePowerReport(action
, result
);
8180 return kIOReturnUnsupported
;
8185 IOLockLock(reserved
->interruptStatisticsLock
);
8187 /* The array count is signed (because the interrupt indices are signed), hence the cast */
8188 for (cnt
= 0; cnt
< (unsigned) reserved
->interruptStatisticsArrayCount
; cnt
++) {
8189 if (reserved
->interruptStatisticsArray
[cnt
].reporter
) {
8191 * If the reporter is currently associated with the statistics
8192 * for an event source, we may need to update the reporter.
8194 if (reserved
->interruptStatisticsArray
[cnt
].statistics
) {
8195 interruptAccountingDataUpdateChannels(reserved
->interruptStatisticsArray
[cnt
].statistics
, reserved
->interruptStatisticsArray
[cnt
].reporter
);
8198 reserved
->interruptStatisticsArray
[cnt
].reporter
->configureReport(channelList
, action
, result
, destination
);
8202 IOLockUnlock(reserved
->interruptStatisticsLock
);
8204 return kIOReturnSuccess
;
8208 IOService::updateReport(IOReportChannelList
*channelList
,
8209 IOReportUpdateAction action
,
8215 for (cnt
= 0; cnt
< channelList
->nchannels
; cnt
++) {
8216 if (channelList
->channels
[cnt
].channel_id
== kPMPowerStatesChID
) {
8218 updatePowerStatesReport(action
, result
, destination
);
8220 return kIOReturnUnsupported
;
8222 } else if (channelList
->channels
[cnt
].channel_id
== kPMCurrStateChID
) {
8224 updateSimplePowerReport(action
, result
, destination
);
8226 return kIOReturnUnsupported
;
8231 IOLockLock(reserved
->interruptStatisticsLock
);
8233 /* The array count is signed (because the interrupt indices are signed), hence the cast */
8234 for (cnt
= 0; cnt
< (unsigned) reserved
->interruptStatisticsArrayCount
; cnt
++) {
8235 if (reserved
->interruptStatisticsArray
[cnt
].reporter
) {
8237 * If the reporter is currently associated with the statistics
8238 * for an event source, we need to update the reporter.
8240 if (reserved
->interruptStatisticsArray
[cnt
].statistics
) {
8241 interruptAccountingDataUpdateChannels(reserved
->interruptStatisticsArray
[cnt
].statistics
, reserved
->interruptStatisticsArray
[cnt
].reporter
);
8244 reserved
->interruptStatisticsArray
[cnt
].reporter
->updateReport(channelList
, action
, result
, destination
);
8248 IOLockUnlock(reserved
->interruptStatisticsLock
);
8250 return kIOReturnSuccess
;
8254 IOService::getAuthorizationID( void )
8256 return reserved
->authorizationID
;
8260 IOService::setAuthorizationID( uint64_t authorizationID
)
8262 OSObject
* entitlement
;
8265 entitlement
= IOUserClient::copyClientEntitlement( current_task(), "com.apple.private.iokit.IOServiceSetAuthorizationID" );
8268 if (entitlement
== kOSBooleanTrue
) {
8269 reserved
->authorizationID
= authorizationID
;
8271 status
= kIOReturnSuccess
;
8273 status
= kIOReturnNotPrivileged
;
8276 entitlement
->release();
8278 status
= kIOReturnNotPrivileged
;
8284 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8288 OSMetaClassDefineReservedUsedX86(IOService
, 0);
8289 OSMetaClassDefineReservedUsedX86(IOService
, 1);
8290 OSMetaClassDefineReservedUnused(IOService
, 2);
8291 OSMetaClassDefineReservedUnused(IOService
, 3);
8292 OSMetaClassDefineReservedUnused(IOService
, 4);
8293 OSMetaClassDefineReservedUnused(IOService
, 5);
8294 OSMetaClassDefineReservedUnused(IOService
, 6);
8295 OSMetaClassDefineReservedUnused(IOService
, 7);
8297 OSMetaClassDefineReservedUsedX86(IOService
, 0);
8298 OSMetaClassDefineReservedUsedX86(IOService
, 1);
8299 OSMetaClassDefineReservedUsedX86(IOService
, 2);
8300 OSMetaClassDefineReservedUsedX86(IOService
, 3);
8301 OSMetaClassDefineReservedUsedX86(IOService
, 4);
8302 OSMetaClassDefineReservedUsedX86(IOService
, 5);
8303 OSMetaClassDefineReservedUsedX86(IOService
, 6);
8304 OSMetaClassDefineReservedUsedX86(IOService
, 7);
8306 OSMetaClassDefineReservedUnused(IOService
, 8);
8307 OSMetaClassDefineReservedUnused(IOService
, 9);
8308 OSMetaClassDefineReservedUnused(IOService
, 10);
8309 OSMetaClassDefineReservedUnused(IOService
, 11);
8310 OSMetaClassDefineReservedUnused(IOService
, 12);
8311 OSMetaClassDefineReservedUnused(IOService
, 13);
8312 OSMetaClassDefineReservedUnused(IOService
, 14);
8313 OSMetaClassDefineReservedUnused(IOService
, 15);
8314 OSMetaClassDefineReservedUnused(IOService
, 16);
8315 OSMetaClassDefineReservedUnused(IOService
, 17);
8316 OSMetaClassDefineReservedUnused(IOService
, 18);
8317 OSMetaClassDefineReservedUnused(IOService
, 19);
8318 OSMetaClassDefineReservedUnused(IOService
, 20);
8319 OSMetaClassDefineReservedUnused(IOService
, 21);
8320 OSMetaClassDefineReservedUnused(IOService
, 22);
8321 OSMetaClassDefineReservedUnused(IOService
, 23);
8322 OSMetaClassDefineReservedUnused(IOService
, 24);
8323 OSMetaClassDefineReservedUnused(IOService
, 25);
8324 OSMetaClassDefineReservedUnused(IOService
, 26);
8325 OSMetaClassDefineReservedUnused(IOService
, 27);
8326 OSMetaClassDefineReservedUnused(IOService
, 28);
8327 OSMetaClassDefineReservedUnused(IOService
, 29);
8328 OSMetaClassDefineReservedUnused(IOService
, 30);
8329 OSMetaClassDefineReservedUnused(IOService
, 31);
8330 OSMetaClassDefineReservedUnused(IOService
, 32);
8331 OSMetaClassDefineReservedUnused(IOService
, 33);
8332 OSMetaClassDefineReservedUnused(IOService
, 34);
8333 OSMetaClassDefineReservedUnused(IOService
, 35);
8334 OSMetaClassDefineReservedUnused(IOService
, 36);
8335 OSMetaClassDefineReservedUnused(IOService
, 37);
8336 OSMetaClassDefineReservedUnused(IOService
, 38);
8337 OSMetaClassDefineReservedUnused(IOService
, 39);
8338 OSMetaClassDefineReservedUnused(IOService
, 40);
8339 OSMetaClassDefineReservedUnused(IOService
, 41);
8340 OSMetaClassDefineReservedUnused(IOService
, 42);
8341 OSMetaClassDefineReservedUnused(IOService
, 43);
8342 OSMetaClassDefineReservedUnused(IOService
, 44);
8343 OSMetaClassDefineReservedUnused(IOService
, 45);
8344 OSMetaClassDefineReservedUnused(IOService
, 46);
8345 OSMetaClassDefineReservedUnused(IOService
, 47);