X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/1c79356b52d46aa6b508fb032f5ae709b1f2897b..d1ecb069dfe24481e4a83f44cb5217a2b06746d7:/iokit/Kernel/IONVRAM.cpp diff --git a/iokit/Kernel/IONVRAM.cpp b/iokit/Kernel/IONVRAM.cpp index e4bc666b2..4c51e4457 100644 --- a/iokit/Kernel/IONVRAM.cpp +++ b/iokit/Kernel/IONVRAM.cpp @@ -1,23 +1,29 @@ /* - * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 1998-2006 Apple Computer, 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,9 +31,15 @@ #include #include #include +#include +#include #define super IOService +#define kIONVRAMPrivilege kIOClientPrivilegeAdministrator +//#define kIONVRAMPrivilege kIOClientPrivilegeLocalUser + + OSDefineMetaClassAndStructors(IODTNVRAM, IOService); bool IODTNVRAM::init(IORegistryEntry *old, const IORegistryPlane *plane) @@ -42,7 +54,13 @@ bool IODTNVRAM::init(IORegistryEntry *old, const IORegistryPlane *plane) _nvramImage = IONew(UInt8, kIODTNVRAMImageSize); if (_nvramImage == 0) return false; - + + _nvramPartitionOffsets = OSDictionary::withCapacity(1); + if (_nvramPartitionOffsets == 0) return false; + + _nvramPartitionLengths = OSDictionary::withCapacity(1); + if (_nvramPartitionLengths == 0) return false; + _registryPropertiesKey = OSSymbol::withCStringNoCopy("aapl,pci"); if (_registryPropertiesKey == 0) return false; @@ -51,7 +69,11 @@ bool IODTNVRAM::init(IORegistryEntry *old, const IORegistryPlane *plane) void IODTNVRAM::registerNVRAMController(IONVRAMController *nvram) { - UInt32 currentOffset = 0; + char partitionID[18]; + UInt32 partitionOffset, partitionLength; + UInt32 freePartitionOffset, freePartitionSize; + UInt32 currentLength, currentOffset = 0; + OSNumber *partitionOffsetNumber, *partitionLengthNumber; if (_nvramController != 0) return; @@ -59,26 +81,58 @@ void IODTNVRAM::registerNVRAMController(IONVRAMController *nvram) _nvramController->read(0, _nvramImage, kIODTNVRAMImageSize); - // Find the offsets for the OF, XPRAM and NameRegistry partitions in NVRAM. + // 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) { - if (strcmp((const char *)_nvramImage + currentOffset + 4, "common") == 0) { - _ofPartitionOffset = currentOffset + 16; - _ofPartitionSize = - (((UInt16 *)(_nvramImage + currentOffset))[1] - 1) * 0x10; - } else if (strcmp((const char *)_nvramImage + currentOffset + 4, "APL,MacOS75") == 0) { - _xpramPartitionOffset = currentOffset + 16; + currentLength = ((UInt16 *)(_nvramImage + currentOffset))[1] * 16; + + partitionOffset = currentOffset + 16; + partitionLength = currentLength - 16; + + 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 = - (((UInt16 *)(_nvramImage + currentOffset))[1] - 1) * 0x10 - - _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. + snprintf(partitionID, sizeof(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 += ((short *)(_nvramImage + currentOffset))[1] * 16; + currentOffset += currentLength; } } else { // Use the fixed address for old world machines. @@ -97,6 +151,60 @@ void IODTNVRAM::registerNVRAMController(IONVRAMController *nvram) if (_nrPartitionOffset != 0xFFFFFFFF) _nrImage = _nvramImage + _nrPartitionOffset; + if (_piPartitionOffset == 0xFFFFFFFF) { + if (freePartitionSize > 0x20) { + // Set the signature to 0xa1. + _nvramImage[freePartitionOffset] = 0xa1; + // Set the checksum to 0. + _nvramImage[freePartitionOffset + 1] = 0; + // Set the name for the Panic Info partition. + strncpy((char *)(_nvramImage + freePartitionOffset + 4), + kIODTNVRAMPanicInfoPartitonName, 12); + + // Calculate the partition offset and size. + _piPartitionOffset = freePartitionOffset + 0x10; + _piPartitionSize = 0x800; + if (_piPartitionSize + 0x20 > freePartitionSize) + _piPartitionSize = freePartitionSize - 0x20; + + _piImage = _nvramImage + _piPartitionOffset; + + // Zero the new partition. + bzero(_piImage, _piPartitionSize); + + // Set the partition size. + *(UInt16 *)(_nvramImage + freePartitionOffset + 2) = + (_piPartitionSize / 0x10) + 1; + + // Set the partition checksum. + _nvramImage[freePartitionOffset + 1] = + calculatePartitionChecksum(_nvramImage + freePartitionOffset); + + // Calculate the free partition offset and size. + freePartitionOffset += _piPartitionSize + 0x10; + freePartitionSize -= _piPartitionSize + 0x10; + + // Set the signature to 0x7f. + _nvramImage[freePartitionOffset] = 0x7f; + // Set the checksum to 0. + _nvramImage[freePartitionOffset + 1] = 0; + // Set the name for the free partition. + strncpy((char *)(_nvramImage + freePartitionOffset + 4), + kIODTNVRAMFreePartitionName, 12); + // Set the partition size. + *(UInt16 *)(_nvramImage + freePartitionOffset + 2) = + freePartitionSize / 0x10; + // Set the partition checksum. + _nvramImage[freePartitionOffset + 1] = + calculatePartitionChecksum(_nvramImage + freePartitionOffset); + + // Set the nvram image as dirty. + _nvramImageDirty = true; + } + } else { + _piImage = _nvramImage + _piPartitionOffset; + } + initOFVariables(); } @@ -104,7 +212,8 @@ void IODTNVRAM::sync(void) { if (!_nvramImageDirty && !_ofImageDirty) return; - syncOFVariables(); + // Don't try to sync OF Variables if the system has already paniced. + if (!_systemPaniced) syncOFVariables(); _nvramController->write(0, _nvramImage, kIODTNVRAMImageSize); _nvramController->sync(); @@ -112,40 +221,38 @@ void IODTNVRAM::sync(void) _nvramImageDirty = false; } -bool IODTNVRAM::serializeProperties(OSSerialize *serialize) const +bool IODTNVRAM::serializeProperties(OSSerialize *s) const { - bool result; + bool result, hasPrivilege; UInt32 variablePerm; const OSSymbol *key; - OSDictionary *dict, *tmpDict = 0; + OSDictionary *dict = 0, *tmpDict = 0; 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; + hasPrivilege = (kIOReturnSuccess == IOUserClient::clientHasPrivilege(current_task(), kIONVRAMPrivilege)); + + tmpDict = OSDictionary::withCapacity(1); + if (tmpDict == 0) return false; - iter = OSCollectionIterator::withCollection(_ofDict); - if (iter == 0) return false; + iter = OSCollectionIterator::withCollection(_ofDict); + if (iter == 0) return false; - while (1) { - key = OSDynamicCast(OSSymbol, iter->getNextObject()); - if (key == 0) break; + while (1) { + key = OSDynamicCast(OSSymbol, iter->getNextObject()); + if (key == 0) break; - variablePerm = getOFVariablePerm(key); - if (variablePerm != kOFVariablePermRootOnly) { - tmpDict->setObject(key, _ofDict->getObject(key)); - } + variablePerm = getOFVariablePerm(key); + if ((hasPrivilege || (variablePerm != kOFVariablePermRootOnly)) && + ( ! (variablePerm == kOFVariablePermKernelOnly && current_task() != kernel_task) )) { + tmpDict->setObject(key, _ofDict->getObject(key)); } dict = tmpDict; - } else { - dict = _ofDict; } - - result = dict->serialize(serialize); + + result = dict->serialize(s); if (tmpDict != 0) tmpDict->release(); if (iter != 0) iter->release(); @@ -161,11 +268,12 @@ OSObject *IODTNVRAM::getProperty(const OSSymbol *aKey) const 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; } + if (variablePerm == kOFVariablePermKernelOnly && current_task() != kernel_task) return 0; return _ofDict->getObject(aKey); } @@ -194,17 +302,21 @@ bool IODTNVRAM::setProperty(const OSSymbol *aKey, OSObject *anObject) if (_ofDict == 0) return false; // Verify permissions. - result = IOUserClient::clientHasPrivilege(current_task(), "root"); + propPerm = getOFVariablePerm(aKey); + result = IOUserClient::clientHasPrivilege(current_task(), kIONVRAMPrivilege); if (result != kIOReturnSuccess) { - propPerm = getOFVariablePerm(aKey); if (propPerm != kOFVariablePermUserWrite) return false; } - + if (propPerm == kOFVariablePermKernelOnly && current_task() != kernel_task) return 0; + // Don't allow creation of new properties on old world machines. if (getPlatform()->getBootROMType() == 0) { if (_ofDict->getObject(aKey) == 0) return false; } + // Don't allow change of 'aapl,panic-info'. + if (aKey->isEqualTo(kIODTNVRAMPanicInfoKey)) return false; + // Make sure the object is of the correct type. propType = getOFVariableType(aKey); switch (propType) { @@ -247,11 +359,42 @@ bool IODTNVRAM::setProperty(const OSSymbol *aKey, OSObject *anObject) 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 removal of properties on old world machines. + if (getPlatform()->getBootROMType() == 0) return; + + // Don't allow change of 'aapl,panic-info'. + if (aKey->isEqualTo(kIODTNVRAMPanicInfoKey)) return; + + // If the object exists, remove it from the dictionary. + result = _ofDict->getObject(aKey) != 0; + if (result) { + _ofDict->removeObject(aKey); + + _ofImageDirty = true; + } +} + IOReturn IODTNVRAM::setProperties(OSObject *properties) { bool result = true; OSObject *object; const OSSymbol *key; + const OSString *tmpStr; OSDictionary *dict; OSCollectionIterator *iter; @@ -268,7 +411,19 @@ 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 { + result = setProperty(key, object); + } } iter->release(); @@ -280,10 +435,9 @@ IOReturn IODTNVRAM::setProperties(OSObject *properties) IOReturn IODTNVRAM::readXPRAM(IOByteCount offset, UInt8 *buffer, IOByteCount length) { - if ((_nvramImage == 0) || (_xpramPartitionOffset == 0)) - return kIOReturnNotReady; + if (_xpramImage == 0) return kIOReturnUnsupported; - if ((buffer == 0) || (length <= 0) || (offset < 0) || + if ((buffer == 0) || (length == 0) || (offset + length > kIODTNVRAMXPRAMSize)) return kIOReturnBadArgument; @@ -295,10 +449,9 @@ IOReturn IODTNVRAM::readXPRAM(IOByteCount offset, UInt8 *buffer, IOReturn IODTNVRAM::writeXPRAM(IOByteCount offset, UInt8 *buffer, IOByteCount length) { - if ((_nvramImage == 0) || (_xpramPartitionOffset == 0)) - return kIOReturnNotReady; + if (_xpramImage == 0) return kIOReturnUnsupported; - if ((buffer == 0) || (length <= 0) || (offset < 0) || + if ((buffer == 0) || (length == 0) || (offset + length > kIODTNVRAMXPRAMSize)) return kIOReturnBadArgument; @@ -337,9 +490,107 @@ IOReturn IODTNVRAM::writeNVRAMProperty(IORegistryEntry *entry, return err; } +OSDictionary *IODTNVRAM::getNVRAMPartitions(void) +{ + return _nvramPartitionLengths; +} + +IOReturn IODTNVRAM::readNVRAMPartition(const OSSymbol *partitionID, + IOByteCount offset, UInt8 *buffer, + IOByteCount length) +{ + OSNumber *partitionOffsetNumber, *partitionLengthNumber; + UInt32 partitionOffset, partitionLength; + + partitionOffsetNumber = + (OSNumber *)_nvramPartitionOffsets->getObject(partitionID); + partitionLengthNumber = + (OSNumber *)_nvramPartitionLengths->getObject(partitionID); + + if ((partitionOffsetNumber == 0) || (partitionLengthNumber == 0)) + return kIOReturnNotFound; + + partitionOffset = partitionOffsetNumber->unsigned32BitValue(); + partitionLength = partitionLengthNumber->unsigned32BitValue(); + + if ((buffer == 0) || (length == 0) || + (offset + length > partitionLength)) + return kIOReturnBadArgument; + + bcopy(_nvramImage + partitionOffset + offset, buffer, length); + + return kIOReturnSuccess; +} + +IOReturn IODTNVRAM::writeNVRAMPartition(const OSSymbol *partitionID, + IOByteCount offset, UInt8 *buffer, + IOByteCount length) +{ + OSNumber *partitionOffsetNumber, *partitionLengthNumber; + UInt32 partitionOffset, partitionLength; + + partitionOffsetNumber = + (OSNumber *)_nvramPartitionOffsets->getObject(partitionID); + partitionLengthNumber = + (OSNumber *)_nvramPartitionLengths->getObject(partitionID); + + if ((partitionOffsetNumber == 0) || (partitionLengthNumber == 0)) + return kIOReturnNotFound; + + partitionOffset = partitionOffsetNumber->unsigned32BitValue(); + partitionLength = partitionLengthNumber->unsigned32BitValue(); + + if ((buffer == 0) || (length == 0) || + (offset + length > partitionLength)) + return kIOReturnBadArgument; + + bcopy(buffer, _nvramImage + partitionOffset + offset, length); + + _nvramImageDirty = true; + + return kIOReturnSuccess; +} + +IOByteCount IODTNVRAM::savePanicInfo(UInt8 *buffer, IOByteCount length) +{ + if ((_piImage == 0) || (length <= 0)) return 0; + + if (length > (_piPartitionSize - 4)) + length = _piPartitionSize - 4; + + // Save the Panic Info. + bcopy(buffer, _piImage + 4, length); + + // Save the Panic Info length. + *(UInt32 *)_piImage = length; + + _nvramImageDirty = true; + /* + * 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; +} +// Private methods -// Private methods for Open Firmware variable access. +UInt8 IODTNVRAM::calculatePartitionChecksum(UInt8 *partitionHeader) +{ + UInt8 cnt, isum, csum = 0; + + for (cnt = 0; cnt < 0x10; cnt++) { + isum = csum + partitionHeader[cnt]; + if (isum < csum) isum++; + csum = isum; + } + + return csum; +} struct OWVariablesHeader { UInt16 owMagic; @@ -416,6 +667,20 @@ IOReturn IODTNVRAM::initOFVariables(void) propObject->release(); } } + + // 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)) { @@ -478,7 +743,8 @@ IOReturn IODTNVRAM::syncOFVariables(void) bool ok; UInt32 cnt, length, maxLength; UInt32 curOffset, tmpOffset, tmpType, tmpDataLength; - UInt8 *buffer, *tmpBuffer, *tmpData; + UInt8 *buffer, *tmpBuffer; + const UInt8 *tmpData; const OSSymbol *tmpSymbol; OSObject *tmpObject; OSBoolean *tmpBoolean; @@ -506,6 +772,9 @@ IOReturn IODTNVRAM::syncOFVariables(void) 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; @@ -559,7 +828,7 @@ IOReturn IODTNVRAM::syncOFVariables(void) case kOFVariableTypeString : tmpString = OSDynamicCast(OSString, tmpObject); - tmpData = (UInt8 *) tmpString->getCStringNoCopy(); + tmpData = (const UInt8 *)tmpString->getCStringNoCopy(); tmpDataLength = tmpString->getLength(); if ((curOffset - tmpDataLength) < sizeof(OWVariablesHeader)) { @@ -599,10 +868,10 @@ IOReturn IODTNVRAM::syncOFVariables(void) } struct OFVariable { - char *variableName; - UInt32 variableType; - UInt32 variablePerm; - SInt32 variableOffset; + const char *variableName; + UInt32 variableType; + UInt32 variablePerm; + SInt32 variableOffset; }; typedef struct OFVariable OFVariable; @@ -657,6 +926,11 @@ 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}, +#endif {0, kOFVariableTypeData, kOFVariablePermUserRead, -1} }; @@ -783,7 +1057,7 @@ bool IODTNVRAM::convertPropToObject(UInt8 *propName, UInt32 propNameLength, bool IODTNVRAM::convertObjectToProp(UInt8 *buffer, UInt32 *length, const OSSymbol *propSymbol, OSObject *propObject) { - UInt8 *propName; + const UInt8 *propName; UInt32 propNameLength, propDataLength; UInt32 propType, tmpValue; OSBoolean *tmpBoolean = 0; @@ -791,7 +1065,7 @@ bool IODTNVRAM::convertObjectToProp(UInt8 *buffer, UInt32 *length, OSString *tmpString = 0; OSData *tmpData = 0; - propName = (UInt8 *)propSymbol->getCStringNoCopy(); + propName = (const UInt8 *)propSymbol->getCStringNoCopy(); propNameLength = propSymbol->getLength(); propType = getOFVariableType(propSymbol); @@ -827,31 +1101,30 @@ 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); switch (propType) { case kOFVariableTypeBoolean : if (tmpBoolean->getValue()) { - strcpy((char *)buffer, "true"); + strlcpy((char *)buffer, "true", *length - propNameLength); } else { - strcpy((char *)buffer, "false"); + strlcpy((char *)buffer, "false", *length - propNameLength); } break; case kOFVariableTypeNumber : tmpValue = tmpNumber->unsigned32BitValue(); if (tmpValue == 0xFFFFFFFF) { - strcpy((char *)buffer, "-1"); + strlcpy((char *)buffer, "-1", *length - propNameLength); } else if (tmpValue < 1000) { - sprintf((char *)buffer, "%ld", tmpValue); + snprintf((char *)buffer, *length - propNameLength, "%d", (uint32_t)tmpValue); } else { - sprintf((char *)buffer, "0x%lx", tmpValue); + snprintf((char *)buffer, *length - propNameLength, "0x%x", (uint32_t)tmpValue); } break; case kOFVariableTypeString : - strcpy((char *)buffer, tmpString->getCStringNoCopy()); + strlcpy((char *)buffer, tmpString->getCStringNoCopy(), *length - propNameLength); break; case kOFVariableTypeData : @@ -896,11 +1169,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; @@ -915,7 +1189,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; @@ -935,7 +1209,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; @@ -943,9 +1217,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) { @@ -971,7 +1244,6 @@ enum { kMaxNVDataLength = 8 }; -#pragma options align=mac68k struct NVRAMProperty { IONVRAMDescriptor header; @@ -980,7 +1252,6 @@ struct NVRAMProperty UInt8 dataLength; UInt8 data[ kMaxNVDataLength ]; }; -#pragma options align=reset bool IODTNVRAM::searchNVRAMProperty(IONVRAMDescriptor *hdr, UInt32 *where) { @@ -1101,7 +1372,7 @@ IOReturn IODTNVRAM::writeNVRAMPropertyType0(IORegistryEntry *entry, return err; } -OSData *IODTNVRAM::unescapeBytesToData(UInt8 *bytes, UInt32 length) +OSData *IODTNVRAM::unescapeBytesToData(const UInt8 *bytes, UInt32 length) { OSData *data = 0; UInt32 totalLength = 0; @@ -1148,29 +1419,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); } @@ -1184,51 +1455,77 @@ 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; data = OSDynamicCast(OSData, _ofDict->getObject(_registryPropertiesKey)); 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; - else if (entry == - IORegistryEntry::fromPath((const char *) nvPath, gIODTPlane)) { - *name = OSSymbol::withCString((const char *) nvName); - *value = unescapeBytesToData(start, where - start - 1); - if ((*name != 0) && (*value != 0)) - err = kIOReturnSuccess; - else - err = kIOReturnNoMemory; - break; - } else - nvPath = nvName = 0; - - start = where; + nvName = (const char *) startPtr; + else { + IORegistryEntry * compareEntry = IORegistryEntry::fromPath((const char *) nvPath, gIODTPlane); + if (compareEntry) + compareEntry->release(); + 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; + } + startPtr = wherePtr; + } + if (resultName) { + *name = OSSymbol::withCString(resultName); + *value = unescapeBytesToData(resultValue, resultValueLen); + if ((*name != 0) && (*value != 0)) + err = kIOReturnSuccess; + else + err = kIOReturnNoMemory; } - return err; } @@ -1236,49 +1533,60 @@ 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; + 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 oldData = OSDynamicCast(OSData, _ofDict->getObject(_registryPropertiesKey)); if (oldData) { - start = (UInt8 *) oldData->getBytesNoCopy(); - end = start + oldData->getLength(); + startPtr = (const UInt8 *) oldData->getBytesNoCopy(); + endPtr = startPtr + oldData->getLength(); - propStart = start; - where = start; - while (where < end) { - byte = *(where++); + 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; - else if (entry == - IORegistryEntry::fromPath((const char *) nvPath, gIODTPlane)) { - // delete old property (nvPath -> where) - data = OSData::withBytes(propStart, nvPath - propStart); - if (data) - ok &= data->appendBytes(where, end - where); - break; - } else - nvPath = nvName = 0; + nvName = (const char *) startPtr; + else { + IORegistryEntry * compareEntry = IORegistryEntry::fromPath((const char *) nvPath, gIODTPlane); + if (compareEntry) + compareEntry->release(); + 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; } } @@ -1293,51 +1601,52 @@ IOReturn IODTNVRAM::writeNVRAMPropertyType1(IORegistryEntry *entry, return kIOReturnNoMemory; } - // 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 (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 == strncmp("pci", name, sizeof("pci"))) + && (0 == strncmp("80000000", comp, sizeof("80000000")))) { + // 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) { ok = _ofDict->setObject(_registryPropertiesKey, data); if (ok)