Loading...
--- xnu/xnu-12377.101.15/iokit/Kernel/IONVRAM.cpp
+++ xnu/xnu-201.19.3/iokit/Kernel/IONVRAM.cpp
@@ -1,2295 +1,1347 @@
/*
- * Copyright (c) 1998-2006 Apple Computer, Inc. All rights reserved.
- * Copyright (c) 2007-2021 Apple Inc. All rights reserved.
+ * Copyright (c) 1998-2000 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. 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
+ * @APPLE_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 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, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
*/
-#define IOKIT_ENABLE_SHARED_PTR
-
-#include <AssertMacros.h>
#include <IOKit/IOLib.h>
#include <IOKit/IONVRAM.h>
#include <IOKit/IOPlatformExpert.h>
#include <IOKit/IOUserClient.h>
#include <IOKit/IOKitKeys.h>
-#include <IOKit/IOKitKeysPrivate.h>
-#include <IOKit/IOBSD.h>
-#include <kern/debug.h>
-#include <os/system_event_log.h>
-#include <pexpert/boot.h>
-#include <sys/csr.h>
#define super IOService
OSDefineMetaClassAndStructors(IODTNVRAM, IOService);
-class IONVRAMCHRPHandler;
-class IONVRAMV3Handler;
-
-#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
-
-#define MAX_VAR_NAME_SIZE 63
-
-#define kNVRAMBankSizeKey "nvram-bank-size"
-#define kNVRAMBankCountKey "nvram-bank-count"
-#define kNVRAMCurrentBankKey "nvram-current-bank"
-#define kNVRAMClearTestVarKey "clear-test-vars"
-
-#define kCurrentGenerationCountKey "Generation"
-#define kCurrentNVRAMVersionKey "Version"
-
-#define kNVRAMCommonUsedKey "CommonUsed"
-#define kNVRAMSystemUsedKey "SystemUsed"
-
-#define kIONVRAMPrivilege kIOClientPrivilegeAdministrator
-
-#define MIN_SYNC_NOW_INTERVAL 15*60 /* Minimum 15 Minutes interval mandated */
-
-enum IONVRAMLogging {
- kIONVRAMNoLogs = 0,
- kIONVRAMInfoLogs = 1,
- kIONVRAMErrorLogs = 2,
- kIONVRAMDataHexDump = 4
+bool IODTNVRAM::init(IORegistryEntry *old, const IORegistryPlane *plane)
+{
+ OSDictionary *dict;
+
+ if (!super::init(old, plane)) return false;
+
+ dict = OSDictionary::withCapacity(1);
+ if (dict == 0) return false;
+ setPropertyTable(dict);
+
+ _nvramImage = IONew(UInt8, kIODTNVRAMImageSize);
+ if (_nvramImage == 0) return false;
+
+ _registryPropertiesKey = OSSymbol::withCStringNoCopy("aapl,pci");
+ if (_registryPropertiesKey == 0) return false;
+
+ return true;
+}
+
+void IODTNVRAM::registerNVRAMController(IONVRAMController *nvram)
+{
+ UInt32 currentOffset = 0;
+
+ if (_nvramController != 0) return;
+
+ _nvramController = nvram;
+
+ _nvramController->read(0, _nvramImage, kIODTNVRAMImageSize);
+
+ // Find the offsets for the OF, XPRAM and NameRegistry partitions in NVRAM.
+ _ofPartitionOffset = 0xFFFFFFFF;
+ _xpramPartitionOffset = 0xFFFFFFFF;
+ _nrPartitionOffset = 0xFFFFFFFF;
+ 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;
+ _xpramPartitionSize = kIODTNVRAMXPRAMSize;
+ _nrPartitionOffset = _xpramPartitionOffset + _xpramPartitionSize;
+ _nrPartitionSize =
+ (((UInt16 *)(_nvramImage + currentOffset))[1] - 1) * 0x10 -
+ _xpramPartitionSize;
+ }
+ currentOffset += ((short *)(_nvramImage + currentOffset))[1] * 16;
+ }
+ } else {
+ // Use the fixed address for old world machines.
+ _ofPartitionOffset = 0x1800;
+ _ofPartitionSize = 0x0800;
+ _xpramPartitionOffset = 0x1300;
+ _xpramPartitionSize = 0x0100;
+ _nrPartitionOffset = 0x1400;
+ _nrPartitionSize = 0x0400;
+ }
+
+ if (_ofPartitionOffset != 0xFFFFFFFF)
+ _ofImage = _nvramImage + _ofPartitionOffset;
+ if (_xpramPartitionOffset != 0xFFFFFFFF)
+ _xpramImage = _nvramImage + _xpramPartitionOffset;
+ if (_nrPartitionOffset != 0xFFFFFFFF)
+ _nrImage = _nvramImage + _nrPartitionOffset;
+
+ initOFVariables();
+}
+
+void IODTNVRAM::sync(void)
+{
+ if (!_nvramImageDirty && !_ofImageDirty) return;
+
+ syncOFVariables();
+
+ _nvramController->write(0, _nvramImage, kIODTNVRAMImageSize);
+ _nvramController->sync();
+
+ _nvramImageDirty = false;
+}
+
+bool IODTNVRAM::serializeProperties(OSSerialize *serialize) const
+{
+ bool result;
+ UInt32 variablePerm;
+ const OSSymbol *key;
+ OSDictionary *dict, *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;
+
+ iter = OSCollectionIterator::withCollection(_ofDict);
+ if (iter == 0) 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));
+ }
+ }
+ dict = tmpDict;
+ } else {
+ dict = _ofDict;
+ }
+
+ result = dict->serialize(serialize);
+
+ if (tmpDict != 0) tmpDict->release();
+ if (iter != 0) iter->release();
+
+ return result;
+}
+
+OSObject *IODTNVRAM::getProperty(const OSSymbol *aKey) const
+{
+ IOReturn result;
+ UInt32 variablePerm;
+
+ if (_ofDict == 0) return 0;
+
+ // Verify permissions.
+ result = IOUserClient::clientHasPrivilege(current_task(), "root");
+ if (result != kIOReturnSuccess) {
+ variablePerm = getOFVariablePerm(aKey);
+ if (variablePerm == kOFVariablePermRootOnly) return 0;
+ }
+
+ return _ofDict->getObject(aKey);
+}
+
+OSObject *IODTNVRAM::getProperty(const char *aKey) const
+{
+ const OSSymbol *keySymbol;
+ OSObject *theObject = 0;
+
+ keySymbol = OSSymbol::withCStringNoCopy(aKey);
+ if (keySymbol != 0) {
+ theObject = getProperty(keySymbol);
+ keySymbol->release();
+ }
+
+ return theObject;
+}
+
+bool IODTNVRAM::setProperty(const OSSymbol *aKey, OSObject *anObject)
+{
+ bool result;
+ UInt32 propType, propPerm;
+ OSString *tmpString;
+ OSObject *propObject = 0;
+
+ if (_ofDict == 0) return false;
+
+ // Verify permissions.
+ result = IOUserClient::clientHasPrivilege(current_task(), "root");
+ if (result != kIOReturnSuccess) {
+ propPerm = getOFVariablePerm(aKey);
+ 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;
+ }
+
+ // Make sure the object is of the correct type.
+ propType = getOFVariableType(aKey);
+ switch (propType) {
+ 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) {
+ tmpString = OSDynamicCast(OSString, anObject);
+ if (tmpString != 0) {
+ propObject = OSData::withBytes(tmpString->getCStringNoCopy(),
+ tmpString->getLength());
+ }
+ }
+ break;
+ }
+
+ if (propObject == 0) return false;
+
+ result = _ofDict->setObject(aKey, propObject);
+
+ if (result) {
+ if (getPlatform()->getBootROMType() == 0) {
+ updateOWBootArgs(aKey, propObject);
+ }
+
+ _ofImageDirty = true;
+ }
+
+ return result;
+}
+
+IOReturn IODTNVRAM::setProperties(OSObject *properties)
+{
+ bool result = true;
+ OSObject *object;
+ const OSSymbol *key;
+ OSDictionary *dict;
+ OSCollectionIterator *iter;
+
+ dict = OSDynamicCast(OSDictionary, properties);
+ if (dict == 0) return kIOReturnBadArgument;
+
+ iter = OSCollectionIterator::withCollection(dict);
+ if (iter == 0) return kIOReturnBadArgument;
+
+ while (result) {
+ key = OSDynamicCast(OSSymbol, iter->getNextObject());
+ if (key == 0) break;
+
+ object = dict->getObject(key);
+ if (object == 0) continue;
+
+ result = setProperty(key, object);
+ }
+
+ iter->release();
+
+ if (result) return kIOReturnSuccess;
+ else return kIOReturnError;
+}
+
+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;
+}
+
+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;
+}
+
+IOReturn IODTNVRAM::readNVRAMProperty(IORegistryEntry *entry,
+ const OSSymbol **name,
+ OSData **value)
+{
+ IOReturn err;
+
+ if (getPlatform()->getBootROMType())
+ err = readNVRAMPropertyType1(entry, name, value);
+ else
+ err = readNVRAMPropertyType0(entry, name, value);
+
+ return err;
+}
+
+IOReturn IODTNVRAM::writeNVRAMProperty(IORegistryEntry *entry,
+ const OSSymbol *name,
+ OSData *value)
+{
+ IOReturn err;
+
+ if (getPlatform()->getBootROMType())
+ err = writeNVRAMPropertyType1(entry, name, value);
+ else
+ err = writeNVRAMPropertyType0(entry, name, value);
+
+ return err;
+}
+
+
+
+// Private methods for Open Firmware variable access.
+
+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];
};
-
-#define IS_LOG_BIT_SET(level) ((gNVRAMLogging & (level)) != 0)
-
-#if defined(DEBUG) || defined(DEVELOPMENT)
-#define DEBUG_IFERROR(err, fmt, args...) \
-({ \
- if ((err != kIOReturnSuccess) || IS_LOG_BIT_SET(kIONVRAMErrorLogs)) \
- IOLog("%s:%s:%u - " fmt, __FILE_NAME__, __FUNCTION__, __LINE__, ##args); \
-})
-
-#define DEBUG_INFO_IF(log, fmt, args...) \
-({ \
- if ((log) && IS_LOG_BIT_SET(kIONVRAMInfoLogs)) \
- IOLog("%s:%s:%u - " fmt, __FILE_NAME__, __FUNCTION__, __LINE__, ##args); \
-})
-
-#define DEBUG_INFO(fmt, args...) \
-({ \
- if (IS_LOG_BIT_SET(kIONVRAMInfoLogs)) \
- IOLog("%s:%s:%u - " fmt, __FILE_NAME__, __FUNCTION__, __LINE__, ##args); \
-})
-
-#define DEBUG_ALWAYS(fmt, args...) \
-({ \
- IOLog("%s:%s:%u - " fmt, __FILE_NAME__, __FUNCTION__, __LINE__, ##args); \
-})
-#else
-#define DEBUG_IFERROR(err, fmt, args...) (void)NULL
-#define DEBUG_INFO(fmt, args...) (void)NULL
-#define DEBUG_ALWAYS(fmt, args...) (void)NULL
-#define DEBUG_INFO_IF(fmt, args...) (void)NULL
-#endif
-
-#define DEBUG_ERROR DEBUG_ALWAYS
-
-#define SAFE_TO_LOCK() (preemption_enabled() && !panic_active())
-
-#define NVRAMLOCK(lock) \
-({ \
- if (SAFE_TO_LOCK()) \
- IOLockLock(lock); \
-})
-
-#define NVRAMUNLOCK(lock) \
-({ \
- if (SAFE_TO_LOCK()) \
- IOLockUnlock(lock); \
-})
-
-#define NVRAMLOCKASSERTHELD(lock) \
-({ \
- if (SAFE_TO_LOCK()) \
- IOLockAssert(lock, kIOLockAssertOwned); \
-})
-
-#define NVRAMREADLOCK(lock) \
-({ \
- if (SAFE_TO_LOCK()) \
- IORWLockRead(lock); \
-})
-
-#define NVRAMWRITELOCK(lock) \
-({ \
- if (SAFE_TO_LOCK()) \
- IORWLockWrite(lock); \
-})
-
-#define NVRAMRWUNLOCK(lock) \
-({ \
- if (SAFE_TO_LOCK()) \
- IORWLockUnlock(lock); \
-})
-
-#define NVRAMRWUNLOCKANDWRITE(lock) \
-({ \
- NVRAMRWUNLOCK(lock); \
- NVRAMWRITELOCK(lock); \
-})
-
-#define NVRAMRWLOCKASSERTHELD(lock) \
-({ \
- if (SAFE_TO_LOCK()) \
- IORWLockAssert(lock, kIORWLockAssertHeld); \
-})
-
-#define NVRAMRWLOCKASSERTEXCLUSIVE(lock) \
-({ \
- if (SAFE_TO_LOCK()) \
- IORWLockAssert(lock, kIORWLockAssertWrite); \
-})
-
-// MOD = Write, Delete
-// RST = Reset, Obliterate
-// RD = Read
-// DEL = Delete
-#define OP_RD ((1 << kIONVRAMOperationRead))
-#define OP_RST ((1 << kIONVRAMOperationObliterate) | (1 << kIONVRAMOperationReset))
-#define OP_DEL ((1 << kIONVRAMOperationDelete))
-#define OP_MOD ((1 << kIONVRAMOperationWrite) | OP_DEL)
-#define OP_MOD_RD (OP_RD | OP_MOD)
-#define OP_MOD_RST (OP_MOD | OP_RST)
-
-enum NVRAMVersion {
- kNVRAMVersionUnknown,
- kNVRAMVersion1, // Legacy, banks, 0x800 common partition size
- kNVRAMVersion2, // V1 but with (0x2000 - sizeof(struct apple_nvram_header) - sizeof(struct chrp_nvram_header)) common region
- kNVRAMVersion3, // New EFI based format
- kNVRAMVersionMax
+typedef struct OWVariablesHeader OWVariablesHeader;
+
+IOReturn IODTNVRAM::initOFVariables(void)
+{
+ UInt32 cnt, propOffset, propType;
+ 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;
+
+ 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();
+ }
+ }
+
+ // 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();
+ }
+ }
+ } else {
+ owHeader = (OWVariablesHeader *)_ofImage;
+ if (!validateOWChecksum(_ofImage)) {
+ _ofDict->release();
+ _ofDict = 0;
+ return kIOReturnBadMedia;
+ }
+
+ 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;
+
+ _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();
+ }
+ }
+
+ return kIOReturnSuccess;
+}
+
+IOReturn IODTNVRAM::syncOFVariables(void)
+{
+ bool ok;
+ UInt32 cnt, length, maxLength;
+ UInt32 curOffset, tmpOffset, tmpType, tmpDataLength;
+ UInt8 *buffer, *tmpBuffer, *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;
+
+ 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;
+ }
+ }
+
+ 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);
+ }
+
+ IODelete(buffer, UInt8, _ofPartitionSize);
+
+ if (!ok) return kIOReturnBadArgument;
+ }
+
+ _ofImageDirty = false;
+ _nvramImageDirty = true;
+
+ return kIOReturnSuccess;
+}
+
+struct OFVariable {
+ char *variableName;
+ UInt32 variableType;
+ UInt32 variablePerm;
+ SInt32 variableOffset;
};
-
-// Guid for Apple System Boot variables
-// 40A0DDD2-77F8-4392-B4A3-1E7304206516
-UUID_DEFINE(gAppleSystemVariableGuid, 0x40, 0xA0, 0xDD, 0xD2, 0x77, 0xF8, 0x43, 0x92, 0xB4, 0xA3, 0x1E, 0x73, 0x04, 0x20, 0x65, 0x16);
-
-// Apple NVRAM Variable namespace (APPLE_VENDOR_OS_VARIABLE_GUID)
-// 7C436110-AB2A-4BBB-A880-FE41995C9F82
-UUID_DEFINE(gAppleNVRAMGuid, 0x7C, 0x43, 0x61, 0x10, 0xAB, 0x2A, 0x4B, 0xBB, 0xA8, 0x80, 0xFE, 0x41, 0x99, 0x5C, 0x9F, 0x82);
-
-// Wifi NVRAM namespace
-// 36C28AB5-6566-4C50-9EBD-CBB920F83843
-UUID_DEFINE(gAppleWifiGuid, 0x36, 0xC2, 0x8A, 0xB5, 0x65, 0x66, 0x4C, 0x50, 0x9E, 0xBD, 0xCB, 0xB9, 0x20, 0xF8, 0x38, 0x43);
-
-// Prefix for kernel-only variables
-#define KERNEL_ONLY_VAR_NAME_PREFIX "krn."
-
-static TUNABLE(uint8_t, gNVRAMLogging, "nvram-log", kIONVRAMNoLogs);
-static TUNABLE(bool, gRestoreBoot, "-restore", false);
-static bool gInternalBuild = false;
-
-// IONVRAMSystemVariableListInternal:
-// Used for internal builds only
-// "force-lock-bits" used by fwam over ssh nvram to device so they are unable to use entitlements
-// "stress-rack" used in SEG stress-rack restore prdocs
-#define IONVRAMSystemVariableListInternal IONVRAMSystemVariableList, \
- "force-lock-bits", \
- "stress-rack"
-
-// allowlist variables from macboot that need to be set/get from system region if present
-static const char * const gNVRAMSystemList[] = { IONVRAMSystemVariableList, nullptr };
-static const char * const gNVRAMSystemListInternal[] = { IONVRAMSystemVariableListInternal, nullptr };
-
-typedef struct {
- const char *name;
- IONVRAMVariableType type;
-} VariableTypeEntry;
-
-static const
-VariableTypeEntry gVariableTypes[] = {
- {"auto-boot?", kOFVariableTypeBoolean},
- {"boot-args", kOFVariableTypeString},
- {"boot-command", kOFVariableTypeString},
- {"boot-device", kOFVariableTypeString},
- {"boot-file", kOFVariableTypeString},
- {"boot-screen", kOFVariableTypeString},
- {"boot-script", kOFVariableTypeString},
- {"console-screen", kOFVariableTypeString},
- {"default-client-ip", kOFVariableTypeString},
- {"default-gateway-ip", kOFVariableTypeString},
- {"default-mac-address?", kOFVariableTypeBoolean},
- {"default-router-ip", kOFVariableTypeString},
- {"default-server-ip", kOFVariableTypeString},
- {"default-subnet-mask", kOFVariableTypeString},
- {"diag-device", kOFVariableTypeString},
- {"diag-file", kOFVariableTypeString},
- {"diag-switch?", kOFVariableTypeBoolean},
- {"fcode-debug?", kOFVariableTypeBoolean},
- {"input-device", kOFVariableTypeString},
- {"input-device-1", kOFVariableTypeString},
- {"little-endian?", kOFVariableTypeBoolean},
- {"ldm", kOFVariableTypeBoolean},
- {"load-base", kOFVariableTypeNumber},
- {"mouse-device", kOFVariableTypeString},
- {"nvramrc", kOFVariableTypeString},
- {"oem-banner", kOFVariableTypeString},
- {"oem-banner?", kOFVariableTypeBoolean},
- {"oem-logo", kOFVariableTypeString},
- {"oem-logo?", kOFVariableTypeBoolean},
- {"output-device", kOFVariableTypeString},
- {"output-device-1", kOFVariableTypeString},
- {"pci-probe-list", kOFVariableTypeNumber},
- {"pci-probe-mask", kOFVariableTypeNumber},
- {"real-base", kOFVariableTypeNumber},
- {"real-mode?", kOFVariableTypeBoolean},
- {"real-size", kOFVariableTypeNumber},
- {"screen-#columns", kOFVariableTypeNumber},
- {"screen-#rows", kOFVariableTypeNumber},
- {"security-mode", kOFVariableTypeString},
- {"selftest-#megs", kOFVariableTypeNumber},
- {"use-generic?", kOFVariableTypeBoolean},
- {"use-nvramrc?", kOFVariableTypeBoolean},
- {"virt-base", kOFVariableTypeNumber},
- {"virt-size", kOFVariableTypeNumber},
- // Variables used for testing
- {"test-bool", kOFVariableTypeBoolean},
- {"test-num", kOFVariableTypeNumber},
- {"test-str", kOFVariableTypeString},
- {"test-data", kOFVariableTypeData},
-#if !defined(__x86_64__)
- {"acc-cm-override-charger-count", kOFVariableTypeNumber},
- {"acc-cm-override-count", kOFVariableTypeNumber},
- {"acc-mb-ld-lifetime", kOFVariableTypeNumber},
- {"com.apple.System.boot-nonce", kOFVariableTypeString},
- {"darkboot", kOFVariableTypeBoolean},
- {"enter-tdm-mode", kOFVariableTypeBoolean},
-#endif /* !defined(__x86_64__) */
- {nullptr, kOFVariableTypeData} // Default type to return
+typedef struct OFVariable OFVariable;
+
+enum {
+ kOWVariableOffsetNumber = 8,
+ kOWVariableOffsetString = 17
};
-union VariablePermission {
- struct {
- uint64_t UserWrite :1;
- uint64_t RootRequired :1;
- uint64_t KernelOnly :1;
- uint64_t ResetNVRAMOnlyDelete :1;
- uint64_t NeverAllowedToDelete :1;
- uint64_t SystemReadHidden :1;
- uint64_t FullAccess :1;
- uint64_t InternalOnly :1;
- uint64_t TestingOnly :1;
- uint64_t RestoreModifyOnly :1;
- uint64_t Reserved:57;
- } Bits;
- uint64_t Uint64;
+OFVariable gOFVariables[] = {
+ {"little-endian?", kOFVariableTypeBoolean, kOFVariablePermUserRead, 0},
+ {"real-mode?", kOFVariableTypeBoolean, kOFVariablePermUserRead, 1},
+ {"auto-boot?", kOFVariableTypeBoolean, kOFVariablePermUserRead, 2},
+ {"diag-switch?", kOFVariableTypeBoolean, kOFVariablePermUserRead, 3},
+ {"fcode-debug?", kOFVariableTypeBoolean, kOFVariablePermUserRead, 4},
+ {"oem-banner?", kOFVariableTypeBoolean, kOFVariablePermUserRead, 5},
+ {"oem-logo?", kOFVariableTypeBoolean, kOFVariablePermUserRead, 6},
+ {"use-nvramrc?", kOFVariableTypeBoolean, kOFVariablePermUserRead, 7},
+ {"use-generic?", kOFVariableTypeBoolean, kOFVariablePermUserRead, -1},
+ {"default-mac-address?", kOFVariableTypeBoolean, kOFVariablePermUserRead,-1},
+ {"real-base", kOFVariableTypeNumber, kOFVariablePermUserRead, 8},
+ {"real-size", kOFVariableTypeNumber, kOFVariablePermUserRead, 9},
+ {"virt-base", kOFVariableTypeNumber, kOFVariablePermUserRead, 10},
+ {"virt-size", kOFVariableTypeNumber, kOFVariablePermUserRead, 11},
+ {"load-base", kOFVariableTypeNumber, kOFVariablePermUserRead, 12},
+ {"pci-probe-list", kOFVariableTypeNumber, kOFVariablePermUserRead, 13},
+ {"pci-probe-mask", kOFVariableTypeNumber, kOFVariablePermUserRead, -1},
+ {"screen-#columns", kOFVariableTypeNumber, kOFVariablePermUserRead, 14},
+ {"screen-#rows", kOFVariableTypeNumber, kOFVariablePermUserRead, 15},
+ {"selftest-#megs", kOFVariableTypeNumber, kOFVariablePermUserRead, 16},
+ {"boot-device", kOFVariableTypeString, kOFVariablePermUserRead, 17},
+ {"boot-file", kOFVariableTypeString, kOFVariablePermUserRead, 18},
+ {"boot-screen", kOFVariableTypeString, kOFVariablePermUserRead, -1},
+ {"console-screen", kOFVariableTypeString, kOFVariablePermUserRead, -1},
+ {"diag-device", kOFVariableTypeString, kOFVariablePermUserRead, 19},
+ {"diag-file", kOFVariableTypeString, kOFVariablePermUserRead, 20},
+ {"input-device", kOFVariableTypeString, kOFVariablePermUserRead, 21},
+ {"output-device", kOFVariableTypeString, kOFVariablePermUserRead, 22},
+ {"input-device-1", kOFVariableTypeString, kOFVariablePermUserRead, -1},
+ {"output-device-1", kOFVariableTypeString, kOFVariablePermUserRead, -1},
+ {"mouse-device", kOFVariableTypeString, kOFVariablePermUserRead, -1},
+ {"oem-banner", kOFVariableTypeString, kOFVariablePermUserRead, 23},
+ {"oem-logo", kOFVariableTypeString, kOFVariablePermUserRead, 24},
+ {"nvramrc", kOFVariableTypeString, kOFVariablePermUserRead, 25},
+ {"boot-command", kOFVariableTypeString, kOFVariablePermUserRead, 26},
+ {"default-client-ip", kOFVariableTypeString, kOFVariablePermUserRead, -1},
+ {"default-server-ip", kOFVariableTypeString, kOFVariablePermUserRead, -1},
+ {"default-gateway-ip", kOFVariableTypeString, kOFVariablePermUserRead, -1},
+ {"default-subnet-mask", kOFVariableTypeString, kOFVariablePermUserRead, -1},
+ {"default-router-ip", kOFVariableTypeString, kOFVariablePermUserRead, -1},
+ {"boot-script", kOFVariableTypeString, kOFVariablePermUserRead, -1},
+ {"boot-args", kOFVariableTypeString, kOFVariablePermUserRead, -1},
+ {"aapl,pci", kOFVariableTypeData, kOFVariablePermRootOnly, -1},
+ {"security-mode", kOFVariableTypeString, kOFVariablePermUserRead, -1},
+ {"security-password", kOFVariableTypeData, kOFVariablePermRootOnly, -1},
+ {0, kOFVariableTypeData, kOFVariablePermUserRead, -1}
};
-typedef struct {
- const char *name;
- VariablePermission p;
-} VariablePermissionEntry;
-
-static const
-VariablePermissionEntry gVariablePermissions[] = {
- {"aapl,pci", .p.Bits.RootRequired = 1},
- {"battery-health", .p.Bits.RootRequired = 1,
- .p.Bits.NeverAllowedToDelete = 1},
- {"boot-image", .p.Bits.UserWrite = 1},
- {"com.apple.System.fp-state", .p.Bits.KernelOnly = 1},
- {"enable-ephdm", .p.Bits.RestoreModifyOnly = 1},
- {"fm-account-masked", .p.Bits.RootRequired = 1,
- .p.Bits.NeverAllowedToDelete = 1},
- {"fm-activation-locked", .p.Bits.RootRequired = 1,
- .p.Bits.NeverAllowedToDelete = 1},
- {"fm-spkeys", .p.Bits.RootRequired = 1,
- .p.Bits.NeverAllowedToDelete = 1},
- {"fm-spstatus", .p.Bits.RootRequired = 1,
- .p.Bits.NeverAllowedToDelete = 1},
- {"policy-nonce-digests", .p.Bits.ResetNVRAMOnlyDelete = 1}, // Deleting this via user triggered obliterate leave J273a unable to boot
- {"recoveryos-passcode-blob", .p.Bits.SystemReadHidden = 1},
- {"security-password", .p.Bits.RootRequired = 1},
- {"system-passcode-lock-blob", .p.Bits.SystemReadHidden = 1},
-
-#if !defined(__x86_64__)
- {"acc-cm-override-charger-count", .p.Bits.KernelOnly = 1},
- {"acc-cm-override-count", .p.Bits.KernelOnly = 1},
- {"acc-mb-ld-lifetime", .p.Bits.KernelOnly = 1},
- {"backlight-level", .p.Bits.UserWrite = 1},
- {"backlight-nits", .p.Bits.UserWrite = 1},
- {"ldm", .p.Bits.KernelOnly = 1},
- {"com.apple.System.boot-nonce", .p.Bits.KernelOnly = 1},
- {"com.apple.System.sep.art", .p.Bits.KernelOnly = 1},
- {"darkboot", .p.Bits.UserWrite = 1},
- {"nonce-seeds", .p.Bits.KernelOnly = 1},
-#endif /* !defined(__x86_64__) */
- // Variables used for testing permissions
- {"testSysReadHidden", .p.Bits.SystemReadHidden = 1,
- .p.Bits.TestingOnly = 1},
- {"testKernelOnly", .p.Bits.KernelOnly = 1,
- .p.Bits.TestingOnly = 1},
- {"testResetOnlyDel", .p.Bits.ResetNVRAMOnlyDelete = 1,
- .p.Bits.TestingOnly = 1},
- {"testNeverDel", .p.Bits.NeverAllowedToDelete = 1,
- .p.Bits.TestingOnly = 1},
- {"testUserWrite", .p.Bits.UserWrite = 1,
- .p.Bits.TestingOnly = 1},
- {"testRootReq", .p.Bits.RootRequired = 1,
- .p.Bits.TestingOnly = 1},
- {"reclaim-int", .p.Bits.InternalOnly = 1},
- {nullptr, {.Bits.FullAccess = 1}} // Default access
+UInt32 IODTNVRAM::getOFVariableType(const OSSymbol *propSymbol) const
+{
+ OFVariable *ofVar;
+
+ ofVar = gOFVariables;
+ while (1) {
+ if ((ofVar->variableName == 0) ||
+ propSymbol->isEqualTo(ofVar->variableName)) break;
+ ofVar++;
+ }
+
+ return ofVar->variableType;
+}
+
+UInt32 IODTNVRAM::getOFVariablePerm(const OSSymbol *propSymbol) const
+{
+ OFVariable *ofVar;
+
+ ofVar = gOFVariables;
+ while (1) {
+ if ((ofVar->variableName == 0) ||
+ propSymbol->isEqualTo(ofVar->variableName)) break;
+ ofVar++;
+ }
+
+ return ofVar->variablePerm;
+}
+
+bool IODTNVRAM::getOWVariableInfo(UInt32 variableNumber, const OSSymbol **propSymbol,
+ UInt32 *propType, UInt32 *propOffset)
+{
+ OFVariable *ofVar;
+
+ ofVar = gOFVariables;
+ while (1) {
+ if (ofVar->variableName == 0) return false;
+
+ if (ofVar->variableOffset == (SInt32) variableNumber) break;
+
+ ofVar++;
+ }
+
+ *propSymbol = OSSymbol::withCStringNoCopy(ofVar->variableName);
+ *propType = ofVar->variableType;
+
+ switch (*propType) {
+ case kOFVariableTypeBoolean :
+ *propOffset = 1 << (31 - variableNumber);
+ break;
+
+ case kOFVariableTypeNumber :
+ *propOffset = variableNumber - kOWVariableOffsetNumber;
+ break;
+
+ case kOFVariableTypeString :
+ *propOffset = variableNumber - kOWVariableOffsetString;
+ break;
+ }
+
+ return true;
+}
+
+bool IODTNVRAM::convertPropToObject(UInt8 *propName, UInt32 propNameLength,
+ UInt8 *propData, UInt32 propDataLength,
+ const OSSymbol **propSymbol,
+ OSObject **propObject)
+{
+ UInt32 propType;
+ const OSSymbol *tmpSymbol;
+ OSObject *tmpObject;
+ OSNumber *tmpNumber;
+ OSString *tmpString;
+
+ // Create the symbol.
+ propName[propNameLength] = '\0';
+ tmpSymbol = OSSymbol::withCString((const char *)propName);
+ propName[propNameLength] = '=';
+ if (tmpSymbol == 0) {
+ return false;
+ }
+
+ propType = getOFVariableType(tmpSymbol);
+
+ // Create the object.
+ tmpObject = 0;
+ switch (propType) {
+ case kOFVariableTypeBoolean :
+ if (!strncmp("true", (const char *)propData, propDataLength)) {
+ tmpObject = kOSBooleanTrue;
+ } else if (!strncmp("false", (const char *)propData, propDataLength)) {
+ tmpObject = kOSBooleanFalse;
+ }
+ break;
+
+ case kOFVariableTypeNumber :
+ tmpNumber = OSNumber::withNumber(strtol((const char *)propData, 0, 0), 32);
+ if (tmpNumber != 0) tmpObject = tmpNumber;
+ break;
+
+ case kOFVariableTypeString :
+ tmpString = OSString::withCString((const char *)propData);
+ if (tmpString != 0) tmpObject = tmpString;
+ break;
+
+ case kOFVariableTypeData :
+ tmpObject = unescapeBytesToData(propData, propDataLength);
+ break;
+ }
+
+ if (tmpObject == 0) {
+ tmpSymbol->release();
+ return false;
+ }
+
+ *propSymbol = tmpSymbol;
+ *propObject = tmpObject;
+
+ return true;
+}
+
+bool IODTNVRAM::convertObjectToProp(UInt8 *buffer, UInt32 *length,
+ const OSSymbol *propSymbol, OSObject *propObject)
+{
+ UInt8 *propName;
+ UInt32 propNameLength, propDataLength;
+ UInt32 propType, tmpValue;
+ OSBoolean *tmpBoolean = 0;
+ OSNumber *tmpNumber = 0;
+ OSString *tmpString = 0;
+ OSData *tmpData = 0;
+
+ propName = (UInt8 *)propSymbol->getCStringNoCopy();
+ propNameLength = propSymbol->getLength();
+ propType = getOFVariableType(propSymbol);
+
+ // Get the size of the data.
+ propDataLength = 0xFFFFFFFF;
+ switch (propType) {
+ case kOFVariableTypeBoolean :
+ tmpBoolean = OSDynamicCast(OSBoolean, propObject);
+ if (tmpBoolean != 0) propDataLength = 5;
+ break;
+
+ case kOFVariableTypeNumber :
+ tmpNumber = OSDynamicCast(OSNumber, propObject);
+ if (tmpNumber != 0) propDataLength = 10;
+ break;
+
+ case kOFVariableTypeString :
+ tmpString = OSDynamicCast(OSString, propObject);
+ if (tmpString != 0) propDataLength = tmpString->getLength();
+ break;
+
+ case kOFVariableTypeData :
+ tmpData = OSDynamicCast(OSData, propObject);
+ if (tmpData != 0) {
+ tmpData = escapeDataToData(tmpData);
+ propDataLength = tmpData->getLength();
+ }
+ break;
+ }
+
+ // Make sure the propertySize is known and will fit.
+ if (propDataLength == 0xFFFFFFFF) return false;
+ if ((propNameLength + propDataLength + 2) > *length) return false;
+
+ // Copy the property name equal sign.
+ sprintf((char *)buffer, "%s=", propName);
+ buffer += propNameLength + 1;
+
+ switch (propType) {
+ case kOFVariableTypeBoolean :
+ if (tmpBoolean->getValue()) {
+ strcpy((char *)buffer, "true");
+ } else {
+ strcpy((char *)buffer, "false");
+ }
+ break;
+
+ case kOFVariableTypeNumber :
+ tmpValue = tmpNumber->unsigned32BitValue();
+ if (tmpValue == 0xFFFFFFFF) {
+ strcpy((char *)buffer, "-1");
+ } else if (tmpValue < 1000) {
+ sprintf((char *)buffer, "%ld", tmpValue);
+ } else {
+ sprintf((char *)buffer, "0x%lx", tmpValue);
+ }
+ break;
+
+ case kOFVariableTypeString :
+ strcpy((char *)buffer, tmpString->getCStringNoCopy());
+ break;
+
+ case kOFVariableTypeData :
+ bcopy(tmpData->getBytesNoCopy(), buffer, propDataLength);
+ tmpData->release();
+ break;
+ }
+
+ propDataLength = strlen((const char *)buffer);
+
+ *length = propNameLength + propDataLength + 2;
+
+ return true;
+}
+
+
+UInt16 IODTNVRAM::generateOWChecksum(UInt8 *buffer)
+{
+ UInt32 cnt, checksum = 0;
+ UInt16 *tmpBuffer = (UInt16 *)buffer;
+
+ for (cnt = 0; cnt < _ofPartitionSize / 2; cnt++)
+ checksum += tmpBuffer[cnt];
+
+ return checksum % 0x0000FFFF;
+}
+
+bool IODTNVRAM::validateOWChecksum(UInt8 *buffer)
+{
+ UInt32 cnt, checksum, sum = 0;
+ UInt16 *tmpBuffer = (UInt16 *)buffer;
+
+ for (cnt = 0; cnt < _ofPartitionSize / 2; cnt++)
+ sum += tmpBuffer[cnt];
+
+ checksum = (sum >> 16) + (sum & 0x0000FFFF);
+ if (checksum == 0x10000) checksum--;
+ checksum = (checksum ^ 0x0000FFFF) & 0x0000FFFF;
+
+ return checksum == 0;
+}
+
+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;
+
+ tmpString = OSDynamicCast(OSString, value);
+ if (tmpString == 0) return;
+
+ if (key->isEqualTo("boot-command")) {
+ wasBootArgs = false;
+ bootCommand = tmpString;
+ } else if (key->isEqualTo("boot-args")) {
+ wasBootArgs = true;
+ bootArgs = tmpString;
+ bootCommand = OSDynamicCast(OSString, _ofDict->getObject("boot-command"));
+ if (bootCommand == 0) return;
+ } else return;
+
+ bootCommandData = (UInt8 *)bootCommand->getCStringNoCopy();
+ bootCommandDataLength = bootCommand->getLength();
+
+ if (bootCommandData == 0) return;
+
+ for (cnt = 0; cnt < bootCommandDataLength; cnt++) {
+ if ((bootCommandData[cnt] == 'b') &&
+ !strncmp("bootr", (const char *)bootCommandData + cnt, 5)) {
+ cnt += 5;
+ while (bootCommandData[cnt] == ' ') cnt++;
+ bootr = true;
+ break;
+ }
+ }
+ if (!bootr) {
+ _ofDict->removeObject("boot-args");
+ return;
+ }
+
+ if (wasBootArgs) {
+ bootArgsData = (UInt8 *)bootArgs->getCStringNoCopy();
+ bootArgsDataLength = bootArgs->getLength();
+ if (bootArgsData == 0) return;
+
+ tmpDataLength = cnt + bootArgsDataLength;
+ 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);
+
+ bootCommand = OSString::withCString((const char *)tmpData);
+ if (bootCommand != 0) {
+ _ofDict->setObject("boot-command", bootCommand);
+ bootCommand->release();
+ }
+
+ IODelete(tmpData, UInt8, tmpDataLength + 1);
+ } else {
+ bootArgs = OSString::withCString((const char *)(bootCommandData + cnt));
+ if (bootArgs != 0) {
+ _ofDict->setObject("boot-args", bootArgs);
+ bootArgs->release();
+ }
+ }
+}
+
+
+// Private methods for Name Registry access.
+
+enum {
+ kMaxNVNameLength = 4,
+ kMaxNVDataLength = 8
};
-typedef struct {
- const uint8_t checkOp;
- const uuid_t *varGuid;
- const char *varName;
- const char *varEntitlement;
-} VariableEntitlementEntry;
-
-// variable-guid pair entries that require entitlement check to do specified nvram operations
-static const
-VariableEntitlementEntry gVariableEntitlements[] = {
- {OP_MOD_RST, &gAppleNVRAMGuid, "ownership-warning", "com.apple.private.iokit.ddl-write"},
- {OP_MOD, &gAppleSystemVariableGuid, "BluetoothInfo", "com.apple.private.iokit.nvram-bluetooth"},
- {OP_MOD, &gAppleSystemVariableGuid, "BluetoothUHEDevices", "com.apple.private.iokit.nvram-bluetooth"},
- {OP_MOD, &gAppleNVRAMGuid, "bluetoothExternalDongleFailed", "com.apple.private.iokit.nvram-bluetooth"},
- {OP_MOD, &gAppleNVRAMGuid, "bluetoothInternalControllerInfo", "com.apple.private.iokit.nvram-bluetooth"},
- {OP_RD, &gAppleSystemVariableGuid, "current-network", "com.apple.private.security.nvram.wifi-psks"},
- {OP_RD, &gAppleWifiGuid, "current-network", "com.apple.private.security.nvram.wifi-psks"},
- {OP_RD, &gAppleSystemVariableGuid, "preferred-networks", "com.apple.private.security.nvram.wifi-psks"},
- {OP_RD, &gAppleWifiGuid, "preferred-networks", "com.apple.private.security.nvram.wifi-psks"},
- {OP_RD, &gAppleSystemVariableGuid, "preferred-count", "com.apple.private.security.nvram.wifi-psks"},
- {OP_RD, &gAppleWifiGuid, "preferred-count", "com.apple.private.security.nvram.wifi-psks"},
- {OP_MOD_RD, &gAppleSystemVariableGuid, "fmm-mobileme-token-FMM", "com.apple.private.security.nvram.fmm"},
- {OP_MOD_RD, &gAppleNVRAMGuid, "fmm-mobileme-token-FMM", "com.apple.private.security.nvram.fmm"},
- {OP_MOD_RD, &gAppleSystemVariableGuid, "fmm-mobileme-token-FMM-BridgeHasAccount", "com.apple.private.security.nvram.fmm"},
- {OP_MOD_RD, &gAppleNVRAMGuid, "fmm-mobileme-token-FMM-BridgeHasAccount", "com.apple.private.security.nvram.fmm"},
- {OP_MOD_RD, &gAppleSystemVariableGuid, "fmm-computer-name", "com.apple.private.security.nvram.fmm"},
- {OP_MOD_RD, &gAppleNVRAMGuid, "fmm-computer-name", "com.apple.private.security.nvram.fmm"},
- {OP_MOD, &gAppleSystemVariableGuid, "rdma-enable", "com.apple.private.iokit.rdma"},
- {OP_MOD, &gAppleNVRAMGuid, "rdma-enable", "com.apple.private.iokit.rdma"},
- // Variables used for testing entitlement
- {OP_MOD_RST, &gAppleNVRAMGuid, "testEntModRst", "com.apple.private.iokit.testEntModRst"},
- {OP_MOD_RST, &gAppleSystemVariableGuid, "testEntModRstSys", "com.apple.private.iokit.testEntModRst"},
- {OP_RST, &gAppleNVRAMGuid, "testEntRst", "com.apple.private.iokit.testEntRst"},
- {OP_RST, &gAppleSystemVariableGuid, "testEntRstSys", "com.apple.private.iokit.testEntRst"},
- {OP_RD, &gAppleNVRAMGuid, "testEntRd", "com.apple.private.iokit.testEntRd"},
- {OP_RD, &gAppleSystemVariableGuid, "testEntRdSys", "com.apple.private.iokit.testEntRd"},
- {OP_DEL, &gAppleNVRAMGuid, "testEntDel", "com.apple.private.iokit.testEntDel"},
- {OP_DEL, &gAppleSystemVariableGuid, "testEntDelSys", "com.apple.private.iokit.testEntDel"},
- {0, &UUID_NULL, nullptr, nullptr}
+#pragma options align=mac68k
+struct NVRAMProperty
+{
+ IONVRAMDescriptor header;
+ UInt8 nameLength;
+ UInt8 name[ kMaxNVNameLength ];
+ UInt8 dataLength;
+ UInt8 data[ kMaxNVDataLength ];
};
-
-static NVRAMPartitionType
-getPartitionTypeForGUID(const uuid_t guid)
-{
- if (uuid_compare(guid, gAppleSystemVariableGuid) == 0) {
- return kIONVRAMPartitionSystem;
- } else {
- return kIONVRAMPartitionCommon;
- }
-}
-
-static IONVRAMVariableType
-getVariableType(const char *propName)
-{
- const VariableTypeEntry *entry;
-
- entry = gVariableTypes;
- while (entry->name != nullptr) {
- if (strcmp(entry->name, propName) == 0) {
- break;
- }
- entry++;
- }
-
- return entry->type;
-}
-
-static IONVRAMVariableType
-getVariableType(const OSSymbol *propSymbol)
-{
- return getVariableType(propSymbol->getCStringNoCopy());
-}
-
-static VariablePermission
-getVariablePermission(const char *propName)
-{
- const VariablePermissionEntry *entry;
-
- entry = gVariablePermissions;
- while (entry->name != nullptr) {
- if (strcmp(entry->name, propName) == 0) {
- break;
- }
- entry++;
- }
-
- return entry->p;
-}
-
-static bool
-variableInAllowList(const char *varName)
-{
- unsigned int i = 0;
- const char * const *list = gInternalBuild ? gNVRAMSystemListInternal : gNVRAMSystemList;
-
- while (list[i] != nullptr) {
- if (strcmp(varName, list[i]) == 0) {
- return true;
- }
- i++;
- }
-
- return false;
-}
-
-static bool
-verifyWriteSizeLimit(const uuid_t varGuid, const char *variableName, size_t propDataSize)
-{
- if (variableInAllowList(variableName)) {
- return propDataSize <= BOOT_LINE_LENGTH;
- }
-
- return true;
-}
-
-#if defined(DEBUG) || defined(DEVELOPMENT)
-static const char *
-getNVRAMOpString(IONVRAMOperation op)
-{
- switch (op) {
- case kIONVRAMOperationRead:
- return "Read";
- case kIONVRAMOperationWrite:
- return "Write";
- case kIONVRAMOperationDelete:
- return "Delete";
- case kIONVRAMOperationObliterate:
- return "Obliterate";
- case kIONVRAMOperationReset:
- return "Reset";
- case kIONVRAMOperationInit:
- return "Init";
- default:
- return "Unknown";
- }
-}
-#endif
-
-/*
- * Parse a variable name of the form "GUID:name".
- * If the name cannot be parsed, substitute the Apple global variable GUID.
- * Returns TRUE if a GUID was found in the name, FALSE otherwise.
- * The guidResult and nameResult arguments may be nullptr if you just want
- * to check the format of the string.
- */
-static bool
-parseVariableName(const char *key, uuid_t *guidResult, const char **nameResult)
-{
- uuid_string_t temp = {0};
- size_t keyLen = strlen(key);
- bool ok = false;
- const char *name = key;
- uuid_t guid;
-
- if (keyLen > sizeof(temp)) {
- // check for at least UUID + ":" + more
- memcpy(temp, key, sizeof(temp) - 1);
-
- if ((uuid_parse(temp, guid) == 0) &&
- (key[sizeof(temp) - 1] == ':')) {
- name = key + sizeof(temp);
- ok = true;
- }
- }
-
- if (guidResult) {
- ok ? uuid_copy(*guidResult, guid) : uuid_copy(*guidResult, gAppleNVRAMGuid);
- }
- if (nameResult) {
- *nameResult = name;
- }
-
- return ok;
-}
-
-static bool
-parseVariableName(const OSSymbol *key, uuid_t *guidResult, const char **nameResult)
-{
- return parseVariableName(key->getCStringNoCopy(), guidResult, nameResult);
-}
-
-/**
- * @brief Translates(if needed) varGuid and stores it in destGuid
- *
- * @param varGuid guid to translate
- * @param variableName variable name attached to the guid
- * @param destGuid translated guid is saved here
- * @param systemActive boolean to indicate if it has system partition size > 0
- */
-static void
-translateGUID(const uuid_t varGuid, const char *variableName, uuid_t destGuid, bool systemActive, bool log)
-{
- if (varGuid == nullptr || variableName == nullptr || destGuid == nullptr) {
- DEBUG_ERROR("nullptr passed as an argument\n");
- return;
- }
-
- bool systemGuid = uuid_compare(varGuid, gAppleSystemVariableGuid) == 0;
-
- if (systemActive) {
- if (variableInAllowList(variableName)) {
- DEBUG_INFO_IF(log, "Using system GUID due to allow list\n");
- uuid_copy(destGuid, gAppleSystemVariableGuid);
- } else if (systemGuid) {
- DEBUG_INFO_IF(log, "System GUID used\n");
- uuid_copy(destGuid, gAppleSystemVariableGuid);
- } else {
- DEBUG_INFO_IF(log, "Use given guid\n");
- uuid_copy(destGuid, varGuid);
- }
- } else if (systemGuid) {
- DEBUG_INFO_IF(log, "Overriding to Apple guid\n");
- uuid_copy(destGuid, gAppleNVRAMGuid);
- } else {
- DEBUG_INFO_IF(log, "Use given guid\n");
- uuid_copy(destGuid, varGuid);
- }
-}
-
-/**
- * @brief Checks if the variable-guid(translated) pair is present in gVariableEntitlements and if so,
- * does it have the required entitlement for the NVRAM operation passed in
- *
- * @param varGuid guid for the variable to be checked, this gets translated by translateGUID
- * @param varName variable name
- * @param op NVRAM operation
- * @param systemActive used to pass into translateGUID to get the correct guid to check against
- * @param veChecked if variable entitlement is checked, this is set to true
- * @return true if variable wasn't present in gVariableEntitlements,
- * entitlement check wasn't required for operation passed in,
- * or if entitlement check returned true
- * @return false if varName/varGuid/veChecked was NULL or if entitlement check returned false
- */
-static bool
-verifyVarEntitlement(const uuid_t varGuid, const char *varName, IONVRAMOperation op, bool systemActive, bool *veChecked, bool log)
-{
- if (varGuid == nullptr || varName == nullptr || veChecked == nullptr) {
- DEBUG_ERROR("nullptr passed as an argument\n");
- return false;
- }
-
- uuid_t translatedGuid;
- const VariableEntitlementEntry *entry;
- *veChecked = false;
-
- translateGUID(varGuid, varName, translatedGuid, systemActive, log);
-
- entry = gVariableEntitlements;
- while ((entry != nullptr) && (entry->varName != nullptr)) {
- if ((strcmp(entry->varName, varName) == 0) && (uuid_compare(translatedGuid, *(entry->varGuid)) == 0)) {
- // check if task entitlement check is required for this operation
- if (entry->checkOp & (1 << op)) {
- *veChecked = true;
- DEBUG_INFO_IF(log, "Checking entitlement %s for %s for operation %s\n", entry->varEntitlement, varName, getNVRAMOpString(op));
- return IOCurrentTaskHasEntitlement(entry->varEntitlement);
- }
- break;
- }
- entry++;
- }
-
- return true;
-}
-
-static bool
-kernelOnlyVar(const char *varName)
-{
- if (strncmp(varName, KERNEL_ONLY_VAR_NAME_PREFIX, sizeof(KERNEL_ONLY_VAR_NAME_PREFIX) - 1) == 0) {
- return true;
- }
-
- return false;
-}
-
-static bool
-verifyPermission(IONVRAMOperation op, const uuid_t varGuid, const char *varName, const bool systemActive, bool log)
-{
- VariablePermission perm;
- bool kernel, varEntitled, writeEntitled = false, readEntitled = false, allowList, systemGuid = false, systemEntitled = false, systemInternalEntitled = false, systemAllow, systemReadHiddenAllow = false;
- bool admin = false;
- bool ok = false;
-
- if (verifyVarEntitlement(varGuid, varName, op, systemActive, &varEntitled, log) == false) {
- goto exit;
- }
-
- perm = getVariablePermission(varName);
-
- kernel = current_task() == kernel_task;
- if (perm.Bits.KernelOnly || kernelOnlyVar(varName)) {
- DEBUG_INFO_IF(log, "KernelOnly access for %s, kernel=%d\n", varName, kernel);
- ok = kernel;
- goto exit;
- }
-
- if (perm.Bits.RestoreModifyOnly && (OP_MOD & (1 << op))) {
- DEBUG_INFO_IF(log, "RestoreModifyOnly access for %s, gRestoreBoot=%d\n", varName, gRestoreBoot);
- ok = gRestoreBoot;
- goto exit;
- }
-
- if (perm.Bits.InternalOnly && !gInternalBuild) {
- DEBUG_INFO_IF(log, "InternalOnly access for %s, gInternalBuild=%d\n", varName, gInternalBuild);
- goto exit;
- }
-
- allowList = variableInAllowList(varName);
- systemGuid = uuid_compare(varGuid, gAppleSystemVariableGuid) == 0;
- admin = IOUserClient::clientHasPrivilege(current_task(), kIONVRAMPrivilege) == kIOReturnSuccess;
- writeEntitled = IOCurrentTaskHasEntitlement(kIONVRAMWriteAccessKey);
- readEntitled = IOCurrentTaskHasEntitlement(kIONVRAMReadAccessKey);
- systemEntitled = IOCurrentTaskHasEntitlement(kIONVRAMSystemAllowKey);
- systemInternalEntitled = IOCurrentTaskHasEntitlement(kIONVRAMSystemInternalAllowKey);
- systemReadHiddenAllow = IOCurrentTaskHasEntitlement(kIONVRAMSystemHiddenAllowKey);
-
- systemAllow = systemEntitled || (systemInternalEntitled && gInternalBuild) || kernel;
-
- switch (op) {
- case kIONVRAMOperationRead:
- if (systemGuid && perm.Bits.SystemReadHidden) {
- ok = systemReadHiddenAllow;
- } else if (kernel || admin || readEntitled || perm.Bits.FullAccess || varEntitled) {
- ok = true;
- }
- break;
-
- case kIONVRAMOperationWrite:
- if (kernel || perm.Bits.UserWrite || admin || writeEntitled || varEntitled) {
- if (systemGuid) {
- if (allowList) {
- if (!systemAllow) {
- DEBUG_ERROR("Allowed write to system region when NOT entitled for %s\n", varName);
- }
- } else if (varEntitled) {
- DEBUG_INFO_IF(log, "Allowed write to system region using variable specific entitlement for %s\n", varName);
- } else if (!systemAllow) {
- DEBUG_ERROR("Not entitled for system region writes for %s\n", varName);
- break;
- }
- }
- ok = true;
- }
- break;
-
- case kIONVRAMOperationDelete:
- case kIONVRAMOperationObliterate:
- case kIONVRAMOperationReset:
- if (perm.Bits.NeverAllowedToDelete) {
- DEBUG_INFO_IF(log, "Never allowed to delete %s\n", varName);
- break;
- } else if ((op == kIONVRAMOperationObliterate) && perm.Bits.ResetNVRAMOnlyDelete) {
- DEBUG_INFO_IF(log, "Not allowed to obliterate %s\n", varName);
- break;
- } else if ((op == kIONVRAMOperationDelete) && perm.Bits.ResetNVRAMOnlyDelete) {
- DEBUG_INFO_IF(log, "Only allowed to delete %s via NVRAM reset\n", varName);
- break;
- }
-
- if (kernel || perm.Bits.UserWrite || admin || writeEntitled || varEntitled) {
- if (systemGuid) {
- if (allowList) {
- if (!systemAllow) {
- DEBUG_ERROR("Allowed delete to system region when NOT entitled for %s\n", varName);
- }
- } else if (varEntitled) {
- DEBUG_INFO_IF(log, "Allowed delete to system region using variable specific entitlement for %s\n", varName);
- } else if (!systemAllow) {
- DEBUG_ERROR("Not entitled for system region deletes for %s\n", varName);
- break;
- }
- }
- ok = true;
- }
- break;
-
- case kIONVRAMOperationInit:
- break;
- }
-
-exit:
- DEBUG_INFO_IF(log, "Permission for %s of %s %s: I=%d R=%d kern=%d, adm=%d, wE=%d, rE=%d, sG=%d, sEd=%d, sIEd=%d, sRHA=%d, UW=%d, vE=%d\n", getNVRAMOpString(op), varName, ok ? "granted" : "denied",
- gInternalBuild, gRestoreBoot, kernel, admin, writeEntitled, readEntitled, systemGuid, systemEntitled, systemInternalEntitled, systemReadHiddenAllow, perm.Bits.UserWrite, varEntitled);
-
- return ok;
-}
-
-static bool
-verifyPermission(IONVRAMOperation op, const OSSymbol *canonicalKey, const bool systemActive)
-{
- const char *varName;
- uuid_t varGuid;
-
- parseVariableName(canonicalKey->getCStringNoCopy(), &varGuid, &varName);
-
- return verifyPermission(op, varGuid, varName, systemActive, true);
-}
-
-static bool
-skipKey(const OSSymbol *aKey)
-{
- return aKey->isEqualTo(kIORegistryEntryAllowableSetPropertiesKey) ||
- aKey->isEqualTo(kIORegistryEntryDefaultLockingSetPropertiesKey) ||
- aKey->isEqualTo(kIOClassNameOverrideKey) ||
- aKey->isEqualTo(kIOBSDNameKey) ||
- aKey->isEqualTo(kIOBSDNamesKey) ||
- aKey->isEqualTo(kIOBSDMajorKey) ||
- aKey->isEqualTo(kIOBSDMinorKey) ||
- aKey->isEqualTo(kIOBSDUnitKey) ||
- aKey->isEqualTo(kIOUserServicePropertiesKey) ||
- aKey->isEqualTo(kIOExclaveAssignedKey) ||
- aKey->isEqualTo(kIOMatchCategoryKey) ||
- aKey->isEqualTo(kIOBusyInterest);
-}
-
-static OSSharedPtr<const OSSymbol>
-keyWithGuidAndCString(const uuid_t guid, const char * cstring)
-{
- size_t length;
- OSSharedPtr<const OSSymbol> symbolObj;
- char *canonicalString;
-
- length = sizeof(uuid_string_t) - 1 + sizeof(':') + strlen(cstring) + 1;
-
- canonicalString = (char *) IOMallocZeroData(length);
- if (canonicalString == nullptr) {
- return NULL;
- }
-
- uuid_unparse(guid, *((uuid_string_t*)canonicalString));
- canonicalString[sizeof(uuid_string_t) - 1] = ':';
-
- strlcpy(&canonicalString[sizeof(uuid_string_t)], cstring, length - sizeof(uuid_string_t));
-
- symbolObj = OSSymbol::withCString(canonicalString);
- IOFreeData(canonicalString, length);
-
- return symbolObj;
-}
-
-static void
-dumpDict(OSSharedPtr<OSDictionary> dict)
-{
- const OSSymbol *key;
- OSSharedPtr<OSCollectionIterator> iter;
- unsigned int count = 0;
-
- iter = OSCollectionIterator::withCollection(dict.get());
- require_action(iter, exit, DEBUG_ERROR("Failed to create iterator\n"));
-
- DEBUG_INFO("Dumping dict...\n");
- while ((key = OSDynamicCast(OSSymbol, iter->getNextObject()))) {
- count++;
- DEBUG_INFO("%u: %s\n", count, key->getCStringNoCopy());
- }
-exit:
- return;
-}
-
-static void
-dumpData(const char *name, OSSharedPtr<OSData> propData)
-{
- if (!IS_LOG_BIT_SET(kIONVRAMDataHexDump) || !propData) {
- return;
- }
-
- uint8_t *dataBuf = (uint8_t *)propData->getBytesNoCopy();
- size_t propDataSize = propData->getLength();
-
- if (dataBuf == nullptr || propDataSize == 0) {
- return;
- }
-
- IOLog("%s:%s:%u - %s: ", __FILE_NAME__, __FUNCTION__, __LINE__, name);
- for (size_t i = 0; i < propDataSize; i++) {
- // if printable character, use that
- if ((dataBuf[i] >= 0x20 && dataBuf[i] <= 0x7e) && dataBuf[i] != '%') {
- IOLog("%c", dataBuf[i]);
- } else {
- IOLog("%%%02x", dataBuf[i]);
- }
- }
- IOLog("\n");
-}
-
-
-typedef struct {
- const char *name;
- OSSharedPtr<OSObject> value;
-} ephDMAllowListEntry;
-
-// common region variables to preserve on ephemeral boot
-static
-ephDMAllowListEntry ephDMEntries[] = {
- // Mobile Obliteration clears the following variables after it runs
- { .name = "oblit-begins" },
- { .name = "orig-oblit" },
- { .name = "oblit-failure" },
- { .name = "oblit-inprogress" },
- { .name = "obliteration" },
- // darwin-init is used for configuring internal builds
- { .name = "darwin-init" },
- { .name = "darwin-init-system" }
-};
-
-// ************************** IODTNVRAMPlatformNotifier ****************************
-// private IOService based class for passing notifications to IODTNVRAM
-
-class IODTNVRAMPlatformNotifier : public IOService
-{
- OSDeclareDefaultStructors(IODTNVRAMPlatformNotifier)
-private:
- IODTNVRAM *_provider;
-
-public:
- bool start(IOService * provider) APPLE_KEXT_OVERRIDE;
-
- virtual IOReturn callPlatformFunction( const OSSymbol * functionName,
- bool waitForFunction,
- void *param1, void *param2,
- void *param3, void *param4 ) APPLE_KEXT_OVERRIDE;
-};
-
-OSDefineMetaClassAndStructors(IODTNVRAMPlatformNotifier, IOService)
-
-bool
-IODTNVRAMPlatformNotifier::start(IOService * provider)
-{
- OSSharedPtr<OSSerializer> serializer;
- OSSharedPtr<OSNumber> value = OSNumber::withNumber(1000, 32);
-
- _provider = OSDynamicCast(IODTNVRAM, provider);
- require(_provider != nullptr, error);
-
- setProperty(gIOPlatformWakeActionKey, value.get());
-
- require(super::start(provider), error);
-
- registerService();
-
- return true;
-
-error:
- stop(provider);
-
- return false;
-}
-
-#include <IOKit/IOHibernatePrivate.h>
-#include <IOKit/pwr_mgt/RootDomain.h>
-static const OSSharedPtr<const OSSymbol> gIOHibernateStateKey = OSSymbol::withCString(kIOHibernateStateKey);
-
-static uint32_t
-hibernateState(void)
-{
- OSSharedPtr<OSData> data = OSDynamicPtrCast<OSData>(IOService::getPMRootDomain()->copyProperty(gIOHibernateStateKey.get()->getCStringNoCopy()));
- uint32_t hibernateState = 0;
- if ((data != NULL) && (data->getLength() == sizeof(hibernateState))) {
- memcpy(&hibernateState, data->getBytesNoCopy(), sizeof(hibernateState));
- }
- return hibernateState;
-}
-
-IOReturn
-IODTNVRAMPlatformNotifier::callPlatformFunction( const OSSymbol * functionName,
- bool waitForFunction,
- void *param1, void *param2,
- void *param3, void *param4 )
-{
- if ((functionName == gIOPlatformWakeActionKey) &&
- (hibernateState() == kIOHibernateStateWakingFromHibernate)) {
- DEBUG_INFO("waking from hibernate\n");
- _provider->reload();
- return kIOReturnSuccess;
- }
-
- return super::callPlatformFunction(functionName, waitForFunction, param1, param2, param3, param4);
-}
-
-
-// ************************** IODTNVRAMDiags ****************************
-// private IOService based class for passing notifications to IODTNVRAM
-#define kIODTNVRAMDiagsStatsKey "Stats"
-#define kIODTNVRAMDiagsInitKey "Init"
-#define kIODTNVRAMDiagsReadKey "Read"
-#define kIODTNVRAMDiagsWriteKey "Write"
-#define kIODTNVRAMDiagsDeleteKey "Delete"
-#define kIODTNVRAMDiagsNameKey "Name"
-#define kIODTNVRAMDiagsSizeKey "Size"
-#define kIODTNVRAMDiagsPresentKey "Present"
-
-// private IOService based class for publishing diagnostic info for IODTNVRAM
-class IODTNVRAMDiags : public IOService
-{
- OSDeclareDefaultStructors(IODTNVRAMDiags)
-private:
- IODTNVRAM *_provider;
- IORWLock *_diagLock;
- OSSharedPtr<OSDictionary> _stats;
-
- bool serializeStats(void *, OSSerialize * serializer);
-
-public:
- bool start(IOService * provider) APPLE_KEXT_OVERRIDE;
- void logVariable(NVRAMPartitionType region, IONVRAMOperation op, const char *name, void *data = nullptr, void *offset = nullptr);
-};
-
-OSDefineMetaClassAndStructors(IODTNVRAMDiags, IOService)
-
-bool
-IODTNVRAMDiags::start(IOService * provider)
-{
- OSSharedPtr<OSSerializer> serializer;
-
- _provider = OSDynamicCast(IODTNVRAM, provider);
- require(_provider != nullptr, error);
-
- require(super::start(provider), error);
-
- _diagLock = IORWLockAlloc();
- require(_diagLock != nullptr, error);
-
- _stats = OSDictionary::withCapacity(1);
- require(_stats != nullptr, error);
-
- serializer = OSSerializer::forTarget(this, OSMemberFunctionCast(OSSerializerCallback, this, &IODTNVRAMDiags::serializeStats));
- require(serializer != nullptr, error);
-
- setProperty(kIODTNVRAMDiagsStatsKey, serializer.get());
-
- registerService();
-
- return true;
-
-error:
- stop(provider);
-
- return false;
-}
-
-void
-IODTNVRAMDiags::logVariable(NVRAMPartitionType region, IONVRAMOperation op, const char *name, void *data, void *offset)
-{
- // "Stats" : OSDictionary
- // - "XX:varName" : OSDictionary, XX is the region value prefix to distinguish which dictionary the variable is in
- // - "Init" : OSNumber variable offset (in the proxy image passed via EDT) if variable is present at initialization (unserialize)
- // - "Read" : OSNumber count
- // - "Write" : OSNumber count
- // - "Delete" : OSNumber count
- // - "Size" : OSNumber data size, latest size from either init or write
- // - "Present" : OSBoolean True/False if variable is present or not
- char *entryKey;
- size_t entryKeySize;
- OSSharedPtr<OSDictionary> existingEntry;
- OSSharedPtr<OSNumber> currentCount;
- OSSharedPtr<OSNumber> varSize;
- OSSharedPtr<OSNumber> varOffset;
- const char *opCountKey = nullptr;
-
- entryKeySize = strlen("XX:") + strlen(name) + 1;
- entryKey = IONewData(char, entryKeySize);
- require(entryKey, exit);
-
- snprintf(entryKey, entryKeySize, "%02X:%s", region, name);
-
- NVRAMWRITELOCK(_diagLock);
- existingEntry.reset(OSDynamicCast(OSDictionary, _stats->getObject(entryKey)), OSRetain);
-
- if (existingEntry == nullptr) {
- existingEntry = OSDictionary::withCapacity(4);
- }
-
- switch (op) {
- case kIONVRAMOperationRead:
- opCountKey = kIODTNVRAMDiagsReadKey;
- if (existingEntry->getObject(kIODTNVRAMDiagsPresentKey) == nullptr) {
- existingEntry->setObject(kIODTNVRAMDiagsPresentKey, kOSBooleanFalse);
- }
- break;
- case kIONVRAMOperationWrite:
- opCountKey = kIODTNVRAMDiagsWriteKey;
- varSize = OSNumber::withNumber((size_t)data, 64);
- existingEntry->setObject(kIODTNVRAMDiagsSizeKey, varSize);
- existingEntry->setObject(kIODTNVRAMDiagsPresentKey, kOSBooleanTrue);
- break;
- case kIONVRAMOperationDelete:
- case kIONVRAMOperationObliterate:
- case kIONVRAMOperationReset:
- opCountKey = kIODTNVRAMDiagsDeleteKey;
- existingEntry->setObject(kIODTNVRAMDiagsPresentKey, kOSBooleanFalse);
- break;
- case kIONVRAMOperationInit:
- varSize = OSNumber::withNumber((size_t)data, 64);
- varOffset = OSNumber::withNumber((size_t)offset, 64);
- existingEntry->setObject(kIODTNVRAMDiagsInitKey, varOffset);
- existingEntry->setObject(kIODTNVRAMDiagsSizeKey, varSize);
- existingEntry->setObject(kIODTNVRAMDiagsPresentKey, kOSBooleanTrue);
- break;
- default:
- goto unlock;
- }
-
- if (opCountKey) {
- currentCount.reset(OSDynamicCast(OSNumber, existingEntry->getObject(opCountKey)), OSRetain);
-
- if (currentCount == nullptr) {
- currentCount = OSNumber::withNumber(1, 64);
- } else {
- currentCount->addValue(1);
- }
-
- existingEntry->setObject(opCountKey, currentCount);
- }
-
- _stats->setObject(entryKey, existingEntry);
-
-unlock:
- NVRAMRWUNLOCK(_diagLock);
-
-exit:
- IODeleteData(entryKey, char, entryKeySize);
-
- return;
-}
-
-bool
-IODTNVRAMDiags::serializeStats(void *, OSSerialize * serializer)
-{
- bool ok;
-
- NVRAMREADLOCK(_diagLock);
- ok = _stats->serialize(serializer);
- NVRAMRWUNLOCK(_diagLock);
-
- return ok;
-}
-
-// ************************** IODTNVRAMVariables ****************************
-
-// private IOService based class for publishing distinct dictionary properties on
-// for easy ioreg access since the serializeProperties call is overloaded and is used
-// as variable access
-class IODTNVRAMVariables : public IOService
-{
- OSDeclareDefaultStructors(IODTNVRAMVariables)
-private:
- IODTNVRAM *_provider;
- uuid_t _guid;
- bool _systemActive;
-
-public:
- bool init(const uuid_t guid, const bool systemActive);
- virtual bool start(IOService * provider) APPLE_KEXT_OVERRIDE;
-
- virtual bool serializeProperties(OSSerialize *s) const APPLE_KEXT_OVERRIDE;
- virtual OSPtr<OSObject> copyProperty(const OSSymbol *aKey) const APPLE_KEXT_OVERRIDE;
- virtual OSObject *getProperty(const OSSymbol *aKey) const APPLE_KEXT_OVERRIDE;
- virtual bool setProperty(const OSSymbol *aKey, OSObject *anObject) APPLE_KEXT_OVERRIDE;
- virtual IOReturn setProperties(OSObject *properties) APPLE_KEXT_OVERRIDE;
- virtual void removeProperty(const OSSymbol *aKey) APPLE_KEXT_OVERRIDE;
-};
-
-OSDefineMetaClassAndStructors(IODTNVRAMVariables, IOService)
-
-bool
-IODTNVRAMVariables::init(const uuid_t guid, const bool systemActive)
-{
- require(super::init(), fail);
-
- uuid_copy(_guid, guid);
- _systemActive = systemActive;
-
- return true;
-
-fail:
- return false;
-}
-
-bool
-IODTNVRAMVariables::start(IOService * provider)
-{
- _provider = OSDynamicCast(IODTNVRAM, provider);
- if (_provider == nullptr) {
- goto error;
- }
-
- if (!super::start(provider)) {
- goto error;
- }
-
- registerService();
-
- return true;
-
-error:
- stop(provider);
-
- return false;
-}
-
-bool
-IODTNVRAMVariables::serializeProperties(OSSerialize *s) const
-{
- const OSSymbol *key;
- OSSharedPtr<OSDictionary> dict;
- OSSharedPtr<OSCollectionIterator> iter;
- OSSharedPtr<OSDictionary> localVariables;
- bool ok = false;
- IOReturn status;
-
- status = _provider->getVarDict(localVariables);
- require_noerr_action(status, exit, DEBUG_ERROR("Failed to get variable dictionary\n"));
-
- dict = OSDictionary::withCapacity(localVariables->getCount());
- require_action(dict, exit, DEBUG_ERROR("Failed to create dict\n"));
-
- iter = OSCollectionIterator::withCollection(localVariables.get());
- require_action(iter, exit, DEBUG_ERROR("Failed to create iterator\n"));
-
- while ((key = OSDynamicCast(OSSymbol, iter->getNextObject()))) {
- if (verifyPermission(kIONVRAMOperationRead, key, _systemActive)) {
- uuid_t guid;
- const char *name;
-
- parseVariableName(key, &guid, &name);
-
- if (uuid_compare(_guid, guid) == 0) {
- OSSharedPtr<const OSSymbol> sym = OSSymbol::withCString(name);
- dict->setObject(sym.get(), localVariables->getObject(key));
- }
- }
- }
-
- ok = dict->serialize(s);
-
-exit:
- DEBUG_INFO("ok=%d\n", ok);
- return ok;
-}
-
-OSPtr<OSObject>
-IODTNVRAMVariables::copyProperty(const OSSymbol *aKey) const
-{
- if (_provider && !skipKey(aKey)) {
- DEBUG_INFO("aKey=%s\n", aKey->getCStringNoCopy());
-
- return _provider->copyPropertyWithGUIDAndName(_guid, aKey->getCStringNoCopy());
- } else {
- return nullptr;
- }
-}
-
-OSObject *
-IODTNVRAMVariables::getProperty(const OSSymbol *aKey) const
-{
- OSSharedPtr<OSObject> theObject = copyProperty(aKey);
-
- return theObject.get();
-}
-
-bool
-IODTNVRAMVariables::setProperty(const OSSymbol *aKey, OSObject *anObject)
-{
- if (_provider) {
- return _provider->setPropertyWithGUIDAndName(_guid, aKey->getCStringNoCopy(), anObject) == kIOReturnSuccess;
- } else {
- return false;
- }
-}
-
-IOReturn
-IODTNVRAMVariables::setProperties(OSObject *properties)
-{
- IOReturn ret = kIOReturnSuccess;
- OSObject *object;
- const OSSymbol *key;
- OSDictionary *dict;
- OSSharedPtr<OSCollectionIterator> iter;
-
- dict = OSDynamicCast(OSDictionary, properties);
- if (dict == nullptr) {
- DEBUG_ERROR("Not a dictionary\n");
- return kIOReturnBadArgument;
- }
-
- iter = OSCollectionIterator::withCollection(dict);
- if (iter == nullptr) {
- DEBUG_ERROR("Couldn't create iterator\n");
- return kIOReturnBadArgument;
- }
-
- while (ret == kIOReturnSuccess) {
- key = OSDynamicCast(OSSymbol, iter->getNextObject());
- if (key == nullptr) {
- break;
- }
-
- object = dict->getObject(key);
- if (object == nullptr) {
- continue;
- }
-
- ret = _provider->setPropertyWithGUIDAndName(_guid, key->getCStringNoCopy(), object);
- }
-
- DEBUG_INFO("ret=%#08x\n", ret);
-
- return ret;
-}
-
-void
-IODTNVRAMVariables::removeProperty(const OSSymbol *aKey)
-{
- _provider->removePropertyWithGUIDAndName(_guid, aKey->getCStringNoCopy());
-}
-
-// ************************** Format Handlers ***************************
-class IODTNVRAMFormatHandler
-{
-protected:
- uint32_t _bankSize;
- uint32_t _bankCount;
- uint32_t _currentBank;
-
-public:
- virtual
- ~IODTNVRAMFormatHandler();
- virtual bool getNVRAMProperties(void);
- virtual IOReturn unserializeVariables(void) = 0;
- virtual IOReturn setVariable(const uuid_t varGuid, const char *variableName, OSObject *object) = 0;
- virtual bool setController(IONVRAMController *_nvramController) = 0;
- virtual IOReturn sync(void) = 0;
- virtual IOReturn flush(const uuid_t guid, IONVRAMOperation op) = 0;
- virtual void reload(void) = 0;
- virtual uint32_t getGeneration(void) const = 0;
- virtual uint32_t getVersion(void) const = 0;
- virtual uint32_t getSystemUsed(void) const = 0;
- virtual uint32_t getCommonUsed(void) const = 0;
- virtual bool getSystemPartitionActive(void) const = 0;
- virtual IOReturn getVarDict(OSSharedPtr<OSDictionary> &varDictCopy) = 0;
- IOReturn handleEphDM(void);
-};
-
-IODTNVRAMFormatHandler::~IODTNVRAMFormatHandler()
-{
-}
-
-bool
-IODTNVRAMFormatHandler::getNVRAMProperties()
-{
- bool ok = false;
- OSSharedPtr<IORegistryEntry> entry;
- OSSharedPtr<OSObject> prop;
- OSData * data;
-
- entry = IORegistryEntry::fromPath("/chosen", gIODTPlane);
- require_action(entry, exit, DEBUG_ERROR("Unable to find chosen node\n"));
-
- prop = entry->copyProperty(kNVRAMBankSizeKey);
- require_action(prop, exit, DEBUG_ERROR("Unable to find %s property\n", kNVRAMBankSizeKey));
-
- data = OSDynamicCast(OSData, prop.get());
- require(data, exit);
-
- _bankSize = *((uint32_t *)data->getBytesNoCopy());
-
- prop = entry->copyProperty(kNVRAMBankCountKey);
- require_action(prop, exit, DEBUG_ERROR("Unable to find %s property\n", kNVRAMBankCountKey));
-
- data = OSDynamicCast(OSData, prop.get());
- require(data, exit);
-
- _bankCount = *((uint32_t *)data->getBytesNoCopy());
-
- prop = entry->copyProperty(kNVRAMCurrentBankKey);
- require_action(prop, exit, DEBUG_ERROR("Unable to find %s property\n", kNVRAMCurrentBankKey));
-
- data = OSDynamicCast(OSData, prop.get());
- require(data, exit);
-
- _currentBank = *((uint32_t *)data->getBytesNoCopy());
-
- ok = true;
-
- DEBUG_ALWAYS("_bankSize=%#X, _bankCount=%#X, _currentBank=%#X\n", _bankSize, _bankCount, _currentBank);
-
-exit:
- return ok;
-}
-
-IOReturn
-IODTNVRAMFormatHandler::handleEphDM(void)
-{
- OSSharedPtr<IORegistryEntry> entry;
- OSData* data;
- OSSharedPtr<OSObject> prop;
- uint32_t ephDM = 0;
- IOReturn ret = kIOReturnSuccess;
- OSSharedPtr<const OSSymbol> canonicalKey;
- uint32_t skip = 0;
- OSSharedPtr<OSDictionary> varDict;
-
- // For ephemeral data mode, NVRAM needs to be cleared on every boot
- // For system region supported targets, iBoot clears the system region
- // For other targets, iBoot clears all the persistent variables
- // So xnu only needs to clear the common region
- entry = IORegistryEntry::fromPath("/product", gIODTPlane);
- if (entry) {
- prop = entry->copyProperty("ephemeral-data-mode");
- if (prop) {
- data = OSDynamicCast(OSData, prop.get());
- if (data) {
- ephDM = *((uint32_t *)data->getBytesNoCopy());
- }
- }
- }
-
- require_action(ephDM != 0, exit, DEBUG_ALWAYS("ephemeral-data-mode not supported\n"));
- require_action(getSystemPartitionActive(), exit, DEBUG_ALWAYS("No system region, no need to clear\n"));
-
- if (PE_parse_boot_argn("epdm-skip-nvram", &skip, sizeof(skip))) {
- require_action(!(gInternalBuild && (skip == 1)), exit, DEBUG_ALWAYS("Internal build + epdm-skip-nvram set to true, skip nvram clearing\n"));
- }
-
- // Get the current variable dictionary
- ret = getVarDict(varDict);
- require_noerr_action(ret, exit, DEBUG_ERROR("Failed to get variable dictionary for EphDM handling\n"));
-
- // Go through the allowlist and stash the values
- for (uint32_t entry = 0; entry < ARRAY_SIZE(ephDMEntries); entry++) {
- canonicalKey = keyWithGuidAndCString(gAppleNVRAMGuid, ephDMEntries[entry].name);
- ephDMEntries[entry].value.reset(OSDynamicCast(OSData, varDict->getObject(canonicalKey.get())), OSRetain);
- }
-
- DEBUG_ALWAYS("Obliterating common region\n");
- ret = flush(gAppleNVRAMGuid, kIONVRAMOperationObliterate);
- require_noerr_action(ret, exit, DEBUG_ERROR("Flushing common region failed, ret=%#08x\n", ret));
-
- // Now write the allowlist variables back
- for (uint32_t entry = 0; entry < ARRAY_SIZE(ephDMEntries); entry++) {
- if (ephDMEntries[entry].value.get() == nullptr) {
- continue;
- }
- ret = setVariable(gAppleNVRAMGuid, ephDMEntries[entry].name, ephDMEntries[entry].value.get());
- require_noerr_action(ret, exit, DEBUG_ERROR("Setting allowlist variable %s failed, ret=%#08x\n", ephDMEntries[entry].name, ret));
- }
-
-exit:
- return ret;
-}
-
-#include "IONVRAMCHRPHandler.cpp"
-
-#include "IONVRAMV3Handler.cpp"
-
-// **************************** IODTNVRAM *********************************
-
-bool
-IODTNVRAM::init(IORegistryEntry *old, const IORegistryPlane *plane)
-{
- OSSharedPtr<OSDictionary> dict;
-
- DEBUG_INFO("...\n");
- require(super::init(old, plane), fail);
- x86Device = false;
-
-#if CONFIG_CSR && XNU_TARGET_OS_OSX
- gInternalBuild = (csr_check(CSR_ALLOW_APPLE_INTERNAL) == 0);
-#elif defined(DEBUG) || defined(DEVELOPMENT)
- gInternalBuild = true;
-#endif
- DEBUG_INFO("gInternalBuild = %d\n", gInternalBuild);
-
- // Clear the IORegistryEntry property table
- dict = OSDictionary::withCapacity(1);
- require(dict != nullptr, fail);
-
- setPropertyTable(dict.get());
- dict.reset();
-
- return true;
-
-fail:
- return false;
-}
-
-bool
-IODTNVRAM::start(IOService *provider)
-{
- OSSharedPtr<OSNumber> version;
-
- DEBUG_ALWAYS("...\n");
-
- require(super::start(provider), fail);
-
- // Check if our overridden init function was called
- // If not, skip any additional initialization being done here.
- // This is not an error we just need to successfully exit this function to allow
- // AppleEFIRuntime to proceed and take over operation
- require_action(x86Device == false, no_common, DEBUG_INFO("x86 init\n"));
-
- _diags = new IODTNVRAMDiags;
- if (!_diags || !_diags->init()) {
- DEBUG_ERROR("Unable to create/init the diags service\n");
- OSSafeReleaseNULL(_diags);
- goto fail;
- }
-
- if (!_diags->attach(this)) {
- DEBUG_ERROR("Unable to attach the diags service!\n");
- OSSafeReleaseNULL(_diags);
- goto fail;
- }
-
- if (!_diags->start(this)) {
- DEBUG_ERROR("Unable to start the diags service!\n");
- _diags->detach(this);
- OSSafeReleaseNULL(_diags);
- goto fail;
- }
-
- _notifier = new IODTNVRAMPlatformNotifier;
- if (!_notifier || !_notifier->init()) {
- DEBUG_ERROR("Unable to create/init the notifier service\n");
- OSSafeReleaseNULL(_notifier);
- goto fail;
- }
-
- if (!_notifier->attach(this)) {
- DEBUG_ERROR("Unable to attach the notifier service!\n");
- OSSafeReleaseNULL(_notifier);
- goto fail;
- }
-
- if (!_notifier->start(this)) {
- DEBUG_ERROR("Unable to start the notifier service!\n");
- _notifier->detach(this);
- OSSafeReleaseNULL(_notifier);
- goto fail;
- }
-
- // This will load the proxied variable data which will call back into
- // IODTNVRAM for the variable sets which will also update the system/common services
- initImageFormat();
-
- version = OSNumber::withNumber(_format->getVersion(), 32);
- _diags->setProperty(kCurrentNVRAMVersionKey, version.get());
-
- if (_format->getSystemUsed()) {
- _systemService = new IODTNVRAMVariables;
-
- if (!_systemService || !_systemService->init(gAppleSystemVariableGuid, _format->getSystemPartitionActive())) {
- DEBUG_ERROR("Unable to start the system service!\n");
- OSSafeReleaseNULL(_systemService);
- goto no_system;
- }
-
- _systemService->setName("options-system");
-
- if (!_systemService->attach(this)) {
- DEBUG_ERROR("Unable to attach the system service!\n");
- OSSafeReleaseNULL(_systemService);
- goto no_system;
- }
-
- if (!_systemService->start(this)) {
- DEBUG_ERROR("Unable to start the system service!\n");
- _systemService->detach(this);
- OSSafeReleaseNULL(_systemService);
- goto no_system;
- }
- }
-
-no_system:
- _commonService = new IODTNVRAMVariables;
-
- if (!_commonService || !_commonService->init(gAppleNVRAMGuid, _format->getSystemPartitionActive())) {
- DEBUG_ERROR("Unable to start the common service!\n");
- OSSafeReleaseNULL(_commonService);
- goto no_common;
- }
-
- _commonService->setName("options-common");
-
- if (!_commonService->attach(this)) {
- DEBUG_ERROR("Unable to attach the common service!\n");
- OSSafeReleaseNULL(_commonService);
- goto no_common;
- }
-
- if (!_commonService->start(this)) {
- DEBUG_ERROR("Unable to start the common service!\n");
- _commonService->detach(this);
- OSSafeReleaseNULL(_commonService);
- goto no_common;
- }
-
-no_common:
- return true;
-
-fail:
- stop(provider);
- return false;
-}
-
-void
-IODTNVRAM::initImageFormat(void)
-{
- OSSharedPtr<IORegistryEntry> entry;
- OSSharedPtr<OSObject> prop;
- const char *proxyDataKey = "nvram-proxy-data";
- const char *bankSizeKey = "nvram-bank-size";
- OSData *data = nullptr;
- uint32_t size = 0;
- const uint8_t *image = nullptr;
- OSSharedPtr<OSDictionary> localVariables;
- IOReturn status;
-
- entry = IORegistryEntry::fromPath("/chosen", gIODTPlane);
-
- require(entry != nullptr, skip);
-
- prop = entry->copyProperty(bankSizeKey);
- require(prop != nullptr, skip);
-
- data = OSDynamicCast(OSData, prop.get());
- require(data != nullptr, skip);
-
- size = *((uint32_t*)data->getBytesNoCopy());
- require_action(size != 0, skip, panic("NVRAM size is 0 bytes, possibly due to bad config with iBoot + xnu mismatch"));
- DEBUG_ALWAYS("NVRAM size is %u bytes\n", size);
-
- prop = entry->copyProperty(proxyDataKey);
- require(prop != nullptr, skip);
-
- data = OSDynamicCast(OSData, prop.get());
- require_action(data != nullptr, skip, DEBUG_ERROR("No proxy data!\n"));
-
- image = (const uint8_t *)data->getBytesNoCopy();
-
-skip:
- if (IONVRAMV3Handler::isValidImage(image, size)) {
- _format = IONVRAMV3Handler::init(this, image, size);
- require_action(_format, skip, panic("IONVRAMV3Handler creation failed\n"));
- } else {
- _format = IONVRAMCHRPHandler::init(this, image, size);
- require_action(_format, skip, panic("IONVRAMCHRPHandler creation failed\n"));
- }
-
- status = _format->unserializeVariables();
- verify_noerr_action(status, DEBUG_ERROR("Failed to unserialize variables, status=%08x\n", status));
-
- status = _format->getVarDict(localVariables);
- verify_noerr_action(status, DEBUG_ERROR("Failed to get variable dictionary, status=%08x\n", status));
-
- dumpDict(localVariables);
-
-#if defined(RELEASE)
- if (entry != nullptr) {
- entry->removeProperty(proxyDataKey);
- }
-#endif
-
- _lastDeviceSync = 0;
- _freshInterval = true;
-}
-
-void
-IODTNVRAM::registerNVRAMController(IONVRAMController *controller)
-{
- DEBUG_INFO("setting controller\n");
-
- require_action(_format != nullptr, exit, DEBUG_ERROR("Handler not initialized yet\n"));
- _format->setController(controller);
-
-exit:
- return;
-}
-
-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;
-}
-
-IOReturn
-IODTNVRAM::syncInternal(bool rateLimit)
-{
- IOReturn ret = kIOReturnSuccess;
-
- DEBUG_INFO("rateLimit=%d\n", rateLimit);
-
- if (!SAFE_TO_LOCK()) {
- DEBUG_INFO("cannot lock\n");
- goto exit;
- }
-
- require_action(_format != nullptr, exit, (ret = kIOReturnNotReady, DEBUG_ERROR("Handler not initialized yet\n")));
-
- // 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) {
- if (safeToSync() == false) {
- DEBUG_INFO("safeToSync()=false\n");
- goto exit;
- }
- }
-
- DEBUG_INFO("Calling sync()\n");
- record_system_event(SYSTEM_EVENT_TYPE_INFO, SYSTEM_EVENT_SUBSYSTEM_NVRAM, "sync", "triggered");
-
- ret = _format->sync();
-
- record_system_event(SYSTEM_EVENT_TYPE_INFO, SYSTEM_EVENT_SUBSYSTEM_NVRAM, "sync", "completed with ret=%08x", ret);
-
- if (_diags) {
- OSSharedPtr<OSNumber> generation = OSNumber::withNumber(_format->getGeneration(), 32);
- _diags->setProperty(kCurrentGenerationCountKey, generation.get());
- }
-
-exit:
- return ret;
-}
-
-IOReturn
-IODTNVRAM::sync(void)
-{
- return syncInternal(false);
-}
-
-void
-IODTNVRAM::reload(void)
-{
- _format->reload();
-}
-
-IOReturn
-IODTNVRAM::getVarDict(OSSharedPtr<OSDictionary> &varDictCopy)
-{
- return _format->getVarDict(varDictCopy);
-}
-
-OSPtr<OSDictionary>
-IODTNVRAM::dictionaryWithProperties(void) const
-{
- const OSSymbol *canonicalKey;
- OSSharedPtr<OSDictionary> localVarDict, returnDict;
- OSSharedPtr<OSCollectionIterator> iter;
- uuid_t varGuid;
- const char * varName;
- IOReturn status;
- require_action(_format, exit, DEBUG_ERROR("Handler not initialized yet\n"));
-
- status = _format->getVarDict(localVarDict);
- require_noerr_action(status, exit, DEBUG_ERROR("Failed to get variable dictionary\n"));
-
- returnDict = OSDictionary::withCapacity(localVarDict->getCapacity());
- require_action(returnDict, exit, DEBUG_ERROR("Failed to create return dict\n"));
-
- // Copy system entries first if present then copy unique other entries
- iter = OSCollectionIterator::withCollection(localVarDict.get());
- require_action(iter, exit, DEBUG_ERROR("Failed to create iterator\n"));
-
- while ((canonicalKey = OSDynamicCast(OSSymbol, iter->getNextObject()))) {
- parseVariableName(canonicalKey, &varGuid, &varName);
-
- if ((uuid_compare(varGuid, gAppleSystemVariableGuid) == 0) &&
- verifyPermission(kIONVRAMOperationRead, varGuid, varName, _format->getSystemPartitionActive(), false)) {
- OSSharedPtr<const OSSymbol> returnKey = OSSymbol::withCString(varName);
- returnDict->setObject(returnKey.get(), localVarDict->getObject(canonicalKey));
- }
- }
-
- iter.reset();
-
- iter = OSCollectionIterator::withCollection(localVarDict.get());
- require_action(iter, exit, DEBUG_ERROR("Failed to create iterator\n"));
-
- while ((canonicalKey = OSDynamicCast(OSSymbol, iter->getNextObject()))) {
- parseVariableName(canonicalKey, &varGuid, &varName);
-
- if (uuid_compare(varGuid, gAppleNVRAMGuid) == 0) {
- if (returnDict->getObject(varName) != nullptr) {
- // Skip non uniques
- continue;
- }
-
- if (verifyPermission(kIONVRAMOperationRead, varGuid, varName, _format->getSystemPartitionActive(), false)) {
- OSSharedPtr<const OSSymbol> returnKey = OSSymbol::withCString(varName);
- returnDict->setObject(returnKey.get(), localVarDict->getObject(canonicalKey));
- }
- }
- }
-exit:
- return returnDict;
-}
-
-bool
-IODTNVRAM::serializeProperties(OSSerialize *s) const
-{
- bool ok = false;
- OSSharedPtr<OSDictionary> dict;
-
- dict = dictionaryWithProperties();
- if (dict) {
- ok = dict->serialize(s);
- }
-
- DEBUG_INFO("ok=%d\n", ok);
- return ok;
-}
-
-IOReturn
-IODTNVRAM::flushGUID(const uuid_t guid, IONVRAMOperation op)
-{
- IOReturn ret = kIOReturnSuccess;
-
- require_action(_format != nullptr, exit, (ret = kIOReturnNotReady, DEBUG_ERROR("Handler not initialized yet\n")));
-
- if (_format->getSystemPartitionActive() && (uuid_compare(guid, gAppleSystemVariableGuid) == 0)) {
- ret = _format->flush(guid, op);
-
- DEBUG_INFO("system variables flushed, ret=%08x\n", ret);
- } else if (uuid_compare(guid, gAppleNVRAMGuid) == 0) {
- ret = _format->flush(guid, op);
-
- DEBUG_INFO("common variables flushed, ret=%08x\n", ret);
- }
-
-exit:
- return ret;
-}
-
-bool
-IODTNVRAM::handleSpecialVariables(const char *name, const uuid_t guid, const OSObject *obj, IOReturn *error)
-{
- IOReturn ret = kIOReturnSuccess;
- bool special = false;
-
- // ResetNVRam flushes both regions in one call
- // Obliterate can flush either separately
- if (strcmp(name, "ObliterateNVRam") == 0) {
- special = true;
- ret = flushGUID(guid, kIONVRAMOperationObliterate);
- } else if (strcmp(name, "ResetNVRam") == 0) {
- special = true;
- ret = flushGUID(gAppleSystemVariableGuid, kIONVRAMOperationReset);
-
- if (ret != kIOReturnSuccess) {
- goto exit;
- }
-
- ret = flushGUID(gAppleNVRAMGuid, kIONVRAMOperationReset);
- }
-
-exit:
- if (error) {
- *error = ret;
- }
-
- return special;
-}
-
-OSSharedPtr<OSObject>
-IODTNVRAM::copyPropertyWithGUIDAndName(const uuid_t guid, const char *name) const
-{
- OSSharedPtr<const OSSymbol> canonicalKey;
- OSSharedPtr<OSObject> theObject;
- uuid_t newGuid;
- OSSharedPtr<OSDictionary> localVarDict;
- IOReturn status;
-
- require_action(_format, exit, DEBUG_ERROR("Handler not initialized yet\n"));
-
- status = _format->getVarDict(localVarDict);
- require_noerr_action(status, exit, DEBUG_ERROR("Failed to get variable dictionary\n"));
-
- if (!verifyPermission(kIONVRAMOperationRead, guid, name, _format->getSystemPartitionActive(), true)) {
- DEBUG_INFO("Not privileged\n");
- goto exit;
- }
-
- translateGUID(guid, name, newGuid, _format->getSystemPartitionActive(), true);
-
- canonicalKey = keyWithGuidAndCString(newGuid, name);
-
- theObject.reset(localVarDict->getObject(canonicalKey.get()), OSRetain);
-
- if (_diags) {
- _diags->logVariable(getPartitionTypeForGUID(newGuid), kIONVRAMOperationRead, name);
- }
-
- if (theObject != nullptr) {
- DEBUG_INFO("%s has object\n", canonicalKey.get()->getCStringNoCopy());
- } else {
- DEBUG_INFO("%s no entry\n", canonicalKey.get()->getCStringNoCopy());
- }
-
-exit:
- return theObject;
-}
-
-OSSharedPtr<OSObject>
-IODTNVRAM::copyProperty(const OSSymbol *aKey) const
-{
- const char *variableName;
- uuid_t varGuid;
-
- if (skipKey(aKey)) {
- return nullptr;
- }
- DEBUG_INFO("aKey=%s\n", aKey->getCStringNoCopy());
-
- parseVariableName(aKey->getCStringNoCopy(), &varGuid, &variableName);
-
- return copyPropertyWithGUIDAndName(varGuid, variableName);
-}
-
-OSSharedPtr<OSObject>
-IODTNVRAM::copyProperty(const char *aKey) const
-{
- OSSharedPtr<const OSSymbol> keySymbol;
- OSSharedPtr<OSObject> theObject;
-
- keySymbol = OSSymbol::withCString(aKey);
- if (keySymbol != nullptr) {
- theObject = copyProperty(keySymbol.get());
- }
-
- return theObject;
-}
-
-OSObject *
-IODTNVRAM::getProperty(const OSSymbol *aKey) const
-{
- // The shared pointer gets released at the end of the function,
- // and returns a view into theObject.
- OSSharedPtr<OSObject> theObject = copyProperty(aKey);
-
- return theObject.get();
-}
-
-OSObject *
-IODTNVRAM::getProperty(const char *aKey) const
-{
- // The shared pointer gets released at the end of the function,
- // and returns a view into theObject.
- OSSharedPtr<OSObject> theObject = copyProperty(aKey);
-
- return theObject.get();
-}
-
-IOReturn
-IODTNVRAM::clearTestVars(const uuid_t guid)
-{
- const VariablePermissionEntry *entry;
- IOReturn ret = kIOReturnSuccess;
- uuid_t newGuid;
-
- entry = gVariablePermissions;
- require_action(gInternalBuild, exit, DEBUG_INFO("Internal build only\n"));
- require_action(_format != nullptr, exit, (ret = kIOReturnNotReady, DEBUG_ERROR("Handler not initialized yet\n")));
-
- while ((entry != nullptr) && (entry->name != nullptr)) {
- if (entry->p.Bits.TestingOnly) {
- translateGUID(guid, entry->name, newGuid, _format->getSystemPartitionActive(), true);
- ret = _format->setVariable(newGuid, entry->name, nullptr);
- }
- entry++;
- }
-
-exit:
- return ret;
-}
-
-IOReturn
-IODTNVRAM::setPropertyWithGUIDAndName(const uuid_t guid, const char *name, OSObject *anObject)
-{
- IOReturn ret = kIOReturnSuccess;
- bool remove = false;
- OSString *tmpString = nullptr;
- OSSharedPtr<OSObject> propObject;
- OSSharedPtr<OSObject> sharedObject(anObject, OSRetain);
- bool deletePropertyKey, syncNowPropertyKey, forceSyncNowPropertyKey, deletePropertyKeyWRet;
- bool ok;
- size_t propDataSize = 0;
- uuid_t newGuid;
-
- require_action(_format != nullptr, exit, (ret = kIOReturnNotReady, DEBUG_ERROR("Handler not initialized yet\n")));
-
- if (strncmp(name, kNVRAMClearTestVarKey, sizeof(kNVRAMClearTestVarKey)) == 0) {
- ret = clearTestVars(guid);
- goto exit;
- }
-
- deletePropertyKey = strncmp(name, kIONVRAMDeletePropertyKey, sizeof(kIONVRAMDeletePropertyKey)) == 0;
- deletePropertyKeyWRet = strncmp(name, kIONVRAMDeletePropertyKeyWRet, sizeof(kIONVRAMDeletePropertyKeyWRet)) == 0;
- syncNowPropertyKey = strncmp(name, kIONVRAMSyncNowPropertyKey, sizeof(kIONVRAMSyncNowPropertyKey)) == 0;
- forceSyncNowPropertyKey = strncmp(name, kIONVRAMForceSyncNowPropertyKey, sizeof(kIONVRAMForceSyncNowPropertyKey)) == 0;
-
- if (deletePropertyKey || deletePropertyKeyWRet) {
- tmpString = OSDynamicCast(OSString, anObject);
- if (tmpString != nullptr) {
- const char *variableName;
- uuid_t valueVarGuid;
- bool guidProvided;
- IOReturn removeRet;
-
- guidProvided = parseVariableName(tmpString->getCStringNoCopy(), &valueVarGuid, &variableName);
-
- // nvram tool will provide a "nvram -d var" or "nvram -d guid:var" as
- // kIONVRAMDeletePropertyKey=var or kIONVRAMDeletePropertyKey=guid:var
- // that will come into this function as (gAppleNVRAMGuid, varname, nullptr)
- // if we provide the "-z" flag to the nvram tool this function will come in as
- // (gAppleSystemVariableGuid, varname, nullptr). We are reparsing the value string,
- // if there is a GUID provided with the value then use that GUID otherwise use the
- // guid that was provided via the node selection or default.
- if (guidProvided == false) {
- DEBUG_INFO("Removing with API provided GUID\n");
- removeRet = removePropertyWithGUIDAndName(guid, variableName);
- } else {
- DEBUG_INFO("Removing with value provided GUID\n");
- removeRet = removePropertyWithGUIDAndName(valueVarGuid, variableName);
- }
- if (deletePropertyKeyWRet) {
- ret = removeRet;
- }
- DEBUG_INFO("%s found, removeRet=%#08x\n", deletePropertyKeyWRet ? "deletePropertyKeyWRet" : "deletePropertyKey", removeRet);
- } else {
- DEBUG_INFO("%s value needs to be an OSString\n", deletePropertyKeyWRet ? "deletePropertyKeyWRet" : "deletePropertyKey");
- ret = kIOReturnError;
- }
- goto exit;
- } else if (syncNowPropertyKey || forceSyncNowPropertyKey) {
- tmpString = OSDynamicCast(OSString, anObject);
- DEBUG_INFO("NVRAM sync key %s found\n", name);
- if (tmpString != nullptr) {
- // We still want to throttle NVRAM commit rate for SyncNow. ForceSyncNow is provided as a really big hammer.
- ret = syncInternal(syncNowPropertyKey);
- } else {
- DEBUG_INFO("%s value needs to be an OSString\n", name);
- ret = kIOReturnError;
- }
- goto exit;
- }
-
- if (!verifyPermission(kIONVRAMOperationWrite, guid, name, _format->getSystemPartitionActive(), true)) {
- DEBUG_INFO("Not privileged\n");
- ret = kIOReturnNotPrivileged;
- goto exit;
- }
-
- // Make sure the object is of the correct type.
- switch (getVariableType(name)) {
- case kOFVariableTypeBoolean:
- propObject = OSDynamicPtrCast<OSBoolean>(sharedObject);
- if (propObject) {
- record_system_event(SYSTEM_EVENT_TYPE_INFO, SYSTEM_EVENT_SUBSYSTEM_NVRAM, "write", "%s as bool to %d", name, ((OSBoolean *)propObject.get())->getValue());
- }
- break;
-
- case kOFVariableTypeNumber:
- propObject = OSDynamicPtrCast<OSNumber>(sharedObject);
- if (propObject) {
- record_system_event(SYSTEM_EVENT_TYPE_INFO, SYSTEM_EVENT_SUBSYSTEM_NVRAM, "write", "%s as number to %#llx", name, ((OSNumber *)propObject.get())->unsigned64BitValue());
- }
- break;
-
- case kOFVariableTypeString:
- propObject = OSDynamicPtrCast<OSString>(sharedObject);
- if (propObject != nullptr) {
- record_system_event(SYSTEM_EVENT_TYPE_INFO, SYSTEM_EVENT_SUBSYSTEM_NVRAM, "write", "%s as string to %s", name, ((OSString *)propObject.get())->getCStringNoCopy());
-
- propDataSize = (OSDynamicPtrCast<OSString>(propObject))->getLength();
-
- if ((strncmp(name, kIONVRAMBootArgsKey, sizeof(kIONVRAMBootArgsKey)) == 0) && (propDataSize >= BOOT_LINE_LENGTH)) {
- DEBUG_ERROR("boot-args size too large for BOOT_LINE_LENGTH, propDataSize=%zu\n", propDataSize);
- ret = kIOReturnNoSpace;
- goto exit;
- }
- }
- break;
-
- case kOFVariableTypeData:
- propObject = OSDynamicPtrCast<OSData>(sharedObject);
- if (propObject == nullptr) {
- tmpString = OSDynamicCast(OSString, sharedObject.get());
- if (tmpString != nullptr) {
- propObject = OSData::withBytes(tmpString->getCStringNoCopy(),
- tmpString->getLength());
- }
- }
-
- if (propObject != nullptr) {
- OSSharedPtr<OSData> propData = OSDynamicPtrCast<OSData>(propObject);
- propDataSize = propData->getLength();
- record_system_event(SYSTEM_EVENT_TYPE_INFO, SYSTEM_EVENT_SUBSYSTEM_NVRAM, "write", "%s as data with size %zu", name, propDataSize);
- dumpData(name, propData);
- }
-
-#if defined(XNU_TARGET_OS_OSX)
- if ((propObject != nullptr) && ((OSDynamicPtrCast<OSData>(propObject))->getLength() == 0)) {
- remove = true;
- }
-#endif /* defined(XNU_TARGET_OS_OSX) */
- break;
- default:
- break;
- }
-
- if (propObject == nullptr) {
- DEBUG_ERROR("No property object\n");
- ret = kIOReturnBadArgument;
- goto exit;
- }
-
- if (!verifyWriteSizeLimit(guid, name, propDataSize)) {
- DEBUG_ERROR("Property data size of %zu too long for %s\n", propDataSize, name);
- ret = kIOReturnNoSpace;
- goto exit;
- }
-
- ok = handleSpecialVariables(name, guid, propObject.get(), &ret);
-
- if (ok) {
- goto exit;
- }
-
- if (remove == false) {
- DEBUG_INFO("Adding object\n");
-
- translateGUID(guid, name, newGuid, _format->getSystemPartitionActive(), true);
- ret = _format->setVariable(newGuid, name, propObject.get());
- } else {
- DEBUG_INFO("Removing object\n");
- ret = removePropertyWithGUIDAndName(guid, name);
- }
-
- if (tmpString) {
- propObject.reset();
- }
-
-exit:
- DEBUG_INFO("ret=%#08x\n", ret);
-
- return ret;
-}
-
-IOReturn
-IODTNVRAM::setPropertyInternal(const OSSymbol *aKey, OSObject *anObject)
-{
- const char *variableName;
- uuid_t varGuid;
-
- DEBUG_INFO("aKey=%s\n", aKey->getCStringNoCopy());
-
- parseVariableName(aKey->getCStringNoCopy(), &varGuid, &variableName);
-
- return setPropertyWithGUIDAndName(varGuid, variableName, anObject);
-}
-
-bool
-IODTNVRAM::setProperty(const OSSymbol *aKey, OSObject *anObject)
-{
- return setPropertyInternal(aKey, anObject) == kIOReturnSuccess;
-}
-
-void
-IODTNVRAM::removeProperty(const OSSymbol *aKey)
-{
- IOReturn ret;
-
- ret = removePropertyInternal(aKey);
-
- if (ret != kIOReturnSuccess) {
- DEBUG_INFO("removePropertyInternal failed, ret=%#08x\n", ret);
- }
-}
-
-IOReturn
-IODTNVRAM::removePropertyWithGUIDAndName(const uuid_t guid, const char *name)
-{
- IOReturn ret;
- uuid_t newGuid;
-
- DEBUG_INFO("name=%s\n", name);
- require_action(_format != nullptr, exit, (ret = kIOReturnNotReady, DEBUG_ERROR("Handler not initialized yet\n")));
-
- if (!verifyPermission(kIONVRAMOperationDelete, guid, name, _format->getSystemPartitionActive(), true)) {
- DEBUG_INFO("Not privileged\n");
- ret = kIOReturnNotPrivileged;
- goto exit;
- }
-
- translateGUID(guid, name, newGuid, _format->getSystemPartitionActive(), true);
- ret = _format->setVariable(newGuid, name, nullptr);
-
- if (ret != kIOReturnSuccess) {
- DEBUG_INFO("%s not found\n", name);
- ret = kIOReturnNotFound;
- }
-
- record_system_event(SYSTEM_EVENT_TYPE_INFO, SYSTEM_EVENT_SUBSYSTEM_NVRAM, "delete", "%s", name);
-
-exit:
- return ret;
-}
-
-IOReturn
-IODTNVRAM::removePropertyInternal(const OSSymbol *aKey)
-{
- IOReturn ret;
- const char *variableName;
- uuid_t varGuid;
-
- DEBUG_INFO("aKey=%s\n", aKey->getCStringNoCopy());
-
- parseVariableName(aKey->getCStringNoCopy(), &varGuid, &variableName);
-
- ret = removePropertyWithGUIDAndName(varGuid, variableName);
-
- return ret;
-}
-
-IOReturn
-IODTNVRAM::setProperties(OSObject *properties)
-{
- IOReturn ret = kIOReturnSuccess;
- OSObject *object;
- const OSSymbol *key;
- OSDictionary *dict;
- OSSharedPtr<OSCollectionIterator> iter;
-
- dict = OSDynamicCast(OSDictionary, properties);
- if (dict == nullptr) {
- DEBUG_ERROR("Not a dictionary\n");
- return kIOReturnBadArgument;
- }
-
- iter = OSCollectionIterator::withCollection(dict);
- if (iter == nullptr) {
- DEBUG_ERROR("Couldn't create iterator\n");
- return kIOReturnBadArgument;
- }
-
- while (ret == kIOReturnSuccess) {
- key = OSDynamicCast(OSSymbol, iter->getNextObject());
- if (key == nullptr) {
- break;
- }
-
- object = dict->getObject(key);
- if (object == nullptr) {
- continue;
- }
-
- ret = setPropertyInternal(key, object);
- }
-
- DEBUG_INFO("ret=%#08x\n", ret);
-
- return ret;
-}
-
-// ********************** Deprecated ********************
-
-IOReturn
-IODTNVRAM::readXPRAM(IOByteCount offset, uint8_t *buffer,
- IOByteCount length)
-{
- return kIOReturnUnsupported;
-}
-
-IOReturn
-IODTNVRAM::writeXPRAM(IOByteCount offset, uint8_t *buffer,
- IOByteCount length)
-{
- return kIOReturnUnsupported;
-}
-
-IOReturn
-IODTNVRAM::readNVRAMProperty(IORegistryEntry *entry,
- const OSSymbol **name,
- OSData **value)
-{
- return kIOReturnUnsupported;
-}
-
-IOReturn
-IODTNVRAM::writeNVRAMProperty(IORegistryEntry *entry,
- const OSSymbol *name,
- OSData *value)
-{
- return kIOReturnUnsupported;
-}
-
-OSDictionary *
-IODTNVRAM::getNVRAMPartitions(void)
-{
- return NULL;
-}
-
-IOReturn
-IODTNVRAM::readNVRAMPartition(const OSSymbol *partitionID,
- IOByteCount offset, uint8_t *buffer,
- IOByteCount length)
-{
- return kIOReturnUnsupported;
-}
-
-IOReturn
-IODTNVRAM::writeNVRAMPartition(const OSSymbol *partitionID,
- IOByteCount offset, uint8_t *buffer,
- IOByteCount length)
-{
- return kIOReturnUnsupported;
-}
-
-IOByteCount
-IODTNVRAM::savePanicInfo(uint8_t *buffer, IOByteCount length)
-{
- return 0;
-}
+#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;
+}
+
+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;
+}
+
+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;
+}
+
+OSData *IODTNVRAM::unescapeBytesToData(UInt8 *bytes, UInt32 length)
+{
+ OSData *data = 0;
+ UInt32 totalLength = 0;
+ UInt32 cnt, cnt2;
+ UInt8 byte;
+ bool ok;
+
+ // Calculate the actual length of the data.
+ ok = true;
+ totalLength = 0;
+ for (cnt = 0; cnt < length;) {
+ byte = bytes[cnt++];
+ if (byte == 0xFF) {
+ byte = bytes[cnt++];
+ if (byte == 0x00) {
+ ok = false;
+ break;
+ }
+ cnt2 = byte & 0x7F;
+ } else
+ cnt2 = 1;
+ totalLength += cnt2;
+ }
+
+ if (ok) {
+ // Create an empty OSData of the correct size.
+ data = OSData::withCapacity(totalLength);
+ if (data != 0) {
+ for (cnt = 0; cnt < length;) {
+ byte = bytes[cnt++];
+ if (byte == 0xFF) {
+ byte = bytes[cnt++];
+ cnt2 = byte & 0x7F;
+ byte = (byte & 0x80) ? 0xFF : 0x00;
+ } else
+ cnt2 = 1;
+ data->appendByte(byte, cnt2);
+ }
+ }
+ }
+
+ return data;
+}
+
+OSData * IODTNVRAM::escapeDataToData(OSData * value)
+{
+ OSData * result;
+ UInt8 * start;
+ UInt8 * end;
+ UInt8 * where;
+ UInt8 byte;
+ bool ok = true;
+
+ where = (UInt8 *) value->getBytesNoCopy();
+ end = where + value->getLength();
+
+ result = OSData::withCapacity(end - where);
+ if (!result)
+ return result;
+
+ while (where < end) {
+ start = where;
+ byte = *where++;
+ if ((byte == 0x00) || (byte == 0xFF)) {
+ for (;
+ ((where - start) < 0x80) && (where < end) && (byte == *where);
+ where++) {}
+ ok &= result->appendByte(0xff, 1);
+ byte = (byte & 0x80) | (where - start);
+ }
+ ok &= result->appendByte(byte, 1);
+ }
+ ok &= result->appendByte(0, 1);
+
+ if (!ok) {
+ result->release();
+ result = 0;
+ }
+
+ return result;
+}
+
+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;
+
+ if (_ofDict == 0) return err;
+ data = OSDynamicCast(OSData, _ofDict->getObject(_registryPropertiesKey));
+ if (data == 0) return err;
+
+ start = (UInt8 *) data->getBytesNoCopy();
+ end = start + data->getLength();
+
+ where = start;
+ while (where < end) {
+ byte = *(where++);
+ if (byte)
+ continue;
+
+ if (nvPath == 0)
+ nvPath = start;
+ 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;
+ }
+
+ return err;
+}
+
+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;
+ const char * comp;
+ const char * name;
+ UInt8 byte;
+ bool ok = true;
+
+ if (_ofDict == 0) return kIOReturnNoResources;
+
+ // copy over existing properties for other entries
+
+ 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++);
+ if (byte)
+ continue;
+ if (nvPath == 0)
+ nvPath = start;
+ 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;
+
+ start = where;
+ }
+ }
+
+ // make the new property
+
+ if (!data) {
+ if (oldData)
+ data = OSData::withData(oldData);
+ else
+ data = OSData::withCapacity(16);
+ if (!data)
+ 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 (ok) {
+ ok = _ofDict->setObject(_registryPropertiesKey, data);
+ if (ok)
+ _ofImageDirty = true;
+ }
+ data->release();
+
+ return ok ? kIOReturnSuccess : kIOReturnNoMemory;
+}