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 lock();
4766 DKLOG("arming ack timer, %u ms\n", dk_power_state_timeout_ms);
4767 clock_interval_to_deadline(dk_power_state_timeout_ms, kMillisecondScale, &deadline);
4768 fSystemState = newState;
4769 fSystemPowerAckRef = ackRef;
4770 fSystemPowerAckTo = ackTo;
4771 thread_call_enter_delayed(fUserServerAckTimer, deadline);
4772 unlock();
4773 matchingEnd(NULL);
4774
4775 *pMaxWaitForReply = dk_power_state_timeout_ms * 2 * 1000;
4776 break;
4777
4778 case kIOServiceSystemStateAOT:
4779 case kIOServiceSystemStateOn:
4780
4781 lock();
4782 fSystemState = newState;
4783 unlock();
4784 matchingEnd(NULL);
4785 *pMaxWaitForReply = 0;
4786 break;
4787
4788 default:
4789 assert(false);
4790 break;
4791 }
4792 }
4793
4794 IOReturn
systemPowerChange(void * target,void * refCon,UInt32 messageType,IOService * service,void * messageArgument,vm_size_t argSize)4795 IOServicePH::systemPowerChange(
4796 void * target,
4797 void * refCon,
4798 UInt32 messageType, IOService * service,
4799 void * messageArgument, vm_size_t argSize)
4800 {
4801 IOReturn ret;
4802 IOPMSystemCapabilityChangeParameters * params;
4803
4804 switch (messageType) {
4805 case kIOMessageSystemCapabilityChange:
4806 params = (typeof params)messageArgument;
4807
4808 IOLog("IOServicePH::kIOMessageSystemCapabilityChange: %s%s 0x%x->0x%x\n",
4809 params->changeFlags & kIOPMSystemCapabilityWillChange ? "will" : "",
4810 params->changeFlags & kIOPMSystemCapabilityDidChange ? "did" : "",
4811 params->fromCapabilities,
4812 params->toCapabilities);
4813
4814 if ((params->changeFlags & kIOPMSystemCapabilityWillChange) &&
4815 (params->fromCapabilities & (kIOPMSystemCapabilityCPU | kIOPMSystemCapabilityAOT)) &&
4816 ((params->toCapabilities & (kIOPMSystemCapabilityCPU | kIOPMSystemCapabilityAOT)) == 0)) {
4817 systemPowerChange(kIOServiceSystemStateOffPhase1, service, params->notifyRef, ¶ms->maxWaitForReply);
4818 ret = kIOReturnSuccess;
4819 } else if ((params->changeFlags & kIOPMSystemCapabilityWillChange) &&
4820 (0 != ((params->fromCapabilities ^ params->toCapabilities)
4821 & (kIOPMSystemCapabilityCPU | kIOPMSystemCapabilityAOT)))) {
4822 systemPowerChange((params->toCapabilities & kIOPMSystemCapabilityCPU) ? kIOServiceSystemStateOn : kIOServiceSystemStateAOT,
4823 service, params->notifyRef, ¶ms->maxWaitForReply);
4824 ret = kIOReturnSuccess;
4825 } else {
4826 params->maxWaitForReply = 0;
4827 ret = kIOReturnSuccess;
4828 }
4829 break;
4830
4831 default:
4832 ret = kIOReturnUnsupported;
4833 break;
4834 }
4835
4836 return ret;
4837 }
4838
4839 IOReturn
rootWillChangeTo(IOPMPowerFlags flags,unsigned long state)4840 IOServicePH::rootWillChangeTo(IOPMPowerFlags flags, unsigned long state)
4841 {
4842 IOReturn ret;
4843 uint32_t maxWaitForReply = kIOPMAckImplied;
4844
4845 if (kIOPMSleepCapability & flags) {
4846 systemPowerChange(kIOServiceSystemStateOffPhase2, gIOUserResources, 0, &maxWaitForReply);
4847 } else if (kIOPMAOTCapability & flags) {
4848 systemPowerChange(kIOServiceSystemStateAOT, NULL, 0, &maxWaitForReply);
4849 } else if (kIOPMPowerOn & flags) {
4850 systemPowerChange(kIOServiceSystemStateOn, NULL, 0, &maxWaitForReply);
4851 }
4852 ret = maxWaitForReply;
4853 return ret;
4854 }
4855
4856 bool
IOSystemStateAOT(void)4857 IOSystemStateAOT(void)
4858 {
4859 return kIOServiceSystemStateAOT == IOServicePH::fSystemState;
4860 }
4861
4862 bool
checkPMReady(void)4863 IOServicePH::checkPMReady(void)
4864 {
4865 bool __block ready = true;
4866
4867 lock();
4868 fUserServers->iterateObjects(^bool (OSObject *obj) {
4869 IOUserServer * us = OSDynamicCast(IOUserServer, obj);
4870 if (us) {
4871 if (!us->checkPMReady()) {
4872 ready = false;
4873 return true;
4874 }
4875 }
4876 return false;
4877 });
4878 unlock();
4879
4880 return ready;
4881 }
4882
4883 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
4884
4885 #if DEBUG || DEVELOPMENT
4886 void
__patchProperties(void)4887 IOService::__patchProperties(void)
4888 {
4889 #if 0
4890 if (!strcmp("AppleCentauriManager", getName())) {
4891 setProperty(kIOPMAOTAllowKey, kIOPMDriverClassNetwork, 64);
4892 }
4893 if (!strcmp("CentauriControl", getName())) {
4894 setProperty(kIOPMAOTAllowKey, kIOPMDriverClassNetwork, 64);
4895 }
4896 if (!strcmp("CentauriAlpha", getName())) {
4897 setProperty(kIOPMAOTAllowKey, kIOPMDriverClassNetwork, 64);
4898 }
4899 if (!strcmp("CentauriBeta", getName())) {
4900 setProperty(kIOPMAOTAllowKey, kIOPMDriverClassNetwork, 64);
4901 }
4902 #endif
4903 }
4904 #endif /* DEBUG || DEVELOPMENT */
4905
4906 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
4907
4908 /*
4909 * Start a previously attached & probed instance,
4910 * called on exporting object instance
4911 */
4912
4913 bool
startCandidate(IOService * service)4914 IOService::startCandidate( IOService * service )
4915 {
4916 bool ok;
4917 OSObject * obj;
4918 OSObject * prop;
4919 IOUserServer * userServer;
4920 bool ph;
4921
4922 userServer = NULL;
4923 obj = service->copyProperty(gIOUserServerNameKey);
4924
4925 if (obj && (this == gIOResources)) {
4926 ok = false;
4927 } else {
4928 ok = service->attach( this );
4929 }
4930 if (!ok) {
4931 OSSafeReleaseNULL(obj);
4932 return false;
4933 }
4934
4935 if ((this != gIOResources) && (this != gIOUserResources)) {
4936 // stall for any nub resources
4937 checkResources();
4938 // stall for any driver resources
4939 service->checkResources();
4940 }
4941 ph = false;
4942 {
4943 OSString * bundleID;
4944 OSString * serverName;
4945 OSString * str;
4946 const OSSymbol * sym;
4947 OSNumber * serverTag;
4948 uint64_t entryID;
4949 IOUserServerCheckInToken * token;
4950 OSData * serverDUI;
4951
4952 if ((serverName = OSDynamicCast(OSString, obj))) {
4953 obj = service->copyProperty(gIOModuleIdentifierKey);
4954 bundleID = OSDynamicCast(OSString, obj);
4955 entryID = service->getRegistryEntryID();
4956 serverTag = OSNumber::withNumber(entryID, 64);
4957 token = NULL;
4958
4959 if (kIODKDisableDextLaunch & gIODKDebug) {
4960 DKLOG(DKS " dext launches are disabled \n", DKN(service));
4961 service->detach(this);
4962 OSSafeReleaseNULL(serverName);
4963 OSSafeReleaseNULL(obj);
4964 OSSafeReleaseNULL(serverTag);
4965 return false;
4966 }
4967
4968 if (gIOKitWillTerminate) {
4969 DKLOG("%s disabled in shutdown\n", serverName->getCStringNoCopy());
4970 service->detach(this);
4971 OSSafeReleaseNULL(serverName);
4972 OSSafeReleaseNULL(obj);
4973 OSSafeReleaseNULL(serverTag);
4974 return false;
4975 }
4976
4977 ph = IOServicePH::matchingStart(this);
4978 if (!ph) {
4979 DKLOG("%s deferred in sleep\n", serverName->getCStringNoCopy());
4980 service->setProperty(gIOServiceMatchDeferredKey, kOSBooleanTrue);
4981 service->detach(this);
4982 OSSafeReleaseNULL(serverName);
4983 OSSafeReleaseNULL(obj);
4984 OSSafeReleaseNULL(serverTag);
4985 return false;
4986 }
4987
4988 prop = service->copyProperty(gIOUserClassKey);
4989 str = OSDynamicCast(OSString, prop);
4990 if (str) {
4991 service->setName(str);
4992 }
4993 OSSafeReleaseNULL(prop);
4994
4995 sym = OSSymbol::withString(serverName);
4996 bool reuse = service->propertyExists(gIOUserServerOneProcessKey);
4997 bool reuseRequired = false;
4998 if (propertyExists(gIOUserServerNameKey)) {
4999 reuseRequired = reuse && service->propertyHasValue(gIOUserServerNameKey, getProperty(gIOUserServerNameKey));
5000 }
5001 serverDUI = OSDynamicCast(OSData, service->getProperty(kOSBundleDextUniqueIdentifierKey));
5002 userServer = IOUserServer::launchUserServer(this, bundleID, sym, serverTag, reuse, &token, serverDUI);
5003 OSSafeReleaseNULL(sym);
5004 OSSafeReleaseNULL(serverTag);
5005 OSSafeReleaseNULL(serverName);
5006 if (userServer) {
5007 DKLOG(DKS " using existing server " DKS "\n", DKN(service), DKN(userServer));
5008 } else if (!reuseRequired && token != NULL) {
5009 const OSSymbol * tokenServerName = token->copyServerName();
5010 OSNumber * tokenServerTag = token->copyServerTag();
5011 assert(tokenServerName && tokenServerTag);
5012 DKLOG(DKS " waiting for server %s-%llx\n", DKN(service), tokenServerName->getCStringNoCopy(), tokenServerTag->unsigned64BitValue());
5013 userServer = __WAITING_FOR_USER_SERVER__(token);
5014 OSSafeReleaseNULL(tokenServerName);
5015 OSSafeReleaseNULL(tokenServerTag);
5016 } else if (reuseRequired) {
5017 DKLOG(DKS " failed to reuse server\n", DKN(service));
5018 } else {
5019 DKLOG(DKS " failed to launch server\n", DKN(service));
5020 }
5021
5022
5023 if (!userServer) {
5024 service->detach(this);
5025 IOServicePH::matchingEnd(this);
5026 OSSafeReleaseNULL(obj);
5027
5028 if (token != NULL) {
5029 DKLOG(DKS " user server timeout\n", DKN(service));
5030 #if DEVELOPMENT || DEBUG
5031 driverkit_checkin_timed_out = mach_absolute_time();
5032 #endif
5033 }
5034
5035 OSSafeReleaseNULL(token);
5036 return false;
5037 }
5038
5039 if (token && !(kIODKDisableCheckInTokenVerification & gIODKDebug)) {
5040 if (!userServer->serviceMatchesCheckInToken(token)) {
5041 OSSafeReleaseNULL(token);
5042 service->detach(this);
5043 IOServicePH::matchingEnd(this);
5044 OSSafeReleaseNULL(obj);
5045 userServer->exit("Check In Token verification failed");
5046 userServer->release();
5047 return false;
5048 }
5049 }
5050 OSSafeReleaseNULL(token);
5051 OSSafeReleaseNULL(obj);
5052
5053 if (!(kIODKDisableEntitlementChecking & gIODKDebug)) {
5054 if (!userServer->checkEntitlements(this, service)) {
5055 service->detach(this);
5056 IOServicePH::matchingEnd(this);
5057 userServer->exit("Entitlements check failed");
5058 userServer->release();
5059 return false;
5060 }
5061 }
5062 #if !XNU_TARGET_OS_OSX && !(DEVELOPMENT || DEBUG)
5063 // Prevent third party drivers from matching IOUserResources/IOResources, except when signed for development
5064 if (!userServer->isPlatformDriver() &&
5065 userServer->getCSValidationCategory() != CS_VALIDATION_CATEGORY_DEVELOPMENT
5066 && (this == gIOUserResources || this == gIOResources)) {
5067 service->detach(this);
5068 IOServicePH::matchingEnd(this);
5069 userServer->exit("Third party driver may only match real hardware");
5070 userServer->release();
5071 return false;
5072 }
5073 #endif /* !XNU_TARGET_OS_OSX && !(DEVELOPMENT || DEBUG) */
5074
5075 userServer->serviceAttach(service, this);
5076 } else {
5077 OSSafeReleaseNULL(obj);
5078 }
5079 }
5080
5081 AbsoluteTime startTime;
5082 AbsoluteTime endTime;
5083 UInt64 nano;
5084 bool recordTime = (kIOLogStart & gIOKitDebug) != 0;
5085
5086 if (recordTime) {
5087 clock_get_uptime(&startTime);
5088 }
5089
5090 #if DEBUG || DEVELOPMENT
5091 service->__patchProperties();
5092 #endif /* DEBUG || DEVELOPMENT */
5093
5094 ok = service->start(this);
5095
5096 if (recordTime) {
5097 clock_get_uptime(&endTime);
5098
5099 if (CMP_ABSOLUTETIME(&endTime, &startTime) > 0) {
5100 SUB_ABSOLUTETIME(&endTime, &startTime);
5101 absolutetime_to_nanoseconds(endTime, &nano);
5102 if (nano > 500000000ULL) {
5103 IOLog("%s[0x%qx]::start took %ld ms\n", service->getName(), service->getRegistryEntryID(), (long)(UInt32)(nano / 1000000ULL));
5104 }
5105 }
5106 }
5107 if (userServer) {
5108 userServer->serviceStarted(service, this, ok);
5109 userServer->release();
5110 }
5111
5112 if (ok) {
5113 IOInstallServiceSleepPlatformActions(service);
5114 #if 00
5115 if (!strcmp("XHC1", getName())) {
5116 service->setProperty(gIOPrimaryDriverTerminateOptionsKey, kOSBooleanTrue);
5117 }
5118 #endif
5119 }
5120
5121 if (!ok) {
5122 service->detach( this );
5123 }
5124
5125 if (ph) {
5126 IOServicePH::matchingEnd(this);
5127 }
5128
5129 return ok;
5130 }
5131
5132 void
publishResource(const char * key,OSObject * value)5133 IOService::publishResource( const char * key, OSObject * value )
5134 {
5135 const OSSymbol * sym;
5136
5137 if ((sym = OSSymbol::withCString( key))) {
5138 publishResource( sym, value);
5139 sym->release();
5140 }
5141 }
5142
5143 void
publishResource(const OSSymbol * key,OSObject * value)5144 IOService::publishResource( const OSSymbol * key, OSObject * value )
5145 {
5146 if (NULL == value) {
5147 value = (OSObject *) gIOServiceKey;
5148 }
5149
5150 gIOResources->setProperty( key, value);
5151
5152 if (IORecursiveLockHaveLock( gNotificationLock)) {
5153 return;
5154 }
5155
5156 gIOResourceGenerationCount++;
5157 gIOResources->registerService();
5158 }
5159
5160 void
publishUserResource(const OSSymbol * key,OSObject * value)5161 IOService::publishUserResource( const OSSymbol * key, OSObject * value )
5162 {
5163 if (NULL == value) {
5164 value = (OSObject *) gIOServiceKey;
5165 }
5166
5167 gIOUserResources->setProperty( key, value);
5168
5169 if (IORecursiveLockHaveLock( gNotificationLock)) {
5170 return;
5171 }
5172
5173 gIOResourceGenerationCount++;
5174 gIOUserResources->registerService();
5175 }
5176
5177 bool
addNeededResource(const char * key)5178 IOService::addNeededResource( const char * key )
5179 {
5180 OSObject * resourcesProp;
5181 OSSet * set;
5182 OSString * newKey;
5183 bool ret;
5184
5185 resourcesProp = copyProperty( gIOResourceMatchKey );
5186 if (!resourcesProp) {
5187 return false;
5188 }
5189
5190 newKey = OSString::withCString( key );
5191 if (!newKey) {
5192 resourcesProp->release();
5193 return false;
5194 }
5195
5196 set = OSDynamicCast( OSSet, resourcesProp );
5197 if (!set) {
5198 set = OSSet::withCapacity( 1 );
5199 set->setObject( resourcesProp );
5200 } else {
5201 set->retain();
5202 }
5203
5204 set->setObject( newKey );
5205 newKey->release();
5206 ret = setProperty( gIOResourceMatchKey, set );
5207 set->release();
5208 resourcesProp->release();
5209
5210 return ret;
5211 }
5212
5213 bool
checkResource(OSObject * matching)5214 IOService::checkResource( OSObject * matching )
5215 {
5216 OSString * str;
5217 OSDictionary * table;
5218
5219 if ((str = OSDynamicCast( OSString, matching ))) {
5220 if (gIOResources->getProperty( str )) {
5221 return true;
5222 }
5223 }
5224
5225 if (str) {
5226 table = resourceMatching( str );
5227 } else if ((table = OSDynamicCast( OSDictionary, matching ))) {
5228 table->retain();
5229 } else {
5230 IOLog("%s: Can't match using: %s\n", getName(),
5231 matching->getMetaClass()->getClassName());
5232 /* false would stall forever */
5233 return true;
5234 }
5235
5236 if (gIOKitDebug & kIOLogConfig) {
5237 LOG("config(%p): stalling %s\n", IOSERVICE_OBFUSCATE(IOThreadSelf()), getName());
5238 }
5239
5240 waitForService( table );
5241
5242 if (gIOKitDebug & kIOLogConfig) {
5243 LOG("config(%p): waking\n", IOSERVICE_OBFUSCATE(IOThreadSelf()));
5244 }
5245
5246 return true;
5247 }
5248
5249 bool
checkResources(void)5250 IOService::checkResources( void )
5251 {
5252 OSObject * resourcesProp;
5253 OSSet * set;
5254 OSObject * obj;
5255 OSIterator * iter;
5256 bool ok;
5257
5258 resourcesProp = copyProperty( gIOResourceMatchKey );
5259 if (NULL == resourcesProp) {
5260 return true;
5261 }
5262
5263 if ((set = OSDynamicCast( OSSet, resourcesProp ))) {
5264 iter = OSCollectionIterator::withCollection( set );
5265 ok = (NULL != iter);
5266 while (ok && (obj = iter->getNextObject())) {
5267 ok = checkResource( obj );
5268 }
5269 if (iter) {
5270 iter->release();
5271 }
5272 } else {
5273 ok = checkResource( resourcesProp );
5274 }
5275
5276 OSSafeReleaseNULL(resourcesProp);
5277
5278 return ok;
5279 }
5280
5281
5282 void
configThread(const char * name)5283 _IOConfigThread::configThread( const char * name )
5284 {
5285 _IOConfigThread * inst;
5286
5287 do {
5288 if (!(inst = new _IOConfigThread)) {
5289 continue;
5290 }
5291 if (!inst->init()) {
5292 continue;
5293 }
5294 thread_t thread;
5295 if (KERN_SUCCESS != kernel_thread_start(&_IOConfigThread::main, inst, &thread)) {
5296 continue;
5297 }
5298
5299 char threadName[MAXTHREADNAMESIZE];
5300 snprintf(threadName, sizeof(threadName), "IOConfigThread_'%s'", name);
5301 thread_set_thread_name(thread, threadName);
5302 thread_deallocate(thread);
5303
5304 return;
5305 } while (false);
5306
5307 if (inst) {
5308 inst->release();
5309 }
5310
5311 return;
5312 }
5313
5314 /*
5315 * To support driver replacement of boot matched drivers later in boot, drivers can
5316 * opt-in to be being terminated if a non-boot driver matches their provider, by
5317 * setting the gIOPrimaryDriverTerminateOptionsKey property. The driver providing the
5318 * root disk media may not be terminated.
5319 * IOMedia objects are hidden from user space until all drivers are available, but any
5320 * associated with the root disk must be published immediately.
5321 */
5322
5323 struct FindRootMediaContext {
5324 OSArray * services;
5325 IOService * parent;
5326 };
5327
5328 bool
hasParent(IOService * parent)5329 IOService::hasParent(IOService * parent)
5330 {
5331 IOService * service;
5332
5333 for (service = this;
5334 service && (service != parent);
5335 service = service->getProvider()) {
5336 }
5337
5338 return service != NULL;
5339 }
5340
5341 bool
publishHiddenMediaApplier(const OSObject * entry,void * context)5342 IOService::publishHiddenMediaApplier(const OSObject * entry, void * context)
5343 {
5344 FindRootMediaContext * ctx = (typeof(ctx))context;
5345 IOService * service = (typeof(service))entry;
5346
5347 do {
5348 if (ctx->parent && !service->hasParent(ctx->parent)) {
5349 break;
5350 }
5351 if (ctx->services) {
5352 ctx->services->setObject(service);
5353 } else {
5354 ctx->services = OSArray::withObjects((const OSObject **) &service, 1);
5355 assert(ctx->services);
5356 }
5357 } while (false);
5358
5359 return false;
5360 }
5361
5362 // publish to user space any hidden IOMedia under the 'parent' object, or all
5363 // if 'parent' is NULL
5364
5365 void
publishHiddenMedia(IOService * parent)5366 IOService::publishHiddenMedia(IOService * parent)
5367 {
5368 const OSMetaClass * iomediaClass;
5369 bool wasHiding;
5370
5371 iomediaClass = OSMetaClass::getMetaClassWithName(gIOMediaKey);
5372 assert(iomediaClass);
5373
5374 LOCKWRITENOTIFY();
5375 wasHiding = gIOServiceHideIOMedia;
5376 if (wasHiding && !parent) {
5377 gIOServiceHideIOMedia = false;
5378 }
5379 UNLOCKNOTIFY();
5380
5381 FindRootMediaContext ctx = { .services = NULL, .parent = parent };
5382
5383 if (wasHiding) {
5384 iomediaClass->applyToInstances(publishHiddenMediaApplier, &ctx);
5385 }
5386 if (ctx.services) {
5387 unsigned int idx, notiIdx;
5388 IOService * service;
5389 OSArray * notifiers[3] = {};
5390
5391 for (idx = 0; (service = (IOService *) ctx.services->getObject(idx)); idx++) {
5392 service->lockForArbitration(true);
5393 if (!(kIOServiceUserInvisibleMatchState & service->__state[0])) {
5394 service->unlockForArbitration();
5395 continue;
5396 }
5397 service->__state[0] &= ~kIOServiceUserInvisibleMatchState;
5398 service->__state[1] |= kIOServiceUserUnhidden;
5399 notifiers[0] = service->copyNotifiers(gIOFirstPublishNotification, 0, 0xffffffff);
5400 if (kIOServiceMatchedState & service->__state[0]) {
5401 notifiers[1] = service->copyNotifiers(gIOMatchedNotification, 0, 0xffffffff);
5402 }
5403 if (kIOServiceFirstMatchState & service->__state[0]) {
5404 notifiers[2] = service->copyNotifiers(gIOFirstMatchNotification, 0, 0xffffffff);
5405 }
5406 service->unlockForArbitration();
5407 for (notiIdx = 0; notiIdx < 3; notiIdx++) {
5408 service->invokeNotifiers(¬ifiers[notiIdx]);
5409 }
5410 }
5411 OSSafeReleaseNULL(ctx.services);
5412 }
5413 }
5414
5415 // Find the block storage driver providing the root disk, or NULL if not booting from
5416 // a block device
5417
5418 void
setRootMedia(IOService * root)5419 IOService::setRootMedia(IOService * root)
5420 {
5421 const OSMetaClass * ioblockstoragedriverClass;
5422 bool unhide;
5423
5424 ioblockstoragedriverClass = OSMetaClass::getMetaClassWithName(gIOBlockStorageDriverKey);
5425 assert(ioblockstoragedriverClass);
5426
5427 while (root) {
5428 if (root->metaCast(ioblockstoragedriverClass)) {
5429 break;
5430 }
5431 root = root->getProvider();
5432 }
5433
5434 LOCKWRITENOTIFY();
5435 unhide = (kIOServiceRootMediaParentInvalid == gIOServiceRootMediaParent);
5436 if (unhide) {
5437 gIOServiceRootMediaParent = root;
5438 }
5439 UNLOCKNOTIFY();
5440
5441 if (unhide) {
5442 if (root) {
5443 root->addPMDriverClass(kIOPMDriverClassStorage);
5444 }
5445 publishHiddenMedia(root);
5446 }
5447 }
5448
5449 // Check if the driver may be terminated when a later driver could be used instead
5450
5451 bool
canTerminateForReplacement(IOService * client)5452 IOService::canTerminateForReplacement(IOService * client)
5453 {
5454 IOService * parent;
5455
5456 assert(kIOServiceRootMediaParentInvalid != gIOServiceRootMediaParent);
5457
5458 if (!gIOServiceHideIOMedia) {
5459 return false;
5460 }
5461 if (!client->propertyExists(gIOPrimaryDriverTerminateOptionsKey)) {
5462 return false;
5463 }
5464 if (!gIOServiceRootMediaParent) {
5465 return false;
5466 }
5467 parent = gIOServiceRootMediaParent;
5468 while (parent && (parent != client)) {
5469 parent = parent->getProvider();
5470 }
5471 if (parent) {
5472 IOLog("Can't replace primary matched driver on root media %s-0x%qx\n",
5473 client->getName(), client->getRegistryEntryID());
5474 return false;
5475 }
5476 return true;
5477 }
5478
5479 void
doServiceMatch(IOOptionBits options)5480 IOService::doServiceMatch( IOOptionBits options )
5481 {
5482 _IOServiceNotifier * notify;
5483 OSIterator * iter;
5484 OSOrderedSet * matches;
5485 OSArray * resourceKeys = NULL;
5486 SInt32 catalogGeneration;
5487 bool keepGuessing = true;
5488 bool reRegistered = true;
5489 bool didRegister;
5490 OSArray * notifiers[2] = {NULL};
5491
5492 // job->nub->deliverNotification( gIOPublishNotification,
5493 // kIOServiceRegisteredState, 0xffffffff );
5494
5495 while (keepGuessing) {
5496 matches = gIOCatalogue->findDrivers( this, &catalogGeneration );
5497 // the matches list should always be created by findDrivers()
5498 if (matches) {
5499 lockForArbitration();
5500 if (0 == (__state[0] & kIOServiceFirstPublishState)) {
5501 getMetaClass()->addInstance(this);
5502 notifiers[0] = copyNotifiers(gIOFirstPublishNotification,
5503 kIOServiceFirstPublishState, 0xffffffff );
5504 }
5505 LOCKREADNOTIFY();
5506 __state[1] &= ~kIOServiceNeedConfigState;
5507 __state[1] |= kIOServiceConfigState | kIOServiceConfigRunning;
5508 didRegister = (0 == (kIOServiceRegisteredState & __state[0]));
5509 __state[0] |= kIOServiceRegisteredState;
5510
5511 if (gIOServiceHideIOMedia
5512 && metaCast(gIOMediaKey)
5513 && !(kIOServiceUserUnhidden & __state[1])
5514 && gIOServiceRootMediaParent
5515 && !hasParent(gIOServiceRootMediaParent)
5516 && propertyExists(gIOPrimaryDriverTerminateOptionsKey, gIOServicePlane)) {
5517 __state[0] |= kIOServiceUserInvisibleMatchState;
5518 }
5519
5520 keepGuessing &= (0 == (__state[0] & kIOServiceInactiveState));
5521 if (reRegistered && keepGuessing) {
5522 iter = OSCollectionIterator::withCollection((OSOrderedSet *)
5523 gNotifications->getObject( gIOPublishNotification ));
5524 if (iter) {
5525 while ((notify = (_IOServiceNotifier *)
5526 iter->getNextObject())) {
5527 if (matchPassive(notify->matching, 0)
5528 && (kIOServiceNotifyEnable & notify->state)) {
5529 matches->setObject( notify );
5530 }
5531 }
5532 iter->release();
5533 }
5534 }
5535
5536 UNLOCKNOTIFY();
5537 unlockForArbitration();
5538 invokeNotifiers(¬ifiers[0]);
5539 if (keepGuessing && matches->getCount() && (kIOReturnSuccess == getResources())) {
5540 if ((this == gIOResources) || (this == gIOUserResources)) {
5541 if (resourceKeys) {
5542 resourceKeys->release();
5543 }
5544 resourceKeys = copyPropertyKeys();
5545 }
5546 probeCandidates( matches );
5547 } else {
5548 matches->release();
5549 }
5550 }
5551
5552 lockForArbitration();
5553 reRegistered = (0 != (__state[1] & kIOServiceNeedConfigState));
5554 keepGuessing =
5555 (reRegistered || (catalogGeneration !=
5556 gIOCatalogue->getGenerationCount()))
5557 && (0 == (__state[0] & kIOServiceInactiveState));
5558
5559 if (keepGuessing) {
5560 unlockForArbitration();
5561 }
5562 }
5563
5564 if ((0 == (__state[0] & kIOServiceInactiveState))
5565 && (0 == (__state[1] & kIOServiceModuleStallState))) {
5566 if (resourceKeys) {
5567 setProperty(gIOResourceMatchedKey, resourceKeys);
5568 }
5569
5570 notifiers[0] = copyNotifiers(gIOMatchedNotification,
5571 kIOServiceMatchedState, 0xffffffff);
5572 if (0 == (__state[0] & kIOServiceFirstMatchState)) {
5573 notifiers[1] = copyNotifiers(gIOFirstMatchNotification,
5574 kIOServiceFirstMatchState, 0xffffffff);
5575 }
5576 }
5577
5578 __state[1] &= ~kIOServiceConfigRunning;
5579 unlockForArbitration();
5580
5581 if (resourceKeys) {
5582 resourceKeys->release();
5583 }
5584
5585 invokeNotifiers(¬ifiers[0]);
5586 invokeNotifiers(¬ifiers[1]);
5587
5588 lockForArbitration();
5589 __state[1] &= ~kIOServiceConfigState;
5590 scheduleTerminatePhase2();
5591
5592 _adjustBusy(-1, /*unlock*/ true);
5593 // does unlockForArbitration();
5594 }
5595
5596 UInt32
_adjustBusy(SInt32 delta)5597 IOService::_adjustBusy(SInt32 delta)
5598 {
5599 return _adjustBusy(delta, false);
5600 }
5601
5602 UInt32
_adjustBusy(SInt32 delta,bool unlock)5603 IOService::_adjustBusy(SInt32 delta, bool unlock)
5604 {
5605 IOService * next;
5606 IOService * nextProvider;
5607 UInt32 count;
5608 UInt32 result;
5609 bool wasQuiet, nowQuiet, needWake;
5610
5611 next = this;
5612 result = __state[1] & kIOServiceBusyStateMask;
5613
5614 if (delta) {
5615 do {
5616 if (next != this) {
5617 next->lockForArbitration();
5618 }
5619 count = next->__state[1] & kIOServiceBusyStateMask;
5620 wasQuiet = (0 == count);
5621 if (((delta < 0) && wasQuiet) || ((delta > 0) && (kIOServiceBusyMax == count))) {
5622 OSReportWithBacktrace("%s: bad busy count (%d,%d)\n", next->getName(), (uint32_t)count, (int)delta);
5623 } else {
5624 count += delta;
5625 }
5626 next->__state[1] = (next->__state[1] & ~kIOServiceBusyStateMask) | count;
5627 nowQuiet = (0 == count);
5628 needWake = (0 != (kIOServiceBusyWaiterState & next->__state[1]));
5629
5630 if (needWake) {
5631 next->__state[1] &= ~kIOServiceBusyWaiterState;
5632 IOLockLock( gIOServiceBusyLock );
5633 thread_wakeup((event_t) next);
5634 IOLockUnlock( gIOServiceBusyLock );
5635 }
5636 if (wasQuiet || nowQuiet) {
5637 nextProvider = next->getProvider();
5638 if (nextProvider) {
5639 nextProvider->retain();
5640 }
5641 }
5642 if ((next != this) || unlock) {
5643 next->unlockForArbitration();
5644 }
5645
5646 if ((wasQuiet || nowQuiet)) {
5647 uint64_t regID = next->getRegistryEntryID();
5648 IOServiceTrace(
5649 ((wasQuiet /*nowBusy*/) ? IOSERVICE_BUSY : IOSERVICE_NONBUSY),
5650 (uintptr_t) regID,
5651 (uintptr_t) (regID >> 32),
5652 (uintptr_t) next,
5653 0);
5654
5655 if (wasQuiet) {
5656 next->__timeBusy = mach_absolute_time();
5657 } else {
5658 next->__accumBusy += mach_absolute_time() - next->__timeBusy;
5659 next->__timeBusy = 0;
5660 }
5661
5662 MessageClientsContext context;
5663
5664 context.service = next;
5665 context.type = kIOMessageServiceBusyStateChange;
5666 context.argument = (void *) wasQuiet; /*nowBusy*/
5667 context.argSize = 0;
5668
5669 applyToInterestNotifiers( next, gIOBusyInterest,
5670 &messageClientsApplier, &context );
5671
5672 #if !NO_KEXTD
5673 if (nowQuiet && (next == gIOServiceRoot)) {
5674 if (gIOServiceHideIOMedia) {
5675 publishHiddenMedia(NULL);
5676 }
5677
5678 OSKext::considerUnloads();
5679 IOServiceTrace(IOSERVICE_REGISTRY_QUIET, 0, 0, 0, 0);
5680 }
5681 #endif
5682 }
5683
5684 delta = nowQuiet ? -1 : +1;
5685 if (next != this) {
5686 next->release();
5687 }
5688 next = nextProvider;
5689 nextProvider = NULL;
5690 } while ((wasQuiet || nowQuiet) && next);
5691 }
5692
5693 return result;
5694 }
5695
5696 void
adjustBusy(SInt32 delta)5697 IOService::adjustBusy( SInt32 delta )
5698 {
5699 lockForArbitration();
5700 _adjustBusy( delta );
5701 unlockForArbitration();
5702 }
5703
5704 uint64_t
getAccumulatedBusyTime(void)5705 IOService::getAccumulatedBusyTime( void )
5706 {
5707 uint64_t accumBusy = __accumBusy;
5708 uint64_t timeBusy = __timeBusy;
5709 uint64_t nano;
5710
5711 do{
5712 accumBusy = __accumBusy;
5713 timeBusy = __timeBusy;
5714 if (timeBusy) {
5715 accumBusy += mach_absolute_time() - timeBusy;
5716 }
5717 }while (timeBusy != __timeBusy);
5718
5719 absolutetime_to_nanoseconds(*(AbsoluteTime *)&accumBusy, &nano);
5720
5721 return nano;
5722 }
5723
5724 UInt32
getBusyState(void)5725 IOService::getBusyState( void )
5726 {
5727 return __state[1] & kIOServiceBusyStateMask;
5728 }
5729
5730 IOReturn
waitForState(UInt32 mask,UInt32 value,mach_timespec_t * timeout)5731 IOService::waitForState( UInt32 mask, UInt32 value,
5732 mach_timespec_t * timeout )
5733 {
5734 panic("waitForState");
5735 return kIOReturnUnsupported;
5736 }
5737
5738 IOReturn
waitForState(UInt32 mask,UInt32 value,uint64_t timeout)5739 IOService::waitForState( UInt32 mask, UInt32 value,
5740 uint64_t timeout )
5741 {
5742 bool wait, done;
5743 int waitResult = THREAD_AWAKENED;
5744 bool computeDeadline = true;
5745 AbsoluteTime abstime;
5746
5747 do {
5748 lockForArbitration();
5749 IOLockLock( gIOServiceBusyLock );
5750 done = (value == (__state[1] & mask));
5751 wait = (waitResult != THREAD_TIMED_OUT) && !done;
5752 if (wait) {
5753 __state[1] |= kIOServiceBusyWaiterState;
5754 unlockForArbitration();
5755 if (timeout != UINT64_MAX) {
5756 if (computeDeadline) {
5757 AbsoluteTime nsinterval;
5758 nanoseconds_to_absolutetime(timeout, &nsinterval );
5759 clock_absolutetime_interval_to_deadline(nsinterval, &abstime);
5760 computeDeadline = false;
5761 }
5762 assert_wait_deadline((event_t)this, THREAD_UNINT, __OSAbsoluteTime(abstime));
5763 } else {
5764 assert_wait((event_t)this, THREAD_UNINT );
5765 }
5766 } else {
5767 unlockForArbitration();
5768 }
5769 IOLockUnlock( gIOServiceBusyLock );
5770 if (wait) {
5771 waitResult = thread_block(THREAD_CONTINUE_NULL);
5772 }
5773 } while (wait);
5774
5775 if (done) {
5776 return kIOReturnSuccess;
5777 } else {
5778 return kIOReturnTimeout;
5779 }
5780 }
5781
5782 IOReturn
waitQuietWithOptions(uint64_t timeout,IOOptionBits options)5783 IOService::waitQuietWithOptions( uint64_t timeout, IOOptionBits options )
5784 {
5785 IOReturn ret;
5786 uint32_t loops, timeoutExtensions;
5787 char * busyEntriesString = NULL;
5788 char * panicString = NULL;
5789 size_t busyEntriesStringLen;
5790 size_t panicStringLen;
5791 uint64_t time;
5792 uint64_t nano;
5793 bool pendingRequests;
5794 bool registryRootBusy;
5795 bool multipleEntries;
5796 bool dopanic = false;
5797
5798 enum { kIOServiceBusyTimeoutExtensionsMax = 8 };
5799 #if KASAN
5800 /*
5801 * On kasan kernels, everything takes longer, so double the number of
5802 * timeout extensions. This should help with issues like 41259215
5803 * where WindowServer was timing out waiting for kextd to get all the
5804 * kasan kexts loaded and started.
5805 *
5806 * On legacy/x86 systems give a bit more time since we may be
5807 * booting from a HDD.
5808 */
5809 enum { kTimeoutExtensions = 8 };
5810 #define WITH_IOWAITQUIET_EXTENSIONS 1
5811 #elif defined(__x86_64__)
5812 enum { kTimeoutExtensions = 4 };
5813 #define WITH_IOWAITQUIET_EXTENSIONS 1
5814 #elif defined(XNU_TARGET_OS_OSX)
5815 enum { kTimeoutExtensions = 1 };
5816 #define WITH_IOWAITQUIET_EXTENSIONS 1
5817 #else
5818 enum { kTimeoutExtensions = 1 };
5819 #define WITH_IOWAITQUIET_EXTENSIONS 0
5820 #endif
5821
5822 timeoutExtensions = kTimeoutExtensions;
5823 time = mach_absolute_time();
5824 pendingRequests = false;
5825 for (loops = 0; loops < timeoutExtensions; loops++) {
5826 ret = waitForState( kIOServiceBusyStateMask, 0, timeout );
5827
5828 if (loops && (kIOReturnSuccess == ret)) {
5829 time = mach_absolute_time() - time;
5830 absolutetime_to_nanoseconds(*(AbsoluteTime *)&time, &nano);
5831 IOLog("busy extended ok[%d], (%llds, %llds)\n",
5832 loops, timeout / 1000000000ULL, nano / 1000000000ULL);
5833 break;
5834 } else if (kIOReturnTimeout != ret) {
5835 break;
5836 } else if (timeout < (41ull * NSEC_PER_SEC)) {
5837 break;
5838 }
5839
5840 {
5841 IORegistryIterator * iter;
5842 OSOrderedSet * set;
5843 OSOrderedSet * leaves;
5844 IOService * next;
5845 IOService * nextParent;
5846 char * s;
5847 size_t l;
5848 size_t busyEntriesStringRemaining;
5849
5850 busyEntriesStringLen = 256;
5851 panicStringLen = 256;
5852 if (!busyEntriesString) {
5853 busyEntriesString = IONewZeroData(char, busyEntriesStringLen);
5854 assert(busyEntriesString != NULL);
5855 }
5856 if (!panicString) {
5857 panicString = IONewZeroData(char, panicStringLen);
5858 assert(panicString != NULL);
5859 }
5860
5861 set = NULL;
5862 pendingRequests = OSKext::pendingIOKitDaemonRequests();
5863 iter = IORegistryIterator::iterateOver(this, gIOServicePlane, kIORegistryIterateRecursively);
5864 leaves = OSOrderedSet::withCapacity(4);
5865 if (iter) {
5866 set = iter->iterateAll();
5867 }
5868 if (leaves && set) {
5869 busyEntriesString[0] = panicString[0] = 0;
5870 set->setObject(this);
5871 while ((next = (IOService *) set->getLastObject())) {
5872 if (next->getBusyState()) {
5873 if (kIOServiceModuleStallState & next->__state[1]) {
5874 pendingRequests = true;
5875 }
5876 #if defined(XNU_TARGET_OS_OSX)
5877 OSObject * prop;
5878 if ((prop = next->copyProperty(kIOServiceBusyTimeoutExtensionsKey, gIOServicePlane))) {
5879 OSNumber * num;
5880 uint32_t value;
5881 if ((num = OSDynamicCast(OSNumber, prop))) {
5882 value = num->unsigned32BitValue();
5883 if (value
5884 && (value <= kIOServiceBusyTimeoutExtensionsMax)
5885 && (value > timeoutExtensions)) {
5886 timeoutExtensions = value;
5887 }
5888 }
5889 OSSafeReleaseNULL(prop);
5890 }
5891 #endif /* defined(XNU_TARGET_OS_OSX) */
5892 leaves->setObject(next);
5893 nextParent = next;
5894 while ((nextParent = nextParent->getProvider())) {
5895 set->removeObject(nextParent);
5896 leaves->removeObject(nextParent);
5897 }
5898 }
5899 set->removeObject(next);
5900 }
5901 registryRootBusy = leaves->getCount() == 1 && leaves->getObject(0) == getServiceRoot();
5902 multipleEntries = leaves->getCount() > 1;
5903 s = busyEntriesString;
5904 busyEntriesStringRemaining = busyEntriesStringLen;
5905
5906 if (registryRootBusy) {
5907 snprintf(s, busyEntriesStringRemaining, "registry root held busy, " kIOKitDaemonName " %s checked in", OSKext::iokitDaemonActive() ? "has" : "has not");
5908 } else {
5909 while ((next = (IOService *) leaves->getLastObject())) {
5910 l = snprintf(s, busyEntriesStringRemaining, "%s'%s' (%x,%x)", ((s == busyEntriesString) ? "" : ", "), next->getName(), (uint32_t)next->__state[0], (uint32_t)next->__state[1]);
5911 if (l >= busyEntriesStringRemaining) {
5912 break;
5913 }
5914 s += l;
5915 busyEntriesStringRemaining -= l;
5916 leaves->removeObject(next);
5917 }
5918 }
5919 }
5920 OSSafeReleaseNULL(leaves);
5921 OSSafeReleaseNULL(set);
5922 OSSafeReleaseNULL(iter);
5923 }
5924
5925 dopanic = (kIOWaitQuietPanics & gIOKitDebug) && (options & kIOWaitQuietPanicOnFailure) && !gIOKitWillTerminate;
5926 #if WITH_IOWAITQUIET_EXTENSIONS
5927 dopanic = (dopanic && (loops >= (timeoutExtensions - 1)));
5928 #endif
5929 assert(panicString != NULL);
5930 if (multipleEntries) {
5931 snprintf(panicString, panicStringLen,
5932 "%s[%d], (%llds): multiple entries holding the registry busy, IOKit termination queue depth %u: %s",
5933 pendingRequests ? "IOKit Daemon (" kIOKitDaemonName ") stall" : "busy timeout",
5934 loops, timeout / 1000000000ULL,
5935 (uint32_t)gIOTerminateWork,
5936 busyEntriesString ? busyEntriesString : "");
5937 } else {
5938 snprintf(panicString, panicStringLen,
5939 "%s[%d], (%llds): %s",
5940 pendingRequests ? "IOKit Daemon (" kIOKitDaemonName ") stall" : "busy timeout",
5941 loops, timeout / 1000000000ULL,
5942 busyEntriesString ? busyEntriesString : "");
5943 }
5944
5945 IOLog("%s\n", panicString);
5946 if (dopanic) {
5947 panic("%s", panicString);
5948 } else if (!loops) {
5949 getPMRootDomain()->startSpinDump(1);
5950 }
5951 }
5952
5953 if (busyEntriesString) {
5954 IODeleteData(busyEntriesString, char, busyEntriesStringLen);
5955 }
5956 if (panicString) {
5957 IODeleteData(panicString, char, panicStringLen);
5958 }
5959
5960 return ret;
5961 }
5962
5963 IOReturn
waitQuiet(uint64_t timeout)5964 IOService::waitQuiet( uint64_t timeout )
5965 {
5966 return waitQuietWithOptions(timeout);
5967 }
5968
5969 IOReturn
waitQuiet(mach_timespec_t * timeout)5970 IOService::waitQuiet( mach_timespec_t * timeout )
5971 {
5972 uint64_t timeoutNS;
5973
5974 if (timeout) {
5975 timeoutNS = timeout->tv_sec;
5976 timeoutNS *= kSecondScale;
5977 timeoutNS += timeout->tv_nsec;
5978 } else {
5979 timeoutNS = UINT64_MAX;
5980 }
5981
5982 return waitQuiet(timeoutNS);
5983 }
5984
5985 bool
serializeProperties(OSSerialize * s) const5986 IOService::serializeProperties( OSSerialize * s ) const
5987 {
5988 #if 0
5989 ((IOService *)this)->setProperty(((IOService *)this)->__state,
5990 sizeof(__state), "__state");
5991 #endif
5992 return super::serializeProperties(s);
5993 }
5994
5995 void
resetRematchProperties()5996 IOService::resetRematchProperties()
5997 {
5998 removeProperty(gIORematchCountKey);
5999 removeProperty(gIORematchPersonalityKey);
6000 }
6001
6002
6003 void
main(void * arg,wait_result_t result)6004 _IOConfigThread::main(void * arg, wait_result_t result)
6005 {
6006 _IOConfigThread * self = (_IOConfigThread *) arg;
6007 _IOServiceJob * job;
6008 IOService * nub;
6009 bool alive = true;
6010 kern_return_t kr;
6011 thread_precedence_policy_data_t precedence = { -1 };
6012
6013 kr = thread_policy_set(current_thread(),
6014 THREAD_PRECEDENCE_POLICY,
6015 (thread_policy_t) &precedence,
6016 THREAD_PRECEDENCE_POLICY_COUNT);
6017 if (KERN_SUCCESS != kr) {
6018 IOLog("thread_policy_set(%d)\n", kr);
6019 }
6020
6021 do {
6022 // randomDelay();
6023
6024 semaphore_wait( gJobsSemaphore );
6025
6026 IOTakeLock( gJobsLock );
6027 job = (_IOServiceJob *) gJobs->getFirstObject();
6028 job->retain();
6029 gJobs->removeObject(job);
6030 if (job) {
6031 gOutstandingJobs--;
6032 // gNumConfigThreads--; // we're out of service
6033 gNumWaitingThreads--; // we're out of service
6034 }
6035 IOUnlock( gJobsLock );
6036
6037 if (job) {
6038 nub = job->nub;
6039
6040 if (gIOKitDebug & kIOLogConfig) {
6041 LOG("config(%p): starting on %s, %d\n",
6042 IOSERVICE_OBFUSCATE(IOThreadSelf()), job->nub->getName(), job->type);
6043 }
6044
6045 switch (job->type) {
6046 case kMatchNubJob:
6047 nub->doServiceMatch( job->options );
6048 break;
6049
6050 default:
6051 LOG("config(%p): strange type (%d)\n",
6052 IOSERVICE_OBFUSCATE(IOThreadSelf()), job->type );
6053 break;
6054 }
6055
6056 if (job->options & kIOServiceDextRequirePowerForMatching) {
6057 gIOPMRootDomain->releaseDriverKitMatchingAssertion();
6058 }
6059
6060 OSSafeReleaseNULL(nub);
6061 OSSafeReleaseNULL(job);
6062
6063 IOTakeLock( gJobsLock );
6064 alive = (gOutstandingJobs > gNumWaitingThreads);
6065 if (alive) {
6066 gNumWaitingThreads++; // back in service
6067 }
6068 // gNumConfigThreads++;
6069 else {
6070 if (0 == --gNumConfigThreads) {
6071 // IOLog("MATCH IDLE\n");
6072 IOLockWakeup( gJobsLock, (event_t) &gNumConfigThreads, /* one-thread */ false );
6073 }
6074 }
6075 IOUnlock( gJobsLock );
6076 }
6077 } while (alive);
6078
6079 if (gIOKitDebug & kIOLogConfig) {
6080 LOG("config(%p): terminating\n", IOSERVICE_OBFUSCATE(IOThreadSelf()));
6081 }
6082
6083 self->release();
6084 }
6085
6086 IOReturn
waitMatchIdle(UInt32 msToWait)6087 IOService::waitMatchIdle( UInt32 msToWait )
6088 {
6089 bool wait;
6090 int waitResult = THREAD_AWAKENED;
6091 bool computeDeadline = true;
6092 AbsoluteTime deadline;
6093
6094 IOLockLock( gJobsLock );
6095 do {
6096 wait = (0 != gNumConfigThreads);
6097 if (wait) {
6098 if (msToWait) {
6099 if (computeDeadline) {
6100 clock_interval_to_deadline(
6101 msToWait, kMillisecondScale, &deadline );
6102 computeDeadline = false;
6103 }
6104 waitResult = IOLockSleepDeadline( gJobsLock, &gNumConfigThreads,
6105 deadline, THREAD_UNINT );
6106 } else {
6107 waitResult = IOLockSleep( gJobsLock, &gNumConfigThreads,
6108 THREAD_UNINT );
6109 }
6110 }
6111 } while (wait && (waitResult != THREAD_TIMED_OUT));
6112 IOLockUnlock( gJobsLock );
6113
6114 if (waitResult == THREAD_TIMED_OUT) {
6115 return kIOReturnTimeout;
6116 } else {
6117 return kIOReturnSuccess;
6118 }
6119 }
6120
6121 void
cpusRunning(void)6122 IOService::cpusRunning(void)
6123 {
6124 gCPUsRunning = true;
6125 }
6126
6127 void
pingConfig(_IOServiceJob * job)6128 _IOServiceJob::pingConfig( _IOServiceJob * job )
6129 {
6130 int count;
6131 bool create;
6132 IOService * nub;
6133
6134 assert( job );
6135 nub = job->nub;
6136
6137 IOTakeLock( gJobsLock );
6138
6139 gOutstandingJobs++;
6140 if (nub == gIOResources) {
6141 gJobs->setFirstObject( job );
6142 } else {
6143 gJobs->setLastObject( job );
6144 }
6145
6146 count = gNumWaitingThreads;
6147 // if( gNumConfigThreads) count++;// assume we're called from a config thread
6148
6149 create = ((gOutstandingJobs > count)
6150 && ((gNumConfigThreads < gMaxConfigThreads)
6151 || (nub == gIOResources)
6152 || !gCPUsRunning));
6153 if (create) {
6154 gNumConfigThreads++;
6155 gNumWaitingThreads++;
6156 if (gNumConfigThreads > gHighNumConfigThreads) {
6157 gHighNumConfigThreads = gNumConfigThreads;
6158 }
6159 }
6160
6161 IOUnlock( gJobsLock );
6162
6163 job->release();
6164
6165 if (create) {
6166 if (gIOKitDebug & kIOLogConfig) {
6167 LOG("config(%d): creating\n", gNumConfigThreads - 1);
6168 }
6169 _IOConfigThread::configThread(nub->getName());
6170 }
6171
6172 semaphore_signal( gJobsSemaphore );
6173 }
6174
6175 struct IOServiceMatchContext {
6176 OSDictionary * table;
6177 OSObject * result;
6178 uint32_t options;
6179 uint32_t state;
6180 uint32_t count;
6181 uint32_t done;
6182 };
6183
6184 bool
instanceMatch(const OSObject * entry,void * context)6185 IOService::instanceMatch(const OSObject * entry, void * context)
6186 {
6187 IOServiceMatchContext * ctx = (typeof(ctx))context;
6188 IOService * service = (typeof(service))entry;
6189 OSDictionary * table = ctx->table;
6190 uint32_t options = ctx->options;
6191 uint32_t state = ctx->state;
6192 uint32_t done;
6193 bool match;
6194
6195 done = 0;
6196 do{
6197 match = ((state == (state & service->__state[0]))
6198 && (0 == (service->__state[0] & kIOServiceInactiveState)));
6199 if (!match) {
6200 break;
6201 }
6202
6203 match = service->matchInternal(table, options, &done);
6204 if (match) {
6205 ctx->count += table->getCount();
6206 ctx->done += done;
6207 }
6208 }while (false);
6209 if (!match) {
6210 return false;
6211 }
6212
6213 if ((kIONotifyOnce & options) && (ctx->done == ctx->count)) {
6214 service->retain();
6215 ctx->result = service;
6216 return true;
6217 } else if (!ctx->result) {
6218 ctx->result = OSSet::withObjects((const OSObject **) &service, 1, 1);
6219 } else {
6220 ((OSSet *)ctx->result)->setObject(service);
6221 }
6222 return false;
6223 }
6224
6225 // internal - call with gNotificationLock
6226 OSObject *
copyExistingServices(OSDictionary * matching,IOOptionBits inState,IOOptionBits options)6227 IOService::copyExistingServices( OSDictionary * matching,
6228 IOOptionBits inState, IOOptionBits options )
6229 {
6230 OSObject * current = NULL;
6231 OSIterator * iter;
6232 IOService * service;
6233 OSObject * obj;
6234 OSString * str;
6235
6236 if (!matching) {
6237 return NULL;
6238 }
6239
6240 #if MATCH_DEBUG
6241 OSSerialize * s = OSSerialize::withCapacity(128);
6242 matching->serialize(s);
6243 #endif
6244
6245 if ((obj = matching->getObject(gIOProviderClassKey))
6246 && gIOResourcesKey
6247 && gIOResourcesKey->isEqualTo(obj)
6248 && (service = gIOResources)) {
6249 if ((inState == (service->__state[0] & inState))
6250 && (0 == (service->__state[0] & kIOServiceInactiveState))
6251 && service->matchPassive(matching, options)) {
6252 if (options & kIONotifyOnce) {
6253 service->retain();
6254 current = service;
6255 } else {
6256 current = OSSet::withObjects((const OSObject **) &service, 1, 1 );
6257 }
6258 }
6259 } else {
6260 IOServiceMatchContext ctx;
6261
6262 options |= kIOServiceClassDone;
6263 ctx.table = matching;
6264 ctx.state = inState;
6265 ctx.count = 0;
6266 ctx.done = 0;
6267 ctx.options = options;
6268 ctx.result = NULL;
6269
6270 if ((str = OSDynamicCast(OSString, obj))) {
6271 const OSSymbol * sym = OSSymbol::withString(str);
6272 OSMetaClass::applyToInstancesOfClassName(sym, instanceMatch, &ctx);
6273 sym->release();
6274 } else {
6275 IOService::gMetaClass.applyToInstances(instanceMatch, &ctx);
6276 }
6277
6278 if (((!(options & kIONotifyOnce) || !ctx.result))
6279 && matching->getObject(gIOCompatibilityMatchKey)) {
6280 IOServiceCompatibility::gMetaClass.applyToInstances(instanceMatch, &ctx);
6281 }
6282
6283 current = ctx.result;
6284 options |= kIOServiceInternalDone;
6285 if (current && (ctx.done != ctx.count)) {
6286 OSSet * source = OSDynamicCast(OSSet, current);
6287 current = NULL;
6288 while ((service = (IOService *) source->getAnyObject())) {
6289 if (service->matchPassive(matching, options)) {
6290 if (options & kIONotifyOnce) {
6291 service->retain();
6292 current = service;
6293 break;
6294 }
6295 if (current) {
6296 ((OSSet *)current)->setObject( service );
6297 } else {
6298 current = OSSet::withObjects(
6299 (const OSObject **) &service, 1, 1 );
6300 }
6301 }
6302 source->removeObject(service);
6303 }
6304 source->release();
6305 }
6306 }
6307
6308 #if MATCH_DEBUG
6309 {
6310 OSObject * _current = 0;
6311
6312 iter = IORegistryIterator::iterateOver( gIOServicePlane,
6313 kIORegistryIterateRecursively );
6314 if (iter) {
6315 do {
6316 iter->reset();
6317 while ((service = (IOService *) iter->getNextObject())) {
6318 if ((inState == (service->__state[0] & inState))
6319 && (0 == (service->__state[0] & kIOServiceInactiveState))
6320 && service->matchPassive(matching, 0)) {
6321 if (options & kIONotifyOnce) {
6322 service->retain();
6323 _current = service;
6324 break;
6325 }
6326 if (_current) {
6327 ((OSSet *)_current)->setObject( service );
6328 } else {
6329 _current = OSSet::withObjects(
6330 (const OSObject **) &service, 1, 1 );
6331 }
6332 }
6333 }
6334 } while (!service && !iter->isValid());
6335 iter->release();
6336 }
6337
6338 if (((current != 0) != (_current != 0))
6339 || (current && _current && !current->isEqualTo(_current))) {
6340 OSSerialize * s1 = OSSerialize::withCapacity(128);
6341 OSSerialize * s2 = OSSerialize::withCapacity(128);
6342 current->serialize(s1);
6343 _current->serialize(s2);
6344 kprintf("**mismatch** %p %p\n%s\n%s\n%s\n", IOSERVICE_OBFUSCATE(current),
6345 IOSERVICE_OBFUSCATE(_current), s->text(), s1->text(), s2->text());
6346 s1->release();
6347 s2->release();
6348 }
6349
6350 if (_current) {
6351 _current->release();
6352 }
6353 }
6354
6355 s->release();
6356 #endif
6357
6358 if (current && (0 == (options & (kIONotifyOnce | kIOServiceExistingSet)))) {
6359 iter = OSCollectionIterator::withCollection((OSSet *)current );
6360 current->release();
6361 current = iter;
6362 }
6363
6364 return current;
6365 }
6366
6367 // public version
6368 OSIterator *
getMatchingServices(OSDictionary * matching)6369 IOService::getMatchingServices( OSDictionary * matching )
6370 {
6371 OSIterator * iter;
6372
6373 // is a lock even needed?
6374 LOCKWRITENOTIFY();
6375
6376 iter = (OSIterator *) copyExistingServices( matching,
6377 kIOServiceMatchedState );
6378
6379 UNLOCKNOTIFY();
6380
6381 return iter;
6382 }
6383
6384 IOService *
copyMatchingService(OSDictionary * matching)6385 IOService::copyMatchingService( OSDictionary * matching )
6386 {
6387 IOService * service;
6388
6389 // is a lock even needed?
6390 LOCKWRITENOTIFY();
6391
6392 service = (IOService *) copyExistingServices( matching,
6393 kIOServiceMatchedState, kIONotifyOnce );
6394
6395 UNLOCKNOTIFY();
6396
6397 return service;
6398 }
6399
6400 struct _IOServiceMatchingNotificationHandlerRef {
6401 IOServiceNotificationHandler handler;
6402 void * ref;
6403 };
6404
6405 static bool
_IOServiceMatchingNotificationHandler(void * target,void * refCon,IOService * newService,IONotifier * notifier)6406 _IOServiceMatchingNotificationHandler( void * target, void * refCon,
6407 IOService * newService,
6408 IONotifier * notifier )
6409 {
6410 return (*((_IOServiceNotifier *) notifier)->compatHandler)(target, refCon, newService);
6411 }
6412
6413 // internal - call with gNotificationLock
6414 IONotifier *
setNotification(const OSSymbol * type,OSDictionary * matching,IOServiceMatchingNotificationHandler handler,void * target,void * ref,SInt32 priority)6415 IOService::setNotification(
6416 const OSSymbol * type, OSDictionary * matching,
6417 IOServiceMatchingNotificationHandler handler, void * target, void * ref,
6418 SInt32 priority )
6419 {
6420 _IOServiceNotifier * notify = NULL;
6421 OSOrderedSet * set;
6422
6423 if (!matching) {
6424 return NULL;
6425 }
6426
6427 notify = new _IOServiceNotifier;
6428 if (notify && !notify->init()) {
6429 notify->release();
6430 notify = NULL;
6431 }
6432
6433 if (notify) {
6434 notify->handler = handler;
6435 notify->target = target;
6436 notify->type = type;
6437 notify->matching = matching;
6438 matching->retain();
6439 if (handler == &_IOServiceMatchingNotificationHandler) {
6440 notify->compatHandler = ((_IOServiceMatchingNotificationHandlerRef *)ref)->handler;
6441 notify->ref = ((_IOServiceMatchingNotificationHandlerRef *)ref)->ref;
6442 } else if (handler == &IOServiceMatchingNotificationHandlerToBlock) {
6443 notify->ref = Block_copy(ref);
6444 } else {
6445 notify->ref = ref;
6446 }
6447 notify->priority = priority;
6448 notify->state = kIOServiceNotifyEnable;
6449 queue_init( ¬ify->handlerInvocations );
6450
6451 ////// queue
6452
6453 if (NULL == (set = (OSOrderedSet *) gNotifications->getObject( type ))) {
6454 set = OSOrderedSet::withCapacity( 1,
6455 IONotifyOrdering, NULL );
6456 if (set) {
6457 gNotifications->setObject( type, set );
6458 set->release();
6459 }
6460 }
6461 notify->whence = set;
6462 if (set) {
6463 set->setObject( notify );
6464 }
6465 }
6466
6467 return notify;
6468 }
6469
6470 // internal - call with gNotificationLock
6471 IONotifier *
doInstallNotification(const OSSymbol * type,OSDictionary * matching,IOServiceMatchingNotificationHandler handler,void * target,void * ref,SInt32 priority,OSIterator ** existing)6472 IOService::doInstallNotification(
6473 const OSSymbol * type, OSDictionary * matching,
6474 IOServiceMatchingNotificationHandler handler,
6475 void * target, void * ref,
6476 SInt32 priority, OSIterator ** existing )
6477 {
6478 OSIterator * exist;
6479 IONotifier * notify;
6480 IOOptionBits inState;
6481
6482 if (!matching) {
6483 return NULL;
6484 }
6485
6486 if (type == gIOPublishNotification) {
6487 inState = kIOServiceRegisteredState;
6488 } else if (type == gIOFirstPublishNotification) {
6489 inState = kIOServiceFirstPublishState;
6490 } else if (type == gIOMatchedNotification) {
6491 inState = kIOServiceMatchedState;
6492 } else if (type == gIOFirstMatchNotification) {
6493 inState = kIOServiceFirstMatchState;
6494 } else if ((type == gIOTerminatedNotification) || (type == gIOWillTerminateNotification)) {
6495 inState = 0;
6496 } else {
6497 return NULL;
6498 }
6499
6500 notify = setNotification( type, matching, handler, target, ref, priority );
6501
6502 if (inState) {
6503 // get the current set
6504 exist = (OSIterator *) copyExistingServices( matching, inState );
6505 } else {
6506 exist = NULL;
6507 }
6508
6509 *existing = exist;
6510
6511 return notify;
6512 }
6513
6514 #if !defined(__LP64__)
6515 IONotifier *
installNotification(const OSSymbol * type,OSDictionary * matching,IOServiceNotificationHandler handler,void * target,void * refCon,SInt32 priority,OSIterator ** existing)6516 IOService::installNotification(const OSSymbol * type, OSDictionary * matching,
6517 IOServiceNotificationHandler handler,
6518 void * target, void * refCon,
6519 SInt32 priority, OSIterator ** existing )
6520 {
6521 IONotifier * result;
6522 _IOServiceMatchingNotificationHandlerRef ref;
6523 ref.handler = handler;
6524 ref.ref = refCon;
6525
6526 result = (_IOServiceNotifier *) installNotification( type, matching,
6527 &_IOServiceMatchingNotificationHandler,
6528 target, &ref, priority, existing );
6529 if (result) {
6530 matching->release();
6531 }
6532
6533 return result;
6534 }
6535
6536 #endif /* !defined(__LP64__) */
6537
6538
6539 IONotifier *
installNotification(const OSSymbol * type,OSDictionary * matching,IOServiceMatchingNotificationHandler handler,void * target,void * ref,SInt32 priority,OSIterator ** existing)6540 IOService::installNotification(
6541 const OSSymbol * type, OSDictionary * matching,
6542 IOServiceMatchingNotificationHandler handler,
6543 void * target, void * ref,
6544 SInt32 priority, OSIterator ** existing )
6545 {
6546 IONotifier * notify;
6547
6548 LOCKWRITENOTIFY();
6549
6550 notify = doInstallNotification( type, matching, handler, target, ref,
6551 priority, existing );
6552
6553 // in case handler remove()s
6554 if (notify) {
6555 notify->retain();
6556 }
6557
6558 UNLOCKNOTIFY();
6559
6560 return notify;
6561 }
6562
6563 IONotifier *
addNotification(const OSSymbol * type,OSDictionary * matching,IOServiceNotificationHandler handler,void * target,void * refCon,SInt32 priority)6564 IOService::addNotification(
6565 const OSSymbol * type, OSDictionary * matching,
6566 IOServiceNotificationHandler handler,
6567 void * target, void * refCon,
6568 SInt32 priority )
6569 {
6570 IONotifier * result;
6571 _IOServiceMatchingNotificationHandlerRef ref;
6572
6573 ref.handler = handler;
6574 ref.ref = refCon;
6575
6576 result = addMatchingNotification(type, matching, &_IOServiceMatchingNotificationHandler,
6577 target, &ref, priority);
6578
6579 if (result) {
6580 matching->release();
6581 }
6582
6583 return result;
6584 }
6585
6586 IONotifier *
addMatchingNotification(const OSSymbol * type,OSDictionary * matching,IOServiceMatchingNotificationHandler handler,void * target,void * ref,SInt32 priority)6587 IOService::addMatchingNotification(
6588 const OSSymbol * type, OSDictionary * matching,
6589 IOServiceMatchingNotificationHandler handler,
6590 void * target, void * ref,
6591 SInt32 priority )
6592 {
6593 OSIterator * existing = NULL;
6594 IONotifier * ret;
6595 _IOServiceNotifier * notify;
6596 IOService * next;
6597
6598 ret = notify = (_IOServiceNotifier *) installNotification( type, matching,
6599 handler, target, ref, priority, &existing );
6600 if (!ret) {
6601 OSSafeReleaseNULL(existing);
6602 return NULL;
6603 }
6604
6605 // send notifications for existing set
6606 if (existing) {
6607 while ((next = (IOService *) existing->getNextObject())) {
6608 if (0 == (next->__state[0] & kIOServiceInactiveState)) {
6609 next->invokeNotifier( notify );
6610 }
6611 }
6612 existing->release();
6613 }
6614
6615 LOCKWRITENOTIFY();
6616 bool removed = (NULL == notify->whence);
6617 notify->release();
6618 if (removed) {
6619 ret = gIOServiceNullNotifier;
6620 }
6621 UNLOCKNOTIFY();
6622
6623 return ret;
6624 }
6625
6626 static bool
IOServiceMatchingNotificationHandlerToBlock(void * target __unused,void * refCon,IOService * newService,IONotifier * notifier)6627 IOServiceMatchingNotificationHandlerToBlock( void * target __unused, void * refCon,
6628 IOService * newService,
6629 IONotifier * notifier )
6630 {
6631 return ((IOServiceMatchingNotificationHandlerBlock) refCon)(newService, notifier);
6632 }
6633
6634 IONotifier *
addMatchingNotification(const OSSymbol * type,OSDictionary * matching,SInt32 priority,IOServiceMatchingNotificationHandlerBlock handler)6635 IOService::addMatchingNotification(
6636 const OSSymbol * type, OSDictionary * matching,
6637 SInt32 priority,
6638 IOServiceMatchingNotificationHandlerBlock handler)
6639 {
6640 IONotifier * notify;
6641
6642 notify = addMatchingNotification(type, matching,
6643 &IOServiceMatchingNotificationHandlerToBlock, NULL, handler, priority);
6644 return notify;
6645 }
6646
6647 struct IOUserServerCancellationHandlerArgs {
6648 IOService ** ref;
6649 bool canceled;
6650 };
6651
6652 void
userServerCheckInTokenCancellationHandler(__unused IOUserServerCheckInToken * token,void * ref)6653 IOService::userServerCheckInTokenCancellationHandler(
6654 __unused IOUserServerCheckInToken *token,
6655 void *ref)
6656 {
6657 IOUserServerCancellationHandlerArgs * args = (typeof(args))ref;
6658 LOCKWRITENOTIFY();
6659 WAKEUPNOTIFY(args->ref);
6660 args->canceled = true;
6661 UNLOCKNOTIFY();
6662 }
6663
6664 bool
syncNotificationHandler(void *,void * ref,IOService * newService,IONotifier * notifier)6665 IOService::syncNotificationHandler(
6666 void * /* target */, void * ref,
6667 IOService * newService,
6668 IONotifier * notifier )
6669 {
6670 LOCKWRITENOTIFY();
6671 if (!*((IOService **) ref)) {
6672 newService->retain();
6673 (*(IOService **) ref) = newService;
6674 WAKEUPNOTIFY(ref);
6675 }
6676 UNLOCKNOTIFY();
6677
6678 return false;
6679 }
6680
6681 IOService *
waitForMatchingServiceWithToken(OSDictionary * matching,uint64_t timeout,IOUserServerCheckInToken * checkInToken)6682 IOService::waitForMatchingServiceWithToken( OSDictionary * matching,
6683 uint64_t timeout,
6684 IOUserServerCheckInToken * checkInToken)
6685 {
6686 IONotifier * notify = NULL;
6687 // priority doesn't help us much since we need a thread wakeup
6688 SInt32 priority = 0;
6689 IOService * result;
6690 IOUserServerCancellationHandlerArgs cancelArgs;
6691 _IOUserServerCheckInCancellationHandler * cancellationHandler = NULL;
6692
6693 if (!matching) {
6694 return NULL;
6695 }
6696
6697 result = NULL;
6698 cancelArgs.ref = &result;
6699 cancelArgs.canceled = false;
6700
6701 #if DEBUG || DEVELOPMENT
6702 char currentName[MAXTHREADNAMESIZE];
6703 char newName[MAXTHREADNAMESIZE];
6704 OSObject * obj;
6705 OSString * str;
6706 OSDictionary * dict;
6707
6708 currentName[0] = '\0';
6709 if (thread_has_thread_name(current_thread())) {
6710 dict = matching;
6711 obj = matching->getObject(gIOPropertyMatchKey);
6712 if ((dict = OSDynamicCast(OSDictionary, obj))) {
6713 OSObject * result __block = NULL;
6714 dict->iterateObjects(^bool (const OSSymbol * sym, OSObject * value) {
6715 result = __DECONST(OSObject *, sym);
6716 return true;
6717 });
6718 obj = result;
6719 }
6720 if (!obj) {
6721 obj = matching->getObject(gIOResourceMatchKey);
6722 }
6723 if (!obj) {
6724 obj = matching->getObject(gIONameMatchKey);
6725 }
6726 if (!obj) {
6727 obj = matching->getObject(gIOProviderClassKey);
6728 }
6729 if ((str = OSDynamicCast(OSString, obj))) {
6730 thread_get_thread_name(current_thread(), currentName);
6731 snprintf(newName, sizeof(newName), "Waiting_'%s'", str->getCStringNoCopy());
6732 thread_set_thread_name(current_thread(), newName);
6733 }
6734 }
6735 #endif /* DEBUG || DEVELOPMENT */
6736
6737 if (checkInToken) {
6738 cancellationHandler = checkInToken->setCancellationHandler(&IOService::userServerCheckInTokenCancellationHandler,
6739 &cancelArgs);
6740 }
6741
6742 LOCKWRITENOTIFY();
6743 do{
6744 if (cancelArgs.canceled) {
6745 // token was already canceled, no need to wait or find services
6746 break;
6747 }
6748 result = (IOService *) copyExistingServices( matching,
6749 kIOServiceMatchedState, kIONotifyOnce );
6750 if (result) {
6751 break;
6752 }
6753 notify = IOService::setNotification( gIOMatchedNotification, matching,
6754 &IOService::syncNotificationHandler, (void *) NULL,
6755 &result, priority );
6756 if (!notify) {
6757 break;
6758 }
6759 if (UINT64_MAX != timeout) {
6760 AbsoluteTime deadline;
6761 nanoseconds_to_absolutetime(timeout, &deadline);
6762 clock_absolutetime_interval_to_deadline(deadline, &deadline);
6763 SLEEPNOTIFYTO(&result, deadline);
6764 } else {
6765 SLEEPNOTIFY(&result);
6766 }
6767 }while (false);
6768
6769 UNLOCKNOTIFY();
6770
6771 if (checkInToken && cancellationHandler) {
6772 checkInToken->removeCancellationHandler(cancellationHandler);
6773 }
6774
6775 #if DEBUG || DEVELOPMENT
6776 if (currentName[0]) {
6777 thread_set_thread_name(current_thread(), currentName);
6778 }
6779 #endif /* DEBUG || DEVELOPMENT */
6780
6781 if (notify) {
6782 notify->remove(); // dequeues
6783 }
6784
6785 OSSafeReleaseNULL(cancellationHandler);
6786
6787 return result;
6788 }
6789
6790 IOService *
waitForMatchingService(OSDictionary * matching,uint64_t timeout)6791 IOService::waitForMatchingService( OSDictionary * matching,
6792 uint64_t timeout)
6793 {
6794 return IOService::waitForMatchingServiceWithToken(matching, timeout, NULL);
6795 }
6796
6797 IOService *
waitForService(OSDictionary * matching,mach_timespec_t * timeout)6798 IOService::waitForService( OSDictionary * matching,
6799 mach_timespec_t * timeout )
6800 {
6801 IOService * result;
6802 uint64_t timeoutNS;
6803
6804 if (timeout) {
6805 timeoutNS = timeout->tv_sec;
6806 timeoutNS *= kSecondScale;
6807 timeoutNS += timeout->tv_nsec;
6808 } else {
6809 timeoutNS = UINT64_MAX;
6810 }
6811
6812 result = waitForMatchingService(matching, timeoutNS);
6813
6814 matching->release();
6815 if (result) {
6816 result->release();
6817 }
6818
6819 return result;
6820 }
6821
6822 __dead2
6823 void
deliverNotification(const OSSymbol * type,IOOptionBits orNewState,IOOptionBits andNewState)6824 IOService::deliverNotification( const OSSymbol * type,
6825 IOOptionBits orNewState, IOOptionBits andNewState )
6826 {
6827 panic("deliverNotification");
6828 }
6829
6830 OSArray *
copyNotifiers(const OSSymbol * type,IOOptionBits orNewState,IOOptionBits andNewState)6831 IOService::copyNotifiers(const OSSymbol * type,
6832 IOOptionBits orNewState, IOOptionBits andNewState )
6833 {
6834 _IOServiceNotifier * notify;
6835 OSIterator * iter;
6836 OSArray * willSend = NULL;
6837
6838 lockForArbitration();
6839
6840 if ((0 == (__state[0] & kIOServiceInactiveState))
6841 || (type == gIOTerminatedNotification)
6842 || (type == gIOWillTerminateNotification)) {
6843 LOCKREADNOTIFY();
6844
6845 iter = OSCollectionIterator::withCollection((OSOrderedSet *)
6846 gNotifications->getObject( type ));
6847
6848 if (iter) {
6849 while ((notify = (_IOServiceNotifier *) iter->getNextObject())) {
6850 if (matchPassive(notify->matching, 0)
6851 && (kIOServiceNotifyEnable & notify->state)) {
6852 if (NULL == willSend) {
6853 willSend = OSArray::withCapacity(8);
6854 }
6855 if (willSend) {
6856 willSend->setObject( notify );
6857 }
6858 }
6859 }
6860 iter->release();
6861 }
6862 __state[0] = (__state[0] | orNewState) & andNewState;
6863 UNLOCKNOTIFY();
6864 }
6865
6866 unlockForArbitration();
6867
6868 return willSend;
6869 }
6870
6871 IOOptionBits
getState(void) const6872 IOService::getState( void ) const
6873 {
6874 return __state[0];
6875 }
6876
6877 /*
6878 * Helpers to make matching objects for simple cases
6879 */
6880
6881 OSDictionary *
serviceMatching(const OSString * name,OSDictionary * table)6882 IOService::serviceMatching( const OSString * name,
6883 OSDictionary * table )
6884 {
6885 const OSString * str;
6886
6887 str = OSSymbol::withString(name);
6888 if (!str) {
6889 return NULL;
6890 }
6891
6892 if (!table) {
6893 table = OSDictionary::withCapacity( 2 );
6894 }
6895 if (table) {
6896 table->setObject(gIOProviderClassKey, (OSObject *)str );
6897 }
6898 str->release();
6899
6900 return table;
6901 }
6902
6903
6904 OSSharedPtr<OSDictionary>
serviceMatching(const OSString * name,OSSharedPtr<OSDictionary> table)6905 IOService::serviceMatching( const OSString * name,
6906 OSSharedPtr<OSDictionary> table)
6907 {
6908 OSDictionary * result = serviceMatching(name, table.get());
6909 if (table) {
6910 return OSSharedPtr<OSDictionary>(result, OSRetain);
6911 } else {
6912 return OSSharedPtr<OSDictionary>(result, OSNoRetain);
6913 }
6914 }
6915
6916
6917 OSDictionary *
serviceMatching(const char * name,OSDictionary * table)6918 IOService::serviceMatching( const char * name,
6919 OSDictionary * table )
6920 {
6921 const OSString * str;
6922
6923 str = OSSymbol::withCString( name );
6924 if (!str) {
6925 return NULL;
6926 }
6927
6928 table = serviceMatching( str, table );
6929 str->release();
6930 return table;
6931 }
6932
6933
6934 OSSharedPtr<OSDictionary>
serviceMatching(const char * className,OSSharedPtr<OSDictionary> table)6935 IOService::serviceMatching( const char * className,
6936 OSSharedPtr<OSDictionary> table)
6937 {
6938 OSDictionary * result = serviceMatching(className, table.get());
6939 if (table) {
6940 return OSSharedPtr<OSDictionary>(result, OSRetain);
6941 } else {
6942 return OSSharedPtr<OSDictionary>(result, OSNoRetain);
6943 }
6944 }
6945
6946
6947 OSDictionary *
nameMatching(const OSString * name,OSDictionary * table)6948 IOService::nameMatching( const OSString * name,
6949 OSDictionary * table )
6950 {
6951 if (!table) {
6952 table = OSDictionary::withCapacity( 2 );
6953 }
6954 if (table) {
6955 table->setObject( gIONameMatchKey, (OSObject *)name );
6956 }
6957
6958 return table;
6959 }
6960
6961
6962 OSSharedPtr<OSDictionary>
nameMatching(const OSString * name,OSSharedPtr<OSDictionary> table)6963 IOService::nameMatching( const OSString * name,
6964 OSSharedPtr<OSDictionary> table)
6965 {
6966 OSDictionary * result = nameMatching(name, table.get());
6967 if (table) {
6968 return OSSharedPtr<OSDictionary>(result, OSRetain);
6969 } else {
6970 return OSSharedPtr<OSDictionary>(result, OSNoRetain);
6971 }
6972 }
6973
6974
6975 OSDictionary *
nameMatching(const char * name,OSDictionary * table)6976 IOService::nameMatching( const char * name,
6977 OSDictionary * table )
6978 {
6979 const OSString * str;
6980
6981 str = OSSymbol::withCString( name );
6982 if (!str) {
6983 return NULL;
6984 }
6985
6986 table = nameMatching( str, table );
6987 str->release();
6988 return table;
6989 }
6990
6991
6992 OSSharedPtr<OSDictionary>
nameMatching(const char * name,OSSharedPtr<OSDictionary> table)6993 IOService::nameMatching( const char * name,
6994 OSSharedPtr<OSDictionary> table)
6995 {
6996 OSDictionary * result = nameMatching(name, table.get());
6997 if (table) {
6998 return OSSharedPtr<OSDictionary>(result, OSRetain);
6999 } else {
7000 return OSSharedPtr<OSDictionary>(result, OSNoRetain);
7001 }
7002 }
7003
7004
7005 OSDictionary *
resourceMatching(const OSString * str,OSDictionary * table)7006 IOService::resourceMatching( const OSString * str,
7007 OSDictionary * table )
7008 {
7009 table = serviceMatching( gIOResourcesKey, table );
7010 if (table) {
7011 table->setObject( gIOResourceMatchKey, (OSObject *) str );
7012 }
7013
7014 return table;
7015 }
7016
7017
7018 OSSharedPtr<OSDictionary>
resourceMatching(const OSString * str,OSSharedPtr<OSDictionary> table)7019 IOService::resourceMatching( const OSString * str,
7020 OSSharedPtr<OSDictionary> table)
7021 {
7022 OSDictionary * result = resourceMatching(str, table.get());
7023 if (table) {
7024 return OSSharedPtr<OSDictionary>(result, OSRetain);
7025 } else {
7026 return OSSharedPtr<OSDictionary>(result, OSNoRetain);
7027 }
7028 }
7029
7030
7031 OSDictionary *
resourceMatching(const char * name,OSDictionary * table)7032 IOService::resourceMatching( const char * name,
7033 OSDictionary * table )
7034 {
7035 const OSSymbol * str;
7036
7037 str = OSSymbol::withCString( name );
7038 if (!str) {
7039 return NULL;
7040 }
7041
7042 table = resourceMatching( str, table );
7043 str->release();
7044
7045 return table;
7046 }
7047
7048
7049 OSSharedPtr<OSDictionary>
resourceMatching(const char * name,OSSharedPtr<OSDictionary> table)7050 IOService::resourceMatching( const char * name,
7051 OSSharedPtr<OSDictionary> table)
7052 {
7053 OSDictionary * result = resourceMatching(name, table.get());
7054 if (table) {
7055 return OSSharedPtr<OSDictionary>(result, OSRetain);
7056 } else {
7057 return OSSharedPtr<OSDictionary>(result, OSNoRetain);
7058 }
7059 }
7060
7061
7062 OSDictionary *
propertyMatching(const OSSymbol * key,const OSObject * value,OSDictionary * table)7063 IOService::propertyMatching( const OSSymbol * key, const OSObject * value,
7064 OSDictionary * table )
7065 {
7066 OSDictionary * properties;
7067
7068 properties = OSDictionary::withCapacity( 2 );
7069 if (!properties) {
7070 return NULL;
7071 }
7072 properties->setObject( key, value );
7073
7074 if (!table) {
7075 table = OSDictionary::withCapacity( 2 );
7076 }
7077 if (table) {
7078 table->setObject( gIOPropertyMatchKey, properties );
7079 }
7080
7081 properties->release();
7082
7083 return table;
7084 }
7085
7086
7087 OSSharedPtr<OSDictionary>
propertyMatching(const OSSymbol * key,const OSObject * value,OSSharedPtr<OSDictionary> table)7088 IOService::propertyMatching( const OSSymbol * key, const OSObject * value,
7089 OSSharedPtr<OSDictionary> table)
7090 {
7091 OSDictionary * result = propertyMatching(key, value, table.get());
7092 if (table) {
7093 return OSSharedPtr<OSDictionary>(result, OSRetain);
7094 } else {
7095 return OSSharedPtr<OSDictionary>(result, OSNoRetain);
7096 }
7097 }
7098
7099
7100 OSDictionary *
registryEntryIDMatching(uint64_t entryID,OSDictionary * table)7101 IOService::registryEntryIDMatching( uint64_t entryID,
7102 OSDictionary * table )
7103 {
7104 OSNumber * num;
7105
7106 num = OSNumber::withNumber( entryID, 64 );
7107 if (!num) {
7108 return NULL;
7109 }
7110
7111 if (!table) {
7112 table = OSDictionary::withCapacity( 2 );
7113 }
7114 if (table) {
7115 table->setObject( gIORegistryEntryIDKey, num );
7116 }
7117
7118 if (num) {
7119 num->release();
7120 }
7121
7122 return table;
7123 }
7124
7125
7126 OSSharedPtr<OSDictionary>
registryEntryIDMatching(uint64_t entryID,OSSharedPtr<OSDictionary> table)7127 IOService::registryEntryIDMatching( uint64_t entryID,
7128 OSSharedPtr<OSDictionary> table)
7129 {
7130 OSDictionary * result = registryEntryIDMatching(entryID, table.get());
7131 if (table) {
7132 return OSSharedPtr<OSDictionary>(result, OSRetain);
7133 } else {
7134 return OSSharedPtr<OSDictionary>(result, OSNoRetain);
7135 }
7136 }
7137
7138
7139
7140 /*
7141 * _IOServiceNotifier
7142 */
7143
7144 // wait for all threads, other than the current one,
7145 // to exit the handler
7146
7147 void
wait()7148 _IOServiceNotifier::wait()
7149 {
7150 _IOServiceNotifierInvocation * next;
7151 bool doWait;
7152
7153 do {
7154 doWait = false;
7155 queue_iterate( &handlerInvocations, next,
7156 _IOServiceNotifierInvocation *, link) {
7157 if (next->thread != current_thread()) {
7158 doWait = true;
7159 break;
7160 }
7161 }
7162 if (doWait) {
7163 state |= kIOServiceNotifyWaiter;
7164 SLEEPNOTIFY(this);
7165 }
7166 } while (doWait);
7167 }
7168
7169 void
free()7170 _IOServiceNotifier::free()
7171 {
7172 assert( queue_empty( &handlerInvocations ));
7173
7174 if (handler == &IOServiceMatchingNotificationHandlerToBlock) {
7175 Block_release(ref);
7176 }
7177
7178 OSObject::free();
7179 }
7180
7181 void
remove()7182 _IOServiceNotifier::remove()
7183 {
7184 LOCKWRITENOTIFY();
7185
7186 if (whence) {
7187 whence->removeObject((OSObject *) this );
7188 whence = NULL;
7189 }
7190 if (matching) {
7191 matching->release();
7192 matching = NULL;
7193 }
7194
7195 state &= ~kIOServiceNotifyEnable;
7196
7197 wait();
7198
7199 UNLOCKNOTIFY();
7200
7201 release();
7202 }
7203
7204 bool
disable()7205 _IOServiceNotifier::disable()
7206 {
7207 bool ret;
7208
7209 LOCKWRITENOTIFY();
7210
7211 ret = (0 != (kIOServiceNotifyEnable & state));
7212 state &= ~kIOServiceNotifyEnable;
7213 if (ret) {
7214 wait();
7215 }
7216
7217 UNLOCKNOTIFY();
7218
7219 return ret;
7220 }
7221
7222 void
enable(bool was)7223 _IOServiceNotifier::enable( bool was )
7224 {
7225 LOCKWRITENOTIFY();
7226 if (was) {
7227 state |= kIOServiceNotifyEnable;
7228 } else {
7229 state &= ~kIOServiceNotifyEnable;
7230 }
7231 UNLOCKNOTIFY();
7232 }
7233
7234
7235 /*
7236 * _IOServiceNullNotifier
7237 */
7238
7239 void
taggedRetain(const void * tag) const7240 _IOServiceNullNotifier::taggedRetain(const void *tag) const
7241 {
7242 }
7243 void
taggedRelease(const void * tag,const int when) const7244 _IOServiceNullNotifier::taggedRelease(const void *tag, const int when) const
7245 {
7246 }
7247 void
free()7248 _IOServiceNullNotifier::free()
7249 {
7250 }
7251 void
wait()7252 _IOServiceNullNotifier::wait()
7253 {
7254 }
7255 void
remove()7256 _IOServiceNullNotifier::remove()
7257 {
7258 }
7259 void
enable(bool was)7260 _IOServiceNullNotifier::enable(bool was)
7261 {
7262 }
7263 bool
disable()7264 _IOServiceNullNotifier::disable()
7265 {
7266 return false;
7267 }
7268
7269 /*
7270 * IOResources
7271 */
7272
7273 IOService *
resources(void)7274 IOResources::resources( void )
7275 {
7276 IOResources * inst;
7277
7278 inst = new IOResources;
7279 if (inst && !inst->init()) {
7280 inst->release();
7281 inst = NULL;
7282 }
7283
7284 return inst;
7285 }
7286
7287 bool
init(OSDictionary * dictionary)7288 IOResources::init( OSDictionary * dictionary )
7289 {
7290 // Do super init first
7291 if (!IOService::init()) {
7292 return false;
7293 }
7294
7295 // Allow PAL layer to publish a value
7296 const char *property_name;
7297 int property_value;
7298
7299 pal_get_resource_property( &property_name, &property_value );
7300
7301 if (property_name) {
7302 OSNumber *num;
7303 const OSSymbol * sym;
7304
7305 if ((num = OSNumber::withNumber(property_value, 32)) != NULL) {
7306 if ((sym = OSSymbol::withCString( property_name)) != NULL) {
7307 this->setProperty( sym, num );
7308 sym->release();
7309 }
7310 num->release();
7311 }
7312 }
7313
7314 return true;
7315 }
7316
7317 IOReturn
newUserClient(task_t owningTask,void * securityID,UInt32 type,OSDictionary * properties,IOUserClient ** handler)7318 IOResources::newUserClient(task_t owningTask, void * securityID,
7319 UInt32 type, OSDictionary * properties,
7320 IOUserClient ** handler)
7321 {
7322 return kIOReturnUnsupported;
7323 }
7324
7325 IOWorkLoop *
getWorkLoop() const7326 IOResources::getWorkLoop() const
7327 {
7328 // If we are the resource root
7329 // then use the platform's workloop
7330 if (this == (IOResources *) gIOResources) {
7331 return getPlatform()->getWorkLoop();
7332 } else {
7333 return IOService::getWorkLoop();
7334 }
7335 }
7336
7337 static bool
IOResourcesMatchPropertyTable(IOService * resources,OSDictionary * table)7338 IOResourcesMatchPropertyTable(IOService * resources, OSDictionary * table)
7339 {
7340 OSObject * prop;
7341 bool __block ok = true;
7342
7343 prop = table->getObject( gIOResourceMatchKey );
7344 if (prop) {
7345 prop->iterateObjects(^bool (OSObject * obj)
7346 {
7347 OSString *
7348 str = OSDynamicCast(OSString, obj);
7349 ok = (NULL != resources->getProperty(str));
7350 return !ok;
7351 });
7352 } else if ((prop = table->getObject(gIOResourceMatchedKey))) {
7353 OSObject * obj;
7354 OSArray * keys;
7355
7356 obj = resources->copyProperty(gIOResourceMatchedKey);
7357 keys = OSDynamicCast(OSArray, obj);
7358 ok = false;
7359 if (keys) {
7360 // assuming OSSymbol
7361 ok = ((-1U) != keys->getNextIndexOfObject(prop, 0));
7362 }
7363 OSSafeReleaseNULL(obj);
7364 }
7365
7366 return ok;
7367 }
7368
7369 bool
matchPropertyTable(OSDictionary * table)7370 IOResources::matchPropertyTable( OSDictionary * table )
7371 {
7372 return IOResourcesMatchPropertyTable(this, table);
7373 }
7374
7375 /*
7376 * IOUserResources
7377 */
7378
7379 IOService *
resources(void)7380 IOUserResources::resources( void )
7381 {
7382 IOUserResources * inst;
7383
7384 inst = OSTypeAlloc(IOUserResources);
7385 if (inst && !inst->init()) {
7386 inst->release();
7387 inst = NULL;
7388 }
7389
7390 return inst;
7391 }
7392
7393 bool
init(OSDictionary * dictionary)7394 IOUserResources::init( OSDictionary * dictionary )
7395 {
7396 // Do super init first
7397 if (!IOService::init()) {
7398 return false;
7399 }
7400 return true;
7401 }
7402
7403 IOReturn
newUserClient(task_t owningTask,void * securityID,UInt32 type,OSDictionary * properties,IOUserClient ** handler)7404 IOUserResources::newUserClient(task_t owningTask, void * securityID,
7405 UInt32 type, OSDictionary * properties,
7406 IOUserClient ** handler)
7407 {
7408 return kIOReturnUnsupported;
7409 }
7410
7411 IOWorkLoop *
getWorkLoop() const7412 IOUserResources::getWorkLoop() const
7413 {
7414 return getPlatform()->getWorkLoop();
7415 }
7416
7417 bool
matchPropertyTable(OSDictionary * table)7418 IOUserResources::matchPropertyTable( OSDictionary * table )
7419 {
7420 return IOResourcesMatchPropertyTable(this, table);
7421 }
7422
7423 IOReturn
powerStateWillChangeTo(IOPMPowerFlags flags,unsigned long state,IOService * service)7424 IOUserResources::powerStateWillChangeTo(IOPMPowerFlags flags, unsigned long state, IOService * service)
7425 {
7426 assert(service == getPMRootDomain());
7427 if (service != getPMRootDomain()) {
7428 return kIOReturnSuccess;
7429 }
7430 return IOServicePH::rootWillChangeTo(flags, state);
7431 }
7432
7433 // --
7434
7435 void
consoleLockTimer(thread_call_param_t p0,thread_call_param_t p1)7436 IOService::consoleLockTimer(thread_call_param_t p0, thread_call_param_t p1)
7437 {
7438 IOService::updateConsoleUsers(NULL, 0);
7439 }
7440
7441 void
updateConsoleUsers(OSArray * consoleUsers,IOMessage systemMessage,bool afterUserspaceReboot)7442 IOService::updateConsoleUsers(OSArray * consoleUsers, IOMessage systemMessage, bool afterUserspaceReboot)
7443 {
7444 IORegistryEntry * regEntry;
7445 OSObject * locked = kOSBooleanFalse;
7446 uint32_t idx;
7447 bool publish;
7448 OSDictionary * user;
7449 clock_sec_t now = 0;
7450 clock_usec_t microsecs;
7451
7452 regEntry = IORegistryEntry::getRegistryRoot();
7453
7454 if (!gIOChosenEntry) {
7455 gIOChosenEntry = IORegistryEntry::fromPath("/chosen", gIODTPlane);
7456 }
7457
7458 IOLockLock(gIOConsoleUsersLock);
7459
7460 if (systemMessage) {
7461 sSystemPower = systemMessage;
7462 #if HIBERNATION
7463 if (kIOMessageSystemHasPoweredOn == systemMessage) {
7464 uint32_t lockState = IOHibernateWasScreenLocked();
7465 switch (lockState) {
7466 case 0:
7467 break;
7468 case kIOScreenLockLocked:
7469 case kIOScreenLockFileVaultDialog:
7470 gIOConsoleBooterLockState = kOSBooleanTrue;
7471 break;
7472 case kIOScreenLockNoLock:
7473 gIOConsoleBooterLockState = NULL;
7474 break;
7475 case kIOScreenLockUnlocked:
7476 default:
7477 gIOConsoleBooterLockState = kOSBooleanFalse;
7478 break;
7479 }
7480 }
7481 #endif /* HIBERNATION */
7482 }
7483
7484 if (consoleUsers) {
7485 OSNumber * num = NULL;
7486 bool loginLocked = true;
7487
7488 gIOConsoleLoggedIn = false;
7489 for (idx = 0;
7490 (user = OSDynamicCast(OSDictionary, consoleUsers->getObject(idx)));
7491 idx++) {
7492 gIOConsoleLoggedIn |= ((kOSBooleanTrue == user->getObject(gIOConsoleSessionOnConsoleKey))
7493 && (kOSBooleanTrue == user->getObject(gIOConsoleSessionLoginDoneKey)));
7494
7495 loginLocked &= (kOSBooleanTrue == user->getObject(gIOConsoleSessionScreenIsLockedKey));
7496 if (!num) {
7497 num = OSDynamicCast(OSNumber, user->getObject(gIOConsoleSessionScreenLockedTimeKey));
7498 }
7499 }
7500 #if HIBERNATION
7501 if (!loginLocked || afterUserspaceReboot) {
7502 gIOConsoleBooterLockState = NULL;
7503 }
7504 IOLog("IOConsoleUsers: time(%d) %ld->%d, lin %d, llk %d, \n",
7505 (num != NULL), gIOConsoleLockTime, (num ? num->unsigned32BitValue() : 0),
7506 gIOConsoleLoggedIn, loginLocked);
7507 #endif /* HIBERNATION */
7508 gIOConsoleLockTime = num ? num->unsigned32BitValue() : 0;
7509 }
7510
7511 if (!gIOConsoleLoggedIn
7512 || (kIOMessageSystemWillSleep == sSystemPower)
7513 || (kIOMessageSystemPagingOff == sSystemPower)) {
7514 if (afterUserspaceReboot) {
7515 // set "locked" to false after a user space reboot
7516 // because the reboot happens directly after a user
7517 // logs into the machine via fvunlock mode.
7518 locked = kOSBooleanFalse;
7519 } else {
7520 locked = kOSBooleanTrue;
7521 }
7522 }
7523 #if HIBERNATION
7524 else if (gIOConsoleBooterLockState) {
7525 locked = gIOConsoleBooterLockState;
7526 }
7527 #endif /* HIBERNATION */
7528 else if (gIOConsoleLockTime) {
7529 clock_get_calendar_microtime(&now, µsecs);
7530 if (gIOConsoleLockTime > now) {
7531 AbsoluteTime deadline;
7532 clock_sec_t interval;
7533 uint32_t interval32;
7534
7535 interval = (gIOConsoleLockTime - now);
7536 interval32 = (uint32_t) interval;
7537 if (interval32 != interval) {
7538 interval32 = UINT_MAX;
7539 }
7540 clock_interval_to_deadline(interval32, kSecondScale, &deadline);
7541 thread_call_enter_delayed(gIOConsoleLockCallout, deadline);
7542 } else {
7543 locked = kOSBooleanTrue;
7544 }
7545 }
7546
7547 publish = (consoleUsers || (locked != regEntry->getProperty(gIOConsoleLockedKey)));
7548 if (publish) {
7549 regEntry->setProperty(gIOConsoleLockedKey, locked);
7550 if (consoleUsers) {
7551 regEntry->setProperty(gIOConsoleUsersKey, consoleUsers);
7552 }
7553 OSIncrementAtomic( &gIOConsoleUsersSeed );
7554 }
7555
7556 #if HIBERNATION
7557 if (gIOChosenEntry) {
7558 if (locked == kOSBooleanTrue) {
7559 gIOScreenLockState = kIOScreenLockLocked;
7560 } else if (gIOConsoleLockTime) {
7561 gIOScreenLockState = kIOScreenLockUnlocked;
7562 } else {
7563 gIOScreenLockState = kIOScreenLockNoLock;
7564 }
7565 gIOChosenEntry->setProperty(kIOScreenLockStateKey, &gIOScreenLockState, sizeof(gIOScreenLockState));
7566
7567 IOLog("IOConsoleUsers: gIOScreenLockState %d, hs %d, bs %d, now %ld, sm 0x%x\n",
7568 gIOScreenLockState, gIOHibernateState, (gIOConsoleBooterLockState != NULL), now, systemMessage);
7569 }
7570 #endif /* HIBERNATION */
7571
7572 IOLockUnlock(gIOConsoleUsersLock);
7573
7574 if (publish) {
7575 publishResource( gIOConsoleUsersSeedKey, gIOConsoleUsersSeedValue );
7576
7577 MessageClientsContext context;
7578
7579 context.service = getServiceRoot();
7580 context.type = kIOMessageConsoleSecurityChange;
7581 context.argument = (void *) regEntry;
7582 context.argSize = 0;
7583
7584 applyToInterestNotifiers(getServiceRoot(), gIOConsoleSecurityInterest,
7585 &messageClientsApplier, &context );
7586 }
7587 }
7588
7589 IOReturn
setProperties(OSObject * properties)7590 IOResources::setProperties( OSObject * properties )
7591 {
7592 IOReturn err;
7593 const OSSymbol * key;
7594 OSDictionary * dict;
7595 OSCollectionIterator * iter;
7596
7597 if (!IOCurrentTaskHasEntitlement(kIOResourcesSetPropertyKey)) {
7598 err = IOUserClient::clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator);
7599 if (kIOReturnSuccess != err) {
7600 return err;
7601 }
7602 }
7603
7604 dict = OSDynamicCast(OSDictionary, properties);
7605 if (NULL == dict) {
7606 return kIOReturnBadArgument;
7607 }
7608
7609 iter = OSCollectionIterator::withCollection( dict);
7610 if (NULL == iter) {
7611 return kIOReturnBadArgument;
7612 }
7613
7614 while ((key = OSDynamicCast(OSSymbol, iter->getNextObject()))) {
7615 if (gIOConsoleUsersKey == key) {
7616 do{
7617 OSArray * consoleUsers;
7618 consoleUsers = OSDynamicCast(OSArray, dict->getObject(key));
7619 if (!consoleUsers) {
7620 continue;
7621 }
7622 IOService::updateConsoleUsers(consoleUsers, 0);
7623 }while (false);
7624 }
7625
7626 publishResource( key, dict->getObject(key));
7627 }
7628
7629 iter->release();
7630
7631 return kIOReturnSuccess;
7632 }
7633
7634 /*
7635 * Helpers for matching dictionaries.
7636 * Keys existing in matching are checked in properties.
7637 * Keys may be a string or OSCollection of IOStrings
7638 */
7639
7640 bool
compareProperty(OSDictionary * matching,const char * key)7641 IOService::compareProperty( OSDictionary * matching,
7642 const char * key )
7643 {
7644 OSObject * value;
7645 OSObject * prop;
7646 bool ok;
7647
7648 value = matching->getObject( key );
7649 if (value) {
7650 prop = copyProperty(key);
7651 ok = value->isEqualTo(prop);
7652 if (prop) {
7653 prop->release();
7654 }
7655 } else {
7656 ok = true;
7657 }
7658
7659 return ok;
7660 }
7661
7662
7663 bool
compareProperty(OSDictionary * matching,const OSString * key)7664 IOService::compareProperty( OSDictionary * matching,
7665 const OSString * key )
7666 {
7667 OSObject * value;
7668 OSObject * prop;
7669 bool ok;
7670
7671 value = matching->getObject( key );
7672 if (value) {
7673 prop = copyProperty(key);
7674 ok = value->isEqualTo(prop);
7675 if (prop) {
7676 prop->release();
7677 }
7678 } else {
7679 ok = true;
7680 }
7681
7682 return ok;
7683 }
7684
7685 #ifndef __clang_analyzer__
7686 // Implementation of this function is hidden from the static analyzer.
7687 // The analyzer was worried about this function's confusing contract over
7688 // the 'keys' parameter. The contract is to either release it or not release it
7689 // depending on whether 'matching' is non-null. Such contracts are discouraged
7690 // but changing it now would break compatibility.
7691 bool
compareProperties(OSDictionary * matching,OSCollection * keys)7692 IOService::compareProperties( OSDictionary * matching,
7693 OSCollection * keys )
7694 {
7695 OSCollectionIterator * iter;
7696 const OSString * key;
7697 bool ok = true;
7698
7699 if (!matching || !keys) {
7700 return false;
7701 }
7702
7703 iter = OSCollectionIterator::withCollection( keys );
7704
7705 if (iter) {
7706 while (ok && (key = OSDynamicCast( OSString, iter->getNextObject()))) {
7707 ok = compareProperty( matching, key );
7708 }
7709
7710 iter->release();
7711 }
7712 keys->release(); // !! consume a ref !!
7713
7714 return ok;
7715 }
7716 #endif // __clang_analyzer__
7717
7718 /* Helper to add a location matching dict to the table */
7719
7720 OSDictionary *
addLocation(OSDictionary * table)7721 IOService::addLocation( OSDictionary * table )
7722 {
7723 OSDictionary * dict;
7724
7725 if (!table) {
7726 return NULL;
7727 }
7728
7729 dict = OSDictionary::withCapacity( 1 );
7730 if (dict) {
7731 bool ok = table->setObject( gIOLocationMatchKey, dict );
7732 dict->release();
7733 if (!ok) {
7734 dict = NULL;
7735 }
7736 }
7737
7738 return dict;
7739 }
7740
7741 /*
7742 * Go looking for a provider to match a location dict.
7743 */
7744
7745 IOService *
matchLocation(IOService *)7746 IOService::matchLocation( IOService * /* client */ )
7747 {
7748 IOService * parent;
7749
7750 parent = getProvider();
7751
7752 if (parent) {
7753 parent = parent->matchLocation( this );
7754 }
7755
7756 return parent;
7757 }
7758
7759 OSDictionary *
_copyPropertiesForMatching(void)7760 IOService::_copyPropertiesForMatching(void)
7761 {
7762 OSDictionary * matchProps;
7763
7764 matchProps = dictionaryWithProperties();
7765 if (matchProps) {
7766 // merge will check the OSDynamicCast
7767 matchProps->merge((const OSDictionary *)matchProps->getObject(gIOUserServicePropertiesKey));
7768 }
7769 return matchProps;
7770 }
7771
7772 bool
matchInternal(OSDictionary * table,uint32_t options,uint32_t * did)7773 IOService::matchInternal(OSDictionary * table, uint32_t options, uint32_t * did)
7774 {
7775 OSString * matched;
7776 OSObject * obj;
7777 OSString * str;
7778 OSDictionary * matchProps;
7779 IORegistryEntry * entry;
7780 OSNumber * num;
7781 bool match = true;
7782 bool changesOK = (0 != (kIOServiceChangesOK & options));
7783 uint32_t count;
7784 uint32_t done;
7785
7786 do{
7787 count = table->getCount();
7788 done = 0;
7789 matchProps = NULL;
7790 bool isUser;
7791
7792 isUser = (NULL != table->getObject(gIOServiceNotificationUserKey));
7793 if (isUser) {
7794 done++;
7795 match = (0 == (kIOServiceUserInvisibleMatchState & __state[0]));
7796 if ((!match) || (done == count)) {
7797 break;
7798 }
7799 }
7800
7801 if (propertyExists(gIOExclaveAssignedKey)) {
7802 if (!table->getObject(gIOExclaveProxyKey) && !isUser) {
7803 match = false;
7804 break;
7805 }
7806 } else if (table->getObject(gIOExclaveProxyKey)) {
7807 match = false;
7808 break;
7809 }
7810
7811 if (table->getObject(gIOCompatibilityMatchKey)) {
7812 done++;
7813 obj = copyProperty(gIOCompatibilityPropertiesKey);
7814 matchProps = OSDynamicCast(OSDictionary, obj);
7815 if (!matchProps) {
7816 OSSafeReleaseNULL(obj);
7817 }
7818 }
7819
7820 str = OSDynamicCast(OSString, table->getObject(gIOProviderClassKey));
7821 if (str) {
7822 done++;
7823 if (matchProps && (obj = matchProps->getObject(gIOClassKey))) {
7824 match = str->isEqualTo(obj);
7825 } else {
7826 match = ((kIOServiceClassDone & options) || (NULL != metaCast(str)));
7827 }
7828
7829 #if MATCH_DEBUG
7830 match = (0 != metaCast( str ));
7831 if ((kIOServiceClassDone & options) && !match) {
7832 panic("classDone");
7833 }
7834 #endif
7835 if ((!match) || (done == count)) {
7836 break;
7837 }
7838 }
7839
7840 obj = table->getObject( gIONameMatchKey );
7841 if (obj) {
7842 done++;
7843 match = compareNames( obj, changesOK ? &matched : NULL );
7844 if (!match) {
7845 break;
7846 }
7847 if (changesOK && matched) {
7848 // leave a hint as to which name matched
7849 table->setObject( gIONameMatchedKey, matched );
7850 matched->release();
7851 }
7852 if (done == count) {
7853 break;
7854 }
7855 }
7856
7857 str = OSDynamicCast( OSString, table->getObject( gIOLocationMatchKey ));
7858 if (str) {
7859 const OSSymbol * sym;
7860 done++;
7861 match = false;
7862 sym = copyLocation();
7863 if (sym) {
7864 match = sym->isEqualTo( str );
7865 sym->release();
7866 }
7867 if ((!match) || (done == count)) {
7868 break;
7869 }
7870 }
7871
7872 obj = table->getObject( gIOPropertyMatchKey );
7873 if (obj) {
7874 OSDictionary * nextDict;
7875 OSIterator * iter;
7876 done++;
7877 match = false;
7878 if (!matchProps) {
7879 matchProps = _copyPropertiesForMatching();
7880 }
7881 if (matchProps) {
7882 nextDict = OSDynamicCast( OSDictionary, obj);
7883 if (nextDict) {
7884 iter = NULL;
7885 } else {
7886 iter = OSCollectionIterator::withCollection(
7887 OSDynamicCast(OSCollection, obj));
7888 }
7889
7890 while (nextDict
7891 || (iter && (NULL != (nextDict = OSDynamicCast(OSDictionary,
7892 iter->getNextObject()))))) {
7893 match = matchProps->isEqualTo( nextDict, nextDict);
7894 if (match) {
7895 break;
7896 }
7897 nextDict = NULL;
7898 }
7899 if (iter) {
7900 iter->release();
7901 }
7902 }
7903 if ((!match) || (done == count)) {
7904 break;
7905 }
7906 }
7907
7908 obj = table->getObject( gIOPropertyExistsMatchKey );
7909 if (obj) {
7910 OSString * nextKey;
7911 OSIterator * iter;
7912 done++;
7913 match = false;
7914 if (!matchProps) {
7915 matchProps = _copyPropertiesForMatching();
7916 }
7917 if (matchProps) {
7918 nextKey = OSDynamicCast( OSString, obj);
7919 if (nextKey) {
7920 iter = NULL;
7921 } else {
7922 iter = OSCollectionIterator::withCollection(
7923 OSDynamicCast(OSCollection, obj));
7924 }
7925
7926 while (nextKey
7927 || (iter && (NULL != (nextKey = OSDynamicCast(OSString,
7928 iter->getNextObject()))))) {
7929 match = (NULL != matchProps->getObject(nextKey));
7930 if (match) {
7931 break;
7932 }
7933 nextKey = NULL;
7934 }
7935 if (iter) {
7936 iter->release();
7937 }
7938 }
7939 if ((!match) || (done == count)) {
7940 break;
7941 }
7942 }
7943
7944 str = OSDynamicCast( OSString, table->getObject( gIOPathMatchKey ));
7945 if (str) {
7946 done++;
7947 entry = IORegistryEntry::fromPath( str->getCStringNoCopy());
7948 match = (this == entry);
7949 if (entry) {
7950 entry->release();
7951 }
7952 if (!match && matchProps && (obj = matchProps->getObject(gIOPathKey))) {
7953 match = str->isEqualTo(obj);
7954 }
7955 if ((!match) || (done == count)) {
7956 break;
7957 }
7958 }
7959
7960 num = OSDynamicCast( OSNumber, table->getObject( gIORegistryEntryIDKey ));
7961 if (num) {
7962 done++;
7963 match = (getRegistryEntryID() == num->unsigned64BitValue());
7964 if ((!match) || (done == count)) {
7965 break;
7966 }
7967 }
7968
7969 num = OSDynamicCast( OSNumber, table->getObject( gIOMatchedServiceCountKey ));
7970 if (num) {
7971 OSIterator * iter;
7972 IOService * service = NULL;
7973 UInt32 serviceCount = 0;
7974
7975 done++;
7976 iter = getClientIterator();
7977 if (iter) {
7978 while ((service = (IOService *) iter->getNextObject())) {
7979 if (kIOServiceInactiveState & service->__state[0]) {
7980 continue;
7981 }
7982 if (NULL == service->getProperty( gIOMatchCategoryKey )) {
7983 continue;
7984 }
7985 ++serviceCount;
7986 }
7987 iter->release();
7988 }
7989 match = (serviceCount == num->unsigned32BitValue());
7990 if ((!match) || (done == count)) {
7991 break;
7992 }
7993 }
7994
7995 #define propMatch(key) \
7996 obj = table->getObject(key); \
7997 if (obj) \
7998 { \
7999 OSObject * prop; \
8000 done++; \
8001 prop = copyProperty(key); \
8002 match = obj->isEqualTo(prop); \
8003 if (prop) prop->release(); \
8004 if ((!match) || (done == count)) break; \
8005 }
8006 propMatch(gIOBSDNameKey)
8007 propMatch(gIOBSDMajorKey)
8008 propMatch(gIOBSDMinorKey)
8009 propMatch(gIOBSDUnitKey)
8010 #undef propMatch
8011 }while (false);
8012
8013 OSSafeReleaseNULL(matchProps);
8014
8015 if (did) {
8016 *did = done;
8017 }
8018 return match;
8019 }
8020
8021 bool
passiveMatch(OSDictionary * table,bool changesOK)8022 IOService::passiveMatch( OSDictionary * table, bool changesOK )
8023 {
8024 return matchPassive(table, changesOK ? kIOServiceChangesOK : 0);
8025 }
8026
8027 bool
matchPassive(OSDictionary * table,uint32_t options)8028 IOService::matchPassive(OSDictionary * table, uint32_t options)
8029 {
8030 IOService * where;
8031 OSDictionary * nextTable;
8032 SInt32 score;
8033 OSNumber * newPri;
8034 bool match = true;
8035 bool matchParent = false;
8036 uint32_t count;
8037 uint32_t done;
8038
8039 assert( table );
8040
8041 #if defined(XNU_TARGET_OS_OSX)
8042 OSArray* aliasServiceRegIds = NULL;
8043 IOService* foundAlternateService = NULL;
8044 #endif /* defined(XNU_TARGET_OS_OSX) */
8045
8046 #if MATCH_DEBUG
8047 OSDictionary * root = table;
8048 #endif
8049
8050 where = this;
8051 do{
8052 do{
8053 count = table->getCount();
8054 if (!(kIOServiceInternalDone & options)) {
8055 match = where->matchInternal(table, options, &done);
8056 // don't call family if we've done all the entries in the table
8057 if ((!match) || (done == count)) {
8058 break;
8059 }
8060 }
8061
8062 // pass in score from property table
8063 score = IOServiceObjectOrder( table, (void *) gIOProbeScoreKey);
8064
8065 // do family specific matching
8066 match = where->matchPropertyTable( table, &score );
8067
8068 if (!match) {
8069 #if IOMATCHDEBUG
8070 if (kIOLogMatch & getDebugFlags( table )) {
8071 LOG("%s: family specific matching fails\n", where->getName());
8072 }
8073 #endif
8074 break;
8075 }
8076
8077 if (kIOServiceChangesOK & options) {
8078 // save the score
8079 newPri = OSNumber::withNumber( score, 32 );
8080 if (newPri) {
8081 table->setObject( gIOProbeScoreKey, newPri );
8082 newPri->release();
8083 }
8084 }
8085
8086 options = 0;
8087 matchParent = false;
8088
8089 nextTable = OSDynamicCast(OSDictionary,
8090 table->getObject( gIOParentMatchKey ));
8091 if (nextTable) {
8092 // look for a matching entry anywhere up to root
8093 match = false;
8094 matchParent = true;
8095 table = nextTable;
8096 break;
8097 }
8098
8099 table = OSDynamicCast(OSDictionary,
8100 table->getObject( gIOLocationMatchKey ));
8101 if (table) {
8102 // look for a matching entry at matchLocation()
8103 match = false;
8104 where = where->getProvider();
8105 if (where && (where = where->matchLocation(where))) {
8106 continue;
8107 }
8108 }
8109 break;
8110 }while (true);
8111
8112 if (match == true) {
8113 break;
8114 }
8115
8116 if (matchParent == true) {
8117 #if defined(XNU_TARGET_OS_OSX)
8118 // check if service has an alias to search its other "parents" if a parent match isn't found
8119 OSObject * prop = where->copyProperty(gIOServiceLegacyMatchingRegistryIDKey);
8120 OSNumber * alternateRegistryID = OSDynamicCast(OSNumber, prop);
8121 if (alternateRegistryID != NULL) {
8122 if (aliasServiceRegIds == NULL) {
8123 aliasServiceRegIds = OSArray::withCapacity(sizeof(alternateRegistryID));
8124 }
8125 aliasServiceRegIds->setObject(alternateRegistryID);
8126 }
8127 OSSafeReleaseNULL(prop);
8128 #endif /* defined(XNU_TARGET_OS_OSX) */
8129 } else {
8130 break;
8131 }
8132
8133 where = where->getProvider();
8134 #if defined(XNU_TARGET_OS_OSX)
8135 if (where == NULL) {
8136 // there were no matching parent services, check to see if there are aliased services that have a matching parent
8137 if (aliasServiceRegIds != NULL) {
8138 unsigned int numAliasedServices = aliasServiceRegIds->getCount();
8139 if (numAliasedServices != 0) {
8140 OSNumber* alternateRegistryID = OSDynamicCast(OSNumber, aliasServiceRegIds->getObject(numAliasedServices - 1));
8141 if (alternateRegistryID != NULL) {
8142 OSDictionary* alternateMatchingDict = IOService::registryEntryIDMatching(alternateRegistryID->unsigned64BitValue());
8143 aliasServiceRegIds->removeObject(numAliasedServices - 1);
8144 if (alternateMatchingDict != NULL) {
8145 OSSafeReleaseNULL(foundAlternateService);
8146 foundAlternateService = IOService::copyMatchingService(alternateMatchingDict);
8147 alternateMatchingDict->release();
8148 if (foundAlternateService != NULL) {
8149 where = foundAlternateService;
8150 }
8151 }
8152 }
8153 }
8154 }
8155 }
8156 #endif /* defined(XNU_TARGET_OS_OSX) */
8157 }while (where != NULL);
8158
8159 #if defined(XNU_TARGET_OS_OSX)
8160 OSSafeReleaseNULL(foundAlternateService);
8161 OSSafeReleaseNULL(aliasServiceRegIds);
8162 #endif /* defined(XNU_TARGET_OS_OSX) */
8163
8164 #if MATCH_DEBUG
8165 if (where != this) {
8166 OSSerialize * s = OSSerialize::withCapacity(128);
8167 root->serialize(s);
8168 kprintf("parent match 0x%llx, %d,\n%s\n", getRegistryEntryID(), match, s->text());
8169 s->release();
8170 }
8171 #endif
8172
8173 return match;
8174 }
8175
8176
8177 IOReturn
newUserClient(task_t owningTask,void * securityID,UInt32 type,OSDictionary * properties,IOUserClient ** handler)8178 IOService::newUserClient( task_t owningTask, void * securityID,
8179 UInt32 type, OSDictionary * properties,
8180 IOUserClient ** handler )
8181 {
8182 const OSSymbol *userClientClass = NULL;
8183 IOUserClient *client;
8184 OSObject *prop;
8185 OSObject *temp;
8186
8187 if (reserved && reserved->uvars && reserved->uvars->userServer) {
8188 return reserved->uvars->userServer->serviceNewUserClient(this, owningTask, securityID, type, properties, handler);
8189 }
8190
8191 if (kIOReturnSuccess == newUserClient( owningTask, securityID, type, handler )) {
8192 return kIOReturnSuccess;
8193 }
8194
8195 // First try my own properties for a user client class name
8196 prop = copyProperty(gIOUserClientClassKey);
8197 if (prop) {
8198 if (OSDynamicCast(OSSymbol, prop)) {
8199 userClientClass = (const OSSymbol *) prop;
8200 prop = NULL;
8201 } else if (OSDynamicCast(OSString, prop)) {
8202 userClientClass = OSSymbol::withString((OSString *) prop);
8203 OSSafeReleaseNULL(prop);
8204 if (userClientClass) {
8205 setProperty(gIOUserClientClassKey,
8206 (OSObject *) userClientClass);
8207 }
8208 } else {
8209 OSSafeReleaseNULL(prop);
8210 }
8211 }
8212
8213 // Didn't find one so lets just bomb out now without further ado.
8214 if (!userClientClass) {
8215 return kIOReturnUnsupported;
8216 }
8217
8218 // This reference is consumed by the IOServiceOpen call
8219 temp = OSMetaClass::allocClassWithName(userClientClass);
8220 OSSafeReleaseNULL(userClientClass);
8221 if (!temp) {
8222 return kIOReturnNoMemory;
8223 }
8224
8225 if (OSDynamicCast(IOUserClient, temp)) {
8226 client = (IOUserClient *) temp;
8227 } else {
8228 temp->release();
8229 return kIOReturnUnsupported;
8230 }
8231
8232 if (!client->initWithTask(owningTask, securityID, type, properties)) {
8233 client->release();
8234 return kIOReturnBadArgument;
8235 }
8236
8237 if (!client->attach(this)) {
8238 client->release();
8239 return kIOReturnUnsupported;
8240 }
8241
8242 if (!client->start(this)) {
8243 client->detach(this);
8244 client->release();
8245 return kIOReturnUnsupported;
8246 }
8247
8248 *handler = client;
8249 return kIOReturnSuccess;
8250 }
8251
8252 IOReturn
newUserClient(task_t owningTask,void * securityID,UInt32 type,OSDictionary * properties,OSSharedPtr<IOUserClient> & handler)8253 IOService::newUserClient( task_t owningTask, void * securityID,
8254 UInt32 type, OSDictionary * properties,
8255 OSSharedPtr<IOUserClient>& handler )
8256 {
8257 IOUserClient* handlerRaw = NULL;
8258 IOReturn result = newUserClient(owningTask, securityID, type, properties, &handlerRaw);
8259 handler.reset(handlerRaw, OSNoRetain);
8260 return result;
8261 }
8262
8263 IOReturn
newUserClient(task_t owningTask,void * securityID,UInt32 type,IOUserClient ** handler)8264 IOService::newUserClient( task_t owningTask, void * securityID,
8265 UInt32 type, IOUserClient ** handler )
8266 {
8267 return kIOReturnUnsupported;
8268 }
8269
8270 IOReturn
newUserClient(task_t owningTask,void * securityID,UInt32 type,OSSharedPtr<IOUserClient> & handler)8271 IOService::newUserClient( task_t owningTask, void * securityID,
8272 UInt32 type, OSSharedPtr<IOUserClient>& handler )
8273 {
8274 IOUserClient* handlerRaw = nullptr;
8275 IOReturn result = IOService::newUserClient(owningTask, securityID, type, &handlerRaw);
8276 handler.reset(handlerRaw, OSNoRetain);
8277 return result;
8278 }
8279
8280
8281 IOReturn
requestProbe(IOOptionBits options)8282 IOService::requestProbe( IOOptionBits options )
8283 {
8284 return kIOReturnUnsupported;
8285 }
8286
8287 bool
hasUserServer() const8288 IOService::hasUserServer() const
8289 {
8290 return reserved && reserved->uvars && reserved->uvars->userServer;
8291 }
8292
8293 /*
8294 * Convert an IOReturn to text. Subclasses which add additional
8295 * IOReturn's should override this method and call
8296 * super::stringFromReturn if the desired value is not found.
8297 */
8298
8299 const char *
stringFromReturn(IOReturn rtn)8300 IOService::stringFromReturn( IOReturn rtn )
8301 {
8302 static const IONamedValue IOReturn_values[] = {
8303 {kIOReturnSuccess, "success" },
8304 {kIOReturnError, "general error" },
8305 {kIOReturnNoMemory, "memory allocation error" },
8306 {kIOReturnNoResources, "resource shortage" },
8307 {kIOReturnIPCError, "Mach IPC failure" },
8308 {kIOReturnNoDevice, "no such device" },
8309 {kIOReturnNotPrivileged, "privilege violation" },
8310 {kIOReturnBadArgument, "invalid argument" },
8311 {kIOReturnLockedRead, "device is read locked" },
8312 {kIOReturnLockedWrite, "device is write locked" },
8313 {kIOReturnExclusiveAccess, "device is exclusive access" },
8314 {kIOReturnBadMessageID, "bad IPC message ID" },
8315 {kIOReturnUnsupported, "unsupported function" },
8316 {kIOReturnVMError, "virtual memory error" },
8317 {kIOReturnInternalError, "internal driver error" },
8318 {kIOReturnIOError, "I/O error" },
8319 {kIOReturnCannotLock, "cannot acquire lock" },
8320 {kIOReturnNotOpen, "device is not open" },
8321 {kIOReturnNotReadable, "device is not readable" },
8322 {kIOReturnNotWritable, "device is not writeable" },
8323 {kIOReturnNotAligned, "alignment error" },
8324 {kIOReturnBadMedia, "media error" },
8325 {kIOReturnStillOpen, "device is still open" },
8326 {kIOReturnRLDError, "rld failure" },
8327 {kIOReturnDMAError, "DMA failure" },
8328 {kIOReturnBusy, "device is busy" },
8329 {kIOReturnTimeout, "I/O timeout" },
8330 {kIOReturnOffline, "device is offline" },
8331 {kIOReturnNotReady, "device is not ready" },
8332 {kIOReturnNotAttached, "device/channel is not attached" },
8333 {kIOReturnNoChannels, "no DMA channels available" },
8334 {kIOReturnNoSpace, "no space for data" },
8335 {kIOReturnPortExists, "device port already exists" },
8336 {kIOReturnCannotWire, "cannot wire physical memory" },
8337 {kIOReturnNoInterrupt, "no interrupt attached" },
8338 {kIOReturnNoFrames, "no DMA frames enqueued" },
8339 {kIOReturnMessageTooLarge, "message is too large" },
8340 {kIOReturnNotPermitted, "operation is not permitted" },
8341 {kIOReturnNoPower, "device is without power" },
8342 {kIOReturnNoMedia, "media is not present" },
8343 {kIOReturnUnformattedMedia, "media is not formatted" },
8344 {kIOReturnUnsupportedMode, "unsupported mode" },
8345 {kIOReturnUnderrun, "data underrun" },
8346 {kIOReturnOverrun, "data overrun" },
8347 {kIOReturnDeviceError, "device error" },
8348 {kIOReturnNoCompletion, "no completion routine" },
8349 {kIOReturnAborted, "operation was aborted" },
8350 {kIOReturnNoBandwidth, "bus bandwidth would be exceeded" },
8351 {kIOReturnNotResponding, "device is not responding" },
8352 {kIOReturnInvalid, "unanticipated driver error" },
8353 {0, NULL }
8354 };
8355
8356 return IOFindNameForValue(rtn, IOReturn_values);
8357 }
8358
8359 /*
8360 * Convert an IOReturn to an errno.
8361 */
8362 int
errnoFromReturn(IOReturn rtn)8363 IOService::errnoFromReturn( IOReturn rtn )
8364 {
8365 if (unix_err(err_get_code(rtn)) == rtn) {
8366 return err_get_code(rtn);
8367 }
8368
8369 switch (rtn) {
8370 // (obvious match)
8371 case kIOReturnSuccess:
8372 return 0;
8373 case kIOReturnNoMemory:
8374 return ENOMEM;
8375 case kIOReturnNoDevice:
8376 return ENXIO;
8377 case kIOReturnVMError:
8378 return EFAULT;
8379 case kIOReturnNotPermitted:
8380 return EPERM;
8381 case kIOReturnNotPrivileged:
8382 return EACCES;
8383 case kIOReturnIOError:
8384 return EIO;
8385 case kIOReturnNotWritable:
8386 return EROFS;
8387 case kIOReturnBadArgument:
8388 return EINVAL;
8389 case kIOReturnUnsupported:
8390 return ENOTSUP;
8391 case kIOReturnBusy:
8392 return EBUSY;
8393 case kIOReturnNoPower:
8394 return EPWROFF;
8395 case kIOReturnDeviceError:
8396 return EDEVERR;
8397 case kIOReturnTimeout:
8398 return ETIMEDOUT;
8399 case kIOReturnMessageTooLarge:
8400 return EMSGSIZE;
8401 case kIOReturnNoSpace:
8402 return ENOSPC;
8403 case kIOReturnCannotLock:
8404 return ENOLCK;
8405
8406 // (best match)
8407 case kIOReturnBadMessageID:
8408 case kIOReturnNoCompletion:
8409 case kIOReturnNotAligned:
8410 return EINVAL;
8411 case kIOReturnNotReady:
8412 return EBUSY;
8413 case kIOReturnRLDError:
8414 return EBADMACHO;
8415 case kIOReturnPortExists:
8416 case kIOReturnStillOpen:
8417 return EEXIST;
8418 case kIOReturnExclusiveAccess:
8419 case kIOReturnLockedRead:
8420 case kIOReturnLockedWrite:
8421 case kIOReturnNotOpen:
8422 case kIOReturnNotReadable:
8423 return EACCES;
8424 case kIOReturnCannotWire:
8425 case kIOReturnNoResources:
8426 return ENOMEM;
8427 case kIOReturnAborted:
8428 case kIOReturnOffline:
8429 case kIOReturnNotResponding:
8430 return EBUSY;
8431 case kIOReturnBadMedia:
8432 case kIOReturnNoMedia:
8433 case kIOReturnNotAttached:
8434 case kIOReturnUnformattedMedia:
8435 return ENXIO; // (media error)
8436 case kIOReturnDMAError:
8437 case kIOReturnOverrun:
8438 case kIOReturnUnderrun:
8439 return EIO; // (transfer error)
8440 case kIOReturnNoBandwidth:
8441 case kIOReturnNoChannels:
8442 case kIOReturnNoFrames:
8443 case kIOReturnNoInterrupt:
8444 return EIO; // (hardware error)
8445 case kIOReturnError:
8446 case kIOReturnInternalError:
8447 case kIOReturnInvalid:
8448 return EIO; // (generic error)
8449 case kIOReturnIPCError:
8450 return EIO; // (ipc error)
8451 default:
8452 return EIO; // (all other errors)
8453 }
8454 }
8455
8456 IOReturn
message(UInt32 type,IOService * provider,void * argument)8457 IOService::message( UInt32 type, IOService * provider,
8458 void * argument )
8459 {
8460 /*
8461 * Generic entry point for calls from the provider. A return value of
8462 * kIOReturnSuccess indicates that the message was received, and where
8463 * applicable, that it was successful.
8464 */
8465
8466 return kIOReturnUnsupported;
8467 }
8468
8469 /*
8470 * Device memory
8471 */
8472
8473 IOItemCount
getDeviceMemoryCount(void)8474 IOService::getDeviceMemoryCount( void )
8475 {
8476 OSArray * array;
8477 IOItemCount count;
8478
8479 array = OSDynamicCast( OSArray, getProperty( gIODeviceMemoryKey));
8480 if (array) {
8481 count = array->getCount();
8482 } else {
8483 count = 0;
8484 }
8485
8486 return count;
8487 }
8488
8489 IODeviceMemory *
getDeviceMemoryWithIndex(unsigned int index)8490 IOService::getDeviceMemoryWithIndex( unsigned int index )
8491 {
8492 OSArray * array;
8493 IODeviceMemory * range;
8494
8495 array = OSDynamicCast( OSArray, getProperty( gIODeviceMemoryKey));
8496 if (array) {
8497 range = (IODeviceMemory *) array->getObject( index );
8498 } else {
8499 range = NULL;
8500 }
8501
8502 return range;
8503 }
8504
8505 IOMemoryMap *
mapDeviceMemoryWithIndex(unsigned int index,IOOptionBits options)8506 IOService::mapDeviceMemoryWithIndex( unsigned int index,
8507 IOOptionBits options )
8508 {
8509 IODeviceMemory * range;
8510 IOMemoryMap * map;
8511
8512 range = getDeviceMemoryWithIndex( index );
8513 if (range) {
8514 map = range->map( options );
8515 } else {
8516 map = NULL;
8517 }
8518
8519 return map;
8520 }
8521
8522 OSArray *
getDeviceMemory(void)8523 IOService::getDeviceMemory( void )
8524 {
8525 return OSDynamicCast( OSArray, getProperty( gIODeviceMemoryKey));
8526 }
8527
8528
8529 void
setDeviceMemory(OSArray * array)8530 IOService::setDeviceMemory( OSArray * array )
8531 {
8532 setProperty( gIODeviceMemoryKey, array);
8533 }
8534
8535 static void
requireMaxCpuDelay(IOService * service,UInt32 ns,UInt32 delayType)8536 requireMaxCpuDelay(IOService * service, UInt32 ns, UInt32 delayType)
8537 {
8538 static const UInt kNoReplace = -1U; // Must be an illegal index
8539 UInt replace = kNoReplace;
8540 bool setCpuDelay = false;
8541
8542 IORecursiveLockLock(sCpuDelayLock);
8543
8544 UInt count = sCpuDelayData->getLength() / sizeof(CpuDelayEntry);
8545 __typed_allocators_ignore_push
8546 CpuDelayEntry *entries = (CpuDelayEntry *) sCpuDelayData->getBytesNoCopy();
8547 __typed_allocators_ignore_pop
8548 IOService * holder = NULL;
8549
8550 if (ns) {
8551 const CpuDelayEntry ne = {service, ns, delayType};
8552 holder = service;
8553 // Set maximum delay.
8554 for (UInt i = 0; i < count; i++) {
8555 IOService *thisService = entries[i].fService;
8556 bool sameType = (delayType == entries[i].fDelayType);
8557 if ((service == thisService) && sameType) {
8558 replace = i;
8559 } else if (!thisService) {
8560 if (kNoReplace == replace) {
8561 replace = i;
8562 }
8563 } else if (sameType) {
8564 const UInt32 thisMax = entries[i].fMaxDelay;
8565 if (thisMax < ns) {
8566 ns = thisMax;
8567 holder = thisService;
8568 }
8569 }
8570 }
8571
8572 setCpuDelay = true;
8573 if (kNoReplace == replace) {
8574 __typed_allocators_ignore_push
8575 sCpuDelayData->appendBytes(&ne, sizeof(ne));
8576 __typed_allocators_ignore_pop
8577 } else {
8578 entries[replace] = ne;
8579 }
8580 } else {
8581 ns = -1U; // Set to max unsigned, i.e. no restriction
8582
8583 for (UInt i = 0; i < count; i++) {
8584 // Clear a maximum delay.
8585 IOService *thisService = entries[i].fService;
8586 if (thisService && (delayType == entries[i].fDelayType)) {
8587 UInt32 thisMax = entries[i].fMaxDelay;
8588 if (service == thisService) {
8589 replace = i;
8590 } else if (thisMax < ns) {
8591 ns = thisMax;
8592 holder = thisService;
8593 }
8594 }
8595 }
8596
8597 // Check if entry found
8598 if (kNoReplace != replace) {
8599 entries[replace].fService = NULL; // Null the entry
8600 setCpuDelay = true;
8601 }
8602 }
8603
8604 if (setCpuDelay) {
8605 if (holder && debug_boot_arg) {
8606 strlcpy(sCPULatencyHolderName[delayType], holder->getName(), sizeof(sCPULatencyHolderName[delayType]));
8607 }
8608
8609 // Must be safe to call from locked context
8610 if (delayType == kCpuDelayBusStall) {
8611 #if defined(__x86_64__)
8612 ml_set_maxbusdelay(ns);
8613 #endif /* defined(__x86_64__) */
8614 }
8615 #if defined(__x86_64__)
8616 else if (delayType == kCpuDelayInterrupt) {
8617 ml_set_maxintdelay(ns);
8618 }
8619 #endif /* defined(__x86_64__) */
8620 sCPULatencyHolder[delayType]->setValue(holder ? holder->getRegistryEntryID() : 0);
8621 sCPULatencySet[delayType]->setValue(ns);
8622
8623 OSArray * handlers = sCpuLatencyHandlers[delayType];
8624 IOService * target;
8625 if (handlers) {
8626 for (unsigned int idx = 0;
8627 (target = (IOService *) handlers->getObject(idx));
8628 idx++) {
8629 target->callPlatformFunction(sCPULatencyFunctionName[delayType], false,
8630 (void *) (uintptr_t) ns, holder,
8631 NULL, NULL);
8632 }
8633 }
8634 }
8635
8636 IORecursiveLockUnlock(sCpuDelayLock);
8637 }
8638
8639 static IOReturn
setLatencyHandler(UInt32 delayType,IOService * target,bool enable)8640 setLatencyHandler(UInt32 delayType, IOService * target, bool enable)
8641 {
8642 IOReturn result = kIOReturnNotFound;
8643 OSArray * array;
8644 unsigned int idx;
8645
8646 IORecursiveLockLock(sCpuDelayLock);
8647
8648 do{
8649 if (enable && !sCpuLatencyHandlers[delayType]) {
8650 sCpuLatencyHandlers[delayType] = OSArray::withCapacity(4);
8651 }
8652 array = sCpuLatencyHandlers[delayType];
8653 if (!array) {
8654 break;
8655 }
8656 idx = array->getNextIndexOfObject(target, 0);
8657 if (!enable) {
8658 if (-1U != idx) {
8659 array->removeObject(idx);
8660 result = kIOReturnSuccess;
8661 }
8662 } else {
8663 if (-1U != idx) {
8664 result = kIOReturnExclusiveAccess;
8665 break;
8666 }
8667 array->setObject(target);
8668
8669 UInt count = sCpuDelayData->getLength() / sizeof(CpuDelayEntry);
8670 __typed_allocators_ignore_push
8671 CpuDelayEntry *entries = (CpuDelayEntry *) sCpuDelayData->getBytesNoCopy();
8672 __typed_allocators_ignore_pop
8673 UInt32 ns = -1U; // Set to max unsigned, i.e. no restriction
8674 IOService * holder = NULL;
8675
8676 for (UInt i = 0; i < count; i++) {
8677 if (entries[i].fService
8678 && (delayType == entries[i].fDelayType)
8679 && (entries[i].fMaxDelay < ns)) {
8680 ns = entries[i].fMaxDelay;
8681 holder = entries[i].fService;
8682 }
8683 }
8684 target->callPlatformFunction(sCPULatencyFunctionName[delayType], false,
8685 (void *) (uintptr_t) ns, holder,
8686 NULL, NULL);
8687 result = kIOReturnSuccess;
8688 }
8689 }while (false);
8690
8691 IORecursiveLockUnlock(sCpuDelayLock);
8692
8693 return result;
8694 }
8695
8696 IOReturn
requireMaxBusStall(UInt32 ns)8697 IOService::requireMaxBusStall(UInt32 ns)
8698 {
8699 #if !defined(__x86_64__)
8700 switch (ns) {
8701 case kIOMaxBusStall40usec:
8702 case kIOMaxBusStall30usec:
8703 case kIOMaxBusStall25usec:
8704 case kIOMaxBusStall20usec:
8705 case kIOMaxBusStall10usec:
8706 case kIOMaxBusStall5usec:
8707 case kIOMaxBusStallNone:
8708 break;
8709 default:
8710 return kIOReturnBadArgument;
8711 }
8712 #endif /* !defined(__x86_64__) */
8713 requireMaxCpuDelay(this, ns, kCpuDelayBusStall);
8714 return kIOReturnSuccess;
8715 }
8716
8717 IOReturn
requireMaxInterruptDelay(uint32_t ns)8718 IOService::requireMaxInterruptDelay(uint32_t ns)
8719 {
8720 #if defined(__x86_64__)
8721 requireMaxCpuDelay(this, ns, kCpuDelayInterrupt);
8722 return kIOReturnSuccess;
8723 #else /* defined(__x86_64__) */
8724 return kIOReturnUnsupported;
8725 #endif /* defined(__x86_64__) */
8726 }
8727
8728 /*
8729 * Device interrupts
8730 */
8731
8732 IOReturn
resolveInterrupt(IOService * nub,int source)8733 IOService::resolveInterrupt(IOService *nub, int source)
8734 {
8735 IOInterruptController *interruptController;
8736 OSArray *array;
8737 OSData *data;
8738 OSSymbol *interruptControllerName;
8739 unsigned int numSources;
8740 IOInterruptSource *interruptSources;
8741 IOInterruptSourcePrivate *interruptSourcesPrivate;
8742
8743 // Get the parents list from the nub.
8744 array = OSDynamicCast(OSArray, nub->getProperty(gIOInterruptControllersKey));
8745 if (array == NULL) {
8746 return kIOReturnNoResources;
8747 }
8748
8749 // Allocate space for the IOInterruptSources if needed... then return early.
8750 if (nub->_interruptSources == NULL) {
8751 numSources = array->getCount();
8752 interruptSources = IONewZero(IOInterruptSource, numSources);
8753 interruptSourcesPrivate = IONewZero(IOInterruptSourcePrivate, numSources);
8754
8755 if (interruptSources == NULL || interruptSourcesPrivate == NULL) {
8756 IODelete(interruptSources, IOInterruptSource, numSources);
8757 IODelete(interruptSourcesPrivate, IOInterruptSourcePrivate, numSources);
8758 return kIOReturnNoMemory;
8759 }
8760
8761 nub->_numInterruptSources = numSources;
8762 nub->_interruptSources = interruptSources;
8763 nub->reserved->interruptSourcesPrivate = interruptSourcesPrivate;
8764 return kIOReturnSuccess;
8765 }
8766
8767 interruptControllerName = OSDynamicCast(OSSymbol, array->getObject(source));
8768 if (interruptControllerName == NULL) {
8769 return kIOReturnNoResources;
8770 }
8771
8772 interruptController = getPlatform()->lookUpInterruptController(interruptControllerName);
8773 if (interruptController == NULL) {
8774 return kIOReturnNoResources;
8775 }
8776
8777 // Get the interrupt numbers from the nub.
8778 array = OSDynamicCast(OSArray, nub->getProperty(gIOInterruptSpecifiersKey));
8779 if (array == NULL) {
8780 return kIOReturnNoResources;
8781 }
8782 data = OSDynamicCast(OSData, array->getObject(source));
8783 if (data == NULL) {
8784 return kIOReturnNoResources;
8785 }
8786
8787 // Set the interruptController and interruptSource in the nub's table.
8788 interruptSources = nub->_interruptSources;
8789 interruptSources[source].interruptController = interruptController;
8790 interruptSources[source].vectorData = data;
8791
8792 return kIOReturnSuccess;
8793 }
8794
8795 IOReturn
lookupInterrupt(int source,bool resolve,IOInterruptController ** interruptController)8796 IOService::lookupInterrupt(int source, bool resolve, IOInterruptController **interruptController)
8797 {
8798 IOReturn ret;
8799
8800 /* Make sure the _interruptSources are set */
8801 if (_interruptSources == NULL) {
8802 ret = resolveInterrupt(this, source);
8803 if (ret != kIOReturnSuccess) {
8804 return ret;
8805 }
8806 }
8807
8808 /* Make sure the local source number is valid */
8809 if ((source < 0) || (source >= _numInterruptSources)) {
8810 return kIOReturnNoInterrupt;
8811 }
8812
8813 /* Look up the contoller for the local source */
8814 *interruptController = _interruptSources[source].interruptController;
8815
8816 if (*interruptController == NULL) {
8817 if (!resolve) {
8818 return kIOReturnNoInterrupt;
8819 }
8820
8821 /* Try to resolve the interrupt */
8822 ret = resolveInterrupt(this, source);
8823 if (ret != kIOReturnSuccess) {
8824 return ret;
8825 }
8826
8827 *interruptController = _interruptSources[source].interruptController;
8828 }
8829
8830 return kIOReturnSuccess;
8831 }
8832
8833 IOReturn
registerInterrupt(int source,OSObject * target,IOInterruptAction handler,void * refCon)8834 IOService::registerInterrupt(int source, OSObject *target,
8835 IOInterruptAction handler,
8836 void *refCon)
8837 {
8838 IOInterruptController *interruptController;
8839 IOReturn ret;
8840
8841 ret = lookupInterrupt(source, true, &interruptController);
8842 if (ret != kIOReturnSuccess) {
8843 return ret;
8844 }
8845
8846 /* Register the source */
8847 return interruptController->registerInterrupt(this, source, target,
8848 (IOInterruptHandler)handler,
8849 refCon);
8850 }
8851
8852 static void
IOServiceInterruptActionToBlock(OSObject * target,void * refCon,IOService * nub,int source)8853 IOServiceInterruptActionToBlock( OSObject * target, void * refCon,
8854 IOService * nub, int source )
8855 {
8856 ((IOInterruptActionBlock)(refCon))(nub, source);
8857 }
8858
8859 IOReturn
registerInterruptBlock(int source,OSObject * target,IOInterruptActionBlock handler)8860 IOService::registerInterruptBlock(int source, OSObject *target,
8861 IOInterruptActionBlock handler)
8862 {
8863 IOReturn ret;
8864 void * block;
8865
8866 block = Block_copy(handler);
8867 if (!block) {
8868 return kIOReturnNoMemory;
8869 }
8870
8871 ret = registerInterrupt(source, target, &IOServiceInterruptActionToBlock, block);
8872 if (kIOReturnSuccess != ret) {
8873 Block_release(block);
8874 return ret;
8875 }
8876
8877 reserved->interruptSourcesPrivate[source].vectorBlock = block;
8878
8879 return ret;
8880 }
8881
8882 IOReturn
unregisterInterrupt(int source)8883 IOService::unregisterInterrupt(int source)
8884 {
8885 IOReturn ret;
8886 IOInterruptController *interruptController;
8887 IOInterruptSourcePrivate *priv;
8888 void *block;
8889
8890 ret = lookupInterrupt(source, false, &interruptController);
8891 if (ret != kIOReturnSuccess) {
8892 return ret;
8893 }
8894
8895 /* Unregister the source */
8896 priv = &reserved->interruptSourcesPrivate[source];
8897 block = priv->vectorBlock;
8898 ret = interruptController->unregisterInterrupt(this, source);
8899 if ((kIOReturnSuccess == ret) && (block = priv->vectorBlock)) {
8900 priv->vectorBlock = NULL;
8901 Block_release(block);
8902 }
8903
8904 return ret;
8905 }
8906
8907 void
unregisterAllInterrupts(void)8908 IOService::unregisterAllInterrupts(void)
8909 {
8910 for (int source = 0; source < _numInterruptSources; source++) {
8911 (void) unregisterInterrupt(source);
8912 }
8913 }
8914
8915 IOReturn
addInterruptStatistics(IOInterruptAccountingData * statistics,int source)8916 IOService::addInterruptStatistics(IOInterruptAccountingData * statistics, int source)
8917 {
8918 IOReportLegend * legend = NULL;
8919 IOInterruptAccountingData * oldValue = NULL;
8920 IOInterruptAccountingReporter * newArray = NULL;
8921 char subgroupName[64];
8922 int newArraySize = 0;
8923 int i = 0;
8924
8925 if (source < 0) {
8926 return kIOReturnBadArgument;
8927 }
8928
8929 /*
8930 * We support statistics on a maximum of 256 interrupts per nub; if a nub
8931 * has more than 256 interrupt specifiers associated with it, and tries
8932 * to register a high interrupt index with interrupt accounting, panic.
8933 * Having more than 256 interrupts associated with a single nub is
8934 * probably a sign that something fishy is going on.
8935 */
8936 if (source > IA_INDEX_MAX) {
8937 panic("addInterruptStatistics called for an excessively large index (%d)", source);
8938 }
8939
8940 /*
8941 * TODO: This is ugly (wrapping a lock around an allocation). I'm only
8942 * leaving it as is because the likelihood of contention where we are
8943 * actually growing the array is minimal (we would realistically need
8944 * to be starting a driver for the first time, with an IOReporting
8945 * client already in place). Nonetheless, cleanup that can be done
8946 * to adhere to best practices; it'll make the code more complicated,
8947 * unfortunately.
8948 */
8949 IOLockLock(&reserved->interruptStatisticsLock);
8950
8951 /*
8952 * Lazily allocate the statistics array.
8953 */
8954 if (!reserved->interruptStatisticsArray) {
8955 reserved->interruptStatisticsArray = IONew(IOInterruptAccountingReporter, 1);
8956 assert(reserved->interruptStatisticsArray);
8957 reserved->interruptStatisticsArrayCount = 1;
8958 bzero(reserved->interruptStatisticsArray, sizeof(*reserved->interruptStatisticsArray));
8959 }
8960
8961 if (source >= reserved->interruptStatisticsArrayCount) {
8962 /*
8963 * We're still within the range of supported indices, but we are out
8964 * of space in the current array. Do a nasty realloc (because
8965 * IORealloc isn't a thing) here. We'll double the size with each
8966 * reallocation.
8967 *
8968 * Yes, the "next power of 2" could be more efficient; but this will
8969 * be invoked incredibly rarely. Who cares.
8970 */
8971 newArraySize = (reserved->interruptStatisticsArrayCount << 1);
8972
8973 while (newArraySize <= source) {
8974 newArraySize = (newArraySize << 1);
8975 }
8976 newArray = IONew(IOInterruptAccountingReporter, newArraySize);
8977
8978 assert(newArray);
8979
8980 /*
8981 * TODO: This even zeroes the memory it is about to overwrite.
8982 * Shameful; fix it. Not particularly high impact, however.
8983 */
8984 bzero(newArray, newArraySize * sizeof(*newArray));
8985 memcpy(newArray, reserved->interruptStatisticsArray, reserved->interruptStatisticsArrayCount * sizeof(*newArray));
8986 IODelete(reserved->interruptStatisticsArray, IOInterruptAccountingReporter, reserved->interruptStatisticsArrayCount);
8987 reserved->interruptStatisticsArray = newArray;
8988 reserved->interruptStatisticsArrayCount = newArraySize;
8989 }
8990
8991 if (!reserved->interruptStatisticsArray[source].reporter) {
8992 /*
8993 * We don't have a reporter associated with this index yet, so we
8994 * need to create one.
8995 */
8996 /*
8997 * TODO: Some statistics do in fact have common units (time); should this be
8998 * split into separate reporters to communicate this?
8999 */
9000 reserved->interruptStatisticsArray[source].reporter = IOSimpleReporter::with(this, kIOReportCategoryPower, kIOReportUnitNone);
9001
9002 /*
9003 * Each statistic is given an identifier based on the interrupt index (which
9004 * should be unique relative to any single nub) and the statistic involved.
9005 * We should now have a sane (small and positive) index, so start
9006 * constructing the channels for statistics.
9007 */
9008 for (i = 0; i < IA_NUM_INTERRUPT_ACCOUNTING_STATISTICS; i++) {
9009 /*
9010 * TODO: Currently, this does not add channels for disabled statistics.
9011 * Will this be confusing for clients? If so, we should just add the
9012 * channels; we can avoid updating the channels even if they exist.
9013 */
9014 if (IA_GET_STATISTIC_ENABLED(i)) {
9015 reserved->interruptStatisticsArray[source].reporter->addChannel(IA_GET_CHANNEL_ID(source, i), kInterruptAccountingStatisticNameArray[i]);
9016 }
9017 }
9018
9019 /*
9020 * We now need to add the legend for this reporter to the registry.
9021 */
9022 OSObject * prop = copyProperty(kIOReportLegendKey);
9023 legend = IOReportLegend::with(OSDynamicCast(OSArray, prop));
9024 OSSafeReleaseNULL(prop);
9025
9026 /*
9027 * Note that while we compose the subgroup name, we do not need to
9028 * manage its lifecycle (the reporter will handle this).
9029 */
9030 snprintf(subgroupName, sizeof(subgroupName), "%s %d", getName(), source);
9031 subgroupName[sizeof(subgroupName) - 1] = 0;
9032 legend->addReporterLegend(reserved->interruptStatisticsArray[source].reporter, kInterruptAccountingGroupName, subgroupName);
9033 setProperty(kIOReportLegendKey, legend->getLegend());
9034 legend->release();
9035
9036 /*
9037 * TODO: Is this a good idea? Probably not; my assumption is it opts
9038 * all entities who register interrupts into public disclosure of all
9039 * IOReporting channels. Unfortunately, this appears to be as fine
9040 * grain as it gets.
9041 */
9042 setProperty(kIOReportLegendPublicKey, true);
9043 }
9044
9045 /*
9046 * Don't stomp existing entries. If we are about to, panic; this
9047 * probably means we failed to tear down our old interrupt source
9048 * correctly.
9049 */
9050 oldValue = reserved->interruptStatisticsArray[source].statistics;
9051
9052 if (oldValue) {
9053 panic("addInterruptStatistics call for index %d would have clobbered existing statistics", source);
9054 }
9055
9056 reserved->interruptStatisticsArray[source].statistics = statistics;
9057
9058 /*
9059 * Inherit the reporter values for each statistic. The target may
9060 * be torn down as part of the runtime of the service (especially
9061 * for sleep/wake), so we inherit in order to avoid having values
9062 * reset for no apparent reason. Our statistics are ultimately
9063 * tied to the index and the sevice, not to an individual target,
9064 * so we should maintain them accordingly.
9065 */
9066 interruptAccountingDataInheritChannels(reserved->interruptStatisticsArray[source].statistics, reserved->interruptStatisticsArray[source].reporter);
9067
9068 IOLockUnlock(&reserved->interruptStatisticsLock);
9069
9070 return kIOReturnSuccess;
9071 }
9072
9073 IOReturn
removeInterruptStatistics(int source)9074 IOService::removeInterruptStatistics(int source)
9075 {
9076 IOInterruptAccountingData * value = NULL;
9077
9078 if (source < 0) {
9079 return kIOReturnBadArgument;
9080 }
9081
9082 IOLockLock(&reserved->interruptStatisticsLock);
9083
9084 /*
9085 * We dynamically grow the statistics array, so an excessively
9086 * large index value has NEVER been registered. This either
9087 * means our cap on the array size is too small (unlikely), or
9088 * that we have been passed a corrupt index (this must be passed
9089 * the plain index into the interrupt specifier list).
9090 */
9091 if (source >= reserved->interruptStatisticsArrayCount) {
9092 panic("removeInterruptStatistics called for index %d, which was never registered", source);
9093 }
9094
9095 assert(reserved->interruptStatisticsArray);
9096
9097 /*
9098 * If there is no existing entry, we are most likely trying to
9099 * free an interrupt owner twice, or we have corrupted the
9100 * index value.
9101 */
9102 value = reserved->interruptStatisticsArray[source].statistics;
9103
9104 if (!value) {
9105 panic("removeInterruptStatistics called for empty index %d", source);
9106 }
9107
9108 /*
9109 * We update the statistics, so that any delta with the reporter
9110 * state is not lost.
9111 */
9112 interruptAccountingDataUpdateChannels(reserved->interruptStatisticsArray[source].statistics, reserved->interruptStatisticsArray[source].reporter);
9113 reserved->interruptStatisticsArray[source].statistics = NULL;
9114 IOLockUnlock(&reserved->interruptStatisticsLock);
9115
9116 return kIOReturnSuccess;
9117 }
9118
9119 IOReturn
getInterruptType(int source,int * interruptType)9120 IOService::getInterruptType(int source, int *interruptType)
9121 {
9122 IOInterruptController *interruptController;
9123 IOReturn ret;
9124
9125 ret = lookupInterrupt(source, true, &interruptController);
9126 if (ret != kIOReturnSuccess) {
9127 return ret;
9128 }
9129
9130 /* Return the type */
9131 return interruptController->getInterruptType(this, source, interruptType);
9132 }
9133
9134 IOReturn
enableInterrupt(int source)9135 IOService::enableInterrupt(int source)
9136 {
9137 IOInterruptController *interruptController;
9138 IOReturn ret;
9139
9140 ret = lookupInterrupt(source, false, &interruptController);
9141 if (ret != kIOReturnSuccess) {
9142 return ret;
9143 }
9144
9145 /* Enable the source */
9146 return interruptController->enableInterrupt(this, source);
9147 }
9148
9149 IOReturn
disableInterrupt(int source)9150 IOService::disableInterrupt(int source)
9151 {
9152 IOInterruptController *interruptController;
9153 IOReturn ret;
9154
9155 ret = lookupInterrupt(source, false, &interruptController);
9156 if (ret != kIOReturnSuccess) {
9157 return ret;
9158 }
9159
9160 /* Disable the source */
9161 return interruptController->disableInterrupt(this, source);
9162 }
9163
9164 IOReturn
causeInterrupt(int source)9165 IOService::causeInterrupt(int source)
9166 {
9167 IOInterruptController *interruptController;
9168 IOReturn ret;
9169
9170 ret = lookupInterrupt(source, false, &interruptController);
9171 if (ret != kIOReturnSuccess) {
9172 return ret;
9173 }
9174
9175 /* Cause an interrupt for the source */
9176 return interruptController->causeInterrupt(this, source);
9177 }
9178
9179 IOReturn
configureReport(IOReportChannelList * channelList,IOReportConfigureAction action,void * result,void * destination)9180 IOService::configureReport(IOReportChannelList *channelList,
9181 IOReportConfigureAction action,
9182 void *result,
9183 void *destination)
9184 {
9185 unsigned cnt;
9186
9187 for (cnt = 0; cnt < channelList->nchannels; cnt++) {
9188 if (channelList->channels[cnt].channel_id == kPMPowerStatesChID) {
9189 if (pwrMgt) {
9190 configurePowerStatesReport(action, result);
9191 } else {
9192 return kIOReturnUnsupported;
9193 }
9194 } else if (channelList->channels[cnt].channel_id == kPMCurrStateChID) {
9195 if (pwrMgt) {
9196 configureSimplePowerReport(action, result);
9197 } else {
9198 return kIOReturnUnsupported;
9199 }
9200 }
9201 }
9202
9203 IOLockLock(&reserved->interruptStatisticsLock);
9204
9205 /* The array count is signed (because the interrupt indices are signed), hence the cast */
9206 for (cnt = 0; cnt < (unsigned) reserved->interruptStatisticsArrayCount; cnt++) {
9207 if (reserved->interruptStatisticsArray[cnt].reporter) {
9208 /*
9209 * If the reporter is currently associated with the statistics
9210 * for an event source, we may need to update the reporter.
9211 */
9212 if (reserved->interruptStatisticsArray[cnt].statistics) {
9213 interruptAccountingDataUpdateChannels(reserved->interruptStatisticsArray[cnt].statistics, reserved->interruptStatisticsArray[cnt].reporter);
9214 }
9215
9216 reserved->interruptStatisticsArray[cnt].reporter->configureReport(channelList, action, result, destination);
9217 }
9218 }
9219
9220 IOLockUnlock(&reserved->interruptStatisticsLock);
9221
9222 if (hasUserServer()) {
9223 return _ConfigureReport(channelList, action, result, destination);
9224 } else {
9225 return kIOReturnSuccess;
9226 }
9227 }
9228
9229 IOReturn
updateReport(IOReportChannelList * channelList,IOReportUpdateAction action,void * result,void * destination)9230 IOService::updateReport(IOReportChannelList *channelList,
9231 IOReportUpdateAction action,
9232 void *result,
9233 void *destination)
9234 {
9235 unsigned cnt;
9236
9237 for (cnt = 0; cnt < channelList->nchannels; cnt++) {
9238 if (channelList->channels[cnt].channel_id == kPMPowerStatesChID) {
9239 if (pwrMgt) {
9240 updatePowerStatesReport(action, result, destination);
9241 } else {
9242 return kIOReturnUnsupported;
9243 }
9244 } else if (channelList->channels[cnt].channel_id == kPMCurrStateChID) {
9245 if (pwrMgt) {
9246 updateSimplePowerReport(action, result, destination);
9247 } else {
9248 return kIOReturnUnsupported;
9249 }
9250 }
9251 }
9252
9253 IOLockLock(&reserved->interruptStatisticsLock);
9254
9255 /* The array count is signed (because the interrupt indices are signed), hence the cast */
9256 for (cnt = 0; cnt < (unsigned) reserved->interruptStatisticsArrayCount; cnt++) {
9257 if (reserved->interruptStatisticsArray[cnt].reporter) {
9258 /*
9259 * If the reporter is currently associated with the statistics
9260 * for an event source, we need to update the reporter.
9261 */
9262 if (reserved->interruptStatisticsArray[cnt].statistics) {
9263 interruptAccountingDataUpdateChannels(reserved->interruptStatisticsArray[cnt].statistics, reserved->interruptStatisticsArray[cnt].reporter);
9264 }
9265
9266 reserved->interruptStatisticsArray[cnt].reporter->updateReport(channelList, action, result, destination);
9267 }
9268 }
9269
9270 IOLockUnlock(&reserved->interruptStatisticsLock);
9271
9272
9273 if (hasUserServer()) {
9274 return _UpdateReport(channelList, action, result, destination);
9275 } else {
9276 return kIOReturnSuccess;
9277 }
9278 }
9279
9280 uint64_t
getAuthorizationID(void)9281 IOService::getAuthorizationID( void )
9282 {
9283 return reserved->authorizationID;
9284 }
9285
9286 IOReturn
setAuthorizationID(uint64_t authorizationID)9287 IOService::setAuthorizationID( uint64_t authorizationID )
9288 {
9289 OSObject * entitlement;
9290 IOReturn status;
9291
9292 entitlement = IOUserClient::copyClientEntitlement( current_task(), "com.apple.private.iokit.IOServiceSetAuthorizationID" );
9293
9294 if (entitlement) {
9295 if (entitlement == kOSBooleanTrue) {
9296 reserved->authorizationID = authorizationID;
9297
9298 status = kIOReturnSuccess;
9299 } else {
9300 status = kIOReturnNotPrivileged;
9301 }
9302
9303 entitlement->release();
9304 } else {
9305 status = kIOReturnNotPrivileged;
9306 }
9307
9308 return status;
9309 }
9310
9311 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9312
9313 #if __LP64__
9314 OSMetaClassDefineReservedUsedX86(IOService, 0);
9315 OSMetaClassDefineReservedUsedX86(IOService, 1);
9316 OSMetaClassDefineReservedUnused(IOService, 2);
9317 OSMetaClassDefineReservedUnused(IOService, 3);
9318 OSMetaClassDefineReservedUnused(IOService, 4);
9319 OSMetaClassDefineReservedUnused(IOService, 5);
9320 OSMetaClassDefineReservedUnused(IOService, 6);
9321 OSMetaClassDefineReservedUnused(IOService, 7);
9322 #else
9323 OSMetaClassDefineReservedUsedX86(IOService, 0);
9324 OSMetaClassDefineReservedUsedX86(IOService, 1);
9325 OSMetaClassDefineReservedUsedX86(IOService, 2);
9326 OSMetaClassDefineReservedUsedX86(IOService, 3);
9327 OSMetaClassDefineReservedUsedX86(IOService, 4);
9328 OSMetaClassDefineReservedUsedX86(IOService, 5);
9329 OSMetaClassDefineReservedUsedX86(IOService, 6);
9330 OSMetaClassDefineReservedUsedX86(IOService, 7);
9331 #endif
9332 OSMetaClassDefineReservedUnused(IOService, 8);
9333 OSMetaClassDefineReservedUnused(IOService, 9);
9334 OSMetaClassDefineReservedUnused(IOService, 10);
9335 OSMetaClassDefineReservedUnused(IOService, 11);
9336 OSMetaClassDefineReservedUnused(IOService, 12);
9337 OSMetaClassDefineReservedUnused(IOService, 13);
9338 OSMetaClassDefineReservedUnused(IOService, 14);
9339 OSMetaClassDefineReservedUnused(IOService, 15);
9340 OSMetaClassDefineReservedUnused(IOService, 16);
9341 OSMetaClassDefineReservedUnused(IOService, 17);
9342 OSMetaClassDefineReservedUnused(IOService, 18);
9343 OSMetaClassDefineReservedUnused(IOService, 19);
9344 OSMetaClassDefineReservedUnused(IOService, 20);
9345 OSMetaClassDefineReservedUnused(IOService, 21);
9346 OSMetaClassDefineReservedUnused(IOService, 22);
9347 OSMetaClassDefineReservedUnused(IOService, 23);
9348 OSMetaClassDefineReservedUnused(IOService, 24);
9349 OSMetaClassDefineReservedUnused(IOService, 25);
9350 OSMetaClassDefineReservedUnused(IOService, 26);
9351 OSMetaClassDefineReservedUnused(IOService, 27);
9352 OSMetaClassDefineReservedUnused(IOService, 28);
9353 OSMetaClassDefineReservedUnused(IOService, 29);
9354 OSMetaClassDefineReservedUnused(IOService, 30);
9355 OSMetaClassDefineReservedUnused(IOService, 31);
9356 OSMetaClassDefineReservedUnused(IOService, 32);
9357 OSMetaClassDefineReservedUnused(IOService, 33);
9358 OSMetaClassDefineReservedUnused(IOService, 34);
9359 OSMetaClassDefineReservedUnused(IOService, 35);
9360 OSMetaClassDefineReservedUnused(IOService, 36);
9361 OSMetaClassDefineReservedUnused(IOService, 37);
9362 OSMetaClassDefineReservedUnused(IOService, 38);
9363 OSMetaClassDefineReservedUnused(IOService, 39);
9364 OSMetaClassDefineReservedUnused(IOService, 40);
9365 OSMetaClassDefineReservedUnused(IOService, 41);
9366 OSMetaClassDefineReservedUnused(IOService, 42);
9367 OSMetaClassDefineReservedUnused(IOService, 43);
9368 OSMetaClassDefineReservedUnused(IOService, 44);
9369 OSMetaClassDefineReservedUnused(IOService, 45);
9370 OSMetaClassDefineReservedUnused(IOService, 46);
9371 OSMetaClassDefineReservedUnused(IOService, 47);
9372