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