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