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