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