Exemple #1
0
/*********************************************************************
* Remove drivers from the catalog which match the
* properties in the matching dictionary.
*********************************************************************/
bool
IOCatalogue::removeDrivers(
    OSDictionary * matching,
    bool doNubMatching)
{
    OSOrderedSet         * set;
    OSCollectionIterator * iter;
    OSDictionary         * dict;
    OSArray              * array;
    const OSSymbol       * key;
    unsigned int           idx;

    if ( !matching )
        return false;
    
    set = OSOrderedSet::withCapacity(10,
                                     IOServiceOrdering,
                                     (void *)gIOProbeScoreKey);
    if ( !set )
        return false;
    iter = OSCollectionIterator::withCollection(personalities);
    if (!iter) 
    {
    	set->release();
    	return (false);
    }

    IORWLockWrite(lock);
    while ((key = (const OSSymbol *) iter->getNextObject()))
    {
        array = (OSArray *) personalities->getObject(key);
        if (array) for (idx = 0; (dict = (OSDictionary *) array->getObject(idx)); idx++)
        {
           /* This comparison must be done with only the keys in the
            * "matching" dict to enable general searches.
            */
            if ( dict->isEqualTo(matching, matching) ) {
                set->setObject(dict);        
                array->removeObject(idx);
                idx--;
            }
        }
        // Start device matching.
        if ( doNubMatching && (set->getCount() > 0) ) {
            IOService::catalogNewDrivers(set);
            generation++;
        }
    }
    IORWLockUnlock(lock);
   
    set->release();
    iter->release();
    
    return true;
}
IOReturn IOAudioSelectorControl::removeAvailableSelection(SInt32 selectionValue)
{
    OSCollectionIterator *iterator;
	OSArray *newSelections;
	OSArray *oldAvailableSelections;
    IOReturn result = kIOReturnNotFound;

    assert(availableSelections);

	oldAvailableSelections = availableSelections;
	newSelections = OSArray::withArray(availableSelections);
	if (!newSelections)
		return kIOReturnNoMemory;

    iterator = OSCollectionIterator::withCollection(newSelections);
    if (iterator) {
        OSDictionary *	selection;
		UInt32			index;

		index = 0;
        while ( (selection = (OSDictionary *)iterator->getNextObject()) ) {
            OSNumber *	sValue;

            sValue = (OSNumber *)selection->getObject(kIOAudioSelectorControlSelectionValueKey);

            if (sValue && ((SInt32)sValue->unsigned32BitValue() == selectionValue)) {
				// Remove the selected dictionary from the array
				newSelections->removeObject(index);
				result = kIOReturnSuccess;
                break;
            }
			index++;
        }
		availableSelections = newSelections;
        setProperty(kIOAudioSelectorControlAvailableSelectionsKey, availableSelections);
		oldAvailableSelections->release();

        iterator->release();
    }

	if (kIOReturnSuccess == result) {
		sendChangeNotification(kIOAudioControlRangeChangeNotification);
	}

    return result;
}
Exemple #3
0
IOReturn IOCatalogue::_removeDrivers(OSDictionary * matching)
{
    IOReturn               ret = kIOReturnSuccess;
    OSCollectionIterator * iter;
    OSDictionary         * dict;
    OSArray              * array;
    const OSSymbol       * key;
    unsigned int           idx;

    // remove configs from catalog.

    iter = OSCollectionIterator::withCollection(personalities);
    if (!iter) return (kIOReturnNoMemory);

    while ((key = (const OSSymbol *) iter->getNextObject()))
    {
        array = (OSArray *) personalities->getObject(key);
        if (array) for (idx = 0; (dict = (OSDictionary *) array->getObject(idx)); idx++)
        {

	    /* Remove from the catalogue's array any personalities
	     * that match the matching dictionary.
	     * This comparison must be done with only the keys in the
	     * "matching" dict to enable general matching.
	     */
            if (dict->isEqualTo(matching, matching))
            {
                array->removeObject(idx);
                idx--;
            }
        }
    }
    iter->release();

    return ret;
}
IORegistryEntry *
IODeviceTreeAlloc( void * dtTop )
{
    IORegistryEntry *		parent;
    IORegistryEntry *		child;
    IORegistryIterator *	regIter;
    DTEntryIterator		iter;
    DTEntry			dtChild;
    DTEntry			mapEntry;
    OSArray *			stack;
    OSData *			prop;
    OSDictionary *		allInts;
    vm_offset_t *		dtMap;
    unsigned int		propSize;
    bool			intMap;
    bool			freeDT;

    gIODTPlane = IORegistryEntry::makePlane( kIODeviceTreePlane );

    gIODTNameKey 		= OSSymbol::withCStringNoCopy( "name" );
    gIODTUnitKey 		= OSSymbol::withCStringNoCopy( "AAPL,unit-string" );
    gIODTCompatibleKey 	= OSSymbol::withCStringNoCopy( "compatible" );
    gIODTTypeKey 		= OSSymbol::withCStringNoCopy( "device_type" );
    gIODTModelKey 		= OSSymbol::withCStringNoCopy( "model" );
    gIODTSizeCellKey 	= OSSymbol::withCStringNoCopy( "#size-cells" );
    gIODTAddressCellKey = OSSymbol::withCStringNoCopy( "#address-cells" );
    gIODTRangeKey 		= OSSymbol::withCStringNoCopy( "ranges" );
    gIODTPersistKey		= OSSymbol::withCStringNoCopy( "IODTPersist" );

    assert(    gIODTPlane && gIODTCompatibleKey
            && gIODTTypeKey && gIODTModelKey
            && gIODTSizeCellKey && gIODTAddressCellKey && gIODTRangeKey
            && gIODTPersistKey );

    gIODTDefaultInterruptController
		= OSSymbol::withCStringNoCopy("IOPrimaryInterruptController");
    gIODTNWInterruptMappingKey
		= OSSymbol::withCStringNoCopy("IONWInterrupts");

    gIODTAAPLInterruptsKey
		= OSSymbol::withCStringNoCopy("AAPL,interrupts");
    gIODTPHandleKey
		= OSSymbol::withCStringNoCopy("AAPL,phandle");

    gIODTInterruptParentKey
		= OSSymbol::withCStringNoCopy("interrupt-parent");

    gIODTPHandles	= OSArray::withCapacity( 1 );
    gIODTPHandleMap	= OSArray::withCapacity( 1 );

    gIODTInterruptCellKey
		= OSSymbol::withCStringNoCopy("#interrupt-cells");

    assert(    gIODTDefaultInterruptController && gIODTNWInterruptMappingKey 
	    && gIODTAAPLInterruptsKey
	    && gIODTPHandleKey && gIODTInterruptParentKey
	    && gIODTPHandles && gIODTPHandleMap
            && gIODTInterruptCellKey
	 );

    freeDT = (kSuccess == DTLookupEntry( 0, "/chosen/memory-map", &mapEntry ))
	  && (kSuccess == DTGetProperty( mapEntry,
                "DeviceTree", (void **) &dtMap, &propSize ))
	  && ((2 * sizeof(uint32_t)) == propSize);

    parent = MakeReferenceTable( (DTEntry)dtTop, freeDT );

    stack = OSArray::withObjects( (const OSObject **) &parent, 1, 10 );
    DTCreateEntryIterator( (DTEntry)dtTop, &iter );

    do {
        parent = (IORegistryEntry *)stack->getObject( stack->getCount() - 1);
        //parent->release();
        stack->removeObject( stack->getCount() - 1);

        while( kSuccess == DTIterateEntries( iter, &dtChild) ) {

            child = MakeReferenceTable( dtChild, freeDT );
            child->attachToParent( parent, gIODTPlane);

            AddPHandle( child );

            if( kSuccess == DTEnterEntry( iter, dtChild)) {
                stack->setObject( parent);
                parent = child;
            }
            // only registry holds retain
            child->release();
        }

    } while( stack->getCount()
		&& (kSuccess == DTExitEntry( iter, &dtChild)));

    stack->release();
    DTDisposeEntryIterator( iter);

    // parent is now root of the created tree

    // make root name first compatible entry (purely cosmetic)
    if( (prop = (OSData *) parent->getProperty( gIODTCompatibleKey))) {
        parent->setName( parent->getName(), gIODTPlane );
        parent->setName( (const char *) prop->getBytesNoCopy() );
    }

    // attach tree to meta root
    parent->attachToParent( IORegistryEntry::getRegistryRoot(), gIODTPlane);
    parent->release();

    if( freeDT ) {
        // free original device tree
        DTInit(0);
        IODTFreeLoaderInfo( "DeviceTree",
			    (void *)dtMap[0], (int) round_page(dtMap[1]) );
    }

    // adjust tree

    gIODTSharedInterrupts = OSDictionary::withCapacity(4);
    allInts = OSDictionary::withCapacity(4);
    intMap = false;
    regIter = IORegistryIterator::iterateOver( gIODTPlane,
						kIORegistryIterateRecursively );
    assert( regIter && allInts && gIODTSharedInterrupts );
    if( regIter && allInts && gIODTSharedInterrupts ) {
        while( (child = regIter->getNextObject())) {
            IODTMapInterruptsSharing( child, allInts );
            if( !intMap && child->getProperty( gIODTInterruptParentKey))
                intMap = true;

        }
        regIter->release();
    }

#if IODTSUPPORTDEBUG
    parent->setProperty("allInts", allInts);
    parent->setProperty("sharedInts", gIODTSharedInterrupts);

    regIter = IORegistryIterator::iterateOver( gIODTPlane,
						kIORegistryIterateRecursively );
    if (regIter) {
        while( (child = regIter->getNextObject())) {
	    OSArray *
	    array = OSDynamicCast(OSArray, child->getProperty( gIOInterruptSpecifiersKey ));
	    for( UInt32 i = 0; array && (i < array->getCount()); i++)
	    {
		IOOptionBits options;
		IOReturn ret = IODTGetInterruptOptions( child, i, &options );
		if( (ret != kIOReturnSuccess) || options)
		    IOLog("%s[%ld] %ld (%x)\n", child->getName(), i, options, ret);
	    }
	}
        regIter->release();
    }
#endif

    allInts->release();

    if( intMap)
        // set a key in the root to indicate we found NW interrupt mapping
        parent->setProperty( gIODTNWInterruptMappingKey,
                (OSObject *) gIODTNWInterruptMappingKey );

    return( parent);
}
Exemple #5
0
void
KLDBootstrap::readPrelinkedExtensions(
    kernel_section_t * prelinkInfoSect)
{
    OSArray                   * infoDictArray           = NULL;  // do not release
    OSObject                  * parsedXML       = NULL;  // must release
    OSDictionary              * prelinkInfoDict         = NULL;  // do not release
    OSString                  * errorString             = NULL;  // must release
    OSKext                    * theKernel               = NULL;  // must release

    kernel_segment_command_t  * prelinkTextSegment      = NULL;  // see code
    kernel_segment_command_t  * prelinkInfoSegment      = NULL;  // see code

   /* We make some copies of data, but if anything fails we're basically
    * going to fail the boot, so these won't be cleaned up on error.
    */
    void                      * prelinkData             = NULL;  // see code
    vm_size_t                   prelinkLength           = 0;


    OSDictionary              * infoDict                = NULL;  // do not release

    IORegistryEntry           * registryRoot            = NULL;  // do not release
    OSNumber                  * prelinkCountObj         = NULL;  // must release

    u_int                       i = 0;
#if NO_KEXTD
    bool                        ramDiskBoot;
    bool                        developerDevice;
    bool                        dontLoad;
#endif
    OSData                     * kaslrOffsets = NULL;
    unsigned long               plk_segSizes[PLK_SEGMENTS];
    vm_offset_t                 plk_segAddrs[PLK_SEGMENTS];

    OSKextLog(/* kext */ NULL,
        kOSKextLogProgressLevel |
        kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag,
        "Starting from prelinked kernel.");

    prelinkTextSegment = getsegbyname(kPrelinkTextSegment);
    if (!prelinkTextSegment) {
        OSKextLog(/* kext */ NULL,
            kOSKextLogErrorLevel |
            kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag,
            "Can't find prelinked kexts' text segment.");
        goto finish;
    }

#if KASLR_KEXT_DEBUG
    unsigned long   scratchSize;
    vm_offset_t     scratchAddr;
    
    IOLog("kaslr: prelinked kernel address info: \n");
    
    scratchAddr = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__TEXT", &scratchSize);
    IOLog("kaslr: start 0x%lx end 0x%lx length %lu for __TEXT \n", 
          (unsigned long)scratchAddr, 
          (unsigned long)(scratchAddr + scratchSize),
          scratchSize);
    
    scratchAddr = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__DATA", &scratchSize);
    IOLog("kaslr: start 0x%lx end 0x%lx length %lu for __DATA \n", 
          (unsigned long)scratchAddr, 
          (unsigned long)(scratchAddr + scratchSize),
          scratchSize);
    
    scratchAddr = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__LINKEDIT", &scratchSize);
    IOLog("kaslr: start 0x%lx end 0x%lx length %lu for __LINKEDIT \n", 
          (unsigned long)scratchAddr, 
          (unsigned long)(scratchAddr + scratchSize),
          scratchSize);
    
    scratchAddr = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__KLD", &scratchSize);
    IOLog("kaslr: start 0x%lx end 0x%lx length %lu for __KLD \n", 
          (unsigned long)scratchAddr, 
          (unsigned long)(scratchAddr + scratchSize),
          scratchSize);
    
    scratchAddr = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__PRELINK_TEXT", &scratchSize);
    IOLog("kaslr: start 0x%lx end 0x%lx length %lu for __PRELINK_TEXT \n", 
          (unsigned long)scratchAddr, 
          (unsigned long)(scratchAddr + scratchSize),
          scratchSize);
    
    scratchAddr = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__PRELINK_INFO", &scratchSize);
    IOLog("kaslr: start 0x%lx end 0x%lx length %lu for __PRELINK_INFO \n", 
          (unsigned long)scratchAddr, 
          (unsigned long)(scratchAddr + scratchSize),
          scratchSize);
#endif

    prelinkData = (void *) prelinkTextSegment->vmaddr;
    prelinkLength = prelinkTextSegment->vmsize;

    /* build arrays of plk info for later use */
    const char ** segNamePtr;

    for (segNamePtr = &plk_segNames[0], i = 0; *segNamePtr && i < PLK_SEGMENTS; segNamePtr++, i++) {
        plk_segSizes[i] = 0;
        plk_segAddrs[i] = (vm_offset_t)getsegdatafromheader(&_mh_execute_header, *segNamePtr, &plk_segSizes[i]);
    }


   /* Unserialize the info dictionary from the prelink info section.
    */
    parsedXML = OSUnserializeXML((const char *)prelinkInfoSect->addr,
        &errorString);
    if (parsedXML) {
        prelinkInfoDict = OSDynamicCast(OSDictionary, parsedXML);
    }
    if (!prelinkInfoDict) {
        const char * errorCString = "(unknown error)";
        
        if (errorString && errorString->getCStringNoCopy()) {
            errorCString = errorString->getCStringNoCopy();
        } else if (parsedXML) {
            errorCString = "not a dictionary";
        }
        OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
            "Error unserializing prelink plist: %s.", errorCString);
        goto finish;
    }

#if NO_KEXTD
    /* Check if we should keep developer kexts around.
     * TODO: Check DeviceTree instead of a boot-arg <rdar://problem/10604201>
     */
    developerDevice = true;
    PE_parse_boot_argn("developer", &developerDevice, sizeof(developerDevice));

    ramDiskBoot = IORamDiskBSDRoot();
#endif /* NO_KEXTD */


    infoDictArray = OSDynamicCast(OSArray, 
        prelinkInfoDict->getObject(kPrelinkInfoDictionaryKey));
    if (!infoDictArray) {
        OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
            "The prelinked kernel has no kext info dictionaries");
        goto finish;
    }
    
    /* kaslrOffsets are available use them to slide local relocations */
    kaslrOffsets = OSDynamicCast(OSData,
                                 prelinkInfoDict->getObject(kPrelinkLinkKASLROffsetsKey));
        
    /* Create dictionary of excluded kexts
     */
    OSKext::createExcludeListFromPrelinkInfo(infoDictArray);
    /* Create OSKext objects for each info dictionary. 
     */
    for (i = 0; i < infoDictArray->getCount(); ++i) {
        infoDict = OSDynamicCast(OSDictionary, infoDictArray->getObject(i));
        if (!infoDict) {
            OSKextLog(/* kext */ NULL,
                kOSKextLogErrorLevel |
                kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag,
                "Can't find info dictionary for prelinked kext #%d.", i);
            continue;
        }

#if NO_KEXTD
        dontLoad = false;

        /* If we're not on a developer device, skip and free developer kexts.
         */
        if (developerDevice == false) {
            OSBoolean *devOnlyBool = OSDynamicCast(OSBoolean,
                infoDict->getObject(kOSBundleDeveloperOnlyKey));
            if (devOnlyBool == kOSBooleanTrue) {
                dontLoad = true;
            }
        }

        /* Skip and free kexts that are only needed when booted from a ram disk.
         */
        if (ramDiskBoot == false) {
            OSBoolean *ramDiskOnlyBool = OSDynamicCast(OSBoolean,
                infoDict->getObject(kOSBundleRamDiskOnlyKey));
            if (ramDiskOnlyBool == kOSBooleanTrue) {
                dontLoad = true;
            }
        }

        if (dontLoad == true) {
            OSString *bundleID = OSDynamicCast(OSString,
                infoDict->getObject(kCFBundleIdentifierKey));
            if (bundleID) {
                OSKextLog(NULL, kOSKextLogWarningLevel | kOSKextLogGeneralFlag,
                    "Kext %s not loading.", bundleID->getCStringNoCopy());
            }
            
            OSNumber *addressNum = OSDynamicCast(OSNumber,
                infoDict->getObject(kPrelinkExecutableLoadKey));
            OSNumber *lengthNum = OSDynamicCast(OSNumber,
                infoDict->getObject(kPrelinkExecutableSizeKey));
            if (addressNum && lengthNum) {
#error Pick the right way to free prelinked data on this arch
            }

            infoDictArray->removeObject(i--);
            continue;
        }
#endif /* NO_KEXTD */

       /* Create the kext for the entry, then release it, because the
        * kext system keeps them around until explicitly removed.
        * Any creation/registration failures are already logged for us.
        */
        OSKext * newKext = OSKext::withPrelinkedInfoDict(infoDict, (kaslrOffsets ? TRUE : FALSE));
        OSSafeReleaseNULL(newKext);
    }

    /* slide kxld relocations */
    if (kaslrOffsets && vm_kernel_slide > 0) {
	    int slidKextAddrCount = 0;
	    int badSlideAddr = 0;
	    int badSlideTarget = 0;

        kaslrPackedOffsets * myOffsets = NULL;
	    myOffsets = (kaslrPackedOffsets *) kaslrOffsets->getBytesNoCopy();

	    for (uint32_t j = 0; j < myOffsets->count; j++) {

		    uint64_t        slideOffset = (uint64_t) myOffsets->offsetsArray[j];
		    uintptr_t *     slideAddr = (uintptr_t *) ((uint64_t)prelinkData + slideOffset);
		    int             slideAddrSegIndex = -1;
		    int             addrToSlideSegIndex = -1;

		    slideAddrSegIndex = __whereIsAddr( (vm_offset_t)slideAddr, &plk_segSizes[0], &plk_segAddrs[0], PLK_SEGMENTS );
		    if (slideAddrSegIndex >= 0) {
			    addrToSlideSegIndex = __whereIsAddr( (vm_offset_t)(*slideAddr + vm_kernel_slide), &plk_segSizes[0], &plk_segAddrs[0], PLK_SEGMENTS );
			    if (addrToSlideSegIndex < 0) {
				    badSlideTarget++;
				    continue;
			    }
		    }
		    else {
			    badSlideAddr++;
			    continue;
		    }

		    slidKextAddrCount++;
		    *(slideAddr) += vm_kernel_slide;
	    } // for ...

	    /* All kexts are now slid, set VM protections for them */
	    OSKext::setAllVMAttributes();
    }

   /* Store the number of prelinked kexts in the registry so we can tell
    * when the system has been started from a prelinked kernel.
    */
    registryRoot = IORegistryEntry::getRegistryRoot();
    assert(registryRoot);

    prelinkCountObj = OSNumber::withNumber(
        (unsigned long long)infoDictArray->getCount(),
        8 * sizeof(uint32_t));
    assert(prelinkCountObj);
    if (prelinkCountObj) {
        registryRoot->setProperty(kOSPrelinkKextCountKey, prelinkCountObj);
    }
    
    OSKextLog(/* kext */ NULL,
        kOSKextLogProgressLevel |
        kOSKextLogGeneralFlag | kOSKextLogKextBookkeepingFlag |
        kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag,
        "%u prelinked kexts", 
        infoDictArray->getCount());

#if CONFIG_KEXT_BASEMENT
        /* On CONFIG_KEXT_BASEMENT systems, kexts are copied to their own 
         * special VM region during OSKext init time, so we can free the whole 
         * segment now.
         */
        ml_static_mfree((vm_offset_t) prelinkData, prelinkLength);
#endif /* __x86_64__ */

   /* Free the prelink info segment, we're done with it.
    */
    prelinkInfoSegment = getsegbyname(kPrelinkInfoSegment);
    if (prelinkInfoSegment) {
        ml_static_mfree((vm_offset_t)prelinkInfoSegment->vmaddr,
            (vm_size_t)prelinkInfoSegment->vmsize);
    }

finish:
    OSSafeReleaseNULL(errorString);
    OSSafeReleaseNULL(parsedXML);
    OSSafeReleaseNULL(theKernel);
    OSSafeReleaseNULL(prelinkCountObj);
    return;
}
Exemple #6
0
bool IOCatalogue::resetAndAddDrivers(OSArray * drivers, bool doNubMatching)
{
    bool                   result              = false;
    OSArray              * newPersonalities    = NULL;  // do not release
    OSCollectionIterator * iter                = NULL;  // must release
    OSOrderedSet         * matchSet            = NULL;  // must release
    const OSSymbol       * key;
    OSArray              * array;
    OSDictionary         * thisNewPersonality  = NULL;  // do not release
    OSDictionary         * thisOldPersonality  = NULL;  // do not release
    signed int             idx, newIdx;

    if (drivers) {
        newPersonalities = OSDynamicCast(OSArray, drivers);
        if (!newPersonalities) {
            goto finish;
        }
        
        matchSet = OSOrderedSet::withCapacity(10, IOServiceOrdering,
            (void *)gIOProbeScoreKey);
        if (!matchSet) {
            goto finish;
        }
        iter = OSCollectionIterator::withCollection(personalities);
        if (!iter) {
            goto finish;
        }
    }

    result = true;

    IOLog("Resetting IOCatalogue.\n");

   /* No goto finish from here to unlock.
    */
    IORWLockWrite(lock);
    
    while ((key = (const OSSymbol *) iter->getNextObject()))
    {
        array = (OSArray *) personalities->getObject(key);
        if (!array) continue;
        for (idx = 0; (thisOldPersonality = (OSDictionary *) array->getObject(idx)); idx++)
        {
            if (thisOldPersonality->getObject("KernelConfigTable")) continue;
            if (newPersonalities) for (newIdx = 0; 
                (thisNewPersonality = (OSDictionary *) newPersonalities->getObject(newIdx)); 
                newIdx++)
            {
	       /* Unlike in other functions, this comparison must be exact!
            * The catalogue must be able to contain personalities that
            * are proper supersets of others.
            * Do not compare just the properties present in one driver
            * pesonality or the other.
            */
                if (thisNewPersonality->isEqualTo(thisOldPersonality))  
                    break;
            }
            if (thisNewPersonality)
            {
                // dup, ignore
                newPersonalities->removeObject(newIdx);
            }
            else
            {
                // not in new set - remove
                // only remove dictionary if this module in not loaded - 9953845
                if ( isModuleLoaded(thisOldPersonality) == false ) 
                {
                    if (matchSet)  matchSet->setObject(thisOldPersonality);
                    array->removeObject(idx);
                    idx--;
                }
            }
        }
    }
    
     // add new
     for (newIdx = 0;
          (thisNewPersonality = (OSDictionary *) newPersonalities->getObject(newIdx)); 
          newIdx++)
     {
         OSKext::uniquePersonalityProperties(thisNewPersonality);
         addPersonality(thisNewPersonality);
         matchSet->setObject(thisNewPersonality);
     }

   /* Finally, start device matching on all new & removed personalities.
    */
    if (result && doNubMatching && (matchSet->getCount() > 0)) {
        IOService::catalogNewDrivers(matchSet);
        generation++;
    }

    IORWLockUnlock(lock);

finish:
    if (matchSet) matchSet->release();
    if (iter)     iter->release();

    return result;
}
Exemple #7
0
bool IOCatalogue::resetAndAddDrivers(OSArray * drivers, bool doNubMatching)
{
    bool                   result              = false;
    OSArray              * newPersonalities    = NULL;  // do not release
    OSCollectionIterator * newPIterator        = NULL;  // must release
    OSOrderedSet         * matchSet            = NULL;  // must release
    OSArray              * oldPersonalities    = NULL;  // must release
    OSArray              * kernelPersonalities = NULL;  // must release
    OSString             * errorString         = NULL;  // must release
    OSObject             * object              = NULL;  // do not release
    OSDictionary         * thisNewPersonality  = NULL;  // do not release
    signed int             count, i;

    extern const char    * gIOKernelConfigTables;

    if (drivers) {
        newPersonalities = OSDynamicCast(OSArray, drivers);
        if (!newPersonalities) {
            goto finish;
        }

        newPIterator = OSCollectionIterator::withCollection(newPersonalities);
        if (!newPIterator) {
            goto finish;
        }
        
        matchSet = OSOrderedSet::withCapacity(10, IOServiceOrdering,
            (void *)gIOProbeScoreKey);
        if (!matchSet) {
            goto finish;
        }
    }

   /* Read personalities for the built-in kernel driver classes.
    * We don't have many any more.
    */
    kernelPersonalities = OSDynamicCast(OSArray,
        OSUnserialize(gIOKernelConfigTables, &errorString));
    if (!kernelPersonalities && errorString) {
        IOLog("KernelConfigTables syntax error: %s\n",
            errorString->getCStringNoCopy());
        goto finish;
    }
    
   /* Now copy the current array of personalities so we can reuse them
    * if the new list contains any duplicates. This saves on memory
    * consumption.
    */
    oldPersonalities = OSDynamicCast(OSArray, array->copyCollection());
    if (!oldPersonalities) {
        goto finish;
    }

    result = true;

    IOLog("Resetting IOCatalogue.\n");
    
   /* No goto finish from here to unlock.
    */
    IOLockLock(lock);
    
    array->flushCollection();

   /* Add back the kernel personalities and remove them from the old
    * array so we don't try to match on them again. Go forward through
    * the arrays as this causes the least iteration since kernel personalities
    * should always be first.
    */
    count = kernelPersonalities->getCount();
    for (i = 0; i < count; i++) {
    
       /* Static cast here, as the data is coming from within the kernel image.
        */
        OSDictionary * thisNewPersonality = (OSDictionary *)
            kernelPersonalities->getObject(i);
        array->setObject(thisNewPersonality);

        signed int oldPCount = oldPersonalities->getCount();
        for (signed int oldPIndex = 0; oldPIndex < oldPCount; oldPIndex++) {
            if (thisNewPersonality->isEqualTo(oldPersonalities->getObject(oldPIndex))) {
                oldPersonalities->removeObject(oldPIndex);
                break;
            }
        }
    }

   /* Now add the new set of personalities passed in, using existing
    * copies if we had them in kernel memory already.
    */
    if (newPIterator) {
        OSDictionary * thisOldPersonality = NULL;  // do not release
        
        while ( (object = newPIterator->getNextObject()) ) {

            thisNewPersonality = OSDynamicCast(OSDictionary, object);
            if (!thisNewPersonality) {
                IOLog("IOCatalogue::resetAndAddDrivers() encountered non-dictionary; bailing.\n");
            result = false;
            break;
            }

           /* Convert common OSString property values to OSSymbols.
            */
            OSKext::uniquePersonalityProperties(thisNewPersonality);
            
           /* Add driver personality to catalogue, but if we had a copy already
            * use that instead so we don't have multiple copies from OSKext instances.
            */
            count = oldPersonalities->getCount();
            thisOldPersonality = NULL;
            while (count--) {
                
                thisOldPersonality = (OSDictionary *)oldPersonalities->getObject(count);
                
               /* Unlike in other functions, this comparison must be exact!
                * The catalogue must be able to contain personalities that
                * are proper supersets of others.
                * Do not compare just the properties present in one driver
                * pesonality or the other.
                */
                if (thisNewPersonality->isEqualTo(thisOldPersonality)) {
                    break;
                }
            }

           /* If we found a dup, add the *original* back to the catalogue,
            * remove it from our bookkeeping list, and continue.
            * Don't worry about matching on personalities we already had.
            */
            if (count >= 0) {
                array->setObject(thisOldPersonality);
                oldPersonalities->removeObject(count);
                continue;
            }

           /* Otherwise add the new personality and mark it for matching.
            */
            array->setObject(thisNewPersonality);
            AddNewImports(matchSet, thisNewPersonality);                
        }

       /*****
        * Now, go through remaining old personalities, which have effectively
        * been removed, and add them to the match set as necessary.
        */
        count = oldPersonalities->getCount();
        while (count--) {
        
           /* Static cast here is ok as these dictionaries were already in the catalogue.
            */
            thisOldPersonality = (OSDictionary *)oldPersonalities->getObject(count);
            AddNewImports(matchSet, thisOldPersonality);
        }

       /* Finally, start device matching on all new & removed personalities.
        */
        if (result && doNubMatching && (matchSet->getCount() > 0)) {
            IOService::catalogNewDrivers(matchSet);
            generation++;
        }
    }

    IOLockUnlock(lock);

finish:
    if (newPIterator) newPIterator->release();
    if (matchSet) matchSet->release();
    if (oldPersonalities) oldPersonalities->release();
    if (kernelPersonalities) kernelPersonalities->release();
    if (errorString) errorString->release();

    return result;
}