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