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(); } }
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; }
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 }
void IORegistrySetOSBuildVersion(char * build_version) { IORegistryEntry * root = IORegistryEntry::getRegistryRoot(); if (root) { if (build_version) { root->setProperty(kOSBuildVersionKey, build_version); } else { root->removeProperty(kOSBuildVersionKey); } } return; }
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; }
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; }
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); }
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; } } } }
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(); } }
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(); } }
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; }