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