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