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