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/Block.h>
37 #include <IOKit/IOCatalogue.h>
38 #include <IOKit/IOCommand.h>
39 #include <IOKit/IODeviceTreeSupport.h>
40 #include <IOKit/IODeviceMemory.h>
41 #include <IOKit/IOInterrupts.h>
42 #include <IOKit/IOInterruptController.h>
43 #include <IOKit/IOPlatformExpert.h>
44 #include <IOKit/IOMessage.h>
45 #include <IOKit/IOLib.h>
46 #include <IOKit/IOKitKeysPrivate.h>
47 #include <IOKit/IOBSD.h>
48 #include <IOKit/IOUserClient.h>
49 #include <IOKit/IOUserServer.h>
50 #include <IOKit/IOWorkLoop.h>
51 #include <IOKit/IOTimeStamp.h>
52 #include <IOKit/IOHibernatePrivate.h>
53 #include <IOKit/IOInterruptAccountingPrivate.h>
54 #include <IOKit/IOKernelReporters.h>
55 #include <IOKit/AppleKeyStoreInterface.h>
56 #include <IOKit/pwr_mgt/RootDomain.h>
57 #include <IOKit/IOCPU.h>
58 #include <mach/sync_policy.h>
59 #include <mach/thread_info.h>
60 #include <IOKit/assert.h>
61 #include <sys/errno.h>
62 #include <sys/kdebug.h>
65 #include <machine/pal_routines.h>
70 #define IOSERVICE_OBFUSCATE(x) ((void *)(VM_KERNEL_ADDRPERM(x)))
72 // disabled since lockForArbitration() can be held externally
73 #define DEBUG_NOTIFIER_LOCKED 0
76 kIOUserServerCheckInTimeoutSecs
= 120ULL
79 #include "IOServicePrivate.h"
80 #include "IOKitKernelInternal.h"
82 // take lockForArbitration before LOCKNOTIFY
84 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
86 #define super IORegistryEntry
88 OSDefineMetaClassAndStructors(IOService
, IORegistryEntry
)
90 OSDefineMetaClassAndStructors(_IOServiceNotifier
, IONotifier
)
91 OSDefineMetaClassAndStructors(_IOServiceNullNotifier
, IONotifier
)
93 OSDefineMetaClassAndStructors(_IOServiceInterestNotifier
, IONotifier
)
95 OSDefineMetaClassAndStructors(_IOConfigThread
, OSObject
)
97 OSDefineMetaClassAndStructors(_IOServiceJob
, OSObject
)
99 OSDefineMetaClassAndStructors(IOResources
, IOService
)
100 OSDefineMetaClassAndStructors(IOUserResources
, IOService
)
102 OSDefineMetaClassAndStructors(_IOOpenServiceIterator
, OSIterator
)
104 OSDefineMetaClassAndAbstractStructors(IONotifier
, OSObject
)
106 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
108 static IOPlatformExpert
* gIOPlatform
;
109 static class IOPMrootDomain
* gIOPMRootDomain
;
110 const IORegistryPlane
* gIOServicePlane
;
111 const IORegistryPlane
* gIOPowerPlane
;
112 const OSSymbol
* gIODeviceMemoryKey
;
113 const OSSymbol
* gIOInterruptControllersKey
;
114 const OSSymbol
* gIOInterruptSpecifiersKey
;
116 const OSSymbol
* gIOResourcesKey
;
117 const OSSymbol
* gIOUserResourcesKey
;
118 const OSSymbol
* gIOResourceMatchKey
;
119 const OSSymbol
* gIOResourceMatchedKey
;
120 const OSSymbol
* gIOResourceIOKitKey
;
122 const OSSymbol
* gIOProviderClassKey
;
123 const OSSymbol
* gIONameMatchKey
;
124 const OSSymbol
* gIONameMatchedKey
;
125 const OSSymbol
* gIOPropertyMatchKey
;
126 const OSSymbol
* gIOPropertyExistsMatchKey
;
127 const OSSymbol
* gIOLocationMatchKey
;
128 const OSSymbol
* gIOParentMatchKey
;
129 const OSSymbol
* gIOPathMatchKey
;
130 const OSSymbol
* gIOMatchCategoryKey
;
131 const OSSymbol
* gIODefaultMatchCategoryKey
;
132 const OSSymbol
* gIOMatchedServiceCountKey
;
133 const OSSymbol
* gIOMatchedPersonalityKey
;
134 const OSSymbol
* gIORematchPersonalityKey
;
135 const OSSymbol
* gIORematchCountKey
;
136 const OSSymbol
* gIODEXTMatchCountKey
;
137 const OSSymbol
* gIOSupportedPropertiesKey
;
138 const OSSymbol
* gIOUserServicePropertiesKey
;
140 const OSSymbol
* gIOServiceLegacyMatchingRegistryIDKey
;
143 const OSSymbol
* gIOMapperIDKey
;
144 const OSSymbol
* gIOUserClientClassKey
;
146 const OSSymbol
* gIOUserClassKey
;
147 const OSSymbol
* gIOUserServerClassKey
;
148 const OSSymbol
* gIOUserServerNameKey
;
149 const OSSymbol
* gIOUserServerTagKey
;
150 const OSSymbol
* gIOUserServerCDHashKey
;
151 const OSSymbol
* gIOUserUserClientKey
;
153 const OSSymbol
* gIOKitDebugKey
;
155 const OSSymbol
* gIOCommandPoolSizeKey
;
157 const OSSymbol
* gIOConsoleLockedKey
;
158 const OSSymbol
* gIOConsoleUsersKey
;
159 const OSSymbol
* gIOConsoleSessionUIDKey
;
160 const OSSymbol
* gIOConsoleSessionAuditIDKey
;
161 const OSSymbol
* gIOConsoleUsersSeedKey
;
162 const OSSymbol
* gIOConsoleSessionOnConsoleKey
;
163 const OSSymbol
* gIOConsoleSessionLoginDoneKey
;
164 const OSSymbol
* gIOConsoleSessionSecureInputPIDKey
;
165 const OSSymbol
* gIOConsoleSessionScreenLockedTimeKey
;
166 const OSSymbol
* gIOConsoleSessionScreenIsLockedKey
;
167 clock_sec_t gIOConsoleLockTime
;
168 static bool gIOConsoleLoggedIn
;
170 static OSBoolean
* gIOConsoleBooterLockState
;
171 static uint32_t gIOScreenLockState
;
173 static IORegistryEntry
* gIOChosenEntry
;
175 static int gIOResourceGenerationCount
;
177 const OSSymbol
* gIOServiceKey
;
178 const OSSymbol
* gIOPublishNotification
;
179 const OSSymbol
* gIOFirstPublishNotification
;
180 const OSSymbol
* gIOMatchedNotification
;
181 const OSSymbol
* gIOFirstMatchNotification
;
182 const OSSymbol
* gIOTerminatedNotification
;
183 const OSSymbol
* gIOWillTerminateNotification
;
185 const OSSymbol
* gIOServiceDEXTEntitlementsKey
;
186 const OSSymbol
* gIODriverKitEntitlementKey
;
187 const OSSymbol
* gIODriverKitUserClientEntitlementsKey
;
188 const OSSymbol
* gIOMatchDeferKey
;
190 const OSSymbol
* gIOGeneralInterest
;
191 const OSSymbol
* gIOBusyInterest
;
192 const OSSymbol
* gIOAppPowerStateInterest
;
193 const OSSymbol
* gIOPriorityPowerStateInterest
;
194 const OSSymbol
* gIOConsoleSecurityInterest
;
196 const OSSymbol
* gIOBSDKey
;
197 const OSSymbol
* gIOBSDNameKey
;
198 const OSSymbol
* gIOBSDMajorKey
;
199 const OSSymbol
* gIOBSDMinorKey
;
200 const OSSymbol
* gIOBSDUnitKey
;
202 const OSSymbol
* gAKSGetKey
;
203 #if defined(__i386__) || defined(__x86_64__)
204 const OSSymbol
* gIOCreateEFIDevicePathSymbol
;
207 static OSDictionary
* gNotifications
;
208 static IORecursiveLock
* gNotificationLock
;
210 static IOService
* gIOResources
;
211 static IOService
* gIOUserResources
;
212 static IOService
* gIOServiceRoot
;
214 static OSOrderedSet
* gJobs
;
215 static semaphore_port_t gJobsSemaphore
;
216 static IOLock
* gJobsLock
;
217 static int gOutstandingJobs
;
218 static int gNumConfigThreads
;
219 static int gNumWaitingThreads
;
220 static IOLock
* gIOServiceBusyLock
;
222 bool gKextdWillTerminate
;
224 static thread_t gIOTerminateThread
;
225 static thread_t gIOTerminateWorkerThread
;
226 static UInt32 gIOTerminateWork
;
227 static OSArray
* gIOTerminatePhase2List
;
228 static OSArray
* gIOStopList
;
229 static OSArray
* gIOStopProviderList
;
230 static OSArray
* gIOFinalizeList
;
233 static OSArray
* gIOMatchDeferList
;
236 static SInt32 gIOConsoleUsersSeed
;
237 static OSData
* gIOConsoleUsersSeedValue
;
239 extern const OSSymbol
* gIODTPHandleKey
;
241 const OSSymbol
* gIOPlatformFunctionHandlerSet
;
244 static IOLock
* gIOConsoleUsersLock
;
245 static thread_call_t gIOConsoleLockCallout
;
246 static IONotifier
* gIOServiceNullNotifier
;
248 static uint32_t gIODextRelaunchMax
= 1000;
250 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
252 #define LOCKREADNOTIFY() \
253 IORecursiveLockLock( gNotificationLock )
254 #define LOCKWRITENOTIFY() \
255 IORecursiveLockLock( gNotificationLock )
256 #define LOCKWRITE2READNOTIFY()
257 #define UNLOCKNOTIFY() \
258 IORecursiveLockUnlock( gNotificationLock )
259 #define SLEEPNOTIFY(event) \
260 IORecursiveLockSleep( gNotificationLock, (void *)(event), THREAD_UNINT )
261 #define SLEEPNOTIFYTO(event, deadline) \
262 IORecursiveLockSleepDeadline( gNotificationLock, (void *)(event), deadline, THREAD_UNINT )
263 #define WAKEUPNOTIFY(event) \
264 IORecursiveLockWakeup( gNotificationLock, (void *)(event), /* wake one */ false )
266 #define randomDelay() \
267 int del = read_processor_clock(); \
268 del = (((int)IOThreadSelf()) ^ del ^ (del >> 10)) & 0x3ff; \
271 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
273 #define queue_element(entry, element, type, field) do { \
274 vm_address_t __ele = (vm_address_t) (entry); \
275 __ele -= -4 + ((size_t)(&((type) 4)->field)); \
276 (element) = (type) __ele; \
279 #define iterqueue(que, elt) \
280 for (queue_entry_t elt = queue_first(que); \
281 !queue_end(que, elt); \
282 elt = queue_next(elt))
284 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
286 struct IOInterruptAccountingReporter
{
287 IOSimpleReporter
* reporter
; /* Reporter responsible for communicating the statistics */
288 IOInterruptAccountingData
* statistics
; /* The live statistics values, if any */
291 struct ArbitrationLockQueueElement
{
300 static queue_head_t gArbitrationLockQueueActive
;
301 static queue_head_t gArbitrationLockQueueWaiting
;
302 static queue_head_t gArbitrationLockQueueFree
;
303 static IOLock
* gArbitrationLockQueueLock
;
306 IOService::isInactive( void ) const
308 return 0 != (kIOServiceInactiveState
& getState());
311 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
313 #if defined(__i386__) || defined(__x86_64__)
315 // Only used by the intel implementation of
316 // IOService::requireMaxBusStall(UInt32 ns)
317 // IOService::requireMaxInterruptDelay(uint32_t ns)
318 struct CpuDelayEntry
{
319 IOService
* fService
;
325 kCpuDelayBusStall
, kCpuDelayInterrupt
,
329 static OSData
*sCpuDelayData
= OSData::withCapacity(8 * sizeof(CpuDelayEntry
));
330 static IORecursiveLock
*sCpuDelayLock
= IORecursiveLockAlloc();
331 static OSArray
*sCpuLatencyHandlers
[kCpuNumDelayTypes
];
332 const OSSymbol
*sCPULatencyFunctionName
[kCpuNumDelayTypes
];
333 static OSNumber
* sCPULatencyHolder
[kCpuNumDelayTypes
];
334 static char sCPULatencyHolderName
[kCpuNumDelayTypes
][128];
335 static OSNumber
* sCPULatencySet
[kCpuNumDelayTypes
];
338 requireMaxCpuDelay(IOService
* service
, UInt32 ns
, UInt32 delayType
);
340 setLatencyHandler(UInt32 delayType
, IOService
* target
, bool enable
);
342 #endif /* defined(__i386__) || defined(__x86_64__) */
344 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
346 namespace IOServicePH
348 IONotifier
* fRootNotifier
;
349 OSArray
* fUserServers
;
350 OSArray
* fUserServersWait
;
351 OSArray
* fMatchingWork
;
352 OSArray
* fMatchingDelayed
;
353 IOService
* fSystemPowerAckTo
;
354 uint32_t fSystemPowerAckRef
;
356 uint8_t fUserServerOff
;
361 void init(IOPMrootDomain
* root
);
363 IOReturn
systemPowerChange(
366 UInt32 messageType
, IOService
* service
,
367 void * messageArgument
, vm_size_t argSize
);
369 bool matchingStart(IOService
* service
);
370 void matchingEnd(IOService
* service
);
373 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
376 IOService::initialize( void )
380 gIOServicePlane
= IORegistryEntry::makePlane( kIOServicePlane
);
381 gIOPowerPlane
= IORegistryEntry::makePlane( kIOPowerPlane
);
383 gIOProviderClassKey
= OSSymbol::withCStringNoCopy( kIOProviderClassKey
);
384 gIONameMatchKey
= OSSymbol::withCStringNoCopy( kIONameMatchKey
);
385 gIONameMatchedKey
= OSSymbol::withCStringNoCopy( kIONameMatchedKey
);
386 gIOPropertyMatchKey
= OSSymbol::withCStringNoCopy( kIOPropertyMatchKey
);
387 gIOPropertyExistsMatchKey
= OSSymbol::withCStringNoCopy( kIOPropertyExistsMatchKey
);
388 gIOPathMatchKey
= OSSymbol::withCStringNoCopy( kIOPathMatchKey
);
389 gIOLocationMatchKey
= OSSymbol::withCStringNoCopy( kIOLocationMatchKey
);
390 gIOParentMatchKey
= OSSymbol::withCStringNoCopy( kIOParentMatchKey
);
392 gIOMatchCategoryKey
= OSSymbol::withCStringNoCopy( kIOMatchCategoryKey
);
393 gIODefaultMatchCategoryKey
= OSSymbol::withCStringNoCopy(
394 kIODefaultMatchCategoryKey
);
395 gIOMatchedServiceCountKey
= OSSymbol::withCStringNoCopy(
396 kIOMatchedServiceCountKey
);
397 gIOMatchedPersonalityKey
= OSSymbol::withCStringNoCopy(
398 kIOMatchedPersonalityKey
);
399 gIORematchPersonalityKey
= OSSymbol::withCStringNoCopy(
400 kIORematchPersonalityKey
);
401 gIORematchCountKey
= OSSymbol::withCStringNoCopy(
402 kIORematchCountKey
);
403 gIODEXTMatchCountKey
= OSSymbol::withCStringNoCopy(
404 kIODEXTMatchCountKey
);
407 gIOServiceLegacyMatchingRegistryIDKey
= OSSymbol::withCStringNoCopy(
408 kIOServiceLegacyMatchingRegistryIDKey
);
411 PE_parse_boot_argn("dextrelaunch", &gIODextRelaunchMax
, sizeof(gIODextRelaunchMax
));
413 gIOUserClientClassKey
= OSSymbol::withCStringNoCopy( kIOUserClientClassKey
);
415 gIOUserClassKey
= OSSymbol::withCStringNoCopy(kIOUserClassKey
);
417 gIOUserServerClassKey
= OSSymbol::withCStringNoCopy(kIOUserServerClassKey
);
418 gIOUserServerNameKey
= OSSymbol::withCStringNoCopy(kIOUserServerNameKey
);
419 gIOUserServerTagKey
= OSSymbol::withCStringNoCopy(kIOUserServerTagKey
);
420 gIOUserServerCDHashKey
= OSSymbol::withCStringNoCopy(kIOUserServerCDHashKey
);
421 gIOUserUserClientKey
= OSSymbol::withCStringNoCopy(kIOUserUserClientKey
);
423 gIOResourcesKey
= OSSymbol::withCStringNoCopy( kIOResourcesClass
);
424 gIOResourceMatchKey
= OSSymbol::withCStringNoCopy( kIOResourceMatchKey
);
425 gIOResourceMatchedKey
= OSSymbol::withCStringNoCopy( kIOResourceMatchedKey
);
426 gIOResourceIOKitKey
= OSSymbol::withCStringNoCopy("IOKit");
428 gIODeviceMemoryKey
= OSSymbol::withCStringNoCopy( "IODeviceMemory" );
429 gIOInterruptControllersKey
430 = OSSymbol::withCStringNoCopy("IOInterruptControllers");
431 gIOInterruptSpecifiersKey
432 = OSSymbol::withCStringNoCopy("IOInterruptSpecifiers");
434 gIOSupportedPropertiesKey
= OSSymbol::withCStringNoCopy(kIOSupportedPropertiesKey
);
435 gIOUserServicePropertiesKey
= OSSymbol::withCStringNoCopy(kIOUserServicePropertiesKey
);
437 gIOMapperIDKey
= OSSymbol::withCStringNoCopy(kIOMapperIDKey
);
439 gIOKitDebugKey
= OSSymbol::withCStringNoCopy( kIOKitDebugKey
);
441 gIOCommandPoolSizeKey
= OSSymbol::withCStringNoCopy( kIOCommandPoolSizeKey
);
443 gIOGeneralInterest
= OSSymbol::withCStringNoCopy( kIOGeneralInterest
);
444 gIOBusyInterest
= OSSymbol::withCStringNoCopy( kIOBusyInterest
);
445 gIOAppPowerStateInterest
= OSSymbol::withCStringNoCopy( kIOAppPowerStateInterest
);
446 gIOPriorityPowerStateInterest
= OSSymbol::withCStringNoCopy( kIOPriorityPowerStateInterest
);
447 gIOConsoleSecurityInterest
= OSSymbol::withCStringNoCopy( kIOConsoleSecurityInterest
);
449 gIOBSDKey
= OSSymbol::withCStringNoCopy(kIOBSDKey
);
450 gIOBSDNameKey
= OSSymbol::withCStringNoCopy(kIOBSDNameKey
);
451 gIOBSDMajorKey
= OSSymbol::withCStringNoCopy(kIOBSDMajorKey
);
452 gIOBSDMinorKey
= OSSymbol::withCStringNoCopy(kIOBSDMinorKey
);
453 gIOBSDUnitKey
= OSSymbol::withCStringNoCopy(kIOBSDUnitKey
);
455 gNotifications
= OSDictionary::withCapacity( 1 );
456 gIOPublishNotification
= OSSymbol::withCStringNoCopy(
457 kIOPublishNotification
);
458 gIOFirstPublishNotification
= OSSymbol::withCStringNoCopy(
459 kIOFirstPublishNotification
);
460 gIOMatchedNotification
= OSSymbol::withCStringNoCopy(
461 kIOMatchedNotification
);
462 gIOFirstMatchNotification
= OSSymbol::withCStringNoCopy(
463 kIOFirstMatchNotification
);
464 gIOTerminatedNotification
= OSSymbol::withCStringNoCopy(
465 kIOTerminatedNotification
);
466 gIOWillTerminateNotification
= OSSymbol::withCStringNoCopy(
467 kIOWillTerminateNotification
);
468 gIOServiceKey
= OSSymbol::withCStringNoCopy( kIOServiceClass
);
471 gIOConsoleLockedKey
= OSSymbol::withCStringNoCopy( kIOConsoleLockedKey
);
472 gIOConsoleUsersKey
= OSSymbol::withCStringNoCopy( kIOConsoleUsersKey
);
473 gIOConsoleSessionUIDKey
= OSSymbol::withCStringNoCopy( kIOConsoleSessionUIDKey
);
474 gIOConsoleSessionAuditIDKey
= OSSymbol::withCStringNoCopy( kIOConsoleSessionAuditIDKey
);
476 gIOConsoleUsersSeedKey
= OSSymbol::withCStringNoCopy(kIOConsoleUsersSeedKey
);
477 gIOConsoleSessionOnConsoleKey
= OSSymbol::withCStringNoCopy(kIOConsoleSessionOnConsoleKey
);
478 gIOConsoleSessionLoginDoneKey
= OSSymbol::withCStringNoCopy(kIOConsoleSessionLoginDoneKey
);
479 gIOConsoleSessionSecureInputPIDKey
= OSSymbol::withCStringNoCopy(kIOConsoleSessionSecureInputPIDKey
);
480 gIOConsoleSessionScreenLockedTimeKey
= OSSymbol::withCStringNoCopy(kIOConsoleSessionScreenLockedTimeKey
);
481 gIOConsoleSessionScreenIsLockedKey
= OSSymbol::withCStringNoCopy(kIOConsoleSessionScreenIsLockedKey
);
483 gIOConsoleUsersSeedValue
= OSData::withBytesNoCopy(&gIOConsoleUsersSeed
, sizeof(gIOConsoleUsersSeed
));
485 gIOServiceDEXTEntitlementsKey
= OSSymbol::withCStringNoCopy( kIOServiceDEXTEntitlementsKey
);
486 gIODriverKitEntitlementKey
= OSSymbol::withCStringNoCopy( kIODriverKitEntitlementKey
);
487 gIODriverKitUserClientEntitlementsKey
= OSSymbol::withCStringNoCopy( kIODriverKitUserClientEntitlementsKey
);
488 gIOMatchDeferKey
= OSSymbol::withCStringNoCopy( kIOMatchDeferKey
);
490 gIOPlatformFunctionHandlerSet
= OSSymbol::withCStringNoCopy(kIOPlatformFunctionHandlerSet
);
491 #if defined(__i386__) || defined(__x86_64__)
492 sCPULatencyFunctionName
[kCpuDelayBusStall
] = OSSymbol::withCStringNoCopy(kIOPlatformFunctionHandlerMaxBusDelay
);
493 sCPULatencyFunctionName
[kCpuDelayInterrupt
] = OSSymbol::withCStringNoCopy(kIOPlatformFunctionHandlerMaxInterruptDelay
);
495 for (idx
= 0; idx
< kCpuNumDelayTypes
; idx
++) {
496 sCPULatencySet
[idx
] = OSNumber::withNumber(-1U, 32);
497 sCPULatencyHolder
[idx
] = OSNumber::withNumber(0ULL, 64);
498 assert(sCPULatencySet
[idx
] && sCPULatencyHolder
[idx
]);
500 gIOCreateEFIDevicePathSymbol
= OSSymbol::withCString("CreateEFIDevicePath");
502 gNotificationLock
= IORecursiveLockAlloc();
504 gAKSGetKey
= OSSymbol::withCStringNoCopy(AKS_PLATFORM_FUNCTION_GETKEY
);
506 assert( gIOServicePlane
&& gIODeviceMemoryKey
507 && gIOInterruptControllersKey
&& gIOInterruptSpecifiersKey
508 && gIOResourcesKey
&& gNotifications
&& gNotificationLock
509 && gIOProviderClassKey
&& gIONameMatchKey
&& gIONameMatchedKey
510 && gIOMatchCategoryKey
&& gIODefaultMatchCategoryKey
511 && gIOPublishNotification
&& gIOMatchedNotification
512 && gIOTerminatedNotification
&& gIOServiceKey
513 && gIOConsoleUsersKey
&& gIOConsoleSessionUIDKey
514 && gIOConsoleSessionOnConsoleKey
&& gIOConsoleSessionSecureInputPIDKey
515 && gIOConsoleUsersSeedKey
&& gIOConsoleUsersSeedValue
);
517 gJobsLock
= IOLockAlloc();
518 gJobs
= OSOrderedSet::withCapacity( 10 );
520 gIOServiceBusyLock
= IOLockAlloc();
522 gIOConsoleUsersLock
= IOLockAlloc();
524 err
= semaphore_create(kernel_task
, &gJobsSemaphore
, SYNC_POLICY_FIFO
, 0);
526 gIOConsoleLockCallout
= thread_call_allocate(&IOService::consoleLockTimer
, NULL
);
528 IORegistryEntry::getRegistryRoot()->setProperty(gIOConsoleLockedKey
, kOSBooleanTrue
);
530 assert( gIOServiceBusyLock
&& gJobs
&& gJobsLock
&& gIOConsoleUsersLock
531 && gIOConsoleLockCallout
&& (err
== KERN_SUCCESS
));
533 gIOResources
= IOResources::resources();
534 gIOUserResources
= IOUserResources::resources();
535 assert( gIOResources
&& gIOUserResources
);
537 gIOServiceNullNotifier
= OSTypeAlloc(_IOServiceNullNotifier
);
538 assert(gIOServiceNullNotifier
);
540 gArbitrationLockQueueLock
= IOLockAlloc();
541 queue_init(&gArbitrationLockQueueActive
);
542 queue_init(&gArbitrationLockQueueWaiting
);
543 queue_init(&gArbitrationLockQueueFree
);
545 assert( gArbitrationLockQueueLock
);
547 gIOTerminatePhase2List
= OSArray::withCapacity( 2 );
548 gIOStopList
= OSArray::withCapacity( 16 );
549 gIOStopProviderList
= OSArray::withCapacity( 16 );
550 gIOFinalizeList
= OSArray::withCapacity( 16 );
552 gIOMatchDeferList
= OSArray::withCapacity( 16 );
554 assert( gIOTerminatePhase2List
&& gIOStopList
&& gIOStopProviderList
&& gIOFinalizeList
);
556 // worker thread that is responsible for terminating / cleaning up threads
557 kernel_thread_start(&terminateThread
, NULL
, &gIOTerminateWorkerThread
);
558 assert(gIOTerminateWorkerThread
);
559 thread_set_thread_name(gIOTerminateWorkerThread
, "IOServiceTerminateThread");
562 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
564 #if defined(__i386__) || defined(__x86_64__)
566 const char *getCpuDelayBusStallHolderName(void);
568 getCpuDelayBusStallHolderName(void)
570 return sCPULatencyHolderName
[kCpuDelayBusStall
];
573 const char *getCpuInterruptDelayHolderName(void);
575 getCpuInterruptDelayHolderName(void)
577 return sCPULatencyHolderName
[kCpuDelayInterrupt
];
584 getDebugFlags( OSDictionary
* props
)
586 OSNumber
* debugProp
;
589 debugProp
= OSDynamicCast( OSNumber
,
590 props
->getObject( gIOKitDebugKey
));
592 debugFlags
= debugProp
->unsigned64BitValue();
594 debugFlags
= gIOKitDebug
;
601 getDebugFlags( IOService
* inst
)
604 OSNumber
* debugProp
;
607 prop
= inst
->copyProperty(gIOKitDebugKey
);
608 debugProp
= OSDynamicCast(OSNumber
, prop
);
610 debugFlags
= debugProp
->unsigned64BitValue();
612 debugFlags
= gIOKitDebug
;
615 OSSafeReleaseNULL(prop
);
621 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
623 // Probe a matched service and return an instance to be started.
624 // The default score is from the property table, & may be altered
625 // during probe to change the start order.
628 IOService::probe( IOService
* provider
,
635 IOService::start( IOService
* provider
)
641 IOService::stop( IOService
* provider
)
643 if (reserved
->uvars
&& reserved
->uvars
->started
&& reserved
->uvars
->userServer
) {
644 reserved
->uvars
->userServer
->serviceStop(this, provider
);
649 IOService::init( OSDictionary
* dictionary
)
653 ret
= super::init(dictionary
);
661 reserved
= IONew(ExpansionData
, 1);
665 bzero(reserved
, sizeof(*reserved
));
668 * TODO: Improve on this. Previous efforts to more lazily allocate this
669 * lock based on the presence of specifiers ran into issues as some
670 * platforms set up the specifiers after IOService initialization.
672 * We may be able to get away with a global lock, as this should only be
673 * contended by IOReporting clients and driver start/stop (unless a
674 * driver wants to remove/add handlers in the course of normal operation,
675 * which should be unlikely).
677 reserved
->interruptStatisticsLock
= IOLockAlloc();
678 if (!reserved
->interruptStatisticsLock
) {
686 IOService::init( IORegistryEntry
* from
,
687 const IORegistryPlane
* inPlane
)
691 ret
= super::init(from
, inPlane
);
699 reserved
= IONew(ExpansionData
, 1);
703 bzero(reserved
, sizeof(*reserved
));
706 * TODO: Improve on this. Previous efforts to more lazily allocate this
707 * lock based on the presence of specifiers ran into issues as some
708 * platforms set up the specifiers after IOService initialization.
710 * We may be able to get away with a global lock, as this should only be
711 * contended by IOReporting clients and driver start/stop (unless a
712 * driver wants to remove/add handlers in the course of normal operation,
713 * which should be unlikely).
715 reserved
->interruptStatisticsLock
= IOLockAlloc();
716 if (!reserved
->interruptStatisticsLock
) {
724 IOService::free( void )
727 requireMaxBusStall(0);
728 requireMaxInterruptDelay(0);
729 if (getPropertyTable()) {
730 unregisterAllInterest();
735 if (reserved
->interruptStatisticsArray
) {
736 for (i
= 0; i
< reserved
->interruptStatisticsArrayCount
; i
++) {
737 if (reserved
->interruptStatisticsArray
[i
].reporter
) {
738 reserved
->interruptStatisticsArray
[i
].reporter
->release();
742 IODelete(reserved
->interruptStatisticsArray
, IOInterruptAccountingReporter
, reserved
->interruptStatisticsArrayCount
);
745 if (reserved
->interruptStatisticsLock
) {
746 IOLockFree(reserved
->interruptStatisticsLock
);
748 if (reserved
->uvars
&& reserved
->uvars
->userServer
) {
749 reserved
->uvars
->userServer
->serviceFree(this);
751 IODelete(reserved
, ExpansionData
, 1);
754 if (_numInterruptSources
&& _interruptSources
) {
755 for (i
= 0; i
< _numInterruptSources
; i
++) {
756 void * block
= _interruptSourcesPrivate(this)[i
].vectorBlock
;
758 Block_release(block
);
761 IOFree(_interruptSources
,
762 _numInterruptSources
* sizeofAllIOInterruptSource
);
763 _interruptSources
= NULL
;
770 * Attach in service plane
773 IOService::attach( IOService
* provider
)
777 AbsoluteTime deadline
;
778 int waitResult
= THREAD_AWAKENED
;
779 bool wait
, computeDeadline
= true;
782 if (gIOKitDebug
& kIOLogAttach
) {
783 LOG( "%s::attach(%s)\n", getName(),
784 provider
->getName());
790 provider
->lockForArbitration();
791 if (provider
->__state
[0] & kIOServiceInactiveState
) {
794 count
= provider
->getChildCount(gIOServicePlane
);
795 wait
= (count
> (kIOServiceBusyMax
- 4));
797 ok
= attachToParent(provider
, gIOServicePlane
);
799 IOLog("stalling for detach from %s\n", provider
->getName());
800 IOLockLock( gIOServiceBusyLock
);
801 provider
->__state
[1] |= kIOServiceWaitDetachState
;
804 provider
->unlockForArbitration();
806 if (computeDeadline
) {
807 clock_interval_to_deadline(15, kSecondScale
, &deadline
);
808 computeDeadline
= false;
810 assert_wait_deadline((event_t
)&provider
->__provider
, THREAD_UNINT
, deadline
);
811 IOLockUnlock( gIOServiceBusyLock
);
812 waitResult
= thread_block(THREAD_CONTINUE_NULL
);
813 wait
= (waitResult
!= THREAD_TIMED_OUT
);
817 gIOServiceRoot
= this;
818 ok
= attachToParent( getRegistryRoot(), gIOServicePlane
);
821 if (ok
&& !__provider
) {
822 (void) getProvider();
829 IOService::getServiceRoot( void )
831 return gIOServiceRoot
;
835 IOService::detach( IOService
* provider
)
837 IOService
* newProvider
= NULL
;
841 if (gIOKitDebug
& kIOLogAttach
) {
842 LOG("%s::detach(%s)\n", getName(), provider
->getName());
846 IOLockLock(gJobsLock
);
847 if (gIOMatchDeferList
) {
848 auto idx
= gIOMatchDeferList
->getNextIndexOfObject(this, 0);
850 gIOMatchDeferList
->removeObject(idx
);
853 if (IOServicePH::fMatchingDelayed
) {
854 auto idx
= IOServicePH::fMatchingDelayed
->getNextIndexOfObject(this, 0);
856 IOServicePH::fMatchingDelayed
->removeObject(idx
);
859 IOLockUnlock(gJobsLock
);
860 #endif /* NO_KEXTD */
862 lockForArbitration();
864 uint64_t regID1
= provider
->getRegistryEntryID();
865 uint64_t regID2
= getRegistryEntryID();
869 (uintptr_t) (regID1
>> 32),
871 (uintptr_t) (regID2
>> 32));
873 adjParent
= ((busy
= (__state
[1] & kIOServiceBusyStateMask
))
874 && (provider
== getProvider()));
876 detachFromParent( provider
, gIOServicePlane
);
879 newProvider
= getProvider();
880 if (busy
&& (__state
[1] & kIOServiceTermPhase3State
) && (NULL
== newProvider
)) {
881 _adjustBusy( -busy
);
885 if (kIOServiceInactiveState
& __state
[0]) {
886 getMetaClass()->removeInstance(this);
887 IORemoveServicePlatformActions(this);
890 unlockForArbitration();
892 if (newProvider
&& adjParent
) {
893 newProvider
->lockForArbitration();
894 newProvider
->_adjustBusy(1);
895 newProvider
->unlockForArbitration();
898 // check for last client detach from a terminated service
899 if (provider
->lockForArbitration( true )) {
900 if (kIOServiceStartState
& __state
[1]) {
901 provider
->scheduleTerminatePhase2();
904 provider
->_adjustBusy( -1 );
906 if ((provider
->__state
[1] & kIOServiceTermPhase3State
)
907 && (NULL
== provider
->getClient())) {
908 provider
->scheduleFinalize(false);
911 IOLockLock( gIOServiceBusyLock
);
912 if (kIOServiceWaitDetachState
& provider
->__state
[1]) {
913 provider
->__state
[1] &= ~kIOServiceWaitDetachState
;
914 thread_wakeup(&provider
->__provider
);
916 IOLockUnlock( gIOServiceBusyLock
);
918 provider
->unlockForArbitration();
923 * Register instance - publish it for matching
927 IOService::registerService( IOOptionBits options
)
933 enum { kMaxPathLen
= 256 };
934 enum { kMaxChars
= 63 };
936 IORegistryEntry
* parent
= this;
937 IORegistryEntry
* root
= getRegistryRoot();
938 while (parent
&& (parent
!= root
)) {
939 parent
= parent
->getParentEntry( gIOServicePlane
);
942 if (parent
!= root
) {
943 IOLog("%s: not registry member at registerService()\n", getName());
947 // Allow the Platform Expert to adjust this node.
948 if (gIOPlatform
&& (!gIOPlatform
->platformAdjustService(this))) {
952 IOInstallServicePlatformActions(this);
954 if ((this != gIOResources
)
955 && (kIOLogRegister
& gIOKitDebug
)) {
956 pathBuf
= (char *) IOMalloc( kMaxPathLen
);
958 IOLog( "Registering: " );
961 if (pathBuf
&& getPath( pathBuf
, &len
, gIOServicePlane
)) {
963 if (len
> kMaxChars
) {
967 if ((skip
= strchr( path
, '/'))) {
975 IOLog( "%s\n", path
);
978 IOFree( pathBuf
, kMaxPathLen
);
982 startMatching( options
);
986 IOService::startMatching( IOOptionBits options
)
988 IOService
* provider
;
991 bool needWake
= false;
996 lockForArbitration();
998 sync
= (options
& kIOServiceSynchronous
)
999 || ((provider
= getProvider())
1000 && (provider
->__state
[1] & kIOServiceSynchronousState
));
1002 if (options
& kIOServiceAsynchronous
) {
1006 needConfig
= (0 == (__state
[1] & (kIOServiceNeedConfigState
| kIOServiceConfigRunning
)))
1007 && (0 == (__state
[0] & kIOServiceInactiveState
));
1009 __state
[1] |= kIOServiceNeedConfigState
;
1011 // __state[0] &= ~kIOServiceInactiveState;
1013 // if( sync) LOG("OSKernelStackRemaining = %08x @ %s\n",
1014 // OSKernelStackRemaining(), getName());
1017 needWake
= (0 != (kIOServiceSyncPubState
& __state
[1]));
1021 __state
[1] |= kIOServiceSynchronousState
;
1023 __state
[1] &= ~kIOServiceSynchronousState
;
1027 prevBusy
= _adjustBusy( 1 );
1030 unlockForArbitration();
1034 IOLockLock( gIOServiceBusyLock
);
1035 thread_wakeup((event_t
) this /*&__state[1]*/ );
1036 IOLockUnlock( gIOServiceBusyLock
);
1037 } else if (!sync
|| (kIOServiceAsynchronous
& options
)) {
1038 ok
= (NULL
!= _IOServiceJob::startJob( this, kMatchNubJob
, options
));
1041 if ((__state
[1] & kIOServiceNeedConfigState
)) {
1042 doServiceMatch( options
);
1045 lockForArbitration();
1046 IOLockLock( gIOServiceBusyLock
);
1048 waitAgain
= ((prevBusy
< (__state
[1] & kIOServiceBusyStateMask
))
1049 && (0 == (__state
[0] & kIOServiceInactiveState
)));
1052 __state
[1] |= kIOServiceSyncPubState
| kIOServiceBusyWaiterState
;
1054 __state
[1] &= ~kIOServiceSyncPubState
;
1057 unlockForArbitration();
1060 assert_wait((event_t
) this /*&__state[1]*/, THREAD_UNINT
);
1063 IOLockUnlock( gIOServiceBusyLock
);
1065 thread_block(THREAD_CONTINUE_NULL
);
1067 } while (waitAgain
);
1074 IOService::startDeferredMatches(void)
1079 IOLockLock(gJobsLock
);
1080 array
= gIOMatchDeferList
;
1081 gIOMatchDeferList
= NULL
;
1082 IOLockUnlock(gJobsLock
);
1085 IOLog("deferred rematching count %d\n", array
->getCount());
1086 array
->iterateObjects(^bool (OSObject
* obj
)
1088 ((IOService
*)obj
)->startMatching(kIOServiceAsynchronous
);
1093 #endif /* !NO_KEXTD */
1097 IOService::kextdLaunched(void)
1100 IOServiceTrace(IOSERVICE_KEXTD_READY
, 0, 0, 0, 0);
1101 startDeferredMatches();
1102 getServiceRoot()->adjustBusy(-1);
1103 IOService::publishUserResource(gIOResourceIOKitKey
);
1104 #endif /* !NO_KEXTD */
1108 IOService::catalogNewDrivers( OSOrderedSet
* newTables
)
1110 OSDictionary
* table
;
1112 OSSet
* allSet
= NULL
;
1113 IOService
* service
;
1118 newTables
->retain();
1120 while ((table
= (OSDictionary
*) newTables
->getFirstObject())) {
1122 set
= (OSSet
*) copyExistingServices( table
,
1123 kIOServiceRegisteredState
,
1124 kIOServiceExistingSet
);
1128 count
+= set
->getCount();
1131 allSet
->merge((const OSSet
*) set
);
1139 if (getDebugFlags( table
) & kIOLogMatch
) {
1140 LOG("Matching service count = %ld\n", (long)count
);
1143 newTables
->removeObject(table
);
1147 while ((service
= (IOService
*) allSet
->getAnyObject())) {
1148 service
->startMatching(kIOServiceAsynchronous
);
1149 allSet
->removeObject(service
);
1154 newTables
->release();
1156 return kIOReturnSuccess
;
1160 _IOServiceJob::startJob( IOService
* nub
, int type
,
1161 IOOptionBits options
)
1163 _IOServiceJob
* job
;
1165 job
= new _IOServiceJob
;
1166 if (job
&& !job
->init()) {
1174 job
->options
= options
;
1175 nub
->retain(); // thread will release()
1183 * Called on a registered service to see if it matches
1188 IOService::matchPropertyTable( OSDictionary
* table
, SInt32
* score
)
1190 return matchPropertyTable(table
);
1194 IOService::matchPropertyTable( OSDictionary
* table
)
1200 * Called on a matched service to allocate resources
1201 * before first driver is attached.
1205 IOService::getResources( void )
1207 return kIOReturnSuccess
;
1211 * Client/provider accessors
1215 IOService::getProvider( void ) const
1217 IOService
* self
= (IOService
*) this;
1221 generation
= getRegistryEntryGenerationCount();
1222 if (__providerGeneration
== generation
) {
1226 parent
= (IOService
*) getParentEntry( gIOServicePlane
);
1227 if (parent
== IORegistryEntry::getRegistryRoot()) {
1228 /* root is not an IOService */
1232 self
->__provider
= parent
;
1234 // save the count from before call to getParentEntry()
1235 self
->__providerGeneration
= generation
;
1241 IOService::getWorkLoop() const
1243 IOService
*provider
= getProvider();
1246 return provider
->getWorkLoop();
1253 IOService::getProviderIterator( void ) const
1255 return getParentIterator( gIOServicePlane
);
1259 IOService::getClient( void ) const
1261 return (IOService
*) getChildEntry( gIOServicePlane
);
1265 IOService::getClientIterator( void ) const
1267 return getChildIterator( gIOServicePlane
);
1271 _IOOpenServiceIterator::iterator( OSIterator
* _iter
,
1272 const IOService
* client
,
1273 const IOService
* provider
)
1275 _IOOpenServiceIterator
* inst
;
1281 inst
= new _IOOpenServiceIterator
;
1283 if (inst
&& !inst
->init()) {
1289 inst
->client
= client
;
1290 inst
->provider
= provider
;
1297 _IOOpenServiceIterator::free()
1301 last
->unlockForArbitration();
1307 _IOOpenServiceIterator::getNextObject()
1312 last
->unlockForArbitration();
1315 while ((next
= (IOService
*) iter
->getNextObject())) {
1316 next
->lockForArbitration();
1317 if ((client
&& (next
->isOpen( client
)))
1318 || (provider
&& (provider
->isOpen( next
)))) {
1321 next
->unlockForArbitration();
1330 _IOOpenServiceIterator::isValid()
1332 return iter
->isValid();
1336 _IOOpenServiceIterator::reset()
1339 last
->unlockForArbitration();
1346 IOService::getOpenProviderIterator( void ) const
1348 return _IOOpenServiceIterator::iterator( getProviderIterator(), this, NULL
);
1352 IOService::getOpenClientIterator( void ) const
1354 return _IOOpenServiceIterator::iterator( getClientIterator(), NULL
, this );
1359 IOService::callPlatformFunction( const OSSymbol
* functionName
,
1360 bool waitForFunction
,
1361 void *param1
, void *param2
,
1362 void *param3
, void *param4
)
1364 IOReturn result
= kIOReturnUnsupported
;
1365 IOService
*provider
;
1367 if (functionName
== gIOPlatformQuiesceActionKey
||
1368 functionName
== gIOPlatformActiveActionKey
) {
1370 * Services which register for IOPlatformQuiesceAction / IOPlatformActiveAction
1371 * must consume that event themselves, without passing it up to super/IOService.
1373 if (gEnforceQuiesceSafety
) {
1374 panic("Class %s passed the quiesce/active action to IOService",
1375 getMetaClass()->getClassName());
1379 if (gIOPlatformFunctionHandlerSet
== functionName
) {
1380 #if defined(__i386__) || defined(__x86_64__)
1381 const OSSymbol
* functionHandlerName
= (const OSSymbol
*) param1
;
1382 IOService
* target
= (IOService
*) param2
;
1383 bool enable
= (param3
!= NULL
);
1385 if (sCPULatencyFunctionName
[kCpuDelayBusStall
] == functionHandlerName
) {
1386 result
= setLatencyHandler(kCpuDelayBusStall
, target
, enable
);
1387 } else if (sCPULatencyFunctionName
[kCpuDelayInterrupt
] == param1
) {
1388 result
= setLatencyHandler(kCpuDelayInterrupt
, target
, enable
);
1390 #endif /* defined(__i386__) || defined(__x86_64__) */
1393 if ((kIOReturnUnsupported
== result
) && (provider
= getProvider())) {
1394 result
= provider
->callPlatformFunction(functionName
, waitForFunction
,
1395 param1
, param2
, param3
, param4
);
1402 IOService::callPlatformFunction( const char * functionName
,
1403 bool waitForFunction
,
1404 void *param1
, void *param2
,
1405 void *param3
, void *param4
)
1407 IOReturn result
= kIOReturnNoMemory
;
1408 const OSSymbol
*functionSymbol
= OSSymbol::withCString(functionName
);
1410 if (functionSymbol
!= NULL
) {
1411 result
= callPlatformFunction(functionSymbol
, waitForFunction
,
1412 param1
, param2
, param3
, param4
);
1413 functionSymbol
->release();
1421 * Accessors for global services
1425 IOService::getPlatform( void )
1430 class IOPMrootDomain
*
1431 IOService::getPMRootDomain( void )
1433 return gIOPMRootDomain
;
1437 IOService::getResourceService( void )
1439 return gIOResources
;
1443 IOService::setPlatform( IOPlatformExpert
* platform
)
1445 gIOPlatform
= platform
;
1446 gIOResources
->attachToParent( gIOServiceRoot
, gIOServicePlane
);
1447 gIOUserResources
->attachToParent( gIOServiceRoot
, gIOServicePlane
);
1449 #if defined(__i386__) || defined(__x86_64__)
1451 static const char * keys
[kCpuNumDelayTypes
] = {
1452 kIOPlatformMaxBusDelay
, kIOPlatformMaxInterruptDelay
};
1453 const OSObject
* objs
[2];
1457 for (idx
= 0; idx
< kCpuNumDelayTypes
; idx
++) {
1458 objs
[0] = sCPULatencySet
[idx
];
1459 objs
[1] = sCPULatencyHolder
[idx
];
1460 array
= OSArray::withObjects(objs
, 2);
1464 platform
->setProperty(keys
[idx
], array
);
1467 #endif /* defined(__i386__) || defined(__x86_64__) */
1471 IOService::setPMRootDomain( class IOPMrootDomain
* rootDomain
)
1473 gIOPMRootDomain
= rootDomain
;
1474 publishResource(gIOResourceIOKitKey
);
1475 IOServicePH::init(rootDomain
);
1483 IOService::lockForArbitration( bool isSuccessRequired
)
1487 ArbitrationLockQueueElement
* element
;
1488 ArbitrationLockQueueElement
* active
;
1489 ArbitrationLockQueueElement
* waiting
;
1491 enum { kPutOnFreeQueue
, kPutOnActiveQueue
, kPutOnWaitingQueue
} action
;
1493 // lock global access
1494 IOTakeLock( gArbitrationLockQueueLock
);
1496 // obtain an unused queue element
1497 if (!queue_empty( &gArbitrationLockQueueFree
)) {
1498 queue_remove_first( &gArbitrationLockQueueFree
,
1500 ArbitrationLockQueueElement
*,
1503 element
= IONew( ArbitrationLockQueueElement
, 1 );
1507 // prepare the queue element
1508 element
->thread
= IOThreadSelf();
1509 element
->service
= this;
1511 element
->required
= isSuccessRequired
;
1512 element
->aborted
= false;
1514 // determine whether this object is already locked (ie. on active queue)
1516 queue_iterate( &gArbitrationLockQueueActive
,
1518 ArbitrationLockQueueElement
*,
1521 if (active
->service
== element
->service
) {
1527 if (found
) { // this object is already locked
1528 // determine whether it is the same or a different thread trying to lock
1529 if (active
->thread
!= element
->thread
) { // it is a different thread
1530 ArbitrationLockQueueElement
* victim
= NULL
;
1532 // before placing this new thread on the waiting queue, we look for
1533 // a deadlock cycle...
1536 // determine whether the active thread holding the object we
1537 // want is waiting for another object to be unlocked
1539 queue_iterate( &gArbitrationLockQueueWaiting
,
1541 ArbitrationLockQueueElement
*,
1544 if (waiting
->thread
== active
->thread
) {
1545 assert( false == waiting
->aborted
);
1551 if (found
) { // yes, active thread waiting for another object
1552 // this may be a candidate for rejection if the required
1553 // flag is not set, should we detect a deadlock later on
1554 if (false == waiting
->required
) {
1558 // find the thread that is holding this other object, that
1559 // is blocking the active thread from proceeding (fun :-)
1561 queue_iterate( &gArbitrationLockQueueActive
,
1562 active
, // (reuse active queue element)
1563 ArbitrationLockQueueElement
*,
1566 if (active
->service
== waiting
->service
) {
1572 // someone must be holding it or it wouldn't be waiting
1575 if (active
->thread
== element
->thread
) {
1576 // doh, it's waiting for the thread that originated
1577 // this whole lock (ie. current thread) -> deadlock
1578 if (false == element
->required
) { // willing to fail?
1579 // the originating thread doesn't have the required
1580 // flag, so it can fail
1581 success
= false; // (fail originating lock request)
1582 break; // (out of while)
1583 } else { // originating thread is not willing to fail
1584 // see if we came across a waiting thread that did
1585 // not have the 'required' flag set: we'll fail it
1587 // we do have a willing victim, fail it's lock
1588 victim
->aborted
= true;
1590 // take the victim off the waiting queue
1591 queue_remove( &gArbitrationLockQueueWaiting
,
1593 ArbitrationLockQueueElement
*,
1597 IOLockWakeup( gArbitrationLockQueueLock
,
1599 /* one thread */ true );
1601 // allow this thread to proceed (ie. wait)
1602 success
= true; // (put request on wait queue)
1603 break; // (out of while)
1605 // all the waiting threads we came across in
1606 // finding this loop had the 'required' flag
1607 // set, so we've got a deadlock we can't avoid
1608 panic("I/O Kit: Unrecoverable deadlock.");
1612 // repeat while loop, redefining active thread to be the
1613 // thread holding "this other object" (see above), and
1614 // looking for threads waiting on it; note the active
1615 // variable points to "this other object" already... so
1616 // there nothing to do in this else clause.
1618 } else { // no, active thread is not waiting for another object
1619 success
= true; // (put request on wait queue)
1620 break; // (out of while)
1624 if (success
) { // put the request on the waiting queue?
1625 kern_return_t wait_result
;
1627 // place this thread on the waiting queue and put it to sleep;
1628 // we place it at the tail of the queue...
1629 queue_enter( &gArbitrationLockQueueWaiting
,
1631 ArbitrationLockQueueElement
*,
1634 // declare that this thread will wait for a given event
1635 restart_sleep
: wait_result
= assert_wait( element
,
1636 element
->required
? THREAD_UNINT
1637 : THREAD_INTERRUPTIBLE
);
1639 // unlock global access
1640 IOUnlock( gArbitrationLockQueueLock
);
1642 // put thread to sleep, waiting for our event to fire...
1643 if (wait_result
== THREAD_WAITING
) {
1644 wait_result
= thread_block(THREAD_CONTINUE_NULL
);
1648 // ...and we've been woken up; we might be in one of two states:
1649 // (a) we've been aborted and our queue element is not on
1650 // any of the three queues, but is floating around
1651 // (b) we're allowed to proceed with the lock and we have
1652 // already been moved from the waiting queue to the
1654 // ...plus a 3rd state, should the thread have been interrupted:
1655 // (c) we're still on the waiting queue
1657 // determine whether we were interrupted out of our sleep
1658 if (THREAD_INTERRUPTED
== wait_result
) {
1659 // re-lock global access
1660 IOTakeLock( gArbitrationLockQueueLock
);
1662 // determine whether we're still on the waiting queue
1664 queue_iterate( &gArbitrationLockQueueWaiting
,
1665 waiting
, // (reuse waiting queue element)
1666 ArbitrationLockQueueElement
*,
1669 if (waiting
== element
) {
1675 if (found
) { // yes, we're still on the waiting queue
1676 // determine whether we're willing to fail
1677 if (false == element
->required
) {
1678 // mark us as aborted
1679 element
->aborted
= true;
1681 // take us off the waiting queue
1682 queue_remove( &gArbitrationLockQueueWaiting
,
1684 ArbitrationLockQueueElement
*,
1686 } else { // we are not willing to fail
1687 // ignore interruption, go back to sleep
1692 // unlock global access
1693 IOUnlock( gArbitrationLockQueueLock
);
1695 // proceed as though this were a normal wake up
1696 wait_result
= THREAD_AWAKENED
;
1699 assert( THREAD_AWAKENED
== wait_result
);
1701 // determine whether we've been aborted while we were asleep
1702 if (element
->aborted
) {
1703 assert( false == element
->required
);
1705 // re-lock global access
1706 IOTakeLock( gArbitrationLockQueueLock
);
1708 action
= kPutOnFreeQueue
;
1710 } else { // we weren't aborted, so we must be ready to go :-)
1711 // we've already been moved from waiting to active queue
1714 } else { // the lock request is to be failed
1715 // return unused queue element to queue
1716 action
= kPutOnFreeQueue
;
1718 } else { // it is the same thread, recursive access is allowed
1719 // add one level of recursion
1722 // return unused queue element to queue
1723 action
= kPutOnFreeQueue
;
1726 } else { // this object is not already locked, so let this thread through
1727 action
= kPutOnActiveQueue
;
1731 // put the new element on a queue
1732 if (kPutOnActiveQueue
== action
) {
1733 queue_enter( &gArbitrationLockQueueActive
,
1735 ArbitrationLockQueueElement
*,
1737 } else if (kPutOnFreeQueue
== action
) {
1738 queue_enter( &gArbitrationLockQueueFree
,
1740 ArbitrationLockQueueElement
*,
1743 assert( 0 ); // kPutOnWaitingQueue never occurs, handled specially above
1746 // unlock global access
1747 IOUnlock( gArbitrationLockQueueLock
);
1753 IOService::unlockForArbitration( void )
1756 ArbitrationLockQueueElement
* element
;
1758 // lock global access
1759 IOTakeLock( gArbitrationLockQueueLock
);
1761 // find the lock element for this object (ie. on active queue)
1763 queue_iterate( &gArbitrationLockQueueActive
,
1765 ArbitrationLockQueueElement
*,
1768 if (element
->service
== this) {
1776 // determine whether the lock has been taken recursively
1777 if (element
->count
> 1) {
1778 // undo one level of recursion
1781 // remove it from the active queue
1782 queue_remove( &gArbitrationLockQueueActive
,
1784 ArbitrationLockQueueElement
*,
1787 // put it on the free queue
1788 queue_enter( &gArbitrationLockQueueFree
,
1790 ArbitrationLockQueueElement
*,
1793 // determine whether a thread is waiting for object (head to tail scan)
1795 queue_iterate( &gArbitrationLockQueueWaiting
,
1797 ArbitrationLockQueueElement
*,
1800 if (element
->service
== this) {
1806 if (found
) { // we found an interested thread on waiting queue
1807 // remove it from the waiting queue
1808 queue_remove( &gArbitrationLockQueueWaiting
,
1810 ArbitrationLockQueueElement
*,
1813 // put it on the active queue
1814 queue_enter( &gArbitrationLockQueueActive
,
1816 ArbitrationLockQueueElement
*,
1819 // wake the waiting thread
1820 IOLockWakeup( gArbitrationLockQueueLock
,
1822 /* one thread */ true );
1826 // unlock global access
1827 IOUnlock( gArbitrationLockQueueLock
);
1831 IOService::isLockedForArbitration(IOService
* service
)
1833 #if DEBUG_NOTIFIER_LOCKED
1835 ArbitrationLockQueueElement
* active
;
1837 // lock global access
1838 IOLockLock(gArbitrationLockQueueLock
);
1840 // determine whether this object is already locked (ie. on active queue)
1842 queue_iterate(&gArbitrationLockQueueActive
,
1844 ArbitrationLockQueueElement
*,
1847 if ((active
->thread
== IOThreadSelf())
1848 && (!service
|| (active
->service
== service
))) {
1850 count
+= active
->count
;
1854 IOLockUnlock(gArbitrationLockQueueLock
);
1858 #else /* DEBUG_NOTIFIER_LOCKED */
1862 #endif /* DEBUG_NOTIFIER_LOCKED */
1866 IOService::applyToProviders( IOServiceApplierFunction applier
,
1869 applyToParents((IORegistryEntryApplierFunction
) applier
,
1870 context
, gIOServicePlane
);
1874 IOService::applyToClients( IOServiceApplierFunction applier
,
1877 applyToChildren((IORegistryEntryApplierFunction
) applier
,
1878 context
, gIOServicePlane
);
1887 // send a message to a client or interested party of this service
1889 IOService::messageClient( UInt32 type
, OSObject
* client
,
1890 void * argument
, vm_size_t argSize
)
1893 IOService
* service
;
1894 _IOServiceInterestNotifier
* notify
;
1896 if ((service
= OSDynamicCast( IOService
, client
))) {
1897 ret
= service
->message( type
, this, argument
);
1898 } else if ((notify
= OSDynamicCast( _IOServiceInterestNotifier
, client
))) {
1899 _IOServiceNotifierInvocation invocation
;
1902 invocation
.thread
= current_thread();
1905 willNotify
= (0 != (kIOServiceNotifyEnable
& notify
->state
));
1908 queue_enter( ¬ify
->handlerInvocations
, &invocation
,
1909 _IOServiceNotifierInvocation
*, link
);
1914 ret
= (*notify
->handler
)( notify
->target
, notify
->ref
,
1915 type
, this, argument
, argSize
);
1918 queue_remove( ¬ify
->handlerInvocations
, &invocation
,
1919 _IOServiceNotifierInvocation
*, link
);
1920 if (kIOServiceNotifyWaiter
& notify
->state
) {
1921 notify
->state
&= ~kIOServiceNotifyWaiter
;
1922 WAKEUPNOTIFY( notify
);
1926 ret
= kIOReturnSuccess
;
1929 ret
= kIOReturnBadArgument
;
1936 applyToInterestNotifiers(const IORegistryEntry
*target
,
1937 const OSSymbol
* typeOfInterest
,
1938 OSObjectApplierFunction applier
,
1941 OSArray
* copyArray
= NULL
;
1946 prop
= target
->copyProperty(typeOfInterest
);
1947 IOCommand
*notifyList
= OSDynamicCast(IOCommand
, prop
);
1950 copyArray
= OSArray::withCapacity(1);
1952 // iterate over queue, entry is set to each element in the list
1953 iterqueue(¬ifyList
->fCommandChain
, entry
) {
1954 _IOServiceInterestNotifier
* notify
;
1956 queue_element(entry
, notify
, _IOServiceInterestNotifier
*, chain
);
1957 copyArray
->setObject(notify
);
1966 for (index
= 0; (next
= copyArray
->getObject( index
)); index
++) {
1967 (*applier
)(next
, context
);
1969 copyArray
->release();
1972 OSSafeReleaseNULL(prop
);
1976 IOService::applyToInterested( const OSSymbol
* typeOfInterest
,
1977 OSObjectApplierFunction applier
,
1980 if (gIOGeneralInterest
== typeOfInterest
) {
1981 applyToClients((IOServiceApplierFunction
) applier
, context
);
1983 applyToInterestNotifiers(this, typeOfInterest
, applier
, context
);
1986 struct MessageClientsContext
{
1987 IOService
* service
;
1995 messageClientsApplier( OSObject
* object
, void * ctx
)
1998 MessageClientsContext
* context
= (MessageClientsContext
*) ctx
;
2000 ret
= context
->service
->messageClient( context
->type
,
2001 object
, context
->argument
, context
->argSize
);
2002 if (kIOReturnSuccess
!= ret
) {
2007 // send a message to all clients
2009 IOService::messageClients( UInt32 type
,
2010 void * argument
, vm_size_t argSize
)
2012 MessageClientsContext context
;
2014 context
.service
= this;
2015 context
.type
= type
;
2016 context
.argument
= argument
;
2017 context
.argSize
= argSize
;
2018 context
.ret
= kIOReturnSuccess
;
2020 applyToInterested( gIOGeneralInterest
,
2021 &messageClientsApplier
, &context
);
2027 IOService::acknowledgeNotification( IONotificationRef notification
,
2028 IOOptionBits response
)
2030 return kIOReturnUnsupported
;
2034 IOService::registerInterest( const OSSymbol
* typeOfInterest
,
2035 IOServiceInterestHandler handler
, void * target
, void * ref
)
2037 _IOServiceInterestNotifier
* notify
= NULL
;
2038 IOReturn rc
= kIOReturnError
;
2040 notify
= new _IOServiceInterestNotifier
;
2045 if (notify
->init()) {
2046 rc
= registerInterestForNotifier(notify
, typeOfInterest
,
2047 handler
, target
, ref
);
2050 if (rc
!= kIOReturnSuccess
) {
2061 IOServiceInterestHandlerToBlock( void * target __unused
, void * refCon
,
2062 UInt32 messageType
, IOService
* provider
,
2063 void * messageArgument
, vm_size_t argSize
)
2065 return ((IOServiceInterestHandlerBlock
) refCon
)(messageType
, provider
, messageArgument
, argSize
);
2069 IOService::registerInterest(const OSSymbol
* typeOfInterest
,
2070 IOServiceInterestHandlerBlock handler
)
2072 IONotifier
* notify
;
2075 block
= Block_copy(handler
);
2080 notify
= registerInterest(typeOfInterest
, &IOServiceInterestHandlerToBlock
, NULL
, block
);
2083 Block_release(block
);
2090 IOService::registerInterestForNotifier( IONotifier
*svcNotify
, const OSSymbol
* typeOfInterest
,
2091 IOServiceInterestHandler handler
, void * target
, void * ref
)
2093 IOReturn rc
= kIOReturnSuccess
;
2094 _IOServiceInterestNotifier
*notify
= NULL
;
2096 if (!svcNotify
|| !(notify
= OSDynamicCast(_IOServiceInterestNotifier
, svcNotify
))) {
2097 return kIOReturnBadArgument
;
2100 notify
->handler
= handler
;
2101 notify
->target
= target
;
2104 if ((typeOfInterest
!= gIOGeneralInterest
)
2105 && (typeOfInterest
!= gIOBusyInterest
)
2106 && (typeOfInterest
!= gIOAppPowerStateInterest
)
2107 && (typeOfInterest
!= gIOConsoleSecurityInterest
)
2108 && (typeOfInterest
!= gIOPriorityPowerStateInterest
)) {
2109 return kIOReturnBadArgument
;
2112 lockForArbitration();
2113 if (0 == (__state
[0] & kIOServiceInactiveState
)) {
2114 notify
->state
= kIOServiceNotifyEnable
;
2120 // Get the head of the notifier linked list
2121 IOCommand
* notifyList
;
2122 OSObject
* obj
= copyProperty( typeOfInterest
);
2123 if (!(notifyList
= OSDynamicCast(IOCommand
, obj
))) {
2124 notifyList
= OSTypeAlloc(IOCommand
);
2127 bool ok
= setProperty( typeOfInterest
, notifyList
);
2128 notifyList
->release();
2139 enqueue(¬ifyList
->fCommandChain
, ¬ify
->chain
);
2140 notify
->retain(); // ref'ed while in list
2145 rc
= kIOReturnNotReady
;
2147 unlockForArbitration();
2153 cleanInterestList( OSObject
* head
)
2155 IOCommand
*notifyHead
= OSDynamicCast(IOCommand
, head
);
2161 while (queue_entry_t entry
= dequeue(¬ifyHead
->fCommandChain
)) {
2162 queue_next(entry
) = queue_prev(entry
) = NULL
;
2164 _IOServiceInterestNotifier
* notify
;
2166 queue_element(entry
, notify
, _IOServiceInterestNotifier
*, chain
);
2173 IOService::unregisterAllInterest( void )
2177 prop
= copyProperty(gIOGeneralInterest
);
2178 cleanInterestList(prop
);
2179 OSSafeReleaseNULL(prop
);
2181 prop
= copyProperty(gIOBusyInterest
);
2182 cleanInterestList(prop
);
2183 OSSafeReleaseNULL(prop
);
2185 prop
= copyProperty(gIOAppPowerStateInterest
);
2186 cleanInterestList(prop
);
2187 OSSafeReleaseNULL(prop
);
2189 prop
= copyProperty(gIOPriorityPowerStateInterest
);
2190 cleanInterestList(prop
);
2191 OSSafeReleaseNULL(prop
);
2193 prop
= copyProperty(gIOConsoleSecurityInterest
);
2194 cleanInterestList(prop
);
2195 OSSafeReleaseNULL(prop
);
2199 * _IOServiceInterestNotifier
2202 // wait for all threads, other than the current one,
2203 // to exit the handler
2206 _IOServiceInterestNotifier::wait()
2208 _IOServiceNotifierInvocation
* next
;
2213 queue_iterate( &handlerInvocations
, next
,
2214 _IOServiceNotifierInvocation
*, link
) {
2215 if (next
->thread
!= current_thread()) {
2221 state
|= kIOServiceNotifyWaiter
;
2228 _IOServiceInterestNotifier::free()
2230 assert( queue_empty( &handlerInvocations
));
2232 if (handler
== &IOServiceInterestHandlerToBlock
) {
2240 _IOServiceInterestNotifier::remove()
2244 if (queue_next( &chain
)) {
2246 queue_next( &chain
) = queue_prev( &chain
) = NULL
;
2250 state
&= ~kIOServiceNotifyEnable
;
2260 _IOServiceInterestNotifier::disable()
2266 ret
= (0 != (kIOServiceNotifyEnable
& state
));
2267 state
&= ~kIOServiceNotifyEnable
;
2278 _IOServiceInterestNotifier::enable( bool was
)
2282 state
|= kIOServiceNotifyEnable
;
2284 state
&= ~kIOServiceNotifyEnable
;
2290 _IOServiceInterestNotifier::init()
2292 queue_init( &handlerInvocations
);
2293 return OSObject::init();
2295 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2301 #define tailQ(o) setObject(o)
2302 #define headQ(o) setObject(0, o)
2303 #define TLOG(fmt, args...) { if(kIOLogYield & gIOKitDebug) { IOLog("[%llx] ", thread_tid(current_thread())); IOLog(fmt, ## args); }}
2306 _workLoopAction( IOWorkLoop::Action action
,
2307 IOService
* service
,
2308 void * p0
= NULL
, void * p1
= NULL
,
2309 void * p2
= NULL
, void * p3
= NULL
)
2313 if ((wl
= service
->getWorkLoop())) {
2315 wl
->runAction( action
, service
, p0
, p1
, p2
, p3
);
2318 (*action
)( service
, p0
, p1
, p2
, p3
);
2323 IOService::requestTerminate( IOService
* provider
, IOOptionBits options
)
2327 // if its our only provider
2328 ok
= isParent( provider
, gIOServicePlane
, true);
2332 provider
->terminateClient( this, options
| kIOServiceRecursing
);
2333 ok
= (0 != (kIOServiceInactiveState
& __state
[0]));
2341 IOService::terminatePhase1( IOOptionBits options
)
2345 IOService
* rematchProvider
;
2347 OSArray
* makeInactive
;
2348 OSArray
* waitingInactive
;
2349 IOOptionBits callerOptions
;
2350 int waitResult
= THREAD_AWAKENED
;
2354 bool startPhase2
= false;
2356 TLOG("%s[0x%qx]::terminatePhase1(%08llx)\n", getName(), getRegistryEntryID(), (long long)options
);
2358 callerOptions
= options
;
2359 rematchProvider
= NULL
;
2360 uint64_t regID
= getRegistryEntryID();
2362 IOSERVICE_TERMINATE_PHASE1
,
2364 (uintptr_t) (regID
>> 32),
2366 (uintptr_t) options
);
2369 if (options
& kIOServiceRecursing
) {
2370 lockForArbitration();
2371 if (0 == (kIOServiceInactiveState
& __state
[0])) {
2372 __state
[0] |= kIOServiceInactiveState
;
2373 __state
[1] |= kIOServiceRecursing
| kIOServiceTermPhase1State
;
2375 unlockForArbitration();
2381 makeInactive
= OSArray::withCapacity( 16 );
2382 waitingInactive
= OSArray::withCapacity( 16 );
2383 if (!makeInactive
|| !waitingInactive
) {
2391 didInactive
= victim
->lockForArbitration( true );
2393 uint64_t regID1
= victim
->getRegistryEntryID();
2394 IOServiceTrace(IOSERVICE_TERM_SET_INACTIVE
,
2396 (uintptr_t) (regID1
>> 32),
2397 (uintptr_t) victim
->__state
[1],
2400 enum { kRP1
= kIOServiceRecursing
| kIOServiceTermPhase1State
};
2401 didInactive
= (kRP1
== (victim
->__state
[1] & kRP1
))
2402 || (0 == (victim
->__state
[0] & kIOServiceInactiveState
));
2405 // a multiply attached IOService can be visited twice
2406 if (-1U == waitingInactive
->getNextIndexOfObject(victim
, 0)) {
2408 IOLockLock(gIOServiceBusyLock
);
2409 wait
= (victim
->__state
[1] & kIOServiceTermPhase1State
);
2411 TLOG("%s[0x%qx]::waitPhase1(%s[0x%qx])\n",
2412 getName(), getRegistryEntryID(), victim
->getName(), victim
->getRegistryEntryID());
2413 victim
->__state
[1] |= kIOServiceTerm1WaiterState
;
2414 victim
->unlockForArbitration();
2415 assert_wait((event_t
)&victim
->__state
[1], THREAD_UNINT
);
2417 IOLockUnlock(gIOServiceBusyLock
);
2419 waitResult
= thread_block(THREAD_CONTINUE_NULL
);
2420 TLOG("%s[0x%qx]::did waitPhase1(%s[0x%qx])\n",
2421 getName(), getRegistryEntryID(), victim
->getName(), victim
->getRegistryEntryID());
2422 victim
->lockForArbitration();
2424 }while (wait
&& (waitResult
!= THREAD_TIMED_OUT
));
2427 victim
->__state
[0] |= kIOServiceInactiveState
;
2428 victim
->__state
[0] &= ~(kIOServiceRegisteredState
| kIOServiceMatchedState
2429 | kIOServiceFirstPublishState
| kIOServiceFirstMatchState
);
2430 victim
->__state
[1] &= ~kIOServiceRecursing
;
2431 victim
->__state
[1] |= kIOServiceTermPhase1State
;
2432 waitingInactive
->headQ(victim
);
2433 if (victim
== this) {
2434 if (kIOServiceTerminateNeedWillTerminate
& options
) {
2435 victim
->__state
[1] |= kIOServiceNeedWillTerminate
;
2438 victim
->_adjustBusy( 1 );
2440 if ((options
& kIOServiceTerminateWithRematch
) && (victim
== this)) {
2442 OSObject
* rematchProps
;
2446 rematchProvider
= getProvider();
2447 if (rematchProvider
) {
2448 obj
= rematchProvider
->copyProperty(gIORematchCountKey
);
2449 num
= OSDynamicCast(OSNumber
, obj
);
2452 count
= num
->unsigned32BitValue();
2455 num
= OSNumber::withNumber(count
, 32);
2456 rematchProvider
->setProperty(gIORematchCountKey
, num
);
2457 rematchProps
= copyProperty(gIOMatchedPersonalityKey
);
2458 rematchProvider
->setProperty(gIORematchPersonalityKey
, rematchProps
);
2459 OSSafeReleaseNULL(num
);
2460 OSSafeReleaseNULL(rematchProps
);
2461 OSSafeReleaseNULL(obj
);
2465 victim
->unlockForArbitration();
2467 if (victim
== this) {
2468 options
&= ~kIOServiceTerminateWithRematch
;
2469 startPhase2
= didInactive
;
2472 OSArray
* notifiers
;
2473 notifiers
= victim
->copyNotifiers(gIOTerminatedNotification
, 0, 0xffffffff);
2474 victim
->invokeNotifiers(¬ifiers
);
2476 IOUserClient::destroyUserReferences( victim
);
2478 iter
= victim
->getClientIterator();
2480 while ((client
= (IOService
*) iter
->getNextObject())) {
2481 TLOG("%s[0x%qx]::requestTerminate(%s[0x%qx], %08llx)\n",
2482 client
->getName(), client
->getRegistryEntryID(),
2483 victim
->getName(), victim
->getRegistryEntryID(), (long long)options
);
2484 ok
= client
->requestTerminate( victim
, options
);
2485 TLOG("%s[0x%qx]::requestTerminate(%s[0x%qx], ok = %d)\n",
2486 client
->getName(), client
->getRegistryEntryID(),
2487 victim
->getName(), victim
->getRegistryEntryID(), ok
);
2489 uint64_t regID1
= client
->getRegistryEntryID();
2490 uint64_t regID2
= victim
->getRegistryEntryID();
2492 (ok
? IOSERVICE_TERMINATE_REQUEST_OK
2493 : IOSERVICE_TERMINATE_REQUEST_FAIL
),
2495 (uintptr_t) (regID1
>> 32),
2497 (uintptr_t) (regID2
>> 32));
2500 makeInactive
->setObject( client
);
2507 victim
= (IOService
*) makeInactive
->getObject(0);
2510 makeInactive
->removeObject(0);
2513 makeInactive
->release();
2515 while ((victim
= (IOService
*) waitingInactive
->getObject(0))) {
2517 waitingInactive
->removeObject(0);
2519 victim
->lockForArbitration();
2520 victim
->__state
[1] &= ~kIOServiceTermPhase1State
;
2521 if (kIOServiceTerm1WaiterState
& victim
->__state
[1]) {
2522 victim
->__state
[1] &= ~kIOServiceTerm1WaiterState
;
2523 TLOG("%s[0x%qx]::wakePhase1\n", victim
->getName(), victim
->getRegistryEntryID());
2524 IOLockLock( gIOServiceBusyLock
);
2525 thread_wakeup((event_t
) &victim
->__state
[1]);
2526 IOLockUnlock( gIOServiceBusyLock
);
2528 victim
->unlockForArbitration();
2531 waitingInactive
->release();
2535 lockForArbitration();
2536 scheduleTerminatePhase2(options
);
2537 unlockForArbitration();
2541 if (rematchProvider
) {
2542 DKLOG(DKS
" rematching after dext crash\n", DKN(rematchProvider
));
2543 rematchProvider
->registerService();
2550 IOService::setTerminateDefer(IOService
* provider
, bool defer
)
2552 lockForArbitration();
2554 __state
[1] |= kIOServiceStartState
;
2556 __state
[1] &= ~kIOServiceStartState
;
2558 unlockForArbitration();
2560 if (provider
&& !defer
) {
2561 provider
->lockForArbitration();
2562 provider
->scheduleTerminatePhase2();
2563 provider
->unlockForArbitration();
2567 // Must call this while holding gJobsLock
2569 IOService::waitToBecomeTerminateThread(void)
2571 IOLockAssert(gJobsLock
, kIOLockAssertOwned
);
2574 wait
= (gIOTerminateThread
!= THREAD_NULL
);
2576 IOLockSleep(gJobsLock
, &gIOTerminateThread
, THREAD_UNINT
);
2579 gIOTerminateThread
= current_thread();
2582 // call with lockForArbitration
2584 IOService::scheduleTerminatePhase2( IOOptionBits options
)
2586 AbsoluteTime deadline
;
2588 int waitResult
= THREAD_AWAKENED
;
2589 bool wait
= false, haveDeadline
= false;
2591 if (!(__state
[0] & kIOServiceInactiveState
)) {
2595 regID1
= getRegistryEntryID();
2597 IOSERVICE_TERM_SCHED_PHASE2
,
2599 (uintptr_t) (regID1
>> 32),
2600 (uintptr_t) __state
[1],
2601 (uintptr_t) options
);
2603 if (__state
[1] & kIOServiceTermPhase1State
) {
2608 unlockForArbitration();
2609 options
|= kIOServiceRequired
;
2610 IOLockLock( gJobsLock
);
2612 if ((options
& kIOServiceSynchronous
)
2613 && (current_thread() != gIOTerminateThread
)) {
2614 waitToBecomeTerminateThread();
2615 gIOTerminatePhase2List
->setObject( this );
2619 while (gIOTerminateWork
) {
2620 terminateWorker( options
);
2622 wait
= (0 != (__state
[1] & kIOServiceBusyStateMask
));
2624 /* wait for the victim to go non-busy */
2625 if (!haveDeadline
) {
2626 clock_interval_to_deadline( 15, kSecondScale
, &deadline
);
2627 haveDeadline
= true;
2629 /* let others do work while we wait */
2630 gIOTerminateThread
= NULL
;
2631 IOLockWakeup( gJobsLock
, (event_t
) &gIOTerminateThread
, /* one-thread */ false);
2632 waitResult
= IOLockSleepDeadline( gJobsLock
, &gIOTerminateWork
,
2633 deadline
, THREAD_UNINT
);
2634 if (__improbable(waitResult
== THREAD_TIMED_OUT
)) {
2635 IOLog("%s[0x%qx]::terminate(kIOServiceSynchronous): THREAD_TIMED_OUT. "
2636 "Attempting to auto-resolve your deadlock. PLEASE FIX!\n", getName(), getRegistryEntryID());
2638 waitToBecomeTerminateThread();
2640 } while (gIOTerminateWork
|| (wait
&& (waitResult
!= THREAD_TIMED_OUT
)));
2642 gIOTerminateThread
= NULL
;
2643 IOLockWakeup( gJobsLock
, (event_t
) &gIOTerminateThread
, /* one-thread */ false);
2645 // ! kIOServiceSynchronous
2647 gIOTerminatePhase2List
->setObject( this );
2648 if (0 == gIOTerminateWork
++) {
2649 assert(gIOTerminateWorkerThread
);
2650 IOLockWakeup(gJobsLock
, (event_t
)&gIOTerminateWork
, /* one-thread */ false );
2654 IOLockUnlock( gJobsLock
);
2655 lockForArbitration();
2659 __attribute__((__noreturn__
))
2661 IOService::terminateThread( void * arg
, wait_result_t waitResult
)
2663 // IOLockSleep re-acquires the lock on wakeup, so we only need to do this once
2664 IOLockLock(gJobsLock
);
2666 if (gIOTerminateThread
!= gIOTerminateWorkerThread
) {
2667 waitToBecomeTerminateThread();
2670 while (gIOTerminateWork
) {
2671 terminateWorker((uintptr_t)arg
);
2674 gIOTerminateThread
= NULL
;
2675 IOLockWakeup( gJobsLock
, (event_t
) &gIOTerminateThread
, /* one-thread */ false);
2676 IOLockSleep(gJobsLock
, &gIOTerminateWork
, THREAD_UNINT
);
2681 IOService::scheduleStop( IOService
* provider
)
2683 uint64_t regID1
= getRegistryEntryID();
2684 uint64_t regID2
= provider
->getRegistryEntryID();
2686 TLOG("%s[0x%qx]::scheduleStop(%s[0x%qx])\n", getName(), regID1
, provider
->getName(), regID2
);
2688 IOSERVICE_TERMINATE_SCHEDULE_STOP
,
2690 (uintptr_t) (regID1
>> 32),
2692 (uintptr_t) (regID2
>> 32));
2694 IOLockLock( gJobsLock
);
2695 gIOStopList
->tailQ( this );
2696 gIOStopProviderList
->tailQ( provider
);
2698 if (0 == gIOTerminateWork
++) {
2699 assert(gIOTerminateWorkerThread
);
2700 IOLockWakeup(gJobsLock
, (event_t
)&gIOTerminateWork
, /* one-thread */ false );
2703 IOLockUnlock( gJobsLock
);
2707 IOService::scheduleFinalize(bool now
)
2709 uint64_t regID1
= getRegistryEntryID();
2711 TLOG("%s[0x%qx]::scheduleFinalize\n", getName(), regID1
);
2713 IOSERVICE_TERMINATE_SCHEDULE_FINALIZE
,
2715 (uintptr_t) (regID1
>> 32),
2718 if (now
|| IOUserClient::finalizeUserReferences(this)) {
2719 IOLockLock( gJobsLock
);
2720 gIOFinalizeList
->tailQ(this);
2721 if (0 == gIOTerminateWork
++) {
2722 assert(gIOTerminateWorkerThread
);
2723 IOLockWakeup(gJobsLock
, (event_t
)&gIOTerminateWork
, /* one-thread */ false );
2725 IOLockUnlock( gJobsLock
);
2730 IOService::willTerminate( IOService
* provider
, IOOptionBits options
)
2732 if (reserved
->uvars
) {
2733 IOUserServer::serviceWillTerminate(this, provider
, options
);
2739 IOService::didTerminate( IOService
* provider
, IOOptionBits options
, bool * defer
)
2741 if (reserved
->uvars
) {
2742 IOUserServer::serviceDidTerminate(this, provider
, options
, defer
);
2745 if (false == *defer
) {
2746 if (lockForArbitration( true )) {
2747 if (false == provider
->handleIsOpen( this )) {
2748 scheduleStop( provider
);
2752 message( kIOMessageServiceIsRequestingClose
, provider
, (void *)(uintptr_t) options
);
2753 if (false == provider
->handleIsOpen( this )) {
2754 scheduleStop( provider
);
2758 unlockForArbitration();
2766 IOService::actionWillTerminate( IOService
* victim
, IOOptionBits options
,
2767 OSArray
* doPhase2List
,
2769 void *unused3 __unused
)
2774 uint64_t regID1
, regID2
= victim
->getRegistryEntryID();
2776 iter
= victim
->getClientIterator();
2778 while ((client
= (IOService
*) iter
->getNextObject())) {
2779 if (user
!= (NULL
!= client
->reserved
->uvars
)) {
2782 regID1
= client
->getRegistryEntryID();
2783 TLOG("%s[0x%qx]::willTerminate(%s[0x%qx], %08llx)\n",
2784 client
->getName(), regID1
,
2785 victim
->getName(), regID2
, (long long)options
);
2787 IOSERVICE_TERMINATE_WILL
,
2789 (uintptr_t) (regID1
>> 32),
2791 (uintptr_t) (regID2
>> 32));
2793 ok
= client
->willTerminate( victim
, options
);
2794 doPhase2List
->tailQ( client
);
2801 IOService::actionDidTerminate( IOService
* victim
, IOOptionBits options
,
2802 void *unused1 __unused
, void *unused2 __unused
,
2803 void *unused3 __unused
)
2808 uint64_t regID1
, regID2
= victim
->getRegistryEntryID();
2810 victim
->messageClients( kIOMessageServiceIsTerminated
, (void *)(uintptr_t) options
);
2812 iter
= victim
->getClientIterator();
2814 while ((client
= (IOService
*) iter
->getNextObject())) {
2815 regID1
= client
->getRegistryEntryID();
2816 TLOG("%s[0x%qx]::didTerminate(%s[0x%qx], %08llx)\n",
2817 client
->getName(), regID1
,
2818 victim
->getName(), regID2
, (long long)options
);
2820 client
->didTerminate( victim
, options
, &defer
);
2823 (defer
? IOSERVICE_TERMINATE_DID_DEFER
2824 : IOSERVICE_TERMINATE_DID
),
2826 (uintptr_t) (regID1
>> 32),
2828 (uintptr_t) (regID2
>> 32));
2830 TLOG("%s[0x%qx]::didTerminate(%s[0x%qx], defer %d)\n",
2831 client
->getName(), regID1
,
2832 victim
->getName(), regID2
, defer
);
2840 IOService::actionWillStop( IOService
* victim
, IOOptionBits options
,
2841 void *unused1 __unused
, void *unused2 __unused
,
2842 void *unused3 __unused
)
2845 IOService
* provider
;
2847 uint64_t regID1
, regID2
= victim
->getRegistryEntryID();
2849 iter
= victim
->getProviderIterator();
2851 while ((provider
= (IOService
*) iter
->getNextObject())) {
2852 regID1
= provider
->getRegistryEntryID();
2853 TLOG("%s[0x%qx]::willTerminate(%s[0x%qx], %08llx)\n",
2854 victim
->getName(), regID2
,
2855 provider
->getName(), regID1
, (long long)options
);
2857 IOSERVICE_TERMINATE_WILL
,
2859 (uintptr_t) (regID2
>> 32),
2861 (uintptr_t) (regID1
>> 32));
2863 ok
= victim
->willTerminate( provider
, options
);
2870 IOService::actionDidStop( IOService
* victim
, IOOptionBits options
,
2871 void *unused1 __unused
, void *unused2 __unused
,
2872 void *unused3 __unused
)
2875 IOService
* provider
;
2877 uint64_t regID1
, regID2
= victim
->getRegistryEntryID();
2879 iter
= victim
->getProviderIterator();
2881 while ((provider
= (IOService
*) iter
->getNextObject())) {
2882 regID1
= provider
->getRegistryEntryID();
2883 TLOG("%s[0x%qx]::didTerminate(%s[0x%qx], %08llx)\n",
2884 victim
->getName(), regID2
,
2885 provider
->getName(), regID1
, (long long)options
);
2886 victim
->didTerminate( provider
, options
, &defer
);
2889 (defer
? IOSERVICE_TERMINATE_DID_DEFER
2890 : IOSERVICE_TERMINATE_DID
),
2892 (uintptr_t) (regID2
>> 32),
2894 (uintptr_t) (regID1
>> 32));
2896 TLOG("%s[0x%qx]::didTerminate(%s[0x%qx], defer %d)\n",
2897 victim
->getName(), regID2
,
2898 provider
->getName(), regID1
, defer
);
2906 IOService::actionFinalize( IOService
* victim
, IOOptionBits options
,
2907 void *unused1 __unused
, void *unused2 __unused
,
2908 void *unused3 __unused
)
2910 uint64_t regID1
= victim
->getRegistryEntryID();
2911 TLOG("%s[0x%qx]::finalize(%08llx)\n", victim
->getName(), regID1
, (long long)options
);
2913 IOSERVICE_TERMINATE_FINALIZE
,
2915 (uintptr_t) (regID1
>> 32),
2918 victim
->finalize( options
);
2922 IOService::actionStop( IOService
* provider
, IOService
* client
,
2923 void *unused1 __unused
, void *unused2 __unused
,
2924 void *unused3 __unused
)
2926 uint64_t regID1
= provider
->getRegistryEntryID();
2927 uint64_t regID2
= client
->getRegistryEntryID();
2929 TLOG("%s[0x%qx]::stop(%s[0x%qx])\n", client
->getName(), regID2
, provider
->getName(), regID1
);
2931 IOSERVICE_TERMINATE_STOP
,
2933 (uintptr_t) (regID1
>> 32),
2935 (uintptr_t) (regID2
>> 32));
2937 client
->stop( provider
);
2938 if (provider
->isOpen( client
)) {
2939 provider
->close( client
);
2942 TLOG("%s[0x%qx]::detach(%s[0x%qx])\n", client
->getName(), regID2
, provider
->getName(), regID1
);
2943 client
->detach( provider
);
2947 IOService::terminateWorker( IOOptionBits options
)
2949 OSArray
* doPhase2List
;
2950 OSArray
* didPhase2List
;
2956 IOService
* provider
;
2962 options
|= kIOServiceRequired
;
2964 doPhase2List
= OSArray::withCapacity( 16 );
2965 didPhase2List
= OSArray::withCapacity( 16 );
2966 freeList
= OSSet::withCapacity( 16 );
2967 if ((NULL
== doPhase2List
) || (NULL
== didPhase2List
) || (NULL
== freeList
)) {
2972 workDone
= gIOTerminateWork
;
2974 while ((victim
= (IOService
*) gIOTerminatePhase2List
->getObject(0))) {
2976 gIOTerminatePhase2List
->removeObject(0);
2977 IOLockUnlock( gJobsLock
);
2979 uint64_t regID1
= victim
->getRegistryEntryID();
2981 IOSERVICE_TERM_START_PHASE2
,
2983 (uintptr_t) (regID1
>> 32),
2988 doPhase2
= victim
->lockForArbitration( true );
2990 doPhase2
= (0 != (kIOServiceInactiveState
& victim
->__state
[0]));
2992 uint64_t regID1
= victim
->getRegistryEntryID();
2994 IOSERVICE_TERM_TRY_PHASE2
,
2996 (uintptr_t) (regID1
>> 32),
2997 (uintptr_t) victim
->__state
[1],
3000 doPhase2
= (0 == (victim
->__state
[1] &
3001 (kIOServiceTermPhase1State
3002 | kIOServiceTermPhase2State
3003 | kIOServiceConfigState
)));
3005 if (doPhase2
&& (iter
= victim
->getClientIterator())) {
3006 while (doPhase2
&& (client
= (IOService
*) iter
->getNextObject())) {
3007 doPhase2
= (0 == (client
->__state
[1] & kIOServiceStartState
));
3009 uint64_t regID1
= client
->getRegistryEntryID();
3011 IOSERVICE_TERM_UC_DEFER
,
3013 (uintptr_t) (regID1
>> 32),
3014 (uintptr_t) client
->__state
[1],
3016 TLOG("%s[0x%qx]::defer phase2(%s[0x%qx])\n",
3017 victim
->getName(), victim
->getRegistryEntryID(),
3018 client
->getName(), client
->getRegistryEntryID());
3024 victim
->__state
[1] |= kIOServiceTermPhase2State
;
3027 victim
->unlockForArbitration();
3030 if (kIOServiceNeedWillTerminate
& victim
->__state
[1]) {
3031 if (NULL
== victim
->reserved
->uvars
) {
3032 _workLoopAction((IOWorkLoop::Action
) &actionWillStop
,
3033 victim
, (void *)(uintptr_t) options
);
3035 actionWillStop(victim
, options
, NULL
, NULL
, NULL
);
3039 OSArray
* notifiers
;
3040 notifiers
= victim
->copyNotifiers(gIOWillTerminateNotification
, 0, 0xffffffff);
3041 victim
->invokeNotifiers(¬ifiers
);
3043 _workLoopAction((IOWorkLoop::Action
) &actionWillTerminate
,
3045 (void *)(uintptr_t) options
,
3046 (void *)(uintptr_t) doPhase2List
,
3047 (void *)(uintptr_t) false);
3049 actionWillTerminate(
3050 victim
, options
, doPhase2List
, true, NULL
);
3052 didPhase2List
->headQ( victim
);
3055 victim
= (IOService
*) doPhase2List
->getObject(0);
3058 doPhase2List
->removeObject(0);
3062 while ((victim
= (IOService
*) didPhase2List
->getObject(0))) {
3063 bool scheduleFinalize
= false;
3064 if (victim
->lockForArbitration( true )) {
3065 victim
->__state
[1] |= kIOServiceTermPhase3State
;
3066 scheduleFinalize
= (NULL
== victim
->getClient());
3067 victim
->unlockForArbitration();
3069 _workLoopAction((IOWorkLoop::Action
) &actionDidTerminate
,
3070 victim
, (void *)(uintptr_t) options
);
3071 if (kIOServiceNeedWillTerminate
& victim
->__state
[1]) {
3072 _workLoopAction((IOWorkLoop::Action
) &actionDidStop
,
3073 victim
, (void *)(uintptr_t) options
, NULL
);
3075 // no clients - will go to finalize
3076 if (scheduleFinalize
) {
3077 victim
->scheduleFinalize(false);
3079 didPhase2List
->removeObject(0);
3081 IOLockLock( gJobsLock
);
3088 while ((victim
= (IOService
*) gIOFinalizeList
->getObject(0))) {
3089 bool sendFinal
= false;
3090 IOLockUnlock( gJobsLock
);
3091 if (victim
->lockForArbitration(true)) {
3092 sendFinal
= (0 == (victim
->__state
[1] & kIOServiceFinalized
));
3094 victim
->__state
[1] |= kIOServiceFinalized
;
3096 victim
->unlockForArbitration();
3099 _workLoopAction((IOWorkLoop::Action
) &actionFinalize
,
3100 victim
, (void *)(uintptr_t) options
);
3102 IOLockLock( gJobsLock
);
3104 freeList
->setObject( victim
);
3105 // safe if finalize list is append only
3106 gIOFinalizeList
->removeObject(0);
3110 (!doPhase3
) && (client
= (IOService
*) gIOStopList
->getObject(idx
));) {
3111 provider
= (IOService
*) gIOStopProviderList
->getObject(idx
);
3114 uint64_t regID1
= provider
->getRegistryEntryID();
3115 uint64_t regID2
= client
->getRegistryEntryID();
3117 if (!provider
->isChild( client
, gIOServicePlane
)) {
3118 // may be multiply queued - nop it
3119 TLOG("%s[0x%qx]::nop stop(%s[0x%qx])\n", client
->getName(), regID2
, provider
->getName(), regID1
);
3121 IOSERVICE_TERMINATE_STOP_NOP
,
3123 (uintptr_t) (regID1
>> 32),
3125 (uintptr_t) (regID2
>> 32));
3127 // a terminated client is not ready for stop if it has clients, skip it
3128 bool deferStop
= (0 != (kIOServiceInactiveState
& client
->__state
[0]));
3129 IOLockUnlock( gJobsLock
);
3130 if (deferStop
&& client
->lockForArbitration(true)) {
3131 deferStop
= (0 == (client
->__state
[1] & kIOServiceFinalized
));
3132 //deferStop = (!deferStop && (0 != client->getClient()));
3133 //deferStop = (0 != client->getClient());
3134 client
->unlockForArbitration();
3136 TLOG("%s[0x%qx]::defer stop()\n", client
->getName(), regID2
);
3137 IOServiceTrace(IOSERVICE_TERMINATE_STOP_DEFER
,
3139 (uintptr_t) (regID1
>> 32),
3141 (uintptr_t) (regID2
>> 32));
3144 IOLockLock( gJobsLock
);
3148 _workLoopAction((IOWorkLoop::Action
) &actionStop
,
3149 provider
, (void *) client
);
3150 IOLockLock( gJobsLock
);
3151 // check the finalize list now
3155 freeList
->setObject( client
);
3156 freeList
->setObject( provider
);
3158 // safe if stop list is append only
3159 gIOStopList
->removeObject( idx
);
3160 gIOStopProviderList
->removeObject( idx
);
3165 gIOTerminateWork
-= workDone
;
3166 moreToDo
= (gIOTerminateWork
!= 0);
3169 TLOG("iokit terminate done, %d stops remain\n", gIOStopList
->getCount());
3171 IOSERVICE_TERMINATE_DONE
,
3172 (uintptr_t) gIOStopList
->getCount(), 0, 0, 0);
3176 IOLockUnlock( gJobsLock
);
3178 freeList
->release();
3179 doPhase2List
->release();
3180 didPhase2List
->release();
3182 IOLockLock( gJobsLock
);
3186 IOService::finalize( IOOptionBits options
)
3189 IOService
* provider
;
3190 uint64_t regID1
, regID2
= getRegistryEntryID();
3192 iter
= getProviderIterator();
3196 while ((provider
= (IOService
*) iter
->getNextObject())) {
3198 if (0 == (__state
[1] & kIOServiceTermPhase3State
)) {
3199 /* we come down here on programmatic terminate */
3201 regID1
= provider
->getRegistryEntryID();
3202 TLOG("%s[0x%qx]::stop1(%s[0x%qx])\n", getName(), regID2
, provider
->getName(), regID1
);
3204 IOSERVICE_TERMINATE_STOP
,
3206 (uintptr_t) (regID1
>> 32),
3208 (uintptr_t) (regID2
>> 32));
3211 if (provider
->isOpen( this )) {
3212 provider
->close( this );
3217 if (provider
->lockForArbitration( true )) {
3218 if (0 == (provider
->__state
[1] & kIOServiceTermPhase3State
)) {
3219 scheduleStop( provider
);
3221 provider
->unlockForArbitration();
3239 IOService::doServiceTerminate( IOOptionBits options
)
3243 // a method in case someone needs to override it
3245 IOService::terminateClient( IOService
* client
, IOOptionBits options
)
3249 if (client
->isParent( this, gIOServicePlane
, true)) {
3250 // we are the clients only provider
3251 ok
= client
->terminate( options
);
3260 IOService::terminate( IOOptionBits options
)
3262 options
|= kIOServiceTerminate
;
3264 return terminatePhase1( options
);
3267 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3273 struct ServiceOpenMessageContext
{
3274 IOService
* service
;
3276 IOService
* excludeClient
;
3277 IOOptionBits options
;
3281 serviceOpenMessageApplier( OSObject
* object
, void * ctx
)
3283 ServiceOpenMessageContext
* context
= (ServiceOpenMessageContext
*) ctx
;
3285 if (object
!= context
->excludeClient
) {
3286 context
->service
->messageClient( context
->type
, object
, (void *)(uintptr_t) context
->options
);
3291 IOService::open( IOService
* forClient
,
3292 IOOptionBits options
,
3296 ServiceOpenMessageContext context
;
3298 context
.service
= this;
3299 context
.type
= kIOMessageServiceIsAttemptingOpen
;
3300 context
.excludeClient
= forClient
;
3301 context
.options
= options
;
3303 applyToInterested( gIOGeneralInterest
,
3304 &serviceOpenMessageApplier
, &context
);
3306 if (false == lockForArbitration(false)) {
3310 ok
= (0 == (__state
[0] & kIOServiceInactiveState
));
3312 ok
= handleOpen( forClient
, options
, arg
);
3315 if (ok
&& forClient
&& forClient
->reserved
->uvars
&& forClient
->reserved
->uvars
->userServer
) {
3316 forClient
->reserved
->uvars
->userServer
->serviceOpen(this, forClient
);
3319 unlockForArbitration();
3325 IOService::close( IOService
* forClient
,
3326 IOOptionBits options
)
3331 lockForArbitration();
3333 wasClosed
= handleIsOpen( forClient
);
3335 handleClose( forClient
, options
);
3336 last
= (__state
[1] & kIOServiceTermPhase3State
);
3338 if (forClient
&& forClient
->reserved
->uvars
&& forClient
->reserved
->uvars
->userServer
) {
3339 forClient
->reserved
->uvars
->userServer
->serviceClose(this, forClient
);
3343 unlockForArbitration();
3346 forClient
->scheduleStop( this );
3347 } else if (wasClosed
) {
3348 ServiceOpenMessageContext context
;
3350 context
.service
= this;
3351 context
.type
= kIOMessageServiceWasClosed
;
3352 context
.excludeClient
= forClient
;
3353 context
.options
= options
;
3355 applyToInterested( gIOGeneralInterest
,
3356 &serviceOpenMessageApplier
, &context
);
3361 IOService::isOpen( const IOService
* forClient
) const
3363 IOService
* self
= (IOService
*) this;
3366 self
->lockForArbitration();
3368 ok
= handleIsOpen( forClient
);
3370 self
->unlockForArbitration();
3376 IOService::handleOpen( IOService
* forClient
,
3377 IOOptionBits options
,
3382 ok
= (NULL
== __owner
);
3384 __owner
= forClient
;
3385 } else if (options
& kIOServiceSeize
) {
3386 ok
= (kIOReturnSuccess
== messageClient( kIOMessageServiceIsRequestingClose
,
3387 __owner
, (void *)(uintptr_t) options
));
3388 if (ok
&& (NULL
== __owner
)) {
3389 __owner
= forClient
;
3398 IOService::handleClose( IOService
* forClient
,
3399 IOOptionBits options
)
3401 if (__owner
== forClient
) {
3407 IOService::handleIsOpen( const IOService
* forClient
) const
3410 return __owner
== forClient
;
3412 return __owner
!= forClient
;
3417 * Probing & starting
3420 IONotifyOrdering( const OSMetaClassBase
* inObj1
, const OSMetaClassBase
* inObj2
, void * ref
)
3422 const _IOServiceNotifier
* obj1
= (const _IOServiceNotifier
*) inObj1
;
3423 const _IOServiceNotifier
* obj2
= (const _IOServiceNotifier
*) inObj2
;
3431 val1
= obj1
->priority
;
3435 val2
= obj2
->priority
;
3442 IOServiceObjectOrder( const OSObject
* entry
, void * ref
)
3444 OSDictionary
* dict
;
3445 IOService
* service
;
3446 _IOServiceNotifier
* notify
;
3447 OSSymbol
* key
= (OSSymbol
*) ref
;
3453 result
= kIODefaultProbeScore
;
3454 if ((dict
= OSDynamicCast( OSDictionary
, entry
))) {
3455 offset
= OSDynamicCast(OSNumber
, dict
->getObject( key
));
3456 } else if ((notify
= OSDynamicCast( _IOServiceNotifier
, entry
))) {
3457 return notify
->priority
;
3458 } else if ((service
= OSDynamicCast( IOService
, entry
))) {
3459 prop
= service
->copyProperty(key
);
3460 offset
= OSDynamicCast(OSNumber
, prop
);
3467 result
= offset
->unsigned32BitValue();
3470 OSSafeReleaseNULL(prop
);
3476 IOServiceOrdering( const OSMetaClassBase
* inObj1
, const OSMetaClassBase
* inObj2
, void * ref
)
3478 const OSObject
* obj1
= (const OSObject
*) inObj1
;
3479 const OSObject
* obj2
= (const OSObject
*) inObj2
;
3487 val1
= IOServiceObjectOrder( obj1
, ref
);
3491 val2
= IOServiceObjectOrder( obj2
, ref
);
3498 IOService::copyClientWithCategory( const OSSymbol
* category
)
3500 IOService
* service
= NULL
;
3502 const OSSymbol
* nextCat
;
3504 iter
= getClientIterator();
3506 while ((service
= (IOService
*) iter
->getNextObject())) {
3507 if (kIOServiceInactiveState
& service
->__state
[0]) {
3510 nextCat
= (const OSSymbol
*) OSDynamicCast( OSSymbol
,
3511 service
->getProperty( gIOMatchCategoryKey
));
3512 if (category
== nextCat
) {
3523 IOService::getClientWithCategory( const OSSymbol
* category
)
3526 service
= copyClientWithCategory(category
);
3534 IOService::invokeNotifier( _IOServiceNotifier
* notify
)
3536 _IOServiceNotifierInvocation invocation
;
3539 invocation
.thread
= current_thread();
3541 #if DEBUG_NOTIFIER_LOCKED
3543 if ((count
= isLockedForArbitration(0))) {
3544 IOLog("[%s, 0x%x]\n", notify
->type
->getCStringNoCopy(), count
);
3545 panic("[%s, 0x%x]\n", notify
->type
->getCStringNoCopy(), count
);
3547 #endif /* DEBUG_NOTIFIER_LOCKED */
3550 willNotify
= (0 != (kIOServiceNotifyEnable
& notify
->state
));
3553 queue_enter( ¬ify
->handlerInvocations
, &invocation
,
3554 _IOServiceNotifierInvocation
*, link
);
3559 ret
= (*notify
->handler
)(notify
->target
, notify
->ref
, this, notify
);
3562 queue_remove( ¬ify
->handlerInvocations
, &invocation
,
3563 _IOServiceNotifierInvocation
*, link
);
3564 if (kIOServiceNotifyWaiter
& notify
->state
) {
3565 notify
->state
&= ~kIOServiceNotifyWaiter
;
3566 WAKEUPNOTIFY( notify
);
3575 IOService::invokeNotifiers(OSArray
* willSend
[])
3578 _IOServiceNotifier
* notify
;
3587 for (unsigned int idx
= 0;
3588 (notify
= (_IOServiceNotifier
*) array
->getObject(idx
));
3590 ret
&= invokeNotifier(notify
);
3599 * Alloc and probe matching classes,
3600 * called on the provider instance
3604 IOService::probeCandidates( OSOrderedSet
* matches
)
3606 OSDictionary
* match
= NULL
;
3609 IOService
* newInst
;
3610 OSDictionary
* props
;
3613 OSOrderedSet
* familyMatches
= NULL
;
3614 OSOrderedSet
* startList
;
3615 OSSet
* kexts
= NULL
;
3618 OSDictionary
* startDict
= NULL
;
3619 const OSSymbol
* category
;
3621 _IOServiceNotifier
* notify
;
3622 OSObject
* nextMatch
= NULL
;
3624 bool needReloc
= false;
3625 bool matchDeferred
= false;
3629 IOService
* client
= NULL
;
3632 OSDictionary
* rematchPersonality
;
3637 bool categoryConsumed
;
3641 prop1
= copyProperty(gIORematchPersonalityKey
);
3642 rematchPersonality
= OSDynamicCast(OSDictionary
, prop1
);
3643 if (rematchPersonality
) {
3644 prop2
= copyProperty(gIORematchCountKey
);
3645 num
= OSDynamicCast(OSNumber
, prop2
);
3647 count
= num
->unsigned32BitValue();
3649 OSSafeReleaseNULL(prop2
);
3655 && (nextMatch
= matches
->getFirstObject())) {
3656 nextMatch
->retain();
3657 matches
->removeObject(nextMatch
);
3659 if ((notify
= OSDynamicCast( _IOServiceNotifier
, nextMatch
))) {
3660 if (0 == (__state
[0] & kIOServiceInactiveState
)) {
3661 invokeNotifier( notify
);
3663 nextMatch
->release();
3666 } else if (!(match
= OSDynamicCast( OSDictionary
, nextMatch
))) {
3667 nextMatch
->release();
3674 debugFlags
= getDebugFlags( match
);
3678 isDext
= (NULL
!= match
->getObject(gIOUserServerNameKey
));
3679 if (isDext
&& !(kIODKEnable
& gIODKDebug
)) {
3683 category
= OSDynamicCast( OSSymbol
,
3684 match
->getObject( gIOMatchCategoryKey
));
3685 if (NULL
== category
) {
3686 category
= gIODefaultMatchCategoryKey
;
3688 client
= copyClientWithCategory(category
);
3690 categoryConsumed
= (client
!= NULL
);
3691 if (categoryConsumed
) {
3693 if ((debugFlags
& kIOLogMatch
) && (this != gIOResources
)) {
3694 LOG("%s: match category %s exists\n", getName(),
3695 category
->getCStringNoCopy());
3698 OSSafeReleaseNULL(client
);
3704 // create a copy now in case its modified during matching
3705 props
= OSDictionary::withDictionary(match
, match
->getCount());
3706 if (NULL
== props
) {
3709 props
->setCapacityIncrement(1);
3711 // check the nub matches
3712 if (false == matchPassive(props
, kIOServiceChangesOK
| kIOServiceClassDone
)) {
3717 if (categoryConsumed
) {
3722 if (rematchPersonality
) {
3723 bool personalityMatch
= match
->isEqualTo(rematchPersonality
);
3724 if (count
> gIODextRelaunchMax
) {
3725 personalityMatch
= !personalityMatch
;
3727 if (!personalityMatch
) {
3732 // Check to see if driver reloc has been loaded.
3733 needReloc
= (false == gIOCatalogue
->isModuleLoaded( match
, &kextRef
));
3736 if (debugFlags
& kIOLogCatalogue
) {
3737 LOG("%s: stalling for module\n", getName());
3740 // If reloc hasn't been loaded, exit;
3741 // reprobing will occur after reloc has been loaded.
3745 if (NULL
== kexts
) {
3746 kexts
= OSSet::withCapacity(1);
3749 kexts
->setObject(kextRef
);
3754 // copy saved for rematchng
3755 props
->setObject(gIOMatchedPersonalityKey
, match
);
3757 // reorder on family matchPropertyTable score.
3758 if (NULL
== familyMatches
) {
3759 familyMatches
= OSOrderedSet::withCapacity( 1,
3760 IOServiceOrdering
, (void *) gIOProbeScoreKey
);
3762 if (familyMatches
) {
3763 familyMatches
->setObject( props
);
3767 OSSafeReleaseNULL(nextMatch
);
3768 OSSafeReleaseNULL(props
);
3773 if (familyMatches
) {
3775 && (props
= (OSDictionary
*) familyMatches
->getFirstObject())) {
3777 familyMatches
->removeObject( props
);
3782 debugFlags
= getDebugFlags( props
);
3785 symbol
= OSDynamicCast( OSSymbol
,
3786 props
->getObject( gIOClassKey
));
3791 //IOLog("%s alloc (symbol %p props %p)\n", symbol->getCStringNoCopy(), IOSERVICE_OBFUSCATE(symbol), IOSERVICE_OBFUSCATE(props));
3793 // alloc the driver instance
3794 inst
= (IOService
*) OSMetaClass::allocClassWithName( symbol
);
3796 if (!inst
|| !OSDynamicCast(IOService
, inst
)) {
3797 IOLog("Couldn't alloc class \"%s\"\n",
3798 symbol
->getCStringNoCopy());
3802 // init driver instance
3803 if (!(inst
->init( props
))) {
3805 if (debugFlags
& kIOLogStart
) {
3806 IOLog("%s::init fails\n", symbol
->getCStringNoCopy());
3811 if (__state
[1] & kIOServiceSynchronousState
) {
3812 inst
->__state
[1] |= kIOServiceSynchronousState
;
3815 // give the driver the default match category if not specified
3816 category
= OSDynamicCast( OSSymbol
,
3817 props
->getObject( gIOMatchCategoryKey
));
3818 if (NULL
== category
) {
3819 category
= gIODefaultMatchCategoryKey
;
3821 inst
->setProperty( gIOMatchCategoryKey
, (OSObject
*) category
);
3822 // attach driver instance
3823 if (!(inst
->attach( this ))) {
3827 // pass in score from property table
3828 score
= familyMatches
->orderObject( props
);
3830 // & probe the new driver instance
3832 if (debugFlags
& kIOLogProbe
) {
3833 LOG("%s::probe(%s)\n",
3834 inst
->getMetaClass()->getClassName(), getName());
3838 newInst
= inst
->probe( this, &score
);
3839 inst
->detach( this );
3840 if (NULL
== newInst
) {
3842 if (debugFlags
& kIOLogProbe
) {
3843 IOLog("%s::probe fails\n", symbol
->getCStringNoCopy());
3850 newPri
= OSNumber::withNumber( score
, 32 );
3852 newInst
->setProperty( gIOProbeScoreKey
, newPri
);
3856 // add to start list for the match category
3857 if (NULL
== startDict
) {
3858 startDict
= OSDictionary::withCapacity( 1 );
3860 assert( startDict
);
3861 startList
= (OSOrderedSet
*)
3862 startDict
->getObject( category
);
3863 if (NULL
== startList
) {
3864 startList
= OSOrderedSet::withCapacity( 1,
3865 IOServiceOrdering
, (void *) gIOProbeScoreKey
);
3866 if (startDict
&& startList
) {
3867 startDict
->setObject( category
, startList
);
3868 startList
->release();
3871 assert( startList
);
3873 startList
->setObject( newInst
);
3882 familyMatches
->release();
3883 familyMatches
= NULL
;
3886 // start the best (until success) of each category
3888 iter
= OSCollectionIterator::withCollection( startDict
);
3890 while ((category
= (const OSSymbol
*) iter
->getNextObject())) {
3891 startList
= (OSOrderedSet
*) startDict
->getObject( category
);
3892 assert( startList
);
3898 while (true // (!started)
3900 && (inst
= (IOService
*)startList
->getFirstObject())) {
3902 startList
->removeObject(inst
);
3905 debugFlags
= getDebugFlags( inst
);
3907 if (debugFlags
& kIOLogStart
) {
3909 LOG( "match category exists, skipping " );
3911 LOG( "%s::start(%s) <%d>\n", inst
->getName(),
3912 getName(), inst
->getRetainCount());
3915 if (false == started
) {
3917 IOLockLock(gJobsLock
);
3918 matchDeferred
= (gIOMatchDeferList
3919 && (kOSBooleanTrue
== inst
->getProperty(gIOMatchDeferKey
)));
3920 if (matchDeferred
&& (-1U == gIOMatchDeferList
->getNextIndexOfObject(this, 0))) {
3921 gIOMatchDeferList
->setObject(this);
3923 IOLockUnlock(gJobsLock
);
3924 if (matchDeferred
) {
3925 symbol
= OSDynamicCast(OSSymbol
, inst
->getProperty(gIOClassKey
));
3926 IOLog("%s(0x%qx): matching deferred by %s\n",
3927 getName(), getRegistryEntryID(),
3928 symbol
? symbol
->getCStringNoCopy() : "");
3929 // rematching will occur after kextd loads all plists
3932 if (!matchDeferred
) {
3933 started
= startCandidate( inst
);
3935 if ((debugFlags
& kIOLogStart
) && (false == started
)) {
3936 LOG( "%s::start(%s) <%d> failed\n", inst
->getName(), getName(),
3937 inst
->getRetainCount());
3948 OSSafeReleaseNULL(prop1
);
3951 num
= OSNumber::withNumber(dextCount
, 32);
3952 setProperty(gIODEXTMatchCountKey
, num
);
3953 OSSafeReleaseNULL(num
);
3954 } else if (rematchPersonality
) {
3955 removeProperty(gIODEXTMatchCountKey
);
3958 // now that instances are created, drop the refs on any kexts allowing unload
3960 OSKext::dropMatchingReferences(kexts
);
3961 OSSafeReleaseNULL(kexts
);
3964 // adjust the busy count by +1 if matching is stalled for a module,
3965 // or -1 if a previously stalled matching is complete.
3966 lockForArbitration();
3968 uint64_t regID
= getRegistryEntryID();
3971 adjBusy
= (__state
[1] & kIOServiceModuleStallState
) ? 0 : 1;
3974 IOSERVICE_MODULESTALL
,
3976 (uintptr_t) (regID
>> 32),
3980 __state
[1] |= kIOServiceModuleStallState
;
3982 } else if (__state
[1] & kIOServiceModuleStallState
) {
3984 IOSERVICE_MODULEUNSTALL
,
3986 (uintptr_t) (regID
>> 32),
3990 __state
[1] &= ~kIOServiceModuleStallState
;
3994 _adjustBusy( adjBusy
);
3996 unlockForArbitration();
3999 startDict
->release();
4004 * Wait for a IOUserServer to check in
4008 __attribute__((noinline
, not_tail_called
))
4010 __WAITING_FOR_USER_SERVER__(OSDictionary
* matching
)
4013 server
= IOService::waitForMatchingService(matching
, kIOUserServerCheckInTimeoutSecs
* NSEC_PER_SEC
);
4018 IOService::willShutdown()
4020 gKextdWillTerminate
= true;
4022 getPlatform()->waitQuiet(30 * NSEC_PER_SEC
);
4024 OSKext::willShutdown();
4027 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
4030 IOServicePH::init(IOPMrootDomain
* root
)
4032 fUserServers
= OSArray::withCapacity(4);
4033 fMatchingWork
= OSArray::withCapacity(4);
4035 assert(fUserServers
&& fMatchingWork
);
4037 fRootNotifier
= root
->registerInterest(
4038 gIOPriorityPowerStateInterest
, &IOServicePH::systemPowerChange
, NULL
, NULL
);
4040 assert(fRootNotifier
);
4046 IOLockLock(gJobsLock
);
4050 IOServicePH::unlock()
4052 IOLockUnlock(gJobsLock
);
4056 IOServicePH::serverAdd(IOUserServer
* server
)
4061 idx
= fUserServers
->getNextIndexOfObject(server
, 0);
4063 fUserServers
->setObject(server
);
4069 IOServicePH::serverRemove(IOUserServer
* server
)
4074 idx
= fUserServers
->getNextIndexOfObject(server
, 0);
4076 fUserServers
->removeObject(idx
);
4082 IOServicePH::serverAck(IOUserServer
* server
)
4090 if (server
&& fUserServersWait
) {
4091 idx
= fUserServersWait
->getNextIndexOfObject(server
, 0);
4093 fUserServersWait
->removeObject(idx
);
4094 if (0 == fUserServersWait
->getCount()) {
4095 OSSafeReleaseNULL(fUserServersWait
);
4099 if (!fUserServersWait
&& !fMatchingWork
->getCount()) {
4100 ackTo
= fSystemPowerAckTo
;
4101 ackToRef
= fSystemPowerAckRef
;
4102 fSystemPowerAckTo
= NULL
;
4107 DKLOG("allowPowerChange\n");
4108 ackTo
->allowPowerChange((uintptr_t) ackToRef
);
4113 IOServicePH::matchingStart(IOService
* service
)
4121 idx
= fMatchingWork
->getNextIndexOfObject(service
, 0);
4123 fMatchingWork
->setObject(service
);
4126 if (!fMatchingDelayed
) {
4127 fMatchingDelayed
= OSArray::withObjects((const OSObject
**) &service
, 1, 1);
4129 idx
= fMatchingDelayed
->getNextIndexOfObject(service
, 0);
4131 fMatchingDelayed
->setObject(service
);
4141 IOServicePH::matchingEnd(IOService
* service
)
4144 OSArray
* notifyServers
;
4145 OSArray
* deferredMatches
;
4147 notifyServers
= NULL
;
4148 deferredMatches
= NULL
;
4153 idx
= fMatchingWork
->getNextIndexOfObject(service
, 0);
4155 fMatchingWork
->removeObject(idx
);
4160 if ((fUserServerOff
!= fSystemOff
) && fUserServers
->getCount()) {
4162 if (0 == fMatchingWork
->getCount()) {
4163 fUserServersWait
= OSArray::withArray(fUserServers
);
4164 notifyServers
= OSArray::withArray(fUserServers
);
4165 fUserServerOff
= fSystemOff
;
4168 notifyServers
= OSArray::withArray(fUserServers
);
4169 fUserServerOff
= fSystemOff
;
4173 if (!fSystemOff
&& fMatchingDelayed
) {
4174 deferredMatches
= fMatchingDelayed
;
4175 fMatchingDelayed
= NULL
;
4180 if (notifyServers
) {
4181 notifyServers
->iterateObjects(^bool (OSObject
* obj
) {
4183 us
= (typeof(us
))obj
;
4184 us
->systemPower(fSystemOff
);
4187 OSSafeReleaseNULL(notifyServers
);
4190 if (deferredMatches
) {
4191 DKLOG("sleep deferred rematching count %d\n", deferredMatches
->getCount());
4192 deferredMatches
->iterateObjects(^bool (OSObject
* obj
)
4194 ((IOService
*)obj
)->startMatching(kIOServiceAsynchronous
);
4197 deferredMatches
->release();
4204 IOServicePH::systemPowerChange(
4207 UInt32 messageType
, IOService
* service
,
4208 void * messageArgument
, vm_size_t argSize
)
4212 IOPMSystemCapabilityChangeParameters
* params
;
4216 switch (messageType
) {
4217 case kIOMessageSystemCapabilityChange
:
4219 params
= (typeof params
)messageArgument
;
4221 if (kIODKLogPM
& gIODKDebug
) {
4222 IOLog("IOServicePH::kIOMessageSystemCapabilityChange: %s%s 0x%x->0x%x\n",
4223 params
->changeFlags
& kIOPMSystemCapabilityWillChange
? "will" : "",
4224 params
->changeFlags
& kIOPMSystemCapabilityDidChange
? "did" : "",
4225 params
->fromCapabilities
,
4226 params
->toCapabilities
);
4229 if ((params
->changeFlags
& kIOPMSystemCapabilityWillChange
) &&
4230 (params
->fromCapabilities
& kIOPMSystemCapabilityCPU
) &&
4231 ((params
->toCapabilities
& kIOPMSystemCapabilityCPU
) == 0)) {
4234 fSystemPowerAckRef
= params
->notifyRef
;
4235 fSystemPowerAckTo
= service
;
4240 params
->maxWaitForReply
= 60 * 1000 * 1000;
4241 ret
= kIOReturnSuccess
;
4242 } else if ((params
->changeFlags
& kIOPMSystemCapabilityWillChange
) &&
4243 ((params
->fromCapabilities
& kIOPMSystemCapabilityCPU
) == 0) &&
4244 (params
->toCapabilities
& kIOPMSystemCapabilityCPU
)) {
4251 params
->maxWaitForReply
= 0;
4252 ret
= kIOReturnSuccess
;
4254 params
->maxWaitForReply
= 0;
4255 ret
= kIOReturnSuccess
;
4260 ret
= kIOReturnUnsupported
;
4267 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
4270 * Start a previously attached & probed instance,
4271 * called on exporting object instance
4275 IOService::startCandidate( IOService
* service
)
4280 IOUserServer
* userServer
;
4284 obj
= service
->copyProperty(gIOUserServerNameKey
);
4286 if (obj
&& (this == gIOResources
)) {
4289 ok
= service
->attach( this );
4295 if ((this != gIOResources
) && (this != gIOUserResources
)) {
4296 // stall for any nub resources
4298 // stall for any driver resources
4299 service
->checkResources();
4303 OSString
* bundleID
;
4304 OSString
* serverName
;
4306 const OSSymbol
* sym
;
4307 OSDictionary
* matching
;
4309 OSNumber
* serverTag
;
4312 if ((serverName
= OSDynamicCast(OSString
, obj
))) {
4313 obj
= service
->copyProperty(gIOModuleIdentifierKey
);
4314 bundleID
= OSDynamicCast(OSString
, obj
);
4315 entryID
= service
->getRegistryEntryID();
4316 serverTag
= OSNumber::withNumber(entryID
, 64);
4318 if (gKextdWillTerminate
) {
4319 DKLOG("%s disabled in shutdown\n", serverName
->getCStringNoCopy());
4320 service
->detach(this);
4321 OSSafeReleaseNULL(obj
);
4325 ph
= IOServicePH::matchingStart(this);
4327 DKLOG("%s deferred in sleep\n", serverName
->getCStringNoCopy());
4328 service
->detach(this);
4329 OSSafeReleaseNULL(obj
);
4333 prop
= service
->copyProperty(gIOUserClassKey
);
4334 str
= OSDynamicCast(OSString
, prop
);
4336 service
->setName(str
);
4338 OSSafeReleaseNULL(prop
);
4340 if (!(kIODKDisableDextLaunch
& gIODKDebug
)) {
4341 OSKext::requestDaemonLaunch(bundleID
, serverName
, serverTag
);
4343 sym
= OSSymbol::withString(serverName
);
4344 matching
= serviceMatching(gIOUserServerClassKey
);
4345 propertyMatching(gIOUserServerNameKey
, sym
, matching
);
4346 if (!(kIODKDisableDextTag
& gIODKDebug
)) {
4347 propertyMatching(gIOUserServerTagKey
, serverTag
, matching
);
4350 server
= __WAITING_FOR_USER_SERVER__(matching
);
4351 matching
->release();
4352 OSSafeReleaseNULL(serverTag
);
4353 OSSafeReleaseNULL(serverName
);
4355 userServer
= OSDynamicCast(IOUserServer
, server
);
4357 service
->detach(this);
4358 IOServicePH::matchingEnd(this);
4359 DKLOG(DKS
" user server timeout\n", DKN(service
));
4363 if (!(kIODKDisableCDHashChecking
& gIODKDebug
)) {
4364 if (!userServer
->serviceMatchesCDHash(service
)) {
4365 service
->detach(this);
4366 IOServicePH::matchingEnd(this);
4367 userServer
->exit("CDHash check failed");
4368 userServer
->release();
4372 OSKext
*kext
= OSKext::lookupKextWithIdentifier(bundleID
);
4374 const char *name
= bundleID
->getCStringNoCopy();
4375 IOLog("%s Could not find OSKext for %s\n", __func__
, name
);
4382 userServer
->setTaskLoadTag(kext
);
4383 userServer
->setDriverKitUUID(kext
);
4384 OSKext::OSKextLogDriverKitInfoLoad(kext
);
4386 OSSafeReleaseNULL(bundleID
);
4387 OSSafeReleaseNULL(kext
);
4389 if (!(kIODKDisableEntitlementChecking
& gIODKDebug
)) {
4390 if (!userServer
->checkEntitlements(this, service
)) {
4391 service
->detach(this);
4392 IOServicePH::matchingEnd(this);
4393 userServer
->exit("Entitlements check failed");
4394 userServer
->release();
4399 userServer
->serviceAttach(service
, this);
4403 AbsoluteTime startTime
;
4404 AbsoluteTime endTime
;
4407 if (kIOLogStart
& gIOKitDebug
) {
4408 clock_get_uptime(&startTime
);
4411 ok
= service
->start(this);
4413 if (kIOLogStart
& gIOKitDebug
) {
4414 clock_get_uptime(&endTime
);
4416 if (CMP_ABSOLUTETIME(&endTime
, &startTime
) > 0) {
4417 SUB_ABSOLUTETIME(&endTime
, &startTime
);
4418 absolutetime_to_nanoseconds(endTime
, &nano
);
4419 if (nano
> 500000000ULL) {
4420 IOLog("%s::start took %ld ms\n", service
->getName(), (long)(UInt32
)(nano
/ 1000000ULL));
4425 userServer
->serviceStarted(service
, this, ok
);
4426 userServer
->release();
4429 service
->detach( this );
4433 IOServicePH::matchingEnd(this);
4440 IOService::publishResource( const char * key
, OSObject
* value
)
4442 const OSSymbol
* sym
;
4444 if ((sym
= OSSymbol::withCString( key
))) {
4445 publishResource( sym
, value
);
4451 IOService::publishResource( const OSSymbol
* key
, OSObject
* value
)
4453 if (NULL
== value
) {
4454 value
= (OSObject
*) gIOServiceKey
;
4457 gIOResources
->setProperty( key
, value
);
4459 if (IORecursiveLockHaveLock( gNotificationLock
)) {
4463 gIOResourceGenerationCount
++;
4464 gIOResources
->registerService();
4468 IOService::publishUserResource( const OSSymbol
* key
, OSObject
* value
)
4470 if (NULL
== value
) {
4471 value
= (OSObject
*) gIOServiceKey
;
4474 gIOUserResources
->setProperty( key
, value
);
4476 if (IORecursiveLockHaveLock( gNotificationLock
)) {
4480 gIOResourceGenerationCount
++;
4481 gIOUserResources
->registerService();
4485 IOService::addNeededResource( const char * key
)
4487 OSObject
* resourcesProp
;
4492 resourcesProp
= copyProperty( gIOResourceMatchKey
);
4493 if (!resourcesProp
) {
4497 newKey
= OSString::withCString( key
);
4499 resourcesProp
->release();
4503 set
= OSDynamicCast( OSSet
, resourcesProp
);
4505 set
= OSSet::withCapacity( 1 );
4507 set
->setObject( resourcesProp
);
4513 set
->setObject( newKey
);
4515 ret
= setProperty( gIOResourceMatchKey
, set
);
4517 resourcesProp
->release();
4523 IOService::checkResource( OSObject
* matching
)
4526 OSDictionary
* table
;
4528 if ((str
= OSDynamicCast( OSString
, matching
))) {
4529 if (gIOResources
->getProperty( str
)) {
4535 table
= resourceMatching( str
);
4536 } else if ((table
= OSDynamicCast( OSDictionary
, matching
))) {
4539 IOLog("%s: Can't match using: %s\n", getName(),
4540 matching
->getMetaClass()->getClassName());
4541 /* false would stall forever */
4545 if (gIOKitDebug
& kIOLogConfig
) {
4546 LOG("config(%p): stalling %s\n", IOSERVICE_OBFUSCATE(IOThreadSelf()), getName());
4549 waitForService( table
);
4551 if (gIOKitDebug
& kIOLogConfig
) {
4552 LOG("config(%p): waking\n", IOSERVICE_OBFUSCATE(IOThreadSelf()));
4559 IOService::checkResources( void )
4561 OSObject
* resourcesProp
;
4566 resourcesProp
= copyProperty( gIOResourceMatchKey
);
4567 if (NULL
== resourcesProp
) {
4571 if ((set
= OSDynamicCast( OSSet
, resourcesProp
))) {
4572 iter
= OSCollectionIterator::withCollection( set
);
4573 ok
= (NULL
!= iter
);
4574 while (ok
&& (resourcesProp
= iter
->getNextObject())) {
4575 ok
= checkResource( resourcesProp
);
4581 ok
= checkResource( resourcesProp
);
4584 OSSafeReleaseNULL(resourcesProp
);
4591 _IOConfigThread::configThread( int configThreadId
)
4593 _IOConfigThread
* inst
;
4596 if (!(inst
= new _IOConfigThread
)) {
4599 if (!inst
->init()) {
4603 if (KERN_SUCCESS
!= kernel_thread_start(&_IOConfigThread::main
, inst
, &thread
)) {
4607 char threadName
[MAXTHREADNAMESIZE
];
4608 snprintf(threadName
, sizeof(threadName
), "IOConfigThread_%d", configThreadId
);
4609 thread_set_thread_name(thread
, threadName
);
4610 thread_deallocate(thread
);
4623 IOService::doServiceMatch( IOOptionBits options
)
4625 _IOServiceNotifier
* notify
;
4627 OSOrderedSet
* matches
;
4628 OSArray
* resourceKeys
= NULL
;
4629 SInt32 catalogGeneration
;
4630 bool keepGuessing
= true;
4631 bool reRegistered
= true;
4633 OSArray
* notifiers
[2] = {NULL
};
4635 // job->nub->deliverNotification( gIOPublishNotification,
4636 // kIOServiceRegisteredState, 0xffffffff );
4638 while (keepGuessing
) {
4639 matches
= gIOCatalogue
->findDrivers( this, &catalogGeneration
);
4640 // the matches list should always be created by findDrivers()
4642 lockForArbitration();
4643 if (0 == (__state
[0] & kIOServiceFirstPublishState
)) {
4644 getMetaClass()->addInstance(this);
4645 notifiers
[0] = copyNotifiers(gIOFirstPublishNotification
,
4646 kIOServiceFirstPublishState
, 0xffffffff );
4649 __state
[1] &= ~kIOServiceNeedConfigState
;
4650 __state
[1] |= kIOServiceConfigState
| kIOServiceConfigRunning
;
4651 didRegister
= (0 == (kIOServiceRegisteredState
& __state
[0]));
4652 __state
[0] |= kIOServiceRegisteredState
;
4654 keepGuessing
&= (0 == (__state
[0] & kIOServiceInactiveState
));
4655 if (reRegistered
&& keepGuessing
) {
4656 iter
= OSCollectionIterator::withCollection((OSOrderedSet
*)
4657 gNotifications
->getObject( gIOPublishNotification
));
4659 while ((notify
= (_IOServiceNotifier
*)
4660 iter
->getNextObject())) {
4661 if (matchPassive(notify
->matching
, 0)
4662 && (kIOServiceNotifyEnable
& notify
->state
)) {
4663 matches
->setObject( notify
);
4671 unlockForArbitration();
4672 invokeNotifiers(¬ifiers
[0]);
4674 if (keepGuessing
&& matches
->getCount() && (kIOReturnSuccess
== getResources())) {
4675 if ((this == gIOResources
) || (this == gIOUserResources
)) {
4677 resourceKeys
->release();
4679 resourceKeys
= copyPropertyKeys();
4681 probeCandidates( matches
);
4687 lockForArbitration();
4688 reRegistered
= (0 != (__state
[1] & kIOServiceNeedConfigState
));
4690 (reRegistered
|| (catalogGeneration
!=
4691 gIOCatalogue
->getGenerationCount()))
4692 && (0 == (__state
[0] & kIOServiceInactiveState
));
4695 unlockForArbitration();
4699 if ((0 == (__state
[0] & kIOServiceInactiveState
))
4700 && (0 == (__state
[1] & kIOServiceModuleStallState
))) {
4702 setProperty(gIOResourceMatchedKey
, resourceKeys
);
4705 notifiers
[0] = copyNotifiers(gIOMatchedNotification
,
4706 kIOServiceMatchedState
, 0xffffffff);
4707 if (0 == (__state
[0] & kIOServiceFirstMatchState
)) {
4708 notifiers
[1] = copyNotifiers(gIOFirstMatchNotification
,
4709 kIOServiceFirstMatchState
, 0xffffffff);
4713 __state
[1] &= ~kIOServiceConfigRunning
;
4714 unlockForArbitration();
4717 resourceKeys
->release();
4720 invokeNotifiers(¬ifiers
[0]);
4721 invokeNotifiers(¬ifiers
[1]);
4723 lockForArbitration();
4724 __state
[1] &= ~kIOServiceConfigState
;
4725 scheduleTerminatePhase2();
4728 unlockForArbitration();
4732 IOService::_adjustBusy( SInt32 delta
)
4737 bool wasQuiet
, nowQuiet
, needWake
;
4740 result
= __state
[1] & kIOServiceBusyStateMask
;
4745 next
->lockForArbitration();
4747 count
= next
->__state
[1] & kIOServiceBusyStateMask
;
4748 wasQuiet
= (0 == count
);
4749 if (((delta
< 0) && wasQuiet
) || ((delta
> 0) && (kIOServiceBusyMax
== count
))) {
4750 OSReportWithBacktrace("%s: bad busy count (%d,%d)\n", next
->getName(), count
, delta
);
4754 next
->__state
[1] = (next
->__state
[1] & ~kIOServiceBusyStateMask
) | count
;
4755 nowQuiet
= (0 == count
);
4756 needWake
= (0 != (kIOServiceBusyWaiterState
& next
->__state
[1]));
4759 next
->__state
[1] &= ~kIOServiceBusyWaiterState
;
4760 IOLockLock( gIOServiceBusyLock
);
4761 thread_wakeup((event_t
) next
);
4762 IOLockUnlock( gIOServiceBusyLock
);
4765 next
->unlockForArbitration();
4768 if ((wasQuiet
|| nowQuiet
)) {
4769 uint64_t regID
= next
->getRegistryEntryID();
4771 ((wasQuiet
/*nowBusy*/) ? IOSERVICE_BUSY
: IOSERVICE_NONBUSY
),
4773 (uintptr_t) (regID
>> 32),
4778 next
->__timeBusy
= mach_absolute_time();
4780 next
->__accumBusy
+= mach_absolute_time() - next
->__timeBusy
;
4781 next
->__timeBusy
= 0;
4784 MessageClientsContext context
;
4786 context
.service
= next
;
4787 context
.type
= kIOMessageServiceBusyStateChange
;
4788 context
.argument
= (void *) wasQuiet
; /*nowBusy*/
4789 context
.argSize
= 0;
4791 applyToInterestNotifiers( next
, gIOBusyInterest
,
4792 &messageClientsApplier
, &context
);
4795 if (nowQuiet
&& (next
== gIOServiceRoot
)) {
4796 OSKext::considerUnloads();
4797 IOServiceTrace(IOSERVICE_REGISTRY_QUIET
, 0, 0, 0, 0);
4802 delta
= nowQuiet
? -1 : +1;
4803 } while ((wasQuiet
|| nowQuiet
) && (next
= next
->getProvider()));
4810 IOService::adjustBusy( SInt32 delta
)
4812 lockForArbitration();
4813 _adjustBusy( delta
);
4814 unlockForArbitration();
4818 IOService::getAccumulatedBusyTime( void )
4820 uint64_t accumBusy
= __accumBusy
;
4821 uint64_t timeBusy
= __timeBusy
;
4825 accumBusy
= __accumBusy
;
4826 timeBusy
= __timeBusy
;
4828 accumBusy
+= mach_absolute_time() - timeBusy
;
4830 }while (timeBusy
!= __timeBusy
);
4832 absolutetime_to_nanoseconds(*(AbsoluteTime
*)&accumBusy
, &nano
);
4838 IOService::getBusyState( void )
4840 return __state
[1] & kIOServiceBusyStateMask
;
4844 IOService::waitForState( UInt32 mask
, UInt32 value
,
4845 mach_timespec_t
* timeout
)
4847 panic("waitForState");
4848 return kIOReturnUnsupported
;
4852 IOService::waitForState( UInt32 mask
, UInt32 value
,
4856 int waitResult
= THREAD_AWAKENED
;
4857 bool computeDeadline
= true;
4858 AbsoluteTime abstime
;
4861 lockForArbitration();
4862 IOLockLock( gIOServiceBusyLock
);
4863 wait
= (value
!= (__state
[1] & mask
));
4865 __state
[1] |= kIOServiceBusyWaiterState
;
4866 unlockForArbitration();
4867 if (timeout
!= UINT64_MAX
) {
4868 if (computeDeadline
) {
4869 AbsoluteTime nsinterval
;
4870 nanoseconds_to_absolutetime(timeout
, &nsinterval
);
4871 clock_absolutetime_interval_to_deadline(nsinterval
, &abstime
);
4872 computeDeadline
= false;
4874 assert_wait_deadline((event_t
)this, THREAD_UNINT
, __OSAbsoluteTime(abstime
));
4876 assert_wait((event_t
)this, THREAD_UNINT
);
4879 unlockForArbitration();
4881 IOLockUnlock( gIOServiceBusyLock
);
4883 waitResult
= thread_block(THREAD_CONTINUE_NULL
);
4885 } while (wait
&& (waitResult
!= THREAD_TIMED_OUT
));
4887 if (waitResult
== THREAD_TIMED_OUT
) {
4888 return kIOReturnTimeout
;
4890 return kIOReturnSuccess
;
4895 IOService::waitQuiet( uint64_t timeout
)
4899 char * string
= NULL
;
4900 char * panicString
= NULL
;
4902 size_t panicStringLen
;
4910 * On kasan kernels, everything takes longer, so double the number of
4911 * timeout extensions. This should help with issues like 41259215
4912 * where WindowServer was timing out waiting for kextd to get all the
4913 * kasan kexts loaded and started.
4915 enum { kTimeoutExtensions
= 8 };
4917 enum { kTimeoutExtensions
= 4 };
4920 time
= mach_absolute_time();
4922 for (loops
= 0; loops
< kTimeoutExtensions
; loops
++) {
4923 ret
= waitForState( kIOServiceBusyStateMask
, 0, timeout
);
4925 if (loops
&& (kIOReturnSuccess
== ret
)) {
4926 time
= mach_absolute_time() - time
;
4927 absolutetime_to_nanoseconds(*(AbsoluteTime
*)&time
, &nano
);
4928 IOLog("busy extended ok[%d], (%llds, %llds)\n",
4929 loops
, timeout
/ 1000000000ULL, nano
/ 1000000000ULL);
4931 } else if (kIOReturnTimeout
!= ret
) {
4933 } else if (timeout
< (4100ull * NSEC_PER_SEC
)) {
4938 IORegistryIterator
* iter
;
4940 OSOrderedSet
* leaves
;
4942 IOService
* nextParent
;
4947 panicStringLen
= 256;
4949 string
= IONew(char, len
);
4952 panicString
= IONew(char, panicStringLen
);
4955 kextdWait
= OSKext::isWaitingKextd();
4956 iter
= IORegistryIterator::iterateOver(this, gIOServicePlane
, kIORegistryIterateRecursively
);
4957 leaves
= OSOrderedSet::withCapacity(4);
4959 set
= iter
->iterateAll();
4961 if (string
&& panicString
&& leaves
&& set
) {
4962 string
[0] = panicString
[0] = 0;
4963 set
->setObject(this);
4964 while ((next
= (IOService
*) set
->getLastObject())) {
4965 if (next
->getBusyState()) {
4966 if (kIOServiceModuleStallState
& next
->__state
[1]) {
4969 leaves
->setObject(next
);
4971 while ((nextParent
= nextParent
->getProvider())) {
4972 set
->removeObject(nextParent
);
4973 leaves
->removeObject(nextParent
);
4976 set
->removeObject(next
);
4979 while ((next
= (IOService
*) leaves
->getLastObject())) {
4980 l
= snprintf(s
, len
, "%s'%s'", ((s
== string
) ? "" : ", "), next
->getName());
4986 leaves
->removeObject(next
);
4989 OSSafeReleaseNULL(leaves
);
4990 OSSafeReleaseNULL(set
);
4991 OSSafeReleaseNULL(iter
);
4994 dopanic
= ((loops
>= (kTimeoutExtensions
- 1)) && (kIOWaitQuietPanics
& gIOKitDebug
));
4995 snprintf(panicString
, panicStringLen
,
4996 "%s[%d], (%llds): %s",
4997 kextdWait
? "kextd stall" : "busy timeout",
4998 loops
, timeout
/ 1000000000ULL,
4999 string
? string
: "");
5000 IOLog("%s\n", panicString
);
5002 panic("%s", panicString
);
5003 } else if (!loops
) {
5004 getPMRootDomain()->startSpinDump(1);
5009 IODelete(string
, char, 256);
5012 IODelete(panicString
, char, panicStringLen
);
5019 IOService::waitQuiet( mach_timespec_t
* timeout
)
5024 timeoutNS
= timeout
->tv_sec
;
5025 timeoutNS
*= kSecondScale
;
5026 timeoutNS
+= timeout
->tv_nsec
;
5028 timeoutNS
= UINT64_MAX
;
5031 return waitQuiet(timeoutNS
);
5035 IOService::serializeProperties( OSSerialize
* s
) const
5038 ((IOService
*)this)->setProperty(((IOService
*)this)->__state
,
5039 sizeof(__state
), "__state");
5041 return super::serializeProperties(s
);
5046 _IOConfigThread::main(void * arg
, wait_result_t result
)
5048 _IOConfigThread
* self
= (_IOConfigThread
*) arg
;
5049 _IOServiceJob
* job
;
5053 thread_precedence_policy_data_t precedence
= { -1 };
5055 kr
= thread_policy_set(current_thread(),
5056 THREAD_PRECEDENCE_POLICY
,
5057 (thread_policy_t
) &precedence
,
5058 THREAD_PRECEDENCE_POLICY_COUNT
);
5059 if (KERN_SUCCESS
!= kr
) {
5060 IOLog("thread_policy_set(%d)\n", kr
);
5066 semaphore_wait( gJobsSemaphore
);
5068 IOTakeLock( gJobsLock
);
5069 job
= (_IOServiceJob
*) gJobs
->getFirstObject();
5071 gJobs
->removeObject(job
);
5074 // gNumConfigThreads--; // we're out of service
5075 gNumWaitingThreads
--; // we're out of service
5077 IOUnlock( gJobsLock
);
5082 if (gIOKitDebug
& kIOLogConfig
) {
5083 LOG("config(%p): starting on %s, %d\n",
5084 IOSERVICE_OBFUSCATE(IOThreadSelf()), job
->nub
->getName(), job
->type
);
5087 switch (job
->type
) {
5089 nub
->doServiceMatch( job
->options
);
5093 LOG("config(%p): strange type (%d)\n",
5094 IOSERVICE_OBFUSCATE(IOThreadSelf()), job
->type
);
5101 IOTakeLock( gJobsLock
);
5102 alive
= (gOutstandingJobs
> gNumWaitingThreads
);
5104 gNumWaitingThreads
++; // back in service
5106 // gNumConfigThreads++;
5108 if (0 == --gNumConfigThreads
) {
5109 // IOLog("MATCH IDLE\n");
5110 IOLockWakeup( gJobsLock
, (event_t
) &gNumConfigThreads
, /* one-thread */ false );
5113 IOUnlock( gJobsLock
);
5117 if (gIOKitDebug
& kIOLogConfig
) {
5118 LOG("config(%p): terminating\n", IOSERVICE_OBFUSCATE(IOThreadSelf()));
5125 IOService::waitMatchIdle( UInt32 msToWait
)
5128 int waitResult
= THREAD_AWAKENED
;
5129 bool computeDeadline
= true;
5130 AbsoluteTime deadline
;
5132 IOLockLock( gJobsLock
);
5134 wait
= (0 != gNumConfigThreads
);
5137 if (computeDeadline
) {
5138 clock_interval_to_deadline(
5139 msToWait
, kMillisecondScale
, &deadline
);
5140 computeDeadline
= false;
5142 waitResult
= IOLockSleepDeadline( gJobsLock
, &gNumConfigThreads
,
5143 deadline
, THREAD_UNINT
);
5145 waitResult
= IOLockSleep( gJobsLock
, &gNumConfigThreads
,
5149 } while (wait
&& (waitResult
!= THREAD_TIMED_OUT
));
5150 IOLockUnlock( gJobsLock
);
5152 if (waitResult
== THREAD_TIMED_OUT
) {
5153 return kIOReturnTimeout
;
5155 return kIOReturnSuccess
;
5160 IOService::cpusRunning(void)
5162 gCPUsRunning
= true;
5166 _IOServiceJob::pingConfig( _IOServiceJob
* job
)
5173 IOTakeLock( gJobsLock
);
5176 gJobs
->setLastObject( job
);
5178 count
= gNumWaitingThreads
;
5179 // if( gNumConfigThreads) count++;// assume we're called from a config thread
5181 create
= ((gOutstandingJobs
> count
)
5182 && ((gNumConfigThreads
< kMaxConfigThreads
)
5183 || (job
->nub
== gIOResources
)
5186 gNumConfigThreads
++;
5187 gNumWaitingThreads
++;
5190 IOUnlock( gJobsLock
);
5195 if (gIOKitDebug
& kIOLogConfig
) {
5196 LOG("config(%d): creating\n", gNumConfigThreads
- 1);
5198 _IOConfigThread::configThread(gNumConfigThreads
- 1);
5201 semaphore_signal( gJobsSemaphore
);
5204 struct IOServiceMatchContext
{
5205 OSDictionary
* table
;
5214 IOService::instanceMatch(const OSObject
* entry
, void * context
)
5216 IOServiceMatchContext
* ctx
= (typeof(ctx
))context
;
5217 IOService
* service
= (typeof(service
))entry
;
5218 OSDictionary
* table
= ctx
->table
;
5219 uint32_t options
= ctx
->options
;
5220 uint32_t state
= ctx
->state
;
5226 match
= ((state
== (state
& service
->__state
[0]))
5227 && (0 == (service
->__state
[0] & kIOServiceInactiveState
)));
5231 ctx
->count
+= table
->getCount();
5232 match
= service
->matchInternal(table
, options
, &done
);
5239 if ((kIONotifyOnce
& options
) && (ctx
->done
== ctx
->count
)) {
5241 ctx
->result
= service
;
5243 } else if (!ctx
->result
) {
5244 ctx
->result
= OSSet::withObjects((const OSObject
**) &service
, 1, 1);
5246 ((OSSet
*)ctx
->result
)->setObject(service
);
5251 // internal - call with gNotificationLock
5253 IOService::copyExistingServices( OSDictionary
* matching
,
5254 IOOptionBits inState
, IOOptionBits options
)
5256 OSObject
* current
= NULL
;
5258 IOService
* service
;
5267 OSSerialize
* s
= OSSerialize::withCapacity(128);
5268 matching
->serialize(s
);
5271 if ((obj
= matching
->getObject(gIOProviderClassKey
))
5273 && gIOResourcesKey
->isEqualTo(obj
)
5274 && (service
= gIOResources
)) {
5275 if ((inState
== (service
->__state
[0] & inState
))
5276 && (0 == (service
->__state
[0] & kIOServiceInactiveState
))
5277 && service
->matchPassive(matching
, options
)) {
5278 if (options
& kIONotifyOnce
) {
5282 current
= OSSet::withObjects((const OSObject
**) &service
, 1, 1 );
5286 IOServiceMatchContext ctx
;
5287 ctx
.table
= matching
;
5288 ctx
.state
= inState
;
5291 ctx
.options
= options
;
5294 if ((str
= OSDynamicCast(OSString
, obj
))) {
5295 const OSSymbol
* sym
= OSSymbol::withString(str
);
5296 OSMetaClass::applyToInstancesOfClassName(sym
, instanceMatch
, &ctx
);
5299 IOService::gMetaClass
.applyToInstances(instanceMatch
, &ctx
);
5303 current
= ctx
.result
;
5305 options
|= kIOServiceInternalDone
| kIOServiceClassDone
;
5306 if (current
&& (ctx
.done
!= ctx
.count
)) {
5308 source
= OSDynamicCast(OSSet
, current
);
5310 while ((service
= (IOService
*) source
->getAnyObject())) {
5311 if (service
->matchPassive(matching
, options
)) {
5312 if (options
& kIONotifyOnce
) {
5318 ((OSSet
*)current
)->setObject( service
);
5320 current
= OSSet::withObjects(
5321 (const OSObject
**) &service
, 1, 1 );
5324 source
->removeObject(service
);
5332 OSObject
* _current
= 0;
5334 iter
= IORegistryIterator::iterateOver( gIOServicePlane
,
5335 kIORegistryIterateRecursively
);
5339 while ((service
= (IOService
*) iter
->getNextObject())) {
5340 if ((inState
== (service
->__state
[0] & inState
))
5341 && (0 == (service
->__state
[0] & kIOServiceInactiveState
))
5342 && service
->matchPassive(matching
, 0)) {
5343 if (options
& kIONotifyOnce
) {
5349 ((OSSet
*)_current
)->setObject( service
);
5351 _current
= OSSet::withObjects(
5352 (const OSObject
**) &service
, 1, 1 );
5356 } while (!service
&& !iter
->isValid());
5360 if (((current
!= 0) != (_current
!= 0))
5361 || (current
&& _current
&& !current
->isEqualTo(_current
))) {
5362 OSSerialize
* s1
= OSSerialize::withCapacity(128);
5363 OSSerialize
* s2
= OSSerialize::withCapacity(128);
5364 current
->serialize(s1
);
5365 _current
->serialize(s2
);
5366 kprintf("**mismatch** %p %p\n%s\n%s\n%s\n", IOSERVICE_OBFUSCATE(current
),
5367 IOSERVICE_OBFUSCATE(_current
), s
->text(), s1
->text(), s2
->text());
5373 _current
->release();
5380 if (current
&& (0 == (options
& (kIONotifyOnce
| kIOServiceExistingSet
)))) {
5381 iter
= OSCollectionIterator::withCollection((OSSet
*)current
);
5391 IOService::getMatchingServices( OSDictionary
* matching
)
5395 // is a lock even needed?
5398 iter
= (OSIterator
*) copyExistingServices( matching
,
5399 kIOServiceMatchedState
);
5407 IOService::copyMatchingService( OSDictionary
* matching
)
5409 IOService
* service
;
5411 // is a lock even needed?
5414 service
= (IOService
*) copyExistingServices( matching
,
5415 kIOServiceMatchedState
, kIONotifyOnce
);
5422 struct _IOServiceMatchingNotificationHandlerRef
{
5423 IOServiceNotificationHandler handler
;
5428 _IOServiceMatchingNotificationHandler( void * target
, void * refCon
,
5429 IOService
* newService
,
5430 IONotifier
* notifier
)
5432 return (*((_IOServiceNotifier
*) notifier
)->compatHandler
)(target
, refCon
, newService
);
5435 // internal - call with gNotificationLock
5437 IOService::setNotification(
5438 const OSSymbol
* type
, OSDictionary
* matching
,
5439 IOServiceMatchingNotificationHandler handler
, void * target
, void * ref
,
5442 _IOServiceNotifier
* notify
= NULL
;
5449 notify
= new _IOServiceNotifier
;
5450 if (notify
&& !notify
->init()) {
5456 notify
->handler
= handler
;
5457 notify
->target
= target
;
5458 notify
->type
= type
;
5459 notify
->matching
= matching
;
5461 if (handler
== &_IOServiceMatchingNotificationHandler
) {
5462 notify
->compatHandler
= ((_IOServiceMatchingNotificationHandlerRef
*)ref
)->handler
;
5463 notify
->ref
= ((_IOServiceMatchingNotificationHandlerRef
*)ref
)->ref
;
5467 notify
->priority
= priority
;
5468 notify
->state
= kIOServiceNotifyEnable
;
5469 queue_init( ¬ify
->handlerInvocations
);
5473 if (NULL
== (set
= (OSOrderedSet
*) gNotifications
->getObject( type
))) {
5474 set
= OSOrderedSet::withCapacity( 1,
5475 IONotifyOrdering
, NULL
);
5477 gNotifications
->setObject( type
, set
);
5481 notify
->whence
= set
;
5483 set
->setObject( notify
);
5490 // internal - call with gNotificationLock
5492 IOService::doInstallNotification(
5493 const OSSymbol
* type
, OSDictionary
* matching
,
5494 IOServiceMatchingNotificationHandler handler
,
5495 void * target
, void * ref
,
5496 SInt32 priority
, OSIterator
** existing
)
5499 IONotifier
* notify
;
5500 IOOptionBits inState
;
5506 if (type
== gIOPublishNotification
) {
5507 inState
= kIOServiceRegisteredState
;
5508 } else if (type
== gIOFirstPublishNotification
) {
5509 inState
= kIOServiceFirstPublishState
;
5510 } else if (type
== gIOMatchedNotification
) {
5511 inState
= kIOServiceMatchedState
;
5512 } else if (type
== gIOFirstMatchNotification
) {
5513 inState
= kIOServiceFirstMatchState
;
5514 } else if ((type
== gIOTerminatedNotification
) || (type
== gIOWillTerminateNotification
)) {
5520 notify
= setNotification( type
, matching
, handler
, target
, ref
, priority
);
5523 // get the current set
5524 exist
= (OSIterator
*) copyExistingServices( matching
, inState
);
5534 #if !defined(__LP64__)
5536 IOService::installNotification(const OSSymbol
* type
, OSDictionary
* matching
,
5537 IOServiceNotificationHandler handler
,
5538 void * target
, void * refCon
,
5539 SInt32 priority
, OSIterator
** existing
)
5541 IONotifier
* result
;
5542 _IOServiceMatchingNotificationHandlerRef ref
;
5543 ref
.handler
= handler
;
5546 result
= (_IOServiceNotifier
*) installNotification( type
, matching
,
5547 &_IOServiceMatchingNotificationHandler
,
5548 target
, &ref
, priority
, existing
);
5550 matching
->release();
5555 #endif /* !defined(__LP64__) */
5559 IOService::installNotification(
5560 const OSSymbol
* type
, OSDictionary
* matching
,
5561 IOServiceMatchingNotificationHandler handler
,
5562 void * target
, void * ref
,
5563 SInt32 priority
, OSIterator
** existing
)
5565 IONotifier
* notify
;
5569 notify
= doInstallNotification( type
, matching
, handler
, target
, ref
,
5570 priority
, existing
);
5572 // in case handler remove()s
5583 IOService::addNotification(
5584 const OSSymbol
* type
, OSDictionary
* matching
,
5585 IOServiceNotificationHandler handler
,
5586 void * target
, void * refCon
,
5589 IONotifier
* result
;
5590 _IOServiceMatchingNotificationHandlerRef ref
;
5592 ref
.handler
= handler
;
5595 result
= addMatchingNotification(type
, matching
, &_IOServiceMatchingNotificationHandler
,
5596 target
, &ref
, priority
);
5599 matching
->release();
5606 IOService::addMatchingNotification(
5607 const OSSymbol
* type
, OSDictionary
* matching
,
5608 IOServiceMatchingNotificationHandler handler
,
5609 void * target
, void * ref
,
5612 OSIterator
* existing
= NULL
;
5614 _IOServiceNotifier
* notify
;
5617 ret
= notify
= (_IOServiceNotifier
*) installNotification( type
, matching
,
5618 handler
, target
, ref
, priority
, &existing
);
5623 // send notifications for existing set
5625 while ((next
= (IOService
*) existing
->getNextObject())) {
5626 if (0 == (next
->__state
[0] & kIOServiceInactiveState
)) {
5627 next
->invokeNotifier( notify
);
5630 existing
->release();
5634 bool removed
= (NULL
== notify
->whence
);
5637 ret
= gIOServiceNullNotifier
;
5645 IOServiceMatchingNotificationHandlerToBlock( void * target __unused
, void * refCon
,
5646 IOService
* newService
,
5647 IONotifier
* notifier
)
5649 return ((IOServiceMatchingNotificationHandlerBlock
) refCon
)(newService
, notifier
);
5653 IOService::addMatchingNotification(
5654 const OSSymbol
* type
, OSDictionary
* matching
,
5656 IOServiceMatchingNotificationHandlerBlock handler
)
5658 IONotifier
* notify
;
5661 block
= Block_copy(handler
);
5666 notify
= addMatchingNotification(type
, matching
,
5667 &IOServiceMatchingNotificationHandlerToBlock
, NULL
, block
, priority
);
5670 Block_release(block
);
5678 IOService::syncNotificationHandler(
5679 void * /* target */, void * ref
,
5680 IOService
* newService
,
5681 IONotifier
* notifier
)
5684 if (!*((IOService
**) ref
)) {
5685 newService
->retain();
5686 (*(IOService
**) ref
) = newService
;
5695 IOService::waitForMatchingService( OSDictionary
* matching
,
5698 IONotifier
* notify
= NULL
;
5699 // priority doesn't help us much since we need a thread wakeup
5700 SInt32 priority
= 0;
5711 result
= (IOService
*) copyExistingServices( matching
,
5712 kIOServiceMatchedState
, kIONotifyOnce
);
5716 notify
= IOService::setNotification( gIOMatchedNotification
, matching
,
5717 &IOService::syncNotificationHandler
, (void *) NULL
,
5718 &result
, priority
);
5722 if (UINT64_MAX
!= timeout
) {
5723 AbsoluteTime deadline
;
5724 nanoseconds_to_absolutetime(timeout
, &deadline
);
5725 clock_absolutetime_interval_to_deadline(deadline
, &deadline
);
5726 SLEEPNOTIFYTO(&result
, deadline
);
5728 SLEEPNOTIFY(&result
);
5735 notify
->remove(); // dequeues
5741 IOService::waitForService( OSDictionary
* matching
,
5742 mach_timespec_t
* timeout
)
5748 timeoutNS
= timeout
->tv_sec
;
5749 timeoutNS
*= kSecondScale
;
5750 timeoutNS
+= timeout
->tv_nsec
;
5752 timeoutNS
= UINT64_MAX
;
5755 result
= waitForMatchingService(matching
, timeoutNS
);
5757 matching
->release();
5767 IOService::deliverNotification( const OSSymbol
* type
,
5768 IOOptionBits orNewState
, IOOptionBits andNewState
)
5770 panic("deliverNotification");
5774 IOService::copyNotifiers(const OSSymbol
* type
,
5775 IOOptionBits orNewState
, IOOptionBits andNewState
)
5777 _IOServiceNotifier
* notify
;
5779 OSArray
* willSend
= NULL
;
5781 lockForArbitration();
5783 if ((0 == (__state
[0] & kIOServiceInactiveState
))
5784 || (type
== gIOTerminatedNotification
)
5785 || (type
== gIOWillTerminateNotification
)) {
5788 iter
= OSCollectionIterator::withCollection((OSOrderedSet
*)
5789 gNotifications
->getObject( type
));
5792 while ((notify
= (_IOServiceNotifier
*) iter
->getNextObject())) {
5793 if (matchPassive(notify
->matching
, 0)
5794 && (kIOServiceNotifyEnable
& notify
->state
)) {
5795 if (NULL
== willSend
) {
5796 willSend
= OSArray::withCapacity(8);
5799 willSend
->setObject( notify
);
5805 __state
[0] = (__state
[0] | orNewState
) & andNewState
;
5809 unlockForArbitration();
5815 IOService::getState( void ) const
5821 * Helpers to make matching objects for simple cases
5825 IOService::serviceMatching( const OSString
* name
,
5826 OSDictionary
* table
)
5828 const OSString
* str
;
5830 str
= OSSymbol::withString(name
);
5836 table
= OSDictionary::withCapacity( 2 );
5839 table
->setObject(gIOProviderClassKey
, (OSObject
*)str
);
5847 IOService::serviceMatching( const char * name
,
5848 OSDictionary
* table
)
5850 const OSString
* str
;
5852 str
= OSSymbol::withCString( name
);
5857 table
= serviceMatching( str
, table
);
5863 IOService::nameMatching( const OSString
* name
,
5864 OSDictionary
* table
)
5867 table
= OSDictionary::withCapacity( 2 );
5870 table
->setObject( gIONameMatchKey
, (OSObject
*)name
);
5877 IOService::nameMatching( const char * name
,
5878 OSDictionary
* table
)
5880 const OSString
* str
;
5882 str
= OSSymbol::withCString( name
);
5887 table
= nameMatching( str
, table
);
5893 IOService::resourceMatching( const OSString
* str
,
5894 OSDictionary
* table
)
5896 table
= serviceMatching( gIOResourcesKey
, table
);
5898 table
->setObject( gIOResourceMatchKey
, (OSObject
*) str
);
5905 IOService::resourceMatching( const char * name
,
5906 OSDictionary
* table
)
5908 const OSSymbol
* str
;
5910 str
= OSSymbol::withCString( name
);
5915 table
= resourceMatching( str
, table
);
5922 IOService::propertyMatching( const OSSymbol
* key
, const OSObject
* value
,
5923 OSDictionary
* table
)
5925 OSDictionary
* properties
;
5927 properties
= OSDictionary::withCapacity( 2 );
5931 properties
->setObject( key
, value
);
5934 table
= OSDictionary::withCapacity( 2 );
5937 table
->setObject( gIOPropertyMatchKey
, properties
);
5940 properties
->release();
5946 IOService::registryEntryIDMatching( uint64_t entryID
,
5947 OSDictionary
* table
)
5951 num
= OSNumber::withNumber( entryID
, 64 );
5957 table
= OSDictionary::withCapacity( 2 );
5960 table
->setObject( gIORegistryEntryIDKey
, num
);
5972 * _IOServiceNotifier
5975 // wait for all threads, other than the current one,
5976 // to exit the handler
5979 _IOServiceNotifier::wait()
5981 _IOServiceNotifierInvocation
* next
;
5986 queue_iterate( &handlerInvocations
, next
,
5987 _IOServiceNotifierInvocation
*, link
) {
5988 if (next
->thread
!= current_thread()) {
5994 state
|= kIOServiceNotifyWaiter
;
6001 _IOServiceNotifier::free()
6003 assert( queue_empty( &handlerInvocations
));
6005 if (handler
== &IOServiceMatchingNotificationHandlerToBlock
) {
6013 _IOServiceNotifier::remove()
6018 whence
->removeObject((OSObject
*) this );
6022 matching
->release();
6026 state
&= ~kIOServiceNotifyEnable
;
6036 _IOServiceNotifier::disable()
6042 ret
= (0 != (kIOServiceNotifyEnable
& state
));
6043 state
&= ~kIOServiceNotifyEnable
;
6054 _IOServiceNotifier::enable( bool was
)
6058 state
|= kIOServiceNotifyEnable
;
6060 state
&= ~kIOServiceNotifyEnable
;
6067 * _IOServiceNullNotifier
6071 _IOServiceNullNotifier::taggedRetain(const void *tag
) const
6075 _IOServiceNullNotifier::taggedRelease(const void *tag
, const int when
) const
6079 _IOServiceNullNotifier::free()
6083 _IOServiceNullNotifier::wait()
6087 _IOServiceNullNotifier::remove()
6091 _IOServiceNullNotifier::enable(bool was
)
6095 _IOServiceNullNotifier::disable()
6105 IOResources::resources( void )
6109 inst
= new IOResources
;
6110 if (inst
&& !inst
->init()) {
6119 IOResources::init( OSDictionary
* dictionary
)
6121 // Do super init first
6122 if (!IOService::init()) {
6126 // Allow PAL layer to publish a value
6127 const char *property_name
;
6130 pal_get_resource_property( &property_name
, &property_value
);
6132 if (property_name
) {
6134 const OSSymbol
* sym
;
6136 if ((num
= OSNumber::withNumber(property_value
, 32)) != NULL
) {
6137 if ((sym
= OSSymbol::withCString( property_name
)) != NULL
) {
6138 this->setProperty( sym
, num
);
6149 IOResources::newUserClient(task_t owningTask
, void * securityID
,
6150 UInt32 type
, OSDictionary
* properties
,
6151 IOUserClient
** handler
)
6153 return kIOReturnUnsupported
;
6157 IOResources::getWorkLoop() const
6159 // If we are the resource root
6160 // then use the platform's workloop
6161 if (this == (IOResources
*) gIOResources
) {
6162 return getPlatform()->getWorkLoop();
6164 return IOService::getWorkLoop();
6169 IOResourcesMatchPropertyTable(IOService
* resources
, OSDictionary
* table
)
6179 prop
= table
->getObject( gIOResourceMatchKey
);
6180 str
= OSDynamicCast( OSString
, prop
);
6182 ok
= (NULL
!= resources
->getProperty( str
));
6183 } else if ((set
= OSDynamicCast( OSSet
, prop
))) {
6184 iter
= OSCollectionIterator::withCollection( set
);
6185 ok
= (iter
!= NULL
);
6186 while (ok
&& (str
= OSDynamicCast( OSString
, iter
->getNextObject()))) {
6187 ok
= (NULL
!= resources
->getProperty( str
));
6193 } else if ((prop
= table
->getObject(gIOResourceMatchedKey
))) {
6194 obj
= resources
->copyProperty(gIOResourceMatchedKey
);
6195 keys
= OSDynamicCast(OSArray
, obj
);
6198 // assuming OSSymbol
6199 ok
= ((-1U) != keys
->getNextIndexOfObject(prop
, 0));
6201 OSSafeReleaseNULL(obj
);
6208 IOResources::matchPropertyTable( OSDictionary
* table
)
6210 return IOResourcesMatchPropertyTable(this, table
);
6218 IOUserResources::resources( void )
6220 IOUserResources
* inst
;
6222 inst
= OSTypeAlloc(IOUserResources
);
6223 if (inst
&& !inst
->init()) {
6232 IOUserResources::init( OSDictionary
* dictionary
)
6234 // Do super init first
6235 if (!IOService::init()) {
6242 IOUserResources::newUserClient(task_t owningTask
, void * securityID
,
6243 UInt32 type
, OSDictionary
* properties
,
6244 IOUserClient
** handler
)
6246 return kIOReturnUnsupported
;
6250 IOUserResources::getWorkLoop() const
6252 return getPlatform()->getWorkLoop();
6256 IOUserResources::matchPropertyTable( OSDictionary
* table
)
6258 return IOResourcesMatchPropertyTable(this, table
);
6264 IOService::consoleLockTimer(thread_call_param_t p0
, thread_call_param_t p1
)
6266 IOService::updateConsoleUsers(NULL
, 0);
6270 IOService::updateConsoleUsers(OSArray
* consoleUsers
, IOMessage systemMessage
)
6272 IORegistryEntry
* regEntry
;
6273 OSObject
* locked
= kOSBooleanFalse
;
6276 OSDictionary
* user
;
6277 static IOMessage sSystemPower
;
6278 clock_sec_t now
= 0;
6279 clock_usec_t microsecs
;
6281 regEntry
= IORegistryEntry::getRegistryRoot();
6283 if (!gIOChosenEntry
) {
6284 gIOChosenEntry
= IORegistryEntry::fromPath("/chosen", gIODTPlane
);
6287 IOLockLock(gIOConsoleUsersLock
);
6289 if (systemMessage
) {
6290 sSystemPower
= systemMessage
;
6292 if (kIOMessageSystemHasPoweredOn
== systemMessage
) {
6293 uint32_t lockState
= IOHibernateWasScreenLocked();
6294 switch (lockState
) {
6297 case kIOScreenLockLocked
:
6298 case kIOScreenLockFileVaultDialog
:
6299 gIOConsoleBooterLockState
= kOSBooleanTrue
;
6301 case kIOScreenLockNoLock
:
6302 gIOConsoleBooterLockState
= NULL
;
6304 case kIOScreenLockUnlocked
:
6306 gIOConsoleBooterLockState
= kOSBooleanFalse
;
6310 #endif /* HIBERNATION */
6314 OSNumber
* num
= NULL
;
6315 bool loginLocked
= true;
6317 gIOConsoleLoggedIn
= false;
6319 (user
= OSDynamicCast(OSDictionary
, consoleUsers
->getObject(idx
)));
6321 gIOConsoleLoggedIn
|= ((kOSBooleanTrue
== user
->getObject(gIOConsoleSessionOnConsoleKey
))
6322 && (kOSBooleanTrue
== user
->getObject(gIOConsoleSessionLoginDoneKey
)));
6324 loginLocked
&= (kOSBooleanTrue
== user
->getObject(gIOConsoleSessionScreenIsLockedKey
));
6326 num
= OSDynamicCast(OSNumber
, user
->getObject(gIOConsoleSessionScreenLockedTimeKey
));
6331 gIOConsoleBooterLockState
= NULL
;
6333 IOLog("IOConsoleUsers: time(%d) %ld->%d, lin %d, llk %d, \n",
6334 (num
!= NULL
), gIOConsoleLockTime
, (num
? num
->unsigned32BitValue() : 0),
6335 gIOConsoleLoggedIn
, loginLocked
);
6336 #endif /* HIBERNATION */
6337 gIOConsoleLockTime
= num
? num
->unsigned32BitValue() : 0;
6340 if (!gIOConsoleLoggedIn
6341 || (kIOMessageSystemWillSleep
== sSystemPower
)
6342 || (kIOMessageSystemPagingOff
== sSystemPower
)) {
6343 locked
= kOSBooleanTrue
;
6346 else if (gIOConsoleBooterLockState
) {
6347 locked
= gIOConsoleBooterLockState
;
6349 #endif /* HIBERNATION */
6350 else if (gIOConsoleLockTime
) {
6351 clock_get_calendar_microtime(&now
, µsecs
);
6352 if (gIOConsoleLockTime
> now
) {
6353 AbsoluteTime deadline
;
6354 clock_interval_to_deadline(gIOConsoleLockTime
- now
, kSecondScale
, &deadline
);
6355 thread_call_enter_delayed(gIOConsoleLockCallout
, deadline
);
6357 locked
= kOSBooleanTrue
;
6361 publish
= (consoleUsers
|| (locked
!= regEntry
->getProperty(gIOConsoleLockedKey
)));
6363 regEntry
->setProperty(gIOConsoleLockedKey
, locked
);
6365 regEntry
->setProperty(gIOConsoleUsersKey
, consoleUsers
);
6367 OSIncrementAtomic( &gIOConsoleUsersSeed
);
6371 if (gIOChosenEntry
) {
6372 if (locked
== kOSBooleanTrue
) {
6373 gIOScreenLockState
= kIOScreenLockLocked
;
6374 } else if (gIOConsoleLockTime
) {
6375 gIOScreenLockState
= kIOScreenLockUnlocked
;
6377 gIOScreenLockState
= kIOScreenLockNoLock
;
6379 gIOChosenEntry
->setProperty(kIOScreenLockStateKey
, &gIOScreenLockState
, sizeof(gIOScreenLockState
));
6381 IOLog("IOConsoleUsers: gIOScreenLockState %d, hs %d, bs %d, now %ld, sm 0x%x\n",
6382 gIOScreenLockState
, gIOHibernateState
, (gIOConsoleBooterLockState
!= NULL
), now
, systemMessage
);
6384 #endif /* HIBERNATION */
6386 IOLockUnlock(gIOConsoleUsersLock
);
6389 publishResource( gIOConsoleUsersSeedKey
, gIOConsoleUsersSeedValue
);
6391 MessageClientsContext context
;
6393 context
.service
= getServiceRoot();
6394 context
.type
= kIOMessageConsoleSecurityChange
;
6395 context
.argument
= (void *) regEntry
;
6396 context
.argSize
= 0;
6398 applyToInterestNotifiers(getServiceRoot(), gIOConsoleSecurityInterest
,
6399 &messageClientsApplier
, &context
);
6404 IOResources::setProperties( OSObject
* properties
)
6407 const OSSymbol
* key
;
6408 OSDictionary
* dict
;
6409 OSCollectionIterator
* iter
;
6411 err
= IOUserClient::clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator
);
6412 if (kIOReturnSuccess
!= err
) {
6416 dict
= OSDynamicCast(OSDictionary
, properties
);
6418 return kIOReturnBadArgument
;
6421 iter
= OSCollectionIterator::withCollection( dict
);
6423 return kIOReturnBadArgument
;
6426 while ((key
= OSDynamicCast(OSSymbol
, iter
->getNextObject()))) {
6427 if (gIOConsoleUsersKey
== key
) {
6429 OSArray
* consoleUsers
;
6430 consoleUsers
= OSDynamicCast(OSArray
, dict
->getObject(key
));
6431 if (!consoleUsers
) {
6434 IOService::updateConsoleUsers(consoleUsers
, 0);
6438 publishResource( key
, dict
->getObject(key
));
6443 return kIOReturnSuccess
;
6447 * Helpers for matching dictionaries.
6448 * Keys existing in matching are checked in properties.
6449 * Keys may be a string or OSCollection of IOStrings
6453 IOService::compareProperty( OSDictionary
* matching
,
6460 value
= matching
->getObject( key
);
6462 prop
= copyProperty(key
);
6463 ok
= value
->isEqualTo(prop
);
6476 IOService::compareProperty( OSDictionary
* matching
,
6477 const OSString
* key
)
6483 value
= matching
->getObject( key
);
6485 prop
= copyProperty(key
);
6486 ok
= value
->isEqualTo(prop
);
6498 IOService::compareProperties( OSDictionary
* matching
,
6499 OSCollection
* keys
)
6501 OSCollectionIterator
* iter
;
6502 const OSString
* key
;
6505 if (!matching
|| !keys
) {
6509 iter
= OSCollectionIterator::withCollection( keys
);
6512 while (ok
&& (key
= OSDynamicCast( OSString
, iter
->getNextObject()))) {
6513 ok
= compareProperty( matching
, key
);
6518 keys
->release(); // !! consume a ref !!
6523 /* Helper to add a location matching dict to the table */
6526 IOService::addLocation( OSDictionary
* table
)
6528 OSDictionary
* dict
;
6534 dict
= OSDictionary::withCapacity( 1 );
6536 bool ok
= table
->setObject( gIOLocationMatchKey
, dict
);
6547 * Go looking for a provider to match a location dict.
6551 IOService::matchLocation( IOService
* /* client */ )
6555 parent
= getProvider();
6558 parent
= parent
->matchLocation( this );
6565 IOService::matchInternal(OSDictionary
* table
, uint32_t options
, uint32_t * did
)
6570 IORegistryEntry
* entry
;
6573 bool changesOK
= (0 != (kIOServiceChangesOK
& options
));
6578 count
= table
->getCount();
6581 str
= OSDynamicCast(OSString
, table
->getObject(gIOProviderClassKey
));
6584 match
= ((kIOServiceClassDone
& options
) || (NULL
!= metaCast(str
)));
6586 match
= (0 != metaCast( str
));
6587 if ((kIOServiceClassDone
& options
) && !match
) {
6591 if ((!match
) || (done
== count
)) {
6596 obj
= table
->getObject( gIONameMatchKey
);
6599 match
= compareNames( obj
, changesOK
? &matched
: NULL
);
6603 if (changesOK
&& matched
) {
6604 // leave a hint as to which name matched
6605 table
->setObject( gIONameMatchedKey
, matched
);
6608 if (done
== count
) {
6613 str
= OSDynamicCast( OSString
, table
->getObject( gIOLocationMatchKey
));
6615 const OSSymbol
* sym
;
6618 sym
= copyLocation();
6620 match
= sym
->isEqualTo( str
);
6623 if ((!match
) || (done
== count
)) {
6628 obj
= table
->getObject( gIOPropertyMatchKey
);
6630 OSDictionary
* dict
;
6631 OSDictionary
* nextDict
;
6635 dict
= dictionaryWithProperties();
6637 nextDict
= OSDynamicCast( OSDictionary
, obj
);
6641 iter
= OSCollectionIterator::withCollection(
6642 OSDynamicCast(OSCollection
, obj
));
6646 || (iter
&& (NULL
!= (nextDict
= OSDynamicCast(OSDictionary
,
6647 iter
->getNextObject()))))) {
6648 match
= dict
->isEqualTo( nextDict
, nextDict
);
6659 if ((!match
) || (done
== count
)) {
6664 obj
= table
->getObject( gIOPropertyExistsMatchKey
);
6666 OSDictionary
* dict
;
6671 dict
= dictionaryWithProperties();
6673 nextKey
= OSDynamicCast( OSString
, obj
);
6677 iter
= OSCollectionIterator::withCollection(
6678 OSDynamicCast(OSCollection
, obj
));
6682 || (iter
&& (NULL
!= (nextKey
= OSDynamicCast(OSString
,
6683 iter
->getNextObject()))))) {
6684 match
= (NULL
!= dict
->getObject(nextKey
));
6695 if ((!match
) || (done
== count
)) {
6700 str
= OSDynamicCast( OSString
, table
->getObject( gIOPathMatchKey
));
6703 entry
= IORegistryEntry::fromPath( str
->getCStringNoCopy());
6704 match
= (this == entry
);
6708 if ((!match
) || (done
== count
)) {
6713 num
= OSDynamicCast( OSNumber
, table
->getObject( gIORegistryEntryIDKey
));
6716 match
= (getRegistryEntryID() == num
->unsigned64BitValue());
6717 if ((!match
) || (done
== count
)) {
6722 num
= OSDynamicCast( OSNumber
, table
->getObject( gIOMatchedServiceCountKey
));
6725 IOService
* service
= NULL
;
6726 UInt32 serviceCount
= 0;
6729 iter
= getClientIterator();
6731 while ((service
= (IOService
*) iter
->getNextObject())) {
6732 if (kIOServiceInactiveState
& service
->__state
[0]) {
6735 if (NULL
== service
->getProperty( gIOMatchCategoryKey
)) {
6742 match
= (serviceCount
== num
->unsigned32BitValue());
6743 if ((!match
) || (done
== count
)) {
6748 #define propMatch(key) \
6749 obj = table->getObject(key); \
6754 prop = copyProperty(key); \
6755 match = obj->isEqualTo(prop); \
6756 if (prop) prop->release(); \
6757 if ((!match) || (done == count)) break; \
6759 propMatch(gIOBSDNameKey
)
6760 propMatch(gIOBSDMajorKey
)
6761 propMatch(gIOBSDMinorKey
)
6762 propMatch(gIOBSDUnitKey
)
6773 IOService::passiveMatch( OSDictionary
* table
, bool changesOK
)
6775 return matchPassive(table
, changesOK
? kIOServiceChangesOK
: 0);
6779 IOService::matchPassive(OSDictionary
* table
, uint32_t options
)
6782 OSDictionary
* nextTable
;
6786 bool matchParent
= false;
6792 #if !CONFIG_EMBEDDED
6793 OSArray
* aliasServiceRegIds
= NULL
;
6794 IOService
* foundAlternateService
= NULL
;
6798 OSDictionary
* root
= table
;
6804 count
= table
->getCount();
6805 if (!(kIOServiceInternalDone
& options
)) {
6806 match
= where
->matchInternal(table
, options
, &done
);
6807 // don't call family if we've done all the entries in the table
6808 if ((!match
) || (done
== count
)) {
6813 // pass in score from property table
6814 score
= IOServiceObjectOrder( table
, (void *) gIOProbeScoreKey
);
6816 // do family specific matching
6817 match
= where
->matchPropertyTable( table
, &score
);
6821 if (kIOLogMatch
& getDebugFlags( table
)) {
6822 LOG("%s: family specific matching fails\n", where
->getName());
6828 if (kIOServiceChangesOK
& options
) {
6830 newPri
= OSNumber::withNumber( score
, 32 );
6832 table
->setObject( gIOProbeScoreKey
, newPri
);
6838 matchParent
= false;
6840 nextTable
= OSDynamicCast(OSDictionary
,
6841 table
->getObject( gIOParentMatchKey
));
6843 // look for a matching entry anywhere up to root
6850 table
= OSDynamicCast(OSDictionary
,
6851 table
->getObject( gIOLocationMatchKey
));
6853 // look for a matching entry at matchLocation()
6855 where
= where
->getProvider();
6856 if (where
&& (where
= where
->matchLocation(where
))) {
6863 if (match
== true) {
6867 if (matchParent
== true) {
6868 #if !CONFIG_EMBEDDED
6869 // check if service has an alias to search its other "parents" if a parent match isn't found
6870 OSObject
* prop
= where
->copyProperty(gIOServiceLegacyMatchingRegistryIDKey
);
6871 OSNumber
* alternateRegistryID
= OSDynamicCast(OSNumber
, prop
);
6872 if (alternateRegistryID
!= NULL
) {
6873 if (aliasServiceRegIds
== NULL
) {
6874 aliasServiceRegIds
= OSArray::withCapacity(sizeof(alternateRegistryID
));
6876 aliasServiceRegIds
->setObject(alternateRegistryID
);
6878 OSSafeReleaseNULL(prop
);
6884 where
= where
->getProvider();
6885 #if !CONFIG_EMBEDDED
6886 if (where
== NULL
) {
6887 // there were no matching parent services, check to see if there are aliased services that have a matching parent
6888 if (aliasServiceRegIds
!= NULL
) {
6889 unsigned int numAliasedServices
= aliasServiceRegIds
->getCount();
6890 if (numAliasedServices
!= 0) {
6891 OSNumber
* alternateRegistryID
= OSDynamicCast(OSNumber
, aliasServiceRegIds
->getObject(numAliasedServices
- 1));
6892 if (alternateRegistryID
!= NULL
) {
6893 OSDictionary
* alternateMatchingDict
= IOService::registryEntryIDMatching(alternateRegistryID
->unsigned64BitValue());
6894 aliasServiceRegIds
->removeObject(numAliasedServices
- 1);
6895 if (alternateMatchingDict
!= NULL
) {
6896 OSSafeReleaseNULL(foundAlternateService
);
6897 foundAlternateService
= IOService::copyMatchingService(alternateMatchingDict
);
6898 alternateMatchingDict
->release();
6899 if (foundAlternateService
!= NULL
) {
6900 where
= foundAlternateService
;
6908 }while (where
!= NULL
);
6910 #if !CONFIG_EMBEDDED
6911 OSSafeReleaseNULL(foundAlternateService
);
6912 OSSafeReleaseNULL(aliasServiceRegIds
);
6916 if (where
!= this) {
6917 OSSerialize
* s
= OSSerialize::withCapacity(128);
6919 kprintf("parent match 0x%llx, %d,\n%s\n", getRegistryEntryID(), match
, s
->text());
6929 IOService::newUserClient( task_t owningTask
, void * securityID
,
6930 UInt32 type
, OSDictionary
* properties
,
6931 IOUserClient
** handler
)
6933 const OSSymbol
*userClientClass
= NULL
;
6934 IOUserClient
*client
;
6938 if (reserved
&& reserved
->uvars
&& reserved
->uvars
->userServer
) {
6939 return reserved
->uvars
->userServer
->serviceNewUserClient(this, owningTask
, securityID
, type
, properties
, handler
);
6942 if (kIOReturnSuccess
== newUserClient( owningTask
, securityID
, type
, handler
)) {
6943 return kIOReturnSuccess
;
6946 // First try my own properties for a user client class name
6947 prop
= copyProperty(gIOUserClientClassKey
);
6949 if (OSDynamicCast(OSSymbol
, prop
)) {
6950 userClientClass
= (const OSSymbol
*) prop
;
6951 } else if (OSDynamicCast(OSString
, prop
)) {
6952 userClientClass
= OSSymbol::withString((OSString
*) prop
);
6953 if (userClientClass
) {
6954 setProperty(gIOUserClientClassKey
,
6955 (OSObject
*) userClientClass
);
6960 // Didn't find one so lets just bomb out now without further ado.
6961 if (!userClientClass
) {
6962 OSSafeReleaseNULL(prop
);
6963 return kIOReturnUnsupported
;
6966 // This reference is consumed by the IOServiceOpen call
6967 temp
= OSMetaClass::allocClassWithName(userClientClass
);
6968 OSSafeReleaseNULL(prop
);
6970 return kIOReturnNoMemory
;
6973 if (OSDynamicCast(IOUserClient
, temp
)) {
6974 client
= (IOUserClient
*) temp
;
6977 return kIOReturnUnsupported
;
6980 if (!client
->initWithTask(owningTask
, securityID
, type
, properties
)) {
6982 return kIOReturnBadArgument
;
6985 if (!client
->attach(this)) {
6987 return kIOReturnUnsupported
;
6990 if (!client
->start(this)) {
6991 client
->detach(this);
6993 return kIOReturnUnsupported
;
6997 return kIOReturnSuccess
;
7001 IOService::newUserClient( task_t owningTask
, void * securityID
,
7002 UInt32 type
, IOUserClient
** handler
)
7004 return kIOReturnUnsupported
;
7008 IOService::requestProbe( IOOptionBits options
)
7010 return kIOReturnUnsupported
;
7014 * Convert an IOReturn to text. Subclasses which add additional
7015 * IOReturn's should override this method and call
7016 * super::stringFromReturn if the desired value is not found.
7020 IOService::stringFromReturn( IOReturn rtn
)
7022 static const IONamedValue IOReturn_values
[] = {
7023 {kIOReturnSuccess
, "success" },
7024 {kIOReturnError
, "general error" },
7025 {kIOReturnNoMemory
, "memory allocation error" },
7026 {kIOReturnNoResources
, "resource shortage" },
7027 {kIOReturnIPCError
, "Mach IPC failure" },
7028 {kIOReturnNoDevice
, "no such device" },
7029 {kIOReturnNotPrivileged
, "privilege violation" },
7030 {kIOReturnBadArgument
, "invalid argument" },
7031 {kIOReturnLockedRead
, "device is read locked" },
7032 {kIOReturnLockedWrite
, "device is write locked" },
7033 {kIOReturnExclusiveAccess
, "device is exclusive access" },
7034 {kIOReturnBadMessageID
, "bad IPC message ID" },
7035 {kIOReturnUnsupported
, "unsupported function" },
7036 {kIOReturnVMError
, "virtual memory error" },
7037 {kIOReturnInternalError
, "internal driver error" },
7038 {kIOReturnIOError
, "I/O error" },
7039 {kIOReturnCannotLock
, "cannot acquire lock" },
7040 {kIOReturnNotOpen
, "device is not open" },
7041 {kIOReturnNotReadable
, "device is not readable" },
7042 {kIOReturnNotWritable
, "device is not writeable" },
7043 {kIOReturnNotAligned
, "alignment error" },
7044 {kIOReturnBadMedia
, "media error" },
7045 {kIOReturnStillOpen
, "device is still open" },
7046 {kIOReturnRLDError
, "rld failure" },
7047 {kIOReturnDMAError
, "DMA failure" },
7048 {kIOReturnBusy
, "device is busy" },
7049 {kIOReturnTimeout
, "I/O timeout" },
7050 {kIOReturnOffline
, "device is offline" },
7051 {kIOReturnNotReady
, "device is not ready" },
7052 {kIOReturnNotAttached
, "device/channel is not attached" },
7053 {kIOReturnNoChannels
, "no DMA channels available" },
7054 {kIOReturnNoSpace
, "no space for data" },
7055 {kIOReturnPortExists
, "device port already exists" },
7056 {kIOReturnCannotWire
, "cannot wire physical memory" },
7057 {kIOReturnNoInterrupt
, "no interrupt attached" },
7058 {kIOReturnNoFrames
, "no DMA frames enqueued" },
7059 {kIOReturnMessageTooLarge
, "message is too large" },
7060 {kIOReturnNotPermitted
, "operation is not permitted" },
7061 {kIOReturnNoPower
, "device is without power" },
7062 {kIOReturnNoMedia
, "media is not present" },
7063 {kIOReturnUnformattedMedia
, "media is not formatted" },
7064 {kIOReturnUnsupportedMode
, "unsupported mode" },
7065 {kIOReturnUnderrun
, "data underrun" },
7066 {kIOReturnOverrun
, "data overrun" },
7067 {kIOReturnDeviceError
, "device error" },
7068 {kIOReturnNoCompletion
, "no completion routine" },
7069 {kIOReturnAborted
, "operation was aborted" },
7070 {kIOReturnNoBandwidth
, "bus bandwidth would be exceeded" },
7071 {kIOReturnNotResponding
, "device is not responding" },
7072 {kIOReturnInvalid
, "unanticipated driver error" },
7076 return IOFindNameForValue(rtn
, IOReturn_values
);
7080 * Convert an IOReturn to an errno.
7083 IOService::errnoFromReturn( IOReturn rtn
)
7085 if (unix_err(err_get_code(rtn
)) == rtn
) {
7086 return err_get_code(rtn
);
7091 case kIOReturnSuccess
:
7093 case kIOReturnNoMemory
:
7095 case kIOReturnNoDevice
:
7097 case kIOReturnVMError
:
7099 case kIOReturnNotPermitted
:
7101 case kIOReturnNotPrivileged
:
7103 case kIOReturnIOError
:
7105 case kIOReturnNotWritable
:
7107 case kIOReturnBadArgument
:
7109 case kIOReturnUnsupported
:
7113 case kIOReturnNoPower
:
7115 case kIOReturnDeviceError
:
7117 case kIOReturnTimeout
:
7119 case kIOReturnMessageTooLarge
:
7121 case kIOReturnNoSpace
:
7123 case kIOReturnCannotLock
:
7127 case kIOReturnBadMessageID
:
7128 case kIOReturnNoCompletion
:
7129 case kIOReturnNotAligned
:
7131 case kIOReturnNotReady
:
7133 case kIOReturnRLDError
:
7135 case kIOReturnPortExists
:
7136 case kIOReturnStillOpen
:
7138 case kIOReturnExclusiveAccess
:
7139 case kIOReturnLockedRead
:
7140 case kIOReturnLockedWrite
:
7141 case kIOReturnNotOpen
:
7142 case kIOReturnNotReadable
:
7144 case kIOReturnCannotWire
:
7145 case kIOReturnNoResources
:
7147 case kIOReturnAborted
:
7148 case kIOReturnOffline
:
7149 case kIOReturnNotResponding
:
7151 case kIOReturnBadMedia
:
7152 case kIOReturnNoMedia
:
7153 case kIOReturnNotAttached
:
7154 case kIOReturnUnformattedMedia
:
7155 return ENXIO
; // (media error)
7156 case kIOReturnDMAError
:
7157 case kIOReturnOverrun
:
7158 case kIOReturnUnderrun
:
7159 return EIO
; // (transfer error)
7160 case kIOReturnNoBandwidth
:
7161 case kIOReturnNoChannels
:
7162 case kIOReturnNoFrames
:
7163 case kIOReturnNoInterrupt
:
7164 return EIO
; // (hardware error)
7165 case kIOReturnError
:
7166 case kIOReturnInternalError
:
7167 case kIOReturnInvalid
:
7168 return EIO
; // (generic error)
7169 case kIOReturnIPCError
:
7170 return EIO
; // (ipc error)
7172 return EIO
; // (all other errors)
7177 IOService::message( UInt32 type
, IOService
* provider
,
7181 * Generic entry point for calls from the provider. A return value of
7182 * kIOReturnSuccess indicates that the message was received, and where
7183 * applicable, that it was successful.
7186 return kIOReturnUnsupported
;
7194 IOService::getDeviceMemoryCount( void )
7199 array
= OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
));
7201 count
= array
->getCount();
7210 IOService::getDeviceMemoryWithIndex( unsigned int index
)
7213 IODeviceMemory
* range
;
7215 array
= OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
));
7217 range
= (IODeviceMemory
*) array
->getObject( index
);
7226 IOService::mapDeviceMemoryWithIndex( unsigned int index
,
7227 IOOptionBits options
)
7229 IODeviceMemory
* range
;
7232 range
= getDeviceMemoryWithIndex( index
);
7234 map
= range
->map( options
);
7243 IOService::getDeviceMemory( void )
7245 return OSDynamicCast( OSArray
, getProperty( gIODeviceMemoryKey
));
7250 IOService::setDeviceMemory( OSArray
* array
)
7252 setProperty( gIODeviceMemoryKey
, array
);
7256 * For machines where the transfers on an I/O bus can stall because
7257 * the CPU is in an idle mode, These APIs allow a driver to specify
7258 * the maximum bus stall that they can handle. 0 indicates no limit.
7262 setCPUSnoopDelay(UInt32 __unused ns
)
7264 #if defined(__i386__) || defined(__x86_64__)
7265 ml_set_maxsnoop(ns
);
7266 #endif /* defined(__i386__) || defined(__x86_64__) */
7273 #if defined(__i386__) || defined(__x86_64__)
7274 return ml_get_maxsnoop();
7277 #endif /* defined(__i386__) || defined(__x86_64__) */
7280 #if defined(__i386__) || defined(__x86_64__)
7282 requireMaxCpuDelay(IOService
* service
, UInt32 ns
, UInt32 delayType
)
7284 static const UInt kNoReplace
= -1U; // Must be an illegal index
7285 UInt replace
= kNoReplace
;
7286 bool setCpuDelay
= false;
7288 IORecursiveLockLock(sCpuDelayLock
);
7290 UInt count
= sCpuDelayData
->getLength() / sizeof(CpuDelayEntry
);
7291 CpuDelayEntry
*entries
= (CpuDelayEntry
*) sCpuDelayData
->getBytesNoCopy();
7292 IOService
* holder
= NULL
;
7295 const CpuDelayEntry ne
= {service
, ns
, delayType
};
7297 // Set maximum delay.
7298 for (UInt i
= 0; i
< count
; i
++) {
7299 IOService
*thisService
= entries
[i
].fService
;
7300 bool sameType
= (delayType
== entries
[i
].fDelayType
);
7301 if ((service
== thisService
) && sameType
) {
7303 } else if (!thisService
) {
7304 if (kNoReplace
== replace
) {
7307 } else if (sameType
) {
7308 const UInt32 thisMax
= entries
[i
].fMaxDelay
;
7311 holder
= thisService
;
7317 if (kNoReplace
== replace
) {
7318 sCpuDelayData
->appendBytes(&ne
, sizeof(ne
));
7320 entries
[replace
] = ne
;
7323 ns
= -1U; // Set to max unsigned, i.e. no restriction
7325 for (UInt i
= 0; i
< count
; i
++) {
7326 // Clear a maximum delay.
7327 IOService
*thisService
= entries
[i
].fService
;
7328 if (thisService
&& (delayType
== entries
[i
].fDelayType
)) {
7329 UInt32 thisMax
= entries
[i
].fMaxDelay
;
7330 if (service
== thisService
) {
7332 } else if (thisMax
< ns
) {
7334 holder
= thisService
;
7339 // Check if entry found
7340 if (kNoReplace
!= replace
) {
7341 entries
[replace
].fService
= NULL
; // Null the entry
7347 if (holder
&& debug_boot_arg
) {
7348 strlcpy(sCPULatencyHolderName
[delayType
], holder
->getName(), sizeof(sCPULatencyHolderName
[delayType
]));
7351 // Must be safe to call from locked context
7352 if (delayType
== kCpuDelayBusStall
) {
7353 ml_set_maxbusdelay(ns
);
7354 } else if (delayType
== kCpuDelayInterrupt
) {
7355 ml_set_maxintdelay(ns
);
7357 sCPULatencyHolder
[delayType
]->setValue(holder
? holder
->getRegistryEntryID() : 0);
7358 sCPULatencySet
[delayType
]->setValue(ns
);
7360 OSArray
* handlers
= sCpuLatencyHandlers
[delayType
];
7363 for (unsigned int idx
= 0;
7364 (target
= (IOService
*) handlers
->getObject(idx
));
7366 target
->callPlatformFunction(sCPULatencyFunctionName
[delayType
], false,
7367 (void *) (uintptr_t) ns
, holder
,
7373 IORecursiveLockUnlock(sCpuDelayLock
);
7377 setLatencyHandler(UInt32 delayType
, IOService
* target
, bool enable
)
7379 IOReturn result
= kIOReturnNotFound
;
7383 IORecursiveLockLock(sCpuDelayLock
);
7386 if (enable
&& !sCpuLatencyHandlers
[delayType
]) {
7387 sCpuLatencyHandlers
[delayType
] = OSArray::withCapacity(4);
7389 array
= sCpuLatencyHandlers
[delayType
];
7393 idx
= array
->getNextIndexOfObject(target
, 0);
7396 array
->removeObject(idx
);
7397 result
= kIOReturnSuccess
;
7401 result
= kIOReturnExclusiveAccess
;
7404 array
->setObject(target
);
7406 UInt count
= sCpuDelayData
->getLength() / sizeof(CpuDelayEntry
);
7407 CpuDelayEntry
*entries
= (CpuDelayEntry
*) sCpuDelayData
->getBytesNoCopy();
7408 UInt32 ns
= -1U; // Set to max unsigned, i.e. no restriction
7409 IOService
* holder
= NULL
;
7411 for (UInt i
= 0; i
< count
; i
++) {
7412 if (entries
[i
].fService
7413 && (delayType
== entries
[i
].fDelayType
)
7414 && (entries
[i
].fMaxDelay
< ns
)) {
7415 ns
= entries
[i
].fMaxDelay
;
7416 holder
= entries
[i
].fService
;
7419 target
->callPlatformFunction(sCPULatencyFunctionName
[delayType
], false,
7420 (void *) (uintptr_t) ns
, holder
,
7422 result
= kIOReturnSuccess
;
7426 IORecursiveLockUnlock(sCpuDelayLock
);
7431 #endif /* defined(__i386__) || defined(__x86_64__) */
7435 requireMaxBusStall(UInt32 __unused ns
)
7437 #if defined(__i386__) || defined(__x86_64__)
7438 requireMaxCpuDelay(this, ns
, kCpuDelayBusStall
);
7444 requireMaxInterruptDelay(uint32_t __unused ns
)
7446 #if defined(__i386__) || defined(__x86_64__)
7447 requireMaxCpuDelay(this, ns
, kCpuDelayInterrupt
);
7456 IOService::resolveInterrupt(IOService
*nub
, int source
)
7458 IOInterruptController
*interruptController
;
7461 OSSymbol
*interruptControllerName
;
7463 IOInterruptSource
*interruptSources
;
7465 // Get the parents list from the nub.
7466 array
= OSDynamicCast(OSArray
, nub
->getProperty(gIOInterruptControllersKey
));
7467 if (array
== NULL
) {
7468 return kIOReturnNoResources
;
7471 // Allocate space for the IOInterruptSources if needed... then return early.
7472 if (nub
->_interruptSources
== NULL
) {
7473 numSources
= array
->getCount();
7474 interruptSources
= (IOInterruptSource
*)IOMalloc(
7475 numSources
* sizeofAllIOInterruptSource
);
7476 if (interruptSources
== NULL
) {
7477 return kIOReturnNoMemory
;
7480 bzero(interruptSources
, numSources
* sizeofAllIOInterruptSource
);
7482 nub
->_numInterruptSources
= numSources
;
7483 nub
->_interruptSources
= interruptSources
;
7484 return kIOReturnSuccess
;
7487 interruptControllerName
= OSDynamicCast(OSSymbol
, array
->getObject(source
));
7488 if (interruptControllerName
== NULL
) {
7489 return kIOReturnNoResources
;
7492 interruptController
= getPlatform()->lookUpInterruptController(interruptControllerName
);
7493 if (interruptController
== NULL
) {
7494 return kIOReturnNoResources
;
7497 // Get the interrupt numbers from the nub.
7498 array
= OSDynamicCast(OSArray
, nub
->getProperty(gIOInterruptSpecifiersKey
));
7499 if (array
== NULL
) {
7500 return kIOReturnNoResources
;
7502 data
= OSDynamicCast(OSData
, array
->getObject(source
));
7504 return kIOReturnNoResources
;
7507 // Set the interruptController and interruptSource in the nub's table.
7508 interruptSources
= nub
->_interruptSources
;
7509 interruptSources
[source
].interruptController
= interruptController
;
7510 interruptSources
[source
].vectorData
= data
;
7512 return kIOReturnSuccess
;
7516 IOService::lookupInterrupt(int source
, bool resolve
, IOInterruptController
**interruptController
)
7520 /* Make sure the _interruptSources are set */
7521 if (_interruptSources
== NULL
) {
7522 ret
= resolveInterrupt(this, source
);
7523 if (ret
!= kIOReturnSuccess
) {
7528 /* Make sure the local source number is valid */
7529 if ((source
< 0) || (source
>= _numInterruptSources
)) {
7530 return kIOReturnNoInterrupt
;
7533 /* Look up the contoller for the local source */
7534 *interruptController
= _interruptSources
[source
].interruptController
;
7536 if (*interruptController
== NULL
) {
7538 return kIOReturnNoInterrupt
;
7541 /* Try to resolve the interrupt */
7542 ret
= resolveInterrupt(this, source
);
7543 if (ret
!= kIOReturnSuccess
) {
7547 *interruptController
= _interruptSources
[source
].interruptController
;
7550 return kIOReturnSuccess
;
7554 IOService::registerInterrupt(int source
, OSObject
*target
,
7555 IOInterruptAction handler
,
7558 IOInterruptController
*interruptController
;
7561 ret
= lookupInterrupt(source
, true, &interruptController
);
7562 if (ret
!= kIOReturnSuccess
) {
7566 /* Register the source */
7567 return interruptController
->registerInterrupt(this, source
, target
,
7568 (IOInterruptHandler
)handler
,
7573 IOServiceInterruptActionToBlock( OSObject
* target
, void * refCon
,
7574 IOService
* nub
, int source
)
7576 ((IOInterruptActionBlock
)(refCon
))(nub
, source
);
7580 IOService::registerInterruptBlock(int source
, OSObject
*target
,
7581 IOInterruptActionBlock handler
)
7586 block
= Block_copy(handler
);
7588 return kIOReturnNoMemory
;
7591 ret
= registerInterrupt(source
, target
, &IOServiceInterruptActionToBlock
, block
);
7592 if (kIOReturnSuccess
!= ret
) {
7593 Block_release(block
);
7596 _interruptSourcesPrivate(this)[source
].vectorBlock
= block
;
7602 IOService::unregisterInterrupt(int source
)
7605 IOInterruptController
*interruptController
;
7608 ret
= lookupInterrupt(source
, false, &interruptController
);
7609 if (ret
!= kIOReturnSuccess
) {
7613 /* Unregister the source */
7614 block
= _interruptSourcesPrivate(this)[source
].vectorBlock
;
7615 ret
= interruptController
->unregisterInterrupt(this, source
);
7616 if ((kIOReturnSuccess
== ret
) && (block
= _interruptSourcesPrivate(this)[source
].vectorBlock
)) {
7617 _interruptSourcesPrivate(this)[source
].vectorBlock
= NULL
;
7618 Block_release(block
);
7625 IOService::addInterruptStatistics(IOInterruptAccountingData
* statistics
, int source
)
7627 IOReportLegend
* legend
= NULL
;
7628 IOInterruptAccountingData
* oldValue
= NULL
;
7629 IOInterruptAccountingReporter
* newArray
= NULL
;
7630 char subgroupName
[64];
7631 int newArraySize
= 0;
7635 return kIOReturnBadArgument
;
7639 * We support statistics on a maximum of 256 interrupts per nub; if a nub
7640 * has more than 256 interrupt specifiers associated with it, and tries
7641 * to register a high interrupt index with interrupt accounting, panic.
7642 * Having more than 256 interrupts associated with a single nub is
7643 * probably a sign that something fishy is going on.
7645 if (source
> IA_INDEX_MAX
) {
7646 panic("addInterruptStatistics called for an excessively large index (%d)", source
);
7650 * TODO: This is ugly (wrapping a lock around an allocation). I'm only
7651 * leaving it as is because the likelihood of contention where we are
7652 * actually growing the array is minimal (we would realistically need
7653 * to be starting a driver for the first time, with an IOReporting
7654 * client already in place). Nonetheless, cleanup that can be done
7655 * to adhere to best practices; it'll make the code more complicated,
7658 IOLockLock(reserved
->interruptStatisticsLock
);
7661 * Lazily allocate the statistics array.
7663 if (!reserved
->interruptStatisticsArray
) {
7664 reserved
->interruptStatisticsArray
= IONew(IOInterruptAccountingReporter
, 1);
7665 assert(reserved
->interruptStatisticsArray
);
7666 reserved
->interruptStatisticsArrayCount
= 1;
7667 bzero(reserved
->interruptStatisticsArray
, sizeof(*reserved
->interruptStatisticsArray
));
7670 if (source
>= reserved
->interruptStatisticsArrayCount
) {
7672 * We're still within the range of supported indices, but we are out
7673 * of space in the current array. Do a nasty realloc (because
7674 * IORealloc isn't a thing) here. We'll double the size with each
7677 * Yes, the "next power of 2" could be more efficient; but this will
7678 * be invoked incredibly rarely. Who cares.
7680 newArraySize
= (reserved
->interruptStatisticsArrayCount
<< 1);
7682 while (newArraySize
<= source
) {
7683 newArraySize
= (newArraySize
<< 1);
7685 newArray
= IONew(IOInterruptAccountingReporter
, newArraySize
);
7690 * TODO: This even zeroes the memory it is about to overwrite.
7691 * Shameful; fix it. Not particularly high impact, however.
7693 bzero(newArray
, newArraySize
* sizeof(*newArray
));
7694 memcpy(newArray
, reserved
->interruptStatisticsArray
, reserved
->interruptStatisticsArrayCount
* sizeof(*newArray
));
7695 IODelete(reserved
->interruptStatisticsArray
, IOInterruptAccountingReporter
, reserved
->interruptStatisticsArrayCount
);
7696 reserved
->interruptStatisticsArray
= newArray
;
7697 reserved
->interruptStatisticsArrayCount
= newArraySize
;
7700 if (!reserved
->interruptStatisticsArray
[source
].reporter
) {
7702 * We don't have a reporter associated with this index yet, so we
7703 * need to create one.
7706 * TODO: Some statistics do in fact have common units (time); should this be
7707 * split into separate reporters to communicate this?
7709 reserved
->interruptStatisticsArray
[source
].reporter
= IOSimpleReporter::with(this, kIOReportCategoryPower
, kIOReportUnitNone
);
7712 * Each statistic is given an identifier based on the interrupt index (which
7713 * should be unique relative to any single nub) and the statistic involved.
7714 * We should now have a sane (small and positive) index, so start
7715 * constructing the channels for statistics.
7717 for (i
= 0; i
< IA_NUM_INTERRUPT_ACCOUNTING_STATISTICS
; i
++) {
7719 * TODO: Currently, this does not add channels for disabled statistics.
7720 * Will this be confusing for clients? If so, we should just add the
7721 * channels; we can avoid updating the channels even if they exist.
7723 if (IA_GET_STATISTIC_ENABLED(i
)) {
7724 reserved
->interruptStatisticsArray
[source
].reporter
->addChannel(IA_GET_CHANNEL_ID(source
, i
), kInterruptAccountingStatisticNameArray
[i
]);
7729 * We now need to add the legend for this reporter to the registry.
7731 OSObject
* prop
= copyProperty(kIOReportLegendKey
);
7732 legend
= IOReportLegend::with(OSDynamicCast(OSArray
, prop
));
7733 OSSafeReleaseNULL(prop
);
7736 * Note that while we compose the subgroup name, we do not need to
7737 * manage its lifecycle (the reporter will handle this).
7739 snprintf(subgroupName
, sizeof(subgroupName
), "%s %d", getName(), source
);
7740 subgroupName
[sizeof(subgroupName
) - 1] = 0;
7741 legend
->addReporterLegend(reserved
->interruptStatisticsArray
[source
].reporter
, kInterruptAccountingGroupName
, subgroupName
);
7742 setProperty(kIOReportLegendKey
, legend
->getLegend());
7746 * TODO: Is this a good idea? Probably not; my assumption is it opts
7747 * all entities who register interrupts into public disclosure of all
7748 * IOReporting channels. Unfortunately, this appears to be as fine
7751 setProperty(kIOReportLegendPublicKey
, true);
7755 * Don't stomp existing entries. If we are about to, panic; this
7756 * probably means we failed to tear down our old interrupt source
7759 oldValue
= reserved
->interruptStatisticsArray
[source
].statistics
;
7762 panic("addInterruptStatistics call for index %d would have clobbered existing statistics", source
);
7765 reserved
->interruptStatisticsArray
[source
].statistics
= statistics
;
7768 * Inherit the reporter values for each statistic. The target may
7769 * be torn down as part of the runtime of the service (especially
7770 * for sleep/wake), so we inherit in order to avoid having values
7771 * reset for no apparent reason. Our statistics are ultimately
7772 * tied to the index and the sevice, not to an individual target,
7773 * so we should maintain them accordingly.
7775 interruptAccountingDataInheritChannels(reserved
->interruptStatisticsArray
[source
].statistics
, reserved
->interruptStatisticsArray
[source
].reporter
);
7777 IOLockUnlock(reserved
->interruptStatisticsLock
);
7779 return kIOReturnSuccess
;
7783 IOService::removeInterruptStatistics(int source
)
7785 IOInterruptAccountingData
* value
= NULL
;
7788 return kIOReturnBadArgument
;
7791 IOLockLock(reserved
->interruptStatisticsLock
);
7794 * We dynamically grow the statistics array, so an excessively
7795 * large index value has NEVER been registered. This either
7796 * means our cap on the array size is too small (unlikely), or
7797 * that we have been passed a corrupt index (this must be passed
7798 * the plain index into the interrupt specifier list).
7800 if (source
>= reserved
->interruptStatisticsArrayCount
) {
7801 panic("removeInterruptStatistics called for index %d, which was never registered", source
);
7804 assert(reserved
->interruptStatisticsArray
);
7807 * If there is no existing entry, we are most likely trying to
7808 * free an interrupt owner twice, or we have corrupted the
7811 value
= reserved
->interruptStatisticsArray
[source
].statistics
;
7814 panic("removeInterruptStatistics called for empty index %d", source
);
7818 * We update the statistics, so that any delta with the reporter
7819 * state is not lost.
7821 interruptAccountingDataUpdateChannels(reserved
->interruptStatisticsArray
[source
].statistics
, reserved
->interruptStatisticsArray
[source
].reporter
);
7822 reserved
->interruptStatisticsArray
[source
].statistics
= NULL
;
7823 IOLockUnlock(reserved
->interruptStatisticsLock
);
7825 return kIOReturnSuccess
;
7829 IOService::getInterruptType(int source
, int *interruptType
)
7831 IOInterruptController
*interruptController
;
7834 ret
= lookupInterrupt(source
, true, &interruptController
);
7835 if (ret
!= kIOReturnSuccess
) {
7839 /* Return the type */
7840 return interruptController
->getInterruptType(this, source
, interruptType
);
7844 IOService::enableInterrupt(int source
)
7846 IOInterruptController
*interruptController
;
7849 ret
= lookupInterrupt(source
, false, &interruptController
);
7850 if (ret
!= kIOReturnSuccess
) {
7854 /* Enable the source */
7855 return interruptController
->enableInterrupt(this, source
);
7859 IOService::disableInterrupt(int source
)
7861 IOInterruptController
*interruptController
;
7864 ret
= lookupInterrupt(source
, false, &interruptController
);
7865 if (ret
!= kIOReturnSuccess
) {
7869 /* Disable the source */
7870 return interruptController
->disableInterrupt(this, source
);
7874 IOService::causeInterrupt(int source
)
7876 IOInterruptController
*interruptController
;
7879 ret
= lookupInterrupt(source
, false, &interruptController
);
7880 if (ret
!= kIOReturnSuccess
) {
7884 /* Cause an interrupt for the source */
7885 return interruptController
->causeInterrupt(this, source
);
7889 IOService::configureReport(IOReportChannelList
*channelList
,
7890 IOReportConfigureAction action
,
7896 for (cnt
= 0; cnt
< channelList
->nchannels
; cnt
++) {
7897 if (channelList
->channels
[cnt
].channel_id
== kPMPowerStatesChID
) {
7899 configurePowerStatesReport(action
, result
);
7901 return kIOReturnUnsupported
;
7903 } else if (channelList
->channels
[cnt
].channel_id
== kPMCurrStateChID
) {
7905 configureSimplePowerReport(action
, result
);
7907 return kIOReturnUnsupported
;
7912 IOLockLock(reserved
->interruptStatisticsLock
);
7914 /* The array count is signed (because the interrupt indices are signed), hence the cast */
7915 for (cnt
= 0; cnt
< (unsigned) reserved
->interruptStatisticsArrayCount
; cnt
++) {
7916 if (reserved
->interruptStatisticsArray
[cnt
].reporter
) {
7918 * If the reporter is currently associated with the statistics
7919 * for an event source, we may need to update the reporter.
7921 if (reserved
->interruptStatisticsArray
[cnt
].statistics
) {
7922 interruptAccountingDataUpdateChannels(reserved
->interruptStatisticsArray
[cnt
].statistics
, reserved
->interruptStatisticsArray
[cnt
].reporter
);
7925 reserved
->interruptStatisticsArray
[cnt
].reporter
->configureReport(channelList
, action
, result
, destination
);
7929 IOLockUnlock(reserved
->interruptStatisticsLock
);
7931 return kIOReturnSuccess
;
7935 IOService::updateReport(IOReportChannelList
*channelList
,
7936 IOReportUpdateAction action
,
7942 for (cnt
= 0; cnt
< channelList
->nchannels
; cnt
++) {
7943 if (channelList
->channels
[cnt
].channel_id
== kPMPowerStatesChID
) {
7945 updatePowerStatesReport(action
, result
, destination
);
7947 return kIOReturnUnsupported
;
7949 } else if (channelList
->channels
[cnt
].channel_id
== kPMCurrStateChID
) {
7951 updateSimplePowerReport(action
, result
, destination
);
7953 return kIOReturnUnsupported
;
7958 IOLockLock(reserved
->interruptStatisticsLock
);
7960 /* The array count is signed (because the interrupt indices are signed), hence the cast */
7961 for (cnt
= 0; cnt
< (unsigned) reserved
->interruptStatisticsArrayCount
; cnt
++) {
7962 if (reserved
->interruptStatisticsArray
[cnt
].reporter
) {
7964 * If the reporter is currently associated with the statistics
7965 * for an event source, we need to update the reporter.
7967 if (reserved
->interruptStatisticsArray
[cnt
].statistics
) {
7968 interruptAccountingDataUpdateChannels(reserved
->interruptStatisticsArray
[cnt
].statistics
, reserved
->interruptStatisticsArray
[cnt
].reporter
);
7971 reserved
->interruptStatisticsArray
[cnt
].reporter
->updateReport(channelList
, action
, result
, destination
);
7975 IOLockUnlock(reserved
->interruptStatisticsLock
);
7977 return kIOReturnSuccess
;
7981 IOService::getAuthorizationID( void )
7983 return reserved
->authorizationID
;
7987 IOService::setAuthorizationID( uint64_t authorizationID
)
7989 OSObject
* entitlement
;
7992 entitlement
= IOUserClient::copyClientEntitlement( current_task(), "com.apple.private.iokit.IOServiceSetAuthorizationID" );
7995 if (entitlement
== kOSBooleanTrue
) {
7996 reserved
->authorizationID
= authorizationID
;
7998 status
= kIOReturnSuccess
;
8000 status
= kIOReturnNotPrivileged
;
8003 entitlement
->release();
8005 status
= kIOReturnNotPrivileged
;
8011 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8015 OSMetaClassDefineReservedUsed(IOService
, 0);
8016 OSMetaClassDefineReservedUsed(IOService
, 1);
8017 OSMetaClassDefineReservedUnused(IOService
, 2);
8018 OSMetaClassDefineReservedUnused(IOService
, 3);
8019 OSMetaClassDefineReservedUnused(IOService
, 4);
8020 OSMetaClassDefineReservedUnused(IOService
, 5);
8021 OSMetaClassDefineReservedUnused(IOService
, 6);
8022 OSMetaClassDefineReservedUnused(IOService
, 7);
8024 OSMetaClassDefineReservedUsed(IOService
, 0);
8025 OSMetaClassDefineReservedUsed(IOService
, 1);
8026 OSMetaClassDefineReservedUsed(IOService
, 2);
8027 OSMetaClassDefineReservedUsed(IOService
, 3);
8028 OSMetaClassDefineReservedUsed(IOService
, 4);
8029 OSMetaClassDefineReservedUsed(IOService
, 5);
8030 OSMetaClassDefineReservedUsed(IOService
, 6);
8031 OSMetaClassDefineReservedUsed(IOService
, 7);
8033 OSMetaClassDefineReservedUnused(IOService
, 8);
8034 OSMetaClassDefineReservedUnused(IOService
, 9);
8035 OSMetaClassDefineReservedUnused(IOService
, 10);
8036 OSMetaClassDefineReservedUnused(IOService
, 11);
8037 OSMetaClassDefineReservedUnused(IOService
, 12);
8038 OSMetaClassDefineReservedUnused(IOService
, 13);
8039 OSMetaClassDefineReservedUnused(IOService
, 14);
8040 OSMetaClassDefineReservedUnused(IOService
, 15);
8041 OSMetaClassDefineReservedUnused(IOService
, 16);
8042 OSMetaClassDefineReservedUnused(IOService
, 17);
8043 OSMetaClassDefineReservedUnused(IOService
, 18);
8044 OSMetaClassDefineReservedUnused(IOService
, 19);
8045 OSMetaClassDefineReservedUnused(IOService
, 20);
8046 OSMetaClassDefineReservedUnused(IOService
, 21);
8047 OSMetaClassDefineReservedUnused(IOService
, 22);
8048 OSMetaClassDefineReservedUnused(IOService
, 23);
8049 OSMetaClassDefineReservedUnused(IOService
, 24);
8050 OSMetaClassDefineReservedUnused(IOService
, 25);
8051 OSMetaClassDefineReservedUnused(IOService
, 26);
8052 OSMetaClassDefineReservedUnused(IOService
, 27);
8053 OSMetaClassDefineReservedUnused(IOService
, 28);
8054 OSMetaClassDefineReservedUnused(IOService
, 29);
8055 OSMetaClassDefineReservedUnused(IOService
, 30);
8056 OSMetaClassDefineReservedUnused(IOService
, 31);
8057 OSMetaClassDefineReservedUnused(IOService
, 32);
8058 OSMetaClassDefineReservedUnused(IOService
, 33);
8059 OSMetaClassDefineReservedUnused(IOService
, 34);
8060 OSMetaClassDefineReservedUnused(IOService
, 35);
8061 OSMetaClassDefineReservedUnused(IOService
, 36);
8062 OSMetaClassDefineReservedUnused(IOService
, 37);
8063 OSMetaClassDefineReservedUnused(IOService
, 38);
8064 OSMetaClassDefineReservedUnused(IOService
, 39);
8065 OSMetaClassDefineReservedUnused(IOService
, 40);
8066 OSMetaClassDefineReservedUnused(IOService
, 41);
8067 OSMetaClassDefineReservedUnused(IOService
, 42);
8068 OSMetaClassDefineReservedUnused(IOService
, 43);
8069 OSMetaClassDefineReservedUnused(IOService
, 44);
8070 OSMetaClassDefineReservedUnused(IOService
, 45);
8071 OSMetaClassDefineReservedUnused(IOService
, 46);
8072 OSMetaClassDefineReservedUnused(IOService
, 47);