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