X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/43866e378188c25dd1e2208016ab3cbeb086ae6c..d26ffc64f583ab2d29df48f13518685602bc8832:/iokit/Kernel/IONVRAM.cpp diff --git a/iokit/Kernel/IONVRAM.cpp b/iokit/Kernel/IONVRAM.cpp index fb6ceb5cd..94d6b75dd 100644 --- a/iokit/Kernel/IONVRAM.cpp +++ b/iokit/Kernel/IONVRAM.cpp @@ -1,16 +1,20 @@ /* - * 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@ - * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * * 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. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * 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. + * + * 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 @@ -20,7 +24,7 @@ * 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 @@ -28,9 +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) @@ -55,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; @@ -66,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) { @@ -188,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; } -bool IODTNVRAM::serializeProperties(OSSerialize *serialize) const +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(), kIOClientPrivilegeAdministrator); - 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(serialize); - - if (tmpDict != 0) tmpDict->release(); + + result = dict->serialize(s); + + 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. - result = IOUserClient::clientHasPrivilege(current_task(), "root"); + 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(), "root"); - 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); @@ -314,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) { @@ -334,27 +431,84 @@ 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; } +void IODTNVRAM::removeProperty(const OSSymbol *aKey) +{ + bool result; + UInt32 propPerm; + + if (_ofDict == 0) return; + + // Verify permissions. + propPerm = getOFVariablePerm(aKey); + result = IOUserClient::clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator); + if (result != kIOReturnSuccess) { + if (propPerm != kOFVariablePermUserWrite) 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); + } + + if (result) { + (void) syncVariables(); + } + + IOLockUnlock(_ofLock); +} + IOReturn IODTNVRAM::setProperties(OSObject *properties) { bool result = true; OSObject *object; const OSSymbol *key; + const OSString *tmpStr; OSDictionary *dict; OSCollectionIterator *iter; @@ -371,7 +525,34 @@ IOReturn IODTNVRAM::setProperties(OSObject *properties) object = dict->getObject(key); if (object == 0) continue; - result = setProperty(key, object); + 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 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(); @@ -383,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 < 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 < 0) || - (offset + length > kIODTNVRAMXPRAMSize)) - return kIOReturnBadArgument; - - bcopy(buffer, _nvramImage + _xpramPartitionOffset + offset, length); - - _nvramImageDirty = true; - - return kIOReturnSuccess; + return kIOReturnUnsupported; } IOReturn IODTNVRAM::readNVRAMProperty(IORegistryEntry *entry, @@ -416,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; } @@ -430,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; } @@ -448,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); @@ -461,8 +618,8 @@ IOReturn IODTNVRAM::readNVRAMPartition(const OSSymbol *partitionID, partitionOffset = partitionOffsetNumber->unsigned32BitValue(); partitionLength = partitionLengthNumber->unsigned32BitValue(); - if ((buffer == 0) || (length <= 0) || (offset < 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); @@ -475,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); @@ -488,18 +645,20 @@ IOReturn IODTNVRAM::writeNVRAMPartition(const OSSymbol *partitionID, partitionOffset = partitionOffsetNumber->unsigned32BitValue(); partitionLength = partitionLengthNumber->unsigned32BitValue(); - if ((buffer == 0) || (length <= 0) || (offset < 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; @@ -512,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; } @@ -534,285 +701,148 @@ 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; - UInt8 *buffer, *tmpBuffer, *tmpData; + UInt32 length, maxLength; + UInt8 *buffer, *tmpBuffer; 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 = (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 { - char *variableName; - UInt32 variableType; - UInt32 variablePerm; - SInt32 variableOffset; + const char *variableName; + UInt32 variableType; + UInt32 variablePerm; + SInt32 variableOffset; }; typedef struct OFVariable OFVariable; @@ -821,6 +851,7 @@ enum { kOWVariableOffsetString = 17 }; +static const OFVariable gOFVariables[] = { {"little-endian?", kOFVariableTypeBoolean, kOFVariablePermUserRead, 0}, {"real-mode?", kOFVariableTypeBoolean, kOFVariablePermUserRead, 1}, @@ -867,12 +898,24 @@ OFVariable gOFVariables[] = { {"aapl,pci", kOFVariableTypeData, kOFVariablePermRootOnly, -1}, {"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) { @@ -886,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) { @@ -901,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) { @@ -993,15 +1036,15 @@ bool IODTNVRAM::convertPropToObject(UInt8 *propName, UInt32 propNameLength, bool IODTNVRAM::convertObjectToProp(UInt8 *buffer, UInt32 *length, const OSSymbol *propSymbol, OSObject *propObject) { - UInt8 *propName; - UInt32 propNameLength, propDataLength; + const UInt8 *propName; + UInt32 propNameLength, propDataLength, remaining; UInt32 propType, tmpValue; OSBoolean *tmpBoolean = 0; OSNumber *tmpNumber = 0; OSString *tmpString = 0; OSData *tmpData = 0; - propName = (UInt8 *)propSymbol->getCStringNoCopy(); + propName = (const UInt8 *)propSymbol->getCStringNoCopy(); propNameLength = propSymbol->getLength(); propType = getOFVariableType(propSymbol); @@ -1037,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 : @@ -1106,11 +1149,12 @@ bool IODTNVRAM::validateOWChecksum(UInt8 *buffer) void IODTNVRAM::updateOWBootArgs(const OSSymbol *key, OSObject *value) { - bool wasBootArgs, bootr = false; - UInt32 cnt; - OSString *tmpString, *bootCommand, *bootArgs = 0; - UInt8 *bootCommandData, *bootArgsData, *tmpData; - UInt32 bootCommandDataLength, bootArgsDataLength, tmpDataLength; + bool wasBootArgs, bootr = false; + UInt32 cnt; + OSString *tmpString, *bootCommand, *bootArgs = 0; + const UInt8 *bootCommandData, *bootArgsData; + UInt8 *tmpData; + UInt32 bootCommandDataLength, bootArgsDataLength, tmpDataLength; tmpString = OSDynamicCast(OSString, value); if (tmpString == 0) return; @@ -1125,7 +1169,7 @@ void IODTNVRAM::updateOWBootArgs(const OSSymbol *key, OSObject *value) if (bootCommand == 0) return; } else return; - bootCommandData = (UInt8 *)bootCommand->getCStringNoCopy(); + bootCommandData = (const UInt8 *)bootCommand->getCStringNoCopy(); bootCommandDataLength = bootCommand->getLength(); if (bootCommandData == 0) return; @@ -1145,7 +1189,7 @@ void IODTNVRAM::updateOWBootArgs(const OSSymbol *key, OSObject *value) } if (wasBootArgs) { - bootArgsData = (UInt8 *)bootArgs->getCStringNoCopy(); + bootArgsData = (const UInt8 *)bootArgs->getCStringNoCopy(); bootArgsDataLength = bootArgs->getLength(); if (bootArgsData == 0) return; @@ -1153,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) { @@ -1173,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; } @@ -1229,89 +1225,19 @@ 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(UInt8 *bytes, UInt32 length) + +OSData *IODTNVRAM::unescapeBytesToData(const UInt8 *bytes, UInt32 length) { OSData *data = 0; UInt32 totalLength = 0; @@ -1358,29 +1284,29 @@ OSData *IODTNVRAM::unescapeBytesToData(UInt8 *bytes, UInt32 length) OSData * IODTNVRAM::escapeDataToData(OSData * value) { - OSData * result; - UInt8 * start; - UInt8 * end; - UInt8 * where; - UInt8 byte; - bool ok = true; + OSData * result; + const UInt8 * startPtr; + const UInt8 * endPtr; + const UInt8 * wherePtr; + UInt8 byte; + bool ok = true; - where = (UInt8 *) value->getBytesNoCopy(); - end = where + value->getLength(); + wherePtr = (const UInt8 *) value->getBytesNoCopy(); + endPtr = wherePtr + value->getLength(); - result = OSData::withCapacity(end - where); + result = OSData::withCapacity(endPtr - wherePtr); if (!result) return result; - while (where < end) { - start = where; - byte = *where++; + while (wherePtr < endPtr) { + startPtr = wherePtr; + byte = *wherePtr++; if ((byte == 0x00) || (byte == 0xFF)) { for (; - ((where - start) < 0x80) && (where < end) && (byte == *where); - where++) {} + ((wherePtr - startPtr) < 0x80) && (wherePtr < endPtr) && (byte == *wherePtr); + wherePtr++) {} ok &= result->appendByte(0xff, 1); - byte = (byte & 0x80) | (where - start); + byte = (byte & 0x80) | (wherePtr - startPtr); } ok &= result->appendByte(byte, 1); } @@ -1394,56 +1320,81 @@ OSData * IODTNVRAM::escapeDataToData(OSData * value) return result; } +static bool IsApplePropertyName(const char * propName) +{ + char c; + while ((c = *propName++)) { + if ((c >= 'A') && (c <= 'Z')) + break; + } + + return (c == 0); +} + IOReturn IODTNVRAM::readNVRAMPropertyType1(IORegistryEntry *entry, const OSSymbol **name, OSData **value) { - IOReturn err = kIOReturnNoResources; - OSData *data; - UInt8 *start; - UInt8 *end; - UInt8 *where; - UInt8 *nvPath = 0; - UInt8 *nvName = 0; - UInt8 byte; + IOReturn err = kIOReturnNoResources; + OSData *data; + const UInt8 *startPtr; + const UInt8 *endPtr; + const UInt8 *wherePtr; + const UInt8 *nvPath = 0; + const char *nvName = 0; + const char *resultName = 0; + const UInt8 *resultValue = 0; + UInt32 resultValueLen = 0; + UInt8 byte; if (_ofDict == 0) return err; + + IOLockLock(_ofLock); data = OSDynamicCast(OSData, _ofDict->getObject(_registryPropertiesKey)); + IOLockUnlock(_ofLock); + if (data == 0) return err; - start = (UInt8 *) data->getBytesNoCopy(); - end = start + data->getLength(); + startPtr = (const UInt8 *) data->getBytesNoCopy(); + endPtr = startPtr + data->getLength(); - where = start; - while (where < end) { - byte = *(where++); + wherePtr = startPtr; + while (wherePtr < endPtr) { + byte = *(wherePtr++); if (byte) continue; if (nvPath == 0) - nvPath = start; + nvPath = startPtr; else if (nvName == 0) - nvName = start; + nvName = (const char *) startPtr; else { IORegistryEntry * compareEntry = IORegistryEntry::fromPath((const char *) nvPath, gIODTPlane); - if (entry == compareEntry) { - if (compareEntry) - compareEntry->release(); - *name = OSSymbol::withCString((const char *) nvName); - *value = unescapeBytesToData(start, where - start - 1); - if ((*name != 0) && (*value != 0)) - err = kIOReturnSuccess; - else - err = kIOReturnNoMemory; - break; - } if (compareEntry) compareEntry->release(); - nvPath = nvName = 0; + if (entry == compareEntry) { + bool appleProp = IsApplePropertyName(nvName); + if (!appleProp || !resultName) { + resultName = nvName; + resultValue = startPtr; + resultValueLen = wherePtr - startPtr - 1; + } + if (!appleProp) + break; + } + nvPath = 0; + nvName = 0; } - start = where; + startPtr = wherePtr; + } + if (resultName) { + *name = OSSymbol::withCString(resultName); + *value = unescapeBytesToData(resultValue, resultValueLen); + if ((*name != 0) && (*value != 0)) + err = kIOReturnSuccess; + else + err = kIOReturnNoMemory; } - return err; } @@ -1451,55 +1402,63 @@ IOReturn IODTNVRAM::writeNVRAMPropertyType1(IORegistryEntry *entry, const OSSymbol *propName, OSData *value) { - OSData *oldData; - OSData *data = 0; - UInt8 *start; - UInt8 *propStart; - UInt8 *end; - UInt8 *where; - UInt8 *nvPath = 0; - UInt8 *nvName = 0; + OSData *oldData, *escapedData; + OSData *data = 0; + const UInt8 *startPtr; + const UInt8 *propStart; + const UInt8 *endPtr; + const UInt8 *wherePtr; + const UInt8 *nvPath = 0; + const char *nvName = 0; const char * comp; const char * name; - UInt8 byte; - bool ok = true; + UInt8 byte; + bool ok = true; + bool settingAppleProp; if (_ofDict == 0) return kIOReturnNoResources; + settingAppleProp = IsApplePropertyName(propName->getCStringNoCopy()); + // copy over existing properties for other entries + IOLockLock(_ofLock); + oldData = OSDynamicCast(OSData, _ofDict->getObject(_registryPropertiesKey)); if (oldData) { - start = (UInt8 *) oldData->getBytesNoCopy(); - end = start + oldData->getLength(); - - propStart = start; - where = start; - while (where < end) { - byte = *(where++); + + startPtr = (const UInt8 *) oldData->getBytesNoCopy(); + endPtr = startPtr + oldData->getLength(); + + propStart = startPtr; + wherePtr = startPtr; + while (wherePtr < endPtr) { + byte = *(wherePtr++); if (byte) continue; if (nvPath == 0) - nvPath = start; + nvPath = startPtr; else if (nvName == 0) - nvName = start; + nvName = (const char *) startPtr; else { IORegistryEntry * compareEntry = IORegistryEntry::fromPath((const char *) nvPath, gIODTPlane); - if (entry == compareEntry) { - if (compareEntry) - compareEntry->release(); - // delete old property (nvPath -> where) - data = OSData::withBytes(propStart, nvPath - propStart); - if (data) - ok &= data->appendBytes(where, end - where); - break; - } if (compareEntry) compareEntry->release(); - nvPath = nvName = 0; + if (entry == compareEntry) { + if ((settingAppleProp && propName->isEqualTo(nvName)) + || (!settingAppleProp && !IsApplePropertyName(nvName))) { + // delete old property (nvPath -> wherePtr) + data = OSData::withBytes(propStart, nvPath - propStart); + if (data) + ok &= data->appendBytes(wherePtr, endPtr - wherePtr); + break; + } + } + nvPath = 0; + nvName = 0; } - - start = where; + + startPtr = wherePtr; } } @@ -1510,61 +1469,96 @@ IOReturn IODTNVRAM::writeNVRAMPropertyType1(IORegistryEntry *entry, data = OSData::withData(oldData); else data = OSData::withCapacity(16); - if (!data) - return kIOReturnNoMemory; + if (!data) ok = false; } - // 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); + 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; + if (!name) continue; + ok &= data->appendByte('/', 1); + comp = name; } + ok &= data->appendBytes(comp, strlen(comp)); } - ok &= data->appendBytes(comp, strlen(comp)); - } - ok &= data->appendByte(0, 1); - array->release(); + 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); + // 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; +}