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