/*
- * Copyright (c) 1998-2008 Apple Inc. All rights reserved.
+ * Copyright (c) 1998-2009 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
#include <IOKit/assert.h>
#include <sys/errno.h>
+#include <machine/pal_routines.h>
+
#define LOG kprintf
//#define LOG IOLog
#include "IOServicePrivate.h"
+#include "IOKitKernelInternal.h"
// take lockForArbitration before LOCKNOTIFY
const OSSymbol * gIOCommandPoolSizeKey;
+const OSSymbol * gIOConsoleLockedKey;
const OSSymbol * gIOConsoleUsersKey;
const OSSymbol * gIOConsoleSessionUIDKey;
+const OSSymbol * gIOConsoleSessionAuditIDKey;
const OSSymbol * gIOConsoleUsersSeedKey;
-const OSSymbol * gIOConsoleSessionOnConsoleKey;
-const OSSymbol * gIOConsoleSessionSecureInputPIDKey;
+const OSSymbol * gIOConsoleSessionOnConsoleKey;
+const OSSymbol * gIOConsoleSessionLoginDoneKey;
+const OSSymbol * gIOConsoleSessionSecureInputPIDKey;
+const OSSymbol * gIOConsoleSessionScreenLockedTimeKey;
+
+static clock_sec_t gIOConsoleLockTime;
static int gIOResourceGenerationCount;
const OSSymbol * gIOBusyInterest;
const OSSymbol * gIOAppPowerStateInterest;
const OSSymbol * gIOPriorityPowerStateInterest;
+const OSSymbol * gIOConsoleSecurityInterest;
static OSDictionary * gNotifications;
static IORecursiveLock * gNotificationLock;
const OSSymbol * gIOPlatformFunctionHandlerSet;
+static IOLock * gIOConsoleUsersLock;
+static thread_call_t gIOConsoleLockCallout;
+
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#define LOCKREADNOTIFY() \
{ return( 0 != (kIOServiceInactiveState & getState())); }
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-#define IOServiceTrace(csc, a, b, c, d) { \
- if(kIOTraceIOService & gIOKitDebug) { \
- KERNEL_DEBUG_CONSTANT(IODBG_IOSERVICE(csc), a, b, c, d, 0); \
- } \
-}
-
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#if defined(__i386__) || defined(__x86_64__)
gIOBusyInterest = OSSymbol::withCStringNoCopy( kIOBusyInterest );
gIOAppPowerStateInterest = OSSymbol::withCStringNoCopy( kIOAppPowerStateInterest );
gIOPriorityPowerStateInterest = OSSymbol::withCStringNoCopy( kIOPriorityPowerStateInterest );
+ gIOConsoleSecurityInterest = OSSymbol::withCStringNoCopy( kIOConsoleSecurityInterest );
gNotifications = OSDictionary::withCapacity( 1 );
gIOPublishNotification = OSSymbol::withCStringNoCopy(
kIOTerminatedNotification );
gIOServiceKey = OSSymbol::withCStringNoCopy( kIOServiceClass);
+ gIOConsoleLockedKey = OSSymbol::withCStringNoCopy( kIOConsoleLockedKey);
gIOConsoleUsersKey = OSSymbol::withCStringNoCopy( kIOConsoleUsersKey);
gIOConsoleSessionUIDKey = OSSymbol::withCStringNoCopy( kIOConsoleSessionUIDKey);
- gIOConsoleUsersSeedKey = OSSymbol::withCStringNoCopy( kIOConsoleUsersSeedKey);
- gIOConsoleSessionOnConsoleKey = OSSymbol::withCStringNoCopy( kIOConsoleSessionOnConsoleKey);
- gIOConsoleSessionSecureInputPIDKey = OSSymbol::withCStringNoCopy( kIOConsoleSessionSecureInputPIDKey);
- gIOConsoleUsersSeedValue = OSData::withBytesNoCopy(&gIOConsoleUsersSeed, sizeof(gIOConsoleUsersSeed));
+ gIOConsoleSessionAuditIDKey = OSSymbol::withCStringNoCopy( kIOConsoleSessionAuditIDKey);
+
+ gIOConsoleUsersSeedKey = OSSymbol::withCStringNoCopy(kIOConsoleUsersSeedKey);
+ gIOConsoleSessionOnConsoleKey = OSSymbol::withCStringNoCopy(kIOConsoleSessionOnConsoleKey);
+ gIOConsoleSessionLoginDoneKey = OSSymbol::withCStringNoCopy(kIOConsoleSessionLoginDoneKey);
+ gIOConsoleSessionSecureInputPIDKey = OSSymbol::withCStringNoCopy(kIOConsoleSessionSecureInputPIDKey);
+ gIOConsoleSessionScreenLockedTimeKey = OSSymbol::withCStringNoCopy(kIOConsoleSessionScreenLockedTimeKey);
+ gIOConsoleUsersSeedValue = OSData::withBytesNoCopy(&gIOConsoleUsersSeed, sizeof(gIOConsoleUsersSeed));
+
gIOPlatformSleepActionKey = OSSymbol::withCStringNoCopy(kIOPlatformSleepActionKey);
gIOPlatformWakeActionKey = OSSymbol::withCStringNoCopy(kIOPlatformWakeActionKey);
gIOPlatformQuiesceActionKey = OSSymbol::withCStringNoCopy(kIOPlatformQuiesceActionKey);
gIOServiceBusyLock = IOLockAlloc();
+ gIOConsoleUsersLock = IOLockAlloc();
+
err = semaphore_create(kernel_task, &gJobsSemaphore, SYNC_POLICY_FIFO, 0);
- assert( gIOServiceBusyLock && gJobs && gJobsLock && (err == KERN_SUCCESS) );
+ gIOConsoleLockCallout = thread_call_allocate(&IOService::consoleLockTimer, NULL);
+
+ IORegistryEntry::getRegistryRoot()->setProperty(gIOConsoleLockedKey, kOSBooleanTrue);
+
+ assert( gIOServiceBusyLock && gJobs && gJobsLock && gIOConsoleUsersLock
+ && gIOConsoleLockCallout && (err == KERN_SUCCESS) );
gIOResources = IOResources::resources();
assert( gIOResources );
// OSKernelStackRemaining(), getName());
if( needConfig) {
- prevBusy = _adjustBusy( 1 );
needWake = (0 != (kIOServiceSyncPubState & __state[1]));
}
if( needConfig) {
+ prevBusy = _adjustBusy( 1 );
+
if( needWake) {
IOLockLock( gIOServiceBusyLock );
thread_wakeup( (event_t) this/*&__state[1]*/ );
if( (typeOfInterest != gIOGeneralInterest)
&& (typeOfInterest != gIOBusyInterest)
&& (typeOfInterest != gIOAppPowerStateInterest)
+ && (typeOfInterest != gIOConsoleSecurityInterest)
&& (typeOfInterest != gIOPriorityPowerStateInterest))
return( 0 );
cleanInterestList( getProperty( gIOBusyInterest ));
cleanInterestList( getProperty( gIOAppPowerStateInterest ));
cleanInterestList( getProperty( gIOPriorityPowerStateInterest ));
+ cleanInterestList( getProperty( gIOConsoleSecurityInterest ));
}
/*
LOCKWRITENOTIFY();
if( queue_next( &chain )) {
- remqueue( 0, &chain);
+ remqueue(&chain);
queue_next( &chain) = queue_prev( &chain) = 0;
release();
}
#define tailQ(o) setObject(o)
#define headQ(o) setObject(0, o)
-#define TLOG(fmt, args...) { if(kIOLogYield & gIOKitDebug) IOLog(fmt, ## args); }
+#define TLOG(fmt, args...) { if(kIOLogYield & gIOKitDebug) { IOLog("[%llx] ", thread_tid(current_thread())); IOLog(fmt, ## args); }}
static void _workLoopAction( IOWorkLoop::Action action,
IOService * service,
bool IOService::terminatePhase1( IOOptionBits options )
{
- IOService * victim;
- IOService * client;
- OSIterator * iter;
- OSArray * makeInactive;
- bool ok;
- bool didInactive;
- bool startPhase2 = false;
+ IOService * victim;
+ IOService * client;
+ OSIterator * iter;
+ OSArray * makeInactive;
+ int waitResult = THREAD_AWAKENED;
+ bool wait;
+ bool ok;
+ bool didInactive;
+ bool startPhase2 = false;
TLOG("%s::terminatePhase1(%08llx)\n", getName(), (long long)options);
while( victim ) {
- didInactive = victim->lockForArbitration( true );
+ didInactive = victim->lockForArbitration( true );
if( didInactive) {
didInactive = (0 == (victim->__state[0] & kIOServiceInactiveState));
if( didInactive) {
victim->__state[0] |= kIOServiceInactiveState;
victim->__state[0] &= ~(kIOServiceRegisteredState | kIOServiceMatchedState
| kIOServiceFirstPublishState | kIOServiceFirstMatchState);
+
+ if (victim == this)
+ victim->__state[1] |= kIOServiceTermPhase1State;
+
victim->_adjustBusy( 1 );
- }
- victim->unlockForArbitration();
+
+ } else if (victim != this) do {
+
+ IOLockLock(gIOServiceBusyLock);
+ wait = (victim->__state[1] & kIOServiceTermPhase1State);
+ if( wait) {
+ TLOG("%s::waitPhase1(%s)\n", getName(), victim->getName());
+ victim->__state[1] |= kIOServiceTerm1WaiterState;
+ victim->unlockForArbitration();
+ assert_wait((event_t)&victim->__state[1], THREAD_UNINT);
+ }
+ IOLockUnlock(gIOServiceBusyLock);
+ if( wait) {
+ waitResult = thread_block(THREAD_CONTINUE_NULL);
+ TLOG("%s::did waitPhase1(%s)\n", getName(), victim->getName());
+ victim->lockForArbitration();
+ }
+ } while( wait && (waitResult != THREAD_TIMED_OUT));
+
+ victim->unlockForArbitration();
}
if( victim == this)
startPhase2 = didInactive;
makeInactive->release();
if( startPhase2)
- scheduleTerminatePhase2( options );
+ {
+ lockForArbitration();
+ __state[1] &= ~kIOServiceTermPhase1State;
+ if (kIOServiceTerm1WaiterState & __state[1])
+ {
+ __state[1] &= ~kIOServiceTerm1WaiterState;
+ TLOG("%s::wakePhase1\n", getName());
+ IOLockLock( gIOServiceBusyLock );
+ thread_wakeup( (event_t) &__state[1]);
+ IOLockUnlock( gIOServiceBusyLock );
+ }
+ unlockForArbitration();
+ scheduleTerminatePhase2( options );
+ }
return( true );
}
}
void IOService::actionWillTerminate( IOService * victim, IOOptionBits options,
- OSArray * doPhase2List )
+ OSArray * doPhase2List,
+ void *unused2 __unused,
+ void *unused3 __unused )
{
OSIterator * iter;
IOService * client;
}
}
-void IOService::actionDidTerminate( IOService * victim, IOOptionBits options )
+void IOService::actionDidTerminate( IOService * victim, IOOptionBits options,
+ void *unused1 __unused, void *unused2 __unused,
+ void *unused3 __unused )
{
OSIterator * iter;
IOService * client;
}
}
-void IOService::actionFinalize( IOService * victim, IOOptionBits options )
+void IOService::actionFinalize( IOService * victim, IOOptionBits options,
+ void *unused1 __unused, void *unused2 __unused,
+ void *unused3 __unused )
{
TLOG("%s::finalize(%08llx)\n", victim->getName(), (long long)options);
victim->finalize( options );
}
-void IOService::actionStop( IOService * provider, IOService * client )
+void IOService::actionStop( IOService * provider, IOService * client,
+ void *unused1 __unused, void *unused2 __unused,
+ void *unused3 __unused )
{
TLOG("%s::stop(%s)\n", client->getName(), provider->getName());
(uintptr_t) (regID2 >> 32));
} else {
- // not ready for stop if it has clients, skip it
- if( (client->__state[1] & kIOServiceTermPhase3State) && client->getClient()) {
+ // a terminated client is not ready for stop if it has clients, skip it
+ if( (kIOServiceInactiveState & client->__state[0]) && client->getClient()) {
TLOG("%s::defer stop(%s)\n", client->getName(), provider->getName());
uint64_t regID1 = provider->getRegistryEntryID();
__state[1] |= kIOServiceConfigState;
__state[0] |= kIOServiceRegisteredState;
- if( reRegistered && (0 == (__state[0] & kIOServiceInactiveState))) {
-
+ keepGuessing &= (0 == (__state[0] & kIOServiceInactiveState));
+ if (reRegistered && keepGuessing) {
iter = OSCollectionIterator::withCollection( (OSOrderedSet *)
gNotifications->getObject( gIOPublishNotification ) );
if( iter) {
UNLOCKNOTIFY();
unlockForArbitration();
- if( matches->getCount() && (kIOReturnSuccess == getResources()))
+ if (keepGuessing && matches->getCount() && (kIOReturnSuccess == getResources()))
probeCandidates( matches );
else
matches->release();
&messageClientsApplier, &context );
#if !NO_KEXTD
- if( nowQuiet && (next == gIOServiceRoot))
+ if( nowQuiet && (next == gIOServiceRoot)) {
OSKext::considerUnloads();
+ IOServiceTrace(IOSERVICE_REGISTRY_QUIET, 0, 0, 0, 0);
+ }
#endif
}
bool wait;
int waitResult = THREAD_AWAKENED;
bool computeDeadline = true;
- AbsoluteTime abstime;
+ AbsoluteTime deadline;
IOLockLock( gJobsLock );
do {
if( wait) {
if( msToWait) {
if( computeDeadline ) {
- clock_interval_to_absolutetime_interval(
- msToWait, kMillisecondScale, &abstime );
- clock_absolutetime_interval_to_deadline(
- abstime, &abstime );
+ clock_interval_to_deadline(
+ msToWait, kMillisecondScale, &deadline );
computeDeadline = false;
}
waitResult = IOLockSleepDeadline( gJobsLock, &gNumConfigThreads,
- abstime, THREAD_UNINT );
+ deadline, THREAD_UNINT );
} else {
waitResult = IOLockSleep( gJobsLock, &gNumConfigThreads,
THREAD_UNINT );
return( inst );
}
+bool IOResources::init( OSDictionary * dictionary )
+{
+ // Do super init first
+ if ( !super::init() )
+ return false;
+
+ // Allow PAL layer to publish a value
+ const char *property_name;
+ int property_value;
+
+ pal_get_resource_property( &property_name, &property_value );
+
+ if( property_name ) {
+ OSNumber *num;
+ const OSSymbol * sym;
+
+ if( (num = OSNumber::withNumber(property_value, 32)) != 0 ) {
+ if( (sym = OSSymbol::withCString( property_name)) != 0 ) {
+ this->setProperty( sym, num );
+ sym->release();
+ }
+ num->release();
+ }
+ }
+
+ return true;
+}
+
IOWorkLoop * IOResources::getWorkLoop() const
{
// If we are the resource root
return( ok );
}
+void IOService::consoleLockTimer(thread_call_param_t p0, thread_call_param_t p1)
+{
+ IOService::updateConsoleUsers(NULL, 0);
+}
+
+void IOService::updateConsoleUsers(OSArray * consoleUsers, IOMessage systemMessage)
+{
+ IORegistryEntry * regEntry;
+ OSObject * locked = kOSBooleanFalse;
+ uint32_t idx;
+ bool loggedIn;
+ bool publish;
+ OSDictionary * user;
+ static IOMessage sSystemPower;
+
+ regEntry = IORegistryEntry::getRegistryRoot();
+
+ IOLockLock(gIOConsoleUsersLock);
+
+ if (systemMessage)
+ {
+ sSystemPower = systemMessage;
+ }
+ loggedIn = false;
+ if (consoleUsers)
+ {
+ OSNumber * num = 0;
+ for (idx = 0;
+ (user = OSDynamicCast(OSDictionary, consoleUsers->getObject(idx)));
+ idx++)
+ {
+ loggedIn |= ((kOSBooleanTrue == user->getObject(gIOConsoleSessionOnConsoleKey))
+ && (kOSBooleanTrue == user->getObject(gIOConsoleSessionLoginDoneKey)));
+ if (!num)
+ {
+ num = OSDynamicCast(OSNumber, user->getObject(gIOConsoleSessionScreenLockedTimeKey));
+ }
+ }
+ gIOConsoleLockTime = num ? num->unsigned32BitValue() : 0;
+ }
+
+ if (!loggedIn
+ || (kIOMessageSystemWillSleep == sSystemPower)
+ || (kIOMessageSystemPagingOff == sSystemPower))
+ {
+ locked = kOSBooleanTrue;
+ }
+ else if (gIOConsoleLockTime)
+ {
+ clock_sec_t now;
+ clock_usec_t microsecs;
+
+ clock_get_calendar_microtime(&now, µsecs);
+ if (gIOConsoleLockTime > now)
+ {
+ AbsoluteTime deadline;
+ clock_interval_to_deadline(gIOConsoleLockTime - now, kSecondScale, &deadline);
+ thread_call_enter_delayed(gIOConsoleLockCallout, deadline);
+ }
+ else
+ {
+ locked = kOSBooleanTrue;
+ }
+ }
+
+ publish = (consoleUsers || (locked != regEntry->getProperty(gIOConsoleLockedKey)));
+ if (publish)
+ {
+ regEntry->setProperty(gIOConsoleLockedKey, locked);
+ if (consoleUsers)
+ {
+ regEntry->setProperty(gIOConsoleUsersKey, consoleUsers);
+ }
+ OSIncrementAtomic( &gIOConsoleUsersSeed );
+ }
+
+ IOLockUnlock(gIOConsoleUsersLock);
+
+ if (publish)
+ {
+ publishResource( gIOConsoleUsersSeedKey, gIOConsoleUsersSeedValue );
+
+ MessageClientsContext context;
+
+ context.service = getServiceRoot();
+ context.type = kIOMessageConsoleSecurityChange;
+ context.argument = (void *) regEntry;
+ context.argSize = 0;
+
+ applyToInterestNotifiers(getServiceRoot(), gIOConsoleSecurityInterest,
+ &messageClientsApplier, &context );
+ }
+}
+
IOReturn IOResources::setProperties( OSObject * properties )
{
IOReturn err;
if( 0 == iter)
return( kIOReturnBadArgument);
- while( (key = OSDynamicCast(OSSymbol, iter->getNextObject()))) {
-
- if (gIOConsoleUsersKey == key)
+ while( (key = OSDynamicCast(OSSymbol, iter->getNextObject())))
+ {
+ if (gIOConsoleUsersKey == key) do
{
- IORegistryEntry::getRegistryRoot()->setProperty(key, dict->getObject(key));
- OSIncrementAtomic( &gIOConsoleUsersSeed );
- publishResource( gIOConsoleUsersSeedKey, gIOConsoleUsersSeedValue );
- continue;
+ OSArray * consoleUsers;
+ consoleUsers = OSDynamicCast(OSArray, dict->getObject(key));
+ if (!consoleUsers)
+ continue;
+ IOService::updateConsoleUsers(consoleUsers, 0);
}
+ while (false);
publishResource( key, dict->getObject(key) );
}
} while( matchParent && (where = where->getProvider()) );
if( kIOLogMatch & gIOKitDebug)
- if( where != this)
+ if( where && (where != this) )
LOG("match parent @ %s = %d\n",
where->getName(), match );
OSMetaClassDefineReservedUnused(IOService, 45);
OSMetaClassDefineReservedUnused(IOService, 46);
OSMetaClassDefineReservedUnused(IOService, 47);
-
-#ifdef __ppc__
-OSMetaClassDefineReservedUnused(IOService, 48);
-OSMetaClassDefineReservedUnused(IOService, 49);
-OSMetaClassDefineReservedUnused(IOService, 50);
-OSMetaClassDefineReservedUnused(IOService, 51);
-OSMetaClassDefineReservedUnused(IOService, 52);
-OSMetaClassDefineReservedUnused(IOService, 53);
-OSMetaClassDefineReservedUnused(IOService, 54);
-OSMetaClassDefineReservedUnused(IOService, 55);
-OSMetaClassDefineReservedUnused(IOService, 56);
-OSMetaClassDefineReservedUnused(IOService, 57);
-OSMetaClassDefineReservedUnused(IOService, 58);
-OSMetaClassDefineReservedUnused(IOService, 59);
-OSMetaClassDefineReservedUnused(IOService, 60);
-OSMetaClassDefineReservedUnused(IOService, 61);
-OSMetaClassDefineReservedUnused(IOService, 62);
-OSMetaClassDefineReservedUnused(IOService, 63);
-#endif