OSString * ACPIBacklightPanel::getACPIPath(IOACPIPlatformDevice * acpiDevice) { OSString * separator = OSString::withCStringNoCopy("."); OSArray * array = OSArray::withCapacity(10); char devicePath[512]; bzero(devicePath, sizeof(devicePath)); IOACPIPlatformDevice * parent = acpiDevice; IORegistryIterator * iter = IORegistryIterator::iterateOver(acpiDevice, gIOACPIPlane, kIORegistryIterateParents | kIORegistryIterateRecursively); if (iter) { do { array->setObject(parent->copyName(gIOACPIPlane)); array->setObject(separator); parent = OSDynamicCast(IOACPIPlatformDevice, iter->getNextObject()); } while (parent); iter->release(); int offset = 0; OSString * str = OSDynamicCast(OSString, array->getLastObject()); for (int i = array->getCount()-2; ((i>=0) || ((offset + str->getLength()) > sizeof(devicePath))) ; i--) { str = OSDynamicCast(OSString, array->getObject(i)); strncpy(devicePath + offset, str->getCStringNoCopy(), str->getLength()); offset += str->getLength(); } } return OSString::withCString(devicePath); }
bool CompareDeviceUsagePairs( IOService * owner, OSDictionary * matching, SInt32 * score, SInt32 increment) { // We return success if we match the key in the dictionary with the key in // the property table, or if the prop isn't present // OSArray * pairArray; OSDictionary * pair; bool matches = true; int count; pairArray = OSDynamicCast(OSArray, matching->getObject( kIOHIDDeviceUsagePairsKey )); if (pairArray) { count = pairArray->getCount(); for (int i=0; i<count; i++) { if ( !(pair = OSDynamicCast(OSDictionary,pairArray->getObject(i))) ) continue; if ( !(matches = CompareDeviceUsage(owner, pair, score, increment)) ) continue; break; } } return matches; }
bool CompareNumberPropertyArray( IOService * owner, OSDictionary * matching, const char * arrayName, const char * key, SInt32 * score, SInt32 increment) { OSNumber *registryProperty = (OSNumber *)owner->copyProperty(key); OSArray *propertyArray = (OSArray *)matching->getObject(arrayName); CONVERT_TO_STACK_RETAIN(registryProperty); // If the property in the matching doesn't exist return true if ( OSDynamicCast(OSArray, propertyArray) ) { if ( OSDynamicCast(OSNumber, registryProperty ) ) { OSNumber *propertyFromArray; int i = 0; for ( i = 0; i < propertyArray->getCount(); i ++ ) { propertyFromArray = OSDynamicCast(OSNumber, propertyArray->getObject(i)); if ( propertyFromArray && propertyFromArray->isEqualTo(registryProperty) ) { if ( score ) *score += increment; return true; } } } } else return true; return false; }
void SuperIO::LoadConfiguration(IOService* provider) { m_Service = provider; OSBoolean* fanControl = OSDynamicCast(OSBoolean, provider->getProperty("Enable Fan Control")); m_FanControl = fanControl->getValue(); OSBoolean* alternateRegisters = OSDynamicCast(OSBoolean, provider->getProperty("Register number alternative variant")); m_AlternateRegisters = alternateRegisters->getValue(); OSArray* fanIDs = OSDynamicCast(OSArray, provider->getProperty("Fan Names")); if (fanIDs) fanIDs = OSArray::withArray(fanIDs); if (fanIDs) { UInt32 count = fanIDs->getCount(); if(count > 5) count = 5; for (UInt32 i = 0; i < count; i++) { OSString* name = OSDynamicCast(OSString, fanIDs->getObject(i)); FanName[i] = name->getCStringNoCopy(); } fanIDs->release(); } }
UInt32 ACPIBacklightPanel::setupIndexedLevels() { DbgLog("%s::%s()\n", this->getName(),__FUNCTION__); OSNumber * num; OSArray * levels = queryACPISupportedBrightnessLevels(); if (levels) { BCLlevelsCount = levels->getCount(); if (BCLlevelsCount < 3) return 0; //verify the types of objects is good once for all for (int i = 0; i< BCLlevelsCount; i++) { if (!OSDynamicCast(OSNumber, levels->getObject(i))) return 0; } //TODO : manage the case when the list has no order! Linux do that //test the order of the list UInt32 min, max; num = OSDynamicCast(OSNumber, levels->getObject(2)); min = num->unsigned32BitValue(); num = OSDynamicCast(OSNumber, levels->getObject(BCLlevelsCount-1)); max = num->unsigned32BitValue(); if (max < min) //list is reverted ! { BCLlevels = new UInt32[BCLlevelsCount]; for (int i = 0; i< BCLlevelsCount; i++) { num = OSDynamicCast(OSNumber, levels->getObject(BCLlevelsCount -1 -i)); BCLlevels[i] = num->unsigned32BitValue(); } } else { BCLlevelsCount = BCLlevelsCount -2; BCLlevels = new UInt32[BCLlevelsCount]; for (int i = 0; i< BCLlevelsCount; i++) { num = OSDynamicCast(OSNumber, levels->getObject(i+2)); BCLlevels[i] = num->unsigned32BitValue(); } } //2 first items are min on ac and max on bat num = OSDynamicCast(OSNumber, levels->getObject(0)); minAC = findIndexForLevel(num->unsigned32BitValue()); setDebugProperty("BCL: Min on AC", num); num = OSDynamicCast(OSNumber, levels->getObject(1)); maxBat = findIndexForLevel(num->unsigned32BitValue()); setDebugProperty("BCL: Max on Bat", num); setDebugProperty("Brightness Control Levels", levels); levels->release(); return BCLlevelsCount-1; } return 0; }
//==================================================================================================== // IOHIDEventOverrideDriver::dispatchKeyboardEvent //==================================================================================================== bool IOHIDEventOverrideDriver::handleStart( IOService * provider ) { OSArray * maps = NULL; if ( !super::handleStart(provider) ) return false; maps = OSDynamicCast(OSArray, getProperty("ButtonMaps")); if ( maps ) { int index; for ( index=0; index<maps->getCount(); index++ ) { OSDictionary * map; OSNumber * number; uint32_t button; uint32_t usagePage; uint32_t usage; uint32_t eventType; map = OSDynamicCast(OSDictionary, maps->getObject(index)); if ( !map ) continue; number = OSDynamicCast(OSNumber, map->getObject("ButtonNumber")); if ( !number ) continue; button = number->unsigned32BitValue(); if ( !button || button>32 ) continue; number = OSDynamicCast(OSNumber, map->getObject("EventType")); if ( !number ) continue; eventType = number->unsigned32BitValue(); number = OSDynamicCast(OSNumber, map->getObject("UsagePage")); if ( !number ) continue; usagePage = number->unsigned32BitValue(); number = OSDynamicCast(OSNumber, map->getObject("Usage")); if ( !number ) continue; usage = number->unsigned32BitValue(); _buttonMap[button-1].eventType = eventType; _buttonMap[button-1].usagePage = usagePage; _buttonMap[button-1].usage = usage; } } return true; }
bool CompareDeviceUsage( IOService * owner, OSDictionary * matching, SInt32 * score, SInt32 increment) { // We return success if we match the key in the dictionary with the key in // the property table, or if the prop isn't present // OSObject * usage; OSObject * usagePage; OSArray * functions; OSDictionary * pair; bool matches = true; int count; usage = matching->getObject( kIOHIDDeviceUsageKey ); usagePage = matching->getObject( kIOHIDDeviceUsagePageKey ); functions = OSDynamicCast(OSArray, owner->copyProperty( kIOHIDDeviceUsagePairsKey )); if ( functions ) { if ( usagePage || usage ) { count = functions->getCount(); for (int i=0; i<count; i++) { if ( !(pair = (OSDictionary *)functions->getObject(i)) ) continue; if ( !usagePage || !(matches = usagePage->isEqualTo(pair->getObject(kIOHIDDeviceUsagePageKey))) ) continue; if ( score && !usage ) { *score += increment / 2; break; } if ( !usage || !(matches = usage->isEqualTo(pair->getObject(kIOHIDDeviceUsageKey))) ) continue; if ( score ) *score += increment; break; } } functions->release(); } else { matches = false; } return matches; }
void AppleACPIPS2Nub::mergeInterruptProperties(IOService *pnpProvider, long) { /* Make sure we're called from within start() where these i-vars are valid */ if(m_interruptControllers == NULL || m_interruptSpecifiers == NULL) return; /* Get the interrupt controllers/specifiers arrays from the provider, and make sure they * exist and contain at least one entry. We assume they contain exactly one entry. */ OSArray *controllers = OSDynamicCast(OSArray,pnpProvider->getProperty(gIOInterruptControllersKey)); OSArray *specifiers = OSDynamicCast(OSArray,pnpProvider->getProperty(gIOInterruptSpecifiersKey)); if(controllers == NULL || specifiers == NULL) return; if(controllers->getCount() == 0 || specifiers->getCount() == 0) return; /* Append the first object of each array into our own respective array */ m_interruptControllers->setObject(controllers->getObject(0)); m_interruptSpecifiers->setObject(specifiers->getObject(0)); }
bool IOPlatformExpert::RegisterServiceInTree (IOService * theService, OSDictionary * theTreeNode, OSDictionary * theTreeParentNode, IOService * theProvider) { IOService * aService; bool registered = false; OSArray * children; unsigned int numChildren; OSDictionary * child; // make sure someone is not already registered here if ( NULL == theTreeNode->getObject ("service") ) { if ( theTreeNode->setObject ("service", OSDynamicCast ( OSObject, theService)) ) { // 1. CHILDREN ------------------ // we registered the node in the tree...now if the node has children // registered we must tell this service to add them. if ( NULL != (children = (OSArray *) theTreeNode->getObject ("children")) ) { numChildren = children->getCount (); for ( unsigned int i = 0; i < numChildren; i++ ) { if ( NULL != (child = (OSDictionary *) children->getObject (i)) ) { if ( NULL != (aService = (IOService *) child->getObject ("service")) ) theService->addPowerChild (aService); } } } // 2. PARENT -------------------- // also we must notify the parent of this node (if a registered service // exists there) of a new child. if ( theTreeParentNode ) { if ( NULL != (aService = (IOService *) theTreeParentNode->getObject ("service")) ) if (aService != theProvider) aService->addPowerChild (theService); } registered = true; } } return registered; }
// This routine will look to see if the OSArray contains any matching keys. The OSArray has to contain a list of OSNumbers. bool IOUSBNub::USBComparePropertyInArray( OSDictionary *matching, const char * arrayName, const char * key, UInt32 * theProductIDThatMatched ) { // We return success iff we match any entry in the array with the key OSArray * propertyIDArray = NULL; OSNumber * registryProperty = NULL; OSNumber * propertyFromArrayItem = NULL; bool matches = false; unsigned int index; *theProductIDThatMatched = 0; // Get our nub's value for the key registryProperty = OSDynamicCast(OSNumber, getProperty(key)); propertyIDArray = OSDynamicCast(OSArray, matching->getObject(arrayName)); // Iterate over the array looking for the entries if (propertyIDArray && registryProperty) { USBLog(7, "%s[%p]::USBComparePropertyInArray - found array with capacity of %d", getName(), this, propertyIDArray->getCount()); for (index = 0; index < propertyIDArray->getCount(); index++) { propertyFromArrayItem = OSDynamicCast(OSNumber, propertyIDArray->getObject(index)); if (propertyFromArrayItem) { // See if this item has the same value as the one in our registry for this key matches = propertyFromArrayItem->isEqualTo( registryProperty); if (matches) { *theProductIDThatMatched = propertyFromArrayItem->unsigned32BitValue(); USBLog(7, "%s[%p]::USBComparePropertyInArray - item %d matched: id = 0x%x", getName(), this, index, (uint32_t) *theProductIDThatMatched); break; } else { USBLog(7, "%s[%p]::USBComparePropertyInArray - item %d did not match", getName(), this, index); } } } } return matches; }
// This routine will look to see if the OSArray contains any matching keys. The OSArray has to contain a list of OSNumbers. bool IOUSBNub::USBComparePropertyInArrayWithMask( OSDictionary *matching, const char * arrayName, const char * key, const char * maskKey, UInt32 * theProductIDThatMatched ) { // We return success iff we match any entry in the array with the key OSArray * propertyIDArray = NULL; OSNumber * registryProperty = NULL; OSNumber * propertyFromArrayItem = NULL; OSNumber * dictionaryMask = NULL; bool matches = false; unsigned int index; *theProductIDThatMatched = 0; // Get our nub's value for the key registryProperty = OSDynamicCast(OSNumber, getProperty(key)); propertyIDArray = OSDynamicCast(OSArray, matching->getObject(arrayName)); dictionaryMask = OSDynamicCast(OSNumber, matching->getObject(maskKey)); // Iterate over the array looking for the entries if (propertyIDArray && registryProperty && dictionaryMask) { USBLog(7, "%s[%p]::USBComparePropertyInArrayWithMask - found array with capacity of %d", getName(), this, propertyIDArray->getCount()); for (index = 0; index < propertyIDArray->getCount(); index++) { propertyFromArrayItem = OSDynamicCast(OSNumber, propertyIDArray->getObject(index)); if (propertyFromArrayItem) { UInt32 registryValue = registryProperty->unsigned32BitValue(); UInt32 arrayValue = propertyFromArrayItem->unsigned32BitValue(); UInt32 mask = dictionaryMask->unsigned32BitValue(); if ( (registryValue & mask) == (arrayValue & mask) ) { USBLog(7, "%s[%p]::USBComparePropertyInArrayWithMask - 0x%x, 0x%x, mask 0x%x matched", getName(), this, (uint32_t)arrayValue, (uint32_t)registryValue, (uint32_t)mask); *theProductIDThatMatched = registryValue; matches = true; } } } } return matches; }
OSArray * ACPIBacklightPanel::queryACPISupportedBrightnessLevels() { DbgLog("%s::%s()\n", this->getName(),__FUNCTION__); OSObject * ret; backLightDevice->evaluateObject("_BCL", &ret); OSArray * data = OSDynamicCast(OSArray, ret); if (data) { DbgLog("%s: %s _BCL %d\n", this->getName(), backLightDevice->getName(), data->getCount() ); return data; } else { DbgLog("%s: Cast Error _BCL is %s\n", this->getName(), ret ? ret->getMetaClass()->getClassName() : "ret=NULL"); } OSSafeRelease(ret); return NULL; }
bool CompareNumberPropertyArrayWithMask( IOService * owner, OSDictionary * matching, const char * arrayName, const char * key, const char * maskKey, SInt32 * score, SInt32 increment) { OSNumber *registryProperty = (OSNumber *)owner->copyProperty(key); OSArray *propertyArray = (OSArray *)matching->getObject(arrayName); OSNumber *valueMask = (OSNumber *)matching->getObject(maskKey); CONVERT_TO_STACK_RETAIN(registryProperty); // If the property array or the value mask doesn't exist then return true if( OSDynamicCast(OSArray, propertyArray) && OSDynamicCast(OSNumber, valueMask) ) { if ( OSDynamicCast(OSNumber, registryProperty) ) { OSNumber *propertyFromArray; UInt32 registryValue = registryProperty->unsigned32BitValue(); UInt32 mask = valueMask->unsigned32BitValue(); int i = 0; for ( i = 0; i < propertyArray->getCount(); i ++ ) { propertyFromArray = OSDynamicCast(OSNumber, propertyArray->getObject(i)); if ( propertyFromArray ) { UInt32 propertyFromArrayValue = propertyFromArray->unsigned32BitValue(); if( (registryValue & mask) == (propertyFromArrayValue & mask ) ) { if ( score ) *score += increment; return true; } } } } } else return true; return false; }
bool IOCatalogue::addDrivers( OSArray * drivers, bool doNubMatching) { bool result = false; OSCollectionIterator * iter = NULL; // must release OSOrderedSet * set = NULL; // must release OSObject * object = NULL; // do not release OSArray * persons = NULL; // do not release persons = OSDynamicCast(OSArray, drivers); if (!persons) { goto finish; } set = OSOrderedSet::withCapacity( 10, IOServiceOrdering, (void *)gIOProbeScoreKey ); if (!set) { goto finish; } iter = OSCollectionIterator::withCollection(persons); if (!iter) { goto finish; } /* Start with success; clear it on an error. */ result = true; IORWLockWrite(lock); while ( (object = iter->getNextObject()) ) { // xxx Deleted OSBundleModuleDemand check; will handle in other ways for SL OSDictionary * personality = OSDynamicCast(OSDictionary, object); SInt count; if (!personality) { IOLog("IOCatalogue::addDrivers() encountered non-dictionary; bailing.\n"); result = false; break; } OSKext::uniquePersonalityProperties(personality); // Add driver personality to catalogue. OSArray * array = arrayForPersonality(personality); if (!array) addPersonality(personality); else { count = array->getCount(); while (count--) { OSDictionary * driver; // Be sure not to double up on personalities. driver = (OSDictionary *)array->getObject(count); /* Unlike in other functions, this comparison must be exact! * The catalogue must be able to contain personalities that * are proper supersets of others. * Do not compare just the properties present in one driver * pesonality or the other. */ if (personality->isEqualTo(driver)) { break; } } if (count >= 0) { // its a dup continue; } result = array->setObject(personality); if (!result) { break; } } set->setObject(personality); } // Start device matching. if (result && doNubMatching && (set->getCount() > 0)) { IOService::catalogNewDrivers(set); generation++; } IORWLockUnlock(lock); finish: if (set) set->release(); if (iter) iter->release(); return result; }
bool createPStateTable(PState* pS, unsigned int* numStates) { checkForPenryn(); // early on, so we can display proper mV values /* If the PState table was specified manually, we dont do the rest. Otherwise autodetect */ if (NumberOfPStates != 0) { dbg("PState table was already created. No autodetection will be performed\n"); return true; } /* Find CPUs in the IODeviceTree plane */ IORegistryEntry* ioreg = IORegistryEntry::fromPath("/cpus", IORegistryEntry::getPlane("IODeviceTree")); if (ioreg == 0) { warn("Holy moly we cannot find your CPU!\n"); return false; } /* Get the first CPU - we assume all CPUs share the same P-State */ IOACPIPlatformDevice* cpu = (IOACPIPlatformDevice*) ioreg->getChildEntry(IORegistryEntry::getPlane("IODeviceTree")); if (cpu == 0) { warn("Um you don't seem to have a CPU o.O\n"); ioreg = 0; return false; } dbg("Using data from %s\n", cpu->getName()); /* Now try to find the performance state table */ OSObject* PSS; cpu->evaluateObject("_PSS", &PSS); if(PSS == 0 ) { warn("Auto-creating a PState table.\n"); int maxFID = MHz_to_FID(getCurrentFrequency()); int maxVID = mV_to_VID(getCurrentVoltage()); int minVID = mV_to_VID(800); // For now we'll use hardcoded minvolt, later use table int minFID = 6; // No LFM right now NumberOfPStates = 1 + ((maxFID - minFID) / 2); for (int i = 1; i < NumberOfPStates; i++) { PStates[i].Frequency = minFID + (2*(NumberOfPStates - i - 1)); PStates[i].AcpiFreq = FID_to_MHz(PStates[i].Frequency); PStates[i].OriginalVoltage = maxVID - (i*((maxVID - minVID) / NumberOfPStates)) ; PStates[i].Voltage = PStates[i].OriginalVoltage; PStates[i].Latency = 110; PStates[i].TimesChosen = 0; } PStates[0].Frequency = maxFID; PStates[0].AcpiFreq = FID_to_MHz(maxFID); PStates[0].OriginalVoltage = maxVID; PStates[0].Voltage = PStates[0].OriginalVoltage; PStates[0].Latency = 110; PStates[0].TimesChosen = 0; MaxLatency = PStates[0].Latency; info("Using %d PStates (auto-created, may not be optimal).\n", NumberOfPStates); ioreg = 0; cpu = 0; return true; } OSArray* PSSArray = (OSArray*) PSS; NumberOfPStates = PSSArray->getCount(); info("Found %d P-States\n", NumberOfPStates); OSArray* onestate; uint16_t ctl, acpifreq; uint32_t power, latency; int i = 0, c = 0; while (c < PSSArray->getCount()) { onestate = ( OSArray* )(PSSArray->getObject(c)); ctl = ((OSNumber*) onestate->getObject(4))->unsigned32BitValue(); acpifreq = ((OSNumber*) onestate->getObject(0))->unsigned32BitValue(); power = ((OSNumber*) onestate->getObject(1))->unsigned32BitValue(); latency = ((OSNumber*) onestate->getObject(2))->unsigned32BitValue(); c++; info("clt: 0x%x , vid: %d , fid: %d \n", ctl , VID(ctl), FID(ctl) ); if (acpifreq - (10 * (acpifreq / 10)) == 1) { // most likely spurious, so skip it warn("** Spurious P-State %d: %d MHz at %d mV, consuming %d W, latency %d usec\n", i, acpifreq, VID_to_mV(ctl), power / 1000, latency); NumberOfPStates--; continue; } if (acpifreq < 1000 && !Below1Ghz) { warn("%d MHz disabled because your processor or kernel doesn't support it.\n",acpifreq); NumberOfPStates--; continue; } PStates[i].AcpiFreq = acpifreq; // cosmetic only PStates[i].Frequency = FID(ctl); PStates[i].OriginalVoltage = VID(ctl); PStates[i].Voltage = PStates[i].OriginalVoltage *50 / 100; // initially same PStates[i].Latency = latency; PStates[i].TimesChosen = 0; if (latency > MaxLatency) MaxLatency = latency; info("Auto: P-State %d: %d MHz at %d mV VID: %d, consuming %d W, latency %d usec\n", i, PStates[i].AcpiFreq, VID_to_mV(PStates[i].Voltage),PStates[i].Voltage, power / 1000, latency); i++; } info("Using %d PStates.\n", NumberOfPStates); ioreg = 0; cpu = 0; PSS = 0; onestate = 0; return true; }
bool ACPIProbe::start(IOService * provider) { ACPISensorsDebugLog("starting..."); if (!super::start(provider)) return false; if (!(acpiDevice = OSDynamicCast(IOACPIPlatformDevice, provider))) { ACPISensorsFatalLog("ACPI device not ready"); return false; } methods = OSArray::withCapacity(0); OSNumber *interval = NULL; OSNumber *timeout = NULL; OSBoolean *logging = NULL; OSArray *list = NULL; // Try to load configuration from info.plist first if (OSDictionary *configuration = getConfigurationNode()) { OSBoolean* disable = OSDynamicCast(OSBoolean, configuration->getObject("DisableDevice")); if (disable && disable->isTrue()) return false; interval = OSDynamicCast(OSNumber, configuration->getObject("PollingInterval")); timeout = OSDynamicCast(OSNumber, configuration->getObject("PollingTimeout")); logging = OSDynamicCast(OSBoolean, configuration->getObject("LoggingEnabled")); list = OSDynamicCast(OSArray, configuration->getObject("Methods")); } // Try to load configuration provided by ACPI device else { OSObject *object = NULL; if (kIOReturnSuccess == acpiDevice->evaluateObject("INVL", &object) && object) interval = OSDynamicCast(OSNumber, object); if (kIOReturnSuccess == acpiDevice->evaluateObject("TOUT", &object) && object) timeout = OSDynamicCast(OSNumber, object); if (kIOReturnSuccess == acpiDevice->evaluateObject("LOGG", &object) && object) { if (OSNumber *number = OSDynamicCast(OSNumber, object)) { logging = OSBoolean::withBoolean(number->unsigned8BitValue() == 1); } } if (kIOReturnSuccess == acpiDevice->evaluateObject("LIST", &object) && object) list = OSDynamicCast(OSArray, object); else ACPISensorsErrorLog("polling methods table (LIST) not found"); } if (interval) { pollingInterval = (double)interval->unsigned64BitValue() / (double)1000.0; ACPISensorsInfoLog("polling interval %lld ms", interval->unsigned64BitValue()); if (pollingInterval) { if (timeout) { pollingTimeout = (double)timeout->unsigned64BitValue() / 1000.0; ACPISensorsInfoLog("polling timeout %lld ms", timeout->unsigned64BitValue()); } if (logging) { loggingEnabled = logging->isTrue(); ACPISensorsInfoLog("logging %s", loggingEnabled ? "enabled" : "disabled"); } if (list) { for (unsigned int i = 0; i < list->getCount(); i++) { if (OSString *method = OSDynamicCast(OSString, list->getObject(i))) { if (method->getLength() && kIOReturnSuccess == acpiDevice->validateObject(method->getCStringNoCopy())) { methods->setObject(method); ACPISensorsInfoLog("method \"%s\" registered", method->getCStringNoCopy()); } else ACPISensorsErrorLog("unable to register method \"%s\"", method->getCStringNoCopy()); } } } } else ACPISensorsWarningLog("polling interval is set to zero, driver will be disabled"); } //REVIEW_REHABMAN: just bail if no methods to call... no need to stick around... if (!methods->getCount()) return false; if (methods->getCount()) { // woorkloop if (!(workloop = getWorkLoop())) { HWSensorsFatalLog("Failed to obtain workloop"); return false; } if (!(timerEventSource = IOTimerEventSource::timerEventSource( this, OSMemberFunctionCast(IOTimerEventSource::Action, this, &ACPIProbe::woorkloopTimerEvent)))) { ACPISensorsFatalLog("failed to initialize timer event source"); return false; } if (kIOReturnSuccess != workloop->addEventSource(timerEventSource)) { ACPISensorsFatalLog("failed to add timer event source into workloop"); return false; } timerEventSource->setTimeoutMS(100); //ACPISensorsInfoLog("%d method%s registered", methods->getCount(), methods->getCount() > 1 ? "s" : ""); } registerService(); ACPISensorsInfoLog("started"); return true; }
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; }
bool ApplePS2Keyboard::start(IOService * provider) { OSBoolean *xml_swap_CAPSLOCK_CTRL; OSBoolean *xml_swap_ALT_WIN; OSBoolean *xml_use_right_modifier_into_HANGUL_HANJA; OSBoolean *xml_make_APP_into_RWIN; OSBoolean *xml_swap_GRAVE_EUROPE2; OSBoolean *xml_make_APP_into_AppleFN; // // The driver has been instructed to start. This is called after a // successful attach. // if (!super::start(provider)) return false; // // Maintain a pointer to and retain the provider object. // _device = (ApplePS2KeyboardDevice *)provider; _device->retain(); // // Configure user preferences from Info.plist // xml_swap_CAPSLOCK_CTRL = OSDynamicCast( OSBoolean, getProperty("Swap capslock and left control")); if (xml_swap_CAPSLOCK_CTRL) { if ( xml_swap_CAPSLOCK_CTRL->getValue()) { char temp = _PS2ToADBMap[0x3a]; _PS2ToADBMap[0x3a] = _PS2ToADBMap[0x1d]; _PS2ToADBMap[0x1d] = temp; } } xml_swap_ALT_WIN = OSDynamicCast( OSBoolean, getProperty("Swap command and option")); if (xml_swap_ALT_WIN) { if ( xml_swap_ALT_WIN->getValue()) { char temp = _PS2ToADBMap[0x38]; _PS2ToADBMap[0x38] = _PS2ToADBMap[0x15b]; _PS2ToADBMap[0x15b] = temp; temp = _PS2ToADBMap[0x138]; _PS2ToADBMap[0x138] = _PS2ToADBMap[0x15c]; _PS2ToADBMap[0x15c] = temp; } } xml_use_right_modifier_into_HANGUL_HANJA = OSDynamicCast( \ OSBoolean, getProperty("Make right modifier keys into Hangul and Hanja")); if (xml_use_right_modifier_into_HANGUL_HANJA) { if ( xml_use_right_modifier_into_HANGUL_HANJA->getValue()) { _PS2ToADBMap[0x138] = _PS2ToADBMap[0xf2]; // Right alt becomes Hangul _PS2ToADBMap[0x11d] = _PS2ToADBMap[0xf1]; // Right control becomes Hanja } } xml_make_APP_into_RWIN = OSDynamicCast( OSBoolean, getProperty("Make Application key into right windows")); if (xml_make_APP_into_RWIN) { if ( xml_make_APP_into_RWIN->getValue()) _PS2ToADBMap[0x15d] = _PS2ToADBMap[0x15c]; } // not implemented yet. // Apple Fn key works well, but no combined key action was made. xml_make_APP_into_AppleFN = OSDynamicCast( OSBoolean, getProperty("Make Application key into Apple Fn key")); if (xml_make_APP_into_AppleFN) { if ( xml_make_APP_into_AppleFN->getValue()) { _PS2ToADBMap[0x15d] = 0x3f; } } // ISO specific mapping to match ADB keyboards // This should really be done in the keymaps. xml_swap_GRAVE_EUROPE2 = OSDynamicCast( OSBoolean, getProperty("Use ISO layout keyboard")); if (xml_swap_GRAVE_EUROPE2) { if ( xml_swap_GRAVE_EUROPE2->getValue()) { char temp = _PS2ToADBMap[0x29]; //Grave '~' _PS2ToADBMap[0x29] = _PS2ToADBMap[0x56]; //Europe2 '¤º' _PS2ToADBMap[0x56] = temp; } } // now load PS2 -> PS2 configuration data OSArray* pArray = OSDynamicCast(OSArray, getProperty("Custom PS2 Map")); if (NULL != pArray) { for (int i = 0; i < pArray->getCount(); i++) { OSString* pString = OSDynamicCast(OSString, pArray->getObject(i)); if (NULL == pString) continue; const char* psz = pString->getCStringNoCopy(); // check for comment if (';' == *psz) continue; // otherwise, try to parse it UInt16 scanIn, scanOut; if (!parseRemap(psz, scanIn, scanOut)) { IOLog("VoodooPS2Keyboard: invalid custom PS2 map entry: \"%s\"\n", psz); continue; } // must be normal scan code or extended, nothing else UInt8 exIn = scanIn >> 8; UInt8 exOut = scanOut >> 8; if ((exIn != 0 && exIn != 0xe0) || (exOut != 0 && exOut != 0xe0)) { IOLog("VoodooPS2Keyboard: scan code invalid for PS2 map entry: \"%s\"\n", psz); continue; } // modify PS2 to PS2 map per remap entry int index = (scanIn & 0xff) + (exIn == 0xe0 ? KBV_NUM_SCANCODES : 0); assert(index < countof(_PS2ToPS2Map)); _PS2ToPS2Map[index] = (scanOut & 0xff) + (exOut == 0xe0 ? KBV_NUM_SCANCODES : 0); } } // now load PS2 -> ADB configuration data pArray = OSDynamicCast(OSArray, getProperty("Custom ADB Map")); if (NULL != pArray) { for (int i = 0; i < pArray->getCount(); i++) { OSString* pString = OSDynamicCast(OSString, pArray->getObject(i)); if (NULL == pString) continue; const char* psz = pString->getCStringNoCopy(); // check for comment if (';' == *psz) continue; // otherwise, try to parse it UInt16 scanIn, adbOut; if (!parseRemap(psz, scanIn, adbOut)) { IOLog("VoodooPS2Keyboard: invalid custom ADB map entry: \"%s\"\n", psz); continue; } // must be normal scan code or extended, nothing else, adbOut is only a byte UInt8 exIn = scanIn >> 8; if ((exIn != 0 && exIn != 0xe0) || adbOut > 0xFF) { IOLog("VoodooPS2Keyboard: scan code invalid for ADB map entry: \"%s\"\n", psz); continue; } // modify PS2 to ADB map per remap entry int index = (scanIn & 0xff) + (exIn == 0xe0 ? ADB_CONVERTER_EX_START : 0); assert(index < countof(_PS2ToADBMap)); _PS2ToADBMap[index] = adbOut; } } // get time before sleep button takes effect OSNumber* num; if ((num = OSDynamicCast(OSNumber, getProperty("SleepPressTime")))) maxsleeppresstime = (uint64_t)num->unsigned32BitValue() * (uint64_t)1000000; // // Reset and enable the keyboard. // initKeyboard(); // // Install our driver's interrupt handler, for asynchronous data delivery. // _device->installInterruptAction(this, OSMemberFunctionCast(PS2InterruptAction,this,&ApplePS2Keyboard::interruptOccurred)); _interruptHandlerInstalled = true; // // Install our power control handler. // _device->installPowerControlAction( this, OSMemberFunctionCast(PS2PowerControlAction,this, &ApplePS2Keyboard::setDevicePowerState )); _powerControlHandlerInstalled = true; return true; }
void testSet() { bool res = true; void *spaceCheck, *spaceCheck2 , *spaceCheck3; int i, count, count2; OSObject *cache[numStrCache], *str, *sym; OSSet *set1, *set2; OSArray *array; // Do first test without memory leak tests to initialise the metaclass set1 = OSSet::withCapacity(1); TEST_ASSERT('S', "0a", set1); if (set1) set1->release(); // Grow the symbol pool to maximum for (i = 0; i < numStrCache; i++) cache[i] = (OSObject *) OSSymbol::withCStringNoCopy(strCache[i]); for (i = 0; i < numStrCache; i++) cache[i]->release(); // Create and destroy an set spaceCheck = checkPointSpace(); set1 = OSSet::withCapacity(1); TEST_ASSERT('S', "1a", set1); if (set1) { TEST_ASSERT('S', "1b", !set1->getCount()); TEST_ASSERT('S', "1c", 1 == set1->getCapacity()); TEST_ASSERT('S', "1d", 1 == set1->getCapacityIncrement()); TEST_ASSERT('S', "1e", 4 == set1->setCapacityIncrement(4)); TEST_ASSERT('S', "1f", 4 == set1->getCapacityIncrement()); TEST_ASSERT('S', "1g", 8 == set1->ensureCapacity(5)); spaceCheck2 = checkPointSpace(); cache[0] = IOString::withCStringNoCopy(strCache[0]); spaceCheck3 = checkPointSpace(); TEST_ASSERT('S', "1h", set1->setObject(cache[0])); TEST_ASSERT('S', "1i", set1->containsObject(cache[0])); TEST_ASSERT('S', "1j", cache[0] == set1->getAnyObject()); cache[0]->release(); res = res && checkSpace("(S)1k", spaceCheck3, 0); TEST_ASSERT('S', "1l", 1 == set1->getCount()); set1->flushCollection(); TEST_ASSERT('S', "1m", !set1->getCount()); res = res && checkSpace("(S)1n", spaceCheck2, 0); set1->release(); } res = res && checkSpace("(S)1", spaceCheck, 0); // Check the creation of a sizable OSSet from an set of IOObjects // Also check member test of set. spaceCheck = checkPointSpace(); for (i = 0; i < numStrCache; i++) cache[i] = OSString::withCStringNoCopy(strCache[i]); set1 = OSSet::withObjects(cache, numStrCache, numStrCache); TEST_ASSERT('S', "2a", set1); for (i = 0; i < numStrCache; i++) cache[i]->release(); if (set1) { TEST_ASSERT('S', "2b", numStrCache == (int) set1->getCount()); TEST_ASSERT('S', "2c", numStrCache == (int) set1->getCapacity()); TEST_ASSERT('S', "2d", numStrCache == (int) set1->getCapacityIncrement()); count = 0; for (i = set1->getCount(); --i >= 0; ) count += set1->member(cache[i]); TEST_ASSERT('S', "2e", numStrCache == count); set1->release(); } res = res && checkSpace("(S)2", spaceCheck, 0); // Test set creation from another set by both the setObject method // and the withArray factory. And test __takeObject code first // with tail removal then with head removal spaceCheck = checkPointSpace(); for (i = 0; i < numStrCache; i++) cache[i] = OSString::withCStringNoCopy(strCache[i]); set1 = OSSet::withObjects(cache, numStrCache, numStrCache); TEST_ASSERT('S', "3a", set1); for (i = 0; i < numStrCache; i++) cache[i]->release(); set2 = 0; if (set1) { set2 = OSSet::withCapacity(set1->getCount()); TEST_ASSERT('S', "3b", set2); TEST_ASSERT('S', "3c", !set2->getCount()); TEST_ASSERT('S', "3d", set2->setObject(set1)); TEST_ASSERT('S', "3e", set1->getCount() == set2->getCount()); } if (set2) { TEST_ASSERT('S', "3f", numStrCache == (int) set2->getCount()); count = count2 = 0; while ( (str = set2->getAnyObject()) ) { count += set2->__takeObject(str); count2 += set1->member(str); str->release(); } TEST_ASSERT('S', "3g", !set2->getCount()); TEST_ASSERT('S', "3h", numStrCache == count); TEST_ASSERT('S', "3i", numStrCache == count2); spaceCheck2 = checkPointSpace(); set2->flushCollection(); res = res && checkSpace("(S)3j", spaceCheck2, 0); set2->release(); set2 = 0; } if (set1) { set2 = OSSet::withSet(set1, numStrCache - 1); TEST_ASSERT('S', "3k", !set2); set2 = OSSet::withSet(set1, set1->getCount()); TEST_ASSERT('S', "3l", set2); set1->release(); } if (set2) { TEST_ASSERT('S', "3m", numStrCache == (int) set2->getCount()); i = count = count2 = 0; while ( (str = set2->getAnyObject()) ) { count += set2->__takeObject(str); count2 += (cache[i++] == str); str->release(); } TEST_ASSERT('S', "3n", !set2->getCount()); TEST_ASSERT('S', "3o", numStrCache == count); TEST_ASSERT('S', "3p", numStrCache == count2); set2->release(); set2 = 0; } res = res && checkSpace("(S)3", spaceCheck, 0); // Test duplicate removal spaceCheck = checkPointSpace(); set2 = 0; set1 = OSSet::withCapacity(numStrCache); TEST_ASSERT('S', "4a", set1); if (set1) { count = 0; for (i = 0; i < numStrCache; i++) { sym = (OSObject *) OSSymbol::withCStringNoCopy(strCache[i]); count += set1->setObject(sym); sym->release(); } TEST_ASSERT('S', "4b", numStrCache != (int) set1->getCount()); TEST_ASSERT('S', "4c", count == (int) set1->getCount()); count = count2 = 0; for (i = 0; i < numStrCache; i++) { sym = (OSObject *) OSSymbol::withCStringNoCopy(strCache[i]); count += set1->member(sym); count2 += sym->getRetainCount(); sym->release(); } TEST_ASSERT('S', "4d", count == numStrCache); TEST_ASSERT('S', "4e", count2 == numStrCache * 2); set2 = OSSet::withSet(set1, 2 * set1->getCount()); } TEST_ASSERT('S', "4f", set2); if (set2) { set2->setObject(set1); TEST_ASSERT('S', "4g", set1->getCount() == set2->getCount()); set1->release(); set2->release(); } res = res && checkSpace("(S)4", spaceCheck, 0); // Test array duplicate removal spaceCheck = checkPointSpace(); array = OSArray::withCapacity(numStrCache); for (i = 0; i < numStrCache; i++) { sym = (OSObject *) OSSymbol::withCStringNoCopy(strCache[i]); count += array->setObject(sym); sym->release(); } set1 = OSSet::withArray(array, numStrCache); TEST_ASSERT('S', "5a", set1); if (set1) { TEST_ASSERT('S', "5b", array->getCount() != set1->getCount()); array->release(); count = count2 = set1->getCount(); while ( (sym = set1->getAnyObject()) ) { count -= set1->__takeObject(sym); count2 -= sym->getRetainCount(); sym->release(); } TEST_ASSERT('S', "5c", !count); TEST_ASSERT('S', "5d", !count2); set1->release(); } res = res && checkSpace("(S)5", spaceCheck, 0); if (res) verPrintf(("testSet: All OSSet Tests passed\n")); else logPrintf(("testSet: Some OSSet Tests failed\n")); }
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; }
void KLDBootstrap::readBuiltinPersonalities(void) { OSObject * parsedXML = NULL; // must release OSArray * builtinExtensions = NULL; // do not release OSArray * allPersonalities = NULL; // must release OSString * errorString = NULL; // must release kernel_section_t * infosect = NULL; // do not free OSCollectionIterator * personalitiesIterator = NULL; // must release unsigned int count, i; OSKextLog(/* kext */ NULL, kOSKextLogStepLevel | kOSKextLogLoadFlag, "Reading built-in kernel personalities for I/O Kit drivers."); /* Look in the __BUILTIN __info segment for an array of Info.plist * entries. For each one, extract the personalities dictionary, add * it to our array, then push them all (without matching) to * the IOCatalogue. This can be used to augment the personalities * in gIOKernelConfigTables, especially when linking entire kexts into * the mach_kernel image. */ infosect = getsectbyname("__BUILTIN", "__info"); if (!infosect) { // this isn't fatal goto finish; } parsedXML = OSUnserializeXML((const char *) (uintptr_t)infosect->addr, &errorString); if (parsedXML) { builtinExtensions = OSDynamicCast(OSArray, parsedXML); } if (!builtinExtensions) { const char * errorCString = "(unknown error)"; if (errorString && errorString->getCStringNoCopy()) { errorCString = errorString->getCStringNoCopy(); } else if (parsedXML) { errorCString = "not an array"; } OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogLoadFlag, "Error unserializing built-in personalities: %s.", errorCString); goto finish; } // estimate 3 personalities per Info.plist/kext count = builtinExtensions->getCount(); allPersonalities = OSArray::withCapacity(count * 3); for (i = 0; i < count; i++) { OSDictionary * infoDict = NULL; // do not release OSString * moduleName = NULL; // do not release OSDictionary * personalities; // do not release OSString * personalityName; // do not release OSSafeReleaseNULL(personalitiesIterator); infoDict = OSDynamicCast(OSDictionary, builtinExtensions->getObject(i)); if (!infoDict) { continue; } moduleName = OSDynamicCast(OSString, infoDict->getObject(kCFBundleIdentifierKey)); if (!moduleName) { continue; } OSKextLog(/* kext */ NULL, kOSKextLogStepLevel | kOSKextLogLoadFlag, "Adding personalities for built-in driver %s:", moduleName->getCStringNoCopy()); personalities = OSDynamicCast(OSDictionary, infoDict->getObject("IOKitPersonalities")); if (!personalities) { continue; } personalitiesIterator = OSCollectionIterator::withCollection(personalities); if (!personalitiesIterator) { continue; // xxx - well really, what can we do? should we panic? } while ((personalityName = OSDynamicCast(OSString, personalitiesIterator->getNextObject()))) { OSDictionary * personality = OSDynamicCast(OSDictionary, personalities->getObject(personalityName)); OSKextLog(/* kext */ NULL, kOSKextLogDetailLevel | kOSKextLogLoadFlag, "Adding built-in driver personality %s.", personalityName->getCStringNoCopy()); if (personality && !personality->getObject(kCFBundleIdentifierKey)) { personality->setObject(kCFBundleIdentifierKey, moduleName); } allPersonalities->setObject(personality); } } gIOCatalogue->addDrivers(allPersonalities, false); finish: OSSafeReleaseNULL(parsedXML); OSSafeReleaseNULL(allPersonalities); OSSafeReleaseNULL(errorString); OSSafeReleaseNULL(personalitiesIterator); return; }
/********************************************************************* * This is the function that IOCatalogue calls in order to load a kmod. * It first checks whether the kmod is already loaded. If the kmod * isn't loaded, this function builds a dependency list and calls * load_kmod() repeatedly to guarantee that each dependency is in fact * loaded. *********************************************************************/ __private_extern__ kern_return_t load_kernel_extension(char * kmod_name) { kern_return_t result = KERN_SUCCESS; kmod_info_t * kmod_info = 0; // must free OSArray * dependencyList = NULL; // must release OSArray * curDependencyList = NULL; // must release /* See if the kmod is already loaded. */ kmod_info = kmod_lookupbyname_locked(kmod_name); if (kmod_info) { // NOT checked result = KERN_SUCCESS; goto finish; } /* It isn't loaded; build a dependency list and * load those. */ unsigned int count; unsigned int i; dependencyList = getDependencyListForKmod(kmod_name); if (!dependencyList) { IOLog("load_kernel_extension(): " "Can't get dependencies for kernel extension \"%s\".\n", kmod_name); LOG_DELAY(); result = KERN_FAILURE; goto finish; } count = dependencyList->getCount(); for (i = 0; i < count; i++) { kern_return_t load_result; OSString * curKmodName; // don't release const char * cur_kmod_name; curKmodName = OSDynamicCast(OSString, dependencyList->getObject(i)); cur_kmod_name = curKmodName->getCStringNoCopy(); curDependencyList = getDependencyListForKmod(cur_kmod_name); if (!curDependencyList) { IOLog("load_kernel_extension(): " "Can't get dependencies for kernel extension \"%s\".\n", cur_kmod_name); LOG_DELAY(); result = KERN_FAILURE; goto finish; } else { load_result = load_kmod(curDependencyList); if (load_result != KERN_SUCCESS) { IOLog("load_kernel_extension(): " "load_kmod() failed for kmod \"%s\".\n", cur_kmod_name); LOG_DELAY(); result = load_result; goto finish; } curDependencyList->release(); curDependencyList = NULL; } } finish: if (kmod_info) { kfree((unsigned int)kmod_info, sizeof(kmod_info_t)); } if (dependencyList) { dependencyList->release(); dependencyList = NULL; } if (curDependencyList) { curDependencyList->release(); curDependencyList = NULL; } return result; }
/********************************************************************* * This function builds a uniqued, in-order list of modules that need * to be loaded in order for kmod_name to be successfully loaded. This * list ends with kmod_name itself. *********************************************************************/ static OSArray * getDependencyListForKmod(const char * kmod_name) { int error = 0; OSDictionary * extensionsDict; // don't release OSDictionary * extDict; // don't release OSDictionary * extPlist; // don't release OSString * extName; // don't release OSArray * dependencyList = NULL; // return value, caller releases unsigned int i; /* These are used to remove duplicates from the dependency list. */ OSArray * originalList = NULL; // must be released OSDictionary * encounteredNames = NULL; // must be release /* Get the dictionary of startup extensions. * This is keyed by module name. */ extensionsDict = getStartupExtensions(); if (!extensionsDict) { IOLog("getDependencyListForKmod(): No extensions dictionary.\n"); LOG_DELAY(); error = 1; goto finish; } /* Get the requested extension's dictionary entry and its property * list, containing module dependencies. */ extDict = OSDynamicCast(OSDictionary, extensionsDict->getObject(kmod_name)); if (!extDict) { IOLog("getDependencyListForKmod(): " "Extension \"%s\" cannot be found.\n", kmod_name); LOG_DELAY(); error = 1; goto finish; } extPlist = OSDynamicCast(OSDictionary, extDict->getObject("plist")); if (!extPlist) { IOLog("getDependencyListForKmod(): " "Extension \"%s\" has no property list.\n", kmod_name); LOG_DELAY(); error = 1; goto finish; } /* Verify that the retrieved entry's "CFBundleIdentifier" property exists. * This will be added to the dependency list. */ extName = OSDynamicCast(OSString, extPlist->getObject("CFBundleIdentifier")); if (!extName) { IOLog("getDependencyListForKmod(): " "Extension \"%s\" has no \"CFBundleIdentifier\" property.\n", kmod_name); LOG_DELAY(); error = 1; goto finish; } dependencyList = OSArray::withCapacity(10); if (!dependencyList) { IOLog("getDependencyListForKmod(): " "Couldn't allocate dependency array for extension \"%s\".\n", kmod_name); LOG_DELAY(); error = 1; goto finish; } /* Okay, let's get started. */ dependencyList->setObject(extName); /* Here's a slightly tricky bit. This loop iterates through * the dependency list until it runs off the end. Each time * through, however, any number of dependencies can be added * to the end of the list. Eventually some extensions won't * have any more dependencies, no more names will be added * to the list, and this loop will terminate. */ for (i = 0; i < dependencyList->getCount(); i++) { // None of these needs to be released, as they're all from plists. OSString * curName; OSDictionary * curExtDict; OSDictionary * curExtDepDict; OSDictionary * curExtPlist; OSString * curDepName; /* An arbitrary limit to prevent infinite loops. */ if (i > 255) { IOLog("getDependencyListForKmod(): " "max dependency list length exceeded for " "extension \"%s\".\n", kmod_name); LOG_DELAY(); error = 1; goto finish; } curName = OSDynamicCast(OSString, dependencyList->getObject(i)); curExtDict = OSDynamicCast(OSDictionary, extensionsDict->getObject(curName)); if (!curExtDict) { IOLog("getDependencyListForKmod(): " "Extension \"%s\", required for extension \"%s\", " "is not available.\n", curName->getCStringNoCopy(), kmod_name); LOG_DELAY(); error = 1; goto finish; } curExtPlist = OSDynamicCast(OSDictionary, curExtDict->getObject("plist")); if (!curExtPlist) { IOLog("getDependencyListForKmod(): " "Extension \"%s\", required for extension \"%s\", " "has no property list.\n", curName->getCStringNoCopy(), kmod_name); LOG_DELAY(); error = 1; goto finish; } curExtDepDict = OSDynamicCast(OSDictionary, curExtPlist->getObject("OSBundleLibraries")); if (curExtDepDict) { OSCollectionIterator * keyIterator = OSCollectionIterator::withCollection(curExtDepDict); if (!keyIterator) { IOLog("getDependencyListForKmod(): " "Couldn't allocate iterator for extension " "\"%s\".\n", kmod_name); LOG_DELAY(); error = 1; goto finish; } while ( (curDepName = OSDynamicCast(OSString, keyIterator->getNextObject())) ) { OSString * requiredVersion = OSDynamicCast(OSString, curExtDepDict->getObject(curDepName)); if (!verifyCompatibility(curDepName, requiredVersion)) { IOLog("getDependencyListForKmod(): " "Dependency %s of %s is not compatible or is unavailable.\n", curDepName->getCStringNoCopy(), curName->getCStringNoCopy()); LOG_DELAY(); error = 1; goto finish; } dependencyList->setObject(curDepName); } keyIterator->release(); } } /***** * The dependency list now exists in the reverse order of required loads, * and may have duplicates. Now we turn the list around and remove * duplicates. */ originalList = dependencyList; dependencyList = OSArray::withCapacity(originalList->getCount()); if (!dependencyList) { IOLog("getDependenciesForKmod(): " "Couldn't allocate reversal dependency list for extension " "\"%s\".\n", kmod_name); LOG_DELAY(); error = 1; goto finish; } encounteredNames = OSDictionary::withCapacity(originalList->getCount()); if (!encounteredNames) { IOLog("getDependenciesForKmod(): " "Couldn't allocate list of encountered names for extension " "\"%s\".\n", kmod_name); LOG_DELAY(); error = 1; goto finish; } /* Go backward through the original list, using the encounteredNames * dictionary to check for duplicates. We put originalList in as the * value because we need some non-NULL value. Here we also drop any * extensions that aren't proper dependencies (that is, any that are * nonkernel kexts without code). */ i = originalList->getCount(); if (i > 0) { do { i--; OSString * item = OSDynamicCast(OSString, originalList->getObject(i)); if ( (!encounteredNames->getObject(item)) && kextIsADependency(item)) { encounteredNames->setObject(item, originalList); dependencyList->setObject(item); } } while (i > 0); } finish: if (originalList) { originalList->release(); } if (encounteredNames) { encounteredNames->release(); } if (error) { if (dependencyList) { dependencyList->release(); dependencyList = NULL; } } return dependencyList; }
bool IOCatalogue::resetAndAddDrivers(OSArray * drivers, bool doNubMatching) { bool result = false; OSArray * newPersonalities = NULL; // do not release OSCollectionIterator * newPIterator = NULL; // must release OSOrderedSet * matchSet = NULL; // must release OSArray * oldPersonalities = NULL; // must release OSArray * kernelPersonalities = NULL; // must release OSString * errorString = NULL; // must release OSObject * object = NULL; // do not release OSDictionary * thisNewPersonality = NULL; // do not release signed int count, i; extern const char * gIOKernelConfigTables; if (drivers) { newPersonalities = OSDynamicCast(OSArray, drivers); if (!newPersonalities) { goto finish; } newPIterator = OSCollectionIterator::withCollection(newPersonalities); if (!newPIterator) { goto finish; } matchSet = OSOrderedSet::withCapacity(10, IOServiceOrdering, (void *)gIOProbeScoreKey); if (!matchSet) { goto finish; } } /* Read personalities for the built-in kernel driver classes. * We don't have many any more. */ kernelPersonalities = OSDynamicCast(OSArray, OSUnserialize(gIOKernelConfigTables, &errorString)); if (!kernelPersonalities && errorString) { IOLog("KernelConfigTables syntax error: %s\n", errorString->getCStringNoCopy()); goto finish; } /* Now copy the current array of personalities so we can reuse them * if the new list contains any duplicates. This saves on memory * consumption. */ oldPersonalities = OSDynamicCast(OSArray, array->copyCollection()); if (!oldPersonalities) { goto finish; } result = true; IOLog("Resetting IOCatalogue.\n"); /* No goto finish from here to unlock. */ IOLockLock(lock); array->flushCollection(); /* Add back the kernel personalities and remove them from the old * array so we don't try to match on them again. Go forward through * the arrays as this causes the least iteration since kernel personalities * should always be first. */ count = kernelPersonalities->getCount(); for (i = 0; i < count; i++) { /* Static cast here, as the data is coming from within the kernel image. */ OSDictionary * thisNewPersonality = (OSDictionary *) kernelPersonalities->getObject(i); array->setObject(thisNewPersonality); signed int oldPCount = oldPersonalities->getCount(); for (signed int oldPIndex = 0; oldPIndex < oldPCount; oldPIndex++) { if (thisNewPersonality->isEqualTo(oldPersonalities->getObject(oldPIndex))) { oldPersonalities->removeObject(oldPIndex); break; } } } /* Now add the new set of personalities passed in, using existing * copies if we had them in kernel memory already. */ if (newPIterator) { OSDictionary * thisOldPersonality = NULL; // do not release while ( (object = newPIterator->getNextObject()) ) { thisNewPersonality = OSDynamicCast(OSDictionary, object); if (!thisNewPersonality) { IOLog("IOCatalogue::resetAndAddDrivers() encountered non-dictionary; bailing.\n"); result = false; break; } /* Convert common OSString property values to OSSymbols. */ OSKext::uniquePersonalityProperties(thisNewPersonality); /* Add driver personality to catalogue, but if we had a copy already * use that instead so we don't have multiple copies from OSKext instances. */ count = oldPersonalities->getCount(); thisOldPersonality = NULL; while (count--) { thisOldPersonality = (OSDictionary *)oldPersonalities->getObject(count); /* Unlike in other functions, this comparison must be exact! * The catalogue must be able to contain personalities that * are proper supersets of others. * Do not compare just the properties present in one driver * pesonality or the other. */ if (thisNewPersonality->isEqualTo(thisOldPersonality)) { break; } } /* If we found a dup, add the *original* back to the catalogue, * remove it from our bookkeeping list, and continue. * Don't worry about matching on personalities we already had. */ if (count >= 0) { array->setObject(thisOldPersonality); oldPersonalities->removeObject(count); continue; } /* Otherwise add the new personality and mark it for matching. */ array->setObject(thisNewPersonality); AddNewImports(matchSet, thisNewPersonality); } /***** * Now, go through remaining old personalities, which have effectively * been removed, and add them to the match set as necessary. */ count = oldPersonalities->getCount(); while (count--) { /* Static cast here is ok as these dictionaries were already in the catalogue. */ thisOldPersonality = (OSDictionary *)oldPersonalities->getObject(count); AddNewImports(matchSet, thisOldPersonality); } /* Finally, start device matching on all new & removed personalities. */ if (result && doNubMatching && (matchSet->getCount() > 0)) { IOService::catalogNewDrivers(matchSet); generation++; } } IOLockUnlock(lock); finish: if (newPIterator) newPIterator->release(); if (matchSet) matchSet->release(); if (oldPersonalities) oldPersonalities->release(); if (kernelPersonalities) kernelPersonalities->release(); if (errorString) errorString->release(); return result; }
bool PTIDSensors::start(IOService * provider) { if (!super::start(provider)) return false; acpiDevice = (IOACPIPlatformDevice *)provider; if (!acpiDevice) { HWSensorsFatalLog("ACPI device not ready"); return false; } // Update timers temperaturesLastUpdated = ptimer_read() - NSEC_PER_SEC; tachometersLastUpdated = temperaturesLastUpdated; acpiDevice->evaluateInteger("IVER", &version); if (version == 0) { OSString *name = OSDynamicCast(OSString, provider->getProperty("name")); if (name && name->isEqualTo("INT3F0D")) version = 0x30000; else return false; } setProperty("version", version, 64); // Parse sensors switch (version) { case 0x30000: { OSObject *object = NULL; // Temperatures if(kIOReturnSuccess == acpiDevice->evaluateObject("TSDL", &object) && object) { OSArray *description = OSDynamicCast(OSArray, object); HWSensorsDebugLog("Parsing temperatures..."); for (UInt32 index = 1; index < description->getCount(); index += 2) { parseTemperatureName(OSDynamicCast(OSString, description->getObject(index)), (index - 1) / 2); } } else HWSensorsErrorLog("failed to evaluate TSDL table"); // Tachometers if(kIOReturnSuccess == acpiDevice->evaluateObject("OSDL", &object) && object) { OSArray *description = OSDynamicCast(OSArray, object); HWSensorsDebugLog("Parsing tachometers..."); for (UInt32 index = 2; index < description->getCount(); index += 3) { parseTachometerName(OSDynamicCast(OSString, description->getObject(index)), OSDynamicCast(OSString, description->getObject(index - 1)), (index - 2) / 3); } } else HWSensorsErrorLog("failed to evaluate OSDL table"); break; } case 0x20001: { OSObject *object = NULL; // Temperatures if(kIOReturnSuccess == acpiDevice->evaluateObject("TMPV", &object) && object) { OSArray *description = OSDynamicCast(OSArray, object); for (UInt32 index = 1; index < description->getCount(); index += 3) { parseTemperatureName(OSDynamicCast(OSString, description->getObject(index)), index + 1); } } else HWSensorsErrorLog("failed to evaluate TMPV table"); // Tachometers if(kIOReturnSuccess == acpiDevice->evaluateObject("OSDV", &object) && object) { OSArray *description = OSDynamicCast(OSArray, object); for (UInt32 index = 2; index < description->getCount(); index += 4) { parseTachometerName(OSDynamicCast(OSString, description->getObject(index)), OSDynamicCast(OSString, description->getObject(index - 1)), index + 1); } } else HWSensorsErrorLog("failed to evaluate OSDV table"); break; } default: HWSensorsFatalLog("usupported interface version: 0x%x", (unsigned int)version); return false; } registerService(); HWSensorsInfoLog("started"); return true; }
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); }