Ejemplo n.º 1
0
void iokit_post_constructor_init(void)
{
    IORegistryEntry *		root;
    OSObject *			obj;

    root = IORegistryEntry::initialize();
    assert( root );
    IOService::initialize();
    IOCatalogue::initialize();
    IOStatistics::initialize();
    OSKext::initialize();
    IOUserClient::initialize();
    IOMemoryDescriptor::initialize();
    IORootParent::initialize();

    // Initializes IOPMinformeeList class-wide shared lock
    IOPMinformeeList::getSharedRecursiveLock();

    obj = OSString::withCString( version );
    assert( obj );
    if( obj ) {
        root->setProperty( kIOKitBuildVersionKey, obj );
	obj->release();
    }
    obj = IOKitDiagnostics::diagnostics();
    if( obj ) {
        root->setProperty( kIOKitDiagnosticsKey, obj );
	obj->release();
    }
}
Ejemplo n.º 2
0
void
IORecordProgressBackbuffer(void * buffer, size_t size, uint32_t theme)
{
    IORegistryEntry * chosen;
    if ((chosen = IORegistryEntry::fromPath(kIODeviceTreePlane ":/chosen")))
    {
        chosen->setProperty(kIOProgressBackbufferKey, buffer, size);
	chosen->setProperty(kIOProgressColorThemeKey, theme, 32);

        chosen->release();
    }
}
OSReturn NoSleepExtension::writeNVRAM(UInt8 value)
{
#ifdef DEBUG
    IOLog("%s: writing nvram, value: 0x%02x\n", getName(), value);
#endif
    
    bool ret;
    IORegistryEntry *entry = IORegistryEntry::fromPath( "/options", gIODTPlane );
    if ( entry )
    {
        OSData *dataToSave = OSData::withBytes(&value, 1);
        
        ret = entry->setProperty(IORegistrySleepSuppressionMode, dataToSave);
        
        dataToSave->release();
        entry->release();
#ifdef DEBUG
        IOLog("%s: writing nvram, result: %s\n", getName(), ret?"true":"false");
#endif
    } else {
        return kOSReturnError;
    }
    
    return ret?kOSReturnSuccess:kOSReturnError;
}
Ejemplo n.º 4
0
void VBOXCALL   supdrvOSLdrNotifyOpened(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
{
#if 1
    NOREF(pDevExt); NOREF(pImage);
#else
    /*
     * Try store the image load address in NVRAM so we can retrived it on panic.
     * Note! This only works if you're root! - Acutally, it doesn't work at all at the moment. FIXME!
     */
    IORegistryEntry *pEntry = IORegistryEntry::fromPath("/options", gIODTPlane);
    if (pEntry)
    {
        char szVar[80];
        RTStrPrintf(szVar, sizeof(szVar), "vboximage"/*-%s*/, pImage->szName);
        char szValue[48];
        RTStrPrintf(szValue, sizeof(szValue), "%#llx,%#llx", (uint64_t)(uintptr_t)pImage->pvImage,
                    (uint64_t)(uintptr_t)pImage->pvImage + pImage->cbImageBits - 1);
        bool fRc = pEntry->setProperty(szVar, szValue); NOREF(fRc);
        pEntry->release();
        SUPR0Printf("fRc=%d '%s'='%s'\n", fRc, szVar, szValue);
    }
    /*else
        SUPR0Printf("failed to find /options in gIODTPlane\n");*/
#endif
}
Ejemplo n.º 5
0
void
IORegistrySetOSBuildVersion(char * build_version)
{
    IORegistryEntry * root = IORegistryEntry::getRegistryRoot();

    if (root) {
        if (build_version) {
            root->setProperty(kOSBuildVersionKey, build_version);
        } else {
            root->removeProperty(kOSBuildVersionKey);
        }
    }

    return;
}
Ejemplo n.º 6
0
IOReturn IOPlatformExpertDevice::setProperties( OSObject * properties )
{
    OSDictionary * dictionary;
    OSObject *     object;
    IOReturn       status;

    status = super::setProperties( properties );
    if ( status != kIOReturnUnsupported ) return status;

    status = IOUserClient::clientHasPrivilege( current_task( ), kIOClientPrivilegeAdministrator );
    if ( status != kIOReturnSuccess ) return status;

    dictionary = OSDynamicCast( OSDictionary, properties );
    if ( dictionary == 0 ) return kIOReturnBadArgument;

    object = dictionary->getObject( kIOPlatformUUIDKey );
    if ( object )
    {
        IORegistryEntry * entry;
        OSString *        string;
        uuid_t            uuid;

        string = ( OSString * ) getProperty( kIOPlatformUUIDKey );
        if ( string ) return kIOReturnNotPermitted;

        string = OSDynamicCast( OSString, object );
        if ( string == 0 ) return kIOReturnBadArgument;

        status = uuid_parse( string->getCStringNoCopy( ), uuid );
        if ( status != 0 ) return kIOReturnBadArgument;

        entry = IORegistryEntry::fromPath( "/options", gIODTPlane );
        if ( entry )
        {
            entry->setProperty( "platform-uuid", uuid, sizeof( uuid_t ) );
            entry->release( );
        }

        setProperty( kIOPlatformUUIDKey, string );
        publishResource( kIOPlatformUUIDKey, string );

        return kIOReturnSuccess;
    }

    return kIOReturnUnsupported;
}
Ejemplo n.º 7
0
OSReturn
KLDBootstrap::readMkextExtensions(
    OSString   * deviceTreeName,
    OSData     * booterData)
{
    OSReturn result = kOSReturnError;

    uint32_t          checksum;
    IORegistryEntry * registryRoot = NULL;  // do not release
    OSData          * checksumObj  = NULL;   // must release

    OSKextLog(/* kext */ NULL,
        kOSKextLogStepLevel |
        kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag,
        "Reading startup mkext archive from device tree entry %s.",
        deviceTreeName->getCStringNoCopy());

   /* If we successfully read the archive,
    * then save the mkext's checksum in the IORegistry.
    * assumes we'll only ever have one mkext to boot
    */
    result = OSKext::readMkextArchive(booterData, &checksum);
    if (result == kOSReturnSuccess) {

        OSKextLog(/* kext */ NULL,
            kOSKextLogProgressLevel |
            kOSKextLogArchiveFlag,
            "Startup mkext archive has checksum 0x%x.", (int)checksum);

        registryRoot = IORegistryEntry::getRegistryRoot();
        assert(registryRoot);
        checksumObj = OSData::withBytes((void *)&checksum, sizeof(checksum));
        assert(checksumObj);
        if (checksumObj) {
            registryRoot->setProperty(kOSStartupMkextCRC, checksumObj);
        }
    }
    
    return result;
}
Ejemplo n.º 8
0
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);
}
Ejemplo n.º 9
0
bool SMBIOSResolver::start(IOService * provider)
{
	if( super::start(provider) != true ) return false;	// Oh no	
	if( IOService::getResourceService()->getProperty("SMBIOS-Resolver") ) return false;	// We should exist only once	
	if( !IOService::getResourceService()->getProperty("SMBIOS") ) return false;	// AppleSMBIOS.kext didn´t start we bail out
	
	IOService * iosRoot = getServiceRoot();
	if( !iosRoot ) return false;	// Unable to get IOServiceRoot
	
	int doVerbose = 0;
	// PE_parse_boot_arg("smbios", &doVerbose);	// bootarg SMBIOS=1 will give a verbose output to log (when I find something verbose worth outputting)
	
	// Dictionary from plist
	OSDictionary * hwDict = OSDynamicCast( OSDictionary, getProperty("Override"));
	
	//	/rom/version
	IORegistryEntry * dtROMNode = fromPath("/rom", gIODTPlane);
	if( dtROMNode )
	{
		OSString * romVersion = OSDynamicCast( OSString, hwDict->getObject("rom-version"));
		if(romVersion->getLength() > 0) dtROMNode->setProperty("version", OSData::withBytes(romVersion->getCStringNoCopy(), romVersion->getLength() + 1) );
		dtROMNode->release();
	}
	else
	{
		return false;	// No /rom node in IODeviceTree plane
	}
	
	// root entries
	OSObject * dictString = 0;
	
	dictString = hwDict->getObject("manufacturer");
	if(dictString)
	{
		OSString * rootManufacturer = OSDynamicCast( OSString, dictString);
		if(rootManufacturer->getLength() > 1) iosRoot->setProperty("manufacturer", OSData::withBytes(rootManufacturer->getCStringNoCopy(), rootManufacturer->getLength() + 1) );
	}
	
	dictString = hwDict->getObject("system-type");
	if(dictString)
	{
		OSData * systemType = OSDynamicCast( OSData, dictString);
		if(systemType) iosRoot->setProperty("system-type", systemType );
	}
	
	dictString = hwDict->getObject("compatible");
	if(dictString) 
	{
		OSString * rootCompatible = OSDynamicCast( OSString, dictString);
		if(rootCompatible->getLength() > 1) iosRoot->setProperty("compatible", OSData::withBytes(rootCompatible->getCStringNoCopy(), rootCompatible->getLength() + 1) );
	}
	
	dictString = hwDict->getObject("product-name");
	if(dictString) 
	{
		OSString * rootProductName = OSDynamicCast( OSString, dictString);
		if(rootProductName->getLength() > 1) iosRoot->setProperty("product-name", OSData::withBytes(rootProductName->getCStringNoCopy(), rootProductName->getLength() + 1) );
	}
	
	dictString = hwDict->getObject("model");
	if(dictString) 
	{
		OSString * rootModel = OSDynamicCast( OSString, dictString);
		if(rootModel->getLength() > 1)
		{
			iosRoot->setProperty("model", OSData::withBytes(rootModel->getCStringNoCopy(), rootModel->getLength() + 1) );
			iosRoot->setName(rootModel->getCStringNoCopy());
		}
	}
	
	dictString = hwDict->getObject("version");
	if(dictString) 
	{
		OSString * rootVersion = OSDynamicCast( OSString, dictString);
		if(rootVersion->getLength() > 1) iosRoot->setProperty("version", OSData::withBytes(rootVersion->getCStringNoCopy(), rootVersion->getLength() + 1) );
	}
	
	dictString = hwDict->getObject("board-id");
	if(dictString) 
	{
		OSString * rootBoardId = OSDynamicCast( OSString, dictString);
		if(rootBoardId->getLength() > 1) iosRoot->setProperty("board-id", OSData::withBytes(rootBoardId->getCStringNoCopy(), rootBoardId->getLength() + 1) );
	}
	
	dictString = hwDict->getObject("serial-number");
	if(dictString) 
	{
		OSString * rootSerial = OSDynamicCast( OSString, dictString);
		if(rootSerial->getLength() > 1)
		{
			UInt8 length = rootSerial->getLength();
			const char *serialNumberString = rootSerial->getCStringNoCopy();
			
			// The serial-number property in the IORegistry is a 43-byte data object.
			// Bytes 0 through 2 are the last three bytes of the serial number string.
			// Bytes 11 through 20, inclusive, are the serial number string itself.
			// All other bytes are '\0'.
			OSData * data = OSData::withCapacity(43);
			if (data)
			{
				data->appendBytes(serialNumberString + (length - 3), 3);
				data->appendBytes(NULL, 10);
				data->appendBytes(serialNumberString, length);
				data->appendBytes(NULL, 43 - length - 10 - 3);
				iosRoot->setProperty("serial-number", data);
				data->release();
			}
			
			iosRoot->setProperty(kIOPlatformSerialNumberKey, rootSerial);
		}
	}
	
	dictString = hwDict->getObject("UUID-key");
	if(dictString) 
	{
		OSString * rootUUIDKey = OSDynamicCast( OSString, hwDict->getObject("UUID-key"));
		iosRoot->setProperty(kIOPlatformUUIDKey, rootUUIDKey);
		publishResource(kIOPlatformUUIDKey, rootUUIDKey);
	}
	
	bool useEfiBus = false;
	UInt64 fsbFrequency = 0;
	UInt64 msr;
	dictString = hwDict->getObject("use-efi-bus");
	if (dictString) useEfiBus = (OSDynamicCast(OSBoolean, dictString))->getValue(); 
	IORegistryEntry * efiPlatform = fromPath("/efi/platform", gIODTPlane);
	if (efiPlatform && useEfiBus)
	{
		OSData * efiFSBFreq = OSDynamicCast(OSData, efiPlatform->getProperty("FSBFrequency"));
		bcopy(efiFSBFreq->getBytesNoCopy(), &fsbFrequency, efiFSBFreq->getLength());
		efiPlatform->release();
	}
	else
	{	// No /efi/platform found
		fsbFrequency = gPEClockFrequencyInfo.bus_frequency_hz;	// Value previously set by AppleSMBIOS 
		if (!strncmp(cpuid_info()->cpuid_vendor, CPUID_VID_INTEL, sizeof(CPUID_VID_INTEL)) && (cpuid_info()->cpuid_features & CPUID_FEATURE_SSE2)) fsbFrequency /= 4;
	}

	dictString = hwDict->getObject("hardcode-bus");
	if(dictString) 
	{
		fsbFrequency = (OSDynamicCast(OSNumber, dictString))->unsigned64BitValue();
		if (fsbFrequency)
		{
			if (fsbFrequency <= 10000) fsbFrequency *= 1000000;
		}
		else
		{
			if (!strncmp(cpuid_info()->cpuid_vendor, CPUID_VID_INTEL, sizeof(CPUID_VID_INTEL)))
			{
				if ((cpuid_info()->cpuid_family == 0x0f) && (cpuid_info()->cpuid_model >= 2))
				{
					msr = rdmsr64(0x0000002C);
					switch ((msr >> 16) & 0x7) {
						case 0:
							if (cpuid_info()->cpuid_model == 2) fsbFrequency = 100 * 1000000;
							else 
							{
								fsbFrequency = (800 * 1000000) / 3;	// 266
								fsbFrequency++;
							}
							break;
						case 1:
							fsbFrequency = (400 * 1000000) / 3;	//	133
							break;
						case 2:
							fsbFrequency = (600 * 1000000) / 3;	// 200
							break;
						case 3:
							fsbFrequency = (500 * 1000000) / 3;	//	166
							fsbFrequency++;
							break;
						case 4:
							fsbFrequency = (1000 * 1000000) / 3;	//	333
							break;
						default:
							break;
					}
				}
				else
				{
					fsbFrequency = 100 * 1000000;
				}
				
				if (cpuid_info()->cpuid_family == 0x06)
				{
					msr = rdmsr64(0x000000CD);
					switch (msr & 0x7) {
						case 0:
							fsbFrequency = (800 * 1000000) / 3;	//	266
							fsbFrequency++;
							break;
						case 1:
							fsbFrequency = (400 * 1000000) / 3;	//	133
							break;
						case 2:
							fsbFrequency = (600 * 1000000) / 3;	//	200
							break;
						case 3:
							fsbFrequency = (500 * 1000000) / 3;	//	166
							fsbFrequency++;
							break;
						case 4:
							fsbFrequency = (1000 * 1000000) / 3;//	333
							break;
						case 5:
							fsbFrequency = (300 * 1000000) / 3;	//	100
							break;
						case 6:
							fsbFrequency = (1200 * 1000000) / 3;//	400
							break;
						case 7:		// should check
							fsbFrequency = (1400 * 1000000) / 3;//	466
							fsbFrequency++;
							break;
						default:
							break;
					}
				}
				 
			}
		}
Ejemplo n.º 10
0
void StartIOKit( void * p1, void * p2, void * p3, void * p4 )
{
    IOPlatformExpertDevice *	rootNub;
    int				debugFlags;
    IORegistryEntry *		root;
    OSObject *			obj;
    extern const char *         gIOKernelKmods;
    OSString *                  errorString = NULL; // must release
    OSDictionary *              fakeKmods;  // must release
    OSCollectionIterator *      kmodIter;   // must release
    OSString *                  kmodName;   // don't release

    IOLog( iokit_version );

    if( PE_parse_boot_arg( "io", &debugFlags ))
	gIOKitDebug = debugFlags;

    // Check for the log synchronous bit set in io
    if (gIOKitDebug & kIOLogSynchronous)
        debug_mode = true;

    //
    // Have to start IOKit environment before we attempt to start
    // the C++ runtime environment.  At some stage we have to clean up
    // the initialisation path so that OS C++ can initialise independantly
    // of iokit basic service initialisation, or better we have IOLib stuff
    // initialise as basic OS services.
    //
    IOLibInit(); 
    OSlibkernInit();

   /*****
    * Declare the fake kmod_info structs for built-in components
    * that must be tracked as independent units for dependencies.
    */
    fakeKmods = OSDynamicCast(OSDictionary,
        OSUnserialize(gIOKernelKmods, &errorString));

    if (!fakeKmods) {
        if (errorString) {
            panic("Kernel kmod list syntax error: %s\n",
                    errorString->getCStringNoCopy());
            errorString->release();
        } else {
            panic("Error loading kernel kmod list.\n");
        }
    }

    kmodIter = OSCollectionIterator::withCollection(fakeKmods);
    if (!kmodIter) {
        panic("Can't declare in-kernel kmods.\n");
    }
    while ((kmodName = OSDynamicCast(OSString, kmodIter->getNextObject()))) {

        OSString * kmodVersion = OSDynamicCast(OSString,
            fakeKmods->getObject(kmodName));
        if (!kmodVersion) {
            panic("Can't declare in-kernel kmod; \"%s\" has "
                "an invalid version.\n",
                kmodName->getCStringNoCopy());
        }
        if (KERN_SUCCESS != kmod_create_fake(kmodName->getCStringNoCopy(),
                kmodVersion->getCStringNoCopy())) {
            panic("Failure declaring in-kernel kmod \"%s\".\n",
                kmodName->getCStringNoCopy());
        }
    }

    kmodIter->release();
    fakeKmods->release();



    root = IORegistryEntry::initialize();
    assert( root );
    IOService::initialize();
    IOCatalogue::initialize();
    IOUserClient::initialize();
    IOMemoryDescriptor::initialize();

    obj = OSString::withCString( iokit_version );
    assert( obj );
    if( obj ) {
        root->setProperty( kIOKitBuildVersionKey, obj );
	obj->release();
    }
    obj = IOKitDiagnostics::diagnostics();
    if( obj ) {
        root->setProperty( kIOKitDiagnosticsKey, obj );
	obj->release();
    }

    rootNub = new IOPlatformExpertDevice;

    if( rootNub && rootNub->initWithArgs( p1, p2, p3, p4)) {
        rootNub->attach( 0 );

       /* Enter into the catalogue the drivers
        * provided by BootX.
        */
        gIOCatalogue->recordStartupExtensions();

        rootNub->registerService();
    }
}
Ejemplo n.º 11
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;
}
static void createNubs(IOService *provider) {
	const char nameID[2][8] = {"@0,name", "@1,name"};
	const char name[11] = "Aty,Radeon";
	const char typeID[2][15] = {"@0,device_type", "@1,device_type"};
	const char type[] = "display";
	OSObject *tempObj;
	
	int i;
	
	if (provider->getProperty(kIONDRVIgnoreKey)) return;
	provider->setProperty(kIONDRVIgnoreKey, kOSBooleanTrue);	//prevent IONDRVFramebuffer from match
	
	LOG("createNubs\n");
	
	if (!provider->getProperty("@0,name") && !provider->getProperty("@1,name")) {
		for (i = 0;i < 2;i++) {	// Debug
			tempObj = OSData::withBytes(name, 11);
			provider->setProperty(nameID[i], tempObj);
			tempObj->release();
			tempObj = OSData::withBytes(type, 8);
			provider->setProperty(typeID[i], tempObj);
			tempObj->release();
		}
	}
	// have to move below part from IONDRVFramebuffer to make it work
	IORegistryIterator * iter;
	IORegistryEntry *    next;
	IOService *          newNub;
	OSArray *            toDo = 0;
	bool                 firstLevel;
    OSData *            data;
	
	if (provider->getProperty("@0,name"))
	{
		OSDictionary *         dict;
		OSCollectionIterator * keys;
		const OSSymbol *       key;
		char                   buffer[80];
		const char *           keyChrs;
		size_t                 len;
		char                   c;
		
		dict = provider->dictionaryWithProperties();
		keys = OSCollectionIterator::withCollection(dict);
		if (dict)
			dict->release();
		if (keys)
		{
			while ((key = OSDynamicCast(OSSymbol, keys->getNextObject())))
			{
				keyChrs = key->getCStringNoCopy();
				if ('@' != keyChrs[0])
					continue;
				
				len = 0;
				do
				{
					c = keyChrs[len];
					if (!c || (c == ','))
						break;
					buffer[len] = c;
					len++;
				}
				while (len < (sizeof(buffer) - 1));
				if (!c)
					continue;
				
				buffer[len] = 0;
				keyChrs += len + 1;
				
				next = provider->childFromPath(buffer, gIODTPlane);
				if (!next)
				{
					next = new IOService;
					if (next && !next->init())
					{
						next->release();
						next = 0;
					}
					if (!next)
						continue;
					next->setLocation(&buffer[1]);
					if (!next->attachToParent(provider, gIODTPlane))
						continue;
				}
				
				OSObject * obj = dict->getObject(key);
				next->setProperty(keyChrs, dict->getObject(key));
				if (!strcmp(keyChrs, "name"))
				{
					OSData * data = OSDynamicCast(OSData, obj);
					if (data)
						next->setName((const char *) data->getBytesNoCopy());
				}
				next->release();
				provider->removeProperty(key);
			}
			keys->release();
		}
	}
	
	iter = IORegistryIterator::iterateOver( provider, gIODTPlane, 0 );
	toDo = OSArray::withCapacity(2);
	
	if (iter && toDo)
	{
		bool haveDoneLibInit = false;
		UInt32 index = 0;
		do
		{
			while ((next = (IORegistryEntry *) iter->getNextObject()))
			{
				firstLevel = (provider == next->getParentEntry(gIODTPlane));
				if (firstLevel)
				{
					data = OSDynamicCast( OSData, next->getProperty("device_type"));
					if (!data || (0 != strcmp("display", (char *) data->getBytesNoCopy())))
						continue;
					
					if (!haveDoneLibInit)
					{
						haveDoneLibInit = (kIOReturnSuccess == _IONDRVLibrariesInitialize(provider));
						if (!haveDoneLibInit)
							continue;
					}
					next->setProperty( kIOFBDependentIDKey, (uintptr_t) provider, 64 );
					next->setProperty( kIOFBDependentIndexKey, index, 32 );
					next->setProperty( kIONDRVIgnoreKey, kOSBooleanTrue );
					index++;
				}
				
				toDo->setObject( next );
				iter->enterEntry();
			}
		}
		while (iter->exitEntry());
	}
	if (iter)
		iter->release();
	
	if (toDo)
	{
		OSObject * obj;
		OSArray  * deviceMemory;
		obj = provider->copyProperty(gIODeviceMemoryKey);
		deviceMemory = OSDynamicCast(OSArray, obj);
		
		for (unsigned int i = 0;
			 (next = (IORegistryEntry *) toDo->getObject(i));
			 i++)
		{
			newNub = new IONDRVDevice;
			if (!newNub)
				continue;
			if (!newNub->init(next, gIODTPlane))
			{
				newNub->free();
				newNub = 0;
				continue;
			}
			if (deviceMemory)
				newNub->setDeviceMemory(deviceMemory);
			newNub->attach(provider);
			newNub->registerService(kIOServiceSynchronous);
		}
		if (obj)
			obj->release();
		toDo->release();
	}
}
Ejemplo n.º 13
0
void
KLDBootstrap::readPrelinkedExtensions(
    kernel_section_t * prelinkInfoSect)
{
    OSArray                   * infoDictArray           = NULL;  // do not release
    OSArray                   * personalitiesArray      = 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

#if CONFIG_KXLD
    kernel_section_t          * kernelLinkStateSection  = NULL;  // see code
#endif
    kernel_segment_command_t  * prelinkLinkStateSegment = NULL;  // see code
    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
    void                      * prelinkCopy             = NULL;  // see code
    vm_size_t                   prelinkLength           = 0;
#if !__LP64__ && !defined(__arm__)
    vm_map_offset_t             prelinkDataMapOffset    = 0;
#endif

    kern_return_t               mem_result              = KERN_SUCCESS;

    OSDictionary              * infoDict                = NULL;  // do not release

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

    u_int                       i = 0;

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

   /*****
    * Wrap the kernel link state in-place in an OSData.
    * This is unnecessary (and the link state may not be present) if the kernel
    * does not have kxld support because this information is only used for
    * runtime linking.
    */
#if CONFIG_KXLD
    kernelLinkStateSection = getsectbyname(kPrelinkLinkStateSegment,
        kPrelinkKernelLinkStateSection);
    if (!kernelLinkStateSection) {
        OSKextLog(/* kext */ NULL,
            kOSKextLogErrorLevel |
            kOSKextLogArchiveFlag,
            "Can't find prelinked kernel link state.");
        goto finish;
    }

    theKernel = OSKext::lookupKextWithIdentifier(kOSKextKernelIdentifier);
    if (!theKernel) {
        OSKextLog(/* kext */ NULL,
            kOSKextLogErrorLevel |
            kOSKextLogArchiveFlag,
            "Can't find kernel kext object in prelinked kernel.");
        goto finish;
    }

    prelinkData = (void *) kernelLinkStateSection->addr;
    prelinkLength = kernelLinkStateSection->size;

    mem_result = kmem_alloc_pageable(kernel_map,
        (vm_offset_t *) &prelinkCopy, prelinkLength);
    if (mem_result != KERN_SUCCESS) {
        OSKextLog(/* kext */ NULL,
            kOSKextLogErrorLevel |
            kOSKextLogGeneralFlag | kOSKextLogArchiveFlag,
            "Can't copy prelinked kernel link state.");
        goto finish;
    }
    memcpy(prelinkCopy, prelinkData, prelinkLength);

    theKernel->linkState = OSData::withBytesNoCopy(prelinkCopy, prelinkLength);
    if (!theKernel->linkState) {
        OSKextLog(/* kext */ NULL,
            kOSKextLogErrorLevel |
            kOSKextLogGeneralFlag | kOSKextLogArchiveFlag,
            "Can't create prelinked kernel link state wrapper.");
        goto finish;
    }
    theKernel->linkState->setDeallocFunction(osdata_kmem_free);
#endif

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

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

#if !__LP64__
    /* To enable paging and write/execute protections on the kext
     * executables, we need to copy them out of the booter-created
     * memory, reallocate that space with VM, then prelinkCopy them back in.
     * This isn't necessary on LP64 because kexts have their own VM
     * region on that architecture model.
     */

    mem_result = kmem_alloc(kernel_map, (vm_offset_t *)&prelinkCopy,
        prelinkLength);
    if (mem_result != KERN_SUCCESS) {
        OSKextLog(/* kext */ NULL,
            kOSKextLogErrorLevel |
            kOSKextLogGeneralFlag | kOSKextLogArchiveFlag,
            "Can't copy prelinked kexts' text for VM reassign.");
        goto finish;
    }

   /* Copy it out.
    */
    memcpy(prelinkCopy, prelinkData, prelinkLength);
    
   /* Dump the booter memory.
    */
    ml_static_mfree((vm_offset_t)prelinkData, prelinkLength);

   /* Set up the VM region.
    */
    prelinkDataMapOffset = (vm_map_offset_t)(uintptr_t)prelinkData;
    mem_result = vm_map_enter_mem_object(
        kernel_map,
        &prelinkDataMapOffset,
        prelinkLength, /* mask */ 0, 
        VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE, 
        (ipc_port_t)NULL,
        (vm_object_offset_t) 0,
        /* copy */ FALSE,
        /* cur_protection */ VM_PROT_ALL,
        /* max_protection */ VM_PROT_ALL,
        /* inheritance */ VM_INHERIT_DEFAULT);
    if ((mem_result != KERN_SUCCESS) || 
        (prelinkTextSegment->vmaddr != prelinkDataMapOffset)) 
    {
        OSKextLog(/* kext */ NULL,
            kOSKextLogErrorLevel |
            kOSKextLogGeneralFlag | kOSKextLogArchiveFlag,
            "Can't create kexts' text VM entry at 0x%llx, length 0x%x (error 0x%x).",
            (unsigned long long) prelinkDataMapOffset, prelinkLength, mem_result);
        goto finish;
    }
    prelinkData = (void *)(uintptr_t)prelinkDataMapOffset;

   /* And copy it back.
    */
    memcpy(prelinkData, prelinkCopy, prelinkLength);

    kmem_free(kernel_map, (vm_offset_t)prelinkCopy, prelinkLength);
#endif /* !__LP64__ */

   /* 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;
    }

    infoDictArray = OSDynamicCast(OSArray, 
        prelinkInfoDict->getObject(kPrelinkInfoDictionaryKey));
    if (!infoDictArray) {
        OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
            "The prelinked kernel has no kext info dictionaries");
        goto finish;
    }

   /* 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;
        }

       /* 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);
        OSSafeReleaseNULL(newKext);
    }
    
    /* Get all of the personalities for kexts that were not prelinked and
     * add them to the catalogue.
     */
    personalitiesArray = OSDynamicCast(OSArray,
        prelinkInfoDict->getObject(kPrelinkPersonalitiesKey));
    if (!personalitiesArray) {
        OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
            "The prelinked kernel has no personalities array");
        goto finish;
    }

    if (personalitiesArray->getCount()) {
        OSKext::setPrelinkedPersonalities(personalitiesArray);
    }

   /* 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);
    }

    OSSafeReleaseNULL(prelinkCountObj);
    prelinkCountObj = OSNumber::withNumber(
        (unsigned long long)personalitiesArray->getCount(),
        8 * sizeof(uint32_t));
    assert(prelinkCountObj);
    if (prelinkCountObj) {
        registryRoot->setProperty(kOSPrelinkPersonalityCountKey, prelinkCountObj);
    }

    OSKextLog(/* kext */ NULL,
        kOSKextLogProgressLevel |
        kOSKextLogGeneralFlag | kOSKextLogKextBookkeepingFlag |
        kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag,
        "%u prelinked kexts, and %u additional personalities.", 
        infoDictArray->getCount(), personalitiesArray->getCount());

#if __LP64__
        /* On LP64 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 /* __LP64__ */

   /* Free the link state segment, kexts have copied out what they need.
    */
    prelinkLinkStateSegment = getsegbyname(kPrelinkLinkStateSegment);
    if (prelinkLinkStateSegment) {
        ml_static_mfree((vm_offset_t)prelinkLinkStateSegment->vmaddr,
            (vm_size_t)prelinkLinkStateSegment->vmsize);
    }

   /* 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:
    OSSafeRelease(errorString);
    OSSafeRelease(parsedXML);
    OSSafeRelease(theKernel);
    OSSafeRelease(prelinkCountObj);
    return;
}