xref: /xnu-10002.61.3/iokit/Kernel/IOService.cpp (revision 0f4c859e951fba394238ab619495c4e1d54d0f34)
1 /*
2  * Copyright (c) 1998-2021 Apple Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5  *
6  * This file contains Original Code and/or Modifications of Original Code
7  * as defined in and that are subject to the Apple Public Source License
8  * Version 2.0 (the 'License'). You may not use this file except in
9  * compliance with the License. The rights granted to you under the License
10  * may not be used to create, or enable the creation or redistribution of,
11  * unlawful or unlicensed copies of an Apple operating system, or to
12  * circumvent, violate, or enable the circumvention or violation of, any
13  * terms of an Apple operating system software license agreement.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
18  * The Original Code and all software distributed under the License are
19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23  * Please see the License for the specific language governing rights and
24  * limitations under the License.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 
29 #include <IOKit/system.h>
30 #include <IOKit/IOService.h>
31 #include <libkern/OSDebug.h>
32 #include <libkern/c++/OSAllocation.h>
33 #include <libkern/c++/OSContainers.h>
34 #include <libkern/c++/OSKext.h>
35 #include <libkern/c++/OSUnserialize.h>
36 #include <libkern/c++/OSKext.h>
37 #include <libkern/c++/OSSharedPtr.h>
38 #include <libkern/Block.h>
39 #include <IOKit/IOCatalogue.h>
40 #include <IOKit/IOCommand.h>
41 #include <IOKit/IODeviceTreeSupport.h>
42 #include <IOKit/IODeviceMemory.h>
43 #include <IOKit/IOInterrupts.h>
44 #include <IOKit/IOInterruptController.h>
45 #include <IOKit/IOPlatformExpert.h>
46 #include <IOKit/IOMessage.h>
47 #include <IOKit/IOLib.h>
48 #include <IOKit/IOKitKeysPrivate.h>
49 #include <IOKit/IOBSD.h>
50 #include <IOKit/IOUserClient.h>
51 #include <IOKit/IOUserServer.h>
52 #include <IOKit/IOWorkLoop.h>
53 #include <IOKit/IOTimeStamp.h>
54 #include <IOKit/IOHibernatePrivate.h>
55 #include <IOKit/IOInterruptAccountingPrivate.h>
56 #include <IOKit/IOKernelReporters.h>
57 #include <IOKit/AppleKeyStoreInterface.h>
58 #include <IOKit/pwr_mgt/RootDomain.h>
59 #include <IOKit/IOCPU.h>
60 #include <Exclaves/Exclaves.h>
61 #include <kern/cs_blobs.h>
62 #include <mach/sync_policy.h>
63 #include <mach/thread_info.h>
64 #include <IOKit/assert.h>
65 #include <sys/errno.h>
66 #include <sys/kdebug.h>
67 #include <string.h>
68 
69 #include <machine/pal_routines.h>
70 
71 #define LOG kprintf
72 //#define LOG IOLog
73 #define MATCH_DEBUG     0
74 #define IOSERVICE_OBFUSCATE(x) ((void *)(VM_KERNEL_ADDRPERM(x)))
75 
76 // disabled since lockForArbitration() can be held externally
77 #define DEBUG_NOTIFIER_LOCKED   0
78 
79 enum{
80 	kIOUserServerCheckInTimeoutSecs = 120ULL
81 };
82 
83 #include "IOServicePrivate.h"
84 #include "IOKitKernelInternal.h"
85 
86 // take lockForArbitration before LOCKNOTIFY
87 
88 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
89 
90 #define super IORegistryEntry
91 
92 OSDefineMetaClassAndStructors(IOService, IORegistryEntry)
93 
94 OSDefineMetaClassAndStructors(_IOServiceNotifier, IONotifier)
95 OSDefineMetaClassAndStructors(_IOServiceNullNotifier, IONotifier)
96 
97 OSDefineMetaClassAndStructors(_IOServiceInterestNotifier, IONotifier)
98 
99 OSDefineMetaClassAndStructors(_IOConfigThread, OSObject)
100 
101 OSDefineMetaClassAndStructors(_IOServiceJob, OSObject)
102 
103 OSDefineMetaClassAndStructors(IOResources, IOService)
104 OSDefineMetaClassAndStructors(IOUserResources, IOService)
105 OSDefineMetaClassAndStructors(IOExclaveProxy, IOService)
106 
107 OSDefineMetaClassAndStructors(_IOOpenServiceIterator, OSIterator)
108 
109 OSDefineMetaClassAndStructors(_IOServiceStateNotification, IOService)
110 
111 OSDefineMetaClassAndAbstractStructors(IONotifier, OSObject)
112 
113 OSDefineMetaClassAndStructors(IOServiceCompatibility, IOService)
114 
115 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
116 
117 static IOPlatformExpert *       gIOPlatform;
118 static class IOPMrootDomain *   gIOPMRootDomain;
119 const IORegistryPlane *         gIOServicePlane;
120 const IORegistryPlane *         gIOPowerPlane;
121 const OSSymbol *                gIODeviceMemoryKey;
122 const OSSymbol *                gIOInterruptControllersKey;
123 const OSSymbol *                gIOInterruptSpecifiersKey;
124 
125 const OSSymbol *                gIOResourcesKey;
126 const OSSymbol *                gIOUserResourcesKey;
127 const OSSymbol *                gIOResourceMatchKey;
128 const OSSymbol *                gIOResourceMatchedKey;
129 const OSSymbol *                gIOResourceIOKitKey;
130 
131 const OSSymbol *                gIOProviderClassKey;
132 const OSSymbol *                gIONameMatchKey;
133 const OSSymbol *                gIONameMatchedKey;
134 const OSSymbol *                gIOPropertyMatchKey;
135 const OSSymbol *                gIOPropertyExistsMatchKey;
136 const OSSymbol *                gIOLocationMatchKey;
137 const OSSymbol *                gIOParentMatchKey;
138 const OSSymbol *                gIOPathMatchKey;
139 const OSSymbol *                gIOMatchCategoryKey;
140 const OSSymbol *                gIODefaultMatchCategoryKey;
141 const OSSymbol *                gIOMatchedAtBootKey;
142 const OSSymbol *                gIOMatchedServiceCountKey;
143 const OSSymbol *                gIOMatchedPersonalityKey;
144 const OSSymbol *                gIORematchPersonalityKey;
145 const OSSymbol *                gIORematchCountKey;
146 const OSSymbol *                gIODEXTMatchCountKey;
147 const OSSymbol *                gIOSupportedPropertiesKey;
148 const OSSymbol *                gIOUserServicePropertiesKey;
149 #if defined(XNU_TARGET_OS_OSX)
150 const OSSymbol *                gIOServiceLegacyMatchingRegistryIDKey;
151 #endif /* defined(XNU_TARGET_OS_OSX) */
152 
153 const OSSymbol *                gIOCompatibilityMatchKey;
154 const OSSymbol *                gIOCompatibilityPropertiesKey;
155 const OSSymbol *                gIOPathKey;
156 
157 const OSSymbol *                gIOMapperIDKey;
158 const OSSymbol *                gIOUserClientClassKey;
159 
160 const OSSymbol *                gIOUserClassKey;
161 const OSSymbol *                gIOUserClassesKey;
162 const OSSymbol *                gIOUserServerClassKey;
163 const OSSymbol *                gIOUserServerNameKey;
164 const OSSymbol *                gIOUserServerTagKey;
165 const OSSymbol *                gIOUserUserClientKey;
166 const OSSymbol *                gIOUserServerOneProcessKey;
167 const OSSymbol *                gIOUserServerPreserveUserspaceRebootKey;
168 
169 const OSSymbol *                gIOKitDebugKey;
170 
171 const OSSymbol *                gIOCommandPoolSizeKey;
172 
173 const OSSymbol *                gIOConsoleLockedKey;
174 const OSSymbol *                gIOConsoleUsersKey;
175 const OSSymbol *                gIOConsoleSessionUIDKey;
176 const OSSymbol *                gIOConsoleSessionAuditIDKey;
177 const OSSymbol *                gIOConsoleUsersSeedKey;
178 const OSSymbol *                gIOConsoleSessionOnConsoleKey;
179 const OSSymbol *                gIOConsoleSessionLoginDoneKey;
180 const OSSymbol *                gIOConsoleSessionSecureInputPIDKey;
181 const OSSymbol *                gIOConsoleSessionScreenLockedTimeKey;
182 const OSSymbol *                gIOConsoleSessionScreenIsLockedKey;
183 clock_sec_t                     gIOConsoleLockTime;
184 static bool                     gIOConsoleLoggedIn;
185 #if HIBERNATION
186 static OSBoolean *              gIOConsoleBooterLockState;
187 static uint32_t                 gIOScreenLockState;
188 #endif
189 static IORegistryEntry *        gIOChosenEntry;
190 
191 static int                      gIOResourceGenerationCount;
192 
193 const OSSymbol *                gIOServiceKey;
194 const OSSymbol *                gIOPublishNotification;
195 const OSSymbol *                gIOFirstPublishNotification;
196 const OSSymbol *                gIOMatchedNotification;
197 const OSSymbol *                gIOFirstMatchNotification;
198 const OSSymbol *                gIOTerminatedNotification;
199 const OSSymbol *                gIOWillTerminateNotification;
200 
201 const OSSymbol *                gIOUserClientEntitlementsKey;
202 const OSSymbol *                gIOServiceDEXTEntitlementsKey;
203 const OSSymbol *                gIODriverKitEntitlementKey;
204 const OSSymbol *                gIODriverKitUserClientEntitlementsKey;
205 const OSSymbol *                gIODriverKitUserClientEntitlementAllowAnyKey;
206 const OSSymbol *                gIODriverKitRequiredEntitlementsKey;
207 const OSSymbol *                gIODriverKitTestDriverEntitlementKey;
208 const OSSymbol *                gIODriverKitUserClientEntitlementCommunicatesWithDriversKey;
209 const OSSymbol *                gIODriverKitUserClientEntitlementAllowThirdPartyUserClientsKey;
210 const OSSymbol *                gIOMatchDeferKey;
211 const OSSymbol *                gIOServiceMatchDeferredKey;
212 const OSSymbol *                gIOServiceNotificationUserKey;
213 
214 const OSSymbol *                gIOExclaveAssignedKey;
215 const OSSymbol *                gIOExclaveProxyKey;
216 
217 const OSSymbol *                gIOPrimaryDriverTerminateOptionsKey;
218 const OSSymbol *                gIOMediaKey;
219 const OSSymbol *                gIOBlockStorageDriverKey;
220 static const OSSymbol *         gPhysicalInterconnectKey;
221 static const OSSymbol *         gVirtualInterfaceKey;
222 
223 const OSSymbol *                gIOAllCPUInitializedKey;
224 
225 const OSSymbol *                gIOGeneralInterest;
226 const OSSymbol *                gIOBusyInterest;
227 const OSSymbol *                gIOAppPowerStateInterest;
228 const OSSymbol *                gIOPriorityPowerStateInterest;
229 const OSSymbol *                gIOConsoleSecurityInterest;
230 
231 const OSSymbol *                gIOBSDKey;
232 const OSSymbol *                gIOBSDNameKey;
233 const OSSymbol *                gIOBSDMajorKey;
234 const OSSymbol *                gIOBSDMinorKey;
235 const OSSymbol *                gIOBSDUnitKey;
236 
237 const  OSSymbol *               gAKSGetKey;
238 #if defined(__i386__) || defined(__x86_64__)
239 const OSSymbol *                gIOCreateEFIDevicePathSymbol;
240 #endif
241 
242 static OSDictionary *           gNotifications;
243 static IORecursiveLock *        gNotificationLock;
244 
245 static IOService *              gIOResources;
246 static IOService *              gIOUserResources;
247 static IOService *              gIOServiceRoot;
248 
249 static OSOrderedSet *           gJobs;
250 static semaphore_port_t         gJobsSemaphore;
251 static IOLock *                 gJobsLock;
252 static int                      gOutstandingJobs;
253 static int                      gNumConfigThreads;
254 static int                      gHighNumConfigThreads;
255 static int                      gMaxConfigThreads = kMaxConfigThreads;
256 static int                      gNumWaitingThreads;
257 static IOLock *                 gIOServiceBusyLock;
258 bool                            gCPUsRunning;
259 bool                            gIOKitWillTerminate;
260 bool                            gInUserspaceReboot;
261 
262 #define kIOServiceRootMediaParentInvalid ((IOService *) -1UL)
263 #if NO_KEXTD
264 static bool                     gIOServiceHideIOMedia = false;
265 static IOService *              gIOServiceRootMediaParent = NULL;
266 #else /* NO_KEXTD */
267 static bool                     gIOServiceHideIOMedia = true;
268 static IOService *              gIOServiceRootMediaParent = kIOServiceRootMediaParentInvalid;
269 #endif /* !NO_KEXTD */
270 
271 static thread_t                 gIOTerminateThread;
272 static thread_t                 gIOTerminateWorkerThread;
273 static UInt32                   gIOTerminateWork;
274 static OSArray *                gIOTerminatePhase2List;
275 static OSArray *                gIOStopList;
276 static OSArray *                gIOStopProviderList;
277 static OSArray *                gIOFinalizeList;
278 
279 #if !NO_KEXTD
280 static OSArray *                gIOMatchDeferList;
281 #endif
282 
283 static SInt32                   gIOConsoleUsersSeed;
284 static OSData *                 gIOConsoleUsersSeedValue;
285 
286 extern const OSSymbol *         gIODTPHandleKey;
287 
288 const OSSymbol *                gIOPlatformFunctionHandlerSet;
289 
290 
291 static IOLock *                 gIOConsoleUsersLock;
292 static thread_call_t            gIOConsoleLockCallout;
293 static IONotifier *             gIOServiceNullNotifier;
294 
295 static uint32_t                 gIODextRelaunchMax = 1000;
296 
297 #if DEVELOPMENT || DEBUG
298 uint64_t                        driverkit_checkin_timed_out = 0;
299 #endif
300 
301 IORecursiveLock               * gDriverKitLaunchLock;
302 OSSet                         * gDriverKitLaunches;
303 const OSSymbol                * gIOAssociatedServicesKey;
304 
305 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
306 
307 #define LOCKREADNOTIFY()        \
308     IORecursiveLockLock( gNotificationLock )
309 #define LOCKWRITENOTIFY()       \
310     IORecursiveLockLock( gNotificationLock )
311 #define LOCKWRITE2READNOTIFY()
312 #define UNLOCKNOTIFY()          \
313     IORecursiveLockUnlock( gNotificationLock )
314 #define SLEEPNOTIFY(event) \
315     IORecursiveLockSleep( gNotificationLock, (void *)(event), THREAD_UNINT )
316 #define SLEEPNOTIFYTO(event, deadline) \
317     IORecursiveLockSleepDeadline( gNotificationLock, (void *)(event), deadline, THREAD_UNINT )
318 #define WAKEUPNOTIFY(event) \
319 	IORecursiveLockWakeup( gNotificationLock, (void *)(event), /* wake one */ false )
320 
321 #define randomDelay()   \
322 	int del = read_processor_clock();                               \
323 	del = (((int)IOThreadSelf()) ^ del ^ (del >> 10)) & 0x3ff;      \
324 	IOSleep( del );
325 
326 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
327 
328 #define queue_element(entry, element, type, field) do { \
329 	vm_address_t __ele = (vm_address_t) (entry);    \
330 	__ele -= -4 + ((size_t)(&((type) 4)->field));   \
331 	(element) = (type) __ele;                       \
332     } while(0)
333 
334 #define iterqueue(que, elt)                             \
335 	for (queue_entry_t elt = queue_first(que);      \
336 	     !queue_end(que, elt);                      \
337 	     elt = queue_next(elt))
338 
339 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
340 
341 struct IOInterruptAccountingReporter {
342 	IOSimpleReporter * reporter; /* Reporter responsible for communicating the statistics */
343 	IOInterruptAccountingData * statistics; /* The live statistics values, if any */
344 };
345 
346 struct ArbitrationLockQueueElement {
347 	queue_chain_t link;
348 	IOThread      thread;
349 	IOService *   service;
350 	unsigned      count;
351 	bool          required;
352 	bool          aborted;
353 };
354 
355 static queue_head_t gArbitrationLockQueueActive;
356 static queue_head_t gArbitrationLockQueueWaiting;
357 static queue_head_t gArbitrationLockQueueFree;
358 static IOLock *     gArbitrationLockQueueLock;
359 
360 bool
isInactive(void) const361 IOService::isInactive( void ) const
362 {
363 	return 0 != (kIOServiceInactiveState & getState());
364 }
365 
366 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
367 
368 // Only used by the intel implementation of
369 //     IOService::requireMaxBusStall(UInt32 ns)
370 //     IOService::requireMaxInterruptDelay(uint32_t ns)
371 struct CpuDelayEntry {
372 	IOService * fService;
373 	UInt32      fMaxDelay;
374 	UInt32      fDelayType;
375 };
376 
377 enum {
378 	kCpuDelayBusStall,
379 #if defined(__x86_64__)
380 	kCpuDelayInterrupt,
381 #endif /* defined(__x86_64__) */
382 	kCpuNumDelayTypes
383 };
384 
385 static OSData          *sCpuDelayData = OSData::withCapacity(8 * sizeof(CpuDelayEntry));
386 static IORecursiveLock *sCpuDelayLock = IORecursiveLockAlloc();
387 static OSArray         *sCpuLatencyHandlers[kCpuNumDelayTypes];
388 const OSSymbol         *sCPULatencyFunctionName[kCpuNumDelayTypes];
389 static OSNumber * sCPULatencyHolder[kCpuNumDelayTypes];
390 static char sCPULatencyHolderName[kCpuNumDelayTypes][128];
391 static OSNumber * sCPULatencySet[kCpuNumDelayTypes];
392 
393 static void
394 requireMaxCpuDelay(IOService * service, UInt32 ns, UInt32 delayType);
395 static IOReturn
396 setLatencyHandler(UInt32 delayType, IOService * target, bool enable);
397 
398 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
399 
400 IOCoreAnalyticsSendEventProc gIOCoreAnalyticsSendEventProc;
401 
402 kern_return_t
IOSetCoreAnalyticsSendEventProc(IOCoreAnalyticsSendEventProc proc)403 IOSetCoreAnalyticsSendEventProc(IOCoreAnalyticsSendEventProc proc)
404 {
405 	if (gIOCoreAnalyticsSendEventProc) {
406 		return kIOReturnNotPermitted;
407 	}
408 	gIOCoreAnalyticsSendEventProc = proc;
409 
410 	return kIOReturnSuccess;
411 }
412 
413 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
414 
415 
416 static IOMessage  sSystemPower;
417 
418 namespace IOServicePH
419 {
420 IONotifier          * fRootNotifier;
421 OSArray             * fUserServers;
422 OSArray             * fUserServersWait;
423 OSArray             * fMatchingWork;
424 OSArray             * fMatchingDelayed;
425 IOService           * fSystemPowerAckTo;
426 uint32_t              fSystemPowerAckRef;
427 uint8_t               fSystemOff;
428 uint8_t               fUserServerOff;
429 uint8_t               fWaitingUserServers;
430 thread_call_t         fUserServerAckTimer;
431 
432 void lock();
433 void unlock();
434 
435 void init(IOPMrootDomain * root);
436 
437 IOReturn systemPowerChange(
438 	void * target,
439 	void * refCon,
440 	UInt32 messageType, IOService * service,
441 	void * messageArgument, vm_size_t argSize);
442 
443 bool matchingStart(IOService * service);
444 void matchingEnd(IOService * service);
445 void userServerAckTimerExpired(void *, void *);
446 };
447 
448 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
449 
450 void
initialize(void)451 IOService::initialize( void )
452 {
453 	kern_return_t       err;
454 
455 	gIOServicePlane     = IORegistryEntry::makePlane( kIOServicePlane );
456 	gIOPowerPlane       = IORegistryEntry::makePlane( kIOPowerPlane );
457 
458 	gIOProviderClassKey = OSSymbol::withCStringNoCopy( kIOProviderClassKey );
459 	gIONameMatchKey     = OSSymbol::withCStringNoCopy( kIONameMatchKey );
460 	gIONameMatchedKey   = OSSymbol::withCStringNoCopy( kIONameMatchedKey );
461 	gIOPropertyMatchKey = OSSymbol::withCStringNoCopy( kIOPropertyMatchKey );
462 	gIOPropertyExistsMatchKey = OSSymbol::withCStringNoCopy( kIOPropertyExistsMatchKey );
463 	gIOPathMatchKey     = OSSymbol::withCStringNoCopy( kIOPathMatchKey );
464 	gIOLocationMatchKey = OSSymbol::withCStringNoCopy( kIOLocationMatchKey );
465 	gIOParentMatchKey   = OSSymbol::withCStringNoCopy( kIOParentMatchKey );
466 
467 	gIOMatchCategoryKey = OSSymbol::withCStringNoCopy( kIOMatchCategoryKey );
468 	gIODefaultMatchCategoryKey  = OSSymbol::withCStringNoCopy(
469 		kIODefaultMatchCategoryKey );
470 	gIOMatchedAtBootKey  = OSSymbol::withCStringNoCopy(
471 		kIOMatchedAtBootKey );
472 
473 	gIOMatchedServiceCountKey   = OSSymbol::withCStringNoCopy(
474 		kIOMatchedServiceCountKey );
475 	gIOMatchedPersonalityKey = OSSymbol::withCStringNoCopy(
476 		kIOMatchedPersonalityKey );
477 	gIORematchPersonalityKey = OSSymbol::withCStringNoCopy(
478 		kIORematchPersonalityKey );
479 	gIORematchCountKey = OSSymbol::withCStringNoCopy(
480 		kIORematchCountKey );
481 	gIODEXTMatchCountKey = OSSymbol::withCStringNoCopy(
482 		kIODEXTMatchCountKey );
483 
484 #if defined(XNU_TARGET_OS_OSX)
485 	gIOServiceLegacyMatchingRegistryIDKey = OSSymbol::withCStringNoCopy(
486 		kIOServiceLegacyMatchingRegistryIDKey );
487 #endif /* defined(XNU_TARGET_OS_OSX) */
488 
489 	PE_parse_boot_argn("dextrelaunch", &gIODextRelaunchMax, sizeof(gIODextRelaunchMax));
490 	PE_parse_boot_argn("iocthreads", &gMaxConfigThreads, sizeof(gMaxConfigThreads));
491 
492 	gIOUserClientClassKey = OSSymbol::withCStringNoCopy( kIOUserClientClassKey );
493 
494 	gIOUserClassKey       = OSSymbol::withCStringNoCopy(kIOUserClassKey);
495 	gIOUserClassesKey     = OSSymbol::withCStringNoCopy(kIOUserClassesKey);
496 
497 	gIOUserServerClassKey  = OSSymbol::withCStringNoCopy(kIOUserServerClassKey);
498 	gIOUserServerNameKey   = OSSymbol::withCStringNoCopy(kIOUserServerNameKey);
499 	gIOUserServerTagKey    = OSSymbol::withCStringNoCopy(kIOUserServerTagKey);
500 	gIOUserUserClientKey   = OSSymbol::withCStringNoCopy(kIOUserUserClientKey);
501 
502 	gIOUserServerOneProcessKey = OSSymbol::withCStringNoCopy(kIOUserServerOneProcessKey);
503 	gIOUserServerPreserveUserspaceRebootKey = OSSymbol::withCStringNoCopy(kIOUserServerPreserveUserspaceRebootKey);
504 
505 	gIOResourcesKey       = OSSymbol::withCStringNoCopy( kIOResourcesClass );
506 	gIOResourceMatchKey   = OSSymbol::withCStringNoCopy( kIOResourceMatchKey );
507 	gIOResourceMatchedKey = OSSymbol::withCStringNoCopy( kIOResourceMatchedKey );
508 	gIOResourceIOKitKey   = OSSymbol::withCStringNoCopy("IOKit");
509 
510 	gIODeviceMemoryKey  = OSSymbol::withCStringNoCopy( "IODeviceMemory" );
511 	gIOInterruptControllersKey
512 	        = OSSymbol::withCStringNoCopy("IOInterruptControllers");
513 	gIOInterruptSpecifiersKey
514 	        = OSSymbol::withCStringNoCopy("IOInterruptSpecifiers");
515 
516 	gIOCompatibilityMatchKey = OSSymbol::withCStringNoCopy(kIOCompatibilityMatchKey);
517 	gIOCompatibilityPropertiesKey = OSSymbol::withCStringNoCopy(kIOCompatibilityPropertiesKey);
518 	gIOPathKey = OSSymbol::withCStringNoCopy(kIOPathKey);
519 	gIOSupportedPropertiesKey = OSSymbol::withCStringNoCopy(kIOSupportedPropertiesKey);
520 	gIOUserServicePropertiesKey = OSSymbol::withCStringNoCopy(kIOUserServicePropertiesKey);
521 
522 	gIOMapperIDKey = OSSymbol::withCStringNoCopy(kIOMapperIDKey);
523 
524 	gIOKitDebugKey      = OSSymbol::withCStringNoCopy( kIOKitDebugKey );
525 
526 	gIOCommandPoolSizeKey       = OSSymbol::withCStringNoCopy( kIOCommandPoolSizeKey );
527 
528 	gIOGeneralInterest          = OSSymbol::withCStringNoCopy( kIOGeneralInterest );
529 	gIOBusyInterest             = OSSymbol::withCStringNoCopy( kIOBusyInterest );
530 	gIOAppPowerStateInterest    = OSSymbol::withCStringNoCopy( kIOAppPowerStateInterest );
531 	gIOPriorityPowerStateInterest       = OSSymbol::withCStringNoCopy( kIOPriorityPowerStateInterest );
532 	gIOConsoleSecurityInterest  = OSSymbol::withCStringNoCopy( kIOConsoleSecurityInterest );
533 
534 	gIOBSDKey      = OSSymbol::withCStringNoCopy(kIOBSDKey);
535 	gIOBSDNameKey  = OSSymbol::withCStringNoCopy(kIOBSDNameKey);
536 	gIOBSDMajorKey = OSSymbol::withCStringNoCopy(kIOBSDMajorKey);
537 	gIOBSDMinorKey = OSSymbol::withCStringNoCopy(kIOBSDMinorKey);
538 	gIOBSDUnitKey  = OSSymbol::withCStringNoCopy(kIOBSDUnitKey);
539 
540 	gNotifications              = OSDictionary::withCapacity( 1 );
541 	gIOPublishNotification      = OSSymbol::withCStringNoCopy(
542 		kIOPublishNotification );
543 	gIOFirstPublishNotification = OSSymbol::withCStringNoCopy(
544 		kIOFirstPublishNotification );
545 	gIOMatchedNotification      = OSSymbol::withCStringNoCopy(
546 		kIOMatchedNotification );
547 	gIOFirstMatchNotification   = OSSymbol::withCStringNoCopy(
548 		kIOFirstMatchNotification );
549 	gIOTerminatedNotification   = OSSymbol::withCStringNoCopy(
550 		kIOTerminatedNotification );
551 	gIOWillTerminateNotification = OSSymbol::withCStringNoCopy(
552 		kIOWillTerminateNotification );
553 	gIOServiceKey               = OSSymbol::withCStringNoCopy( kIOServiceClass);
554 
555 
556 	gIOConsoleLockedKey         = OSSymbol::withCStringNoCopy( kIOConsoleLockedKey);
557 	gIOConsoleUsersKey          = OSSymbol::withCStringNoCopy( kIOConsoleUsersKey);
558 	gIOConsoleSessionUIDKey     = OSSymbol::withCStringNoCopy( kIOConsoleSessionUIDKey);
559 	gIOConsoleSessionAuditIDKey = OSSymbol::withCStringNoCopy( kIOConsoleSessionAuditIDKey);
560 
561 	gIOConsoleUsersSeedKey               = OSSymbol::withCStringNoCopy(kIOConsoleUsersSeedKey);
562 	gIOConsoleSessionOnConsoleKey        = OSSymbol::withCStringNoCopy(kIOConsoleSessionOnConsoleKey);
563 	gIOConsoleSessionLoginDoneKey        = OSSymbol::withCStringNoCopy(kIOConsoleSessionLoginDoneKey);
564 	gIOConsoleSessionSecureInputPIDKey   = OSSymbol::withCStringNoCopy(kIOConsoleSessionSecureInputPIDKey);
565 	gIOConsoleSessionScreenLockedTimeKey = OSSymbol::withCStringNoCopy(kIOConsoleSessionScreenLockedTimeKey);
566 	gIOConsoleSessionScreenIsLockedKey   = OSSymbol::withCStringNoCopy(kIOConsoleSessionScreenIsLockedKey);
567 
568 	gIOConsoleUsersSeedValue           = OSData::withValueNoCopy(gIOConsoleUsersSeed);
569 
570 	gIOUserClientEntitlementsKey           = OSSymbol::withCStringNoCopy( kIOUserClientEntitlementsKey );
571 	gIOServiceDEXTEntitlementsKey           = OSSymbol::withCStringNoCopy( kIOServiceDEXTEntitlementsKey );
572 	gIODriverKitEntitlementKey             = OSSymbol::withCStringNoCopy( kIODriverKitEntitlementKey );
573 	gIODriverKitUserClientEntitlementsKey   = OSSymbol::withCStringNoCopy( kIODriverKitUserClientEntitlementsKey );
574 #if XNU_TARGET_OS_OSX
575 	gIODriverKitUserClientEntitlementAllowAnyKey   = OSSymbol::withCStringNoCopy( kIODriverKitUserClientEntitlementAllowAnyKey );
576 #else
577 	gIODriverKitUserClientEntitlementAllowAnyKey   = NULL;
578 #endif
579 	gIODriverKitRequiredEntitlementsKey   = OSSymbol::withCStringNoCopy( kIODriverKitRequiredEntitlementsKey );
580 	gIODriverKitTestDriverEntitlementKey  = OSSymbol::withCStringNoCopy( kIODriverKitTestDriverEntitlementKey );
581 	gIODriverKitUserClientEntitlementCommunicatesWithDriversKey = OSSymbol::withCStringNoCopy(kIODriverKitUserClientEntitlementCommunicatesWithDriversKey);
582 	gIODriverKitUserClientEntitlementAllowThirdPartyUserClientsKey = OSSymbol::withCStringNoCopy(kIODriverKitUserClientEntitlementAllowThirdPartyUserClientsKey);
583 
584 	gIOMatchDeferKey                    = OSSymbol::withCStringNoCopy( kIOMatchDeferKey );
585 	gIOServiceMatchDeferredKey          = OSSymbol::withCStringNoCopy( kIOServiceMatchDeferredKey );
586 	gIOServiceNotificationUserKey       = OSSymbol::withCStringNoCopy( kIOServiceNotificationUserKey );
587 	gIOExclaveAssignedKey               = OSSymbol::withCStringNoCopy(kIOExclaveAssignedKey);
588 	gIOExclaveProxyKey                  = OSSymbol::withCStringNoCopy(kIOExclaveProxyKey);
589 
590 	gIOPrimaryDriverTerminateOptionsKey = OSSymbol::withCStringNoCopy(kIOPrimaryDriverTerminateOptionsKey);
591 	gIOMediaKey                         = OSSymbol::withCStringNoCopy("IOMedia");
592 	gIOBlockStorageDriverKey            = OSSymbol::withCStringNoCopy("IOBlockStorageDriver");
593 	gPhysicalInterconnectKey            = OSSymbol::withCStringNoCopy("Physical Interconnect");
594 	gVirtualInterfaceKey                = OSSymbol::withCStringNoCopy("Virtual Interface");
595 
596 	gIOAllCPUInitializedKey                 = OSSymbol::withCStringNoCopy( kIOAllCPUInitializedKey );
597 
598 	gIOPlatformFunctionHandlerSet               = OSSymbol::withCStringNoCopy(kIOPlatformFunctionHandlerSet);
599 	sCPULatencyFunctionName[kCpuDelayBusStall]  = OSSymbol::withCStringNoCopy(kIOPlatformFunctionHandlerMaxBusDelay);
600 #if defined(__x86_64__)
601 	sCPULatencyFunctionName[kCpuDelayInterrupt] = OSSymbol::withCStringNoCopy(kIOPlatformFunctionHandlerMaxInterruptDelay);
602 #endif /* defined(__x86_64__) */
603 	uint32_t  idx;
604 	for (idx = 0; idx < kCpuNumDelayTypes; idx++) {
605 		sCPULatencySet[idx]    = OSNumber::withNumber(UINT_MAX, 32);
606 		sCPULatencyHolder[idx] = OSNumber::withNumber(0ULL, 64);
607 		assert(sCPULatencySet[idx] && sCPULatencyHolder[idx]);
608 	}
609 
610 #if defined(__x86_64__)
611 	gIOCreateEFIDevicePathSymbol = OSSymbol::withCString("CreateEFIDevicePath");
612 #endif /* defined(__x86_64__) */
613 
614 	gNotificationLock           = IORecursiveLockAlloc();
615 
616 	gAKSGetKey                   = OSSymbol::withCStringNoCopy(AKS_PLATFORM_FUNCTION_GETKEY);
617 
618 
619 	assert( gIOServicePlane && gIODeviceMemoryKey
620 	    && gIOInterruptControllersKey && gIOInterruptSpecifiersKey
621 	    && gIOResourcesKey && gNotifications && gNotificationLock
622 	    && gIOProviderClassKey && gIONameMatchKey && gIONameMatchedKey
623 	    && gIOMatchCategoryKey && gIODefaultMatchCategoryKey
624 	    && gIOPublishNotification && gIOMatchedNotification
625 	    && gIOTerminatedNotification && gIOServiceKey
626 	    && gIOConsoleUsersKey && gIOConsoleSessionUIDKey
627 	    && gIOConsoleSessionOnConsoleKey && gIOConsoleSessionSecureInputPIDKey
628 	    && gIOConsoleUsersSeedKey && gIOConsoleUsersSeedValue);
629 
630 	gJobsLock   = IOLockAlloc();
631 	gJobs       = OSOrderedSet::withCapacity( 10 );
632 
633 	gIOServiceBusyLock = IOLockAlloc();
634 
635 	gIOConsoleUsersLock = IOLockAlloc();
636 
637 	err = semaphore_create(kernel_task, &gJobsSemaphore, SYNC_POLICY_FIFO, 0);
638 
639 	gIOConsoleLockCallout = thread_call_allocate(&IOService::consoleLockTimer, NULL);
640 
641 	IORegistryEntry::getRegistryRoot()->setProperty(gIOConsoleLockedKey, kOSBooleanTrue);
642 
643 	assert( gIOServiceBusyLock && gJobs && gJobsLock && gIOConsoleUsersLock
644 	    && gIOConsoleLockCallout && (err == KERN_SUCCESS));
645 
646 	gIOResources = IOResources::resources();
647 	gIOUserResources = IOUserResources::resources();
648 	assert( gIOResources && gIOUserResources );
649 
650 	gIOServiceNullNotifier = OSTypeAlloc(_IOServiceNullNotifier);
651 	assert(gIOServiceNullNotifier);
652 
653 	gArbitrationLockQueueLock = IOLockAlloc();
654 	queue_init(&gArbitrationLockQueueActive);
655 	queue_init(&gArbitrationLockQueueWaiting);
656 	queue_init(&gArbitrationLockQueueFree);
657 
658 	assert( gArbitrationLockQueueLock );
659 
660 	allocPMInitLock();
661 
662 	gIOTerminatePhase2List = OSArray::withCapacity( 2 );
663 	gIOStopList            = OSArray::withCapacity( 16 );
664 	gIOStopProviderList    = OSArray::withCapacity( 16 );
665 	gIOFinalizeList        = OSArray::withCapacity( 16 );
666 #if !NO_KEXTD
667 	if (OSKext::iokitDaemonAvailable()) {
668 		gIOMatchDeferList      = OSArray::withCapacity( 16 );
669 	} else {
670 		gIOMatchDeferList      = NULL;
671 	}
672 #endif
673 	assert( gIOTerminatePhase2List && gIOStopList && gIOStopProviderList && gIOFinalizeList );
674 
675 	gDriverKitLaunches = OSSet::withCapacity(0);
676 	gDriverKitLaunchLock = IORecursiveLockAlloc();
677 	gIOAssociatedServicesKey = OSSymbol::withCStringNoCopy( "IOAssociatedServices" );
678 
679 	// worker thread that is responsible for terminating / cleaning up threads
680 	kernel_thread_start(&terminateThread, NULL, &gIOTerminateWorkerThread);
681 	assert(gIOTerminateWorkerThread);
682 	thread_set_thread_name(gIOTerminateWorkerThread, "IOServiceTerminateThread");
683 }
684 
685 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
686 
687 #if defined(__x86_64__)
688 extern "C" {
689 const char *getCpuDelayBusStallHolderName(void);
690 const char *
getCpuDelayBusStallHolderName(void)691 getCpuDelayBusStallHolderName(void)
692 {
693 	return sCPULatencyHolderName[kCpuDelayBusStall];
694 }
695 
696 const char *getCpuInterruptDelayHolderName(void);
697 const char *
getCpuInterruptDelayHolderName(void)698 getCpuInterruptDelayHolderName(void)
699 {
700 	return sCPULatencyHolderName[kCpuDelayInterrupt];
701 }
702 }
703 #endif /* defined(__x86_64__) */
704 
705 
706 
707 #if IOMATCHDEBUG
708 static UInt64
getDebugFlags(OSDictionary * props)709 getDebugFlags( OSDictionary * props )
710 {
711 	OSNumber *  debugProp;
712 	UInt64      debugFlags;
713 
714 	debugProp = OSDynamicCast( OSNumber,
715 	    props->getObject( gIOKitDebugKey ));
716 	if (debugProp) {
717 		debugFlags = debugProp->unsigned64BitValue();
718 	} else {
719 		debugFlags = gIOKitDebug;
720 	}
721 
722 	return debugFlags;
723 }
724 
725 static UInt64
getDebugFlags(IOService * inst)726 getDebugFlags( IOService * inst )
727 {
728 	OSObject *  prop;
729 	OSNumber *  debugProp;
730 	UInt64      debugFlags;
731 
732 	prop = inst->copyProperty(gIOKitDebugKey);
733 	debugProp = OSDynamicCast(OSNumber, prop);
734 	if (debugProp) {
735 		debugFlags = debugProp->unsigned64BitValue();
736 	} else {
737 		debugFlags = gIOKitDebug;
738 	}
739 
740 	OSSafeReleaseNULL(prop);
741 
742 	return debugFlags;
743 }
744 #endif
745 
746 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
747 
748 // Probe a matched service and return an instance to be started.
749 // The default score is from the property table, & may be altered
750 // during probe to change the start order.
751 
752 IOService *
probe(IOService * provider,SInt32 * score)753 IOService::probe(   IOService * provider,
754     SInt32    * score )
755 {
756 	return this;
757 }
758 
759 bool
start(IOService * provider)760 IOService::start( IOService * provider )
761 {
762 	return true;
763 }
764 
765 void
stop(IOService * provider)766 IOService::stop( IOService * provider )
767 {
768 	if (reserved->uvars && reserved->uvars->started && reserved->uvars->userServer) {
769 		reserved->uvars->userServer->serviceStop(this, provider);
770 	}
771 }
772 
773 bool
init(OSDictionary * dictionary)774 IOService::init( OSDictionary * dictionary )
775 {
776 	bool ret;
777 
778 	ret = super::init(dictionary);
779 	if (!ret) {
780 		return false;
781 	}
782 	if (reserved) {
783 		return true;
784 	}
785 
786 	reserved = IOMallocType(ExpansionData);
787 	IOLockInlineInit(&reserved->interruptStatisticsLock);
788 	return true;
789 }
790 
791 bool
init(IORegistryEntry * from,const IORegistryPlane * inPlane)792 IOService::init( IORegistryEntry * from,
793     const IORegistryPlane * inPlane )
794 {
795 	bool ret;
796 
797 	ret = super::init(from, inPlane);
798 	if (!ret) {
799 		return false;
800 	}
801 	if (reserved) {
802 		return true;
803 	}
804 
805 	reserved = IOMallocType(ExpansionData);
806 	IOLockInlineInit(&reserved->interruptStatisticsLock);
807 
808 	return true;
809 }
810 
811 void
free(void)812 IOService::free( void )
813 {
814 	IOInterruptSourcePrivate *sourcesPrivate = NULL;
815 	int i = 0;
816 	requireMaxBusStall(0);
817 #if defined(__x86_64__)
818 	requireMaxInterruptDelay(0);
819 #endif /* defined(__x86_64__) */
820 	if (getPropertyTable()) {
821 		unregisterAllInterest();
822 	}
823 	PMfree();
824 
825 	if (reserved) {
826 		if (reserved->interruptStatisticsArray) {
827 			for (i = 0; i < reserved->interruptStatisticsArrayCount; i++) {
828 				if (reserved->interruptStatisticsArray[i].reporter) {
829 					reserved->interruptStatisticsArray[i].reporter->release();
830 				}
831 			}
832 
833 			IODelete(reserved->interruptStatisticsArray, IOInterruptAccountingReporter, reserved->interruptStatisticsArrayCount);
834 		}
835 
836 		if (reserved->uvars && reserved->uvars->userServer) {
837 			reserved->uvars->userServer->serviceFree(this);
838 		}
839 		sourcesPrivate = reserved->interruptSourcesPrivate;
840 		IOLockInlineDestroy(&reserved->interruptStatisticsLock);
841 		IOFreeType(reserved, ExpansionData);
842 	}
843 
844 	if (_numInterruptSources && _interruptSources) {
845 		assert(sourcesPrivate);
846 		for (i = 0; i < _numInterruptSources; i++) {
847 			void * block = sourcesPrivate[i].vectorBlock;
848 			if (block) {
849 				Block_release(block);
850 			}
851 		}
852 		IODelete(_interruptSources, IOInterruptSource, _numInterruptSources);
853 		_interruptSources = NULL;
854 		IODelete(sourcesPrivate, IOInterruptSourcePrivate, _numInterruptSources);
855 	}
856 
857 	super::free();
858 }
859 
860 /*
861  * Attach in service plane
862  */
863 bool
attach(IOService * provider)864 IOService::attach( IOService * provider )
865 {
866 	bool         ok;
867 	uint32_t     count;
868 	AbsoluteTime deadline;
869 	int          waitResult = THREAD_AWAKENED;
870 	bool         wait, computeDeadline = true;
871 
872 	if (provider) {
873 		if (gIOKitDebug & kIOLogAttach) {
874 			LOG( "%s::attach(%s)\n", getName(),
875 			    provider->getName());
876 		}
877 
878 		ok   = false;
879 		do{
880 			wait = false;
881 			provider->lockForArbitration();
882 			if (provider->__state[0] & kIOServiceInactiveState) {
883 				ok = false;
884 			} else {
885 				count = provider->getChildCount(gIOServicePlane);
886 				wait = (count > (kIOServiceBusyMax - 4));
887 				if (!wait) {
888 					ok = attachToParent(provider, gIOServicePlane);
889 				} else {
890 					IOLog("stalling for detach from %s\n", provider->getName());
891 					IOLockLock( gIOServiceBusyLock );
892 					provider->__state[1] |= kIOServiceWaitDetachState;
893 				}
894 			}
895 			provider->unlockForArbitration();
896 			if (wait) {
897 				if (computeDeadline) {
898 					clock_interval_to_deadline(15, kSecondScale, &deadline);
899 					computeDeadline = false;
900 				}
901 				assert_wait_deadline((event_t)&provider->__provider, THREAD_UNINT, deadline);
902 				IOLockUnlock( gIOServiceBusyLock );
903 				waitResult = thread_block(THREAD_CONTINUE_NULL);
904 				wait = (waitResult != THREAD_TIMED_OUT);
905 			}
906 		}while (wait);
907 	} else {
908 		gIOServiceRoot = this;
909 		ok = attachToParent( getRegistryRoot(), gIOServicePlane);
910 	}
911 
912 	if (ok && !__provider) {
913 		(void) getProvider();
914 	}
915 
916 	return ok;
917 }
918 
919 IOService *
getServiceRoot(void)920 IOService::getServiceRoot( void )
921 {
922 	return gIOServiceRoot;
923 }
924 
925 void
detach(IOService * provider)926 IOService::detach( IOService * provider )
927 {
928 	IOService * newProvider = NULL;
929 	SInt32      busy;
930 	bool        adjParent;
931 
932 	if (gIOKitDebug & kIOLogAttach) {
933 		LOG("%s::detach(%s)\n", getName(), provider->getName());
934 	}
935 
936 #if !NO_KEXTD
937 	IOLockLock(gJobsLock);
938 	if (gIOMatchDeferList) {
939 		auto idx = gIOMatchDeferList->getNextIndexOfObject(this, 0);
940 		if (-1U != idx) {
941 			gIOMatchDeferList->removeObject(idx);
942 		}
943 	}
944 	if (IOServicePH::fMatchingDelayed) {
945 		auto idx = IOServicePH::fMatchingDelayed->getNextIndexOfObject(this, 0);
946 		if (-1U != idx) {
947 			IOServicePH::fMatchingDelayed->removeObject(idx);
948 		}
949 	}
950 	IOLockUnlock(gJobsLock);
951 #endif /* NO_KEXTD */
952 
953 	lockForArbitration();
954 
955 	uint64_t regID1 = provider->getRegistryEntryID();
956 	uint64_t regID2 = getRegistryEntryID();
957 	IOServiceTrace(
958 		IOSERVICE_DETACH,
959 		(uintptr_t) regID1,
960 		(uintptr_t) (regID1 >> 32),
961 		(uintptr_t) regID2,
962 		(uintptr_t) (regID2 >> 32));
963 
964 	adjParent = ((busy = (__state[1] & kIOServiceBusyStateMask))
965 	    && (provider == getProvider()));
966 
967 	detachFromParent( provider, gIOServicePlane );
968 
969 	if (busy) {
970 		newProvider = getProvider();
971 		if (busy && (__state[1] & kIOServiceTermPhase3State) && (NULL == newProvider)) {
972 			_adjustBusy( -busy );
973 		}
974 	}
975 
976 	if (kIOServiceInactiveState & __state[0]) {
977 		getMetaClass()->removeInstance(this);
978 		IORemoveServicePlatformActions(this);
979 	}
980 
981 	unlockForArbitration();
982 
983 	if (newProvider && adjParent) {
984 		newProvider->lockForArbitration();
985 		newProvider->_adjustBusy(1);
986 		newProvider->unlockForArbitration();
987 	}
988 
989 	// check for last client detach from a terminated service
990 	if (provider->lockForArbitration( true )) {
991 		if (kIOServiceStartState & __state[1]) {
992 			provider->scheduleTerminatePhase2();
993 		}
994 		if (adjParent) {
995 			provider->_adjustBusy( -1 );
996 		}
997 		if ((provider->__state[1] & kIOServiceTermPhase3State)
998 		    && (NULL == provider->getClient())) {
999 			provider->scheduleFinalize(false);
1000 		}
1001 
1002 		IOLockLock( gIOServiceBusyLock );
1003 		if (kIOServiceWaitDetachState & provider->__state[1]) {
1004 			provider->__state[1] &= ~kIOServiceWaitDetachState;
1005 			thread_wakeup(&provider->__provider);
1006 		}
1007 		IOLockUnlock( gIOServiceBusyLock );
1008 
1009 		provider->unlockForArbitration();
1010 	}
1011 
1012 	if (kIOServiceRematchOnDetach & __state[1]) {
1013 		provider->registerService();
1014 	}
1015 }
1016 
1017 /*
1018  * Register instance - publish it for matching
1019  */
1020 
1021 void
registerService(IOOptionBits options)1022 IOService::registerService( IOOptionBits options )
1023 {
1024 	OSDataAllocation<char> pathBuf;
1025 	const char *        path;
1026 	const char *        skip;
1027 	int                 len;
1028 	enum { kMaxPathLen  = 256 };
1029 	enum { kMaxChars    = 63 };
1030 
1031 	IORegistryEntry * parent = this;
1032 	IORegistryEntry * root = getRegistryRoot();
1033 	while (parent && (parent != root)) {
1034 		parent = parent->getParentEntry( gIOServicePlane);
1035 	}
1036 
1037 	if (parent != root) {
1038 		IOLog("%s: not registry member at registerService()\n", getName());
1039 		return;
1040 	}
1041 
1042 	// Allow the Platform Expert to adjust this node.
1043 	if (gIOPlatform && (!gIOPlatform->platformAdjustService(this))) {
1044 		return;
1045 	}
1046 
1047 	IOInstallServicePlatformActions(this);
1048 	IOInstallServiceSleepPlatformActions(this);
1049 
1050 	if ((this != gIOResources)
1051 	    && (kIOLogRegister & gIOKitDebug)) {
1052 		pathBuf = OSDataAllocation<char>( kMaxPathLen, OSAllocateMemory );
1053 
1054 		IOLog( "Registering: " );
1055 
1056 		len = kMaxPathLen;
1057 		if (pathBuf && getPath( pathBuf.data(), &len, gIOServicePlane)) {
1058 			path = pathBuf.data();
1059 			if (len > kMaxChars) {
1060 				IOLog("..");
1061 				len -= kMaxChars;
1062 				path += len;
1063 				if ((skip = strchr( path, '/'))) {
1064 					path = skip;
1065 				}
1066 			}
1067 		} else {
1068 			path = getName();
1069 		}
1070 
1071 		IOLog( "%s\n", path );
1072 	}
1073 
1074 	startMatching( options );
1075 }
1076 
1077 void
startMatching(IOOptionBits options)1078 IOService::startMatching( IOOptionBits options )
1079 {
1080 	IOService * provider;
1081 	UInt32      prevBusy = 0;
1082 	bool        needConfig;
1083 	bool        needWake = false;
1084 	bool        sync;
1085 	bool        waitAgain;
1086 	bool        releaseAssertion = false;
1087 
1088 	if (options & kIOServiceDextRequirePowerForMatching) {
1089 		bool ok = gIOPMRootDomain->acquireDriverKitMatchingAssertion() == kIOReturnSuccess;
1090 		if (!ok) {
1091 			panic("%s: Failed to acquire power assertion for matching", getName());
1092 		}
1093 		releaseAssertion = true;
1094 	}
1095 
1096 	lockForArbitration();
1097 
1098 	sync = (options & kIOServiceSynchronous)
1099 	    || ((provider = getProvider())
1100 	    && (provider->__state[1] & kIOServiceSynchronousState));
1101 
1102 	if (options & kIOServiceAsynchronous) {
1103 		sync = false;
1104 	}
1105 
1106 	needConfig =  (0 == (__state[1] & (kIOServiceNeedConfigState | kIOServiceConfigRunning)))
1107 	    && (0 == (__state[0] & kIOServiceInactiveState));
1108 
1109 	__state[1] |= kIOServiceNeedConfigState;
1110 
1111 //    __state[0] &= ~kIOServiceInactiveState;
1112 
1113 //    if( sync) LOG("OSKernelStackRemaining = %08x @ %s\n",
1114 //			OSKernelStackRemaining(), getName());
1115 
1116 	if (needConfig) {
1117 		needWake = (0 != (kIOServiceSyncPubState & __state[1]));
1118 	}
1119 
1120 	if (sync) {
1121 		__state[1] |= kIOServiceSynchronousState;
1122 	} else {
1123 		__state[1] &= ~kIOServiceSynchronousState;
1124 	}
1125 
1126 	if (needConfig) {
1127 		prevBusy = _adjustBusy( 1 );
1128 	}
1129 
1130 	unlockForArbitration();
1131 
1132 	if (needConfig) {
1133 		if (needWake) {
1134 			IOLockLock( gIOServiceBusyLock );
1135 			thread_wakeup((event_t) this /*&__state[1]*/ );
1136 			IOLockUnlock( gIOServiceBusyLock );
1137 		} else if (!sync || (kIOServiceAsynchronous & options)) {
1138 			// assertion will be released when matching job is complete
1139 			releaseAssertion = false;
1140 			_IOServiceJob::startJob( this, kMatchNubJob, options );
1141 		} else {
1142 			do {
1143 				if ((__state[1] & kIOServiceNeedConfigState)) {
1144 					doServiceMatch( options );
1145 				}
1146 
1147 				lockForArbitration();
1148 				IOLockLock( gIOServiceBusyLock );
1149 
1150 				waitAgain = ((prevBusy < (__state[1] & kIOServiceBusyStateMask))
1151 				    && (0 == (__state[0] & kIOServiceInactiveState)));
1152 
1153 				if (waitAgain) {
1154 					__state[1] |= kIOServiceSyncPubState | kIOServiceBusyWaiterState;
1155 				} else {
1156 					__state[1] &= ~kIOServiceSyncPubState;
1157 				}
1158 
1159 				unlockForArbitration();
1160 
1161 				if (waitAgain) {
1162 					assert_wait((event_t) this /*&__state[1]*/, THREAD_UNINT);
1163 				}
1164 
1165 				IOLockUnlock( gIOServiceBusyLock );
1166 				if (waitAgain) {
1167 					thread_block(THREAD_CONTINUE_NULL);
1168 				}
1169 			} while (waitAgain);
1170 		}
1171 	}
1172 
1173 	if (releaseAssertion) {
1174 		gIOPMRootDomain->releaseDriverKitMatchingAssertion();
1175 	}
1176 }
1177 
1178 
1179 void
startDeferredMatches(void)1180 IOService::startDeferredMatches(void)
1181 {
1182 #if !NO_KEXTD
1183 	OSArray * array;
1184 
1185 	IOLockLock(gJobsLock);
1186 	array = gIOMatchDeferList;
1187 	gIOMatchDeferList = NULL;
1188 	IOLockUnlock(gJobsLock);
1189 
1190 	if (array) {
1191 		IOLog("deferred rematching count %d\n", array->getCount());
1192 		array->iterateObjects(^bool (OSObject * obj)
1193 		{
1194 			((IOService *)obj)->startMatching(kIOServiceAsynchronous);
1195 			return false;
1196 		});
1197 		array->release();
1198 	}
1199 #endif /* !NO_KEXTD */
1200 }
1201 
1202 void
iokitDaemonLaunched(void)1203 IOService::iokitDaemonLaunched(void)
1204 {
1205 #if !NO_KEXTD
1206 	if (!OSKext::iokitDaemonAvailable()) {
1207 		panic(kIOKitDaemonName " is unavailable in this environment, but it was launched");
1208 	}
1209 	IOServiceTrace(IOSERVICE_KEXTD_READY, 0, 0, 0, 0);
1210 	startDeferredMatches();
1211 	getServiceRoot()->adjustBusy(-1);
1212 	IOService::publishUserResource(gIOResourceIOKitKey);
1213 #endif /* !NO_KEXTD */
1214 }
1215 
1216 /*
1217  * Possibly called with IORWLock from IOCatalog held.
1218  * This means that no calls to OSKext that could take
1219  * sKextLock can be performed from this function.
1220  */
1221 IOReturn
catalogNewDrivers(OSOrderedSet * newTables)1222 IOService::catalogNewDrivers( OSOrderedSet * newTables )
1223 {
1224 	OSDictionary *      table;
1225 	OSSet *             set;
1226 	OSSet *             allSet = NULL;
1227 	IOService *         service;
1228 #if IOMATCHDEBUG
1229 	SInt32              count = 0;
1230 #endif
1231 
1232 	newTables->retain();
1233 
1234 	while ((table = (OSDictionary *) newTables->getFirstObject())) {
1235 		LOCKWRITENOTIFY();
1236 		set = (OSSet *) copyExistingServices( table,
1237 		    kIOServiceRegisteredState,
1238 		    kIOServiceExistingSet);
1239 		UNLOCKNOTIFY();
1240 		if (set) {
1241 #if IOMATCHDEBUG
1242 			count += set->getCount();
1243 #endif
1244 			if (allSet) {
1245 				allSet->merge((const OSSet *) set);
1246 				set->release();
1247 			} else {
1248 				allSet = set;
1249 			}
1250 		}
1251 
1252 #if IOMATCHDEBUG
1253 		if (getDebugFlags( table ) & kIOLogMatch) {
1254 			LOG("Matching service count = %ld\n", (long)count);
1255 		}
1256 #endif
1257 		newTables->removeObject(table);
1258 	}
1259 
1260 	if (allSet) {
1261 		while ((service = (IOService *) allSet->getAnyObject())) {
1262 			service->startMatching(kIOServiceAsynchronous);
1263 			allSet->removeObject(service);
1264 		}
1265 		allSet->release();
1266 	}
1267 
1268 	newTables->release();
1269 
1270 	return kIOReturnSuccess;
1271 }
1272 
1273 _IOServiceJob *
startJob(IOService * nub,int type,IOOptionBits options)1274 _IOServiceJob::startJob( IOService * nub, int type,
1275     IOOptionBits options )
1276 {
1277 	_IOServiceJob *     job;
1278 
1279 	job = new _IOServiceJob;
1280 	if (job && !job->init()) {
1281 		job->release();
1282 		job = NULL;
1283 	}
1284 
1285 	if (job) {
1286 		job->type       = type;
1287 		job->nub        = nub;
1288 		job->options    = options;
1289 		nub->retain();          // thread will release()
1290 		pingConfig( job );
1291 	}
1292 
1293 	return job;
1294 }
1295 
1296 /*
1297  * Called on a registered service to see if it matches
1298  * a property table.
1299  */
1300 
1301 bool
matchPropertyTable(OSDictionary * table,SInt32 * score)1302 IOService::matchPropertyTable( OSDictionary * table, SInt32 * score )
1303 {
1304 	return matchPropertyTable(table);
1305 }
1306 
1307 bool
matchPropertyTable(OSDictionary * table)1308 IOService::matchPropertyTable( OSDictionary * table )
1309 {
1310 	return true;
1311 }
1312 
1313 /*
1314  * Called on a matched service to allocate resources
1315  * before first driver is attached.
1316  */
1317 
1318 IOReturn
getResources(void)1319 IOService::getResources( void )
1320 {
1321 	return kIOReturnSuccess;
1322 }
1323 
1324 /*
1325  * Client/provider accessors
1326  */
1327 
1328 IOService *
getProvider(void) const1329 IOService::getProvider( void ) const
1330 {
1331 	IOService * self = (IOService *) this;
1332 	IOService * parent;
1333 	SInt32      generation;
1334 
1335 	generation = getRegistryEntryGenerationCount();
1336 	if (__providerGeneration == generation) {
1337 		return __provider;
1338 	}
1339 
1340 	parent = (IOService *) getParentEntry( gIOServicePlane);
1341 	if (parent == IORegistryEntry::getRegistryRoot()) {
1342 		/* root is not an IOService */
1343 		parent = NULL;
1344 	}
1345 
1346 	self->__provider = parent;
1347 	OSMemoryBarrier();
1348 	// save the count from before call to getParentEntry()
1349 	self->__providerGeneration = generation;
1350 
1351 	return parent;
1352 }
1353 
1354 IOWorkLoop *
getWorkLoop() const1355 IOService::getWorkLoop() const
1356 {
1357 	IOService *provider = getProvider();
1358 
1359 	if (provider) {
1360 		return provider->getWorkLoop();
1361 	} else {
1362 		return NULL;
1363 	}
1364 }
1365 
1366 OSIterator *
getProviderIterator(void) const1367 IOService::getProviderIterator( void ) const
1368 {
1369 	return getParentIterator( gIOServicePlane);
1370 }
1371 
1372 IOService *
getClient(void) const1373 IOService::getClient( void ) const
1374 {
1375 	return (IOService *) getChildEntry( gIOServicePlane);
1376 }
1377 
1378 OSIterator *
getClientIterator(void) const1379 IOService::getClientIterator( void ) const
1380 {
1381 	return getChildIterator( gIOServicePlane);
1382 }
1383 
1384 OSIterator *
iterator(OSIterator * _iter,const IOService * client,const IOService * provider)1385 _IOOpenServiceIterator::iterator( OSIterator * _iter,
1386     const IOService * client,
1387     const IOService * provider )
1388 {
1389 	_IOOpenServiceIterator * inst;
1390 
1391 	if (!_iter) {
1392 		return NULL;
1393 	}
1394 
1395 	inst = new _IOOpenServiceIterator;
1396 
1397 	if (inst && !inst->init()) {
1398 		inst->release();
1399 		inst = NULL;
1400 	}
1401 	if (inst) {
1402 		inst->iter = _iter;
1403 		inst->client = client;
1404 		inst->provider = provider;
1405 	} else {
1406 		OSSafeReleaseNULL(_iter);
1407 	}
1408 
1409 	return inst;
1410 }
1411 
1412 void
free()1413 _IOOpenServiceIterator::free()
1414 {
1415 	iter->release();
1416 	if (last) {
1417 		last->unlockForArbitration();
1418 	}
1419 	OSIterator::free();
1420 }
1421 
1422 OSObject *
getNextObject()1423 _IOOpenServiceIterator::getNextObject()
1424 {
1425 	IOService * next;
1426 
1427 	if (last) {
1428 		last->unlockForArbitration();
1429 	}
1430 
1431 	while ((next = (IOService *) iter->getNextObject())) {
1432 		next->lockForArbitration();
1433 		if ((client && (next->isOpen( client )))
1434 		    || (provider && (provider->isOpen( next )))) {
1435 			break;
1436 		}
1437 		next->unlockForArbitration();
1438 	}
1439 
1440 	last = next;
1441 
1442 	return next;
1443 }
1444 
1445 bool
isValid()1446 _IOOpenServiceIterator::isValid()
1447 {
1448 	return iter->isValid();
1449 }
1450 
1451 void
reset()1452 _IOOpenServiceIterator::reset()
1453 {
1454 	if (last) {
1455 		last->unlockForArbitration();
1456 		last = NULL;
1457 	}
1458 	iter->reset();
1459 }
1460 
1461 OSIterator *
getOpenProviderIterator(void) const1462 IOService::getOpenProviderIterator( void ) const
1463 {
1464 	return _IOOpenServiceIterator::iterator( getProviderIterator(), this, NULL );
1465 }
1466 
1467 OSIterator *
getOpenClientIterator(void) const1468 IOService::getOpenClientIterator( void ) const
1469 {
1470 	return _IOOpenServiceIterator::iterator( getClientIterator(), NULL, this );
1471 }
1472 
1473 
1474 IOReturn
callPlatformFunction(const OSSymbol * functionName,bool waitForFunction,void * param1,void * param2,void * param3,void * param4)1475 IOService::callPlatformFunction( const OSSymbol * functionName,
1476     bool waitForFunction,
1477     void *param1, void *param2,
1478     void *param3, void *param4 )
1479 {
1480 	IOReturn  result = kIOReturnUnsupported;
1481 	IOService *provider;
1482 
1483 	if (functionName == gIOPlatformQuiesceActionKey ||
1484 	    functionName == gIOPlatformActiveActionKey ||
1485 	    functionName == gIOPlatformPanicActionKey) {
1486 		/*
1487 		 * Services which register for IOPlatformQuiesceAction / IOPlatformActiveAction / IOPlatformPanicAction
1488 		 * must consume that event themselves, without passing it up to super/IOService.
1489 		 */
1490 		if (gEnforcePlatformActionSafety) {
1491 			panic("Class %s passed the %s action to IOService",
1492 			    getMetaClass()->getClassName(), functionName->getCStringNoCopy());
1493 		}
1494 	}
1495 
1496 	if (gIOPlatformFunctionHandlerSet == functionName) {
1497 		const OSSymbol * functionHandlerName = (const OSSymbol *) param1;
1498 		IOService *      target              = (IOService *) param2;
1499 		bool             enable              = (param3 != NULL);
1500 
1501 		if (sCPULatencyFunctionName[kCpuDelayBusStall] == functionHandlerName) {
1502 			result = setLatencyHandler(kCpuDelayBusStall, target, enable);
1503 		}
1504 #if defined(__x86_64__)
1505 		else if (sCPULatencyFunctionName[kCpuDelayInterrupt] == param1) {
1506 			result = setLatencyHandler(kCpuDelayInterrupt, target, enable);
1507 		}
1508 #endif /* defined(__x86_64__) */
1509 	}
1510 
1511 	if ((kIOReturnUnsupported == result) && (provider = getProvider())) {
1512 		result = provider->callPlatformFunction(functionName, waitForFunction,
1513 		    param1, param2, param3, param4);
1514 	}
1515 
1516 	return result;
1517 }
1518 
1519 IOReturn
callPlatformFunction(const char * functionName,bool waitForFunction,void * param1,void * param2,void * param3,void * param4)1520 IOService::callPlatformFunction( const char * functionName,
1521     bool waitForFunction,
1522     void *param1, void *param2,
1523     void *param3, void *param4 )
1524 {
1525 	IOReturn result = kIOReturnNoMemory;
1526 	const OSSymbol *functionSymbol = OSSymbol::withCString(functionName);
1527 
1528 	if (functionSymbol != NULL) {
1529 		result = callPlatformFunction(functionSymbol, waitForFunction,
1530 		    param1, param2, param3, param4);
1531 		functionSymbol->release();
1532 	}
1533 
1534 	return result;
1535 }
1536 
1537 
1538 /*
1539  * Accessors for global services
1540  */
1541 
1542 IOPlatformExpert *
getPlatform(void)1543 IOService::getPlatform( void )
1544 {
1545 	return gIOPlatform;
1546 }
1547 
1548 class IOPMrootDomain *
getPMRootDomain(void)1549 	IOService::getPMRootDomain( void )
1550 {
1551 	return gIOPMRootDomain;
1552 }
1553 
1554 IOService *
getResourceService(void)1555 IOService::getResourceService( void )
1556 {
1557 	return gIOResources;
1558 }
1559 
1560 IOService * gIOSystemStateNotificationService;
1561 
1562 IOService *
getSystemStateNotificationService(void)1563 IOService::getSystemStateNotificationService(void)
1564 {
1565 	return gIOSystemStateNotificationService;
1566 }
1567 
1568 void
setPlatform(IOPlatformExpert * platform)1569 IOService::setPlatform( IOPlatformExpert * platform)
1570 {
1571 	gIOPlatform = platform;
1572 	gIOResources->attachToParent( gIOServiceRoot, gIOServicePlane );
1573 
1574 	gIOUserResources->attachToParent( gIOServiceRoot, gIOServicePlane );
1575 
1576 #if DEVELOPMENT || DEBUG
1577 	// Test object that will be terminated for dext to match
1578 	{
1579 		IOService * ios;
1580 		ios = OSTypeAlloc(IOService);
1581 		ios->init();
1582 		ios->attach(gIOUserResources);
1583 		ios->setProperty(gIOMatchCategoryKey->getCStringNoCopy(), "com.apple.iokit.test");
1584 		ios->setProperty(gIOModuleIdentifierKey->getCStringNoCopy(), "com.apple.kpi.iokit");
1585 		ios->setProperty(gIOMatchedAtBootKey, kOSBooleanTrue);
1586 		ios->setProperty(gIOPrimaryDriverTerminateOptionsKey, kOSBooleanTrue);
1587 		ios->release();
1588 	}
1589 #endif
1590 
1591 	gIOSystemStateNotificationService = IOSystemStateNotification::initialize();
1592 	gIOSystemStateNotificationService->attachToParent(platform, gIOServicePlane);
1593 	gIOSystemStateNotificationService->registerService();
1594 
1595 	static const char * keys[kCpuNumDelayTypes] = {
1596 		kIOPlatformMaxBusDelay,
1597 #if defined(__x86_64__)
1598 		kIOPlatformMaxInterruptDelay
1599 #endif /* defined(__x86_64__) */
1600 	};
1601 	const OSObject * objs[2];
1602 	OSArray * array;
1603 	uint32_t  idx;
1604 
1605 	for (idx = 0; idx < kCpuNumDelayTypes; idx++) {
1606 		objs[0] = sCPULatencySet[idx];
1607 		objs[1] = sCPULatencyHolder[idx];
1608 		array   = OSArray::withObjects(objs, 2);
1609 		if (!array) {
1610 			break;
1611 		}
1612 		platform->setProperty(keys[idx], array);
1613 		array->release();
1614 	}
1615 }
1616 
1617 void
setPMRootDomain(class IOPMrootDomain * rootDomain)1618 IOService::setPMRootDomain( class IOPMrootDomain * rootDomain)
1619 {
1620 	gIOPMRootDomain = rootDomain;
1621 }
1622 
1623 void
publishPMRootDomain(void)1624 IOService::publishPMRootDomain( void )
1625 {
1626 	assert(getPMRootDomain() != NULL);
1627 	publishResource(gIOResourceIOKitKey);
1628 #if NO_KEXTD
1629 	// Publish IOUserResources now since there is no IOKit daemon.
1630 	publishUserResource(gIOResourceIOKitKey);
1631 #endif
1632 	IOServicePH::init(getPMRootDomain());
1633 }
1634 
1635 /*
1636  * Stacking change
1637  */
1638 
1639 bool
lockForArbitration(bool isSuccessRequired)1640 IOService::lockForArbitration( bool isSuccessRequired )
1641 {
1642 	bool                          found;
1643 	bool                          success;
1644 	ArbitrationLockQueueElement * element;
1645 	ArbitrationLockQueueElement * owner;
1646 	ArbitrationLockQueueElement * active;
1647 	ArbitrationLockQueueElement * waiting;
1648 
1649 	enum { kPutOnFreeQueue, kPutOnActiveQueue, kPutOnWaitingQueue } action;
1650 
1651 	// lock global access
1652 	IOTakeLock( gArbitrationLockQueueLock );
1653 
1654 	// obtain an unused queue element
1655 	if (!queue_empty( &gArbitrationLockQueueFree )) {
1656 		queue_remove_first( &gArbitrationLockQueueFree,
1657 		    element,
1658 		    ArbitrationLockQueueElement *,
1659 		    link );
1660 	} else {
1661 		element = IOMallocType(ArbitrationLockQueueElement);
1662 		assert( element );
1663 	}
1664 
1665 	// prepare the queue element
1666 	element->thread   = IOThreadSelf();
1667 	element->service  = this;
1668 	element->count    = 1;
1669 	element->required = isSuccessRequired;
1670 	element->aborted  = false;
1671 
1672 	// determine whether this object is already locked (ie. on active queue)
1673 	found = false;
1674 	queue_iterate( &gArbitrationLockQueueActive,
1675 	    owner,
1676 	    ArbitrationLockQueueElement *,
1677 	    link )
1678 	{
1679 		if (owner->service == element->service) {
1680 			found = true;
1681 			break;
1682 		}
1683 	}
1684 
1685 	if (found) { // this object is already locked
1686 		active = owner;
1687 		// determine whether it is the same or a different thread trying to lock
1688 		if (active->thread != element->thread) { // it is a different thread
1689 			ArbitrationLockQueueElement * victim = NULL;
1690 
1691 			// before placing this new thread on the waiting queue, we look for
1692 			// a deadlock cycle...
1693 
1694 			while (1) {
1695 				// determine whether the active thread holding the object we
1696 				// want is waiting for another object to be unlocked
1697 				found = false;
1698 				queue_iterate( &gArbitrationLockQueueWaiting,
1699 				    waiting,
1700 				    ArbitrationLockQueueElement *,
1701 				    link )
1702 				{
1703 					if (waiting->thread == active->thread) {
1704 						assert( false == waiting->aborted );
1705 						found = true;
1706 						break;
1707 					}
1708 				}
1709 
1710 				if (found) { // yes, active thread waiting for another object
1711 					// this may be a candidate for rejection if the required
1712 					// flag is not set, should we detect a deadlock later on
1713 					if (false == waiting->required) {
1714 						victim = waiting;
1715 					}
1716 
1717 					// find the thread that is holding this other object, that
1718 					// is blocking the active thread from proceeding (fun :-)
1719 					found = false;
1720 					queue_iterate( &gArbitrationLockQueueActive,
1721 					    active, // (reuse active queue element)
1722 					    ArbitrationLockQueueElement *,
1723 					    link )
1724 					{
1725 						if (active->service == waiting->service) {
1726 							found = true;
1727 							break;
1728 						}
1729 					}
1730 
1731 					// someone must be holding it or it wouldn't be waiting
1732 					assert( found );
1733 
1734 					if (active->thread == element->thread) {
1735 						// doh, it's waiting for the thread that originated
1736 						// this whole lock (ie. current thread) -> deadlock
1737 						if (false == element->required) { // willing to fail?
1738 							// the originating thread doesn't have the required
1739 							// flag, so it can fail
1740 							success = false; // (fail originating lock request)
1741 							break; // (out of while)
1742 						} else { // originating thread is not willing to fail
1743 							// see if we came across a waiting thread that did
1744 							// not have the 'required' flag set: we'll fail it
1745 							if (victim) {
1746 								// we do have a willing victim, fail it's lock
1747 								victim->aborted = true;
1748 
1749 								// take the victim off the waiting queue
1750 								queue_remove( &gArbitrationLockQueueWaiting,
1751 								    victim,
1752 								    ArbitrationLockQueueElement *,
1753 								    link );
1754 
1755 								// wake the victim
1756 								wakeup_thread_with_inheritor(&victim->service->__machPortHoldDestroy, // event
1757 								    THREAD_AWAKENED, LCK_WAKE_DEFAULT, victim->thread);
1758 
1759 								// allow this thread to proceed (ie. wait)
1760 								success = true; // (put request on wait queue)
1761 								break; // (out of while)
1762 							} else {
1763 								// all the waiting threads we came across in
1764 								// finding this loop had the 'required' flag
1765 								// set, so we've got a deadlock we can't avoid
1766 								panic("I/O Kit: Unrecoverable deadlock.");
1767 							}
1768 						}
1769 					} else {
1770 						// repeat while loop, redefining active thread to be the
1771 						// thread holding "this other object" (see above), and
1772 						// looking for threads waiting on it; note the active
1773 						// variable points to "this other object" already... so
1774 						// there nothing to do in this else clause.
1775 					}
1776 				} else { // no, active thread is not waiting for another object
1777 					success = true; // (put request on wait queue)
1778 					break; // (out of while)
1779 				}
1780 			} // while forever
1781 
1782 			if (success) { // put the request on the waiting queue?
1783 				kern_return_t wait_result;
1784 
1785 				// place this thread on the waiting queue and put it to sleep;
1786 				// we place it at the tail of the queue...
1787 				queue_enter( &gArbitrationLockQueueWaiting,
1788 				    element,
1789 				    ArbitrationLockQueueElement *,
1790 				    link );
1791 
1792 				// declare that this thread will wait for a given event
1793 restart_sleep:
1794 				// unlock global access
1795 				// & put thread to sleep, waiting for our event to fire...
1796 				wait_result = lck_mtx_sleep_with_inheritor(gArbitrationLockQueueLock,
1797 				    LCK_SLEEP_UNLOCK,
1798 				    &element->service->__machPortHoldDestroy,     // event
1799 				    owner->thread,
1800 				    element->required ? THREAD_UNINT : THREAD_INTERRUPTIBLE, TIMEOUT_WAIT_FOREVER);
1801 
1802 				// ...and we've been woken up; we might be in one of two states:
1803 				// (a) we've been aborted and our queue element is not on
1804 				//     any of the three queues, but is floating around
1805 				// (b) we're allowed to proceed with the lock and we have
1806 				//     already been moved from the waiting queue to the
1807 				//     active queue.
1808 				// ...plus a 3rd state, should the thread have been interrupted:
1809 				// (c) we're still on the waiting queue
1810 
1811 				// determine whether we were interrupted out of our sleep
1812 				if (THREAD_INTERRUPTED == wait_result) {
1813 					// re-lock global access
1814 					IOTakeLock( gArbitrationLockQueueLock );
1815 
1816 					// determine whether we're still on the waiting queue
1817 					found = false;
1818 					queue_iterate( &gArbitrationLockQueueWaiting,
1819 					    waiting, // (reuse waiting queue element)
1820 					    ArbitrationLockQueueElement *,
1821 					    link )
1822 					{
1823 						if (waiting == element) {
1824 							found = true;
1825 							break;
1826 						}
1827 					}
1828 
1829 					if (found) { // yes, we're still on the waiting queue
1830 						// determine whether we're willing to fail
1831 						if (false == element->required) {
1832 							// mark us as aborted
1833 							element->aborted = true;
1834 
1835 							// take us off the waiting queue
1836 							queue_remove( &gArbitrationLockQueueWaiting,
1837 							    element,
1838 							    ArbitrationLockQueueElement *,
1839 							    link );
1840 						} else { // we are not willing to fail
1841 							// ignore interruption, go back to sleep
1842 							goto restart_sleep;
1843 						}
1844 					}
1845 
1846 					// unlock global access
1847 					IOUnlock( gArbitrationLockQueueLock );
1848 
1849 					// proceed as though this were a normal wake up
1850 					wait_result = THREAD_AWAKENED;
1851 				}
1852 
1853 				assert( THREAD_AWAKENED == wait_result );
1854 
1855 				// determine whether we've been aborted while we were asleep
1856 				if (element->aborted) {
1857 					assert( false == element->required );
1858 					// re-lock global access
1859 					IOTakeLock( gArbitrationLockQueueLock );
1860 
1861 					action = kPutOnFreeQueue;
1862 					success = false;
1863 				} else { // we weren't aborted, so we must be ready to go :-)
1864 					// we've already been moved from waiting to active queue
1865 					return true;
1866 				}
1867 			} else { // the lock request is to be failed
1868 				// return unused queue element to queue
1869 				action = kPutOnFreeQueue;
1870 			}
1871 		} else { // it is the same thread, recursive access is allowed
1872 			// add one level of recursion
1873 			active->count++;
1874 
1875 			// return unused queue element to queue
1876 			action = kPutOnFreeQueue;
1877 			success = true;
1878 		}
1879 	} else { // this object is not already locked, so let this thread through
1880 		action = kPutOnActiveQueue;
1881 		success = true;
1882 	}
1883 
1884 	// put the new element on a queue
1885 	if (kPutOnActiveQueue == action) {
1886 		queue_enter( &gArbitrationLockQueueActive,
1887 		    element,
1888 		    ArbitrationLockQueueElement *,
1889 		    link );
1890 	} else if (kPutOnFreeQueue == action) {
1891 		queue_enter( &gArbitrationLockQueueFree,
1892 		    element,
1893 		    ArbitrationLockQueueElement *,
1894 		    link );
1895 	} else {
1896 		assert( 0 ); // kPutOnWaitingQueue never occurs, handled specially above
1897 	}
1898 
1899 	// unlock global access
1900 	IOUnlock( gArbitrationLockQueueLock );
1901 
1902 	return success;
1903 }
1904 
1905 void
unlockForArbitration(void)1906 IOService::unlockForArbitration( void )
1907 {
1908 	bool                          found;
1909 	ArbitrationLockQueueElement * element;
1910 
1911 	// lock global access
1912 	IOTakeLock( gArbitrationLockQueueLock );
1913 
1914 	// find the lock element for this object (ie. on active queue)
1915 	found = false;
1916 	queue_iterate( &gArbitrationLockQueueActive,
1917 	    element,
1918 	    ArbitrationLockQueueElement *,
1919 	    link )
1920 	{
1921 		if (element->service == this) {
1922 			found = true;
1923 			break;
1924 		}
1925 	}
1926 
1927 	assert( found );
1928 
1929 	// determine whether the lock has been taken recursively
1930 	if (element->count > 1) {
1931 		// undo one level of recursion
1932 		element->count--;
1933 	} else {
1934 		// remove it from the active queue
1935 		queue_remove( &gArbitrationLockQueueActive,
1936 		    element,
1937 		    ArbitrationLockQueueElement *,
1938 		    link );
1939 
1940 		// put it on the free queue
1941 		queue_enter( &gArbitrationLockQueueFree,
1942 		    element,
1943 		    ArbitrationLockQueueElement *,
1944 		    link );
1945 
1946 		// determine whether a thread is waiting for object
1947 		thread_t woken;
1948 		kern_return_t kr =
1949 		    wakeup_one_with_inheritor(&__machPortHoldDestroy, // event
1950 		    THREAD_AWAKENED, LCK_WAKE_DEFAULT, &woken);
1951 
1952 		if (KERN_SUCCESS == kr) {
1953 			found = false;
1954 			queue_iterate( &gArbitrationLockQueueWaiting,
1955 			    element,
1956 			    ArbitrationLockQueueElement *,
1957 			    link )
1958 			{
1959 				if (element->thread == woken) {
1960 					found = true;
1961 					break;
1962 				}
1963 			}
1964 			assert(found); // we found an interested thread on waiting queue
1965 			// remove it from the waiting queue
1966 			queue_remove( &gArbitrationLockQueueWaiting,
1967 			    element,
1968 			    ArbitrationLockQueueElement *,
1969 			    link );
1970 
1971 			// put it on the active queue
1972 			queue_enter( &gArbitrationLockQueueActive,
1973 			    element,
1974 			    ArbitrationLockQueueElement *,
1975 			    link );
1976 
1977 			thread_deallocate(woken);
1978 		}
1979 	}
1980 
1981 	// unlock global access
1982 	IOUnlock( gArbitrationLockQueueLock );
1983 }
1984 
1985 uint32_t
isLockedForArbitration(IOService * service)1986 IOService::isLockedForArbitration(IOService * service)
1987 {
1988 #if DEBUG_NOTIFIER_LOCKED
1989 	uint32_t                      count;
1990 	ArbitrationLockQueueElement * active;
1991 
1992 	// lock global access
1993 	IOLockLock(gArbitrationLockQueueLock);
1994 
1995 	// determine whether this object is already locked (ie. on active queue)
1996 	count = 0;
1997 	queue_iterate(&gArbitrationLockQueueActive,
1998 	    active,
1999 	    ArbitrationLockQueueElement *,
2000 	    link)
2001 	{
2002 		if ((active->thread == IOThreadSelf())
2003 		    && (!service || (active->service == service))) {
2004 			count += 0x10000;
2005 			count += active->count;
2006 		}
2007 	}
2008 
2009 	IOLockUnlock(gArbitrationLockQueueLock);
2010 
2011 	return count;
2012 
2013 #else /* DEBUG_NOTIFIER_LOCKED */
2014 
2015 	return 0;
2016 
2017 #endif /* DEBUG_NOTIFIER_LOCKED */
2018 }
2019 
2020 void
setMachPortHoldDestroy(bool holdDestroy)2021 IOService::setMachPortHoldDestroy(bool holdDestroy)
2022 {
2023 	__machPortHoldDestroy = holdDestroy;
2024 }
2025 
2026 bool
machPortHoldDestroy()2027 IOService::machPortHoldDestroy()
2028 {
2029 	return __machPortHoldDestroy;
2030 }
2031 
2032 void
applyToProviders(IOServiceApplierFunction applier,void * context)2033 IOService::applyToProviders( IOServiceApplierFunction applier,
2034     void * context )
2035 {
2036 	applyToParents((IORegistryEntryApplierFunction) applier,
2037 	    context, gIOServicePlane );
2038 }
2039 
2040 void
applyToClients(IOServiceApplierFunction applier,void * context)2041 IOService::applyToClients( IOServiceApplierFunction applier,
2042     void * context )
2043 {
2044 	applyToChildren((IORegistryEntryApplierFunction) applier,
2045 	    context, gIOServicePlane );
2046 }
2047 
2048 
2049 static void
IOServiceApplierToBlock(IOService * next,void * context)2050 IOServiceApplierToBlock(IOService * next, void * context)
2051 {
2052 	IOServiceApplierBlock block = (IOServiceApplierBlock) context;
2053 	block(next);
2054 }
2055 
2056 void
applyToProviders(IOServiceApplierBlock applier)2057 IOService::applyToProviders(IOServiceApplierBlock applier)
2058 {
2059 	applyToProviders(&IOServiceApplierToBlock, applier);
2060 }
2061 
2062 void
applyToClients(IOServiceApplierBlock applier)2063 IOService::applyToClients(IOServiceApplierBlock applier)
2064 {
2065 	applyToClients(&IOServiceApplierToBlock, applier);
2066 }
2067 
2068 /*
2069  * Client messages
2070  */
2071 
2072 
2073 // send a message to a client or interested party of this service
2074 IOReturn
messageClient(UInt32 type,OSObject * client,void * argument,vm_size_t argSize)2075 IOService::messageClient( UInt32 type, OSObject * client,
2076     void * argument, vm_size_t argSize )
2077 {
2078 	IOReturn                            ret;
2079 	IOService *                         service;
2080 	_IOServiceInterestNotifier *        notify;
2081 
2082 	if ((service = OSDynamicCast( IOService, client))) {
2083 		ret = service->message( type, this, argument );
2084 	} else if ((notify = OSDynamicCast( _IOServiceInterestNotifier, client))) {
2085 		_IOServiceNotifierInvocation invocation;
2086 		bool                     willNotify;
2087 
2088 		invocation.thread = current_thread();
2089 
2090 		LOCKWRITENOTIFY();
2091 		willNotify = (0 != (kIOServiceNotifyEnable & notify->state));
2092 
2093 		if (willNotify) {
2094 			queue_enter( &notify->handlerInvocations, &invocation,
2095 			    _IOServiceNotifierInvocation *, link );
2096 		}
2097 		UNLOCKNOTIFY();
2098 
2099 		if (willNotify) {
2100 			ret = (*notify->handler)( notify->target, notify->ref,
2101 			    type, this, argument, argSize );
2102 
2103 			LOCKWRITENOTIFY();
2104 			queue_remove( &notify->handlerInvocations, &invocation,
2105 			    _IOServiceNotifierInvocation *, link );
2106 			if (kIOServiceNotifyWaiter & notify->state) {
2107 				notify->state &= ~kIOServiceNotifyWaiter;
2108 				WAKEUPNOTIFY( notify );
2109 			}
2110 			UNLOCKNOTIFY();
2111 		} else {
2112 			ret = kIOReturnSuccess;
2113 		}
2114 	} else {
2115 		ret = kIOReturnBadArgument;
2116 	}
2117 
2118 	return ret;
2119 }
2120 
2121 static void
applyToInterestNotifiers(const IORegistryEntry * target,const OSSymbol * typeOfInterest,OSObjectApplierFunction applier,void * context)2122 applyToInterestNotifiers(const IORegistryEntry *target,
2123     const OSSymbol * typeOfInterest,
2124     OSObjectApplierFunction applier,
2125     void * context )
2126 {
2127 	OSArray *  copyArray = NULL;
2128 	OSObject * prop;
2129 
2130 	LOCKREADNOTIFY();
2131 
2132 	prop = target->copyProperty(typeOfInterest);
2133 	IOCommand *notifyList = OSDynamicCast(IOCommand, prop);
2134 
2135 	if (notifyList) {
2136 		copyArray = OSArray::withCapacity(1);
2137 
2138 		// iterate over queue, entry is set to each element in the list
2139 		iterqueue(&notifyList->fCommandChain, entry) {
2140 			_IOServiceInterestNotifier * notify;
2141 
2142 			queue_element(entry, notify, _IOServiceInterestNotifier *, chain);
2143 			copyArray->setObject(notify);
2144 		}
2145 	}
2146 	UNLOCKNOTIFY();
2147 
2148 	if (copyArray) {
2149 		unsigned int    index;
2150 		OSObject *      next;
2151 
2152 		for (index = 0; (next = copyArray->getObject( index )); index++) {
2153 			(*applier)(next, context);
2154 		}
2155 		copyArray->release();
2156 	}
2157 
2158 	OSSafeReleaseNULL(prop);
2159 }
2160 
2161 void
applyToInterested(const OSSymbol * typeOfInterest,OSObjectApplierFunction applier,void * context)2162 IOService::applyToInterested( const OSSymbol * typeOfInterest,
2163     OSObjectApplierFunction applier,
2164     void * context )
2165 {
2166 	if (gIOGeneralInterest == typeOfInterest) {
2167 		applyToClients((IOServiceApplierFunction) applier, context );
2168 	}
2169 	applyToInterestNotifiers(this, typeOfInterest, applier, context);
2170 }
2171 
2172 struct MessageClientsContext {
2173 	IOService * service;
2174 	UInt32      type;
2175 	void *      argument;
2176 	vm_size_t   argSize;
2177 	IOReturn    ret;
2178 };
2179 
2180 static void
messageClientsApplier(OSObject * object,void * ctx)2181 messageClientsApplier( OSObject * object, void * ctx )
2182 {
2183 	IOReturn                ret;
2184 	MessageClientsContext * context = (MessageClientsContext *) ctx;
2185 
2186 	ret = context->service->messageClient( context->type,
2187 	    object, context->argument, context->argSize );
2188 	if (kIOReturnSuccess != ret) {
2189 		context->ret = ret;
2190 	}
2191 }
2192 
2193 // send a message to all clients
2194 IOReturn
messageClients(UInt32 type,void * argument,vm_size_t argSize)2195 IOService::messageClients( UInt32 type,
2196     void * argument, vm_size_t argSize )
2197 {
2198 	MessageClientsContext       context;
2199 
2200 	context.service     = this;
2201 	context.type        = type;
2202 	context.argument    = argument;
2203 	context.argSize     = argSize;
2204 	context.ret         = kIOReturnSuccess;
2205 
2206 	applyToInterested( gIOGeneralInterest,
2207 	    &messageClientsApplier, &context );
2208 
2209 	return context.ret;
2210 }
2211 
2212 IOReturn
acknowledgeNotification(IONotificationRef notification,IOOptionBits response)2213 IOService::acknowledgeNotification( IONotificationRef notification,
2214     IOOptionBits response )
2215 {
2216 	return kIOReturnUnsupported;
2217 }
2218 
2219 IONotifier *
registerInterest(const OSSymbol * typeOfInterest,IOServiceInterestHandler handler,void * target,void * ref)2220 IOService::registerInterest( const OSSymbol * typeOfInterest,
2221     IOServiceInterestHandler handler, void * target, void * ref )
2222 {
2223 	_IOServiceInterestNotifier * notify = NULL;
2224 	IOReturn rc = kIOReturnError;
2225 
2226 	notify = new _IOServiceInterestNotifier;
2227 	if (!notify) {
2228 		return NULL;
2229 	}
2230 
2231 	if (notify->init()) {
2232 		rc = registerInterestForNotifier(notify, typeOfInterest,
2233 		    handler, target, ref);
2234 	}
2235 
2236 	if (rc != kIOReturnSuccess) {
2237 		notify->release();
2238 		notify = NULL;
2239 	}
2240 
2241 	return notify;
2242 }
2243 
2244 
2245 
2246 static IOReturn
IOServiceInterestHandlerToBlock(void * target __unused,void * refCon,UInt32 messageType,IOService * provider,void * messageArgument,vm_size_t argSize)2247 IOServiceInterestHandlerToBlock( void * target __unused, void * refCon,
2248     UInt32 messageType, IOService * provider,
2249     void * messageArgument, vm_size_t argSize )
2250 {
2251 	return ((IOServiceInterestHandlerBlock) refCon)(messageType, provider, messageArgument, argSize);
2252 }
2253 
2254 IONotifier *
registerInterest(const OSSymbol * typeOfInterest,IOServiceInterestHandlerBlock handler)2255 IOService::registerInterest(const OSSymbol * typeOfInterest,
2256     IOServiceInterestHandlerBlock handler)
2257 {
2258 	IONotifier * notify;
2259 	void       * block;
2260 
2261 	block = Block_copy(handler);
2262 	if (!block) {
2263 		return NULL;
2264 	}
2265 
2266 	notify = registerInterest(typeOfInterest, &IOServiceInterestHandlerToBlock, NULL, block);
2267 
2268 	if (!notify) {
2269 		Block_release(block);
2270 	}
2271 
2272 	return notify;
2273 }
2274 
2275 IOReturn
registerInterestForNotifier(IONotifier * svcNotify,const OSSymbol * typeOfInterest,IOServiceInterestHandler handler,void * target,void * ref)2276 IOService::registerInterestForNotifier( IONotifier *svcNotify, const OSSymbol * typeOfInterest,
2277     IOServiceInterestHandler handler, void * target, void * ref )
2278 {
2279 	IOReturn rc = kIOReturnSuccess;
2280 	_IOServiceInterestNotifier  *notify = NULL;
2281 
2282 
2283 	if (!svcNotify || !(notify = OSDynamicCast(_IOServiceInterestNotifier, svcNotify)) || !handler) {
2284 		return kIOReturnBadArgument;
2285 	}
2286 
2287 	notify->handler = handler;
2288 	notify->target = target;
2289 	notify->ref = ref;
2290 
2291 	if ((typeOfInterest != gIOGeneralInterest)
2292 	    && (typeOfInterest != gIOBusyInterest)
2293 	    && (typeOfInterest != gIOAppPowerStateInterest)
2294 	    && (typeOfInterest != gIOConsoleSecurityInterest)
2295 	    && (typeOfInterest != gIOPriorityPowerStateInterest)) {
2296 		return kIOReturnBadArgument;
2297 	}
2298 
2299 	lockForArbitration();
2300 	if (0 == (__state[0] & kIOServiceInactiveState)) {
2301 		notify->state = kIOServiceNotifyEnable;
2302 
2303 		////// queue
2304 
2305 		LOCKWRITENOTIFY();
2306 
2307 		// Get the head of the notifier linked list
2308 		IOCommand * notifyList;
2309 		OSObject  * obj = copyProperty( typeOfInterest );
2310 		if (!(notifyList = OSDynamicCast(IOCommand, obj))) {
2311 			notifyList = OSTypeAlloc(IOCommand);
2312 			if (notifyList) {
2313 				notifyList->init();
2314 				bool ok = setProperty( typeOfInterest, notifyList);
2315 				notifyList->release();
2316 				if (!ok) {
2317 					notifyList = NULL;
2318 				}
2319 			}
2320 		}
2321 		if (obj) {
2322 			obj->release();
2323 		}
2324 
2325 		if (notifyList) {
2326 			enqueue(&notifyList->fCommandChain, &notify->chain);
2327 			notify->retain(); // ref'ed while in list
2328 		}
2329 
2330 		UNLOCKNOTIFY();
2331 	} else {
2332 		rc = kIOReturnNotReady;
2333 	}
2334 	unlockForArbitration();
2335 
2336 	return rc;
2337 }
2338 
2339 static void
cleanInterestList(OSObject * head)2340 cleanInterestList( OSObject * head )
2341 {
2342 	IOCommand *notifyHead = OSDynamicCast(IOCommand, head);
2343 	if (!notifyHead) {
2344 		return;
2345 	}
2346 
2347 	LOCKWRITENOTIFY();
2348 	while (queue_entry_t entry = dequeue(&notifyHead->fCommandChain)) {
2349 		queue_next(entry) = queue_prev(entry) = NULL;
2350 
2351 		_IOServiceInterestNotifier * notify;
2352 
2353 		queue_element(entry, notify, _IOServiceInterestNotifier *, chain);
2354 		notify->release();
2355 	}
2356 	UNLOCKNOTIFY();
2357 }
2358 
2359 void
unregisterAllInterest(void)2360 IOService::unregisterAllInterest( void )
2361 {
2362 	OSObject * prop;
2363 
2364 	prop = copyProperty(gIOGeneralInterest);
2365 	cleanInterestList(prop);
2366 	OSSafeReleaseNULL(prop);
2367 
2368 	prop = copyProperty(gIOBusyInterest);
2369 	cleanInterestList(prop);
2370 	OSSafeReleaseNULL(prop);
2371 
2372 	prop = copyProperty(gIOAppPowerStateInterest);
2373 	cleanInterestList(prop);
2374 	OSSafeReleaseNULL(prop);
2375 
2376 	prop = copyProperty(gIOPriorityPowerStateInterest);
2377 	cleanInterestList(prop);
2378 	OSSafeReleaseNULL(prop);
2379 
2380 	prop = copyProperty(gIOConsoleSecurityInterest);
2381 	cleanInterestList(prop);
2382 	OSSafeReleaseNULL(prop);
2383 }
2384 
2385 /*
2386  * _IOServiceInterestNotifier
2387  */
2388 
2389 // wait for all threads, other than the current one,
2390 //  to exit the handler
2391 
2392 void
wait()2393 _IOServiceInterestNotifier::wait()
2394 {
2395 	_IOServiceNotifierInvocation * next;
2396 	bool doWait;
2397 
2398 	do {
2399 		doWait = false;
2400 		queue_iterate( &handlerInvocations, next,
2401 		    _IOServiceNotifierInvocation *, link) {
2402 			if (next->thread != current_thread()) {
2403 				doWait = true;
2404 				break;
2405 			}
2406 		}
2407 		if (doWait) {
2408 			state |= kIOServiceNotifyWaiter;
2409 			SLEEPNOTIFY(this);
2410 		}
2411 	} while (doWait);
2412 }
2413 
2414 void
free()2415 _IOServiceInterestNotifier::free()
2416 {
2417 	assert( queue_empty( &handlerInvocations ));
2418 
2419 	if (handler == &IOServiceInterestHandlerToBlock) {
2420 		Block_release(ref);
2421 	}
2422 
2423 	OSObject::free();
2424 }
2425 
2426 void
remove()2427 _IOServiceInterestNotifier::remove()
2428 {
2429 	LOCKWRITENOTIFY();
2430 
2431 	if (queue_next( &chain )) {
2432 		remqueue(&chain);
2433 		queue_next( &chain) = queue_prev( &chain) = NULL;
2434 		release();
2435 	}
2436 
2437 	state &= ~kIOServiceNotifyEnable;
2438 
2439 	wait();
2440 
2441 	UNLOCKNOTIFY();
2442 
2443 	release();
2444 }
2445 
2446 bool
disable()2447 _IOServiceInterestNotifier::disable()
2448 {
2449 	bool        ret;
2450 
2451 	LOCKWRITENOTIFY();
2452 
2453 	ret = (0 != (kIOServiceNotifyEnable & state));
2454 	state &= ~kIOServiceNotifyEnable;
2455 	if (ret) {
2456 		wait();
2457 	}
2458 
2459 	UNLOCKNOTIFY();
2460 
2461 	return ret;
2462 }
2463 
2464 void
enable(bool was)2465 _IOServiceInterestNotifier::enable( bool was )
2466 {
2467 	LOCKWRITENOTIFY();
2468 	if (was) {
2469 		state |= kIOServiceNotifyEnable;
2470 	} else {
2471 		state &= ~kIOServiceNotifyEnable;
2472 	}
2473 	UNLOCKNOTIFY();
2474 }
2475 
2476 bool
init()2477 _IOServiceInterestNotifier::init()
2478 {
2479 	queue_init( &handlerInvocations );
2480 	return OSObject::init();
2481 }
2482 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2483 
2484 /*
2485  * Termination
2486  */
2487 
2488 #define tailQ(o)                setObject(o)
2489 #define headQ(o)                setObject(0, o)
2490 #define TLOG(fmt, args...)      { if(kIOLogYield & gIOKitDebug) { IOLog("[%llx] ", thread_tid(current_thread())); IOLog(fmt, ## args); }}
2491 
2492 static void
_workLoopAction(IOWorkLoop::Action action,IOService * service,void * p0=NULL,void * p1=NULL,void * p2=NULL,void * p3=NULL)2493 _workLoopAction( IOWorkLoop::Action action,
2494     IOService * service,
2495     void * p0 = NULL, void * p1 = NULL,
2496     void * p2 = NULL, void * p3 = NULL )
2497 {
2498 	IOWorkLoop * wl;
2499 
2500 	if ((wl = service->getWorkLoop())) {
2501 		wl->retain();
2502 		wl->runAction( action, service, p0, p1, p2, p3 );
2503 		wl->release();
2504 	} else {
2505 		(*action)( service, p0, p1, p2, p3 );
2506 	}
2507 }
2508 
2509 bool
requestTerminate(IOService * provider,IOOptionBits options)2510 IOService::requestTerminate( IOService * provider, IOOptionBits options )
2511 {
2512 	bool ok;
2513 
2514 	// if its our only provider
2515 	ok = isParent( provider, gIOServicePlane, true);
2516 
2517 	// -- compat
2518 	if (ok) {
2519 		provider->terminateClient( this, options | kIOServiceRecursing );
2520 		ok = (0 != (kIOServiceInactiveState & __state[0]));
2521 	}
2522 	// --
2523 
2524 	return ok;
2525 }
2526 
2527 bool
terminatePhase1(IOOptionBits options)2528 IOService::terminatePhase1( IOOptionBits options )
2529 {
2530 	IOService *  victim;
2531 	IOService *  client;
2532 	IOService *  rematchProvider;
2533 	OSIterator * iter;
2534 	OSArray *    makeInactive;
2535 	OSArray *    waitingInactive;
2536 	IOOptionBits callerOptions;
2537 	int          waitResult = THREAD_AWAKENED;
2538 	bool         wait;
2539 	bool                 ok;
2540 	bool                 didInactive;
2541 	bool                 startPhase2 = false;
2542 
2543 	TLOG("%s[0x%qx]::terminatePhase1(%08llx)\n", getName(), getRegistryEntryID(), (long long)options);
2544 
2545 	callerOptions = options;
2546 	rematchProvider = NULL;
2547 	uint64_t regID = getRegistryEntryID();
2548 	IOServiceTrace(
2549 		IOSERVICE_TERMINATE_PHASE1,
2550 		(uintptr_t) regID,
2551 		(uintptr_t) (regID >> 32),
2552 		(uintptr_t) this,
2553 		(uintptr_t) options);
2554 
2555 	// -- compat
2556 	if (options & kIOServiceRecursing) {
2557 		lockForArbitration();
2558 		if (0 == (kIOServiceInactiveState & __state[0])) {
2559 			__state[0] |= kIOServiceInactiveState;
2560 			__state[1] |= kIOServiceRecursing | kIOServiceTermPhase1State;
2561 		}
2562 		unlockForArbitration();
2563 
2564 		return true;
2565 	}
2566 	// --
2567 
2568 	makeInactive    = OSArray::withCapacity( 16 );
2569 	waitingInactive = OSArray::withCapacity( 16 );
2570 	if (!makeInactive || !waitingInactive) {
2571 		OSSafeReleaseNULL(makeInactive);
2572 		OSSafeReleaseNULL(waitingInactive);
2573 		return false;
2574 	}
2575 
2576 	victim = this;
2577 	victim->retain();
2578 
2579 	while (victim) {
2580 		didInactive = victim->lockForArbitration( true );
2581 		if (didInactive) {
2582 			uint64_t regID1 = victim->getRegistryEntryID();
2583 			IOServiceTrace(IOSERVICE_TERM_SET_INACTIVE,
2584 			    (uintptr_t) regID1,
2585 			    (uintptr_t) (regID1 >> 32),
2586 			    (uintptr_t) victim->__state[1],
2587 			    (uintptr_t) 0);
2588 
2589 			enum { kRP1 = kIOServiceRecursing | kIOServiceTermPhase1State };
2590 			didInactive = (kRP1 == (victim->__state[1] & kRP1))
2591 			    || (0 == (victim->__state[0] & kIOServiceInactiveState));
2592 
2593 			if (!didInactive) {
2594 				// a multiply attached IOService can be visited twice
2595 				if (-1U == waitingInactive->getNextIndexOfObject(victim, 0)) {
2596 					do{
2597 						IOLockLock(gIOServiceBusyLock);
2598 						wait = (victim->__state[1] & kIOServiceTermPhase1State);
2599 						if (wait) {
2600 							TLOG("%s[0x%qx]::waitPhase1(%s[0x%qx])\n",
2601 							    getName(), getRegistryEntryID(), victim->getName(), victim->getRegistryEntryID());
2602 							victim->__state[1] |= kIOServiceTerm1WaiterState;
2603 							victim->unlockForArbitration();
2604 							assert_wait((event_t)&victim->__state[1], THREAD_UNINT);
2605 						}
2606 						IOLockUnlock(gIOServiceBusyLock);
2607 						if (wait) {
2608 							waitResult = thread_block(THREAD_CONTINUE_NULL);
2609 							TLOG("%s[0x%qx]::did waitPhase1(%s[0x%qx])\n",
2610 							    getName(), getRegistryEntryID(), victim->getName(), victim->getRegistryEntryID());
2611 							victim->lockForArbitration();
2612 						}
2613 					}while (wait && (waitResult != THREAD_TIMED_OUT));
2614 				}
2615 			} else {
2616 				victim->__state[0] |= kIOServiceInactiveState;
2617 				victim->__state[0] &= ~(kIOServiceRegisteredState | kIOServiceMatchedState
2618 				    | kIOServiceFirstPublishState | kIOServiceFirstMatchState);
2619 				victim->__state[1] &= ~kIOServiceRecursing;
2620 				victim->__state[1] |= kIOServiceTermPhase1State;
2621 				waitingInactive->headQ(victim);
2622 				if (victim == this) {
2623 					if (kIOServiceTerminateNeedWillTerminate & options) {
2624 						victim->__state[1] |= kIOServiceNeedWillTerminate;
2625 					}
2626 				}
2627 				victim->_adjustBusy( 1 );
2628 
2629 				if ((options & kIOServiceTerminateWithRematch) && (victim == this)) {
2630 					if ((options & kIOServiceTerminateWithRematchCurrentDext)) {
2631 						OSObject     * obj;
2632 						OSObject     * rematchProps;
2633 						OSNumber     * num;
2634 						uint32_t       count;
2635 
2636 						rematchProvider = getProvider();
2637 						if (rematchProvider) {
2638 							obj = rematchProvider->copyProperty(gIORematchCountKey);
2639 							num = OSDynamicCast(OSNumber, obj);
2640 							count = 0;
2641 							if (num) {
2642 								count = num->unsigned32BitValue();
2643 								count++;
2644 							}
2645 							num = OSNumber::withNumber(count, 32);
2646 							rematchProvider->setProperty(gIORematchCountKey, num);
2647 							rematchProps = copyProperty(gIOMatchedPersonalityKey);
2648 							rematchProvider->setProperty(gIORematchPersonalityKey, rematchProps);
2649 							OSSafeReleaseNULL(num);
2650 							OSSafeReleaseNULL(rematchProps);
2651 							OSSafeReleaseNULL(obj);
2652 						}
2653 					}
2654 					victim->__state[1] |= kIOServiceRematchOnDetach;
2655 				}
2656 			}
2657 			victim->unlockForArbitration();
2658 		}
2659 		if (victim == this) {
2660 			options &= ~(kIOServiceTerminateWithRematch | kIOServiceTerminateWithRematchCurrentDext);
2661 			startPhase2 = didInactive;
2662 		}
2663 		if (didInactive) {
2664 			OSArray * notifiers;
2665 			notifiers = victim->copyNotifiers(gIOTerminatedNotification, 0, 0xffffffff);
2666 			victim->invokeNotifiers(&notifiers);
2667 
2668 			IOUserClient::destroyUserReferences( victim );
2669 
2670 			iter = victim->getClientIterator();
2671 			if (iter) {
2672 				while ((client = (IOService *) iter->getNextObject())) {
2673 					TLOG("%s[0x%qx]::requestTerminate(%s[0x%qx], %08llx)\n",
2674 					    client->getName(), client->getRegistryEntryID(),
2675 					    victim->getName(), victim->getRegistryEntryID(), (long long)options);
2676 					ok = client->requestTerminate( victim, options );
2677 					TLOG("%s[0x%qx]::requestTerminate(%s[0x%qx], ok = %d)\n",
2678 					    client->getName(), client->getRegistryEntryID(),
2679 					    victim->getName(), victim->getRegistryEntryID(), ok);
2680 
2681 					uint64_t regID1 = client->getRegistryEntryID();
2682 					uint64_t regID2 = victim->getRegistryEntryID();
2683 					IOServiceTrace(
2684 						(ok ? IOSERVICE_TERMINATE_REQUEST_OK
2685 						: IOSERVICE_TERMINATE_REQUEST_FAIL),
2686 						(uintptr_t) regID1,
2687 						(uintptr_t) (regID1 >> 32),
2688 						(uintptr_t) regID2,
2689 						(uintptr_t) (regID2 >> 32));
2690 
2691 					if (ok) {
2692 						makeInactive->setObject( client );
2693 					}
2694 				}
2695 				iter->release();
2696 			}
2697 		}
2698 		victim->release();
2699 		victim = (IOService *) makeInactive->getObject(0);
2700 		if (victim) {
2701 			victim->retain();
2702 			makeInactive->removeObject(0);
2703 		}
2704 	}
2705 
2706 	makeInactive->release();
2707 
2708 	while ((victim = (IOService *) waitingInactive->getObject(0))) {
2709 		victim->retain();
2710 		waitingInactive->removeObject(0);
2711 
2712 		victim->lockForArbitration();
2713 		victim->__state[1] &= ~kIOServiceTermPhase1State;
2714 		if (kIOServiceTerm1WaiterState & victim->__state[1]) {
2715 			victim->__state[1] &= ~kIOServiceTerm1WaiterState;
2716 			TLOG("%s[0x%qx]::wakePhase1\n", victim->getName(), victim->getRegistryEntryID());
2717 			IOLockLock( gIOServiceBusyLock );
2718 			thread_wakeup((event_t) &victim->__state[1]);
2719 			IOLockUnlock( gIOServiceBusyLock );
2720 		}
2721 		victim->unlockForArbitration();
2722 		victim->release();
2723 	}
2724 
2725 	waitingInactive->release();
2726 
2727 	if (startPhase2) {
2728 		retain();
2729 		lockForArbitration();
2730 		scheduleTerminatePhase2(options);
2731 		unlockForArbitration();
2732 		release();
2733 	}
2734 
2735 	if (rematchProvider) {
2736 		DKLOG(DKS " rematching after dext crash\n", DKN(rematchProvider));
2737 	}
2738 
2739 	return true;
2740 }
2741 
2742 void
setTerminateDefer(IOService * provider,bool defer)2743 IOService::setTerminateDefer(IOService * provider, bool defer)
2744 {
2745 	lockForArbitration();
2746 	if (defer) {
2747 		__state[1] |= kIOServiceStartState;
2748 	} else {
2749 		__state[1] &= ~kIOServiceStartState;
2750 	}
2751 	unlockForArbitration();
2752 
2753 	if (provider && !defer) {
2754 		provider->lockForArbitration();
2755 		provider->scheduleTerminatePhase2();
2756 		provider->unlockForArbitration();
2757 	}
2758 }
2759 
2760 // Must call this while holding gJobsLock
2761 void
waitToBecomeTerminateThread(void)2762 IOService::waitToBecomeTerminateThread(void)
2763 {
2764 	IOLockAssert(gJobsLock, kIOLockAssertOwned);
2765 	bool wait;
2766 	do {
2767 		wait = (gIOTerminateThread != THREAD_NULL);
2768 		if (wait) {
2769 			IOLockSleep(gJobsLock, &gIOTerminateThread, THREAD_UNINT);
2770 		}
2771 	} while (wait);
2772 	gIOTerminateThread = current_thread();
2773 }
2774 
2775 // call with lockForArbitration
2776 void
scheduleTerminatePhase2(IOOptionBits options)2777 IOService::scheduleTerminatePhase2( IOOptionBits options )
2778 {
2779 	AbsoluteTime        deadline;
2780 	uint64_t            regID1;
2781 	int                 waitResult = THREAD_AWAKENED;
2782 	bool                wait = false, haveDeadline = false;
2783 
2784 	if (!(__state[0] & kIOServiceInactiveState)) {
2785 		return;
2786 	}
2787 
2788 	regID1 = getRegistryEntryID();
2789 	IOServiceTrace(
2790 		IOSERVICE_TERM_SCHED_PHASE2,
2791 		(uintptr_t) regID1,
2792 		(uintptr_t) (regID1 >> 32),
2793 		(uintptr_t) __state[1],
2794 		(uintptr_t) options);
2795 
2796 	if (__state[1] & kIOServiceTermPhase1State) {
2797 		return;
2798 	}
2799 
2800 	retain();
2801 	unlockForArbitration();
2802 	options |= kIOServiceRequired;
2803 	IOLockLock( gJobsLock );
2804 
2805 	if ((options & kIOServiceSynchronous)
2806 	    && (current_thread() != gIOTerminateThread)) {
2807 		waitToBecomeTerminateThread();
2808 		gIOTerminatePhase2List->setObject( this );
2809 		gIOTerminateWork++;
2810 
2811 		do {
2812 			while (gIOTerminateWork) {
2813 				terminateWorker( options );
2814 			}
2815 			wait = (0 != (__state[1] & kIOServiceBusyStateMask));
2816 			if (wait) {
2817 				/* wait for the victim to go non-busy */
2818 				if (!haveDeadline) {
2819 					clock_interval_to_deadline( 15, kSecondScale, &deadline );
2820 					haveDeadline = true;
2821 				}
2822 				/* let others do work while we wait */
2823 				gIOTerminateThread = NULL;
2824 				IOLockWakeup( gJobsLock, (event_t) &gIOTerminateThread, /* one-thread */ false);
2825 				waitResult = IOLockSleepDeadline( gJobsLock, &gIOTerminateWork,
2826 				    deadline, THREAD_UNINT );
2827 				if (__improbable(waitResult == THREAD_TIMED_OUT)) {
2828 					IOLog("%s[0x%qx]::terminate(kIOServiceSynchronous): THREAD_TIMED_OUT. "
2829 					    "Attempting to auto-resolve your deadlock. PLEASE FIX!\n", getName(), getRegistryEntryID());
2830 				}
2831 				waitToBecomeTerminateThread();
2832 			}
2833 		} while (gIOTerminateWork || (wait && (waitResult != THREAD_TIMED_OUT)));
2834 
2835 		gIOTerminateThread = NULL;
2836 		IOLockWakeup( gJobsLock, (event_t) &gIOTerminateThread, /* one-thread */ false);
2837 	} else {
2838 		// ! kIOServiceSynchronous
2839 
2840 		gIOTerminatePhase2List->setObject( this );
2841 		if (0 == gIOTerminateWork++) {
2842 			assert(gIOTerminateWorkerThread);
2843 			IOLockWakeup(gJobsLock, (event_t)&gIOTerminateWork, /* one-thread */ false );
2844 		}
2845 	}
2846 
2847 	IOLockUnlock( gJobsLock );
2848 	lockForArbitration();
2849 	release();
2850 }
2851 
2852 __attribute__((__noreturn__))
2853 void
terminateThread(void * arg,wait_result_t waitResult)2854 IOService::terminateThread( void * arg, wait_result_t waitResult )
2855 {
2856 	// IOLockSleep re-acquires the lock on wakeup, so we only need to do this once
2857 	IOLockLock(gJobsLock);
2858 	while (true) {
2859 		if (gIOTerminateThread != gIOTerminateWorkerThread) {
2860 			waitToBecomeTerminateThread();
2861 		}
2862 
2863 		while (gIOTerminateWork) {
2864 			terminateWorker((IOOptionBits)(uintptr_t)arg );
2865 		}
2866 
2867 		gIOTerminateThread = NULL;
2868 		IOLockWakeup( gJobsLock, (event_t) &gIOTerminateThread, /* one-thread */ false);
2869 		IOLockSleep(gJobsLock, &gIOTerminateWork, THREAD_UNINT);
2870 	}
2871 }
2872 
2873 void
scheduleStop(IOService * provider)2874 IOService::scheduleStop( IOService * provider )
2875 {
2876 	uint64_t regID1 = getRegistryEntryID();
2877 	uint64_t regID2 = provider->getRegistryEntryID();
2878 
2879 	TLOG("%s[0x%qx]::scheduleStop(%s[0x%qx])\n", getName(), regID1, provider->getName(), regID2);
2880 	IOServiceTrace(
2881 		IOSERVICE_TERMINATE_SCHEDULE_STOP,
2882 		(uintptr_t) regID1,
2883 		(uintptr_t) (regID1 >> 32),
2884 		(uintptr_t) regID2,
2885 		(uintptr_t) (regID2 >> 32));
2886 
2887 	IOLockLock( gJobsLock );
2888 	gIOStopList->tailQ( this );
2889 	gIOStopProviderList->tailQ( provider );
2890 
2891 	if (0 == gIOTerminateWork++) {
2892 		assert(gIOTerminateWorkerThread);
2893 		IOLockWakeup(gJobsLock, (event_t)&gIOTerminateWork, /* one-thread */ false );
2894 	}
2895 
2896 	IOLockUnlock( gJobsLock );
2897 }
2898 
2899 void
scheduleFinalize(bool now)2900 IOService::scheduleFinalize(bool now)
2901 {
2902 	uint64_t regID1 = getRegistryEntryID();
2903 
2904 	TLOG("%s[0x%qx]::scheduleFinalize\n", getName(), regID1);
2905 	IOServiceTrace(
2906 		IOSERVICE_TERMINATE_SCHEDULE_FINALIZE,
2907 		(uintptr_t) regID1,
2908 		(uintptr_t) (regID1 >> 32),
2909 		0, 0);
2910 
2911 	if (now || IOUserClient::finalizeUserReferences(this)) {
2912 		IOLockLock( gJobsLock );
2913 		gIOFinalizeList->tailQ(this);
2914 		if (0 == gIOTerminateWork++) {
2915 			assert(gIOTerminateWorkerThread);
2916 			IOLockWakeup(gJobsLock, (event_t)&gIOTerminateWork, /* one-thread */ false );
2917 		}
2918 		IOLockUnlock( gJobsLock );
2919 	}
2920 }
2921 
2922 bool
willTerminate(IOService * provider,IOOptionBits options)2923 IOService::willTerminate( IOService * provider, IOOptionBits options )
2924 {
2925 	if (reserved->uvars) {
2926 		IOUserServer::serviceWillTerminate(this, provider, options);
2927 	}
2928 	return true;
2929 }
2930 
2931 bool
didTerminate(IOService * provider,IOOptionBits options,bool * defer)2932 IOService::didTerminate( IOService * provider, IOOptionBits options, bool * defer )
2933 {
2934 	if (reserved->uvars) {
2935 		IOUserServer::serviceDidTerminate(this, provider, options, defer);
2936 	}
2937 
2938 	if (false == *defer) {
2939 		if (lockForArbitration( true )) {
2940 			if (false == provider->handleIsOpen( this )) {
2941 				scheduleStop( provider );
2942 			}
2943 			// -- compat
2944 			else {
2945 				message( kIOMessageServiceIsRequestingClose, provider, (void *)(uintptr_t) options );
2946 				if (false == provider->handleIsOpen( this )) {
2947 					scheduleStop( provider );
2948 				}
2949 			}
2950 			// --
2951 			unlockForArbitration();
2952 		}
2953 	}
2954 
2955 	return true;
2956 }
2957 
2958 void
actionWillTerminate(IOService * victim,IOOptionBits options,OSArray * doPhase2List,bool user,void * unused3 __unused)2959 IOService::actionWillTerminate( IOService * victim, IOOptionBits options,
2960     OSArray * doPhase2List,
2961     bool user,
2962     void *unused3 __unused)
2963 {
2964 	OSIterator * iter;
2965 	IOService *  client;
2966 	bool         ok;
2967 	uint64_t     regID1, regID2 = victim->getRegistryEntryID();
2968 
2969 	iter = victim->getClientIterator();
2970 	if (iter) {
2971 		while ((client = (IOService *) iter->getNextObject())) {
2972 			if (user != (NULL != client->reserved->uvars)) {
2973 				continue;
2974 			}
2975 			regID1 = client->getRegistryEntryID();
2976 			TLOG("%s[0x%qx]::willTerminate(%s[0x%qx], %08llx)\n",
2977 			    client->getName(), regID1,
2978 			    victim->getName(), regID2, (long long)options);
2979 			IOServiceTrace(
2980 				IOSERVICE_TERMINATE_WILL,
2981 				(uintptr_t) regID1,
2982 				(uintptr_t) (regID1 >> 32),
2983 				(uintptr_t) regID2,
2984 				(uintptr_t) (regID2 >> 32));
2985 
2986 			ok = client->willTerminate( victim, options );
2987 			doPhase2List->tailQ( client );
2988 		}
2989 		iter->release();
2990 	}
2991 }
2992 
2993 void
actionDidTerminate(IOService * victim,IOOptionBits options,void * unused1 __unused,void * unused2 __unused,void * unused3 __unused)2994 IOService::actionDidTerminate( IOService * victim, IOOptionBits options,
2995     void *unused1 __unused, void *unused2 __unused,
2996     void *unused3 __unused )
2997 {
2998 	OSIterator * iter;
2999 	IOService *  client;
3000 	bool         defer;
3001 	uint64_t     regID1, regID2 = victim->getRegistryEntryID();
3002 
3003 	victim->messageClients( kIOMessageServiceIsTerminated, (void *)(uintptr_t) options );
3004 
3005 	iter = victim->getClientIterator();
3006 	if (iter) {
3007 		while ((client = (IOService *) iter->getNextObject())) {
3008 			regID1 = client->getRegistryEntryID();
3009 			TLOG("%s[0x%qx]::didTerminate(%s[0x%qx], %08llx)\n",
3010 			    client->getName(), regID1,
3011 			    victim->getName(), regID2, (long long)options);
3012 			defer = false;
3013 			client->didTerminate( victim, options, &defer );
3014 
3015 			IOServiceTrace(
3016 				(defer ? IOSERVICE_TERMINATE_DID_DEFER
3017 				: IOSERVICE_TERMINATE_DID),
3018 				(uintptr_t) regID1,
3019 				(uintptr_t) (regID1 >> 32),
3020 				(uintptr_t) regID2,
3021 				(uintptr_t) (regID2 >> 32));
3022 
3023 			TLOG("%s[0x%qx]::didTerminate(%s[0x%qx], defer %d)\n",
3024 			    client->getName(), regID1,
3025 			    victim->getName(), regID2, defer);
3026 		}
3027 		iter->release();
3028 	}
3029 }
3030 
3031 
3032 void
actionWillStop(IOService * victim,IOOptionBits options,void * unused1 __unused,void * unused2 __unused,void * unused3 __unused)3033 IOService::actionWillStop( IOService * victim, IOOptionBits options,
3034     void *unused1 __unused, void *unused2 __unused,
3035     void *unused3 __unused )
3036 {
3037 	OSIterator * iter;
3038 	IOService *  provider;
3039 	bool         ok;
3040 	uint64_t     regID1, regID2 = victim->getRegistryEntryID();
3041 
3042 	iter = victim->getProviderIterator();
3043 	if (iter) {
3044 		while ((provider = (IOService *) iter->getNextObject())) {
3045 			regID1 = provider->getRegistryEntryID();
3046 			TLOG("%s[0x%qx]::willTerminate(%s[0x%qx], %08llx)\n",
3047 			    victim->getName(), regID2,
3048 			    provider->getName(), regID1, (long long)options);
3049 			IOServiceTrace(
3050 				IOSERVICE_TERMINATE_WILL,
3051 				(uintptr_t) regID2,
3052 				(uintptr_t) (regID2 >> 32),
3053 				(uintptr_t) regID1,
3054 				(uintptr_t) (regID1 >> 32));
3055 
3056 			ok = victim->willTerminate( provider, options );
3057 		}
3058 		iter->release();
3059 	}
3060 }
3061 
3062 void
actionDidStop(IOService * victim,IOOptionBits options,void * unused1 __unused,void * unused2 __unused,void * unused3 __unused)3063 IOService::actionDidStop( IOService * victim, IOOptionBits options,
3064     void *unused1 __unused, void *unused2 __unused,
3065     void *unused3 __unused )
3066 {
3067 	OSIterator * iter;
3068 	IOService *  provider;
3069 	bool defer = false;
3070 	uint64_t     regID1, regID2 = victim->getRegistryEntryID();
3071 
3072 	iter = victim->getProviderIterator();
3073 	if (iter) {
3074 		while ((provider = (IOService *) iter->getNextObject())) {
3075 			regID1 = provider->getRegistryEntryID();
3076 			TLOG("%s[0x%qx]::didTerminate(%s[0x%qx], %08llx)\n",
3077 			    victim->getName(), regID2,
3078 			    provider->getName(), regID1, (long long)options);
3079 			victim->didTerminate( provider, options, &defer );
3080 
3081 			IOServiceTrace(
3082 				(defer ? IOSERVICE_TERMINATE_DID_DEFER
3083 				: IOSERVICE_TERMINATE_DID),
3084 				(uintptr_t) regID2,
3085 				(uintptr_t) (regID2 >> 32),
3086 				(uintptr_t) regID1,
3087 				(uintptr_t) (regID1 >> 32));
3088 
3089 			TLOG("%s[0x%qx]::didTerminate(%s[0x%qx], defer %d)\n",
3090 			    victim->getName(), regID2,
3091 			    provider->getName(), regID1, defer);
3092 		}
3093 		iter->release();
3094 	}
3095 }
3096 
3097 
3098 void
actionFinalize(IOService * victim,IOOptionBits options,void * unused1 __unused,void * unused2 __unused,void * unused3 __unused)3099 IOService::actionFinalize( IOService * victim, IOOptionBits options,
3100     void *unused1 __unused, void *unused2 __unused,
3101     void *unused3 __unused )
3102 {
3103 	uint64_t regID1 = victim->getRegistryEntryID();
3104 	TLOG("%s[0x%qx]::finalize(%08llx)\n", victim->getName(), regID1, (long long)options);
3105 	IOServiceTrace(
3106 		IOSERVICE_TERMINATE_FINALIZE,
3107 		(uintptr_t) regID1,
3108 		(uintptr_t) (regID1 >> 32),
3109 		0, 0);
3110 
3111 	victim->finalize( options );
3112 }
3113 
3114 void
actionStop(IOService * provider,IOService * client,void * unused1 __unused,void * unused2 __unused,void * unused3 __unused)3115 IOService::actionStop( IOService * provider, IOService * client,
3116     void *unused1 __unused, void *unused2 __unused,
3117     void *unused3 __unused )
3118 {
3119 	uint64_t regID1 = provider->getRegistryEntryID();
3120 	uint64_t regID2 = client->getRegistryEntryID();
3121 
3122 	TLOG("%s[0x%qx]::stop(%s[0x%qx])\n", client->getName(), regID2, provider->getName(), regID1);
3123 	IOServiceTrace(
3124 		IOSERVICE_TERMINATE_STOP,
3125 		(uintptr_t) regID1,
3126 		(uintptr_t) (regID1 >> 32),
3127 		(uintptr_t) regID2,
3128 		(uintptr_t) (regID2 >> 32));
3129 
3130 	client->stop( provider );
3131 	if (provider->isOpen( client )) {
3132 		provider->close( client );
3133 	}
3134 
3135 	TLOG("%s[0x%qx]::detach(%s[0x%qx])\n", client->getName(), regID2, provider->getName(), regID1);
3136 	client->detach( provider );
3137 }
3138 
3139 #pragma clang diagnostic push
3140 #pragma clang diagnostic ignored "-Wcast-function-type"
3141 
3142 void
terminateWorker(IOOptionBits options)3143 IOService::terminateWorker( IOOptionBits options )
3144 {
3145 	OSArray *           doPhase2List;
3146 	OSArray *           didPhase2List;
3147 	OSSet *             freeList;
3148 	OSIterator *        iter;
3149 	UInt32              workDone;
3150 	IOService *         victim;
3151 	IOService *         client;
3152 	IOService *         provider;
3153 	unsigned int        idx;
3154 	bool                moreToDo;
3155 	bool                doPhase2;
3156 	bool                doPhase3;
3157 
3158 	options |= kIOServiceRequired;
3159 
3160 	doPhase2List  = OSArray::withCapacity( 16 );
3161 	didPhase2List = OSArray::withCapacity( 16 );
3162 	freeList      = OSSet::withCapacity( 16 );
3163 	if ((NULL == doPhase2List) || (NULL == didPhase2List) || (NULL == freeList)) {
3164 		OSSafeReleaseNULL(doPhase2List);
3165 		OSSafeReleaseNULL(didPhase2List);
3166 		OSSafeReleaseNULL(freeList);
3167 		return;
3168 	}
3169 
3170 	do {
3171 		workDone = gIOTerminateWork;
3172 
3173 		while ((victim = (IOService *) gIOTerminatePhase2List->getObject(0))) {
3174 			victim->retain();
3175 			gIOTerminatePhase2List->removeObject(0);
3176 			IOLockUnlock( gJobsLock );
3177 
3178 			uint64_t regID1 = victim->getRegistryEntryID();
3179 			IOServiceTrace(
3180 				IOSERVICE_TERM_START_PHASE2,
3181 				(uintptr_t) regID1,
3182 				(uintptr_t) (regID1 >> 32),
3183 				(uintptr_t) 0,
3184 				(uintptr_t) 0);
3185 
3186 			while (victim) {
3187 				doPhase2 = victim->lockForArbitration( true );
3188 				if (doPhase2) {
3189 					doPhase2 = (0 != (kIOServiceInactiveState & victim->__state[0]));
3190 					if (doPhase2) {
3191 						uint64_t regID1 = victim->getRegistryEntryID();
3192 						IOServiceTrace(
3193 							IOSERVICE_TERM_TRY_PHASE2,
3194 							(uintptr_t) regID1,
3195 							(uintptr_t) (regID1 >> 32),
3196 							(uintptr_t) victim->__state[1],
3197 							(uintptr_t) 0);
3198 
3199 						doPhase2 = (0 == (victim->__state[1] &
3200 						    (kIOServiceTermPhase1State
3201 						    | kIOServiceTermPhase2State
3202 						    | kIOServiceConfigState)));
3203 
3204 						if (doPhase2 && (iter = victim->getClientIterator())) {
3205 							while (doPhase2 && (client = (IOService *) iter->getNextObject())) {
3206 								doPhase2 = (0 == (client->__state[1] & kIOServiceStartState));
3207 								if (!doPhase2) {
3208 									uint64_t regID1 = client->getRegistryEntryID();
3209 									IOServiceTrace(
3210 										IOSERVICE_TERM_UC_DEFER,
3211 										(uintptr_t) regID1,
3212 										(uintptr_t) (regID1 >> 32),
3213 										(uintptr_t) client->__state[1],
3214 										(uintptr_t) 0);
3215 									TLOG("%s[0x%qx]::defer phase2(%s[0x%qx])\n",
3216 									    victim->getName(), victim->getRegistryEntryID(),
3217 									    client->getName(), client->getRegistryEntryID());
3218 								}
3219 							}
3220 							iter->release();
3221 						}
3222 						if (doPhase2) {
3223 							victim->__state[1] |= kIOServiceTermPhase2State;
3224 						}
3225 					}
3226 					victim->unlockForArbitration();
3227 				}
3228 				if (doPhase2) {
3229 					if (kIOServiceNeedWillTerminate & victim->__state[1]) {
3230 						if (NULL == victim->reserved->uvars) {
3231 							_workLoopAction((IOWorkLoop::Action) &actionWillStop,
3232 							    victim, (void *)(uintptr_t) options);
3233 						} else {
3234 							actionWillStop(victim, options, NULL, NULL, NULL);
3235 						}
3236 					}
3237 
3238 					OSArray * notifiers;
3239 					notifiers = victim->copyNotifiers(gIOWillTerminateNotification, 0, 0xffffffff);
3240 					victim->invokeNotifiers(&notifiers);
3241 
3242 					_workLoopAction((IOWorkLoop::Action) &actionWillTerminate,
3243 					    victim,
3244 					    (void *)(uintptr_t) options,
3245 					    (void *)(uintptr_t) doPhase2List,
3246 					    (void *)(uintptr_t) false);
3247 
3248 					actionWillTerminate(
3249 						victim, options, doPhase2List, true, NULL);
3250 
3251 					didPhase2List->headQ( victim );
3252 				}
3253 				victim->release();
3254 				victim = (IOService *) doPhase2List->getObject(0);
3255 				if (victim) {
3256 					victim->retain();
3257 					doPhase2List->removeObject(0);
3258 				}
3259 			}
3260 
3261 			while ((victim = (IOService *) didPhase2List->getObject(0))) {
3262 				bool scheduleFinalize = false;
3263 				if (victim->lockForArbitration( true )) {
3264 					victim->__state[1] |= kIOServiceTermPhase3State;
3265 					scheduleFinalize = (NULL == victim->getClient());
3266 					victim->unlockForArbitration();
3267 				}
3268 				_workLoopAction((IOWorkLoop::Action) &actionDidTerminate,
3269 				    victim, (void *)(uintptr_t) options );
3270 				if (kIOServiceNeedWillTerminate & victim->__state[1]) {
3271 					_workLoopAction((IOWorkLoop::Action) &actionDidStop,
3272 					    victim, (void *)(uintptr_t) options, NULL );
3273 				}
3274 				// no clients - will go to finalize
3275 				if (scheduleFinalize) {
3276 					victim->scheduleFinalize(false);
3277 				}
3278 				didPhase2List->removeObject(0);
3279 			}
3280 			IOLockLock( gJobsLock );
3281 		}
3282 
3283 		// phase 3
3284 		do {
3285 			doPhase3 = false;
3286 			// finalize leaves
3287 			while ((victim = (IOService *) gIOFinalizeList->getObject(0))) {
3288 				bool sendFinal = false;
3289 				IOLockUnlock( gJobsLock );
3290 				if (victim->lockForArbitration(true)) {
3291 					sendFinal = (0 == (victim->__state[1] & kIOServiceFinalized));
3292 					if (sendFinal) {
3293 						victim->__state[1] |= kIOServiceFinalized;
3294 					}
3295 					victim->unlockForArbitration();
3296 				}
3297 				if (sendFinal) {
3298 					_workLoopAction((IOWorkLoop::Action) &actionFinalize,
3299 					    victim, (void *)(uintptr_t) options );
3300 				}
3301 				IOLockLock( gJobsLock );
3302 				// hold off free
3303 				freeList->setObject( victim );
3304 				// safe if finalize list is append only
3305 				gIOFinalizeList->removeObject(0);
3306 			}
3307 
3308 			for (idx = 0;
3309 			    (!doPhase3) && (client = (IOService *) gIOStopList->getObject(idx));) {
3310 				provider = (IOService *) gIOStopProviderList->getObject(idx);
3311 				assert( provider );
3312 
3313 				uint64_t regID1 = provider->getRegistryEntryID();
3314 				uint64_t regID2 = client->getRegistryEntryID();
3315 
3316 				if (!provider->isChild( client, gIOServicePlane )) {
3317 					// may be multiply queued - nop it
3318 					TLOG("%s[0x%qx]::nop stop(%s[0x%qx])\n", client->getName(), regID2, provider->getName(), regID1);
3319 					IOServiceTrace(
3320 						IOSERVICE_TERMINATE_STOP_NOP,
3321 						(uintptr_t) regID1,
3322 						(uintptr_t) (regID1 >> 32),
3323 						(uintptr_t) regID2,
3324 						(uintptr_t) (regID2 >> 32));
3325 				} else {
3326 					// a terminated client is not ready for stop if it has clients, skip it
3327 					bool deferStop = (0 != (kIOServiceInactiveState & client->__state[0]));
3328 					IOLockUnlock( gJobsLock );
3329 					if (deferStop && client->lockForArbitration(true)) {
3330 						deferStop = (0 == (client->__state[1] & kIOServiceFinalized));
3331 						//deferStop = (!deferStop && (0 != client->getClient()));
3332 						//deferStop = (0 != client->getClient());
3333 						client->unlockForArbitration();
3334 						if (deferStop) {
3335 							TLOG("%s[0x%qx]::defer stop()\n", client->getName(), regID2);
3336 							IOServiceTrace(IOSERVICE_TERMINATE_STOP_DEFER,
3337 							    (uintptr_t) regID1,
3338 							    (uintptr_t) (regID1 >> 32),
3339 							    (uintptr_t) regID2,
3340 							    (uintptr_t) (regID2 >> 32));
3341 
3342 							idx++;
3343 							IOLockLock( gJobsLock );
3344 							continue;
3345 						}
3346 					}
3347 					_workLoopAction((IOWorkLoop::Action) &actionStop,
3348 					    provider, (void *) client );
3349 					IOLockLock( gJobsLock );
3350 					// check the finalize list now
3351 					doPhase3 = true;
3352 				}
3353 				// hold off free
3354 				freeList->setObject( client );
3355 				freeList->setObject( provider );
3356 
3357 				// safe if stop list is append only
3358 				gIOStopList->removeObject( idx );
3359 				gIOStopProviderList->removeObject( idx );
3360 				idx = 0;
3361 			}
3362 		} while (doPhase3);
3363 
3364 		gIOTerminateWork -= workDone;
3365 		moreToDo = (gIOTerminateWork != 0);
3366 
3367 		if (!moreToDo) {
3368 			TLOG("iokit terminate done, %d stops remain\n", gIOStopList->getCount());
3369 			IOServiceTrace(
3370 				IOSERVICE_TERMINATE_DONE,
3371 				(uintptr_t) gIOStopList->getCount(), 0, 0, 0);
3372 		}
3373 	} while (moreToDo);
3374 
3375 	IOLockUnlock( gJobsLock );
3376 
3377 	freeList->release();
3378 	doPhase2List->release();
3379 	didPhase2List->release();
3380 
3381 	IOLockLock( gJobsLock );
3382 }
3383 
3384 #pragma clang diagnostic pop
3385 
3386 bool
finalize(IOOptionBits options)3387 IOService::finalize( IOOptionBits options )
3388 {
3389 	OSIterator *  iter;
3390 	IOService *   provider;
3391 	uint64_t      regID1, regID2 = getRegistryEntryID();
3392 
3393 	iter = getProviderIterator();
3394 	assert( iter );
3395 
3396 	if (iter) {
3397 		while ((provider = (IOService *) iter->getNextObject())) {
3398 			// -- compat
3399 			if (0 == (__state[1] & kIOServiceTermPhase3State)) {
3400 				/* we come down here on programmatic terminate */
3401 
3402 				regID1 = provider->getRegistryEntryID();
3403 				TLOG("%s[0x%qx]::stop1(%s[0x%qx])\n", getName(), regID2, provider->getName(), regID1);
3404 				IOServiceTrace(
3405 					IOSERVICE_TERMINATE_STOP,
3406 					(uintptr_t) regID1,
3407 					(uintptr_t) (regID1 >> 32),
3408 					(uintptr_t) regID2,
3409 					(uintptr_t) (regID2 >> 32));
3410 
3411 				stop( provider );
3412 				if (provider->isOpen( this )) {
3413 					provider->close( this );
3414 				}
3415 				detach( provider );
3416 			} else {
3417 				//--
3418 				if (provider->lockForArbitration( true )) {
3419 					if (0 == (provider->__state[1] & kIOServiceTermPhase3State)) {
3420 						scheduleStop( provider );
3421 					}
3422 					provider->unlockForArbitration();
3423 				}
3424 			}
3425 		}
3426 		iter->release();
3427 	}
3428 
3429 	return true;
3430 }
3431 
3432 #undef tailQ
3433 #undef headQ
3434 
3435 /*
3436  * Terminate
3437  */
3438 
3439 void
doServiceTerminate(IOOptionBits options)3440 IOService::doServiceTerminate( IOOptionBits options )
3441 {
3442 }
3443 
3444 // a method in case someone needs to override it
3445 bool
terminateClient(IOService * client,IOOptionBits options)3446 IOService::terminateClient( IOService * client, IOOptionBits options )
3447 {
3448 	bool ok;
3449 
3450 	if (client->isParent( this, gIOServicePlane, true)) {
3451 		// we are the clients only provider
3452 		ok = client->terminate( options );
3453 	} else {
3454 		ok = true;
3455 	}
3456 
3457 	return ok;
3458 }
3459 
3460 bool
terminate(IOOptionBits options)3461 IOService::terminate( IOOptionBits options )
3462 {
3463 	options |= kIOServiceTerminate;
3464 
3465 	return terminatePhase1( options );
3466 }
3467 
3468 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3469 
3470 /*
3471  * Open & close
3472  */
3473 
3474 struct ServiceOpenMessageContext {
3475 	IOService *  service;
3476 	UInt32       type;
3477 	IOService *  excludeClient;
3478 	IOOptionBits options;
3479 };
3480 
3481 static void
serviceOpenMessageApplier(OSObject * object,void * ctx)3482 serviceOpenMessageApplier( OSObject * object, void * ctx )
3483 {
3484 	ServiceOpenMessageContext * context = (ServiceOpenMessageContext *) ctx;
3485 
3486 	if (object != context->excludeClient) {
3487 		context->service->messageClient( context->type, object, (void *)(uintptr_t) context->options );
3488 	}
3489 }
3490 
3491 bool
open(IOService * forClient,IOOptionBits options,void * arg)3492 IOService::open(   IOService *     forClient,
3493     IOOptionBits    options,
3494     void *          arg )
3495 {
3496 	bool                        ok;
3497 	kern_return_t               ret = kIOReturnSuccess;
3498 	ServiceOpenMessageContext   context;
3499 
3500 	context.service             = this;
3501 	context.type                = kIOMessageServiceIsAttemptingOpen;
3502 	context.excludeClient       = forClient;
3503 	context.options             = options;
3504 
3505 	applyToInterested( gIOGeneralInterest,
3506 	    &serviceOpenMessageApplier, &context );
3507 
3508 	if (false == lockForArbitration(false)) {
3509 		return false;
3510 	}
3511 
3512 	ok = (0 == (__state[0] & kIOServiceInactiveState));
3513 
3514 	if (ok && forClient && forClient->reserved->uvars && forClient->reserved->uvars->userServer) {
3515 		ret = forClient->reserved->uvars->userServer->serviceOpen(this, forClient);
3516 		if (ret != kIOReturnSuccess) {
3517 			ok = false;
3518 		}
3519 	}
3520 
3521 	if (ok) {
3522 		ok = handleOpen( forClient, options, arg );
3523 
3524 		if (!ok && forClient && forClient->reserved->uvars && forClient->reserved->uvars->userServer) {
3525 			forClient->reserved->uvars->userServer->serviceClose(this, forClient);
3526 		}
3527 	}
3528 
3529 	unlockForArbitration();
3530 
3531 	return ok;
3532 }
3533 
3534 void
close(IOService * forClient,IOOptionBits options)3535 IOService::close(  IOService *     forClient,
3536     IOOptionBits    options )
3537 {
3538 	bool                wasClosed;
3539 	bool                last = false;
3540 
3541 	lockForArbitration();
3542 
3543 	wasClosed = handleIsOpen( forClient );
3544 	if (wasClosed) {
3545 		handleClose( forClient, options );
3546 		last = (__state[1] & kIOServiceTermPhase3State);
3547 
3548 		if (forClient && forClient->reserved->uvars && forClient->reserved->uvars->userServer) {
3549 			forClient->reserved->uvars->userServer->serviceClose(this, forClient);
3550 		}
3551 	}
3552 
3553 	unlockForArbitration();
3554 
3555 	if (last) {
3556 		forClient->scheduleStop( this );
3557 	} else if (wasClosed) {
3558 		ServiceOpenMessageContext context;
3559 
3560 		context.service         = this;
3561 		context.type            = kIOMessageServiceWasClosed;
3562 		context.excludeClient   = forClient;
3563 		context.options         = options;
3564 
3565 		applyToInterested( gIOGeneralInterest,
3566 		    &serviceOpenMessageApplier, &context );
3567 	}
3568 }
3569 
3570 bool
isOpen(const IOService * forClient) const3571 IOService::isOpen( const IOService * forClient ) const
3572 {
3573 	IOService * self = (IOService *) this;
3574 	bool ok;
3575 
3576 	self->lockForArbitration();
3577 
3578 	ok = handleIsOpen( forClient );
3579 
3580 	self->unlockForArbitration();
3581 
3582 	return ok;
3583 }
3584 
3585 bool
handleOpen(IOService * forClient,IOOptionBits options,void * arg)3586 IOService::handleOpen(     IOService *     forClient,
3587     IOOptionBits    options,
3588     void *          arg )
3589 {
3590 	bool        ok;
3591 
3592 	ok = (NULL == __owner);
3593 	if (ok) {
3594 		__owner = forClient;
3595 	} else if (options & kIOServiceSeize) {
3596 		ok = (kIOReturnSuccess == messageClient( kIOMessageServiceIsRequestingClose,
3597 		    __owner, (void *)(uintptr_t) options ));
3598 		if (ok && (NULL == __owner)) {
3599 			__owner = forClient;
3600 		} else {
3601 			ok = false;
3602 		}
3603 	}
3604 	return ok;
3605 }
3606 
3607 void
handleClose(IOService * forClient,IOOptionBits options)3608 IOService::handleClose(    IOService *     forClient,
3609     IOOptionBits    options )
3610 {
3611 	if (__owner == forClient) {
3612 		__owner = NULL;
3613 	}
3614 }
3615 
3616 bool
handleIsOpen(const IOService * forClient) const3617 IOService::handleIsOpen(   const IOService * forClient ) const
3618 {
3619 	if (forClient) {
3620 		return __owner == forClient;
3621 	} else {
3622 		return __owner != forClient;
3623 	}
3624 }
3625 
3626 /*
3627  * Probing & starting
3628  */
3629 static SInt32
IONotifyOrdering(const OSMetaClassBase * inObj1,const OSMetaClassBase * inObj2,void * ref)3630 IONotifyOrdering( const OSMetaClassBase * inObj1, const OSMetaClassBase * inObj2, void * ref )
3631 {
3632 	const _IOServiceNotifier * obj1 = (const _IOServiceNotifier *) inObj1;
3633 	const _IOServiceNotifier * obj2 = (const _IOServiceNotifier *) inObj2;
3634 	SInt32             val1;
3635 	SInt32             val2;
3636 
3637 	val1 = 0;
3638 	val2 = 0;
3639 	if (obj1) {
3640 		val1 = obj1->priority;
3641 	}
3642 	if (obj2) {
3643 		val2 = obj2->priority;
3644 	}
3645 	if (val1 > val2) {
3646 		return 1;
3647 	}
3648 	if (val1 < val2) {
3649 		return -1;
3650 	}
3651 	return 0;
3652 }
3653 
3654 static SInt32
IOServiceObjectOrder(const OSObject * entry,void * ref)3655 IOServiceObjectOrder( const OSObject * entry, void * ref)
3656 {
3657 	OSDictionary *      dict;
3658 	IOService *         service;
3659 	_IOServiceNotifier * notify;
3660 	OSSymbol *          key = (OSSymbol *) ref;
3661 	OSNumber *          offset;
3662 	OSObject *          prop;
3663 	SInt32              result;
3664 
3665 	prop = NULL;
3666 	result = kIODefaultProbeScore;
3667 	if ((dict = OSDynamicCast( OSDictionary, entry))) {
3668 		offset = OSDynamicCast(OSNumber, dict->getObject( key ));
3669 	} else if ((notify = OSDynamicCast( _IOServiceNotifier, entry))) {
3670 		return notify->priority;
3671 	} else if ((service = OSDynamicCast( IOService, entry))) {
3672 		prop = service->copyProperty(key);
3673 		offset = OSDynamicCast(OSNumber, prop);
3674 	} else {
3675 		assert( false );
3676 		offset = NULL;
3677 	}
3678 
3679 	if (offset) {
3680 		result = offset->unsigned32BitValue();
3681 	}
3682 
3683 	OSSafeReleaseNULL(prop);
3684 
3685 	return result;
3686 }
3687 
3688 __attribute__((no_sanitize("signed-integer-overflow"))) SInt32
IOServiceOrdering(const OSMetaClassBase * inObj1,const OSMetaClassBase * inObj2,void * ref)3689 IOServiceOrdering( const OSMetaClassBase * inObj1, const OSMetaClassBase * inObj2, void * ref )
3690 {
3691 	const OSObject *    obj1 = (const OSObject *) inObj1;
3692 	const OSObject *    obj2 = (const OSObject *) inObj2;
3693 	SInt32               val1;
3694 	SInt32               val2;
3695 
3696 	val1 = 0;
3697 	val2 = 0;
3698 
3699 	if (obj1) {
3700 		val1 = IOServiceObjectOrder( obj1, ref );
3701 	}
3702 
3703 	if (obj2) {
3704 		val2 = IOServiceObjectOrder( obj2, ref );
3705 	}
3706 
3707 	return val1 - val2;
3708 }
3709 
3710 IOService *
copyClientWithCategory(const OSSymbol * category)3711 IOService::copyClientWithCategory( const OSSymbol * category )
3712 {
3713 	IOService *         service = NULL;
3714 	OSIterator *        iter;
3715 	const OSSymbol *    nextCat;
3716 
3717 	iter = getClientIterator();
3718 	if (iter) {
3719 		while ((service = (IOService *) iter->getNextObject())) {
3720 			if (kIOServiceInactiveState & service->__state[0]) {
3721 				if (!(kIOServiceRematchOnDetach & service->__state[1])) {
3722 					continue;
3723 				}
3724 			}
3725 			nextCat = (const OSSymbol *) OSDynamicCast( OSSymbol,
3726 			    service->getProperty( gIOMatchCategoryKey ));
3727 			if (category == nextCat) {
3728 				service->retain();
3729 				break;
3730 			}
3731 		}
3732 		iter->release();
3733 	}
3734 	return service;
3735 }
3736 
3737 IOService *
getClientWithCategory(const OSSymbol * category)3738 IOService::getClientWithCategory( const OSSymbol * category )
3739 {
3740 	IOService *
3741 	    service = copyClientWithCategory(category);
3742 	if (service) {
3743 		service->release();
3744 	}
3745 	return service;
3746 }
3747 
3748 bool
invokeNotifier(_IOServiceNotifier * notify)3749 IOService::invokeNotifier( _IOServiceNotifier * notify )
3750 {
3751 	_IOServiceNotifierInvocation invocation;
3752 	bool                         willNotify;
3753 	bool                         ret = true;
3754 	invocation.thread = current_thread();
3755 
3756 #if DEBUG_NOTIFIER_LOCKED
3757 	uint32_t count;
3758 	if ((count = isLockedForArbitration(0))) {
3759 		IOLog("[%s, 0x%x]\n", notify->type->getCStringNoCopy(), count);
3760 		panic("[%s, 0x%x]", notify->type->getCStringNoCopy(), count);
3761 	}
3762 #endif /* DEBUG_NOTIFIER_LOCKED */
3763 
3764 	LOCKWRITENOTIFY();
3765 	willNotify = (0 != (kIOServiceNotifyEnable & notify->state));
3766 
3767 	if (willNotify) {
3768 		queue_enter( &notify->handlerInvocations, &invocation,
3769 		    _IOServiceNotifierInvocation *, link );
3770 	}
3771 	UNLOCKNOTIFY();
3772 
3773 	if (willNotify) {
3774 		ret = (*notify->handler)(notify->target, notify->ref, this, notify);
3775 
3776 		LOCKWRITENOTIFY();
3777 		queue_remove( &notify->handlerInvocations, &invocation,
3778 		    _IOServiceNotifierInvocation *, link );
3779 		if (kIOServiceNotifyWaiter & notify->state) {
3780 			notify->state &= ~kIOServiceNotifyWaiter;
3781 			WAKEUPNOTIFY( notify );
3782 		}
3783 		UNLOCKNOTIFY();
3784 	}
3785 
3786 	return ret;
3787 }
3788 
3789 bool
invokeNotifiers(OSArray * willSend[])3790 IOService::invokeNotifiers(OSArray * willSend[])
3791 {
3792 	OSArray *            array;
3793 	_IOServiceNotifier * notify;
3794 	bool                 ret = true;
3795 
3796 	array = *willSend;
3797 	if (!array) {
3798 		return true;
3799 	}
3800 	*willSend = NULL;
3801 
3802 	for (unsigned int idx = 0;
3803 	    (notify = (_IOServiceNotifier *) array->getObject(idx));
3804 	    idx++) {
3805 		ret &= invokeNotifier(notify);
3806 	}
3807 	array->release();
3808 
3809 	return ret;
3810 }
3811 
3812 
3813 TUNABLE(bool, iokit_print_verbose_match_logs, "iokit_print_verbose_match_logs", false);
3814 
3815 /*
3816  * Alloc and probe matching classes,
3817  * called on the provider instance
3818  */
3819 
3820 void
probeCandidates(OSOrderedSet * matches)3821 IOService::probeCandidates( OSOrderedSet * matches )
3822 {
3823 	OSDictionary        *       match = NULL;
3824 	OSSymbol            *       symbol;
3825 	IOService           *       inst;
3826 	IOService           *       newInst;
3827 	OSDictionary        *       props;
3828 	SInt32                      score;
3829 	OSNumber            *       newPri;
3830 	OSOrderedSet        *       familyMatches = NULL;
3831 	OSOrderedSet        *       startList;
3832 	OSSet               *       kexts = NULL;
3833 	OSObject            *       kextRef;
3834 
3835 	OSDictionary        *       startDict = NULL;
3836 	const OSSymbol      *       category;
3837 	OSIterator          *       iter;
3838 	_IOServiceNotifier  *       notify;
3839 	OSObject            *       nextMatch = NULL;
3840 	bool                        started;
3841 	bool                        needReloc = false;
3842 	bool                        matchDeferred = false;
3843 #if IOMATCHDEBUG
3844 	SInt64                      debugFlags;
3845 #endif
3846 	IOService           *       client = NULL;
3847 	OSObject            *       prop1;
3848 	OSObject            *       rematchCountProp;
3849 	OSDictionary        *       rematchPersonality;
3850 	OSNumber            *       num;
3851 	uint32_t                    count;
3852 	uint32_t                    dextCount;
3853 	bool                        isDext;
3854 	bool                        categoryConsumed;
3855 
3856 	rematchCountProp = NULL;
3857 	count = 0;
3858 	prop1 = copyProperty(gIORematchPersonalityKey);
3859 	rematchPersonality = OSDynamicCast(OSDictionary, prop1);
3860 	if (rematchPersonality) {
3861 		rematchCountProp = copyProperty(gIORematchCountKey);
3862 		num = OSDynamicCast(OSNumber, rematchCountProp);
3863 		if (num) {
3864 			count = num->unsigned32BitValue();
3865 		}
3866 		removeProperty(gIORematchPersonalityKey);
3867 	}
3868 	dextCount = 0;
3869 
3870 	assert( matches );
3871 	while (!needReloc
3872 	    && (nextMatch = matches->getFirstObject())) {
3873 		nextMatch->retain();
3874 		matches->removeObject(nextMatch);
3875 
3876 		if ((notify = OSDynamicCast( _IOServiceNotifier, nextMatch ))) {
3877 			if (0 == (__state[0] & kIOServiceInactiveState)) {
3878 				invokeNotifier( notify );
3879 			}
3880 			nextMatch->release();
3881 			nextMatch = NULL;
3882 			continue;
3883 		} else if (!(match = OSDynamicCast( OSDictionary, nextMatch ))) {
3884 			nextMatch->release();
3885 			nextMatch = NULL;
3886 			continue;
3887 		}
3888 
3889 		props = NULL;
3890 #if IOMATCHDEBUG
3891 		debugFlags = getDebugFlags( match );
3892 #endif
3893 
3894 		bool newIsBoot = false;
3895 		bool existingIsBoot = false;
3896 		bool isReplacementCandidate = false;
3897 
3898 		do {
3899 			client = NULL;
3900 			isDext = (NULL != match->getObject(gIOUserServerNameKey));
3901 			if (isDext && !(kIODKEnable & gIODKDebug)) {
3902 				continue;
3903 			}
3904 			if (isDext && !gIODextRelaunchMax && rematchCountProp) {
3905 				continue;
3906 			}
3907 			newIsBoot = gIOCatalogue->personalityIsBoot(match);
3908 
3909 			category = OSDynamicCast( OSSymbol,
3910 			    match->getObject( gIOMatchCategoryKey ));
3911 			if (NULL == category) {
3912 				category = gIODefaultMatchCategoryKey;
3913 			}
3914 			client = copyClientWithCategory(category);
3915 
3916 			categoryConsumed = (client != NULL);
3917 			if (categoryConsumed) {
3918 #if IOMATCHDEBUG
3919 				if ((debugFlags & kIOLogMatch) && (this != gIOResources)) {
3920 					LOG("%s: match category %s exists\n", getName(),
3921 					    category->getCStringNoCopy());
3922 				}
3923 #endif
3924 				existingIsBoot = client->propertyExists(gIOMatchedAtBootKey);
3925 				isReplacementCandidate = existingIsBoot && !newIsBoot;
3926 				if (!isDext && !isReplacementCandidate) {
3927 					break;
3928 				}
3929 			}
3930 
3931 			// create a copy now in case its modified during matching
3932 			props = OSDictionary::withDictionary(match, match->getCount());
3933 			if (NULL == props) {
3934 				break;
3935 			}
3936 			props->setCapacityIncrement(1);
3937 
3938 			// check the nub matches
3939 			if (false == matchPassive(props, kIOServiceChangesOK | kIOServiceClassDone)) {
3940 				break;
3941 			}
3942 			if (isReplacementCandidate) {
3943 				if (canTerminateForReplacement(client)) {
3944 					client->terminate(kIOServiceTerminateNeedWillTerminate | kIOServiceTerminateWithRematch);
3945 					break;
3946 				}
3947 			}
3948 
3949 			if (isDext || isReplacementCandidate) {
3950 				if (isDext) {
3951 					dextCount++;
3952 				}
3953 				if (categoryConsumed) {
3954 					break;
3955 				}
3956 			}
3957 			if (rematchPersonality) {
3958 				bool personalityMatch = match->isEqualTo(rematchPersonality);
3959 				if (count > gIODextRelaunchMax) {
3960 					personalityMatch = !personalityMatch;
3961 				}
3962 				if (!personalityMatch) {
3963 					break;
3964 				}
3965 			}
3966 
3967 			// Check to see if driver reloc has been loaded.
3968 			needReloc = (false == gIOCatalogue->isModuleLoaded( match, &kextRef ));
3969 			if (needReloc) {
3970 #if IOMATCHDEBUG
3971 				if (debugFlags & kIOLogCatalogue) {
3972 					LOG("%s: stalling for module\n", getName());
3973 				}
3974 #endif
3975 				// If reloc hasn't been loaded, exit;
3976 				// reprobing will occur after reloc has been loaded.
3977 				break;
3978 			}
3979 			if (kextRef) {
3980 				if (NULL == kexts) {
3981 					kexts = OSSet::withCapacity(1);
3982 				}
3983 				if (kexts) {
3984 					kexts->setObject(kextRef);
3985 					kextRef->release();
3986 				}
3987 			}
3988 			if (newIsBoot) {
3989 				props->setObject(gIOMatchedAtBootKey, kOSBooleanTrue);
3990 			}
3991 			if (isDext) {
3992 				// copy saved for rematchng
3993 				props->setObject(gIOMatchedPersonalityKey, match);
3994 			}
3995 			// reorder on family matchPropertyTable score.
3996 			if (NULL == familyMatches) {
3997 				familyMatches = OSOrderedSet::withCapacity( 1,
3998 				    IOServiceOrdering, (void *) gIOProbeScoreKey );
3999 			}
4000 			if (familyMatches) {
4001 				familyMatches->setObject( props );
4002 			}
4003 		} while (false);
4004 
4005 		OSSafeReleaseNULL(client);
4006 		OSSafeReleaseNULL(nextMatch);
4007 		OSSafeReleaseNULL(props);
4008 	}
4009 	OSSafeReleaseNULL(matches);
4010 	OSSafeReleaseNULL(rematchCountProp);
4011 
4012 	if (familyMatches) {
4013 		while (!needReloc
4014 		    && (props = (OSDictionary *) familyMatches->getFirstObject())) {
4015 			props->retain();
4016 			familyMatches->removeObject( props );
4017 
4018 			inst = NULL;
4019 			newInst = NULL;
4020 #if IOMATCHDEBUG
4021 			debugFlags = getDebugFlags( props );
4022 #endif
4023 			do {
4024 				symbol = OSDynamicCast( OSSymbol,
4025 				    props->getObject( gIOClassKey));
4026 				if (!symbol) {
4027 					continue;
4028 				}
4029 
4030 				//IOLog("%s alloc (symbol %p props %p)\n", symbol->getCStringNoCopy(), IOSERVICE_OBFUSCATE(symbol), IOSERVICE_OBFUSCATE(props));
4031 
4032 				// alloc the driver instance
4033 				inst = (IOService *) OSMetaClass::allocClassWithName( symbol);
4034 
4035 				if (!inst || !OSDynamicCast(IOService, inst)) {
4036 					IOLog("Couldn't alloc class \"%s\"\n",
4037 					    symbol->getCStringNoCopy());
4038 					continue;
4039 				}
4040 
4041 				// init driver instance
4042 				if (!(inst->init( props ))) {
4043 #if IOMATCHDEBUG
4044 					if (debugFlags & kIOLogStart) {
4045 						IOLog("%s::init fails\n", symbol->getCStringNoCopy());
4046 					}
4047 #endif
4048 					continue;
4049 				}
4050 				if (__state[1] & kIOServiceSynchronousState) {
4051 					inst->__state[1] |= kIOServiceSynchronousState;
4052 				}
4053 
4054 				// give the driver the default match category if not specified
4055 				category = OSDynamicCast( OSSymbol,
4056 				    props->getObject( gIOMatchCategoryKey ));
4057 				if (NULL == category) {
4058 					category = gIODefaultMatchCategoryKey;
4059 				}
4060 				inst->setProperty( gIOMatchCategoryKey, (OSObject *) category );
4061 				// attach driver instance
4062 				if (!(inst->attach( this ))) {
4063 					continue;
4064 				}
4065 
4066 				// pass in score from property table
4067 				score = familyMatches->orderObject( props );
4068 
4069 				// & probe the new driver instance
4070 #if IOMATCHDEBUG
4071 				if (debugFlags & kIOLogProbe) {
4072 					LOG("%s::probe(%s)\n",
4073 					    inst->getMetaClass()->getClassName(), getName());
4074 				}
4075 #endif
4076 				newInst = inst->probe( this, &score );
4077 				inst->detach( this );
4078 				if (NULL == newInst) {
4079 #if IOMATCHDEBUG
4080 					if (debugFlags & kIOLogProbe) {
4081 						IOLog("%s::probe fails\n", symbol->getCStringNoCopy());
4082 					}
4083 #endif
4084 					continue;
4085 				}
4086 
4087 				// save the score
4088 				newPri = OSNumber::withNumber( score, 32 );
4089 				if (newPri) {
4090 					newInst->setProperty( gIOProbeScoreKey, newPri );
4091 					newPri->release();
4092 				}
4093 
4094 				// add to start list for the match category
4095 				if (NULL == startDict) {
4096 					startDict = OSDictionary::withCapacity( 1 );
4097 				}
4098 				assert( startDict );
4099 				startList = (OSOrderedSet *)
4100 				    startDict->getObject( category );
4101 				if (NULL == startList) {
4102 					startList = OSOrderedSet::withCapacity( 1,
4103 					    IOServiceOrdering, (void *) gIOProbeScoreKey );
4104 					if (startDict && startList) {
4105 						startDict->setObject( category, startList );
4106 						startList->release();
4107 					}
4108 				}
4109 				assert( startList );
4110 				if (startList) {
4111 					startList->setObject( newInst );
4112 				}
4113 			} while (false);
4114 
4115 			props->release();
4116 			if (inst) {
4117 				inst->release();
4118 			}
4119 		}
4120 		familyMatches->release();
4121 		familyMatches = NULL;
4122 	}
4123 
4124 	if ((debugFlags & kIOLogMatch) && iokit_print_verbose_match_logs && startDict != NULL) {
4125 		IOLog("%s(0x%qx): %u categories\n", getName(), getRegistryEntryID(), startList->getCount());
4126 		startDict->iterateObjects(^(const OSSymbol *key, OSObject *value) {
4127 			OSOrderedSet *startList = OSDynamicCast(OSOrderedSet, value);
4128 			if (startList) {
4129 			        IOLog("%s(0x%qx): category %s, %u matches\n", getName(), getRegistryEntryID(), key->getCStringNoCopy(), startList->getCount());
4130 			        startList->iterateObjects(^(OSObject *obj) {
4131 					IOService *match = OSDynamicCast(IOService, obj);
4132 					OSNumber *probeScore = OSDynamicCast(OSNumber, match->getProperty(gIOProbeScoreKey));
4133 
4134 					if (match && probeScore) {
4135 					        IOLog("%s(0x%qx): category %s: matched %s, probe score %qd\n", getName(), getRegistryEntryID(), key->getCStringNoCopy(), match->getName(), probeScore->unsigned64BitValue());
4136 					}
4137 					return false;
4138 				});
4139 			}
4140 			return false;
4141 		});
4142 	}
4143 
4144 	// start the best (until success) of each category
4145 
4146 	iter = OSCollectionIterator::withCollection( startDict );
4147 	assert(startDict || !iter);
4148 	if (iter) {
4149 		while ((category = (const OSSymbol *) iter->getNextObject())) {
4150 			startList = (OSOrderedSet *) startDict->getObject( category );
4151 			assert( startList );
4152 			if (!startList) {
4153 				continue;
4154 			}
4155 			started = false;
4156 			while (true // (!started)
4157 			    && !matchDeferred
4158 			    && (inst = (IOService *)startList->getFirstObject())) {
4159 				inst->retain();
4160 				startList->removeObject(inst);
4161 #if IOMATCHDEBUG
4162 				debugFlags = getDebugFlags( inst );
4163 
4164 				if (debugFlags & kIOLogStart) {
4165 					if (started) {
4166 						LOG( "match category exists, skipping " );
4167 					}
4168 					LOG( "%s::start(%s) <%d>\n", inst->getName(),
4169 					    getName(), inst->getRetainCount());
4170 				}
4171 #endif
4172 				if (false == started) {
4173 #if !NO_KEXTD
4174 					IOLockLock(gJobsLock);
4175 					matchDeferred = (gIOMatchDeferList
4176 					    && kOSBooleanTrue == inst->getProperty(gIOMatchDeferKey));
4177 					if (matchDeferred && (-1U == gIOMatchDeferList->getNextIndexOfObject(this, 0))) {
4178 						gIOMatchDeferList->setObject(this);
4179 					}
4180 					if (matchDeferred) {
4181 						symbol = OSDynamicCast(OSSymbol, inst->getProperty(gIOClassKey));
4182 						IOLog("%s(0x%qx): matching deferred by %s%s\n",
4183 						    getName(), getRegistryEntryID(),
4184 						    symbol ? symbol->getCStringNoCopy() : "",
4185 						    gInUserspaceReboot ? " in userspace reboot" : "");
4186 						// rematching will occur after the IOKit daemon loads all plists
4187 					}
4188 					IOLockUnlock(gJobsLock);
4189 #endif
4190 					if (!matchDeferred) {
4191 						/* TODO
4192 						 * If a dext fails to start because an upgrade happened
4193 						 * concurrently, then the matching process has to restart
4194 						 */
4195 						started = startCandidate( inst );
4196 #if IOMATCHDEBUG
4197 						if ((debugFlags & kIOLogStart) && (false == started)) {
4198 							LOG( "%s::start(%s) <%d> failed\n", inst->getName(), getName(),
4199 							    inst->getRetainCount());
4200 						}
4201 #endif
4202 						if (!started && inst->propertyExists(gIOServiceMatchDeferredKey)) {
4203 							matchDeferred = true;
4204 						}
4205 					}
4206 				}
4207 				inst->release();
4208 			}
4209 		}
4210 		iter->release();
4211 	}
4212 
4213 	OSSafeReleaseNULL(prop1);
4214 
4215 	if (dextCount) {
4216 		num = OSNumber::withNumber(dextCount, 32);
4217 		setProperty(gIODEXTMatchCountKey, num);
4218 		OSSafeReleaseNULL(num);
4219 	} else if (rematchPersonality) {
4220 		removeProperty(gIODEXTMatchCountKey);
4221 	}
4222 
4223 	// now that instances are created, drop the refs on any kexts allowing unload
4224 	if (kexts) {
4225 		OSKext::dropMatchingReferences(kexts);
4226 		OSSafeReleaseNULL(kexts);
4227 	}
4228 
4229 	// adjust the busy count by +1 if matching is stalled for a module,
4230 	// or -1 if a previously stalled matching is complete.
4231 	lockForArbitration();
4232 	SInt32 adjBusy = 0;
4233 	uint64_t regID = getRegistryEntryID();
4234 
4235 	if (needReloc) {
4236 		adjBusy = (__state[1] & kIOServiceModuleStallState) ? 0 : 1;
4237 		if (adjBusy) {
4238 			IOServiceTrace(
4239 				IOSERVICE_MODULESTALL,
4240 				(uintptr_t) regID,
4241 				(uintptr_t) (regID >> 32),
4242 				(uintptr_t) this,
4243 				0);
4244 
4245 			__state[1] |= kIOServiceModuleStallState;
4246 		}
4247 	} else if (__state[1] & kIOServiceModuleStallState) {
4248 		IOServiceTrace(
4249 			IOSERVICE_MODULEUNSTALL,
4250 			(uintptr_t) regID,
4251 			(uintptr_t) (regID >> 32),
4252 			(uintptr_t) this,
4253 			0);
4254 
4255 		__state[1] &= ~kIOServiceModuleStallState;
4256 		adjBusy = -1;
4257 	}
4258 	if (adjBusy) {
4259 		_adjustBusy( adjBusy );
4260 	}
4261 	unlockForArbitration();
4262 
4263 	if (startDict) {
4264 		startDict->release();
4265 	}
4266 }
4267 
4268 /*
4269  * Wait for a IOUserServer to check in
4270  */
4271 
4272 static
4273 __attribute__((noinline, not_tail_called))
4274 IOUserServer *
__WAITING_FOR_USER_SERVER__(IOUserServerCheckInToken * token)4275 __WAITING_FOR_USER_SERVER__(IOUserServerCheckInToken * token)
4276 {
4277 	IOUserServer * result = NULL;
4278 	IOService * server = NULL;
4279 	const OSSymbol * serverName = token->copyServerName();
4280 	OSNumber       * serverTag = token->copyServerTag();
4281 	OSDictionary   * matching = IOService::serviceMatching(gIOUserServerClassKey);
4282 
4283 	if (!matching || !serverName || !serverTag) {
4284 		goto finish;
4285 	}
4286 	IOService::propertyMatching(gIOUserServerNameKey, serverName, matching);
4287 	if (!(kIODKDisableDextTag & gIODKDebug)) {
4288 		IOService::propertyMatching(gIOUserServerTagKey, serverTag, matching);
4289 	}
4290 
4291 	server = IOService::waitForMatchingServiceWithToken(matching, kIOUserServerCheckInTimeoutSecs * NSEC_PER_SEC, token);
4292 	result = OSDynamicCast(IOUserServer, server);
4293 	if (!result) {
4294 		OSSafeReleaseNULL(server);
4295 		token->cancel();
4296 	}
4297 
4298 finish:
4299 	OSSafeReleaseNULL(matching);
4300 	OSSafeReleaseNULL(serverName);
4301 	OSSafeReleaseNULL(serverTag);
4302 
4303 	return result;
4304 }
4305 
4306 void
willShutdown()4307 IOService::willShutdown()
4308 {
4309 	gIOKitWillTerminate = true;
4310 #if !NO_KEXTD
4311 	IOUserServerCheckInToken::cancelAll();
4312 #endif
4313 	OSKext::willShutdown();
4314 }
4315 
4316 void
userSpaceWillReboot()4317 IOService::userSpaceWillReboot()
4318 {
4319 	IOLockLock(gJobsLock);
4320 #if !NO_KEXTD
4321 	IOService  * provider;
4322 	IOService  * service;
4323 	OSIterator * iter;
4324 
4325 	// Recreate the defer list if it does not exist
4326 	if (!gIOMatchDeferList && OSKext::iokitDaemonAvailable()) {
4327 		gIOMatchDeferList = OSArray::withCapacity( 16 );
4328 	}
4329 
4330 	if (gIOMatchDeferList) {
4331 		iter = IORegistryIterator::iterateOver(gIOServicePlane, kIORegistryIterateRecursively);
4332 		if (iter) {
4333 			do {
4334 				iter->reset();
4335 				while ((service = (IOService *)iter->getNextObject())) {
4336 					/* Rematch providers of services that will be terminated on userspace reboot, after the userspace reboot
4337 					 * is complete. This normally happens automatically as the IOKit daemon sends personalities to the kernel
4338 					 * which triggers rematching. But if this doesn't happen (for example, if a feature flag is turned off),
4339 					 * then these services will never get rematched.
4340 					 */
4341 					if (service->propertyHasValue(gIOMatchDeferKey, kOSBooleanTrue) || service->hasUserServer()) {
4342 						provider = service->getProvider();
4343 						IOLog("deferring %s-%llx (provider of %s-%llx) matching after userspace reboot\n",
4344 						    provider->getName(), provider->getRegistryEntryID(), service->getName(), service->getRegistryEntryID());
4345 						gIOMatchDeferList->setObject(provider);
4346 					}
4347 				}
4348 			} while (!service && !iter->isValid());
4349 
4350 			OSSafeReleaseNULL(iter);
4351 		}
4352 	}
4353 #endif
4354 	gInUserspaceReboot = true;
4355 	IOLockUnlock(gJobsLock);
4356 }
4357 
4358 void
userSpaceDidReboot()4359 IOService::userSpaceDidReboot()
4360 {
4361 	IOLockLock(gJobsLock);
4362 	gInUserspaceReboot = false;
4363 	IOLockUnlock(gJobsLock);
4364 }
4365 
4366 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
4367 
4368 void
init(IOPMrootDomain * root)4369 IOServicePH::init(IOPMrootDomain * root)
4370 {
4371 	fUserServers     = OSArray::withCapacity(4);
4372 	fMatchingWork    = OSArray::withCapacity(4);
4373 
4374 	assert(fUserServers && fMatchingWork);
4375 
4376 	fRootNotifier = root->registerInterest(
4377 		gIOPriorityPowerStateInterest, &IOServicePH::systemPowerChange, NULL, NULL);
4378 
4379 	assert(fRootNotifier);
4380 
4381 	fUserServerAckTimer = thread_call_allocate(&IOServicePH::userServerAckTimerExpired, (thread_call_param_t)NULL);
4382 }
4383 
4384 void
lock()4385 IOServicePH::lock()
4386 {
4387 	IOLockLock(gJobsLock);
4388 }
4389 
4390 void
unlock()4391 IOServicePH::unlock()
4392 {
4393 	IOLockUnlock(gJobsLock);
4394 }
4395 
4396 void
serverAdd(IOUserServer * server)4397 IOServicePH::serverAdd(IOUserServer * server)
4398 {
4399 	uint32_t idx;
4400 
4401 	lock();
4402 	idx = fUserServers->getNextIndexOfObject(server, 0);
4403 	if (idx == -1U) {
4404 		fUserServers->setObject(server);
4405 	}
4406 	unlock();
4407 }
4408 
4409 void
serverRemove(IOUserServer * server)4410 IOServicePH::serverRemove(IOUserServer * server)
4411 {
4412 	uint32_t idx;
4413 
4414 	lock();
4415 	idx = fUserServers->getNextIndexOfObject(server, 0);
4416 	if (idx != -1U) {
4417 		fUserServers->removeObject(idx);
4418 	}
4419 
4420 	if (fWaitingUserServers) {
4421 		fWaitingUserServers = false;
4422 		IOLockWakeup(gJobsLock, &fWaitingUserServers, /* one-thread */ false);
4423 	}
4424 
4425 	unlock();
4426 }
4427 
4428 void
serverAck(IOUserServer * server)4429 IOServicePH::serverAck(IOUserServer * server)
4430 {
4431 	uint32_t    idx;
4432 	IOService * ackTo;
4433 	uint32_t    ackToRef;
4434 
4435 	ackTo = NULL;
4436 	lock();
4437 	if (server && fUserServersWait) {
4438 		idx = fUserServersWait->getNextIndexOfObject(server, 0);
4439 		if (idx != -1U) {
4440 			fUserServersWait->removeObject(idx);
4441 			if (0 == fUserServersWait->getCount()) {
4442 				OSSafeReleaseNULL(fUserServersWait);
4443 			}
4444 		}
4445 	}
4446 	if (!fUserServersWait && !fMatchingWork->getCount()) {
4447 		ackTo             = fSystemPowerAckTo;
4448 		ackToRef          = fSystemPowerAckRef;
4449 		fSystemPowerAckTo = NULL;
4450 		if (ackTo) {
4451 			thread_call_cancel(fUserServerAckTimer);
4452 		}
4453 	}
4454 	if (fUserServersWait && fUserServersWait->getCount() > 0 && fMatchingWork && fMatchingWork->getCount() > 0) {
4455 		DKLOG("Waiting for %u user servers, %u matching work\n", fUserServersWait->getCount(), fMatchingWork->getCount());
4456 	}
4457 	unlock();
4458 
4459 	if (ackTo) {
4460 		DKLOG("allowPowerChange\n");
4461 		ackTo->allowPowerChange((uintptr_t) ackToRef);
4462 	}
4463 }
4464 
4465 bool
matchingStart(IOService * service)4466 IOServicePH::matchingStart(IOService * service)
4467 {
4468 	uint32_t idx;
4469 	bool assertionActive = gIOPMRootDomain->acquireDriverKitMatchingAssertion() == kIOReturnSuccess;
4470 
4471 	lock();
4472 	bool matchNow = !fSystemOff && assertionActive;
4473 	if (matchNow) {
4474 		idx = fMatchingWork->getNextIndexOfObject(service, 0);
4475 		if (idx == -1U) {
4476 			fMatchingWork->setObject(service);
4477 		}
4478 	} else {
4479 		// Delay matching if system is transitioning to sleep
4480 		if (!fMatchingDelayed) {
4481 			fMatchingDelayed = OSArray::withObjects((const OSObject **) &service, 1, 1);
4482 		} else {
4483 			idx = fMatchingDelayed->getNextIndexOfObject(service, 0);
4484 			if (idx == -1U) {
4485 				fMatchingDelayed->setObject(service);
4486 			}
4487 		}
4488 	}
4489 	unlock();
4490 	if (!matchNow && assertionActive) {
4491 		gIOPMRootDomain->releaseDriverKitMatchingAssertion();
4492 	}
4493 
4494 	return matchNow;
4495 }
4496 
4497 void
matchingEnd(IOService * service)4498 IOServicePH::matchingEnd(IOService * service)
4499 {
4500 	uint32_t idx;
4501 	OSArray   * notifyServers;
4502 	OSArray   * deferredMatches;
4503 
4504 	notifyServers   = NULL;
4505 	deferredMatches = NULL;
4506 
4507 	if (service) {
4508 		gIOPMRootDomain->releaseDriverKitMatchingAssertion();
4509 	}
4510 
4511 	lock();
4512 
4513 	if (service) {
4514 		idx = fMatchingWork->getNextIndexOfObject(service, 0);
4515 		if (idx != -1U) {
4516 			fMatchingWork->removeObject(idx);
4517 		}
4518 	}
4519 
4520 
4521 	if ((fUserServerOff != fSystemOff) && fUserServers->getCount()) {
4522 		if (fSystemOff) {
4523 			if (0 == fMatchingWork->getCount()) {
4524 				fUserServersWait = OSArray::withArray(fUserServers);
4525 				notifyServers = OSArray::withArray(fUserServers);
4526 				fUserServerOff = fSystemOff;
4527 			}
4528 		} else {
4529 			notifyServers = OSArray::withArray(fUserServers);
4530 			fUserServerOff = fSystemOff;
4531 		}
4532 	}
4533 
4534 	if (!fSystemOff && fMatchingDelayed) {
4535 		deferredMatches = fMatchingDelayed;
4536 		fMatchingDelayed = NULL;
4537 	}
4538 
4539 	unlock();
4540 
4541 	if (notifyServers) {
4542 		notifyServers->iterateObjects(^bool (OSObject * obj) {
4543 			IOUserServer * us;
4544 			us = (typeof(us))obj;
4545 			us->systemPower(fSystemOff);
4546 			return false;
4547 		});
4548 		OSSafeReleaseNULL(notifyServers);
4549 	}
4550 
4551 	if (deferredMatches) {
4552 		DKLOG("sleep deferred rematching count %d\n", deferredMatches->getCount());
4553 		deferredMatches->iterateObjects(^bool (OSObject * obj)
4554 		{
4555 			((IOService *)obj)->startMatching(kIOServiceAsynchronous);
4556 			return false;
4557 		});
4558 		deferredMatches->release();
4559 	}
4560 
4561 	serverAck(NULL);
4562 }
4563 
4564 TUNABLE(uint32_t, dk_shutdown_timeout_ms, "dk_shutdown_timeout_ms", 5000);
4565 TUNABLE(bool, dk_panic_on_shutdown_hang, "dk_panic_on_shutdown_hang", false);
4566 TUNABLE(bool, dk_panic_on_setpowerstate_hang, "dk_panic_on_setpowerstate_hang", false);
4567 
4568 void
userServerAckTimerExpired(void *,void *)4569 IOServicePH::userServerAckTimerExpired(void *, void *)
4570 {
4571 	OSArray * userServers = NULL;
4572 	lock();
4573 	if (fSystemPowerAckTo) {
4574 		DKLOG("ack timer expired\n");
4575 		if (dk_panic_on_setpowerstate_hang) {
4576 			panic("DK ack timer expired after %u ms", dk_shutdown_timeout_ms);
4577 		}
4578 		userServers = fUserServersWait;
4579 		fUserServersWait = NULL;
4580 	}
4581 	unlock();
4582 
4583 	if (userServers != NULL) {
4584 		userServers->iterateObjects(^bool (OSObject *obj) {
4585 			IOUserServer * us = OSDynamicCast(IOUserServer, obj);
4586 			if (us) {
4587 			        DKLOG(DKS " power state transition failed\n", DKN(us));
4588 			        us->setPowerManagementFailed(true);
4589 			}
4590 			return false;
4591 		});
4592 		OSSafeReleaseNULL(userServers);
4593 	}
4594 
4595 	serverAck(NULL);
4596 }
4597 
4598 void
systemHalt(int howto)4599 IOServicePH::systemHalt(int howto)
4600 {
4601 	OSArray * notifyServers;
4602 	uint64_t  deadline;
4603 
4604 	lock();
4605 	notifyServers = OSArray::withArray(fUserServers);
4606 	unlock();
4607 
4608 	if (notifyServers) {
4609 		notifyServers->iterateObjects(^bool (OSObject * obj) {
4610 			IOUserServer * us;
4611 			us = (typeof(us))obj;
4612 			us->systemHalt(howto);
4613 			return false;
4614 		});
4615 		OSSafeReleaseNULL(notifyServers);
4616 	}
4617 
4618 	lock();
4619 	clock_interval_to_deadline(dk_shutdown_timeout_ms, kMillisecondScale, &deadline);
4620 	while (0 < fUserServers->getCount()) {
4621 		fWaitingUserServers = true;
4622 		__assert_only int waitResult =
4623 		    IOLockSleepDeadline(gJobsLock, &fWaitingUserServers, deadline, THREAD_UNINT);
4624 		assert((THREAD_AWAKENED == waitResult) || (THREAD_TIMED_OUT == waitResult));
4625 		if (THREAD_TIMED_OUT == waitResult) {
4626 			IOUserServer::beginLeakingObjects();
4627 #if DEVELOPMENT || DEBUG
4628 			if (dk_panic_on_shutdown_hang) {
4629 				panic("Shutdown timed out waiting for DK drivers to stop");
4630 			}
4631 #endif /* DEVELOPMENT || DEBUG */
4632 			break;
4633 		}
4634 	}
4635 	unlock();
4636 }
4637 
4638 bool
serverSlept(void)4639 IOServicePH::serverSlept(void)
4640 {
4641 	bool ret;
4642 
4643 	lock();
4644 	ret = (kIOMessageSystemWillSleep == sSystemPower)
4645 	    || (kIOMessageSystemWillPowerOff == sSystemPower)
4646 	    || (kIOMessageSystemWillRestart == sSystemPower);
4647 	unlock();
4648 
4649 	return ret;
4650 }
4651 
4652 TUNABLE(uint32_t, dk_power_state_timeout_ms, "dk_power_state_timeout_ms", 30000);
4653 
4654 IOReturn
systemPowerChange(void * target,void * refCon,UInt32 messageType,IOService * service,void * messageArgument,vm_size_t argSize)4655 IOServicePH::systemPowerChange(
4656 	void * target,
4657 	void * refCon,
4658 	UInt32 messageType, IOService * service,
4659 	void * messageArgument, vm_size_t argSize)
4660 {
4661 	IOReturn                               ret;
4662 	IOUserServer                         * us;
4663 	IOPMSystemCapabilityChangeParameters * params;
4664 	AbsoluteTime                           deadline;
4665 
4666 	us = NULL;
4667 
4668 	switch (messageType) {
4669 	case kIOMessageSystemCapabilityChange:
4670 
4671 		params = (typeof params)messageArgument;
4672 
4673 		if (kIODKLogPM & gIODKDebug) {
4674 			IOLog("IOServicePH::kIOMessageSystemCapabilityChange: %s%s 0x%x->0x%x\n",
4675 			    params->changeFlags & kIOPMSystemCapabilityWillChange ? "will" : "",
4676 			    params->changeFlags & kIOPMSystemCapabilityDidChange ? "did" : "",
4677 			    params->fromCapabilities,
4678 			    params->toCapabilities);
4679 		}
4680 
4681 		if ((params->changeFlags & kIOPMSystemCapabilityWillChange) &&
4682 		    (params->fromCapabilities & kIOPMSystemCapabilityCPU) &&
4683 		    ((params->toCapabilities & kIOPMSystemCapabilityCPU) == 0)) {
4684 			lock();
4685 			DKLOG("arming ack timer, %u ms\n", dk_power_state_timeout_ms);
4686 			clock_interval_to_deadline(dk_power_state_timeout_ms, kMillisecondScale, &deadline);
4687 			fSystemOff         = true;
4688 			fSystemPowerAckRef = params->notifyRef;
4689 			fSystemPowerAckTo  = service;
4690 			thread_call_enter_delayed(fUserServerAckTimer, deadline);
4691 			unlock();
4692 
4693 			matchingEnd(NULL);
4694 
4695 			params->maxWaitForReply = dk_power_state_timeout_ms * 2 * 1000;
4696 			ret = kIOReturnSuccess;
4697 		} else if ((params->changeFlags & kIOPMSystemCapabilityWillChange) &&
4698 		    ((params->fromCapabilities & kIOPMSystemCapabilityCPU) == 0) &&
4699 		    (params->toCapabilities & kIOPMSystemCapabilityCPU)) {
4700 			lock();
4701 			fSystemOff = false;
4702 			unlock();
4703 
4704 			matchingEnd(NULL);
4705 
4706 			params->maxWaitForReply = 0;
4707 			ret                 = kIOReturnSuccess;
4708 		} else {
4709 			params->maxWaitForReply = 0;
4710 			ret                 = kIOReturnSuccess;
4711 		}
4712 		break;
4713 
4714 	default:
4715 		ret = kIOReturnUnsupported;
4716 		break;
4717 	}
4718 
4719 	return ret;
4720 }
4721 
4722 bool
checkPMReady(void)4723 IOServicePH::checkPMReady(void)
4724 {
4725 	bool __block ready = true;
4726 
4727 	lock();
4728 	fUserServers->iterateObjects(^bool (OSObject *obj) {
4729 		IOUserServer * us = OSDynamicCast(IOUserServer, obj);
4730 		if (us) {
4731 		        if (!us->checkPMReady()) {
4732 		                ready = false;
4733 		                return true;
4734 			}
4735 		}
4736 		return false;
4737 	});
4738 	unlock();
4739 
4740 	return ready;
4741 }
4742 
4743 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
4744 
4745 /*
4746  * Start a previously attached & probed instance,
4747  * called on exporting object instance
4748  */
4749 
4750 bool
startCandidate(IOService * service)4751 IOService::startCandidate( IOService * service )
4752 {
4753 	bool                ok;
4754 	OSObject          * obj;
4755 	OSObject          * prop;
4756 	IOUserServer      * userServer;
4757 	bool                ph;
4758 
4759 	userServer = NULL;
4760 	obj = service->copyProperty(gIOUserServerNameKey);
4761 
4762 	if (obj && (this == gIOResources)) {
4763 		ok = false;
4764 	} else {
4765 		ok = service->attach( this );
4766 	}
4767 	if (!ok) {
4768 		OSSafeReleaseNULL(obj);
4769 		return false;
4770 	}
4771 
4772 	if ((this != gIOResources) && (this != gIOUserResources)) {
4773 		// stall for any nub resources
4774 		checkResources();
4775 		// stall for any driver resources
4776 		service->checkResources();
4777 	}
4778 	ph = false;
4779 	{
4780 		OSString       * bundleID;
4781 		OSString       * serverName;
4782 		OSString       * str;
4783 		const OSSymbol * sym;
4784 		OSNumber       * serverTag;
4785 		uint64_t         entryID;
4786 		IOUserServerCheckInToken * token;
4787 		OSData         * serverDUI;
4788 
4789 		if ((serverName = OSDynamicCast(OSString, obj))) {
4790 			obj       = service->copyProperty(gIOModuleIdentifierKey);
4791 			bundleID  = OSDynamicCast(OSString, obj);
4792 			entryID   = service->getRegistryEntryID();
4793 			serverTag = OSNumber::withNumber(entryID, 64);
4794 			token     = NULL;
4795 
4796 			if (kIODKDisableDextLaunch & gIODKDebug) {
4797 				DKLOG(DKS " dext launches are disabled \n", DKN(service));
4798 				service->detach(this);
4799 				OSSafeReleaseNULL(serverName);
4800 				OSSafeReleaseNULL(obj);
4801 				OSSafeReleaseNULL(serverTag);
4802 				return false;
4803 			}
4804 
4805 			if (gIOKitWillTerminate) {
4806 				DKLOG("%s disabled in shutdown\n", serverName->getCStringNoCopy());
4807 				service->detach(this);
4808 				OSSafeReleaseNULL(serverName);
4809 				OSSafeReleaseNULL(obj);
4810 				OSSafeReleaseNULL(serverTag);
4811 				return false;
4812 			}
4813 
4814 			ph = IOServicePH::matchingStart(this);
4815 			if (!ph) {
4816 				DKLOG("%s deferred in sleep\n", serverName->getCStringNoCopy());
4817 				service->setProperty(gIOServiceMatchDeferredKey, kOSBooleanTrue);
4818 				service->detach(this);
4819 				OSSafeReleaseNULL(serverName);
4820 				OSSafeReleaseNULL(obj);
4821 				OSSafeReleaseNULL(serverTag);
4822 				return false;
4823 			}
4824 
4825 			prop = service->copyProperty(gIOUserClassKey);
4826 			str = OSDynamicCast(OSString, prop);
4827 			if (str) {
4828 				service->setName(str);
4829 			}
4830 			OSSafeReleaseNULL(prop);
4831 
4832 			sym = OSSymbol::withString(serverName);
4833 			bool reuse = service->propertyExists(gIOUserServerOneProcessKey);
4834 			serverDUI = OSDynamicCast(OSData, service->getProperty(kOSBundleDextUniqueIdentifierKey));
4835 			userServer = IOUserServer::launchUserServer(bundleID, sym, serverTag, reuse, &token, serverDUI);
4836 			OSSafeReleaseNULL(sym);
4837 			OSSafeReleaseNULL(serverTag);
4838 			OSSafeReleaseNULL(serverName);
4839 			if (userServer) {
4840 				DKLOG(DKS " using existing server " DKS "\n", DKN(service), DKN(userServer));
4841 			} else if (token != NULL) {
4842 				const OSSymbol * tokenServerName = token->copyServerName();
4843 				OSNumber * tokenServerTag = token->copyServerTag();
4844 				assert(tokenServerName && tokenServerTag);
4845 				DKLOG(DKS " waiting for server %s-%llx\n", DKN(service), tokenServerName->getCStringNoCopy(), tokenServerTag->unsigned64BitValue());
4846 				userServer = __WAITING_FOR_USER_SERVER__(token);
4847 				OSSafeReleaseNULL(tokenServerName);
4848 				OSSafeReleaseNULL(tokenServerTag);
4849 			} else {
4850 				DKLOG(DKS " failed to launch server\n", DKN(service));
4851 			}
4852 
4853 
4854 			if (!userServer) {
4855 				service->detach(this);
4856 				IOServicePH::matchingEnd(this);
4857 				OSSafeReleaseNULL(obj);
4858 
4859 				if (token != NULL) {
4860 					DKLOG(DKS " user server timeout\n", DKN(service));
4861 #if DEVELOPMENT || DEBUG
4862 					driverkit_checkin_timed_out = mach_absolute_time();
4863 #endif
4864 				}
4865 
4866 				OSSafeReleaseNULL(token);
4867 				return false;
4868 			}
4869 
4870 			if (token && !(kIODKDisableCheckInTokenVerification & gIODKDebug)) {
4871 				if (!userServer->serviceMatchesCheckInToken(token)) {
4872 					OSSafeReleaseNULL(token);
4873 					service->detach(this);
4874 					IOServicePH::matchingEnd(this);
4875 					OSSafeReleaseNULL(obj);
4876 					userServer->exit("Check In Token verification failed");
4877 					userServer->release();
4878 					return false;
4879 				}
4880 			}
4881 			OSSafeReleaseNULL(token);
4882 			OSSafeReleaseNULL(obj);
4883 
4884 			if (!(kIODKDisableEntitlementChecking & gIODKDebug)) {
4885 				if (!userServer->checkEntitlements(this, service)) {
4886 					service->detach(this);
4887 					IOServicePH::matchingEnd(this);
4888 					userServer->exit("Entitlements check failed");
4889 					userServer->release();
4890 					return false;
4891 				}
4892 			}
4893 #if !XNU_TARGET_OS_OSX && !(DEVELOPMENT || DEBUG)
4894 			// Prevent third party drivers from matching IOUserResources/IOResources, except when signed for development
4895 			if (!userServer->isPlatformDriver() &&
4896 			    userServer->getCSValidationCategory() != CS_VALIDATION_CATEGORY_DEVELOPMENT
4897 			    && (this == gIOUserResources || this == gIOResources)) {
4898 				service->detach(this);
4899 				IOServicePH::matchingEnd(this);
4900 				userServer->exit("Third party driver may only match real hardware");
4901 				userServer->release();
4902 				return false;
4903 			}
4904 #endif /* !XNU_TARGET_OS_OSX && !(DEVELOPMENT || DEBUG) */
4905 
4906 			userServer->serviceAttach(service, this);
4907 		} else {
4908 			OSSafeReleaseNULL(obj);
4909 		}
4910 	}
4911 
4912 	AbsoluteTime startTime;
4913 	AbsoluteTime endTime;
4914 	UInt64       nano;
4915 	bool recordTime = (kIOLogStart & gIOKitDebug) != 0;
4916 
4917 	if (recordTime) {
4918 		clock_get_uptime(&startTime);
4919 	}
4920 
4921 	ok = service->start(this);
4922 
4923 	if (recordTime) {
4924 		clock_get_uptime(&endTime);
4925 
4926 		if (CMP_ABSOLUTETIME(&endTime, &startTime) > 0) {
4927 			SUB_ABSOLUTETIME(&endTime, &startTime);
4928 			absolutetime_to_nanoseconds(endTime, &nano);
4929 			if (nano > 500000000ULL) {
4930 				IOLog("%s::start took %ld ms\n", service->getName(), (long)(UInt32)(nano / 1000000ULL));
4931 			}
4932 		}
4933 	}
4934 	if (userServer) {
4935 		userServer->serviceStarted(service, this, ok);
4936 		userServer->release();
4937 	}
4938 
4939 	if (ok) {
4940 		IOInstallServiceSleepPlatformActions(service);
4941 #if 00
4942 		if (!strcmp("XHC1", getName())) {
4943 			service->setProperty(gIOPrimaryDriverTerminateOptionsKey, kOSBooleanTrue);
4944 		}
4945 #endif
4946 	}
4947 
4948 	if (!ok) {
4949 		service->detach( this );
4950 	}
4951 
4952 	if (ph) {
4953 		IOServicePH::matchingEnd(this);
4954 	}
4955 
4956 	return ok;
4957 }
4958 
4959 void
publishResource(const char * key,OSObject * value)4960 IOService::publishResource( const char * key, OSObject * value )
4961 {
4962 	const OSSymbol *    sym;
4963 
4964 	if ((sym = OSSymbol::withCString( key))) {
4965 		publishResource( sym, value);
4966 		sym->release();
4967 	}
4968 }
4969 
4970 void
publishResource(const OSSymbol * key,OSObject * value)4971 IOService::publishResource( const OSSymbol * key, OSObject * value )
4972 {
4973 	if (NULL == value) {
4974 		value = (OSObject *) gIOServiceKey;
4975 	}
4976 
4977 	gIOResources->setProperty( key, value);
4978 
4979 	if (IORecursiveLockHaveLock( gNotificationLock)) {
4980 		return;
4981 	}
4982 
4983 	gIOResourceGenerationCount++;
4984 	gIOResources->registerService();
4985 }
4986 
4987 void
publishUserResource(const OSSymbol * key,OSObject * value)4988 IOService::publishUserResource( const OSSymbol * key, OSObject * value )
4989 {
4990 	if (NULL == value) {
4991 		value = (OSObject *) gIOServiceKey;
4992 	}
4993 
4994 	gIOUserResources->setProperty( key, value);
4995 
4996 	if (IORecursiveLockHaveLock( gNotificationLock)) {
4997 		return;
4998 	}
4999 
5000 	gIOResourceGenerationCount++;
5001 	gIOUserResources->registerService();
5002 }
5003 
5004 bool
addNeededResource(const char * key)5005 IOService::addNeededResource( const char * key )
5006 {
5007 	OSObject *  resourcesProp;
5008 	OSSet *     set;
5009 	OSString *  newKey;
5010 	bool ret;
5011 
5012 	resourcesProp = copyProperty( gIOResourceMatchKey );
5013 	if (!resourcesProp) {
5014 		return false;
5015 	}
5016 
5017 	newKey = OSString::withCString( key );
5018 	if (!newKey) {
5019 		resourcesProp->release();
5020 		return false;
5021 	}
5022 
5023 	set = OSDynamicCast( OSSet, resourcesProp );
5024 	if (!set) {
5025 		set = OSSet::withCapacity( 1 );
5026 		set->setObject( resourcesProp );
5027 	} else {
5028 		set->retain();
5029 	}
5030 
5031 	set->setObject( newKey );
5032 	newKey->release();
5033 	ret = setProperty( gIOResourceMatchKey, set );
5034 	set->release();
5035 	resourcesProp->release();
5036 
5037 	return ret;
5038 }
5039 
5040 bool
checkResource(OSObject * matching)5041 IOService::checkResource( OSObject * matching )
5042 {
5043 	OSString *          str;
5044 	OSDictionary *      table;
5045 
5046 	if ((str = OSDynamicCast( OSString, matching ))) {
5047 		if (gIOResources->getProperty( str )) {
5048 			return true;
5049 		}
5050 	}
5051 
5052 	if (str) {
5053 		table = resourceMatching( str );
5054 	} else if ((table = OSDynamicCast( OSDictionary, matching ))) {
5055 		table->retain();
5056 	} else {
5057 		IOLog("%s: Can't match using: %s\n", getName(),
5058 		    matching->getMetaClass()->getClassName());
5059 		/* false would stall forever */
5060 		return true;
5061 	}
5062 
5063 	if (gIOKitDebug & kIOLogConfig) {
5064 		LOG("config(%p): stalling %s\n", IOSERVICE_OBFUSCATE(IOThreadSelf()), getName());
5065 	}
5066 
5067 	waitForService( table );
5068 
5069 	if (gIOKitDebug & kIOLogConfig) {
5070 		LOG("config(%p): waking\n", IOSERVICE_OBFUSCATE(IOThreadSelf()));
5071 	}
5072 
5073 	return true;
5074 }
5075 
5076 bool
checkResources(void)5077 IOService::checkResources( void )
5078 {
5079 	OSObject *          resourcesProp;
5080 	OSSet *             set;
5081 	OSObject *          obj;
5082 	OSIterator *        iter;
5083 	bool                ok;
5084 
5085 	resourcesProp = copyProperty( gIOResourceMatchKey );
5086 	if (NULL == resourcesProp) {
5087 		return true;
5088 	}
5089 
5090 	if ((set = OSDynamicCast( OSSet, resourcesProp ))) {
5091 		iter = OSCollectionIterator::withCollection( set );
5092 		ok = (NULL != iter);
5093 		while (ok && (obj = iter->getNextObject())) {
5094 			ok = checkResource( obj );
5095 		}
5096 		if (iter) {
5097 			iter->release();
5098 		}
5099 	} else {
5100 		ok = checkResource( resourcesProp );
5101 	}
5102 
5103 	OSSafeReleaseNULL(resourcesProp);
5104 
5105 	return ok;
5106 }
5107 
5108 
5109 void
configThread(const char * name)5110 _IOConfigThread::configThread( const char * name )
5111 {
5112 	_IOConfigThread *   inst;
5113 
5114 	do {
5115 		if (!(inst = new _IOConfigThread)) {
5116 			continue;
5117 		}
5118 		if (!inst->init()) {
5119 			continue;
5120 		}
5121 		thread_t thread;
5122 		if (KERN_SUCCESS != kernel_thread_start(&_IOConfigThread::main, inst, &thread)) {
5123 			continue;
5124 		}
5125 
5126 		char threadName[MAXTHREADNAMESIZE];
5127 		snprintf(threadName, sizeof(threadName), "IOConfigThread_'%s'", name);
5128 		thread_set_thread_name(thread, threadName);
5129 		thread_deallocate(thread);
5130 
5131 		return;
5132 	} while (false);
5133 
5134 	if (inst) {
5135 		inst->release();
5136 	}
5137 
5138 	return;
5139 }
5140 
5141 /*
5142  * To support driver replacement of boot matched drivers later in boot, drivers can
5143  * opt-in to be being terminated if a non-boot driver matches their provider, by
5144  * setting the gIOPrimaryDriverTerminateOptionsKey property. The driver providing the
5145  * root disk media may not be terminated.
5146  * IOMedia objects are hidden from user space until all drivers are available, but any
5147  * associated with the root disk must be published immediately.
5148  */
5149 
5150 struct FindRootMediaContext {
5151 	OSArray   * services;
5152 	IOService * parent;
5153 };
5154 
5155 bool
hasParent(IOService * parent)5156 IOService::hasParent(IOService * parent)
5157 {
5158 	IOService * service;
5159 
5160 	for (service = this;
5161 	    service && (service != parent);
5162 	    service = service->getProvider()) {
5163 	}
5164 
5165 	return service != NULL;
5166 }
5167 
5168 bool
publishHiddenMediaApplier(const OSObject * entry,void * context)5169 IOService::publishHiddenMediaApplier(const OSObject * entry, void * context)
5170 {
5171 	FindRootMediaContext * ctx     = (typeof(ctx))context;
5172 	IOService            * service = (typeof(service))entry;
5173 
5174 	do {
5175 		if (ctx->parent && !service->hasParent(ctx->parent)) {
5176 			break;
5177 		}
5178 		if (ctx->services) {
5179 			ctx->services->setObject(service);
5180 		} else {
5181 			ctx->services  = OSArray::withObjects((const OSObject **) &service, 1);
5182 			assert(ctx->services);
5183 		}
5184 	} while (false);
5185 
5186 	return false;
5187 }
5188 
5189 // publish to user space any hidden IOMedia under the 'parent' object, or all
5190 // if 'parent' is NULL
5191 
5192 void
publishHiddenMedia(IOService * parent)5193 IOService::publishHiddenMedia(IOService * parent)
5194 {
5195 	const OSMetaClass * iomediaClass;
5196 	bool                wasHiding;
5197 
5198 	iomediaClass = OSMetaClass::getMetaClassWithName(gIOMediaKey);
5199 	assert(iomediaClass);
5200 
5201 	LOCKWRITENOTIFY();
5202 	wasHiding = gIOServiceHideIOMedia;
5203 	if (wasHiding && !parent) {
5204 		gIOServiceHideIOMedia = false;
5205 	}
5206 	UNLOCKNOTIFY();
5207 
5208 	FindRootMediaContext ctx = { .services = NULL, .parent = parent };
5209 
5210 	if (wasHiding) {
5211 		iomediaClass->applyToInstances(publishHiddenMediaApplier, &ctx);
5212 	}
5213 	if (ctx.services) {
5214 		unsigned int idx, notiIdx;
5215 		IOService * service;
5216 		OSArray   * notifiers[3] = {};
5217 
5218 		for (idx = 0; (service = (IOService *) ctx.services->getObject(idx)); idx++) {
5219 			service->lockForArbitration(true);
5220 			if (!(kIOServiceUserInvisibleMatchState & service->__state[0])) {
5221 				service->unlockForArbitration();
5222 				continue;
5223 			}
5224 			service->__state[0] &= ~kIOServiceUserInvisibleMatchState;
5225 			service->__state[1] |= kIOServiceUserUnhidden;
5226 			notifiers[0] = service->copyNotifiers(gIOFirstPublishNotification, 0, 0xffffffff);
5227 			if (kIOServiceMatchedState & service->__state[0]) {
5228 				notifiers[1] = service->copyNotifiers(gIOMatchedNotification, 0, 0xffffffff);
5229 			}
5230 			if (kIOServiceFirstMatchState & service->__state[0]) {
5231 				notifiers[2] = service->copyNotifiers(gIOFirstMatchNotification, 0, 0xffffffff);
5232 			}
5233 			service->unlockForArbitration();
5234 			for (notiIdx = 0; notiIdx < 3; notiIdx++) {
5235 				service->invokeNotifiers(&notifiers[notiIdx]);
5236 			}
5237 		}
5238 		OSSafeReleaseNULL(ctx.services);
5239 	}
5240 }
5241 
5242 // Find the block storage driver providing the root disk, or NULL if not booting from
5243 // a block device
5244 
5245 void
setRootMedia(IOService * root)5246 IOService::setRootMedia(IOService * root)
5247 {
5248 	const OSMetaClass * ioblockstoragedriverClass;
5249 	bool unhide;
5250 
5251 	ioblockstoragedriverClass = OSMetaClass::getMetaClassWithName(gIOBlockStorageDriverKey);
5252 	assert(ioblockstoragedriverClass);
5253 
5254 	while (root) {
5255 		if (root->metaCast(ioblockstoragedriverClass)) {
5256 			break;
5257 		}
5258 		root = root->getProvider();
5259 	}
5260 
5261 	LOCKWRITENOTIFY();
5262 	unhide = (kIOServiceRootMediaParentInvalid == gIOServiceRootMediaParent);
5263 	if (unhide) {
5264 		gIOServiceRootMediaParent = root;
5265 	}
5266 	UNLOCKNOTIFY();
5267 
5268 	if (unhide) {
5269 		publishHiddenMedia(root);
5270 	}
5271 }
5272 
5273 // Check if the driver may be terminated when a later driver could be used instead
5274 
5275 bool
canTerminateForReplacement(IOService * client)5276 IOService::canTerminateForReplacement(IOService * client)
5277 {
5278 	IOService * parent;
5279 
5280 	assert(kIOServiceRootMediaParentInvalid != gIOServiceRootMediaParent);
5281 
5282 	if (!client->propertyExists(gIOPrimaryDriverTerminateOptionsKey)) {
5283 		return false;
5284 	}
5285 	if (!gIOServiceRootMediaParent) {
5286 		return false;
5287 	}
5288 	parent = client;
5289 	while (parent && (parent != gIOServiceRootMediaParent)) {
5290 		parent = parent->getProvider();
5291 	}
5292 	if (parent) {
5293 		IOLog("Can't replace primary matched driver on root media %s-0x%qx\n",
5294 		    client->getName(), client->getRegistryEntryID());
5295 		return false;
5296 	}
5297 	return true;
5298 }
5299 
5300 void
doServiceMatch(IOOptionBits options)5301 IOService::doServiceMatch( IOOptionBits options )
5302 {
5303 	_IOServiceNotifier * notify;
5304 	OSIterator *        iter;
5305 	OSOrderedSet *      matches;
5306 	OSArray *           resourceKeys = NULL;
5307 	SInt32              catalogGeneration;
5308 	bool                keepGuessing = true;
5309 	bool                reRegistered = true;
5310 	bool                didRegister;
5311 	OSArray *           notifiers[2] = {NULL};
5312 
5313 //    job->nub->deliverNotification( gIOPublishNotification,
5314 //                              kIOServiceRegisteredState, 0xffffffff );
5315 
5316 	while (keepGuessing) {
5317 		matches = gIOCatalogue->findDrivers( this, &catalogGeneration );
5318 		// the matches list should always be created by findDrivers()
5319 		if (matches) {
5320 			lockForArbitration();
5321 			if (0 == (__state[0] & kIOServiceFirstPublishState)) {
5322 				getMetaClass()->addInstance(this);
5323 				notifiers[0] = copyNotifiers(gIOFirstPublishNotification,
5324 				    kIOServiceFirstPublishState, 0xffffffff );
5325 			}
5326 			LOCKREADNOTIFY();
5327 			__state[1] &= ~kIOServiceNeedConfigState;
5328 			__state[1] |= kIOServiceConfigState | kIOServiceConfigRunning;
5329 			didRegister = (0 == (kIOServiceRegisteredState & __state[0]));
5330 			__state[0] |= kIOServiceRegisteredState;
5331 
5332 			if (gIOServiceHideIOMedia
5333 			    && metaCast(gIOMediaKey)
5334 			    && !(kIOServiceUserUnhidden & __state[1])
5335 			    && gIOServiceRootMediaParent
5336 			    && !hasParent(gIOServiceRootMediaParent)
5337 			    && propertyExists(gIOPrimaryDriverTerminateOptionsKey, gIOServicePlane)) {
5338 				__state[0] |= kIOServiceUserInvisibleMatchState;
5339 			}
5340 
5341 			keepGuessing &= (0 == (__state[0] & kIOServiceInactiveState));
5342 			if (reRegistered && keepGuessing) {
5343 				iter = OSCollectionIterator::withCollection((OSOrderedSet *)
5344 				    gNotifications->getObject( gIOPublishNotification ));
5345 				if (iter) {
5346 					while ((notify = (_IOServiceNotifier *)
5347 					    iter->getNextObject())) {
5348 						if (matchPassive(notify->matching, 0)
5349 						    && (kIOServiceNotifyEnable & notify->state)) {
5350 							matches->setObject( notify );
5351 						}
5352 					}
5353 					iter->release();
5354 				}
5355 			}
5356 
5357 			UNLOCKNOTIFY();
5358 			unlockForArbitration();
5359 			invokeNotifiers(&notifiers[0]);
5360 			if (keepGuessing && matches->getCount() && (kIOReturnSuccess == getResources())) {
5361 				if ((this == gIOResources) || (this == gIOUserResources)) {
5362 					if (resourceKeys) {
5363 						resourceKeys->release();
5364 					}
5365 					resourceKeys = copyPropertyKeys();
5366 				}
5367 				probeCandidates( matches );
5368 			} else {
5369 				matches->release();
5370 			}
5371 		}
5372 
5373 		lockForArbitration();
5374 		reRegistered = (0 != (__state[1] & kIOServiceNeedConfigState));
5375 		keepGuessing =
5376 		    (reRegistered || (catalogGeneration !=
5377 		    gIOCatalogue->getGenerationCount()))
5378 		    && (0 == (__state[0] & kIOServiceInactiveState));
5379 
5380 		if (keepGuessing) {
5381 			unlockForArbitration();
5382 		}
5383 	}
5384 
5385 	if ((0 == (__state[0] & kIOServiceInactiveState))
5386 	    && (0 == (__state[1] & kIOServiceModuleStallState))) {
5387 		if (resourceKeys) {
5388 			setProperty(gIOResourceMatchedKey, resourceKeys);
5389 		}
5390 
5391 		notifiers[0] = copyNotifiers(gIOMatchedNotification,
5392 		    kIOServiceMatchedState, 0xffffffff);
5393 		if (0 == (__state[0] & kIOServiceFirstMatchState)) {
5394 			notifiers[1] = copyNotifiers(gIOFirstMatchNotification,
5395 			    kIOServiceFirstMatchState, 0xffffffff);
5396 		}
5397 	}
5398 
5399 	__state[1] &= ~kIOServiceConfigRunning;
5400 	unlockForArbitration();
5401 
5402 	if (resourceKeys) {
5403 		resourceKeys->release();
5404 	}
5405 
5406 	invokeNotifiers(&notifiers[0]);
5407 	invokeNotifiers(&notifiers[1]);
5408 
5409 	lockForArbitration();
5410 	__state[1] &= ~kIOServiceConfigState;
5411 	scheduleTerminatePhase2();
5412 
5413 	_adjustBusy( -1 );
5414 	unlockForArbitration();
5415 }
5416 
5417 UInt32
_adjustBusy(SInt32 delta)5418 IOService::_adjustBusy( SInt32 delta )
5419 {
5420 	IOService * next;
5421 	UInt32      count;
5422 	UInt32      result;
5423 	bool        wasQuiet, nowQuiet, needWake;
5424 
5425 	next = this;
5426 	result = __state[1] & kIOServiceBusyStateMask;
5427 
5428 	if (delta) {
5429 		do {
5430 			if (next != this) {
5431 				next->lockForArbitration();
5432 			}
5433 			count = next->__state[1] & kIOServiceBusyStateMask;
5434 			wasQuiet = (0 == count);
5435 			if (((delta < 0) && wasQuiet) || ((delta > 0) && (kIOServiceBusyMax == count))) {
5436 				OSReportWithBacktrace("%s: bad busy count (%d,%d)\n", next->getName(), (uint32_t)count, (int)delta);
5437 			} else {
5438 				count += delta;
5439 			}
5440 			next->__state[1] = (next->__state[1] & ~kIOServiceBusyStateMask) | count;
5441 			nowQuiet = (0 == count);
5442 			needWake = (0 != (kIOServiceBusyWaiterState & next->__state[1]));
5443 
5444 			if (needWake) {
5445 				next->__state[1] &= ~kIOServiceBusyWaiterState;
5446 				IOLockLock( gIOServiceBusyLock );
5447 				thread_wakeup((event_t) next);
5448 				IOLockUnlock( gIOServiceBusyLock );
5449 			}
5450 			if (next != this) {
5451 				next->unlockForArbitration();
5452 			}
5453 
5454 			if ((wasQuiet || nowQuiet)) {
5455 				uint64_t regID = next->getRegistryEntryID();
5456 				IOServiceTrace(
5457 					((wasQuiet /*nowBusy*/) ? IOSERVICE_BUSY : IOSERVICE_NONBUSY),
5458 					(uintptr_t) regID,
5459 					(uintptr_t) (regID >> 32),
5460 					(uintptr_t) next,
5461 					0);
5462 
5463 				if (wasQuiet) {
5464 					next->__timeBusy = mach_absolute_time();
5465 				} else {
5466 					next->__accumBusy += mach_absolute_time() - next->__timeBusy;
5467 					next->__timeBusy = 0;
5468 				}
5469 
5470 				MessageClientsContext context;
5471 
5472 				context.service  = next;
5473 				context.type     = kIOMessageServiceBusyStateChange;
5474 				context.argument = (void *) wasQuiet; /*nowBusy*/
5475 				context.argSize  = 0;
5476 
5477 				applyToInterestNotifiers( next, gIOBusyInterest,
5478 				    &messageClientsApplier, &context );
5479 
5480 #if !NO_KEXTD
5481 				if (nowQuiet && (next == gIOServiceRoot)) {
5482 					if (gIOServiceHideIOMedia) {
5483 						publishHiddenMedia(NULL);
5484 					}
5485 
5486 					OSKext::considerUnloads();
5487 					IOServiceTrace(IOSERVICE_REGISTRY_QUIET, 0, 0, 0, 0);
5488 				}
5489 #endif
5490 			}
5491 
5492 			delta = nowQuiet ? -1 : +1;
5493 		} while ((wasQuiet || nowQuiet) && (next = next->getProvider()));
5494 	}
5495 
5496 	return result;
5497 }
5498 
5499 void
adjustBusy(SInt32 delta)5500 IOService::adjustBusy( SInt32 delta )
5501 {
5502 	lockForArbitration();
5503 	_adjustBusy( delta );
5504 	unlockForArbitration();
5505 }
5506 
5507 uint64_t
getAccumulatedBusyTime(void)5508 IOService::getAccumulatedBusyTime( void )
5509 {
5510 	uint64_t accumBusy = __accumBusy;
5511 	uint64_t timeBusy = __timeBusy;
5512 	uint64_t nano;
5513 
5514 	do{
5515 		accumBusy = __accumBusy;
5516 		timeBusy  = __timeBusy;
5517 		if (timeBusy) {
5518 			accumBusy += mach_absolute_time() - timeBusy;
5519 		}
5520 	}while (timeBusy != __timeBusy);
5521 
5522 	absolutetime_to_nanoseconds(*(AbsoluteTime *)&accumBusy, &nano);
5523 
5524 	return nano;
5525 }
5526 
5527 UInt32
getBusyState(void)5528 IOService::getBusyState( void )
5529 {
5530 	return __state[1] & kIOServiceBusyStateMask;
5531 }
5532 
5533 IOReturn
waitForState(UInt32 mask,UInt32 value,mach_timespec_t * timeout)5534 IOService::waitForState( UInt32 mask, UInt32 value,
5535     mach_timespec_t * timeout )
5536 {
5537 	panic("waitForState");
5538 	return kIOReturnUnsupported;
5539 }
5540 
5541 IOReturn
waitForState(UInt32 mask,UInt32 value,uint64_t timeout)5542 IOService::waitForState( UInt32 mask, UInt32 value,
5543     uint64_t timeout )
5544 {
5545 	bool            wait;
5546 	int             waitResult = THREAD_AWAKENED;
5547 	bool            computeDeadline = true;
5548 	AbsoluteTime    abstime;
5549 
5550 	do {
5551 		lockForArbitration();
5552 		IOLockLock( gIOServiceBusyLock );
5553 		wait = (value != (__state[1] & mask));
5554 		if (wait) {
5555 			__state[1] |= kIOServiceBusyWaiterState;
5556 			unlockForArbitration();
5557 			if (timeout != UINT64_MAX) {
5558 				if (computeDeadline) {
5559 					AbsoluteTime  nsinterval;
5560 					nanoseconds_to_absolutetime(timeout, &nsinterval );
5561 					clock_absolutetime_interval_to_deadline(nsinterval, &abstime);
5562 					computeDeadline = false;
5563 				}
5564 				assert_wait_deadline((event_t)this, THREAD_UNINT, __OSAbsoluteTime(abstime));
5565 			} else {
5566 				assert_wait((event_t)this, THREAD_UNINT );
5567 			}
5568 		} else {
5569 			unlockForArbitration();
5570 		}
5571 		IOLockUnlock( gIOServiceBusyLock );
5572 		if (wait) {
5573 			waitResult = thread_block(THREAD_CONTINUE_NULL);
5574 		}
5575 	} while (wait && (waitResult != THREAD_TIMED_OUT));
5576 
5577 	if (waitResult == THREAD_TIMED_OUT) {
5578 		return kIOReturnTimeout;
5579 	} else {
5580 		return kIOReturnSuccess;
5581 	}
5582 }
5583 
5584 IOReturn
waitQuietWithOptions(uint64_t timeout,IOOptionBits options)5585 IOService::waitQuietWithOptions( uint64_t timeout, IOOptionBits options )
5586 {
5587 	IOReturn ret;
5588 	uint32_t loops, timeoutExtensions;
5589 	char *   busyEntriesString = NULL;
5590 	char *   panicString = NULL;
5591 	size_t   busyEntriesStringLen;
5592 	size_t   panicStringLen;
5593 	uint64_t time;
5594 	uint64_t nano;
5595 	bool     pendingRequests;
5596 	bool     registryRootBusy;
5597 	bool     multipleEntries;
5598 	bool     dopanic = false;
5599 
5600 	enum { kIOServiceBusyTimeoutExtensionsMax = 8 };
5601 #if KASAN
5602 	/*
5603 	 * On kasan kernels, everything takes longer, so double the number of
5604 	 * timeout extensions. This should help with issues like 41259215
5605 	 * where WindowServer was timing out waiting for kextd to get all the
5606 	 * kasan kexts loaded and started.
5607 	 *
5608 	 * On legacy/x86 systems give a bit more time since we may be
5609 	 * booting from a HDD.
5610 	 */
5611 	enum { kTimeoutExtensions = 8 };
5612 #define WITH_IOWAITQUIET_EXTENSIONS 1
5613 #elif defined(__x86_64__)
5614 	enum { kTimeoutExtensions = 4 };
5615 #define WITH_IOWAITQUIET_EXTENSIONS 1
5616 #elif  defined(XNU_TARGET_OS_OSX)
5617 	enum { kTimeoutExtensions = 1 };
5618 #define WITH_IOWAITQUIET_EXTENSIONS 1
5619 #else
5620 	enum { kTimeoutExtensions = 1 };
5621 #define WITH_IOWAITQUIET_EXTENSIONS 0
5622 #endif
5623 
5624 	timeoutExtensions = kTimeoutExtensions;
5625 	time = mach_absolute_time();
5626 	pendingRequests = false;
5627 	for (loops = 0; loops < timeoutExtensions; loops++) {
5628 		ret = waitForState( kIOServiceBusyStateMask, 0, timeout );
5629 
5630 		if (loops && (kIOReturnSuccess == ret)) {
5631 			time = mach_absolute_time() - time;
5632 			absolutetime_to_nanoseconds(*(AbsoluteTime *)&time, &nano);
5633 			IOLog("busy extended ok[%d], (%llds, %llds)\n",
5634 			    loops, timeout / 1000000000ULL, nano / 1000000000ULL);
5635 			break;
5636 		} else if (kIOReturnTimeout != ret) {
5637 			break;
5638 		} else if (timeout < (41ull * NSEC_PER_SEC)) {
5639 			break;
5640 		}
5641 
5642 		{
5643 			IORegistryIterator * iter;
5644 			OSOrderedSet       * set;
5645 			OSOrderedSet       * leaves;
5646 			IOService          * next;
5647 			IOService          * nextParent;
5648 			char               * s;
5649 			size_t               l;
5650 			size_t               busyEntriesStringRemaining;
5651 
5652 			busyEntriesStringLen = 256;
5653 			panicStringLen = 256;
5654 			if (!busyEntriesString) {
5655 				busyEntriesString = IONewZeroData(char, busyEntriesStringLen);
5656 				assert(busyEntriesString != NULL);
5657 			}
5658 			if (!panicString) {
5659 				panicString = IONewZeroData(char, panicStringLen);
5660 				assert(panicString != NULL);
5661 			}
5662 
5663 			set = NULL;
5664 			pendingRequests = OSKext::pendingIOKitDaemonRequests();
5665 			iter = IORegistryIterator::iterateOver(this, gIOServicePlane, kIORegistryIterateRecursively);
5666 			leaves = OSOrderedSet::withCapacity(4);
5667 			if (iter) {
5668 				set = iter->iterateAll();
5669 			}
5670 			if (leaves && set) {
5671 				busyEntriesString[0] = panicString[0] = 0;
5672 				set->setObject(this);
5673 				while ((next = (IOService *) set->getLastObject())) {
5674 					if (next->getBusyState()) {
5675 						if (kIOServiceModuleStallState & next->__state[1]) {
5676 							pendingRequests = true;
5677 						}
5678 #if defined(XNU_TARGET_OS_OSX)
5679 						OSObject * prop;
5680 						if ((prop = next->copyProperty(kIOServiceBusyTimeoutExtensionsKey))) {
5681 							OSNumber * num;
5682 							uint32_t   value;
5683 							if ((num = OSDynamicCast(OSNumber, prop))) {
5684 								value = num->unsigned32BitValue();
5685 								if (value
5686 								    && (value <= kIOServiceBusyTimeoutExtensionsMax)
5687 								    && (value > timeoutExtensions)) {
5688 									timeoutExtensions = value;
5689 								}
5690 							}
5691 							OSSafeReleaseNULL(prop);
5692 						}
5693 #endif /* defined(XNU_TARGET_OS_OSX) */
5694 						leaves->setObject(next);
5695 						nextParent = next;
5696 						while ((nextParent = nextParent->getProvider())) {
5697 							set->removeObject(nextParent);
5698 							leaves->removeObject(nextParent);
5699 						}
5700 					}
5701 					set->removeObject(next);
5702 				}
5703 				registryRootBusy = leaves->getCount() == 1 && leaves->getObject(0) == getServiceRoot();
5704 				multipleEntries = leaves->getCount() > 1;
5705 				s = busyEntriesString;
5706 				busyEntriesStringRemaining = busyEntriesStringLen;
5707 
5708 				if (registryRootBusy) {
5709 					snprintf(s, busyEntriesStringRemaining, "registry root held busy, " kIOKitDaemonName " %s checked in", OSKext::iokitDaemonActive() ? "has" : "has not");
5710 				} else {
5711 					while ((next = (IOService *) leaves->getLastObject())) {
5712 						l = snprintf(s, busyEntriesStringRemaining, "%s'%s' (%x,%x)", ((s == busyEntriesString) ? "" : ", "), next->getName(), (uint32_t)next->__state[0], (uint32_t)next->__state[1]);
5713 						if (l >= busyEntriesStringRemaining) {
5714 							break;
5715 						}
5716 						s += l;
5717 						busyEntriesStringRemaining -= l;
5718 						leaves->removeObject(next);
5719 					}
5720 				}
5721 			}
5722 			OSSafeReleaseNULL(leaves);
5723 			OSSafeReleaseNULL(set);
5724 			OSSafeReleaseNULL(iter);
5725 		}
5726 
5727 		dopanic = (kIOWaitQuietPanics & gIOKitDebug) && (options & kIOWaitQuietPanicOnFailure);
5728 #if WITH_IOWAITQUIET_EXTENSIONS
5729 		dopanic = (dopanic && (loops >= (timeoutExtensions - 1)));
5730 #endif
5731 		assert(panicString != NULL);
5732 		if (multipleEntries) {
5733 			snprintf(panicString, panicStringLen,
5734 			    "%s[%d], (%llds): multiple entries holding the registry busy, IOKit termination queue depth %u: %s",
5735 			    pendingRequests ? "IOKit Daemon (" kIOKitDaemonName ") stall" : "busy timeout",
5736 			    loops, timeout / 1000000000ULL,
5737 			    (uint32_t)gIOTerminateWork,
5738 			    busyEntriesString ? busyEntriesString : "");
5739 		} else {
5740 			snprintf(panicString, panicStringLen,
5741 			    "%s[%d], (%llds): %s",
5742 			    pendingRequests ? "IOKit Daemon (" kIOKitDaemonName ") stall" : "busy timeout",
5743 			    loops, timeout / 1000000000ULL,
5744 			    busyEntriesString ? busyEntriesString : "");
5745 		}
5746 
5747 		IOLog("%s\n", panicString);
5748 		if (dopanic) {
5749 			panic("%s", panicString);
5750 		} else if (!loops) {
5751 			getPMRootDomain()->startSpinDump(1);
5752 		}
5753 	}
5754 
5755 	if (busyEntriesString) {
5756 		IODeleteData(busyEntriesString, char, busyEntriesStringLen);
5757 	}
5758 	if (panicString) {
5759 		IODeleteData(panicString, char, panicStringLen);
5760 	}
5761 
5762 	return ret;
5763 }
5764 
5765 IOReturn
waitQuiet(uint64_t timeout)5766 IOService::waitQuiet( uint64_t timeout )
5767 {
5768 	return waitQuietWithOptions(timeout);
5769 }
5770 
5771 IOReturn
waitQuiet(mach_timespec_t * timeout)5772 IOService::waitQuiet( mach_timespec_t * timeout )
5773 {
5774 	uint64_t    timeoutNS;
5775 
5776 	if (timeout) {
5777 		timeoutNS = timeout->tv_sec;
5778 		timeoutNS *= kSecondScale;
5779 		timeoutNS += timeout->tv_nsec;
5780 	} else {
5781 		timeoutNS = UINT64_MAX;
5782 	}
5783 
5784 	return waitQuiet(timeoutNS);
5785 }
5786 
5787 bool
serializeProperties(OSSerialize * s) const5788 IOService::serializeProperties( OSSerialize * s ) const
5789 {
5790 #if 0
5791 	((IOService *)this)->setProperty(((IOService *)this)->__state,
5792 	    sizeof(__state), "__state");
5793 #endif
5794 	return super::serializeProperties(s);
5795 }
5796 
5797 void
resetRematchProperties()5798 IOService::resetRematchProperties()
5799 {
5800 	removeProperty(gIORematchCountKey);
5801 	removeProperty(gIORematchPersonalityKey);
5802 }
5803 
5804 
5805 void
main(void * arg,wait_result_t result)5806 _IOConfigThread::main(void * arg, wait_result_t result)
5807 {
5808 	_IOConfigThread * self = (_IOConfigThread *) arg;
5809 	_IOServiceJob * job;
5810 	IOService   *   nub;
5811 	bool            alive = true;
5812 	kern_return_t   kr;
5813 	thread_precedence_policy_data_t precedence = { -1 };
5814 
5815 	kr = thread_policy_set(current_thread(),
5816 	    THREAD_PRECEDENCE_POLICY,
5817 	    (thread_policy_t) &precedence,
5818 	    THREAD_PRECEDENCE_POLICY_COUNT);
5819 	if (KERN_SUCCESS != kr) {
5820 		IOLog("thread_policy_set(%d)\n", kr);
5821 	}
5822 
5823 	do {
5824 //	randomDelay();
5825 
5826 		semaphore_wait( gJobsSemaphore );
5827 
5828 		IOTakeLock( gJobsLock );
5829 		job = (_IOServiceJob *) gJobs->getFirstObject();
5830 		job->retain();
5831 		gJobs->removeObject(job);
5832 		if (job) {
5833 			gOutstandingJobs--;
5834 //	    gNumConfigThreads--;	// we're out of service
5835 			gNumWaitingThreads--; // we're out of service
5836 		}
5837 		IOUnlock( gJobsLock );
5838 
5839 		if (job) {
5840 			nub = job->nub;
5841 
5842 			if (gIOKitDebug & kIOLogConfig) {
5843 				LOG("config(%p): starting on %s, %d\n",
5844 				    IOSERVICE_OBFUSCATE(IOThreadSelf()), job->nub->getName(), job->type);
5845 			}
5846 
5847 			switch (job->type) {
5848 			case kMatchNubJob:
5849 				nub->doServiceMatch( job->options );
5850 				break;
5851 
5852 			default:
5853 				LOG("config(%p): strange type (%d)\n",
5854 				    IOSERVICE_OBFUSCATE(IOThreadSelf()), job->type );
5855 				break;
5856 			}
5857 
5858 			if (job->options & kIOServiceDextRequirePowerForMatching) {
5859 				gIOPMRootDomain->releaseDriverKitMatchingAssertion();
5860 			}
5861 
5862 			OSSafeReleaseNULL(nub);
5863 			OSSafeReleaseNULL(job);
5864 
5865 			IOTakeLock( gJobsLock );
5866 			alive = (gOutstandingJobs > gNumWaitingThreads);
5867 			if (alive) {
5868 				gNumWaitingThreads++; // back in service
5869 			}
5870 //		gNumConfigThreads++;
5871 			else {
5872 				if (0 == --gNumConfigThreads) {
5873 //                    IOLog("MATCH IDLE\n");
5874 					IOLockWakeup( gJobsLock, (event_t) &gNumConfigThreads, /* one-thread */ false );
5875 				}
5876 			}
5877 			IOUnlock( gJobsLock );
5878 		}
5879 	} while (alive);
5880 
5881 	if (gIOKitDebug & kIOLogConfig) {
5882 		LOG("config(%p): terminating\n", IOSERVICE_OBFUSCATE(IOThreadSelf()));
5883 	}
5884 
5885 	self->release();
5886 }
5887 
5888 IOReturn
waitMatchIdle(UInt32 msToWait)5889 IOService::waitMatchIdle( UInt32 msToWait )
5890 {
5891 	bool            wait;
5892 	int             waitResult = THREAD_AWAKENED;
5893 	bool            computeDeadline = true;
5894 	AbsoluteTime    deadline;
5895 
5896 	IOLockLock( gJobsLock );
5897 	do {
5898 		wait = (0 != gNumConfigThreads);
5899 		if (wait) {
5900 			if (msToWait) {
5901 				if (computeDeadline) {
5902 					clock_interval_to_deadline(
5903 						msToWait, kMillisecondScale, &deadline );
5904 					computeDeadline = false;
5905 				}
5906 				waitResult = IOLockSleepDeadline( gJobsLock, &gNumConfigThreads,
5907 				    deadline, THREAD_UNINT );
5908 			} else {
5909 				waitResult = IOLockSleep( gJobsLock, &gNumConfigThreads,
5910 				    THREAD_UNINT );
5911 			}
5912 		}
5913 	} while (wait && (waitResult != THREAD_TIMED_OUT));
5914 	IOLockUnlock( gJobsLock );
5915 
5916 	if (waitResult == THREAD_TIMED_OUT) {
5917 		return kIOReturnTimeout;
5918 	} else {
5919 		return kIOReturnSuccess;
5920 	}
5921 }
5922 
5923 void
cpusRunning(void)5924 IOService::cpusRunning(void)
5925 {
5926 	gCPUsRunning = true;
5927 }
5928 
5929 void
pingConfig(_IOServiceJob * job)5930 _IOServiceJob::pingConfig( _IOServiceJob * job )
5931 {
5932 	int         count;
5933 	bool        create;
5934 	IOService * nub;
5935 
5936 	assert( job );
5937 	nub = job->nub;
5938 
5939 	IOTakeLock( gJobsLock );
5940 
5941 	gOutstandingJobs++;
5942 	if (nub == gIOResources) {
5943 		gJobs->setFirstObject( job );
5944 	} else {
5945 		gJobs->setLastObject( job );
5946 	}
5947 
5948 	count = gNumWaitingThreads;
5949 //    if( gNumConfigThreads) count++;// assume we're called from a config thread
5950 
5951 	create = ((gOutstandingJobs > count)
5952 	    && ((gNumConfigThreads < gMaxConfigThreads)
5953 	    || (nub == gIOResources)
5954 	    || !gCPUsRunning));
5955 	if (create) {
5956 		gNumConfigThreads++;
5957 		gNumWaitingThreads++;
5958 		if (gNumConfigThreads > gHighNumConfigThreads) {
5959 			gHighNumConfigThreads = gNumConfigThreads;
5960 		}
5961 	}
5962 
5963 	IOUnlock( gJobsLock );
5964 
5965 	job->release();
5966 
5967 	if (create) {
5968 		if (gIOKitDebug & kIOLogConfig) {
5969 			LOG("config(%d): creating\n", gNumConfigThreads - 1);
5970 		}
5971 		_IOConfigThread::configThread(nub->getName());
5972 	}
5973 
5974 	semaphore_signal( gJobsSemaphore );
5975 }
5976 
5977 struct IOServiceMatchContext {
5978 	OSDictionary * table;
5979 	OSObject *     result;
5980 	uint32_t       options;
5981 	uint32_t       state;
5982 	uint32_t       count;
5983 	uint32_t       done;
5984 };
5985 
5986 bool
instanceMatch(const OSObject * entry,void * context)5987 IOService::instanceMatch(const OSObject * entry, void * context)
5988 {
5989 	IOServiceMatchContext * ctx = (typeof(ctx))context;
5990 	IOService *    service = (typeof(service))entry;
5991 	OSDictionary * table   = ctx->table;
5992 	uint32_t       options = ctx->options;
5993 	uint32_t       state   = ctx->state;
5994 	uint32_t       done;
5995 	bool           match;
5996 
5997 	done = 0;
5998 	do{
5999 		match = ((state == (state & service->__state[0]))
6000 		    && (0 == (service->__state[0] & kIOServiceInactiveState)));
6001 		if (!match) {
6002 			break;
6003 		}
6004 
6005 		match = service->matchInternal(table, options, &done);
6006 		if (match) {
6007 			ctx->count += table->getCount();
6008 			ctx->done += done;
6009 		}
6010 	}while (false);
6011 	if (!match) {
6012 		return false;
6013 	}
6014 
6015 	if ((kIONotifyOnce & options) && (ctx->done == ctx->count)) {
6016 		service->retain();
6017 		ctx->result = service;
6018 		return true;
6019 	} else if (!ctx->result) {
6020 		ctx->result = OSSet::withObjects((const OSObject **) &service, 1, 1);
6021 	} else {
6022 		((OSSet *)ctx->result)->setObject(service);
6023 	}
6024 	return false;
6025 }
6026 
6027 // internal - call with gNotificationLock
6028 OSObject *
copyExistingServices(OSDictionary * matching,IOOptionBits inState,IOOptionBits options)6029 IOService::copyExistingServices( OSDictionary * matching,
6030     IOOptionBits inState, IOOptionBits options )
6031 {
6032 	OSObject *   current = NULL;
6033 	OSIterator * iter;
6034 	IOService *  service;
6035 	OSObject *   obj;
6036 	OSString *   str;
6037 
6038 	if (!matching) {
6039 		return NULL;
6040 	}
6041 
6042 #if MATCH_DEBUG
6043 	OSSerialize * s = OSSerialize::withCapacity(128);
6044 	matching->serialize(s);
6045 #endif
6046 
6047 	if ((obj = matching->getObject(gIOProviderClassKey))
6048 	    && gIOResourcesKey
6049 	    && gIOResourcesKey->isEqualTo(obj)
6050 	    && (service = gIOResources)) {
6051 		if ((inState == (service->__state[0] & inState))
6052 		    && (0 == (service->__state[0] & kIOServiceInactiveState))
6053 		    && service->matchPassive(matching, options)) {
6054 			if (options & kIONotifyOnce) {
6055 				service->retain();
6056 				current = service;
6057 			} else {
6058 				current = OSSet::withObjects((const OSObject **) &service, 1, 1 );
6059 			}
6060 		}
6061 	} else {
6062 		IOServiceMatchContext ctx;
6063 
6064 		options    |= kIOServiceClassDone;
6065 		ctx.table   = matching;
6066 		ctx.state   = inState;
6067 		ctx.count   = 0;
6068 		ctx.done    = 0;
6069 		ctx.options = options;
6070 		ctx.result  = NULL;
6071 
6072 		if ((str = OSDynamicCast(OSString, obj))) {
6073 			const OSSymbol * sym = OSSymbol::withString(str);
6074 			OSMetaClass::applyToInstancesOfClassName(sym, instanceMatch, &ctx);
6075 			sym->release();
6076 		} else {
6077 			IOService::gMetaClass.applyToInstances(instanceMatch, &ctx);
6078 		}
6079 
6080 		if (((!(options & kIONotifyOnce) || !ctx.result))
6081 		    && matching->getObject(gIOCompatibilityMatchKey)) {
6082 			IOServiceCompatibility::gMetaClass.applyToInstances(instanceMatch, &ctx);
6083 		}
6084 
6085 		current = ctx.result;
6086 		options |= kIOServiceInternalDone;
6087 		if (current && (ctx.done != ctx.count)) {
6088 			OSSet * source = OSDynamicCast(OSSet, current);
6089 			current = NULL;
6090 			while ((service = (IOService *) source->getAnyObject())) {
6091 				if (service->matchPassive(matching, options)) {
6092 					if (options & kIONotifyOnce) {
6093 						service->retain();
6094 						current = service;
6095 						break;
6096 					}
6097 					if (current) {
6098 						((OSSet *)current)->setObject( service );
6099 					} else {
6100 						current = OSSet::withObjects(
6101 							(const OSObject **) &service, 1, 1 );
6102 					}
6103 				}
6104 				source->removeObject(service);
6105 			}
6106 			source->release();
6107 		}
6108 	}
6109 
6110 #if MATCH_DEBUG
6111 	{
6112 		OSObject * _current = 0;
6113 
6114 		iter = IORegistryIterator::iterateOver( gIOServicePlane,
6115 		    kIORegistryIterateRecursively );
6116 		if (iter) {
6117 			do {
6118 				iter->reset();
6119 				while ((service = (IOService *) iter->getNextObject())) {
6120 					if ((inState == (service->__state[0] & inState))
6121 					    && (0 == (service->__state[0] & kIOServiceInactiveState))
6122 					    && service->matchPassive(matching, 0)) {
6123 						if (options & kIONotifyOnce) {
6124 							service->retain();
6125 							_current = service;
6126 							break;
6127 						}
6128 						if (_current) {
6129 							((OSSet *)_current)->setObject( service );
6130 						} else {
6131 							_current = OSSet::withObjects(
6132 								(const OSObject **) &service, 1, 1 );
6133 						}
6134 					}
6135 				}
6136 			} while (!service && !iter->isValid());
6137 			iter->release();
6138 		}
6139 
6140 		if (((current != 0) != (_current != 0))
6141 		    || (current && _current && !current->isEqualTo(_current))) {
6142 			OSSerialize * s1 = OSSerialize::withCapacity(128);
6143 			OSSerialize * s2 = OSSerialize::withCapacity(128);
6144 			current->serialize(s1);
6145 			_current->serialize(s2);
6146 			kprintf("**mismatch** %p %p\n%s\n%s\n%s\n", IOSERVICE_OBFUSCATE(current),
6147 			    IOSERVICE_OBFUSCATE(_current), s->text(), s1->text(), s2->text());
6148 			s1->release();
6149 			s2->release();
6150 		}
6151 
6152 		if (_current) {
6153 			_current->release();
6154 		}
6155 	}
6156 
6157 	s->release();
6158 #endif
6159 
6160 	if (current && (0 == (options & (kIONotifyOnce | kIOServiceExistingSet)))) {
6161 		iter = OSCollectionIterator::withCollection((OSSet *)current );
6162 		current->release();
6163 		current = iter;
6164 	}
6165 
6166 	return current;
6167 }
6168 
6169 // public version
6170 OSIterator *
getMatchingServices(OSDictionary * matching)6171 IOService::getMatchingServices( OSDictionary * matching )
6172 {
6173 	OSIterator *        iter;
6174 
6175 	// is a lock even needed?
6176 	LOCKWRITENOTIFY();
6177 
6178 	iter = (OSIterator *) copyExistingServices( matching,
6179 	    kIOServiceMatchedState );
6180 
6181 	UNLOCKNOTIFY();
6182 
6183 	return iter;
6184 }
6185 
6186 IOService *
copyMatchingService(OSDictionary * matching)6187 IOService::copyMatchingService( OSDictionary * matching )
6188 {
6189 	IOService * service;
6190 
6191 	// is a lock even needed?
6192 	LOCKWRITENOTIFY();
6193 
6194 	service = (IOService *) copyExistingServices( matching,
6195 	    kIOServiceMatchedState, kIONotifyOnce );
6196 
6197 	UNLOCKNOTIFY();
6198 
6199 	return service;
6200 }
6201 
6202 struct _IOServiceMatchingNotificationHandlerRef {
6203 	IOServiceNotificationHandler handler;
6204 	void * ref;
6205 };
6206 
6207 static bool
_IOServiceMatchingNotificationHandler(void * target,void * refCon,IOService * newService,IONotifier * notifier)6208 _IOServiceMatchingNotificationHandler( void * target, void * refCon,
6209     IOService * newService,
6210     IONotifier * notifier )
6211 {
6212 	return (*((_IOServiceNotifier *) notifier)->compatHandler)(target, refCon, newService);
6213 }
6214 
6215 // internal - call with gNotificationLock
6216 IONotifier *
setNotification(const OSSymbol * type,OSDictionary * matching,IOServiceMatchingNotificationHandler handler,void * target,void * ref,SInt32 priority)6217 IOService::setNotification(
6218 	const OSSymbol * type, OSDictionary * matching,
6219 	IOServiceMatchingNotificationHandler handler, void * target, void * ref,
6220 	SInt32 priority )
6221 {
6222 	_IOServiceNotifier * notify = NULL;
6223 	OSOrderedSet *      set;
6224 
6225 	if (!matching) {
6226 		return NULL;
6227 	}
6228 
6229 	notify = new _IOServiceNotifier;
6230 	if (notify && !notify->init()) {
6231 		notify->release();
6232 		notify = NULL;
6233 	}
6234 
6235 	if (notify) {
6236 		notify->handler = handler;
6237 		notify->target = target;
6238 		notify->type = type;
6239 		notify->matching = matching;
6240 		matching->retain();
6241 		if (handler == &_IOServiceMatchingNotificationHandler) {
6242 			notify->compatHandler = ((_IOServiceMatchingNotificationHandlerRef *)ref)->handler;
6243 			notify->ref = ((_IOServiceMatchingNotificationHandlerRef *)ref)->ref;
6244 		} else {
6245 			notify->ref = ref;
6246 		}
6247 		notify->priority = priority;
6248 		notify->state = kIOServiceNotifyEnable;
6249 		queue_init( &notify->handlerInvocations );
6250 
6251 		////// queue
6252 
6253 		if (NULL == (set = (OSOrderedSet *) gNotifications->getObject( type ))) {
6254 			set = OSOrderedSet::withCapacity( 1,
6255 			    IONotifyOrdering, NULL );
6256 			if (set) {
6257 				gNotifications->setObject( type, set );
6258 				set->release();
6259 			}
6260 		}
6261 		notify->whence = set;
6262 		if (set) {
6263 			set->setObject( notify );
6264 		}
6265 	}
6266 
6267 	return notify;
6268 }
6269 
6270 // internal - call with gNotificationLock
6271 IONotifier *
doInstallNotification(const OSSymbol * type,OSDictionary * matching,IOServiceMatchingNotificationHandler handler,void * target,void * ref,SInt32 priority,OSIterator ** existing)6272 IOService::doInstallNotification(
6273 	const OSSymbol * type, OSDictionary * matching,
6274 	IOServiceMatchingNotificationHandler handler,
6275 	void * target, void * ref,
6276 	SInt32 priority, OSIterator ** existing )
6277 {
6278 	OSIterator *        exist;
6279 	IONotifier *        notify;
6280 	IOOptionBits        inState;
6281 
6282 	if (!matching) {
6283 		return NULL;
6284 	}
6285 
6286 	if (type == gIOPublishNotification) {
6287 		inState = kIOServiceRegisteredState;
6288 	} else if (type == gIOFirstPublishNotification) {
6289 		inState = kIOServiceFirstPublishState;
6290 	} else if (type == gIOMatchedNotification) {
6291 		inState = kIOServiceMatchedState;
6292 	} else if (type == gIOFirstMatchNotification) {
6293 		inState = kIOServiceFirstMatchState;
6294 	} else if ((type == gIOTerminatedNotification) || (type == gIOWillTerminateNotification)) {
6295 		inState = 0;
6296 	} else {
6297 		return NULL;
6298 	}
6299 
6300 	notify = setNotification( type, matching, handler, target, ref, priority );
6301 
6302 	if (inState) {
6303 		// get the current set
6304 		exist = (OSIterator *) copyExistingServices( matching, inState );
6305 	} else {
6306 		exist = NULL;
6307 	}
6308 
6309 	*existing = exist;
6310 
6311 	return notify;
6312 }
6313 
6314 #if !defined(__LP64__)
6315 IONotifier *
installNotification(const OSSymbol * type,OSDictionary * matching,IOServiceNotificationHandler handler,void * target,void * refCon,SInt32 priority,OSIterator ** existing)6316 IOService::installNotification(const OSSymbol * type, OSDictionary * matching,
6317     IOServiceNotificationHandler handler,
6318     void * target, void * refCon,
6319     SInt32 priority, OSIterator ** existing )
6320 {
6321 	IONotifier * result;
6322 	_IOServiceMatchingNotificationHandlerRef ref;
6323 	ref.handler = handler;
6324 	ref.ref     = refCon;
6325 
6326 	result = (_IOServiceNotifier *) installNotification( type, matching,
6327 	    &_IOServiceMatchingNotificationHandler,
6328 	    target, &ref, priority, existing );
6329 	if (result) {
6330 		matching->release();
6331 	}
6332 
6333 	return result;
6334 }
6335 
6336 #endif /* !defined(__LP64__) */
6337 
6338 
6339 IONotifier *
installNotification(const OSSymbol * type,OSDictionary * matching,IOServiceMatchingNotificationHandler handler,void * target,void * ref,SInt32 priority,OSIterator ** existing)6340 IOService::installNotification(
6341 	const OSSymbol * type, OSDictionary * matching,
6342 	IOServiceMatchingNotificationHandler handler,
6343 	void * target, void * ref,
6344 	SInt32 priority, OSIterator ** existing )
6345 {
6346 	IONotifier * notify;
6347 
6348 	LOCKWRITENOTIFY();
6349 
6350 	notify = doInstallNotification( type, matching, handler, target, ref,
6351 	    priority, existing );
6352 
6353 	// in case handler remove()s
6354 	if (notify) {
6355 		notify->retain();
6356 	}
6357 
6358 	UNLOCKNOTIFY();
6359 
6360 	return notify;
6361 }
6362 
6363 IONotifier *
addNotification(const OSSymbol * type,OSDictionary * matching,IOServiceNotificationHandler handler,void * target,void * refCon,SInt32 priority)6364 IOService::addNotification(
6365 	const OSSymbol * type, OSDictionary * matching,
6366 	IOServiceNotificationHandler handler,
6367 	void * target, void * refCon,
6368 	SInt32 priority )
6369 {
6370 	IONotifier * result;
6371 	_IOServiceMatchingNotificationHandlerRef ref;
6372 
6373 	ref.handler = handler;
6374 	ref.ref     = refCon;
6375 
6376 	result = addMatchingNotification(type, matching, &_IOServiceMatchingNotificationHandler,
6377 	    target, &ref, priority);
6378 
6379 	if (result) {
6380 		matching->release();
6381 	}
6382 
6383 	return result;
6384 }
6385 
6386 IONotifier *
addMatchingNotification(const OSSymbol * type,OSDictionary * matching,IOServiceMatchingNotificationHandler handler,void * target,void * ref,SInt32 priority)6387 IOService::addMatchingNotification(
6388 	const OSSymbol * type, OSDictionary * matching,
6389 	IOServiceMatchingNotificationHandler handler,
6390 	void * target, void * ref,
6391 	SInt32 priority )
6392 {
6393 	OSIterator *                existing = NULL;
6394 	IONotifier *                ret;
6395 	_IOServiceNotifier *        notify;
6396 	IOService *                 next;
6397 
6398 	ret = notify = (_IOServiceNotifier *) installNotification( type, matching,
6399 	    handler, target, ref, priority, &existing );
6400 	if (!ret) {
6401 		OSSafeReleaseNULL(existing);
6402 		return NULL;
6403 	}
6404 
6405 	// send notifications for existing set
6406 	if (existing) {
6407 		while ((next = (IOService *) existing->getNextObject())) {
6408 			if (0 == (next->__state[0] & kIOServiceInactiveState)) {
6409 				next->invokeNotifier( notify );
6410 			}
6411 		}
6412 		existing->release();
6413 	}
6414 
6415 	LOCKWRITENOTIFY();
6416 	bool removed = (NULL == notify->whence);
6417 	notify->release();
6418 	if (removed) {
6419 		ret = gIOServiceNullNotifier;
6420 	}
6421 	UNLOCKNOTIFY();
6422 
6423 	return ret;
6424 }
6425 
6426 static bool
IOServiceMatchingNotificationHandlerToBlock(void * target __unused,void * refCon,IOService * newService,IONotifier * notifier)6427 IOServiceMatchingNotificationHandlerToBlock( void * target __unused, void * refCon,
6428     IOService * newService,
6429     IONotifier * notifier )
6430 {
6431 	return ((IOServiceMatchingNotificationHandlerBlock) refCon)(newService, notifier);
6432 }
6433 
6434 IONotifier *
addMatchingNotification(const OSSymbol * type,OSDictionary * matching,SInt32 priority,IOServiceMatchingNotificationHandlerBlock handler)6435 IOService::addMatchingNotification(
6436 	const OSSymbol * type, OSDictionary * matching,
6437 	SInt32 priority,
6438 	IOServiceMatchingNotificationHandlerBlock handler)
6439 {
6440 	IONotifier * notify;
6441 	void       * block;
6442 
6443 	block = Block_copy(handler);
6444 	if (!block) {
6445 		return NULL;
6446 	}
6447 
6448 	notify = addMatchingNotification(type, matching,
6449 	    &IOServiceMatchingNotificationHandlerToBlock, NULL, block, priority);
6450 
6451 	if (!notify) {
6452 		Block_release(block);
6453 	}
6454 
6455 	return notify;
6456 }
6457 
6458 struct IOUserServerCancellationHandlerArgs {
6459 	IOService ** ref;
6460 	bool canceled;
6461 };
6462 
6463 void
userServerCheckInTokenCancellationHandler(__unused IOUserServerCheckInToken * token,void * ref)6464 IOService::userServerCheckInTokenCancellationHandler(
6465 	__unused IOUserServerCheckInToken *token,
6466 	void *ref)
6467 {
6468 	IOUserServerCancellationHandlerArgs * args = (typeof(args))ref;
6469 	LOCKWRITENOTIFY();
6470 	WAKEUPNOTIFY(args->ref);
6471 	args->canceled = true;
6472 	UNLOCKNOTIFY();
6473 }
6474 
6475 bool
syncNotificationHandler(void *,void * ref,IOService * newService,IONotifier * notifier)6476 IOService::syncNotificationHandler(
6477 	void * /* target */, void * ref,
6478 	IOService * newService,
6479 	IONotifier * notifier )
6480 {
6481 	LOCKWRITENOTIFY();
6482 	if (!*((IOService **) ref)) {
6483 		newService->retain();
6484 		(*(IOService **) ref) = newService;
6485 		WAKEUPNOTIFY(ref);
6486 	}
6487 	UNLOCKNOTIFY();
6488 
6489 	return false;
6490 }
6491 
6492 IOService *
waitForMatchingServiceWithToken(OSDictionary * matching,uint64_t timeout,IOUserServerCheckInToken * checkInToken)6493 IOService::waitForMatchingServiceWithToken( OSDictionary * matching,
6494     uint64_t timeout,
6495     IOUserServerCheckInToken * checkInToken)
6496 {
6497 	IONotifier *        notify = NULL;
6498 	// priority doesn't help us much since we need a thread wakeup
6499 	SInt32              priority = 0;
6500 	IOService *         result;
6501 	IOUserServerCancellationHandlerArgs cancelArgs;
6502 	_IOUserServerCheckInCancellationHandler * cancellationHandler = NULL;
6503 
6504 	if (!matching) {
6505 		return NULL;
6506 	}
6507 
6508 	result = NULL;
6509 	cancelArgs.ref = &result;
6510 	cancelArgs.canceled = false;
6511 
6512 #if DEBUG || DEVELOPMENT
6513 	char                currentName[MAXTHREADNAMESIZE];
6514 	char                newName[MAXTHREADNAMESIZE];
6515 	OSObject          * obj;
6516 	OSString          * str;
6517 	OSDictionary      * dict;
6518 
6519 	currentName[0] = '\0';
6520 	if (thread_has_thread_name(current_thread())) {
6521 		dict = matching;
6522 		obj = matching->getObject(gIOPropertyMatchKey);
6523 		if ((dict = OSDynamicCast(OSDictionary, obj))) {
6524 			OSObject * result __block = NULL;
6525 			dict->iterateObjects(^bool (const OSSymbol * sym, OSObject * value) {
6526 				result = __DECONST(OSObject *, sym);
6527 				return true;
6528 			});
6529 			obj = result;
6530 		}
6531 		if (!obj) {
6532 			obj = matching->getObject(gIOResourceMatchKey);
6533 		}
6534 		if (!obj) {
6535 			obj = matching->getObject(gIONameMatchKey);
6536 		}
6537 		if (!obj) {
6538 			obj = matching->getObject(gIOProviderClassKey);
6539 		}
6540 		if ((str = OSDynamicCast(OSString, obj))) {
6541 			thread_get_thread_name(current_thread(), currentName);
6542 			snprintf(newName, sizeof(newName), "Waiting_'%s'", str->getCStringNoCopy());
6543 			thread_set_thread_name(current_thread(), newName);
6544 		}
6545 	}
6546 #endif /* DEBUG || DEVELOPMENT */
6547 
6548 	if (checkInToken) {
6549 		cancellationHandler = checkInToken->setCancellationHandler(&IOService::userServerCheckInTokenCancellationHandler,
6550 		    &cancelArgs);
6551 	}
6552 
6553 	LOCKWRITENOTIFY();
6554 	do{
6555 		if (cancelArgs.canceled) {
6556 			// token was already canceled, no need to wait or find services
6557 			break;
6558 		}
6559 		result = (IOService *) copyExistingServices( matching,
6560 		    kIOServiceMatchedState, kIONotifyOnce );
6561 		if (result) {
6562 			break;
6563 		}
6564 		notify = IOService::setNotification( gIOMatchedNotification, matching,
6565 		    &IOService::syncNotificationHandler, (void *) NULL,
6566 		    &result, priority );
6567 		if (!notify) {
6568 			break;
6569 		}
6570 		if (UINT64_MAX != timeout) {
6571 			AbsoluteTime deadline;
6572 			nanoseconds_to_absolutetime(timeout, &deadline);
6573 			clock_absolutetime_interval_to_deadline(deadline, &deadline);
6574 			SLEEPNOTIFYTO(&result, deadline);
6575 		} else {
6576 			SLEEPNOTIFY(&result);
6577 		}
6578 	}while (false);
6579 
6580 	UNLOCKNOTIFY();
6581 
6582 	if (checkInToken && cancellationHandler) {
6583 		checkInToken->removeCancellationHandler(cancellationHandler);
6584 	}
6585 
6586 #if DEBUG || DEVELOPMENT
6587 	if (currentName[0]) {
6588 		thread_set_thread_name(current_thread(), currentName);
6589 	}
6590 #endif /* DEBUG || DEVELOPMENT */
6591 
6592 	if (notify) {
6593 		notify->remove(); // dequeues
6594 	}
6595 
6596 	OSSafeReleaseNULL(cancellationHandler);
6597 
6598 	return result;
6599 }
6600 
6601 IOService *
waitForMatchingService(OSDictionary * matching,uint64_t timeout)6602 IOService::waitForMatchingService( OSDictionary * matching,
6603     uint64_t timeout)
6604 {
6605 	return IOService::waitForMatchingServiceWithToken(matching, timeout, NULL);
6606 }
6607 
6608 IOService *
waitForService(OSDictionary * matching,mach_timespec_t * timeout)6609 IOService::waitForService( OSDictionary * matching,
6610     mach_timespec_t * timeout )
6611 {
6612 	IOService * result;
6613 	uint64_t    timeoutNS;
6614 
6615 	if (timeout) {
6616 		timeoutNS = timeout->tv_sec;
6617 		timeoutNS *= kSecondScale;
6618 		timeoutNS += timeout->tv_nsec;
6619 	} else {
6620 		timeoutNS = UINT64_MAX;
6621 	}
6622 
6623 	result = waitForMatchingService(matching, timeoutNS);
6624 
6625 	matching->release();
6626 	if (result) {
6627 		result->release();
6628 	}
6629 
6630 	return result;
6631 }
6632 
6633 __dead2
6634 void
deliverNotification(const OSSymbol * type,IOOptionBits orNewState,IOOptionBits andNewState)6635 IOService::deliverNotification( const OSSymbol * type,
6636     IOOptionBits orNewState, IOOptionBits andNewState )
6637 {
6638 	panic("deliverNotification");
6639 }
6640 
6641 OSArray *
copyNotifiers(const OSSymbol * type,IOOptionBits orNewState,IOOptionBits andNewState)6642 IOService::copyNotifiers(const OSSymbol * type,
6643     IOOptionBits orNewState, IOOptionBits andNewState )
6644 {
6645 	_IOServiceNotifier * notify;
6646 	OSIterator *         iter;
6647 	OSArray *            willSend = NULL;
6648 
6649 	lockForArbitration();
6650 
6651 	if ((0 == (__state[0] & kIOServiceInactiveState))
6652 	    || (type == gIOTerminatedNotification)
6653 	    || (type == gIOWillTerminateNotification)) {
6654 		LOCKREADNOTIFY();
6655 
6656 		iter = OSCollectionIterator::withCollection((OSOrderedSet *)
6657 		    gNotifications->getObject( type ));
6658 
6659 		if (iter) {
6660 			while ((notify = (_IOServiceNotifier *) iter->getNextObject())) {
6661 				if (matchPassive(notify->matching, 0)
6662 				    && (kIOServiceNotifyEnable & notify->state)) {
6663 					if (NULL == willSend) {
6664 						willSend = OSArray::withCapacity(8);
6665 					}
6666 					if (willSend) {
6667 						willSend->setObject( notify );
6668 					}
6669 				}
6670 			}
6671 			iter->release();
6672 		}
6673 		__state[0] = (__state[0] | orNewState) & andNewState;
6674 		UNLOCKNOTIFY();
6675 	}
6676 
6677 	unlockForArbitration();
6678 
6679 	return willSend;
6680 }
6681 
6682 IOOptionBits
getState(void) const6683 IOService::getState( void ) const
6684 {
6685 	return __state[0];
6686 }
6687 
6688 /*
6689  * Helpers to make matching objects for simple cases
6690  */
6691 
6692 OSDictionary *
serviceMatching(const OSString * name,OSDictionary * table)6693 IOService::serviceMatching( const OSString * name,
6694     OSDictionary * table )
6695 {
6696 	const OSString *    str;
6697 
6698 	str = OSSymbol::withString(name);
6699 	if (!str) {
6700 		return NULL;
6701 	}
6702 
6703 	if (!table) {
6704 		table = OSDictionary::withCapacity( 2 );
6705 	}
6706 	if (table) {
6707 		table->setObject(gIOProviderClassKey, (OSObject *)str );
6708 	}
6709 	str->release();
6710 
6711 	return table;
6712 }
6713 
6714 
6715 OSSharedPtr<OSDictionary>
serviceMatching(const OSString * name,OSSharedPtr<OSDictionary> table)6716 IOService::serviceMatching( const OSString * name,
6717     OSSharedPtr<OSDictionary> table)
6718 {
6719 	OSDictionary * result = serviceMatching(name, table.get());
6720 	if (table) {
6721 		return OSSharedPtr<OSDictionary>(result, OSRetain);
6722 	} else {
6723 		return OSSharedPtr<OSDictionary>(result, OSNoRetain);
6724 	}
6725 }
6726 
6727 
6728 OSDictionary *
serviceMatching(const char * name,OSDictionary * table)6729 IOService::serviceMatching( const char * name,
6730     OSDictionary * table )
6731 {
6732 	const OSString *    str;
6733 
6734 	str = OSSymbol::withCString( name );
6735 	if (!str) {
6736 		return NULL;
6737 	}
6738 
6739 	table = serviceMatching( str, table );
6740 	str->release();
6741 	return table;
6742 }
6743 
6744 
6745 OSSharedPtr<OSDictionary>
serviceMatching(const char * className,OSSharedPtr<OSDictionary> table)6746 IOService::serviceMatching( const char * className,
6747     OSSharedPtr<OSDictionary> table)
6748 {
6749 	OSDictionary * result = serviceMatching(className, table.get());
6750 	if (table) {
6751 		return OSSharedPtr<OSDictionary>(result, OSRetain);
6752 	} else {
6753 		return OSSharedPtr<OSDictionary>(result, OSNoRetain);
6754 	}
6755 }
6756 
6757 
6758 OSDictionary *
nameMatching(const OSString * name,OSDictionary * table)6759 IOService::nameMatching( const OSString * name,
6760     OSDictionary * table )
6761 {
6762 	if (!table) {
6763 		table = OSDictionary::withCapacity( 2 );
6764 	}
6765 	if (table) {
6766 		table->setObject( gIONameMatchKey, (OSObject *)name );
6767 	}
6768 
6769 	return table;
6770 }
6771 
6772 
6773 OSSharedPtr<OSDictionary>
nameMatching(const OSString * name,OSSharedPtr<OSDictionary> table)6774 IOService::nameMatching( const OSString * name,
6775     OSSharedPtr<OSDictionary> table)
6776 {
6777 	OSDictionary * result = nameMatching(name, table.get());
6778 	if (table) {
6779 		return OSSharedPtr<OSDictionary>(result, OSRetain);
6780 	} else {
6781 		return OSSharedPtr<OSDictionary>(result, OSNoRetain);
6782 	}
6783 }
6784 
6785 
6786 OSDictionary *
nameMatching(const char * name,OSDictionary * table)6787 IOService::nameMatching( const char * name,
6788     OSDictionary * table )
6789 {
6790 	const OSString *    str;
6791 
6792 	str = OSSymbol::withCString( name );
6793 	if (!str) {
6794 		return NULL;
6795 	}
6796 
6797 	table = nameMatching( str, table );
6798 	str->release();
6799 	return table;
6800 }
6801 
6802 
6803 OSSharedPtr<OSDictionary>
nameMatching(const char * name,OSSharedPtr<OSDictionary> table)6804 IOService::nameMatching( const char * name,
6805     OSSharedPtr<OSDictionary> table)
6806 {
6807 	OSDictionary * result = nameMatching(name, table.get());
6808 	if (table) {
6809 		return OSSharedPtr<OSDictionary>(result, OSRetain);
6810 	} else {
6811 		return OSSharedPtr<OSDictionary>(result, OSNoRetain);
6812 	}
6813 }
6814 
6815 
6816 OSDictionary *
resourceMatching(const OSString * str,OSDictionary * table)6817 IOService::resourceMatching( const OSString * str,
6818     OSDictionary * table )
6819 {
6820 	table = serviceMatching( gIOResourcesKey, table );
6821 	if (table) {
6822 		table->setObject( gIOResourceMatchKey, (OSObject *) str );
6823 	}
6824 
6825 	return table;
6826 }
6827 
6828 
6829 OSSharedPtr<OSDictionary>
resourceMatching(const OSString * str,OSSharedPtr<OSDictionary> table)6830 IOService::resourceMatching( const OSString * str,
6831     OSSharedPtr<OSDictionary> table)
6832 {
6833 	OSDictionary * result = resourceMatching(str, table.get());
6834 	if (table) {
6835 		return OSSharedPtr<OSDictionary>(result, OSRetain);
6836 	} else {
6837 		return OSSharedPtr<OSDictionary>(result, OSNoRetain);
6838 	}
6839 }
6840 
6841 
6842 OSDictionary *
resourceMatching(const char * name,OSDictionary * table)6843 IOService::resourceMatching( const char * name,
6844     OSDictionary * table )
6845 {
6846 	const OSSymbol *    str;
6847 
6848 	str = OSSymbol::withCString( name );
6849 	if (!str) {
6850 		return NULL;
6851 	}
6852 
6853 	table = resourceMatching( str, table );
6854 	str->release();
6855 
6856 	return table;
6857 }
6858 
6859 
6860 OSSharedPtr<OSDictionary>
resourceMatching(const char * name,OSSharedPtr<OSDictionary> table)6861 IOService::resourceMatching( const char * name,
6862     OSSharedPtr<OSDictionary> table)
6863 {
6864 	OSDictionary * result = resourceMatching(name, table.get());
6865 	if (table) {
6866 		return OSSharedPtr<OSDictionary>(result, OSRetain);
6867 	} else {
6868 		return OSSharedPtr<OSDictionary>(result, OSNoRetain);
6869 	}
6870 }
6871 
6872 
6873 OSDictionary *
propertyMatching(const OSSymbol * key,const OSObject * value,OSDictionary * table)6874 IOService::propertyMatching( const OSSymbol * key, const OSObject * value,
6875     OSDictionary * table )
6876 {
6877 	OSDictionary * properties;
6878 
6879 	properties = OSDictionary::withCapacity( 2 );
6880 	if (!properties) {
6881 		return NULL;
6882 	}
6883 	properties->setObject( key, value );
6884 
6885 	if (!table) {
6886 		table = OSDictionary::withCapacity( 2 );
6887 	}
6888 	if (table) {
6889 		table->setObject( gIOPropertyMatchKey, properties );
6890 	}
6891 
6892 	properties->release();
6893 
6894 	return table;
6895 }
6896 
6897 
6898 OSSharedPtr<OSDictionary>
propertyMatching(const OSSymbol * key,const OSObject * value,OSSharedPtr<OSDictionary> table)6899 IOService::propertyMatching( const OSSymbol * key, const OSObject * value,
6900     OSSharedPtr<OSDictionary> table)
6901 {
6902 	OSDictionary * result = propertyMatching(key, value, table.get());
6903 	if (table) {
6904 		return OSSharedPtr<OSDictionary>(result, OSRetain);
6905 	} else {
6906 		return OSSharedPtr<OSDictionary>(result, OSNoRetain);
6907 	}
6908 }
6909 
6910 
6911 OSDictionary *
registryEntryIDMatching(uint64_t entryID,OSDictionary * table)6912 IOService::registryEntryIDMatching( uint64_t entryID,
6913     OSDictionary * table )
6914 {
6915 	OSNumber *     num;
6916 
6917 	num = OSNumber::withNumber( entryID, 64 );
6918 	if (!num) {
6919 		return NULL;
6920 	}
6921 
6922 	if (!table) {
6923 		table = OSDictionary::withCapacity( 2 );
6924 	}
6925 	if (table) {
6926 		table->setObject( gIORegistryEntryIDKey, num );
6927 	}
6928 
6929 	if (num) {
6930 		num->release();
6931 	}
6932 
6933 	return table;
6934 }
6935 
6936 
6937 OSSharedPtr<OSDictionary>
registryEntryIDMatching(uint64_t entryID,OSSharedPtr<OSDictionary> table)6938 IOService::registryEntryIDMatching( uint64_t entryID,
6939     OSSharedPtr<OSDictionary> table)
6940 {
6941 	OSDictionary * result = registryEntryIDMatching(entryID, table.get());
6942 	if (table) {
6943 		return OSSharedPtr<OSDictionary>(result, OSRetain);
6944 	} else {
6945 		return OSSharedPtr<OSDictionary>(result, OSNoRetain);
6946 	}
6947 }
6948 
6949 
6950 
6951 /*
6952  * _IOServiceNotifier
6953  */
6954 
6955 // wait for all threads, other than the current one,
6956 //  to exit the handler
6957 
6958 void
wait()6959 _IOServiceNotifier::wait()
6960 {
6961 	_IOServiceNotifierInvocation * next;
6962 	bool doWait;
6963 
6964 	do {
6965 		doWait = false;
6966 		queue_iterate( &handlerInvocations, next,
6967 		    _IOServiceNotifierInvocation *, link) {
6968 			if (next->thread != current_thread()) {
6969 				doWait = true;
6970 				break;
6971 			}
6972 		}
6973 		if (doWait) {
6974 			state |= kIOServiceNotifyWaiter;
6975 			SLEEPNOTIFY(this);
6976 		}
6977 	} while (doWait);
6978 }
6979 
6980 void
free()6981 _IOServiceNotifier::free()
6982 {
6983 	assert( queue_empty( &handlerInvocations ));
6984 
6985 	if (handler == &IOServiceMatchingNotificationHandlerToBlock) {
6986 		Block_release(ref);
6987 	}
6988 
6989 	OSObject::free();
6990 }
6991 
6992 void
remove()6993 _IOServiceNotifier::remove()
6994 {
6995 	LOCKWRITENOTIFY();
6996 
6997 	if (whence) {
6998 		whence->removeObject((OSObject *) this );
6999 		whence = NULL;
7000 	}
7001 	if (matching) {
7002 		matching->release();
7003 		matching = NULL;
7004 	}
7005 
7006 	state &= ~kIOServiceNotifyEnable;
7007 
7008 	wait();
7009 
7010 	UNLOCKNOTIFY();
7011 
7012 	release();
7013 }
7014 
7015 bool
disable()7016 _IOServiceNotifier::disable()
7017 {
7018 	bool        ret;
7019 
7020 	LOCKWRITENOTIFY();
7021 
7022 	ret = (0 != (kIOServiceNotifyEnable & state));
7023 	state &= ~kIOServiceNotifyEnable;
7024 	if (ret) {
7025 		wait();
7026 	}
7027 
7028 	UNLOCKNOTIFY();
7029 
7030 	return ret;
7031 }
7032 
7033 void
enable(bool was)7034 _IOServiceNotifier::enable( bool was )
7035 {
7036 	LOCKWRITENOTIFY();
7037 	if (was) {
7038 		state |= kIOServiceNotifyEnable;
7039 	} else {
7040 		state &= ~kIOServiceNotifyEnable;
7041 	}
7042 	UNLOCKNOTIFY();
7043 }
7044 
7045 
7046 /*
7047  * _IOServiceNullNotifier
7048  */
7049 
7050 void
taggedRetain(const void * tag) const7051 _IOServiceNullNotifier::taggedRetain(const void *tag) const
7052 {
7053 }
7054 void
taggedRelease(const void * tag,const int when) const7055 _IOServiceNullNotifier::taggedRelease(const void *tag, const int when) const
7056 {
7057 }
7058 void
free()7059 _IOServiceNullNotifier::free()
7060 {
7061 }
7062 void
wait()7063 _IOServiceNullNotifier::wait()
7064 {
7065 }
7066 void
remove()7067 _IOServiceNullNotifier::remove()
7068 {
7069 }
7070 void
enable(bool was)7071 _IOServiceNullNotifier::enable(bool was)
7072 {
7073 }
7074 bool
disable()7075 _IOServiceNullNotifier::disable()
7076 {
7077 	return false;
7078 }
7079 
7080 /*
7081  * IOResources
7082  */
7083 
7084 IOService *
resources(void)7085 IOResources::resources( void )
7086 {
7087 	IOResources *       inst;
7088 
7089 	inst = new IOResources;
7090 	if (inst && !inst->init()) {
7091 		inst->release();
7092 		inst = NULL;
7093 	}
7094 
7095 	return inst;
7096 }
7097 
7098 bool
init(OSDictionary * dictionary)7099 IOResources::init( OSDictionary * dictionary )
7100 {
7101 	// Do super init first
7102 	if (!IOService::init()) {
7103 		return false;
7104 	}
7105 
7106 	// Allow PAL layer to publish a value
7107 	const char *property_name;
7108 	int property_value;
7109 
7110 	pal_get_resource_property( &property_name, &property_value );
7111 
7112 	if (property_name) {
7113 		OSNumber *num;
7114 		const OSSymbol *        sym;
7115 
7116 		if ((num = OSNumber::withNumber(property_value, 32)) != NULL) {
7117 			if ((sym = OSSymbol::withCString( property_name)) != NULL) {
7118 				this->setProperty( sym, num );
7119 				sym->release();
7120 			}
7121 			num->release();
7122 		}
7123 	}
7124 
7125 	return true;
7126 }
7127 
7128 IOReturn
newUserClient(task_t owningTask,void * securityID,UInt32 type,OSDictionary * properties,IOUserClient ** handler)7129 IOResources::newUserClient(task_t owningTask, void * securityID,
7130     UInt32 type, OSDictionary * properties,
7131     IOUserClient ** handler)
7132 {
7133 	return kIOReturnUnsupported;
7134 }
7135 
7136 IOWorkLoop *
getWorkLoop() const7137 IOResources::getWorkLoop() const
7138 {
7139 	// If we are the resource root
7140 	// then use the platform's workloop
7141 	if (this == (IOResources *) gIOResources) {
7142 		return getPlatform()->getWorkLoop();
7143 	} else {
7144 		return IOService::getWorkLoop();
7145 	}
7146 }
7147 
7148 static bool
IOResourcesMatchPropertyTable(IOService * resources,OSDictionary * table)7149 IOResourcesMatchPropertyTable(IOService * resources, OSDictionary * table)
7150 {
7151 	OSObject *          prop;
7152 	bool __block        ok = true;
7153 
7154 	prop = table->getObject( gIOResourceMatchKey );
7155 	if (prop) {
7156 		prop->iterateObjects(^bool (OSObject * obj)
7157 		{
7158 			OSString *
7159 			str = OSDynamicCast(OSString, obj);
7160 			ok = (NULL != resources->getProperty(str));
7161 			return !ok;
7162 		});
7163 	} else if ((prop = table->getObject(gIOResourceMatchedKey))) {
7164 		OSObject * obj;
7165 		OSArray *  keys;
7166 
7167 		obj = resources->copyProperty(gIOResourceMatchedKey);
7168 		keys = OSDynamicCast(OSArray, obj);
7169 		ok = false;
7170 		if (keys) {
7171 			// assuming OSSymbol
7172 			ok = ((-1U) != keys->getNextIndexOfObject(prop, 0));
7173 		}
7174 		OSSafeReleaseNULL(obj);
7175 	}
7176 
7177 	return ok;
7178 }
7179 
7180 bool
matchPropertyTable(OSDictionary * table)7181 IOResources::matchPropertyTable( OSDictionary * table )
7182 {
7183 	return IOResourcesMatchPropertyTable(this, table);
7184 }
7185 
7186 /*
7187  * IOUserResources
7188  */
7189 
7190 IOService *
resources(void)7191 IOUserResources::resources( void )
7192 {
7193 	IOUserResources *       inst;
7194 
7195 	inst = OSTypeAlloc(IOUserResources);
7196 	if (inst && !inst->init()) {
7197 		inst->release();
7198 		inst = NULL;
7199 	}
7200 
7201 	return inst;
7202 }
7203 
7204 bool
init(OSDictionary * dictionary)7205 IOUserResources::init( OSDictionary * dictionary )
7206 {
7207 	// Do super init first
7208 	if (!IOService::init()) {
7209 		return false;
7210 	}
7211 	return true;
7212 }
7213 
7214 IOReturn
newUserClient(task_t owningTask,void * securityID,UInt32 type,OSDictionary * properties,IOUserClient ** handler)7215 IOUserResources::newUserClient(task_t owningTask, void * securityID,
7216     UInt32 type, OSDictionary * properties,
7217     IOUserClient ** handler)
7218 {
7219 	return kIOReturnUnsupported;
7220 }
7221 
7222 IOWorkLoop *
getWorkLoop() const7223 IOUserResources::getWorkLoop() const
7224 {
7225 	return getPlatform()->getWorkLoop();
7226 }
7227 
7228 bool
matchPropertyTable(OSDictionary * table)7229 IOUserResources::matchPropertyTable( OSDictionary * table )
7230 {
7231 	return IOResourcesMatchPropertyTable(this, table);
7232 }
7233 
7234 // --
7235 
7236 void
consoleLockTimer(thread_call_param_t p0,thread_call_param_t p1)7237 IOService::consoleLockTimer(thread_call_param_t p0, thread_call_param_t p1)
7238 {
7239 	IOService::updateConsoleUsers(NULL, 0);
7240 }
7241 
7242 void
updateConsoleUsers(OSArray * consoleUsers,IOMessage systemMessage,bool afterUserspaceReboot)7243 IOService::updateConsoleUsers(OSArray * consoleUsers, IOMessage systemMessage, bool afterUserspaceReboot)
7244 {
7245 	IORegistryEntry * regEntry;
7246 	OSObject *        locked = kOSBooleanFalse;
7247 	uint32_t          idx;
7248 	bool              publish;
7249 	OSDictionary *    user;
7250 	clock_sec_t       now = 0;
7251 	clock_usec_t      microsecs;
7252 
7253 	regEntry = IORegistryEntry::getRegistryRoot();
7254 
7255 	if (!gIOChosenEntry) {
7256 		gIOChosenEntry = IORegistryEntry::fromPath("/chosen", gIODTPlane);
7257 	}
7258 
7259 	IOLockLock(gIOConsoleUsersLock);
7260 
7261 	if (systemMessage) {
7262 		sSystemPower = systemMessage;
7263 #if HIBERNATION
7264 		if (kIOMessageSystemHasPoweredOn == systemMessage) {
7265 			uint32_t lockState = IOHibernateWasScreenLocked();
7266 			switch (lockState) {
7267 			case 0:
7268 				break;
7269 			case kIOScreenLockLocked:
7270 			case kIOScreenLockFileVaultDialog:
7271 				gIOConsoleBooterLockState = kOSBooleanTrue;
7272 				break;
7273 			case kIOScreenLockNoLock:
7274 				gIOConsoleBooterLockState = NULL;
7275 				break;
7276 			case kIOScreenLockUnlocked:
7277 			default:
7278 				gIOConsoleBooterLockState = kOSBooleanFalse;
7279 				break;
7280 			}
7281 		}
7282 #endif /* HIBERNATION */
7283 	}
7284 
7285 	if (consoleUsers) {
7286 		OSNumber * num = NULL;
7287 		bool       loginLocked = true;
7288 
7289 		gIOConsoleLoggedIn = false;
7290 		for (idx = 0;
7291 		    (user = OSDynamicCast(OSDictionary, consoleUsers->getObject(idx)));
7292 		    idx++) {
7293 			gIOConsoleLoggedIn |= ((kOSBooleanTrue == user->getObject(gIOConsoleSessionOnConsoleKey))
7294 			    && (kOSBooleanTrue == user->getObject(gIOConsoleSessionLoginDoneKey)));
7295 
7296 			loginLocked &= (kOSBooleanTrue == user->getObject(gIOConsoleSessionScreenIsLockedKey));
7297 			if (!num) {
7298 				num = OSDynamicCast(OSNumber, user->getObject(gIOConsoleSessionScreenLockedTimeKey));
7299 			}
7300 		}
7301 #if HIBERNATION
7302 		if (!loginLocked || afterUserspaceReboot) {
7303 			gIOConsoleBooterLockState = NULL;
7304 		}
7305 		IOLog("IOConsoleUsers: time(%d) %ld->%d, lin %d, llk %d, \n",
7306 		    (num != NULL), gIOConsoleLockTime, (num ? num->unsigned32BitValue() : 0),
7307 		    gIOConsoleLoggedIn, loginLocked);
7308 #endif /* HIBERNATION */
7309 		gIOConsoleLockTime = num ? num->unsigned32BitValue() : 0;
7310 	}
7311 
7312 	if (!gIOConsoleLoggedIn
7313 	    || (kIOMessageSystemWillSleep == sSystemPower)
7314 	    || (kIOMessageSystemPagingOff == sSystemPower)) {
7315 		if (afterUserspaceReboot) {
7316 			// set "locked" to false after a user space reboot
7317 			// because the reboot happens directly after a user
7318 			// logs into the machine via fvunlock mode.
7319 			locked = kOSBooleanFalse;
7320 		} else {
7321 			locked = kOSBooleanTrue;
7322 		}
7323 	}
7324 #if HIBERNATION
7325 	else if (gIOConsoleBooterLockState) {
7326 		locked = gIOConsoleBooterLockState;
7327 	}
7328 #endif /* HIBERNATION */
7329 	else if (gIOConsoleLockTime) {
7330 		clock_get_calendar_microtime(&now, &microsecs);
7331 		if (gIOConsoleLockTime > now) {
7332 			AbsoluteTime deadline;
7333 			clock_sec_t interval;
7334 			uint32_t interval32;
7335 
7336 			interval = (gIOConsoleLockTime - now);
7337 			interval32 = (uint32_t) interval;
7338 			if (interval32 != interval) {
7339 				interval32 = UINT_MAX;
7340 			}
7341 			clock_interval_to_deadline(interval32, kSecondScale, &deadline);
7342 			thread_call_enter_delayed(gIOConsoleLockCallout, deadline);
7343 		} else {
7344 			locked = kOSBooleanTrue;
7345 		}
7346 	}
7347 
7348 	publish = (consoleUsers || (locked != regEntry->getProperty(gIOConsoleLockedKey)));
7349 	if (publish) {
7350 		regEntry->setProperty(gIOConsoleLockedKey, locked);
7351 		if (consoleUsers) {
7352 			regEntry->setProperty(gIOConsoleUsersKey, consoleUsers);
7353 		}
7354 		OSIncrementAtomic( &gIOConsoleUsersSeed );
7355 	}
7356 
7357 #if HIBERNATION
7358 	if (gIOChosenEntry) {
7359 		if (locked == kOSBooleanTrue) {
7360 			gIOScreenLockState = kIOScreenLockLocked;
7361 		} else if (gIOConsoleLockTime) {
7362 			gIOScreenLockState = kIOScreenLockUnlocked;
7363 		} else {
7364 			gIOScreenLockState = kIOScreenLockNoLock;
7365 		}
7366 		gIOChosenEntry->setProperty(kIOScreenLockStateKey, &gIOScreenLockState, sizeof(gIOScreenLockState));
7367 
7368 		IOLog("IOConsoleUsers: gIOScreenLockState %d, hs %d, bs %d, now %ld, sm 0x%x\n",
7369 		    gIOScreenLockState, gIOHibernateState, (gIOConsoleBooterLockState != NULL), now, systemMessage);
7370 	}
7371 #endif /* HIBERNATION */
7372 
7373 	IOLockUnlock(gIOConsoleUsersLock);
7374 
7375 	if (publish) {
7376 		publishResource( gIOConsoleUsersSeedKey, gIOConsoleUsersSeedValue );
7377 
7378 		MessageClientsContext context;
7379 
7380 		context.service  = getServiceRoot();
7381 		context.type     = kIOMessageConsoleSecurityChange;
7382 		context.argument = (void *) regEntry;
7383 		context.argSize  = 0;
7384 
7385 		applyToInterestNotifiers(getServiceRoot(), gIOConsoleSecurityInterest,
7386 		    &messageClientsApplier, &context );
7387 	}
7388 }
7389 
7390 IOReturn
setProperties(OSObject * properties)7391 IOResources::setProperties( OSObject * properties )
7392 {
7393 	IOReturn                    err;
7394 	const OSSymbol *            key;
7395 	OSDictionary *              dict;
7396 	OSCollectionIterator *      iter;
7397 
7398 	if (!IOCurrentTaskHasEntitlement(kIOResourcesSetPropertyKey)) {
7399 		err = IOUserClient::clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator);
7400 		if (kIOReturnSuccess != err) {
7401 			return err;
7402 		}
7403 	}
7404 
7405 	dict = OSDynamicCast(OSDictionary, properties);
7406 	if (NULL == dict) {
7407 		return kIOReturnBadArgument;
7408 	}
7409 
7410 	iter = OSCollectionIterator::withCollection( dict);
7411 	if (NULL == iter) {
7412 		return kIOReturnBadArgument;
7413 	}
7414 
7415 	while ((key = OSDynamicCast(OSSymbol, iter->getNextObject()))) {
7416 		if (gIOConsoleUsersKey == key) {
7417 			do{
7418 				OSArray * consoleUsers;
7419 				consoleUsers = OSDynamicCast(OSArray, dict->getObject(key));
7420 				if (!consoleUsers) {
7421 					continue;
7422 				}
7423 				IOService::updateConsoleUsers(consoleUsers, 0);
7424 			}while (false);
7425 		}
7426 
7427 		publishResource( key, dict->getObject(key));
7428 	}
7429 
7430 	iter->release();
7431 
7432 	return kIOReturnSuccess;
7433 }
7434 
7435 /*
7436  * Helpers for matching dictionaries.
7437  * Keys existing in matching are checked in properties.
7438  * Keys may be a string or OSCollection of IOStrings
7439  */
7440 
7441 bool
compareProperty(OSDictionary * matching,const char * key)7442 IOService::compareProperty( OSDictionary * matching,
7443     const char *   key )
7444 {
7445 	OSObject *  value;
7446 	OSObject *  prop;
7447 	bool        ok;
7448 
7449 	value = matching->getObject( key );
7450 	if (value) {
7451 		prop = copyProperty(key);
7452 		ok = value->isEqualTo(prop);
7453 		if (prop) {
7454 			prop->release();
7455 		}
7456 	} else {
7457 		ok = true;
7458 	}
7459 
7460 	return ok;
7461 }
7462 
7463 
7464 bool
compareProperty(OSDictionary * matching,const OSString * key)7465 IOService::compareProperty( OSDictionary *   matching,
7466     const OSString * key )
7467 {
7468 	OSObject *  value;
7469 	OSObject *  prop;
7470 	bool        ok;
7471 
7472 	value = matching->getObject( key );
7473 	if (value) {
7474 		prop = copyProperty(key);
7475 		ok = value->isEqualTo(prop);
7476 		if (prop) {
7477 			prop->release();
7478 		}
7479 	} else {
7480 		ok = true;
7481 	}
7482 
7483 	return ok;
7484 }
7485 
7486 #ifndef __clang_analyzer__
7487 // Implementation of this function is hidden from the static analyzer.
7488 // The analyzer was worried about this function's confusing contract over
7489 // the 'keys' parameter. The contract is to either release it or not release it
7490 // depending on whether 'matching' is non-null. Such contracts are discouraged
7491 // but changing it now would break compatibility.
7492 bool
compareProperties(OSDictionary * matching,OSCollection * keys)7493 IOService::compareProperties( OSDictionary * matching,
7494     OSCollection * keys )
7495 {
7496 	OSCollectionIterator *      iter;
7497 	const OSString *            key;
7498 	bool                        ok = true;
7499 
7500 	if (!matching || !keys) {
7501 		return false;
7502 	}
7503 
7504 	iter = OSCollectionIterator::withCollection( keys );
7505 
7506 	if (iter) {
7507 		while (ok && (key = OSDynamicCast( OSString, iter->getNextObject()))) {
7508 			ok = compareProperty( matching, key );
7509 		}
7510 
7511 		iter->release();
7512 	}
7513 	keys->release(); // !! consume a ref !!
7514 
7515 	return ok;
7516 }
7517 #endif // __clang_analyzer__
7518 
7519 /* Helper to add a location matching dict to the table */
7520 
7521 OSDictionary *
addLocation(OSDictionary * table)7522 IOService::addLocation( OSDictionary * table )
7523 {
7524 	OSDictionary *      dict;
7525 
7526 	if (!table) {
7527 		return NULL;
7528 	}
7529 
7530 	dict = OSDictionary::withCapacity( 1 );
7531 	if (dict) {
7532 		bool ok = table->setObject( gIOLocationMatchKey, dict );
7533 		dict->release();
7534 		if (!ok) {
7535 			dict = NULL;
7536 		}
7537 	}
7538 
7539 	return dict;
7540 }
7541 
7542 /*
7543  * Go looking for a provider to match a location dict.
7544  */
7545 
7546 IOService *
matchLocation(IOService *)7547 IOService::matchLocation( IOService * /* client */ )
7548 {
7549 	IOService * parent;
7550 
7551 	parent = getProvider();
7552 
7553 	if (parent) {
7554 		parent = parent->matchLocation( this );
7555 	}
7556 
7557 	return parent;
7558 }
7559 
7560 bool
matchInternal(OSDictionary * table,uint32_t options,uint32_t * did)7561 IOService::matchInternal(OSDictionary * table, uint32_t options, uint32_t * did)
7562 {
7563 	OSString *          matched;
7564 	OSObject *          obj;
7565 	OSString *          str;
7566 	OSDictionary *      matchProps;
7567 	IORegistryEntry *   entry;
7568 	OSNumber *          num;
7569 	bool                match = true;
7570 	bool                changesOK = (0 != (kIOServiceChangesOK & options));
7571 	uint32_t            count;
7572 	uint32_t            done;
7573 
7574 	do{
7575 		count = table->getCount();
7576 		done = 0;
7577 		matchProps = NULL;
7578 
7579 		if (table->getObject(gIOServiceNotificationUserKey)) {
7580 			done++;
7581 			match = (0 == (kIOServiceUserInvisibleMatchState & __state[0]));
7582 			if ((!match) || (done == count)) {
7583 				break;
7584 			}
7585 		}
7586 
7587 		if (propertyExists(gIOExclaveAssignedKey)) {
7588 			if (!table->getObject(gIOExclaveProxyKey)) {
7589 				match = false;
7590 				break;
7591 			}
7592 		} else if (table->getObject(gIOExclaveProxyKey)) {
7593 			match = false;
7594 			break;
7595 		}
7596 
7597 		if (table->getObject(gIOCompatibilityMatchKey)) {
7598 			done++;
7599 			obj = copyProperty(gIOCompatibilityPropertiesKey);
7600 			matchProps = OSDynamicCast(OSDictionary, obj);
7601 			if (!matchProps) {
7602 				OSSafeReleaseNULL(obj);
7603 			}
7604 		}
7605 
7606 		str = OSDynamicCast(OSString, table->getObject(gIOProviderClassKey));
7607 		if (str) {
7608 			done++;
7609 			if (matchProps && (obj = matchProps->getObject(gIOClassKey))) {
7610 				match = str->isEqualTo(obj);
7611 			} else {
7612 				match = ((kIOServiceClassDone & options) || (NULL != metaCast(str)));
7613 			}
7614 
7615 #if MATCH_DEBUG
7616 			match = (0 != metaCast( str ));
7617 			if ((kIOServiceClassDone & options) && !match) {
7618 				panic("classDone");
7619 			}
7620 #endif
7621 			if ((!match) || (done == count)) {
7622 				break;
7623 			}
7624 		}
7625 
7626 		obj = table->getObject( gIONameMatchKey );
7627 		if (obj) {
7628 			done++;
7629 			match = compareNames( obj, changesOK ? &matched : NULL );
7630 			if (!match) {
7631 				break;
7632 			}
7633 			if (changesOK && matched) {
7634 				// leave a hint as to which name matched
7635 				table->setObject( gIONameMatchedKey, matched );
7636 				matched->release();
7637 			}
7638 			if (done == count) {
7639 				break;
7640 			}
7641 		}
7642 
7643 		str = OSDynamicCast( OSString, table->getObject( gIOLocationMatchKey ));
7644 		if (str) {
7645 			const OSSymbol * sym;
7646 			done++;
7647 			match = false;
7648 			sym = copyLocation();
7649 			if (sym) {
7650 				match = sym->isEqualTo( str );
7651 				sym->release();
7652 			}
7653 			if ((!match) || (done == count)) {
7654 				break;
7655 			}
7656 		}
7657 
7658 		obj = table->getObject( gIOPropertyMatchKey );
7659 		if (obj) {
7660 			OSDictionary * nextDict;
7661 			OSIterator *   iter;
7662 			done++;
7663 			match = false;
7664 			if (!matchProps) {
7665 				matchProps = dictionaryWithProperties();
7666 			}
7667 			if (matchProps) {
7668 				nextDict = OSDynamicCast( OSDictionary, obj);
7669 				if (nextDict) {
7670 					iter = NULL;
7671 				} else {
7672 					iter = OSCollectionIterator::withCollection(
7673 						OSDynamicCast(OSCollection, obj));
7674 				}
7675 
7676 				while (nextDict
7677 				    || (iter && (NULL != (nextDict = OSDynamicCast(OSDictionary,
7678 				    iter->getNextObject()))))) {
7679 					match = matchProps->isEqualTo( nextDict, nextDict);
7680 					if (match) {
7681 						break;
7682 					}
7683 					nextDict = NULL;
7684 				}
7685 				if (iter) {
7686 					iter->release();
7687 				}
7688 			}
7689 			if ((!match) || (done == count)) {
7690 				break;
7691 			}
7692 		}
7693 
7694 		obj = table->getObject( gIOPropertyExistsMatchKey );
7695 		if (obj) {
7696 			OSString     * nextKey;
7697 			OSIterator *   iter;
7698 			done++;
7699 			match = false;
7700 			if (!matchProps) {
7701 				matchProps = dictionaryWithProperties();
7702 			}
7703 			if (matchProps) {
7704 				nextKey = OSDynamicCast( OSString, obj);
7705 				if (nextKey) {
7706 					iter = NULL;
7707 				} else {
7708 					iter = OSCollectionIterator::withCollection(
7709 						OSDynamicCast(OSCollection, obj));
7710 				}
7711 
7712 				while (nextKey
7713 				    || (iter && (NULL != (nextKey = OSDynamicCast(OSString,
7714 				    iter->getNextObject()))))) {
7715 					match = (NULL != matchProps->getObject(nextKey));
7716 					if (match) {
7717 						break;
7718 					}
7719 					nextKey = NULL;
7720 				}
7721 				if (iter) {
7722 					iter->release();
7723 				}
7724 			}
7725 			if ((!match) || (done == count)) {
7726 				break;
7727 			}
7728 		}
7729 
7730 		str = OSDynamicCast( OSString, table->getObject( gIOPathMatchKey ));
7731 		if (str) {
7732 			done++;
7733 			entry = IORegistryEntry::fromPath( str->getCStringNoCopy());
7734 			match = (this == entry);
7735 			if (entry) {
7736 				entry->release();
7737 			}
7738 			if (!match && matchProps && (obj = matchProps->getObject(gIOPathKey))) {
7739 				match = str->isEqualTo(obj);
7740 			}
7741 			if ((!match) || (done == count)) {
7742 				break;
7743 			}
7744 		}
7745 
7746 		num = OSDynamicCast( OSNumber, table->getObject( gIORegistryEntryIDKey ));
7747 		if (num) {
7748 			done++;
7749 			match = (getRegistryEntryID() == num->unsigned64BitValue());
7750 			if ((!match) || (done == count)) {
7751 				break;
7752 			}
7753 		}
7754 
7755 		num = OSDynamicCast( OSNumber, table->getObject( gIOMatchedServiceCountKey ));
7756 		if (num) {
7757 			OSIterator *        iter;
7758 			IOService *         service = NULL;
7759 			UInt32              serviceCount = 0;
7760 
7761 			done++;
7762 			iter = getClientIterator();
7763 			if (iter) {
7764 				while ((service = (IOService *) iter->getNextObject())) {
7765 					if (kIOServiceInactiveState & service->__state[0]) {
7766 						continue;
7767 					}
7768 					if (NULL == service->getProperty( gIOMatchCategoryKey )) {
7769 						continue;
7770 					}
7771 					++serviceCount;
7772 				}
7773 				iter->release();
7774 			}
7775 			match = (serviceCount == num->unsigned32BitValue());
7776 			if ((!match) || (done == count)) {
7777 				break;
7778 			}
7779 		}
7780 
7781 #define propMatch(key)                                  \
7782 	obj = table->getObject(key);                    \
7783 	if (obj)                                        \
7784 	{                                               \
7785 	    OSObject * prop;                            \
7786 	    done++;                                     \
7787 	    prop = copyProperty(key);                   \
7788 	    match = obj->isEqualTo(prop);               \
7789 	    if (prop) prop->release();                  \
7790 	    if ((!match) || (done == count)) break;     \
7791 	}
7792 		propMatch(gIOBSDNameKey)
7793 		propMatch(gIOBSDMajorKey)
7794 		propMatch(gIOBSDMinorKey)
7795 		propMatch(gIOBSDUnitKey)
7796 #undef propMatch
7797 	}while (false);
7798 
7799 	OSSafeReleaseNULL(matchProps);
7800 
7801 	if (did) {
7802 		*did = done;
7803 	}
7804 	return match;
7805 }
7806 
7807 bool
passiveMatch(OSDictionary * table,bool changesOK)7808 IOService::passiveMatch( OSDictionary * table, bool changesOK )
7809 {
7810 	return matchPassive(table, changesOK ? kIOServiceChangesOK : 0);
7811 }
7812 
7813 bool
matchPassive(OSDictionary * table,uint32_t options)7814 IOService::matchPassive(OSDictionary * table, uint32_t options)
7815 {
7816 	IOService *         where;
7817 	OSDictionary *      nextTable;
7818 	SInt32              score;
7819 	OSNumber *          newPri;
7820 	bool                match = true;
7821 	bool                matchParent = false;
7822 	uint32_t            count;
7823 	uint32_t            done;
7824 
7825 	assert( table );
7826 
7827 #if defined(XNU_TARGET_OS_OSX)
7828 	OSArray* aliasServiceRegIds = NULL;
7829 	IOService* foundAlternateService = NULL;
7830 #endif /* defined(XNU_TARGET_OS_OSX) */
7831 
7832 #if MATCH_DEBUG
7833 	OSDictionary * root = table;
7834 #endif
7835 
7836 	where = this;
7837 	do{
7838 		do{
7839 			count = table->getCount();
7840 			if (!(kIOServiceInternalDone & options)) {
7841 				match = where->matchInternal(table, options, &done);
7842 				// don't call family if we've done all the entries in the table
7843 				if ((!match) || (done == count)) {
7844 					break;
7845 				}
7846 			}
7847 
7848 			// pass in score from property table
7849 			score = IOServiceObjectOrder( table, (void *) gIOProbeScoreKey);
7850 
7851 			// do family specific matching
7852 			match = where->matchPropertyTable( table, &score );
7853 
7854 			if (!match) {
7855 #if IOMATCHDEBUG
7856 				if (kIOLogMatch & getDebugFlags( table )) {
7857 					LOG("%s: family specific matching fails\n", where->getName());
7858 				}
7859 #endif
7860 				break;
7861 			}
7862 
7863 			if (kIOServiceChangesOK & options) {
7864 				// save the score
7865 				newPri = OSNumber::withNumber( score, 32 );
7866 				if (newPri) {
7867 					table->setObject( gIOProbeScoreKey, newPri );
7868 					newPri->release();
7869 				}
7870 			}
7871 
7872 			options = 0;
7873 			matchParent = false;
7874 
7875 			nextTable = OSDynamicCast(OSDictionary,
7876 			    table->getObject( gIOParentMatchKey ));
7877 			if (nextTable) {
7878 				// look for a matching entry anywhere up to root
7879 				match = false;
7880 				matchParent = true;
7881 				table = nextTable;
7882 				break;
7883 			}
7884 
7885 			table = OSDynamicCast(OSDictionary,
7886 			    table->getObject( gIOLocationMatchKey ));
7887 			if (table) {
7888 				// look for a matching entry at matchLocation()
7889 				match = false;
7890 				where = where->getProvider();
7891 				if (where && (where = where->matchLocation(where))) {
7892 					continue;
7893 				}
7894 			}
7895 			break;
7896 		}while (true);
7897 
7898 		if (match == true) {
7899 			break;
7900 		}
7901 
7902 		if (matchParent == true) {
7903 #if defined(XNU_TARGET_OS_OSX)
7904 			// check if service has an alias to search its other "parents" if a parent match isn't found
7905 			OSObject * prop = where->copyProperty(gIOServiceLegacyMatchingRegistryIDKey);
7906 			OSNumber * alternateRegistryID = OSDynamicCast(OSNumber, prop);
7907 			if (alternateRegistryID != NULL) {
7908 				if (aliasServiceRegIds == NULL) {
7909 					aliasServiceRegIds = OSArray::withCapacity(sizeof(alternateRegistryID));
7910 				}
7911 				aliasServiceRegIds->setObject(alternateRegistryID);
7912 			}
7913 			OSSafeReleaseNULL(prop);
7914 #endif /* defined(XNU_TARGET_OS_OSX) */
7915 		} else {
7916 			break;
7917 		}
7918 
7919 		where = where->getProvider();
7920 #if defined(XNU_TARGET_OS_OSX)
7921 		if (where == NULL) {
7922 			// there were no matching parent services, check to see if there are aliased services that have a matching parent
7923 			if (aliasServiceRegIds != NULL) {
7924 				unsigned int numAliasedServices = aliasServiceRegIds->getCount();
7925 				if (numAliasedServices != 0) {
7926 					OSNumber* alternateRegistryID = OSDynamicCast(OSNumber, aliasServiceRegIds->getObject(numAliasedServices - 1));
7927 					if (alternateRegistryID != NULL) {
7928 						OSDictionary* alternateMatchingDict = IOService::registryEntryIDMatching(alternateRegistryID->unsigned64BitValue());
7929 						aliasServiceRegIds->removeObject(numAliasedServices - 1);
7930 						if (alternateMatchingDict != NULL) {
7931 							OSSafeReleaseNULL(foundAlternateService);
7932 							foundAlternateService = IOService::copyMatchingService(alternateMatchingDict);
7933 							alternateMatchingDict->release();
7934 							if (foundAlternateService != NULL) {
7935 								where = foundAlternateService;
7936 							}
7937 						}
7938 					}
7939 				}
7940 			}
7941 		}
7942 #endif /* defined(XNU_TARGET_OS_OSX) */
7943 	}while (where != NULL);
7944 
7945 #if defined(XNU_TARGET_OS_OSX)
7946 	OSSafeReleaseNULL(foundAlternateService);
7947 	OSSafeReleaseNULL(aliasServiceRegIds);
7948 #endif /* defined(XNU_TARGET_OS_OSX) */
7949 
7950 #if MATCH_DEBUG
7951 	if (where != this) {
7952 		OSSerialize * s = OSSerialize::withCapacity(128);
7953 		root->serialize(s);
7954 		kprintf("parent match 0x%llx, %d,\n%s\n", getRegistryEntryID(), match, s->text());
7955 		s->release();
7956 	}
7957 #endif
7958 
7959 	return match;
7960 }
7961 
7962 
7963 IOReturn
newUserClient(task_t owningTask,void * securityID,UInt32 type,OSDictionary * properties,IOUserClient ** handler)7964 IOService::newUserClient( task_t owningTask, void * securityID,
7965     UInt32 type, OSDictionary * properties,
7966     IOUserClient ** handler )
7967 {
7968 	const OSSymbol *userClientClass = NULL;
7969 	IOUserClient *client;
7970 	OSObject *prop;
7971 	OSObject *temp;
7972 
7973 	if (reserved && reserved->uvars && reserved->uvars->userServer) {
7974 		return reserved->uvars->userServer->serviceNewUserClient(this, owningTask, securityID, type, properties, handler);
7975 	}
7976 
7977 	if (kIOReturnSuccess == newUserClient( owningTask, securityID, type, handler )) {
7978 		return kIOReturnSuccess;
7979 	}
7980 
7981 	// First try my own properties for a user client class name
7982 	prop = copyProperty(gIOUserClientClassKey);
7983 	if (prop) {
7984 		if (OSDynamicCast(OSSymbol, prop)) {
7985 			userClientClass = (const OSSymbol *) prop;
7986 			prop = NULL;
7987 		} else if (OSDynamicCast(OSString, prop)) {
7988 			userClientClass = OSSymbol::withString((OSString *) prop);
7989 			OSSafeReleaseNULL(prop);
7990 			if (userClientClass) {
7991 				setProperty(gIOUserClientClassKey,
7992 				    (OSObject *) userClientClass);
7993 			}
7994 		} else {
7995 			OSSafeReleaseNULL(prop);
7996 		}
7997 	}
7998 
7999 	// Didn't find one so lets just bomb out now without further ado.
8000 	if (!userClientClass) {
8001 		return kIOReturnUnsupported;
8002 	}
8003 
8004 	// This reference is consumed by the IOServiceOpen call
8005 	temp = OSMetaClass::allocClassWithName(userClientClass);
8006 	OSSafeReleaseNULL(userClientClass);
8007 	if (!temp) {
8008 		return kIOReturnNoMemory;
8009 	}
8010 
8011 	if (OSDynamicCast(IOUserClient, temp)) {
8012 		client = (IOUserClient *) temp;
8013 	} else {
8014 		temp->release();
8015 		return kIOReturnUnsupported;
8016 	}
8017 
8018 	if (!client->initWithTask(owningTask, securityID, type, properties)) {
8019 		client->release();
8020 		return kIOReturnBadArgument;
8021 	}
8022 
8023 	if (!client->attach(this)) {
8024 		client->release();
8025 		return kIOReturnUnsupported;
8026 	}
8027 
8028 	if (!client->start(this)) {
8029 		client->detach(this);
8030 		client->release();
8031 		return kIOReturnUnsupported;
8032 	}
8033 
8034 	*handler = client;
8035 	return kIOReturnSuccess;
8036 }
8037 
8038 IOReturn
newUserClient(task_t owningTask,void * securityID,UInt32 type,OSDictionary * properties,OSSharedPtr<IOUserClient> & handler)8039 IOService::newUserClient( task_t owningTask, void * securityID,
8040     UInt32 type, OSDictionary * properties,
8041     OSSharedPtr<IOUserClient>& handler )
8042 {
8043 	IOUserClient* handlerRaw = NULL;
8044 	IOReturn result = newUserClient(owningTask, securityID, type, properties, &handlerRaw);
8045 	handler.reset(handlerRaw, OSNoRetain);
8046 	return result;
8047 }
8048 
8049 IOReturn
newUserClient(task_t owningTask,void * securityID,UInt32 type,IOUserClient ** handler)8050 IOService::newUserClient( task_t owningTask, void * securityID,
8051     UInt32 type, IOUserClient ** handler )
8052 {
8053 	return kIOReturnUnsupported;
8054 }
8055 
8056 IOReturn
newUserClient(task_t owningTask,void * securityID,UInt32 type,OSSharedPtr<IOUserClient> & handler)8057 IOService::newUserClient( task_t owningTask, void * securityID,
8058     UInt32 type, OSSharedPtr<IOUserClient>& handler )
8059 {
8060 	IOUserClient* handlerRaw = nullptr;
8061 	IOReturn result = IOService::newUserClient(owningTask, securityID, type, &handlerRaw);
8062 	handler.reset(handlerRaw, OSNoRetain);
8063 	return result;
8064 }
8065 
8066 
8067 IOReturn
requestProbe(IOOptionBits options)8068 IOService::requestProbe( IOOptionBits options )
8069 {
8070 	return kIOReturnUnsupported;
8071 }
8072 
8073 bool
hasUserServer() const8074 IOService::hasUserServer() const
8075 {
8076 	return reserved && reserved->uvars && reserved->uvars->userServer;
8077 }
8078 
8079 /*
8080  * Convert an IOReturn to text. Subclasses which add additional
8081  * IOReturn's should override this method and call
8082  * super::stringFromReturn if the desired value is not found.
8083  */
8084 
8085 const char *
stringFromReturn(IOReturn rtn)8086 IOService::stringFromReturn( IOReturn rtn )
8087 {
8088 	static const IONamedValue IOReturn_values[] = {
8089 		{kIOReturnSuccess, "success"                           },
8090 		{kIOReturnError, "general error"                     },
8091 		{kIOReturnNoMemory, "memory allocation error"           },
8092 		{kIOReturnNoResources, "resource shortage"                 },
8093 		{kIOReturnIPCError, "Mach IPC failure"                  },
8094 		{kIOReturnNoDevice, "no such device"                    },
8095 		{kIOReturnNotPrivileged, "privilege violation"               },
8096 		{kIOReturnBadArgument, "invalid argument"                  },
8097 		{kIOReturnLockedRead, "device is read locked"             },
8098 		{kIOReturnLockedWrite, "device is write locked"            },
8099 		{kIOReturnExclusiveAccess, "device is exclusive access"        },
8100 		{kIOReturnBadMessageID, "bad IPC message ID"                },
8101 		{kIOReturnUnsupported, "unsupported function"              },
8102 		{kIOReturnVMError, "virtual memory error"              },
8103 		{kIOReturnInternalError, "internal driver error"             },
8104 		{kIOReturnIOError, "I/O error"                         },
8105 		{kIOReturnCannotLock, "cannot acquire lock"               },
8106 		{kIOReturnNotOpen, "device is not open"                },
8107 		{kIOReturnNotReadable, "device is not readable"            },
8108 		{kIOReturnNotWritable, "device is not writeable"           },
8109 		{kIOReturnNotAligned, "alignment error"                   },
8110 		{kIOReturnBadMedia, "media error"                       },
8111 		{kIOReturnStillOpen, "device is still open"              },
8112 		{kIOReturnRLDError, "rld failure"                       },
8113 		{kIOReturnDMAError, "DMA failure"                       },
8114 		{kIOReturnBusy, "device is busy"                    },
8115 		{kIOReturnTimeout, "I/O timeout"                       },
8116 		{kIOReturnOffline, "device is offline"                 },
8117 		{kIOReturnNotReady, "device is not ready"               },
8118 		{kIOReturnNotAttached, "device/channel is not attached"    },
8119 		{kIOReturnNoChannels, "no DMA channels available"         },
8120 		{kIOReturnNoSpace, "no space for data"                 },
8121 		{kIOReturnPortExists, "device port already exists"        },
8122 		{kIOReturnCannotWire, "cannot wire physical memory"       },
8123 		{kIOReturnNoInterrupt, "no interrupt attached"             },
8124 		{kIOReturnNoFrames, "no DMA frames enqueued"            },
8125 		{kIOReturnMessageTooLarge, "message is too large"              },
8126 		{kIOReturnNotPermitted, "operation is not permitted"        },
8127 		{kIOReturnNoPower, "device is without power"           },
8128 		{kIOReturnNoMedia, "media is not present"              },
8129 		{kIOReturnUnformattedMedia, "media is not formatted"            },
8130 		{kIOReturnUnsupportedMode, "unsupported mode"                  },
8131 		{kIOReturnUnderrun, "data underrun"                     },
8132 		{kIOReturnOverrun, "data overrun"                      },
8133 		{kIOReturnDeviceError, "device error"                      },
8134 		{kIOReturnNoCompletion, "no completion routine"             },
8135 		{kIOReturnAborted, "operation was aborted"             },
8136 		{kIOReturnNoBandwidth, "bus bandwidth would be exceeded"   },
8137 		{kIOReturnNotResponding, "device is not responding"          },
8138 		{kIOReturnInvalid, "unanticipated driver error"        },
8139 		{0, NULL                                }
8140 	};
8141 
8142 	return IOFindNameForValue(rtn, IOReturn_values);
8143 }
8144 
8145 /*
8146  * Convert an IOReturn to an errno.
8147  */
8148 int
errnoFromReturn(IOReturn rtn)8149 IOService::errnoFromReturn( IOReturn rtn )
8150 {
8151 	if (unix_err(err_get_code(rtn)) == rtn) {
8152 		return err_get_code(rtn);
8153 	}
8154 
8155 	switch (rtn) {
8156 	// (obvious match)
8157 	case kIOReturnSuccess:
8158 		return 0;
8159 	case kIOReturnNoMemory:
8160 		return ENOMEM;
8161 	case kIOReturnNoDevice:
8162 		return ENXIO;
8163 	case kIOReturnVMError:
8164 		return EFAULT;
8165 	case kIOReturnNotPermitted:
8166 		return EPERM;
8167 	case kIOReturnNotPrivileged:
8168 		return EACCES;
8169 	case kIOReturnIOError:
8170 		return EIO;
8171 	case kIOReturnNotWritable:
8172 		return EROFS;
8173 	case kIOReturnBadArgument:
8174 		return EINVAL;
8175 	case kIOReturnUnsupported:
8176 		return ENOTSUP;
8177 	case kIOReturnBusy:
8178 		return EBUSY;
8179 	case kIOReturnNoPower:
8180 		return EPWROFF;
8181 	case kIOReturnDeviceError:
8182 		return EDEVERR;
8183 	case kIOReturnTimeout:
8184 		return ETIMEDOUT;
8185 	case kIOReturnMessageTooLarge:
8186 		return EMSGSIZE;
8187 	case kIOReturnNoSpace:
8188 		return ENOSPC;
8189 	case kIOReturnCannotLock:
8190 		return ENOLCK;
8191 
8192 	// (best match)
8193 	case kIOReturnBadMessageID:
8194 	case kIOReturnNoCompletion:
8195 	case kIOReturnNotAligned:
8196 		return EINVAL;
8197 	case kIOReturnNotReady:
8198 		return EBUSY;
8199 	case kIOReturnRLDError:
8200 		return EBADMACHO;
8201 	case kIOReturnPortExists:
8202 	case kIOReturnStillOpen:
8203 		return EEXIST;
8204 	case kIOReturnExclusiveAccess:
8205 	case kIOReturnLockedRead:
8206 	case kIOReturnLockedWrite:
8207 	case kIOReturnNotOpen:
8208 	case kIOReturnNotReadable:
8209 		return EACCES;
8210 	case kIOReturnCannotWire:
8211 	case kIOReturnNoResources:
8212 		return ENOMEM;
8213 	case kIOReturnAborted:
8214 	case kIOReturnOffline:
8215 	case kIOReturnNotResponding:
8216 		return EBUSY;
8217 	case kIOReturnBadMedia:
8218 	case kIOReturnNoMedia:
8219 	case kIOReturnNotAttached:
8220 	case kIOReturnUnformattedMedia:
8221 		return ENXIO; // (media error)
8222 	case kIOReturnDMAError:
8223 	case kIOReturnOverrun:
8224 	case kIOReturnUnderrun:
8225 		return EIO; // (transfer error)
8226 	case kIOReturnNoBandwidth:
8227 	case kIOReturnNoChannels:
8228 	case kIOReturnNoFrames:
8229 	case kIOReturnNoInterrupt:
8230 		return EIO; // (hardware error)
8231 	case kIOReturnError:
8232 	case kIOReturnInternalError:
8233 	case kIOReturnInvalid:
8234 		return EIO; // (generic error)
8235 	case kIOReturnIPCError:
8236 		return EIO; // (ipc error)
8237 	default:
8238 		return EIO; // (all other errors)
8239 	}
8240 }
8241 
8242 IOReturn
message(UInt32 type,IOService * provider,void * argument)8243 IOService::message( UInt32 type, IOService * provider,
8244     void * argument )
8245 {
8246 	/*
8247 	 * Generic entry point for calls from the provider.  A return value of
8248 	 * kIOReturnSuccess indicates that the message was received, and where
8249 	 * applicable, that it was successful.
8250 	 */
8251 
8252 	return kIOReturnUnsupported;
8253 }
8254 
8255 /*
8256  * Device memory
8257  */
8258 
8259 IOItemCount
getDeviceMemoryCount(void)8260 IOService::getDeviceMemoryCount( void )
8261 {
8262 	OSArray *           array;
8263 	IOItemCount         count;
8264 
8265 	array = OSDynamicCast( OSArray, getProperty( gIODeviceMemoryKey));
8266 	if (array) {
8267 		count = array->getCount();
8268 	} else {
8269 		count = 0;
8270 	}
8271 
8272 	return count;
8273 }
8274 
8275 IODeviceMemory *
getDeviceMemoryWithIndex(unsigned int index)8276 IOService::getDeviceMemoryWithIndex( unsigned int index )
8277 {
8278 	OSArray *           array;
8279 	IODeviceMemory *    range;
8280 
8281 	array = OSDynamicCast( OSArray, getProperty( gIODeviceMemoryKey));
8282 	if (array) {
8283 		range = (IODeviceMemory *) array->getObject( index );
8284 	} else {
8285 		range = NULL;
8286 	}
8287 
8288 	return range;
8289 }
8290 
8291 IOMemoryMap *
mapDeviceMemoryWithIndex(unsigned int index,IOOptionBits options)8292 IOService::mapDeviceMemoryWithIndex( unsigned int index,
8293     IOOptionBits options )
8294 {
8295 	IODeviceMemory *    range;
8296 	IOMemoryMap *       map;
8297 
8298 	range = getDeviceMemoryWithIndex( index );
8299 	if (range) {
8300 		map = range->map( options );
8301 	} else {
8302 		map = NULL;
8303 	}
8304 
8305 	return map;
8306 }
8307 
8308 OSArray *
getDeviceMemory(void)8309 IOService::getDeviceMemory( void )
8310 {
8311 	return OSDynamicCast( OSArray, getProperty( gIODeviceMemoryKey));
8312 }
8313 
8314 
8315 void
setDeviceMemory(OSArray * array)8316 IOService::setDeviceMemory( OSArray * array )
8317 {
8318 	setProperty( gIODeviceMemoryKey, array);
8319 }
8320 
8321 static void
requireMaxCpuDelay(IOService * service,UInt32 ns,UInt32 delayType)8322 requireMaxCpuDelay(IOService * service, UInt32 ns, UInt32 delayType)
8323 {
8324 	static const UInt kNoReplace = -1U; // Must be an illegal index
8325 	UInt replace = kNoReplace;
8326 	bool setCpuDelay = false;
8327 
8328 	IORecursiveLockLock(sCpuDelayLock);
8329 
8330 	UInt count = sCpuDelayData->getLength() / sizeof(CpuDelayEntry);
8331 	CpuDelayEntry *entries = (CpuDelayEntry *) sCpuDelayData->getBytesNoCopy();
8332 	IOService * holder = NULL;
8333 
8334 	if (ns) {
8335 		const CpuDelayEntry ne = {service, ns, delayType};
8336 		holder = service;
8337 		// Set maximum delay.
8338 		for (UInt i = 0; i < count; i++) {
8339 			IOService *thisService = entries[i].fService;
8340 			bool sameType = (delayType == entries[i].fDelayType);
8341 			if ((service == thisService) && sameType) {
8342 				replace = i;
8343 			} else if (!thisService) {
8344 				if (kNoReplace == replace) {
8345 					replace = i;
8346 				}
8347 			} else if (sameType) {
8348 				const UInt32 thisMax = entries[i].fMaxDelay;
8349 				if (thisMax < ns) {
8350 					ns = thisMax;
8351 					holder = thisService;
8352 				}
8353 			}
8354 		}
8355 
8356 		setCpuDelay = true;
8357 		if (kNoReplace == replace) {
8358 			sCpuDelayData->appendBytes(&ne, sizeof(ne));
8359 		} else {
8360 			entries[replace] = ne;
8361 		}
8362 	} else {
8363 		ns = -1U; // Set to max unsigned, i.e. no restriction
8364 
8365 		for (UInt i = 0; i < count; i++) {
8366 			// Clear a maximum delay.
8367 			IOService *thisService = entries[i].fService;
8368 			if (thisService && (delayType == entries[i].fDelayType)) {
8369 				UInt32 thisMax = entries[i].fMaxDelay;
8370 				if (service == thisService) {
8371 					replace = i;
8372 				} else if (thisMax < ns) {
8373 					ns = thisMax;
8374 					holder = thisService;
8375 				}
8376 			}
8377 		}
8378 
8379 		// Check if entry found
8380 		if (kNoReplace != replace) {
8381 			entries[replace].fService = NULL; // Null the entry
8382 			setCpuDelay = true;
8383 		}
8384 	}
8385 
8386 	if (setCpuDelay) {
8387 		if (holder && debug_boot_arg) {
8388 			strlcpy(sCPULatencyHolderName[delayType], holder->getName(), sizeof(sCPULatencyHolderName[delayType]));
8389 		}
8390 
8391 		// Must be safe to call from locked context
8392 		if (delayType == kCpuDelayBusStall) {
8393 #if defined(__x86_64__)
8394 			ml_set_maxbusdelay(ns);
8395 #endif /* defined(__x86_64__) */
8396 		}
8397 #if defined(__x86_64__)
8398 		else if (delayType == kCpuDelayInterrupt) {
8399 			ml_set_maxintdelay(ns);
8400 		}
8401 #endif /* defined(__x86_64__) */
8402 		sCPULatencyHolder[delayType]->setValue(holder ? holder->getRegistryEntryID() : 0);
8403 		sCPULatencySet[delayType]->setValue(ns);
8404 
8405 		OSArray * handlers = sCpuLatencyHandlers[delayType];
8406 		IOService * target;
8407 		if (handlers) {
8408 			for (unsigned int idx = 0;
8409 			    (target = (IOService *) handlers->getObject(idx));
8410 			    idx++) {
8411 				target->callPlatformFunction(sCPULatencyFunctionName[delayType], false,
8412 				    (void *) (uintptr_t) ns, holder,
8413 				    NULL, NULL);
8414 			}
8415 		}
8416 	}
8417 
8418 	IORecursiveLockUnlock(sCpuDelayLock);
8419 }
8420 
8421 static IOReturn
setLatencyHandler(UInt32 delayType,IOService * target,bool enable)8422 setLatencyHandler(UInt32 delayType, IOService * target, bool enable)
8423 {
8424 	IOReturn result = kIOReturnNotFound;
8425 	OSArray * array;
8426 	unsigned int idx;
8427 
8428 	IORecursiveLockLock(sCpuDelayLock);
8429 
8430 	do{
8431 		if (enable && !sCpuLatencyHandlers[delayType]) {
8432 			sCpuLatencyHandlers[delayType] = OSArray::withCapacity(4);
8433 		}
8434 		array = sCpuLatencyHandlers[delayType];
8435 		if (!array) {
8436 			break;
8437 		}
8438 		idx = array->getNextIndexOfObject(target, 0);
8439 		if (!enable) {
8440 			if (-1U != idx) {
8441 				array->removeObject(idx);
8442 				result = kIOReturnSuccess;
8443 			}
8444 		} else {
8445 			if (-1U != idx) {
8446 				result = kIOReturnExclusiveAccess;
8447 				break;
8448 			}
8449 			array->setObject(target);
8450 
8451 			UInt count = sCpuDelayData->getLength() / sizeof(CpuDelayEntry);
8452 			CpuDelayEntry *entries = (CpuDelayEntry *) sCpuDelayData->getBytesNoCopy();
8453 			UInt32 ns = -1U; // Set to max unsigned, i.e. no restriction
8454 			IOService * holder = NULL;
8455 
8456 			for (UInt i = 0; i < count; i++) {
8457 				if (entries[i].fService
8458 				    && (delayType == entries[i].fDelayType)
8459 				    && (entries[i].fMaxDelay < ns)) {
8460 					ns = entries[i].fMaxDelay;
8461 					holder = entries[i].fService;
8462 				}
8463 			}
8464 			target->callPlatformFunction(sCPULatencyFunctionName[delayType], false,
8465 			    (void *) (uintptr_t) ns, holder,
8466 			    NULL, NULL);
8467 			result = kIOReturnSuccess;
8468 		}
8469 	}while (false);
8470 
8471 	IORecursiveLockUnlock(sCpuDelayLock);
8472 
8473 	return result;
8474 }
8475 
8476 IOReturn
requireMaxBusStall(UInt32 ns)8477 IOService::requireMaxBusStall(UInt32 ns)
8478 {
8479 #if !defined(__x86_64__)
8480 	switch (ns) {
8481 	case kIOMaxBusStall40usec:
8482 	case kIOMaxBusStall30usec:
8483 	case kIOMaxBusStall25usec:
8484 	case kIOMaxBusStall20usec:
8485 	case kIOMaxBusStall10usec:
8486 	case kIOMaxBusStall5usec:
8487 	case kIOMaxBusStallNone:
8488 		break;
8489 	default:
8490 		return kIOReturnBadArgument;
8491 	}
8492 #endif /* !defined(__x86_64__) */
8493 	requireMaxCpuDelay(this, ns, kCpuDelayBusStall);
8494 	return kIOReturnSuccess;
8495 }
8496 
8497 IOReturn
requireMaxInterruptDelay(uint32_t ns)8498 IOService::requireMaxInterruptDelay(uint32_t ns)
8499 {
8500 #if defined(__x86_64__)
8501 	requireMaxCpuDelay(this, ns, kCpuDelayInterrupt);
8502 	return kIOReturnSuccess;
8503 #else /* defined(__x86_64__) */
8504 	return kIOReturnUnsupported;
8505 #endif /* defined(__x86_64__) */
8506 }
8507 
8508 /*
8509  * Device interrupts
8510  */
8511 
8512 IOReturn
resolveInterrupt(IOService * nub,int source)8513 IOService::resolveInterrupt(IOService *nub, int source)
8514 {
8515 	IOInterruptController *interruptController;
8516 	OSArray               *array;
8517 	OSData                *data;
8518 	OSSymbol              *interruptControllerName;
8519 	unsigned int           numSources;
8520 	IOInterruptSource     *interruptSources;
8521 	IOInterruptSourcePrivate *interruptSourcesPrivate;
8522 
8523 	// Get the parents list from the nub.
8524 	array = OSDynamicCast(OSArray, nub->getProperty(gIOInterruptControllersKey));
8525 	if (array == NULL) {
8526 		return kIOReturnNoResources;
8527 	}
8528 
8529 	// Allocate space for the IOInterruptSources if needed... then return early.
8530 	if (nub->_interruptSources == NULL) {
8531 		numSources = array->getCount();
8532 		interruptSources = IONewZero(IOInterruptSource, numSources);
8533 		interruptSourcesPrivate = IONewZero(IOInterruptSourcePrivate, numSources);
8534 
8535 		if (interruptSources == NULL || interruptSourcesPrivate == NULL) {
8536 			IODelete(interruptSources, IOInterruptSource, numSources);
8537 			IODelete(interruptSourcesPrivate, IOInterruptSourcePrivate, numSources);
8538 			return kIOReturnNoMemory;
8539 		}
8540 
8541 		nub->_numInterruptSources = numSources;
8542 		nub->_interruptSources = interruptSources;
8543 		nub->reserved->interruptSourcesPrivate = interruptSourcesPrivate;
8544 		return kIOReturnSuccess;
8545 	}
8546 
8547 	interruptControllerName = OSDynamicCast(OSSymbol, array->getObject(source));
8548 	if (interruptControllerName == NULL) {
8549 		return kIOReturnNoResources;
8550 	}
8551 
8552 	interruptController = getPlatform()->lookUpInterruptController(interruptControllerName);
8553 	if (interruptController == NULL) {
8554 		return kIOReturnNoResources;
8555 	}
8556 
8557 	// Get the interrupt numbers from the nub.
8558 	array = OSDynamicCast(OSArray, nub->getProperty(gIOInterruptSpecifiersKey));
8559 	if (array == NULL) {
8560 		return kIOReturnNoResources;
8561 	}
8562 	data = OSDynamicCast(OSData, array->getObject(source));
8563 	if (data == NULL) {
8564 		return kIOReturnNoResources;
8565 	}
8566 
8567 	// Set the interruptController and interruptSource in the nub's table.
8568 	interruptSources = nub->_interruptSources;
8569 	interruptSources[source].interruptController = interruptController;
8570 	interruptSources[source].vectorData = data;
8571 
8572 	return kIOReturnSuccess;
8573 }
8574 
8575 IOReturn
lookupInterrupt(int source,bool resolve,IOInterruptController ** interruptController)8576 IOService::lookupInterrupt(int source, bool resolve, IOInterruptController **interruptController)
8577 {
8578 	IOReturn ret;
8579 
8580 	/* Make sure the _interruptSources are set */
8581 	if (_interruptSources == NULL) {
8582 		ret = resolveInterrupt(this, source);
8583 		if (ret != kIOReturnSuccess) {
8584 			return ret;
8585 		}
8586 	}
8587 
8588 	/* Make sure the local source number is valid */
8589 	if ((source < 0) || (source >= _numInterruptSources)) {
8590 		return kIOReturnNoInterrupt;
8591 	}
8592 
8593 	/* Look up the contoller for the local source */
8594 	*interruptController = _interruptSources[source].interruptController;
8595 
8596 	if (*interruptController == NULL) {
8597 		if (!resolve) {
8598 			return kIOReturnNoInterrupt;
8599 		}
8600 
8601 		/* Try to resolve the interrupt */
8602 		ret = resolveInterrupt(this, source);
8603 		if (ret != kIOReturnSuccess) {
8604 			return ret;
8605 		}
8606 
8607 		*interruptController = _interruptSources[source].interruptController;
8608 	}
8609 
8610 	return kIOReturnSuccess;
8611 }
8612 
8613 IOReturn
registerInterrupt(int source,OSObject * target,IOInterruptAction handler,void * refCon)8614 IOService::registerInterrupt(int source, OSObject *target,
8615     IOInterruptAction handler,
8616     void *refCon)
8617 {
8618 	IOInterruptController *interruptController;
8619 	IOReturn              ret;
8620 
8621 	ret = lookupInterrupt(source, true, &interruptController);
8622 	if (ret != kIOReturnSuccess) {
8623 		return ret;
8624 	}
8625 
8626 	/* Register the source */
8627 	return interruptController->registerInterrupt(this, source, target,
8628 	           (IOInterruptHandler)handler,
8629 	           refCon);
8630 }
8631 
8632 static void
IOServiceInterruptActionToBlock(OSObject * target,void * refCon,IOService * nub,int source)8633 IOServiceInterruptActionToBlock( OSObject * target, void * refCon,
8634     IOService * nub, int source )
8635 {
8636 	((IOInterruptActionBlock)(refCon))(nub, source);
8637 }
8638 
8639 IOReturn
registerInterruptBlock(int source,OSObject * target,IOInterruptActionBlock handler)8640 IOService::registerInterruptBlock(int source, OSObject *target,
8641     IOInterruptActionBlock handler)
8642 {
8643 	IOReturn ret;
8644 	void   * block;
8645 
8646 	block = Block_copy(handler);
8647 	if (!block) {
8648 		return kIOReturnNoMemory;
8649 	}
8650 
8651 	ret = registerInterrupt(source, target, &IOServiceInterruptActionToBlock, block);
8652 	if (kIOReturnSuccess != ret) {
8653 		Block_release(block);
8654 		return ret;
8655 	}
8656 
8657 	reserved->interruptSourcesPrivate[source].vectorBlock = block;
8658 
8659 	return ret;
8660 }
8661 
8662 IOReturn
unregisterInterrupt(int source)8663 IOService::unregisterInterrupt(int source)
8664 {
8665 	IOReturn              ret;
8666 	IOInterruptController *interruptController;
8667 	IOInterruptSourcePrivate *priv;
8668 	void                  *block;
8669 
8670 	ret = lookupInterrupt(source, false, &interruptController);
8671 	if (ret != kIOReturnSuccess) {
8672 		return ret;
8673 	}
8674 
8675 	/* Unregister the source */
8676 	priv = &reserved->interruptSourcesPrivate[source];
8677 	block = priv->vectorBlock;
8678 	ret = interruptController->unregisterInterrupt(this, source);
8679 	if ((kIOReturnSuccess == ret) && (block = priv->vectorBlock)) {
8680 		priv->vectorBlock = NULL;
8681 		Block_release(block);
8682 	}
8683 
8684 	return ret;
8685 }
8686 
8687 IOReturn
addInterruptStatistics(IOInterruptAccountingData * statistics,int source)8688 IOService::addInterruptStatistics(IOInterruptAccountingData * statistics, int source)
8689 {
8690 	IOReportLegend * legend = NULL;
8691 	IOInterruptAccountingData * oldValue = NULL;
8692 	IOInterruptAccountingReporter * newArray = NULL;
8693 	char subgroupName[64];
8694 	int newArraySize = 0;
8695 	int i = 0;
8696 
8697 	if (source < 0) {
8698 		return kIOReturnBadArgument;
8699 	}
8700 
8701 	/*
8702 	 * We support statistics on a maximum of 256 interrupts per nub; if a nub
8703 	 * has more than 256 interrupt specifiers associated with it, and tries
8704 	 * to register a high interrupt index with interrupt accounting, panic.
8705 	 * Having more than 256 interrupts associated with a single nub is
8706 	 * probably a sign that something fishy is going on.
8707 	 */
8708 	if (source > IA_INDEX_MAX) {
8709 		panic("addInterruptStatistics called for an excessively large index (%d)", source);
8710 	}
8711 
8712 	/*
8713 	 * TODO: This is ugly (wrapping a lock around an allocation).  I'm only
8714 	 * leaving it as is because the likelihood of contention where we are
8715 	 * actually growing the array is minimal (we would realistically need
8716 	 * to be starting a driver for the first time, with an IOReporting
8717 	 * client already in place).  Nonetheless, cleanup that can be done
8718 	 * to adhere to best practices; it'll make the code more complicated,
8719 	 * unfortunately.
8720 	 */
8721 	IOLockLock(&reserved->interruptStatisticsLock);
8722 
8723 	/*
8724 	 * Lazily allocate the statistics array.
8725 	 */
8726 	if (!reserved->interruptStatisticsArray) {
8727 		reserved->interruptStatisticsArray = IONew(IOInterruptAccountingReporter, 1);
8728 		assert(reserved->interruptStatisticsArray);
8729 		reserved->interruptStatisticsArrayCount = 1;
8730 		bzero(reserved->interruptStatisticsArray, sizeof(*reserved->interruptStatisticsArray));
8731 	}
8732 
8733 	if (source >= reserved->interruptStatisticsArrayCount) {
8734 		/*
8735 		 * We're still within the range of supported indices, but we are out
8736 		 * of space in the current array.  Do a nasty realloc (because
8737 		 * IORealloc isn't a thing) here.  We'll double the size with each
8738 		 * reallocation.
8739 		 *
8740 		 * Yes, the "next power of 2" could be more efficient; but this will
8741 		 * be invoked incredibly rarely.  Who cares.
8742 		 */
8743 		newArraySize = (reserved->interruptStatisticsArrayCount << 1);
8744 
8745 		while (newArraySize <= source) {
8746 			newArraySize = (newArraySize << 1);
8747 		}
8748 		newArray = IONew(IOInterruptAccountingReporter, newArraySize);
8749 
8750 		assert(newArray);
8751 
8752 		/*
8753 		 * TODO: This even zeroes the memory it is about to overwrite.
8754 		 * Shameful; fix it.  Not particularly high impact, however.
8755 		 */
8756 		bzero(newArray, newArraySize * sizeof(*newArray));
8757 		memcpy(newArray, reserved->interruptStatisticsArray, reserved->interruptStatisticsArrayCount * sizeof(*newArray));
8758 		IODelete(reserved->interruptStatisticsArray, IOInterruptAccountingReporter, reserved->interruptStatisticsArrayCount);
8759 		reserved->interruptStatisticsArray = newArray;
8760 		reserved->interruptStatisticsArrayCount = newArraySize;
8761 	}
8762 
8763 	if (!reserved->interruptStatisticsArray[source].reporter) {
8764 		/*
8765 		 * We don't have a reporter associated with this index yet, so we
8766 		 * need to create one.
8767 		 */
8768 		/*
8769 		 * TODO: Some statistics do in fact have common units (time); should this be
8770 		 * split into separate reporters to communicate this?
8771 		 */
8772 		reserved->interruptStatisticsArray[source].reporter = IOSimpleReporter::with(this, kIOReportCategoryPower, kIOReportUnitNone);
8773 
8774 		/*
8775 		 * Each statistic is given an identifier based on the interrupt index (which
8776 		 * should be unique relative to any single nub) and the statistic involved.
8777 		 * We should now have a sane (small and positive) index, so start
8778 		 * constructing the channels for statistics.
8779 		 */
8780 		for (i = 0; i < IA_NUM_INTERRUPT_ACCOUNTING_STATISTICS; i++) {
8781 			/*
8782 			 * TODO: Currently, this does not add channels for disabled statistics.
8783 			 * Will this be confusing for clients?  If so, we should just add the
8784 			 * channels; we can avoid updating the channels even if they exist.
8785 			 */
8786 			if (IA_GET_STATISTIC_ENABLED(i)) {
8787 				reserved->interruptStatisticsArray[source].reporter->addChannel(IA_GET_CHANNEL_ID(source, i), kInterruptAccountingStatisticNameArray[i]);
8788 			}
8789 		}
8790 
8791 		/*
8792 		 * We now need to add the legend for this reporter to the registry.
8793 		 */
8794 		OSObject * prop = copyProperty(kIOReportLegendKey);
8795 		legend = IOReportLegend::with(OSDynamicCast(OSArray, prop));
8796 		OSSafeReleaseNULL(prop);
8797 
8798 		/*
8799 		 * Note that while we compose the subgroup name, we do not need to
8800 		 * manage its lifecycle (the reporter will handle this).
8801 		 */
8802 		snprintf(subgroupName, sizeof(subgroupName), "%s %d", getName(), source);
8803 		subgroupName[sizeof(subgroupName) - 1] = 0;
8804 		legend->addReporterLegend(reserved->interruptStatisticsArray[source].reporter, kInterruptAccountingGroupName, subgroupName);
8805 		setProperty(kIOReportLegendKey, legend->getLegend());
8806 		legend->release();
8807 
8808 		/*
8809 		 * TODO: Is this a good idea?  Probably not; my assumption is it opts
8810 		 * all entities who register interrupts into public disclosure of all
8811 		 * IOReporting channels.  Unfortunately, this appears to be as fine
8812 		 * grain as it gets.
8813 		 */
8814 		setProperty(kIOReportLegendPublicKey, true);
8815 	}
8816 
8817 	/*
8818 	 * Don't stomp existing entries.  If we are about to, panic; this
8819 	 * probably means we failed to tear down our old interrupt source
8820 	 * correctly.
8821 	 */
8822 	oldValue = reserved->interruptStatisticsArray[source].statistics;
8823 
8824 	if (oldValue) {
8825 		panic("addInterruptStatistics call for index %d would have clobbered existing statistics", source);
8826 	}
8827 
8828 	reserved->interruptStatisticsArray[source].statistics = statistics;
8829 
8830 	/*
8831 	 * Inherit the reporter values for each statistic.  The target may
8832 	 * be torn down as part of the runtime of the service (especially
8833 	 * for sleep/wake), so we inherit in order to avoid having values
8834 	 * reset for no apparent reason.  Our statistics are ultimately
8835 	 * tied to the index and the sevice, not to an individual target,
8836 	 * so we should maintain them accordingly.
8837 	 */
8838 	interruptAccountingDataInheritChannels(reserved->interruptStatisticsArray[source].statistics, reserved->interruptStatisticsArray[source].reporter);
8839 
8840 	IOLockUnlock(&reserved->interruptStatisticsLock);
8841 
8842 	return kIOReturnSuccess;
8843 }
8844 
8845 IOReturn
removeInterruptStatistics(int source)8846 IOService::removeInterruptStatistics(int source)
8847 {
8848 	IOInterruptAccountingData * value = NULL;
8849 
8850 	if (source < 0) {
8851 		return kIOReturnBadArgument;
8852 	}
8853 
8854 	IOLockLock(&reserved->interruptStatisticsLock);
8855 
8856 	/*
8857 	 * We dynamically grow the statistics array, so an excessively
8858 	 * large index value has NEVER been registered.  This either
8859 	 * means our cap on the array size is too small (unlikely), or
8860 	 * that we have been passed a corrupt index (this must be passed
8861 	 * the plain index into the interrupt specifier list).
8862 	 */
8863 	if (source >= reserved->interruptStatisticsArrayCount) {
8864 		panic("removeInterruptStatistics called for index %d, which was never registered", source);
8865 	}
8866 
8867 	assert(reserved->interruptStatisticsArray);
8868 
8869 	/*
8870 	 * If there is no existing entry, we are most likely trying to
8871 	 * free an interrupt owner twice, or we have corrupted the
8872 	 * index value.
8873 	 */
8874 	value = reserved->interruptStatisticsArray[source].statistics;
8875 
8876 	if (!value) {
8877 		panic("removeInterruptStatistics called for empty index %d", source);
8878 	}
8879 
8880 	/*
8881 	 * We update the statistics, so that any delta with the reporter
8882 	 * state is not lost.
8883 	 */
8884 	interruptAccountingDataUpdateChannels(reserved->interruptStatisticsArray[source].statistics, reserved->interruptStatisticsArray[source].reporter);
8885 	reserved->interruptStatisticsArray[source].statistics = NULL;
8886 	IOLockUnlock(&reserved->interruptStatisticsLock);
8887 
8888 	return kIOReturnSuccess;
8889 }
8890 
8891 IOReturn
getInterruptType(int source,int * interruptType)8892 IOService::getInterruptType(int source, int *interruptType)
8893 {
8894 	IOInterruptController *interruptController;
8895 	IOReturn              ret;
8896 
8897 	ret = lookupInterrupt(source, true, &interruptController);
8898 	if (ret != kIOReturnSuccess) {
8899 		return ret;
8900 	}
8901 
8902 	/* Return the type */
8903 	return interruptController->getInterruptType(this, source, interruptType);
8904 }
8905 
8906 IOReturn
enableInterrupt(int source)8907 IOService::enableInterrupt(int source)
8908 {
8909 	IOInterruptController *interruptController;
8910 	IOReturn              ret;
8911 
8912 	ret = lookupInterrupt(source, false, &interruptController);
8913 	if (ret != kIOReturnSuccess) {
8914 		return ret;
8915 	}
8916 
8917 	/* Enable the source */
8918 	return interruptController->enableInterrupt(this, source);
8919 }
8920 
8921 IOReturn
disableInterrupt(int source)8922 IOService::disableInterrupt(int source)
8923 {
8924 	IOInterruptController *interruptController;
8925 	IOReturn              ret;
8926 
8927 	ret = lookupInterrupt(source, false, &interruptController);
8928 	if (ret != kIOReturnSuccess) {
8929 		return ret;
8930 	}
8931 
8932 	/* Disable the source */
8933 	return interruptController->disableInterrupt(this, source);
8934 }
8935 
8936 IOReturn
causeInterrupt(int source)8937 IOService::causeInterrupt(int source)
8938 {
8939 	IOInterruptController *interruptController;
8940 	IOReturn              ret;
8941 
8942 	ret = lookupInterrupt(source, false, &interruptController);
8943 	if (ret != kIOReturnSuccess) {
8944 		return ret;
8945 	}
8946 
8947 	/* Cause an interrupt for the source */
8948 	return interruptController->causeInterrupt(this, source);
8949 }
8950 
8951 IOReturn
configureReport(IOReportChannelList * channelList,IOReportConfigureAction action,void * result,void * destination)8952 IOService::configureReport(IOReportChannelList    *channelList,
8953     IOReportConfigureAction action,
8954     void                   *result,
8955     void                   *destination)
8956 {
8957 	unsigned cnt;
8958 
8959 	for (cnt = 0; cnt < channelList->nchannels; cnt++) {
8960 		if (channelList->channels[cnt].channel_id == kPMPowerStatesChID) {
8961 			if (pwrMgt) {
8962 				configurePowerStatesReport(action, result);
8963 			} else {
8964 				return kIOReturnUnsupported;
8965 			}
8966 		} else if (channelList->channels[cnt].channel_id == kPMCurrStateChID) {
8967 			if (pwrMgt) {
8968 				configureSimplePowerReport(action, result);
8969 			} else {
8970 				return kIOReturnUnsupported;
8971 			}
8972 		}
8973 	}
8974 
8975 	IOLockLock(&reserved->interruptStatisticsLock);
8976 
8977 	/* The array count is signed (because the interrupt indices are signed), hence the cast */
8978 	for (cnt = 0; cnt < (unsigned) reserved->interruptStatisticsArrayCount; cnt++) {
8979 		if (reserved->interruptStatisticsArray[cnt].reporter) {
8980 			/*
8981 			 * If the reporter is currently associated with the statistics
8982 			 * for an event source, we may need to update the reporter.
8983 			 */
8984 			if (reserved->interruptStatisticsArray[cnt].statistics) {
8985 				interruptAccountingDataUpdateChannels(reserved->interruptStatisticsArray[cnt].statistics, reserved->interruptStatisticsArray[cnt].reporter);
8986 			}
8987 
8988 			reserved->interruptStatisticsArray[cnt].reporter->configureReport(channelList, action, result, destination);
8989 		}
8990 	}
8991 
8992 	IOLockUnlock(&reserved->interruptStatisticsLock);
8993 
8994 	if (hasUserServer()) {
8995 		return _ConfigureReport(channelList, action, result, destination);
8996 	} else {
8997 		return kIOReturnSuccess;
8998 	}
8999 }
9000 
9001 IOReturn
updateReport(IOReportChannelList * channelList,IOReportUpdateAction action,void * result,void * destination)9002 IOService::updateReport(IOReportChannelList      *channelList,
9003     IOReportUpdateAction      action,
9004     void                     *result,
9005     void                     *destination)
9006 {
9007 	unsigned cnt;
9008 
9009 	for (cnt = 0; cnt < channelList->nchannels; cnt++) {
9010 		if (channelList->channels[cnt].channel_id == kPMPowerStatesChID) {
9011 			if (pwrMgt) {
9012 				updatePowerStatesReport(action, result, destination);
9013 			} else {
9014 				return kIOReturnUnsupported;
9015 			}
9016 		} else if (channelList->channels[cnt].channel_id == kPMCurrStateChID) {
9017 			if (pwrMgt) {
9018 				updateSimplePowerReport(action, result, destination);
9019 			} else {
9020 				return kIOReturnUnsupported;
9021 			}
9022 		}
9023 	}
9024 
9025 	IOLockLock(&reserved->interruptStatisticsLock);
9026 
9027 	/* The array count is signed (because the interrupt indices are signed), hence the cast */
9028 	for (cnt = 0; cnt < (unsigned) reserved->interruptStatisticsArrayCount; cnt++) {
9029 		if (reserved->interruptStatisticsArray[cnt].reporter) {
9030 			/*
9031 			 * If the reporter is currently associated with the statistics
9032 			 * for an event source, we need to update the reporter.
9033 			 */
9034 			if (reserved->interruptStatisticsArray[cnt].statistics) {
9035 				interruptAccountingDataUpdateChannels(reserved->interruptStatisticsArray[cnt].statistics, reserved->interruptStatisticsArray[cnt].reporter);
9036 			}
9037 
9038 			reserved->interruptStatisticsArray[cnt].reporter->updateReport(channelList, action, result, destination);
9039 		}
9040 	}
9041 
9042 	IOLockUnlock(&reserved->interruptStatisticsLock);
9043 
9044 
9045 	if (hasUserServer()) {
9046 		return _UpdateReport(channelList, action, result, destination);
9047 	} else {
9048 		return kIOReturnSuccess;
9049 	}
9050 }
9051 
9052 uint64_t
getAuthorizationID(void)9053 IOService::getAuthorizationID( void )
9054 {
9055 	return reserved->authorizationID;
9056 }
9057 
9058 IOReturn
setAuthorizationID(uint64_t authorizationID)9059 IOService::setAuthorizationID( uint64_t authorizationID )
9060 {
9061 	OSObject * entitlement;
9062 	IOReturn status;
9063 
9064 	entitlement = IOUserClient::copyClientEntitlement( current_task(), "com.apple.private.iokit.IOServiceSetAuthorizationID" );
9065 
9066 	if (entitlement) {
9067 		if (entitlement == kOSBooleanTrue) {
9068 			reserved->authorizationID = authorizationID;
9069 
9070 			status = kIOReturnSuccess;
9071 		} else {
9072 			status = kIOReturnNotPrivileged;
9073 		}
9074 
9075 		entitlement->release();
9076 	} else {
9077 		status = kIOReturnNotPrivileged;
9078 	}
9079 
9080 	return status;
9081 }
9082 
9083 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9084 
9085 #if __LP64__
9086 OSMetaClassDefineReservedUsedX86(IOService, 0);
9087 OSMetaClassDefineReservedUsedX86(IOService, 1);
9088 OSMetaClassDefineReservedUnused(IOService, 2);
9089 OSMetaClassDefineReservedUnused(IOService, 3);
9090 OSMetaClassDefineReservedUnused(IOService, 4);
9091 OSMetaClassDefineReservedUnused(IOService, 5);
9092 OSMetaClassDefineReservedUnused(IOService, 6);
9093 OSMetaClassDefineReservedUnused(IOService, 7);
9094 #else
9095 OSMetaClassDefineReservedUsedX86(IOService, 0);
9096 OSMetaClassDefineReservedUsedX86(IOService, 1);
9097 OSMetaClassDefineReservedUsedX86(IOService, 2);
9098 OSMetaClassDefineReservedUsedX86(IOService, 3);
9099 OSMetaClassDefineReservedUsedX86(IOService, 4);
9100 OSMetaClassDefineReservedUsedX86(IOService, 5);
9101 OSMetaClassDefineReservedUsedX86(IOService, 6);
9102 OSMetaClassDefineReservedUsedX86(IOService, 7);
9103 #endif
9104 OSMetaClassDefineReservedUnused(IOService, 8);
9105 OSMetaClassDefineReservedUnused(IOService, 9);
9106 OSMetaClassDefineReservedUnused(IOService, 10);
9107 OSMetaClassDefineReservedUnused(IOService, 11);
9108 OSMetaClassDefineReservedUnused(IOService, 12);
9109 OSMetaClassDefineReservedUnused(IOService, 13);
9110 OSMetaClassDefineReservedUnused(IOService, 14);
9111 OSMetaClassDefineReservedUnused(IOService, 15);
9112 OSMetaClassDefineReservedUnused(IOService, 16);
9113 OSMetaClassDefineReservedUnused(IOService, 17);
9114 OSMetaClassDefineReservedUnused(IOService, 18);
9115 OSMetaClassDefineReservedUnused(IOService, 19);
9116 OSMetaClassDefineReservedUnused(IOService, 20);
9117 OSMetaClassDefineReservedUnused(IOService, 21);
9118 OSMetaClassDefineReservedUnused(IOService, 22);
9119 OSMetaClassDefineReservedUnused(IOService, 23);
9120 OSMetaClassDefineReservedUnused(IOService, 24);
9121 OSMetaClassDefineReservedUnused(IOService, 25);
9122 OSMetaClassDefineReservedUnused(IOService, 26);
9123 OSMetaClassDefineReservedUnused(IOService, 27);
9124 OSMetaClassDefineReservedUnused(IOService, 28);
9125 OSMetaClassDefineReservedUnused(IOService, 29);
9126 OSMetaClassDefineReservedUnused(IOService, 30);
9127 OSMetaClassDefineReservedUnused(IOService, 31);
9128 OSMetaClassDefineReservedUnused(IOService, 32);
9129 OSMetaClassDefineReservedUnused(IOService, 33);
9130 OSMetaClassDefineReservedUnused(IOService, 34);
9131 OSMetaClassDefineReservedUnused(IOService, 35);
9132 OSMetaClassDefineReservedUnused(IOService, 36);
9133 OSMetaClassDefineReservedUnused(IOService, 37);
9134 OSMetaClassDefineReservedUnused(IOService, 38);
9135 OSMetaClassDefineReservedUnused(IOService, 39);
9136 OSMetaClassDefineReservedUnused(IOService, 40);
9137 OSMetaClassDefineReservedUnused(IOService, 41);
9138 OSMetaClassDefineReservedUnused(IOService, 42);
9139 OSMetaClassDefineReservedUnused(IOService, 43);
9140 OSMetaClassDefineReservedUnused(IOService, 44);
9141 OSMetaClassDefineReservedUnused(IOService, 45);
9142 OSMetaClassDefineReservedUnused(IOService, 46);
9143 OSMetaClassDefineReservedUnused(IOService, 47);
9144