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