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 assertionActive = gIOPMRootDomain->acquireDriverKitMatchingAssertion() == kIOReturnSuccess;
4470
4471 lock();
4472 bool matchNow = !fSystemOff && assertionActive;
4473 if (matchNow) {
4474 idx = fMatchingWork->getNextIndexOfObject(service, 0);
4475 if (idx == -1U) {
4476 fMatchingWork->setObject(service);
4477 }
4478 } else {
4479 // Delay matching if system is transitioning to sleep
4480 if (!fMatchingDelayed) {
4481 fMatchingDelayed = OSArray::withObjects((const OSObject **) &service, 1, 1);
4482 } else {
4483 idx = fMatchingDelayed->getNextIndexOfObject(service, 0);
4484 if (idx == -1U) {
4485 fMatchingDelayed->setObject(service);
4486 }
4487 }
4488 }
4489 unlock();
4490 if (!matchNow && assertionActive) {
4491 gIOPMRootDomain->releaseDriverKitMatchingAssertion();
4492 }
4493
4494 return matchNow;
4495 }
4496
4497 void
matchingEnd(IOService * service)4498 IOServicePH::matchingEnd(IOService * service)
4499 {
4500 uint32_t idx;
4501 OSArray * notifyServers;
4502 OSArray * deferredMatches;
4503
4504 notifyServers = NULL;
4505 deferredMatches = NULL;
4506
4507 if (service) {
4508 gIOPMRootDomain->releaseDriverKitMatchingAssertion();
4509 }
4510
4511 lock();
4512
4513 if (service) {
4514 idx = fMatchingWork->getNextIndexOfObject(service, 0);
4515 if (idx != -1U) {
4516 fMatchingWork->removeObject(idx);
4517 }
4518 }
4519
4520
4521 if ((fUserServerOff != fSystemOff) && fUserServers->getCount()) {
4522 if (fSystemOff) {
4523 if (0 == fMatchingWork->getCount()) {
4524 fUserServersWait = OSArray::withArray(fUserServers);
4525 notifyServers = OSArray::withArray(fUserServers);
4526 fUserServerOff = fSystemOff;
4527 }
4528 } else {
4529 notifyServers = OSArray::withArray(fUserServers);
4530 fUserServerOff = fSystemOff;
4531 }
4532 }
4533
4534 if (!fSystemOff && fMatchingDelayed) {
4535 deferredMatches = fMatchingDelayed;
4536 fMatchingDelayed = NULL;
4537 }
4538
4539 unlock();
4540
4541 if (notifyServers) {
4542 notifyServers->iterateObjects(^bool (OSObject * obj) {
4543 IOUserServer * us;
4544 us = (typeof(us))obj;
4545 us->systemPower(fSystemOff);
4546 return false;
4547 });
4548 OSSafeReleaseNULL(notifyServers);
4549 }
4550
4551 if (deferredMatches) {
4552 DKLOG("sleep deferred rematching count %d\n", deferredMatches->getCount());
4553 deferredMatches->iterateObjects(^bool (OSObject * obj)
4554 {
4555 ((IOService *)obj)->startMatching(kIOServiceAsynchronous);
4556 return false;
4557 });
4558 deferredMatches->release();
4559 }
4560
4561 serverAck(NULL);
4562 }
4563
4564 TUNABLE(uint32_t, dk_shutdown_timeout_ms, "dk_shutdown_timeout_ms", 5000);
4565 TUNABLE(bool, dk_panic_on_shutdown_hang, "dk_panic_on_shutdown_hang", false);
4566 TUNABLE(bool, dk_panic_on_setpowerstate_hang, "dk_panic_on_setpowerstate_hang", false);
4567
4568 void
userServerAckTimerExpired(void *,void *)4569 IOServicePH::userServerAckTimerExpired(void *, void *)
4570 {
4571 OSArray * userServers = NULL;
4572 lock();
4573 if (fSystemPowerAckTo) {
4574 DKLOG("ack timer expired\n");
4575 if (dk_panic_on_setpowerstate_hang) {
4576 panic("DK ack timer expired after %u ms", dk_shutdown_timeout_ms);
4577 }
4578 userServers = fUserServersWait;
4579 fUserServersWait = NULL;
4580 }
4581 unlock();
4582
4583 if (userServers != NULL) {
4584 userServers->iterateObjects(^bool (OSObject *obj) {
4585 IOUserServer * us = OSDynamicCast(IOUserServer, obj);
4586 if (us) {
4587 DKLOG(DKS " power state transition failed\n", DKN(us));
4588 us->setPowerManagementFailed(true);
4589 }
4590 return false;
4591 });
4592 OSSafeReleaseNULL(userServers);
4593 }
4594
4595 serverAck(NULL);
4596 }
4597
4598 void
systemHalt(int howto)4599 IOServicePH::systemHalt(int howto)
4600 {
4601 OSArray * notifyServers;
4602 uint64_t deadline;
4603
4604 lock();
4605 notifyServers = OSArray::withArray(fUserServers);
4606 unlock();
4607
4608 if (notifyServers) {
4609 notifyServers->iterateObjects(^bool (OSObject * obj) {
4610 IOUserServer * us;
4611 us = (typeof(us))obj;
4612 us->systemHalt(howto);
4613 return false;
4614 });
4615 OSSafeReleaseNULL(notifyServers);
4616 }
4617
4618 lock();
4619 clock_interval_to_deadline(dk_shutdown_timeout_ms, kMillisecondScale, &deadline);
4620 while (0 < fUserServers->getCount()) {
4621 fWaitingUserServers = true;
4622 __assert_only int waitResult =
4623 IOLockSleepDeadline(gJobsLock, &fWaitingUserServers, deadline, THREAD_UNINT);
4624 assert((THREAD_AWAKENED == waitResult) || (THREAD_TIMED_OUT == waitResult));
4625 if (THREAD_TIMED_OUT == waitResult) {
4626 IOUserServer::beginLeakingObjects();
4627 #if DEVELOPMENT || DEBUG
4628 if (dk_panic_on_shutdown_hang) {
4629 panic("Shutdown timed out waiting for DK drivers to stop");
4630 }
4631 #endif /* DEVELOPMENT || DEBUG */
4632 break;
4633 }
4634 }
4635 unlock();
4636 }
4637
4638 bool
serverSlept(void)4639 IOServicePH::serverSlept(void)
4640 {
4641 bool ret;
4642
4643 lock();
4644 ret = (kIOMessageSystemWillSleep == sSystemPower)
4645 || (kIOMessageSystemWillPowerOff == sSystemPower)
4646 || (kIOMessageSystemWillRestart == sSystemPower);
4647 unlock();
4648
4649 return ret;
4650 }
4651
4652 TUNABLE(uint32_t, dk_power_state_timeout_ms, "dk_power_state_timeout_ms", 30000);
4653
4654 IOReturn
systemPowerChange(void * target,void * refCon,UInt32 messageType,IOService * service,void * messageArgument,vm_size_t argSize)4655 IOServicePH::systemPowerChange(
4656 void * target,
4657 void * refCon,
4658 UInt32 messageType, IOService * service,
4659 void * messageArgument, vm_size_t argSize)
4660 {
4661 IOReturn ret;
4662 IOUserServer * us;
4663 IOPMSystemCapabilityChangeParameters * params;
4664 AbsoluteTime deadline;
4665
4666 us = NULL;
4667
4668 switch (messageType) {
4669 case kIOMessageSystemCapabilityChange:
4670
4671 params = (typeof params)messageArgument;
4672
4673 if (kIODKLogPM & gIODKDebug) {
4674 IOLog("IOServicePH::kIOMessageSystemCapabilityChange: %s%s 0x%x->0x%x\n",
4675 params->changeFlags & kIOPMSystemCapabilityWillChange ? "will" : "",
4676 params->changeFlags & kIOPMSystemCapabilityDidChange ? "did" : "",
4677 params->fromCapabilities,
4678 params->toCapabilities);
4679 }
4680
4681 if ((params->changeFlags & kIOPMSystemCapabilityWillChange) &&
4682 (params->fromCapabilities & kIOPMSystemCapabilityCPU) &&
4683 ((params->toCapabilities & kIOPMSystemCapabilityCPU) == 0)) {
4684 lock();
4685 DKLOG("arming ack timer, %u ms\n", dk_power_state_timeout_ms);
4686 clock_interval_to_deadline(dk_power_state_timeout_ms, kMillisecondScale, &deadline);
4687 fSystemOff = true;
4688 fSystemPowerAckRef = params->notifyRef;
4689 fSystemPowerAckTo = service;
4690 thread_call_enter_delayed(fUserServerAckTimer, deadline);
4691 unlock();
4692
4693 matchingEnd(NULL);
4694
4695 params->maxWaitForReply = dk_power_state_timeout_ms * 2 * 1000;
4696 ret = kIOReturnSuccess;
4697 } else if ((params->changeFlags & kIOPMSystemCapabilityWillChange) &&
4698 ((params->fromCapabilities & kIOPMSystemCapabilityCPU) == 0) &&
4699 (params->toCapabilities & kIOPMSystemCapabilityCPU)) {
4700 lock();
4701 fSystemOff = false;
4702 unlock();
4703
4704 matchingEnd(NULL);
4705
4706 params->maxWaitForReply = 0;
4707 ret = kIOReturnSuccess;
4708 } else {
4709 params->maxWaitForReply = 0;
4710 ret = kIOReturnSuccess;
4711 }
4712 break;
4713
4714 default:
4715 ret = kIOReturnUnsupported;
4716 break;
4717 }
4718
4719 return ret;
4720 }
4721
4722 bool
checkPMReady(void)4723 IOServicePH::checkPMReady(void)
4724 {
4725 bool __block ready = true;
4726
4727 lock();
4728 fUserServers->iterateObjects(^bool (OSObject *obj) {
4729 IOUserServer * us = OSDynamicCast(IOUserServer, obj);
4730 if (us) {
4731 if (!us->checkPMReady()) {
4732 ready = false;
4733 return true;
4734 }
4735 }
4736 return false;
4737 });
4738 unlock();
4739
4740 return ready;
4741 }
4742
4743 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
4744
4745 /*
4746 * Start a previously attached & probed instance,
4747 * called on exporting object instance
4748 */
4749
4750 bool
startCandidate(IOService * service)4751 IOService::startCandidate( IOService * service )
4752 {
4753 bool ok;
4754 OSObject * obj;
4755 OSObject * prop;
4756 IOUserServer * userServer;
4757 bool ph;
4758
4759 userServer = NULL;
4760 obj = service->copyProperty(gIOUserServerNameKey);
4761
4762 if (obj && (this == gIOResources)) {
4763 ok = false;
4764 } else {
4765 ok = service->attach( this );
4766 }
4767 if (!ok) {
4768 OSSafeReleaseNULL(obj);
4769 return false;
4770 }
4771
4772 if ((this != gIOResources) && (this != gIOUserResources)) {
4773 // stall for any nub resources
4774 checkResources();
4775 // stall for any driver resources
4776 service->checkResources();
4777 }
4778 ph = false;
4779 {
4780 OSString * bundleID;
4781 OSString * serverName;
4782 OSString * str;
4783 const OSSymbol * sym;
4784 OSNumber * serverTag;
4785 uint64_t entryID;
4786 IOUserServerCheckInToken * token;
4787 OSData * serverDUI;
4788
4789 if ((serverName = OSDynamicCast(OSString, obj))) {
4790 obj = service->copyProperty(gIOModuleIdentifierKey);
4791 bundleID = OSDynamicCast(OSString, obj);
4792 entryID = service->getRegistryEntryID();
4793 serverTag = OSNumber::withNumber(entryID, 64);
4794 token = NULL;
4795
4796 if (kIODKDisableDextLaunch & gIODKDebug) {
4797 DKLOG(DKS " dext launches are disabled \n", DKN(service));
4798 service->detach(this);
4799 OSSafeReleaseNULL(serverName);
4800 OSSafeReleaseNULL(obj);
4801 OSSafeReleaseNULL(serverTag);
4802 return false;
4803 }
4804
4805 if (gIOKitWillTerminate) {
4806 DKLOG("%s disabled in shutdown\n", serverName->getCStringNoCopy());
4807 service->detach(this);
4808 OSSafeReleaseNULL(serverName);
4809 OSSafeReleaseNULL(obj);
4810 OSSafeReleaseNULL(serverTag);
4811 return false;
4812 }
4813
4814 ph = IOServicePH::matchingStart(this);
4815 if (!ph) {
4816 DKLOG("%s deferred in sleep\n", serverName->getCStringNoCopy());
4817 service->setProperty(gIOServiceMatchDeferredKey, kOSBooleanTrue);
4818 service->detach(this);
4819 OSSafeReleaseNULL(serverName);
4820 OSSafeReleaseNULL(obj);
4821 OSSafeReleaseNULL(serverTag);
4822 return false;
4823 }
4824
4825 prop = service->copyProperty(gIOUserClassKey);
4826 str = OSDynamicCast(OSString, prop);
4827 if (str) {
4828 service->setName(str);
4829 }
4830 OSSafeReleaseNULL(prop);
4831
4832 sym = OSSymbol::withString(serverName);
4833 bool reuse = service->propertyExists(gIOUserServerOneProcessKey);
4834 serverDUI = OSDynamicCast(OSData, service->getProperty(kOSBundleDextUniqueIdentifierKey));
4835 userServer = IOUserServer::launchUserServer(bundleID, sym, serverTag, reuse, &token, serverDUI);
4836 OSSafeReleaseNULL(sym);
4837 OSSafeReleaseNULL(serverTag);
4838 OSSafeReleaseNULL(serverName);
4839 if (userServer) {
4840 DKLOG(DKS " using existing server " DKS "\n", DKN(service), DKN(userServer));
4841 } else if (token != NULL) {
4842 const OSSymbol * tokenServerName = token->copyServerName();
4843 OSNumber * tokenServerTag = token->copyServerTag();
4844 assert(tokenServerName && tokenServerTag);
4845 DKLOG(DKS " waiting for server %s-%llx\n", DKN(service), tokenServerName->getCStringNoCopy(), tokenServerTag->unsigned64BitValue());
4846 userServer = __WAITING_FOR_USER_SERVER__(token);
4847 OSSafeReleaseNULL(tokenServerName);
4848 OSSafeReleaseNULL(tokenServerTag);
4849 } else {
4850 DKLOG(DKS " failed to launch server\n", DKN(service));
4851 }
4852
4853
4854 if (!userServer) {
4855 service->detach(this);
4856 IOServicePH::matchingEnd(this);
4857 OSSafeReleaseNULL(obj);
4858
4859 if (token != NULL) {
4860 DKLOG(DKS " user server timeout\n", DKN(service));
4861 #if DEVELOPMENT || DEBUG
4862 driverkit_checkin_timed_out = mach_absolute_time();
4863 #endif
4864 }
4865
4866 OSSafeReleaseNULL(token);
4867 return false;
4868 }
4869
4870 if (token && !(kIODKDisableCheckInTokenVerification & gIODKDebug)) {
4871 if (!userServer->serviceMatchesCheckInToken(token)) {
4872 OSSafeReleaseNULL(token);
4873 service->detach(this);
4874 IOServicePH::matchingEnd(this);
4875 OSSafeReleaseNULL(obj);
4876 userServer->exit("Check In Token verification failed");
4877 userServer->release();
4878 return false;
4879 }
4880 }
4881 OSSafeReleaseNULL(token);
4882 OSSafeReleaseNULL(obj);
4883
4884 if (!(kIODKDisableEntitlementChecking & gIODKDebug)) {
4885 if (!userServer->checkEntitlements(this, service)) {
4886 service->detach(this);
4887 IOServicePH::matchingEnd(this);
4888 userServer->exit("Entitlements check failed");
4889 userServer->release();
4890 return false;
4891 }
4892 }
4893 #if !XNU_TARGET_OS_OSX && !(DEVELOPMENT || DEBUG)
4894 // Prevent third party drivers from matching IOUserResources/IOResources, except when signed for development
4895 if (!userServer->isPlatformDriver() &&
4896 userServer->getCSValidationCategory() != CS_VALIDATION_CATEGORY_DEVELOPMENT
4897 && (this == gIOUserResources || this == gIOResources)) {
4898 service->detach(this);
4899 IOServicePH::matchingEnd(this);
4900 userServer->exit("Third party driver may only match real hardware");
4901 userServer->release();
4902 return false;
4903 }
4904 #endif /* !XNU_TARGET_OS_OSX && !(DEVELOPMENT || DEBUG) */
4905
4906 userServer->serviceAttach(service, this);
4907 } else {
4908 OSSafeReleaseNULL(obj);
4909 }
4910 }
4911
4912 AbsoluteTime startTime;
4913 AbsoluteTime endTime;
4914 UInt64 nano;
4915 bool recordTime = (kIOLogStart & gIOKitDebug) != 0;
4916
4917 if (recordTime) {
4918 clock_get_uptime(&startTime);
4919 }
4920
4921 ok = service->start(this);
4922
4923 if (recordTime) {
4924 clock_get_uptime(&endTime);
4925
4926 if (CMP_ABSOLUTETIME(&endTime, &startTime) > 0) {
4927 SUB_ABSOLUTETIME(&endTime, &startTime);
4928 absolutetime_to_nanoseconds(endTime, &nano);
4929 if (nano > 500000000ULL) {
4930 IOLog("%s::start took %ld ms\n", service->getName(), (long)(UInt32)(nano / 1000000ULL));
4931 }
4932 }
4933 }
4934 if (userServer) {
4935 userServer->serviceStarted(service, this, ok);
4936 userServer->release();
4937 }
4938
4939 if (ok) {
4940 IOInstallServiceSleepPlatformActions(service);
4941 #if 00
4942 if (!strcmp("XHC1", getName())) {
4943 service->setProperty(gIOPrimaryDriverTerminateOptionsKey, kOSBooleanTrue);
4944 }
4945 #endif
4946 }
4947
4948 if (!ok) {
4949 service->detach( this );
4950 }
4951
4952 if (ph) {
4953 IOServicePH::matchingEnd(this);
4954 }
4955
4956 return ok;
4957 }
4958
4959 void
publishResource(const char * key,OSObject * value)4960 IOService::publishResource( const char * key, OSObject * value )
4961 {
4962 const OSSymbol * sym;
4963
4964 if ((sym = OSSymbol::withCString( key))) {
4965 publishResource( sym, value);
4966 sym->release();
4967 }
4968 }
4969
4970 void
publishResource(const OSSymbol * key,OSObject * value)4971 IOService::publishResource( const OSSymbol * key, OSObject * value )
4972 {
4973 if (NULL == value) {
4974 value = (OSObject *) gIOServiceKey;
4975 }
4976
4977 gIOResources->setProperty( key, value);
4978
4979 if (IORecursiveLockHaveLock( gNotificationLock)) {
4980 return;
4981 }
4982
4983 gIOResourceGenerationCount++;
4984 gIOResources->registerService();
4985 }
4986
4987 void
publishUserResource(const OSSymbol * key,OSObject * value)4988 IOService::publishUserResource( const OSSymbol * key, OSObject * value )
4989 {
4990 if (NULL == value) {
4991 value = (OSObject *) gIOServiceKey;
4992 }
4993
4994 gIOUserResources->setProperty( key, value);
4995
4996 if (IORecursiveLockHaveLock( gNotificationLock)) {
4997 return;
4998 }
4999
5000 gIOResourceGenerationCount++;
5001 gIOUserResources->registerService();
5002 }
5003
5004 bool
addNeededResource(const char * key)5005 IOService::addNeededResource( const char * key )
5006 {
5007 OSObject * resourcesProp;
5008 OSSet * set;
5009 OSString * newKey;
5010 bool ret;
5011
5012 resourcesProp = copyProperty( gIOResourceMatchKey );
5013 if (!resourcesProp) {
5014 return false;
5015 }
5016
5017 newKey = OSString::withCString( key );
5018 if (!newKey) {
5019 resourcesProp->release();
5020 return false;
5021 }
5022
5023 set = OSDynamicCast( OSSet, resourcesProp );
5024 if (!set) {
5025 set = OSSet::withCapacity( 1 );
5026 set->setObject( resourcesProp );
5027 } else {
5028 set->retain();
5029 }
5030
5031 set->setObject( newKey );
5032 newKey->release();
5033 ret = setProperty( gIOResourceMatchKey, set );
5034 set->release();
5035 resourcesProp->release();
5036
5037 return ret;
5038 }
5039
5040 bool
checkResource(OSObject * matching)5041 IOService::checkResource( OSObject * matching )
5042 {
5043 OSString * str;
5044 OSDictionary * table;
5045
5046 if ((str = OSDynamicCast( OSString, matching ))) {
5047 if (gIOResources->getProperty( str )) {
5048 return true;
5049 }
5050 }
5051
5052 if (str) {
5053 table = resourceMatching( str );
5054 } else if ((table = OSDynamicCast( OSDictionary, matching ))) {
5055 table->retain();
5056 } else {
5057 IOLog("%s: Can't match using: %s\n", getName(),
5058 matching->getMetaClass()->getClassName());
5059 /* false would stall forever */
5060 return true;
5061 }
5062
5063 if (gIOKitDebug & kIOLogConfig) {
5064 LOG("config(%p): stalling %s\n", IOSERVICE_OBFUSCATE(IOThreadSelf()), getName());
5065 }
5066
5067 waitForService( table );
5068
5069 if (gIOKitDebug & kIOLogConfig) {
5070 LOG("config(%p): waking\n", IOSERVICE_OBFUSCATE(IOThreadSelf()));
5071 }
5072
5073 return true;
5074 }
5075
5076 bool
checkResources(void)5077 IOService::checkResources( void )
5078 {
5079 OSObject * resourcesProp;
5080 OSSet * set;
5081 OSObject * obj;
5082 OSIterator * iter;
5083 bool ok;
5084
5085 resourcesProp = copyProperty( gIOResourceMatchKey );
5086 if (NULL == resourcesProp) {
5087 return true;
5088 }
5089
5090 if ((set = OSDynamicCast( OSSet, resourcesProp ))) {
5091 iter = OSCollectionIterator::withCollection( set );
5092 ok = (NULL != iter);
5093 while (ok && (obj = iter->getNextObject())) {
5094 ok = checkResource( obj );
5095 }
5096 if (iter) {
5097 iter->release();
5098 }
5099 } else {
5100 ok = checkResource( resourcesProp );
5101 }
5102
5103 OSSafeReleaseNULL(resourcesProp);
5104
5105 return ok;
5106 }
5107
5108
5109 void
configThread(const char * name)5110 _IOConfigThread::configThread( const char * name )
5111 {
5112 _IOConfigThread * inst;
5113
5114 do {
5115 if (!(inst = new _IOConfigThread)) {
5116 continue;
5117 }
5118 if (!inst->init()) {
5119 continue;
5120 }
5121 thread_t thread;
5122 if (KERN_SUCCESS != kernel_thread_start(&_IOConfigThread::main, inst, &thread)) {
5123 continue;
5124 }
5125
5126 char threadName[MAXTHREADNAMESIZE];
5127 snprintf(threadName, sizeof(threadName), "IOConfigThread_'%s'", name);
5128 thread_set_thread_name(thread, threadName);
5129 thread_deallocate(thread);
5130
5131 return;
5132 } while (false);
5133
5134 if (inst) {
5135 inst->release();
5136 }
5137
5138 return;
5139 }
5140
5141 /*
5142 * To support driver replacement of boot matched drivers later in boot, drivers can
5143 * opt-in to be being terminated if a non-boot driver matches their provider, by
5144 * setting the gIOPrimaryDriverTerminateOptionsKey property. The driver providing the
5145 * root disk media may not be terminated.
5146 * IOMedia objects are hidden from user space until all drivers are available, but any
5147 * associated with the root disk must be published immediately.
5148 */
5149
5150 struct FindRootMediaContext {
5151 OSArray * services;
5152 IOService * parent;
5153 };
5154
5155 bool
hasParent(IOService * parent)5156 IOService::hasParent(IOService * parent)
5157 {
5158 IOService * service;
5159
5160 for (service = this;
5161 service && (service != parent);
5162 service = service->getProvider()) {
5163 }
5164
5165 return service != NULL;
5166 }
5167
5168 bool
publishHiddenMediaApplier(const OSObject * entry,void * context)5169 IOService::publishHiddenMediaApplier(const OSObject * entry, void * context)
5170 {
5171 FindRootMediaContext * ctx = (typeof(ctx))context;
5172 IOService * service = (typeof(service))entry;
5173
5174 do {
5175 if (ctx->parent && !service->hasParent(ctx->parent)) {
5176 break;
5177 }
5178 if (ctx->services) {
5179 ctx->services->setObject(service);
5180 } else {
5181 ctx->services = OSArray::withObjects((const OSObject **) &service, 1);
5182 assert(ctx->services);
5183 }
5184 } while (false);
5185
5186 return false;
5187 }
5188
5189 // publish to user space any hidden IOMedia under the 'parent' object, or all
5190 // if 'parent' is NULL
5191
5192 void
publishHiddenMedia(IOService * parent)5193 IOService::publishHiddenMedia(IOService * parent)
5194 {
5195 const OSMetaClass * iomediaClass;
5196 bool wasHiding;
5197
5198 iomediaClass = OSMetaClass::getMetaClassWithName(gIOMediaKey);
5199 assert(iomediaClass);
5200
5201 LOCKWRITENOTIFY();
5202 wasHiding = gIOServiceHideIOMedia;
5203 if (wasHiding && !parent) {
5204 gIOServiceHideIOMedia = false;
5205 }
5206 UNLOCKNOTIFY();
5207
5208 FindRootMediaContext ctx = { .services = NULL, .parent = parent };
5209
5210 if (wasHiding) {
5211 iomediaClass->applyToInstances(publishHiddenMediaApplier, &ctx);
5212 }
5213 if (ctx.services) {
5214 unsigned int idx, notiIdx;
5215 IOService * service;
5216 OSArray * notifiers[3] = {};
5217
5218 for (idx = 0; (service = (IOService *) ctx.services->getObject(idx)); idx++) {
5219 service->lockForArbitration(true);
5220 if (!(kIOServiceUserInvisibleMatchState & service->__state[0])) {
5221 service->unlockForArbitration();
5222 continue;
5223 }
5224 service->__state[0] &= ~kIOServiceUserInvisibleMatchState;
5225 service->__state[1] |= kIOServiceUserUnhidden;
5226 notifiers[0] = service->copyNotifiers(gIOFirstPublishNotification, 0, 0xffffffff);
5227 if (kIOServiceMatchedState & service->__state[0]) {
5228 notifiers[1] = service->copyNotifiers(gIOMatchedNotification, 0, 0xffffffff);
5229 }
5230 if (kIOServiceFirstMatchState & service->__state[0]) {
5231 notifiers[2] = service->copyNotifiers(gIOFirstMatchNotification, 0, 0xffffffff);
5232 }
5233 service->unlockForArbitration();
5234 for (notiIdx = 0; notiIdx < 3; notiIdx++) {
5235 service->invokeNotifiers(¬ifiers[notiIdx]);
5236 }
5237 }
5238 OSSafeReleaseNULL(ctx.services);
5239 }
5240 }
5241
5242 // Find the block storage driver providing the root disk, or NULL if not booting from
5243 // a block device
5244
5245 void
setRootMedia(IOService * root)5246 IOService::setRootMedia(IOService * root)
5247 {
5248 const OSMetaClass * ioblockstoragedriverClass;
5249 bool unhide;
5250
5251 ioblockstoragedriverClass = OSMetaClass::getMetaClassWithName(gIOBlockStorageDriverKey);
5252 assert(ioblockstoragedriverClass);
5253
5254 while (root) {
5255 if (root->metaCast(ioblockstoragedriverClass)) {
5256 break;
5257 }
5258 root = root->getProvider();
5259 }
5260
5261 LOCKWRITENOTIFY();
5262 unhide = (kIOServiceRootMediaParentInvalid == gIOServiceRootMediaParent);
5263 if (unhide) {
5264 gIOServiceRootMediaParent = root;
5265 }
5266 UNLOCKNOTIFY();
5267
5268 if (unhide) {
5269 publishHiddenMedia(root);
5270 }
5271 }
5272
5273 // Check if the driver may be terminated when a later driver could be used instead
5274
5275 bool
canTerminateForReplacement(IOService * client)5276 IOService::canTerminateForReplacement(IOService * client)
5277 {
5278 IOService * parent;
5279
5280 assert(kIOServiceRootMediaParentInvalid != gIOServiceRootMediaParent);
5281
5282 if (!client->propertyExists(gIOPrimaryDriverTerminateOptionsKey)) {
5283 return false;
5284 }
5285 if (!gIOServiceRootMediaParent) {
5286 return false;
5287 }
5288 parent = client;
5289 while (parent && (parent != gIOServiceRootMediaParent)) {
5290 parent = parent->getProvider();
5291 }
5292 if (parent) {
5293 IOLog("Can't replace primary matched driver on root media %s-0x%qx\n",
5294 client->getName(), client->getRegistryEntryID());
5295 return false;
5296 }
5297 return true;
5298 }
5299
5300 void
doServiceMatch(IOOptionBits options)5301 IOService::doServiceMatch( IOOptionBits options )
5302 {
5303 _IOServiceNotifier * notify;
5304 OSIterator * iter;
5305 OSOrderedSet * matches;
5306 OSArray * resourceKeys = NULL;
5307 SInt32 catalogGeneration;
5308 bool keepGuessing = true;
5309 bool reRegistered = true;
5310 bool didRegister;
5311 OSArray * notifiers[2] = {NULL};
5312
5313 // job->nub->deliverNotification( gIOPublishNotification,
5314 // kIOServiceRegisteredState, 0xffffffff );
5315
5316 while (keepGuessing) {
5317 matches = gIOCatalogue->findDrivers( this, &catalogGeneration );
5318 // the matches list should always be created by findDrivers()
5319 if (matches) {
5320 lockForArbitration();
5321 if (0 == (__state[0] & kIOServiceFirstPublishState)) {
5322 getMetaClass()->addInstance(this);
5323 notifiers[0] = copyNotifiers(gIOFirstPublishNotification,
5324 kIOServiceFirstPublishState, 0xffffffff );
5325 }
5326 LOCKREADNOTIFY();
5327 __state[1] &= ~kIOServiceNeedConfigState;
5328 __state[1] |= kIOServiceConfigState | kIOServiceConfigRunning;
5329 didRegister = (0 == (kIOServiceRegisteredState & __state[0]));
5330 __state[0] |= kIOServiceRegisteredState;
5331
5332 if (gIOServiceHideIOMedia
5333 && metaCast(gIOMediaKey)
5334 && !(kIOServiceUserUnhidden & __state[1])
5335 && gIOServiceRootMediaParent
5336 && !hasParent(gIOServiceRootMediaParent)
5337 && propertyExists(gIOPrimaryDriverTerminateOptionsKey, gIOServicePlane)) {
5338 __state[0] |= kIOServiceUserInvisibleMatchState;
5339 }
5340
5341 keepGuessing &= (0 == (__state[0] & kIOServiceInactiveState));
5342 if (reRegistered && keepGuessing) {
5343 iter = OSCollectionIterator::withCollection((OSOrderedSet *)
5344 gNotifications->getObject( gIOPublishNotification ));
5345 if (iter) {
5346 while ((notify = (_IOServiceNotifier *)
5347 iter->getNextObject())) {
5348 if (matchPassive(notify->matching, 0)
5349 && (kIOServiceNotifyEnable & notify->state)) {
5350 matches->setObject( notify );
5351 }
5352 }
5353 iter->release();
5354 }
5355 }
5356
5357 UNLOCKNOTIFY();
5358 unlockForArbitration();
5359 invokeNotifiers(¬ifiers[0]);
5360 if (keepGuessing && matches->getCount() && (kIOReturnSuccess == getResources())) {
5361 if ((this == gIOResources) || (this == gIOUserResources)) {
5362 if (resourceKeys) {
5363 resourceKeys->release();
5364 }
5365 resourceKeys = copyPropertyKeys();
5366 }
5367 probeCandidates( matches );
5368 } else {
5369 matches->release();
5370 }
5371 }
5372
5373 lockForArbitration();
5374 reRegistered = (0 != (__state[1] & kIOServiceNeedConfigState));
5375 keepGuessing =
5376 (reRegistered || (catalogGeneration !=
5377 gIOCatalogue->getGenerationCount()))
5378 && (0 == (__state[0] & kIOServiceInactiveState));
5379
5380 if (keepGuessing) {
5381 unlockForArbitration();
5382 }
5383 }
5384
5385 if ((0 == (__state[0] & kIOServiceInactiveState))
5386 && (0 == (__state[1] & kIOServiceModuleStallState))) {
5387 if (resourceKeys) {
5388 setProperty(gIOResourceMatchedKey, resourceKeys);
5389 }
5390
5391 notifiers[0] = copyNotifiers(gIOMatchedNotification,
5392 kIOServiceMatchedState, 0xffffffff);
5393 if (0 == (__state[0] & kIOServiceFirstMatchState)) {
5394 notifiers[1] = copyNotifiers(gIOFirstMatchNotification,
5395 kIOServiceFirstMatchState, 0xffffffff);
5396 }
5397 }
5398
5399 __state[1] &= ~kIOServiceConfigRunning;
5400 unlockForArbitration();
5401
5402 if (resourceKeys) {
5403 resourceKeys->release();
5404 }
5405
5406 invokeNotifiers(¬ifiers[0]);
5407 invokeNotifiers(¬ifiers[1]);
5408
5409 lockForArbitration();
5410 __state[1] &= ~kIOServiceConfigState;
5411 scheduleTerminatePhase2();
5412
5413 _adjustBusy( -1 );
5414 unlockForArbitration();
5415 }
5416
5417 UInt32
_adjustBusy(SInt32 delta)5418 IOService::_adjustBusy( SInt32 delta )
5419 {
5420 IOService * next;
5421 UInt32 count;
5422 UInt32 result;
5423 bool wasQuiet, nowQuiet, needWake;
5424
5425 next = this;
5426 result = __state[1] & kIOServiceBusyStateMask;
5427
5428 if (delta) {
5429 do {
5430 if (next != this) {
5431 next->lockForArbitration();
5432 }
5433 count = next->__state[1] & kIOServiceBusyStateMask;
5434 wasQuiet = (0 == count);
5435 if (((delta < 0) && wasQuiet) || ((delta > 0) && (kIOServiceBusyMax == count))) {
5436 OSReportWithBacktrace("%s: bad busy count (%d,%d)\n", next->getName(), (uint32_t)count, (int)delta);
5437 } else {
5438 count += delta;
5439 }
5440 next->__state[1] = (next->__state[1] & ~kIOServiceBusyStateMask) | count;
5441 nowQuiet = (0 == count);
5442 needWake = (0 != (kIOServiceBusyWaiterState & next->__state[1]));
5443
5444 if (needWake) {
5445 next->__state[1] &= ~kIOServiceBusyWaiterState;
5446 IOLockLock( gIOServiceBusyLock );
5447 thread_wakeup((event_t) next);
5448 IOLockUnlock( gIOServiceBusyLock );
5449 }
5450 if (next != this) {
5451 next->unlockForArbitration();
5452 }
5453
5454 if ((wasQuiet || nowQuiet)) {
5455 uint64_t regID = next->getRegistryEntryID();
5456 IOServiceTrace(
5457 ((wasQuiet /*nowBusy*/) ? IOSERVICE_BUSY : IOSERVICE_NONBUSY),
5458 (uintptr_t) regID,
5459 (uintptr_t) (regID >> 32),
5460 (uintptr_t) next,
5461 0);
5462
5463 if (wasQuiet) {
5464 next->__timeBusy = mach_absolute_time();
5465 } else {
5466 next->__accumBusy += mach_absolute_time() - next->__timeBusy;
5467 next->__timeBusy = 0;
5468 }
5469
5470 MessageClientsContext context;
5471
5472 context.service = next;
5473 context.type = kIOMessageServiceBusyStateChange;
5474 context.argument = (void *) wasQuiet; /*nowBusy*/
5475 context.argSize = 0;
5476
5477 applyToInterestNotifiers( next, gIOBusyInterest,
5478 &messageClientsApplier, &context );
5479
5480 #if !NO_KEXTD
5481 if (nowQuiet && (next == gIOServiceRoot)) {
5482 if (gIOServiceHideIOMedia) {
5483 publishHiddenMedia(NULL);
5484 }
5485
5486 OSKext::considerUnloads();
5487 IOServiceTrace(IOSERVICE_REGISTRY_QUIET, 0, 0, 0, 0);
5488 }
5489 #endif
5490 }
5491
5492 delta = nowQuiet ? -1 : +1;
5493 } while ((wasQuiet || nowQuiet) && (next = next->getProvider()));
5494 }
5495
5496 return result;
5497 }
5498
5499 void
adjustBusy(SInt32 delta)5500 IOService::adjustBusy( SInt32 delta )
5501 {
5502 lockForArbitration();
5503 _adjustBusy( delta );
5504 unlockForArbitration();
5505 }
5506
5507 uint64_t
getAccumulatedBusyTime(void)5508 IOService::getAccumulatedBusyTime( void )
5509 {
5510 uint64_t accumBusy = __accumBusy;
5511 uint64_t timeBusy = __timeBusy;
5512 uint64_t nano;
5513
5514 do{
5515 accumBusy = __accumBusy;
5516 timeBusy = __timeBusy;
5517 if (timeBusy) {
5518 accumBusy += mach_absolute_time() - timeBusy;
5519 }
5520 }while (timeBusy != __timeBusy);
5521
5522 absolutetime_to_nanoseconds(*(AbsoluteTime *)&accumBusy, &nano);
5523
5524 return nano;
5525 }
5526
5527 UInt32
getBusyState(void)5528 IOService::getBusyState( void )
5529 {
5530 return __state[1] & kIOServiceBusyStateMask;
5531 }
5532
5533 IOReturn
waitForState(UInt32 mask,UInt32 value,mach_timespec_t * timeout)5534 IOService::waitForState( UInt32 mask, UInt32 value,
5535 mach_timespec_t * timeout )
5536 {
5537 panic("waitForState");
5538 return kIOReturnUnsupported;
5539 }
5540
5541 IOReturn
waitForState(UInt32 mask,UInt32 value,uint64_t timeout)5542 IOService::waitForState( UInt32 mask, UInt32 value,
5543 uint64_t timeout )
5544 {
5545 bool wait;
5546 int waitResult = THREAD_AWAKENED;
5547 bool computeDeadline = true;
5548 AbsoluteTime abstime;
5549
5550 do {
5551 lockForArbitration();
5552 IOLockLock( gIOServiceBusyLock );
5553 wait = (value != (__state[1] & mask));
5554 if (wait) {
5555 __state[1] |= kIOServiceBusyWaiterState;
5556 unlockForArbitration();
5557 if (timeout != UINT64_MAX) {
5558 if (computeDeadline) {
5559 AbsoluteTime nsinterval;
5560 nanoseconds_to_absolutetime(timeout, &nsinterval );
5561 clock_absolutetime_interval_to_deadline(nsinterval, &abstime);
5562 computeDeadline = false;
5563 }
5564 assert_wait_deadline((event_t)this, THREAD_UNINT, __OSAbsoluteTime(abstime));
5565 } else {
5566 assert_wait((event_t)this, THREAD_UNINT );
5567 }
5568 } else {
5569 unlockForArbitration();
5570 }
5571 IOLockUnlock( gIOServiceBusyLock );
5572 if (wait) {
5573 waitResult = thread_block(THREAD_CONTINUE_NULL);
5574 }
5575 } while (wait && (waitResult != THREAD_TIMED_OUT));
5576
5577 if (waitResult == THREAD_TIMED_OUT) {
5578 return kIOReturnTimeout;
5579 } else {
5580 return kIOReturnSuccess;
5581 }
5582 }
5583
5584 IOReturn
waitQuietWithOptions(uint64_t timeout,IOOptionBits options)5585 IOService::waitQuietWithOptions( uint64_t timeout, IOOptionBits options )
5586 {
5587 IOReturn ret;
5588 uint32_t loops, timeoutExtensions;
5589 char * busyEntriesString = NULL;
5590 char * panicString = NULL;
5591 size_t busyEntriesStringLen;
5592 size_t panicStringLen;
5593 uint64_t time;
5594 uint64_t nano;
5595 bool pendingRequests;
5596 bool registryRootBusy;
5597 bool multipleEntries;
5598 bool dopanic = false;
5599
5600 enum { kIOServiceBusyTimeoutExtensionsMax = 8 };
5601 #if KASAN
5602 /*
5603 * On kasan kernels, everything takes longer, so double the number of
5604 * timeout extensions. This should help with issues like 41259215
5605 * where WindowServer was timing out waiting for kextd to get all the
5606 * kasan kexts loaded and started.
5607 *
5608 * On legacy/x86 systems give a bit more time since we may be
5609 * booting from a HDD.
5610 */
5611 enum { kTimeoutExtensions = 8 };
5612 #define WITH_IOWAITQUIET_EXTENSIONS 1
5613 #elif defined(__x86_64__)
5614 enum { kTimeoutExtensions = 4 };
5615 #define WITH_IOWAITQUIET_EXTENSIONS 1
5616 #elif defined(XNU_TARGET_OS_OSX)
5617 enum { kTimeoutExtensions = 1 };
5618 #define WITH_IOWAITQUIET_EXTENSIONS 1
5619 #else
5620 enum { kTimeoutExtensions = 1 };
5621 #define WITH_IOWAITQUIET_EXTENSIONS 0
5622 #endif
5623
5624 timeoutExtensions = kTimeoutExtensions;
5625 time = mach_absolute_time();
5626 pendingRequests = false;
5627 for (loops = 0; loops < timeoutExtensions; loops++) {
5628 ret = waitForState( kIOServiceBusyStateMask, 0, timeout );
5629
5630 if (loops && (kIOReturnSuccess == ret)) {
5631 time = mach_absolute_time() - time;
5632 absolutetime_to_nanoseconds(*(AbsoluteTime *)&time, &nano);
5633 IOLog("busy extended ok[%d], (%llds, %llds)\n",
5634 loops, timeout / 1000000000ULL, nano / 1000000000ULL);
5635 break;
5636 } else if (kIOReturnTimeout != ret) {
5637 break;
5638 } else if (timeout < (41ull * NSEC_PER_SEC)) {
5639 break;
5640 }
5641
5642 {
5643 IORegistryIterator * iter;
5644 OSOrderedSet * set;
5645 OSOrderedSet * leaves;
5646 IOService * next;
5647 IOService * nextParent;
5648 char * s;
5649 size_t l;
5650 size_t busyEntriesStringRemaining;
5651
5652 busyEntriesStringLen = 256;
5653 panicStringLen = 256;
5654 if (!busyEntriesString) {
5655 busyEntriesString = IONewZeroData(char, busyEntriesStringLen);
5656 assert(busyEntriesString != NULL);
5657 }
5658 if (!panicString) {
5659 panicString = IONewZeroData(char, panicStringLen);
5660 assert(panicString != NULL);
5661 }
5662
5663 set = NULL;
5664 pendingRequests = OSKext::pendingIOKitDaemonRequests();
5665 iter = IORegistryIterator::iterateOver(this, gIOServicePlane, kIORegistryIterateRecursively);
5666 leaves = OSOrderedSet::withCapacity(4);
5667 if (iter) {
5668 set = iter->iterateAll();
5669 }
5670 if (leaves && set) {
5671 busyEntriesString[0] = panicString[0] = 0;
5672 set->setObject(this);
5673 while ((next = (IOService *) set->getLastObject())) {
5674 if (next->getBusyState()) {
5675 if (kIOServiceModuleStallState & next->__state[1]) {
5676 pendingRequests = true;
5677 }
5678 #if defined(XNU_TARGET_OS_OSX)
5679 OSObject * prop;
5680 if ((prop = next->copyProperty(kIOServiceBusyTimeoutExtensionsKey))) {
5681 OSNumber * num;
5682 uint32_t value;
5683 if ((num = OSDynamicCast(OSNumber, prop))) {
5684 value = num->unsigned32BitValue();
5685 if (value
5686 && (value <= kIOServiceBusyTimeoutExtensionsMax)
5687 && (value > timeoutExtensions)) {
5688 timeoutExtensions = value;
5689 }
5690 }
5691 OSSafeReleaseNULL(prop);
5692 }
5693 #endif /* defined(XNU_TARGET_OS_OSX) */
5694 leaves->setObject(next);
5695 nextParent = next;
5696 while ((nextParent = nextParent->getProvider())) {
5697 set->removeObject(nextParent);
5698 leaves->removeObject(nextParent);
5699 }
5700 }
5701 set->removeObject(next);
5702 }
5703 registryRootBusy = leaves->getCount() == 1 && leaves->getObject(0) == getServiceRoot();
5704 multipleEntries = leaves->getCount() > 1;
5705 s = busyEntriesString;
5706 busyEntriesStringRemaining = busyEntriesStringLen;
5707
5708 if (registryRootBusy) {
5709 snprintf(s, busyEntriesStringRemaining, "registry root held busy, " kIOKitDaemonName " %s checked in", OSKext::iokitDaemonActive() ? "has" : "has not");
5710 } else {
5711 while ((next = (IOService *) leaves->getLastObject())) {
5712 l = snprintf(s, busyEntriesStringRemaining, "%s'%s' (%x,%x)", ((s == busyEntriesString) ? "" : ", "), next->getName(), (uint32_t)next->__state[0], (uint32_t)next->__state[1]);
5713 if (l >= busyEntriesStringRemaining) {
5714 break;
5715 }
5716 s += l;
5717 busyEntriesStringRemaining -= l;
5718 leaves->removeObject(next);
5719 }
5720 }
5721 }
5722 OSSafeReleaseNULL(leaves);
5723 OSSafeReleaseNULL(set);
5724 OSSafeReleaseNULL(iter);
5725 }
5726
5727 dopanic = (kIOWaitQuietPanics & gIOKitDebug) && (options & kIOWaitQuietPanicOnFailure);
5728 #if WITH_IOWAITQUIET_EXTENSIONS
5729 dopanic = (dopanic && (loops >= (timeoutExtensions - 1)));
5730 #endif
5731 assert(panicString != NULL);
5732 if (multipleEntries) {
5733 snprintf(panicString, panicStringLen,
5734 "%s[%d], (%llds): multiple entries holding the registry busy, IOKit termination queue depth %u: %s",
5735 pendingRequests ? "IOKit Daemon (" kIOKitDaemonName ") stall" : "busy timeout",
5736 loops, timeout / 1000000000ULL,
5737 (uint32_t)gIOTerminateWork,
5738 busyEntriesString ? busyEntriesString : "");
5739 } else {
5740 snprintf(panicString, panicStringLen,
5741 "%s[%d], (%llds): %s",
5742 pendingRequests ? "IOKit Daemon (" kIOKitDaemonName ") stall" : "busy timeout",
5743 loops, timeout / 1000000000ULL,
5744 busyEntriesString ? busyEntriesString : "");
5745 }
5746
5747 IOLog("%s\n", panicString);
5748 if (dopanic) {
5749 panic("%s", panicString);
5750 } else if (!loops) {
5751 getPMRootDomain()->startSpinDump(1);
5752 }
5753 }
5754
5755 if (busyEntriesString) {
5756 IODeleteData(busyEntriesString, char, busyEntriesStringLen);
5757 }
5758 if (panicString) {
5759 IODeleteData(panicString, char, panicStringLen);
5760 }
5761
5762 return ret;
5763 }
5764
5765 IOReturn
waitQuiet(uint64_t timeout)5766 IOService::waitQuiet( uint64_t timeout )
5767 {
5768 return waitQuietWithOptions(timeout);
5769 }
5770
5771 IOReturn
waitQuiet(mach_timespec_t * timeout)5772 IOService::waitQuiet( mach_timespec_t * timeout )
5773 {
5774 uint64_t timeoutNS;
5775
5776 if (timeout) {
5777 timeoutNS = timeout->tv_sec;
5778 timeoutNS *= kSecondScale;
5779 timeoutNS += timeout->tv_nsec;
5780 } else {
5781 timeoutNS = UINT64_MAX;
5782 }
5783
5784 return waitQuiet(timeoutNS);
5785 }
5786
5787 bool
serializeProperties(OSSerialize * s) const5788 IOService::serializeProperties( OSSerialize * s ) const
5789 {
5790 #if 0
5791 ((IOService *)this)->setProperty(((IOService *)this)->__state,
5792 sizeof(__state), "__state");
5793 #endif
5794 return super::serializeProperties(s);
5795 }
5796
5797 void
resetRematchProperties()5798 IOService::resetRematchProperties()
5799 {
5800 removeProperty(gIORematchCountKey);
5801 removeProperty(gIORematchPersonalityKey);
5802 }
5803
5804
5805 void
main(void * arg,wait_result_t result)5806 _IOConfigThread::main(void * arg, wait_result_t result)
5807 {
5808 _IOConfigThread * self = (_IOConfigThread *) arg;
5809 _IOServiceJob * job;
5810 IOService * nub;
5811 bool alive = true;
5812 kern_return_t kr;
5813 thread_precedence_policy_data_t precedence = { -1 };
5814
5815 kr = thread_policy_set(current_thread(),
5816 THREAD_PRECEDENCE_POLICY,
5817 (thread_policy_t) &precedence,
5818 THREAD_PRECEDENCE_POLICY_COUNT);
5819 if (KERN_SUCCESS != kr) {
5820 IOLog("thread_policy_set(%d)\n", kr);
5821 }
5822
5823 do {
5824 // randomDelay();
5825
5826 semaphore_wait( gJobsSemaphore );
5827
5828 IOTakeLock( gJobsLock );
5829 job = (_IOServiceJob *) gJobs->getFirstObject();
5830 job->retain();
5831 gJobs->removeObject(job);
5832 if (job) {
5833 gOutstandingJobs--;
5834 // gNumConfigThreads--; // we're out of service
5835 gNumWaitingThreads--; // we're out of service
5836 }
5837 IOUnlock( gJobsLock );
5838
5839 if (job) {
5840 nub = job->nub;
5841
5842 if (gIOKitDebug & kIOLogConfig) {
5843 LOG("config(%p): starting on %s, %d\n",
5844 IOSERVICE_OBFUSCATE(IOThreadSelf()), job->nub->getName(), job->type);
5845 }
5846
5847 switch (job->type) {
5848 case kMatchNubJob:
5849 nub->doServiceMatch( job->options );
5850 break;
5851
5852 default:
5853 LOG("config(%p): strange type (%d)\n",
5854 IOSERVICE_OBFUSCATE(IOThreadSelf()), job->type );
5855 break;
5856 }
5857
5858 if (job->options & kIOServiceDextRequirePowerForMatching) {
5859 gIOPMRootDomain->releaseDriverKitMatchingAssertion();
5860 }
5861
5862 OSSafeReleaseNULL(nub);
5863 OSSafeReleaseNULL(job);
5864
5865 IOTakeLock( gJobsLock );
5866 alive = (gOutstandingJobs > gNumWaitingThreads);
5867 if (alive) {
5868 gNumWaitingThreads++; // back in service
5869 }
5870 // gNumConfigThreads++;
5871 else {
5872 if (0 == --gNumConfigThreads) {
5873 // IOLog("MATCH IDLE\n");
5874 IOLockWakeup( gJobsLock, (event_t) &gNumConfigThreads, /* one-thread */ false );
5875 }
5876 }
5877 IOUnlock( gJobsLock );
5878 }
5879 } while (alive);
5880
5881 if (gIOKitDebug & kIOLogConfig) {
5882 LOG("config(%p): terminating\n", IOSERVICE_OBFUSCATE(IOThreadSelf()));
5883 }
5884
5885 self->release();
5886 }
5887
5888 IOReturn
waitMatchIdle(UInt32 msToWait)5889 IOService::waitMatchIdle( UInt32 msToWait )
5890 {
5891 bool wait;
5892 int waitResult = THREAD_AWAKENED;
5893 bool computeDeadline = true;
5894 AbsoluteTime deadline;
5895
5896 IOLockLock( gJobsLock );
5897 do {
5898 wait = (0 != gNumConfigThreads);
5899 if (wait) {
5900 if (msToWait) {
5901 if (computeDeadline) {
5902 clock_interval_to_deadline(
5903 msToWait, kMillisecondScale, &deadline );
5904 computeDeadline = false;
5905 }
5906 waitResult = IOLockSleepDeadline( gJobsLock, &gNumConfigThreads,
5907 deadline, THREAD_UNINT );
5908 } else {
5909 waitResult = IOLockSleep( gJobsLock, &gNumConfigThreads,
5910 THREAD_UNINT );
5911 }
5912 }
5913 } while (wait && (waitResult != THREAD_TIMED_OUT));
5914 IOLockUnlock( gJobsLock );
5915
5916 if (waitResult == THREAD_TIMED_OUT) {
5917 return kIOReturnTimeout;
5918 } else {
5919 return kIOReturnSuccess;
5920 }
5921 }
5922
5923 void
cpusRunning(void)5924 IOService::cpusRunning(void)
5925 {
5926 gCPUsRunning = true;
5927 }
5928
5929 void
pingConfig(_IOServiceJob * job)5930 _IOServiceJob::pingConfig( _IOServiceJob * job )
5931 {
5932 int count;
5933 bool create;
5934 IOService * nub;
5935
5936 assert( job );
5937 nub = job->nub;
5938
5939 IOTakeLock( gJobsLock );
5940
5941 gOutstandingJobs++;
5942 if (nub == gIOResources) {
5943 gJobs->setFirstObject( job );
5944 } else {
5945 gJobs->setLastObject( job );
5946 }
5947
5948 count = gNumWaitingThreads;
5949 // if( gNumConfigThreads) count++;// assume we're called from a config thread
5950
5951 create = ((gOutstandingJobs > count)
5952 && ((gNumConfigThreads < gMaxConfigThreads)
5953 || (nub == gIOResources)
5954 || !gCPUsRunning));
5955 if (create) {
5956 gNumConfigThreads++;
5957 gNumWaitingThreads++;
5958 if (gNumConfigThreads > gHighNumConfigThreads) {
5959 gHighNumConfigThreads = gNumConfigThreads;
5960 }
5961 }
5962
5963 IOUnlock( gJobsLock );
5964
5965 job->release();
5966
5967 if (create) {
5968 if (gIOKitDebug & kIOLogConfig) {
5969 LOG("config(%d): creating\n", gNumConfigThreads - 1);
5970 }
5971 _IOConfigThread::configThread(nub->getName());
5972 }
5973
5974 semaphore_signal( gJobsSemaphore );
5975 }
5976
5977 struct IOServiceMatchContext {
5978 OSDictionary * table;
5979 OSObject * result;
5980 uint32_t options;
5981 uint32_t state;
5982 uint32_t count;
5983 uint32_t done;
5984 };
5985
5986 bool
instanceMatch(const OSObject * entry,void * context)5987 IOService::instanceMatch(const OSObject * entry, void * context)
5988 {
5989 IOServiceMatchContext * ctx = (typeof(ctx))context;
5990 IOService * service = (typeof(service))entry;
5991 OSDictionary * table = ctx->table;
5992 uint32_t options = ctx->options;
5993 uint32_t state = ctx->state;
5994 uint32_t done;
5995 bool match;
5996
5997 done = 0;
5998 do{
5999 match = ((state == (state & service->__state[0]))
6000 && (0 == (service->__state[0] & kIOServiceInactiveState)));
6001 if (!match) {
6002 break;
6003 }
6004
6005 match = service->matchInternal(table, options, &done);
6006 if (match) {
6007 ctx->count += table->getCount();
6008 ctx->done += done;
6009 }
6010 }while (false);
6011 if (!match) {
6012 return false;
6013 }
6014
6015 if ((kIONotifyOnce & options) && (ctx->done == ctx->count)) {
6016 service->retain();
6017 ctx->result = service;
6018 return true;
6019 } else if (!ctx->result) {
6020 ctx->result = OSSet::withObjects((const OSObject **) &service, 1, 1);
6021 } else {
6022 ((OSSet *)ctx->result)->setObject(service);
6023 }
6024 return false;
6025 }
6026
6027 // internal - call with gNotificationLock
6028 OSObject *
copyExistingServices(OSDictionary * matching,IOOptionBits inState,IOOptionBits options)6029 IOService::copyExistingServices( OSDictionary * matching,
6030 IOOptionBits inState, IOOptionBits options )
6031 {
6032 OSObject * current = NULL;
6033 OSIterator * iter;
6034 IOService * service;
6035 OSObject * obj;
6036 OSString * str;
6037
6038 if (!matching) {
6039 return NULL;
6040 }
6041
6042 #if MATCH_DEBUG
6043 OSSerialize * s = OSSerialize::withCapacity(128);
6044 matching->serialize(s);
6045 #endif
6046
6047 if ((obj = matching->getObject(gIOProviderClassKey))
6048 && gIOResourcesKey
6049 && gIOResourcesKey->isEqualTo(obj)
6050 && (service = gIOResources)) {
6051 if ((inState == (service->__state[0] & inState))
6052 && (0 == (service->__state[0] & kIOServiceInactiveState))
6053 && service->matchPassive(matching, options)) {
6054 if (options & kIONotifyOnce) {
6055 service->retain();
6056 current = service;
6057 } else {
6058 current = OSSet::withObjects((const OSObject **) &service, 1, 1 );
6059 }
6060 }
6061 } else {
6062 IOServiceMatchContext ctx;
6063
6064 options |= kIOServiceClassDone;
6065 ctx.table = matching;
6066 ctx.state = inState;
6067 ctx.count = 0;
6068 ctx.done = 0;
6069 ctx.options = options;
6070 ctx.result = NULL;
6071
6072 if ((str = OSDynamicCast(OSString, obj))) {
6073 const OSSymbol * sym = OSSymbol::withString(str);
6074 OSMetaClass::applyToInstancesOfClassName(sym, instanceMatch, &ctx);
6075 sym->release();
6076 } else {
6077 IOService::gMetaClass.applyToInstances(instanceMatch, &ctx);
6078 }
6079
6080 if (((!(options & kIONotifyOnce) || !ctx.result))
6081 && matching->getObject(gIOCompatibilityMatchKey)) {
6082 IOServiceCompatibility::gMetaClass.applyToInstances(instanceMatch, &ctx);
6083 }
6084
6085 current = ctx.result;
6086 options |= kIOServiceInternalDone;
6087 if (current && (ctx.done != ctx.count)) {
6088 OSSet * source = OSDynamicCast(OSSet, current);
6089 current = NULL;
6090 while ((service = (IOService *) source->getAnyObject())) {
6091 if (service->matchPassive(matching, options)) {
6092 if (options & kIONotifyOnce) {
6093 service->retain();
6094 current = service;
6095 break;
6096 }
6097 if (current) {
6098 ((OSSet *)current)->setObject( service );
6099 } else {
6100 current = OSSet::withObjects(
6101 (const OSObject **) &service, 1, 1 );
6102 }
6103 }
6104 source->removeObject(service);
6105 }
6106 source->release();
6107 }
6108 }
6109
6110 #if MATCH_DEBUG
6111 {
6112 OSObject * _current = 0;
6113
6114 iter = IORegistryIterator::iterateOver( gIOServicePlane,
6115 kIORegistryIterateRecursively );
6116 if (iter) {
6117 do {
6118 iter->reset();
6119 while ((service = (IOService *) iter->getNextObject())) {
6120 if ((inState == (service->__state[0] & inState))
6121 && (0 == (service->__state[0] & kIOServiceInactiveState))
6122 && service->matchPassive(matching, 0)) {
6123 if (options & kIONotifyOnce) {
6124 service->retain();
6125 _current = service;
6126 break;
6127 }
6128 if (_current) {
6129 ((OSSet *)_current)->setObject( service );
6130 } else {
6131 _current = OSSet::withObjects(
6132 (const OSObject **) &service, 1, 1 );
6133 }
6134 }
6135 }
6136 } while (!service && !iter->isValid());
6137 iter->release();
6138 }
6139
6140 if (((current != 0) != (_current != 0))
6141 || (current && _current && !current->isEqualTo(_current))) {
6142 OSSerialize * s1 = OSSerialize::withCapacity(128);
6143 OSSerialize * s2 = OSSerialize::withCapacity(128);
6144 current->serialize(s1);
6145 _current->serialize(s2);
6146 kprintf("**mismatch** %p %p\n%s\n%s\n%s\n", IOSERVICE_OBFUSCATE(current),
6147 IOSERVICE_OBFUSCATE(_current), s->text(), s1->text(), s2->text());
6148 s1->release();
6149 s2->release();
6150 }
6151
6152 if (_current) {
6153 _current->release();
6154 }
6155 }
6156
6157 s->release();
6158 #endif
6159
6160 if (current && (0 == (options & (kIONotifyOnce | kIOServiceExistingSet)))) {
6161 iter = OSCollectionIterator::withCollection((OSSet *)current );
6162 current->release();
6163 current = iter;
6164 }
6165
6166 return current;
6167 }
6168
6169 // public version
6170 OSIterator *
getMatchingServices(OSDictionary * matching)6171 IOService::getMatchingServices( OSDictionary * matching )
6172 {
6173 OSIterator * iter;
6174
6175 // is a lock even needed?
6176 LOCKWRITENOTIFY();
6177
6178 iter = (OSIterator *) copyExistingServices( matching,
6179 kIOServiceMatchedState );
6180
6181 UNLOCKNOTIFY();
6182
6183 return iter;
6184 }
6185
6186 IOService *
copyMatchingService(OSDictionary * matching)6187 IOService::copyMatchingService( OSDictionary * matching )
6188 {
6189 IOService * service;
6190
6191 // is a lock even needed?
6192 LOCKWRITENOTIFY();
6193
6194 service = (IOService *) copyExistingServices( matching,
6195 kIOServiceMatchedState, kIONotifyOnce );
6196
6197 UNLOCKNOTIFY();
6198
6199 return service;
6200 }
6201
6202 struct _IOServiceMatchingNotificationHandlerRef {
6203 IOServiceNotificationHandler handler;
6204 void * ref;
6205 };
6206
6207 static bool
_IOServiceMatchingNotificationHandler(void * target,void * refCon,IOService * newService,IONotifier * notifier)6208 _IOServiceMatchingNotificationHandler( void * target, void * refCon,
6209 IOService * newService,
6210 IONotifier * notifier )
6211 {
6212 return (*((_IOServiceNotifier *) notifier)->compatHandler)(target, refCon, newService);
6213 }
6214
6215 // internal - call with gNotificationLock
6216 IONotifier *
setNotification(const OSSymbol * type,OSDictionary * matching,IOServiceMatchingNotificationHandler handler,void * target,void * ref,SInt32 priority)6217 IOService::setNotification(
6218 const OSSymbol * type, OSDictionary * matching,
6219 IOServiceMatchingNotificationHandler handler, void * target, void * ref,
6220 SInt32 priority )
6221 {
6222 _IOServiceNotifier * notify = NULL;
6223 OSOrderedSet * set;
6224
6225 if (!matching) {
6226 return NULL;
6227 }
6228
6229 notify = new _IOServiceNotifier;
6230 if (notify && !notify->init()) {
6231 notify->release();
6232 notify = NULL;
6233 }
6234
6235 if (notify) {
6236 notify->handler = handler;
6237 notify->target = target;
6238 notify->type = type;
6239 notify->matching = matching;
6240 matching->retain();
6241 if (handler == &_IOServiceMatchingNotificationHandler) {
6242 notify->compatHandler = ((_IOServiceMatchingNotificationHandlerRef *)ref)->handler;
6243 notify->ref = ((_IOServiceMatchingNotificationHandlerRef *)ref)->ref;
6244 } else {
6245 notify->ref = ref;
6246 }
6247 notify->priority = priority;
6248 notify->state = kIOServiceNotifyEnable;
6249 queue_init( ¬ify->handlerInvocations );
6250
6251 ////// queue
6252
6253 if (NULL == (set = (OSOrderedSet *) gNotifications->getObject( type ))) {
6254 set = OSOrderedSet::withCapacity( 1,
6255 IONotifyOrdering, NULL );
6256 if (set) {
6257 gNotifications->setObject( type, set );
6258 set->release();
6259 }
6260 }
6261 notify->whence = set;
6262 if (set) {
6263 set->setObject( notify );
6264 }
6265 }
6266
6267 return notify;
6268 }
6269
6270 // internal - call with gNotificationLock
6271 IONotifier *
doInstallNotification(const OSSymbol * type,OSDictionary * matching,IOServiceMatchingNotificationHandler handler,void * target,void * ref,SInt32 priority,OSIterator ** existing)6272 IOService::doInstallNotification(
6273 const OSSymbol * type, OSDictionary * matching,
6274 IOServiceMatchingNotificationHandler handler,
6275 void * target, void * ref,
6276 SInt32 priority, OSIterator ** existing )
6277 {
6278 OSIterator * exist;
6279 IONotifier * notify;
6280 IOOptionBits inState;
6281
6282 if (!matching) {
6283 return NULL;
6284 }
6285
6286 if (type == gIOPublishNotification) {
6287 inState = kIOServiceRegisteredState;
6288 } else if (type == gIOFirstPublishNotification) {
6289 inState = kIOServiceFirstPublishState;
6290 } else if (type == gIOMatchedNotification) {
6291 inState = kIOServiceMatchedState;
6292 } else if (type == gIOFirstMatchNotification) {
6293 inState = kIOServiceFirstMatchState;
6294 } else if ((type == gIOTerminatedNotification) || (type == gIOWillTerminateNotification)) {
6295 inState = 0;
6296 } else {
6297 return NULL;
6298 }
6299
6300 notify = setNotification( type, matching, handler, target, ref, priority );
6301
6302 if (inState) {
6303 // get the current set
6304 exist = (OSIterator *) copyExistingServices( matching, inState );
6305 } else {
6306 exist = NULL;
6307 }
6308
6309 *existing = exist;
6310
6311 return notify;
6312 }
6313
6314 #if !defined(__LP64__)
6315 IONotifier *
installNotification(const OSSymbol * type,OSDictionary * matching,IOServiceNotificationHandler handler,void * target,void * refCon,SInt32 priority,OSIterator ** existing)6316 IOService::installNotification(const OSSymbol * type, OSDictionary * matching,
6317 IOServiceNotificationHandler handler,
6318 void * target, void * refCon,
6319 SInt32 priority, OSIterator ** existing )
6320 {
6321 IONotifier * result;
6322 _IOServiceMatchingNotificationHandlerRef ref;
6323 ref.handler = handler;
6324 ref.ref = refCon;
6325
6326 result = (_IOServiceNotifier *) installNotification( type, matching,
6327 &_IOServiceMatchingNotificationHandler,
6328 target, &ref, priority, existing );
6329 if (result) {
6330 matching->release();
6331 }
6332
6333 return result;
6334 }
6335
6336 #endif /* !defined(__LP64__) */
6337
6338
6339 IONotifier *
installNotification(const OSSymbol * type,OSDictionary * matching,IOServiceMatchingNotificationHandler handler,void * target,void * ref,SInt32 priority,OSIterator ** existing)6340 IOService::installNotification(
6341 const OSSymbol * type, OSDictionary * matching,
6342 IOServiceMatchingNotificationHandler handler,
6343 void * target, void * ref,
6344 SInt32 priority, OSIterator ** existing )
6345 {
6346 IONotifier * notify;
6347
6348 LOCKWRITENOTIFY();
6349
6350 notify = doInstallNotification( type, matching, handler, target, ref,
6351 priority, existing );
6352
6353 // in case handler remove()s
6354 if (notify) {
6355 notify->retain();
6356 }
6357
6358 UNLOCKNOTIFY();
6359
6360 return notify;
6361 }
6362
6363 IONotifier *
addNotification(const OSSymbol * type,OSDictionary * matching,IOServiceNotificationHandler handler,void * target,void * refCon,SInt32 priority)6364 IOService::addNotification(
6365 const OSSymbol * type, OSDictionary * matching,
6366 IOServiceNotificationHandler handler,
6367 void * target, void * refCon,
6368 SInt32 priority )
6369 {
6370 IONotifier * result;
6371 _IOServiceMatchingNotificationHandlerRef ref;
6372
6373 ref.handler = handler;
6374 ref.ref = refCon;
6375
6376 result = addMatchingNotification(type, matching, &_IOServiceMatchingNotificationHandler,
6377 target, &ref, priority);
6378
6379 if (result) {
6380 matching->release();
6381 }
6382
6383 return result;
6384 }
6385
6386 IONotifier *
addMatchingNotification(const OSSymbol * type,OSDictionary * matching,IOServiceMatchingNotificationHandler handler,void * target,void * ref,SInt32 priority)6387 IOService::addMatchingNotification(
6388 const OSSymbol * type, OSDictionary * matching,
6389 IOServiceMatchingNotificationHandler handler,
6390 void * target, void * ref,
6391 SInt32 priority )
6392 {
6393 OSIterator * existing = NULL;
6394 IONotifier * ret;
6395 _IOServiceNotifier * notify;
6396 IOService * next;
6397
6398 ret = notify = (_IOServiceNotifier *) installNotification( type, matching,
6399 handler, target, ref, priority, &existing );
6400 if (!ret) {
6401 OSSafeReleaseNULL(existing);
6402 return NULL;
6403 }
6404
6405 // send notifications for existing set
6406 if (existing) {
6407 while ((next = (IOService *) existing->getNextObject())) {
6408 if (0 == (next->__state[0] & kIOServiceInactiveState)) {
6409 next->invokeNotifier( notify );
6410 }
6411 }
6412 existing->release();
6413 }
6414
6415 LOCKWRITENOTIFY();
6416 bool removed = (NULL == notify->whence);
6417 notify->release();
6418 if (removed) {
6419 ret = gIOServiceNullNotifier;
6420 }
6421 UNLOCKNOTIFY();
6422
6423 return ret;
6424 }
6425
6426 static bool
IOServiceMatchingNotificationHandlerToBlock(void * target __unused,void * refCon,IOService * newService,IONotifier * notifier)6427 IOServiceMatchingNotificationHandlerToBlock( void * target __unused, void * refCon,
6428 IOService * newService,
6429 IONotifier * notifier )
6430 {
6431 return ((IOServiceMatchingNotificationHandlerBlock) refCon)(newService, notifier);
6432 }
6433
6434 IONotifier *
addMatchingNotification(const OSSymbol * type,OSDictionary * matching,SInt32 priority,IOServiceMatchingNotificationHandlerBlock handler)6435 IOService::addMatchingNotification(
6436 const OSSymbol * type, OSDictionary * matching,
6437 SInt32 priority,
6438 IOServiceMatchingNotificationHandlerBlock handler)
6439 {
6440 IONotifier * notify;
6441 void * block;
6442
6443 block = Block_copy(handler);
6444 if (!block) {
6445 return NULL;
6446 }
6447
6448 notify = addMatchingNotification(type, matching,
6449 &IOServiceMatchingNotificationHandlerToBlock, NULL, block, priority);
6450
6451 if (!notify) {
6452 Block_release(block);
6453 }
6454
6455 return notify;
6456 }
6457
6458 struct IOUserServerCancellationHandlerArgs {
6459 IOService ** ref;
6460 bool canceled;
6461 };
6462
6463 void
userServerCheckInTokenCancellationHandler(__unused IOUserServerCheckInToken * token,void * ref)6464 IOService::userServerCheckInTokenCancellationHandler(
6465 __unused IOUserServerCheckInToken *token,
6466 void *ref)
6467 {
6468 IOUserServerCancellationHandlerArgs * args = (typeof(args))ref;
6469 LOCKWRITENOTIFY();
6470 WAKEUPNOTIFY(args->ref);
6471 args->canceled = true;
6472 UNLOCKNOTIFY();
6473 }
6474
6475 bool
syncNotificationHandler(void *,void * ref,IOService * newService,IONotifier * notifier)6476 IOService::syncNotificationHandler(
6477 void * /* target */, void * ref,
6478 IOService * newService,
6479 IONotifier * notifier )
6480 {
6481 LOCKWRITENOTIFY();
6482 if (!*((IOService **) ref)) {
6483 newService->retain();
6484 (*(IOService **) ref) = newService;
6485 WAKEUPNOTIFY(ref);
6486 }
6487 UNLOCKNOTIFY();
6488
6489 return false;
6490 }
6491
6492 IOService *
waitForMatchingServiceWithToken(OSDictionary * matching,uint64_t timeout,IOUserServerCheckInToken * checkInToken)6493 IOService::waitForMatchingServiceWithToken( OSDictionary * matching,
6494 uint64_t timeout,
6495 IOUserServerCheckInToken * checkInToken)
6496 {
6497 IONotifier * notify = NULL;
6498 // priority doesn't help us much since we need a thread wakeup
6499 SInt32 priority = 0;
6500 IOService * result;
6501 IOUserServerCancellationHandlerArgs cancelArgs;
6502 _IOUserServerCheckInCancellationHandler * cancellationHandler = NULL;
6503
6504 if (!matching) {
6505 return NULL;
6506 }
6507
6508 result = NULL;
6509 cancelArgs.ref = &result;
6510 cancelArgs.canceled = false;
6511
6512 #if DEBUG || DEVELOPMENT
6513 char currentName[MAXTHREADNAMESIZE];
6514 char newName[MAXTHREADNAMESIZE];
6515 OSObject * obj;
6516 OSString * str;
6517 OSDictionary * dict;
6518
6519 currentName[0] = '\0';
6520 if (thread_has_thread_name(current_thread())) {
6521 dict = matching;
6522 obj = matching->getObject(gIOPropertyMatchKey);
6523 if ((dict = OSDynamicCast(OSDictionary, obj))) {
6524 OSObject * result __block = NULL;
6525 dict->iterateObjects(^bool (const OSSymbol * sym, OSObject * value) {
6526 result = __DECONST(OSObject *, sym);
6527 return true;
6528 });
6529 obj = result;
6530 }
6531 if (!obj) {
6532 obj = matching->getObject(gIOResourceMatchKey);
6533 }
6534 if (!obj) {
6535 obj = matching->getObject(gIONameMatchKey);
6536 }
6537 if (!obj) {
6538 obj = matching->getObject(gIOProviderClassKey);
6539 }
6540 if ((str = OSDynamicCast(OSString, obj))) {
6541 thread_get_thread_name(current_thread(), currentName);
6542 snprintf(newName, sizeof(newName), "Waiting_'%s'", str->getCStringNoCopy());
6543 thread_set_thread_name(current_thread(), newName);
6544 }
6545 }
6546 #endif /* DEBUG || DEVELOPMENT */
6547
6548 if (checkInToken) {
6549 cancellationHandler = checkInToken->setCancellationHandler(&IOService::userServerCheckInTokenCancellationHandler,
6550 &cancelArgs);
6551 }
6552
6553 LOCKWRITENOTIFY();
6554 do{
6555 if (cancelArgs.canceled) {
6556 // token was already canceled, no need to wait or find services
6557 break;
6558 }
6559 result = (IOService *) copyExistingServices( matching,
6560 kIOServiceMatchedState, kIONotifyOnce );
6561 if (result) {
6562 break;
6563 }
6564 notify = IOService::setNotification( gIOMatchedNotification, matching,
6565 &IOService::syncNotificationHandler, (void *) NULL,
6566 &result, priority );
6567 if (!notify) {
6568 break;
6569 }
6570 if (UINT64_MAX != timeout) {
6571 AbsoluteTime deadline;
6572 nanoseconds_to_absolutetime(timeout, &deadline);
6573 clock_absolutetime_interval_to_deadline(deadline, &deadline);
6574 SLEEPNOTIFYTO(&result, deadline);
6575 } else {
6576 SLEEPNOTIFY(&result);
6577 }
6578 }while (false);
6579
6580 UNLOCKNOTIFY();
6581
6582 if (checkInToken && cancellationHandler) {
6583 checkInToken->removeCancellationHandler(cancellationHandler);
6584 }
6585
6586 #if DEBUG || DEVELOPMENT
6587 if (currentName[0]) {
6588 thread_set_thread_name(current_thread(), currentName);
6589 }
6590 #endif /* DEBUG || DEVELOPMENT */
6591
6592 if (notify) {
6593 notify->remove(); // dequeues
6594 }
6595
6596 OSSafeReleaseNULL(cancellationHandler);
6597
6598 return result;
6599 }
6600
6601 IOService *
waitForMatchingService(OSDictionary * matching,uint64_t timeout)6602 IOService::waitForMatchingService( OSDictionary * matching,
6603 uint64_t timeout)
6604 {
6605 return IOService::waitForMatchingServiceWithToken(matching, timeout, NULL);
6606 }
6607
6608 IOService *
waitForService(OSDictionary * matching,mach_timespec_t * timeout)6609 IOService::waitForService( OSDictionary * matching,
6610 mach_timespec_t * timeout )
6611 {
6612 IOService * result;
6613 uint64_t timeoutNS;
6614
6615 if (timeout) {
6616 timeoutNS = timeout->tv_sec;
6617 timeoutNS *= kSecondScale;
6618 timeoutNS += timeout->tv_nsec;
6619 } else {
6620 timeoutNS = UINT64_MAX;
6621 }
6622
6623 result = waitForMatchingService(matching, timeoutNS);
6624
6625 matching->release();
6626 if (result) {
6627 result->release();
6628 }
6629
6630 return result;
6631 }
6632
6633 __dead2
6634 void
deliverNotification(const OSSymbol * type,IOOptionBits orNewState,IOOptionBits andNewState)6635 IOService::deliverNotification( const OSSymbol * type,
6636 IOOptionBits orNewState, IOOptionBits andNewState )
6637 {
6638 panic("deliverNotification");
6639 }
6640
6641 OSArray *
copyNotifiers(const OSSymbol * type,IOOptionBits orNewState,IOOptionBits andNewState)6642 IOService::copyNotifiers(const OSSymbol * type,
6643 IOOptionBits orNewState, IOOptionBits andNewState )
6644 {
6645 _IOServiceNotifier * notify;
6646 OSIterator * iter;
6647 OSArray * willSend = NULL;
6648
6649 lockForArbitration();
6650
6651 if ((0 == (__state[0] & kIOServiceInactiveState))
6652 || (type == gIOTerminatedNotification)
6653 || (type == gIOWillTerminateNotification)) {
6654 LOCKREADNOTIFY();
6655
6656 iter = OSCollectionIterator::withCollection((OSOrderedSet *)
6657 gNotifications->getObject( type ));
6658
6659 if (iter) {
6660 while ((notify = (_IOServiceNotifier *) iter->getNextObject())) {
6661 if (matchPassive(notify->matching, 0)
6662 && (kIOServiceNotifyEnable & notify->state)) {
6663 if (NULL == willSend) {
6664 willSend = OSArray::withCapacity(8);
6665 }
6666 if (willSend) {
6667 willSend->setObject( notify );
6668 }
6669 }
6670 }
6671 iter->release();
6672 }
6673 __state[0] = (__state[0] | orNewState) & andNewState;
6674 UNLOCKNOTIFY();
6675 }
6676
6677 unlockForArbitration();
6678
6679 return willSend;
6680 }
6681
6682 IOOptionBits
getState(void) const6683 IOService::getState( void ) const
6684 {
6685 return __state[0];
6686 }
6687
6688 /*
6689 * Helpers to make matching objects for simple cases
6690 */
6691
6692 OSDictionary *
serviceMatching(const OSString * name,OSDictionary * table)6693 IOService::serviceMatching( const OSString * name,
6694 OSDictionary * table )
6695 {
6696 const OSString * str;
6697
6698 str = OSSymbol::withString(name);
6699 if (!str) {
6700 return NULL;
6701 }
6702
6703 if (!table) {
6704 table = OSDictionary::withCapacity( 2 );
6705 }
6706 if (table) {
6707 table->setObject(gIOProviderClassKey, (OSObject *)str );
6708 }
6709 str->release();
6710
6711 return table;
6712 }
6713
6714
6715 OSSharedPtr<OSDictionary>
serviceMatching(const OSString * name,OSSharedPtr<OSDictionary> table)6716 IOService::serviceMatching( const OSString * name,
6717 OSSharedPtr<OSDictionary> table)
6718 {
6719 OSDictionary * result = serviceMatching(name, table.get());
6720 if (table) {
6721 return OSSharedPtr<OSDictionary>(result, OSRetain);
6722 } else {
6723 return OSSharedPtr<OSDictionary>(result, OSNoRetain);
6724 }
6725 }
6726
6727
6728 OSDictionary *
serviceMatching(const char * name,OSDictionary * table)6729 IOService::serviceMatching( const char * name,
6730 OSDictionary * table )
6731 {
6732 const OSString * str;
6733
6734 str = OSSymbol::withCString( name );
6735 if (!str) {
6736 return NULL;
6737 }
6738
6739 table = serviceMatching( str, table );
6740 str->release();
6741 return table;
6742 }
6743
6744
6745 OSSharedPtr<OSDictionary>
serviceMatching(const char * className,OSSharedPtr<OSDictionary> table)6746 IOService::serviceMatching( const char * className,
6747 OSSharedPtr<OSDictionary> table)
6748 {
6749 OSDictionary * result = serviceMatching(className, table.get());
6750 if (table) {
6751 return OSSharedPtr<OSDictionary>(result, OSRetain);
6752 } else {
6753 return OSSharedPtr<OSDictionary>(result, OSNoRetain);
6754 }
6755 }
6756
6757
6758 OSDictionary *
nameMatching(const OSString * name,OSDictionary * table)6759 IOService::nameMatching( const OSString * name,
6760 OSDictionary * table )
6761 {
6762 if (!table) {
6763 table = OSDictionary::withCapacity( 2 );
6764 }
6765 if (table) {
6766 table->setObject( gIONameMatchKey, (OSObject *)name );
6767 }
6768
6769 return table;
6770 }
6771
6772
6773 OSSharedPtr<OSDictionary>
nameMatching(const OSString * name,OSSharedPtr<OSDictionary> table)6774 IOService::nameMatching( const OSString * name,
6775 OSSharedPtr<OSDictionary> table)
6776 {
6777 OSDictionary * result = nameMatching(name, table.get());
6778 if (table) {
6779 return OSSharedPtr<OSDictionary>(result, OSRetain);
6780 } else {
6781 return OSSharedPtr<OSDictionary>(result, OSNoRetain);
6782 }
6783 }
6784
6785
6786 OSDictionary *
nameMatching(const char * name,OSDictionary * table)6787 IOService::nameMatching( const char * name,
6788 OSDictionary * table )
6789 {
6790 const OSString * str;
6791
6792 str = OSSymbol::withCString( name );
6793 if (!str) {
6794 return NULL;
6795 }
6796
6797 table = nameMatching( str, table );
6798 str->release();
6799 return table;
6800 }
6801
6802
6803 OSSharedPtr<OSDictionary>
nameMatching(const char * name,OSSharedPtr<OSDictionary> table)6804 IOService::nameMatching( const char * name,
6805 OSSharedPtr<OSDictionary> table)
6806 {
6807 OSDictionary * result = nameMatching(name, table.get());
6808 if (table) {
6809 return OSSharedPtr<OSDictionary>(result, OSRetain);
6810 } else {
6811 return OSSharedPtr<OSDictionary>(result, OSNoRetain);
6812 }
6813 }
6814
6815
6816 OSDictionary *
resourceMatching(const OSString * str,OSDictionary * table)6817 IOService::resourceMatching( const OSString * str,
6818 OSDictionary * table )
6819 {
6820 table = serviceMatching( gIOResourcesKey, table );
6821 if (table) {
6822 table->setObject( gIOResourceMatchKey, (OSObject *) str );
6823 }
6824
6825 return table;
6826 }
6827
6828
6829 OSSharedPtr<OSDictionary>
resourceMatching(const OSString * str,OSSharedPtr<OSDictionary> table)6830 IOService::resourceMatching( const OSString * str,
6831 OSSharedPtr<OSDictionary> table)
6832 {
6833 OSDictionary * result = resourceMatching(str, table.get());
6834 if (table) {
6835 return OSSharedPtr<OSDictionary>(result, OSRetain);
6836 } else {
6837 return OSSharedPtr<OSDictionary>(result, OSNoRetain);
6838 }
6839 }
6840
6841
6842 OSDictionary *
resourceMatching(const char * name,OSDictionary * table)6843 IOService::resourceMatching( const char * name,
6844 OSDictionary * table )
6845 {
6846 const OSSymbol * str;
6847
6848 str = OSSymbol::withCString( name );
6849 if (!str) {
6850 return NULL;
6851 }
6852
6853 table = resourceMatching( str, table );
6854 str->release();
6855
6856 return table;
6857 }
6858
6859
6860 OSSharedPtr<OSDictionary>
resourceMatching(const char * name,OSSharedPtr<OSDictionary> table)6861 IOService::resourceMatching( const char * name,
6862 OSSharedPtr<OSDictionary> table)
6863 {
6864 OSDictionary * result = resourceMatching(name, table.get());
6865 if (table) {
6866 return OSSharedPtr<OSDictionary>(result, OSRetain);
6867 } else {
6868 return OSSharedPtr<OSDictionary>(result, OSNoRetain);
6869 }
6870 }
6871
6872
6873 OSDictionary *
propertyMatching(const OSSymbol * key,const OSObject * value,OSDictionary * table)6874 IOService::propertyMatching( const OSSymbol * key, const OSObject * value,
6875 OSDictionary * table )
6876 {
6877 OSDictionary * properties;
6878
6879 properties = OSDictionary::withCapacity( 2 );
6880 if (!properties) {
6881 return NULL;
6882 }
6883 properties->setObject( key, value );
6884
6885 if (!table) {
6886 table = OSDictionary::withCapacity( 2 );
6887 }
6888 if (table) {
6889 table->setObject( gIOPropertyMatchKey, properties );
6890 }
6891
6892 properties->release();
6893
6894 return table;
6895 }
6896
6897
6898 OSSharedPtr<OSDictionary>
propertyMatching(const OSSymbol * key,const OSObject * value,OSSharedPtr<OSDictionary> table)6899 IOService::propertyMatching( const OSSymbol * key, const OSObject * value,
6900 OSSharedPtr<OSDictionary> table)
6901 {
6902 OSDictionary * result = propertyMatching(key, value, table.get());
6903 if (table) {
6904 return OSSharedPtr<OSDictionary>(result, OSRetain);
6905 } else {
6906 return OSSharedPtr<OSDictionary>(result, OSNoRetain);
6907 }
6908 }
6909
6910
6911 OSDictionary *
registryEntryIDMatching(uint64_t entryID,OSDictionary * table)6912 IOService::registryEntryIDMatching( uint64_t entryID,
6913 OSDictionary * table )
6914 {
6915 OSNumber * num;
6916
6917 num = OSNumber::withNumber( entryID, 64 );
6918 if (!num) {
6919 return NULL;
6920 }
6921
6922 if (!table) {
6923 table = OSDictionary::withCapacity( 2 );
6924 }
6925 if (table) {
6926 table->setObject( gIORegistryEntryIDKey, num );
6927 }
6928
6929 if (num) {
6930 num->release();
6931 }
6932
6933 return table;
6934 }
6935
6936
6937 OSSharedPtr<OSDictionary>
registryEntryIDMatching(uint64_t entryID,OSSharedPtr<OSDictionary> table)6938 IOService::registryEntryIDMatching( uint64_t entryID,
6939 OSSharedPtr<OSDictionary> table)
6940 {
6941 OSDictionary * result = registryEntryIDMatching(entryID, table.get());
6942 if (table) {
6943 return OSSharedPtr<OSDictionary>(result, OSRetain);
6944 } else {
6945 return OSSharedPtr<OSDictionary>(result, OSNoRetain);
6946 }
6947 }
6948
6949
6950
6951 /*
6952 * _IOServiceNotifier
6953 */
6954
6955 // wait for all threads, other than the current one,
6956 // to exit the handler
6957
6958 void
wait()6959 _IOServiceNotifier::wait()
6960 {
6961 _IOServiceNotifierInvocation * next;
6962 bool doWait;
6963
6964 do {
6965 doWait = false;
6966 queue_iterate( &handlerInvocations, next,
6967 _IOServiceNotifierInvocation *, link) {
6968 if (next->thread != current_thread()) {
6969 doWait = true;
6970 break;
6971 }
6972 }
6973 if (doWait) {
6974 state |= kIOServiceNotifyWaiter;
6975 SLEEPNOTIFY(this);
6976 }
6977 } while (doWait);
6978 }
6979
6980 void
free()6981 _IOServiceNotifier::free()
6982 {
6983 assert( queue_empty( &handlerInvocations ));
6984
6985 if (handler == &IOServiceMatchingNotificationHandlerToBlock) {
6986 Block_release(ref);
6987 }
6988
6989 OSObject::free();
6990 }
6991
6992 void
remove()6993 _IOServiceNotifier::remove()
6994 {
6995 LOCKWRITENOTIFY();
6996
6997 if (whence) {
6998 whence->removeObject((OSObject *) this );
6999 whence = NULL;
7000 }
7001 if (matching) {
7002 matching->release();
7003 matching = NULL;
7004 }
7005
7006 state &= ~kIOServiceNotifyEnable;
7007
7008 wait();
7009
7010 UNLOCKNOTIFY();
7011
7012 release();
7013 }
7014
7015 bool
disable()7016 _IOServiceNotifier::disable()
7017 {
7018 bool ret;
7019
7020 LOCKWRITENOTIFY();
7021
7022 ret = (0 != (kIOServiceNotifyEnable & state));
7023 state &= ~kIOServiceNotifyEnable;
7024 if (ret) {
7025 wait();
7026 }
7027
7028 UNLOCKNOTIFY();
7029
7030 return ret;
7031 }
7032
7033 void
enable(bool was)7034 _IOServiceNotifier::enable( bool was )
7035 {
7036 LOCKWRITENOTIFY();
7037 if (was) {
7038 state |= kIOServiceNotifyEnable;
7039 } else {
7040 state &= ~kIOServiceNotifyEnable;
7041 }
7042 UNLOCKNOTIFY();
7043 }
7044
7045
7046 /*
7047 * _IOServiceNullNotifier
7048 */
7049
7050 void
taggedRetain(const void * tag) const7051 _IOServiceNullNotifier::taggedRetain(const void *tag) const
7052 {
7053 }
7054 void
taggedRelease(const void * tag,const int when) const7055 _IOServiceNullNotifier::taggedRelease(const void *tag, const int when) const
7056 {
7057 }
7058 void
free()7059 _IOServiceNullNotifier::free()
7060 {
7061 }
7062 void
wait()7063 _IOServiceNullNotifier::wait()
7064 {
7065 }
7066 void
remove()7067 _IOServiceNullNotifier::remove()
7068 {
7069 }
7070 void
enable(bool was)7071 _IOServiceNullNotifier::enable(bool was)
7072 {
7073 }
7074 bool
disable()7075 _IOServiceNullNotifier::disable()
7076 {
7077 return false;
7078 }
7079
7080 /*
7081 * IOResources
7082 */
7083
7084 IOService *
resources(void)7085 IOResources::resources( void )
7086 {
7087 IOResources * inst;
7088
7089 inst = new IOResources;
7090 if (inst && !inst->init()) {
7091 inst->release();
7092 inst = NULL;
7093 }
7094
7095 return inst;
7096 }
7097
7098 bool
init(OSDictionary * dictionary)7099 IOResources::init( OSDictionary * dictionary )
7100 {
7101 // Do super init first
7102 if (!IOService::init()) {
7103 return false;
7104 }
7105
7106 // Allow PAL layer to publish a value
7107 const char *property_name;
7108 int property_value;
7109
7110 pal_get_resource_property( &property_name, &property_value );
7111
7112 if (property_name) {
7113 OSNumber *num;
7114 const OSSymbol * sym;
7115
7116 if ((num = OSNumber::withNumber(property_value, 32)) != NULL) {
7117 if ((sym = OSSymbol::withCString( property_name)) != NULL) {
7118 this->setProperty( sym, num );
7119 sym->release();
7120 }
7121 num->release();
7122 }
7123 }
7124
7125 return true;
7126 }
7127
7128 IOReturn
newUserClient(task_t owningTask,void * securityID,UInt32 type,OSDictionary * properties,IOUserClient ** handler)7129 IOResources::newUserClient(task_t owningTask, void * securityID,
7130 UInt32 type, OSDictionary * properties,
7131 IOUserClient ** handler)
7132 {
7133 return kIOReturnUnsupported;
7134 }
7135
7136 IOWorkLoop *
getWorkLoop() const7137 IOResources::getWorkLoop() const
7138 {
7139 // If we are the resource root
7140 // then use the platform's workloop
7141 if (this == (IOResources *) gIOResources) {
7142 return getPlatform()->getWorkLoop();
7143 } else {
7144 return IOService::getWorkLoop();
7145 }
7146 }
7147
7148 static bool
IOResourcesMatchPropertyTable(IOService * resources,OSDictionary * table)7149 IOResourcesMatchPropertyTable(IOService * resources, OSDictionary * table)
7150 {
7151 OSObject * prop;
7152 bool __block ok = true;
7153
7154 prop = table->getObject( gIOResourceMatchKey );
7155 if (prop) {
7156 prop->iterateObjects(^bool (OSObject * obj)
7157 {
7158 OSString *
7159 str = OSDynamicCast(OSString, obj);
7160 ok = (NULL != resources->getProperty(str));
7161 return !ok;
7162 });
7163 } else if ((prop = table->getObject(gIOResourceMatchedKey))) {
7164 OSObject * obj;
7165 OSArray * keys;
7166
7167 obj = resources->copyProperty(gIOResourceMatchedKey);
7168 keys = OSDynamicCast(OSArray, obj);
7169 ok = false;
7170 if (keys) {
7171 // assuming OSSymbol
7172 ok = ((-1U) != keys->getNextIndexOfObject(prop, 0));
7173 }
7174 OSSafeReleaseNULL(obj);
7175 }
7176
7177 return ok;
7178 }
7179
7180 bool
matchPropertyTable(OSDictionary * table)7181 IOResources::matchPropertyTable( OSDictionary * table )
7182 {
7183 return IOResourcesMatchPropertyTable(this, table);
7184 }
7185
7186 /*
7187 * IOUserResources
7188 */
7189
7190 IOService *
resources(void)7191 IOUserResources::resources( void )
7192 {
7193 IOUserResources * inst;
7194
7195 inst = OSTypeAlloc(IOUserResources);
7196 if (inst && !inst->init()) {
7197 inst->release();
7198 inst = NULL;
7199 }
7200
7201 return inst;
7202 }
7203
7204 bool
init(OSDictionary * dictionary)7205 IOUserResources::init( OSDictionary * dictionary )
7206 {
7207 // Do super init first
7208 if (!IOService::init()) {
7209 return false;
7210 }
7211 return true;
7212 }
7213
7214 IOReturn
newUserClient(task_t owningTask,void * securityID,UInt32 type,OSDictionary * properties,IOUserClient ** handler)7215 IOUserResources::newUserClient(task_t owningTask, void * securityID,
7216 UInt32 type, OSDictionary * properties,
7217 IOUserClient ** handler)
7218 {
7219 return kIOReturnUnsupported;
7220 }
7221
7222 IOWorkLoop *
getWorkLoop() const7223 IOUserResources::getWorkLoop() const
7224 {
7225 return getPlatform()->getWorkLoop();
7226 }
7227
7228 bool
matchPropertyTable(OSDictionary * table)7229 IOUserResources::matchPropertyTable( OSDictionary * table )
7230 {
7231 return IOResourcesMatchPropertyTable(this, table);
7232 }
7233
7234 // --
7235
7236 void
consoleLockTimer(thread_call_param_t p0,thread_call_param_t p1)7237 IOService::consoleLockTimer(thread_call_param_t p0, thread_call_param_t p1)
7238 {
7239 IOService::updateConsoleUsers(NULL, 0);
7240 }
7241
7242 void
updateConsoleUsers(OSArray * consoleUsers,IOMessage systemMessage,bool afterUserspaceReboot)7243 IOService::updateConsoleUsers(OSArray * consoleUsers, IOMessage systemMessage, bool afterUserspaceReboot)
7244 {
7245 IORegistryEntry * regEntry;
7246 OSObject * locked = kOSBooleanFalse;
7247 uint32_t idx;
7248 bool publish;
7249 OSDictionary * user;
7250 clock_sec_t now = 0;
7251 clock_usec_t microsecs;
7252
7253 regEntry = IORegistryEntry::getRegistryRoot();
7254
7255 if (!gIOChosenEntry) {
7256 gIOChosenEntry = IORegistryEntry::fromPath("/chosen", gIODTPlane);
7257 }
7258
7259 IOLockLock(gIOConsoleUsersLock);
7260
7261 if (systemMessage) {
7262 sSystemPower = systemMessage;
7263 #if HIBERNATION
7264 if (kIOMessageSystemHasPoweredOn == systemMessage) {
7265 uint32_t lockState = IOHibernateWasScreenLocked();
7266 switch (lockState) {
7267 case 0:
7268 break;
7269 case kIOScreenLockLocked:
7270 case kIOScreenLockFileVaultDialog:
7271 gIOConsoleBooterLockState = kOSBooleanTrue;
7272 break;
7273 case kIOScreenLockNoLock:
7274 gIOConsoleBooterLockState = NULL;
7275 break;
7276 case kIOScreenLockUnlocked:
7277 default:
7278 gIOConsoleBooterLockState = kOSBooleanFalse;
7279 break;
7280 }
7281 }
7282 #endif /* HIBERNATION */
7283 }
7284
7285 if (consoleUsers) {
7286 OSNumber * num = NULL;
7287 bool loginLocked = true;
7288
7289 gIOConsoleLoggedIn = false;
7290 for (idx = 0;
7291 (user = OSDynamicCast(OSDictionary, consoleUsers->getObject(idx)));
7292 idx++) {
7293 gIOConsoleLoggedIn |= ((kOSBooleanTrue == user->getObject(gIOConsoleSessionOnConsoleKey))
7294 && (kOSBooleanTrue == user->getObject(gIOConsoleSessionLoginDoneKey)));
7295
7296 loginLocked &= (kOSBooleanTrue == user->getObject(gIOConsoleSessionScreenIsLockedKey));
7297 if (!num) {
7298 num = OSDynamicCast(OSNumber, user->getObject(gIOConsoleSessionScreenLockedTimeKey));
7299 }
7300 }
7301 #if HIBERNATION
7302 if (!loginLocked || afterUserspaceReboot) {
7303 gIOConsoleBooterLockState = NULL;
7304 }
7305 IOLog("IOConsoleUsers: time(%d) %ld->%d, lin %d, llk %d, \n",
7306 (num != NULL), gIOConsoleLockTime, (num ? num->unsigned32BitValue() : 0),
7307 gIOConsoleLoggedIn, loginLocked);
7308 #endif /* HIBERNATION */
7309 gIOConsoleLockTime = num ? num->unsigned32BitValue() : 0;
7310 }
7311
7312 if (!gIOConsoleLoggedIn
7313 || (kIOMessageSystemWillSleep == sSystemPower)
7314 || (kIOMessageSystemPagingOff == sSystemPower)) {
7315 if (afterUserspaceReboot) {
7316 // set "locked" to false after a user space reboot
7317 // because the reboot happens directly after a user
7318 // logs into the machine via fvunlock mode.
7319 locked = kOSBooleanFalse;
7320 } else {
7321 locked = kOSBooleanTrue;
7322 }
7323 }
7324 #if HIBERNATION
7325 else if (gIOConsoleBooterLockState) {
7326 locked = gIOConsoleBooterLockState;
7327 }
7328 #endif /* HIBERNATION */
7329 else if (gIOConsoleLockTime) {
7330 clock_get_calendar_microtime(&now, µsecs);
7331 if (gIOConsoleLockTime > now) {
7332 AbsoluteTime deadline;
7333 clock_sec_t interval;
7334 uint32_t interval32;
7335
7336 interval = (gIOConsoleLockTime - now);
7337 interval32 = (uint32_t) interval;
7338 if (interval32 != interval) {
7339 interval32 = UINT_MAX;
7340 }
7341 clock_interval_to_deadline(interval32, kSecondScale, &deadline);
7342 thread_call_enter_delayed(gIOConsoleLockCallout, deadline);
7343 } else {
7344 locked = kOSBooleanTrue;
7345 }
7346 }
7347
7348 publish = (consoleUsers || (locked != regEntry->getProperty(gIOConsoleLockedKey)));
7349 if (publish) {
7350 regEntry->setProperty(gIOConsoleLockedKey, locked);
7351 if (consoleUsers) {
7352 regEntry->setProperty(gIOConsoleUsersKey, consoleUsers);
7353 }
7354 OSIncrementAtomic( &gIOConsoleUsersSeed );
7355 }
7356
7357 #if HIBERNATION
7358 if (gIOChosenEntry) {
7359 if (locked == kOSBooleanTrue) {
7360 gIOScreenLockState = kIOScreenLockLocked;
7361 } else if (gIOConsoleLockTime) {
7362 gIOScreenLockState = kIOScreenLockUnlocked;
7363 } else {
7364 gIOScreenLockState = kIOScreenLockNoLock;
7365 }
7366 gIOChosenEntry->setProperty(kIOScreenLockStateKey, &gIOScreenLockState, sizeof(gIOScreenLockState));
7367
7368 IOLog("IOConsoleUsers: gIOScreenLockState %d, hs %d, bs %d, now %ld, sm 0x%x\n",
7369 gIOScreenLockState, gIOHibernateState, (gIOConsoleBooterLockState != NULL), now, systemMessage);
7370 }
7371 #endif /* HIBERNATION */
7372
7373 IOLockUnlock(gIOConsoleUsersLock);
7374
7375 if (publish) {
7376 publishResource( gIOConsoleUsersSeedKey, gIOConsoleUsersSeedValue );
7377
7378 MessageClientsContext context;
7379
7380 context.service = getServiceRoot();
7381 context.type = kIOMessageConsoleSecurityChange;
7382 context.argument = (void *) regEntry;
7383 context.argSize = 0;
7384
7385 applyToInterestNotifiers(getServiceRoot(), gIOConsoleSecurityInterest,
7386 &messageClientsApplier, &context );
7387 }
7388 }
7389
7390 IOReturn
setProperties(OSObject * properties)7391 IOResources::setProperties( OSObject * properties )
7392 {
7393 IOReturn err;
7394 const OSSymbol * key;
7395 OSDictionary * dict;
7396 OSCollectionIterator * iter;
7397
7398 if (!IOCurrentTaskHasEntitlement(kIOResourcesSetPropertyKey)) {
7399 err = IOUserClient::clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator);
7400 if (kIOReturnSuccess != err) {
7401 return err;
7402 }
7403 }
7404
7405 dict = OSDynamicCast(OSDictionary, properties);
7406 if (NULL == dict) {
7407 return kIOReturnBadArgument;
7408 }
7409
7410 iter = OSCollectionIterator::withCollection( dict);
7411 if (NULL == iter) {
7412 return kIOReturnBadArgument;
7413 }
7414
7415 while ((key = OSDynamicCast(OSSymbol, iter->getNextObject()))) {
7416 if (gIOConsoleUsersKey == key) {
7417 do{
7418 OSArray * consoleUsers;
7419 consoleUsers = OSDynamicCast(OSArray, dict->getObject(key));
7420 if (!consoleUsers) {
7421 continue;
7422 }
7423 IOService::updateConsoleUsers(consoleUsers, 0);
7424 }while (false);
7425 }
7426
7427 publishResource( key, dict->getObject(key));
7428 }
7429
7430 iter->release();
7431
7432 return kIOReturnSuccess;
7433 }
7434
7435 /*
7436 * Helpers for matching dictionaries.
7437 * Keys existing in matching are checked in properties.
7438 * Keys may be a string or OSCollection of IOStrings
7439 */
7440
7441 bool
compareProperty(OSDictionary * matching,const char * key)7442 IOService::compareProperty( OSDictionary * matching,
7443 const char * key )
7444 {
7445 OSObject * value;
7446 OSObject * prop;
7447 bool ok;
7448
7449 value = matching->getObject( key );
7450 if (value) {
7451 prop = copyProperty(key);
7452 ok = value->isEqualTo(prop);
7453 if (prop) {
7454 prop->release();
7455 }
7456 } else {
7457 ok = true;
7458 }
7459
7460 return ok;
7461 }
7462
7463
7464 bool
compareProperty(OSDictionary * matching,const OSString * key)7465 IOService::compareProperty( OSDictionary * matching,
7466 const OSString * key )
7467 {
7468 OSObject * value;
7469 OSObject * prop;
7470 bool ok;
7471
7472 value = matching->getObject( key );
7473 if (value) {
7474 prop = copyProperty(key);
7475 ok = value->isEqualTo(prop);
7476 if (prop) {
7477 prop->release();
7478 }
7479 } else {
7480 ok = true;
7481 }
7482
7483 return ok;
7484 }
7485
7486 #ifndef __clang_analyzer__
7487 // Implementation of this function is hidden from the static analyzer.
7488 // The analyzer was worried about this function's confusing contract over
7489 // the 'keys' parameter. The contract is to either release it or not release it
7490 // depending on whether 'matching' is non-null. Such contracts are discouraged
7491 // but changing it now would break compatibility.
7492 bool
compareProperties(OSDictionary * matching,OSCollection * keys)7493 IOService::compareProperties( OSDictionary * matching,
7494 OSCollection * keys )
7495 {
7496 OSCollectionIterator * iter;
7497 const OSString * key;
7498 bool ok = true;
7499
7500 if (!matching || !keys) {
7501 return false;
7502 }
7503
7504 iter = OSCollectionIterator::withCollection( keys );
7505
7506 if (iter) {
7507 while (ok && (key = OSDynamicCast( OSString, iter->getNextObject()))) {
7508 ok = compareProperty( matching, key );
7509 }
7510
7511 iter->release();
7512 }
7513 keys->release(); // !! consume a ref !!
7514
7515 return ok;
7516 }
7517 #endif // __clang_analyzer__
7518
7519 /* Helper to add a location matching dict to the table */
7520
7521 OSDictionary *
addLocation(OSDictionary * table)7522 IOService::addLocation( OSDictionary * table )
7523 {
7524 OSDictionary * dict;
7525
7526 if (!table) {
7527 return NULL;
7528 }
7529
7530 dict = OSDictionary::withCapacity( 1 );
7531 if (dict) {
7532 bool ok = table->setObject( gIOLocationMatchKey, dict );
7533 dict->release();
7534 if (!ok) {
7535 dict = NULL;
7536 }
7537 }
7538
7539 return dict;
7540 }
7541
7542 /*
7543 * Go looking for a provider to match a location dict.
7544 */
7545
7546 IOService *
matchLocation(IOService *)7547 IOService::matchLocation( IOService * /* client */ )
7548 {
7549 IOService * parent;
7550
7551 parent = getProvider();
7552
7553 if (parent) {
7554 parent = parent->matchLocation( this );
7555 }
7556
7557 return parent;
7558 }
7559
7560 bool
matchInternal(OSDictionary * table,uint32_t options,uint32_t * did)7561 IOService::matchInternal(OSDictionary * table, uint32_t options, uint32_t * did)
7562 {
7563 OSString * matched;
7564 OSObject * obj;
7565 OSString * str;
7566 OSDictionary * matchProps;
7567 IORegistryEntry * entry;
7568 OSNumber * num;
7569 bool match = true;
7570 bool changesOK = (0 != (kIOServiceChangesOK & options));
7571 uint32_t count;
7572 uint32_t done;
7573
7574 do{
7575 count = table->getCount();
7576 done = 0;
7577 matchProps = NULL;
7578
7579 if (table->getObject(gIOServiceNotificationUserKey)) {
7580 done++;
7581 match = (0 == (kIOServiceUserInvisibleMatchState & __state[0]));
7582 if ((!match) || (done == count)) {
7583 break;
7584 }
7585 }
7586
7587 if (propertyExists(gIOExclaveAssignedKey)) {
7588 if (!table->getObject(gIOExclaveProxyKey)) {
7589 match = false;
7590 break;
7591 }
7592 } else if (table->getObject(gIOExclaveProxyKey)) {
7593 match = false;
7594 break;
7595 }
7596
7597 if (table->getObject(gIOCompatibilityMatchKey)) {
7598 done++;
7599 obj = copyProperty(gIOCompatibilityPropertiesKey);
7600 matchProps = OSDynamicCast(OSDictionary, obj);
7601 if (!matchProps) {
7602 OSSafeReleaseNULL(obj);
7603 }
7604 }
7605
7606 str = OSDynamicCast(OSString, table->getObject(gIOProviderClassKey));
7607 if (str) {
7608 done++;
7609 if (matchProps && (obj = matchProps->getObject(gIOClassKey))) {
7610 match = str->isEqualTo(obj);
7611 } else {
7612 match = ((kIOServiceClassDone & options) || (NULL != metaCast(str)));
7613 }
7614
7615 #if MATCH_DEBUG
7616 match = (0 != metaCast( str ));
7617 if ((kIOServiceClassDone & options) && !match) {
7618 panic("classDone");
7619 }
7620 #endif
7621 if ((!match) || (done == count)) {
7622 break;
7623 }
7624 }
7625
7626 obj = table->getObject( gIONameMatchKey );
7627 if (obj) {
7628 done++;
7629 match = compareNames( obj, changesOK ? &matched : NULL );
7630 if (!match) {
7631 break;
7632 }
7633 if (changesOK && matched) {
7634 // leave a hint as to which name matched
7635 table->setObject( gIONameMatchedKey, matched );
7636 matched->release();
7637 }
7638 if (done == count) {
7639 break;
7640 }
7641 }
7642
7643 str = OSDynamicCast( OSString, table->getObject( gIOLocationMatchKey ));
7644 if (str) {
7645 const OSSymbol * sym;
7646 done++;
7647 match = false;
7648 sym = copyLocation();
7649 if (sym) {
7650 match = sym->isEqualTo( str );
7651 sym->release();
7652 }
7653 if ((!match) || (done == count)) {
7654 break;
7655 }
7656 }
7657
7658 obj = table->getObject( gIOPropertyMatchKey );
7659 if (obj) {
7660 OSDictionary * nextDict;
7661 OSIterator * iter;
7662 done++;
7663 match = false;
7664 if (!matchProps) {
7665 matchProps = dictionaryWithProperties();
7666 }
7667 if (matchProps) {
7668 nextDict = OSDynamicCast( OSDictionary, obj);
7669 if (nextDict) {
7670 iter = NULL;
7671 } else {
7672 iter = OSCollectionIterator::withCollection(
7673 OSDynamicCast(OSCollection, obj));
7674 }
7675
7676 while (nextDict
7677 || (iter && (NULL != (nextDict = OSDynamicCast(OSDictionary,
7678 iter->getNextObject()))))) {
7679 match = matchProps->isEqualTo( nextDict, nextDict);
7680 if (match) {
7681 break;
7682 }
7683 nextDict = NULL;
7684 }
7685 if (iter) {
7686 iter->release();
7687 }
7688 }
7689 if ((!match) || (done == count)) {
7690 break;
7691 }
7692 }
7693
7694 obj = table->getObject( gIOPropertyExistsMatchKey );
7695 if (obj) {
7696 OSString * nextKey;
7697 OSIterator * iter;
7698 done++;
7699 match = false;
7700 if (!matchProps) {
7701 matchProps = dictionaryWithProperties();
7702 }
7703 if (matchProps) {
7704 nextKey = OSDynamicCast( OSString, obj);
7705 if (nextKey) {
7706 iter = NULL;
7707 } else {
7708 iter = OSCollectionIterator::withCollection(
7709 OSDynamicCast(OSCollection, obj));
7710 }
7711
7712 while (nextKey
7713 || (iter && (NULL != (nextKey = OSDynamicCast(OSString,
7714 iter->getNextObject()))))) {
7715 match = (NULL != matchProps->getObject(nextKey));
7716 if (match) {
7717 break;
7718 }
7719 nextKey = NULL;
7720 }
7721 if (iter) {
7722 iter->release();
7723 }
7724 }
7725 if ((!match) || (done == count)) {
7726 break;
7727 }
7728 }
7729
7730 str = OSDynamicCast( OSString, table->getObject( gIOPathMatchKey ));
7731 if (str) {
7732 done++;
7733 entry = IORegistryEntry::fromPath( str->getCStringNoCopy());
7734 match = (this == entry);
7735 if (entry) {
7736 entry->release();
7737 }
7738 if (!match && matchProps && (obj = matchProps->getObject(gIOPathKey))) {
7739 match = str->isEqualTo(obj);
7740 }
7741 if ((!match) || (done == count)) {
7742 break;
7743 }
7744 }
7745
7746 num = OSDynamicCast( OSNumber, table->getObject( gIORegistryEntryIDKey ));
7747 if (num) {
7748 done++;
7749 match = (getRegistryEntryID() == num->unsigned64BitValue());
7750 if ((!match) || (done == count)) {
7751 break;
7752 }
7753 }
7754
7755 num = OSDynamicCast( OSNumber, table->getObject( gIOMatchedServiceCountKey ));
7756 if (num) {
7757 OSIterator * iter;
7758 IOService * service = NULL;
7759 UInt32 serviceCount = 0;
7760
7761 done++;
7762 iter = getClientIterator();
7763 if (iter) {
7764 while ((service = (IOService *) iter->getNextObject())) {
7765 if (kIOServiceInactiveState & service->__state[0]) {
7766 continue;
7767 }
7768 if (NULL == service->getProperty( gIOMatchCategoryKey )) {
7769 continue;
7770 }
7771 ++serviceCount;
7772 }
7773 iter->release();
7774 }
7775 match = (serviceCount == num->unsigned32BitValue());
7776 if ((!match) || (done == count)) {
7777 break;
7778 }
7779 }
7780
7781 #define propMatch(key) \
7782 obj = table->getObject(key); \
7783 if (obj) \
7784 { \
7785 OSObject * prop; \
7786 done++; \
7787 prop = copyProperty(key); \
7788 match = obj->isEqualTo(prop); \
7789 if (prop) prop->release(); \
7790 if ((!match) || (done == count)) break; \
7791 }
7792 propMatch(gIOBSDNameKey)
7793 propMatch(gIOBSDMajorKey)
7794 propMatch(gIOBSDMinorKey)
7795 propMatch(gIOBSDUnitKey)
7796 #undef propMatch
7797 }while (false);
7798
7799 OSSafeReleaseNULL(matchProps);
7800
7801 if (did) {
7802 *did = done;
7803 }
7804 return match;
7805 }
7806
7807 bool
passiveMatch(OSDictionary * table,bool changesOK)7808 IOService::passiveMatch( OSDictionary * table, bool changesOK )
7809 {
7810 return matchPassive(table, changesOK ? kIOServiceChangesOK : 0);
7811 }
7812
7813 bool
matchPassive(OSDictionary * table,uint32_t options)7814 IOService::matchPassive(OSDictionary * table, uint32_t options)
7815 {
7816 IOService * where;
7817 OSDictionary * nextTable;
7818 SInt32 score;
7819 OSNumber * newPri;
7820 bool match = true;
7821 bool matchParent = false;
7822 uint32_t count;
7823 uint32_t done;
7824
7825 assert( table );
7826
7827 #if defined(XNU_TARGET_OS_OSX)
7828 OSArray* aliasServiceRegIds = NULL;
7829 IOService* foundAlternateService = NULL;
7830 #endif /* defined(XNU_TARGET_OS_OSX) */
7831
7832 #if MATCH_DEBUG
7833 OSDictionary * root = table;
7834 #endif
7835
7836 where = this;
7837 do{
7838 do{
7839 count = table->getCount();
7840 if (!(kIOServiceInternalDone & options)) {
7841 match = where->matchInternal(table, options, &done);
7842 // don't call family if we've done all the entries in the table
7843 if ((!match) || (done == count)) {
7844 break;
7845 }
7846 }
7847
7848 // pass in score from property table
7849 score = IOServiceObjectOrder( table, (void *) gIOProbeScoreKey);
7850
7851 // do family specific matching
7852 match = where->matchPropertyTable( table, &score );
7853
7854 if (!match) {
7855 #if IOMATCHDEBUG
7856 if (kIOLogMatch & getDebugFlags( table )) {
7857 LOG("%s: family specific matching fails\n", where->getName());
7858 }
7859 #endif
7860 break;
7861 }
7862
7863 if (kIOServiceChangesOK & options) {
7864 // save the score
7865 newPri = OSNumber::withNumber( score, 32 );
7866 if (newPri) {
7867 table->setObject( gIOProbeScoreKey, newPri );
7868 newPri->release();
7869 }
7870 }
7871
7872 options = 0;
7873 matchParent = false;
7874
7875 nextTable = OSDynamicCast(OSDictionary,
7876 table->getObject( gIOParentMatchKey ));
7877 if (nextTable) {
7878 // look for a matching entry anywhere up to root
7879 match = false;
7880 matchParent = true;
7881 table = nextTable;
7882 break;
7883 }
7884
7885 table = OSDynamicCast(OSDictionary,
7886 table->getObject( gIOLocationMatchKey ));
7887 if (table) {
7888 // look for a matching entry at matchLocation()
7889 match = false;
7890 where = where->getProvider();
7891 if (where && (where = where->matchLocation(where))) {
7892 continue;
7893 }
7894 }
7895 break;
7896 }while (true);
7897
7898 if (match == true) {
7899 break;
7900 }
7901
7902 if (matchParent == true) {
7903 #if defined(XNU_TARGET_OS_OSX)
7904 // check if service has an alias to search its other "parents" if a parent match isn't found
7905 OSObject * prop = where->copyProperty(gIOServiceLegacyMatchingRegistryIDKey);
7906 OSNumber * alternateRegistryID = OSDynamicCast(OSNumber, prop);
7907 if (alternateRegistryID != NULL) {
7908 if (aliasServiceRegIds == NULL) {
7909 aliasServiceRegIds = OSArray::withCapacity(sizeof(alternateRegistryID));
7910 }
7911 aliasServiceRegIds->setObject(alternateRegistryID);
7912 }
7913 OSSafeReleaseNULL(prop);
7914 #endif /* defined(XNU_TARGET_OS_OSX) */
7915 } else {
7916 break;
7917 }
7918
7919 where = where->getProvider();
7920 #if defined(XNU_TARGET_OS_OSX)
7921 if (where == NULL) {
7922 // there were no matching parent services, check to see if there are aliased services that have a matching parent
7923 if (aliasServiceRegIds != NULL) {
7924 unsigned int numAliasedServices = aliasServiceRegIds->getCount();
7925 if (numAliasedServices != 0) {
7926 OSNumber* alternateRegistryID = OSDynamicCast(OSNumber, aliasServiceRegIds->getObject(numAliasedServices - 1));
7927 if (alternateRegistryID != NULL) {
7928 OSDictionary* alternateMatchingDict = IOService::registryEntryIDMatching(alternateRegistryID->unsigned64BitValue());
7929 aliasServiceRegIds->removeObject(numAliasedServices - 1);
7930 if (alternateMatchingDict != NULL) {
7931 OSSafeReleaseNULL(foundAlternateService);
7932 foundAlternateService = IOService::copyMatchingService(alternateMatchingDict);
7933 alternateMatchingDict->release();
7934 if (foundAlternateService != NULL) {
7935 where = foundAlternateService;
7936 }
7937 }
7938 }
7939 }
7940 }
7941 }
7942 #endif /* defined(XNU_TARGET_OS_OSX) */
7943 }while (where != NULL);
7944
7945 #if defined(XNU_TARGET_OS_OSX)
7946 OSSafeReleaseNULL(foundAlternateService);
7947 OSSafeReleaseNULL(aliasServiceRegIds);
7948 #endif /* defined(XNU_TARGET_OS_OSX) */
7949
7950 #if MATCH_DEBUG
7951 if (where != this) {
7952 OSSerialize * s = OSSerialize::withCapacity(128);
7953 root->serialize(s);
7954 kprintf("parent match 0x%llx, %d,\n%s\n", getRegistryEntryID(), match, s->text());
7955 s->release();
7956 }
7957 #endif
7958
7959 return match;
7960 }
7961
7962
7963 IOReturn
newUserClient(task_t owningTask,void * securityID,UInt32 type,OSDictionary * properties,IOUserClient ** handler)7964 IOService::newUserClient( task_t owningTask, void * securityID,
7965 UInt32 type, OSDictionary * properties,
7966 IOUserClient ** handler )
7967 {
7968 const OSSymbol *userClientClass = NULL;
7969 IOUserClient *client;
7970 OSObject *prop;
7971 OSObject *temp;
7972
7973 if (reserved && reserved->uvars && reserved->uvars->userServer) {
7974 return reserved->uvars->userServer->serviceNewUserClient(this, owningTask, securityID, type, properties, handler);
7975 }
7976
7977 if (kIOReturnSuccess == newUserClient( owningTask, securityID, type, handler )) {
7978 return kIOReturnSuccess;
7979 }
7980
7981 // First try my own properties for a user client class name
7982 prop = copyProperty(gIOUserClientClassKey);
7983 if (prop) {
7984 if (OSDynamicCast(OSSymbol, prop)) {
7985 userClientClass = (const OSSymbol *) prop;
7986 prop = NULL;
7987 } else if (OSDynamicCast(OSString, prop)) {
7988 userClientClass = OSSymbol::withString((OSString *) prop);
7989 OSSafeReleaseNULL(prop);
7990 if (userClientClass) {
7991 setProperty(gIOUserClientClassKey,
7992 (OSObject *) userClientClass);
7993 }
7994 } else {
7995 OSSafeReleaseNULL(prop);
7996 }
7997 }
7998
7999 // Didn't find one so lets just bomb out now without further ado.
8000 if (!userClientClass) {
8001 return kIOReturnUnsupported;
8002 }
8003
8004 // This reference is consumed by the IOServiceOpen call
8005 temp = OSMetaClass::allocClassWithName(userClientClass);
8006 OSSafeReleaseNULL(userClientClass);
8007 if (!temp) {
8008 return kIOReturnNoMemory;
8009 }
8010
8011 if (OSDynamicCast(IOUserClient, temp)) {
8012 client = (IOUserClient *) temp;
8013 } else {
8014 temp->release();
8015 return kIOReturnUnsupported;
8016 }
8017
8018 if (!client->initWithTask(owningTask, securityID, type, properties)) {
8019 client->release();
8020 return kIOReturnBadArgument;
8021 }
8022
8023 if (!client->attach(this)) {
8024 client->release();
8025 return kIOReturnUnsupported;
8026 }
8027
8028 if (!client->start(this)) {
8029 client->detach(this);
8030 client->release();
8031 return kIOReturnUnsupported;
8032 }
8033
8034 *handler = client;
8035 return kIOReturnSuccess;
8036 }
8037
8038 IOReturn
newUserClient(task_t owningTask,void * securityID,UInt32 type,OSDictionary * properties,OSSharedPtr<IOUserClient> & handler)8039 IOService::newUserClient( task_t owningTask, void * securityID,
8040 UInt32 type, OSDictionary * properties,
8041 OSSharedPtr<IOUserClient>& handler )
8042 {
8043 IOUserClient* handlerRaw = NULL;
8044 IOReturn result = newUserClient(owningTask, securityID, type, properties, &handlerRaw);
8045 handler.reset(handlerRaw, OSNoRetain);
8046 return result;
8047 }
8048
8049 IOReturn
newUserClient(task_t owningTask,void * securityID,UInt32 type,IOUserClient ** handler)8050 IOService::newUserClient( task_t owningTask, void * securityID,
8051 UInt32 type, IOUserClient ** handler )
8052 {
8053 return kIOReturnUnsupported;
8054 }
8055
8056 IOReturn
newUserClient(task_t owningTask,void * securityID,UInt32 type,OSSharedPtr<IOUserClient> & handler)8057 IOService::newUserClient( task_t owningTask, void * securityID,
8058 UInt32 type, OSSharedPtr<IOUserClient>& handler )
8059 {
8060 IOUserClient* handlerRaw = nullptr;
8061 IOReturn result = IOService::newUserClient(owningTask, securityID, type, &handlerRaw);
8062 handler.reset(handlerRaw, OSNoRetain);
8063 return result;
8064 }
8065
8066
8067 IOReturn
requestProbe(IOOptionBits options)8068 IOService::requestProbe( IOOptionBits options )
8069 {
8070 return kIOReturnUnsupported;
8071 }
8072
8073 bool
hasUserServer() const8074 IOService::hasUserServer() const
8075 {
8076 return reserved && reserved->uvars && reserved->uvars->userServer;
8077 }
8078
8079 /*
8080 * Convert an IOReturn to text. Subclasses which add additional
8081 * IOReturn's should override this method and call
8082 * super::stringFromReturn if the desired value is not found.
8083 */
8084
8085 const char *
stringFromReturn(IOReturn rtn)8086 IOService::stringFromReturn( IOReturn rtn )
8087 {
8088 static const IONamedValue IOReturn_values[] = {
8089 {kIOReturnSuccess, "success" },
8090 {kIOReturnError, "general error" },
8091 {kIOReturnNoMemory, "memory allocation error" },
8092 {kIOReturnNoResources, "resource shortage" },
8093 {kIOReturnIPCError, "Mach IPC failure" },
8094 {kIOReturnNoDevice, "no such device" },
8095 {kIOReturnNotPrivileged, "privilege violation" },
8096 {kIOReturnBadArgument, "invalid argument" },
8097 {kIOReturnLockedRead, "device is read locked" },
8098 {kIOReturnLockedWrite, "device is write locked" },
8099 {kIOReturnExclusiveAccess, "device is exclusive access" },
8100 {kIOReturnBadMessageID, "bad IPC message ID" },
8101 {kIOReturnUnsupported, "unsupported function" },
8102 {kIOReturnVMError, "virtual memory error" },
8103 {kIOReturnInternalError, "internal driver error" },
8104 {kIOReturnIOError, "I/O error" },
8105 {kIOReturnCannotLock, "cannot acquire lock" },
8106 {kIOReturnNotOpen, "device is not open" },
8107 {kIOReturnNotReadable, "device is not readable" },
8108 {kIOReturnNotWritable, "device is not writeable" },
8109 {kIOReturnNotAligned, "alignment error" },
8110 {kIOReturnBadMedia, "media error" },
8111 {kIOReturnStillOpen, "device is still open" },
8112 {kIOReturnRLDError, "rld failure" },
8113 {kIOReturnDMAError, "DMA failure" },
8114 {kIOReturnBusy, "device is busy" },
8115 {kIOReturnTimeout, "I/O timeout" },
8116 {kIOReturnOffline, "device is offline" },
8117 {kIOReturnNotReady, "device is not ready" },
8118 {kIOReturnNotAttached, "device/channel is not attached" },
8119 {kIOReturnNoChannels, "no DMA channels available" },
8120 {kIOReturnNoSpace, "no space for data" },
8121 {kIOReturnPortExists, "device port already exists" },
8122 {kIOReturnCannotWire, "cannot wire physical memory" },
8123 {kIOReturnNoInterrupt, "no interrupt attached" },
8124 {kIOReturnNoFrames, "no DMA frames enqueued" },
8125 {kIOReturnMessageTooLarge, "message is too large" },
8126 {kIOReturnNotPermitted, "operation is not permitted" },
8127 {kIOReturnNoPower, "device is without power" },
8128 {kIOReturnNoMedia, "media is not present" },
8129 {kIOReturnUnformattedMedia, "media is not formatted" },
8130 {kIOReturnUnsupportedMode, "unsupported mode" },
8131 {kIOReturnUnderrun, "data underrun" },
8132 {kIOReturnOverrun, "data overrun" },
8133 {kIOReturnDeviceError, "device error" },
8134 {kIOReturnNoCompletion, "no completion routine" },
8135 {kIOReturnAborted, "operation was aborted" },
8136 {kIOReturnNoBandwidth, "bus bandwidth would be exceeded" },
8137 {kIOReturnNotResponding, "device is not responding" },
8138 {kIOReturnInvalid, "unanticipated driver error" },
8139 {0, NULL }
8140 };
8141
8142 return IOFindNameForValue(rtn, IOReturn_values);
8143 }
8144
8145 /*
8146 * Convert an IOReturn to an errno.
8147 */
8148 int
errnoFromReturn(IOReturn rtn)8149 IOService::errnoFromReturn( IOReturn rtn )
8150 {
8151 if (unix_err(err_get_code(rtn)) == rtn) {
8152 return err_get_code(rtn);
8153 }
8154
8155 switch (rtn) {
8156 // (obvious match)
8157 case kIOReturnSuccess:
8158 return 0;
8159 case kIOReturnNoMemory:
8160 return ENOMEM;
8161 case kIOReturnNoDevice:
8162 return ENXIO;
8163 case kIOReturnVMError:
8164 return EFAULT;
8165 case kIOReturnNotPermitted:
8166 return EPERM;
8167 case kIOReturnNotPrivileged:
8168 return EACCES;
8169 case kIOReturnIOError:
8170 return EIO;
8171 case kIOReturnNotWritable:
8172 return EROFS;
8173 case kIOReturnBadArgument:
8174 return EINVAL;
8175 case kIOReturnUnsupported:
8176 return ENOTSUP;
8177 case kIOReturnBusy:
8178 return EBUSY;
8179 case kIOReturnNoPower:
8180 return EPWROFF;
8181 case kIOReturnDeviceError:
8182 return EDEVERR;
8183 case kIOReturnTimeout:
8184 return ETIMEDOUT;
8185 case kIOReturnMessageTooLarge:
8186 return EMSGSIZE;
8187 case kIOReturnNoSpace:
8188 return ENOSPC;
8189 case kIOReturnCannotLock:
8190 return ENOLCK;
8191
8192 // (best match)
8193 case kIOReturnBadMessageID:
8194 case kIOReturnNoCompletion:
8195 case kIOReturnNotAligned:
8196 return EINVAL;
8197 case kIOReturnNotReady:
8198 return EBUSY;
8199 case kIOReturnRLDError:
8200 return EBADMACHO;
8201 case kIOReturnPortExists:
8202 case kIOReturnStillOpen:
8203 return EEXIST;
8204 case kIOReturnExclusiveAccess:
8205 case kIOReturnLockedRead:
8206 case kIOReturnLockedWrite:
8207 case kIOReturnNotOpen:
8208 case kIOReturnNotReadable:
8209 return EACCES;
8210 case kIOReturnCannotWire:
8211 case kIOReturnNoResources:
8212 return ENOMEM;
8213 case kIOReturnAborted:
8214 case kIOReturnOffline:
8215 case kIOReturnNotResponding:
8216 return EBUSY;
8217 case kIOReturnBadMedia:
8218 case kIOReturnNoMedia:
8219 case kIOReturnNotAttached:
8220 case kIOReturnUnformattedMedia:
8221 return ENXIO; // (media error)
8222 case kIOReturnDMAError:
8223 case kIOReturnOverrun:
8224 case kIOReturnUnderrun:
8225 return EIO; // (transfer error)
8226 case kIOReturnNoBandwidth:
8227 case kIOReturnNoChannels:
8228 case kIOReturnNoFrames:
8229 case kIOReturnNoInterrupt:
8230 return EIO; // (hardware error)
8231 case kIOReturnError:
8232 case kIOReturnInternalError:
8233 case kIOReturnInvalid:
8234 return EIO; // (generic error)
8235 case kIOReturnIPCError:
8236 return EIO; // (ipc error)
8237 default:
8238 return EIO; // (all other errors)
8239 }
8240 }
8241
8242 IOReturn
message(UInt32 type,IOService * provider,void * argument)8243 IOService::message( UInt32 type, IOService * provider,
8244 void * argument )
8245 {
8246 /*
8247 * Generic entry point for calls from the provider. A return value of
8248 * kIOReturnSuccess indicates that the message was received, and where
8249 * applicable, that it was successful.
8250 */
8251
8252 return kIOReturnUnsupported;
8253 }
8254
8255 /*
8256 * Device memory
8257 */
8258
8259 IOItemCount
getDeviceMemoryCount(void)8260 IOService::getDeviceMemoryCount( void )
8261 {
8262 OSArray * array;
8263 IOItemCount count;
8264
8265 array = OSDynamicCast( OSArray, getProperty( gIODeviceMemoryKey));
8266 if (array) {
8267 count = array->getCount();
8268 } else {
8269 count = 0;
8270 }
8271
8272 return count;
8273 }
8274
8275 IODeviceMemory *
getDeviceMemoryWithIndex(unsigned int index)8276 IOService::getDeviceMemoryWithIndex( unsigned int index )
8277 {
8278 OSArray * array;
8279 IODeviceMemory * range;
8280
8281 array = OSDynamicCast( OSArray, getProperty( gIODeviceMemoryKey));
8282 if (array) {
8283 range = (IODeviceMemory *) array->getObject( index );
8284 } else {
8285 range = NULL;
8286 }
8287
8288 return range;
8289 }
8290
8291 IOMemoryMap *
mapDeviceMemoryWithIndex(unsigned int index,IOOptionBits options)8292 IOService::mapDeviceMemoryWithIndex( unsigned int index,
8293 IOOptionBits options )
8294 {
8295 IODeviceMemory * range;
8296 IOMemoryMap * map;
8297
8298 range = getDeviceMemoryWithIndex( index );
8299 if (range) {
8300 map = range->map( options );
8301 } else {
8302 map = NULL;
8303 }
8304
8305 return map;
8306 }
8307
8308 OSArray *
getDeviceMemory(void)8309 IOService::getDeviceMemory( void )
8310 {
8311 return OSDynamicCast( OSArray, getProperty( gIODeviceMemoryKey));
8312 }
8313
8314
8315 void
setDeviceMemory(OSArray * array)8316 IOService::setDeviceMemory( OSArray * array )
8317 {
8318 setProperty( gIODeviceMemoryKey, array);
8319 }
8320
8321 static void
requireMaxCpuDelay(IOService * service,UInt32 ns,UInt32 delayType)8322 requireMaxCpuDelay(IOService * service, UInt32 ns, UInt32 delayType)
8323 {
8324 static const UInt kNoReplace = -1U; // Must be an illegal index
8325 UInt replace = kNoReplace;
8326 bool setCpuDelay = false;
8327
8328 IORecursiveLockLock(sCpuDelayLock);
8329
8330 UInt count = sCpuDelayData->getLength() / sizeof(CpuDelayEntry);
8331 CpuDelayEntry *entries = (CpuDelayEntry *) sCpuDelayData->getBytesNoCopy();
8332 IOService * holder = NULL;
8333
8334 if (ns) {
8335 const CpuDelayEntry ne = {service, ns, delayType};
8336 holder = service;
8337 // Set maximum delay.
8338 for (UInt i = 0; i < count; i++) {
8339 IOService *thisService = entries[i].fService;
8340 bool sameType = (delayType == entries[i].fDelayType);
8341 if ((service == thisService) && sameType) {
8342 replace = i;
8343 } else if (!thisService) {
8344 if (kNoReplace == replace) {
8345 replace = i;
8346 }
8347 } else if (sameType) {
8348 const UInt32 thisMax = entries[i].fMaxDelay;
8349 if (thisMax < ns) {
8350 ns = thisMax;
8351 holder = thisService;
8352 }
8353 }
8354 }
8355
8356 setCpuDelay = true;
8357 if (kNoReplace == replace) {
8358 sCpuDelayData->appendBytes(&ne, sizeof(ne));
8359 } else {
8360 entries[replace] = ne;
8361 }
8362 } else {
8363 ns = -1U; // Set to max unsigned, i.e. no restriction
8364
8365 for (UInt i = 0; i < count; i++) {
8366 // Clear a maximum delay.
8367 IOService *thisService = entries[i].fService;
8368 if (thisService && (delayType == entries[i].fDelayType)) {
8369 UInt32 thisMax = entries[i].fMaxDelay;
8370 if (service == thisService) {
8371 replace = i;
8372 } else if (thisMax < ns) {
8373 ns = thisMax;
8374 holder = thisService;
8375 }
8376 }
8377 }
8378
8379 // Check if entry found
8380 if (kNoReplace != replace) {
8381 entries[replace].fService = NULL; // Null the entry
8382 setCpuDelay = true;
8383 }
8384 }
8385
8386 if (setCpuDelay) {
8387 if (holder && debug_boot_arg) {
8388 strlcpy(sCPULatencyHolderName[delayType], holder->getName(), sizeof(sCPULatencyHolderName[delayType]));
8389 }
8390
8391 // Must be safe to call from locked context
8392 if (delayType == kCpuDelayBusStall) {
8393 #if defined(__x86_64__)
8394 ml_set_maxbusdelay(ns);
8395 #endif /* defined(__x86_64__) */
8396 }
8397 #if defined(__x86_64__)
8398 else if (delayType == kCpuDelayInterrupt) {
8399 ml_set_maxintdelay(ns);
8400 }
8401 #endif /* defined(__x86_64__) */
8402 sCPULatencyHolder[delayType]->setValue(holder ? holder->getRegistryEntryID() : 0);
8403 sCPULatencySet[delayType]->setValue(ns);
8404
8405 OSArray * handlers = sCpuLatencyHandlers[delayType];
8406 IOService * target;
8407 if (handlers) {
8408 for (unsigned int idx = 0;
8409 (target = (IOService *) handlers->getObject(idx));
8410 idx++) {
8411 target->callPlatformFunction(sCPULatencyFunctionName[delayType], false,
8412 (void *) (uintptr_t) ns, holder,
8413 NULL, NULL);
8414 }
8415 }
8416 }
8417
8418 IORecursiveLockUnlock(sCpuDelayLock);
8419 }
8420
8421 static IOReturn
setLatencyHandler(UInt32 delayType,IOService * target,bool enable)8422 setLatencyHandler(UInt32 delayType, IOService * target, bool enable)
8423 {
8424 IOReturn result = kIOReturnNotFound;
8425 OSArray * array;
8426 unsigned int idx;
8427
8428 IORecursiveLockLock(sCpuDelayLock);
8429
8430 do{
8431 if (enable && !sCpuLatencyHandlers[delayType]) {
8432 sCpuLatencyHandlers[delayType] = OSArray::withCapacity(4);
8433 }
8434 array = sCpuLatencyHandlers[delayType];
8435 if (!array) {
8436 break;
8437 }
8438 idx = array->getNextIndexOfObject(target, 0);
8439 if (!enable) {
8440 if (-1U != idx) {
8441 array->removeObject(idx);
8442 result = kIOReturnSuccess;
8443 }
8444 } else {
8445 if (-1U != idx) {
8446 result = kIOReturnExclusiveAccess;
8447 break;
8448 }
8449 array->setObject(target);
8450
8451 UInt count = sCpuDelayData->getLength() / sizeof(CpuDelayEntry);
8452 CpuDelayEntry *entries = (CpuDelayEntry *) sCpuDelayData->getBytesNoCopy();
8453 UInt32 ns = -1U; // Set to max unsigned, i.e. no restriction
8454 IOService * holder = NULL;
8455
8456 for (UInt i = 0; i < count; i++) {
8457 if (entries[i].fService
8458 && (delayType == entries[i].fDelayType)
8459 && (entries[i].fMaxDelay < ns)) {
8460 ns = entries[i].fMaxDelay;
8461 holder = entries[i].fService;
8462 }
8463 }
8464 target->callPlatformFunction(sCPULatencyFunctionName[delayType], false,
8465 (void *) (uintptr_t) ns, holder,
8466 NULL, NULL);
8467 result = kIOReturnSuccess;
8468 }
8469 }while (false);
8470
8471 IORecursiveLockUnlock(sCpuDelayLock);
8472
8473 return result;
8474 }
8475
8476 IOReturn
requireMaxBusStall(UInt32 ns)8477 IOService::requireMaxBusStall(UInt32 ns)
8478 {
8479 #if !defined(__x86_64__)
8480 switch (ns) {
8481 case kIOMaxBusStall40usec:
8482 case kIOMaxBusStall30usec:
8483 case kIOMaxBusStall25usec:
8484 case kIOMaxBusStall20usec:
8485 case kIOMaxBusStall10usec:
8486 case kIOMaxBusStall5usec:
8487 case kIOMaxBusStallNone:
8488 break;
8489 default:
8490 return kIOReturnBadArgument;
8491 }
8492 #endif /* !defined(__x86_64__) */
8493 requireMaxCpuDelay(this, ns, kCpuDelayBusStall);
8494 return kIOReturnSuccess;
8495 }
8496
8497 IOReturn
requireMaxInterruptDelay(uint32_t ns)8498 IOService::requireMaxInterruptDelay(uint32_t ns)
8499 {
8500 #if defined(__x86_64__)
8501 requireMaxCpuDelay(this, ns, kCpuDelayInterrupt);
8502 return kIOReturnSuccess;
8503 #else /* defined(__x86_64__) */
8504 return kIOReturnUnsupported;
8505 #endif /* defined(__x86_64__) */
8506 }
8507
8508 /*
8509 * Device interrupts
8510 */
8511
8512 IOReturn
resolveInterrupt(IOService * nub,int source)8513 IOService::resolveInterrupt(IOService *nub, int source)
8514 {
8515 IOInterruptController *interruptController;
8516 OSArray *array;
8517 OSData *data;
8518 OSSymbol *interruptControllerName;
8519 unsigned int numSources;
8520 IOInterruptSource *interruptSources;
8521 IOInterruptSourcePrivate *interruptSourcesPrivate;
8522
8523 // Get the parents list from the nub.
8524 array = OSDynamicCast(OSArray, nub->getProperty(gIOInterruptControllersKey));
8525 if (array == NULL) {
8526 return kIOReturnNoResources;
8527 }
8528
8529 // Allocate space for the IOInterruptSources if needed... then return early.
8530 if (nub->_interruptSources == NULL) {
8531 numSources = array->getCount();
8532 interruptSources = IONewZero(IOInterruptSource, numSources);
8533 interruptSourcesPrivate = IONewZero(IOInterruptSourcePrivate, numSources);
8534
8535 if (interruptSources == NULL || interruptSourcesPrivate == NULL) {
8536 IODelete(interruptSources, IOInterruptSource, numSources);
8537 IODelete(interruptSourcesPrivate, IOInterruptSourcePrivate, numSources);
8538 return kIOReturnNoMemory;
8539 }
8540
8541 nub->_numInterruptSources = numSources;
8542 nub->_interruptSources = interruptSources;
8543 nub->reserved->interruptSourcesPrivate = interruptSourcesPrivate;
8544 return kIOReturnSuccess;
8545 }
8546
8547 interruptControllerName = OSDynamicCast(OSSymbol, array->getObject(source));
8548 if (interruptControllerName == NULL) {
8549 return kIOReturnNoResources;
8550 }
8551
8552 interruptController = getPlatform()->lookUpInterruptController(interruptControllerName);
8553 if (interruptController == NULL) {
8554 return kIOReturnNoResources;
8555 }
8556
8557 // Get the interrupt numbers from the nub.
8558 array = OSDynamicCast(OSArray, nub->getProperty(gIOInterruptSpecifiersKey));
8559 if (array == NULL) {
8560 return kIOReturnNoResources;
8561 }
8562 data = OSDynamicCast(OSData, array->getObject(source));
8563 if (data == NULL) {
8564 return kIOReturnNoResources;
8565 }
8566
8567 // Set the interruptController and interruptSource in the nub's table.
8568 interruptSources = nub->_interruptSources;
8569 interruptSources[source].interruptController = interruptController;
8570 interruptSources[source].vectorData = data;
8571
8572 return kIOReturnSuccess;
8573 }
8574
8575 IOReturn
lookupInterrupt(int source,bool resolve,IOInterruptController ** interruptController)8576 IOService::lookupInterrupt(int source, bool resolve, IOInterruptController **interruptController)
8577 {
8578 IOReturn ret;
8579
8580 /* Make sure the _interruptSources are set */
8581 if (_interruptSources == NULL) {
8582 ret = resolveInterrupt(this, source);
8583 if (ret != kIOReturnSuccess) {
8584 return ret;
8585 }
8586 }
8587
8588 /* Make sure the local source number is valid */
8589 if ((source < 0) || (source >= _numInterruptSources)) {
8590 return kIOReturnNoInterrupt;
8591 }
8592
8593 /* Look up the contoller for the local source */
8594 *interruptController = _interruptSources[source].interruptController;
8595
8596 if (*interruptController == NULL) {
8597 if (!resolve) {
8598 return kIOReturnNoInterrupt;
8599 }
8600
8601 /* Try to resolve the interrupt */
8602 ret = resolveInterrupt(this, source);
8603 if (ret != kIOReturnSuccess) {
8604 return ret;
8605 }
8606
8607 *interruptController = _interruptSources[source].interruptController;
8608 }
8609
8610 return kIOReturnSuccess;
8611 }
8612
8613 IOReturn
registerInterrupt(int source,OSObject * target,IOInterruptAction handler,void * refCon)8614 IOService::registerInterrupt(int source, OSObject *target,
8615 IOInterruptAction handler,
8616 void *refCon)
8617 {
8618 IOInterruptController *interruptController;
8619 IOReturn ret;
8620
8621 ret = lookupInterrupt(source, true, &interruptController);
8622 if (ret != kIOReturnSuccess) {
8623 return ret;
8624 }
8625
8626 /* Register the source */
8627 return interruptController->registerInterrupt(this, source, target,
8628 (IOInterruptHandler)handler,
8629 refCon);
8630 }
8631
8632 static void
IOServiceInterruptActionToBlock(OSObject * target,void * refCon,IOService * nub,int source)8633 IOServiceInterruptActionToBlock( OSObject * target, void * refCon,
8634 IOService * nub, int source )
8635 {
8636 ((IOInterruptActionBlock)(refCon))(nub, source);
8637 }
8638
8639 IOReturn
registerInterruptBlock(int source,OSObject * target,IOInterruptActionBlock handler)8640 IOService::registerInterruptBlock(int source, OSObject *target,
8641 IOInterruptActionBlock handler)
8642 {
8643 IOReturn ret;
8644 void * block;
8645
8646 block = Block_copy(handler);
8647 if (!block) {
8648 return kIOReturnNoMemory;
8649 }
8650
8651 ret = registerInterrupt(source, target, &IOServiceInterruptActionToBlock, block);
8652 if (kIOReturnSuccess != ret) {
8653 Block_release(block);
8654 return ret;
8655 }
8656
8657 reserved->interruptSourcesPrivate[source].vectorBlock = block;
8658
8659 return ret;
8660 }
8661
8662 IOReturn
unregisterInterrupt(int source)8663 IOService::unregisterInterrupt(int source)
8664 {
8665 IOReturn ret;
8666 IOInterruptController *interruptController;
8667 IOInterruptSourcePrivate *priv;
8668 void *block;
8669
8670 ret = lookupInterrupt(source, false, &interruptController);
8671 if (ret != kIOReturnSuccess) {
8672 return ret;
8673 }
8674
8675 /* Unregister the source */
8676 priv = &reserved->interruptSourcesPrivate[source];
8677 block = priv->vectorBlock;
8678 ret = interruptController->unregisterInterrupt(this, source);
8679 if ((kIOReturnSuccess == ret) && (block = priv->vectorBlock)) {
8680 priv->vectorBlock = NULL;
8681 Block_release(block);
8682 }
8683
8684 return ret;
8685 }
8686
8687 IOReturn
addInterruptStatistics(IOInterruptAccountingData * statistics,int source)8688 IOService::addInterruptStatistics(IOInterruptAccountingData * statistics, int source)
8689 {
8690 IOReportLegend * legend = NULL;
8691 IOInterruptAccountingData * oldValue = NULL;
8692 IOInterruptAccountingReporter * newArray = NULL;
8693 char subgroupName[64];
8694 int newArraySize = 0;
8695 int i = 0;
8696
8697 if (source < 0) {
8698 return kIOReturnBadArgument;
8699 }
8700
8701 /*
8702 * We support statistics on a maximum of 256 interrupts per nub; if a nub
8703 * has more than 256 interrupt specifiers associated with it, and tries
8704 * to register a high interrupt index with interrupt accounting, panic.
8705 * Having more than 256 interrupts associated with a single nub is
8706 * probably a sign that something fishy is going on.
8707 */
8708 if (source > IA_INDEX_MAX) {
8709 panic("addInterruptStatistics called for an excessively large index (%d)", source);
8710 }
8711
8712 /*
8713 * TODO: This is ugly (wrapping a lock around an allocation). I'm only
8714 * leaving it as is because the likelihood of contention where we are
8715 * actually growing the array is minimal (we would realistically need
8716 * to be starting a driver for the first time, with an IOReporting
8717 * client already in place). Nonetheless, cleanup that can be done
8718 * to adhere to best practices; it'll make the code more complicated,
8719 * unfortunately.
8720 */
8721 IOLockLock(&reserved->interruptStatisticsLock);
8722
8723 /*
8724 * Lazily allocate the statistics array.
8725 */
8726 if (!reserved->interruptStatisticsArray) {
8727 reserved->interruptStatisticsArray = IONew(IOInterruptAccountingReporter, 1);
8728 assert(reserved->interruptStatisticsArray);
8729 reserved->interruptStatisticsArrayCount = 1;
8730 bzero(reserved->interruptStatisticsArray, sizeof(*reserved->interruptStatisticsArray));
8731 }
8732
8733 if (source >= reserved->interruptStatisticsArrayCount) {
8734 /*
8735 * We're still within the range of supported indices, but we are out
8736 * of space in the current array. Do a nasty realloc (because
8737 * IORealloc isn't a thing) here. We'll double the size with each
8738 * reallocation.
8739 *
8740 * Yes, the "next power of 2" could be more efficient; but this will
8741 * be invoked incredibly rarely. Who cares.
8742 */
8743 newArraySize = (reserved->interruptStatisticsArrayCount << 1);
8744
8745 while (newArraySize <= source) {
8746 newArraySize = (newArraySize << 1);
8747 }
8748 newArray = IONew(IOInterruptAccountingReporter, newArraySize);
8749
8750 assert(newArray);
8751
8752 /*
8753 * TODO: This even zeroes the memory it is about to overwrite.
8754 * Shameful; fix it. Not particularly high impact, however.
8755 */
8756 bzero(newArray, newArraySize * sizeof(*newArray));
8757 memcpy(newArray, reserved->interruptStatisticsArray, reserved->interruptStatisticsArrayCount * sizeof(*newArray));
8758 IODelete(reserved->interruptStatisticsArray, IOInterruptAccountingReporter, reserved->interruptStatisticsArrayCount);
8759 reserved->interruptStatisticsArray = newArray;
8760 reserved->interruptStatisticsArrayCount = newArraySize;
8761 }
8762
8763 if (!reserved->interruptStatisticsArray[source].reporter) {
8764 /*
8765 * We don't have a reporter associated with this index yet, so we
8766 * need to create one.
8767 */
8768 /*
8769 * TODO: Some statistics do in fact have common units (time); should this be
8770 * split into separate reporters to communicate this?
8771 */
8772 reserved->interruptStatisticsArray[source].reporter = IOSimpleReporter::with(this, kIOReportCategoryPower, kIOReportUnitNone);
8773
8774 /*
8775 * Each statistic is given an identifier based on the interrupt index (which
8776 * should be unique relative to any single nub) and the statistic involved.
8777 * We should now have a sane (small and positive) index, so start
8778 * constructing the channels for statistics.
8779 */
8780 for (i = 0; i < IA_NUM_INTERRUPT_ACCOUNTING_STATISTICS; i++) {
8781 /*
8782 * TODO: Currently, this does not add channels for disabled statistics.
8783 * Will this be confusing for clients? If so, we should just add the
8784 * channels; we can avoid updating the channels even if they exist.
8785 */
8786 if (IA_GET_STATISTIC_ENABLED(i)) {
8787 reserved->interruptStatisticsArray[source].reporter->addChannel(IA_GET_CHANNEL_ID(source, i), kInterruptAccountingStatisticNameArray[i]);
8788 }
8789 }
8790
8791 /*
8792 * We now need to add the legend for this reporter to the registry.
8793 */
8794 OSObject * prop = copyProperty(kIOReportLegendKey);
8795 legend = IOReportLegend::with(OSDynamicCast(OSArray, prop));
8796 OSSafeReleaseNULL(prop);
8797
8798 /*
8799 * Note that while we compose the subgroup name, we do not need to
8800 * manage its lifecycle (the reporter will handle this).
8801 */
8802 snprintf(subgroupName, sizeof(subgroupName), "%s %d", getName(), source);
8803 subgroupName[sizeof(subgroupName) - 1] = 0;
8804 legend->addReporterLegend(reserved->interruptStatisticsArray[source].reporter, kInterruptAccountingGroupName, subgroupName);
8805 setProperty(kIOReportLegendKey, legend->getLegend());
8806 legend->release();
8807
8808 /*
8809 * TODO: Is this a good idea? Probably not; my assumption is it opts
8810 * all entities who register interrupts into public disclosure of all
8811 * IOReporting channels. Unfortunately, this appears to be as fine
8812 * grain as it gets.
8813 */
8814 setProperty(kIOReportLegendPublicKey, true);
8815 }
8816
8817 /*
8818 * Don't stomp existing entries. If we are about to, panic; this
8819 * probably means we failed to tear down our old interrupt source
8820 * correctly.
8821 */
8822 oldValue = reserved->interruptStatisticsArray[source].statistics;
8823
8824 if (oldValue) {
8825 panic("addInterruptStatistics call for index %d would have clobbered existing statistics", source);
8826 }
8827
8828 reserved->interruptStatisticsArray[source].statistics = statistics;
8829
8830 /*
8831 * Inherit the reporter values for each statistic. The target may
8832 * be torn down as part of the runtime of the service (especially
8833 * for sleep/wake), so we inherit in order to avoid having values
8834 * reset for no apparent reason. Our statistics are ultimately
8835 * tied to the index and the sevice, not to an individual target,
8836 * so we should maintain them accordingly.
8837 */
8838 interruptAccountingDataInheritChannels(reserved->interruptStatisticsArray[source].statistics, reserved->interruptStatisticsArray[source].reporter);
8839
8840 IOLockUnlock(&reserved->interruptStatisticsLock);
8841
8842 return kIOReturnSuccess;
8843 }
8844
8845 IOReturn
removeInterruptStatistics(int source)8846 IOService::removeInterruptStatistics(int source)
8847 {
8848 IOInterruptAccountingData * value = NULL;
8849
8850 if (source < 0) {
8851 return kIOReturnBadArgument;
8852 }
8853
8854 IOLockLock(&reserved->interruptStatisticsLock);
8855
8856 /*
8857 * We dynamically grow the statistics array, so an excessively
8858 * large index value has NEVER been registered. This either
8859 * means our cap on the array size is too small (unlikely), or
8860 * that we have been passed a corrupt index (this must be passed
8861 * the plain index into the interrupt specifier list).
8862 */
8863 if (source >= reserved->interruptStatisticsArrayCount) {
8864 panic("removeInterruptStatistics called for index %d, which was never registered", source);
8865 }
8866
8867 assert(reserved->interruptStatisticsArray);
8868
8869 /*
8870 * If there is no existing entry, we are most likely trying to
8871 * free an interrupt owner twice, or we have corrupted the
8872 * index value.
8873 */
8874 value = reserved->interruptStatisticsArray[source].statistics;
8875
8876 if (!value) {
8877 panic("removeInterruptStatistics called for empty index %d", source);
8878 }
8879
8880 /*
8881 * We update the statistics, so that any delta with the reporter
8882 * state is not lost.
8883 */
8884 interruptAccountingDataUpdateChannels(reserved->interruptStatisticsArray[source].statistics, reserved->interruptStatisticsArray[source].reporter);
8885 reserved->interruptStatisticsArray[source].statistics = NULL;
8886 IOLockUnlock(&reserved->interruptStatisticsLock);
8887
8888 return kIOReturnSuccess;
8889 }
8890
8891 IOReturn
getInterruptType(int source,int * interruptType)8892 IOService::getInterruptType(int source, int *interruptType)
8893 {
8894 IOInterruptController *interruptController;
8895 IOReturn ret;
8896
8897 ret = lookupInterrupt(source, true, &interruptController);
8898 if (ret != kIOReturnSuccess) {
8899 return ret;
8900 }
8901
8902 /* Return the type */
8903 return interruptController->getInterruptType(this, source, interruptType);
8904 }
8905
8906 IOReturn
enableInterrupt(int source)8907 IOService::enableInterrupt(int source)
8908 {
8909 IOInterruptController *interruptController;
8910 IOReturn ret;
8911
8912 ret = lookupInterrupt(source, false, &interruptController);
8913 if (ret != kIOReturnSuccess) {
8914 return ret;
8915 }
8916
8917 /* Enable the source */
8918 return interruptController->enableInterrupt(this, source);
8919 }
8920
8921 IOReturn
disableInterrupt(int source)8922 IOService::disableInterrupt(int source)
8923 {
8924 IOInterruptController *interruptController;
8925 IOReturn ret;
8926
8927 ret = lookupInterrupt(source, false, &interruptController);
8928 if (ret != kIOReturnSuccess) {
8929 return ret;
8930 }
8931
8932 /* Disable the source */
8933 return interruptController->disableInterrupt(this, source);
8934 }
8935
8936 IOReturn
causeInterrupt(int source)8937 IOService::causeInterrupt(int source)
8938 {
8939 IOInterruptController *interruptController;
8940 IOReturn ret;
8941
8942 ret = lookupInterrupt(source, false, &interruptController);
8943 if (ret != kIOReturnSuccess) {
8944 return ret;
8945 }
8946
8947 /* Cause an interrupt for the source */
8948 return interruptController->causeInterrupt(this, source);
8949 }
8950
8951 IOReturn
configureReport(IOReportChannelList * channelList,IOReportConfigureAction action,void * result,void * destination)8952 IOService::configureReport(IOReportChannelList *channelList,
8953 IOReportConfigureAction action,
8954 void *result,
8955 void *destination)
8956 {
8957 unsigned cnt;
8958
8959 for (cnt = 0; cnt < channelList->nchannels; cnt++) {
8960 if (channelList->channels[cnt].channel_id == kPMPowerStatesChID) {
8961 if (pwrMgt) {
8962 configurePowerStatesReport(action, result);
8963 } else {
8964 return kIOReturnUnsupported;
8965 }
8966 } else if (channelList->channels[cnt].channel_id == kPMCurrStateChID) {
8967 if (pwrMgt) {
8968 configureSimplePowerReport(action, result);
8969 } else {
8970 return kIOReturnUnsupported;
8971 }
8972 }
8973 }
8974
8975 IOLockLock(&reserved->interruptStatisticsLock);
8976
8977 /* The array count is signed (because the interrupt indices are signed), hence the cast */
8978 for (cnt = 0; cnt < (unsigned) reserved->interruptStatisticsArrayCount; cnt++) {
8979 if (reserved->interruptStatisticsArray[cnt].reporter) {
8980 /*
8981 * If the reporter is currently associated with the statistics
8982 * for an event source, we may need to update the reporter.
8983 */
8984 if (reserved->interruptStatisticsArray[cnt].statistics) {
8985 interruptAccountingDataUpdateChannels(reserved->interruptStatisticsArray[cnt].statistics, reserved->interruptStatisticsArray[cnt].reporter);
8986 }
8987
8988 reserved->interruptStatisticsArray[cnt].reporter->configureReport(channelList, action, result, destination);
8989 }
8990 }
8991
8992 IOLockUnlock(&reserved->interruptStatisticsLock);
8993
8994 if (hasUserServer()) {
8995 return _ConfigureReport(channelList, action, result, destination);
8996 } else {
8997 return kIOReturnSuccess;
8998 }
8999 }
9000
9001 IOReturn
updateReport(IOReportChannelList * channelList,IOReportUpdateAction action,void * result,void * destination)9002 IOService::updateReport(IOReportChannelList *channelList,
9003 IOReportUpdateAction action,
9004 void *result,
9005 void *destination)
9006 {
9007 unsigned cnt;
9008
9009 for (cnt = 0; cnt < channelList->nchannels; cnt++) {
9010 if (channelList->channels[cnt].channel_id == kPMPowerStatesChID) {
9011 if (pwrMgt) {
9012 updatePowerStatesReport(action, result, destination);
9013 } else {
9014 return kIOReturnUnsupported;
9015 }
9016 } else if (channelList->channels[cnt].channel_id == kPMCurrStateChID) {
9017 if (pwrMgt) {
9018 updateSimplePowerReport(action, result, destination);
9019 } else {
9020 return kIOReturnUnsupported;
9021 }
9022 }
9023 }
9024
9025 IOLockLock(&reserved->interruptStatisticsLock);
9026
9027 /* The array count is signed (because the interrupt indices are signed), hence the cast */
9028 for (cnt = 0; cnt < (unsigned) reserved->interruptStatisticsArrayCount; cnt++) {
9029 if (reserved->interruptStatisticsArray[cnt].reporter) {
9030 /*
9031 * If the reporter is currently associated with the statistics
9032 * for an event source, we need to update the reporter.
9033 */
9034 if (reserved->interruptStatisticsArray[cnt].statistics) {
9035 interruptAccountingDataUpdateChannels(reserved->interruptStatisticsArray[cnt].statistics, reserved->interruptStatisticsArray[cnt].reporter);
9036 }
9037
9038 reserved->interruptStatisticsArray[cnt].reporter->updateReport(channelList, action, result, destination);
9039 }
9040 }
9041
9042 IOLockUnlock(&reserved->interruptStatisticsLock);
9043
9044
9045 if (hasUserServer()) {
9046 return _UpdateReport(channelList, action, result, destination);
9047 } else {
9048 return kIOReturnSuccess;
9049 }
9050 }
9051
9052 uint64_t
getAuthorizationID(void)9053 IOService::getAuthorizationID( void )
9054 {
9055 return reserved->authorizationID;
9056 }
9057
9058 IOReturn
setAuthorizationID(uint64_t authorizationID)9059 IOService::setAuthorizationID( uint64_t authorizationID )
9060 {
9061 OSObject * entitlement;
9062 IOReturn status;
9063
9064 entitlement = IOUserClient::copyClientEntitlement( current_task(), "com.apple.private.iokit.IOServiceSetAuthorizationID" );
9065
9066 if (entitlement) {
9067 if (entitlement == kOSBooleanTrue) {
9068 reserved->authorizationID = authorizationID;
9069
9070 status = kIOReturnSuccess;
9071 } else {
9072 status = kIOReturnNotPrivileged;
9073 }
9074
9075 entitlement->release();
9076 } else {
9077 status = kIOReturnNotPrivileged;
9078 }
9079
9080 return status;
9081 }
9082
9083 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9084
9085 #if __LP64__
9086 OSMetaClassDefineReservedUsedX86(IOService, 0);
9087 OSMetaClassDefineReservedUsedX86(IOService, 1);
9088 OSMetaClassDefineReservedUnused(IOService, 2);
9089 OSMetaClassDefineReservedUnused(IOService, 3);
9090 OSMetaClassDefineReservedUnused(IOService, 4);
9091 OSMetaClassDefineReservedUnused(IOService, 5);
9092 OSMetaClassDefineReservedUnused(IOService, 6);
9093 OSMetaClassDefineReservedUnused(IOService, 7);
9094 #else
9095 OSMetaClassDefineReservedUsedX86(IOService, 0);
9096 OSMetaClassDefineReservedUsedX86(IOService, 1);
9097 OSMetaClassDefineReservedUsedX86(IOService, 2);
9098 OSMetaClassDefineReservedUsedX86(IOService, 3);
9099 OSMetaClassDefineReservedUsedX86(IOService, 4);
9100 OSMetaClassDefineReservedUsedX86(IOService, 5);
9101 OSMetaClassDefineReservedUsedX86(IOService, 6);
9102 OSMetaClassDefineReservedUsedX86(IOService, 7);
9103 #endif
9104 OSMetaClassDefineReservedUnused(IOService, 8);
9105 OSMetaClassDefineReservedUnused(IOService, 9);
9106 OSMetaClassDefineReservedUnused(IOService, 10);
9107 OSMetaClassDefineReservedUnused(IOService, 11);
9108 OSMetaClassDefineReservedUnused(IOService, 12);
9109 OSMetaClassDefineReservedUnused(IOService, 13);
9110 OSMetaClassDefineReservedUnused(IOService, 14);
9111 OSMetaClassDefineReservedUnused(IOService, 15);
9112 OSMetaClassDefineReservedUnused(IOService, 16);
9113 OSMetaClassDefineReservedUnused(IOService, 17);
9114 OSMetaClassDefineReservedUnused(IOService, 18);
9115 OSMetaClassDefineReservedUnused(IOService, 19);
9116 OSMetaClassDefineReservedUnused(IOService, 20);
9117 OSMetaClassDefineReservedUnused(IOService, 21);
9118 OSMetaClassDefineReservedUnused(IOService, 22);
9119 OSMetaClassDefineReservedUnused(IOService, 23);
9120 OSMetaClassDefineReservedUnused(IOService, 24);
9121 OSMetaClassDefineReservedUnused(IOService, 25);
9122 OSMetaClassDefineReservedUnused(IOService, 26);
9123 OSMetaClassDefineReservedUnused(IOService, 27);
9124 OSMetaClassDefineReservedUnused(IOService, 28);
9125 OSMetaClassDefineReservedUnused(IOService, 29);
9126 OSMetaClassDefineReservedUnused(IOService, 30);
9127 OSMetaClassDefineReservedUnused(IOService, 31);
9128 OSMetaClassDefineReservedUnused(IOService, 32);
9129 OSMetaClassDefineReservedUnused(IOService, 33);
9130 OSMetaClassDefineReservedUnused(IOService, 34);
9131 OSMetaClassDefineReservedUnused(IOService, 35);
9132 OSMetaClassDefineReservedUnused(IOService, 36);
9133 OSMetaClassDefineReservedUnused(IOService, 37);
9134 OSMetaClassDefineReservedUnused(IOService, 38);
9135 OSMetaClassDefineReservedUnused(IOService, 39);
9136 OSMetaClassDefineReservedUnused(IOService, 40);
9137 OSMetaClassDefineReservedUnused(IOService, 41);
9138 OSMetaClassDefineReservedUnused(IOService, 42);
9139 OSMetaClassDefineReservedUnused(IOService, 43);
9140 OSMetaClassDefineReservedUnused(IOService, 44);
9141 OSMetaClassDefineReservedUnused(IOService, 45);
9142 OSMetaClassDefineReservedUnused(IOService, 46);
9143 OSMetaClassDefineReservedUnused(IOService, 47);
9144