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