Loading...
iokit/Kernel/IONVRAM.cpp xnu-8019.41.5 xnu-201.5
--- xnu/xnu-8019.41.5/iokit/Kernel/IONVRAM.cpp
+++ xnu/xnu-201.5/iokit/Kernel/IONVRAM.cpp
@@ -1,2916 +1,1349 @@
 /*
- * Copyright (c) 1998-2006 Apple Computer, Inc. All rights reserved.
- * Copyright (c) 2007-2012 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 <sys/csr.h>
 
 #define super IOService
 
 OSDefineMetaClassAndStructors(IODTNVRAM, IOService);
 
-#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
-
-#define MAX_VAR_NAME_SIZE     63
-
-#define kCurrentGenerationCountKey "Generation"
-#define kCurrentNVRAMVersionKey    "Version"
-
-#define NVRAM_CHRP_APPLE_HEADER_NAME_V1  "nvram"
-#define NVRAM_CHRP_APPLE_HEADER_NAME_V2  "2nvram"
-
-#define NVRAM_CHRP_PARTITION_NAME_COMMON_V1   "common"
-#define NVRAM_CHRP_PARTITION_NAME_SYSTEM_V1   "system"
-#define NVRAM_CHRP_PARTITION_NAME_COMMON_V2   "2common"
-#define NVRAM_CHRP_PARTITION_NAME_SYSTEM_V2   "2system"
-
-#define NVRAM_CHRP_LENGTH_BLOCK_SIZE 0x10 // CHRP length field is in 16 byte blocks
-
-typedef struct chrp_nvram_header { //16 bytes
-	uint8_t  sig;
-	uint8_t  cksum; // checksum on sig, len, and name
-	uint16_t len;   // total length of the partition in 16 byte blocks starting with the signature
-	// and ending with the last byte of data area, ie len includes its own header size
-	char     name[12];
-	uint8_t  data[0];
-} chrp_nvram_header_t;
-
-typedef struct apple_nvram_header {  // 16 + 16 bytes
-	struct   chrp_nvram_header chrp;
-	uint32_t adler;
-	uint32_t generation;
-	uint8_t  padding[8];
-} apple_nvram_header_t;
-
-#define kIONVRAMPrivilege       kIOClientPrivilegeAdministrator
-
-#define MIN_SYNC_NOW_INTERVAL 15*60 /* Minimum 15 Minutes interval mandated */
-
-#if defined(DEBUG) || defined(DEVELOPMENT)
-#define DEBUG_INFO(fmt, args...)                                    \
-({                                                                  \
-	if (gNVRAMLogging)                                              \
-	IOLog("IONVRAM::%s:%u - " fmt, __FUNCTION__, __LINE__, ##args); \
-})
-
-#define DEBUG_ALWAYS(fmt, args...)                                  \
-({                                                                  \
-	IOLog("IONVRAM::%s:%u - " fmt, __FUNCTION__, __LINE__, ##args); \
-})
-#else
-#define DEBUG_INFO(fmt, args...) (void)NULL
-#define DEBUG_ALWAYS(fmt, args...) (void)NULL
-#endif
-
-#define DEBUG_ERROR DEBUG_ALWAYS
-
-#define SAFE_TO_LOCK() (preemption_enabled() && !panic_active())
-
-#define CONTROLLERLOCK()                 \
-({                                       \
-	if (SAFE_TO_LOCK())                  \
-	        IOLockLock(_controllerLock); \
-})
-
-#define CONTROLLERUNLOCK()                 \
-({                                         \
-	if (SAFE_TO_LOCK())                    \
-	        IOLockUnlock(_controllerLock); \
-})
-
-#define NVRAMREADLOCK()                   \
-({                                        \
-	if (SAFE_TO_LOCK())                   \
-	        IORWLockRead(_variableLock);  \
-})
-
-#define NVRAMWRITELOCK()                  \
-({                                        \
-	if (SAFE_TO_LOCK())                   \
-	        IORWLockWrite(_variableLock); \
-})
-
-#define NVRAMUNLOCK()                      \
-({                                         \
-	if (SAFE_TO_LOCK())                    \
-	        IORWLockUnlock(_variableLock); \
-})
-
-#define NVRAMLOCKASSERTHELD()                                   \
-({                                                              \
-	if (SAFE_TO_LOCK())                                         \
-	        IORWLockAssert(_variableLock, kIORWLockAssertHeld); \
-})
-
-#define NVRAMLOCKASSERTEXCLUSIVE()                               \
-({                                                               \
-	if (SAFE_TO_LOCK())                                          \
-	        IORWLockAssert(_variableLock, kIORWLockAssertWrite); \
-})
-
-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
-	kNVRAMVersionMax
+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 ((_nvramImage == 0) || (_xpramPartitionOffset == 0))
+    return kIOReturnNotReady;
+  
+  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 ((_nvramImage == 0) || (_xpramPartitionOffset == 0))
+    return kIOReturnNotReady;
+  
+  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];
 };
-
-typedef struct {
-	NVRAMPartitionType        type;
-	UInt32                    offset;
-	UInt32                    size;
-	OSSharedPtr<OSDictionary> &dict;
-} NVRAMRegionInfo;
-
-// 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);
-
-static TUNABLE(bool, gNVRAMLogging, "nvram-log", false);
-static bool gInternalBuild = false;
-
-// allowlist variables from macboot that need to be set/get from system region if present
-static const char * const gNVRAMSystemList[] = {
-	"allow-root-hash-mismatch",
-	"auto-boot",
-	"auto-boot-halt-stage",
-	"base-system-path",
-	"boot-args",
-	"boot-command",
-	"boot-image",
-	"bootdelay",
-	"com.apple.System.boot-nonce",
-	"darkboot",
-	"emu",
-	"one-time-boot-command", // Needed for diags customer install flows
-	"policy-nonce-digests",
-	"prevent-restores", // Keep for factory <rdar://problem/70476321>
-	"prev-lang:kbd",
-	"root-live-fs",
-	"sep-debug-args", // Needed to simplify debug flows for SEP
-	"StartupMute", // Set by customers via nvram tool
-	"SystemAudioVolume",
-	"SystemAudioVolumeExtension",
-	"SystemAudioVolumeSaved",
-	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},
-	{"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},
-
-#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
-};
-
-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 Reserved:57;
-	} Bits;
-	uint64_t Uint64;
-};
-
-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},
-	{"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},
-	{"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__) */
-
-	{nullptr, {.Bits.FullAccess = 1}} // Default access
-};
-
-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;
-
-	while (gNVRAMSystemList[i] != nullptr) {
-		if (strcmp(varName, gNVRAMSystemList[i]) == 0) {
-			return true;
-		}
-		i++;
-	}
-
-	return false;
-}
-
-static bool
-verifyWriteSizeLimit(const uuid_t *varGuid, const char *variableName, size_t propDataSize)
-{
-	if (variableInAllowList(variableName)) {
-		if (strnstr(variableName, "breadcrumbs", strlen(variableName)) != NULL) {
-			return propDataSize <= 1024;
-		} else {
-			return propDataSize <= 768;
-		}
-	}
-
-	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
-
-static bool
-verifyPermission(IONVRAMOperation op, const uuid_t *varGuid, const char *varName)
-{
-	VariablePermission perm;
-	bool kernel, writeEntitled, readEntitled, allowList, systemGuid, systemEntitled, systemInternalEntitled, systemAllow, systemReadHiddenAllow;
-	bool admin = false;
-	bool ok = false;
-
-	perm = getVariablePermission(varName);
-
-	kernel = current_task() == kernel_task;
-
-	if (perm.Bits.KernelOnly) {
-		DEBUG_INFO("KernelOnly access for %s, kernel=%d\n", varName, kernel);
-		ok = kernel;
-		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) {
-			ok = true;
-		}
-		break;
-
-	case kIONVRAMOperationWrite:
-		if (kernel || perm.Bits.UserWrite || admin || writeEntitled) {
-			if (systemGuid) {
-				if (allowList) {
-					if (!systemAllow) {
-						DEBUG_ERROR("Allowed write to system region when NOT entitled 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("Never allowed to delete %s\n", varName);
-			break;
-		} else if ((op == kIONVRAMOperationObliterate) && perm.Bits.ResetNVRAMOnlyDelete) {
-			DEBUG_INFO("Not allowed to obliterate %s\n", varName);
-			break;
-		} else if ((op == kIONVRAMOperationDelete) && perm.Bits.ResetNVRAMOnlyDelete) {
-			DEBUG_INFO("Only allowed to delete %s via NVRAM reset\n", varName);
-			break;
-		}
-
-		if (kernel || perm.Bits.UserWrite || admin || writeEntitled) {
-			if (systemGuid) {
-				if (allowList) {
-					if (!systemAllow) {
-						DEBUG_ERROR("Allowed delete to system region when NOT entitled 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("Permission for %s of %s %s: kernel=%d, admin=%d, writeEntitled=%d, readEntitled=%d, systemGuid=%d, systemEntitled=%d, systemInternalEntitled=%d, systemReadHiddenAllow=%d, UserWrite=%d\n",
-	    getNVRAMOpString(op), varName, ok ? "granted" : "denied", kernel, admin, writeEntitled, readEntitled, systemGuid, systemEntitled, systemInternalEntitled, systemReadHiddenAllow, perm.Bits.UserWrite);
-	return ok;
-}
-
-static bool
-verifyPermission(IONVRAMOperation op, const uuid_t *varGuid, const OSSymbol *varName)
-{
-	return verifyPermission(op, varGuid, varName->getCStringNoCopy());
-}
-
-/*
- * 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 false;
-}
-
-static bool
-skipKey(const OSSymbol *aKey)
-{
-	return aKey->isEqualTo(kIOClassNameOverrideKey) ||
-	       aKey->isEqualTo(kIOBSDNameKey) ||
-	       aKey->isEqualTo(kIOBSDNamesKey) ||
-	       aKey->isEqualTo(kIOBSDMajorKey) ||
-	       aKey->isEqualTo(kIOBSDMinorKey) ||
-	       aKey->isEqualTo(kIOBSDUnitKey) ||
-	       aKey->isEqualTo(kIOUserServicePropertiesKey) ||
-	       aKey->isEqualTo(kIOMatchCategoryKey);
-}
-
-// ************************** IODTNVRAMDiags ****************************
-
-#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                  *_variableLock;
-	OSSharedPtr<OSDictionary> _stats;
-
-	bool serializeStats(void *, OSSerialize * serializer);
-
-public:
-	bool start(IOService * provider, IORWLock *lock);
-	void logVariable(NVRAMPartitionType region, IONVRAMOperation op, const char *name, void *data);
-};
-
-OSDefineMetaClassAndStructors(IODTNVRAMDiags, IOService)
-
-bool
-IODTNVRAMDiags::start(IOService * provider, IORWLock *lock)
-{
-	OSSharedPtr<OSSerializer> serializer;
-
-	require(super::start(provider), error);
-
-	_variableLock = lock;
-	require(_variableLock, error);
-
-	_provider = OSDynamicCast(IODTNVRAM, provider);
-	require(_provider != 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)
-{
-	// "Stats"        : OSDictionary
-	// - "XX:varName" : OSDictionary, XX is the region value prefix to distinguish which dictionary the variable is in
-	//   - "Init"     : OSBoolean True/present if variable present at initialization
-	//   - "Read"     : OSNumber count
-	//   - "Write"    : OSNumber count
-	//   - "Delete"   : OSNumber count
-	//   - "Size"     : OSNumber 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;
-	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();
-	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);
-		existingEntry->setObject(kIODTNVRAMDiagsInitKey, varSize);
-		existingEntry->setObject(kIODTNVRAMDiagsSizeKey, varSize);
-		existingEntry->setObject(kIODTNVRAMDiagsPresentKey, kOSBooleanTrue);
-		break;
-	default:
-		goto exit;
-	}
-
-	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);
-	NVRAMUNLOCK();
-
-exit:
-	IODeleteData(entryKey, char, entryKeySize);
-
-	return;
-}
-
-bool
-IODTNVRAMDiags::serializeStats(void *, OSSerialize * serializer)
-{
-	bool ok;
-
-	NVRAMREADLOCK();
-	ok = _stats->serialize(serializer);
-	NVRAMUNLOCK();
-
-	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;
-	OSDictionary     *_variables;
-	uuid_t           _guid;
-
-public:
-	bool                    init(const uuid_t *guid);
-	virtual bool            start(IOService * provider) APPLE_KEXT_OVERRIDE;
-	virtual IOReturn        setVariables(OSObject * properties);
-
-	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)
-{
-	require(super::init() && (guid != nullptr), fail);
-
-	uuid_copy(_guid, *guid);
-
-	return true;
-
-fail:
-	return false;
-}
-
-bool
-IODTNVRAMVariables::start(IOService * provider)
-{
-	if (!super::start(provider)) {
-		goto error;
-	}
-
-	_provider = OSDynamicCast(IODTNVRAM, provider);
-	if (_provider == nullptr) {
-		goto error;
-	}
-
-	registerService();
-
-	return true;
-
-error:
-	stop(provider);
-
-	return false;
-}
-
-IOReturn
-IODTNVRAMVariables::setVariables(OSObject * variables)
-{
-	if (OSDynamicCast(OSDictionary, variables)) {
-		OSSafeReleaseNULL(_variables);
-		_variables = OSDynamicCast(OSDictionary, variables);
-		variables->retain();
-	}
-
-	return kIOReturnSuccess;
-}
-
-bool
-IODTNVRAMVariables::serializeProperties(OSSerialize *s) const
-{
-	const OSSymbol                    *key;
-	OSSharedPtr<OSDictionary>         dict;
-	OSSharedPtr<OSCollectionIterator> iter;
-	OSSharedPtr<OSDictionary>         localVariables(_variables, OSRetain);
-	bool                              ok = false;
-
-	if (localVariables == nullptr) {
-		goto exit;
-	}
-
-	dict = OSDictionary::withCapacity(localVariables->getCount());
-	if (dict == nullptr) {
-		DEBUG_ERROR("No dictionary\n");
-		goto exit;
-	}
-
-	iter = OSCollectionIterator::withCollection(localVariables.get());
-	if (iter == nullptr) {
-		DEBUG_ERROR("failed to create iterator\n");
-		goto exit;
-	}
-
-	while ((key = OSDynamicCast(OSSymbol, iter->getNextObject()))) {
-		if (verifyPermission(kIONVRAMOperationRead, &_guid, key)) {
-			dict->setObject(key, 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;
-
-	if (_provider) {
-		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 = setProperty(key, object);
-		}
-	} else {
-		ret = kIOReturnNotReady;
-	}
-
-	DEBUG_INFO("ret=%#08x\n", ret);
-
-	return ret;
-}
-
-void
-IODTNVRAMVariables::removeProperty(const OSSymbol *aKey)
-{
-	if (_provider) {
-		_provider->removePropertyWithGUIDAndName(&_guid, aKey->getCStringNoCopy());
-	}
-}
-
-
-// **************************** IODTNVRAM *********************************
-
-bool
-IODTNVRAM::init(IORegistryEntry *old, const IORegistryPlane *plane)
-{
-	OSSharedPtr<OSDictionary> dict;
-
-	require(super::init(old, plane), fail);
-
-#if XNU_TARGET_OS_OSX
-#if CONFIG_CSR
-	gInternalBuild = (csr_check(CSR_ALLOW_APPLE_INTERNAL) == 0);
-	DEBUG_INFO("gInternalBuild = %d\n", gInternalBuild);
-#endif // CONFIG_CSR
-#endif // XNU_TARGET_OS_OSX
-
-	_variableLock = IORWLockAlloc();
-	require(_variableLock != nullptr, fail);
-
-	_controllerLock = IOLockAlloc();
-	require(_controllerLock != nullptr, fail);
-
-	dict =  OSDictionary::withCapacity(1);
-	require(dict != nullptr, fail);
-
-	setPropertyTable(dict.get());
-	dict.reset();
-
-	_nvramSize = getNVRAMSize();
-	if (_nvramSize == 0) {
-		DEBUG_ERROR("NVRAM : Error - default size not specified in DT\n");
-		return false;
-	}
-	// partition offsets are UInt16 (bytes / 0x10) + 1
-	if (_nvramSize > 0xFFFF * 0x10) {
-		DEBUG_ERROR("NVRAM : truncating _nvramSize from %ld\n", (long) _nvramSize);
-		_nvramSize = 0xFFFF * 0x10;
-	}
-	_nvramImage = IONewData(UInt8, _nvramSize);
-	require(_nvramImage != nullptr, fail);
-
-	_nvramPartitionOffsets = OSDictionary::withCapacity(1);
-	require(_nvramPartitionOffsets != nullptr, fail);
-
-	_nvramPartitionLengths = OSDictionary::withCapacity(1);
-	require(_nvramPartitionLengths != nullptr, fail);
-
-	_registryPropertiesKey = OSSymbol::withCStringNoCopy("aapl,pci");
-	require(_registryPropertiesKey != nullptr, fail);
-
-	return true;
-
-fail:
-	return false;
-}
-
-bool
-IODTNVRAM::start(IOService *provider)
-{
-	IOReturn ret;
-	OSSharedPtr<OSNumber> version;
-
-	require(super::start(provider), fail);
-
-	// Check if _nvramImage is created from our init() function.
-	// 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(_nvramImage, 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, _variableLock)) {
-		DEBUG_ERROR("Unable to start the diags service!\n");
-		_diags->detach(this);
-		OSSafeReleaseNULL(_diags);
-		goto fail;
-	}
-
-	// <rdar://problem/9529235> race condition possible between
-	// IODTNVRAM and IONVRAMController (restore loses boot-args)
-	initProxyData();
-
-	version = OSNumber::withNumber(_nvramVersion, 32);
-	_diags->setProperty(kCurrentNVRAMVersionKey, version.get());
-
-	// Require at least the common partition to be present and error free
-	require(_commonDict != nullptr, fail);
-
-	if (_systemPartitionSize) {
-		_systemService = new IODTNVRAMVariables;
-
-		if (!_systemService || !_systemService->init(&gAppleSystemVariableGuid)) {
-			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:
-	if (_commonPartitionSize) {
-		_commonService = new IODTNVRAMVariables;
-
-		if (!_commonService || !_commonService->init(&gAppleNVRAMGuid)) {
-			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;
-		}
-	}
-
-	ret = serializeVariables();
-	DEBUG_INFO("serializeVariables ret=%#08x\n", ret);
-
-no_common:
-	return true;
-
-fail:
-	stop(provider);
-	return false;
-}
-
-void
-IODTNVRAM::initProxyData(void)
-{
-	OSSharedPtr<IORegistryEntry> entry;
-	const char                   *key = "nvram-proxy-data";
-	OSData                       *data;
-	const void                   *bytes;
-
-	entry = IORegistryEntry::fromPath("/chosen", gIODTPlane);
-	if (entry != nullptr) {
-		OSSharedPtr<OSObject> prop = entry->copyProperty(key);
-		if (prop != nullptr) {
-			data = OSDynamicCast(OSData, prop.get());
-			if (data != nullptr) {
-				bytes = data->getBytesNoCopy();
-				if ((bytes != nullptr) && (data->getLength() <= _nvramSize)) {
-					bcopy(bytes, _nvramImage, data->getLength());
-					initNVRAMImage();
-					_isProxied = true;
-				}
-			}
-		}
-#if defined(RELEASE)
-		entry->removeProperty(key);
-#endif
-	}
-}
-
-UInt32
-IODTNVRAM::getNVRAMSize(void)
-{
-	OSSharedPtr<IORegistryEntry> entry;
-	const char                   *key = "nvram-bank-size";
-	OSData                       *data;
-	UInt32                       size = 0;
-
-	entry = IORegistryEntry::fromPath("/chosen", gIODTPlane);
-	if (entry != nullptr) {
-		OSSharedPtr<OSObject> prop = entry->copyProperty(key);
-		if (prop != nullptr) {
-			data = OSDynamicCast(OSData, prop.get());
-			if (data != nullptr) {
-				size = *((UInt32*)data->getBytesNoCopy());
-				DEBUG_ALWAYS("NVRAM size is %u bytes\n", (unsigned int) size);
-			}
-		}
-	}
-	return size;
-}
-
-void
-IODTNVRAM::registerNVRAMController(IONVRAMController *nvram)
-{
-	IOReturn ret;
-	OSSharedPtr<OSNumber> version;
-
-	if (_nvramController != nullptr) {
-		DEBUG_ERROR("Duplicate controller set\n");
-		return;
-	}
-
-	DEBUG_INFO("setting controller\n");
-
-	CONTROLLERLOCK();
-	_nvramController = nvram;
-	CONTROLLERUNLOCK();
-
-	// <rdar://problem/9529235> race condition possible between
-	// IODTNVRAM and IONVRAMController (restore loses boot-args)
-	if (!_isProxied) {
-		DEBUG_INFO("Reading non-proxied NVRAM data\n");
-		_nvramController->read(0, _nvramImage, _nvramSize);
-		initNVRAMImage();
-	}
-
-	ret = serializeVariables();
-	DEBUG_INFO("serializeVariables ret=%#08x\n", ret);
-
-	return;
-}
-
-static const char *
-get_bank_version_string(int version)
-{
-	switch (version) {
-	case kNVRAMVersion1:
-		return NVRAM_CHRP_APPLE_HEADER_NAME_V1;
-	case kNVRAMVersion2:
-		return NVRAM_CHRP_APPLE_HEADER_NAME_V2;
-	default:
-		return "Unknown";
-	}
-}
-
-static UInt32
-adler32(const UInt8 *buffer, size_t length)
-{
-	UInt32 offset;
-	UInt32 adler, lowHalf, highHalf;
-
-	lowHalf = 1;
-	highHalf = 0;
-
-	for (offset = 0; offset < length; offset++) {
-		if ((offset % 5000) == 0) {
-			lowHalf  %= 65521L;
-			highHalf %= 65521L;
-		}
-
-		lowHalf += buffer[offset];
-		highHalf += lowHalf;
-	}
-
-	lowHalf  %= 65521L;
-	highHalf %= 65521L;
-
-	adler = (highHalf << 16) | lowHalf;
-
-	return adler;
-}
-
-static UInt32
-nvram_get_adler(UInt8 *buf, int version)
-{
-	return ((struct apple_nvram_header *)buf)->adler;
-}
-
-static UInt32
-adler32_with_version(const UInt8 *buf, size_t len, int version)
-{
-	size_t offset;
-
-	switch (version) {
-	case kNVRAMVersion1:
-	case kNVRAMVersion2:
-		offset = offsetof(struct apple_nvram_header, generation);
-		break;
-	default:
-		return 0;
-	}
-
-	return adler32(buf + offset, len - offset);
-}
-
-static UInt8
-chrp_checksum(const struct chrp_nvram_header *hdr)
-{
-	UInt16 sum;
-	const UInt8 *p;
-	const UInt8 *begin = (const uint8_t *)hdr + offsetof(struct chrp_nvram_header, len);
-	const UInt8 *end = (const uint8_t *)hdr + offsetof(struct chrp_nvram_header, data);
-
-	// checksum the header (minus the checksum itself)
-	sum = hdr->sig;
-	for (p = begin; p < end; p++) {
-		sum += *p;
-	}
-	while (sum > 0xff) {
-		sum = (sum & 0xff) + (sum >> 8);
-	}
-
-	return sum & 0xff;
-}
-
-static IOReturn
-nvram_validate_header_v1v2(const UInt8 * buf, UInt32 *generation, int version)
-{
-	IOReturn result = kIOReturnError;
-	UInt8 checksum;
-	const char *header_string = get_bank_version_string(version);
-	struct chrp_nvram_header *chrp_header = (struct chrp_nvram_header *)buf;
-	UInt32 local_gen = 0;
-
-	// <rdar://problem/73454488> Recovery Mode [Internal Build] 18D52-->18E141 [J307/308 Only]
-	// we can only compare the first "nvram" parts of the name as some devices have additional junk from
-	// a previous build likely copying past bounds of the "nvram" name in the const section
-	if (memcmp(header_string, chrp_header->name, strlen(header_string)) == 0) {
-		checksum = chrp_checksum(chrp_header);
-		if (checksum == chrp_header->cksum) {
-			result = kIOReturnSuccess;
-			local_gen = ((struct apple_nvram_header*)buf)->generation;
-
-			DEBUG_INFO("Found %s gen=%u\n", header_string, (unsigned int)local_gen);
-
-			if (generation) {
-				*generation = local_gen;
-			}
-		} else {
-			DEBUG_INFO("invalid checksum in header, found %#02x, expected %#02x\n", chrp_header->cksum, checksum);
-		}
-	} else {
-		DEBUG_INFO("invalid bank for \"%s\", name = %#02x %#02x %#02x %#02x\n", header_string,
-		    chrp_header->name[0],
-		    chrp_header->name[1],
-		    chrp_header->name[2],
-		    chrp_header->name[3]);
-	}
-
-	return result;
-}
-
-static int
-findNVRAMVersion(UInt8 *buf, size_t len, UInt32 *generation)
-{
-	NVRAMVersion version = kNVRAMVersionUnknown;
-
-	if (nvram_validate_header_v1v2(buf, generation, kNVRAMVersion1) == kIOReturnSuccess) {
-		version = kNVRAMVersion1;
-		goto exit;
-	}
-
-	if (nvram_validate_header_v1v2(buf, generation, kNVRAMVersion2) == kIOReturnSuccess) {
-		version = kNVRAMVersion2;
-		goto exit;
-	}
-
-	DEBUG_INFO("Unable to determine version, defaulting to V1\n");
-	version = kNVRAMVersion1;
-
-exit:
-	DEBUG_INFO("version=%u\n", version);
-	return version;
-}
-
-static void
-nvram_set_apple_header(UInt8 *buf, size_t len, UInt32 generation, int version)
-{
-	if (version == kNVRAMVersion1 ||
-	    version == kNVRAMVersion2) {
-		struct apple_nvram_header *apple_hdr = (struct apple_nvram_header *)buf;
-		generation += 1;
-		apple_hdr->generation = generation;
-		apple_hdr->adler = adler32_with_version(buf, len, version);
-	}
-}
-
-void
-IODTNVRAM::initNVRAMImage(void)
-{
-	char   partitionID[18];
-	UInt32 partitionOffset, partitionLength;
-	UInt32 currentLength, currentOffset = 0;
-	UInt32 hdr_adler, calculated_adler;
-
-	_commonPartitionOffset = 0xFFFFFFFF;
-	_systemPartitionOffset = 0xFFFFFFFF;
-
-	_nvramVersion = findNVRAMVersion(_nvramImage, _nvramSize, &_nvramGeneration);
-
-	hdr_adler = nvram_get_adler(_nvramImage, _nvramVersion);
-	calculated_adler = adler32_with_version(_nvramImage, _nvramSize, _nvramVersion);
-
-	if (hdr_adler != calculated_adler) {
-		panic("header adler %#08X != calculated_adler %#08X\n", (unsigned int)hdr_adler, (unsigned int)calculated_adler);
-		return;
-	}
-
-	// Look through the partitions to find the common and system partitions.
-	while (currentOffset < _nvramSize) {
-		bool common_partition;
-		bool system_partition;
-		chrp_nvram_header_t * header = (chrp_nvram_header_t *)(_nvramImage + currentOffset);
-		const uint8_t common_v1_name[sizeof(header->name)] = {NVRAM_CHRP_PARTITION_NAME_COMMON_V1};
-		const uint8_t common_v2_name[sizeof(header->name)] = {NVRAM_CHRP_PARTITION_NAME_COMMON_V2};
-		const uint8_t system_v1_name[sizeof(header->name)] = {NVRAM_CHRP_PARTITION_NAME_SYSTEM_V1};
-		const uint8_t system_v2_name[sizeof(header->name)] = {NVRAM_CHRP_PARTITION_NAME_SYSTEM_V2};
-
-		currentLength = header->len * NVRAM_CHRP_LENGTH_BLOCK_SIZE;
-
-		if (currentLength < sizeof(chrp_nvram_header_t)) {
-			break;
-		}
-
-		partitionOffset = currentOffset + sizeof(chrp_nvram_header_t);
-		partitionLength = currentLength - sizeof(chrp_nvram_header_t);
-
-		if ((partitionOffset + partitionLength) > _nvramSize) {
-			break;
-		}
-
-		common_partition = (memcmp(header->name, common_v1_name, sizeof(header->name)) == 0) ||
-		    (memcmp(header->name, common_v2_name, sizeof(header->name)) == 0);
-		system_partition = (memcmp(header->name, system_v1_name, sizeof(header->name)) == 0) ||
-		    (memcmp(header->name, system_v2_name, sizeof(header->name)) == 0);
-
-		if (common_partition) {
-			_commonPartitionOffset = partitionOffset;
-			_commonPartitionSize = partitionLength;
-		} else if (system_partition) {
-			_systemPartitionOffset = partitionOffset;
-			_systemPartitionSize = partitionLength;
-		} else {
-			OSSharedPtr<OSNumber> partitionOffsetNumber, partitionLengthNumber;
-
-			// Construct the partition ID from the signature and name.
-			snprintf(partitionID, sizeof(partitionID), "%#02x,", header->sig);
-			memcpy(partitionID + 5, header->name, sizeof(header->name));
-			partitionID[17] = '\0';
-
-			partitionOffsetNumber = OSNumber::withNumber(partitionOffset, 32);
-			partitionLengthNumber = OSNumber::withNumber(partitionLength, 32);
-
-			// Save the partition offset and length
-			_nvramPartitionOffsets->setObject(partitionID, partitionOffsetNumber.get());
-			_nvramPartitionLengths->setObject(partitionID, partitionLengthNumber.get());
-		}
-		currentOffset += currentLength;
-	}
-
-	DEBUG_ALWAYS("NVRAM : commonPartitionOffset - %#x, commonPartitionSize - %#x, systemPartitionOffset - %#x, systemPartitionSize - %#x\n",
-	    (unsigned int) _commonPartitionOffset, (unsigned int) _commonPartitionSize, (unsigned int) _systemPartitionOffset, (unsigned int) _systemPartitionSize);
-
-	_lastDeviceSync = 0;
-	_freshInterval = TRUE;          // we will allow sync() even before the first 15 minutes have passed.
-
-	initVariables();
-}
-
-void
-IODTNVRAM::syncInternal(bool rateLimit)
-{
-	IOReturn ret;
-
-	DEBUG_INFO("rateLimit=%d\n", rateLimit);
-
-	// Don't try to perform controller operations if none has been registered.
-	if (_nvramController == nullptr) {
-		return;
-	}
-
-	// Rate limit requests to sync. Drivers that need this rate limiting will
-	// shadow the data and only write to flash when they get a sync call
-	if (rateLimit) {
-		if (safeToSync() == false) {
-			DEBUG_INFO("safeToSync()=false\n");
-			return;
-		}
-	}
-
-	CONTROLLERLOCK();
-
-	_nvramGeneration++;
-	nvram_set_apple_header(_nvramImage, _nvramSize, _nvramGeneration, _nvramVersion);
-
-	ret = _nvramController->write(0, _nvramImage, _nvramSize);
-	DEBUG_INFO("nvramController->write() for gen=%u ret=%#08x\n", (unsigned int)_nvramGeneration, ret);
-
-	if (_diags && SAFE_TO_LOCK()) {
-		OSSharedPtr<OSNumber> generation = OSNumber::withNumber(_nvramGeneration, 32);
-		_diags->setProperty(kCurrentGenerationCountKey, generation.get());
-	}
-
-	DEBUG_INFO("Calling sync()\n");
-	_nvramController->sync();
-
-	CONTROLLERUNLOCK();
-}
-
-void
-IODTNVRAM::sync(void)
-{
-	syncInternal(false);
-}
-
-bool
-IODTNVRAM::serializeProperties(OSSerialize *s) const
-{
-	const OSSymbol                    *key;
-	OSSharedPtr<OSDictionary>         systemDict, commonDict, dict;
-	OSSharedPtr<OSCollectionIterator> iter;
-	bool                              ok = false;
-	unsigned int                      totalCapacity = 0;
-
-	NVRAMREADLOCK();
-	if (_commonDict) {
-		commonDict = OSDictionary::withDictionary(_commonDict.get());
-	}
-
-	if (_systemDict) {
-		systemDict = OSDictionary::withDictionary(_systemDict.get());
-	}
-	NVRAMUNLOCK();
-
-	totalCapacity += (commonDict != nullptr) ? commonDict->getCapacity() : 0;
-	totalCapacity += (systemDict != nullptr) ? systemDict->getCapacity() : 0;
-
-	dict = OSDictionary::withCapacity(totalCapacity);
-
-	if (dict == nullptr) {
-		DEBUG_ERROR("No dictionary\n");
-		goto exit;
-	}
-
-	// Copy system entries first if present then copy unique common entries
-	if (systemDict != nullptr) {
-		iter = OSCollectionIterator::withCollection(systemDict.get());
-		if (iter == nullptr) {
-			DEBUG_ERROR("failed to create iterator\n");
-			goto exit;
-		}
-
-		while ((key = OSDynamicCast(OSSymbol, iter->getNextObject()))) {
-			if (verifyPermission(kIONVRAMOperationRead, &gAppleSystemVariableGuid, key)) {
-				dict->setObject(key, systemDict->getObject(key));
-			}
-		}
-
-		iter.reset();
-	}
-
-	if (commonDict != nullptr) {
-		iter = OSCollectionIterator::withCollection(commonDict.get());
-		if (iter == nullptr) {
-			DEBUG_ERROR("failed to create common iterator\n");
-			goto exit;
-		}
-
-		while ((key = OSDynamicCast(OSSymbol, iter->getNextObject()))) {
-			if (dict->getObject(key) != nullptr) {
-				// Skip non uniques
-				continue;
-			}
-			if (verifyPermission(kIONVRAMOperationRead, &gAppleNVRAMGuid, key)) {
-				dict->setObject(key, commonDict->getObject(key));
-			}
-		}
-	}
-
-	ok = dict->serialize(s);
-
-exit:
-	DEBUG_INFO("ok=%d\n", ok);
-
-	return ok;
-}
-
-NVRAMPartitionType
-IODTNVRAM::getDictionaryType(const OSDictionary *dict) const
-{
-	if (dict == _commonDict) {
-		return kIONVRAMPartitionCommon;
-	} else if (dict == _systemDict) {
-		return kIONVRAMPartitionSystem;
-	} else {
-		return kIONVRAMPartitionTypeUnknown;
-	}
-}
-
-IOReturn
-IODTNVRAM::chooseDictionary(IONVRAMOperation operation, const uuid_t *varGuid, const char *variableName, OSDictionary **dict) const
-{
-	if (_systemDict != nullptr) {
-		bool systemGuid = uuid_compare(*varGuid, gAppleSystemVariableGuid) == 0;
-
-		if (variableInAllowList(variableName)) {
-			DEBUG_INFO("Using system dictionary due to allow list\n");
-			if (!systemGuid) {
-				DEBUG_ERROR("System GUID NOT used for %s\n", variableName);
-			}
-			*dict = _systemDict.get();
-		} else if (systemGuid) {
-			DEBUG_INFO("Using system dictionary via GUID\n");
-			*dict = _systemDict.get();
-		} else {
-			DEBUG_INFO("Using common dictionary\n");
-			*dict = _commonDict.get();
-		}
-		return kIOReturnSuccess;
-	} else if (_commonDict != nullptr) {
-		DEBUG_INFO("Defaulting to common dictionary\n");
-		*dict = _commonDict.get();
-		return kIOReturnSuccess;
-	}
-
-	return kIOReturnNotFound;
-}
-
-IOReturn
-IODTNVRAM::flushDict(const uuid_t *guid, IONVRAMOperation op)
-{
-	IOReturn err = kIOReturnSuccess;
-
-	if ((_systemDict != nullptr) && (uuid_compare(*guid, gAppleSystemVariableGuid) == 0)) {
-		const OSSymbol *key;
-		OSSharedPtr<OSDictionary> newDict;
-		OSSharedPtr<OSCollectionIterator> iter;
-
-		newDict = OSDictionary::withCapacity(_systemDict->getCapacity());
-		iter = OSCollectionIterator::withCollection(_systemDict.get());
-		if ((newDict == nullptr) || (iter == nullptr)) {
-			err = kIOReturnNoMemory;
-			goto exit;
-		}
-
-		while ((key = OSDynamicCast(OSSymbol, iter->getNextObject()))) {
-			if (!verifyPermission(op, &gAppleSystemVariableGuid, key)) {
-				newDict->setObject(key, _systemDict->getObject(key));
-			}
-		}
-
-		_systemDict = newDict;
-
-		DEBUG_INFO("system dictionary flushed\n");
-	} else if ((_commonDict != nullptr) && (uuid_compare(*guid, gAppleNVRAMGuid) == 0)) {
-		const OSSymbol *key;
-		OSSharedPtr<OSDictionary> newDict;
-		OSSharedPtr<OSCollectionIterator> iter;
-
-		newDict = OSDictionary::withCapacity(_commonDict->getCapacity());
-		iter = OSCollectionIterator::withCollection(_commonDict.get());
-		if ((newDict == nullptr) || (iter == nullptr)) {
-			err = kIOReturnNoMemory;
-			goto exit;
-		}
-
-		while ((key = OSDynamicCast(OSSymbol, iter->getNextObject()))) {
-			if (!verifyPermission(op, &gAppleNVRAMGuid, key)) {
-				newDict->setObject(key, _commonDict->getObject(key));
-			}
-		}
-
-		_commonDict = newDict;
-
-		DEBUG_INFO("common dictionary flushed\n");
-	}
-
-exit:
-	return err;
-}
-
-bool
-IODTNVRAM::handleSpecialVariables(const char *name, const uuid_t *guid, const OSObject *obj, IOReturn *error)
-{
-	IOReturn err = kIOReturnSuccess;
-	bool special = false;
-
-	NVRAMLOCKASSERTEXCLUSIVE();
-
-	// ResetNVRam flushes both regions in one call
-	// Obliterate can flush either separately
-	if (strcmp(name, "ObliterateNVRam") == 0) {
-		special = true;
-		err = flushDict(guid, kIONVRAMOperationObliterate);
-	} else if (strcmp(name, "ResetNVRam") == 0) {
-		special = true;
-		err = flushDict(&gAppleSystemVariableGuid, kIONVRAMOperationReset);
-
-		if (err != kIOReturnSuccess) {
-			goto exit;
-		}
-
-		err = flushDict(&gAppleNVRAMGuid, kIONVRAMOperationReset);
-	}
-
-exit:
-	if (error) {
-		*error = err;
-	}
-
-	return special;
-}
-
-OSSharedPtr<OSObject>
-IODTNVRAM::copyPropertyWithGUIDAndName(const uuid_t *guid, const char *name) const
-{
-	IOReturn              result;
-	OSDictionary          *dict;
-	OSSharedPtr<OSObject> theObject = nullptr;
-
-	result = chooseDictionary(kIONVRAMOperationRead, guid, name, &dict);
-	if (result != kIOReturnSuccess) {
-		DEBUG_INFO("No dictionary\n");
-		goto exit;
-	}
-
-	if (!verifyPermission(kIONVRAMOperationRead, guid, name)) {
-		DEBUG_INFO("Not privileged\n");
-		goto exit;
-	}
-
-	NVRAMREADLOCK();
-	theObject.reset(dict->getObject(name), OSRetain);
-	NVRAMUNLOCK();
-
-	if (_diags) {
-		_diags->logVariable(getDictionaryType(dict), kIONVRAMOperationRead, name, NULL);
-	}
-
-	if (theObject != nullptr) {
-		DEBUG_INFO("found data\n");
-	}
-
-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::setPropertyWithGUIDAndName(const uuid_t *guid, const char *name, OSObject *anObject)
-{
-	IOReturn              ret = kIOReturnSuccess;
-	bool                  remove = false;
-	OSString              *tmpString = nullptr;
-	OSSharedPtr<OSObject> propObject, oldObject;
-	OSSharedPtr<OSObject> sharedObject(anObject, OSRetain);
-	OSDictionary          *dict;
-	bool                  deletePropertyKey, syncNowPropertyKey, forceSyncNowPropertyKey;
-	bool                  ok;
-	size_t                propDataSize = 0;
-
-	deletePropertyKey = strncmp(name, kIONVRAMDeletePropertyKey, sizeof(kIONVRAMDeletePropertyKey)) == 0;
-	syncNowPropertyKey = strncmp(name, kIONVRAMSyncNowPropertyKey, sizeof(kIONVRAMSyncNowPropertyKey)) == 0;
-	forceSyncNowPropertyKey = strncmp(name, kIONVRAMForceSyncNowPropertyKey, sizeof(kIONVRAMForceSyncNowPropertyKey)) == 0;
-
-	if (deletePropertyKey) {
-		tmpString = OSDynamicCast(OSString, anObject);
-		if (tmpString != nullptr) {
-			const char *variableName;
-			uuid_t     varGuid;
-			IOReturn   removeRet;
-
-			parseVariableName(tmpString->getCStringNoCopy(), &varGuid, &variableName);
-			removeRet = removePropertyWithGUIDAndName(&varGuid, variableName);
-
-			DEBUG_INFO("kIONVRAMDeletePropertyKey found, removeRet=%#08x\n", removeRet);
-		} else {
-			DEBUG_INFO("kIONVRAMDeletePropertyKey value needs to be an OSString\n");
-			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.
-			syncInternal(syncNowPropertyKey);
-		} else {
-			DEBUG_INFO("%s value needs to be an OSString\n", name);
-			ret = kIOReturnError;
-		}
-		goto exit;
-	}
-
-	ret = chooseDictionary(kIONVRAMOperationWrite, guid, name, &dict);
-	if (ret != kIOReturnSuccess) {
-		DEBUG_INFO("No dictionary\n");
-		goto exit;
-	}
-
-	if (!verifyPermission(kIONVRAMOperationWrite, guid, name)) {
-		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);
-		break;
-
-	case kOFVariableTypeNumber:
-		propObject = OSDynamicPtrCast<OSNumber>(sharedObject);
-		break;
-
-	case kOFVariableTypeString:
-		propObject = OSDynamicPtrCast<OSString>(sharedObject);
-		if (propObject != nullptr) {
-			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) {
-			propDataSize = (OSDynamicPtrCast<OSData>(propObject))->getLength();
-		}
-
-#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_INFO("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;
-	}
-
-	NVRAMWRITELOCK();
-	ok = handleSpecialVariables(name, guid, propObject.get(), &ret);
-	NVRAMUNLOCK();
-
-	if (ok) {
-		serializeVariables();
-		goto exit;
-	}
-
-	NVRAMREADLOCK();
-	oldObject.reset(dict->getObject(name), OSRetain);
-	NVRAMUNLOCK();
-
-	if (remove == false) {
-		DEBUG_INFO("Adding object\n");
-		NVRAMWRITELOCK();
-		if (!dict->setObject(name, propObject.get())) {
-			ret = kIOReturnBadArgument;
-		}
-		NVRAMUNLOCK();
-		if (_diags) {
-			UInt32 logSize = 0;
-			convertObjectToProp(nullptr, &logSize, name, propObject.get());
-			_diags->logVariable(getDictionaryType(dict), kIONVRAMOperationWrite, name, (void *)(uintptr_t)logSize);
-		}
-	} else {
-		DEBUG_INFO("Removing object\n");
-		// Check for existence so we can decide whether we need to sync variables
-		if (oldObject) {
-			ret = removePropertyWithGUIDAndName(guid, name);
-		} else {
-			ret = kIOReturnNotFound;
-		}
-	}
-
-	if (ret == kIOReturnSuccess) {
-		ret = serializeVariables();
-		if (ret != kIOReturnSuccess) {
-			DEBUG_ERROR("serializeVariables failed, ret=%#08x\n", ret);
-
-			NVRAMWRITELOCK();
-			if (oldObject) {
-				dict->setObject(name, oldObject.get());
-			} else {
-				dict->removeObject(name);
-			}
-			NVRAMUNLOCK();
-
-			(void) serializeVariables();
-			ret = kIOReturnNoSpace;
-		}
-	}
-
-	if (oldObject) {
-		oldObject.reset();
-	}
-	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) {
-		serializeVariables();
-	} else {
-		DEBUG_INFO("removePropertyInternal failed, ret=%#08x\n", ret);
-	}
-}
-
-IOReturn
-IODTNVRAM::removePropertyWithGUIDAndName(const uuid_t *guid, const char *name)
-{
-	IOReturn     ret;
-	OSDictionary *dict;
-	bool removed = false;
-
-	DEBUG_INFO("name=%s\n", name);
-
-	ret = chooseDictionary(kIONVRAMOperationDelete, guid, name, &dict);
-	if (ret != kIOReturnSuccess) {
-		DEBUG_INFO("No dictionary\n");
-		goto exit;
-	}
-
-	if (!verifyPermission(kIONVRAMOperationDelete, guid, name)) {
-		DEBUG_INFO("Not priveleged\n");
-		ret = kIOReturnNotPrivileged;
-		goto exit;
-	}
-
-	NVRAMWRITELOCK();
-
-	// If the object exists, remove it from the dictionary.
-	if (dict->getObject(name) != nullptr) {
-		dict->removeObject(name);
-		removed = true;
-	} else {
-		DEBUG_INFO("%s not found\n", name);
-	}
-
-	NVRAMUNLOCK();
-
-	if (removed) {
-		if (_diags) {
-			_diags->logVariable(getDictionaryType(dict), kIONVRAMOperationDelete, name, nullptr);
-		}
-		ret = serializeVariables();
-		DEBUG_INFO("serializeVariables ret=0x%08x\n", ret);
-	}
-
-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;
-}
-
-IOReturn
-IODTNVRAM::readXPRAM(IOByteCount offset, UInt8 *buffer,
-    IOByteCount length)
-{
-	return kIOReturnUnsupported;
-}
-
-IOReturn
-IODTNVRAM::writeXPRAM(IOByteCount offset, UInt8 *buffer,
-    IOByteCount length)
-{
-	return kIOReturnUnsupported;
-}
-
-IOReturn
-IODTNVRAM::readNVRAMProperty(IORegistryEntry *entry,
-    const OSSymbol **name,
-    OSData **value)
-{
-	IOReturn err;
-
-	err = readNVRAMPropertyType1(entry, name, value);
-
-	return err;
-}
-
-IOReturn
-IODTNVRAM::writeNVRAMProperty(IORegistryEntry *entry,
-    const OSSymbol *name,
-    OSData *value)
-{
-	IOReturn err;
-
-	err = writeNVRAMPropertyType1(entry, name, value);
-
-	return err;
-}
-
-OSDictionary *
-IODTNVRAM::getNVRAMPartitions(void)
-{
-	return _nvramPartitionLengths.get();
-}
-
-IOReturn
-IODTNVRAM::readNVRAMPartition(const OSSymbol *partitionID,
-    IOByteCount offset, UInt8 *buffer,
-    IOByteCount length)
-{
-	OSNumber *partitionOffsetNumber, *partitionLengthNumber;
-	UInt32   partitionOffset, partitionLength, end;
-
-	partitionOffsetNumber =
-	    (OSNumber *)_nvramPartitionOffsets->getObject(partitionID);
-	partitionLengthNumber =
-	    (OSNumber *)_nvramPartitionLengths->getObject(partitionID);
-
-	if ((partitionOffsetNumber == nullptr) || (partitionLengthNumber == nullptr)) {
-		return kIOReturnNotFound;
-	}
-
-	partitionOffset = partitionOffsetNumber->unsigned32BitValue();
-	partitionLength = partitionLengthNumber->unsigned32BitValue();
-
-	if (os_add_overflow(offset, length, &end)) {
-		return kIOReturnBadArgument;
-	}
-	if ((buffer == nullptr) || (length == 0) || (end > partitionLength)) {
-		return kIOReturnBadArgument;
-	}
-
-	bcopy(_nvramImage + partitionOffset + offset, buffer, length);
-
-	return kIOReturnSuccess;
-}
-
-IOReturn
-IODTNVRAM::writeNVRAMPartition(const OSSymbol *partitionID,
-    IOByteCount offset, UInt8 *buffer,
-    IOByteCount length)
-{
-	OSNumber *partitionOffsetNumber, *partitionLengthNumber;
-	UInt32   partitionOffset, partitionLength, end;
-
-	partitionOffsetNumber =
-	    (OSNumber *)_nvramPartitionOffsets->getObject(partitionID);
-	partitionLengthNumber =
-	    (OSNumber *)_nvramPartitionLengths->getObject(partitionID);
-
-	if ((partitionOffsetNumber == nullptr) || (partitionLengthNumber == nullptr)) {
-		return kIOReturnNotFound;
-	}
-
-	partitionOffset = partitionOffsetNumber->unsigned32BitValue();
-	partitionLength = partitionLengthNumber->unsigned32BitValue();
-
-	if (os_add_overflow(offset, length, &end)) {
-		return kIOReturnBadArgument;
-	}
-	if ((buffer == nullptr) || (length == 0) || (end > partitionLength)) {
-		return kIOReturnBadArgument;
-	}
-
-	bcopy(buffer, _nvramImage + partitionOffset + offset, length);
-
-	if (_nvramController != nullptr) {
-		_nvramController->write(0, _nvramImage, _nvramSize);
-	}
-
-	return kIOReturnSuccess;
-}
-
-IOByteCount
-IODTNVRAM::savePanicInfo(UInt8 *buffer, IOByteCount length)
-{
-	return 0;
-}
-
-// Private methods
-
-IOReturn
-IODTNVRAM::initVariables(void)
-{
-	UInt32                      cnt, cntStart;
-	const UInt8                 *propName, *propData;
-	UInt32                      propNameLength, propDataLength, regionIndex;
-	OSSharedPtr<const OSSymbol> propSymbol;
-	OSSharedPtr<OSObject>       propObject;
-	NVRAMRegionInfo             *currentRegion;
-	NVRAMRegionInfo             variableRegions[] = { { kIONVRAMPartitionCommon, _commonPartitionOffset, _commonPartitionSize, _commonDict},
-							  { kIONVRAMPartitionSystem, _systemPartitionOffset, _systemPartitionSize, _systemDict} };
-
-	DEBUG_INFO("...\n");
-
-	for (regionIndex = 0; regionIndex < ARRAY_SIZE(variableRegions); regionIndex++) {
-		currentRegion = &variableRegions[regionIndex];
-		const uint8_t * imageData = _nvramImage + currentRegion->offset;
-
-		if (currentRegion->size == 0) {
-			continue;
-		}
-
-		currentRegion->dict = OSDictionary::withCapacity(1);
-
-		DEBUG_INFO("region = %d\n", currentRegion->type);
-		cnt = 0;
-		while (cnt < currentRegion->size) {
-			cntStart = cnt;
-			// Break if there is no name.
-			if (imageData[cnt] == '\0') {
-				break;
-			}
-
-			// Find the length of the name.
-			propName = imageData + cnt;
-			for (propNameLength = 0; (cnt + propNameLength) < currentRegion->size;
-			    propNameLength++) {
-				if (imageData[cnt + propNameLength] == '=') {
-					break;
-				}
-			}
-
-			// Break if the name goes past the end of the partition.
-			if ((cnt + propNameLength) >= currentRegion->size) {
-				break;
-			}
-			cnt += propNameLength + 1;
-
-			propData = imageData + cnt;
-			for (propDataLength = 0; (cnt + propDataLength) < currentRegion->size;
-			    propDataLength++) {
-				if (imageData[cnt + propDataLength] == '\0') {
-					break;
-				}
-			}
-
-			// Break if the data goes past the end of the partition.
-			if ((cnt + propDataLength) >= currentRegion->size) {
-				break;
-			}
-			cnt += propDataLength + 1;
-
-			if (convertPropToObject(propName, propNameLength,
-			    propData, propDataLength,
-			    propSymbol, propObject)) {
-				DEBUG_INFO("adding %s, dataLength=%u\n", propSymbol.get()->getCStringNoCopy(), (unsigned int)propDataLength);
-				currentRegion->dict.get()->setObject(propSymbol.get(), propObject.get());
-				if (_diags) {
-					_diags->logVariable(getDictionaryType(currentRegion->dict.get()), kIONVRAMOperationInit, propSymbol.get()->getCStringNoCopy(), (void *)(uintptr_t)(cnt - cntStart));
-				}
-			}
-		}
-	}
-
-	// Create the boot-args property if it is not in the dictionary.
-	if (_systemDict != nullptr) {
-		if (_systemDict->getObject(kIONVRAMBootArgsKey) == nullptr) {
-			propObject = OSString::withCStringNoCopy("");
-			if (propObject != nullptr) {
-				_systemDict->setObject(kIONVRAMBootArgsKey, propObject.get());
-			}
-		}
-	} else if (_commonDict != nullptr) {
-		if (_commonDict->getObject(kIONVRAMBootArgsKey) == nullptr) {
-			propObject = OSString::withCStringNoCopy("");
-			if (propObject != nullptr) {
-				_commonDict->setObject(kIONVRAMBootArgsKey, propObject.get());
-			}
-		}
-	}
-
-	DEBUG_INFO("%s _commonDict=%p _systemDict=%p\n", __FUNCTION__, _commonDict ? _commonDict.get() : nullptr, _systemDict ? _systemDict.get() : nullptr);
-
-	return kIOReturnSuccess;
-}
-
-IOReturn
-IODTNVRAM::serializeVariables(void)
-{
-	IOReturn                          ret;
-	bool                              ok = false;
-	UInt32                            length, maxLength, regionIndex;
-	UInt8                             *buffer, *tmpBuffer;
-	const OSSymbol                    *tmpSymbol;
-	OSObject                          *tmpObject;
-	OSSharedPtr<OSCollectionIterator> iter;
-	OSSharedPtr<OSNumber>             sizeUsed;
-	OSSharedPtr<OSNumber>             generation;
-	UInt32                            systemUsed = 0;
-	UInt32                            commonUsed = 0;
-	UInt8                             *nvramImage;
-	NVRAMRegionInfo                   *currentRegion;
-	NVRAMRegionInfo                   variableRegions[] = { { kIONVRAMPartitionCommon, _commonPartitionOffset, _commonPartitionSize, _commonDict},
-								{ kIONVRAMPartitionSystem, _systemPartitionOffset, _systemPartitionSize, _systemDict} };
-
-	require_action(_systemPanicked == false, exit, ret = kIOReturnNotReady);
-
-	require_action(_nvramController != nullptr, exit, (ret = kIOReturnNotReady, DEBUG_ERROR("No _nvramController\n")));
-
-	nvramImage = IONewZeroData(UInt8, _nvramSize);
-	require_action(nvramImage != nullptr, exit, (ret = kIOReturnNoMemory, DEBUG_ERROR("Can't create NVRAM image copy\n")));
-
-	DEBUG_INFO("...\n");
-
-	// Lock here to synchronize with possible sync() call contention
-	// when updating header
-	CONTROLLERLOCK();
-	bcopy(_nvramImage, nvramImage, _nvramSize);
-	CONTROLLERUNLOCK();
-
-	NVRAMREADLOCK();
-
-	for (regionIndex = 0; regionIndex < ARRAY_SIZE(variableRegions); regionIndex++) {
-		currentRegion = &variableRegions[regionIndex];
-
-		if (currentRegion->size == 0) {
-			continue;
-		}
-
-		DEBUG_INFO("region = %d\n", currentRegion->type);
-		buffer = tmpBuffer = nvramImage + currentRegion->offset;
-
-		bzero(buffer, currentRegion->size);
-
-		ok = true;
-		maxLength = currentRegion->size;
-
-		iter = OSCollectionIterator::withCollection(currentRegion->dict.get());
-		if (iter == nullptr) {
-			ok = false;
-		}
-
-		while (ok) {
-			tmpSymbol = OSDynamicCast(OSSymbol, iter->getNextObject());
-			if (tmpSymbol == nullptr) {
-				break;
-			}
-
-			DEBUG_INFO("adding variable %s\n", tmpSymbol->getCStringNoCopy());
-
-			tmpObject = currentRegion->dict->getObject(tmpSymbol);
-
-			length = maxLength;
-			ok = convertObjectToProp(tmpBuffer, &length, tmpSymbol, tmpObject);
-			if (ok) {
-				tmpBuffer += length;
-				maxLength -= length;
-			}
-		}
-
-		if (!ok) {
-			ret = kIOReturnNoSpace;
-			IODeleteData(nvramImage, UInt8, _nvramSize);
-			break;
-		}
-
-		if ((currentRegion->type == kIONVRAMPartitionSystem) &&
-		    (_systemService != nullptr)) {
-			_systemService->setVariables(_systemDict.get());
-			systemUsed = (uint32_t)(tmpBuffer - buffer);
-		} else if ((currentRegion->type == kIONVRAMPartitionCommon) &&
-		    (_commonService != nullptr)) {
-			_commonService->setVariables(_commonDict.get());
-			commonUsed = (uint32_t)(tmpBuffer - buffer);
-		}
-	}
-
-	NVRAMUNLOCK();
-
-	DEBUG_INFO("ok=%d\n", ok);
-	require(ok, exit);
-
-	CONTROLLERLOCK();
-
-	if (_systemService && _diags) {
-		sizeUsed = OSNumber::withNumber(systemUsed, 32);
-		_diags->setProperty("SystemUsed", sizeUsed.get());
-		DEBUG_INFO("SystemUsed=%u\n", (unsigned int)systemUsed);
-		sizeUsed.reset();
-	}
-
-	if (_commonService && _diags) {
-		sizeUsed = OSNumber::withNumber(commonUsed, 32);
-		_diags->setProperty("CommonUsed", sizeUsed.get());
-		DEBUG_INFO("CommonUsed=%u\n", (unsigned int)commonUsed);
-		sizeUsed.reset();
-	}
-
-	nvram_set_apple_header(nvramImage, _nvramSize, _nvramGeneration, _nvramVersion);
-
-	ret = _nvramController->write(0, nvramImage, _nvramSize);
-
-	if (_diags) {
-		generation = OSNumber::withNumber(_nvramGeneration, 32);
-		_diags->setProperty(kCurrentGenerationCountKey, generation.get());
-	}
-
-	if (_nvramImage) {
-		IODeleteData(_nvramImage, UInt8, _nvramSize);
-	}
-
-	_nvramImage = nvramImage;
-
-	CONTROLLERUNLOCK();
-
-exit:
-	return ret;
-}
-
-bool
-IODTNVRAM::convertPropToObject(const UInt8 *propName, UInt32 propNameLength,
-    const UInt8 *propData, UInt32 propDataLength,
-    const OSSymbol **propSymbol,
-    OSObject **propObject)
-{
-	OSSharedPtr<const OSString> delimitedName;
-	OSSharedPtr<const OSSymbol> tmpSymbol;
-	OSSharedPtr<OSNumber>       tmpNumber;
-	OSSharedPtr<OSString>       tmpString;
-	OSSharedPtr<OSObject>       tmpObject = nullptr;
-
-	delimitedName = OSString::withCString((const char *)propName, propNameLength);
-	tmpSymbol = OSSymbol::withString(delimitedName.get());
-
-	if (tmpSymbol == nullptr) {
-		return false;
-	}
-
-	switch (getVariableType(tmpSymbol.get())) {
-	case kOFVariableTypeBoolean:
-		if (!strncmp("true", (const char *)propData, propDataLength)) {
-			tmpObject.reset(kOSBooleanTrue, OSRetain);
-		} else if (!strncmp("false", (const char *)propData, propDataLength)) {
-			tmpObject.reset(kOSBooleanFalse, OSRetain);
-		}
-		break;
-
-	case kOFVariableTypeNumber:
-		tmpNumber = OSNumber::withNumber(strtol((const char *)propData, nullptr, 0), 32);
-		if (tmpNumber != nullptr) {
-			tmpObject = tmpNumber;
-		}
-		break;
-
-	case kOFVariableTypeString:
-		tmpString = OSString::withCString((const char *)propData, propDataLength);
-		if (tmpString != nullptr) {
-			tmpObject = tmpString;
-		}
-		break;
-
-	case kOFVariableTypeData:
-		tmpObject = unescapeBytesToData(propData, propDataLength);
-		break;
-
-	default:
-		break;
-	}
-
-	if (tmpObject == nullptr) {
-		tmpSymbol.reset();
-		return false;
-	}
-
-	*propSymbol = tmpSymbol.detach();
-	*propObject = tmpObject.detach();
-
-	return true;
-}
-
-bool
-IODTNVRAM::convertPropToObject(const UInt8 *propName, UInt32 propNameLength,
-    const UInt8 *propData, UInt32 propDataLength,
-    OSSharedPtr<const OSSymbol>& propSymbol,
-    OSSharedPtr<OSObject>& propObject)
-{
-	const OSSymbol* propSymbolRaw = nullptr;
-	OSObject* propObjectRaw = nullptr;
-	bool ok = convertPropToObject(propName, propNameLength, propData, propDataLength,
-	    &propSymbolRaw, &propObjectRaw);
-	propSymbol.reset(propSymbolRaw, OSNoRetain);
-	propObject.reset(propObjectRaw, OSNoRetain);
-	return ok;
-}
-
-bool
-IODTNVRAM::convertObjectToProp(UInt8 *buffer, UInt32 *length,
-    const OSSymbol *propSymbol, OSObject *propObject)
-{
-	return convertObjectToProp(buffer, length, propSymbol->getCStringNoCopy(), propObject);
-}
-
-bool
-IODTNVRAM::convertObjectToProp(UInt8 *buffer, UInt32 *length,
-    const char *propName, OSObject *propObject)
-{
-	UInt32               propNameLength, propDataLength, remaining, offset;
-	IONVRAMVariableType  propType;
-	OSBoolean            *tmpBoolean = nullptr;
-	OSNumber             *tmpNumber = nullptr;
-	OSString             *tmpString = nullptr;
-	OSSharedPtr<OSData>  tmpData;
-
-	propNameLength = (UInt32)strlen(propName);
-	propType = getVariableType(propName);
-	offset = 0;
-	remaining = 0;
-
-	// Get the size of the data.
-	propDataLength = 0xFFFFFFFF;
-	switch (propType) {
-	case kOFVariableTypeBoolean:
-		tmpBoolean = OSDynamicCast(OSBoolean, propObject);
-		if (tmpBoolean != nullptr) {
-			propDataLength = 5;
-		}
-		break;
-
-	case kOFVariableTypeNumber:
-		tmpNumber = OSDynamicCast(OSNumber, propObject);
-		if (tmpNumber != nullptr) {
-			propDataLength = 10;
-		}
-		break;
-
-	case kOFVariableTypeString:
-		tmpString = OSDynamicCast(OSString, propObject);
-		if (tmpString != nullptr) {
-			propDataLength = tmpString->getLength();
-		}
-		break;
-
-	case kOFVariableTypeData:
-		tmpData.reset(OSDynamicCast(OSData, propObject), OSNoRetain);
-		if (tmpData != nullptr) {
-			tmpData = escapeDataToData(tmpData.detach());
-			// escapeDataToData() adds the NULL byte to the data
-			// subtract 1 here to keep offset consistent with the other cases
-			propDataLength = tmpData->getLength() - 1;
-		}
-		break;
-
-	default:
-		break;
-	}
-
-	// Make sure the propertySize is known and will fit.
-	if (propDataLength == 0xFFFFFFFF) {
-		return false;
-	}
-
-	if (buffer) {
-		// name + '=' + data + '\0'
-		if ((propNameLength + propDataLength + 2) > *length) {
-			return false;
-		}
-
-		remaining = *length;
-	}
-
-	*length = 0;
-
-	// Copy the property name equal sign.
-	offset += snprintf((char *)buffer, remaining, "%s=", propName);
-	if (buffer) {
-		if (remaining > offset) {
-			buffer += offset;
-			remaining = remaining - offset;
-		} else {
-			return false;
-		}
-	}
-
-	switch (propType) {
-	case kOFVariableTypeBoolean:
-		if (tmpBoolean->getValue()) {
-			offset += strlcpy((char *)buffer, "true", remaining);
-		} else {
-			offset += strlcpy((char *)buffer, "false", remaining);
-		}
-		break;
-
-	case kOFVariableTypeNumber:
-	{
-		uint32_t tmpValue = tmpNumber->unsigned32BitValue();
-		if (tmpValue == 0xFFFFFFFF) {
-			offset += strlcpy((char *)buffer, "-1", remaining);
-		} else if (tmpValue < 1000) {
-			offset += snprintf((char *)buffer, remaining, "%d", (uint32_t)tmpValue);
-		} else {
-			offset += snprintf((char *)buffer, remaining, "%#x", (uint32_t)tmpValue);
-		}
+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;
-
-	case kOFVariableTypeString:
-		offset += strlcpy((char *)buffer, tmpString->getCStringNoCopy(), remaining);
-		break;
-
-	case kOFVariableTypeData:
-		if (buffer) {
-			bcopy(tmpData->getBytesNoCopy(), buffer, propDataLength);
-		}
-		tmpData.reset();
-		offset += propDataLength;
-		break;
-
-	default:
-		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;
 	}
-
-	*length = offset + 1;
-
-	return true;
-}
-
-OSSharedPtr<OSData>
-IODTNVRAM::unescapeBytesToData(const UInt8 *bytes, UInt32 length)
-{
-	OSSharedPtr<OSData> data;
-	UInt32              totalLength = 0;
-	UInt32              offset, offset2;
-	UInt8               byte;
-	bool                ok;
-
-	// Calculate the actual length of the data.
-	ok = true;
-	totalLength = 0;
-	for (offset = 0; offset < length;) {
-		byte = bytes[offset++];
-		if (byte == 0xFF) {
-			byte = bytes[offset++];
-			if (byte == 0x00) {
-				ok = false;
-				break;
-			}
-			offset2 = byte & 0x7F;
-		} else {
-			offset2 = 1;
-		}
-		totalLength += offset2;
-	}
-
-	if (ok) {
-		// Create an empty OSData of the correct size.
-		data = OSData::withCapacity(totalLength);
-		if (data != nullptr) {
-			for (offset = 0; offset < length;) {
-				byte = bytes[offset++];
-				if (byte == 0xFF) {
-					byte = bytes[offset++];
-					offset2 = byte & 0x7F;
-					byte = (byte & 0x80) ? 0xFF : 0x00;
-				} else {
-					offset2 = 1;
-				}
-				data->appendByte(byte, offset2);
-			}
-		}
-	}
-
-	return data;
-}
-
-OSSharedPtr<OSData>
-IODTNVRAM::escapeDataToData(OSData * value)
-{
-	OSSharedPtr<OSData> result;
-	const UInt8         *startPtr;
-	const UInt8         *endPtr;
-	const UInt8         *wherePtr;
-	UInt8               byte;
-	bool                ok = true;
-
-	wherePtr = (const UInt8 *) value->getBytesNoCopy();
-	endPtr = wherePtr + value->getLength();
-
-	result = OSData::withCapacity((unsigned int) (endPtr - wherePtr));
-	if (!result) {
-		return result;
-	}
-
-	while (wherePtr < endPtr) {
-		startPtr = wherePtr;
-		byte = *wherePtr++;
-		if ((byte == 0x00) || (byte == 0xFF)) {
-			for (;
-			    ((wherePtr - startPtr) < 0x7F) && (wherePtr < endPtr) && (byte == *wherePtr);
-			    wherePtr++) {
-			}
-			ok &= result->appendByte(0xff, 1);
-			byte = (byte & 0x80) | ((UInt8)(wherePtr - startPtr));
-		}
-		ok &= result->appendByte(byte, 1);
-	}
-	ok &= result->appendByte(0, 1);
-
-	if (!ok) {
-		result.reset();
-	}
-
-	return result;
-}
-
-static bool
-IsApplePropertyName(const char * propName)
-{
-	char c;
-	while ((c = *propName++)) {
-		if ((c >= 'A') && (c <= 'Z')) {
-			break;
-		}
-	}
-
-	return c == 0;
-}
-
-IOReturn
-IODTNVRAM::readNVRAMPropertyType1(IORegistryEntry *entry,
-    const OSSymbol **name,
-    OSData **value)
-{
-	IOReturn    err = kIOReturnNoResources;
-	OSData      *data;
-	const UInt8 *startPtr;
-	const UInt8 *endPtr;
-	const UInt8 *wherePtr;
-	const UInt8 *nvPath = nullptr;
-	const char  *nvName = nullptr;
-	const char  *resultName = nullptr;
-	const UInt8 *resultValue = nullptr;
-	UInt32       resultValueLen = 0;
-	UInt8       byte;
-
-	NVRAMREADLOCK();
-	data = OSDynamicCast(OSData, _commonDict->getObject(_registryPropertiesKey.get()));
-	NVRAMUNLOCK();
-
-	if (data == nullptr) {
-		return err;
-	}
-
-	startPtr = (const UInt8 *) data->getBytesNoCopy();
-	endPtr = startPtr + data->getLength();
-
-	wherePtr = startPtr;
-	while (wherePtr < endPtr) {
-		byte = *(wherePtr++);
-		if (byte) {
-			continue;
-		}
-
-		if (nvPath == nullptr) {
-			nvPath = startPtr;
-		} else if (nvName == nullptr) {
-			nvName = (const char *) startPtr;
-		} else {
-			OSSharedPtr<IORegistryEntry> compareEntry = IORegistryEntry::fromPath((const char *) nvPath, gIODTPlane);
-			if (entry == compareEntry) {
-				bool appleProp = IsApplePropertyName(nvName);
-				if (!appleProp || !resultName) {
-					resultName     = nvName;
-					resultValue    = startPtr;
-					resultValueLen = (UInt32) (wherePtr - startPtr - 1);  // OSData getLength() is 32b
-				}
-				if (!appleProp) {
-					break;
-				}
-			}
-			nvPath = nullptr;
-			nvName = nullptr;
-		}
-		startPtr = wherePtr;
-	}
-	if (resultName) {
-		*name = OSSymbol::withCString(resultName).detach();
-		*value = unescapeBytesToData(resultValue, resultValueLen).detach();
-		if ((*name != nullptr) && (*value != nullptr)) {
-			err = kIOReturnSuccess;
-		} else {
-			err = kIOReturnNoMemory;
-		}
-	}
-	return err;
-}
-
-IOReturn
-IODTNVRAM::writeNVRAMPropertyType1(IORegistryEntry *entry,
-    const OSSymbol *propName,
-    OSData *value)
-{
-	OSSharedPtr<OSData> data, oldData;
-	const UInt8         *startPtr;
-	const UInt8         *propStart;
-	const UInt8         *endPtr;
-	const UInt8         *wherePtr;
-	const UInt8         *nvPath = nullptr;
-	const char          *nvName = nullptr;
-	const char          *comp;
-	const char          *name;
-	UInt8               byte;
-	bool                ok = true;
-	bool                settingAppleProp;
-
-	settingAppleProp = IsApplePropertyName(propName->getCStringNoCopy());
-
-	// copy over existing properties for other entries
-
-	NVRAMWRITELOCK();
-
-	oldData.reset(OSDynamicCast(OSData, _commonDict->getObject(_registryPropertiesKey.get())), OSRetain);
-	if (oldData) {
-		startPtr = (const UInt8 *) oldData->getBytesNoCopy();
-		endPtr = startPtr + oldData->getLength();
-
-		propStart = startPtr;
-		wherePtr = startPtr;
-		while (wherePtr < endPtr) {
-			byte = *(wherePtr++);
-			if (byte) {
-				continue;
-			}
-			if (nvPath == nullptr) {
-				nvPath = startPtr;
-			} else if (nvName == nullptr) {
-				nvName = (const char *) startPtr;
-			} else {
-				OSSharedPtr<IORegistryEntry> compareEntry = IORegistryEntry::fromPath((const char *) nvPath, gIODTPlane);
-
-				if (entry == compareEntry) {
-					if ((settingAppleProp && propName->isEqualTo(nvName))
-					    || (!settingAppleProp && !IsApplePropertyName(nvName))) {
-						// delete old property (nvPath -> wherePtr) source OSData len is 32b
-						data = OSData::withBytes(propStart, (UInt32)(nvPath - propStart));
-						if (data) {
-							ok &= data->appendBytes(wherePtr, (UInt32)(endPtr - wherePtr));
-						}
-						break;
-					}
-				}
-				nvPath = nullptr;
-				nvName = nullptr;
-			}
-
-			startPtr = wherePtr;
-		}
-	}
-
-	// make the new property
-
-	if (!data) {
-		if (oldData) {
-			data = OSData::withData(oldData.get());
-		} else {
-			data = OSData::withCapacity(16);
-		}
-		if (!data) {
-			ok = false;
-		}
-	}
-
-	if (ok && value && value->getLength()) {
-		do {
-			// get entries in path
-			OSSharedPtr<OSArray> array = OSArray::withCapacity(5);
-			if (!array) {
-				ok = false;
-				break;
-			}
-			do{
-				array->setObject(entry);
-			} while ((entry = entry->getParentEntry(gIODTPlane)));
-
-			// append path
-			for (int i = array->getCount() - 3;
-			    (entry = (IORegistryEntry *) array->getObject(i));
-			    i--) {
-				name = entry->getName(gIODTPlane);
-				comp = entry->getLocation(gIODTPlane);
-				if (comp) {
-					ok &= data->appendBytes("/@", 2);
-				} else {
-					if (!name) {
-						continue;
-					}
-					ok &= data->appendByte('/', 1);
-					comp = name;
-				}
-				ok &= data->appendBytes(comp, (unsigned int) strnlen(comp, UINT16_MAX));
-			}
-			ok &= data->appendByte(0, 1);
-			// append prop name
-			ok &= data->appendBytes(propName->getCStringNoCopy(), propName->getLength() + 1);
-
-			// append escaped data
-			OSSharedPtr<OSData> escapedData = escapeDataToData(value);
-			ok &= (escapedData != nullptr);
-			if (ok) {
-				ok &= data->appendBytes(escapedData.get());
-			}
-		} while (false);
-	}
-
-	if (ok) {
-		ok = _commonDict->setObject(_registryPropertiesKey.get(), data.get());
-	}
-
-	NVRAMUNLOCK();
-
-	if (ok) {
-		if (serializeVariables() != kIOReturnSuccess) {
-			NVRAMWRITELOCK();
-			if (oldData) {
-				_commonDict->setObject(_registryPropertiesKey.get(), oldData.get());
-			} else {
-				_commonDict->removeObject(_registryPropertiesKey.get());
-			}
-			NVRAMUNLOCK();
-
-			(void) serializeVariables();
-			ok = false;
-		}
-	}
-
-	oldData.reset();
-
-	return ok ? kIOReturnSuccess : kIOReturnNoSpace;
-}
-
-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;
-}
+	
+	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;
+};
+typedef struct OFVariable OFVariable;
+
+enum {
+  kOWVariableOffsetNumber = 8,
+  kOWVariableOffsetString = 17
+};
+
+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}
+};
+
+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
+};
+
+#pragma options align=mac68k
+struct NVRAMProperty
+{
+  IONVRAMDescriptor   header;
+  UInt8               nameLength;
+  UInt8               name[ kMaxNVNameLength ];
+  UInt8               dataLength;
+  UInt8               data[ kMaxNVDataLength ];
+};
+#pragma options align=reset
+
+bool IODTNVRAM::searchNVRAMProperty(IONVRAMDescriptor *hdr, UInt32 *where)
+{
+  UInt32 offset;
+  SInt32 nvEnd;
+  
+  nvEnd = *((UInt16 *)_nrImage);
+  if(getPlatform()->getBootROMType()) {
+    // on NewWorld, offset to partition start
+    nvEnd -= 0x100;
+  } else {
+    // on old world, absolute
+    nvEnd -= _nrPartitionOffset;
+  }
+  if((nvEnd < 0) || (nvEnd >= kIODTNVRAMNameRegistrySize))
+    nvEnd = 2;
+  
+  offset = 2;
+  while ((offset + sizeof(NVRAMProperty)) <= (UInt32)nvEnd) {
+    if (bcmp(_nrImage + offset, hdr, sizeof(*hdr)) == 0) {
+      *where = offset;
+      return true;
+    }
+    offset += sizeof(NVRAMProperty);
+  }
+  
+  if ((nvEnd + sizeof(NVRAMProperty)) <= kIODTNVRAMNameRegistrySize)
+    *where = nvEnd;
+  else
+    *where = 0;
+  
+  return false;
+}
+
+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;
+}