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