X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/6601e61aa18bf4f09af135ff61fc7f4771d23b06..d26ffc64f583ab2d29df48f13518685602bc8832:/iokit/Kernel/IONVRAM.cpp diff --git a/iokit/Kernel/IONVRAM.cpp b/iokit/Kernel/IONVRAM.cpp index 315aefe11..94d6b75dd 100644 --- a/iokit/Kernel/IONVRAM.cpp +++ b/iokit/Kernel/IONVRAM.cpp @@ -1,23 +1,30 @@ /* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 1998-2006 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2007-2012 Apple Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. * - * @APPLE_LICENSE_HEADER_END@ + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ #include @@ -25,13 +32,22 @@ #include #include #include +#include +#include +#include + +#if CONFIG_MACF +extern "C" { +#include +#include +}; +#endif /* MAC */ #define super IOService #define kIONVRAMPrivilege kIOClientPrivilegeAdministrator //#define kIONVRAMPrivilege kIOClientPrivilegeLocalUser - OSDefineMetaClassAndStructors(IODTNVRAM, IOService); bool IODTNVRAM::init(IORegistryEntry *old, const IORegistryPlane *plane) @@ -56,10 +72,59 @@ bool IODTNVRAM::init(IORegistryEntry *old, const IORegistryPlane *plane) _registryPropertiesKey = OSSymbol::withCStringNoCopy("aapl,pci"); if (_registryPropertiesKey == 0) return false; + // race condition possible between + // IODTNVRAM and IONVRAMController (restore loses boot-args) + initProxyData(); + return true; } +void IODTNVRAM::initProxyData(void) +{ + IORegistryEntry *entry; + const char *key = "nvram-proxy-data"; + OSObject *prop; + OSData *data; + const void *bytes; + + entry = IORegistryEntry::fromPath("/chosen", gIODTPlane); + if (entry != 0) { + prop = entry->getProperty(key); + if (prop != 0) { + data = OSDynamicCast(OSData, prop); + if (data != 0) { + bytes = data->getBytesNoCopy(); + if ((bytes != 0) && (data->getLength() <= kIODTNVRAMImageSize)) { + bcopy(bytes, _nvramImage, data->getLength()); + initNVRAMImage(); + _isProxied = true; + } + } + } + entry->removeProperty(key); + entry->release(); + } +} + void IODTNVRAM::registerNVRAMController(IONVRAMController *nvram) +{ + if (_nvramController != 0) return; + + _nvramController = nvram; + + // race condition possible between + // IODTNVRAM and IONVRAMController (restore loses boot-args) + if (!_isProxied) { + _nvramController->read(0, _nvramImage, kIODTNVRAMImageSize); + initNVRAMImage(); + } else { + IOLockLock(_ofLock); + (void) syncVariables(); + IOLockUnlock(_ofLock); + } +} + +void IODTNVRAM::initNVRAMImage(void) { char partitionID[18]; UInt32 partitionOffset, partitionLength; @@ -67,81 +132,58 @@ void IODTNVRAM::registerNVRAMController(IONVRAMController *nvram) UInt32 currentLength, currentOffset = 0; OSNumber *partitionOffsetNumber, *partitionLengthNumber; - if (_nvramController != 0) return; - - _nvramController = nvram; - - _nvramController->read(0, _nvramImage, kIODTNVRAMImageSize); - // Find the offsets for the OF, XPRAM, NameRegistry and PanicInfo partitions. _ofPartitionOffset = 0xFFFFFFFF; - _xpramPartitionOffset = 0xFFFFFFFF; - _nrPartitionOffset = 0xFFFFFFFF; _piPartitionOffset = 0xFFFFFFFF; freePartitionOffset = 0xFFFFFFFF; freePartitionSize = 0; - if (getPlatform()->getBootROMType()) { - // Look through the partitions to find the OF, MacOS partitions. - while (currentOffset < kIODTNVRAMImageSize) { - currentLength = ((UInt16 *)(_nvramImage + currentOffset))[1] * 16; + + // Look through the partitions to find the OF, MacOS partitions. + while (currentOffset < kIODTNVRAMImageSize) { + currentLength = ((UInt16 *)(_nvramImage + currentOffset))[1] * 16; + + if (currentLength < 16) break; + partitionOffset = currentOffset + 16; + partitionLength = currentLength - 16; + if ((partitionOffset + partitionLength) > kIODTNVRAMImageSize) break; + + if (strncmp((const char *)_nvramImage + currentOffset + 4, + kIODTNVRAMOFPartitionName, 12) == 0) { + _ofPartitionOffset = partitionOffset; + _ofPartitionSize = partitionLength; + } else if (strncmp((const char *)_nvramImage + currentOffset + 4, + kIODTNVRAMXPRAMPartitionName, 12) == 0) { + } else if (strncmp((const char *)_nvramImage + currentOffset + 4, + kIODTNVRAMPanicInfoPartitonName, 12) == 0) { + _piPartitionOffset = partitionOffset; + _piPartitionSize = partitionLength; + } else if (strncmp((const char *)_nvramImage + currentOffset + 4, + kIODTNVRAMFreePartitionName, 12) == 0) { + freePartitionOffset = currentOffset; + freePartitionSize = currentLength; + } else { + // Construct the partition ID from the signature and name. + snprintf(partitionID, sizeof(partitionID), "0x%02x,", + *(UInt8 *)(_nvramImage + currentOffset)); + strncpy(partitionID + 5, + (const char *)(_nvramImage + currentOffset + 4), 12); + partitionID[17] = '\0'; - partitionOffset = currentOffset + 16; - partitionLength = currentLength - 16; + partitionOffsetNumber = OSNumber::withNumber(partitionOffset, 32); + partitionLengthNumber = OSNumber::withNumber(partitionLength, 32); - if (strncmp((const char *)_nvramImage + currentOffset + 4, - kIODTNVRAMOFPartitionName, 12) == 0) { - _ofPartitionOffset = partitionOffset; - _ofPartitionSize = partitionLength; - } else if (strncmp((const char *)_nvramImage + currentOffset + 4, - kIODTNVRAMXPRAMPartitionName, 12) == 0) { - _xpramPartitionOffset = partitionOffset; - _xpramPartitionSize = kIODTNVRAMXPRAMSize; - _nrPartitionOffset = _xpramPartitionOffset + _xpramPartitionSize; - _nrPartitionSize = partitionLength - _xpramPartitionSize; - } else if (strncmp((const char *)_nvramImage + currentOffset + 4, - kIODTNVRAMPanicInfoPartitonName, 12) == 0) { - _piPartitionOffset = partitionOffset; - _piPartitionSize = partitionLength; - } else if (strncmp((const char *)_nvramImage + currentOffset + 4, - kIODTNVRAMFreePartitionName, 12) == 0) { - freePartitionOffset = currentOffset; - freePartitionSize = currentLength; - } else { - // Construct the partition ID from the signature and name. - sprintf(partitionID, "0x%02x,", - *(UInt8 *)(_nvramImage + currentOffset)); - strncpy(partitionID + 5, - (const char *)(_nvramImage + currentOffset + 4), 12); - partitionID[17] = '\0'; - - partitionOffsetNumber = OSNumber::withNumber(partitionOffset, 32); - partitionLengthNumber = OSNumber::withNumber(partitionLength, 32); - - // Save the partition offset and length - _nvramPartitionOffsets->setObject(partitionID, partitionOffsetNumber); - _nvramPartitionLengths->setObject(partitionID, partitionLengthNumber); - - partitionOffsetNumber->release(); - partitionLengthNumber->release(); - } - currentOffset += currentLength; + // Save the partition offset and length + _nvramPartitionOffsets->setObject(partitionID, partitionOffsetNumber); + _nvramPartitionLengths->setObject(partitionID, partitionLengthNumber); + + partitionOffsetNumber->release(); + partitionLengthNumber->release(); } - } else { - // Use the fixed address for old world machines. - _ofPartitionOffset = 0x1800; - _ofPartitionSize = 0x0800; - _xpramPartitionOffset = 0x1300; - _xpramPartitionSize = 0x0100; - _nrPartitionOffset = 0x1400; - _nrPartitionSize = 0x0400; + currentOffset += currentLength; } if (_ofPartitionOffset != 0xFFFFFFFF) _ofImage = _nvramImage + _ofPartitionOffset; - if (_xpramPartitionOffset != 0xFFFFFFFF) - _xpramImage = _nvramImage + _xpramPartitionOffset; - if (_nrPartitionOffset != 0xFFFFFFFF) - _nrImage = _nvramImage + _nrPartitionOffset; if (_piPartitionOffset == 0xFFFFFFFF) { if (freePartitionSize > 0x20) { @@ -189,125 +231,179 @@ void IODTNVRAM::registerNVRAMController(IONVRAMController *nvram) // Set the partition checksum. _nvramImage[freePartitionOffset + 1] = calculatePartitionChecksum(_nvramImage + freePartitionOffset); - - // Set the nvram image as dirty. - _nvramImageDirty = true; + + if (_nvramController != 0) { + _nvramController->write(0, _nvramImage, kIODTNVRAMImageSize); + } } } else { _piImage = _nvramImage + _piPartitionOffset; } + _lastDeviceSync = 0; + _freshInterval = TRUE; // we will allow sync() even before the first 15 minutes have passed. + initOFVariables(); } -void IODTNVRAM::sync(void) +void IODTNVRAM::syncInternal(bool rateLimit) { - if (!_nvramImageDirty && !_ofImageDirty) return; - - // Don't try to sync OF Variables if the system has already paniced. - if (!_systemPaniced) syncOFVariables(); + // Don't try to perform controller operations if none has been registered. + if (_nvramController == 0) return; + + // Rate limit requests to sync. Drivers that need this rate limiting will + // shadow the data and only write to flash when they get a sync call + if (rateLimit && !safeToSync()) return; - _nvramController->write(0, _nvramImage, kIODTNVRAMImageSize); _nvramController->sync(); - - _nvramImageDirty = false; +} + +void IODTNVRAM::sync(void) +{ + syncInternal(false); } bool IODTNVRAM::serializeProperties(OSSerialize *s) const { - bool result; + bool result, hasPrivilege; UInt32 variablePerm; const OSSymbol *key; - OSDictionary *dict, *tmpDict = 0; + OSDictionary *dict; OSCollectionIterator *iter = 0; - if (_ofDict == 0) return false; - // Verify permissions. - result = IOUserClient::clientHasPrivilege(current_task(), kIONVRAMPrivilege); - if (result != kIOReturnSuccess) { - tmpDict = OSDictionary::withCapacity(1); - if (tmpDict == 0) return false; - - iter = OSCollectionIterator::withCollection(_ofDict); - if (iter == 0) return false; - + hasPrivilege = (kIOReturnSuccess == IOUserClient::clientHasPrivilege(current_task(), kIONVRAMPrivilege)); + + if (_ofDict == 0) { + /* No nvram. Return an empty dictionary. */ + dict = OSDictionary::withCapacity(1); + if (dict == 0) return false; + } else { + IOLockLock(_ofLock); + dict = OSDictionary::withDictionary(_ofDict); + IOLockUnlock(_ofLock); + if (dict == 0) return false; + + /* Copy properties with client privilege. */ + iter = OSCollectionIterator::withCollection(dict); + if (iter == 0) { + dict->release(); + return false; + } while (1) { key = OSDynamicCast(OSSymbol, iter->getNextObject()); if (key == 0) break; variablePerm = getOFVariablePerm(key); - if (variablePerm != kOFVariablePermRootOnly) { - tmpDict->setObject(key, _ofDict->getObject(key)); + if ((hasPrivilege || (variablePerm != kOFVariablePermRootOnly)) && + ( ! (variablePerm == kOFVariablePermKernelOnly && current_task() != kernel_task) ) +#if CONFIG_MACF + && (current_task() == kernel_task || mac_iokit_check_nvram_get(kauth_cred_get(), key->getCStringNoCopy()) == 0) +#endif + ) { } + else { + dict->removeObject(key); + iter->reset(); } } - dict = tmpDict; - } else { - dict = _ofDict; } - + result = dict->serialize(s); - - if (tmpDict != 0) tmpDict->release(); + + dict->release(); if (iter != 0) iter->release(); return result; } -OSObject *IODTNVRAM::getProperty(const OSSymbol *aKey) const +OSObject *IODTNVRAM::copyProperty(const OSSymbol *aKey) const { IOReturn result; UInt32 variablePerm; + OSObject *theObject; if (_ofDict == 0) return 0; // Verify permissions. + variablePerm = getOFVariablePerm(aKey); result = IOUserClient::clientHasPrivilege(current_task(), kIONVRAMPrivilege); if (result != kIOReturnSuccess) { - variablePerm = getOFVariablePerm(aKey); if (variablePerm == kOFVariablePermRootOnly) return 0; } - - return _ofDict->getObject(aKey); + if (variablePerm == kOFVariablePermKernelOnly && current_task() != kernel_task) return 0; + +#if CONFIG_MACF + if (current_task() != kernel_task && + mac_iokit_check_nvram_get(kauth_cred_get(), aKey->getCStringNoCopy()) != 0) + return 0; +#endif + + IOLockLock(_ofLock); + theObject = _ofDict->getObject(aKey); + if (theObject) theObject->retain(); + IOLockUnlock(_ofLock); + + return theObject; } -OSObject *IODTNVRAM::getProperty(const char *aKey) const +OSObject *IODTNVRAM::copyProperty(const char *aKey) const { const OSSymbol *keySymbol; OSObject *theObject = 0; - keySymbol = OSSymbol::withCStringNoCopy(aKey); + keySymbol = OSSymbol::withCString(aKey); if (keySymbol != 0) { - theObject = getProperty(keySymbol); + theObject = copyProperty(keySymbol); keySymbol->release(); } return theObject; } +OSObject *IODTNVRAM::getProperty(const OSSymbol *aKey) const +{ + OSObject *theObject; + + theObject = copyProperty(aKey); + if (theObject) theObject->release(); + + return theObject; +} + +OSObject *IODTNVRAM::getProperty(const char *aKey) const +{ + OSObject *theObject; + + theObject = copyProperty(aKey); + if (theObject) theObject->release(); + + return theObject; +} + bool IODTNVRAM::setProperty(const OSSymbol *aKey, OSObject *anObject) { bool result; UInt32 propType, propPerm; OSString *tmpString; - OSObject *propObject = 0; - + OSObject *propObject = 0, *oldObject; + if (_ofDict == 0) return false; - + // Verify permissions. - result = IOUserClient::clientHasPrivilege(current_task(), kIONVRAMPrivilege); - if (result != kIOReturnSuccess) { - propPerm = getOFVariablePerm(aKey); + propPerm = getOFVariablePerm(aKey); + if (IOUserClient::clientHasPrivilege(current_task(), kIONVRAMPrivilege) != kIOReturnSuccess) { if (propPerm != kOFVariablePermUserWrite) return false; } - - // Don't allow creation of new properties on old world machines. - if (getPlatform()->getBootROMType() == 0) { - if (_ofDict->getObject(aKey) == 0) return false; - } - + if (propPerm == kOFVariablePermKernelOnly && current_task() != kernel_task) return 0; + // Don't allow change of 'aapl,panic-info'. if (aKey->isEqualTo(kIODTNVRAMPanicInfoKey)) return false; + +#if CONFIG_MACF + if (current_task() != kernel_task && + mac_iokit_check_nvram_set(kauth_cred_get(), aKey->getCStringNoCopy(), anObject) != 0) + return false; +#endif // Make sure the object is of the correct type. propType = getOFVariableType(aKey); @@ -315,15 +411,15 @@ bool IODTNVRAM::setProperty(const OSSymbol *aKey, OSObject *anObject) case kOFVariableTypeBoolean : propObject = OSDynamicCast(OSBoolean, anObject); break; - + case kOFVariableTypeNumber : propObject = OSDynamicCast(OSNumber, anObject); break; - + case kOFVariableTypeString : propObject = OSDynamicCast(OSString, anObject); break; - + case kOFVariableTypeData : propObject = OSDynamicCast(OSData, anObject); if (propObject == 0) { @@ -335,19 +431,36 @@ bool IODTNVRAM::setProperty(const OSSymbol *aKey, OSObject *anObject) } break; } - + if (propObject == 0) return false; - + + IOLockLock(_ofLock); + + oldObject = _ofDict->getObject(aKey); + if (oldObject) { + oldObject->retain(); + } result = _ofDict->setObject(aKey, propObject); - + if (result) { - if (getPlatform()->getBootROMType() == 0) { - updateOWBootArgs(aKey, propObject); + if (syncVariables() != kIOReturnSuccess) { + if (oldObject) { + _ofDict->setObject(aKey, oldObject); + } + else { + _ofDict->removeObject(aKey); + } + (void) syncVariables(); + result = false; } - - _ofImageDirty = true; } - + + if (oldObject) { + oldObject->release(); + } + + IOLockUnlock(_ofLock); + return result; } @@ -359,25 +472,35 @@ void IODTNVRAM::removeProperty(const OSSymbol *aKey) if (_ofDict == 0) return; // Verify permissions. + propPerm = getOFVariablePerm(aKey); result = IOUserClient::clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator); if (result != kIOReturnSuccess) { - propPerm = getOFVariablePerm(aKey); if (propPerm != kOFVariablePermUserWrite) return; } - - // Don't allow removal of properties on old world machines. - if (getPlatform()->getBootROMType() == 0) return; + if (propPerm == kOFVariablePermKernelOnly && current_task() != kernel_task) return; // Don't allow change of 'aapl,panic-info'. if (aKey->isEqualTo(kIODTNVRAMPanicInfoKey)) return; +#if CONFIG_MACF + if (current_task() != kernel_task && + mac_iokit_check_nvram_delete(kauth_cred_get(), aKey->getCStringNoCopy()) != 0) + return; +#endif + // If the object exists, remove it from the dictionary. + + IOLockLock(_ofLock); result = _ofDict->getObject(aKey) != 0; if (result) { _ofDict->removeObject(aKey); - - _ofImageDirty = true; } + + if (result) { + (void) syncVariables(); + } + + IOLockUnlock(_ofLock); } IOReturn IODTNVRAM::setProperties(OSObject *properties) @@ -403,18 +526,33 @@ IOReturn IODTNVRAM::setProperties(OSObject *properties) if (object == 0) continue; if (key->isEqualTo(kIONVRAMDeletePropertyKey)) { - tmpStr = OSDynamicCast(OSString, object); - if (tmpStr != 0) { - key = OSSymbol::withString(tmpStr); - removeProperty(key); - key->release(); - result = true; - } else { - result = false; - } - } else { - result = setProperty(key, object); + tmpStr = OSDynamicCast(OSString, object); + if (tmpStr != 0) { + key = OSSymbol::withString(tmpStr); + removeProperty(key); + key->release(); + result = true; + } else { + result = false; + } + } else if(key->isEqualTo(kIONVRAMSyncNowPropertyKey) || key->isEqualTo(kIONVRAMForceSyncNowPropertyKey)) { + tmpStr = OSDynamicCast(OSString, object); + if (tmpStr != 0) { + + result = true; + + // We still want to throttle NVRAM commit rate for SyncNow. ForceSyncNow is provided as a really big hammer. + + syncInternal(key->isEqualTo(kIONVRAMSyncNowPropertyKey)); + + } else { + result = false; + } + } + else { + result = setProperty(key, object); } + } iter->release(); @@ -426,31 +564,13 @@ IOReturn IODTNVRAM::setProperties(OSObject *properties) IOReturn IODTNVRAM::readXPRAM(IOByteCount offset, UInt8 *buffer, IOByteCount length) { - if (_xpramImage == 0) return kIOReturnUnsupported; - - if ((buffer == 0) || (length == 0) || - (offset + length > kIODTNVRAMXPRAMSize)) - return kIOReturnBadArgument; - - bcopy(_nvramImage + _xpramPartitionOffset + offset, buffer, length); - - return kIOReturnSuccess; + return kIOReturnUnsupported; } IOReturn IODTNVRAM::writeXPRAM(IOByteCount offset, UInt8 *buffer, IOByteCount length) { - if (_xpramImage == 0) return kIOReturnUnsupported; - - if ((buffer == 0) || (length == 0) || - (offset + length > kIODTNVRAMXPRAMSize)) - return kIOReturnBadArgument; - - bcopy(buffer, _nvramImage + _xpramPartitionOffset + offset, length); - - _nvramImageDirty = true; - - return kIOReturnSuccess; + return kIOReturnUnsupported; } IOReturn IODTNVRAM::readNVRAMProperty(IORegistryEntry *entry, @@ -459,10 +579,7 @@ IOReturn IODTNVRAM::readNVRAMProperty(IORegistryEntry *entry, { IOReturn err; - if (getPlatform()->getBootROMType()) - err = readNVRAMPropertyType1(entry, name, value); - else - err = readNVRAMPropertyType0(entry, name, value); + err = readNVRAMPropertyType1(entry, name, value); return err; } @@ -473,10 +590,7 @@ IOReturn IODTNVRAM::writeNVRAMProperty(IORegistryEntry *entry, { IOReturn err; - if (getPlatform()->getBootROMType()) - err = writeNVRAMPropertyType1(entry, name, value); - else - err = writeNVRAMPropertyType0(entry, name, value); + err = writeNVRAMPropertyType1(entry, name, value); return err; } @@ -491,7 +605,7 @@ IOReturn IODTNVRAM::readNVRAMPartition(const OSSymbol *partitionID, IOByteCount length) { OSNumber *partitionOffsetNumber, *partitionLengthNumber; - UInt32 partitionOffset, partitionLength; + UInt32 partitionOffset, partitionLength, end; partitionOffsetNumber = (OSNumber *)_nvramPartitionOffsets->getObject(partitionID); @@ -504,8 +618,8 @@ IOReturn IODTNVRAM::readNVRAMPartition(const OSSymbol *partitionID, partitionOffset = partitionOffsetNumber->unsigned32BitValue(); partitionLength = partitionLengthNumber->unsigned32BitValue(); - if ((buffer == 0) || (length == 0) || - (offset + length > partitionLength)) + if (os_add_overflow(offset, length, &end)) return kIOReturnBadArgument; + if ((buffer == 0) || (length == 0) || (end > partitionLength)) return kIOReturnBadArgument; bcopy(_nvramImage + partitionOffset + offset, buffer, length); @@ -518,7 +632,7 @@ IOReturn IODTNVRAM::writeNVRAMPartition(const OSSymbol *partitionID, IOByteCount length) { OSNumber *partitionOffsetNumber, *partitionLengthNumber; - UInt32 partitionOffset, partitionLength; + UInt32 partitionOffset, partitionLength, end; partitionOffsetNumber = (OSNumber *)_nvramPartitionOffsets->getObject(partitionID); @@ -531,18 +645,20 @@ IOReturn IODTNVRAM::writeNVRAMPartition(const OSSymbol *partitionID, partitionOffset = partitionOffsetNumber->unsigned32BitValue(); partitionLength = partitionLengthNumber->unsigned32BitValue(); - if ((buffer == 0) || (length == 0) || - (offset + length > partitionLength)) + if (os_add_overflow(offset, length, &end)) return kIOReturnBadArgument; + if ((buffer == 0) || (length == 0) || (end > partitionLength)) return kIOReturnBadArgument; bcopy(buffer, _nvramImage + partitionOffset + offset, length); - _nvramImageDirty = true; + if (_nvramController != 0) { + _nvramController->write(0, _nvramImage, kIODTNVRAMImageSize); + } return kIOReturnSuccess; } -UInt32 IODTNVRAM::savePanicInfo(UInt8 *buffer, IOByteCount length) +IOByteCount IODTNVRAM::savePanicInfo(UInt8 *buffer, IOByteCount length) { if ((_piImage == 0) || (length <= 0)) return 0; @@ -555,10 +671,18 @@ UInt32 IODTNVRAM::savePanicInfo(UInt8 *buffer, IOByteCount length) // Save the Panic Info length. *(UInt32 *)_piImage = length; - _nvramImageDirty = true; - + if (_nvramController != 0) { + _nvramController->write(0, _nvramImage, kIODTNVRAMImageSize); + } + /* + * This prevents OF variables from being committed if the system has panicked + */ _systemPaniced = true; - + /* The call to sync() forces the NVRAM controller to write the panic info + * partition to NVRAM. + */ + sync(); + return length; } @@ -577,279 +701,141 @@ UInt8 IODTNVRAM::calculatePartitionChecksum(UInt8 *partitionHeader) return csum; } -struct OWVariablesHeader { - UInt16 owMagic; - UInt8 owVersion; - UInt8 owPages; - UInt16 owChecksum; - UInt16 owHere; - UInt16 owTop; - UInt16 owNext; - UInt32 owFlags; - UInt32 owNumbers[9]; - struct { - UInt16 offset; - UInt16 length; - } owStrings[10]; -}; -typedef struct OWVariablesHeader OWVariablesHeader; - IOReturn IODTNVRAM::initOFVariables(void) { - UInt32 cnt, propOffset, propType; + UInt32 cnt; UInt8 *propName, *propData; UInt32 propNameLength, propDataLength; const OSSymbol *propSymbol; OSObject *propObject; - OWVariablesHeader *owHeader; if (_ofImage == 0) return kIOReturnNotReady; - _ofDict = OSDictionary::withCapacity(1); - if (_ofDict == 0) return kIOReturnNoMemory; + _ofDict = OSDictionary::withCapacity(1); + _ofLock = IOLockAlloc(); + if (!_ofDict || !_ofLock) return kIOReturnNoMemory; - if (getPlatform()->getBootROMType()) { - cnt = 0; - while (cnt < _ofPartitionSize) { - // Break if there is no name. - if (_ofImage[cnt] == '\0') break; - - // Find the length of the name. - propName = _ofImage + cnt; - for (propNameLength = 0; (cnt + propNameLength) < _ofPartitionSize; - propNameLength++) { - if (_ofImage[cnt + propNameLength] == '=') break; - } - - // Break if the name goes past the end of the partition. - if ((cnt + propNameLength) >= _ofPartitionSize) break; - cnt += propNameLength + 1; - - propData = _ofImage + cnt; - for (propDataLength = 0; (cnt + propDataLength) < _ofPartitionSize; - propDataLength++) { - if (_ofImage[cnt + propDataLength] == '\0') break; - } - - // Break if the data goes past the end of the partition. - if ((cnt + propDataLength) >= _ofPartitionSize) break; - cnt += propDataLength + 1; - - if (convertPropToObject(propName, propNameLength, - propData, propDataLength, - &propSymbol, &propObject)) { - _ofDict->setObject(propSymbol, propObject); - propSymbol->release(); - propObject->release(); - } - } + cnt = 0; + while (cnt < _ofPartitionSize) { + // Break if there is no name. + if (_ofImage[cnt] == '\0') break; - // Create the boot-args property if it is not in the dictionary. - if (_ofDict->getObject("boot-args") == 0) { - propObject = OSString::withCStringNoCopy(""); - if (propObject != 0) { - _ofDict->setObject("boot-args", propObject); - propObject->release(); - } + // Find the length of the name. + propName = _ofImage + cnt; + for (propNameLength = 0; (cnt + propNameLength) < _ofPartitionSize; + propNameLength++) { + if (_ofImage[cnt + propNameLength] == '=') break; } - // Create the 'aapl,panic-info' property if needed. - if (_piImage != 0) { - propDataLength = *(UInt32 *)_piImage; - if ((propDataLength != 0) && (propDataLength < (_piPartitionSize - 4))) { - propObject = OSData::withBytes(_piImage + 4, propDataLength); - _ofDict->setObject(kIODTNVRAMPanicInfoKey, propObject); - propObject->release(); - - // Clear the length from _piImage and mark dirty. - *(UInt32 *)_piImage = 0; - _nvramImageDirty = true; - } - } - } else { - owHeader = (OWVariablesHeader *)_ofImage; - if (!validateOWChecksum(_ofImage)) { - _ofDict->release(); - _ofDict = 0; - return kIOReturnBadMedia; + // Break if the name goes past the end of the partition. + if ((cnt + propNameLength) >= _ofPartitionSize) break; + cnt += propNameLength + 1; + + propData = _ofImage + cnt; + for (propDataLength = 0; (cnt + propDataLength) < _ofPartitionSize; + propDataLength++) { + if (_ofImage[cnt + propDataLength] == '\0') break; } - cnt = 0; - while (1) { - if (!getOWVariableInfo(cnt++, &propSymbol, &propType, &propOffset)) - break; - - switch (propType) { - case kOFVariableTypeBoolean : - propObject = OSBoolean::withBoolean(owHeader->owFlags & propOffset); - break; - - case kOFVariableTypeNumber : - propObject = OSNumber::withNumber(owHeader->owNumbers[propOffset], 32); - break; - - case kOFVariableTypeString : - propData = _ofImage + owHeader->owStrings[propOffset].offset - - _ofPartitionOffset; - propDataLength = owHeader->owStrings[propOffset].length; - propName = IONew(UInt8, propDataLength + 1); - if (propName != 0) { - strncpy((char *)propName, (const char *)propData, propDataLength); - propName[propDataLength] = '\0'; - propObject = OSString::withCString((const char *)propName); - IODelete(propName, UInt8, propDataLength + 1); - } - break; - } - - if (propObject == 0) break; - + // Break if the data goes past the end of the partition. + if ((cnt + propDataLength) >= _ofPartitionSize) break; + cnt += propDataLength + 1; + + if (convertPropToObject(propName, propNameLength, + propData, propDataLength, + &propSymbol, &propObject)) { _ofDict->setObject(propSymbol, propObject); propSymbol->release(); propObject->release(); } - - // Create the boot-args property. - propSymbol = OSSymbol::withCString("boot-command"); - if (propSymbol != 0) { - propObject = _ofDict->getObject(propSymbol); - if (propObject != 0) { - updateOWBootArgs(propSymbol, propObject); - } - propSymbol->release(); + } + + // Create the boot-args property if it is not in the dictionary. + if (_ofDict->getObject("boot-args") == 0) { + propObject = OSString::withCStringNoCopy(""); + if (propObject != 0) { + _ofDict->setObject("boot-args", propObject); + propObject->release(); } } + if (_piImage != 0) { + propDataLength = *(UInt32 *)_piImage; + if ((propDataLength != 0) && (propDataLength <= (_piPartitionSize - 4))) { + propObject = OSData::withBytes(_piImage + 4, propDataLength); + _ofDict->setObject(kIODTNVRAMPanicInfoKey, propObject); + propObject->release(); + + // Clear the length from _piImage and mark dirty. + *(UInt32 *)_piImage = 0; + if (_nvramController != 0) { + _nvramController->write(0, _nvramImage, kIODTNVRAMImageSize); + } + } + } + return kIOReturnSuccess; } IOReturn IODTNVRAM::syncOFVariables(void) +{ + return kIOReturnUnsupported; +} + +IOReturn IODTNVRAM::syncVariables(void) { bool ok; - UInt32 cnt, length, maxLength; - UInt32 curOffset, tmpOffset, tmpType, tmpDataLength; + UInt32 length, maxLength; UInt8 *buffer, *tmpBuffer; - const UInt8 *tmpData; const OSSymbol *tmpSymbol; OSObject *tmpObject; - OSBoolean *tmpBoolean; - OSNumber *tmpNumber; - OSString *tmpString; OSCollectionIterator *iter; - OWVariablesHeader *owHeader, *owHeaderOld; - - if ((_ofImage == 0) || (_ofDict == 0)) return kIOReturnNotReady; - - if (!_ofImageDirty) return kIOReturnSuccess; - - if (getPlatform()->getBootROMType()) { - buffer = tmpBuffer = IONew(UInt8, _ofPartitionSize); - if (buffer == 0) return kIOReturnNoMemory; - bzero(buffer, _ofPartitionSize); - - ok = true; - maxLength = _ofPartitionSize; - - iter = OSCollectionIterator::withCollection(_ofDict); - if (iter == 0) ok = false; - - while (ok) { - tmpSymbol = OSDynamicCast(OSSymbol, iter->getNextObject()); - if (tmpSymbol == 0) break; - - // Don't save 'aapl,panic-info'. - if (tmpSymbol->isEqualTo(kIODTNVRAMPanicInfoKey)) continue; - - tmpObject = _ofDict->getObject(tmpSymbol); - - length = maxLength; - ok = convertObjectToProp(tmpBuffer, &length, tmpSymbol, tmpObject); - if (ok) { - tmpBuffer += length; - maxLength -= length; - } - } - iter->release(); - - if (ok) { - bcopy(buffer, _ofImage, _ofPartitionSize); - } - - IODelete(buffer, UInt8, _ofPartitionSize); - - if (!ok) return kIOReturnBadArgument; - } else { - buffer = IONew(UInt8, _ofPartitionSize); - if (buffer == 0) return kIOReturnNoMemory; - bzero(buffer, _ofPartitionSize); - - owHeader = (OWVariablesHeader *)buffer; - owHeaderOld = (OWVariablesHeader *)_ofImage; - - owHeader->owMagic = owHeaderOld->owMagic; - owHeader->owVersion = owHeaderOld->owVersion; - owHeader->owPages = owHeaderOld->owPages; - - curOffset = _ofPartitionSize; - - ok = true; - cnt = 0; - while (ok) { - if (!getOWVariableInfo(cnt++, &tmpSymbol, &tmpType, &tmpOffset)) - break; - - tmpObject = _ofDict->getObject(tmpSymbol); - - switch (tmpType) { - case kOFVariableTypeBoolean : - tmpBoolean = OSDynamicCast(OSBoolean, tmpObject); - if (tmpBoolean->getValue()) owHeader->owFlags |= tmpOffset; - break; - - case kOFVariableTypeNumber : - tmpNumber = OSDynamicCast(OSNumber, tmpObject); - owHeader->owNumbers[tmpOffset] = tmpNumber->unsigned32BitValue(); - break; - - case kOFVariableTypeString : - tmpString = OSDynamicCast(OSString, tmpObject); - tmpData = (const UInt8 *)tmpString->getCStringNoCopy(); - tmpDataLength = tmpString->getLength(); - - if ((curOffset - tmpDataLength) < sizeof(OWVariablesHeader)) { - ok = false; - break; - } - - owHeader->owStrings[tmpOffset].length = tmpDataLength; - curOffset -= tmpDataLength; - owHeader->owStrings[tmpOffset].offset = curOffset + _ofPartitionOffset; - if (tmpDataLength != 0) - bcopy(tmpData, buffer + curOffset, tmpDataLength); - break; - } - } - + + IOLockAssert(_ofLock, kIOLockAssertOwned); + + if ((_ofImage == 0) || (_ofDict == 0) || _systemPaniced) return kIOReturnNotReady; + + buffer = tmpBuffer = IONew(UInt8, _ofPartitionSize); + if (buffer == 0) return kIOReturnNoMemory; + bzero(buffer, _ofPartitionSize); + + ok = true; + maxLength = _ofPartitionSize; + + iter = OSCollectionIterator::withCollection(_ofDict); + if (iter == 0) ok = false; + + while (ok) { + tmpSymbol = OSDynamicCast(OSSymbol, iter->getNextObject()); + if (tmpSymbol == 0) break; + + // Don't save 'aapl,panic-info'. + if (tmpSymbol->isEqualTo(kIODTNVRAMPanicInfoKey)) continue; + + tmpObject = _ofDict->getObject(tmpSymbol); + + length = maxLength; + ok = convertObjectToProp(tmpBuffer, &length, tmpSymbol, tmpObject); if (ok) { - owHeader->owHere = _ofPartitionOffset + sizeof(OWVariablesHeader); - owHeader->owTop = _ofPartitionOffset + curOffset; - owHeader->owNext = 0; - - owHeader->owChecksum = 0; - owHeader->owChecksum = ~generateOWChecksum(buffer); - - bcopy(buffer, _ofImage, _ofPartitionSize); + tmpBuffer += length; + maxLength -= length; } - - IODelete(buffer, UInt8, _ofPartitionSize); - - if (!ok) return kIOReturnBadArgument; } - - _ofImageDirty = false; - _nvramImageDirty = true; - - return kIOReturnSuccess; + iter->release(); + + if (ok) { + bcopy(buffer, _ofImage, _ofPartitionSize); + } + + IODelete(buffer, UInt8, _ofPartitionSize); + + if (!ok) return kIOReturnBadArgument; + + if (_nvramController != 0) { + return _nvramController->write(0, _nvramImage, kIODTNVRAMImageSize); + } + + return kIOReturnNotReady; } struct OFVariable { @@ -865,6 +851,7 @@ enum { kOWVariableOffsetString = 17 }; +static const OFVariable gOFVariables[] = { {"little-endian?", kOFVariableTypeBoolean, kOFVariablePermUserRead, 0}, {"real-mode?", kOFVariableTypeBoolean, kOFVariablePermUserRead, 1}, @@ -912,12 +899,23 @@ OFVariable gOFVariables[] = { {"security-mode", kOFVariableTypeString, kOFVariablePermUserRead, -1}, {"security-password", kOFVariableTypeData, kOFVariablePermRootOnly, -1}, {"boot-image", kOFVariableTypeData, kOFVariablePermUserWrite, -1}, + {"com.apple.System.fp-state", kOFVariableTypeData, kOFVariablePermKernelOnly, -1}, +#if CONFIG_EMBEDDED + {"backlight-level", kOFVariableTypeData, kOFVariablePermUserWrite, -1}, + {"com.apple.System.sep.art", kOFVariableTypeData, kOFVariablePermKernelOnly, -1}, + {"com.apple.System.boot-nonce", kOFVariableTypeString, kOFVariablePermKernelOnly, -1}, + {"darkboot", kOFVariableTypeBoolean, kOFVariablePermUserWrite, -1}, + {"acc-mb-ld-lifetime", kOFVariableTypeNumber, kOFVariablePermKernelOnly, -1}, + {"acc-cm-override-charger-count", kOFVariableTypeNumber, kOFVariablePermKernelOnly, -1}, + {"acc-cm-override-count", kOFVariableTypeNumber, kOFVariablePermKernelOnly, -1}, + {"enter-tdm-mode", kOFVariableTypeBoolean, kOFVariablePermUserWrite, -1}, +#endif {0, kOFVariableTypeData, kOFVariablePermUserRead, -1} }; UInt32 IODTNVRAM::getOFVariableType(const OSSymbol *propSymbol) const { - OFVariable *ofVar; + const OFVariable *ofVar; ofVar = gOFVariables; while (1) { @@ -931,7 +929,7 @@ UInt32 IODTNVRAM::getOFVariableType(const OSSymbol *propSymbol) const UInt32 IODTNVRAM::getOFVariablePerm(const OSSymbol *propSymbol) const { - OFVariable *ofVar; + const OFVariable *ofVar; ofVar = gOFVariables; while (1) { @@ -946,7 +944,7 @@ UInt32 IODTNVRAM::getOFVariablePerm(const OSSymbol *propSymbol) const bool IODTNVRAM::getOWVariableInfo(UInt32 variableNumber, const OSSymbol **propSymbol, UInt32 *propType, UInt32 *propOffset) { - OFVariable *ofVar; + const OFVariable *ofVar; ofVar = gOFVariables; while (1) { @@ -1039,7 +1037,7 @@ bool IODTNVRAM::convertObjectToProp(UInt8 *buffer, UInt32 *length, const OSSymbol *propSymbol, OSObject *propObject) { const UInt8 *propName; - UInt32 propNameLength, propDataLength; + UInt32 propNameLength, propDataLength, remaining; UInt32 propType, tmpValue; OSBoolean *tmpBoolean = 0; OSNumber *tmpNumber = 0; @@ -1082,31 +1080,31 @@ bool IODTNVRAM::convertObjectToProp(UInt8 *buffer, UInt32 *length, if ((propNameLength + propDataLength + 2) > *length) return false; // Copy the property name equal sign. - sprintf((char *)buffer, "%s=", propName); - buffer += propNameLength + 1; - + buffer += snprintf((char *)buffer, *length, "%s=", propName); + remaining = *length - propNameLength - 1; + switch (propType) { case kOFVariableTypeBoolean : if (tmpBoolean->getValue()) { - strcpy((char *)buffer, "true"); + strlcpy((char *)buffer, "true", remaining); } else { - strcpy((char *)buffer, "false"); + strlcpy((char *)buffer, "false", remaining); } break; case kOFVariableTypeNumber : tmpValue = tmpNumber->unsigned32BitValue(); if (tmpValue == 0xFFFFFFFF) { - strcpy((char *)buffer, "-1"); + strlcpy((char *)buffer, "-1", remaining); } else if (tmpValue < 1000) { - sprintf((char *)buffer, "%ld", tmpValue); + snprintf((char *)buffer, remaining, "%d", (uint32_t)tmpValue); } else { - sprintf((char *)buffer, "0x%lx", tmpValue); + snprintf((char *)buffer, remaining, "0x%x", (uint32_t)tmpValue); } break; case kOFVariableTypeString : - strcpy((char *)buffer, tmpString->getCStringNoCopy()); + strlcpy((char *)buffer, tmpString->getCStringNoCopy(), remaining); break; case kOFVariableTypeData : @@ -1199,9 +1197,8 @@ void IODTNVRAM::updateOWBootArgs(const OSSymbol *key, OSObject *value) tmpData = IONew(UInt8, tmpDataLength + 1); if (tmpData == 0) return; - strncpy((char *)tmpData, (const char *)bootCommandData, cnt); - tmpData[cnt] = '\0'; - strcat((char *)tmpData, (const char *)bootArgsData); + cnt -= strlcpy((char *)tmpData, (const char *)bootCommandData, cnt); + strlcat((char *)tmpData, (const char *)bootArgsData, cnt); bootCommand = OSString::withCString((const char *)tmpData); if (bootCommand != 0) { @@ -1219,55 +1216,8 @@ void IODTNVRAM::updateOWBootArgs(const OSSymbol *key, OSObject *value) } } - -// Private methods for Name Registry access. - -enum { - kMaxNVNameLength = 4, - kMaxNVDataLength = 8 -}; - -#pragma options align=mac68k -struct NVRAMProperty -{ - IONVRAMDescriptor header; - UInt8 nameLength; - UInt8 name[ kMaxNVNameLength ]; - UInt8 dataLength; - UInt8 data[ kMaxNVDataLength ]; -}; -#pragma options align=reset - bool IODTNVRAM::searchNVRAMProperty(IONVRAMDescriptor *hdr, UInt32 *where) { - UInt32 offset; - SInt32 nvEnd; - - nvEnd = *((UInt16 *)_nrImage); - if(getPlatform()->getBootROMType()) { - // on NewWorld, offset to partition start - nvEnd -= 0x100; - } else { - // on old world, absolute - nvEnd -= _nrPartitionOffset; - } - if((nvEnd < 0) || (nvEnd >= kIODTNVRAMNameRegistrySize)) - nvEnd = 2; - - offset = 2; - while ((offset + sizeof(NVRAMProperty)) <= (UInt32)nvEnd) { - if (bcmp(_nrImage + offset, hdr, sizeof(*hdr)) == 0) { - *where = offset; - return true; - } - offset += sizeof(NVRAMProperty); - } - - if ((nvEnd + sizeof(NVRAMProperty)) <= kIODTNVRAMNameRegistrySize) - *where = nvEnd; - else - *where = 0; - return false; } @@ -1275,88 +1225,18 @@ IOReturn IODTNVRAM::readNVRAMPropertyType0(IORegistryEntry *entry, const OSSymbol **name, OSData **value) { - IONVRAMDescriptor hdr; - NVRAMProperty *prop; - IOByteCount length; - UInt32 offset; - IOReturn err; - char nameBuf[kMaxNVNameLength + 1]; - - if (_nrImage == 0) return kIOReturnUnsupported; - if ((entry == 0) || (name == 0) || (value == 0)) return kIOReturnBadArgument; - - err = IODTMakeNVDescriptor(entry, &hdr); - if (err != kIOReturnSuccess) return err; - - if (searchNVRAMProperty(&hdr, &offset)) { - prop = (NVRAMProperty *)(_nrImage + offset); - - length = prop->nameLength; - if (length > kMaxNVNameLength) length = kMaxNVNameLength; - strncpy(nameBuf, (const char *)prop->name, length); - nameBuf[length] = 0; - *name = OSSymbol::withCString(nameBuf); - - length = prop->dataLength; - if (length > kMaxNVDataLength) length = kMaxNVDataLength; - *value = OSData::withBytes(prop->data, length); - - if ((*name != 0) && (*value != 0)) return kIOReturnSuccess; - else return kIOReturnNoMemory; - } - - return kIOReturnNoResources; + return kIOReturnUnsupported; } + IOReturn IODTNVRAM::writeNVRAMPropertyType0(IORegistryEntry *entry, const OSSymbol *name, OSData *value) { - IONVRAMDescriptor hdr; - NVRAMProperty *prop; - IOByteCount nameLength; - IOByteCount dataLength; - UInt32 offset; - IOReturn err; - UInt16 nvLength; - bool exists; - - if (_nrImage == 0) return kIOReturnUnsupported; - if ((entry == 0) || (name == 0) || (value == 0)) return kIOReturnBadArgument; - - nameLength = name->getLength(); - dataLength = value->getLength(); - if (nameLength > kMaxNVNameLength) return kIOReturnNoSpace; - if (dataLength > kMaxNVDataLength) return kIOReturnNoSpace; - - err = IODTMakeNVDescriptor(entry, &hdr); - if (err != kIOReturnSuccess) return err; - - exists = searchNVRAMProperty(&hdr, &offset); - if (offset == 0) return kIOReturnNoMemory; - - prop = (NVRAMProperty *)(_nrImage + offset); - if (!exists) bcopy(&hdr, &prop->header, sizeof(hdr)); - - prop->nameLength = nameLength; - bcopy(name->getCStringNoCopy(), prop->name, nameLength); - prop->dataLength = dataLength; - bcopy(value->getBytesNoCopy(), prop->data, dataLength); - - if (!exists) { - nvLength = offset + sizeof(NVRAMProperty); - if (getPlatform()->getBootROMType()) - nvLength += 0x100; - else - nvLength += _nrPartitionOffset; - *((UInt16 *)_nrImage) = nvLength; - } - - _nvramImageDirty = true; - - return err; + return kIOReturnUnsupported; } + OSData *IODTNVRAM::unescapeBytesToData(const UInt8 *bytes, UInt32 length) { OSData *data = 0; @@ -1468,7 +1348,11 @@ IOReturn IODTNVRAM::readNVRAMPropertyType1(IORegistryEntry *entry, UInt8 byte; if (_ofDict == 0) return err; + + IOLockLock(_ofLock); data = OSDynamicCast(OSData, _ofDict->getObject(_registryPropertiesKey)); + IOLockUnlock(_ofLock); + if (data == 0) return err; startPtr = (const UInt8 *) data->getBytesNoCopy(); @@ -1518,7 +1402,7 @@ IOReturn IODTNVRAM::writeNVRAMPropertyType1(IORegistryEntry *entry, const OSSymbol *propName, OSData *value) { - OSData *oldData; + OSData *oldData, *escapedData; OSData *data = 0; const UInt8 *startPtr; const UInt8 *propStart; @@ -1538,11 +1422,14 @@ IOReturn IODTNVRAM::writeNVRAMPropertyType1(IORegistryEntry *entry, // copy over existing properties for other entries + IOLockLock(_ofLock); + oldData = OSDynamicCast(OSData, _ofDict->getObject(_registryPropertiesKey)); if (oldData) { + startPtr = (const UInt8 *) oldData->getBytesNoCopy(); endPtr = startPtr + oldData->getLength(); - + propStart = startPtr; wherePtr = startPtr; while (wherePtr < endPtr) { @@ -1570,7 +1457,7 @@ IOReturn IODTNVRAM::writeNVRAMPropertyType1(IORegistryEntry *entry, nvPath = 0; nvName = 0; } - + startPtr = wherePtr; } } @@ -1582,62 +1469,96 @@ IOReturn IODTNVRAM::writeNVRAMPropertyType1(IORegistryEntry *entry, data = OSData::withData(oldData); else data = OSData::withCapacity(16); - if (!data) - return kIOReturnNoMemory; + if (!data) ok = false; } - if (value && value->getLength()) { - // get entries in path - OSArray *array = OSArray::withCapacity(5); - if (!array) { - data->release(); - return kIOReturnNoMemory; - } - do - array->setObject(entry); - while ((entry = entry->getParentEntry(gIODTPlane))); - - // append path - for (int i = array->getCount() - 3; - (entry = (IORegistryEntry *) array->getObject(i)); - i--) { - - name = entry->getName(gIODTPlane); - comp = entry->getLocation(gIODTPlane); - if( comp && (0 == strcmp("pci", name)) - && (0 == strcmp("80000000", comp))) { - // yosemite hack - comp = "/pci@80000000"; - } else { - if (comp) - ok &= data->appendBytes("/@", 2); - else { - if (!name) - continue; - ok &= data->appendByte('/', 1); - comp = name; - } - } - ok &= data->appendBytes(comp, strlen(comp)); - } - ok &= data->appendByte(0, 1); - array->release(); - - // append prop name - ok &= data->appendBytes(propName->getCStringNoCopy(), propName->getLength() + 1); - - // append escaped data - oldData = escapeDataToData(value); - ok &= (oldData != 0); - if (ok) - ok &= data->appendBytes(oldData); - } + if (ok && value && value->getLength()) do { + // get entries in path + OSArray *array = OSArray::withCapacity(5); + if (!array) { + ok = false; + break; + } + do + array->setObject(entry); + while ((entry = entry->getParentEntry(gIODTPlane))); + + // append path + for (int i = array->getCount() - 3; + (entry = (IORegistryEntry *) array->getObject(i)); + i--) { + + name = entry->getName(gIODTPlane); + comp = entry->getLocation(gIODTPlane); + if (comp) ok &= data->appendBytes("/@", 2); + else { + if (!name) continue; + ok &= data->appendByte('/', 1); + comp = name; + } + ok &= data->appendBytes(comp, strlen(comp)); + } + ok &= data->appendByte(0, 1); + array->release(); + + // append prop name + ok &= data->appendBytes(propName->getCStringNoCopy(), propName->getLength() + 1); + + // append escaped data + escapedData = escapeDataToData(value); + ok &= (escapedData != 0); + if (ok) ok &= data->appendBytes(escapedData); + + } while (false); + + oldData->retain(); if (ok) { ok = _ofDict->setObject(_registryPropertiesKey, data); - if (ok) - _ofImageDirty = true; } - data->release(); + + if (data) data->release(); + + if (ok) { + if (syncVariables() != kIOReturnSuccess) { + if (oldData) { + _ofDict->setObject(_registryPropertiesKey, oldData); + } + else { + _ofDict->removeObject(_registryPropertiesKey); + } + (void) syncVariables(); + ok = false; + } + } + + if (oldData) { + oldData->release(); + } + + IOLockUnlock(_ofLock); return ok ? kIOReturnSuccess : kIOReturnNoMemory; } + +bool IODTNVRAM::safeToSync(void) +{ + AbsoluteTime delta; + UInt64 delta_ns; + SInt32 delta_secs; + + // delta interval went by + clock_get_uptime(&delta); + + // Figure it in seconds. + absolutetime_to_nanoseconds(delta, &delta_ns); + delta_secs = (SInt32)(delta_ns / NSEC_PER_SEC); + + if ((delta_secs > (_lastDeviceSync + MIN_SYNC_NOW_INTERVAL)) || _freshInterval) + { + _lastDeviceSync = delta_secs; + _freshInterval = FALSE; + return TRUE; + } + + return FALSE; +}