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