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
;
373 uint8_t fWaitingUserServers
;
378 void init(IOPMrootDomain
* root
);
380 IOReturn
systemPowerChange(
383 UInt32 messageType
, IOService
* service
,
384 void * messageArgument
, vm_size_t argSize
);
386 bool matchingStart(IOService
* service
);
387 void matchingEnd(IOService
* service
);
390 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
393 IOService::initialize( void )
397 gIOServicePlane
= IORegistryEntry::makePlane( kIOServicePlane
);
398 gIOPowerPlane
= IORegistryEntry::makePlane( kIOPowerPlane
);
400 gIOProviderClassKey
= OSSymbol::withCStringNoCopy( kIOProviderClassKey
);
401 gIONameMatchKey
= OSSymbol::withCStringNoCopy( kIONameMatchKey
);
402 gIONameMatchedKey
= OSSymbol::withCStringNoCopy( kIONameMatchedKey
);
403 gIOPropertyMatchKey
= OSSymbol::withCStringNoCopy( kIOPropertyMatchKey
);
404 gIOPropertyExistsMatchKey
= OSSymbol::withCStringNoCopy( kIOPropertyExistsMatchKey
);
405 gIOPathMatchKey
= OSSymbol::withCStringNoCopy( kIOPathMatchKey
);
406 gIOLocationMatchKey
= OSSymbol::withCStringNoCopy( kIOLocationMatchKey
);
407 gIOParentMatchKey
= OSSymbol::withCStringNoCopy( kIOParentMatchKey
);
409 gIOMatchCategoryKey
= OSSymbol::withCStringNoCopy( kIOMatchCategoryKey
);
410 gIODefaultMatchCategoryKey
= OSSymbol::withCStringNoCopy(
411 kIODefaultMatchCategoryKey
);
412 gIOMatchedServiceCountKey
= OSSymbol::withCStringNoCopy(
413 kIOMatchedServiceCountKey
);
414 gIOMatchedPersonalityKey
= OSSymbol::withCStringNoCopy(
415 kIOMatchedPersonalityKey
);
416 gIORematchPersonalityKey
= OSSymbol::withCStringNoCopy(
417 kIORematchPersonalityKey
);
418 gIORematchCountKey
= OSSymbol::withCStringNoCopy(
419 kIORematchCountKey
);
420 gIODEXTMatchCountKey
= OSSymbol::withCStringNoCopy(
421 kIODEXTMatchCountKey
);
423 #if defined(XNU_TARGET_OS_OSX)
424 gIOServiceLegacyMatchingRegistryIDKey
= OSSymbol::withCStringNoCopy(
425 kIOServiceLegacyMatchingRegistryIDKey
);
426 #endif /* defined(XNU_TARGET_OS_OSX) */
428 PE_parse_boot_argn("dextrelaunch", &gIODextRelaunchMax
, sizeof(gIODextRelaunchMax
));
429 PE_parse_boot_argn("iocthreads", &gMaxConfigThreads
, sizeof(gMaxConfigThreads
));
431 gIOUserClientClassKey
= OSSymbol::withCStringNoCopy( kIOUserClientClassKey
);
433 gIOUserClassKey
= OSSymbol::withCStringNoCopy(kIOUserClassKey
);
435 gIOUserServerClassKey
= OSSymbol::withCStringNoCopy(kIOUserServerClassKey
);
436 gIOUserServerNameKey
= OSSymbol::withCStringNoCopy(kIOUserServerNameKey
);
437 gIOUserServerTagKey
= OSSymbol::withCStringNoCopy(kIOUserServerTagKey
);
438 gIOUserUserClientKey
= OSSymbol::withCStringNoCopy(kIOUserUserClientKey
);
440 gIOResourcesKey
= OSSymbol::withCStringNoCopy( kIOResourcesClass
);
441 gIOResourceMatchKey
= OSSymbol::withCStringNoCopy( kIOResourceMatchKey
);
442 gIOResourceMatchedKey
= OSSymbol::withCStringNoCopy( kIOResourceMatchedKey
);
443 gIOResourceIOKitKey
= OSSymbol::withCStringNoCopy("IOKit");
445 gIODeviceMemoryKey
= OSSymbol::withCStringNoCopy( "IODeviceMemory" );
446 gIOInterruptControllersKey
447 = OSSymbol::withCStringNoCopy("IOInterruptControllers");
448 gIOInterruptSpecifiersKey
449 = OSSymbol::withCStringNoCopy("IOInterruptSpecifiers");
451 gIOCompatibilityMatchKey
= OSSymbol::withCStringNoCopy(kIOCompatibilityMatchKey
);
452 gIOCompatibilityPropertiesKey
= OSSymbol::withCStringNoCopy(kIOCompatibilityPropertiesKey
);
453 gIOPathKey
= OSSymbol::withCStringNoCopy(kIOPathKey
);
454 gIOSupportedPropertiesKey
= OSSymbol::withCStringNoCopy(kIOSupportedPropertiesKey
);
455 gIOUserServicePropertiesKey
= OSSymbol::withCStringNoCopy(kIOUserServicePropertiesKey
);
457 gIOMapperIDKey
= OSSymbol::withCStringNoCopy(kIOMapperIDKey
);
459 gIOKitDebugKey
= OSSymbol::withCStringNoCopy( kIOKitDebugKey
);
461 gIOCommandPoolSizeKey
= OSSymbol::withCStringNoCopy( kIOCommandPoolSizeKey
);
463 gIOGeneralInterest
= OSSymbol::withCStringNoCopy( kIOGeneralInterest
);
464 gIOBusyInterest
= OSSymbol::withCStringNoCopy( kIOBusyInterest
);
465 gIOAppPowerStateInterest
= OSSymbol::withCStringNoCopy( kIOAppPowerStateInterest
);
466 gIOPriorityPowerStateInterest
= OSSymbol::withCStringNoCopy( kIOPriorityPowerStateInterest
);
467 gIOConsoleSecurityInterest
= OSSymbol::withCStringNoCopy( kIOConsoleSecurityInterest
);
469 gIOBSDKey
= OSSymbol::withCStringNoCopy(kIOBSDKey
);
470 gIOBSDNameKey
= OSSymbol::withCStringNoCopy(kIOBSDNameKey
);
471 gIOBSDMajorKey
= OSSymbol::withCStringNoCopy(kIOBSDMajorKey
);
472 gIOBSDMinorKey
= OSSymbol::withCStringNoCopy(kIOBSDMinorKey
);
473 gIOBSDUnitKey
= OSSymbol::withCStringNoCopy(kIOBSDUnitKey
);
475 gNotifications
= OSDictionary::withCapacity( 1 );
476 gIOPublishNotification
= OSSymbol::withCStringNoCopy(
477 kIOPublishNotification
);
478 gIOFirstPublishNotification
= OSSymbol::withCStringNoCopy(
479 kIOFirstPublishNotification
);
480 gIOMatchedNotification
= OSSymbol::withCStringNoCopy(
481 kIOMatchedNotification
);
482 gIOFirstMatchNotification
= OSSymbol::withCStringNoCopy(
483 kIOFirstMatchNotification
);
484 gIOTerminatedNotification
= OSSymbol::withCStringNoCopy(
485 kIOTerminatedNotification
);
486 gIOWillTerminateNotification
= OSSymbol::withCStringNoCopy(
487 kIOWillTerminateNotification
);
488 gIOServiceKey
= OSSymbol::withCStringNoCopy( kIOServiceClass
);
491 gIOConsoleLockedKey
= OSSymbol::withCStringNoCopy( kIOConsoleLockedKey
);
492 gIOConsoleUsersKey
= OSSymbol::withCStringNoCopy( kIOConsoleUsersKey
);
493 gIOConsoleSessionUIDKey
= OSSymbol::withCStringNoCopy( kIOConsoleSessionUIDKey
);
494 gIOConsoleSessionAuditIDKey
= OSSymbol::withCStringNoCopy( kIOConsoleSessionAuditIDKey
);
496 gIOConsoleUsersSeedKey
= OSSymbol::withCStringNoCopy(kIOConsoleUsersSeedKey
);
497 gIOConsoleSessionOnConsoleKey
= OSSymbol::withCStringNoCopy(kIOConsoleSessionOnConsoleKey
);
498 gIOConsoleSessionLoginDoneKey
= OSSymbol::withCStringNoCopy(kIOConsoleSessionLoginDoneKey
);
499 gIOConsoleSessionSecureInputPIDKey
= OSSymbol::withCStringNoCopy(kIOConsoleSessionSecureInputPIDKey
);
500 gIOConsoleSessionScreenLockedTimeKey
= OSSymbol::withCStringNoCopy(kIOConsoleSessionScreenLockedTimeKey
);
501 gIOConsoleSessionScreenIsLockedKey
= OSSymbol::withCStringNoCopy(kIOConsoleSessionScreenIsLockedKey
);
503 gIOConsoleUsersSeedValue
= OSData::withBytesNoCopy(&gIOConsoleUsersSeed
, sizeof(gIOConsoleUsersSeed
));
505 gIOServiceDEXTEntitlementsKey
= OSSymbol::withCStringNoCopy( kIOServiceDEXTEntitlementsKey
);
506 gIODriverKitEntitlementKey
= OSSymbol::withCStringNoCopy( kIODriverKitEntitlementKey
);
507 gIODriverKitUserClientEntitlementsKey
= OSSymbol::withCStringNoCopy( kIODriverKitUserClientEntitlementsKey
);
508 gIODriverKitUserClientEntitlementAllowAnyKey
= OSSymbol::withCStringNoCopy( kIODriverKitUserClientEntitlementAllowAnyKey
);
509 gIOMatchDeferKey
= OSSymbol::withCStringNoCopy( kIOMatchDeferKey
);
510 gIOAllCPUInitializedKey
= OSSymbol::withCStringNoCopy( kIOAllCPUInitializedKey
);
512 gIOPlatformFunctionHandlerSet
= OSSymbol::withCStringNoCopy(kIOPlatformFunctionHandlerSet
);
513 sCPULatencyFunctionName
[kCpuDelayBusStall
] = OSSymbol::withCStringNoCopy(kIOPlatformFunctionHandlerMaxBusDelay
);
514 #if defined(__x86_64__)
515 sCPULatencyFunctionName
[kCpuDelayInterrupt
] = OSSymbol::withCStringNoCopy(kIOPlatformFunctionHandlerMaxInterruptDelay
);
516 #endif /* defined(__x86_64__) */
518 for (idx
= 0; idx
< kCpuNumDelayTypes
; idx
++) {
519 sCPULatencySet
[idx
] = OSNumber::withNumber(UINT_MAX
, 32);
520 sCPULatencyHolder
[idx
] = OSNumber::withNumber(0ULL, 64);
521 assert(sCPULatencySet
[idx
] && sCPULatencyHolder
[idx
]);
524 #if defined(__x86_64__)
525 gIOCreateEFIDevicePathSymbol
= OSSymbol::withCString("CreateEFIDevicePath");
526 #endif /* defined(__x86_64__) */
528 gNotificationLock
= IORecursiveLockAlloc();
530 gAKSGetKey
= OSSymbol::withCStringNoCopy(AKS_PLATFORM_FUNCTION_GETKEY
);
532 assert( gIOServicePlane
&& gIODeviceMemoryKey
533 && gIOInterruptControllersKey
&& gIOInterruptSpecifiersKey
534 && gIOResourcesKey
&& gNotifications
&& gNotificationLock
535 && gIOProviderClassKey
&& gIONameMatchKey
&& gIONameMatchedKey
536 && gIOMatchCategoryKey
&& gIODefaultMatchCategoryKey
537 && gIOPublishNotification
&& gIOMatchedNotification
538 && gIOTerminatedNotification
&& gIOServiceKey
539 && gIOConsoleUsersKey
&& gIOConsoleSessionUIDKey
540 && gIOConsoleSessionOnConsoleKey
&& gIOConsoleSessionSecureInputPIDKey
541 && gIOConsoleUsersSeedKey
&& gIOConsoleUsersSeedValue
);
543 gJobsLock
= IOLockAlloc();
544 gJobs
= OSOrderedSet::withCapacity( 10 );
546 gIOServiceBusyLock
= IOLockAlloc();
548 gIOConsoleUsersLock
= IOLockAlloc();
550 err
= semaphore_create(kernel_task
, &gJobsSemaphore
, SYNC_POLICY_FIFO
, 0);
552 gIOConsoleLockCallout
= thread_call_allocate(&IOService::consoleLockTimer
, NULL
);
554 IORegistryEntry::getRegistryRoot()->setProperty(gIOConsoleLockedKey
, kOSBooleanTrue
);
556 assert( gIOServiceBusyLock
&& gJobs
&& gJobsLock
&& gIOConsoleUsersLock
557 && gIOConsoleLockCallout
&& (err
== KERN_SUCCESS
));
559 gIOResources
= IOResources::resources();
560 gIOUserResources
= IOUserResources::resources();
561 assert( gIOResources
&& gIOUserResources
);
563 gIOServiceNullNotifier
= OSTypeAlloc(_IOServiceNullNotifier
);
564 assert(gIOServiceNullNotifier
);
566 gArbitrationLockQueueLock
= IOLockAlloc();
567 queue_init(&gArbitrationLockQueueActive
);
568 queue_init(&gArbitrationLockQueueWaiting
);
569 queue_init(&gArbitrationLockQueueFree
);
571 assert( gArbitrationLockQueueLock
);
573 gIOTerminatePhase2List
= OSArray::withCapacity( 2 );
574 gIOStopList
= OSArray::withCapacity( 16 );
575 gIOStopProviderList
= OSArray::withCapacity( 16 );
576 gIOFinalizeList
= OSArray::withCapacity( 16 );
578 gIOMatchDeferList
= OSArray::withCapacity( 16 );
580 assert( gIOTerminatePhase2List
&& gIOStopList
&& gIOStopProviderList
&& gIOFinalizeList
);
582 // worker thread that is responsible for terminating / cleaning up threads
583 kernel_thread_start(&terminateThread
, NULL
, &gIOTerminateWorkerThread
);
584 assert(gIOTerminateWorkerThread
);
585 thread_set_thread_name(gIOTerminateWorkerThread
, "IOServiceTerminateThread");
588 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
590 #if defined(__x86_64__)
592 const char *getCpuDelayBusStallHolderName(void);
594 getCpuDelayBusStallHolderName(void)
596 return sCPULatencyHolderName
[kCpuDelayBusStall
];
599 const char *getCpuInterruptDelayHolderName(void);
601 getCpuInterruptDelayHolderName(void)
603 return sCPULatencyHolderName
[kCpuDelayInterrupt
];
606 #endif /* defined(__x86_64__) */
612 getDebugFlags( OSDictionary
* props
)
614 OSNumber
* debugProp
;
617 debugProp
= OSDynamicCast( OSNumber
,
618 props
->getObject( gIOKitDebugKey
));
620 debugFlags
= debugProp
->unsigned64BitValue();
622 debugFlags
= gIOKitDebug
;
629 getDebugFlags( IOService
* inst
)
632 OSNumber
* debugProp
;
635 prop
= inst
->copyProperty(gIOKitDebugKey
);
636 debugProp
= OSDynamicCast(OSNumber
, prop
);
638 debugFlags
= debugProp
->unsigned64BitValue();
640 debugFlags
= gIOKitDebug
;
643 OSSafeReleaseNULL(prop
);
649 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
651 // Probe a matched service and return an instance to be started.
652 // The default score is from the property table, & may be altered
653 // during probe to change the start order.
656 IOService::probe( IOService
* provider
,
663 IOService::start( IOService
* provider
)
669 IOService::stop( IOService
* provider
)
671 if (reserved
->uvars
&& reserved
->uvars
->started
&& reserved
->uvars
->userServer
) {
672 reserved
->uvars
->userServer
->serviceStop(this, provider
);
677 IOService::init( OSDictionary
* dictionary
)
681 ret
= super::init(dictionary
);
689 reserved
= IONew(ExpansionData
, 1);
693 bzero(reserved
, sizeof(*reserved
));
696 * TODO: Improve on this. Previous efforts to more lazily allocate this
697 * lock based on the presence of specifiers ran into issues as some
698 * platforms set up the specifiers after IOService initialization.
700 * We may be able to get away with a global lock, as this should only be
701 * contended by IOReporting clients and driver start/stop (unless a
702 * driver wants to remove/add handlers in the course of normal operation,
703 * which should be unlikely).
705 reserved
->interruptStatisticsLock
= IOLockAlloc();
706 if (!reserved
->interruptStatisticsLock
) {
714 IOService::init( IORegistryEntry
* from
,
715 const IORegistryPlane
* inPlane
)
719 ret
= super::init(from
, inPlane
);
727 reserved
= IONew(ExpansionData
, 1);
731 bzero(reserved
, sizeof(*reserved
));
734 * TODO: Improve on this. Previous efforts to more lazily allocate this
735 * lock based on the presence of specifiers ran into issues as some
736 * platforms set up the specifiers after IOService initialization.
738 * We may be able to get away with a global lock, as this should only be
739 * contended by IOReporting clients and driver start/stop (unless a
740 * driver wants to remove/add handlers in the course of normal operation,
741 * which should be unlikely).
743 reserved
->interruptStatisticsLock
= IOLockAlloc();
744 if (!reserved
->interruptStatisticsLock
) {
752 IOService::free( void )
755 requireMaxBusStall(0);
756 #if defined(__x86_64__)
757 requireMaxInterruptDelay(0);
758 #endif /* defined(__x86_64__) */
759 if (getPropertyTable()) {
760 unregisterAllInterest();
765 if (reserved
->interruptStatisticsArray
) {
766 for (i
= 0; i
< reserved
->interruptStatisticsArrayCount
; i
++) {
767 if (reserved
->interruptStatisticsArray
[i
].reporter
) {
768 reserved
->interruptStatisticsArray
[i
].reporter
->release();
772 IODelete(reserved
->interruptStatisticsArray
, IOInterruptAccountingReporter
, reserved
->interruptStatisticsArrayCount
);
775 if (reserved
->interruptStatisticsLock
) {
776 IOLockFree(reserved
->interruptStatisticsLock
);
778 if (reserved
->uvars
&& reserved
->uvars
->userServer
) {
779 reserved
->uvars
->userServer
->serviceFree(this);
781 IODelete(reserved
, ExpansionData
, 1);
784 if (_numInterruptSources
&& _interruptSources
) {
785 for (i
= 0; i
< _numInterruptSources
; i
++) {
786 void * block
= _interruptSourcesPrivate(this)[i
].vectorBlock
;
788 Block_release(block
);
791 IOFree(_interruptSources
,
792 _numInterruptSources
* sizeofAllIOInterruptSource
);
793 _interruptSources
= NULL
;
800 * Attach in service plane
803 IOService::attach( IOService
* provider
)
807 AbsoluteTime deadline
;
808 int waitResult
= THREAD_AWAKENED
;
809 bool wait
, computeDeadline
= true;
812 if (gIOKitDebug
& kIOLogAttach
) {
813 LOG( "%s::attach(%s)\n", getName(),
814 provider
->getName());
820 provider
->lockForArbitration();
821 if (provider
->__state
[0] & kIOServiceInactiveState
) {
824 count
= provider
->getChildCount(gIOServicePlane
);
825 wait
= (count
> (kIOServiceBusyMax
- 4));
827 ok
= attachToParent(provider
, gIOServicePlane
);
829 IOLog("stalling for detach from %s\n", provider
->getName());
830 IOLockLock( gIOServiceBusyLock
);
831 provider
->__state
[1] |= kIOServiceWaitDetachState
;
834 provider
->unlockForArbitration();
836 if (computeDeadline
) {
837 clock_interval_to_deadline(15, kSecondScale
, &deadline
);
838 computeDeadline
= false;
840 assert_wait_deadline((event_t
)&provider
->__provider
, THREAD_UNINT
, deadline
);
841 IOLockUnlock( gIOServiceBusyLock
);
842 waitResult
= thread_block(THREAD_CONTINUE_NULL
);
843 wait
= (waitResult
!= THREAD_TIMED_OUT
);
847 gIOServiceRoot
= this;
848 ok
= attachToParent( getRegistryRoot(), gIOServicePlane
);
851 if (ok
&& !__provider
) {
852 (void) getProvider();
859 IOService::getServiceRoot( void )
861 return gIOServiceRoot
;
865 IOService::detach( IOService
* provider
)
867 IOService
* newProvider
= NULL
;
871 if (gIOKitDebug
& kIOLogAttach
) {
872 LOG("%s::detach(%s)\n", getName(), provider
->getName());
876 IOLockLock(gJobsLock
);
877 if (gIOMatchDeferList
) {
878 auto idx
= gIOMatchDeferList
->getNextIndexOfObject(this, 0);
880 gIOMatchDeferList
->removeObject(idx
);
883 if (IOServicePH::fMatchingDelayed
) {
884 auto idx
= IOServicePH::fMatchingDelayed
->getNextIndexOfObject(this, 0);
886 IOServicePH::fMatchingDelayed
->removeObject(idx
);
889 IOLockUnlock(gJobsLock
);
890 #endif /* NO_KEXTD */
892 lockForArbitration();
894 uint64_t regID1
= provider
->getRegistryEntryID();
895 uint64_t regID2
= getRegistryEntryID();
899 (uintptr_t) (regID1
>> 32),
901 (uintptr_t) (regID2
>> 32));
903 adjParent
= ((busy
= (__state
[1] & kIOServiceBusyStateMask
))
904 && (provider
== getProvider()));
906 detachFromParent( provider
, gIOServicePlane
);
909 newProvider
= getProvider();
910 if (busy
&& (__state
[1] & kIOServiceTermPhase3State
) && (NULL
== newProvider
)) {
911 _adjustBusy( -busy
);
915 if (kIOServiceInactiveState
& __state
[0]) {
916 getMetaClass()->removeInstance(this);
917 IORemoveServicePlatformActions(this);
920 unlockForArbitration();
922 if (newProvider
&& adjParent
) {
923 newProvider
->lockForArbitration();
924 newProvider
->_adjustBusy(1);
925 newProvider
->unlockForArbitration();
928 // check for last client detach from a terminated service
929 if (provider
->lockForArbitration( true )) {
930 if (kIOServiceStartState
& __state
[1]) {
931 provider
->scheduleTerminatePhase2();
934 provider
->_adjustBusy( -1 );
936 if ((provider
->__state
[1] & kIOServiceTermPhase3State
)
937 && (NULL
== provider
->getClient())) {
938 provider
->scheduleFinalize(false);
941 IOLockLock( gIOServiceBusyLock
);
942 if (kIOServiceWaitDetachState
& provider
->__state
[1]) {
943 provider
->__state
[1] &= ~kIOServiceWaitDetachState
;
944 thread_wakeup(&provider
->__provider
);
946 IOLockUnlock( gIOServiceBusyLock
);
948 provider
->unlockForArbitration();
953 * Register instance - publish it for matching
957 IOService::registerService( IOOptionBits options
)
963 enum { kMaxPathLen
= 256 };
964 enum { kMaxChars
= 63 };
966 IORegistryEntry
* parent
= this;
967 IORegistryEntry
* root
= getRegistryRoot();
968 while (parent
&& (parent
!= root
)) {
969 parent
= parent
->getParentEntry( gIOServicePlane
);
972 if (parent
!= root
) {
973 IOLog("%s: not registry member at registerService()\n", getName());
977 // Allow the Platform Expert to adjust this node.
978 if (gIOPlatform
&& (!gIOPlatform
->platformAdjustService(this))) {
982 IOInstallServicePlatformActions(this);
983 IOInstallServiceSleepPlatformActions(this);
985 if ((this != gIOResources
)
986 && (kIOLogRegister
& gIOKitDebug
)) {
987 pathBuf
= (char *) IOMalloc( kMaxPathLen
);
989 IOLog( "Registering: " );
992 if (pathBuf
&& getPath( pathBuf
, &len
, gIOServicePlane
)) {
994 if (len
> kMaxChars
) {
998 if ((skip
= strchr( path
, '/'))) {
1006 IOLog( "%s\n", path
);
1009 IOFree( pathBuf
, kMaxPathLen
);
1013 startMatching( options
);
1017 IOService::startMatching( IOOptionBits options
)
1019 IOService
* provider
;
1020 UInt32 prevBusy
= 0;
1022 bool needWake
= false;
1027 lockForArbitration();
1029 sync
= (options
& kIOServiceSynchronous
)
1030 || ((provider
= getProvider())
1031 && (provider
->__state
[1] & kIOServiceSynchronousState
));
1033 if (options
& kIOServiceAsynchronous
) {
1037 needConfig
= (0 == (__state
[1] & (kIOServiceNeedConfigState
| kIOServiceConfigRunning
)))
1038 && (0 == (__state
[0] & kIOServiceInactiveState
));
1040 __state
[1] |= kIOServiceNeedConfigState
;
1042 // __state[0] &= ~kIOServiceInactiveState;
1044 // if( sync) LOG("OSKernelStackRemaining = %08x @ %s\n",
1045 // OSKernelStackRemaining(), getName());
1048 needWake
= (0 != (kIOServiceSyncPubState
& __state
[1]));
1052 __state
[1] |= kIOServiceSynchronousState
;
1054 __state
[1] &= ~kIOServiceSynchronousState
;
1058 prevBusy
= _adjustBusy( 1 );
1061 unlockForArbitration();
1065 IOLockLock( gIOServiceBusyLock
);
1066 thread_wakeup((event_t
) this /*&__state[1]*/ );
1067 IOLockUnlock( gIOServiceBusyLock
);
1068 } else if (!sync
|| (kIOServiceAsynchronous
& options
)) {
1069 ok
= (NULL
!= _IOServiceJob::startJob( this, kMatchNubJob
, options
));
1072 if ((__state
[1] & kIOServiceNeedConfigState
)) {
1073 doServiceMatch( options
);
1076 lockForArbitration();
1077 IOLockLock( gIOServiceBusyLock
);
1079 waitAgain
= ((prevBusy
< (__state
[1] & kIOServiceBusyStateMask
))
1080 && (0 == (__state
[0] & kIOServiceInactiveState
)));
1083 __state
[1] |= kIOServiceSyncPubState
| kIOServiceBusyWaiterState
;
1085 __state
[1] &= ~kIOServiceSyncPubState
;
1088 unlockForArbitration();
1091 assert_wait((event_t
) this /*&__state[1]*/, THREAD_UNINT
);
1094 IOLockUnlock( gIOServiceBusyLock
);
1096 thread_block(THREAD_CONTINUE_NULL
);
1098 } while (waitAgain
);
1105 IOService::startDeferredMatches(void)
1110 IOLockLock(gJobsLock
);
1111 array
= gIOMatchDeferList
;
1112 gIOMatchDeferList
= NULL
;
1113 IOLockUnlock(gJobsLock
);
1116 IOLog("deferred rematching count %d\n", array
->getCount());
1117 array
->iterateObjects(^bool (OSObject
* obj
)
1119 ((IOService
*)obj
)->startMatching(kIOServiceAsynchronous
);
1124 #endif /* !NO_KEXTD */
1128 IOService::iokitDaemonLaunched(void)
1131 IOServiceTrace(IOSERVICE_KEXTD_READY
, 0, 0, 0, 0);
1132 startDeferredMatches();
1133 getServiceRoot()->adjustBusy(-1);
1134 IOService::publishUserResource(gIOResourceIOKitKey
);
1135 #endif /* !NO_KEXTD */
1139 IOService::catalogNewDrivers( OSOrderedSet
* newTables
)
1141 OSDictionary
* table
;
1143 OSSet
* allSet
= NULL
;
1144 IOService
* service
;
1149 newTables
->retain();
1151 while ((table
= (OSDictionary
*) newTables
->getFirstObject())) {
1153 set
= (OSSet
*) copyExistingServices( table
,
1154 kIOServiceRegisteredState
,
1155 kIOServiceExistingSet
);
1159 count
+= set
->getCount();
1162 allSet
->merge((const OSSet
*) set
);
1170 if (getDebugFlags( table
) & kIOLogMatch
) {
1171 LOG("Matching service count = %ld\n", (long)count
);
1174 newTables
->removeObject(table
);
1178 while ((service
= (IOService
*) allSet
->getAnyObject())) {
1179 service
->startMatching(kIOServiceAsynchronous
);
1180 allSet
->removeObject(service
);
1185 newTables
->release();
1187 return kIOReturnSuccess
;
1191 _IOServiceJob::startJob( IOService
* nub
, int type
,
1192 IOOptionBits options
)
1194 _IOServiceJob
* job
;
1196 job
= new _IOServiceJob
;
1197 if (job
&& !job
->init()) {
1205 job
->options
= options
;
1206 nub
->retain(); // thread will release()
1214 * Called on a registered service to see if it matches
1219 IOService::matchPropertyTable( OSDictionary
* table
, SInt32
* score
)
1221 return matchPropertyTable(table
);
1225 IOService::matchPropertyTable( OSDictionary
* table
)
1231 * Called on a matched service to allocate resources
1232 * before first driver is attached.
1236 IOService::getResources( void )
1238 return kIOReturnSuccess
;
1242 * Client/provider accessors
1246 IOService::getProvider( void ) const
1248 IOService
* self
= (IOService
*) this;
1252 generation
= getRegistryEntryGenerationCount();
1253 if (__providerGeneration
== generation
) {
1257 parent
= (IOService
*) getParentEntry( gIOServicePlane
);
1258 if (parent
== IORegistryEntry::getRegistryRoot()) {
1259 /* root is not an IOService */
1263 self
->__provider
= parent
;
1265 // save the count from before call to getParentEntry()
1266 self
->__providerGeneration
= generation
;
1272 IOService::getWorkLoop() const
1274 IOService
*provider
= getProvider();
1277 return provider
->getWorkLoop();
1284 IOService::getProviderIterator( void ) const
1286 return getParentIterator( gIOServicePlane
);
1290 IOService::getClient( void ) const
1292 return (IOService
*) getChildEntry( gIOServicePlane
);
1296 IOService::getClientIterator( void ) const
1298 return getChildIterator( gIOServicePlane
);
1302 _IOOpenServiceIterator::iterator( OSIterator
* _iter
,
1303 const IOService
* client
,
1304 const IOService
* provider
)
1306 _IOOpenServiceIterator
* inst
;
1312 inst
= new _IOOpenServiceIterator
;
1314 if (inst
&& !inst
->init()) {
1320 inst
->client
= client
;
1321 inst
->provider
= provider
;
1328 _IOOpenServiceIterator::free()
1332 last
->unlockForArbitration();
1338 _IOOpenServiceIterator::getNextObject()
1343 last
->unlockForArbitration();
1346 while ((next
= (IOService
*) iter
->getNextObject())) {
1347 next
->lockForArbitration();
1348 if ((client
&& (next
->isOpen( client
)))
1349 || (provider
&& (provider
->isOpen( next
)))) {
1352 next
->unlockForArbitration();
1361 _IOOpenServiceIterator::isValid()
1363 return iter
->isValid();
1367 _IOOpenServiceIterator::reset()
1370 last
->unlockForArbitration();
1377 IOService::getOpenProviderIterator( void ) const
1379 return _IOOpenServiceIterator::iterator( getProviderIterator(), this, NULL
);
1383 IOService::getOpenClientIterator( void ) const
1385 return _IOOpenServiceIterator::iterator( getClientIterator(), NULL
, this );
1390 IOService::callPlatformFunction( const OSSymbol
* functionName
,
1391 bool waitForFunction
,
1392 void *param1
, void *param2
,
1393 void *param3
, void *param4
)
1395 IOReturn result
= kIOReturnUnsupported
;
1396 IOService
*provider
;
1398 if (functionName
== gIOPlatformQuiesceActionKey
||
1399 functionName
== gIOPlatformActiveActionKey
) {
1401 * Services which register for IOPlatformQuiesceAction / IOPlatformActiveAction
1402 * must consume that event themselves, without passing it up to super/IOService.
1404 if (gEnforceQuiesceSafety
) {
1405 panic("Class %s passed the quiesce/active action to IOService",
1406 getMetaClass()->getClassName());
1410 if (gIOPlatformFunctionHandlerSet
== functionName
) {
1411 const OSSymbol
* functionHandlerName
= (const OSSymbol
*) param1
;
1412 IOService
* target
= (IOService
*) param2
;
1413 bool enable
= (param3
!= NULL
);
1415 if (sCPULatencyFunctionName
[kCpuDelayBusStall
] == functionHandlerName
) {
1416 result
= setLatencyHandler(kCpuDelayBusStall
, target
, enable
);
1418 #if defined(__x86_64__)
1419 else if (sCPULatencyFunctionName
[kCpuDelayInterrupt
] == param1
) {
1420 result
= setLatencyHandler(kCpuDelayInterrupt
, target
, enable
);
1422 #endif /* defined(__x86_64__) */
1425 if ((kIOReturnUnsupported
== result
) && (provider
= getProvider())) {
1426 result
= provider
->callPlatformFunction(functionName
, waitForFunction
,
1427 param1
, param2
, param3
, param4
);
1434 IOService::callPlatformFunction( const char * functionName
,
1435 bool waitForFunction
,
1436 void *param1
, void *param2
,
1437 void *param3
, void *param4
)
1439 IOReturn result
= kIOReturnNoMemory
;
1440 const OSSymbol
*functionSymbol
= OSSymbol::withCString(functionName
);
1442 if (functionSymbol
!= NULL
) {
1443 result
= callPlatformFunction(functionSymbol
, waitForFunction
,
1444 param1
, param2
, param3
, param4
);
1445 functionSymbol
->release();
1453 * Accessors for global services
1457 IOService::getPlatform( void )
1462 class IOPMrootDomain
*
1463 IOService::getPMRootDomain( void )
1465 return gIOPMRootDomain
;
1469 IOService::getResourceService( void )
1471 return gIOResources
;
1475 IOService::setPlatform( IOPlatformExpert
* platform
)
1477 gIOPlatform
= platform
;
1478 gIOResources
->attachToParent( gIOServiceRoot
, gIOServicePlane
);
1479 gIOUserResources
->attachToParent( gIOServiceRoot
, gIOServicePlane
);
1481 static const char * keys
[kCpuNumDelayTypes
] = {
1482 kIOPlatformMaxBusDelay
,
1483 #if defined(__x86_64__)
1484 kIOPlatformMaxInterruptDelay
1485 #endif /* defined(__x86_64__) */
1487 const OSObject
* objs
[2];
1491 for (idx
= 0; idx
< kCpuNumDelayTypes
; idx
++) {
1492 objs
[0] = sCPULatencySet
[idx
];
1493 objs
[1] = sCPULatencyHolder
[idx
];
1494 array
= OSArray::withObjects(objs
, 2);
1498 platform
->setProperty(keys
[idx
], array
);
1504 IOService::setPMRootDomain( class IOPMrootDomain
* rootDomain
)
1506 gIOPMRootDomain
= rootDomain
;
1507 publishResource(gIOResourceIOKitKey
);
1508 IOServicePH::init(rootDomain
);
1516 IOService::lockForArbitration( bool isSuccessRequired
)
1520 ArbitrationLockQueueElement
* element
;
1521 ArbitrationLockQueueElement
* active
;
1522 ArbitrationLockQueueElement
* waiting
;
1524 enum { kPutOnFreeQueue
, kPutOnActiveQueue
, kPutOnWaitingQueue
} action
;
1526 // lock global access
1527 IOTakeLock( gArbitrationLockQueueLock
);
1529 // obtain an unused queue element
1530 if (!queue_empty( &gArbitrationLockQueueFree
)) {
1531 queue_remove_first( &gArbitrationLockQueueFree
,
1533 ArbitrationLockQueueElement
*,
1536 element
= IONew( ArbitrationLockQueueElement
, 1 );
1540 // prepare the queue element
1541 element
->thread
= IOThreadSelf();
1542 element
->service
= this;
1544 element
->required
= isSuccessRequired
;
1545 element
->aborted
= false;
1547 // determine whether this object is already locked (ie. on active queue)
1549 queue_iterate( &gArbitrationLockQueueActive
,
1551 ArbitrationLockQueueElement
*,
1554 if (active
->service
== element
->service
) {
1560 if (found
) { // this object is already locked
1561 // determine whether it is the same or a different thread trying to lock
1562 if (active
->thread
!= element
->thread
) { // it is a different thread
1563 ArbitrationLockQueueElement
* victim
= NULL
;
1565 // before placing this new thread on the waiting queue, we look for
1566 // a deadlock cycle...
1569 // determine whether the active thread holding the object we
1570 // want is waiting for another object to be unlocked
1572 queue_iterate( &gArbitrationLockQueueWaiting
,
1574 ArbitrationLockQueueElement
*,
1577 if (waiting
->thread
== active
->thread
) {
1578 assert( false == waiting
->aborted
);
1584 if (found
) { // yes, active thread waiting for another object
1585 // this may be a candidate for rejection if the required
1586 // flag is not set, should we detect a deadlock later on
1587 if (false == waiting
->required
) {
1591 // find the thread that is holding this other object, that
1592 // is blocking the active thread from proceeding (fun :-)
1594 queue_iterate( &gArbitrationLockQueueActive
,
1595 active
, // (reuse active queue element)
1596 ArbitrationLockQueueElement
*,
1599 if (active
->service
== waiting
->service
) {
1605 // someone must be holding it or it wouldn't be waiting
1608 if (active
->thread
== element
->thread
) {
1609 // doh, it's waiting for the thread that originated
1610 // this whole lock (ie. current thread) -> deadlock
1611 if (false == element
->required
) { // willing to fail?
1612 // the originating thread doesn't have the required
1613 // flag, so it can fail
1614 success
= false; // (fail originating lock request)
1615 break; // (out of while)
1616 } else { // originating thread is not willing to fail
1617 // see if we came across a waiting thread that did
1618 // not have the 'required' flag set: we'll fail it
1620 // we do have a willing victim, fail it's lock
1621 victim
->aborted
= true;
1623 // take the victim off the waiting queue
1624 queue_remove( &gArbitrationLockQueueWaiting
,
1626 ArbitrationLockQueueElement
*,
1630 IOLockWakeup( gArbitrationLockQueueLock
,
1632 /* one thread */ true );
1634 // allow this thread to proceed (ie. wait)
1635 success
= true; // (put request on wait queue)
1636 break; // (out of while)
1638 // all the waiting threads we came across in
1639 // finding this loop had the 'required' flag
1640 // set, so we've got a deadlock we can't avoid
1641 panic("I/O Kit: Unrecoverable deadlock.");
1645 // repeat while loop, redefining active thread to be the
1646 // thread holding "this other object" (see above), and
1647 // looking for threads waiting on it; note the active
1648 // variable points to "this other object" already... so
1649 // there nothing to do in this else clause.
1651 } else { // no, active thread is not waiting for another object
1652 success
= true; // (put request on wait queue)
1653 break; // (out of while)
1657 if (success
) { // put the request on the waiting queue?
1658 kern_return_t wait_result
;
1660 // place this thread on the waiting queue and put it to sleep;
1661 // we place it at the tail of the queue...
1662 queue_enter( &gArbitrationLockQueueWaiting
,
1664 ArbitrationLockQueueElement
*,
1667 // declare that this thread will wait for a given event
1668 restart_sleep
: wait_result
= assert_wait( element
,
1669 element
->required
? THREAD_UNINT
1670 : THREAD_INTERRUPTIBLE
);
1672 // unlock global access
1673 IOUnlock( gArbitrationLockQueueLock
);
1675 // put thread to sleep, waiting for our event to fire...
1676 if (wait_result
== THREAD_WAITING
) {
1677 wait_result
= thread_block(THREAD_CONTINUE_NULL
);
1681 // ...and we've been woken up; we might be in one of two states:
1682 // (a) we've been aborted and our queue element is not on
1683 // any of the three queues, but is floating around
1684 // (b) we're allowed to proceed with the lock and we have
1685 // already been moved from the waiting queue to the
1687 // ...plus a 3rd state, should the thread have been interrupted:
1688 // (c) we're still on the waiting queue
1690 // determine whether we were interrupted out of our sleep
1691 if (THREAD_INTERRUPTED
== wait_result
) {
1692 // re-lock global access
1693 IOTakeLock( gArbitrationLockQueueLock
);
1695 // determine whether we're still on the waiting queue
1697 queue_iterate( &gArbitrationLockQueueWaiting
,
1698 waiting
, // (reuse waiting queue element)
1699 ArbitrationLockQueueElement
*,
1702 if (waiting
== element
) {
1708 if (found
) { // yes, we're still on the waiting queue
1709 // determine whether we're willing to fail
1710 if (false == element
->required
) {
1711 // mark us as aborted
1712 element
->aborted
= true;
1714 // take us off the waiting queue
1715 queue_remove( &gArbitrationLockQueueWaiting
,
1717 ArbitrationLockQueueElement
*,
1719 } else { // we are not willing to fail
1720 // ignore interruption, go back to sleep
1725 // unlock global access
1726 IOUnlock( gArbitrationLockQueueLock
);
1728 // proceed as though this were a normal wake up
1729 wait_result
= THREAD_AWAKENED
;
1732 assert( THREAD_AWAKENED
== wait_result
);
1734 // determine whether we've been aborted while we were asleep
1735 if (element
->aborted
) {
1736 assert( false == element
->required
);
1738 // re-lock global access
1739 IOTakeLock( gArbitrationLockQueueLock
);
1741 action
= kPutOnFreeQueue
;
1743 } else { // we weren't aborted, so we must be ready to go :-)
1744 // we've already been moved from waiting to active queue
1747 } else { // the lock request is to be failed
1748 // return unused queue element to queue
1749 action
= kPutOnFreeQueue
;
1751 } else { // it is the same thread, recursive access is allowed
1752 // add one level of recursion
1755 // return unused queue element to queue
1756 action
= kPutOnFreeQueue
;
1759 } else { // this object is not already locked, so let this thread through
1760 action
= kPutOnActiveQueue
;
1764 // put the new element on a queue
1765 if (kPutOnActiveQueue
== action
) {
1766 queue_enter( &gArbitrationLockQueueActive
,
1768 ArbitrationLockQueueElement
*,
1770 } else if (kPutOnFreeQueue
== action
) {
1771 queue_enter( &gArbitrationLockQueueFree
,
1773 ArbitrationLockQueueElement
*,
1776 assert( 0 ); // kPutOnWaitingQueue never occurs, handled specially above
1779 // unlock global access
1780 IOUnlock( gArbitrationLockQueueLock
);
1786 IOService::unlockForArbitration( void )
1789 ArbitrationLockQueueElement
* element
;
1791 // lock global access
1792 IOTakeLock( gArbitrationLockQueueLock
);
1794 // find the lock element for this object (ie. on active queue)
1796 queue_iterate( &gArbitrationLockQueueActive
,
1798 ArbitrationLockQueueElement
*,
1801 if (element
->service
== this) {
1809 // determine whether the lock has been taken recursively
1810 if (element
->count
> 1) {
1811 // undo one level of recursion
1814 // remove it from the active queue
1815 queue_remove( &gArbitrationLockQueueActive
,
1817 ArbitrationLockQueueElement
*,
1820 // put it on the free queue
1821 queue_enter( &gArbitrationLockQueueFree
,
1823 ArbitrationLockQueueElement
*,
1826 // determine whether a thread is waiting for object (head to tail scan)
1828 queue_iterate( &gArbitrationLockQueueWaiting
,
1830 ArbitrationLockQueueElement
*,
1833 if (element
->service
== this) {
1839 if (found
) { // we found an interested thread on waiting queue
1840 // remove it from the waiting queue
1841 queue_remove( &gArbitrationLockQueueWaiting
,
1843 ArbitrationLockQueueElement
*,
1846 // put it on the active queue
1847 queue_enter( &gArbitrationLockQueueActive
,
1849 ArbitrationLockQueueElement
*,
1852 // wake the waiting thread
1853 IOLockWakeup( gArbitrationLockQueueLock
,
1855 /* one thread */ true );
1859 // unlock global access
1860 IOUnlock( gArbitrationLockQueueLock
);
1864 IOService::isLockedForArbitration(IOService
* service
)
1866 #if DEBUG_NOTIFIER_LOCKED
1868 ArbitrationLockQueueElement
* active
;
1870 // lock global access
1871 IOLockLock(gArbitrationLockQueueLock
);
1873 // determine whether this object is already locked (ie. on active queue)
1875 queue_iterate(&gArbitrationLockQueueActive
,
1877 ArbitrationLockQueueElement
*,
1880 if ((active
->thread
== IOThreadSelf())
1881 && (!service
|| (active
->service
== service
))) {
1883 count
+= active
->count
;
1887 IOLockUnlock(gArbitrationLockQueueLock
);
1891 #else /* DEBUG_NOTIFIER_LOCKED */
1895 #endif /* DEBUG_NOTIFIER_LOCKED */
1899 IOService::applyToProviders( IOServiceApplierFunction applier
,
1902 applyToParents((IORegistryEntryApplierFunction
) applier
,
1903 context
, gIOServicePlane
);
1907 IOService::applyToClients( IOServiceApplierFunction applier
,
1910 applyToChildren((IORegistryEntryApplierFunction
) applier
,
1911 context
, gIOServicePlane
);
1916 IOServiceApplierToBlock(IOService
* next
, void * context
)
1918 IOServiceApplierBlock block
= (IOServiceApplierBlock
) context
;
1923 IOService::applyToProviders(IOServiceApplierBlock applier
)
1925 applyToProviders(&IOServiceApplierToBlock
, applier
);
1929 IOService::applyToClients(IOServiceApplierBlock applier
)
1931 applyToClients(&IOServiceApplierToBlock
, applier
);
1939 // send a message to a client or interested party of this service
1941 IOService::messageClient( UInt32 type
, OSObject
* client
,
1942 void * argument
, vm_size_t argSize
)
1945 IOService
* service
;
1946 _IOServiceInterestNotifier
* notify
;
1948 if ((service
= OSDynamicCast( IOService
, client
))) {
1949 ret
= service
->message( type
, this, argument
);
1950 } else if ((notify
= OSDynamicCast( _IOServiceInterestNotifier
, client
))) {
1951 _IOServiceNotifierInvocation invocation
;
1954 invocation
.thread
= current_thread();
1957 willNotify
= (0 != (kIOServiceNotifyEnable
& notify
->state
));
1960 queue_enter( ¬ify
->handlerInvocations
, &invocation
,
1961 _IOServiceNotifierInvocation
*, link
);
1966 ret
= (*notify
->handler
)( notify
->target
, notify
->ref
,
1967 type
, this, argument
, argSize
);
1970 queue_remove( ¬ify
->handlerInvocations
, &invocation
,
1971 _IOServiceNotifierInvocation
*, link
);
1972 if (kIOServiceNotifyWaiter
& notify
->state
) {
1973 notify
->state
&= ~kIOServiceNotifyWaiter
;
1974 WAKEUPNOTIFY( notify
);
1978 ret
= kIOReturnSuccess
;
1981 ret
= kIOReturnBadArgument
;
1988 applyToInterestNotifiers(const IORegistryEntry
*target
,
1989 const OSSymbol
* typeOfInterest
,
1990 OSObjectApplierFunction applier
,
1993 OSArray
* copyArray
= NULL
;
1998 prop
= target
->copyProperty(typeOfInterest
);
1999 IOCommand
*notifyList
= OSDynamicCast(IOCommand
, prop
);
2002 copyArray
= OSArray::withCapacity(1);
2004 // iterate over queue, entry is set to each element in the list
2005 iterqueue(¬ifyList
->fCommandChain
, entry
) {
2006 _IOServiceInterestNotifier
* notify
;
2008 queue_element(entry
, notify
, _IOServiceInterestNotifier
*, chain
);
2009 copyArray
->setObject(notify
);
2018 for (index
= 0; (next
= copyArray
->getObject( index
)); index
++) {
2019 (*applier
)(next
, context
);
2021 copyArray
->release();
2024 OSSafeReleaseNULL(prop
);
2028 IOService::applyToInterested( const OSSymbol
* typeOfInterest
,
2029 OSObjectApplierFunction applier
,
2032 if (gIOGeneralInterest
== typeOfInterest
) {
2033 applyToClients((IOServiceApplierFunction
) applier
, context
);
2035 applyToInterestNotifiers(this, typeOfInterest
, applier
, context
);
2038 struct MessageClientsContext
{
2039 IOService
* service
;
2047 messageClientsApplier( OSObject
* object
, void * ctx
)
2050 MessageClientsContext
* context
= (MessageClientsContext
*) ctx
;
2052 ret
= context
->service
->messageClient( context
->type
,
2053 object
, context
->argument
, context
->argSize
);
2054 if (kIOReturnSuccess
!= ret
) {
2059 // send a message to all clients
2061 IOService::messageClients( UInt32 type
,
2062 void * argument
, vm_size_t argSize
)
2064 MessageClientsContext context
;
2066 context
.service
= this;
2067 context
.type
= type
;
2068 context
.argument
= argument
;
2069 context
.argSize
= argSize
;
2070 context
.ret
= kIOReturnSuccess
;
2072 applyToInterested( gIOGeneralInterest
,
2073 &messageClientsApplier
, &context
);
2079 IOService::acknowledgeNotification( IONotificationRef notification
,
2080 IOOptionBits response
)
2082 return kIOReturnUnsupported
;
2086 IOService::registerInterest( const OSSymbol
* typeOfInterest
,
2087 IOServiceInterestHandler handler
, void * target
, void * ref
)
2089 _IOServiceInterestNotifier
* notify
= NULL
;
2090 IOReturn rc
= kIOReturnError
;
2092 notify
= new _IOServiceInterestNotifier
;
2097 if (notify
->init()) {
2098 rc
= registerInterestForNotifier(notify
, typeOfInterest
,
2099 handler
, target
, ref
);
2102 if (rc
!= kIOReturnSuccess
) {
2113 IOServiceInterestHandlerToBlock( void * target __unused
, void * refCon
,
2114 UInt32 messageType
, IOService
* provider
,
2115 void * messageArgument
, vm_size_t argSize
)
2117 return ((IOServiceInterestHandlerBlock
) refCon
)(messageType
, provider
, messageArgument
, argSize
);
2121 IOService::registerInterest(const OSSymbol
* typeOfInterest
,
2122 IOServiceInterestHandlerBlock handler
)
2124 IONotifier
* notify
;
2127 block
= Block_copy(handler
);
2132 notify
= registerInterest(typeOfInterest
, &IOServiceInterestHandlerToBlock
, NULL
, block
);
2135 Block_release(block
);
2142 IOService::registerInterestForNotifier( IONotifier
*svcNotify
, const OSSymbol
* typeOfInterest
,
2143 IOServiceInterestHandler handler
, void * target
, void * ref
)
2145 IOReturn rc
= kIOReturnSuccess
;
2146 _IOServiceInterestNotifier
*notify
= NULL
;
2148 if (!svcNotify
|| !(notify
= OSDynamicCast(_IOServiceInterestNotifier
, svcNotify
))) {
2149 return kIOReturnBadArgument
;
2152 notify
->handler
= handler
;
2153 notify
->target
= target
;
2156 if ((typeOfInterest
!= gIOGeneralInterest
)
2157 && (typeOfInterest
!= gIOBusyInterest
)
2158 && (typeOfInterest
!= gIOAppPowerStateInterest
)
2159 && (typeOfInterest
!= gIOConsoleSecurityInterest
)
2160 && (typeOfInterest
!= gIOPriorityPowerStateInterest
)) {
2161 return kIOReturnBadArgument
;
2164 lockForArbitration();
2165 if (0 == (__state
[0] & kIOServiceInactiveState
)) {
2166 notify
->state
= kIOServiceNotifyEnable
;
2172 // Get the head of the notifier linked list
2173 IOCommand
* notifyList
;
2174 OSObject
* obj
= copyProperty( typeOfInterest
);
2175 if (!(notifyList
= OSDynamicCast(IOCommand
, obj
))) {
2176 notifyList
= OSTypeAlloc(IOCommand
);
2179 bool ok
= setProperty( typeOfInterest
, notifyList
);
2180 notifyList
->release();
2191 enqueue(¬ifyList
->fCommandChain
, ¬ify
->chain
);
2192 notify
->retain(); // ref'ed while in list
2197 rc
= kIOReturnNotReady
;
2199 unlockForArbitration();
2205 cleanInterestList( OSObject
* head
)
2207 IOCommand
*notifyHead
= OSDynamicCast(IOCommand
, head
);
2213 while (queue_entry_t entry
= dequeue(¬ifyHead
->fCommandChain
)) {
2214 queue_next(entry
) = queue_prev(entry
) = NULL
;
2216 _IOServiceInterestNotifier
* notify
;
2218 queue_element(entry
, notify
, _IOServiceInterestNotifier
*, chain
);
2225 IOService::unregisterAllInterest( void )
2229 prop
= copyProperty(gIOGeneralInterest
);
2230 cleanInterestList(prop
);
2231 OSSafeReleaseNULL(prop
);
2233 prop
= copyProperty(gIOBusyInterest
);
2234 cleanInterestList(prop
);
2235 OSSafeReleaseNULL(prop
);
2237 prop
= copyProperty(gIOAppPowerStateInterest
);
2238 cleanInterestList(prop
);
2239 OSSafeReleaseNULL(prop
);
2241 prop
= copyProperty(gIOPriorityPowerStateInterest
);
2242 cleanInterestList(prop
);
2243 OSSafeReleaseNULL(prop
);
2245 prop
= copyProperty(gIOConsoleSecurityInterest
);
2246 cleanInterestList(prop
);
2247 OSSafeReleaseNULL(prop
);
2251 * _IOServiceInterestNotifier
2254 // wait for all threads, other than the current one,
2255 // to exit the handler
2258 _IOServiceInterestNotifier::wait()
2260 _IOServiceNotifierInvocation
* next
;
2265 queue_iterate( &handlerInvocations
, next
,
2266 _IOServiceNotifierInvocation
*, link
) {
2267 if (next
->thread
!= current_thread()) {
2273 state
|= kIOServiceNotifyWaiter
;
2280 _IOServiceInterestNotifier::free()
2282 assert( queue_empty( &handlerInvocations
));
2284 if (handler
== &IOServiceInterestHandlerToBlock
) {
2292 _IOServiceInterestNotifier::remove()
2296 if (queue_next( &chain
)) {
2298 queue_next( &chain
) = queue_prev( &chain
) = NULL
;
2302 state
&= ~kIOServiceNotifyEnable
;
2312 _IOServiceInterestNotifier::disable()
2318 ret
= (0 != (kIOServiceNotifyEnable
& state
));
2319 state
&= ~kIOServiceNotifyEnable
;
2330 _IOServiceInterestNotifier::enable( bool was
)
2334 state
|= kIOServiceNotifyEnable
;
2336 state
&= ~kIOServiceNotifyEnable
;
2342 _IOServiceInterestNotifier::init()
2344 queue_init( &handlerInvocations
);
2345 return OSObject::init();
2347 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2353 #define tailQ(o) setObject(o)
2354 #define headQ(o) setObject(0, o)
2355 #define TLOG(fmt, args...) { if(kIOLogYield & gIOKitDebug) { IOLog("[%llx] ", thread_tid(current_thread())); IOLog(fmt, ## args); }}
2358 _workLoopAction( IOWorkLoop::Action action
,
2359 IOService
* service
,
2360 void * p0
= NULL
, void * p1
= NULL
,
2361 void * p2
= NULL
, void * p3
= NULL
)
2365 if ((wl
= service
->getWorkLoop())) {
2367 wl
->runAction( action
, service
, p0
, p1
, p2
, p3
);
2370 (*action
)( service
, p0
, p1
, p2
, p3
);
2375 IOService::requestTerminate( IOService
* provider
, IOOptionBits options
)
2379 // if its our only provider
2380 ok
= isParent( provider
, gIOServicePlane
, true);
2384 provider
->terminateClient( this, options
| kIOServiceRecursing
);
2385 ok
= (0 != (kIOServiceInactiveState
& __state
[0]));
2393 IOService::terminatePhase1( IOOptionBits options
)
2397 IOService
* rematchProvider
;
2399 OSArray
* makeInactive
;
2400 OSArray
* waitingInactive
;
2401 IOOptionBits callerOptions
;
2402 int waitResult
= THREAD_AWAKENED
;
2406 bool startPhase2
= false;
2408 TLOG("%s[0x%qx]::terminatePhase1(%08llx)\n", getName(), getRegistryEntryID(), (long long)options
);
2410 callerOptions
= options
;
2411 rematchProvider
= NULL
;
2412 uint64_t regID
= getRegistryEntryID();
2414 IOSERVICE_TERMINATE_PHASE1
,
2416 (uintptr_t) (regID
>> 32),
2418 (uintptr_t) options
);
2421 if (options
& kIOServiceRecursing
) {
2422 lockForArbitration();
2423 if (0 == (kIOServiceInactiveState
& __state
[0])) {
2424 __state
[0] |= kIOServiceInactiveState
;
2425 __state
[1] |= kIOServiceRecursing
| kIOServiceTermPhase1State
;
2427 unlockForArbitration();
2433 makeInactive
= OSArray::withCapacity( 16 );
2434 waitingInactive
= OSArray::withCapacity( 16 );
2435 if (!makeInactive
|| !waitingInactive
) {
2443 didInactive
= victim
->lockForArbitration( true );
2445 uint64_t regID1
= victim
->getRegistryEntryID();
2446 IOServiceTrace(IOSERVICE_TERM_SET_INACTIVE
,
2448 (uintptr_t) (regID1
>> 32),
2449 (uintptr_t) victim
->__state
[1],
2452 enum { kRP1
= kIOServiceRecursing
| kIOServiceTermPhase1State
};
2453 didInactive
= (kRP1
== (victim
->__state
[1] & kRP1
))
2454 || (0 == (victim
->__state
[0] & kIOServiceInactiveState
));
2457 // a multiply attached IOService can be visited twice
2458 if (-1U == waitingInactive
->getNextIndexOfObject(victim
, 0)) {
2460 IOLockLock(gIOServiceBusyLock
);
2461 wait
= (victim
->__state
[1] & kIOServiceTermPhase1State
);
2463 TLOG("%s[0x%qx]::waitPhase1(%s[0x%qx])\n",
2464 getName(), getRegistryEntryID(), victim
->getName(), victim
->getRegistryEntryID());
2465 victim
->__state
[1] |= kIOServiceTerm1WaiterState
;
2466 victim
->unlockForArbitration();
2467 assert_wait((event_t
)&victim
->__state
[1], THREAD_UNINT
);
2469 IOLockUnlock(gIOServiceBusyLock
);
2471 waitResult
= thread_block(THREAD_CONTINUE_NULL
);
2472 TLOG("%s[0x%qx]::did waitPhase1(%s[0x%qx])\n",
2473 getName(), getRegistryEntryID(), victim
->getName(), victim
->getRegistryEntryID());
2474 victim
->lockForArbitration();
2476 }while (wait
&& (waitResult
!= THREAD_TIMED_OUT
));
2479 victim
->__state
[0] |= kIOServiceInactiveState
;
2480 victim
->__state
[0] &= ~(kIOServiceRegisteredState
| kIOServiceMatchedState
2481 | kIOServiceFirstPublishState
| kIOServiceFirstMatchState
);
2482 victim
->__state
[1] &= ~kIOServiceRecursing
;
2483 victim
->__state
[1] |= kIOServiceTermPhase1State
;
2484 waitingInactive
->headQ(victim
);
2485 if (victim
== this) {
2486 if (kIOServiceTerminateNeedWillTerminate
& options
) {
2487 victim
->__state
[1] |= kIOServiceNeedWillTerminate
;
2490 victim
->_adjustBusy( 1 );
2492 if ((options
& kIOServiceTerminateWithRematch
) && (victim
== this)) {
2494 OSObject
* rematchProps
;
2498 rematchProvider
= getProvider();
2499 if (rematchProvider
) {
2500 obj
= rematchProvider
->copyProperty(gIORematchCountKey
);
2501 num
= OSDynamicCast(OSNumber
, obj
);
2504 count
= num
->unsigned32BitValue();
2507 num
= OSNumber::withNumber(count
, 32);
2508 rematchProvider
->setProperty(gIORematchCountKey
, num
);
2509 rematchProps
= copyProperty(gIOMatchedPersonalityKey
);
2510 rematchProvider
->setProperty(gIORematchPersonalityKey
, rematchProps
);
2511 OSSafeReleaseNULL(num
);
2512 OSSafeReleaseNULL(rematchProps
);
2513 OSSafeReleaseNULL(obj
);
2517 victim
->unlockForArbitration();
2519 if (victim
== this) {
2520 options
&= ~kIOServiceTerminateWithRematch
;
2521 startPhase2
= didInactive
;
2524 OSArray
* notifiers
;
2525 notifiers
= victim
->copyNotifiers(gIOTerminatedNotification
, 0, 0xffffffff);
2526 victim
->invokeNotifiers(¬ifiers
);
2528 IOUserClient::destroyUserReferences( victim
);
2530 iter
= victim
->getClientIterator();
2532 while ((client
= (IOService
*) iter
->getNextObject())) {
2533 TLOG("%s[0x%qx]::requestTerminate(%s[0x%qx], %08llx)\n",
2534 client
->getName(), client
->getRegistryEntryID(),
2535 victim
->getName(), victim
->getRegistryEntryID(), (long long)options
);
2536 ok
= client
->requestTerminate( victim
, options
);
2537 TLOG("%s[0x%qx]::requestTerminate(%s[0x%qx], ok = %d)\n",
2538 client
->getName(), client
->getRegistryEntryID(),
2539 victim
->getName(), victim
->getRegistryEntryID(), ok
);
2541 uint64_t regID1
= client
->getRegistryEntryID();
2542 uint64_t regID2
= victim
->getRegistryEntryID();
2544 (ok
? IOSERVICE_TERMINATE_REQUEST_OK
2545 : IOSERVICE_TERMINATE_REQUEST_FAIL
),
2547 (uintptr_t) (regID1
>> 32),
2549 (uintptr_t) (regID2
>> 32));
2552 makeInactive
->setObject( client
);
2559 victim
= (IOService
*) makeInactive
->getObject(0);
2562 makeInactive
->removeObject(0);
2565 makeInactive
->release();
2567 while ((victim
= (IOService
*) waitingInactive
->getObject(0))) {
2569 waitingInactive
->removeObject(0);
2571 victim
->lockForArbitration();
2572 victim
->__state
[1] &= ~kIOServiceTermPhase1State
;
2573 if (kIOServiceTerm1WaiterState
& victim
->__state
[1]) {
2574 victim
->__state
[1] &= ~kIOServiceTerm1WaiterState
;
2575 TLOG("%s[0x%qx]::wakePhase1\n", victim
->getName(), victim
->getRegistryEntryID());
2576 IOLockLock( gIOServiceBusyLock
);
2577 thread_wakeup((event_t
) &victim
->__state
[1]);
2578 IOLockUnlock( gIOServiceBusyLock
);
2580 victim
->unlockForArbitration();
2583 waitingInactive
->release();
2587 lockForArbitration();
2588 scheduleTerminatePhase2(options
);
2589 unlockForArbitration();
2593 if (rematchProvider
) {
2594 DKLOG(DKS
" rematching after dext crash\n", DKN(rematchProvider
));
2595 rematchProvider
->registerService();
2602 IOService::setTerminateDefer(IOService
* provider
, bool defer
)
2604 lockForArbitration();
2606 __state
[1] |= kIOServiceStartState
;
2608 __state
[1] &= ~kIOServiceStartState
;
2610 unlockForArbitration();
2612 if (provider
&& !defer
) {
2613 provider
->lockForArbitration();
2614 provider
->scheduleTerminatePhase2();
2615 provider
->unlockForArbitration();
2619 // Must call this while holding gJobsLock
2621 IOService::waitToBecomeTerminateThread(void)
2623 IOLockAssert(gJobsLock
, kIOLockAssertOwned
);
2626 wait
= (gIOTerminateThread
!= THREAD_NULL
);
2628 IOLockSleep(gJobsLock
, &gIOTerminateThread
, THREAD_UNINT
);
2631 gIOTerminateThread
= current_thread();
2634 // call with lockForArbitration
2636 IOService::scheduleTerminatePhase2( IOOptionBits options
)
2638 AbsoluteTime deadline
;
2640 int waitResult
= THREAD_AWAKENED
;
2641 bool wait
= false, haveDeadline
= false;
2643 if (!(__state
[0] & kIOServiceInactiveState
)) {
2647 regID1
= getRegistryEntryID();
2649 IOSERVICE_TERM_SCHED_PHASE2
,
2651 (uintptr_t) (regID1
>> 32),
2652 (uintptr_t) __state
[1],
2653 (uintptr_t) options
);
2655 if (__state
[1] & kIOServiceTermPhase1State
) {
2660 unlockForArbitration();
2661 options
|= kIOServiceRequired
;
2662 IOLockLock( gJobsLock
);
2664 if ((options
& kIOServiceSynchronous
)
2665 && (current_thread() != gIOTerminateThread
)) {
2666 waitToBecomeTerminateThread();
2667 gIOTerminatePhase2List
->setObject( this );
2671 while (gIOTerminateWork
) {
2672 terminateWorker( options
);
2674 wait
= (0 != (__state
[1] & kIOServiceBusyStateMask
));
2676 /* wait for the victim to go non-busy */
2677 if (!haveDeadline
) {
2678 clock_interval_to_deadline( 15, kSecondScale
, &deadline
);
2679 haveDeadline
= true;
2681 /* let others do work while we wait */
2682 gIOTerminateThread
= NULL
;
2683 IOLockWakeup( gJobsLock
, (event_t
) &gIOTerminateThread
, /* one-thread */ false);
2684 waitResult
= IOLockSleepDeadline( gJobsLock
, &gIOTerminateWork
,
2685 deadline
, THREAD_UNINT
);
2686 if (__improbable(waitResult
== THREAD_TIMED_OUT
)) {
2687 IOLog("%s[0x%qx]::terminate(kIOServiceSynchronous): THREAD_TIMED_OUT. "
2688 "Attempting to auto-resolve your deadlock. PLEASE FIX!\n", getName(), getRegistryEntryID());
2690 waitToBecomeTerminateThread();
2692 } while (gIOTerminateWork
|| (wait
&& (waitResult
!= THREAD_TIMED_OUT
)));
2694 gIOTerminateThread
= NULL
;
2695 IOLockWakeup( gJobsLock
, (event_t
) &gIOTerminateThread
, /* one-thread */ false);
2697 // ! kIOServiceSynchronous
2699 gIOTerminatePhase2List
->setObject( this );
2700 if (0 == gIOTerminateWork
++) {
2701 assert(gIOTerminateWorkerThread
);
2702 IOLockWakeup(gJobsLock
, (event_t
)&gIOTerminateWork
, /* one-thread */ false );
2706 IOLockUnlock( gJobsLock
);
2707 lockForArbitration();
2711 __attribute__((__noreturn__
))
2713 IOService::terminateThread( void * arg
, wait_result_t waitResult
)
2715 // IOLockSleep re-acquires the lock on wakeup, so we only need to do this once
2716 IOLockLock(gJobsLock
);
2718 if (gIOTerminateThread
!= gIOTerminateWorkerThread
) {
2719 waitToBecomeTerminateThread();
2722 while (gIOTerminateWork
) {
2723 terminateWorker((IOOptionBits
)(uintptr_t)arg
);
2726 gIOTerminateThread
= NULL
;
2727 IOLockWakeup( gJobsLock
, (event_t
) &gIOTerminateThread
, /* one-thread */ false);
2728 IOLockSleep(gJobsLock
, &gIOTerminateWork
, THREAD_UNINT
);
2733 IOService::scheduleStop( IOService
* provider
)
2735 uint64_t regID1
= getRegistryEntryID();
2736 uint64_t regID2
= provider
->getRegistryEntryID();
2738 TLOG("%s[0x%qx]::scheduleStop(%s[0x%qx])\n", getName(), regID1
, provider
->getName(), regID2
);
2740 IOSERVICE_TERMINATE_SCHEDULE_STOP
,
2742 (uintptr_t) (regID1
>> 32),
2744 (uintptr_t) (regID2
>> 32));
2746 IOLockLock( gJobsLock
);
2747 gIOStopList
->tailQ( this );
2748 gIOStopProviderList
->tailQ( provider
);
2750 if (0 == gIOTerminateWork
++) {
2751 assert(gIOTerminateWorkerThread
);
2752 IOLockWakeup(gJobsLock
, (event_t
)&gIOTerminateWork
, /* one-thread */ false );
2755 IOLockUnlock( gJobsLock
);
2759 IOService::scheduleFinalize(bool now
)
2761 uint64_t regID1
= getRegistryEntryID();
2763 TLOG("%s[0x%qx]::scheduleFinalize\n", getName(), regID1
);
2765 IOSERVICE_TERMINATE_SCHEDULE_FINALIZE
,
2767 (uintptr_t) (regID1
>> 32),
2770 if (now
|| IOUserClient::finalizeUserReferences(this)) {
2771 IOLockLock( gJobsLock
);
2772 gIOFinalizeList
->tailQ(this);
2773 if (0 == gIOTerminateWork
++) {
2774 assert(gIOTerminateWorkerThread
);
2775 IOLockWakeup(gJobsLock
, (event_t
)&gIOTerminateWork
, /* one-thread */ false );
2777 IOLockUnlock( gJobsLock
);
2782 IOService::willTerminate( IOService
* provider
, IOOptionBits options
)
2784 if (reserved
->uvars
) {
2785 IOUserServer::serviceWillTerminate(this, provider
, options
);
2791 IOService::didTerminate( IOService
* provider
, IOOptionBits options
, bool * defer
)
2793 if (reserved
->uvars
) {
2794 IOUserServer::serviceDidTerminate(this, provider
, options
, defer
);
2797 if (false == *defer
) {
2798 if (lockForArbitration( true )) {
2799 if (false == provider
->handleIsOpen( this )) {
2800 scheduleStop( provider
);
2804 message( kIOMessageServiceIsRequestingClose
, provider
, (void *)(uintptr_t) options
);
2805 if (false == provider
->handleIsOpen( this )) {
2806 scheduleStop( provider
);
2810 unlockForArbitration();
2818 IOService::actionWillTerminate( IOService
* victim
, IOOptionBits options
,
2819 OSArray
* doPhase2List
,
2821 void *unused3 __unused
)
2826 uint64_t regID1
, regID2
= victim
->getRegistryEntryID();
2828 iter
= victim
->getClientIterator();
2830 while ((client
= (IOService
*) iter
->getNextObject())) {
2831 if (user
!= (NULL
!= client
->reserved
->uvars
)) {
2834 regID1
= client
->getRegistryEntryID();
2835 TLOG("%s[0x%qx]::willTerminate(%s[0x%qx], %08llx)\n",
2836 client
->getName(), regID1
,
2837 victim
->getName(), regID2
, (long long)options
);
2839 IOSERVICE_TERMINATE_WILL
,
2841 (uintptr_t) (regID1
>> 32),
2843 (uintptr_t) (regID2
>> 32));
2845 ok
= client
->willTerminate( victim
, options
);
2846 doPhase2List
->tailQ( client
);
2853 IOService::actionDidTerminate( IOService
* victim
, IOOptionBits options
,
2854 void *unused1 __unused
, void *unused2 __unused
,
2855 void *unused3 __unused
)
2860 uint64_t regID1
, regID2
= victim
->getRegistryEntryID();
2862 victim
->messageClients( kIOMessageServiceIsTerminated
, (void *)(uintptr_t) options
);
2864 iter
= victim
->getClientIterator();
2866 while ((client
= (IOService
*) iter
->getNextObject())) {
2867 regID1
= client
->getRegistryEntryID();
2868 TLOG("%s[0x%qx]::didTerminate(%s[0x%qx], %08llx)\n",
2869 client
->getName(), regID1
,
2870 victim
->getName(), regID2
, (long long)options
);
2872 client
->didTerminate( victim
, options
, &defer
);
2875 (defer
? IOSERVICE_TERMINATE_DID_DEFER
2876 : IOSERVICE_TERMINATE_DID
),
2878 (uintptr_t) (regID1
>> 32),
2880 (uintptr_t) (regID2
>> 32));
2882 TLOG("%s[0x%qx]::didTerminate(%s[0x%qx], defer %d)\n",
2883 client
->getName(), regID1
,
2884 victim
->getName(), regID2
, defer
);
2892 IOService::actionWillStop( IOService
* victim
, IOOptionBits options
,
2893 void *unused1 __unused
, void *unused2 __unused
,
2894 void *unused3 __unused
)
2897 IOService
* provider
;
2899 uint64_t regID1
, regID2
= victim
->getRegistryEntryID();
2901 iter
= victim
->getProviderIterator();
2903 while ((provider
= (IOService
*) iter
->getNextObject())) {
2904 regID1
= provider
->getRegistryEntryID();
2905 TLOG("%s[0x%qx]::willTerminate(%s[0x%qx], %08llx)\n",
2906 victim
->getName(), regID2
,
2907 provider
->getName(), regID1
, (long long)options
);
2909 IOSERVICE_TERMINATE_WILL
,
2911 (uintptr_t) (regID2
>> 32),
2913 (uintptr_t) (regID1
>> 32));
2915 ok
= victim
->willTerminate( provider
, options
);
2922 IOService::actionDidStop( IOService
* victim
, IOOptionBits options
,
2923 void *unused1 __unused
, void *unused2 __unused
,
2924 void *unused3 __unused
)
2927 IOService
* provider
;
2929 uint64_t regID1
, regID2
= victim
->getRegistryEntryID();
2931 iter
= victim
->getProviderIterator();
2933 while ((provider
= (IOService
*) iter
->getNextObject())) {
2934 regID1
= provider
->getRegistryEntryID();
2935 TLOG("%s[0x%qx]::didTerminate(%s[0x%qx], %08llx)\n",
2936 victim
->getName(), regID2
,
2937 provider
->getName(), regID1
, (long long)options
);
2938 victim
->didTerminate( provider
, options
, &defer
);
2941 (defer
? IOSERVICE_TERMINATE_DID_DEFER
2942 : IOSERVICE_TERMINATE_DID
),
2944 (uintptr_t) (regID2
>> 32),
2946 (uintptr_t) (regID1
>> 32));
2948 TLOG("%s[0x%qx]::didTerminate(%s[0x%qx], defer %d)\n",
2949 victim
->getName(), regID2
,
2950 provider
->getName(), regID1
, defer
);
2958 IOService::actionFinalize( IOService
* victim
, IOOptionBits options
,
2959 void *unused1 __unused
, void *unused2 __unused
,
2960 void *unused3 __unused
)
2962 uint64_t regID1
= victim
->getRegistryEntryID();
2963 TLOG("%s[0x%qx]::finalize(%08llx)\n", victim
->getName(), regID1
, (long long)options
);
2965 IOSERVICE_TERMINATE_FINALIZE
,
2967 (uintptr_t) (regID1
>> 32),
2970 victim
->finalize( options
);
2974 IOService::actionStop( IOService
* provider
, IOService
* client
,
2975 void *unused1 __unused
, void *unused2 __unused
,
2976 void *unused3 __unused
)
2978 uint64_t regID1
= provider
->getRegistryEntryID();
2979 uint64_t regID2
= client
->getRegistryEntryID();
2981 TLOG("%s[0x%qx]::stop(%s[0x%qx])\n", client
->getName(), regID2
, provider
->getName(), regID1
);
2983 IOSERVICE_TERMINATE_STOP
,
2985 (uintptr_t) (regID1
>> 32),
2987 (uintptr_t) (regID2
>> 32));
2989 client
->stop( provider
);
2990 if (provider
->isOpen( client
)) {
2991 provider
->close( client
);
2994 TLOG("%s[0x%qx]::detach(%s[0x%qx])\n", client
->getName(), regID2
, provider
->getName(), regID1
);
2995 client
->detach( provider
);
2999 IOService::terminateWorker( IOOptionBits options
)
3001 OSArray
* doPhase2List
;
3002 OSArray
* didPhase2List
;
3008 IOService
* provider
;
3014 options
|= kIOServiceRequired
;
3016 doPhase2List
= OSArray::withCapacity( 16 );
3017 didPhase2List
= OSArray::withCapacity( 16 );
3018 freeList
= OSSet::withCapacity( 16 );
3019 if ((NULL
== doPhase2List
) || (NULL
== didPhase2List
) || (NULL
== freeList
)) {
3024 workDone
= gIOTerminateWork
;
3026 while ((victim
= (IOService
*) gIOTerminatePhase2List
->getObject(0))) {
3028 gIOTerminatePhase2List
->removeObject(0);
3029 IOLockUnlock( gJobsLock
);
3031 uint64_t regID1
= victim
->getRegistryEntryID();
3033 IOSERVICE_TERM_START_PHASE2
,
3035 (uintptr_t) (regID1
>> 32),
3040 doPhase2
= victim
->lockForArbitration( true );
3042 doPhase2
= (0 != (kIOServiceInactiveState
& victim
->__state
[0]));
3044 uint64_t regID1
= victim
->getRegistryEntryID();
3046 IOSERVICE_TERM_TRY_PHASE2
,
3048 (uintptr_t) (regID1
>> 32),
3049 (uintptr_t) victim
->__state
[1],
3052 doPhase2
= (0 == (victim
->__state
[1] &
3053 (kIOServiceTermPhase1State
3054 | kIOServiceTermPhase2State
3055 | kIOServiceConfigState
)));
3057 if (doPhase2
&& (iter
= victim
->getClientIterator())) {
3058 while (doPhase2
&& (client
= (IOService
*) iter
->getNextObject())) {
3059 doPhase2
= (0 == (client
->__state
[1] & kIOServiceStartState
));
3061 uint64_t regID1
= client
->getRegistryEntryID();
3063 IOSERVICE_TERM_UC_DEFER
,
3065 (uintptr_t) (regID1
>> 32),
3066 (uintptr_t) client
->__state
[1],
3068 TLOG("%s[0x%qx]::defer phase2(%s[0x%qx])\n",
3069 victim
->getName(), victim
->getRegistryEntryID(),
3070 client
->getName(), client
->getRegistryEntryID());
3076 victim
->__state
[1] |= kIOServiceTermPhase2State
;
3079 victim
->unlockForArbitration();
3082 if (kIOServiceNeedWillTerminate
& victim
->__state
[1]) {
3083 if (NULL
== victim
->reserved
->uvars
) {
3084 _workLoopAction((IOWorkLoop::Action
) &actionWillStop
,
3085 victim
, (void *)(uintptr_t) options
);
3087 actionWillStop(victim
, options
, NULL
, NULL
, NULL
);
3091 OSArray
* notifiers
;
3092 notifiers
= victim
->copyNotifiers(gIOWillTerminateNotification
, 0, 0xffffffff);
3093 victim
->invokeNotifiers(¬ifiers
);
3095 _workLoopAction((IOWorkLoop::Action
) &actionWillTerminate
,
3097 (void *)(uintptr_t) options
,
3098 (void *)(uintptr_t) doPhase2List
,
3099 (void *)(uintptr_t) false);
3101 actionWillTerminate(
3102 victim
, options
, doPhase2List
, true, NULL
);
3104 didPhase2List
->headQ( victim
);
3107 victim
= (IOService
*) doPhase2List
->getObject(0);
3110 doPhase2List
->removeObject(0);
3114 while ((victim
= (IOService
*) didPhase2List
->getObject(0))) {
3115 bool scheduleFinalize
= false;
3116 if (victim
->lockForArbitration( true )) {
3117 victim
->__state
[1] |= kIOServiceTermPhase3State
;
3118 scheduleFinalize
= (NULL
== victim
->getClient());
3119 victim
->unlockForArbitration();
3121 _workLoopAction((IOWorkLoop::Action
) &actionDidTerminate
,
3122 victim
, (void *)(uintptr_t) options
);
3123 if (kIOServiceNeedWillTerminate
& victim
->__state
[1]) {
3124 _workLoopAction((IOWorkLoop::Action
) &actionDidStop
,
3125 victim
, (void *)(uintptr_t) options
, NULL
);
3127 // no clients - will go to finalize
3128 if (scheduleFinalize
) {
3129 victim
->scheduleFinalize(false);
3131 didPhase2List
->removeObject(0);
3133 IOLockLock( gJobsLock
);
3140 while ((victim
= (IOService
*) gIOFinalizeList
->getObject(0))) {
3141 bool sendFinal
= false;
3142 IOLockUnlock( gJobsLock
);
3143 if (victim
->lockForArbitration(true)) {
3144 sendFinal
= (0 == (victim
->__state
[1] & kIOServiceFinalized
));
3146 victim
->__state
[1] |= kIOServiceFinalized
;
3148 victim
->unlockForArbitration();
3151 _workLoopAction((IOWorkLoop::Action
) &actionFinalize
,
3152 victim
, (void *)(uintptr_t) options
);
3154 IOLockLock( gJobsLock
);
3156 freeList
->setObject( victim
);
3157 // safe if finalize list is append only
3158 gIOFinalizeList
->removeObject(0);
3162 (!doPhase3
) && (client
= (IOService
*) gIOStopList
->getObject(idx
));) {
3163 provider
= (IOService
*) gIOStopProviderList
->getObject(idx
);
3166 uint64_t regID1
= provider
->getRegistryEntryID();
3167 uint64_t regID2
= client
->getRegistryEntryID();
3169 if (!provider
->isChild( client
, gIOServicePlane
)) {
3170 // may be multiply queued - nop it
3171 TLOG("%s[0x%qx]::nop stop(%s[0x%qx])\n", client
->getName(), regID2
, provider
->getName(), regID1
);
3173 IOSERVICE_TERMINATE_STOP_NOP
,
3175 (uintptr_t) (regID1
>> 32),
3177 (uintptr_t) (regID2
>> 32));
3179 // a terminated client is not ready for stop if it has clients, skip it
3180 bool deferStop
= (0 != (kIOServiceInactiveState
& client
->__state
[0]));
3181 IOLockUnlock( gJobsLock
);
3182 if (deferStop
&& client
->lockForArbitration(true)) {
3183 deferStop
= (0 == (client
->__state
[1] & kIOServiceFinalized
));
3184 //deferStop = (!deferStop && (0 != client->getClient()));
3185 //deferStop = (0 != client->getClient());
3186 client
->unlockForArbitration();
3188 TLOG("%s[0x%qx]::defer stop()\n", client
->getName(), regID2
);
3189 IOServiceTrace(IOSERVICE_TERMINATE_STOP_DEFER
,
3191 (uintptr_t) (regID1
>> 32),
3193 (uintptr_t) (regID2
>> 32));
3196 IOLockLock( gJobsLock
);
3200 _workLoopAction((IOWorkLoop::Action
) &actionStop
,
3201 provider
, (void *) client
);
3202 IOLockLock( gJobsLock
);
3203 // check the finalize list now
3207 freeList
->setObject( client
);
3208 freeList
->setObject( provider
);
3210 // safe if stop list is append only
3211 gIOStopList
->removeObject( idx
);
3212 gIOStopProviderList
->removeObject( idx
);
3217 gIOTerminateWork
-= workDone
;
3218 moreToDo
= (gIOTerminateWork
!= 0);
3221 TLOG("iokit terminate done, %d stops remain\n", gIOStopList
->getCount());
3223 IOSERVICE_TERMINATE_DONE
,
3224 (uintptr_t) gIOStopList
->getCount(), 0, 0, 0);
3228 IOLockUnlock( gJobsLock
);
3230 freeList
->release();
3231 doPhase2List
->release();
3232 didPhase2List
->release();
3234 IOLockLock( gJobsLock
);
3238 IOService::finalize( IOOptionBits options
)
3241 IOService
* provider
;
3242 uint64_t regID1
, regID2
= getRegistryEntryID();
3244 iter
= getProviderIterator();
3248 while ((provider
= (IOService
*) iter
->getNextObject())) {
3250 if (0 == (__state
[1] & kIOServiceTermPhase3State
)) {
3251 /* we come down here on programmatic terminate */
3253 regID1
= provider
->getRegistryEntryID();
3254 TLOG("%s[0x%qx]::stop1(%s[0x%qx])\n", getName(), regID2
, provider
->getName(), regID1
);
3256 IOSERVICE_TERMINATE_STOP
,
3258 (uintptr_t) (regID1
>> 32),
3260 (uintptr_t) (regID2
>> 32));
3263 if (provider
->isOpen( this )) {
3264 provider
->close( this );
3269 if (provider
->lockForArbitration( true )) {
3270 if (0 == (provider
->__state
[1] & kIOServiceTermPhase3State
)) {
3271 scheduleStop( provider
);
3273 provider
->unlockForArbitration();
3291 IOService::doServiceTerminate( IOOptionBits options
)
3295 // a method in case someone needs to override it
3297 IOService::terminateClient( IOService
* client
, IOOptionBits options
)
3301 if (client
->isParent( this, gIOServicePlane
, true)) {
3302 // we are the clients only provider
3303 ok
= client
->terminate( options
);
3312 IOService::terminate( IOOptionBits options
)
3314 options
|= kIOServiceTerminate
;
3316 return terminatePhase1( options
);
3319 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3325 struct ServiceOpenMessageContext
{
3326 IOService
* service
;
3328 IOService
* excludeClient
;
3329 IOOptionBits options
;
3333 serviceOpenMessageApplier( OSObject
* object
, void * ctx
)
3335 ServiceOpenMessageContext
* context
= (ServiceOpenMessageContext
*) ctx
;
3337 if (object
!= context
->excludeClient
) {
3338 context
->service
->messageClient( context
->type
, object
, (void *)(uintptr_t) context
->options
);
3343 IOService::open( IOService
* forClient
,
3344 IOOptionBits options
,
3348 ServiceOpenMessageContext context
;
3350 context
.service
= this;
3351 context
.type
= kIOMessageServiceIsAttemptingOpen
;
3352 context
.excludeClient
= forClient
;
3353 context
.options
= options
;
3355 applyToInterested( gIOGeneralInterest
,
3356 &serviceOpenMessageApplier
, &context
);
3358 if (false == lockForArbitration(false)) {
3362 ok
= (0 == (__state
[0] & kIOServiceInactiveState
));
3364 ok
= handleOpen( forClient
, options
, arg
);
3367 if (ok
&& forClient
&& forClient
->reserved
->uvars
&& forClient
->reserved
->uvars
->userServer
) {
3368 forClient
->reserved
->uvars
->userServer
->serviceOpen(this, forClient
);
3371 unlockForArbitration();
3377 IOService::close( IOService
* forClient
,
3378 IOOptionBits options
)
3383 lockForArbitration();
3385 wasClosed
= handleIsOpen( forClient
);
3387 handleClose( forClient
, options
);
3388 last
= (__state
[1] & kIOServiceTermPhase3State
);
3390 if (forClient
&& forClient
->reserved
->uvars
&& forClient
->reserved
->uvars
->userServer
) {
3391 forClient
->reserved
->uvars
->userServer
->serviceClose(this, forClient
);
3395 unlockForArbitration();
3398 forClient
->scheduleStop( this );
3399 } else if (wasClosed
) {
3400 ServiceOpenMessageContext context
;
3402 context
.service
= this;
3403 context
.type
= kIOMessageServiceWasClosed
;
3404 context
.excludeClient
= forClient
;
3405 context
.options
= options
;
3407 applyToInterested( gIOGeneralInterest
,
3408 &serviceOpenMessageApplier
, &context
);
3413 IOService::isOpen( const IOService
* forClient
) const
3415 IOService
* self
= (IOService
*) this;
3418 self
->lockForArbitration();
3420 ok
= handleIsOpen( forClient
);
3422 self
->unlockForArbitration();
3428 IOService::handleOpen( IOService
* forClient
,
3429 IOOptionBits options
,
3434 ok
= (NULL
== __owner
);
3436 __owner
= forClient
;
3437 } else if (options
& kIOServiceSeize
) {
3438 ok
= (kIOReturnSuccess
== messageClient( kIOMessageServiceIsRequestingClose
,
3439 __owner
, (void *)(uintptr_t) options
));
3440 if (ok
&& (NULL
== __owner
)) {
3441 __owner
= forClient
;
3450 IOService::handleClose( IOService
* forClient
,
3451 IOOptionBits options
)
3453 if (__owner
== forClient
) {
3459 IOService::handleIsOpen( const IOService
* forClient
) const
3462 return __owner
== forClient
;
3464 return __owner
!= forClient
;
3469 * Probing & starting
3472 IONotifyOrdering( const OSMetaClassBase
* inObj1
, const OSMetaClassBase
* inObj2
, void * ref
)
3474 const _IOServiceNotifier
* obj1
= (const _IOServiceNotifier
*) inObj1
;
3475 const _IOServiceNotifier
* obj2
= (const _IOServiceNotifier
*) inObj2
;
3482 val1
= obj1
->priority
;
3485 val2
= obj2
->priority
;
3497 IOServiceObjectOrder( const OSObject
* entry
, void * ref
)
3499 OSDictionary
* dict
;
3500 IOService
* service
;
3501 _IOServiceNotifier
* notify
;
3502 OSSymbol
* key
= (OSSymbol
*) ref
;
3508 result
= kIODefaultProbeScore
;
3509 if ((dict
= OSDynamicCast( OSDictionary
, entry
))) {
3510 offset
= OSDynamicCast(OSNumber
, dict
->getObject( key
));
3511 } else if ((notify
= OSDynamicCast( _IOServiceNotifier
, entry
))) {
3512 return notify
->priority
;
3513 } else if ((service
= OSDynamicCast( IOService
, entry
))) {
3514 prop
= service
->copyProperty(key
);
3515 offset
= OSDynamicCast(OSNumber
, prop
);
3522 result
= offset
->unsigned32BitValue();
3525 OSSafeReleaseNULL(prop
);
3531 IOServiceOrdering( const OSMetaClassBase
* inObj1
, const OSMetaClassBase
* inObj2
, void * ref
)
3533 const OSObject
* obj1
= (const OSObject
*) inObj1
;
3534 const OSObject
* obj2
= (const OSObject
*) inObj2
;
3542 val1
= IOServiceObjectOrder( obj1
, ref
);
3546 val2
= IOServiceObjectOrder( obj2
, ref
);
3553 IOService::copyClientWithCategory( const OSSymbol
* category
)
3555 IOService
* service
= NULL
;
3557 const OSSymbol
* nextCat
;
3559 iter
= getClientIterator();
3561 while ((service
= (IOService
*) iter
->getNextObject())) {
3562 if (kIOServiceInactiveState
& service
->__state
[0]) {
3565 nextCat
= (const OSSymbol
*) OSDynamicCast( OSSymbol
,
3566 service
->getProperty( gIOMatchCategoryKey
));
3567 if (category
== nextCat
) {
3578 IOService::getClientWithCategory( const OSSymbol
* category
)
3581 service
= copyClientWithCategory(category
);
3589 IOService::invokeNotifier( _IOServiceNotifier
* notify
)
3591 _IOServiceNotifierInvocation invocation
;
3594 invocation
.thread
= current_thread();
3596 #if DEBUG_NOTIFIER_LOCKED
3598 if ((count
= isLockedForArbitration(0))) {
3599 IOLog("[%s, 0x%x]\n", notify
->type
->getCStringNoCopy(), count
);
3600 panic("[%s, 0x%x]\n", notify
->type
->getCStringNoCopy(), count
);
3602 #endif /* DEBUG_NOTIFIER_LOCKED */
3605 willNotify
= (0 != (kIOServiceNotifyEnable
& notify
->state
));
3608 queue_enter( ¬ify
->handlerInvocations
, &invocation
,
3609 _IOServiceNotifierInvocation
*, link
);
3614 ret
= (*notify
->handler
)(notify
->target
, notify
->ref
, this, notify
);
3617 queue_remove( ¬ify
->handlerInvocations
, &invocation
,
3618 _IOServiceNotifierInvocation
*, link
);
3619 if (kIOServiceNotifyWaiter
& notify
->state
) {
3620 notify
->state
&= ~kIOServiceNotifyWaiter
;
3621 WAKEUPNOTIFY( notify
);
3630 IOService::invokeNotifiers(OSArray
* willSend
[])
3633 _IOServiceNotifier
* notify
;
3642 for (unsigned int idx
= 0;
3643 (notify
= (_IOServiceNotifier
*) array
->getObject(idx
));
3645 ret
&= invokeNotifier(notify
);
3653 * Alloc and probe matching classes,
3654 * called on the provider instance
3658 IOService::probeCandidates( OSOrderedSet
* matches
)
3660 OSDictionary
* match
= NULL
;
3663 IOService
* newInst
;
3664 OSDictionary
* props
;
3667 OSOrderedSet
* familyMatches
= NULL
;
3668 OSOrderedSet
* startList
;
3669 OSSet
* kexts
= NULL
;
3672 OSDictionary
* startDict
= NULL
;
3673 const OSSymbol
* category
;
3675 _IOServiceNotifier
* notify
;
3676 OSObject
* nextMatch
= NULL
;
3678 bool needReloc
= false;
3679 bool matchDeferred
= false;
3683 IOService
* client
= NULL
;
3686 OSDictionary
* rematchPersonality
;
3691 bool categoryConsumed
;
3695 prop1
= copyProperty(gIORematchPersonalityKey
);
3696 rematchPersonality
= OSDynamicCast(OSDictionary
, prop1
);
3697 if (rematchPersonality
) {
3698 prop2
= copyProperty(gIORematchCountKey
);
3699 num
= OSDynamicCast(OSNumber
, prop2
);
3701 count
= num
->unsigned32BitValue();
3703 OSSafeReleaseNULL(prop2
);
3709 && (nextMatch
= matches
->getFirstObject())) {
3710 nextMatch
->retain();
3711 matches
->removeObject(nextMatch
);
3713 if ((notify
= OSDynamicCast( _IOServiceNotifier
, nextMatch
))) {
3714 if (0 == (__state
[0] & kIOServiceInactiveState
)) {
3715 invokeNotifier( notify
);
3717 nextMatch
->release();
3720 } else if (!(match
= OSDynamicCast( OSDictionary
, nextMatch
))) {
3721 nextMatch
->release();
3728 debugFlags
= getDebugFlags( match
);
3732 isDext
= (NULL
!= match
->getObject(gIOUserServerNameKey
));
3733 if (isDext
&& !(kIODKEnable
& gIODKDebug
)) {
3737 category
= OSDynamicCast( OSSymbol
,
3738 match
->getObject( gIOMatchCategoryKey
));
3739 if (NULL
== category
) {
3740 category
= gIODefaultMatchCategoryKey
;
3742 client
= copyClientWithCategory(category
);
3744 categoryConsumed
= (client
!= NULL
);
3745 if (categoryConsumed
) {
3747 if ((debugFlags
& kIOLogMatch
) && (this != gIOResources
)) {
3748 LOG("%s: match category %s exists\n", getName(),
3749 category
->getCStringNoCopy());
3752 OSSafeReleaseNULL(client
);
3758 // create a copy now in case its modified during matching
3759 props
= OSDictionary::withDictionary(match
, match
->getCount());
3760 if (NULL
== props
) {
3763 props
->setCapacityIncrement(1);
3765 // check the nub matches
3766 if (false == matchPassive(props
, kIOServiceChangesOK
| kIOServiceClassDone
)) {
3771 if (categoryConsumed
) {
3776 if (rematchPersonality
) {
3777 bool personalityMatch
= match
->isEqualTo(rematchPersonality
);
3778 if (count
> gIODextRelaunchMax
) {
3779 personalityMatch
= !personalityMatch
;
3781 if (!personalityMatch
) {
3786 // Check to see if driver reloc has been loaded.
3787 needReloc
= (false == gIOCatalogue
->isModuleLoaded( match
, &kextRef
));
3790 if (debugFlags
& kIOLogCatalogue
) {
3791 LOG("%s: stalling for module\n", getName());
3794 // If reloc hasn't been loaded, exit;
3795 // reprobing will occur after reloc has been loaded.
3799 if (NULL
== kexts
) {
3800 kexts
= OSSet::withCapacity(1);
3803 kexts
->setObject(kextRef
);
3808 // copy saved for rematchng
3809 props
->setObject(gIOMatchedPersonalityKey
, match
);
3811 // reorder on family matchPropertyTable score.
3812 if (NULL
== familyMatches
) {
3813 familyMatches
= OSOrderedSet::withCapacity( 1,
3814 IOServiceOrdering
, (void *) gIOProbeScoreKey
);
3816 if (familyMatches
) {
3817 familyMatches
->setObject( props
);
3821 OSSafeReleaseNULL(nextMatch
);
3822 OSSafeReleaseNULL(props
);
3827 if (familyMatches
) {
3829 && (props
= (OSDictionary
*) familyMatches
->getFirstObject())) {
3831 familyMatches
->removeObject( props
);
3836 debugFlags
= getDebugFlags( props
);
3839 symbol
= OSDynamicCast( OSSymbol
,
3840 props
->getObject( gIOClassKey
));
3845 //IOLog("%s alloc (symbol %p props %p)\n", symbol->getCStringNoCopy(), IOSERVICE_OBFUSCATE(symbol), IOSERVICE_OBFUSCATE(props));
3847 // alloc the driver instance
3848 inst
= (IOService
*) OSMetaClass::allocClassWithName( symbol
);
3850 if (!inst
|| !OSDynamicCast(IOService
, inst
)) {
3851 IOLog("Couldn't alloc class \"%s\"\n",
3852 symbol
->getCStringNoCopy());
3856 // init driver instance
3857 if (!(inst
->init( props
))) {
3859 if (debugFlags
& kIOLogStart
) {
3860 IOLog("%s::init fails\n", symbol
->getCStringNoCopy());
3865 if (__state
[1] & kIOServiceSynchronousState
) {
3866 inst
->__state
[1] |= kIOServiceSynchronousState
;
3869 // give the driver the default match category if not specified
3870 category
= OSDynamicCast( OSSymbol
,
3871 props
->getObject( gIOMatchCategoryKey
));
3872 if (NULL
== category
) {
3873 category
= gIODefaultMatchCategoryKey
;
3875 inst
->setProperty( gIOMatchCategoryKey
, (OSObject
*) category
);
3876 // attach driver instance
3877 if (!(inst
->attach( this ))) {
3881 // pass in score from property table
3882 score
= familyMatches
->orderObject( props
);
3884 // & probe the new driver instance
3886 if (debugFlags
& kIOLogProbe
) {
3887 LOG("%s::probe(%s)\n",
3888 inst
->getMetaClass()->getClassName(), getName());
3892 newInst
= inst
->probe( this, &score
);
3893 inst
->detach( this );
3894 if (NULL
== newInst
) {
3896 if (debugFlags
& kIOLogProbe
) {
3897 IOLog("%s::probe fails\n", symbol
->getCStringNoCopy());
3904 newPri
= OSNumber::withNumber( score
, 32 );
3906 newInst
->setProperty( gIOProbeScoreKey
, newPri
);
3910 // add to start list for the match category
3911 if (NULL
== startDict
) {
3912 startDict
= OSDictionary::withCapacity( 1 );
3914 assert( startDict
);
3915 startList
= (OSOrderedSet
*)
3916 startDict
->getObject( category
);
3917 if (NULL
== startList
) {
3918 startList
= OSOrderedSet::withCapacity( 1,
3919 IOServiceOrdering
, (void *) gIOProbeScoreKey
);
3920 if (startDict
&& startList
) {
3921 startDict
->setObject( category
, startList
);
3922 startList
->release();
3925 assert( startList
);
3927 startList
->setObject( newInst
);
3936 familyMatches
->release();
3937 familyMatches
= NULL
;
3940 // start the best (until success) of each category
3942 iter
= OSCollectionIterator::withCollection( startDict
);
3944 while ((category
= (const OSSymbol
*) iter
->getNextObject())) {
3945 startList
= (OSOrderedSet
*) startDict
->getObject( category
);
3946 assert( startList
);
3952 while (true // (!started)
3954 && (inst
= (IOService
*)startList
->getFirstObject())) {
3956 startList
->removeObject(inst
);
3959 debugFlags
= getDebugFlags( inst
);
3961 if (debugFlags
& kIOLogStart
) {
3963 LOG( "match category exists, skipping " );
3965 LOG( "%s::start(%s) <%d>\n", inst
->getName(),
3966 getName(), inst
->getRetainCount());
3969 if (false == started
) {
3971 IOLockLock(gJobsLock
);
3972 matchDeferred
= (gIOMatchDeferList
3973 && (kOSBooleanTrue
== inst
->getProperty(gIOMatchDeferKey
) || gInUserspaceReboot
));
3974 if (matchDeferred
&& (-1U == gIOMatchDeferList
->getNextIndexOfObject(this, 0))) {
3975 gIOMatchDeferList
->setObject(this);
3977 IOLockUnlock(gJobsLock
);
3978 if (matchDeferred
) {
3979 symbol
= OSDynamicCast(OSSymbol
, inst
->getProperty(gIOClassKey
));
3980 IOLog("%s(0x%qx): matching deferred by %s\n",
3981 getName(), getRegistryEntryID(),
3982 symbol
? symbol
->getCStringNoCopy() : "");
3983 // rematching will occur after the IOKit daemon loads all plists
3986 if (!matchDeferred
) {
3987 started
= startCandidate( inst
);
3989 if ((debugFlags
& kIOLogStart
) && (false == started
)) {
3990 LOG( "%s::start(%s) <%d> failed\n", inst
->getName(), getName(),
3991 inst
->getRetainCount());
4002 OSSafeReleaseNULL(prop1
);
4005 num
= OSNumber::withNumber(dextCount
, 32);
4006 setProperty(gIODEXTMatchCountKey
, num
);
4007 OSSafeReleaseNULL(num
);
4008 } else if (rematchPersonality
) {
4009 removeProperty(gIODEXTMatchCountKey
);
4012 // now that instances are created, drop the refs on any kexts allowing unload
4014 OSKext::dropMatchingReferences(kexts
);
4015 OSSafeReleaseNULL(kexts
);
4018 // adjust the busy count by +1 if matching is stalled for a module,
4019 // or -1 if a previously stalled matching is complete.
4020 lockForArbitration();
4022 uint64_t regID
= getRegistryEntryID();
4025 adjBusy
= (__state
[1] & kIOServiceModuleStallState
) ? 0 : 1;
4028 IOSERVICE_MODULESTALL
,
4030 (uintptr_t) (regID
>> 32),
4034 __state
[1] |= kIOServiceModuleStallState
;
4036 } else if (__state
[1] & kIOServiceModuleStallState
) {
4038 IOSERVICE_MODULEUNSTALL
,
4040 (uintptr_t) (regID
>> 32),
4044 __state
[1] &= ~kIOServiceModuleStallState
;
4048 _adjustBusy( adjBusy
);
4050 unlockForArbitration();
4053 startDict
->release();
4058 * Wait for a IOUserServer to check in
4062 __attribute__((noinline
, not_tail_called
))
4064 __WAITING_FOR_USER_SERVER__(OSDictionary
* matching
, IOUserServerCheckInToken
* token
)
4067 server
= IOService::waitForMatchingServiceWithToken(matching
, kIOUserServerCheckInTimeoutSecs
* NSEC_PER_SEC
, token
);
4072 IOService::willShutdown()
4074 gIOKitWillTerminate
= true;
4076 getPlatform()->waitQuiet(30 * NSEC_PER_SEC
);
4078 OSKext::willShutdown();
4082 IOService::userSpaceWillReboot()
4084 IOLockLock(gJobsLock
);
4086 // Recreate the defer list if it does not exist
4087 if (!gIOMatchDeferList
) {
4088 gIOMatchDeferList
= OSArray::withCapacity( 16 );
4091 gInUserspaceReboot
= true;
4092 IOLockUnlock(gJobsLock
);
4096 IOService::userSpaceDidReboot()
4098 IOLockLock(gJobsLock
);
4099 gInUserspaceReboot
= false;
4100 IOLockUnlock(gJobsLock
);
4103 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
4106 IOServicePH::init(IOPMrootDomain
* root
)
4108 fUserServers
= OSArray::withCapacity(4);
4109 fMatchingWork
= OSArray::withCapacity(4);
4111 assert(fUserServers
&& fMatchingWork
);
4113 fRootNotifier
= root
->registerInterest(
4114 gIOPriorityPowerStateInterest
, &IOServicePH::systemPowerChange
, NULL
, NULL
);
4116 assert(fRootNotifier
);
4122 IOLockLock(gJobsLock
);
4126 IOServicePH::unlock()
4128 IOLockUnlock(gJobsLock
);
4132 IOServicePH::serverAdd(IOUserServer
* server
)
4137 idx
= fUserServers
->getNextIndexOfObject(server
, 0);
4139 fUserServers
->setObject(server
);
4145 IOServicePH::serverRemove(IOUserServer
* server
)
4150 idx
= fUserServers
->getNextIndexOfObject(server
, 0);
4152 fUserServers
->removeObject(idx
);
4155 if (fWaitingUserServers
) {
4156 fWaitingUserServers
= false;
4157 IOLockWakeup(gJobsLock
, &fWaitingUserServers
, /* one-thread */ false);
4164 IOServicePH::serverAck(IOUserServer
* server
)
4172 if (server
&& fUserServersWait
) {
4173 idx
= fUserServersWait
->getNextIndexOfObject(server
, 0);
4175 fUserServersWait
->removeObject(idx
);
4176 if (0 == fUserServersWait
->getCount()) {
4177 OSSafeReleaseNULL(fUserServersWait
);
4181 if (!fUserServersWait
&& !fMatchingWork
->getCount()) {
4182 ackTo
= fSystemPowerAckTo
;
4183 ackToRef
= fSystemPowerAckRef
;
4184 fSystemPowerAckTo
= NULL
;
4189 DKLOG("allowPowerChange\n");
4190 ackTo
->allowPowerChange((uintptr_t) ackToRef
);
4195 IOServicePH::matchingStart(IOService
* service
)
4203 idx
= fMatchingWork
->getNextIndexOfObject(service
, 0);
4205 fMatchingWork
->setObject(service
);
4208 if (!fMatchingDelayed
) {
4209 fMatchingDelayed
= OSArray::withObjects((const OSObject
**) &service
, 1, 1);
4211 idx
= fMatchingDelayed
->getNextIndexOfObject(service
, 0);
4213 fMatchingDelayed
->setObject(service
);
4223 IOServicePH::matchingEnd(IOService
* service
)
4226 OSArray
* notifyServers
;
4227 OSArray
* deferredMatches
;
4229 notifyServers
= NULL
;
4230 deferredMatches
= NULL
;
4235 idx
= fMatchingWork
->getNextIndexOfObject(service
, 0);
4237 fMatchingWork
->removeObject(idx
);
4242 if ((fUserServerOff
!= fSystemOff
) && fUserServers
->getCount()) {
4244 if (0 == fMatchingWork
->getCount()) {
4245 fUserServersWait
= OSArray::withArray(fUserServers
);
4246 notifyServers
= OSArray::withArray(fUserServers
);
4247 fUserServerOff
= fSystemOff
;
4250 notifyServers
= OSArray::withArray(fUserServers
);
4251 fUserServerOff
= fSystemOff
;
4255 if (!fSystemOff
&& fMatchingDelayed
) {
4256 deferredMatches
= fMatchingDelayed
;
4257 fMatchingDelayed
= NULL
;
4262 if (notifyServers
) {
4263 notifyServers
->iterateObjects(^bool (OSObject
* obj
) {
4265 us
= (typeof(us
))obj
;
4266 us
->systemPower(fSystemOff
);
4269 OSSafeReleaseNULL(notifyServers
);
4272 if (deferredMatches
) {
4273 DKLOG("sleep deferred rematching count %d\n", deferredMatches
->getCount());
4274 deferredMatches
->iterateObjects(^bool (OSObject
* obj
)
4276 ((IOService
*)obj
)->startMatching(kIOServiceAsynchronous
);
4279 deferredMatches
->release();
4287 IOServicePH::systemHalt(void)
4289 OSArray
* notifyServers
;
4293 notifyServers
= OSArray::withArray(fUserServers
);
4296 if (notifyServers
) {
4297 notifyServers
->iterateObjects(^bool (OSObject
* obj
) {
4299 us
= (typeof(us
))obj
;
4303 OSSafeReleaseNULL(notifyServers
);
4307 clock_interval_to_deadline(1000, kMillisecondScale
, &deadline
);
4308 while (0 < fUserServers
->getCount()) {
4309 fWaitingUserServers
= true;
4310 __assert_only
int waitResult
=
4311 IOLockSleepDeadline(gJobsLock
, &fWaitingUserServers
, deadline
, THREAD_UNINT
);
4312 assert((THREAD_AWAKENED
== waitResult
) || (THREAD_TIMED_OUT
== waitResult
));
4313 if (THREAD_TIMED_OUT
== waitResult
) {
4321 IOServicePH::serverSlept(void)
4326 ret
= (kIOMessageSystemWillSleep
== sSystemPower
)
4327 || (kIOMessageSystemPagingOff
== sSystemPower
);
4334 IOServicePH::systemPowerChange(
4337 UInt32 messageType
, IOService
* service
,
4338 void * messageArgument
, vm_size_t argSize
)
4342 IOPMSystemCapabilityChangeParameters
* params
;
4346 switch (messageType
) {
4347 case kIOMessageSystemCapabilityChange
:
4349 params
= (typeof params
)messageArgument
;
4351 if (kIODKLogPM
& gIODKDebug
) {
4352 IOLog("IOServicePH::kIOMessageSystemCapabilityChange: %s%s 0x%x->0x%x\n",
4353 params
->changeFlags
& kIOPMSystemCapabilityWillChange
? "will" : "",
4354 params
->changeFlags
& kIOPMSystemCapabilityDidChange
? "did" : "",
4355 params
->fromCapabilities
,
4356 params
->toCapabilities
);
4359 if ((params
->changeFlags
& kIOPMSystemCapabilityWillChange
) &&
4360 (params
->fromCapabilities
& kIOPMSystemCapabilityCPU
) &&
4361 ((params
->toCapabilities
& kIOPMSystemCapabilityCPU
) == 0)) {
4364 fSystemPowerAckRef
= params
->notifyRef
;
4365 fSystemPowerAckTo
= service
;
4370 params
->maxWaitForReply
= 60 * 1000 * 1000;
4371 ret
= kIOReturnSuccess
;
4372 } else if ((params
->changeFlags
& kIOPMSystemCapabilityWillChange
) &&
4373 ((params
->fromCapabilities
& kIOPMSystemCapabilityCPU
) == 0) &&
4374 (params
->toCapabilities
& kIOPMSystemCapabilityCPU
)) {
4381 params
->maxWaitForReply
= 0;
4382 ret
= kIOReturnSuccess
;
4384 params
->maxWaitForReply
= 0;
4385 ret
= kIOReturnSuccess
;
4390 ret
= kIOReturnUnsupported
;
4397 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
4400 * Start a previously attached & probed instance,
4401 * called on exporting object instance
4405 IOService::startCandidate( IOService
* service
)
4410 IOUserServer
* userServer
;
4414 obj
= service
->copyProperty(gIOUserServerNameKey
);
4416 if (obj
&& (this == gIOResources
)) {
4419 ok
= service
->attach( this );
4425 if ((this != gIOResources
) && (this != gIOUserResources
)) {
4426 // stall for any nub resources
4428 // stall for any driver resources
4429 service
->checkResources();
4433 OSString
* bundleID
;
4434 OSString
* serverName
;
4436 const OSSymbol
* sym
;
4437 OSDictionary
* matching
;
4439 OSNumber
* serverTag
;
4441 IOUserServerCheckInToken
* token
;
4443 if ((serverName
= OSDynamicCast(OSString
, obj
))) {
4444 obj
= service
->copyProperty(gIOModuleIdentifierKey
);
4445 bundleID
= OSDynamicCast(OSString
, obj
);
4446 entryID
= service
->getRegistryEntryID();
4447 serverTag
= OSNumber::withNumber(entryID
, 64);
4450 if (gIOKitWillTerminate
) {
4451 DKLOG("%s disabled in shutdown\n", serverName
->getCStringNoCopy());
4452 service
->detach(this);
4453 OSSafeReleaseNULL(obj
);
4457 ph
= IOServicePH::matchingStart(this);
4459 DKLOG("%s deferred in sleep\n", serverName
->getCStringNoCopy());
4460 service
->detach(this);
4461 OSSafeReleaseNULL(obj
);
4465 prop
= service
->copyProperty(gIOUserClassKey
);
4466 str
= OSDynamicCast(OSString
, prop
);
4468 service
->setName(str
);
4470 OSSafeReleaseNULL(prop
);
4472 if (!(kIODKDisableDextLaunch
& gIODKDebug
)) {
4473 OSKext::requestDaemonLaunch(bundleID
, serverName
, serverTag
, &token
);
4476 DKLOG("%s failed to create check in token\n", serverName
->getCStringNoCopy());
4477 service
->detach(this);
4478 OSSafeReleaseNULL(obj
);
4481 sym
= OSSymbol::withString(serverName
);
4482 matching
= serviceMatching(gIOUserServerClassKey
);
4483 propertyMatching(gIOUserServerNameKey
, sym
, matching
);
4484 if (!(kIODKDisableDextTag
& gIODKDebug
)) {
4485 propertyMatching(gIOUserServerTagKey
, serverTag
, matching
);
4488 server
= __WAITING_FOR_USER_SERVER__(matching
, token
);
4489 matching
->release();
4490 OSSafeReleaseNULL(serverTag
);
4491 OSSafeReleaseNULL(serverName
);
4493 userServer
= OSDynamicCast(IOUserServer
, server
);
4496 service
->detach(this);
4497 IOServicePH::matchingEnd(this);
4498 OSSafeReleaseNULL(obj
);
4499 DKLOG(DKS
" user server timeout\n", DKN(service
));
4500 #if DEVELOPMENT || DEBUG
4501 driverkit_checkin_timed_out
= mach_absolute_time();
4506 if (!(kIODKDisableCheckInTokenVerification
& gIODKDebug
)) {
4507 if (!userServer
->serviceMatchesCheckInToken(token
)) {
4509 service
->detach(this);
4510 IOServicePH::matchingEnd(this);
4511 OSSafeReleaseNULL(obj
);
4512 userServer
->exit("Check In Token verification failed");
4513 userServer
->release();
4519 OSKext
*kext
= OSKext::lookupKextWithIdentifier(bundleID
);
4521 const char *name
= bundleID
->getCStringNoCopy();
4522 IOLog("%s Could not find OSKext for %s\n", __func__
, name
);
4529 userServer
->setTaskLoadTag(kext
);
4530 userServer
->setDriverKitUUID(kext
);
4531 OSKext::OSKextLogDriverKitInfoLoad(kext
);
4533 OSSafeReleaseNULL(bundleID
);
4534 OSSafeReleaseNULL(kext
);
4536 if (!(kIODKDisableEntitlementChecking
& gIODKDebug
)) {
4537 if (!userServer
->checkEntitlements(this, service
)) {
4538 service
->detach(this);
4539 IOServicePH::matchingEnd(this);
4540 userServer
->exit("Entitlements check failed");
4541 userServer
->release();
4546 userServer
->serviceAttach(service
, this);
4550 AbsoluteTime startTime
;
4551 AbsoluteTime endTime
;
4554 if (kIOLogStart
& gIOKitDebug
) {
4555 clock_get_uptime(&startTime
);
4558 ok
= service
->start(this);
4560 if (kIOLogStart
& gIOKitDebug
) {
4561 clock_get_uptime(&endTime
);
4563 if (CMP_ABSOLUTETIME(&endTime
, &startTime
) > 0) {
4564 SUB_ABSOLUTETIME(&endTime
, &startTime
);
4565 absolutetime_to_nanoseconds(endTime
, &nano
);
4566 if (nano
> 500000000ULL) {
4567 IOLog("%s::start took %ld ms\n", service
->getName(), (long)(UInt32
)(nano
/ 1000000ULL));
4572 userServer
->serviceStarted(service
, this, ok
);
4573 userServer
->release();
4577 IOInstallServiceSleepPlatformActions(service
);
4581 service
->detach( this );
4585 IOServicePH::matchingEnd(this);
4592 IOService::publishResource( const char * key
, OSObject
* value
)
4594 const OSSymbol
* sym
;
4596 if ((sym
= OSSymbol::withCString( key
))) {
4597 publishResource( sym
, value
);
4603 IOService::publishResource( const OSSymbol
* key
, OSObject
* value
)
4605 if (NULL
== value
) {
4606 value
= (OSObject
*) gIOServiceKey
;
4609 gIOResources
->setProperty( key
, value
);
4611 if (IORecursiveLockHaveLock( gNotificationLock
)) {
4615 gIOResourceGenerationCount
++;
4616 gIOResources
->registerService();
4620 IOService::publishUserResource( const OSSymbol
* key
, OSObject
* value
)
4622 if (NULL
== value
) {
4623 value
= (OSObject
*) gIOServiceKey
;
4626 gIOUserResources
->setProperty( key
, value
);
4628 if (IORecursiveLockHaveLock( gNotificationLock
)) {
4632 gIOResourceGenerationCount
++;
4633 gIOUserResources
->registerService();
4637 IOService::addNeededResource( const char * key
)
4639 OSObject
* resourcesProp
;
4644 resourcesProp
= copyProperty( gIOResourceMatchKey
);
4645 if (!resourcesProp
) {
4649 newKey
= OSString::withCString( key
);
4651 resourcesProp
->release();
4655 set
= OSDynamicCast( OSSet
, resourcesProp
);
4657 set
= OSSet::withCapacity( 1 );
4659 set
->setObject( resourcesProp
);
4665 set
->setObject( newKey
);
4667 ret
= setProperty( gIOResourceMatchKey
, set
);
4669 resourcesProp
->release();
4675 IOService::checkResource( OSObject
* matching
)
4678 OSDictionary
* table
;
4680 if ((str
= OSDynamicCast( OSString
, matching
))) {
4681 if (gIOResources
->getProperty( str
)) {
4687 table
= resourceMatching( str
);
4688 } else if ((table
= OSDynamicCast( OSDictionary
, matching
))) {
4691 IOLog("%s: Can't match using: %s\n", getName(),
4692 matching
->getMetaClass()->getClassName());
4693 /* false would stall forever */
4697 if (gIOKitDebug
& kIOLogConfig
) {
4698 LOG("config(%p): stalling %s\n", IOSERVICE_OBFUSCATE(IOThreadSelf()), getName());
4701 waitForService( table
);
4703 if (gIOKitDebug
& kIOLogConfig
) {
4704 LOG("config(%p): waking\n", IOSERVICE_OBFUSCATE(IOThreadSelf()));
4711 IOService::checkResources( void )
4713 OSObject
* resourcesProp
;
4719 resourcesProp
= copyProperty( gIOResourceMatchKey
);
4720 if (NULL
== resourcesProp
) {
4724 if ((set
= OSDynamicCast( OSSet
, resourcesProp
))) {
4725 iter
= OSCollectionIterator::withCollection( set
);
4726 ok
= (NULL
!= iter
);
4727 while (ok
&& (obj
= iter
->getNextObject())) {
4728 ok
= checkResource( obj
);
4734 ok
= checkResource( resourcesProp
);
4737 OSSafeReleaseNULL(resourcesProp
);
4744 _IOConfigThread::configThread( const char * name
)
4746 _IOConfigThread
* inst
;
4749 if (!(inst
= new _IOConfigThread
)) {
4752 if (!inst
->init()) {
4756 if (KERN_SUCCESS
!= kernel_thread_start(&_IOConfigThread::main
, inst
, &thread
)) {
4760 char threadName
[MAXTHREADNAMESIZE
];
4761 snprintf(threadName
, sizeof(threadName
), "IOConfigThread_'%s'", name
);
4762 thread_set_thread_name(thread
, threadName
);
4763 thread_deallocate(thread
);
4776 IOService::doServiceMatch( IOOptionBits options
)
4778 _IOServiceNotifier
* notify
;
4780 OSOrderedSet
* matches
;
4781 OSArray
* resourceKeys
= NULL
;
4782 SInt32 catalogGeneration
;
4783 bool keepGuessing
= true;
4784 bool reRegistered
= true;
4786 OSArray
* notifiers
[2] = {NULL
};
4788 // job->nub->deliverNotification( gIOPublishNotification,
4789 // kIOServiceRegisteredState, 0xffffffff );
4791 while (keepGuessing
) {
4792 matches
= gIOCatalogue
->findDrivers( this, &catalogGeneration
);
4793 // the matches list should always be created by findDrivers()
4795 lockForArbitration();
4796 if (0 == (__state
[0] & kIOServiceFirstPublishState
)) {
4797 getMetaClass()->addInstance(this);
4798 notifiers
[0] = copyNotifiers(gIOFirstPublishNotification
,
4799 kIOServiceFirstPublishState
, 0xffffffff );
4802 __state
[1] &= ~kIOServiceNeedConfigState
;
4803 __state
[1] |= kIOServiceConfigState
| kIOServiceConfigRunning
;
4804 didRegister
= (0 == (kIOServiceRegisteredState
& __state
[0]));
4805 __state
[0] |= kIOServiceRegisteredState
;
4807 keepGuessing
&= (0 == (__state
[0] & kIOServiceInactiveState
));
4808 if (reRegistered
&& keepGuessing
) {
4809 iter
= OSCollectionIterator::withCollection((OSOrderedSet
*)
4810 gNotifications
->getObject( gIOPublishNotification
));
4812 while ((notify
= (_IOServiceNotifier
*)
4813 iter
->getNextObject())) {
4814 if (matchPassive(notify
->matching
, 0)
4815 && (kIOServiceNotifyEnable
& notify
->state
)) {
4816 matches
->setObject( notify
);
4824 unlockForArbitration();
4825 invokeNotifiers(¬ifiers
[0]);
4827 if (keepGuessing
&& matches
->getCount() && (kIOReturnSuccess
== getResources())) {
4828 if ((this == gIOResources
) || (this == gIOUserResources
)) {
4830 resourceKeys
->release();
4832 resourceKeys
= copyPropertyKeys();
4834 probeCandidates( matches
);
4840 lockForArbitration();
4841 reRegistered
= (0 != (__state
[1] & kIOServiceNeedConfigState
));
4843 (reRegistered
|| (catalogGeneration
!=
4844 gIOCatalogue
->getGenerationCount()))
4845 && (0 == (__state
[0] & kIOServiceInactiveState
));
4848 unlockForArbitration();
4852 if ((0 == (__state
[0] & kIOServiceInactiveState
))
4853 && (0 == (__state
[1] & kIOServiceModuleStallState
))) {
4855 setProperty(gIOResourceMatchedKey
, resourceKeys
);
4858 notifiers
[0] = copyNotifiers(gIOMatchedNotification
,
4859 kIOServiceMatchedState
, 0xffffffff);
4860 if (0 == (__state
[0] & kIOServiceFirstMatchState
)) {
4861 notifiers
[1] = copyNotifiers(gIOFirstMatchNotification
,
4862 kIOServiceFirstMatchState
, 0xffffffff);
4866 __state
[1] &= ~kIOServiceConfigRunning
;
4867 unlockForArbitration();
4870 resourceKeys
->release();
4873 invokeNotifiers(¬ifiers
[0]);
4874 invokeNotifiers(¬ifiers
[1]);
4876 lockForArbitration();
4877 __state
[1] &= ~kIOServiceConfigState
;
4878 scheduleTerminatePhase2();
4881 unlockForArbitration();
4885 IOService::_adjustBusy( SInt32 delta
)
4890 bool wasQuiet
, nowQuiet
, needWake
;
4893 result
= __state
[1] & kIOServiceBusyStateMask
;
4898 next
->lockForArbitration();
4900 count
= next
->__state
[1] & kIOServiceBusyStateMask
;
4901 wasQuiet
= (0 == count
);
4902 if (((delta
< 0) && wasQuiet
) || ((delta
> 0) && (kIOServiceBusyMax
== count
))) {
4903 OSReportWithBacktrace("%s: bad busy count (%d,%d)\n", next
->getName(), count
, delta
);
4907 next
->__state
[1] = (next
->__state
[1] & ~kIOServiceBusyStateMask
) | count
;
4908 nowQuiet
= (0 == count
);
4909 needWake
= (0 != (kIOServiceBusyWaiterState
& next
->__state
[1]));
4912 next
->__state
[1] &= ~kIOServiceBusyWaiterState
;
4913 IOLockLock( gIOServiceBusyLock
);
4914 thread_wakeup((event_t
) next
);
4915 IOLockUnlock( gIOServiceBusyLock
);
4918 next
->unlockForArbitration();
4921 if ((wasQuiet
|| nowQuiet
)) {
4922 uint64_t regID
= next
->getRegistryEntryID();
4924 ((wasQuiet
/*nowBusy*/) ? IOSERVICE_BUSY
: IOSERVICE_NONBUSY
),
4926 (uintptr_t) (regID
>> 32),
4931 next
->__timeBusy
= mach_absolute_time();
4933 next
->__accumBusy
+= mach_absolute_time() - next
->__timeBusy
;
4934 next
->__timeBusy
= 0;
4937 MessageClientsContext context
;
4939 context
.service
= next
;
4940 context
.type
= kIOMessageServiceBusyStateChange
;
4941 context
.argument
= (void *) wasQuiet
; /*nowBusy*/
4942 context
.argSize
= 0;
4944 applyToInterestNotifiers( next
, gIOBusyInterest
,
4945 &messageClientsApplier
, &context
);
4948 if (nowQuiet
&& (next
== gIOServiceRoot
)) {
4949 OSKext::considerUnloads();
4950 IOServiceTrace(IOSERVICE_REGISTRY_QUIET
, 0, 0, 0, 0);
4955 delta
= nowQuiet
? -1 : +1;
4956 } while ((wasQuiet
|| nowQuiet
) && (next
= next
->getProvider()));
4963 IOService::adjustBusy( SInt32 delta
)
4965 lockForArbitration();
4966 _adjustBusy( delta
);
4967 unlockForArbitration();
4971 IOService::getAccumulatedBusyTime( void )
4973 uint64_t accumBusy
= __accumBusy
;
4974 uint64_t timeBusy
= __timeBusy
;
4978 accumBusy
= __accumBusy
;
4979 timeBusy
= __timeBusy
;
4981 accumBusy
+= mach_absolute_time() - timeBusy
;
4983 }while (timeBusy
!= __timeBusy
);
4985 absolutetime_to_nanoseconds(*(AbsoluteTime
*)&accumBusy
, &nano
);
4991 IOService::getBusyState( void )
4993 return __state
[1] & kIOServiceBusyStateMask
;
4997 IOService::waitForState( UInt32 mask
, UInt32 value
,
4998 mach_timespec_t
* timeout
)
5000 panic("waitForState");
5001 return kIOReturnUnsupported
;
5005 IOService::waitForState( UInt32 mask
, UInt32 value
,
5009 int waitResult
= THREAD_AWAKENED
;
5010 bool computeDeadline
= true;
5011 AbsoluteTime abstime
;
5014 lockForArbitration();
5015 IOLockLock( gIOServiceBusyLock
);
5016 wait
= (value
!= (__state
[1] & mask
));
5018 __state
[1] |= kIOServiceBusyWaiterState
;
5019 unlockForArbitration();
5020 if (timeout
!= UINT64_MAX
) {
5021 if (computeDeadline
) {
5022 AbsoluteTime nsinterval
;
5023 nanoseconds_to_absolutetime(timeout
, &nsinterval
);
5024 clock_absolutetime_interval_to_deadline(nsinterval
, &abstime
);
5025 computeDeadline
= false;
5027 assert_wait_deadline((event_t
)this, THREAD_UNINT
, __OSAbsoluteTime(abstime
));
5029 assert_wait((event_t
)this, THREAD_UNINT
);
5032 unlockForArbitration();
5034 IOLockUnlock( gIOServiceBusyLock
);
5036 waitResult
= thread_block(THREAD_CONTINUE_NULL
);
5038 } while (wait
&& (waitResult
!= THREAD_TIMED_OUT
));
5040 if (waitResult
== THREAD_TIMED_OUT
) {
5041 return kIOReturnTimeout
;
5043 return kIOReturnSuccess
;
5048 IOService::waitQuiet( uint64_t timeout
)
5052 char * string
= NULL
;
5053 char * panicString
= NULL
;
5055 size_t panicStringLen
;
5058 bool pendingRequests
;
5059 bool dopanic
= false;
5063 * On kasan kernels, everything takes longer, so double the number of
5064 * timeout extensions. This should help with issues like 41259215
5065 * where WindowServer was timing out waiting for kextd to get all the
5066 * kasan kexts loaded and started.
5068 enum { kTimeoutExtensions
= 8 };
5069 #define WITH_IOWAITQUIET_EXTENSIONS 1
5070 #elif XNU_TARGET_OS_OSX && defined(__arm64__)
5071 enum { kTimeoutExtensions
= 1 };
5072 #define WITH_IOWAITQUIET_EXTENSIONS 0
5074 enum { kTimeoutExtensions
= 4 };
5075 #define WITH_IOWAITQUIET_EXTENSIONS 1
5078 time
= mach_absolute_time();
5079 pendingRequests
= false;
5080 for (loops
= 0; loops
< kTimeoutExtensions
; loops
++) {
5081 ret
= waitForState( kIOServiceBusyStateMask
, 0, timeout
);
5083 if (loops
&& (kIOReturnSuccess
== ret
)) {
5084 time
= mach_absolute_time() - time
;
5085 absolutetime_to_nanoseconds(*(AbsoluteTime
*)&time
, &nano
);
5086 IOLog("busy extended ok[%d], (%llds, %llds)\n",
5087 loops
, timeout
/ 1000000000ULL, nano
/ 1000000000ULL);
5089 } else if (kIOReturnTimeout
!= ret
) {
5091 } else if (timeout
< (41ull * NSEC_PER_SEC
)) {
5096 IORegistryIterator
* iter
;
5098 OSOrderedSet
* leaves
;
5100 IOService
* nextParent
;
5105 panicStringLen
= 256;
5107 string
= IONew(char, len
);
5110 panicString
= IONew(char, panicStringLen
);
5113 pendingRequests
= OSKext::pendingIOKitDaemonRequests();
5114 iter
= IORegistryIterator::iterateOver(this, gIOServicePlane
, kIORegistryIterateRecursively
);
5115 leaves
= OSOrderedSet::withCapacity(4);
5117 set
= iter
->iterateAll();
5119 if (string
&& panicString
&& leaves
&& set
) {
5120 string
[0] = panicString
[0] = 0;
5121 set
->setObject(this);
5122 while ((next
= (IOService
*) set
->getLastObject())) {
5123 if (next
->getBusyState()) {
5124 if (kIOServiceModuleStallState
& next
->__state
[1]) {
5125 pendingRequests
= true;
5127 leaves
->setObject(next
);
5129 while ((nextParent
= nextParent
->getProvider())) {
5130 set
->removeObject(nextParent
);
5131 leaves
->removeObject(nextParent
);
5134 set
->removeObject(next
);
5137 while ((next
= (IOService
*) leaves
->getLastObject())) {
5138 l
= snprintf(s
, len
, "%s'%s'", ((s
== string
) ? "" : ", "), next
->getName());
5144 leaves
->removeObject(next
);
5147 OSSafeReleaseNULL(leaves
);
5148 OSSafeReleaseNULL(set
);
5149 OSSafeReleaseNULL(iter
);
5152 dopanic
= (kIOWaitQuietPanics
& gIOKitDebug
);
5153 #if WITH_IOWAITQUIET_EXTENSIONS
5154 dopanic
= (dopanic
&& (loops
>= (kTimeoutExtensions
- 1)));
5156 snprintf(panicString
, panicStringLen
,
5157 "%s[%d], (%llds): %s",
5158 pendingRequests
? "IOKit Daemon (" kIOKitDaemonName
") stall" : "busy timeout",
5159 loops
, timeout
/ 1000000000ULL,
5160 string
? string
: "");
5161 IOLog("%s\n", panicString
);
5163 panic("%s", panicString
);
5164 } else if (!loops
) {
5165 getPMRootDomain()->startSpinDump(1);
5170 IODelete(string
, char, 256);
5173 IODelete(panicString
, char, panicStringLen
);
5180 IOService::waitQuiet( mach_timespec_t
* timeout
)
5185 timeoutNS
= timeout
->tv_sec
;
5186 timeoutNS
*= kSecondScale
;
5187 timeoutNS
+= timeout
->tv_nsec
;
5189 timeoutNS
= UINT64_MAX
;
5192 return waitQuiet(timeoutNS
);
5196 IOService::serializeProperties( OSSerialize
* s
) const
5199 ((IOService
*)this)->setProperty(((IOService
*)this)->__state
,
5200 sizeof(__state
), "__state");
5202 return super::serializeProperties(s
);
5206 IOService::resetRematchProperties()
5208 removeProperty(gIORematchCountKey
);
5209 removeProperty(gIORematchPersonalityKey
);
5214 _IOConfigThread::main(void * arg
, wait_result_t result
)
5216 _IOConfigThread
* self
= (_IOConfigThread
*) arg
;
5217 _IOServiceJob
* job
;
5221 thread_precedence_policy_data_t precedence
= { -1 };
5223 kr
= thread_policy_set(current_thread(),
5224 THREAD_PRECEDENCE_POLICY
,
5225 (thread_policy_t
) &precedence
,
5226 THREAD_PRECEDENCE_POLICY_COUNT
);
5227 if (KERN_SUCCESS
!= kr
) {
5228 IOLog("thread_policy_set(%d)\n", kr
);
5234 semaphore_wait( gJobsSemaphore
);
5236 IOTakeLock( gJobsLock
);
5237 job
= (_IOServiceJob
*) gJobs
->getFirstObject();
5239 gJobs
->removeObject(job
);
5242 // gNumConfigThreads--; // we're out of service
5243 gNumWaitingThreads
--; // we're out of service
5245 IOUnlock( gJobsLock
);
5250 if (gIOKitDebug
& kIOLogConfig
) {
5251 LOG("config(%p): starting on %s, %d\n",
5252 IOSERVICE_OBFUSCATE(IOThreadSelf()), job
->nub
->getName(), job
->type
);
5255 switch (job
->type
) {
5257 nub
->doServiceMatch( job
->options
);
5261 LOG("config(%p): strange type (%d)\n",
5262 IOSERVICE_OBFUSCATE(IOThreadSelf()), job
->type
);
5269 IOTakeLock( gJobsLock
);
5270 alive
= (gOutstandingJobs
> gNumWaitingThreads
);
5272 gNumWaitingThreads
++; // back in service
5274 // gNumConfigThreads++;
5276 if (0 == --gNumConfigThreads
) {
5277 // IOLog("MATCH IDLE\n");
5278 IOLockWakeup( gJobsLock
, (event_t
) &gNumConfigThreads
, /* one-thread */ false );
5281 IOUnlock( gJobsLock
);
5285 if (gIOKitDebug
& kIOLogConfig
) {
5286 LOG("config(%p): terminating\n", IOSERVICE_OBFUSCATE(IOThreadSelf()));
5293 IOService::waitMatchIdle( UInt32 msToWait
)
5296 int waitResult
= THREAD_AWAKENED
;
5297 bool computeDeadline
= true;
5298 AbsoluteTime deadline
;
5300 IOLockLock( gJobsLock
);
5302 wait
= (0 != gNumConfigThreads
);
5305 if (computeDeadline
) {
5306 clock_interval_to_deadline(
5307 msToWait
, kMillisecondScale
, &deadline
);
5308 computeDeadline
= false;
5310 waitResult
= IOLockSleepDeadline( gJobsLock
, &gNumConfigThreads
,
5311 deadline
, THREAD_UNINT
);
5313 waitResult
= IOLockSleep( gJobsLock
, &gNumConfigThreads
,
5317 } while (wait
&& (waitResult
!= THREAD_TIMED_OUT
));
5318 IOLockUnlock( gJobsLock
);
5320 if (waitResult
== THREAD_TIMED_OUT
) {
5321 return kIOReturnTimeout
;
5323 return kIOReturnSuccess
;
5328 IOService::cpusRunning(void)
5330 gCPUsRunning
= true;
5334 _IOServiceJob::pingConfig( _IOServiceJob
* job
)
5343 IOTakeLock( gJobsLock
);
5346 if (nub
== gIOResources
) {
5347 gJobs
->setFirstObject( job
);
5349 gJobs
->setLastObject( job
);
5352 count
= gNumWaitingThreads
;
5353 // if( gNumConfigThreads) count++;// assume we're called from a config thread
5355 create
= ((gOutstandingJobs
> count
)
5356 && ((gNumConfigThreads
< gMaxConfigThreads
)
5357 || (nub
== gIOResources
)
5360 gNumConfigThreads
++;
5361 gNumWaitingThreads
++;
5362 if (gNumConfigThreads
> gHighNumConfigThreads
) {
5363 gHighNumConfigThreads
= gNumConfigThreads
;
5367 IOUnlock( gJobsLock
);
5372 if (gIOKitDebug
& kIOLogConfig
) {
5373 LOG("config(%d): creating\n", gNumConfigThreads
- 1);
5375 _IOConfigThread::configThread(nub
->getName());
5378 semaphore_signal( gJobsSemaphore
);
5381 struct IOServiceMatchContext
{
5382 OSDictionary
* table
;
5391 IOService::instanceMatch(const OSObject
* entry
, void * context
)
5393 IOServiceMatchContext
* ctx
= (typeof(ctx
))context
;
5394 IOService
* service
= (typeof(service
))entry
;
5395 OSDictionary
* table
= ctx
->table
;
5396 uint32_t options
= ctx
->options
;
5397 uint32_t state
= ctx
->state
;
5403 match
= ((state
== (state
& service
->__state
[0]))
5404 && (0 == (service
->__state
[0] & kIOServiceInactiveState
)));
5408 match
= service
->matchInternal(table
, options
, &done
);
5410 ctx
->count
+= table
->getCount();
5418 if ((kIONotifyOnce
& options
) && (ctx
->done
== ctx
->count
)) {
5420 ctx
->result
= service
;
5422 } else if (!ctx
->result
) {
5423 ctx
->result
= OSSet::withObjects((const OSObject
**) &service
, 1, 1);
5425 ((OSSet
*)ctx
->result
)->setObject(service
);
5430 // internal - call with gNotificationLock
5432 IOService::copyExistingServices( OSDictionary
* matching
,
5433 IOOptionBits inState
, IOOptionBits options
)
5435 OSObject
* current
= NULL
;
5437 IOService
* service
;
5446 OSSerialize
* s
= OSSerialize::withCapacity(128);
5447 matching
->serialize(s
);
5450 if ((obj
= matching
->getObject(gIOProviderClassKey
))
5452 && gIOResourcesKey
->isEqualTo(obj
)
5453 && (service
= gIOResources
)) {
5454 if ((inState
== (service
->__state
[0] & inState
))
5455 && (0 == (service
->__state
[0] & kIOServiceInactiveState
))
5456 && service
->matchPassive(matching
, options
)) {
5457 if (options
& kIONotifyOnce
) {
5461 current
= OSSet::withObjects((const OSObject
**) &service
, 1, 1 );
5465 IOServiceMatchContext ctx
;
5467 options
|= kIOServiceClassDone
;
5468 ctx
.table
= matching
;
5469 ctx
.state
= inState
;
5472 ctx
.options
= options
;
5475 if ((str
= OSDynamicCast(OSString
, obj
))) {
5476 const OSSymbol
* sym
= OSSymbol::withString(str
);
5477 OSMetaClass::applyToInstancesOfClassName(sym
, instanceMatch
, &ctx
);
5480 IOService::gMetaClass
.applyToInstances(instanceMatch
, &ctx
);
5483 if (((!(options
& kIONotifyOnce
) || !ctx
.result
))
5484 && matching
->getObject(gIOCompatibilityMatchKey
)) {
5485 IOServiceCompatibility::gMetaClass
.applyToInstances(instanceMatch
, &ctx
);
5488 current
= ctx
.result
;
5489 options
|= kIOServiceInternalDone
;
5490 if (current
&& (ctx
.done
!= ctx
.count
)) {
5491 OSSet
* source
= OSDynamicCast(OSSet
, current
);
5493 while ((service
= (IOService
*) source
->getAnyObject())) {
5494 if (service
->matchPassive(matching
, options
)) {
5495 if (options
& kIONotifyOnce
) {
5501 ((OSSet
*)current
)->setObject( service
);
5503 current
= OSSet::withObjects(
5504 (const OSObject
**) &service
, 1, 1 );
5507 source
->removeObject(service
);
5515 OSObject
* _current
= 0;
5517 iter
= IORegistryIterator::iterateOver( gIOServicePlane
,
5518 kIORegistryIterateRecursively
);
5522 while ((service
= (IOService
*) iter
->getNextObject())) {
5523 if ((inState
== (service
->__state
[0] & inState
))
5524 && (0 == (service
->__state
[0] & kIOServiceInactiveState
))
5525 && service
->matchPassive(matching
, 0)) {
5526 if (options
& kIONotifyOnce
) {
5532 ((OSSet
*)_current
)->setObject( service
);
5534 _current
= OSSet::withObjects(
5535 (const OSObject
**) &service
, 1, 1 );
5539 } while (!service
&& !iter
->isValid());
5543 if (((current
!= 0) != (_current
!= 0))
5544 || (current
&& _current
&& !current
->isEqualTo(_current
))) {
5545 OSSerialize
* s1
= OSSerialize::withCapacity(128);
5546 OSSerialize
* s2
= OSSerialize::withCapacity(128);
5547 current
->serialize(s1
);
5548 _current
->serialize(s2
);
5549 kprintf("**mismatch** %p %p\n%s\n%s\n%s\n", IOSERVICE_OBFUSCATE(current
),
5550 IOSERVICE_OBFUSCATE(_current
), s
->text(), s1
->text(), s2
->text());
5556 _current
->release();
5563 if (current
&& (0 == (options
& (kIONotifyOnce
| kIOServiceExistingSet
)))) {
5564 iter
= OSCollectionIterator::withCollection((OSSet
*)current
);
5574 IOService::getMatchingServices( OSDictionary
* matching
)
5578 // is a lock even needed?
5581 iter
= (OSIterator
*) copyExistingServices( matching
,
5582 kIOServiceMatchedState
);
5590 IOService::copyMatchingService( OSDictionary
* matching
)
5592 IOService
* service
;
5594 // is a lock even needed?
5597 service
= (IOService
*) copyExistingServices( matching
,
5598 kIOServiceMatchedState
, kIONotifyOnce
);
5605 struct _IOServiceMatchingNotificationHandlerRef
{
5606 IOServiceNotificationHandler handler
;
5611 _IOServiceMatchingNotificationHandler( void * target
, void * refCon
,
5612 IOService
* newService
,
5613 IONotifier
* notifier
)
5615 return (*((_IOServiceNotifier
*) notifier
)->compatHandler
)(target
, refCon
, newService
);
5618 // internal - call with gNotificationLock
5620 IOService::setNotification(
5621 const OSSymbol
* type
, OSDictionary
* matching
,
5622 IOServiceMatchingNotificationHandler handler
, void * target
, void * ref
,
5625 _IOServiceNotifier
* notify
= NULL
;
5632 notify
= new _IOServiceNotifier
;
5633 if (notify
&& !notify
->init()) {
5639 notify
->handler
= handler
;
5640 notify
->target
= target
;
5641 notify
->type
= type
;
5642 notify
->matching
= matching
;
5644 if (handler
== &_IOServiceMatchingNotificationHandler
) {
5645 notify
->compatHandler
= ((_IOServiceMatchingNotificationHandlerRef
*)ref
)->handler
;
5646 notify
->ref
= ((_IOServiceMatchingNotificationHandlerRef
*)ref
)->ref
;
5650 notify
->priority
= priority
;
5651 notify
->state
= kIOServiceNotifyEnable
;
5652 queue_init( ¬ify
->handlerInvocations
);
5656 if (NULL
== (set
= (OSOrderedSet
*) gNotifications
->getObject( type
))) {
5657 set
= OSOrderedSet::withCapacity( 1,
5658 IONotifyOrdering
, NULL
);
5660 gNotifications
->setObject( type
, set
);
5664 notify
->whence
= set
;
5666 set
->setObject( notify
);
5673 // internal - call with gNotificationLock
5675 IOService::doInstallNotification(
5676 const OSSymbol
* type
, OSDictionary
* matching
,
5677 IOServiceMatchingNotificationHandler handler
,
5678 void * target
, void * ref
,
5679 SInt32 priority
, OSIterator
** existing
)
5682 IONotifier
* notify
;
5683 IOOptionBits inState
;
5689 if (type
== gIOPublishNotification
) {
5690 inState
= kIOServiceRegisteredState
;
5691 } else if (type
== gIOFirstPublishNotification
) {
5692 inState
= kIOServiceFirstPublishState
;
5693 } else if (type
== gIOMatchedNotification
) {
5694 inState
= kIOServiceMatchedState
;
5695 } else if (type
== gIOFirstMatchNotification
) {
5696 inState
= kIOServiceFirstMatchState
;
5697 } else if ((type
== gIOTerminatedNotification
) || (type
== gIOWillTerminateNotification
)) {
5703 notify
= setNotification( type
, matching
, handler
, target
, ref
, priority
);
5706 // get the current set
5707 exist
= (OSIterator
*) copyExistingServices( matching
, inState
);
5717 #if !defined(__LP64__)
5719 IOService::installNotification(const OSSymbol
* type
, OSDictionary
* matching
,
5720 IOServiceNotificationHandler handler
,
5721 void * target
, void * refCon
,
5722 SInt32 priority
, OSIterator
** existing
)
5724 IONotifier
* result
;
5725 _IOServiceMatchingNotificationHandlerRef ref
;
5726 ref
.handler
= handler
;
5729 result
= (_IOServiceNotifier
*) installNotification( type
, matching
,
5730 &_IOServiceMatchingNotificationHandler
,
5731 target
, &ref
, priority
, existing
);
5733 matching
->release();
5739 #endif /* !defined(__LP64__) */
5743 IOService::installNotification(
5744 const OSSymbol
* type
, OSDictionary
* matching
,
5745 IOServiceMatchingNotificationHandler handler
,
5746 void * target
, void * ref
,
5747 SInt32 priority
, OSIterator
** existing
)
5749 IONotifier
* notify
;
5753 notify
= doInstallNotification( type
, matching
, handler
, target
, ref
,
5754 priority
, existing
);
5756 // in case handler remove()s
5767 IOService::addNotification(
5768 const OSSymbol
* type
, OSDictionary
* matching
,
5769 IOServiceNotificationHandler handler
,
5770 void * target
, void * refCon
,
5773 IONotifier
* result
;
5774 _IOServiceMatchingNotificationHandlerRef ref
;
5776 ref
.handler
= handler
;
5779 result
= addMatchingNotification(type
, matching
, &_IOServiceMatchingNotificationHandler
,
5780 target
, &ref
, priority
);
5783 matching
->release();
5790 IOService::addMatchingNotification(
5791 const OSSymbol
* type
, OSDictionary
* matching
,
5792 IOServiceMatchingNotificationHandler handler
,
5793 void * target
, void * ref
,
5796 OSIterator
* existing
= NULL
;
5798 _IOServiceNotifier
* notify
;
5801 ret
= notify
= (_IOServiceNotifier
*) installNotification( type
, matching
,
5802 handler
, target
, ref
, priority
, &existing
);
5807 // send notifications for existing set
5809 while ((next
= (IOService
*) existing
->getNextObject())) {
5810 if (0 == (next
->__state
[0] & kIOServiceInactiveState
)) {
5811 next
->invokeNotifier( notify
);
5814 existing
->release();
5818 bool removed
= (NULL
== notify
->whence
);
5821 ret
= gIOServiceNullNotifier
;
5829 IOServiceMatchingNotificationHandlerToBlock( void * target __unused
, void * refCon
,
5830 IOService
* newService
,
5831 IONotifier
* notifier
)
5833 return ((IOServiceMatchingNotificationHandlerBlock
) refCon
)(newService
, notifier
);
5837 IOService::addMatchingNotification(
5838 const OSSymbol
* type
, OSDictionary
* matching
,
5840 IOServiceMatchingNotificationHandlerBlock handler
)
5842 IONotifier
* notify
;
5845 block
= Block_copy(handler
);
5850 notify
= addMatchingNotification(type
, matching
,
5851 &IOServiceMatchingNotificationHandlerToBlock
, NULL
, block
, priority
);
5854 Block_release(block
);
5861 IOService::userServerCheckInTokenNotificationHandler(
5862 __unused IOUserServerCheckInToken
*token
,
5871 IOService::syncNotificationHandler(
5872 void * /* target */, void * ref
,
5873 IOService
* newService
,
5874 IONotifier
* notifier
)
5877 if (!*((IOService
**) ref
)) {
5878 newService
->retain();
5879 (*(IOService
**) ref
) = newService
;
5888 IOService::waitForMatchingServiceWithToken( OSDictionary
* matching
,
5890 IOUserServerCheckInToken
* checkInToken
)
5892 IONotifier
* notify
= NULL
;
5893 // priority doesn't help us much since we need a thread wakeup
5894 SInt32 priority
= 0;
5903 #if DEBUG || DEVELOPMENT
5904 char currentName
[MAXTHREADNAMESIZE
];
5905 char newName
[MAXTHREADNAMESIZE
];
5908 OSDictionary
* dict
;
5910 currentName
[0] = '\0';
5911 if (thread_has_thread_name(current_thread())) {
5913 obj
= matching
->getObject(gIOPropertyMatchKey
);
5914 if ((dict
= OSDynamicCast(OSDictionary
, obj
))) {
5915 OSObject
* result __block
= NULL
;
5916 dict
->iterateObjects(^bool (const OSSymbol
* sym
, OSObject
* value
) {
5917 result
= __DECONST(OSObject
*, sym
);
5923 obj
= matching
->getObject(gIOResourceMatchKey
);
5926 obj
= matching
->getObject(gIONameMatchKey
);
5929 obj
= matching
->getObject(gIOProviderClassKey
);
5931 if ((str
= OSDynamicCast(OSString
, obj
))) {
5932 thread_get_thread_name(current_thread(), currentName
);
5933 snprintf(newName
, sizeof(newName
), "Waiting_'%s'", str
->getCStringNoCopy());
5934 thread_set_thread_name(current_thread(), newName
);
5937 #endif /* DEBUG || DEVELOPMENT */
5942 checkInToken
->setNoSendersNotification(&IOService::userServerCheckInTokenNotificationHandler
,
5945 result
= (IOService
*) copyExistingServices( matching
,
5946 kIOServiceMatchedState
, kIONotifyOnce
);
5950 notify
= IOService::setNotification( gIOMatchedNotification
, matching
,
5951 &IOService::syncNotificationHandler
, (void *) NULL
,
5952 &result
, priority
);
5956 if (UINT64_MAX
!= timeout
) {
5957 AbsoluteTime deadline
;
5958 nanoseconds_to_absolutetime(timeout
, &deadline
);
5959 clock_absolutetime_interval_to_deadline(deadline
, &deadline
);
5960 SLEEPNOTIFYTO(&result
, deadline
);
5962 SLEEPNOTIFY(&result
);
5968 #if DEBUG || DEVELOPMENT
5969 if (currentName
[0]) {
5970 thread_set_thread_name(current_thread(), currentName
);
5972 #endif /* DEBUG || DEVELOPMENT */
5975 notify
->remove(); // dequeues
5979 checkInToken
->clearNotification();
5986 IOService::waitForMatchingService( OSDictionary
* matching
,
5989 return IOService::waitForMatchingServiceWithToken(matching
, timeout
, NULL
);
5993 IOService::waitForService( OSDictionary
* matching
,
5994 mach_timespec_t
* timeout
)
6000 timeoutNS
= timeout
->tv_sec
;
6001 timeoutNS
*= kSecondScale
;
6002 timeoutNS
+= timeout
->tv_nsec
;
6004 timeoutNS
= UINT64_MAX
;
6007 result
= waitForMatchingService(matching
, timeoutNS
);
6009 matching
->release();
6019 IOService::deliverNotification( const OSSymbol
* type
,
6020 IOOptionBits orNewState
, IOOptionBits andNewState
)
6022 panic("deliverNotification");
6026 IOService::copyNotifiers(const OSSymbol
* type
,
6027 IOOptionBits orNewState
, IOOptionBits andNewState
)
6029 _IOServiceNotifier
* notify
;
6031 OSArray
* willSend
= NULL
;
6033 lockForArbitration();
6035 if ((0 == (__state
[0] & kIOServiceInactiveState
))
6036 || (type
== gIOTerminatedNotification
)
6037 || (type
== gIOWillTerminateNotification
)) {
6040 iter
= OSCollectionIterator::withCollection((OSOrderedSet
*)
6041 gNotifications
->getObject( type
));
6044 while ((notify
= (_IOServiceNotifier
*) iter
->getNextObject())) {
6045 if (matchPassive(notify
->matching
, 0)
6046 && (kIOServiceNotifyEnable
& notify
->state
)) {
6047 if (NULL
== willSend
) {
6048 willSend
= OSArray::withCapacity(8);
6051 willSend
->setObject( notify
);
6057 __state
[0] = (__state
[0] | orNewState
) & andNewState
;
6061 unlockForArbitration();
6067 IOService::getState( void ) const
6073 * Helpers to make matching objects for simple cases
6077 IOService::serviceMatching( const OSString
* name
,
6078 OSDictionary
* table
)
6080 const OSString
* str
;
6082 str
= OSSymbol::withString(name
);
6088 table
= OSDictionary::withCapacity( 2 );
6091 table
->setObject(gIOProviderClassKey
, (OSObject
*)str
);
6099 IOService::serviceMatching( const char * name
,
6100 OSDictionary
* table
)
6102 const OSString
* str
;
6104 str
= OSSymbol::withCString( name
);
6109 table
= serviceMatching( str
, table
);
6115 IOService::nameMatching( const OSString
* name
,
6116 OSDictionary
* table
)
6119 table
= OSDictionary::withCapacity( 2 );
6122 table
->setObject( gIONameMatchKey
, (OSObject
*)name
);
6129 IOService::nameMatching( const char * name
,
6130 OSDictionary
* table
)
6132 const OSString
* str
;
6134 str
= OSSymbol::withCString( name
);
6139 table
= nameMatching( str
, table
);
6145 IOService::resourceMatching( const OSString
* str
,
6146 OSDictionary
* table
)
6148 table
= serviceMatching( gIOResourcesKey
, table
);
6150 table
->setObject( gIOResourceMatchKey
, (OSObject
*) str
);
6157 IOService::resourceMatching( const char * name
,
6158 OSDictionary
* table
)
6160 const OSSymbol
* str
;
6162 str
= OSSymbol::withCString( name
);
6167 table
= resourceMatching( str
, table
);
6174 IOService::propertyMatching( const OSSymbol
* key
, const OSObject
* value
,
6175 OSDictionary
* table
)
6177 OSDictionary
* properties
;
6179 properties
= OSDictionary::withCapacity( 2 );
6183 properties
->setObject( key
, value
);
6186 table
= OSDictionary::withCapacity( 2 );
6189 table
->setObject( gIOPropertyMatchKey
, properties
);
6192 properties
->release();
6198 IOService::registryEntryIDMatching( uint64_t entryID
,
6199 OSDictionary
* table
)
6203 num
= OSNumber::withNumber( entryID
, 64 );
6209 table
= OSDictionary::withCapacity( 2 );
6212 table
->setObject( gIORegistryEntryIDKey
, num
);
6224 * _IOServiceNotifier
6227 // wait for all threads, other than the current one,
6228 // to exit the handler
6231 _IOServiceNotifier::wait()
6233 _IOServiceNotifierInvocation
* next
;
6238 queue_iterate( &handlerInvocations
, next
,
6239 _IOServiceNotifierInvocation
*, link
) {
6240 if (next
->thread
!= current_thread()) {
6246 state
|= kIOServiceNotifyWaiter
;
6253 _IOServiceNotifier::free()
6255 assert( queue_empty( &handlerInvocations
));
6257 if (handler
== &IOServiceMatchingNotificationHandlerToBlock
) {
6265 _IOServiceNotifier::remove()
6270 whence
->removeObject((OSObject
*) this );
6274 matching
->release();
6278 state
&= ~kIOServiceNotifyEnable
;
6288 _IOServiceNotifier::disable()
6294 ret
= (0 != (kIOServiceNotifyEnable
& state
));
6295 state
&= ~kIOServiceNotifyEnable
;
6306 _IOServiceNotifier::enable( bool was
)
6310 state
|= kIOServiceNotifyEnable
;
6312 state
&= ~kIOServiceNotifyEnable
;
6319 * _IOServiceNullNotifier
6323 _IOServiceNullNotifier::taggedRetain(const void *tag
) const
6327 _IOServiceNullNotifier::taggedRelease(const void *tag
, const int when
) const
6331 _IOServiceNullNotifier::free()
6335 _IOServiceNullNotifier::wait()
6339 _IOServiceNullNotifier::remove()
6343 _IOServiceNullNotifier::enable(bool was
)
6347 _IOServiceNullNotifier::disable()
6357 IOResources::resources( void )
6361 inst
= new IOResources
;
6362 if (inst
&& !inst
->init()) {
6371 IOResources::init( OSDictionary
* dictionary
)
6373 // Do super init first
6374 if (!IOService::init()) {
6378 // Allow PAL layer to publish a value
6379 const char *property_name
;
6382 pal_get_resource_property( &property_name
, &property_value
);
6384 if (property_name
) {
6386 const OSSymbol
* sym
;
6388 if ((num
= OSNumber::withNumber(property_value
, 32)) != NULL
) {
6389 if ((sym
= OSSymbol::withCString( property_name
)) != NULL
) {
6390 this->setProperty( sym
, num
);
6401 IOResources::newUserClient(task_t owningTask
, void * securityID
,
6402 UInt32 type
, OSDictionary
* properties
,
6403 IOUserClient
** handler
)
6405 return kIOReturnUnsupported
;
6409 IOResources::getWorkLoop() const
6411 // If we are the resource root
6412 // then use the platform's workloop
6413 if (this == (IOResources
*) gIOResources
) {
6414 return getPlatform()->getWorkLoop();
6416 return IOService::getWorkLoop();
6421 IOResourcesMatchPropertyTable(IOService
* resources
, OSDictionary
* table
)
6431 prop
= table
->getObject( gIOResourceMatchKey
);
6432 str
= OSDynamicCast( OSString
, prop
);
6434 ok
= (NULL
!= resources
->getProperty( str
));
6435 } else if ((set
= OSDynamicCast( OSSet
, prop
))) {
6436 iter
= OSCollectionIterator::withCollection( set
);
6437 ok
= (iter
!= NULL
);
6438 while (ok
&& (str
= OSDynamicCast( OSString
, iter
->getNextObject()))) {
6439 ok
= (NULL
!= resources
->getProperty( str
));
6445 } else if ((prop
= table
->getObject(gIOResourceMatchedKey
))) {
6446 obj
= resources
->copyProperty(gIOResourceMatchedKey
);
6447 keys
= OSDynamicCast(OSArray
, obj
);
6450 // assuming OSSymbol
6451 ok
= ((-1U) != keys
->getNextIndexOfObject(prop
, 0));
6453 OSSafeReleaseNULL(obj
);
6460 IOResources::matchPropertyTable( OSDictionary
* table
)
6462 return IOResourcesMatchPropertyTable(this, table
);
6470 IOUserResources::resources( void )
6472 IOUserResources
* inst
;
6474 inst
= OSTypeAlloc(IOUserResources
);
6475 if (inst
&& !inst
->init()) {
6484 IOUserResources::init( OSDictionary
* dictionary
)
6486 // Do super init first
6487 if (!IOService::init()) {
6494 IOUserResources::newUserClient(task_t owningTask
, void * securityID
,
6495 UInt32 type
, OSDictionary
* properties
,
6496 IOUserClient
** handler
)
6498 return kIOReturnUnsupported
;
6502 IOUserResources::getWorkLoop() const
6504 return getPlatform()->getWorkLoop();
6508 IOUserResources::matchPropertyTable( OSDictionary
* table
)
6510 return IOResourcesMatchPropertyTable(this, table
);
6516 IOService::consoleLockTimer(thread_call_param_t p0
, thread_call_param_t p1
)
6518 IOService::updateConsoleUsers(NULL
, 0);
6522 IOService::updateConsoleUsers(OSArray
* consoleUsers
, IOMessage systemMessage
, bool afterUserspaceReboot
)
6524 IORegistryEntry
* regEntry
;
6525 OSObject
* locked
= kOSBooleanFalse
;
6528 OSDictionary
* user
;
6529 clock_sec_t now
= 0;
6530 clock_usec_t microsecs
;
6532 regEntry
= IORegistryEntry::getRegistryRoot();
6534 if (!gIOChosenEntry
) {
6535 gIOChosenEntry
= IORegistryEntry::fromPath("/chosen", gIODTPlane
);
6538 IOLockLock(gIOConsoleUsersLock
);
6540 if (systemMessage
) {
6541 sSystemPower
= systemMessage
;
6543 if (kIOMessageSystemHasPoweredOn
== systemMessage
) {
6544 uint32_t lockState
= IOHibernateWasScreenLocked();
6545 switch (lockState
) {
6548 case kIOScreenLockLocked
:
6549 case kIOScreenLockFileVaultDialog
:
6550 gIOConsoleBooterLockState
= kOSBooleanTrue
;
6552 case kIOScreenLockNoLock
:
6553 gIOConsoleBooterLockState
= NULL
;
6555 case kIOScreenLockUnlocked
:
6557 gIOConsoleBooterLockState
= kOSBooleanFalse
;
6561 #endif /* HIBERNATION */
6565 OSNumber
* num
= NULL
;
6566 bool loginLocked
= true;
6568 gIOConsoleLoggedIn
= false;
6570 (user
= OSDynamicCast(OSDictionary
, consoleUsers
->getObject(idx
)));
6572 gIOConsoleLoggedIn
|= ((kOSBooleanTrue
== user
->getObject(gIOConsoleSessionOnConsoleKey
))
6573 && (kOSBooleanTrue
== user
->getObject(gIOConsoleSessionLoginDoneKey
)));
6575 loginLocked
&= (kOSBooleanTrue
== user
->getObject(gIOConsoleSessionScreenIsLockedKey
));
6577 num
= OSDynamicCast(OSNumber
, user
->getObject(gIOConsoleSessionScreenLockedTimeKey
));
6581 if (!loginLocked
|| afterUserspaceReboot
) {
6582 gIOConsoleBooterLockState
= NULL
;
6584 IOLog("IOConsoleUsers: time(%d) %ld->%d, lin %d, llk %d, \n",
6585 (num
!= NULL
), gIOConsoleLockTime
, (num
? num
->unsigned32BitValue() : 0),
6586 gIOConsoleLoggedIn
, loginLocked
);
6587 #endif /* HIBERNATION */
6588 gIOConsoleLockTime
= num
? num
->unsigned32BitValue() : 0;
6591 if (!gIOConsoleLoggedIn
6592 || (kIOMessageSystemWillSleep
== sSystemPower
)
6593 || (kIOMessageSystemPagingOff
== sSystemPower
)) {
6594 if (afterUserspaceReboot
) {
6595 // set "locked" to false after a user space reboot
6596 // because the reboot happens directly after a user
6597 // logs into the machine via fvunlock mode.
6598 locked
= kOSBooleanFalse
;
6600 locked
= kOSBooleanTrue
;
6604 else if (gIOConsoleBooterLockState
) {
6605 locked
= gIOConsoleBooterLockState
;
6607 #endif /* HIBERNATION */
6608 else if (gIOConsoleLockTime
) {
6609 clock_get_calendar_microtime(&now
, µsecs
);
6610 if (gIOConsoleLockTime
> now
) {
6611 AbsoluteTime deadline
;
6612 clock_sec_t interval
;
6613 uint32_t interval32
;
6615 interval
= (gIOConsoleLockTime
- now
);
6616 interval32
= (uint32_t) interval
;
6617 if (interval32
!= interval
) {
6618 interval32
= UINT_MAX
;
6620 clock_interval_to_deadline(interval32
, kSecondScale
, &deadline
);
6621 thread_call_enter_delayed(gIOConsoleLockCallout
, deadline
);
6623 locked
= kOSBooleanTrue
;
6627 publish
= (consoleUsers
|| (locked
!= regEntry
->getProperty(gIOConsoleLockedKey
)));
6629 regEntry
->setProperty(gIOConsoleLockedKey
, locked
);
6631 regEntry
->setProperty(gIOConsoleUsersKey
, consoleUsers
);
6633 OSIncrementAtomic( &gIOConsoleUsersSeed
);
6637 if (gIOChosenEntry
) {
6638 if (locked
== kOSBooleanTrue
) {
6639 gIOScreenLockState
= kIOScreenLockLocked
;
6640 } else if (gIOConsoleLockTime
) {
6641 gIOScreenLockState
= kIOScreenLockUnlocked
;
6643 gIOScreenLockState
= kIOScreenLockNoLock
;
6645 gIOChosenEntry
->setProperty(kIOScreenLockStateKey
, &gIOScreenLockState
, sizeof(gIOScreenLockState
));
6647 IOLog("IOConsoleUsers: gIOScreenLockState %d, hs %d, bs %d, now %ld, sm 0x%x\n",
6648 gIOScreenLockState
, gIOHibernateState
, (gIOConsoleBooterLockState
!= NULL
), now
, systemMessage
);
6650 #endif /* HIBERNATION */
6652 IOLockUnlock(gIOConsoleUsersLock
);
6655 publishResource( gIOConsoleUsersSeedKey
, gIOConsoleUsersSeedValue
);
6657 MessageClientsContext context
;
6659 context
.service
= getServiceRoot();
6660 context
.type
= kIOMessageConsoleSecurityChange
;
6661 context
.argument
= (void *) regEntry
;
6662 context
.argSize
= 0;
6664 applyToInterestNotifiers(getServiceRoot(), gIOConsoleSecurityInterest
,
6665 &messageClientsApplier
, &context
);
6670 IOResources::setProperties( OSObject
* properties
)
6673 const OSSymbol
* key
;
6674 OSDictionary
* dict
;
6675 OSCollectionIterator
* iter
;
6677 if (!IOTaskHasEntitlement(current_task(), kIOResourcesSetPropertyKey
)) {
6678 err
= IOUserClient::clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator
);
6679 if (kIOReturnSuccess
!= err
) {
6684 dict
= OSDynamicCast(OSDictionary
, properties
);
6686 return kIOReturnBadArgument
;
6689 iter
= OSCollectionIterator::withCollection( dict
);
6691 return kIOReturnBadArgument
;
6694 while ((key
= OSDynamicCast(OSSymbol
, iter
->getNextObject()))) {
6695 if (gIOConsoleUsersKey
== key
) {
6697 OSArray
* consoleUsers
;
6698 consoleUsers
= OSDynamicCast(OSArray
, dict
->getObject(key
));
6699 if (!consoleUsers
) {
6702 IOService::updateConsoleUsers(consoleUsers
, 0);
6706 publishResource( key
, dict
->getObject(key
));
6711 return kIOReturnSuccess
;
6715 * Helpers for matching dictionaries.
6716 * Keys existing in matching are checked in properties.
6717 * Keys may be a string or OSCollection of IOStrings
6721 IOService::compareProperty( OSDictionary
* matching
,
6728 value
= matching
->getObject( key
);
6730 prop
= copyProperty(key
);
6731 ok
= value
->isEqualTo(prop
);
6744 IOService::compareProperty( OSDictionary
* matching
,
6745 const OSString
* key
)
6751 value
= matching
->getObject( key
);
6753 prop
= copyProperty(key
);
6754 ok
= value
->isEqualTo(prop
);
6765 #ifndef __clang_analyzer__
6766 // Implementation of this function is hidden from the static analyzer.
6767 // The analyzer was worried about this function's confusing contract over
6768 // the 'keys' parameter. The contract is to either release it or not release it
6769 // depending on whether 'matching' is non-null. Such contracts are discouraged
6770 // but changing it now would break compatibility.
6772 IOService::compareProperties( OSDictionary
* matching
,
6773 OSCollection
* keys
)
6775 OSCollectionIterator
* iter
;
6776 const OSString
* key
;
6779 if (!matching
|| !keys
) {
6783 iter
= OSCollectionIterator::withCollection( keys
);
6786 while (ok
&& (key
= OSDynamicCast( OSString
, iter
->getNextObject()))) {
6787 ok
= compareProperty( matching
, key
);
6792 keys
->release(); // !! consume a ref !!
6796 #endif // __clang_analyzer__
6798 /* Helper to add a location matching dict to the table */
6801 IOService::addLocation( OSDictionary
* table
)
6803 OSDictionary
* dict
;
6809 dict
= OSDictionary::withCapacity( 1 );
6811 bool ok
= table
->setObject( gIOLocationMatchKey
, dict
);
6822 * Go looking for a provider to match a location dict.
6826 IOService::matchLocation( IOService
* /* client */ )
6830 parent
= getProvider();
6833 parent
= parent
->matchLocation( this );
6840 IOService::matchInternal(OSDictionary
* table
, uint32_t options
, uint32_t * did
)
6845 OSDictionary
* matchProps
;
6846 IORegistryEntry
* entry
;
6849 bool changesOK
= (0 != (kIOServiceChangesOK
& options
));
6854 count
= table
->getCount();
6858 if (table
->getObject(gIOCompatibilityMatchKey
)) {
6860 obj
= copyProperty(gIOCompatibilityPropertiesKey
);
6861 matchProps
= OSDynamicCast(OSDictionary
, obj
);
6863 OSSafeReleaseNULL(obj
);
6867 str
= OSDynamicCast(OSString
, table
->getObject(gIOProviderClassKey
));
6870 if (matchProps
&& (obj
= matchProps
->getObject(gIOClassKey
))) {
6871 match
= str
->isEqualTo(obj
);
6873 match
= ((kIOServiceClassDone
& options
) || (NULL
!= metaCast(str
)));
6877 match
= (0 != metaCast( str
));
6878 if ((kIOServiceClassDone
& options
) && !match
) {
6882 if ((!match
) || (done
== count
)) {
6887 obj
= table
->getObject( gIONameMatchKey
);
6890 match
= compareNames( obj
, changesOK
? &matched
: NULL
);
6894 if (changesOK
&& matched
) {
6895 // leave a hint as to which name matched
6896 table
->setObject( gIONameMatchedKey
, matched
);
6899 if (done
== count
) {
6904 str
= OSDynamicCast( OSString
, table
->getObject( gIOLocationMatchKey
));
6906 const OSSymbol
* sym
;
6909 sym
= copyLocation();
6911 match
= sym
->isEqualTo( str
);
6914 if ((!match
) || (done
== count
)) {
6919 obj
= table
->getObject( gIOPropertyMatchKey
);
6921 OSDictionary
* nextDict
;
6926 matchProps
= dictionaryWithProperties();
6929 nextDict
= OSDynamicCast( OSDictionary
, obj
);
6933 iter
= OSCollectionIterator::withCollection(
6934 OSDynamicCast(OSCollection
, obj
));
6938 || (iter
&& (NULL
!= (nextDict
= OSDynamicCast(OSDictionary
,
6939 iter
->getNextObject()))))) {
6940 match
= matchProps
->isEqualTo( nextDict
, nextDict
);
6950 if ((!match
) || (done
== count
)) {
6955 obj
= table
->getObject( gIOPropertyExistsMatchKey
);
6962 matchProps
= dictionaryWithProperties();
6965 nextKey
= OSDynamicCast( OSString
, obj
);
6969 iter
= OSCollectionIterator::withCollection(
6970 OSDynamicCast(OSCollection
, obj
));
6974 || (iter
&& (NULL
!= (nextKey
= OSDynamicCast(OSString
,
6975 iter
->getNextObject()))))) {
6976 match
= (NULL
!= matchProps
->getObject(nextKey
));
6986 if ((!match
) || (done
== count
)) {
6991 str
= OSDynamicCast( OSString
, table
->getObject( gIOPathMatchKey
));
6994 entry
= IORegistryEntry::fromPath( str
->getCStringNoCopy());
6995 match
= (this == entry
);
6999 if (!match
&& matchProps
&& (obj
= matchProps
->getObject(gIOPathKey
))) {
7000 match
= str
->isEqualTo(obj
);
7002 if ((!match
) || (done
== count
)) {
7007 num
= OSDynamicCast( OSNumber
, table
->getObject( gIORegistryEntryIDKey
));
7010 match
= (getRegistryEntryID() == num
->unsigned64BitValue());
7011 if ((!match
) || (done
== count
)) {
7016 num
= OSDynamicCast( OSNumber
, table
->getObject( gIOMatchedServiceCountKey
));
7019 IOService
* service
= NULL
;
7020 UInt32 serviceCount
= 0;
7023 iter
= getClientIterator();
7025 while ((service
= (IOService
*) iter
->getNextObject())) {
7026 if (kIOServiceInactiveState
& service
->__state
[0]) {
7029 if (NULL
== service
->getProperty( gIOMatchCategoryKey
)) {
7036 match
= (serviceCount
== num
->unsigned32BitValue());
7037 if ((!match
) || (done
== count
)) {
7042 #define propMatch(key) \
7043 obj = table->getObject(key); \
7048 prop = copyProperty(key); \
7049 match = obj->isEqualTo(prop); \
7050 if (prop) prop->release(); \
7051 if ((!match) || (done == count)) break; \
7053 propMatch(gIOBSDNameKey
)
7054 propMatch(gIOBSDMajorKey
)
7055 propMatch(gIOBSDMinorKey
)
7056 propMatch(gIOBSDUnitKey
)
7060 OSSafeReleaseNULL(matchProps
);
7069 IOService::passiveMatch( OSDictionary
* table
, bool changesOK
)
7071 return matchPassive(table
, changesOK
? kIOServiceChangesOK
: 0);
7075 IOService::matchPassive(OSDictionary
* table
, uint32_t options
)
7078 OSDictionary
* nextTable
;
7082 bool matchParent
= false;
7088 #if defined(XNU_TARGET_OS_OSX)
7089 OSArray
* aliasServiceRegIds
= NULL
;
7090 IOService
* foundAlternateService
= NULL
;
7091 #endif /* defined(XNU_TARGET_OS_OSX) */
7094 OSDictionary
* root
= table
;
7100 count
= table
->getCount();
7101 if (!(kIOServiceInternalDone
& options
)) {
7102 match
= where
->matchInternal(table
, options
, &done
);
7103 // don't call family if we've done all the entries in the table
7104 if ((!match
) || (done
== count
)) {
7109 // pass in score from property table
7110 score
= IOServiceObjectOrder( table
, (void *) gIOProbeScoreKey
);
7112 // do family specific matching
7113 match
= where
->matchPropertyTable( table
, &score
);
7117 if (kIOLogMatch
& getDebugFlags( table
)) {
7118 LOG("%s: family specific matching fails\n", where
->getName());
7124 if (kIOServiceChangesOK
& options
) {
7126 newPri
= OSNumber::withNumber( score
, 32 );
7128 table
->setObject( gIOProbeScoreKey
, newPri
);
7134 matchParent
= false;
7136 nextTable
= OSDynamicCast(OSDictionary
,
7137 table
->getObject( gIOParentMatchKey
));
7139 // look for a matching entry anywhere up to root
7146 table
= OSDynamicCast(OSDictionary
,
7147 table
->getObject( gIOLocationMatchKey
));
7149 // look for a matching entry at matchLocation()
7151 where
= where
->getProvider();
7152 if (where
&& (where
= where
->matchLocation(where
))) {
7159 if (match
== true) {
7163 if (matchParent
== true) {
7164 #if defined(XNU_TARGET_OS_OSX)
7165 // check if service has an alias to search its other "parents" if a parent match isn't found
7166 OSObject
* prop
= where
->copyProperty(gIOServiceLegacyMatchingRegistryIDKey
);
7167 OSNumber
* alternateRegistryID
= OSDynamicCast(OSNumber
, prop
);
7168 if (alternateRegistryID
!= NULL
) {
7169 if (aliasServiceRegIds
== NULL
) {
7170 aliasServiceRegIds
= OSArray::withCapacity(sizeof(alternateRegistryID
));
7172 aliasServiceRegIds
->setObject(alternateRegistryID
);
7174 OSSafeReleaseNULL(prop
);
7175 #endif /* defined(XNU_TARGET_OS_OSX) */
7180 where
= where
->getProvider();
7181 #if defined(XNU_TARGET_OS_OSX)
7182 if (where
== NULL
) {
7183 // there were no matching parent services, check to see if there are aliased services that have a matching parent
7184 if (aliasServiceRegIds
!= NULL
) {
7185 unsigned int numAliasedServices
= aliasServiceRegIds
->getCount();
7186 if (numAliasedServices
!= 0) {
7187 OSNumber
* alternateRegistryID
= OSDynamicCast(OSNumber
, aliasServiceRegIds
->getObject(numAliasedServices
- 1));
7188 if (alternateRegistryID
!= NULL
) {
7189 OSDictionary
* alternateMatchingDict
= IOService::registryEntryIDMatching(alternateRegistryID
->unsigned64BitValue());
7190 aliasServiceRegIds
->removeObject(numAliasedServices
- 1);
7191 if (alternateMatchingDict
!= NULL
) {
7192 OSSafeReleaseNULL(foundAlternateService
);
7193 foundAlternateService
= IOService::copyMatchingService(alternateMatchingDict
);
7194 alternateMatchingDict
->release();
7195 if (foundAlternateService
!= NULL
) {
7196 where
= foundAlternateService
;
7203 #endif /* defined(XNU_TARGET_OS_OSX) */
7204 }while (where
!= NULL
);
7206 #if defined(XNU_TARGET_OS_OSX)
7207 OSSafeReleaseNULL(foundAlternateService
);
7208 OSSafeReleaseNULL(aliasServiceRegIds
);
7209 #endif /* defined(XNU_TARGET_OS_OSX) */
7212 if (where
!= this) {
7213 OSSerialize
* s
= OSSerialize::withCapacity(128);
7215 kprintf("parent match 0x%llx, %d,\n%s\n", getRegistryEntryID(), match
, s
->text());
7225 IOService::newUserClient( task_t owningTask
, void * securityID
,
7226 UInt32 type
, OSDictionary
* properties
,
7227 IOUserClient
** handler
)
7229 const OSSymbol
*userClientClass
= NULL
;
7230 IOUserClient
*client
;
7234 if (reserved
&& reserved
->uvars
&& reserved
->uvars
->userServer
) {
7235 return reserved
->uvars
->userServer
->serviceNewUserClient(this, owningTask
, securityID
, type
, properties
, handler
);
7238 if (kIOReturnSuccess
== newUserClient( owningTask
, securityID
, type
, handler
)) {
7239 return kIOReturnSuccess
;
7242 // First try my own properties for a user client class name
7243 prop
= copyProperty(gIOUserClientClassKey
);
7245 if (OSDynamicCast(OSSymbol
, prop
)) {
7246 userClientClass
= (const OSSymbol
*) prop
;
7247 } else if (OSDynamicCast(OSString
, prop
)) {
7248 userClientClass
= OSSymbol::withString((OSString
*) prop
);
7249 if (userClientClass
) {
7250 setProperty(gIOUserClientClassKey
,
7251 (OSObject
*) userClientClass
);
7256 // Didn't find one so lets just bomb out now without further ado.
7257 if (!userClientClass
) {
7258 OSSafeReleaseNULL(prop
);
7259 return kIOReturnUnsupported
;
7262 // This reference is consumed by the IOServiceOpen call
7263 temp
= OSMetaClass::allocClassWithName(userClientClass
);
7264 OSSafeReleaseNULL(prop
);
7266 return kIOReturnNoMemory
;
7269 if (OSDynamicCast(IOUserClient
, temp
)) {
7270 client
= (IOUserClient
*) temp
;
7273 return kIOReturnUnsupported
;
7276 if (!client
->initWithTask(owningTask
, securityID
, type
, properties
)) {
7278 return kIOReturnBadArgument
;
7281 if (!client
->attach(this)) {
7283 return kIOReturnUnsupported
;
7286 if (!client
->start(this)) {
7287 client
->detach(this);
7289 return kIOReturnUnsupported
;
7293 return kIOReturnSuccess
;
7297 IOService::newUserClient( task_t owningTask
, void * securityID
,
7298 UInt32 type
, OSDictionary
* properties
,
7299 OSSharedPtr
<IOUserClient
>& handler
)
7301 IOUserClient
* handlerRaw
= NULL
;
7302 IOReturn result
= newUserClient(owningTask
, securityID
, type
, properties
, &handlerRaw
);
7303 handler
.reset(handlerRaw
, OSNoRetain
);
7308 IOService::newUserClient( task_t owningTask
, void * securityID
,
7309 UInt32 type
, IOUserClient
** handler
)
7311 return kIOReturnUnsupported
;
7315 IOService::newUserClient( task_t owningTask
, void * securityID
,
7316 UInt32 type
, OSSharedPtr
<IOUserClient
>& handler
)
7318 IOUserClient
* handlerRaw
= nullptr;
7319 IOReturn result
= IOService::newUserClient(owningTask
, securityID
, type
, &handlerRaw
);
7320 handler
.reset(handlerRaw
, OSNoRetain
);
7326 IOService::requestProbe( IOOptionBits options
)
7328 return kIOReturnUnsupported
;
7332 IOService::hasUserServer() const
7334 return reserved
&& reserved
->uvars
&& reserved
->uvars
->userServer
;
7338 * Convert an IOReturn to text. Subclasses which add additional
7339 * IOReturn's should override this method and call
7340 * super::stringFromReturn if the desired value is not found.
7344 IOService::stringFromReturn( IOReturn rtn
)
7346 static const IONamedValue IOReturn_values
[] = {
7347 {kIOReturnSuccess
, "success" },
7348 {kIOReturnError
, "general error" },
7349 {kIOReturnNoMemory
, "memory allocation error" },
7350 {kIOReturnNoResources
, "resource shortage" },
7351 {kIOReturnIPCError
, "Mach IPC failure" },
7352 {kIOReturnNoDevice
, "no such device" },
7353 {kIOReturnNotPrivileged
, "privilege violation" },
7354 {kIOReturnBadArgument
, "invalid argument" },
7355 {kIOReturnLockedRead
, "device is read locked" },
7356 {kIOReturnLockedWrite
, "device is write locked" },
7357 {kIOReturnExclusiveAccess
, "device is exclusive access" },
7358 {kIOReturnBadMessageID
, "bad IPC message ID" },
7359 {kIOReturnUnsupported
, "unsupported function" },
7360 {kIOReturnVMError
, "virtual memory error" },
7361 {kIOReturnInternalError
, "internal driver error" },
7362 {kIOReturnIOError
, "I/O error" },
7363 {kIOReturnCannotLock
, "cannot acquire lock" },
7364 {kIOReturnNotOpen
, "device is not open" },
7365 {kIOReturnNotReadable
, "device is not readable" },
7366 {kIOReturnNotWritable
, "device is not writeable" },
7367 {kIOReturnNotAligned
, "alignment error" },
7368 {kIOReturnBadMedia
, "media error" },
7369 {kIOReturnStillOpen
, "device is still open" },
7370 {kIOReturnRLDError
, "rld failure" },
7371 {kIOReturnDMAError
, "DMA failure" },
7372 {kIOReturnBusy
, "device is busy" },
7373 {kIOReturnTimeout
, "I/O timeout" },
7374 {kIOReturnOffline
, "device is offline" },
7375 {kIOReturnNotReady
, "device is not ready" },
7376 {kIOReturnNotAttached
, "device/channel is not attached" },
7377 {kIOReturnNoChannels
, "no DMA channels available" },
7378 {kIOReturnNoSpace
, "no space for data" },
7379 {kIOReturnPortExists
, "device port already exists" },
7380 {kIOReturnCannotWire
, "cannot wire physical memory" },
7381 {kIOReturnNoInterrupt
, "no interrupt attached" },
7382 {kIOReturnNoFrames
, "no DMA frames enqueued" },
7383 {kIOReturnMessageTooLarge
, "message is too large" },
7384 {kIOReturnNotPermitted
, "operation is not permitted" },
7385 {kIOReturnNoPower
, "device is without power" },
7386 {kIOReturnNoMedia
, "media is not present" },
7387 {kIOReturnUnformattedMedia
, "media is not formatted" },
7388 {kIOReturnUnsupportedMode
, "unsupported mode" },
7389 {kIOReturnUnderrun
, "data underrun" },
7390 {kIOReturnOverrun
, "data overrun" },
7391 {kIOReturnDeviceError
, "device error" },
7392 {kIOReturnNoCompletion
, "no completion routine" },
7393 {kIOReturnAborted
, "operation was aborted" },
7394 {kIOReturnNoBandwidth
, "bus bandwidth would be exceeded" },
7395 {kIOReturnNotResponding
, "device is not responding" },
7396 {kIOReturnInvalid
, "unanticipated driver error" },
7400 return IOFindNameForValue(rtn
, IOReturn_values
);
7404 * Convert an IOReturn to an errno.
7407 IOService::errnoFromReturn( IOReturn rtn
)
7409 if (unix_err(err_get_code(rtn
)) == rtn
) {
7410 return err_get_code(rtn
);
7415 case kIOReturnSuccess
:
7417 case kIOReturnNoMemory
:
7419 case kIOReturnNoDevice
:
7421 case kIOReturnVMError
:
7423 case kIOReturnNotPermitted
:
7425 case kIOReturnNotPrivileged
:
7427 case kIOReturnIOError
:
7429 case kIOReturnNotWritable
:
7431 case kIOReturnBadArgument
:
7433 case kIOReturnUnsupported
:
7437 case kIOReturnNoPower
:
7439 case kIOReturnDeviceError
:
7441 case kIOReturnTimeout
:
7443 case kIOReturnMessageTooLarge
:
7445 case kIOReturnNoSpace
:
7447 case kIOReturnCannotLock
:
7451 case kIOReturnBadMessageID
:
7452 case kIOReturnNoCompletion
:
7453 case kIOReturnNotAligned
:
7455 case kIOReturnNotReady
:
7457 case kIOReturnRLDError
:
7459 case kIOReturnPortExists
:
7460 case kIOReturnStillOpen
:
7462 case kIOReturnExclusiveAccess
:
7463 case kIOReturnLockedRead
:
7464 case kIOReturnLockedWrite
:
7465 case kIOReturnNotOpen
:
7466 case kIOReturnNotReadable
:
7468 case kIOReturnCannotWire
:
7469 case kIOReturnNoResources
:
7471 case kIOReturnAborted
:
7472 case kIOReturnOffline
:
7473 case kIOReturnNotResponding
:
7475 case kIOReturnBadMedia
:
7476 case kIOReturnNoMedia
:
7477 case kIOReturnNotAttached
:
7478 case kIOReturnUnformattedMedia
:
7479 return ENXIO
; // (media error)
7480 case kIOReturnDMAError
:
7481 case kIOReturnOverrun
:
7482 case kIOReturnUnderrun
:
7483 return EIO
; // (transfer error)
7484 case kIOReturnNoBandwidth
:
7485 case kIOReturnNoChannels
:
7486 case kIOReturnNoFrames
:
7487 case kIOReturnNoInterrupt
:
7488 return EIO
; // (hardware error)
7489 case kIOReturnError
:
7490 case kIOReturnInternalError
:
7491 case kIOReturnInvalid
:
7492 return EIO
; // (generic error)
7493 case kIOReturnIPCError
:
7494 return EIO
; // (ipc error)
7496 return EIO
; // (all other errors)
7501 IOService::message( UInt32 type
, IOService
* provider
,
7505 * Generic entry point for calls from the provider. A return value of
7506 * kIOReturnSuccess indicates that the message was received, and where
7507 * applicable, that it was successful.
7510 return kIOReturnUnsupported
;
7518 IOService::getDeviceMemoryCount( void )
7523 array
= OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
));
7525 count
= array
->getCount();
7534 IOService::getDeviceMemoryWithIndex( unsigned int index
)
7537 IODeviceMemory
* range
;
7539 array
= OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
));
7541 range
= (IODeviceMemory
*) array
->getObject( index
);
7550 IOService::mapDeviceMemoryWithIndex( unsigned int index
,
7551 IOOptionBits options
)
7553 IODeviceMemory
* range
;
7556 range
= getDeviceMemoryWithIndex( index
);
7558 map
= range
->map( options
);
7567 IOService::getDeviceMemory( void )
7569 return OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
));
7574 IOService::setDeviceMemory( OSArray
* array
)
7576 setProperty( gIODeviceMemoryKey
, array
);
7580 requireMaxCpuDelay(IOService
* service
, UInt32 ns
, UInt32 delayType
)
7582 static const UInt kNoReplace
= -1U; // Must be an illegal index
7583 UInt replace
= kNoReplace
;
7584 bool setCpuDelay
= false;
7586 IORecursiveLockLock(sCpuDelayLock
);
7588 UInt count
= sCpuDelayData
->getLength() / sizeof(CpuDelayEntry
);
7589 CpuDelayEntry
*entries
= (CpuDelayEntry
*) sCpuDelayData
->getBytesNoCopy();
7590 IOService
* holder
= NULL
;
7593 const CpuDelayEntry ne
= {service
, ns
, delayType
};
7595 // Set maximum delay.
7596 for (UInt i
= 0; i
< count
; i
++) {
7597 IOService
*thisService
= entries
[i
].fService
;
7598 bool sameType
= (delayType
== entries
[i
].fDelayType
);
7599 if ((service
== thisService
) && sameType
) {
7601 } else if (!thisService
) {
7602 if (kNoReplace
== replace
) {
7605 } else if (sameType
) {
7606 const UInt32 thisMax
= entries
[i
].fMaxDelay
;
7609 holder
= thisService
;
7615 if (kNoReplace
== replace
) {
7616 sCpuDelayData
->appendBytes(&ne
, sizeof(ne
));
7618 entries
[replace
] = ne
;
7621 ns
= -1U; // Set to max unsigned, i.e. no restriction
7623 for (UInt i
= 0; i
< count
; i
++) {
7624 // Clear a maximum delay.
7625 IOService
*thisService
= entries
[i
].fService
;
7626 if (thisService
&& (delayType
== entries
[i
].fDelayType
)) {
7627 UInt32 thisMax
= entries
[i
].fMaxDelay
;
7628 if (service
== thisService
) {
7630 } else if (thisMax
< ns
) {
7632 holder
= thisService
;
7637 // Check if entry found
7638 if (kNoReplace
!= replace
) {
7639 entries
[replace
].fService
= NULL
; // Null the entry
7645 if (holder
&& debug_boot_arg
) {
7646 strlcpy(sCPULatencyHolderName
[delayType
], holder
->getName(), sizeof(sCPULatencyHolderName
[delayType
]));
7649 // Must be safe to call from locked context
7650 if (delayType
== kCpuDelayBusStall
) {
7651 #if defined(__x86_64__)
7652 ml_set_maxbusdelay(ns
);
7653 #endif /* defined(__x86_64__) */
7655 #if defined(__x86_64__)
7656 else if (delayType
== kCpuDelayInterrupt
) {
7657 ml_set_maxintdelay(ns
);
7659 #endif /* defined(__x86_64__) */
7660 sCPULatencyHolder
[delayType
]->setValue(holder
? holder
->getRegistryEntryID() : 0);
7661 sCPULatencySet
[delayType
]->setValue(ns
);
7663 OSArray
* handlers
= sCpuLatencyHandlers
[delayType
];
7666 for (unsigned int idx
= 0;
7667 (target
= (IOService
*) handlers
->getObject(idx
));
7669 target
->callPlatformFunction(sCPULatencyFunctionName
[delayType
], false,
7670 (void *) (uintptr_t) ns
, holder
,
7676 IORecursiveLockUnlock(sCpuDelayLock
);
7680 setLatencyHandler(UInt32 delayType
, IOService
* target
, bool enable
)
7682 IOReturn result
= kIOReturnNotFound
;
7686 IORecursiveLockLock(sCpuDelayLock
);
7689 if (enable
&& !sCpuLatencyHandlers
[delayType
]) {
7690 sCpuLatencyHandlers
[delayType
] = OSArray::withCapacity(4);
7692 array
= sCpuLatencyHandlers
[delayType
];
7696 idx
= array
->getNextIndexOfObject(target
, 0);
7699 array
->removeObject(idx
);
7700 result
= kIOReturnSuccess
;
7704 result
= kIOReturnExclusiveAccess
;
7707 array
->setObject(target
);
7709 UInt count
= sCpuDelayData
->getLength() / sizeof(CpuDelayEntry
);
7710 CpuDelayEntry
*entries
= (CpuDelayEntry
*) sCpuDelayData
->getBytesNoCopy();
7711 UInt32 ns
= -1U; // Set to max unsigned, i.e. no restriction
7712 IOService
* holder
= NULL
;
7714 for (UInt i
= 0; i
< count
; i
++) {
7715 if (entries
[i
].fService
7716 && (delayType
== entries
[i
].fDelayType
)
7717 && (entries
[i
].fMaxDelay
< ns
)) {
7718 ns
= entries
[i
].fMaxDelay
;
7719 holder
= entries
[i
].fService
;
7722 target
->callPlatformFunction(sCPULatencyFunctionName
[delayType
], false,
7723 (void *) (uintptr_t) ns
, holder
,
7725 result
= kIOReturnSuccess
;
7729 IORecursiveLockUnlock(sCpuDelayLock
);
7735 IOService::requireMaxBusStall(UInt32 ns
)
7737 #if !defined(__x86_64__)
7739 case kIOMaxBusStall40usec
:
7740 case kIOMaxBusStall30usec
:
7741 case kIOMaxBusStall25usec
:
7742 case kIOMaxBusStall20usec
:
7743 case kIOMaxBusStall10usec
:
7744 case kIOMaxBusStall5usec
:
7745 case kIOMaxBusStallNone
:
7748 return kIOReturnBadArgument
;
7750 #endif /* !defined(__x86_64__) */
7751 requireMaxCpuDelay(this, ns
, kCpuDelayBusStall
);
7752 return kIOReturnSuccess
;
7756 IOService::requireMaxInterruptDelay(uint32_t ns
)
7758 #if defined(__x86_64__)
7759 requireMaxCpuDelay(this, ns
, kCpuDelayInterrupt
);
7760 return kIOReturnSuccess
;
7761 #else /* defined(__x86_64__) */
7762 return kIOReturnUnsupported
;
7763 #endif /* defined(__x86_64__) */
7771 IOService::resolveInterrupt(IOService
*nub
, int source
)
7773 IOInterruptController
*interruptController
;
7776 OSSymbol
*interruptControllerName
;
7777 unsigned int numSources
;
7778 IOInterruptSource
*interruptSources
;
7780 // Get the parents list from the nub.
7781 array
= OSDynamicCast(OSArray
, nub
->getProperty(gIOInterruptControllersKey
));
7782 if (array
== NULL
) {
7783 return kIOReturnNoResources
;
7786 // Allocate space for the IOInterruptSources if needed... then return early.
7787 if (nub
->_interruptSources
== NULL
) {
7788 numSources
= array
->getCount();
7789 interruptSources
= (IOInterruptSource
*)IOMalloc(
7790 numSources
* sizeofAllIOInterruptSource
);
7791 if (interruptSources
== NULL
) {
7792 return kIOReturnNoMemory
;
7795 bzero(interruptSources
, numSources
* sizeofAllIOInterruptSource
);
7797 nub
->_numInterruptSources
= numSources
;
7798 nub
->_interruptSources
= interruptSources
;
7799 return kIOReturnSuccess
;
7802 interruptControllerName
= OSDynamicCast(OSSymbol
, array
->getObject(source
));
7803 if (interruptControllerName
== NULL
) {
7804 return kIOReturnNoResources
;
7807 interruptController
= getPlatform()->lookUpInterruptController(interruptControllerName
);
7808 if (interruptController
== NULL
) {
7809 return kIOReturnNoResources
;
7812 // Get the interrupt numbers from the nub.
7813 array
= OSDynamicCast(OSArray
, nub
->getProperty(gIOInterruptSpecifiersKey
));
7814 if (array
== NULL
) {
7815 return kIOReturnNoResources
;
7817 data
= OSDynamicCast(OSData
, array
->getObject(source
));
7819 return kIOReturnNoResources
;
7822 // Set the interruptController and interruptSource in the nub's table.
7823 interruptSources
= nub
->_interruptSources
;
7824 interruptSources
[source
].interruptController
= interruptController
;
7825 interruptSources
[source
].vectorData
= data
;
7827 return kIOReturnSuccess
;
7831 IOService::lookupInterrupt(int source
, bool resolve
, IOInterruptController
**interruptController
)
7835 /* Make sure the _interruptSources are set */
7836 if (_interruptSources
== NULL
) {
7837 ret
= resolveInterrupt(this, source
);
7838 if (ret
!= kIOReturnSuccess
) {
7843 /* Make sure the local source number is valid */
7844 if ((source
< 0) || (source
>= _numInterruptSources
)) {
7845 return kIOReturnNoInterrupt
;
7848 /* Look up the contoller for the local source */
7849 *interruptController
= _interruptSources
[source
].interruptController
;
7851 if (*interruptController
== NULL
) {
7853 return kIOReturnNoInterrupt
;
7856 /* Try to resolve the interrupt */
7857 ret
= resolveInterrupt(this, source
);
7858 if (ret
!= kIOReturnSuccess
) {
7862 *interruptController
= _interruptSources
[source
].interruptController
;
7865 return kIOReturnSuccess
;
7869 IOService::registerInterrupt(int source
, OSObject
*target
,
7870 IOInterruptAction handler
,
7873 IOInterruptController
*interruptController
;
7876 ret
= lookupInterrupt(source
, true, &interruptController
);
7877 if (ret
!= kIOReturnSuccess
) {
7881 /* Register the source */
7882 return interruptController
->registerInterrupt(this, source
, target
,
7883 (IOInterruptHandler
)handler
,
7888 IOServiceInterruptActionToBlock( OSObject
* target
, void * refCon
,
7889 IOService
* nub
, int source
)
7891 ((IOInterruptActionBlock
)(refCon
))(nub
, source
);
7895 IOService::registerInterruptBlock(int source
, OSObject
*target
,
7896 IOInterruptActionBlock handler
)
7901 block
= Block_copy(handler
);
7903 return kIOReturnNoMemory
;
7906 ret
= registerInterrupt(source
, target
, &IOServiceInterruptActionToBlock
, block
);
7907 if (kIOReturnSuccess
!= ret
) {
7908 Block_release(block
);
7911 _interruptSourcesPrivate(this)[source
].vectorBlock
= block
;
7917 IOService::unregisterInterrupt(int source
)
7920 IOInterruptController
*interruptController
;
7923 ret
= lookupInterrupt(source
, false, &interruptController
);
7924 if (ret
!= kIOReturnSuccess
) {
7928 /* Unregister the source */
7929 block
= _interruptSourcesPrivate(this)[source
].vectorBlock
;
7930 ret
= interruptController
->unregisterInterrupt(this, source
);
7931 if ((kIOReturnSuccess
== ret
) && (block
= _interruptSourcesPrivate(this)[source
].vectorBlock
)) {
7932 _interruptSourcesPrivate(this)[source
].vectorBlock
= NULL
;
7933 Block_release(block
);
7940 IOService::addInterruptStatistics(IOInterruptAccountingData
* statistics
, int source
)
7942 IOReportLegend
* legend
= NULL
;
7943 IOInterruptAccountingData
* oldValue
= NULL
;
7944 IOInterruptAccountingReporter
* newArray
= NULL
;
7945 char subgroupName
[64];
7946 int newArraySize
= 0;
7950 return kIOReturnBadArgument
;
7954 * We support statistics on a maximum of 256 interrupts per nub; if a nub
7955 * has more than 256 interrupt specifiers associated with it, and tries
7956 * to register a high interrupt index with interrupt accounting, panic.
7957 * Having more than 256 interrupts associated with a single nub is
7958 * probably a sign that something fishy is going on.
7960 if (source
> IA_INDEX_MAX
) {
7961 panic("addInterruptStatistics called for an excessively large index (%d)", source
);
7965 * TODO: This is ugly (wrapping a lock around an allocation). I'm only
7966 * leaving it as is because the likelihood of contention where we are
7967 * actually growing the array is minimal (we would realistically need
7968 * to be starting a driver for the first time, with an IOReporting
7969 * client already in place). Nonetheless, cleanup that can be done
7970 * to adhere to best practices; it'll make the code more complicated,
7973 IOLockLock(reserved
->interruptStatisticsLock
);
7976 * Lazily allocate the statistics array.
7978 if (!reserved
->interruptStatisticsArray
) {
7979 reserved
->interruptStatisticsArray
= IONew(IOInterruptAccountingReporter
, 1);
7980 assert(reserved
->interruptStatisticsArray
);
7981 reserved
->interruptStatisticsArrayCount
= 1;
7982 bzero(reserved
->interruptStatisticsArray
, sizeof(*reserved
->interruptStatisticsArray
));
7985 if (source
>= reserved
->interruptStatisticsArrayCount
) {
7987 * We're still within the range of supported indices, but we are out
7988 * of space in the current array. Do a nasty realloc (because
7989 * IORealloc isn't a thing) here. We'll double the size with each
7992 * Yes, the "next power of 2" could be more efficient; but this will
7993 * be invoked incredibly rarely. Who cares.
7995 newArraySize
= (reserved
->interruptStatisticsArrayCount
<< 1);
7997 while (newArraySize
<= source
) {
7998 newArraySize
= (newArraySize
<< 1);
8000 newArray
= IONew(IOInterruptAccountingReporter
, newArraySize
);
8005 * TODO: This even zeroes the memory it is about to overwrite.
8006 * Shameful; fix it. Not particularly high impact, however.
8008 bzero(newArray
, newArraySize
* sizeof(*newArray
));
8009 memcpy(newArray
, reserved
->interruptStatisticsArray
, reserved
->interruptStatisticsArrayCount
* sizeof(*newArray
));
8010 IODelete(reserved
->interruptStatisticsArray
, IOInterruptAccountingReporter
, reserved
->interruptStatisticsArrayCount
);
8011 reserved
->interruptStatisticsArray
= newArray
;
8012 reserved
->interruptStatisticsArrayCount
= newArraySize
;
8015 if (!reserved
->interruptStatisticsArray
[source
].reporter
) {
8017 * We don't have a reporter associated with this index yet, so we
8018 * need to create one.
8021 * TODO: Some statistics do in fact have common units (time); should this be
8022 * split into separate reporters to communicate this?
8024 reserved
->interruptStatisticsArray
[source
].reporter
= IOSimpleReporter::with(this, kIOReportCategoryPower
, kIOReportUnitNone
);
8027 * Each statistic is given an identifier based on the interrupt index (which
8028 * should be unique relative to any single nub) and the statistic involved.
8029 * We should now have a sane (small and positive) index, so start
8030 * constructing the channels for statistics.
8032 for (i
= 0; i
< IA_NUM_INTERRUPT_ACCOUNTING_STATISTICS
; i
++) {
8034 * TODO: Currently, this does not add channels for disabled statistics.
8035 * Will this be confusing for clients? If so, we should just add the
8036 * channels; we can avoid updating the channels even if they exist.
8038 if (IA_GET_STATISTIC_ENABLED(i
)) {
8039 reserved
->interruptStatisticsArray
[source
].reporter
->addChannel(IA_GET_CHANNEL_ID(source
, i
), kInterruptAccountingStatisticNameArray
[i
]);
8044 * We now need to add the legend for this reporter to the registry.
8046 OSObject
* prop
= copyProperty(kIOReportLegendKey
);
8047 legend
= IOReportLegend::with(OSDynamicCast(OSArray
, prop
));
8048 OSSafeReleaseNULL(prop
);
8051 * Note that while we compose the subgroup name, we do not need to
8052 * manage its lifecycle (the reporter will handle this).
8054 snprintf(subgroupName
, sizeof(subgroupName
), "%s %d", getName(), source
);
8055 subgroupName
[sizeof(subgroupName
) - 1] = 0;
8056 legend
->addReporterLegend(reserved
->interruptStatisticsArray
[source
].reporter
, kInterruptAccountingGroupName
, subgroupName
);
8057 setProperty(kIOReportLegendKey
, legend
->getLegend());
8061 * TODO: Is this a good idea? Probably not; my assumption is it opts
8062 * all entities who register interrupts into public disclosure of all
8063 * IOReporting channels. Unfortunately, this appears to be as fine
8066 setProperty(kIOReportLegendPublicKey
, true);
8070 * Don't stomp existing entries. If we are about to, panic; this
8071 * probably means we failed to tear down our old interrupt source
8074 oldValue
= reserved
->interruptStatisticsArray
[source
].statistics
;
8077 panic("addInterruptStatistics call for index %d would have clobbered existing statistics", source
);
8080 reserved
->interruptStatisticsArray
[source
].statistics
= statistics
;
8083 * Inherit the reporter values for each statistic. The target may
8084 * be torn down as part of the runtime of the service (especially
8085 * for sleep/wake), so we inherit in order to avoid having values
8086 * reset for no apparent reason. Our statistics are ultimately
8087 * tied to the index and the sevice, not to an individual target,
8088 * so we should maintain them accordingly.
8090 interruptAccountingDataInheritChannels(reserved
->interruptStatisticsArray
[source
].statistics
, reserved
->interruptStatisticsArray
[source
].reporter
);
8092 IOLockUnlock(reserved
->interruptStatisticsLock
);
8094 return kIOReturnSuccess
;
8098 IOService::removeInterruptStatistics(int source
)
8100 IOInterruptAccountingData
* value
= NULL
;
8103 return kIOReturnBadArgument
;
8106 IOLockLock(reserved
->interruptStatisticsLock
);
8109 * We dynamically grow the statistics array, so an excessively
8110 * large index value has NEVER been registered. This either
8111 * means our cap on the array size is too small (unlikely), or
8112 * that we have been passed a corrupt index (this must be passed
8113 * the plain index into the interrupt specifier list).
8115 if (source
>= reserved
->interruptStatisticsArrayCount
) {
8116 panic("removeInterruptStatistics called for index %d, which was never registered", source
);
8119 assert(reserved
->interruptStatisticsArray
);
8122 * If there is no existing entry, we are most likely trying to
8123 * free an interrupt owner twice, or we have corrupted the
8126 value
= reserved
->interruptStatisticsArray
[source
].statistics
;
8129 panic("removeInterruptStatistics called for empty index %d", source
);
8133 * We update the statistics, so that any delta with the reporter
8134 * state is not lost.
8136 interruptAccountingDataUpdateChannels(reserved
->interruptStatisticsArray
[source
].statistics
, reserved
->interruptStatisticsArray
[source
].reporter
);
8137 reserved
->interruptStatisticsArray
[source
].statistics
= NULL
;
8138 IOLockUnlock(reserved
->interruptStatisticsLock
);
8140 return kIOReturnSuccess
;
8144 IOService::getInterruptType(int source
, int *interruptType
)
8146 IOInterruptController
*interruptController
;
8149 ret
= lookupInterrupt(source
, true, &interruptController
);
8150 if (ret
!= kIOReturnSuccess
) {
8154 /* Return the type */
8155 return interruptController
->getInterruptType(this, source
, interruptType
);
8159 IOService::enableInterrupt(int source
)
8161 IOInterruptController
*interruptController
;
8164 ret
= lookupInterrupt(source
, false, &interruptController
);
8165 if (ret
!= kIOReturnSuccess
) {
8169 /* Enable the source */
8170 return interruptController
->enableInterrupt(this, source
);
8174 IOService::disableInterrupt(int source
)
8176 IOInterruptController
*interruptController
;
8179 ret
= lookupInterrupt(source
, false, &interruptController
);
8180 if (ret
!= kIOReturnSuccess
) {
8184 /* Disable the source */
8185 return interruptController
->disableInterrupt(this, source
);
8189 IOService::causeInterrupt(int source
)
8191 IOInterruptController
*interruptController
;
8194 ret
= lookupInterrupt(source
, false, &interruptController
);
8195 if (ret
!= kIOReturnSuccess
) {
8199 /* Cause an interrupt for the source */
8200 return interruptController
->causeInterrupt(this, source
);
8204 IOService::configureReport(IOReportChannelList
*channelList
,
8205 IOReportConfigureAction action
,
8211 for (cnt
= 0; cnt
< channelList
->nchannels
; cnt
++) {
8212 if (channelList
->channels
[cnt
].channel_id
== kPMPowerStatesChID
) {
8214 configurePowerStatesReport(action
, result
);
8216 return kIOReturnUnsupported
;
8218 } else if (channelList
->channels
[cnt
].channel_id
== kPMCurrStateChID
) {
8220 configureSimplePowerReport(action
, result
);
8222 return kIOReturnUnsupported
;
8227 IOLockLock(reserved
->interruptStatisticsLock
);
8229 /* The array count is signed (because the interrupt indices are signed), hence the cast */
8230 for (cnt
= 0; cnt
< (unsigned) reserved
->interruptStatisticsArrayCount
; cnt
++) {
8231 if (reserved
->interruptStatisticsArray
[cnt
].reporter
) {
8233 * If the reporter is currently associated with the statistics
8234 * for an event source, we may need to update the reporter.
8236 if (reserved
->interruptStatisticsArray
[cnt
].statistics
) {
8237 interruptAccountingDataUpdateChannels(reserved
->interruptStatisticsArray
[cnt
].statistics
, reserved
->interruptStatisticsArray
[cnt
].reporter
);
8240 reserved
->interruptStatisticsArray
[cnt
].reporter
->configureReport(channelList
, action
, result
, destination
);
8244 IOLockUnlock(reserved
->interruptStatisticsLock
);
8246 return kIOReturnSuccess
;
8250 IOService::updateReport(IOReportChannelList
*channelList
,
8251 IOReportUpdateAction action
,
8257 for (cnt
= 0; cnt
< channelList
->nchannels
; cnt
++) {
8258 if (channelList
->channels
[cnt
].channel_id
== kPMPowerStatesChID
) {
8260 updatePowerStatesReport(action
, result
, destination
);
8262 return kIOReturnUnsupported
;
8264 } else if (channelList
->channels
[cnt
].channel_id
== kPMCurrStateChID
) {
8266 updateSimplePowerReport(action
, result
, destination
);
8268 return kIOReturnUnsupported
;
8273 IOLockLock(reserved
->interruptStatisticsLock
);
8275 /* The array count is signed (because the interrupt indices are signed), hence the cast */
8276 for (cnt
= 0; cnt
< (unsigned) reserved
->interruptStatisticsArrayCount
; cnt
++) {
8277 if (reserved
->interruptStatisticsArray
[cnt
].reporter
) {
8279 * If the reporter is currently associated with the statistics
8280 * for an event source, we need to update the reporter.
8282 if (reserved
->interruptStatisticsArray
[cnt
].statistics
) {
8283 interruptAccountingDataUpdateChannels(reserved
->interruptStatisticsArray
[cnt
].statistics
, reserved
->interruptStatisticsArray
[cnt
].reporter
);
8286 reserved
->interruptStatisticsArray
[cnt
].reporter
->updateReport(channelList
, action
, result
, destination
);
8290 IOLockUnlock(reserved
->interruptStatisticsLock
);
8292 return kIOReturnSuccess
;
8296 IOService::getAuthorizationID( void )
8298 return reserved
->authorizationID
;
8302 IOService::setAuthorizationID( uint64_t authorizationID
)
8304 OSObject
* entitlement
;
8307 entitlement
= IOUserClient::copyClientEntitlement( current_task(), "com.apple.private.iokit.IOServiceSetAuthorizationID" );
8310 if (entitlement
== kOSBooleanTrue
) {
8311 reserved
->authorizationID
= authorizationID
;
8313 status
= kIOReturnSuccess
;
8315 status
= kIOReturnNotPrivileged
;
8318 entitlement
->release();
8320 status
= kIOReturnNotPrivileged
;
8326 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8330 OSMetaClassDefineReservedUsedX86(IOService
, 0);
8331 OSMetaClassDefineReservedUsedX86(IOService
, 1);
8332 OSMetaClassDefineReservedUnused(IOService
, 2);
8333 OSMetaClassDefineReservedUnused(IOService
, 3);
8334 OSMetaClassDefineReservedUnused(IOService
, 4);
8335 OSMetaClassDefineReservedUnused(IOService
, 5);
8336 OSMetaClassDefineReservedUnused(IOService
, 6);
8337 OSMetaClassDefineReservedUnused(IOService
, 7);
8339 OSMetaClassDefineReservedUsedX86(IOService
, 0);
8340 OSMetaClassDefineReservedUsedX86(IOService
, 1);
8341 OSMetaClassDefineReservedUsedX86(IOService
, 2);
8342 OSMetaClassDefineReservedUsedX86(IOService
, 3);
8343 OSMetaClassDefineReservedUsedX86(IOService
, 4);
8344 OSMetaClassDefineReservedUsedX86(IOService
, 5);
8345 OSMetaClassDefineReservedUsedX86(IOService
, 6);
8346 OSMetaClassDefineReservedUsedX86(IOService
, 7);
8348 OSMetaClassDefineReservedUnused(IOService
, 8);
8349 OSMetaClassDefineReservedUnused(IOService
, 9);
8350 OSMetaClassDefineReservedUnused(IOService
, 10);
8351 OSMetaClassDefineReservedUnused(IOService
, 11);
8352 OSMetaClassDefineReservedUnused(IOService
, 12);
8353 OSMetaClassDefineReservedUnused(IOService
, 13);
8354 OSMetaClassDefineReservedUnused(IOService
, 14);
8355 OSMetaClassDefineReservedUnused(IOService
, 15);
8356 OSMetaClassDefineReservedUnused(IOService
, 16);
8357 OSMetaClassDefineReservedUnused(IOService
, 17);
8358 OSMetaClassDefineReservedUnused(IOService
, 18);
8359 OSMetaClassDefineReservedUnused(IOService
, 19);
8360 OSMetaClassDefineReservedUnused(IOService
, 20);
8361 OSMetaClassDefineReservedUnused(IOService
, 21);
8362 OSMetaClassDefineReservedUnused(IOService
, 22);
8363 OSMetaClassDefineReservedUnused(IOService
, 23);
8364 OSMetaClassDefineReservedUnused(IOService
, 24);
8365 OSMetaClassDefineReservedUnused(IOService
, 25);
8366 OSMetaClassDefineReservedUnused(IOService
, 26);
8367 OSMetaClassDefineReservedUnused(IOService
, 27);
8368 OSMetaClassDefineReservedUnused(IOService
, 28);
8369 OSMetaClassDefineReservedUnused(IOService
, 29);
8370 OSMetaClassDefineReservedUnused(IOService
, 30);
8371 OSMetaClassDefineReservedUnused(IOService
, 31);
8372 OSMetaClassDefineReservedUnused(IOService
, 32);
8373 OSMetaClassDefineReservedUnused(IOService
, 33);
8374 OSMetaClassDefineReservedUnused(IOService
, 34);
8375 OSMetaClassDefineReservedUnused(IOService
, 35);
8376 OSMetaClassDefineReservedUnused(IOService
, 36);
8377 OSMetaClassDefineReservedUnused(IOService
, 37);
8378 OSMetaClassDefineReservedUnused(IOService
, 38);
8379 OSMetaClassDefineReservedUnused(IOService
, 39);
8380 OSMetaClassDefineReservedUnused(IOService
, 40);
8381 OSMetaClassDefineReservedUnused(IOService
, 41);
8382 OSMetaClassDefineReservedUnused(IOService
, 42);
8383 OSMetaClassDefineReservedUnused(IOService
, 43);
8384 OSMetaClassDefineReservedUnused(IOService
, 44);
8385 OSMetaClassDefineReservedUnused(IOService
, 45);
8386 OSMetaClassDefineReservedUnused(IOService
, 46);
8387 OSMetaClassDefineReservedUnused(IOService
, 47);