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