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