IOReturn IOGUIDPartitionScheme::requestProbe(IOOptionBits options)
{
    //
    // Request that the provider media be re-scanned for partitions.
    //

    OSSet * partitions    = 0;
    OSSet * partitionsNew;
    SInt32  score         = 0;

    // Scan the provider media for partitions.

    partitionsNew = scan( &score );

    if ( partitionsNew )
    {
        if ( lockForArbitration( false ) )
        {
            partitions = juxtaposeMediaObjects( _partitions, partitionsNew );

            if ( partitions )
            {
                _partitions->release( );

                _partitions = partitions;
            }

            unlockForArbitration( );
        }

        partitionsNew->release( );
    }

    return partitions ? kIOReturnSuccess : kIOReturnError;
}
Beispiel #2
0
OSCollection * OSSet::copyCollection(OSDictionary *cycleDict)
{
    bool allocDict = !cycleDict;
    OSCollection *ret = 0;
    OSSet *newSet = 0;

    if (allocDict) {
	cycleDict = OSDictionary::withCapacity(16);
	if (!cycleDict)
	    return 0;
    }

    do {
	// Check for a cycle
	ret = super::copyCollection(cycleDict);
	if (ret)
	    continue;	// Found it

	newSet = OSSet::withCapacity(members->capacity);
	if (!newSet)
	    continue;	// Couldn't create new set abort

	// Insert object into cycle Dictionary
	cycleDict->setObject((const OSSymbol *) this, newSet);

	OSArray *newMembers = newSet->members;
	newMembers->capacityIncrement = members->capacityIncrement;

	// Now copy over the contents into the new duplicate
	for (unsigned int i = 0; i < members->count; i++) {
	    OSObject *obj = EXT_CAST(members->array[i]);
	    OSCollection *coll = OSDynamicCast(OSCollection, obj);
	    if (coll) {
		OSCollection *newColl = coll->copyCollection(cycleDict);
		if (newColl) {
		    obj = newColl;	// Rely on cycleDict ref for a bit
		    newColl->release();
		}
		else
		    goto abortCopy;
	    };
	    newMembers->setObject(obj);
	};

	ret = newSet;
	newSet = 0;

    } while(false);

abortCopy:
    if (newSet)
	newSet->release();

    if (allocDict)
	cycleDict->release();

    return ret;
}
Beispiel #3
0
OSSet *OSSet::withCapacity(unsigned int capacity)
{
    OSSet *me = new OSSet;

    if (me && !me->initWithCapacity(capacity)) {
        me->release();
        return 0;
    }

    return me;
}
Beispiel #4
0
OSSet *OSSet::withSet(const OSSet *set,
                      unsigned int capacity)
{
    OSSet *me = new OSSet;

    if (me && !me->initWithSet(set, capacity)) {
        me->release();
        return 0;
    }

    return me;
}
Beispiel #5
0
OSSet *OSSet::withArray(const OSArray *array,
                        unsigned int capacity)
{
    OSSet *me = new OSSet;

    if (me && !me->initWithArray(array, capacity)) {
        me->release();
        return 0;
    }

    return me;
}
Beispiel #6
0
OSSet *OSSet::withObjects(const OSObject *objects[],
                          unsigned int count,
                          unsigned int capacity)
{
    OSSet *me = new OSSet;

    if (me && !me->initWithObjects(objects, count, capacity)) {
        me->release();
        return 0;
    }

    return me;
}
OSMetaClass::~OSMetaClass()
{
    do {
	OSCollectionIterator *iter;

	if (sAllClassesDict)
	    sAllClassesDict->removeObject(className);

	iter = OSCollectionIterator::withCollection(sKModClassesDict);
	if (!iter)
	    break;

	OSSymbol *iterKey;
	while ( (iterKey = (OSSymbol *) iter->getNextObject()) ) {
	    OSSet *kmodClassSet;
	    kmodClassSet = (OSSet *) sKModClassesDict->getObject(iterKey);
	    if (kmodClassSet && kmodClassSet->containsObject(this)) {
		kmodClassSet->removeObject(this);
		break;
	    }
	}
	iter->release();
    } while (false);

    if (sStalled) {
	unsigned int i;

	// First pass find class in stalled list
	for (i = 0; i < sStalled->count; i++)
	    if (this == sStalled->classes[i])
		break;

	if (i < sStalled->count) {
	    sStalled->count--;
	    if (i < sStalled->count)
		memmove(&sStalled->classes[i], &sStalled->classes[i+1],
			    (sStalled->count - i) * sizeof(OSMetaClass *));
	}
	return;
    }
}
bool IOPlatformExpert::configure( IOService * provider )
{
    OSSet *		topLevel;
    OSDictionary *	dict;
    IOService * 	nub;

    topLevel = OSDynamicCast( OSSet, getProperty("top-level"));

    if( topLevel) {
        while( (dict = OSDynamicCast( OSDictionary,
				topLevel->getAnyObject()))) {
            dict->retain();
            topLevel->removeObject( dict );
            nub = createNub( dict );
            if( 0 == nub)
                continue;
            dict->release();
            nub->attach( this );
            nub->registerService();
        }
    }

    return( true );
}
Beispiel #9
0
OSObject *
OSUnserializeBinary(const char *buffer, size_t bufferSize, OSString **errorString)
{
	OSObject ** objsArray;
	uint32_t    objsCapacity;
	enum      { objsCapacityMax = 16*1024*1024 };
	uint32_t    objsIdx;

	OSObject ** stackArray;
	uint32_t    stackCapacity;
	enum      { stackCapacityMax = 64 };
	uint32_t    stackIdx;

    OSObject     * result;
    OSObject     * parent;
    OSDictionary * dict;
    OSArray      * array;
    OSSet        * set;
    OSDictionary * newDict;
    OSArray      * newArray;
    OSSet        * newSet;
    OSObject     * o;
    OSSymbol     * sym;
    OSString     * str;

    size_t           bufferPos;
    const uint32_t * next;
    uint32_t         key, len, wordLen;
    bool             end, newCollect, isRef;
    unsigned long long value;
    bool ok;

	if (errorString) *errorString = 0;
	if (bufferSize < sizeof(kOSSerializeBinarySignature)) return (NULL);
	if (0 != strcmp(kOSSerializeBinarySignature, buffer)) return (NULL);
	if (3 & ((uintptr_t) buffer)) return (NULL);
	bufferPos = sizeof(kOSSerializeBinarySignature);
	next = (typeof(next)) (((uintptr_t) buffer) + bufferPos);

	DEBG("---------OSUnserializeBinary(%p)\n", buffer);

	objsArray = stackArray    = NULL;
	objsIdx   = objsCapacity  = 0;
	stackIdx  = stackCapacity = 0;

    result   = 0;
    parent   = 0;
	dict     = 0;
	array    = 0;
	set      = 0;
	sym      = 0;

	ok = true;
	while (ok)
	{
		bufferPos += sizeof(*next);
		if (!(ok = (bufferPos <= bufferSize))) break;
		key = *next++;

        len = (key & kOSSerializeDataMask);
        wordLen = (len + 3) >> 2;
		end = (0 != (kOSSerializeEndCollecton & key));
        DEBG("key 0x%08x: 0x%04x, %d\n", key, len, end);

        newCollect = isRef = false;
		o = 0; newDict = 0; newArray = 0; newSet = 0;
		
		switch (kOSSerializeTypeMask & key)
		{
		    case kOSSerializeDictionary:
				o = newDict = OSDictionary::withCapacity(len);
				newCollect = (len != 0);
		        break;
		    case kOSSerializeArray:
				o = newArray = OSArray::withCapacity(len);
				newCollect = (len != 0);
		        break;
		    case kOSSerializeSet:
				o = newSet = OSSet::withCapacity(len);
				newCollect = (len != 0);
		        break;

		    case kOSSerializeObject:
				if (len >= objsIdx) break;
				o = objsArray[len];
				isRef = true;
				break;

		    case kOSSerializeNumber:
				bufferPos += sizeof(long long);
				if (bufferPos > bufferSize) break;
		        if ((len != 32) && (len != 64) && (len != 16) && (len != 8)) break;
		    	value = next[1];
		    	value <<= 32;
		    	value |= next[0];
		    	o = OSNumber::withNumber(value, len);
		    	next += 2;
		        break;

		    case kOSSerializeSymbol:
				bufferPos += (wordLen * sizeof(uint32_t));
				if (bufferPos > bufferSize)           break;
				if (len < 2)                          break;
				if (0 != ((const char *)next)[len-1]) break;
		        o = (OSObject *) OSSymbol::withCString((const char *) next);
		        next += wordLen;
		        break;

		    case kOSSerializeString:
				bufferPos += (wordLen * sizeof(uint32_t));
				if (bufferPos > bufferSize) break;
		        o = OSString::withStringOfLength((const char *) next, len);
		        next += wordLen;
		        break;

    	    case kOSSerializeData:
				bufferPos += (wordLen * sizeof(uint32_t));
				if (bufferPos > bufferSize) break;
		        o = OSData::withBytes(next, len);
		        next += wordLen;
		        break;

    	    case kOSSerializeBoolean:
				o = (len ? kOSBooleanTrue : kOSBooleanFalse);
		        break;

		    default:
		        break;
		}

		if (!(ok = (o != 0))) break;

		if (!isRef)
		{
			setAtIndex(objs, objsIdx, o);
			if (!ok)
			{
			    o->release();
                break;
            }
			objsIdx++;
		}

		if (dict)
		{
			if (!sym) sym = (OSSymbol *) o;
			else
			{
                str = sym;
				sym = OSDynamicCast(OSSymbol, sym);
				if (!sym && (str = OSDynamicCast(OSString, str)))
				{
				    sym = const_cast<OSSymbol *>(OSSymbol::withString(str));
                    ok = (sym != 0);
                    if (!ok) break;
				}
				DEBG("%s = %s\n", sym->getCStringNoCopy(), o->getMetaClass()->getClassName());
				if (o != dict) ok = dict->setObject(sym, o);
                if (sym && (sym != str)) sym->release();
				sym = 0;
			}
		}
		else if (array)  ok = array->setObject(o);
		else if (set)    ok = set->setObject(o);
		else if (result) ok = false;
		else
		{
		    assert(!parent);
		    result = o;
		}

		if (!ok) break;

        if (end) parent = 0;
		if (newCollect)
		{
            stackIdx++;
            setAtIndex(stack, stackIdx, parent);
            if (!ok) break;
			DEBG("++stack[%d] %p\n", stackIdx, parent);
			parent = o;
			dict   = newDict;
			array  = newArray;
			set    = newSet;
			end    = false;
		}

		if (end)
		{
            while (stackIdx)
            {
                parent = stackArray[stackIdx];
                DEBG("--stack[%d] %p\n", stackIdx, parent);
                stackIdx--;
                if (parent) break;
            }
            if (!parent) break;
			set   = 0;
			dict  = 0; 
			array = 0;
			if (!(dict = OSDynamicCast(OSDictionary, parent)))
			{
				if (!(array = OSDynamicCast(OSArray, parent))) ok = (0 != (set = OSDynamicCast(OSSet, parent)));
			}
		}
	}
	DEBG("ret %p\n", result);

	if (!ok) result = 0;

	if (objsCapacity)
	{
        for (len = (result != 0); len < objsIdx; len++) objsArray[len]->release();
	    kfree(objsArray,  objsCapacity  * sizeof(*objsArray));
    }
	if (stackCapacity) kfree(stackArray, stackCapacity * sizeof(*stackArray));

	return (result);
}
Beispiel #10
0
void testIterator()
{
    bool res = true;
    void *spaceCheck;
    OSObject *cache[numStrCache];
    OSString *str = 0;
    const OSSymbol *symCache[numStrCache], *sym;
    OSDictionary *dict;
    OSSet *set;
    OSArray *array, *bigReturn;
    OSCollectionIterator *iter1, *iter2;
    int i, numSymbols, count1, count2, count3;

    // Setup symbol and string pools
    for (i = 0, numSymbols = 0; i < numStrCache; i++) {
        sym = OSSymbol::withCStringNoCopy(strCache[i]);
        if (1 == sym->getRetainCount()) {
            cache[numSymbols] = OSString::withCStringNoCopy(strCache[i]);
            symCache[numSymbols] = sym;
            numSymbols++;
        }
        else
            sym->release();
    }

    // Test the array iterator
    spaceCheck = checkPointSpace();
    iter1 = iter2 = 0;
    array = OSArray::withCapacity(numSymbols);
    TEST_ASSERT('I', "1a", array);
    if (array) {
        count1 = count2 = 0;
        for (i = numSymbols; --i >= 0; )
            count1 += array->setObject(cache[i], 0);
        TEST_ASSERT('I', "1b", count1 == numSymbols);

        iter1 = OSCollectionIterator::withCollection(array);
        iter2 = OSCollectionIterator::withCollection(array);
    }
    TEST_ASSERT('I', "1c", iter1);
    TEST_ASSERT('I', "1d", iter2);
    if (iter1 && iter2) {
        count1 = count2 = count3 = 0;
        for (i = 0; (str = (IOString *) iter1->getNextObject()); i++) {
            bigReturn = iter2->nextEntries();
            count1 += (bigReturn->getCount() == 1);
            count2 += (cache[i] == bigReturn->getObject(0));
            count3 += (cache[i] == str);
        }
        TEST_ASSERT('I', "1e", count1 == numSymbols);
        TEST_ASSERT('I', "1f", count2 == numSymbols);
        TEST_ASSERT('I', "1g", count3 == numSymbols);
        TEST_ASSERT('I', "1h", iter1->valid());
        TEST_ASSERT('I', "1i", iter2->valid());

        iter1->reset();
        str = (OSString *) array->__takeObject(0);
        array->setObject(str, 0);
        str->release();
        TEST_ASSERT('I', "1j", !iter1->getNextObject());
        TEST_ASSERT('I', "1k", !iter1->valid());

        iter1->reset();
        count1 = count2 = count3 = 0;
        for (i = 0; ; i++) {
            if (i & 1)
                str = (OSString *) iter1->getNextObject();
            else if ( (bigReturn = iter1->nextEntries()) )
                str = (OSString *) bigReturn->getObject(0);
            else
                str = 0;

            if (!str)
                break;
            count1 += (cache[i] == str);
        }
        TEST_ASSERT('I', "1l", count1 == numSymbols);
        TEST_ASSERT('I', "1m", i == numSymbols);
        TEST_ASSERT('I', "1n", iter1->valid());

        TEST_ASSERT('I', "1o", 3 == array->getRetainCount());
        array->release();
    }

    if (iter1) iter1->release();
    if (iter2) iter2->release();
    res = res && checkSpace("(I)1", spaceCheck, 0);

    // Test the set iterator
    spaceCheck = checkPointSpace();
    iter1 = 0;
    set = OSSet::withCapacity(numSymbols);
    TEST_ASSERT('I', "2a", set);
    if (set) {
        count1 = count2 = 0;
        for (i = 0; i < numSymbols; i++)
            count1 += set->setObject(cache[i]);
        TEST_ASSERT('I', "2b", count1 == numSymbols);

        iter1 = OSCollectionIterator::withCollection(set);
        iter2 = OSCollectionIterator::withCollection(set);
    }
    TEST_ASSERT('I', "2c", iter1);
    TEST_ASSERT('I', "2d", iter2);
    if (iter1 && iter2) {
        count1 = count2 = count3 = 0;
        for (i = 0; (str = (IOString *) iter1->getNextObject()); i++) {
            bigReturn = iter2->nextEntries();
            count1 += (bigReturn->getCount() == 1);
            count2 += (cache[i] == bigReturn->getObject(0));
            count3 += (cache[i] == str);
        }
        TEST_ASSERT('I', "2e", count1 == numSymbols);
        TEST_ASSERT('I', "2f", count2 == numSymbols);
        TEST_ASSERT('I', "2g", count3 == numSymbols);
        TEST_ASSERT('I', "2h", iter1->valid());
        TEST_ASSERT('I', "2i", iter2->valid());

        iter1->reset();
        count1 = count2 = count3 = 0;
        for (i = 0; ; i++) {
            if (i & 1)
                str = (OSString *) iter1->getNextObject();
            else if ( (bigReturn = iter1->nextEntries()) )
                str = (OSString *) bigReturn->getObject(0);
            else
                str = 0;

            if (!str)
                break;
            count1 += (cache[i] == str);
        }
        TEST_ASSERT('I', "2l", count1 == numSymbols);
        TEST_ASSERT('I', "2m", i == numSymbols);
        TEST_ASSERT('I', "2n", iter1->valid());

        iter1->reset();
        str = (OSString *) set->getAnyObject();
        (void) set->__takeObject(str);
        set->setObject(str);
        str->release();
        TEST_ASSERT('I', "2j", !iter1->getNextObject());
        TEST_ASSERT('I', "2k", !iter1->valid());

        TEST_ASSERT('I', "2o", 3 == set->getRetainCount());
        set->release();
    }

    if (iter1) iter1->release();
    if (iter2) iter2->release();
    res = res && checkSpace("(I)2", spaceCheck, 0);

    // Test the dictionary iterator
    spaceCheck = checkPointSpace();
    iter1 = 0;
    dict = OSDictionary::withCapacity(numSymbols);
    TEST_ASSERT('I', "3a", dict);
    if (dict) {
        count1 = count2 = 0;
        for (i = 0; i < numSymbols; i++)
            count1 += (0 != dict->setObject(cache[i], symCache[i]));
        TEST_ASSERT('I', "3b", count1 == numSymbols);

        iter1 = OSCollectionIterator::withCollection(dict);
        iter2 = OSCollectionIterator::withCollection(dict);
    }
    TEST_ASSERT('I', "3c", iter1);
    TEST_ASSERT('I', "3d", iter2);
    if (iter1 && iter2) {
        count1 = count2 = count3 = 0;
        for (i = 0; (sym = (const IOSymbol *) iter1->getNextObject()); i++) {
            bigReturn = iter2->nextEntries();
            count1 += (bigReturn->getCount() == 2);
            count2 += (cache[i] == bigReturn->getObject(1));
            count3 += (symCache[i] == sym);
        }
        TEST_ASSERT('I', "3e", count1 == numSymbols);
        TEST_ASSERT('I', "3f", count2 == numSymbols);
        TEST_ASSERT('I', "3g", count3 == numSymbols);
        TEST_ASSERT('I', "3h", iter1->valid());
        TEST_ASSERT('I', "3i", iter2->valid());

        iter1->reset();
        count1 = count2 = count3 = 0;
        i = 0;
        for (i = 0; ; i++) {
            if (i & 1) {
                sym = (const OSSymbol *) iter1->getNextObject();
                str = 0;
            }
            else if ( (bigReturn = iter1->nextEntries()) ) {
                sym = (const OSSymbol *) bigReturn->getObject(0);
                str = (OSString *) bigReturn->getObject(1);
            }
            else
                sym = 0;

            if (!sym)
                break;

            count1 += (symCache[i] == sym);
            count2 += (!str || cache[i] == str);
        }
        TEST_ASSERT('I', "3l", count1 == numSymbols);
        TEST_ASSERT('I', "3m", count2 == numSymbols);
        TEST_ASSERT('I', "3n", i == numSymbols);
        TEST_ASSERT('I', "3o", iter1->valid());

        iter1->reset();
        str = (OSString *) dict->__takeObject(symCache[numSymbols-1]);
        dict->setObject(str, symCache[numSymbols-1]);
        str->release();
        TEST_ASSERT('I', "3j", !iter1->getNextObject());
        TEST_ASSERT('I', "3k", !iter1->valid());

        TEST_ASSERT('I', "3p", 3 == dict->getRetainCount());
        dict->release();
    }

    if (iter1) iter1->release();
    if (iter2) iter2->release();
    res = res && checkSpace("(I)3", spaceCheck, 0);

    count1 = count2 = count3 = 0;
    for (i = 0; i < numSymbols; i++) {
        count1 += (1 == cache[i]->getRetainCount());
        count2 += (1 == symCache[i]->getRetainCount());
        cache[i]->release();
        symCache[i]->release();
    }
    TEST_ASSERT('I', "4a", count1 == numSymbols);
    TEST_ASSERT('I', "4b", count2 == numSymbols);

    if (res)
        verPrintf(("testIterator: All OSCollectionIterator Tests passed\n"));
    else
        logPrintf(("testIterator: Some OSCollectionIterator Tests failed\n"));
}
OSSet * IOGUIDPartitionScheme::scan(SInt32 * score)
{
    //
    // Scan the provider media for a GUID partition map.    Returns the set
    // of media objects representing each of the partitions (the retain for
    // the set is passed to the caller), or null should no partition map be
    // found.  The default probe score can be adjusted up or down, based on
    // the confidence of the scan.
    //

    IOBufferMemoryDescriptor * buffer         = 0;
    IOByteCount                bufferSize     = 0;
    UInt32                     fdiskID        = 0;
    disk_blk0 *                fdiskMap       = 0;
    UInt64                     gptBlock       = 0;
    UInt32                     gptCheck       = 0;
    UInt32                     gptCount       = 0;
    UInt32                     gptID          = 0;
    gpt_ent *                  gptMap         = 0;
    UInt32                     gptSize        = 0;
    UInt32                     headerCheck    = 0;
    gpt_hdr *                  headerMap      = 0;
    UInt32                     headerSize     = 0;
    IOMedia *                  media          = getProvider();
    UInt64                     mediaBlockSize = media->getPreferredBlockSize();
    bool                       mediaIsOpen    = false;
    OSSet *                    partitions     = 0;
    IOReturn                   status         = kIOReturnError;

    // Determine whether this media is formatted.

    if ( media->isFormatted() == false )  goto scanErr;

    // Determine whether this media has an appropriate block size.

    if ( (mediaBlockSize % sizeof(disk_blk0)) )  goto scanErr;

    // Allocate a buffer large enough to hold one map, rounded to a media block.

    bufferSize = IORound(sizeof(disk_blk0), mediaBlockSize);
    buffer     = IOBufferMemoryDescriptor::withCapacity(
                                           /* capacity      */ bufferSize,
                                           /* withDirection */ kIODirectionIn );
    if ( buffer == 0 )  goto scanErr;

    // Allocate a set to hold the set of media objects representing partitions.

    partitions = OSSet::withCapacity(8);
    if ( partitions == 0 )  goto scanErr;

    // Open the media with read access.

    mediaIsOpen = open(this, 0, kIOStorageAccessReader);
    if ( mediaIsOpen == false )  goto scanErr;

    // Read the protective map into our buffer.

    status = media->read(this, 0, buffer);
    if ( status != kIOReturnSuccess )  goto scanErr;

    fdiskMap = (disk_blk0 *) buffer->getBytesNoCopy();

    // Determine whether the protective map signature is present.

    if ( OSSwapLittleToHostInt16(fdiskMap->signature) != DISK_SIGNATURE )
    {
         goto scanErr;
    }

    // Scan for valid partition entries in the protective map.

    for ( unsigned index = 0; index < DISK_NPART; index++ )
    {
        if ( fdiskMap->parts[index].systid )
        {
            if ( fdiskMap->parts[index].systid == 0xEE )
            {
                if ( fdiskID )  goto scanErr;

                fdiskID = index + 1;
            }
        }
    }

    if ( fdiskID == 0 )  goto scanErr;

    // Read the partition header into our buffer.

    status = media->read(this, mediaBlockSize, buffer);
    if ( status != kIOReturnSuccess )  goto scanErr;

    headerMap = (gpt_hdr *) buffer->getBytesNoCopy();

    // Determine whether the partition header signature is present.

    if ( memcmp(headerMap->hdr_sig, GPT_HDR_SIG, strlen(GPT_HDR_SIG)) )
    {
        goto scanErr;
    }

    // Determine whether the partition header size is valid.

    headerCheck = OSSwapLittleToHostInt32(headerMap->hdr_crc_self);
    headerSize  = OSSwapLittleToHostInt32(headerMap->hdr_size);

    if ( headerSize < offsetof(gpt_hdr, padding) )
    {
        goto scanErr;
    }

    if ( headerSize > mediaBlockSize )
    {
        goto scanErr;
    }

    // Determine whether the partition header checksum is valid.

    headerMap->hdr_crc_self = 0;

    if ( crc32(0, headerMap, headerSize) != headerCheck )
    {
        goto scanErr;
    }

    // Determine whether the partition entry size is valid.

    gptCheck = OSSwapLittleToHostInt32(headerMap->hdr_crc_table);
    gptSize  = OSSwapLittleToHostInt32(headerMap->hdr_entsz);

    if ( gptSize < sizeof(gpt_ent) )
    {
        goto scanErr;
    }

    if ( gptSize > UINT16_MAX )
    {
        goto scanErr;
    }

    // Determine whether the partition entry count is valid.

    gptBlock = OSSwapLittleToHostInt64(headerMap->hdr_lba_table);
    gptCount = OSSwapLittleToHostInt32(headerMap->hdr_entries);

    if ( gptCount > UINT16_MAX )
    {
        goto scanErr;
    }

    // Allocate a buffer large enough to hold one map, rounded to a media block.

    buffer->release();

    bufferSize = IORound(gptCount * gptSize, mediaBlockSize);
    buffer     = IOBufferMemoryDescriptor::withCapacity(
                                           /* capacity      */ bufferSize,
                                           /* withDirection */ kIODirectionIn );
    if ( buffer == 0 )  goto scanErr;

    // Read the partition header into our buffer.

    status = media->read(this, gptBlock * mediaBlockSize, buffer);
    if ( status != kIOReturnSuccess )  goto scanErr;

    gptMap = (gpt_ent *) buffer->getBytesNoCopy();

    // Determine whether the partition entry checksum is valid.

    if ( crc32(0, gptMap, gptCount * gptSize) != gptCheck )
    {
        goto scanErr;
    }

    // Scan for valid partition entries in the partition map.

    for ( gptID = 1; gptID <= gptCount; gptID++ )
    {
        gptMap = (gpt_ent *) ( ((UInt8 *) buffer->getBytesNoCopy()) +
                               (gptID * gptSize) - gptSize );

        uuid_unswap( gptMap->ent_type );
        uuid_unswap( gptMap->ent_uuid );
 
        if ( isPartitionUsed( gptMap ) )
        {
            // Determine whether the partition is corrupt (fatal).

            if ( isPartitionCorrupt( gptMap, gptID ) )
            {
                goto scanErr;
            }

            // Determine whether the partition is invalid (skipped).

            if ( isPartitionInvalid( gptMap, gptID ) )
            {
                continue;
            }

            // Create a media object to represent this partition.

            IOMedia * newMedia = instantiateMediaObject( gptMap, gptID );

            if ( newMedia )
            {
                partitions->setObject(newMedia);
                newMedia->release();
            }
        }
    }

    // Release our resources.

    close(this);
    buffer->release();

    return partitions;

scanErr:

    // Release our resources.

    if ( mediaIsOpen )  close(this);
    if ( partitions )  partitions->release();
    if ( buffer )  buffer->release();

    return 0;
}
OSSet * IOFDiskPartitionScheme::scan(SInt32 * score)
{
    //
    // Scan the provider media for an FDisk partition map.  Returns the set
    // of media objects representing each of the partitions (the retain for
    // the set is passed to the caller), or null should no partition map be
    // found.  The default probe score can be adjusted up or down, based on
    // the confidence of the scan.
    //

    IOBufferMemoryDescriptor * buffer         = 0;
    UInt32                     bufferSize     = 0;
    UInt32                     fdiskBlock     = 0;
    UInt32                     fdiskBlockExtn = 0;
    UInt32                     fdiskBlockNext = 0;
    UInt32                     fdiskID        = 0;
    disk_blk0 *                fdiskMap       = 0;
    IOMedia *                  media          = getProvider();
    UInt64                     mediaBlockSize = media->getPreferredBlockSize();
    bool                       mediaIsOpen    = false;
    OSSet *                    partitions     = 0;
    IOReturn                   status         = kIOReturnError;

    // Determine whether this media is formatted.

    if ( media->isFormatted() == false )  goto scanErr;

    // Determine whether this media has an appropriate block size.

    if ( (mediaBlockSize % sizeof(disk_blk0)) )  goto scanErr;

    // Allocate a buffer large enough to hold one map, rounded to a media block.

    bufferSize = IORound(sizeof(disk_blk0), mediaBlockSize);
    buffer     = IOBufferMemoryDescriptor::withCapacity(
                                           /* capacity      */ bufferSize,
                                           /* withDirection */ kIODirectionIn );
    if ( buffer == 0 )  goto scanErr;

    // Allocate a set to hold the set of media objects representing partitions.

    partitions = OSSet::withCapacity(4);
    if ( partitions == 0 )  goto scanErr;

    // Open the media with read access.

    mediaIsOpen = open(this, 0, kIOStorageAccessReader);
    if ( mediaIsOpen == false )  goto scanErr;

    // Scan the media for FDisk partition map(s).

    do
    {
        // Read the next FDisk map into our buffer.

        status = media->read(this, fdiskBlock * mediaBlockSize, buffer);
        if ( status != kIOReturnSuccess )  goto scanErr;

        fdiskMap = (disk_blk0 *) buffer->getBytesNoCopy();

        // Determine whether the partition map signature is present.

        if ( OSSwapLittleToHostInt16(fdiskMap->signature) != DISK_SIGNATURE )
        {
            goto scanErr;
        }

        // Scan for valid partition entries in the partition map.

        fdiskBlockNext = 0;

        for ( unsigned index = 0; index < DISK_NPART; index++ )
        {
            // Determine whether this is an extended (vs. data) partition.

            if ( isPartitionExtended(fdiskMap->parts + index) )    // (extended)
            {
                // If peer extended partitions exist, we accept only the first.

                if ( fdiskBlockNext == 0 )      // (no peer extended partition)
                {
                    fdiskBlockNext = fdiskBlockExtn +
                                     OSSwapLittleToHostInt32(
                                    /* data */ fdiskMap->parts[index].relsect );

                    if ( fdiskBlockNext * mediaBlockSize >= media->getSize() )
                    {
                        fdiskBlockNext = 0;       // (exceeds confines of media)
                    }
                }
            }
            else if ( isPartitionUsed(fdiskMap->parts + index) )       // (data)
            {
                // Prepare this partition's ID.

                fdiskID = ( fdiskBlock == 0 ) ? (index + 1) : (fdiskID + 1);

                // Determine whether the partition is corrupt (fatal).

                if ( isPartitionCorrupt(
                                   /* partition   */ fdiskMap->parts + index,
                                   /* partitionID */ fdiskID,
                                   /* fdiskBlock  */ fdiskBlock ) )
                {
                    goto scanErr;
                }

                // Determine whether the partition is invalid (skipped).

                if ( isPartitionInvalid(
                                   /* partition   */ fdiskMap->parts + index,
                                   /* partitionID */ fdiskID,
                                   /* fdiskBlock  */ fdiskBlock ) )
                {
                    continue;
                }

                // Create a media object to represent this partition.

                IOMedia * newMedia = instantiateMediaObject(
                                   /* partition   */ fdiskMap->parts + index,
                                   /* partitionID */ fdiskID,
                                   /* fdiskBlock  */ fdiskBlock );

                if ( newMedia )
                {
                    partitions->setObject(newMedia);
                    newMedia->release();
                }
            }
        }

        // Prepare for first extended partition, if any.

        if ( fdiskBlock == 0 )
        {
            fdiskID        = DISK_NPART;
            fdiskBlockExtn = fdiskBlockNext;
        }

    } while ( (fdiskBlock = fdiskBlockNext) );

    // Release our resources.

    close(this);
    buffer->release();

    return partitions;

scanErr:

    // Release our resources.

    if ( mediaIsOpen )  close(this);
    if ( partitions )  partitions->release();
    if ( buffer )  buffer->release();

    return 0;
}
OSSet * AppleIntelPIIXATARoot::createATAChannelNubs( void )
{
    OSSet *           nubSet;
    OSDictionary *    channelInfo;
    IORegistryEntry * dtEntry;
    UInt32            priChannelMode;
    UInt32            secChannelMode;
    UInt8             mapValue = 0;

    do {
        nubSet = OSSet::withCapacity(2);
        if ( nubSet == 0 )
            break;

        if ( _provider->open( this ) != true )
            break;

        priChannelMode = kChannelModePATA;
        secChannelMode = kChannelModePATA;

        // Determine SATA channel mode based on Port Mapping Register.

        if ( getProperty( kSerialATAKey ) == kOSBooleanTrue )
        {
            OSString * hwName;

            hwName = OSDynamicCast(OSString, getProperty(kControllerNameKey));
            mapValue = _provider->configRead8(kPIIX_PCI_MAP);
            setProperty( kPortMappingKey, mapValue, 8 );

            priChannelMode = kChannelModeDisabled;
            secChannelMode = kChannelModeDisabled;

            if (hwName)
            {
                if (hwName->isEqualTo("ICH7-M SATA"))
                {
                    mapValue &= 0x3;
                    priChannelMode = gICH7MChannelModeMap[mapValue][0];
                    secChannelMode = gICH7MChannelModeMap[mapValue][1];
                }
                else if (hwName->isEqualTo("ICH6 SATA") || hwName->isEqualTo("ESB2 SATA"))
                {
                    mapValue &= 0x3;
                    priChannelMode = gICH6ChannelModeMap[mapValue][0];
                    secChannelMode = gICH6ChannelModeMap[mapValue][1];
                }
                else if (hwName->isEqualTo("ICH6-M SATA"))
                {
                    mapValue &= 0x3;
                    priChannelMode = gICH6MChannelModeMap[mapValue][0];
                    secChannelMode = gICH6MChannelModeMap[mapValue][1];
                }
                else if (hwName->isEqualTo("ICH5 SATA"))
                {
                    mapValue &= 0x7;
                    priChannelMode = gICH5ChannelModeMap[mapValue][0];
                    secChannelMode = gICH5ChannelModeMap[mapValue][1];
                }
                else /* if (hwName->isEqualTo("ICH7 SATA")) */
                {
                    mapValue &= 0x3;
                    priChannelMode = gICH7ChannelModeMap[mapValue][0];
                    secChannelMode = gICH7ChannelModeMap[mapValue][1];
                }
            }
        }

        if ( priChannelMode == kChannelModeDisabled &&
             secChannelMode == kChannelModeDisabled )
        {
            IOLog("%s: bad value (%x) in Port Mapping register",
                  getName(), mapValue);
            _provider->close( this );
            break;
        }

        for ( UInt32 channelID = 0; channelID < 2; channelID++ )
        {
            UInt32 channelMode = (channelID ? secChannelMode : priChannelMode);

            // Create a dictionary for the channel info. Use native mode
            // settings if possible, else default to legacy mode.

            channelInfo = createNativeModeChannelInfo( channelID, channelMode );
            if (channelInfo == 0)
                channelInfo = createLegacyModeChannelInfo( channelID, channelMode );
            if (channelInfo == 0)
                continue;

            // Create a nub for each ATA channel.

            AppleIntelPIIXATAChannel * nub = new AppleIntelPIIXATAChannel;
            if ( nub )
            {
                dtEntry = getDTChannelEntry( channelID );

                if ( nub->init( this, channelInfo, dtEntry ) &&
                     nub->attach( this ) )
                {
                    nubSet->setObject( nub );
                }

                if ( dtEntry )
                {
                    dtEntry->release();
                }
                else
                {
                    // Platform did not create a device tree entry for
                    // this ATA channel. Do it here.

                    char channelName[5] = {'C','H','N','_','\0'};

                    channelName[3] = '0' + channelID;
                    nub->setName( channelName );

                    if ( _provider->inPlane(gIODTPlane) )
                    {
                        nub->attachToParent( _provider, gIODTPlane );
                    }
                }

                nub->release();
            }

            channelInfo->release();
        }
        
        _provider->close( this );
    }
    while ( false );

    // Release and invalidate an empty set.

    if ( nubSet && (nubSet->getCount() == 0) )
    {
        nubSet->release();
        nubSet = 0;
    }

    return nubSet;
}
OSSet * AppleNForceATARoot::createATAChannels( void )
{
    OSSet *           nubSet;
    OSDictionary *    channelInfo;
    IORegistryEntry * dtEntry;
	char* debugInfo;

    do {
        nubSet = OSSet::withCapacity(2);
        if (nubSet == 0)
            break;

        if (fProvider->open(this) != true)
            break;

        for ( UInt32 channelID = 0; channelID < 2; channelID++ )
        {        
            // Create a dictionary for the channel info. Use native mode
            // settings if possible, else default to legacy mode.

			debugInfo = "native";
            channelInfo = createNativeModeChannelInfo( channelID );
            if (channelInfo == 0) 
			{
				debugInfo = "legacy";
                channelInfo = createLegacyModeChannelInfo( channelID );
			}
            if (channelInfo == 0)
                continue;
				
			DEBUG_LOG( "%s::%s() [this=%p] created channel %d in %s mode.\n", 
				getName(), __FUNCTION__, this, (int)channelID, debugInfo );

            // Create a nub for each ATA channel.

            AppleNForceATAChannel * nub = new AppleNForceATAChannel;
            if ( nub )
            {
                dtEntry = getDTChannelEntry( channelID );

                // Invoke special init method in channel nub.

                if (nub->init( this, channelInfo, dtEntry ) &&
                    nub->attach( this ))
                {
                    nubSet->setObject( nub );
                }

                if ( dtEntry )
                {
                    dtEntry->release();
                }
                else
                {
                    // Platform did not create a device tree entry for
                    // this ATA channel. Do it here.

                    char channelName[5] = {'C','H','N','_','\0'};

                    channelName[3] = '0' + channelID;
                    nub->setName( channelName );

                    if (fProvider->inPlane(gIODTPlane))
                    {
                        nub->attachToParent( fProvider, gIODTPlane );
                    }
                }

                nub->release();
            }

            channelInfo->release();
        }
        
        fProvider->close( this );
    }
    while ( false );

    // Release and invalidate an empty set.

    if (nubSet && (nubSet->getCount() == 0))
    {
        nubSet->release();
        nubSet = 0;
    }

    return nubSet;
}
OSSet * IOPartitionScheme::juxtaposeMediaObjects(OSSet * partitionsOld,
                                                 OSSet * partitionsNew)
{
    //
    // Updates a set of existing partitions, represented by partitionsOld,
    // with possible updates from a rescan of the disk, represented by
    // partitionsNew.  It returns a new set of partitions with the results,
    // removing partitions from partitionsOld where applicable, adding
    // partitions from partitionsNew where applicable, and folding in property
    // changes to partitions from partitionsNew into partitionsOld where
    // applicable.
    //

    OSIterator *   iterator    = 0;
    OSIterator *   iterator1   = 0;
    OSIterator *   iterator2   = 0;
    OSSymbol *     key;
    OSSet *        keys        = 0;
    IOMedia *      partition;
    IOMedia *      partition1;
    IOMedia *      partition2;
    OSSet *        partitions  = 0;
    OSOrderedSet * partitions1 = 0;
    OSOrderedSet * partitions2 = 0;
    UInt32         partitionID = 0;
    OSDictionary * properties;

    // Allocate a set to hold the set of media objects representing partitions.

    partitions = OSSet::withCapacity( partitionsNew->getCapacity( ) );
    if ( partitions == 0 ) goto juxtaposeErr;

    // Prepare the reference set of partitions.

    partitions1 = OSOrderedSet::withCapacity( partitionsOld->getCapacity( ), partitionComparison, 0 );
    if ( partitions1 == 0 ) goto juxtaposeErr;

    iterator1 = OSCollectionIterator::withCollection( partitionsOld );
    if ( iterator1 == 0 ) goto juxtaposeErr;

    while ( ( partition1 = ( IOMedia * ) iterator1->getNextObject( ) ) )
    {
        partitionID = max( partitionID, strtoul( partition1->getLocation( ), NULL, 10 ) );

        partitions1->setObject( partition1 );
    }

    iterator1->release( );
    iterator1 = 0;

    // Prepare the comparison set of partitions.

    partitions2 = OSOrderedSet::withCapacity( partitionsNew->getCapacity( ), partitionComparison, 0 );
    if ( partitions2 == 0 ) goto juxtaposeErr;

    iterator2 = OSCollectionIterator::withCollection( partitionsNew );
    if ( iterator2 == 0 ) goto juxtaposeErr;

    while ( ( partition2 = ( IOMedia * ) iterator2->getNextObject( ) ) )
    {
        partitionID = max( partitionID, strtoul( partition2->getLocation( ), NULL, 10 ) );

        partitions2->setObject( partition2 );
    }

    iterator2->release( );
    iterator2 = 0;

    // Juxtapose the partitions.

    iterator1 = OSCollectionIterator::withCollection( partitions1 );
    if ( iterator1 == 0 ) goto juxtaposeErr;

    iterator2 = OSCollectionIterator::withCollection( partitions2 );
    if ( iterator2 == 0 ) goto juxtaposeErr;

    partition1 = ( IOMedia * ) iterator1->getNextObject( );
    partition2 = ( IOMedia * ) iterator2->getNextObject( );

    while ( partition1 || partition2 )
    {
        UInt64 base1;
        UInt64 base2;

        base1 = partition1 ? partition1->getBase( ) : UINT64_MAX;
        base2 = partition2 ? partition2->getBase( ) : UINT64_MAX;

#if TARGET_OS_EMBEDDED
        if ( partition1 && partition2 )
        {
            OSString * uuid1;
            OSString * uuid2;

            uuid1 = OSDynamicCast( OSString, partition1->getProperty( kIOMediaUUIDKey ) );
            uuid2 = OSDynamicCast( OSString, partition2->getProperty( kIOMediaUUIDKey ) );

            if ( uuid1 || uuid2 )
            {
                if ( uuid1 == 0 )
                {
                   base1 = UINT64_MAX;
                }
                else if ( uuid2 == 0 )
                {
                   base2 = UINT64_MAX;
                }
                else
                {
                    int compare;

                    compare = strcmp( uuid1->getCStringNoCopy( ), uuid2->getCStringNoCopy( ) );

                    if ( compare > 0 )
                    {
                        base1 = UINT64_MAX;
                    }
                    else if ( compare < 0 )
                    {
                        base2 = UINT64_MAX;
                    }
                    else
                    {
                        base1 = base2;
                    }
                }
            }
        }
#endif /* TARGET_OS_EMBEDDED */

        if ( base1 > base2 )
        {
            // A partition was added.

            partition2->setProperty( kIOMediaLiveKey, true );

            iterator = OSCollectionIterator::withCollection( partitions1 );
            if ( iterator == 0 ) goto juxtaposeErr;

            while ( ( partition = ( IOMedia * ) iterator->getNextObject( ) ) )
            {
                if ( strcmp( partition->getLocation( ), partition2->getLocation( ) ) == 0 )
                {
                    // Set a location value for this partition.

                    char location[ 12 ];

                    partitionID++;

                    snprintf( location, sizeof( location ), "%d", ( int ) partitionID );

                    partition2->setLocation( location );

                    partition2->setProperty( kIOMediaLiveKey, false );

                    break;
                }
            }

            iterator->release( );
            iterator = 0;

            if ( partition2->attach( this ) )
            {
                attachMediaObjectToDeviceTree( partition2 );

                partition2->registerService( kIOServiceAsynchronous );
            }

            partitions->setObject( partition2 );

            partition2 = ( IOMedia * ) iterator2->getNextObject( );
        }
        else if ( base1 < base2 )
        {
            // A partition was removed.

            partition1->setProperty( kIOMediaLiveKey, false );

            if ( handleIsOpen( partition1 ) == false )
            {
                partition1->terminate( kIOServiceSynchronous );

                detachMediaObjectFromDeviceTree( partition1 );
            }
            else
            {
                partition1->removeProperty( kIOMediaPartitionIDKey );

                partitions->setObject( partition1 );
            }

            partition1 = ( IOMedia * ) iterator1->getNextObject( );
        }
        else
        {
            // A partition was matched.

            bool edit;
            bool move;

            edit = false;
            move = false;

            keys = OSSet::withCapacity( 1 );
            if ( keys == 0 ) goto juxtaposeErr;

            properties = partition2->getPropertyTable( );

            // Determine which properties were updated.

            if ( partition1->getBase( )               != partition2->getBase( )               ||
                 partition1->getSize( )               != partition2->getSize( )               ||
                 partition1->getPreferredBlockSize( ) != partition2->getPreferredBlockSize( ) ||
                 partition1->getAttributes( )         != partition2->getAttributes( )         ||
                 partition1->isWhole( )               != partition2->isWhole( )               ||
                 partition1->isWritable( )            != partition2->isWritable( )            ||
                 strcmp( partition1->getContentHint( ), partition2->getContentHint( ) )       )
            {
                edit = true;
            }

            if ( strcmp( partition1->getName( ),     partition2->getName( )     ) ||
                 strcmp( partition1->getLocation( ), partition2->getLocation( ) ) )
            {
                move = true;
            }

            iterator = OSCollectionIterator::withCollection( properties );
            if ( iterator == 0 ) goto juxtaposeErr;

            while ( ( key = ( OSSymbol * ) iterator->getNextObject( ) ) )
            {
                OSObject * value1;
                OSObject * value2;

                if ( key->isEqualTo( kIOMediaContentHintKey        ) ||
                     key->isEqualTo( kIOMediaEjectableKey          ) ||
                     key->isEqualTo( kIOMediaPreferredBlockSizeKey ) ||
                     key->isEqualTo( kIOMediaRemovableKey          ) ||
                     key->isEqualTo( kIOMediaSizeKey               ) ||
                     key->isEqualTo( kIOMediaWholeKey              ) ||
                     key->isEqualTo( kIOMediaWritableKey           ) )
                {
                    continue;
                }

                if ( key->isEqualTo( kIOMediaContentKey ) ||
                     key->isEqualTo( kIOMediaLeafKey    ) ||
                     key->isEqualTo( kIOMediaLiveKey    ) ||
                     key->isEqualTo( kIOMediaOpenKey    ) )
                {
                    continue;
                }

                value1 = partition1->getProperty( key );
                value2 = partition2->getProperty( key );

                if ( value1 == 0 || value1->isEqualTo( value2 ) == false )
                {
                    keys->setObject( key );
                }
            }

            iterator->release( );
            iterator = 0;

            // A partition was updated.

            partition1->setProperty( kIOMediaLiveKey, ( move == false ) );

            if ( edit )
            {
                partition1->init( partition2->getBase( ),
                                  partition2->getSize( ),
                                  partition2->getPreferredBlockSize( ),
                                  partition2->getAttributes( ),
                                  partition2->isWhole( ),
                                  partition2->isWritable( ),
                                  partition2->getContentHint( ) );
            }

            if ( keys->getCount( ) )
            {
                iterator = OSCollectionIterator::withCollection( keys );
                if ( iterator == 0 ) goto juxtaposeErr;

                while ( ( key = ( OSSymbol * ) iterator->getNextObject( ) ) )
                {
                    partition1->setProperty( key, partition2->getProperty( key ) );
                }

                iterator->release( );
                iterator = 0;
            }

            if ( edit || keys->getCount( ) )
            {
                partition1->messageClients( kIOMessageServicePropertyChange );

                partition1->registerService( kIOServiceAsynchronous );
            }

            keys->release( );
            keys = 0;

            partitions->setObject( partition1 );

            partition1 = ( IOMedia * ) iterator1->getNextObject( );
            partition2 = ( IOMedia * ) iterator2->getNextObject( );
        }
    }

    // Release our resources.

    iterator1->release( );
    iterator2->release( );
    partitions1->release( );
    partitions2->release( );

    return partitions;

juxtaposeErr:

    // Release our resources.

    if ( iterator    ) iterator->release( );
    if ( iterator1   ) iterator1->release( );
    if ( iterator2   ) iterator2->release( );
    if ( keys        ) keys->release( );
    if ( partitions  ) partitions->release( );
    if ( partitions1 ) partitions1->release( );
    if ( partitions2 ) partitions2->release( );

    return 0;
}
Beispiel #16
0
OSReturn OSMetaClass::postModLoad(void *loadHandle)
{
    OSReturn result = kOSReturnSuccess;
    OSSet *kmodSet = 0;

    if (!sStalled || loadHandle != sStalled) {
	logError(kOSMetaClassInternal);
	return kOSMetaClassInternal;
    }

    if (sStalled->result)
	result = sStalled->result;
    else switch (sBootstrapState) {
    case kNoDictionaries:
	sBootstrapState = kMakingDictionaries;
	// No break; fall through

    case kMakingDictionaries:
	sKModClassesDict = OSDictionary::withCapacity(kKModCapacityIncrement);
	sAllClassesDict = OSDictionary::withCapacity(kClassCapacityIncrement);
	if (!sAllClassesDict || !sKModClassesDict) {
	    result = kOSMetaClassNoDicts;
	    break;
	}
	// No break; fall through

    case kCompletedBootstrap:
    {
        unsigned int i;

	if (!sStalled->count)
	    break;	// Nothing to do so just get out

	// First pass checking classes aren't already loaded
	for (i = 0; i < sStalled->count; i++) {
	    OSMetaClass *me = sStalled->classes[i];

	    if (0 != sAllClassesDict->getObject((const char *) me->className)) {
                printf("Class \"%s\" is duplicate\n", (const char *) me->className);
                result = kOSMetaClassDuplicateClass;
                break;
            }
	}
        if (i != sStalled->count)
	    break;

	kmodSet = OSSet::withCapacity(sStalled->count);
	if (!kmodSet) {
	    result = kOSMetaClassNoKModSet;
	    break;
	}

	if (!sKModClassesDict->setObject(sStalled->kmodName, kmodSet)) {
	    result = kOSMetaClassNoInsKModSet;
	    break;
	}

	// Second pass symbolling strings and inserting classes in dictionary
	for (unsigned int i = 0; i < sStalled->count; i++) {
	    OSMetaClass *me = sStalled->classes[i];
	    me->className = 
                OSSymbol::withCStringNoCopy((const char *) me->className);

	    sAllClassesDict->setObject(me->className, me);
	    kmodSet->setObject(me);
	}
	sBootstrapState = kCompletedBootstrap;
	break;
    }

    default:
	result = kOSMetaClassInternal;
	break;
    }

    if (kmodSet)
	kmodSet->release();

    if (sStalled) {
	ACCUMSIZE(-(sStalled->capacity * sizeof(OSMetaClass *)
		     + sizeof(*sStalled)));
	kfree((vm_offset_t) sStalled->classes,
	      sStalled->capacity * sizeof(OSMetaClass *));
	kfree((vm_offset_t) sStalled, sizeof(*sStalled));
	sStalled = 0;
    }

    logError(result);
    mutex_unlock(loadLock);
    return result;
}