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