*/
#include <IOKit/system.h>
-
#include <IOKit/IOService.h>
#include <libkern/OSDebug.h>
#include <libkern/c++/OSContainers.h>
#include <libkern/c++/OSKext.h>
#include <libkern/c++/OSUnserialize.h>
+#include <libkern/c++/OSKext.h>
#include <libkern/Block.h>
#include <IOKit/IOCatalogue.h>
#include <IOKit/IOCommand.h>
#include <IOKit/IOKitKeysPrivate.h>
#include <IOKit/IOBSD.h>
#include <IOKit/IOUserClient.h>
+#include <IOKit/IOUserServer.h>
#include <IOKit/IOWorkLoop.h>
#include <IOKit/IOTimeStamp.h>
#include <IOKit/IOHibernatePrivate.h>
#include <IOKit/pwr_mgt/RootDomain.h>
#include <IOKit/IOCPU.h>
#include <mach/sync_policy.h>
+#include <mach/thread_info.h>
#include <IOKit/assert.h>
#include <sys/errno.h>
#include <sys/kdebug.h>
// disabled since lockForArbitration() can be held externally
#define DEBUG_NOTIFIER_LOCKED 0
+enum{
+ kIOUserServerCheckInTimeoutSecs = 120ULL
+};
+
#include "IOServicePrivate.h"
#include "IOKitKernelInternal.h"
OSDefineMetaClassAndStructors(_IOServiceJob, OSObject)
OSDefineMetaClassAndStructors(IOResources, IOService)
+OSDefineMetaClassAndStructors(IOUserResources, IOService)
OSDefineMetaClassAndStructors(_IOOpenServiceIterator, OSIterator)
const OSSymbol * gIOInterruptSpecifiersKey;
const OSSymbol * gIOResourcesKey;
+const OSSymbol * gIOUserResourcesKey;
const OSSymbol * gIOResourceMatchKey;
const OSSymbol * gIOResourceMatchedKey;
+const OSSymbol * gIOResourceIOKitKey;
+
const OSSymbol * gIOProviderClassKey;
const OSSymbol * gIONameMatchKey;
const OSSymbol * gIONameMatchedKey;
const OSSymbol * gIOMatchCategoryKey;
const OSSymbol * gIODefaultMatchCategoryKey;
const OSSymbol * gIOMatchedServiceCountKey;
+const OSSymbol * gIOMatchedPersonalityKey;
+const OSSymbol * gIORematchPersonalityKey;
+const OSSymbol * gIORematchCountKey;
+const OSSymbol * gIODEXTMatchCountKey;
+const OSSymbol * gIOSupportedPropertiesKey;
+const OSSymbol * gIOUserServicePropertiesKey;
#if !CONFIG_EMBEDDED
const OSSymbol * gIOServiceLegacyMatchingRegistryIDKey;
#endif
const OSSymbol * gIOMapperIDKey;
const OSSymbol * gIOUserClientClassKey;
+
+const OSSymbol * gIOUserClassKey;
+const OSSymbol * gIOUserServerClassKey;
+const OSSymbol * gIOUserServerNameKey;
+const OSSymbol * gIOUserServerTagKey;
+const OSSymbol * gIOUserServerCDHashKey;
+const OSSymbol * gIOUserUserClientKey;
+
const OSSymbol * gIOKitDebugKey;
const OSSymbol * gIOCommandPoolSizeKey;
const OSSymbol * gIOTerminatedNotification;
const OSSymbol * gIOWillTerminateNotification;
+const OSSymbol * gIOServiceDEXTEntitlementsKey;
+const OSSymbol * gIODriverKitEntitlementKey;
+const OSSymbol * gIODriverKitUserClientEntitlementsKey;
+const OSSymbol * gIODriverKitUserClientEntitlementAllowAnyKey;
+const OSSymbol * gIOMatchDeferKey;
+
const OSSymbol * gIOGeneralInterest;
const OSSymbol * gIOBusyInterest;
const OSSymbol * gIOAppPowerStateInterest;
static IORecursiveLock * gNotificationLock;
static IOService * gIOResources;
+static IOService * gIOUserResources;
static IOService * gIOServiceRoot;
static OSOrderedSet * gJobs;
static int gNumWaitingThreads;
static IOLock * gIOServiceBusyLock;
bool gCPUsRunning;
+bool gKextdWillTerminate;
static thread_t gIOTerminateThread;
static thread_t gIOTerminateWorkerThread;
static OSArray * gIOStopProviderList;
static OSArray * gIOFinalizeList;
+#if !NO_KEXTD
+static OSArray * gIOMatchDeferList;
+#endif
+
static SInt32 gIOConsoleUsersSeed;
static OSData * gIOConsoleUsersSeedValue;
const OSSymbol * gIOPlatformFunctionHandlerSet;
+
static IOLock * gIOConsoleUsersLock;
static thread_call_t gIOConsoleLockCallout;
static IONotifier * gIOServiceNullNotifier;
+static uint32_t gIODextRelaunchMax = 1000;
+
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#define LOCKREADNOTIFY() \
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+namespace IOServicePH
+{
+IONotifier * fRootNotifier;
+OSArray * fUserServers;
+OSArray * fUserServersWait;
+OSArray * fMatchingWork;
+OSArray * fMatchingDelayed;
+IOService * fSystemPowerAckTo;
+uint32_t fSystemPowerAckRef;
+uint8_t fSystemOff;
+uint8_t fUserServerOff;
+
+void lock();
+void unlock();
+
+void init(IOPMrootDomain * root);
+
+IOReturn systemPowerChange(
+ void * target,
+ void * refCon,
+ UInt32 messageType, IOService * service,
+ void * messageArgument, vm_size_t argSize);
+
+bool matchingStart(IOService * service);
+void matchingEnd(IOService * service);
+};
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
void
IOService::initialize( void )
{
kIODefaultMatchCategoryKey );
gIOMatchedServiceCountKey = OSSymbol::withCStringNoCopy(
kIOMatchedServiceCountKey );
+ gIOMatchedPersonalityKey = OSSymbol::withCStringNoCopy(
+ kIOMatchedPersonalityKey );
+ gIORematchPersonalityKey = OSSymbol::withCStringNoCopy(
+ kIORematchPersonalityKey );
+ gIORematchCountKey = OSSymbol::withCStringNoCopy(
+ kIORematchCountKey );
+ gIODEXTMatchCountKey = OSSymbol::withCStringNoCopy(
+ kIODEXTMatchCountKey );
+
#if !CONFIG_EMBEDDED
gIOServiceLegacyMatchingRegistryIDKey = OSSymbol::withCStringNoCopy(
kIOServiceLegacyMatchingRegistryIDKey );
#endif
+ PE_parse_boot_argn("dextrelaunch", &gIODextRelaunchMax, sizeof(gIODextRelaunchMax));
+
gIOUserClientClassKey = OSSymbol::withCStringNoCopy( kIOUserClientClassKey );
+ gIOUserClassKey = OSSymbol::withCStringNoCopy(kIOUserClassKey);
+
+ gIOUserServerClassKey = OSSymbol::withCStringNoCopy(kIOUserServerClassKey);
+ gIOUserServerNameKey = OSSymbol::withCStringNoCopy(kIOUserServerNameKey);
+ gIOUserServerTagKey = OSSymbol::withCStringNoCopy(kIOUserServerTagKey);
+ gIOUserServerCDHashKey = OSSymbol::withCStringNoCopy(kIOUserServerCDHashKey);
+ gIOUserUserClientKey = OSSymbol::withCStringNoCopy(kIOUserUserClientKey);
+
gIOResourcesKey = OSSymbol::withCStringNoCopy( kIOResourcesClass );
gIOResourceMatchKey = OSSymbol::withCStringNoCopy( kIOResourceMatchKey );
gIOResourceMatchedKey = OSSymbol::withCStringNoCopy( kIOResourceMatchedKey );
+ gIOResourceIOKitKey = OSSymbol::withCStringNoCopy("IOKit");
gIODeviceMemoryKey = OSSymbol::withCStringNoCopy( "IODeviceMemory" );
gIOInterruptControllersKey
gIOInterruptSpecifiersKey
= OSSymbol::withCStringNoCopy("IOInterruptSpecifiers");
+ gIOSupportedPropertiesKey = OSSymbol::withCStringNoCopy(kIOSupportedPropertiesKey);
+ gIOUserServicePropertiesKey = OSSymbol::withCStringNoCopy(kIOUserServicePropertiesKey);
+
gIOMapperIDKey = OSSymbol::withCStringNoCopy(kIOMapperIDKey);
gIOKitDebugKey = OSSymbol::withCStringNoCopy( kIOKitDebugKey );
kIOWillTerminateNotification );
gIOServiceKey = OSSymbol::withCStringNoCopy( kIOServiceClass);
+
gIOConsoleLockedKey = OSSymbol::withCStringNoCopy( kIOConsoleLockedKey);
gIOConsoleUsersKey = OSSymbol::withCStringNoCopy( kIOConsoleUsersKey);
gIOConsoleSessionUIDKey = OSSymbol::withCStringNoCopy( kIOConsoleSessionUIDKey);
gIOConsoleUsersSeedValue = OSData::withBytesNoCopy(&gIOConsoleUsersSeed, sizeof(gIOConsoleUsersSeed));
+ gIOServiceDEXTEntitlementsKey = OSSymbol::withCStringNoCopy( kIOServiceDEXTEntitlementsKey );
+ gIODriverKitEntitlementKey = OSSymbol::withCStringNoCopy( kIODriverKitEntitlementKey );
+ gIODriverKitUserClientEntitlementsKey = OSSymbol::withCStringNoCopy( kIODriverKitUserClientEntitlementsKey );
+ gIODriverKitUserClientEntitlementAllowAnyKey = OSSymbol::withCStringNoCopy( kIODriverKitUserClientEntitlementAllowAnyKey );
+ gIOMatchDeferKey = OSSymbol::withCStringNoCopy( kIOMatchDeferKey );
+
gIOPlatformFunctionHandlerSet = OSSymbol::withCStringNoCopy(kIOPlatformFunctionHandlerSet);
#if defined(__i386__) || defined(__x86_64__)
sCPULatencyFunctionName[kCpuDelayBusStall] = OSSymbol::withCStringNoCopy(kIOPlatformFunctionHandlerMaxBusDelay);
&& gIOConsoleLockCallout && (err == KERN_SUCCESS));
gIOResources = IOResources::resources();
- assert( gIOResources );
+ gIOUserResources = IOUserResources::resources();
+ assert( gIOResources && gIOUserResources );
gIOServiceNullNotifier = OSTypeAlloc(_IOServiceNullNotifier);
assert(gIOServiceNullNotifier);
gIOStopList = OSArray::withCapacity( 16 );
gIOStopProviderList = OSArray::withCapacity( 16 );
gIOFinalizeList = OSArray::withCapacity( 16 );
+#if !NO_KEXTD
+ gIOMatchDeferList = OSArray::withCapacity( 16 );
+#endif
assert( gIOTerminatePhase2List && gIOStopList && gIOStopProviderList && gIOFinalizeList );
// worker thread that is responsible for terminating / cleaning up threads
void
IOService::stop( IOService * provider )
{
+ if (reserved->uvars && reserved->uvars->started && reserved->uvars->userServer) {
+ reserved->uvars->userServer->serviceStop(this, provider);
+ }
}
bool
if (reserved->interruptStatisticsLock) {
IOLockFree(reserved->interruptStatisticsLock);
}
+ if (reserved->uvars && reserved->uvars->userServer) {
+ reserved->uvars->userServer->serviceFree(this);
+ }
IODelete(reserved, ExpansionData, 1);
}
}
IOFree(_interruptSources,
_numInterruptSources * sizeofAllIOInterruptSource);
- _interruptSources = 0;
+ _interruptSources = NULL;
}
super::free();
void
IOService::detach( IOService * provider )
{
- IOService * newProvider = 0;
+ IOService * newProvider = NULL;
SInt32 busy;
bool adjParent;
LOG("%s::detach(%s)\n", getName(), provider->getName());
}
+#if !NO_KEXTD
+ IOLockLock(gJobsLock);
+ if (gIOMatchDeferList) {
+ auto idx = gIOMatchDeferList->getNextIndexOfObject(this, 0);
+ if (-1U != idx) {
+ gIOMatchDeferList->removeObject(idx);
+ }
+ }
+ if (IOServicePH::fMatchingDelayed) {
+ auto idx = IOServicePH::fMatchingDelayed->getNextIndexOfObject(this, 0);
+ if (-1U != idx) {
+ IOServicePH::fMatchingDelayed->removeObject(idx);
+ }
+ }
+ IOLockUnlock(gJobsLock);
+#endif /* NO_KEXTD */
+
lockForArbitration();
uint64_t regID1 = provider->getRegistryEntryID();
if (busy) {
newProvider = getProvider();
- if (busy && (__state[1] & kIOServiceTermPhase3State) && (0 == newProvider)) {
+ if (busy && (__state[1] & kIOServiceTermPhase3State) && (NULL == newProvider)) {
_adjustBusy( -busy );
}
}
provider->_adjustBusy( -1 );
}
if ((provider->__state[1] & kIOServiceTermPhase3State)
- && (0 == provider->getClient())) {
+ && (NULL == provider->getClient())) {
provider->scheduleFinalize(false);
}
thread_wakeup((event_t) this /*&__state[1]*/ );
IOLockUnlock( gIOServiceBusyLock );
} else if (!sync || (kIOServiceAsynchronous & options)) {
- ok = (0 != _IOServiceJob::startJob( this, kMatchNubJob, options ));
+ ok = (NULL != _IOServiceJob::startJob( this, kMatchNubJob, options ));
} else {
do {
if ((__state[1] & kIOServiceNeedConfigState)) {
}
}
+
+void
+IOService::startDeferredMatches(void)
+{
+#if !NO_KEXTD
+ OSArray * array;
+
+ IOLockLock(gJobsLock);
+ array = gIOMatchDeferList;
+ gIOMatchDeferList = NULL;
+ IOLockUnlock(gJobsLock);
+
+ if (array) {
+ IOLog("deferred rematching count %d\n", array->getCount());
+ array->iterateObjects(^bool (OSObject * obj)
+ {
+ ((IOService *)obj)->startMatching(kIOServiceAsynchronous);
+ return false;
+ });
+ array->release();
+ }
+#endif /* !NO_KEXTD */
+}
+
+void
+IOService::kextdLaunched(void)
+{
+#if !NO_KEXTD
+ IOServiceTrace(IOSERVICE_KEXTD_READY, 0, 0, 0, 0);
+ startDeferredMatches();
+ getServiceRoot()->adjustBusy(-1);
+ IOService::publishUserResource(gIOResourceIOKitKey);
+#endif /* !NO_KEXTD */
+}
+
IOReturn
IOService::catalogNewDrivers( OSOrderedSet * newTables )
{
OSDictionary * table;
OSSet * set;
- OSSet * allSet = 0;
+ OSSet * allSet = NULL;
IOService * service;
#if IOMATCHDEBUG
SInt32 count = 0;
job = new _IOServiceJob;
if (job && !job->init()) {
job->release();
- job = 0;
+ job = NULL;
}
if (job) {
parent = (IOService *) getParentEntry( gIOServicePlane);
if (parent == IORegistryEntry::getRegistryRoot()) {
/* root is not an IOService */
- parent = 0;
+ parent = NULL;
}
self->__provider = parent;
if (provider) {
return provider->getWorkLoop();
} else {
- return 0;
+ return NULL;
}
}
_IOOpenServiceIterator * inst;
if (!_iter) {
- return 0;
+ return NULL;
}
inst = new _IOOpenServiceIterator;
if (inst && !inst->init()) {
inst->release();
- inst = 0;
+ inst = NULL;
}
if (inst) {
inst->iter = _iter;
{
if (last) {
last->unlockForArbitration();
- last = 0;
+ last = NULL;
}
iter->reset();
}
OSIterator *
IOService::getOpenProviderIterator( void ) const
{
- return _IOOpenServiceIterator::iterator( getProviderIterator(), this, 0 );
+ return _IOOpenServiceIterator::iterator( getProviderIterator(), this, NULL );
}
OSIterator *
IOService::getOpenClientIterator( void ) const
{
- return _IOOpenServiceIterator::iterator( getClientIterator(), 0, this );
+ return _IOOpenServiceIterator::iterator( getClientIterator(), NULL, this );
}
IOReturn result = kIOReturnUnsupported;
IOService *provider;
+ if (functionName == gIOPlatformQuiesceActionKey ||
+ functionName == gIOPlatformActiveActionKey) {
+ /*
+ * Services which register for IOPlatformQuiesceAction / IOPlatformActiveAction
+ * must consume that event themselves, without passing it up to super/IOService.
+ */
+ if (gEnforceQuiesceSafety) {
+ panic("Class %s passed the quiesce/active action to IOService",
+ getMetaClass()->getClassName());
+ }
+ }
+
if (gIOPlatformFunctionHandlerSet == functionName) {
#if defined(__i386__) || defined(__x86_64__)
const OSSymbol * functionHandlerName = (const OSSymbol *) param1;
IOService * target = (IOService *) param2;
- bool enable = (param3 != 0);
+ bool enable = (param3 != NULL);
if (sCPULatencyFunctionName[kCpuDelayBusStall] == functionHandlerName) {
result = setLatencyHandler(kCpuDelayBusStall, target, enable);
IOReturn result = kIOReturnNoMemory;
const OSSymbol *functionSymbol = OSSymbol::withCString(functionName);
- if (functionSymbol != 0) {
+ if (functionSymbol != NULL) {
result = callPlatformFunction(functionSymbol, waitForFunction,
param1, param2, param3, param4);
functionSymbol->release();
{
gIOPlatform = platform;
gIOResources->attachToParent( gIOServiceRoot, gIOServicePlane );
+ gIOUserResources->attachToParent( gIOServiceRoot, gIOServicePlane );
#if defined(__i386__) || defined(__x86_64__)
IOService::setPMRootDomain( class IOPMrootDomain * rootDomain)
{
gIOPMRootDomain = rootDomain;
- publishResource("IOKit");
+ publishResource(gIOResourceIOKitKey);
+ IOServicePH::init(rootDomain);
}
/*
if (found) { // this object is already locked
// determine whether it is the same or a different thread trying to lock
if (active->thread != element->thread) { // it is a different thread
- ArbitrationLockQueueElement * victim = 0;
+ ArbitrationLockQueueElement * victim = NULL;
// before placing this new thread on the waiting queue, we look for
// a deadlock cycle...
OSObjectApplierFunction applier,
void * context )
{
- OSArray * copyArray = 0;
+ OSArray * copyArray = NULL;
OSObject * prop;
LOCKREADNOTIFY();
IOService::registerInterest( const OSSymbol * typeOfInterest,
IOServiceInterestHandler handler, void * target, void * ref )
{
- _IOServiceInterestNotifier * notify = 0;
+ _IOServiceInterestNotifier * notify = NULL;
IOReturn rc = kIOReturnError;
notify = new _IOServiceInterestNotifier;
if (rc != kIOReturnSuccess) {
notify->release();
- notify = 0;
+ notify = NULL;
}
return notify;
IOServiceInterestHandler handler, void * target, void * ref )
{
IOReturn rc = kIOReturnSuccess;
- _IOServiceInterestNotifier *notify = 0;
+ _IOServiceInterestNotifier *notify = NULL;
if (!svcNotify || !(notify = OSDynamicCast(_IOServiceInterestNotifier, svcNotify))) {
return kIOReturnBadArgument;
bool ok = setProperty( typeOfInterest, notifyList);
notifyList->release();
if (!ok) {
- notifyList = 0;
+ notifyList = NULL;
}
}
}
LOCKWRITENOTIFY();
while (queue_entry_t entry = dequeue(¬ifyHead->fCommandChain)) {
- queue_next(entry) = queue_prev(entry) = 0;
+ queue_next(entry) = queue_prev(entry) = NULL;
_IOServiceInterestNotifier * notify;
if (queue_next( &chain )) {
remqueue(&chain);
- queue_next( &chain) = queue_prev( &chain) = 0;
+ queue_next( &chain) = queue_prev( &chain) = NULL;
release();
}
static void
_workLoopAction( IOWorkLoop::Action action,
IOService * service,
- void * p0 = 0, void * p1 = 0,
- void * p2 = 0, void * p3 = 0 )
+ void * p0 = NULL, void * p1 = NULL,
+ void * p2 = NULL, void * p3 = NULL )
{
IOWorkLoop * wl;
{
IOService * victim;
IOService * client;
+ IOService * rematchProvider;
OSIterator * iter;
OSArray * makeInactive;
OSArray * waitingInactive;
+ IOOptionBits callerOptions;
int waitResult = THREAD_AWAKENED;
bool wait;
bool ok;
TLOG("%s[0x%qx]::terminatePhase1(%08llx)\n", getName(), getRegistryEntryID(), (long long)options);
+ callerOptions = options;
+ rematchProvider = NULL;
uint64_t regID = getRegistryEntryID();
IOServiceTrace(
IOSERVICE_TERMINATE_PHASE1,
}
}
victim->_adjustBusy( 1 );
+
+ if ((options & kIOServiceTerminateWithRematch) && (victim == this)) {
+ OSObject * obj;
+ OSObject * rematchProps;
+ OSNumber * num;
+ uint32_t count;
+
+ rematchProvider = getProvider();
+ if (rematchProvider) {
+ obj = rematchProvider->copyProperty(gIORematchCountKey);
+ num = OSDynamicCast(OSNumber, obj);
+ count = 0;
+ if (num) {
+ count = num->unsigned32BitValue();
+ count++;
+ }
+ num = OSNumber::withNumber(count, 32);
+ rematchProvider->setProperty(gIORematchCountKey, num);
+ rematchProps = copyProperty(gIOMatchedPersonalityKey);
+ rematchProvider->setProperty(gIORematchPersonalityKey, rematchProps);
+ OSSafeReleaseNULL(num);
+ OSSafeReleaseNULL(rematchProps);
+ OSSafeReleaseNULL(obj);
+ }
+ }
}
victim->unlockForArbitration();
}
if (victim == this) {
+ options &= ~kIOServiceTerminateWithRematch;
startPhase2 = didInactive;
}
if (didInactive) {
release();
}
+ if (rematchProvider) {
+ DKLOG(DKS " rematching after dext crash\n", DKN(rematchProvider));
+ rematchProvider->registerService();
+ }
+
return true;
}
haveDeadline = true;
}
/* let others do work while we wait */
- gIOTerminateThread = 0;
+ gIOTerminateThread = NULL;
IOLockWakeup( gJobsLock, (event_t) &gIOTerminateThread, /* one-thread */ false);
waitResult = IOLockSleepDeadline( gJobsLock, &gIOTerminateWork,
deadline, THREAD_UNINT );
if (__improbable(waitResult == THREAD_TIMED_OUT)) {
- panic("%s[0x%qx]::terminate(kIOServiceSynchronous) timeout\n", getName(), getRegistryEntryID());
+ IOLog("%s[0x%qx]::terminate(kIOServiceSynchronous): THREAD_TIMED_OUT. "
+ "Attempting to auto-resolve your deadlock. PLEASE FIX!\n", getName(), getRegistryEntryID());
}
waitToBecomeTerminateThread();
}
} while (gIOTerminateWork || (wait && (waitResult != THREAD_TIMED_OUT)));
- gIOTerminateThread = 0;
+ gIOTerminateThread = NULL;
IOLockWakeup( gJobsLock, (event_t) &gIOTerminateThread, /* one-thread */ false);
} else {
// ! kIOServiceSynchronous
terminateWorker((uintptr_t)arg );
}
- gIOTerminateThread = 0;
+ gIOTerminateThread = NULL;
IOLockWakeup( gJobsLock, (event_t) &gIOTerminateThread, /* one-thread */ false);
IOLockSleep(gJobsLock, &gIOTerminateWork, THREAD_UNINT);
}
bool
IOService::willTerminate( IOService * provider, IOOptionBits options )
{
+ if (reserved->uvars) {
+ IOUserServer::serviceWillTerminate(this, provider, options);
+ }
return true;
}
bool
IOService::didTerminate( IOService * provider, IOOptionBits options, bool * defer )
{
+ if (reserved->uvars) {
+ IOUserServer::serviceDidTerminate(this, provider, options, defer);
+ }
+
if (false == *defer) {
if (lockForArbitration( true )) {
if (false == provider->handleIsOpen( this )) {
void
IOService::actionWillTerminate( IOService * victim, IOOptionBits options,
OSArray * doPhase2List,
- void *unused2 __unused,
- void *unused3 __unused )
+ bool user,
+ void *unused3 __unused)
{
OSIterator * iter;
IOService * client;
iter = victim->getClientIterator();
if (iter) {
while ((client = (IOService *) iter->getNextObject())) {
+ if (user != (NULL != client->reserved->uvars)) {
+ continue;
+ }
regID1 = client->getRegistryEntryID();
TLOG("%s[0x%qx]::willTerminate(%s[0x%qx], %08llx)\n",
client->getName(), regID1,
doPhase2List = OSArray::withCapacity( 16 );
didPhase2List = OSArray::withCapacity( 16 );
freeList = OSSet::withCapacity( 16 );
- if ((0 == doPhase2List) || (0 == didPhase2List) || (0 == freeList)) {
+ if ((NULL == doPhase2List) || (NULL == didPhase2List) || (NULL == freeList)) {
return;
}
}
if (doPhase2) {
if (kIOServiceNeedWillTerminate & victim->__state[1]) {
- _workLoopAction((IOWorkLoop::Action) &actionWillStop,
- victim, (void *)(uintptr_t) options, NULL );
+ if (NULL == victim->reserved->uvars) {
+ _workLoopAction((IOWorkLoop::Action) &actionWillStop,
+ victim, (void *)(uintptr_t) options);
+ } else {
+ actionWillStop(victim, options, NULL, NULL, NULL);
+ }
}
OSArray * notifiers;
victim->invokeNotifiers(¬ifiers);
_workLoopAction((IOWorkLoop::Action) &actionWillTerminate,
- victim, (void *)(uintptr_t) options, (void *)(uintptr_t) doPhase2List );
+ victim,
+ (void *)(uintptr_t) options,
+ (void *)(uintptr_t) doPhase2List,
+ (void *)(uintptr_t) false);
+
+ actionWillTerminate(
+ victim, options, doPhase2List, true, NULL);
didPhase2List->headQ( victim );
}
bool scheduleFinalize = false;
if (victim->lockForArbitration( true )) {
victim->__state[1] |= kIOServiceTermPhase3State;
- scheduleFinalize = (0 == victim->getClient());
+ scheduleFinalize = (NULL == victim->getClient());
victim->unlockForArbitration();
}
_workLoopAction((IOWorkLoop::Action) &actionDidTerminate,
ok = handleOpen( forClient, options, arg );
}
+ if (ok && forClient && forClient->reserved->uvars && forClient->reserved->uvars->userServer) {
+ forClient->reserved->uvars->userServer->serviceOpen(this, forClient);
+ }
+
unlockForArbitration();
return ok;
if (wasClosed) {
handleClose( forClient, options );
last = (__state[1] & kIOServiceTermPhase3State);
+
+ if (forClient && forClient->reserved->uvars && forClient->reserved->uvars->userServer) {
+ forClient->reserved->uvars->userServer->serviceClose(this, forClient);
+ }
}
unlockForArbitration();
{
bool ok;
- ok = (0 == __owner);
+ ok = (NULL == __owner);
if (ok) {
__owner = forClient;
} else if (options & kIOServiceSeize) {
ok = (kIOReturnSuccess == messageClient( kIOMessageServiceIsRequestingClose,
__owner, (void *)(uintptr_t) options ));
- if (ok && (0 == __owner)) {
+ if (ok && (NULL == __owner)) {
__owner = forClient;
} else {
ok = false;
IOOptionBits options )
{
if (__owner == forClient) {
- __owner = 0;
+ __owner = NULL;
}
}
OSObject * prop;
SInt32 result;
- prop = 0;
+ prop = NULL;
result = kIODefaultProbeScore;
if ((dict = OSDynamicCast( OSDictionary, entry))) {
offset = OSDynamicCast(OSNumber, dict->getObject( key ));
offset = OSDynamicCast(OSNumber, prop);
} else {
assert( false );
- offset = 0;
+ offset = NULL;
}
if (offset) {
IOService *
IOService::copyClientWithCategory( const OSSymbol * category )
{
- IOService * service = 0;
+ IOService * service = NULL;
OSIterator * iter;
const OSSymbol * nextCat;
}
bool
-IOService::invokeNotifiers(OSArray ** willSend)
+IOService::invokeNotifiers(OSArray * willSend[])
{
OSArray * array;
_IOServiceNotifier * notify;
if (!array) {
return true;
}
- *willSend = 0;
+ *willSend = NULL;
for (unsigned int idx = 0;
(notify = (_IOServiceNotifier *) array->getObject(idx));
void
IOService::probeCandidates( OSOrderedSet * matches )
{
- OSDictionary * match = 0;
+ OSDictionary * match = NULL;
OSSymbol * symbol;
IOService * inst;
IOService * newInst;
OSDictionary * props;
SInt32 score;
OSNumber * newPri;
- OSOrderedSet * familyMatches = 0;
+ OSOrderedSet * familyMatches = NULL;
OSOrderedSet * startList;
- OSDictionary * startDict = 0;
+ OSSet * kexts = NULL;
+ OSObject * kextRef;
+
+ OSDictionary * startDict = NULL;
const OSSymbol * category;
OSIterator * iter;
- _IOServiceNotifier * notify;
- OSObject * nextMatch = 0;
+ _IOServiceNotifier * notify;
+ OSObject * nextMatch = NULL;
bool started;
bool needReloc = false;
+ bool matchDeferred = false;
#if IOMATCHDEBUG
SInt64 debugFlags;
#endif
- IOService * client = NULL;
-
+ IOService * client = NULL;
+ OSObject * prop1;
+ OSObject * prop2;
+ OSDictionary * rematchPersonality;
+ OSNumber * num;
+ uint32_t count;
+ uint32_t dextCount;
+ bool isDext;
+ bool categoryConsumed;
+
+ prop2 = NULL;
+ count = 0;
+ prop1 = copyProperty(gIORematchPersonalityKey);
+ rematchPersonality = OSDynamicCast(OSDictionary, prop1);
+ if (rematchPersonality) {
+ prop2 = copyProperty(gIORematchCountKey);
+ num = OSDynamicCast(OSNumber, prop2);
+ if (num) {
+ count = num->unsigned32BitValue();
+ }
+ OSSafeReleaseNULL(prop2);
+ }
+ dextCount = 0;
assert( matches );
- while (!needReloc && (nextMatch = matches->getFirstObject())) {
+ while (!needReloc
+ && (nextMatch = matches->getFirstObject())) {
nextMatch->retain();
matches->removeObject(nextMatch);
invokeNotifier( notify );
}
nextMatch->release();
- nextMatch = 0;
+ nextMatch = NULL;
continue;
} else if (!(match = OSDynamicCast( OSDictionary, nextMatch ))) {
nextMatch->release();
- nextMatch = 0;
+ nextMatch = NULL;
continue;
}
- props = 0;
+ props = NULL;
#if IOMATCHDEBUG
debugFlags = getDebugFlags( match );
#endif
do {
+ isDext = (NULL != match->getObject(gIOUserServerNameKey));
+ if (isDext && !(kIODKEnable & gIODKDebug)) {
+ continue;
+ }
+
category = OSDynamicCast( OSSymbol,
match->getObject( gIOMatchCategoryKey ));
- if (0 == category) {
+ if (NULL == category) {
category = gIODefaultMatchCategoryKey;
}
+ client = copyClientWithCategory(category);
- if ((client = copyClientWithCategory(category))) {
+ categoryConsumed = (client != NULL);
+ if (categoryConsumed) {
#if IOMATCHDEBUG
if ((debugFlags & kIOLogMatch) && (this != gIOResources)) {
LOG("%s: match category %s exists\n", getName(),
category->getCStringNoCopy());
}
#endif
- nextMatch->release();
- nextMatch = 0;
-
- client->release();
- client = NULL;
-
- continue;
+ OSSafeReleaseNULL(client);
+ if (!isDext) {
+ break;
+ }
}
// create a copy now in case its modified during matching
- props = OSDictionary::withDictionary( match, match->getCount());
- if (0 == props) {
- continue;
+ props = OSDictionary::withDictionary(match, match->getCount());
+ if (NULL == props) {
+ break;
}
props->setCapacityIncrement(1);
// check the nub matches
if (false == matchPassive(props, kIOServiceChangesOK | kIOServiceClassDone)) {
- continue;
+ break;
+ }
+ if (isDext) {
+ dextCount++;
+ if (categoryConsumed) {
+ break;
+ }
+ }
+
+ if (rematchPersonality) {
+ bool personalityMatch = match->isEqualTo(rematchPersonality);
+ if (count > gIODextRelaunchMax) {
+ personalityMatch = !personalityMatch;
+ }
+ if (!personalityMatch) {
+ break;
+ }
}
// Check to see if driver reloc has been loaded.
- needReloc = (false == gIOCatalogue->isModuleLoaded( match ));
+ needReloc = (false == gIOCatalogue->isModuleLoaded( match, &kextRef ));
if (needReloc) {
#if IOMATCHDEBUG
if (debugFlags & kIOLogCatalogue) {
#endif
// If reloc hasn't been loaded, exit;
// reprobing will occur after reloc has been loaded.
- continue;
+ break;
+ }
+ if (kextRef) {
+ if (NULL == kexts) {
+ kexts = OSSet::withCapacity(1);
+ }
+ if (kexts) {
+ kexts->setObject(kextRef);
+ kextRef->release();
+ }
+ }
+ if (isDext) {
+ // copy saved for rematchng
+ props->setObject(gIOMatchedPersonalityKey, match);
}
-
// reorder on family matchPropertyTable score.
- if (0 == familyMatches) {
+ if (NULL == familyMatches) {
familyMatches = OSOrderedSet::withCapacity( 1,
IOServiceOrdering, (void *) gIOProbeScoreKey );
}
}
} while (false);
- if (nextMatch) {
- nextMatch->release();
- nextMatch = 0;
- }
- if (props) {
- props->release();
- }
+ OSSafeReleaseNULL(nextMatch);
+ OSSafeReleaseNULL(props);
}
matches->release();
- matches = 0;
+ matches = NULL;
if (familyMatches) {
while (!needReloc
props->retain();
familyMatches->removeObject( props );
- inst = 0;
- newInst = 0;
+ inst = NULL;
+ newInst = NULL;
#if IOMATCHDEBUG
debugFlags = getDebugFlags( props );
#endif
// give the driver the default match category if not specified
category = OSDynamicCast( OSSymbol,
props->getObject( gIOMatchCategoryKey ));
- if (0 == category) {
+ if (NULL == category) {
category = gIODefaultMatchCategoryKey;
}
inst->setProperty( gIOMatchCategoryKey, (OSObject *) category );
newInst = inst->probe( this, &score );
inst->detach( this );
- if (0 == newInst) {
+ if (NULL == newInst) {
#if IOMATCHDEBUG
if (debugFlags & kIOLogProbe) {
IOLog("%s::probe fails\n", symbol->getCStringNoCopy());
}
// add to start list for the match category
- if (0 == startDict) {
+ if (NULL == startDict) {
startDict = OSDictionary::withCapacity( 1 );
}
assert( startDict );
startList = (OSOrderedSet *)
startDict->getObject( category );
- if (0 == startList) {
+ if (NULL == startList) {
startList = OSOrderedSet::withCapacity( 1,
IOServiceOrdering, (void *) gIOProbeScoreKey );
if (startDict && startList) {
}
}
familyMatches->release();
- familyMatches = 0;
+ familyMatches = NULL;
}
// start the best (until success) of each category
started = false;
while (true // (!started)
+ && !matchDeferred
&& (inst = (IOService *)startList->getFirstObject())) {
inst->retain();
startList->removeObject(inst);
}
#endif
if (false == started) {
- started = startCandidate( inst );
- }
+#if !NO_KEXTD
+ IOLockLock(gJobsLock);
+ matchDeferred = (gIOMatchDeferList
+ && (kOSBooleanTrue == inst->getProperty(gIOMatchDeferKey)));
+ if (matchDeferred && (-1U == gIOMatchDeferList->getNextIndexOfObject(this, 0))) {
+ gIOMatchDeferList->setObject(this);
+ }
+ IOLockUnlock(gJobsLock);
+ if (matchDeferred) {
+ symbol = OSDynamicCast(OSSymbol, inst->getProperty(gIOClassKey));
+ IOLog("%s(0x%qx): matching deferred by %s\n",
+ getName(), getRegistryEntryID(),
+ symbol ? symbol->getCStringNoCopy() : "");
+ // rematching will occur after kextd loads all plists
+ }
+#endif
+ if (!matchDeferred) {
+ started = startCandidate( inst );
#if IOMATCHDEBUG
- if ((debugFlags & kIOLogStart) && (false == started)) {
- LOG( "%s::start(%s) <%d> failed\n", inst->getName(), getName(),
- inst->getRetainCount());
- }
+ if ((debugFlags & kIOLogStart) && (false == started)) {
+ LOG( "%s::start(%s) <%d> failed\n", inst->getName(), getName(),
+ inst->getRetainCount());
+ }
#endif
+ }
+ }
inst->release();
}
}
iter->release();
}
+ OSSafeReleaseNULL(prop1);
+
+ if (dextCount) {
+ num = OSNumber::withNumber(dextCount, 32);
+ setProperty(gIODEXTMatchCountKey, num);
+ OSSafeReleaseNULL(num);
+ } else if (rematchPersonality) {
+ removeProperty(gIODEXTMatchCountKey);
+ }
+
+ // now that instances are created, drop the refs on any kexts allowing unload
+ if (kexts) {
+ OSKext::dropMatchingReferences(kexts);
+ OSSafeReleaseNULL(kexts);
+ }
// adjust the busy count by +1 if matching is stalled for a module,
// or -1 if a previously stalled matching is complete.
}
}
+/*
+ * Wait for a IOUserServer to check in
+ */
+
+static
+__attribute__((noinline, not_tail_called))
+IOService *
+__WAITING_FOR_USER_SERVER__(OSDictionary * matching)
+{
+ IOService * server;
+ server = IOService::waitForMatchingService(matching, kIOUserServerCheckInTimeoutSecs * NSEC_PER_SEC);
+ return server;
+}
+
+void
+IOService::willShutdown()
+{
+ gKextdWillTerminate = true;
+#if !NO_KEXTD
+ getPlatform()->waitQuiet(30 * NSEC_PER_SEC);
+#endif
+ OSKext::willShutdown();
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+void
+IOServicePH::init(IOPMrootDomain * root)
+{
+ fUserServers = OSArray::withCapacity(4);
+ fMatchingWork = OSArray::withCapacity(4);
+
+ assert(fUserServers && fMatchingWork);
+
+ fRootNotifier = root->registerInterest(
+ gIOPriorityPowerStateInterest, &IOServicePH::systemPowerChange, NULL, NULL);
+
+ assert(fRootNotifier);
+}
+
+void
+IOServicePH::lock()
+{
+ IOLockLock(gJobsLock);
+}
+
+void
+IOServicePH::unlock()
+{
+ IOLockUnlock(gJobsLock);
+}
+
+void
+IOServicePH::serverAdd(IOUserServer * server)
+{
+ uint32_t idx;
+
+ lock();
+ idx = fUserServers->getNextIndexOfObject(server, 0);
+ if (idx == -1U) {
+ fUserServers->setObject(server);
+ }
+ unlock();
+}
+
+void
+IOServicePH::serverRemove(IOUserServer * server)
+{
+ uint32_t idx;
+
+ lock();
+ idx = fUserServers->getNextIndexOfObject(server, 0);
+ if (idx != -1U) {
+ fUserServers->removeObject(idx);
+ }
+ unlock();
+}
+
+void
+IOServicePH::serverAck(IOUserServer * server)
+{
+ uint32_t idx;
+ IOService * ackTo;
+ uint32_t ackToRef;
+
+ ackTo = NULL;
+ lock();
+ if (server && fUserServersWait) {
+ idx = fUserServersWait->getNextIndexOfObject(server, 0);
+ if (idx != -1U) {
+ fUserServersWait->removeObject(idx);
+ if (0 == fUserServersWait->getCount()) {
+ OSSafeReleaseNULL(fUserServersWait);
+ }
+ }
+ }
+ if (!fUserServersWait && !fMatchingWork->getCount()) {
+ ackTo = fSystemPowerAckTo;
+ ackToRef = fSystemPowerAckRef;
+ fSystemPowerAckTo = NULL;
+ }
+ unlock();
+
+ if (ackTo) {
+ DKLOG("allowPowerChange\n");
+ ackTo->allowPowerChange((uintptr_t) ackToRef);
+ }
+}
+
+bool
+IOServicePH::matchingStart(IOService * service)
+{
+ uint32_t idx;
+ bool ok;
+
+ lock();
+ ok = !fSystemOff;
+ if (ok) {
+ idx = fMatchingWork->getNextIndexOfObject(service, 0);
+ if (idx == -1U) {
+ fMatchingWork->setObject(service);
+ }
+ } else {
+ if (!fMatchingDelayed) {
+ fMatchingDelayed = OSArray::withObjects((const OSObject **) &service, 1, 1);
+ } else {
+ idx = fMatchingDelayed->getNextIndexOfObject(service, 0);
+ if (idx == -1U) {
+ fMatchingDelayed->setObject(service);
+ }
+ }
+ }
+ unlock();
+
+ return ok;
+}
+
+void
+IOServicePH::matchingEnd(IOService * service)
+{
+ uint32_t idx;
+ OSArray * notifyServers;
+ OSArray * deferredMatches;
+
+ notifyServers = NULL;
+ deferredMatches = NULL;
+
+ lock();
+
+ if (service) {
+ idx = fMatchingWork->getNextIndexOfObject(service, 0);
+ if (idx != -1U) {
+ fMatchingWork->removeObject(idx);
+ }
+ }
+
+
+ if ((fUserServerOff != fSystemOff) && fUserServers->getCount()) {
+ if (fSystemOff) {
+ if (0 == fMatchingWork->getCount()) {
+ fUserServersWait = OSArray::withArray(fUserServers);
+ notifyServers = OSArray::withArray(fUserServers);
+ fUserServerOff = fSystemOff;
+ }
+ } else {
+ notifyServers = OSArray::withArray(fUserServers);
+ fUserServerOff = fSystemOff;
+ }
+ }
+
+ if (!fSystemOff && fMatchingDelayed) {
+ deferredMatches = fMatchingDelayed;
+ fMatchingDelayed = NULL;
+ }
+
+ unlock();
+
+ if (notifyServers) {
+ notifyServers->iterateObjects(^bool (OSObject * obj) {
+ IOUserServer * us;
+ us = (typeof(us))obj;
+ us->systemPower(fSystemOff);
+ return false;
+ });
+ OSSafeReleaseNULL(notifyServers);
+ }
+
+ if (deferredMatches) {
+ DKLOG("sleep deferred rematching count %d\n", deferredMatches->getCount());
+ deferredMatches->iterateObjects(^bool (OSObject * obj)
+ {
+ ((IOService *)obj)->startMatching(kIOServiceAsynchronous);
+ return false;
+ });
+ deferredMatches->release();
+ }
+
+ serverAck(NULL);
+}
+
+IOReturn
+IOServicePH::systemPowerChange(
+ void * target,
+ void * refCon,
+ UInt32 messageType, IOService * service,
+ void * messageArgument, vm_size_t argSize)
+{
+ IOReturn ret;
+ IOUserServer * us;
+ IOPMSystemCapabilityChangeParameters * params;
+
+ us = NULL;
+
+ switch (messageType) {
+ case kIOMessageSystemCapabilityChange:
+
+ params = (typeof params)messageArgument;
+
+ if (kIODKLogPM & gIODKDebug) {
+ IOLog("IOServicePH::kIOMessageSystemCapabilityChange: %s%s 0x%x->0x%x\n",
+ params->changeFlags & kIOPMSystemCapabilityWillChange ? "will" : "",
+ params->changeFlags & kIOPMSystemCapabilityDidChange ? "did" : "",
+ params->fromCapabilities,
+ params->toCapabilities);
+ }
+
+ if ((params->changeFlags & kIOPMSystemCapabilityWillChange) &&
+ (params->fromCapabilities & kIOPMSystemCapabilityCPU) &&
+ ((params->toCapabilities & kIOPMSystemCapabilityCPU) == 0)) {
+ lock();
+ fSystemOff = true;
+ fSystemPowerAckRef = params->notifyRef;
+ fSystemPowerAckTo = service;
+ unlock();
+
+ matchingEnd(NULL);
+
+ params->maxWaitForReply = 60 * 1000 * 1000;
+ ret = kIOReturnSuccess;
+ } else if ((params->changeFlags & kIOPMSystemCapabilityWillChange) &&
+ ((params->fromCapabilities & kIOPMSystemCapabilityCPU) == 0) &&
+ (params->toCapabilities & kIOPMSystemCapabilityCPU)) {
+ lock();
+ fSystemOff = false;
+ unlock();
+
+ matchingEnd(NULL);
+
+ params->maxWaitForReply = 0;
+ ret = kIOReturnSuccess;
+ } else {
+ params->maxWaitForReply = 0;
+ ret = kIOReturnSuccess;
+ }
+ break;
+
+ default:
+ ret = kIOReturnUnsupported;
+ break;
+ }
+
+ return ret;
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
/*
* Start a previously attached & probed instance,
* called on exporting object instance
IOService::startCandidate( IOService * service )
{
bool ok;
+ OSObject * obj;
+ OSObject * prop;
+ IOUserServer * userServer;
+ bool ph;
- ok = service->attach( this );
+ userServer = NULL;
+ obj = service->copyProperty(gIOUserServerNameKey);
- if (ok) {
- if (this != gIOResources) {
- // stall for any nub resources
- checkResources();
- // stall for any driver resources
- service->checkResources();
- }
+ if (obj && (this == gIOResources)) {
+ ok = false;
+ } else {
+ ok = service->attach( this );
+ }
+ if (!ok) {
+ return false;
+ }
- AbsoluteTime startTime;
- AbsoluteTime endTime;
- UInt64 nano;
+ if ((this != gIOResources) && (this != gIOUserResources)) {
+ // stall for any nub resources
+ checkResources();
+ // stall for any driver resources
+ service->checkResources();
+ }
+ ph = false;
+ {
+ OSString * bundleID;
+ OSString * serverName;
+ OSString * str;
+ const OSSymbol * sym;
+ OSDictionary * matching;
+ IOService * server;
+ OSNumber * serverTag;
+ uint64_t entryID;
+
+ if ((serverName = OSDynamicCast(OSString, obj))) {
+ obj = service->copyProperty(gIOModuleIdentifierKey);
+ bundleID = OSDynamicCast(OSString, obj);
+ entryID = service->getRegistryEntryID();
+ serverTag = OSNumber::withNumber(entryID, 64);
+
+ if (gKextdWillTerminate) {
+ DKLOG("%s disabled in shutdown\n", serverName->getCStringNoCopy());
+ service->detach(this);
+ OSSafeReleaseNULL(obj);
+ return false;
+ }
- if (kIOLogStart & gIOKitDebug) {
- clock_get_uptime(&startTime);
- }
+ ph = IOServicePH::matchingStart(this);
+ if (!ph) {
+ DKLOG("%s deferred in sleep\n", serverName->getCStringNoCopy());
+ service->detach(this);
+ OSSafeReleaseNULL(obj);
+ return false;
+ }
+
+ prop = service->copyProperty(gIOUserClassKey);
+ str = OSDynamicCast(OSString, prop);
+ if (str) {
+ service->setName(str);
+ }
+ OSSafeReleaseNULL(prop);
- ok = service->start(this);
+ if (!(kIODKDisableDextLaunch & gIODKDebug)) {
+ OSKext::requestDaemonLaunch(bundleID, serverName, serverTag);
+ }
+ sym = OSSymbol::withString(serverName);
+ matching = serviceMatching(gIOUserServerClassKey);
+ propertyMatching(gIOUserServerNameKey, sym, matching);
+ if (!(kIODKDisableDextTag & gIODKDebug)) {
+ propertyMatching(gIOUserServerTagKey, serverTag, matching);
+ }
- if (kIOLogStart & gIOKitDebug) {
- clock_get_uptime(&endTime);
+ server = __WAITING_FOR_USER_SERVER__(matching);
+ matching->release();
+ OSSafeReleaseNULL(serverTag);
+ OSSafeReleaseNULL(serverName);
+
+ userServer = OSDynamicCast(IOUserServer, server);
+ if (!userServer) {
+ service->detach(this);
+ IOServicePH::matchingEnd(this);
+ DKLOG(DKS " user server timeout\n", DKN(service));
+ return false;
+ }
- if (CMP_ABSOLUTETIME(&endTime, &startTime) > 0) {
- SUB_ABSOLUTETIME(&endTime, &startTime);
- absolutetime_to_nanoseconds(endTime, &nano);
- if (nano > 500000000ULL) {
- IOLog("%s::start took %ld ms\n", service->getName(), (long)(UInt32)(nano / 1000000ULL));
+ if (!(kIODKDisableCDHashChecking & gIODKDebug)) {
+ if (!userServer->serviceMatchesCDHash(service)) {
+ service->detach(this);
+ IOServicePH::matchingEnd(this);
+ userServer->exit("CDHash check failed");
+ userServer->release();
+ return false;
}
}
+ OSKext *kext = OSKext::lookupKextWithIdentifier(bundleID);
+ if (!kext) {
+ const char *name = bundleID->getCStringNoCopy();
+ IOLog("%s Could not find OSKext for %s\n", __func__, name);
+ goto skip_log;
+ }
+
+ /*
+ * Used for logging
+ */
+ userServer->setTaskLoadTag(kext);
+ userServer->setDriverKitUUID(kext);
+ OSKext::OSKextLogDriverKitInfoLoad(kext);
+skip_log:
+ OSSafeReleaseNULL(bundleID);
+ OSSafeReleaseNULL(kext);
+
+ if (!(kIODKDisableEntitlementChecking & gIODKDebug)) {
+ if (!userServer->checkEntitlements(this, service)) {
+ service->detach(this);
+ IOServicePH::matchingEnd(this);
+ userServer->exit("Entitlements check failed");
+ userServer->release();
+ return false;
+ }
+ }
+
+ userServer->serviceAttach(service, this);
}
- if (!ok) {
- service->detach( this );
+ }
+
+ AbsoluteTime startTime;
+ AbsoluteTime endTime;
+ UInt64 nano;
+
+ if (kIOLogStart & gIOKitDebug) {
+ clock_get_uptime(&startTime);
+ }
+
+ ok = service->start(this);
+
+ if (kIOLogStart & gIOKitDebug) {
+ clock_get_uptime(&endTime);
+
+ if (CMP_ABSOLUTETIME(&endTime, &startTime) > 0) {
+ SUB_ABSOLUTETIME(&endTime, &startTime);
+ absolutetime_to_nanoseconds(endTime, &nano);
+ if (nano > 500000000ULL) {
+ IOLog("%s::start took %ld ms\n", service->getName(), (long)(UInt32)(nano / 1000000ULL));
+ }
}
}
+ if (userServer) {
+ userServer->serviceStarted(service, this, ok);
+ userServer->release();
+ }
+ if (!ok) {
+ service->detach( this );
+ }
+
+ if (ph) {
+ IOServicePH::matchingEnd(this);
+ }
+
return ok;
}
void
IOService::publishResource( const OSSymbol * key, OSObject * value )
{
- if (0 == value) {
+ if (NULL == value) {
value = (OSObject *) gIOServiceKey;
}
gIOResources->registerService();
}
+void
+IOService::publishUserResource( const OSSymbol * key, OSObject * value )
+{
+ if (NULL == value) {
+ value = (OSObject *) gIOServiceKey;
+ }
+
+ gIOUserResources->setProperty( key, value);
+
+ if (IORecursiveLockHaveLock( gNotificationLock)) {
+ return;
+ }
+
+ gIOResourceGenerationCount++;
+ gIOUserResources->registerService();
+}
+
bool
IOService::addNeededResource( const char * key )
{
bool ok;
resourcesProp = copyProperty( gIOResourceMatchKey );
- if (0 == resourcesProp) {
+ if (NULL == resourcesProp) {
return true;
}
if ((set = OSDynamicCast( OSSet, resourcesProp ))) {
iter = OSCollectionIterator::withCollection( set );
- ok = (0 != iter);
+ ok = (NULL != iter);
while (ok && (resourcesProp = iter->getNextObject())) {
ok = checkResource( resourcesProp );
}
void
-_IOConfigThread::configThread( void )
+_IOConfigThread::configThread( int configThreadId )
{
_IOConfigThread * inst;
if (!inst->init()) {
continue;
}
- thread_t unused;
- if (KERN_SUCCESS != kernel_thread_start(&_IOConfigThread::main, inst, &unused)) {
+ thread_t thread;
+ if (KERN_SUCCESS != kernel_thread_start(&_IOConfigThread::main, inst, &thread)) {
continue;
}
+ char threadName[MAXTHREADNAMESIZE];
+ snprintf(threadName, sizeof(threadName), "IOConfigThread_%d", configThreadId);
+ thread_set_thread_name(thread, threadName);
+ thread_deallocate(thread);
+
return;
} while (false);
return;
}
-void
-_IOConfigThread::free( void )
-{
- thread_deallocate(current_thread());
- OSObject::free();
-}
-
void
IOService::doServiceMatch( IOOptionBits options )
{
_IOServiceNotifier * notify;
OSIterator * iter;
OSOrderedSet * matches;
- OSArray * resourceKeys = 0;
+ OSArray * resourceKeys = NULL;
SInt32 catalogGeneration;
bool keepGuessing = true;
bool reRegistered = true;
bool didRegister;
- OSArray * notifiers[2] = {0};
+ OSArray * notifiers[2] = {NULL};
// job->nub->deliverNotification( gIOPublishNotification,
// kIOServiceRegisteredState, 0xffffffff );
invokeNotifiers(¬ifiers[0]);
if (keepGuessing && matches->getCount() && (kIOReturnSuccess == getResources())) {
- if (this == gIOResources) {
+ if ((this == gIOResources) || (this == gIOUserResources)) {
if (resourceKeys) {
resourceKeys->release();
}
bool kextdWait;
bool dopanic;
+#if KASAN
+ /*
+ * On kasan kernels, everything takes longer, so double the number of
+ * timeout extensions. This should help with issues like 41259215
+ * where WindowServer was timing out waiting for kextd to get all the
+ * kasan kexts loaded and started.
+ */
+ enum { kTimeoutExtensions = 8 };
+#else
enum { kTimeoutExtensions = 4 };
+#endif
time = mach_absolute_time();
kextdWait = false;
break;
} else if (kIOReturnTimeout != ret) {
break;
- } else if (timeout < 41000000000) {
+ } else if (timeout < (4100ull * NSEC_PER_SEC)) {
break;
}
if (gIOKitDebug & kIOLogConfig) {
LOG("config(%d): creating\n", gNumConfigThreads - 1);
}
- _IOConfigThread::configThread();
+ _IOConfigThread::configThread(gNumConfigThreads - 1);
}
semaphore_signal( gJobsSemaphore );
IOService::copyExistingServices( OSDictionary * matching,
IOOptionBits inState, IOOptionBits options )
{
- OSObject * current = 0;
+ OSObject * current = NULL;
OSIterator * iter;
IOService * service;
OSObject * obj;
OSString * str;
if (!matching) {
- return 0;
+ return NULL;
}
#if MATCH_DEBUG
ctx.count = 0;
ctx.done = 0;
ctx.options = options;
- ctx.result = 0;
+ ctx.result = NULL;
if ((str = OSDynamicCast(OSString, obj))) {
const OSSymbol * sym = OSSymbol::withString(str);
if (current && (ctx.done != ctx.count)) {
OSSet *
source = OSDynamicCast(OSSet, current);
- current = 0;
+ current = NULL;
while ((service = (IOService *) source->getAnyObject())) {
if (service->matchPassive(matching, options)) {
if (options & kIONotifyOnce) {
iter->release();
}
-
if (((current != 0) != (_current != 0))
|| (current && _current && !current->isEqualTo(_current))) {
OSSerialize * s1 = OSSerialize::withCapacity(128);
IOServiceMatchingNotificationHandler handler, void * target, void * ref,
SInt32 priority )
{
- _IOServiceNotifier * notify = 0;
+ _IOServiceNotifier * notify = NULL;
OSOrderedSet * set;
if (!matching) {
- return 0;
+ return NULL;
}
notify = new _IOServiceNotifier;
if (notify && !notify->init()) {
notify->release();
- notify = 0;
+ notify = NULL;
}
if (notify) {
////// queue
- if (0 == (set = (OSOrderedSet *) gNotifications->getObject( type ))) {
+ if (NULL == (set = (OSOrderedSet *) gNotifications->getObject( type ))) {
set = OSOrderedSet::withCapacity( 1,
- IONotifyOrdering, 0 );
+ IONotifyOrdering, NULL );
if (set) {
gNotifications->setObject( type, set );
set->release();
IOOptionBits inState;
if (!matching) {
- return 0;
+ return NULL;
}
if (type == gIOPublishNotification) {
} else if ((type == gIOTerminatedNotification) || (type == gIOWillTerminateNotification)) {
inState = 0;
} else {
- return 0;
+ return NULL;
}
notify = setNotification( type, matching, handler, target, ref, priority );
// get the current set
exist = (OSIterator *) copyExistingServices( matching, inState );
} else {
- exist = 0;
+ exist = NULL;
}
*existing = exist;
ret = notify = (_IOServiceNotifier *) installNotification( type, matching,
handler, target, ref, priority, &existing );
if (!ret) {
- return 0;
+ return NULL;
}
// send notifications for existing set
}
LOCKWRITENOTIFY();
- bool removed = (0 == notify->whence);
+ bool removed = (NULL == notify->whence);
notify->release();
if (removed) {
ret = gIOServiceNullNotifier;
IOService::waitForMatchingService( OSDictionary * matching,
uint64_t timeout)
{
- IONotifier * notify = 0;
+ IONotifier * notify = NULL;
// priority doesn't help us much since we need a thread wakeup
SInt32 priority = 0;
IOService * result;
if (!matching) {
- return 0;
+ return NULL;
}
result = NULL;
break;
}
notify = IOService::setNotification( gIOMatchedNotification, matching,
- &IOService::syncNotificationHandler, (void *) 0,
+ &IOService::syncNotificationHandler, (void *) NULL,
&result, priority );
if (!notify) {
break;
return result;
}
+__dead2
void
IOService::deliverNotification( const OSSymbol * type,
IOOptionBits orNewState, IOOptionBits andNewState )
{
_IOServiceNotifier * notify;
OSIterator * iter;
- OSArray * willSend = 0;
+ OSArray * willSend = NULL;
lockForArbitration();
while ((notify = (_IOServiceNotifier *) iter->getNextObject())) {
if (matchPassive(notify->matching, 0)
&& (kIOServiceNotifyEnable & notify->state)) {
- if (0 == willSend) {
+ if (NULL == willSend) {
willSend = OSArray::withCapacity(8);
}
if (willSend) {
str = OSSymbol::withString(name);
if (!str) {
- return 0;
+ return NULL;
}
if (!table) {
str = OSSymbol::withCString( name );
if (!str) {
- return 0;
+ return NULL;
}
table = serviceMatching( str, table );
str = OSSymbol::withCString( name );
if (!str) {
- return 0;
+ return NULL;
}
table = nameMatching( str, table );
str = OSSymbol::withCString( name );
if (!str) {
- return 0;
+ return NULL;
}
table = resourceMatching( str, table );
properties = OSDictionary::withCapacity( 2 );
if (!properties) {
- return 0;
+ return NULL;
}
properties->setObject( key, value );
num = OSNumber::withNumber( entryID, 64 );
if (!num) {
- return 0;
+ return NULL;
}
if (!table) {
if (whence) {
whence->removeObject((OSObject *) this );
- whence = 0;
+ whence = NULL;
}
if (matching) {
matching->release();
- matching = 0;
+ matching = NULL;
}
state &= ~kIOServiceNotifyEnable;
inst = new IOResources;
if (inst && !inst->init()) {
inst->release();
- inst = 0;
+ inst = NULL;
}
return inst;
OSNumber *num;
const OSSymbol * sym;
- if ((num = OSNumber::withNumber(property_value, 32)) != 0) {
- if ((sym = OSSymbol::withCString( property_name)) != 0) {
+ if ((num = OSNumber::withNumber(property_value, 32)) != NULL) {
+ if ((sym = OSSymbol::withCString( property_name)) != NULL) {
this->setProperty( sym, num );
sym->release();
}
}
}
-bool
-IOResources::matchPropertyTable( OSDictionary * table )
+static bool
+IOResourcesMatchPropertyTable(IOService * resources, OSDictionary * table)
{
OSObject * prop;
OSString * str;
prop = table->getObject( gIOResourceMatchKey );
str = OSDynamicCast( OSString, prop );
if (str) {
- ok = (0 != getProperty( str ));
+ ok = (NULL != resources->getProperty( str ));
} else if ((set = OSDynamicCast( OSSet, prop))) {
iter = OSCollectionIterator::withCollection( set );
- ok = (iter != 0);
+ ok = (iter != NULL);
while (ok && (str = OSDynamicCast( OSString, iter->getNextObject()))) {
- ok = (0 != getProperty( str ));
+ ok = (NULL != resources->getProperty( str ));
}
if (iter) {
iter->release();
}
} else if ((prop = table->getObject(gIOResourceMatchedKey))) {
- obj = copyProperty(gIOResourceMatchedKey);
+ obj = resources->copyProperty(gIOResourceMatchedKey);
keys = OSDynamicCast(OSArray, obj);
ok = false;
if (keys) {
return ok;
}
+bool
+IOResources::matchPropertyTable( OSDictionary * table )
+{
+ return IOResourcesMatchPropertyTable(this, table);
+}
+
+/*
+ * IOUserResources
+ */
+
+IOService *
+IOUserResources::resources( void )
+{
+ IOUserResources * inst;
+
+ inst = OSTypeAlloc(IOUserResources);
+ if (inst && !inst->init()) {
+ inst->release();
+ inst = NULL;
+ }
+
+ return inst;
+}
+
+bool
+IOUserResources::init( OSDictionary * dictionary )
+{
+ // Do super init first
+ if (!IOService::init()) {
+ return false;
+ }
+ return true;
+}
+
+IOReturn
+IOUserResources::newUserClient(task_t owningTask, void * securityID,
+ UInt32 type, OSDictionary * properties,
+ IOUserClient ** handler)
+{
+ return kIOReturnUnsupported;
+}
+
+IOWorkLoop *
+IOUserResources::getWorkLoop() const
+{
+ return getPlatform()->getWorkLoop();
+}
+
+bool
+IOUserResources::matchPropertyTable( OSDictionary * table )
+{
+ return IOResourcesMatchPropertyTable(this, table);
+}
+
+// --
+
void
IOService::consoleLockTimer(thread_call_param_t p0, thread_call_param_t p1)
{
gIOConsoleBooterLockState = kOSBooleanTrue;
break;
case kIOScreenLockNoLock:
- gIOConsoleBooterLockState = 0;
+ gIOConsoleBooterLockState = NULL;
break;
case kIOScreenLockUnlocked:
default:
}
if (consoleUsers) {
- OSNumber * num = 0;
+ OSNumber * num = NULL;
bool loginLocked = true;
gIOConsoleLoggedIn = false;
}
#if HIBERNATION
if (!loginLocked) {
- gIOConsoleBooterLockState = 0;
+ gIOConsoleBooterLockState = NULL;
}
IOLog("IOConsoleUsers: time(%d) %ld->%d, lin %d, llk %d, \n",
- (num != 0), gIOConsoleLockTime, (num ? num->unsigned32BitValue() : 0),
+ (num != NULL), gIOConsoleLockTime, (num ? num->unsigned32BitValue() : 0),
gIOConsoleLoggedIn, loginLocked);
#endif /* HIBERNATION */
gIOConsoleLockTime = num ? num->unsigned32BitValue() : 0;
gIOChosenEntry->setProperty(kIOScreenLockStateKey, &gIOScreenLockState, sizeof(gIOScreenLockState));
IOLog("IOConsoleUsers: gIOScreenLockState %d, hs %d, bs %d, now %ld, sm 0x%x\n",
- gIOScreenLockState, gIOHibernateState, (gIOConsoleBooterLockState != 0), now, systemMessage);
+ gIOScreenLockState, gIOHibernateState, (gIOConsoleBooterLockState != NULL), now, systemMessage);
}
#endif /* HIBERNATION */
}
dict = OSDynamicCast(OSDictionary, properties);
- if (0 == dict) {
+ if (NULL == dict) {
return kIOReturnBadArgument;
}
iter = OSCollectionIterator::withCollection( dict);
- if (0 == iter) {
+ if (NULL == iter) {
return kIOReturnBadArgument;
}
OSDictionary * dict;
if (!table) {
- return 0;
+ return NULL;
}
dict = OSDictionary::withCapacity( 1 );
if (dict) {
- table->setObject( gIOLocationMatchKey, dict );
+ bool ok = table->setObject( gIOLocationMatchKey, dict );
dict->release();
+ if (!ok) {
+ dict = NULL;
+ }
}
return dict;
str = OSDynamicCast(OSString, table->getObject(gIOProviderClassKey));
if (str) {
done++;
- match = ((kIOServiceClassDone & options) || (0 != metaCast(str)));
+ match = ((kIOServiceClassDone & options) || (NULL != metaCast(str)));
#if MATCH_DEBUG
match = (0 != metaCast( str ));
if ((kIOServiceClassDone & options) && !match) {
obj = table->getObject( gIONameMatchKey );
if (obj) {
done++;
- match = compareNames( obj, changesOK ? &matched : 0 );
+ match = compareNames( obj, changesOK ? &matched : NULL );
if (!match) {
break;
}
if (dict) {
nextDict = OSDynamicCast( OSDictionary, obj);
if (nextDict) {
- iter = 0;
+ iter = NULL;
} else {
iter = OSCollectionIterator::withCollection(
OSDynamicCast(OSCollection, obj));
}
while (nextDict
- || (iter && (0 != (nextDict = OSDynamicCast(OSDictionary,
+ || (iter && (NULL != (nextDict = OSDynamicCast(OSDictionary,
iter->getNextObject()))))) {
match = dict->isEqualTo( nextDict, nextDict);
if (match) {
break;
}
- nextDict = 0;
+ nextDict = NULL;
}
dict->release();
if (iter) {
if (dict) {
nextKey = OSDynamicCast( OSString, obj);
if (nextKey) {
- iter = 0;
+ iter = NULL;
} else {
iter = OSCollectionIterator::withCollection(
OSDynamicCast(OSCollection, obj));
}
while (nextKey
- || (iter && (0 != (nextKey = OSDynamicCast(OSString,
+ || (iter && (NULL != (nextKey = OSDynamicCast(OSString,
iter->getNextObject()))))) {
- match = (0 != dict->getObject(nextKey));
+ match = (NULL != dict->getObject(nextKey));
if (match) {
break;
}
- nextKey = 0;
+ nextKey = NULL;
}
dict->release();
if (iter) {
num = OSDynamicCast( OSNumber, table->getObject( gIOMatchedServiceCountKey ));
if (num) {
OSIterator * iter;
- IOService * service = 0;
+ IOService * service = NULL;
UInt32 serviceCount = 0;
done++;
if (kIOServiceInactiveState & service->__state[0]) {
continue;
}
- if (0 == service->getProperty( gIOMatchCategoryKey )) {
+ if (NULL == service->getProperty( gIOMatchCategoryKey )) {
continue;
}
++serviceCount;
UInt32 type, OSDictionary * properties,
IOUserClient ** handler )
{
- const OSSymbol *userClientClass = 0;
+ const OSSymbol *userClientClass = NULL;
IOUserClient *client;
OSObject *prop;
OSObject *temp;
+ if (reserved && reserved->uvars && reserved->uvars->userServer) {
+ return reserved->uvars->userServer->serviceNewUserClient(this, owningTask, securityID, type, properties, handler);
+ }
+
if (kIOReturnSuccess == newUserClient( owningTask, securityID, type, handler )) {
return kIOReturnSuccess;
}
if (array) {
range = (IODeviceMemory *) array->getObject( index );
} else {
- range = 0;
+ range = NULL;
}
return range;
if (range) {
map = range->map( options );
} else {
- map = 0;
+ map = NULL;
}
return map;
// Check if entry found
if (kNoReplace != replace) {
- entries[replace].fService = 0; // Null the entry
+ entries[replace].fService = NULL; // Null the entry
setCpuDelay = true;
}
}
// Get the parents list from the nub.
array = OSDynamicCast(OSArray, nub->getProperty(gIOInterruptControllersKey));
- if (array == 0) {
+ if (array == NULL) {
return kIOReturnNoResources;
}
// Allocate space for the IOInterruptSources if needed... then return early.
- if (nub->_interruptSources == 0) {
+ if (nub->_interruptSources == NULL) {
numSources = array->getCount();
interruptSources = (IOInterruptSource *)IOMalloc(
numSources * sizeofAllIOInterruptSource);
- if (interruptSources == 0) {
+ if (interruptSources == NULL) {
return kIOReturnNoMemory;
}
}
interruptControllerName = OSDynamicCast(OSSymbol, array->getObject(source));
- if (interruptControllerName == 0) {
+ if (interruptControllerName == NULL) {
return kIOReturnNoResources;
}
interruptController = getPlatform()->lookUpInterruptController(interruptControllerName);
- if (interruptController == 0) {
+ if (interruptController == NULL) {
return kIOReturnNoResources;
}
// Get the interrupt numbers from the nub.
array = OSDynamicCast(OSArray, nub->getProperty(gIOInterruptSpecifiersKey));
- if (array == 0) {
+ if (array == NULL) {
return kIOReturnNoResources;
}
data = OSDynamicCast(OSData, array->getObject(source));
- if (data == 0) {
+ if (data == NULL) {
return kIOReturnNoResources;
}
IOReturn ret;
/* Make sure the _interruptSources are set */
- if (_interruptSources == 0) {
+ if (_interruptSources == NULL) {
ret = resolveInterrupt(this, source);
if (ret != kIOReturnSuccess) {
return ret;
return status;
}
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+
#if __LP64__
OSMetaClassDefineReservedUsed(IOService, 0);
OSMetaClassDefineReservedUsed(IOService, 1);