]> git.saurik.com Git - apple/xnu.git/blobdiff - iokit/Kernel/IOService.cpp
xnu-3789.31.2.tar.gz
[apple/xnu.git] / iokit / Kernel / IOService.cpp
index 189f008fab66d24469a5b45b4bdbc550c89b0c46..440b5c589e6ae26ab33a18098a2e85e88ab8cc31 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998-2014 Apple Inc. All rights reserved.
+ * Copyright (c) 1998-2016 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  * 
@@ -77,6 +77,7 @@
 OSDefineMetaClassAndStructors(IOService, IORegistryEntry)
 
 OSDefineMetaClassAndStructors(_IOServiceNotifier, IONotifier)
+OSDefineMetaClassAndStructors(_IOServiceNullNotifier, IONotifier)
 
 OSDefineMetaClassAndStructors(_IOServiceInterestNotifier, IONotifier)
 
@@ -102,10 +103,12 @@ const OSSymbol *          gIOInterruptSpecifiersKey;
 
 const OSSymbol *               gIOResourcesKey;
 const OSSymbol *               gIOResourceMatchKey;
+const OSSymbol *               gIOResourceMatchedKey;
 const OSSymbol *               gIOProviderClassKey;
 const OSSymbol *               gIONameMatchKey;
 const OSSymbol *               gIONameMatchedKey;
 const OSSymbol *               gIOPropertyMatchKey;
+const OSSymbol *               gIOPropertyExistsMatchKey;
 const OSSymbol *               gIOLocationMatchKey;
 const OSSymbol *               gIOParentMatchKey;
 const OSSymbol *               gIOPathMatchKey;
@@ -128,10 +131,11 @@ const OSSymbol *          gIOConsoleSessionOnConsoleKey;
 const OSSymbol *               gIOConsoleSessionLoginDoneKey;
 const OSSymbol *               gIOConsoleSessionSecureInputPIDKey;
 const OSSymbol *               gIOConsoleSessionScreenLockedTimeKey;
-
+const OSSymbol *               gIOConsoleSessionScreenIsLockedKey;
 clock_sec_t                    gIOConsoleLockTime;
 static bool                    gIOConsoleLoggedIn;
 #if HIBERNATION
+static OSBoolean *             gIOConsoleBooterLockState;
 static uint32_t                        gIOScreenLockState;
 #endif
 static IORegistryEntry *        gIOChosenEntry;
@@ -151,6 +155,12 @@ const OSSymbol *           gIOAppPowerStateInterest;
 const OSSymbol *               gIOPriorityPowerStateInterest;
 const OSSymbol *               gIOConsoleSecurityInterest;
 
+const OSSymbol *               gIOBSDKey;
+const OSSymbol *               gIOBSDNameKey;
+const OSSymbol *               gIOBSDMajorKey;
+const OSSymbol *               gIOBSDMinorKey;
+const OSSymbol *               gIOBSDUnitKey;
+
 const  OSSymbol *               gAKSGetKey;
 #if defined(__i386__) || defined(__x86_64__)
 const OSSymbol *                gIOCreateEFIDevicePathSymbol;
@@ -187,6 +197,7 @@ const OSSymbol *            gIOPlatformFunctionHandlerSet;
 
 static IOLock *                        gIOConsoleUsersLock;
 static thread_call_t           gIOConsoleLockCallout;
+static IONotifier *             gIOServiceNullNotifier;
 
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 
@@ -293,6 +304,7 @@ void IOService::initialize( void )
     gIONameMatchKey    = OSSymbol::withCStringNoCopy( kIONameMatchKey );
     gIONameMatchedKey  = OSSymbol::withCStringNoCopy( kIONameMatchedKey );
     gIOPropertyMatchKey        = OSSymbol::withCStringNoCopy( kIOPropertyMatchKey );
+    gIOPropertyExistsMatchKey = OSSymbol::withCStringNoCopy( kIOPropertyExistsMatchKey );
     gIOPathMatchKey    = OSSymbol::withCStringNoCopy( kIOPathMatchKey );
     gIOLocationMatchKey        = OSSymbol::withCStringNoCopy( kIOLocationMatchKey );
     gIOParentMatchKey  = OSSymbol::withCStringNoCopy( kIOParentMatchKey );
@@ -305,8 +317,9 @@ void IOService::initialize( void )
 
     gIOUserClientClassKey = OSSymbol::withCStringNoCopy( kIOUserClientClassKey );
 
-    gIOResourcesKey    = OSSymbol::withCStringNoCopy( kIOResourcesClass );
-    gIOResourceMatchKey        = OSSymbol::withCStringNoCopy( kIOResourceMatchKey );
+    gIOResourcesKey      = OSSymbol::withCStringNoCopy( kIOResourcesClass );
+    gIOResourceMatchKey          = OSSymbol::withCStringNoCopy( kIOResourceMatchKey );
+    gIOResourceMatchedKey = OSSymbol::withCStringNoCopy( kIOResourceMatchedKey );
 
     gIODeviceMemoryKey = OSSymbol::withCStringNoCopy( "IODeviceMemory" );
     gIOInterruptControllersKey
@@ -326,6 +339,12 @@ void IOService::initialize( void )
     gIOPriorityPowerStateInterest      = OSSymbol::withCStringNoCopy( kIOPriorityPowerStateInterest );
     gIOConsoleSecurityInterest         = OSSymbol::withCStringNoCopy( kIOConsoleSecurityInterest );
 
+    gIOBSDKey     = OSSymbol::withCStringNoCopy(kIOBSDKey);
+    gIOBSDNameKey  = OSSymbol::withCStringNoCopy(kIOBSDNameKey);
+    gIOBSDMajorKey = OSSymbol::withCStringNoCopy(kIOBSDMajorKey);
+    gIOBSDMinorKey = OSSymbol::withCStringNoCopy(kIOBSDMinorKey);
+    gIOBSDUnitKey  = OSSymbol::withCStringNoCopy(kIOBSDUnitKey);
+
     gNotifications             = OSDictionary::withCapacity( 1 );
     gIOPublishNotification     = OSSymbol::withCStringNoCopy(
                                                 kIOPublishNotification );
@@ -349,6 +368,7 @@ void IOService::initialize( void )
     gIOConsoleSessionLoginDoneKey        = OSSymbol::withCStringNoCopy(kIOConsoleSessionLoginDoneKey);
     gIOConsoleSessionSecureInputPIDKey   = OSSymbol::withCStringNoCopy(kIOConsoleSessionSecureInputPIDKey);
     gIOConsoleSessionScreenLockedTimeKey = OSSymbol::withCStringNoCopy(kIOConsoleSessionScreenLockedTimeKey);
+    gIOConsoleSessionScreenIsLockedKey   = OSSymbol::withCStringNoCopy(kIOConsoleSessionScreenIsLockedKey);
 
     gIOConsoleUsersSeedValue          = OSData::withBytesNoCopy(&gIOConsoleUsersSeed, sizeof(gIOConsoleUsersSeed));
 
@@ -399,6 +419,9 @@ void IOService::initialize( void )
     gIOResources = IOResources::resources();
     assert( gIOResources );
 
+    gIOServiceNullNotifier = OSTypeAlloc(_IOServiceNullNotifier);
+    assert(gIOServiceNullNotifier);
+
     gArbitrationLockQueueLock = IOLockAlloc();
     queue_init(&gArbitrationLockQueueActive);
     queue_init(&gArbitrationLockQueueWaiting);
@@ -411,7 +434,6 @@ void IOService::initialize( void )
     gIOStopProviderList    = OSArray::withCapacity( 16 );
     gIOFinalizeList       = OSArray::withCapacity( 16 );
     assert( gIOTerminatePhase2List && gIOStopList && gIOStopProviderList && gIOFinalizeList );
-
 }
 
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
@@ -419,6 +441,7 @@ void IOService::initialize( void )
 #if defined(__i386__) || defined(__x86_64__)
 extern "C" {
 
+const char *getCpuDelayBusStallHolderName(void);
 const char *getCpuDelayBusStallHolderName(void) {
     return sCPULatencyHolderName[kCpuDelayBusStall];
 }
@@ -559,7 +582,11 @@ void IOService::free( void )
  */
 bool IOService::attach( IOService * provider )
 {
-    bool       ok;
+    bool         ok;
+    uint32_t     count;
+    AbsoluteTime deadline;
+    int                 waitResult = THREAD_AWAKENED;
+    bool        wait, computeDeadline = true;
 
     if( provider) {
 
@@ -567,12 +594,39 @@ bool IOService::attach( IOService * provider )
             LOG( "%s::attach(%s)\n", getName(),
                     provider->getName());
 
-        provider->lockForArbitration();
-        if( provider->__state[0] & kIOServiceInactiveState)
-            ok = false;
-        else
-            ok = attachToParent( provider, gIOServicePlane);
-        provider->unlockForArbitration();
+       ok   = false;
+       do
+       {
+            wait = false;
+           provider->lockForArbitration();
+           if (provider->__state[0] & kIOServiceInactiveState) ok = false;
+           else
+           {
+               count = provider->getChildCount(gIOServicePlane);
+               wait = (count > (kIOServiceBusyMax - 4));
+               if (!wait) ok = attachToParent(provider, gIOServicePlane);
+               else
+               {
+                   IOLog("stalling for detach from %s\n", provider->getName());
+                   IOLockLock( gIOServiceBusyLock );
+                   provider->__state[1] |= kIOServiceWaitDetachState;
+               }
+           }
+           provider->unlockForArbitration();
+           if (wait)
+           {
+                if (computeDeadline)
+                {
+                    clock_interval_to_deadline(15, kSecondScale, &deadline);
+                    computeDeadline = false;
+                }
+                assert_wait_deadline((event_t)&provider->__provider, THREAD_UNINT, deadline);
+                IOLockUnlock( gIOServiceBusyLock );
+               waitResult = thread_block(THREAD_CONTINUE_NULL);
+               wait = (waitResult != THREAD_TIMED_OUT);
+           }
+       }
+       while (wait);
 
     } else {
        gIOServiceRoot = this;
@@ -645,6 +699,15 @@ void IOService::detach( IOService * provider )
          && (0 == provider->getClient())) {
             provider->scheduleFinalize(false);
         }
+
+        IOLockLock( gIOServiceBusyLock );
+       if (kIOServiceWaitDetachState & provider->__state[1])
+       {
+           provider->__state[1] &= ~kIOServiceWaitDetachState;
+           thread_wakeup(&provider->__provider);
+       }
+        IOLockUnlock( gIOServiceBusyLock );
+
         provider->unlockForArbitration();
     }
 }
@@ -899,7 +962,7 @@ IOService * IOService::getProvider( void ) const
     IOService *        parent;
     SInt32     generation;
 
-    generation = getGenerationCount();
+    generation = getRegistryEntryGenerationCount();
     if( __providerGeneration == generation)
        return( __provider );
 
@@ -3116,7 +3179,7 @@ void IOService::probeCandidates( OSOrderedSet * matches )
                 // alloc the driver instance
                 inst = (IOService *) OSMetaClass::allocClassWithName( symbol);
     
-                if( !inst) {
+                if( !inst || !OSDynamicCast(IOService, inst)) {
                     IOLog("Couldn't alloc class \"%s\"\n",
                         symbol->getCStringNoCopy());
                     continue;
@@ -3475,6 +3538,7 @@ void IOService::doServiceMatch( IOOptionBits options )
     _IOServiceNotifier * notify;
     OSIterator *       iter;
     OSOrderedSet *     matches;
+    OSArray *           resourceKeys = 0;
     SInt32             catalogGeneration;
     bool               keepGuessing = true;
     bool               reRegistered = true;
@@ -3521,7 +3585,14 @@ void IOService::doServiceMatch( IOOptionBits options )
             unlockForArbitration();
 
             if (keepGuessing && matches->getCount() && (kIOReturnSuccess == getResources()))
+            {
+                if (this == gIOResources)
+                {
+                   if (resourceKeys) resourceKeys->release();
+                   resourceKeys = copyPropertyKeys();
+                }
                 probeCandidates( matches );
+            }
             else
                 matches->release();
         }
@@ -3539,6 +3610,9 @@ void IOService::doServiceMatch( IOOptionBits options )
 
     if( (0 == (__state[0] & kIOServiceInactiveState))
      && (0 == (__state[1] & kIOServiceModuleStallState)) ) {
+
+        if (resourceKeys) setProperty(gIOResourceMatchedKey, resourceKeys);
+
         deliverNotification( gIOMatchedNotification,
                kIOServiceMatchedState, 0xffffffff );
        if( 0 == (__state[0] & kIOServiceFirstMatchState))
@@ -3546,6 +3620,8 @@ void IOService::doServiceMatch( IOOptionBits options )
                kIOServiceFirstMatchState, 0xffffffff );
     }
 
+    if (resourceKeys) resourceKeys->release();
+
     __state[1] &= ~kIOServiceConfigState;
     scheduleTerminatePhase2();
 
@@ -3709,55 +3785,101 @@ IOReturn IOService::waitForState( UInt32 mask, UInt32 value,
         return( kIOReturnSuccess );
 }
 
+#if NO_KEXTD
+#define WAITING_KEXTD     false
+#else
+extern bool gIOKextdClearedBusy;
+#define WAITING_KEXTD     (false == gIOKextdClearedBusy)
+#endif
+
 IOReturn IOService::waitQuiet( uint64_t timeout )
 {
     IOReturn ret;
-    ret = waitForState( kIOServiceBusyStateMask, 0, timeout );
-    if ((kIOReturnTimeout == ret) && (timeout >= 41000000000) && (kIOWaitQuietPanics & gIOKitDebug))
+    uint32_t loops;
+    char * string = NULL;
+    size_t len;
+    uint64_t time;
+    uint64_t nano;
+
+    time = mach_absolute_time();
+    for (loops = 0; loops < 2; loops++)
     {
-       IORegistryIterator * iter;
-       OSOrderedSet       * set;
-       OSOrderedSet       * leaves;
-       IOService          * next;
-       IOService          * nextParent;
-       char               * string;
-       char               * s;
-       size_t               len, l;
-
-       len = 256;
-       string = IONew(char, len);
-       set = NULL;
-        iter = IORegistryIterator::iterateOver(this, gIOServicePlane, kIORegistryIterateRecursively);
-        leaves = OSOrderedSet::withCapacity(4);
-       if (iter) set = iter->iterateAll();
-       if (string && leaves && set)
-       {
-           while ((next = (IOService *) set->getLastObject()))
-           {
-               if (next->getBusyState())
-               {
-                   leaves->setObject(next);
-                   nextParent = next;
-                   while ((nextParent = nextParent->getProvider()))
-                   {
-                       set->removeObject(nextParent);
-                       leaves->removeObject(nextParent);
-                   }
-               }
-               set->removeObject(next);            
-           }
-           s = string;
-           while ((next = (IOService *) leaves->getLastObject()))
-           {
-               l = snprintf(s, len, "%s'%s'", ((s == string) ? "" : ", "), next->getName());
-               if (l >= len) break;
-               s += l;
-               len -= l;
-               leaves->removeObject(next);         
-           }
-       }
-        panic("busy timeout(%llds): %s", timeout / 1000000000ULL, string ? string : "");
+        ret = waitForState( kIOServiceBusyStateMask, 0, timeout );
+
+        if (loops && (kIOReturnSuccess == ret))
+        {
+            time = mach_absolute_time() - time;
+            absolutetime_to_nanoseconds(*(AbsoluteTime *)&time, &nano);
+            IOLog("busy extended ok[%d], (%llds, %llds), kextd wait(%d): %s\n",
+                  loops, timeout / 1000000000ULL, nano / 1000000000ULL, WAITING_KEXTD,
+                  string ? string : "");
+            break;
+        }
+        else if (kIOReturnTimeout != ret) break;
+        else if (timeout < 41000000000)   break;
+
+        if (!loops)
+        {
+            IORegistryIterator * iter;
+            OSOrderedSet       * set;
+            OSOrderedSet       * leaves;
+            IOService          * next;
+            IOService          * nextParent;
+            char               * s;
+            size_t               l;
+
+            len = 256;
+            string = IONew(char, len);
+            set = NULL;
+            iter = IORegistryIterator::iterateOver(this, gIOServicePlane, kIORegistryIterateRecursively);
+            leaves = OSOrderedSet::withCapacity(4);
+            if (iter) set = iter->iterateAll();
+            if (string && leaves && set)
+            {
+                while ((next = (IOService *) set->getLastObject()))
+                {
+                    if (next->getBusyState())
+                    {
+                        leaves->setObject(next);
+                        nextParent = next;
+                        while ((nextParent = nextParent->getProvider()))
+                        {
+                            set->removeObject(nextParent);
+                            leaves->removeObject(nextParent);
+                        }
+                    }
+                    set->removeObject(next);
+                }
+                s = string;
+                while ((next = (IOService *) leaves->getLastObject()))
+                {
+                    l = snprintf(s, len, "%s'%s'", ((s == string) ? "" : ", "), next->getName());
+                    if (l >= len) break;
+                    s += l;
+                    len -= l;
+                    leaves->removeObject(next);
+                }
+            }
+            OSSafeReleaseNULL(leaves);
+            OSSafeReleaseNULL(set);
+            OSSafeReleaseNULL(iter);
+        }
+        if (loops && (kIOWaitQuietPanics & gIOKitDebug))
+        {
+            panic("busy timeout[%d], (%llds), kextd wait(%d): %s",
+                    loops, timeout / 1000000000ULL, WAITING_KEXTD,
+                    string ? string : "");
+        }
+        else
+        {
+            IOLog("busy timeout[%d], (%llds), kextd wait(%d): %s\n",
+                    loops, timeout / 1000000000ULL, WAITING_KEXTD,
+                    string ? string : "");
+        }
     }
+
+    if (string) IODelete(string, char, 256);
+
     return (ret);
 }
 
@@ -4258,9 +4380,12 @@ IONotifier * IOService::doInstallNotification(
     else if( type == gIOFirstPublishNotification)
        inState = kIOServiceFirstPublishState;
 
-    else if( (type == gIOMatchedNotification)
-         || (type == gIOFirstMatchNotification))
+    else if (type == gIOMatchedNotification)
        inState = kIOServiceMatchedState;
+
+    else if (type == gIOFirstMatchNotification)
+       inState = kIOServiceFirstMatchState;
+
     else if( type == gIOTerminatedNotification)
        inState = 0;
     else
@@ -4314,6 +4439,9 @@ IONotifier * IOService::installNotification(
     notify = doInstallNotification( type, matching, handler, target, ref,
                priority, existing );
 
+    // in case handler remove()s
+    if (notify) notify->retain();
+
     UNLOCKNOTIFY();
 
     return( notify );
@@ -4347,16 +4475,17 @@ IONotifier * IOService::addMatchingNotification(
                        SInt32 priority )
 {
     OSIterator *               existing = NULL;
+    IONotifier *                ret;
     _IOServiceNotifier *       notify;
     IOService *                        next;
 
-    notify = (_IOServiceNotifier *) installNotification( type, matching,
+    ret = notify = (_IOServiceNotifier *) installNotification( type, matching,
                handler, target, ref, priority, &existing );
+    if (!ret) return (0);
 
     // send notifications for existing set
-    ifexisting) {
+    if (existing) {
 
-        notify->retain();              // in case handler remove()s
         while( (next = (IOService *) existing->getNextObject())) {
 
            next->lockForArbitration();
@@ -4364,11 +4493,16 @@ IONotifier * IOService::addMatchingNotification(
                 next->invokeNotifer( notify );
            next->unlockForArbitration();
        }
-        notify->release();
        existing->release();
     }
 
-    return( notify );
+    LOCKWRITENOTIFY();
+    bool removed = (0 == notify->whence);
+    notify->release();
+    if (removed) ret = gIOServiceNullNotifier;
+    UNLOCKNOTIFY();
+
+    return( ret );
 }
 
 bool IOService::syncNotificationHandler(
@@ -4723,6 +4857,19 @@ void _IOServiceNotifier::enable( bool was )
     UNLOCKNOTIFY();
 }
 
+
+/*
+ * _IOServiceNullNotifier
+ */
+
+void _IOServiceNullNotifier::taggedRetain(const void *tag) const                      {}
+void _IOServiceNullNotifier::taggedRelease(const void *tag, const int when) const     {}
+void _IOServiceNullNotifier::free()                                                   {}
+void _IOServiceNullNotifier::wait()                                                   {}
+void _IOServiceNullNotifier::remove()                                                 {}
+void _IOServiceNullNotifier::enable(bool was)                                         {}
+bool _IOServiceNullNotifier::disable()                                { return(false); }
+
 /*
  * IOResources
  */
@@ -4743,7 +4890,7 @@ IOService * IOResources::resources( void )
 bool IOResources::init( OSDictionary * dictionary )
 {
     // Do super init first
-    if ( !super::init() )
+    if ( !IOService::init() )
         return false;
 
     // Allow PAL layer to publish a value
@@ -4791,6 +4938,7 @@ bool IOResources::matchPropertyTable( OSDictionary * table )
     OSString *         str;
     OSSet *            set;
     OSIterator *       iter;
+    OSArray *           keys;
     bool               ok = true;
 
     prop = table->getObject( gIOResourceMatchKey );
@@ -4808,6 +4956,17 @@ bool IOResources::matchPropertyTable( OSDictionary * table )
         if( iter)
            iter->release();
     }
+    else if ((prop = table->getObject(gIOResourceMatchedKey)))
+    {
+        keys = (OSArray *) copyProperty(gIOResourceMatchedKey);
+        ok = false;
+        if (keys)
+        {
+            // assuming OSSymbol
+            ok = ((-1U) != keys->getNextIndexOfObject(prop, 0));
+            keys->release();
+        }
+    }
 
     return( ok );
 }
@@ -4837,9 +4996,25 @@ void IOService::updateConsoleUsers(OSArray * consoleUsers, IOMessage systemMessa
     {
         sSystemPower = systemMessage;
 #if HIBERNATION
-       if ((kIOMessageSystemHasPoweredOn == systemMessage) && IOHibernateWasScreenLocked())
+       if (kIOMessageSystemHasPoweredOn == systemMessage)
        {
-           locked = kOSBooleanTrue;
+           uint32_t lockState = IOHibernateWasScreenLocked();
+           switch (lockState)
+           {
+               case 0:
+                   break;
+               case kIOScreenLockLocked:
+               case kIOScreenLockFileVaultDialog:
+                   gIOConsoleBooterLockState = kOSBooleanTrue;
+                   break;
+               case kIOScreenLockNoLock:
+                   gIOConsoleBooterLockState = 0;
+                   break;
+               case kIOScreenLockUnlocked:
+               default:
+                   gIOConsoleBooterLockState = kOSBooleanFalse;
+                   break;
+           }
        }
 #endif /* HIBERNATION */
     }
@@ -4847,6 +5022,8 @@ void IOService::updateConsoleUsers(OSArray * consoleUsers, IOMessage systemMessa
     if (consoleUsers)
     {
         OSNumber * num = 0;
+       bool       loginLocked = true;
+
        gIOConsoleLoggedIn = false;
        for (idx = 0; 
              (user = OSDynamicCast(OSDictionary, consoleUsers->getObject(idx))); 
@@ -4854,11 +5031,16 @@ void IOService::updateConsoleUsers(OSArray * consoleUsers, IOMessage systemMessa
        {
            gIOConsoleLoggedIn |= ((kOSBooleanTrue == user->getObject(gIOConsoleSessionOnConsoleKey))
                        && (kOSBooleanTrue == user->getObject(gIOConsoleSessionLoginDoneKey)));
+
+           loginLocked &= (kOSBooleanTrue == user->getObject(gIOConsoleSessionScreenIsLockedKey));
            if (!num)
            {
                num = OSDynamicCast(OSNumber, user->getObject(gIOConsoleSessionScreenLockedTimeKey));
            }
        }
+#if HIBERNATION
+        if (!loginLocked) gIOConsoleBooterLockState = 0;
+#endif /* HIBERNATION */
         gIOConsoleLockTime = num ? num->unsigned32BitValue() : 0;
     }
 
@@ -4868,6 +5050,12 @@ void IOService::updateConsoleUsers(OSArray * consoleUsers, IOMessage systemMessa
     {
        locked = kOSBooleanTrue;
     }
+#if HIBERNATION
+    else if (gIOConsoleBooterLockState)
+    {
+       locked = gIOConsoleBooterLockState;
+    }
+#endif /* HIBERNATION */
     else if (gIOConsoleLockTime)
     {
        clock_sec_t  now;
@@ -4974,11 +5162,16 @@ bool IOService::compareProperty( OSDictionary * matching,
                                  const char *  key )
 {
     OSObject * value;
+    OSObject * prop;
     bool       ok;
 
     value = matching->getObject( key );
     if( value)
-        ok = value->isEqualTo( getProperty( key ));
+    {
+        prop = copyProperty(key);
+        ok = value->isEqualTo(prop);
+        if (prop) prop->release();
+    }
     else
        ok = true;
 
@@ -4990,11 +5183,16 @@ bool IOService::compareProperty( OSDictionary *   matching,
                                  const OSString * key )
 {
     OSObject * value;
+    OSObject * prop;
     bool       ok;
 
     value = matching->getObject( key );
     if( value)
-        ok = value->isEqualTo( getProperty( key ));
+    {
+        prop = copyProperty(key);
+        ok = value->isEqualTo(prop);
+        if (prop) prop->release();
+    }
     else
        ok = true;
 
@@ -5074,8 +5272,8 @@ bool IOService::matchInternal(OSDictionary * table, uint32_t options, uint32_t *
     {
        count = table->getCount();
        done = 0;
-       str = OSDynamicCast(OSString, table->getObject(gIOProviderClassKey));
 
+       str = OSDynamicCast(OSString, table->getObject(gIOProviderClassKey));
        if (str) {
            done++;
            match = ((kIOServiceClassDone & options) || (0 != metaCast(str)));
@@ -5145,6 +5343,38 @@ bool IOService::matchInternal(OSDictionary * table, uint32_t options, uint32_t *
            if ((!match) || (done == count)) break;
        }
 
+       obj = table->getObject( gIOPropertyExistsMatchKey );
+       if( obj)
+       {
+           OSDictionary * dict;
+           OSString     * nextKey;
+           OSIterator *   iter;
+           done++;
+           match = false;
+           dict = dictionaryWithProperties();
+           if( dict) {
+               nextKey = OSDynamicCast( OSString, obj);
+               if( nextKey)
+                   iter = 0;
+               else
+                   iter = OSCollectionIterator::withCollection(
+                               OSDynamicCast(OSCollection, obj));
+
+               while( nextKey
+                   || (iter && (0 != (nextKey = OSDynamicCast(OSString,
+                                           iter->getNextObject()))))) {
+                   match = (0 != dict->getObject(nextKey));
+                   if( match)
+                       break;
+                   nextKey = 0;
+               }
+               dict->release();
+               if( iter)
+                   iter->release();
+           }
+           if ((!match) || (done == count)) break;
+       }
+
        str = OSDynamicCast( OSString, table->getObject( gIOPathMatchKey ));
        if( str) {
            done++;
@@ -5196,10 +5426,10 @@ bool IOService::matchInternal(OSDictionary * table, uint32_t options, uint32_t *
             if (prop) prop->release();                 \
            if ((!match) || (done == count)) break;     \
        }
-       propMatch(kIOBSDNameKey)
-       propMatch(kIOBSDMajorKey)
-       propMatch(kIOBSDMinorKey)
-       propMatch(kIOBSDUnitKey)
+       propMatch(gIOBSDNameKey)
+       propMatch(gIOBSDMajorKey)
+       propMatch(gIOBSDMinorKey)
+       propMatch(gIOBSDUnitKey)
 #undef propMatch
     }
     while (false);
@@ -5229,7 +5459,7 @@ bool IOService::matchPassive(OSDictionary * table, uint32_t options)
     OSArray* aliasServiceRegIds = NULL;
     IOService* foundAlternateService = NULL;
 
-#if MATCH_DEBUG 
+#if MATCH_DEBUG
     OSDictionary * root = table;
 #endif
 
@@ -5239,7 +5469,6 @@ bool IOService::matchPassive(OSDictionary * table, uint32_t options)
         do
         {
            count = table->getCount();
-            
            if (!(kIOServiceInternalDone & options))
            {
                match = where->matchInternal(table, options, &done);
@@ -5275,7 +5504,7 @@ bool IOService::matchPassive(OSDictionary * table, uint32_t options)
 
             nextTable = OSDynamicCast(OSDictionary,
                   table->getObject( gIOParentMatchKey ));
-            if(nextTable) {
+            if( nextTable) {
                // look for a matching entry anywhere up to root
                 match = false;
                 matchParent = true;
@@ -5339,11 +5568,11 @@ bool IOService::matchPassive(OSDictionary * table, uint32_t options)
     }
     while( where != NULL );
 
-    OSSafeRelease(foundAlternateService);
-    OSSafeRelease(aliasServiceRegIds);
+    OSSafeReleaseNULL(foundAlternateService);
+    OSSafeReleaseNULL(aliasServiceRegIds);
 
 #if MATCH_DEBUG
-    if (where != this)
+    if (where != this) 
     {
        OSSerialize * s = OSSerialize::withCapacity(128);
        root->serialize(s);