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