]> git.saurik.com Git - apple/xnu.git/blobdiff - iokit/Kernel/IONVRAM.cpp
xnu-7195.81.3.tar.gz
[apple/xnu.git] / iokit / Kernel / IONVRAM.cpp
index 88d58595fcfb6ae30ab58234fa3779864c199309..69725d4036657eaf7c4a6ca8da913764f24fd422 100644 (file)
  * @APPLE_OSREFERENCE_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 <pexpert/boot.h>
 #include <pexpert/pexpert.h>
 
 #define super IOService
 
+#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
+
+// Internal values
+#define NVRAM_CHRP_SIG_APPLE             0x5A
+#define NVRAM_CHRP_APPLE_HEADER_NAME     "nvram"
+
+// From Apple CHRP Spec
+#define NVRAM_CHRP_SIG_SYSTEM    0x70
+#define NVRAM_CHRP_SIG_CONFIG    0x71
+#define NVRAM_CHRP_SIG_FREESPACE 0x7F
+
+#define NVRAM_CHRP_PARTITION_NAME_COMMON        "common"
+#define NVRAM_CHRP_PARTITION_NAME_SYSTEM        "system"
+#define NVRAM_CHRP_PARTITION_NAME_SYSTEM_LEGACY "secure"
+#define NVRAM_CHRP_PARTITION_NAME_FREESPACE     "\x77\x77\x77\x77\x77\x77\x77\x77\x77\x77\x77\x77"
+
+#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 kIONVRAMPrivilege    kIOClientPrivilegeLocalUser
 
 OSDefineMetaClassAndStructors(IODTNVRAM, IOService);
 
+#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...)
+#define DEBUG_ALWAYS(fmt, args...)
+#endif
+
+#define DEBUG_ERROR DEBUG_ALWAYS
+
+#define CONTROLLERLOCK()                             \
+({                                                   \
+       if (preemption_enabled() && !panic_active()) \
+               IOLockLock(_controllerLock);         \
+})
+
+#define CONTROLLERUNLOCK()                           \
+({                                                   \
+       if (preemption_enabled() && !panic_active()) \
+               IOLockUnlock(_controllerLock);       \
+})
+
+#define NVRAMLOCK()                              \
+({                                               \
+       if (preemption_enabled() && !panic_active()) \
+               IOLockLock(_variableLock);           \
+})
+
+#define NVRAMUNLOCK()                            \
+({                                               \
+       if (preemption_enabled() && !panic_active()) \
+               IOLockUnlock(_variableLock);         \
+})
+
+#define NVRAMLOCKASSERT()                                    \
+({                                                           \
+       if (preemption_enabled() && !panic_active())             \
+               IOLockAssert(_variableLock, kIOLockAssertOwned); \
+})
+
+typedef struct {
+       const char                *name;
+       UInt32                    offset;
+       UInt32                    size;
+       OSSharedPtr<OSDictionary> &dict;
+       UInt8                     *image;
+} 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 bool gNVRAMLogging = false;
+
+// allowlist variables from macboot that need to be set/get from system region if present
+static const char * const gNVRAMSystemList[] = {
+       "adbe-tunable",
+       "adbe-tunables",
+       "adfe-tunables",
+       "alamo-path",
+       "alt-boot-volume",
+       "ASMB",
+       "atc0",
+       "atc1",
+       "auto-boot",
+       "auto-boot-halt-stage",
+       "auto-boot-once",
+       "auto-boot-usb",
+       "auxkc-path",
+       "backlight-level",
+       "backlight-nits",
+       "base-system-path",
+       "boot-args",
+       "boot-breadcrumbs",
+       "boot-command",
+       "boot-device",
+       "boot-image",
+       "boot-partition",
+       "boot-path",
+       "boot-ramdisk",
+       "boot-script",
+       "boot-volume",
+       "bootdelay",
+       "bt1addr",
+       "btaddr",
+       "cam-use-ext-ldo",
+       "CLCG_override",
+       "com.apple.System.boot-nonce",
+       "com.apple.System.rtc-offset",
+       "com.apple.System.tz0-size",
+       "core-bin-offset",
+       "cpu-bin-offset",
+       "darkboot",
+       "DClr_override",
+       "dcp-auto-boot",
+       "debug-gg",
+       "debug-soc",
+       "debug-uarts",
+       "diags-path",
+       "disable-boot-wdt",
+       "display-color-space",
+       "display-timing",
+       "display-vsh-comp",
+       "dpcd-max-brightness",
+       "dtdump",
+       "dtdump-path",
+       "e75",
+       "emu",
+       "enable-auth-debug",
+       "enable-jop",
+       "enable-marconi",
+       "enable-upgrade-fallback",
+       "enforce-iuob",
+       "eth1addr",
+       "ethaddr",
+       "failboot-breadcrumbs",
+       "fixed-lcm-boost",
+       "force-ctrr-lock",
+       "force-upgrade-fail",
+       "fuos-path",
+       "hib-ui-force",
+       "hibhack-test-hmac",
+       "iboot-data",
+       "iboot-failure-reason",
+       "iboot-failure-reason-str",
+       "iboot-failure-volume",
+       "iboot1-precommitted",
+       "idle-off",
+       "is-tethered",
+       "kaslr-off",
+       "kaslr-slide",
+       "kis-rsm",
+       "knobs",
+       "loadaddr",
+       "memmapdump",
+       "mipi-bridge-cmd-verify",
+       "mipi-bridge-poll-cmd-fifo",
+       "no-ctrr",
+       "one-time-boot-command",
+       "osenvironment",
+       "ota-breadcrumbs",
+       "ota-outcome",
+       "panicmedic",
+       "panicmedic-threshold",
+       "panicmedic-timestamps",
+       "phleet-path",
+       "pinot-panel-id",
+       "pintoaddr",
+       "policy-nonce-digests",
+       "preserve-debuggability",
+       "prevent-restores", // Keep for factory <rdar://problem/70476321>
+       "prev-lang:kbd",
+       "ramrod-kickstart-aces",
+       "rbdaddr0",
+       "rbm-path",
+       "reconfig-behavior",
+       "reconfig-breakpoints",
+       "recovery-boot-mode",
+       "recovery-breadcrumbs",
+       "restored-host-timeout",
+       "root-live-fs",
+       "rtos-path",
+       "soc-bin-offset",
+       "StartupMute",
+       "StartupMuteAccessibility",
+       "storage-prev-assert",
+       "storage-prev-assert-stored",
+       "summit-panel-id",
+       "SystemAudioVolume",
+       "SystemAudioVolumeExtension",
+       "SystemAudioVolumeSaved",
+       "tz0-size-override",
+       "upgrade-fallback-boot-command",
+       "upgrade-retry",
+       "usb-enabled",
+       "wifi1addr",
+       "wifiaddr",
+       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 FullAccess           :1;
+               uint64_t Reserved:58;
+       } 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},
+       {"policy-nonce-digests", .p.Bits.ResetNVRAMOnlyDelete = 1},
+       {"security-password", .p.Bits.RootRequired = 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},
+       {"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;
+}
+
+static bool
+verifyPermission(IONVRAMOperation op, const uuid_t *varGuid, const char *varName)
+{
+       VariablePermission perm;
+       bool kernel, admin, writeEntitled, readEntitled, allowList, systemGuid, systemEntitled;
+
+       perm = getVariablePermission(varName);
+
+       kernel = current_task() == kernel_task;
+
+       if (perm.Bits.KernelOnly) {
+               DEBUG_INFO("KernelOnly access for %s, kernel=%d\n", varName, kernel);
+               return kernel;
+       }
+
+       allowList = variableInAllowList(varName);
+       systemGuid = uuid_compare(*varGuid, gAppleSystemVariableGuid) == 0;
+       admin = IOUserClient::clientHasPrivilege(current_task(), kIONVRAMPrivilege) == kIOReturnSuccess;
+       writeEntitled = IOTaskHasEntitlement(current_task(), kIONVRAMWriteAccessKey);
+       readEntitled = IOTaskHasEntitlement(current_task(), kIONVRAMReadAccessKey);
+       systemEntitled = IOTaskHasEntitlement(current_task(), kIONVRAMSystemAllowKey) || kernel;
+
+       switch (op) {
+       case kIONVRAMOperationRead:
+               if (kernel || admin || readEntitled || perm.Bits.FullAccess) {
+                       return true;
+               }
+               break;
+
+       case kIONVRAMOperationWrite:
+               if (kernel || perm.Bits.UserWrite || admin || writeEntitled) {
+                       if (systemGuid) {
+                               if (allowList) {
+                                       if (!systemEntitled) {
+                                               DEBUG_ERROR("Allowed write to system region when NOT entitled for %s\n", varName);
+                                       }
+                               } else if (!systemEntitled) {
+                                       DEBUG_ERROR("Not entitled for system region writes for %s\n", varName);
+                                       break;
+                               }
+                       }
+                       return 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;
+               }
+
+               if (kernel || perm.Bits.UserWrite || admin || writeEntitled) {
+                       if (systemGuid) {
+                               if (allowList) {
+                                       if (!systemEntitled) {
+                                               DEBUG_ERROR("Allowed delete to system region when NOT entitled for %s\n", varName);
+                                       }
+                               } else if (!systemEntitled) {
+                                       DEBUG_ERROR("Not entitled for system region deletes for %s\n", varName);
+                                       break;
+                               }
+                       }
+                       return true;
+               }
+               break;
+       }
+
+       DEBUG_INFO("Permission for %s denied, kernel=%d, admin=%d, writeEntitled=%d, readEntitled=%d, systemGuid=%d, systemEntitled=%d\n",
+           varName, kernel, admin, writeEntitled, readEntitled, systemGuid, systemEntitled);
+       return false;
+}
+
+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          result  = 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);
+                       result = true;
+               }
+       }
+
+       if (guidResult) {
+               result ? uuid_copy(*guidResult, guid) : uuid_copy(*guidResult, gAppleNVRAMGuid);
+       }
+       if (nameResult) {
+               *nameResult = name;
+       }
+
+       return false;
+}
+
+// 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     *_properties;
+       uuid_t           _guid;
+
+public:
+       bool             init(const uuid_t *guid);
+       virtual bool     start(IOService * provider) APPLE_KEXT_OVERRIDE;
+       virtual IOReturn setProperties(OSObject * properties) APPLE_KEXT_OVERRIDE;
+       virtual bool     serializeProperties(OSSerialize *s) const APPLE_KEXT_OVERRIDE;
+};
+
+OSDefineMetaClassAndStructors(IODTNVRAMVariables, IOService)
+
+bool
+IODTNVRAMVariables::init(const uuid_t *guid)
+{
+       require(super::init(), error);
+       require(guid, error);
+
+       uuid_copy(_guid, *guid);
+
+       return true;
+
+error:
+       return false;
+}
+
+bool
+IODTNVRAMVariables::start(IOService * provider)
+{
+       require(IOService::start(provider), error);
+
+       require(_provider = OSDynamicCast(IODTNVRAM, provider), error);
+
+       registerService();
+
+       return true;
+
+error:
+       stop(provider);
+
+       return false;
+}
+
+IOReturn
+IODTNVRAMVariables::setProperties(OSObject * properties)
+{
+       if (OSDynamicCast(OSDictionary, properties)) {
+               OSSafeReleaseNULL(_properties);
+               _properties = OSDynamicCast(OSDictionary, properties);
+               properties->retain();
+       }
+
+       return IOService::setProperties(properties);
+}
+
+bool
+IODTNVRAMVariables::serializeProperties(OSSerialize *s) const
+{
+       const OSSymbol                    *key;
+       OSSharedPtr<OSDictionary>         dict;
+       OSSharedPtr<OSCollectionIterator> iter;
+       OSSharedPtr<OSDictionary>         localProperties(_properties, OSRetain);
+       bool                              result = false;
+
+       require(localProperties != nullptr, exit);
+
+       dict = OSDictionary::withCapacity(localProperties->getCount());
+       require_action(dict, exit, DEBUG_ERROR("No dictionary\n"));
+
+       iter = OSCollectionIterator::withCollection(localProperties.get());
+       require_action(iter, exit, DEBUG_ERROR("failed to create iterator\n"));
+
+       while ((key = OSDynamicCast(OSSymbol, iter->getNextObject()))) {
+               if (verifyPermission(kIONVRAMOperationRead, &_guid, key)) {
+                       dict->setObject(key, localProperties->getObject(key));
+               }
+       }
+
+       result = dict->serialize(s);
+
+exit:
+       DEBUG_INFO("result=%d\n", result);
+       return result;
+}
+
 bool
 IODTNVRAM::init(IORegistryEntry *old, const IORegistryPlane *plane)
 {
-       OSDictionary *dict;
+       OSSharedPtr<OSDictionary> dict;
 
        if (!super::init(old, plane)) {
                return false;
        }
 
+       _variableLock = IOLockAlloc();
+       if (!_variableLock) {
+               return false;
+       }
+
+       _controllerLock = IOLockAlloc();
+       if (!_controllerLock) {
+               return false;
+       }
+
+       PE_parse_boot_argn("nvram-log", &gNVRAMLogging, sizeof(gNVRAMLogging));
+
        dict =  OSDictionary::withCapacity(1);
-       if (dict == 0) {
+       if (dict == nullptr) {
                return false;
        }
-       setPropertyTable(dict);
+       setPropertyTable(dict.get());
+       dict.reset();
 
-       _nvramImage = IONew(UInt8, kIODTNVRAMImageSize);
-       if (_nvramImage == 0) {
+       _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 = IONew(UInt8, _nvramSize);
+       if (_nvramImage == nullptr) {
                return false;
        }
 
        _nvramPartitionOffsets = OSDictionary::withCapacity(1);
-       if (_nvramPartitionOffsets == 0) {
+       if (_nvramPartitionOffsets == nullptr) {
                return false;
        }
 
        _nvramPartitionLengths = OSDictionary::withCapacity(1);
-       if (_nvramPartitionLengths == 0) {
+       if (_nvramPartitionLengths == nullptr) {
                return false;
        }
 
        _registryPropertiesKey = OSSymbol::withCStringNoCopy("aapl,pci");
-       if (_registryPropertiesKey == 0) {
+       if (_registryPropertiesKey == nullptr) {
                return false;
        }
 
@@ -82,26 +720,30 @@ IODTNVRAM::init(IORegistryEntry *old, const IORegistryPlane *plane)
        // IODTNVRAM and IONVRAMController (restore loses boot-args)
        initProxyData();
 
+       // Require at least the common partition to be present and error free
+       if (_commonDict == nullptr) {
+               return false;
+       }
+
        return true;
 }
 
 void
 IODTNVRAM::initProxyData(void)
 {
-       IORegistryEntry *entry;
-       const char *key = "nvram-proxy-data";
-       OSObject *prop;
-       OSData *data;
-       const void *bytes;
+       OSSharedPtr<IORegistryEntry> entry;
+       const char                   *key = "nvram-proxy-data";
+       OSData                       *data;
+       const void                   *bytes;
 
        entry = IORegistryEntry::fromPath("/chosen", gIODTPlane);
-       if (entry != 0) {
-               prop = entry->getProperty(key);
-               if (prop != 0) {
-                       data = OSDynamicCast(OSData, prop);
-                       if (data != 0) {
+       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 != 0) && (data->getLength() <= kIODTNVRAMImageSize)) {
+                               if ((bytes != nullptr) && (data->getLength() <= _nvramSize)) {
                                        bcopy(bytes, _nvramImage, data->getLength());
                                        initNVRAMImage();
                                        _isProxied = true;
@@ -109,29 +751,106 @@ IODTNVRAM::initProxyData(void)
                        }
                }
                entry->removeProperty(key);
-               entry->release();
        }
 }
 
+UInt32
+IODTNVRAM::getNVRAMSize(void)
+{
+       OSSharedPtr<IORegistryEntry> entry;
+       const char                   *key = "nvram-total-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)
 {
-       if (_nvramController != 0) {
+       IOReturn ret;
+
+       if (_nvramController != nullptr) {
+               DEBUG_ERROR("Duplicate controller set\n");
                return;
        }
 
+       DEBUG_INFO("setting controller\n");
+
        _nvramController = nvram;
 
        // <rdar://problem/9529235> race condition possible between
        // IODTNVRAM and IONVRAMController (restore loses boot-args)
        if (!_isProxied) {
-               _nvramController->read(0, _nvramImage, kIODTNVRAMImageSize);
+               DEBUG_INFO("Proxied NVRAM data\n");
+               _nvramController->read(0, _nvramImage, _nvramSize);
                initNVRAMImage();
-       } else {
-               IOLockLock(_ofLock);
-               (void) syncVariables();
-               IOLockUnlock(_ofLock);
        }
+
+       if (_systemPartitionSize) {
+               _systemService = new IODTNVRAMVariables;
+
+               if (!_systemService || !_systemService->init(&gAppleSystemVariableGuid)) {
+                       DEBUG_ERROR("Unable to start the system service!\n");
+                       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");
+                       goto no_common;
+               }
+
+               _commonService->setName("options-common");
+
+               if (!_commonService->attach(this)) {
+                       DEBUG_ERROR("Unable to attach the common service!\n");
+                       OSSafeReleaseNULL(_commonService);
+                       goto no_common;
+               }
+
+               if (!_commonService->start(this)) {
+                       DEBUG_ERROR("Unable to start the common service!\n");
+                       _commonService->detach(this);
+                       OSSafeReleaseNULL(_commonService);
+                       goto no_common;
+               }
+       }
+
+no_common:
+       ret = serializeVariables();
+       DEBUG_INFO("serializeVariables ret=0x%08x\n", ret);
 }
 
 void
@@ -139,135 +858,83 @@ IODTNVRAM::initNVRAMImage(void)
 {
        char   partitionID[18];
        UInt32 partitionOffset, partitionLength;
-       UInt32 freePartitionOffset, freePartitionSize;
        UInt32 currentLength, currentOffset = 0;
-       OSNumber *partitionOffsetNumber, *partitionLengthNumber;
 
-       // Find the offsets for the OF, XPRAM, NameRegistry and PanicInfo partitions.
-       _ofPartitionOffset = 0xFFFFFFFF;
-       _piPartitionOffset = 0xFFFFFFFF;
-       freePartitionOffset = 0xFFFFFFFF;
-       freePartitionSize = 0;
+       _commonPartitionOffset = 0xFFFFFFFF;
+       _systemPartitionOffset = 0xFFFFFFFF;
+
+       // Look through the partitions to find the OF and System partitions.
+       while (currentOffset < _nvramSize) {
+               bool common_partition;
+               bool system_partition;
+
+               chrp_nvram_header_t * header = (chrp_nvram_header_t *)(_nvramImage + currentOffset);
 
-       // Look through the partitions to find the OF, MacOS partitions.
-       while (currentOffset < kIODTNVRAMImageSize) {
-               currentLength = ((UInt16 *)(_nvramImage + currentOffset))[1] * 16;
+               currentLength = header->len * NVRAM_CHRP_LENGTH_BLOCK_SIZE;
 
-               if (currentLength < 16) {
+               if (currentLength < sizeof(chrp_nvram_header_t)) {
                        break;
                }
-               partitionOffset = currentOffset + 16;
-               partitionLength = currentLength - 16;
-               if ((partitionOffset + partitionLength) > kIODTNVRAMImageSize) {
+
+               partitionOffset = currentOffset + sizeof(chrp_nvram_header_t);
+               partitionLength = currentLength - sizeof(chrp_nvram_header_t);
+
+               if ((partitionOffset + partitionLength) > _nvramSize) {
                        break;
                }
 
-               if (strncmp((const char *)_nvramImage + currentOffset + 4,
-                   kIODTNVRAMOFPartitionName, 12) == 0) {
-                       _ofPartitionOffset = partitionOffset;
-                       _ofPartitionSize = partitionLength;
-               } else if (strncmp((const char *)_nvramImage + currentOffset + 4,
-                   kIODTNVRAMXPRAMPartitionName, 12) == 0) {
-               } else if (strncmp((const char *)_nvramImage + currentOffset + 4,
-                   kIODTNVRAMPanicInfoPartitonName, 12) == 0) {
-                       _piPartitionOffset = partitionOffset;
-                       _piPartitionSize = partitionLength;
-               } else if (strncmp((const char *)_nvramImage + currentOffset + 4,
-                   kIODTNVRAMFreePartitionName, 12) == 0) {
-                       freePartitionOffset = currentOffset;
-                       freePartitionSize = currentLength;
+               common_partition = memcmp(header->name, NVRAM_CHRP_PARTITION_NAME_COMMON, strlen(NVRAM_CHRP_PARTITION_NAME_COMMON)) == 0;
+               system_partition = (memcmp(header->name, NVRAM_CHRP_PARTITION_NAME_SYSTEM, strlen(NVRAM_CHRP_PARTITION_NAME_SYSTEM)) == 0) ||
+                   (memcmp(header->name, NVRAM_CHRP_PARTITION_NAME_SYSTEM_LEGACY, strlen(NVRAM_CHRP_PARTITION_NAME_SYSTEM_LEGACY)) == 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), "0x%02x,",
-                           *(UInt8 *)(_nvramImage + currentOffset));
-                       strncpy(partitionID + 5,
-                           (const char *)(_nvramImage + currentOffset + 4), 12);
+                       snprintf(partitionID, sizeof(partitionID), "0x%02x,", header->sig);
+                       strncpy(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);
-                       _nvramPartitionLengths->setObject(partitionID, partitionLengthNumber);
-
-                       partitionOffsetNumber->release();
-                       partitionLengthNumber->release();
+                       _nvramPartitionOffsets->setObject(partitionID, partitionOffsetNumber.get());
+                       _nvramPartitionLengths->setObject(partitionID, partitionLengthNumber.get());
                }
                currentOffset += currentLength;
        }
 
-       if (_ofPartitionOffset != 0xFFFFFFFF) {
-               _ofImage    = _nvramImage + _ofPartitionOffset;
+       if (_commonPartitionOffset != 0xFFFFFFFF) {
+               _commonImage = _nvramImage + _commonPartitionOffset;
        }
 
-       if (_piPartitionOffset == 0xFFFFFFFF) {
-               if (freePartitionSize > 0x20) {
-                       // Set the signature to 0xa1.
-                       _nvramImage[freePartitionOffset] = 0xa1;
-                       // Set the checksum to 0.
-                       _nvramImage[freePartitionOffset + 1] = 0;
-                       // Set the name for the Panic Info partition.
-                       strncpy((char *)(_nvramImage + freePartitionOffset + 4),
-                           kIODTNVRAMPanicInfoPartitonName, 12);
-
-                       // Calculate the partition offset and size.
-                       _piPartitionOffset = freePartitionOffset + 0x10;
-                       _piPartitionSize = 0x800;
-                       if (_piPartitionSize + 0x20 > freePartitionSize) {
-                               _piPartitionSize = freePartitionSize - 0x20;
-                       }
-
-                       _piImage = _nvramImage + _piPartitionOffset;
-
-                       // Zero the new partition.
-                       bzero(_piImage, _piPartitionSize);
-
-                       // Set the partition size.
-                       *(UInt16 *)(_nvramImage + freePartitionOffset + 2) =
-                           (_piPartitionSize / 0x10) + 1;
-
-                       // Set the partition checksum.
-                       _nvramImage[freePartitionOffset + 1] =
-                           calculatePartitionChecksum(_nvramImage + freePartitionOffset);
-
-                       // Calculate the free partition offset and size.
-                       freePartitionOffset += _piPartitionSize + 0x10;
-                       freePartitionSize -= _piPartitionSize + 0x10;
-
-                       // Set the signature to 0x7f.
-                       _nvramImage[freePartitionOffset] = 0x7f;
-                       // Set the checksum to 0.
-                       _nvramImage[freePartitionOffset + 1] = 0;
-                       // Set the name for the free partition.
-                       strncpy((char *)(_nvramImage + freePartitionOffset + 4),
-                           kIODTNVRAMFreePartitionName, 12);
-                       // Set the partition size.
-                       *(UInt16 *)(_nvramImage + freePartitionOffset + 2) =
-                           freePartitionSize / 0x10;
-                       // Set the partition checksum.
-                       _nvramImage[freePartitionOffset + 1] =
-                           calculatePartitionChecksum(_nvramImage + freePartitionOffset);
-
-                       if (_nvramController != 0) {
-                               _nvramController->write(0, _nvramImage, kIODTNVRAMImageSize);
-                       }
-               }
-       } else {
-               _piImage = _nvramImage + _piPartitionOffset;
+       if (_systemPartitionOffset != 0xFFFFFFFF) {
+               _systemImage = _nvramImage + _systemPartitionOffset;
        }
 
+       DEBUG_ALWAYS("NVRAM : ofPartitionOffset - 0x%x, ofPartitionSize - 0x%x, systemPartitionOffset - 0x%x, systemPartitionSize - 0x%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.
 
-       initOFVariables();
+       initVariables();
 }
 
 void
 IODTNVRAM::syncInternal(bool rateLimit)
 {
+       DEBUG_INFO("rateLimit=%d\n", rateLimit);
+
        // Don't try to perform controller operations if none has been registered.
-       if (_nvramController == 0) {
+       if (_nvramController == nullptr) {
                return;
        }
 
@@ -277,7 +944,11 @@ IODTNVRAM::syncInternal(bool rateLimit)
                return;
        }
 
+       DEBUG_INFO("Calling sync()\n");
+
+       CONTROLLERLOCK();
        _nvramController->sync();
+       CONTROLLERUNLOCK();
 }
 
 void
@@ -289,104 +960,240 @@ IODTNVRAM::sync(void)
 bool
 IODTNVRAM::serializeProperties(OSSerialize *s) const
 {
-       bool                 result, hasPrivilege;
-       UInt32               variablePerm;
-       const OSSymbol       *key;
-       OSDictionary         *dict;
-       OSCollectionIterator *iter = 0;
+       const OSSymbol                    *key;
+       OSSharedPtr<OSDictionary>         systemDict, commonDict, dict;
+       OSSharedPtr<OSCollectionIterator> iter;
+       bool                              result = false;
+       unsigned int                      totalCapacity = 0;
+
+       NVRAMLOCK();
+       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;
 
-       // Verify permissions.
-       hasPrivilege = (kIOReturnSuccess == IOUserClient::clientHasPrivilege(current_task(), kIONVRAMPrivilege));
+       dict = OSDictionary::withCapacity(totalCapacity);
 
-       if (_ofDict == 0) {
-               /* No nvram. Return an empty dictionary. */
-               dict = OSDictionary::withCapacity(1);
-               if (dict == 0) {
-                       return false;
+       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;
                }
-       } else {
-               IOLockLock(_ofLock);
-               dict = OSDictionary::withDictionary(_ofDict);
-               IOLockUnlock(_ofLock);
-               if (dict == 0) {
-                       return false;
-               }
-
-               /* Copy properties with client privilege. */
-               iter = OSCollectionIterator::withCollection(dict);
-               if (iter == 0) {
-                       dict->release();
-                       return false;
-               }
-               while (1) {
-                       key = OSDynamicCast(OSSymbol, iter->getNextObject());
-                       if (key == 0) {
-                               break;
+
+               while ((key = OSDynamicCast(OSSymbol, iter->getNextObject()))) {
+                       if (verifyPermission(kIONVRAMOperationRead, &gAppleSystemVariableGuid, key)) {
+                               dict->setObject(key, systemDict->getObject(key));
                        }
+               }
 
-                       variablePerm = getOFVariablePerm(key);
-                       if ((hasPrivilege || (variablePerm != kOFVariablePermRootOnly)) &&
-                           (!(variablePerm == kOFVariablePermKernelOnly && current_task() != kernel_task))) {
-                       } else {
-                               dict->removeObject(key);
-                               iter->reset();
+               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));
+                       }
+               }
+       }
+
+       result = dict->serialize(s);
+
+exit:
+       DEBUG_INFO("result=%d\n", result);
+
+       return result;
+}
+
+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();
                }
+       } else {
+               DEBUG_INFO("Defaulting to common dictionary\n");
+               *dict = _commonDict.get();
        }
 
-       result = dict->serialize(s);
+       return kIOReturnSuccess;
+}
+
+bool
+IODTNVRAM::handleSpecialVariables(const char *name, uuid_t *guid, OSObject *obj, IOReturn *error)
+{
+       IOReturn err = kIOReturnSuccess;
+       bool special = false;
+
+       NVRAMLOCKASSERT();
+
+       if (strcmp(name, "ResetNVRam") == 0) {
+               DEBUG_INFO("%s requested\n", name);
+
+               if (uuid_compare(*guid, gAppleSystemVariableGuid) == 0) {
+                       if (_systemDict != nullptr) {
+                               _systemDict->flushCollection();
+                       }
+
+                       _commonDict->flushCollection();
+                       DEBUG_INFO("system & common dictionary flushed\n");
+               }
+
+               special = true;
+       } else if (strcmp(name, "ObliterateNVRam") == 0) {
+               DEBUG_INFO("%s requested\n", name);
+
+               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(newDict.get());
+                       if ((newDict == nullptr) || (iter == nullptr)) {
+                               err = kIOReturnNoMemory;
+                               goto exit;
+                       }
+
+                       while ((key = OSDynamicCast(OSSymbol, iter->getNextObject()))) {
+                               const OSSymbol *key = OSDynamicCast(OSSymbol, iter->getNextObject());
+                               if (key == nullptr) {
+                                       err = kIOReturnNoMemory;
+                                       goto exit;
+                               }
+
+                               if (!verifyPermission(kIONVRAMOperationObliterate, &gAppleSystemVariableGuid, key)) {
+                                       newDict->setObject(key, _systemDict->getObject(key));
+                               }
+                       }
+
+                       _systemDict = newDict;
+
+                       DEBUG_INFO("system dictionary flushed\n");
+               } else if (_commonDict != nullptr) {
+                       const OSSymbol *key;
+                       OSSharedPtr<OSDictionary> newDict;
+                       OSSharedPtr<OSCollectionIterator> iter;
+
+                       newDict = OSDictionary::withCapacity(_commonDict->getCapacity());
+                       iter = OSCollectionIterator::withCollection(newDict.get());
+                       if ((newDict == nullptr) || (iter == nullptr)) {
+                               err = kIOReturnNoMemory;
+                               goto exit;
+                       }
+
+                       while ((key = OSDynamicCast(OSSymbol, iter->getNextObject()))) {
+                               if (!verifyPermission(kIONVRAMOperationObliterate, &gAppleNVRAMGuid, key)) {
+                                       newDict->setObject(key, _commonDict->getObject(key));
+                               }
+                       }
+
+                       _commonDict = newDict;
+
+                       DEBUG_INFO("common dictionary flushed\n");
+               }
+
+               special = true;
+       }
 
-       dict->release();
-       if (iter != 0) {
-               iter->release();
+exit:
+       if (error) {
+               *error = err;
        }
 
-       return result;
+       return special;
 }
 
-OSObject *
+OSSharedPtr<OSObject>
 IODTNVRAM::copyProperty(const OSSymbol *aKey) const
 {
-       IOReturn result;
-       UInt32   variablePerm;
-       OSObject *theObject;
-
-       if (_ofDict == 0) {
-               return 0;
-       }
-
-       // Verify permissions.
-       variablePerm = getOFVariablePerm(aKey);
-       result = IOUserClient::clientHasPrivilege(current_task(), kIONVRAMPrivilege);
+       IOReturn              result;
+       const char            *variableName;
+       uuid_t                varGuid;
+       OSDictionary          *dict;
+       OSSharedPtr<OSObject> theObject = nullptr;
+
+       if (aKey->isEqualTo(kIOBSDNameKey) ||
+           aKey->isEqualTo(kIOBSDNamesKey) ||
+           aKey->isEqualTo(kIOBSDMajorKey) ||
+           aKey->isEqualTo(kIOBSDMinorKey) ||
+           aKey->isEqualTo(kIOBSDUnitKey)) {
+               // These will never match.
+               // Check here and exit to avoid logging spam
+               return nullptr;
+       }
+       DEBUG_INFO("aKey=%s\n", aKey->getCStringNoCopy());
+
+       parseVariableName(aKey->getCStringNoCopy(), &varGuid, &variableName);
+
+       result = chooseDictionary(kIONVRAMOperationRead, &varGuid, variableName, &dict);
        if (result != kIOReturnSuccess) {
-               if (variablePerm == kOFVariablePermRootOnly) {
-                       return 0;
-               }
+               goto exit;
        }
-       if (variablePerm == kOFVariablePermKernelOnly && current_task() != kernel_task) {
-               return 0;
+
+       if (!verifyPermission(kIONVRAMOperationRead, &varGuid, variableName)) {
+               DEBUG_INFO("Not privileged\n");
+               goto exit;
        }
 
-       IOLockLock(_ofLock);
-       theObject = _ofDict->getObject(aKey);
-       if (theObject) {
-               theObject->retain();
+       NVRAMLOCK();
+       theObject.reset(dict->getObject(variableName), OSRetain);
+       NVRAMUNLOCK();
+
+       if (theObject != nullptr) {
+               DEBUG_INFO("found data\n");
        }
-       IOLockUnlock(_ofLock);
 
+exit:
        return theObject;
 }
 
-OSObject *
+OSSharedPtr<OSObject>
 IODTNVRAM::copyProperty(const char *aKey) const
 {
-       const OSSymbol *keySymbol;
-       OSObject *theObject = 0;
+       OSSharedPtr<const OSSymbol> keySymbol;
+       OSSharedPtr<OSObject>       theObject;
 
        keySymbol = OSSymbol::withCString(aKey);
-       if (keySymbol != 0) {
-               theObject = copyProperty(keySymbol);
-               keySymbol->release();
+       if (keySymbol != nullptr) {
+               theObject = copyProperty(keySymbol.get());
        }
 
        return theObject;
@@ -395,226 +1202,291 @@ IODTNVRAM::copyProperty(const char *aKey) const
 OSObject *
 IODTNVRAM::getProperty(const OSSymbol *aKey) const
 {
-       OSObject *theObject;
-
-       theObject = copyProperty(aKey);
-       if (theObject) {
-               theObject->release();
-       }
+       // The shared pointer gets released at the end of the function,
+       // and returns a view into theObject.
+       OSSharedPtr<OSObject> theObject = copyProperty(aKey);
 
-       return theObject;
+       return theObject.get();
 }
 
 OSObject *
 IODTNVRAM::getProperty(const char *aKey) const
 {
-       OSObject *theObject;
-
-       theObject = copyProperty(aKey);
-       if (theObject) {
-               theObject->release();
-       }
+       // The shared pointer gets released at the end of the function,
+       // and returns a view into theObject.
+       OSSharedPtr<OSObject> theObject = copyProperty(aKey);
 
-       return theObject;
+       return theObject.get();
 }
 
-bool
-IODTNVRAM::setProperty(const OSSymbol *aKey, OSObject *anObject)
+IOReturn
+IODTNVRAM::setPropertyInternal(const OSSymbol *aKey, OSObject *anObject)
 {
-       bool     result;
-       UInt32   propType, propPerm;
-       OSString *tmpString = 0;
-       OSObject *propObject = 0, *oldObject;
-
-       if (_ofDict == 0) {
-               return false;
-       }
-
-       // Verify permissions.
-       propPerm = getOFVariablePerm(aKey);
-       if (IOUserClient::clientHasPrivilege(current_task(), kIONVRAMPrivilege) != kIOReturnSuccess) {
-               if (propPerm != kOFVariablePermUserWrite) {
-                       return false;
+       IOReturn              result = kIOReturnSuccess;
+       bool                  remove = false;
+       OSString              *tmpString = nullptr;
+       OSSharedPtr<OSObject> propObject, oldObject;
+       OSSharedPtr<OSObject> sharedObject(anObject, OSRetain);
+       const char            *variableName;
+       uuid_t                varGuid;
+       OSDictionary          *dict;
+       bool                  deletePropertyKey, syncNowPropertyKey, forceSyncNowPropertyKey;
+       bool                  ok;
+       size_t                propDataSize = 0;
+
+       DEBUG_INFO("aKey=%s\n", aKey->getCStringNoCopy());
+
+       parseVariableName(aKey->getCStringNoCopy(), &varGuid, &variableName);
+       deletePropertyKey = strncmp(variableName, kIONVRAMDeletePropertyKey, sizeof(kIONVRAMDeletePropertyKey)) == 0;
+       syncNowPropertyKey = strncmp(variableName, kIONVRAMSyncNowPropertyKey, sizeof(kIONVRAMSyncNowPropertyKey)) == 0;
+       forceSyncNowPropertyKey = strncmp(variableName, kIONVRAMForceSyncNowPropertyKey, sizeof(kIONVRAMForceSyncNowPropertyKey)) == 0;
+
+       if (deletePropertyKey) {
+               tmpString = OSDynamicCast(OSString, anObject);
+               if (tmpString != nullptr) {
+                       DEBUG_INFO("kIONVRAMDeletePropertyKey found\n");
+                       OSSharedPtr<const OSSymbol> sharedKey = OSSymbol::withString(tmpString);
+                       removeProperty(sharedKey.get());
+               } else {
+                       DEBUG_INFO("kIONVRAMDeletePropertyKey value needs to be an OSString\n");
+                       result = kIOReturnError;
+               }
+               goto exit;
+       } else if (syncNowPropertyKey || forceSyncNowPropertyKey) {
+               tmpString = OSDynamicCast(OSString, anObject);
+               DEBUG_INFO("NVRAM sync key %s found\n", aKey->getCStringNoCopy());
+               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", variableName);
+                       result = kIOReturnError;
                }
+               goto exit;
        }
-       if (propPerm == kOFVariablePermKernelOnly && current_task() != kernel_task) {
-               return 0;
+
+       result = chooseDictionary(kIONVRAMOperationWrite, &varGuid, variableName, &dict);
+       if (result != kIOReturnSuccess) {
+               goto exit;
        }
 
-       // Don't allow change of 'aapl,panic-info'.
-       if (aKey->isEqualTo(kIODTNVRAMPanicInfoKey)) {
-               return false;
+       if (!verifyPermission(kIONVRAMOperationWrite, &varGuid, variableName)) {
+               DEBUG_INFO("Not privileged\n");
+               result = kIOReturnNotPrivileged;
+               goto exit;
        }
 
        // Make sure the object is of the correct type.
-       propType = getOFVariableType(aKey);
-       switch (propType) {
+       switch (getVariableType(variableName)) {
        case kOFVariableTypeBoolean:
-               propObject = OSDynamicCast(OSBoolean, anObject);
+               propObject = OSDynamicPtrCast<OSBoolean>(sharedObject);
                break;
 
        case kOFVariableTypeNumber:
-               propObject = OSDynamicCast(OSNumber, anObject);
+               propObject = OSDynamicPtrCast<OSNumber>(sharedObject);
                break;
 
        case kOFVariableTypeString:
-               propObject = OSDynamicCast(OSString, anObject);
+               propObject = OSDynamicPtrCast<OSString>(sharedObject);
+               if (propObject != nullptr) {
+                       propDataSize = (OSDynamicPtrCast<OSString>(propObject))->getLength();
+
+                       if (aKey->isEqualTo(kIONVRAMBootArgsKey) && (propDataSize >= BOOT_LINE_LENGTH)) {
+                               DEBUG_ERROR("boot-args size too large for BOOT_LINE_LENGTH, propDataSize=%zu\n", propDataSize);
+                               result = kIOReturnNoSpace;
+                               goto exit;
+                       }
+               }
                break;
 
        case kOFVariableTypeData:
-               propObject = OSDynamicCast(OSData, anObject);
-               if (propObject == 0) {
-                       tmpString = OSDynamicCast(OSString, anObject);
-                       if (tmpString != 0) {
+               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 == 0) {
-               return false;
+       if (propObject == nullptr) {
+               DEBUG_INFO("No property object\n");
+               result = kIOReturnBadArgument;
+               goto exit;
+       }
+
+       if (!verifyWriteSizeLimit(&varGuid, variableName, propDataSize)) {
+               DEBUG_ERROR("Property data size of %zu too long for %s\n", propDataSize, variableName);
+               result = kIOReturnNoSpace;
+               goto exit;
        }
 
-       IOLockLock(_ofLock);
+       NVRAMLOCK();
+       ok = handleSpecialVariables(variableName, &varGuid, propObject.get(), &result);
+       NVRAMUNLOCK();
 
-       oldObject = _ofDict->getObject(aKey);
-       if (oldObject) {
-               oldObject->retain();
+       if (ok) {
+               serializeVariables();
+               goto exit;
+       }
+
+       NVRAMLOCK();
+       oldObject.reset(dict->getObject(variableName), OSRetain);
+       if (remove == false) {
+               DEBUG_INFO("Adding object\n");
+               if (!dict->setObject(variableName, propObject.get())) {
+                       result = kIOReturnBadArgument;
+               }
+       } else {
+               DEBUG_INFO("Removing object\n");
+               // Check for existence so we can decide whether we need to sync variables
+               if (oldObject) {
+                       result = removePropertyInternal(aKey);
+               } else {
+                       result = kIOReturnNotFound;
+               }
        }
-       result = _ofDict->setObject(aKey, propObject);
+       NVRAMUNLOCK();
+
+       if (result == kIOReturnSuccess) {
+               result = serializeVariables();
+               if (result != kIOReturnSuccess) {
+                       DEBUG_ERROR("serializeVariables failed, result=0x%08x\n", result);
 
-       if (result) {
-               if (syncVariables() != kIOReturnSuccess) {
+                       NVRAMLOCK();
                        if (oldObject) {
-                               _ofDict->setObject(aKey, oldObject);
+                               dict->setObject(variableName, oldObject.get());
                        } else {
-                               _ofDict->removeObject(aKey);
+                               dict->removeObject(variableName);
                        }
-                       (void) syncVariables();
-                       result = false;
+                       NVRAMUNLOCK();
+
+                       (void) serializeVariables();
+                       result = kIOReturnNoMemory;
                }
        }
 
        if (oldObject) {
-               oldObject->release();
+               oldObject.reset();
        }
        if (tmpString) {
-               propObject->release();
+               propObject.reset();
        }
 
-       IOLockUnlock(_ofLock);
+exit:
+       DEBUG_INFO("result=0x%08x\n", result);
 
        return result;
 }
 
+bool
+IODTNVRAM::setProperty(const OSSymbol *aKey, OSObject *anObject)
+{
+       return setPropertyInternal(aKey, anObject) == kIOReturnSuccess;
+}
+
 void
 IODTNVRAM::removeProperty(const OSSymbol *aKey)
 {
-       bool     result;
-       UInt32   propPerm;
+       IOReturn ret;
 
-       if (_ofDict == 0) {
-               return;
+       NVRAMLOCK();
+       ret = removePropertyInternal(aKey);
+       NVRAMUNLOCK();
+
+       if (ret == kIOReturnSuccess) {
+               serializeVariables();
+       } else {
+               DEBUG_INFO("removePropertyInternal failed, ret=0x%08x\n", ret);
        }
+}
+
+IOReturn
+IODTNVRAM::removePropertyInternal(const OSSymbol *aKey)
+{
+       IOReturn     result;
+       const char   *variableName;
+       uuid_t       varGuid;
+       OSDictionary *dict;
 
-       // Verify permissions.
-       propPerm = getOFVariablePerm(aKey);
-       result = IOUserClient::clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator);
+       DEBUG_INFO("aKey=%s\n", aKey->getCStringNoCopy());
+
+       NVRAMLOCKASSERT();
+
+       parseVariableName(aKey->getCStringNoCopy(), &varGuid, &variableName);
+
+       result = chooseDictionary(kIONVRAMOperationDelete, &varGuid, variableName, &dict);
        if (result != kIOReturnSuccess) {
-               if (propPerm != kOFVariablePermUserWrite) {
-                       return;
-               }
-       }
-       if (propPerm == kOFVariablePermKernelOnly && current_task() != kernel_task) {
-               return;
+               goto exit;
        }
 
-       // Don't allow change of 'aapl,panic-info'.
-       if (aKey->isEqualTo(kIODTNVRAMPanicInfoKey)) {
-               return;
+       if (!verifyPermission(kIONVRAMOperationDelete, &varGuid, variableName)) {
+               DEBUG_INFO("Not priveleged\n");
+               result = kIOReturnNotPrivileged;
+               goto exit;
        }
 
        // If the object exists, remove it from the dictionary.
-
-       IOLockLock(_ofLock);
-       result = _ofDict->getObject(aKey) != 0;
-       if (result) {
-               _ofDict->removeObject(aKey);
+       if (dict->getObject(variableName) != nullptr) {
+               dict->removeObject(variableName);
        }
 
-       if (result) {
-               (void) syncVariables();
-       }
-
-       IOLockUnlock(_ofLock);
+exit:
+       return result;
 }
 
 IOReturn
 IODTNVRAM::setProperties(OSObject *properties)
 {
-       bool                 result = true;
-       OSObject             *object;
-       const OSSymbol       *key;
-       const OSString       *tmpStr;
-       OSDictionary         *dict;
-       OSCollectionIterator *iter;
+       IOReturn                          result = kIOReturnSuccess;
+       OSObject                          *object;
+       const OSSymbol                    *key;
+       OSDictionary                      *dict;
+       OSSharedPtr<OSCollectionIterator> iter;
 
        dict = OSDynamicCast(OSDictionary, properties);
-       if (dict == 0) {
+       if (dict == nullptr) {
+               DEBUG_ERROR("Not a dictionary\n");
                return kIOReturnBadArgument;
        }
 
        iter = OSCollectionIterator::withCollection(dict);
-       if (iter == 0) {
+       if (iter == nullptr) {
+               DEBUG_ERROR("Couldn't create iterator\n");
                return kIOReturnBadArgument;
        }
 
-       while (result) {
+       while (result == kIOReturnSuccess) {
                key = OSDynamicCast(OSSymbol, iter->getNextObject());
-               if (key == 0) {
+               if (key == nullptr) {
                        break;
                }
 
                object = dict->getObject(key);
-               if (object == 0) {
+               if (object == nullptr) {
                        continue;
                }
 
-               if (key->isEqualTo(kIONVRAMDeletePropertyKey)) {
-                       tmpStr = OSDynamicCast(OSString, object);
-                       if (tmpStr != 0) {
-                               key = OSSymbol::withString(tmpStr);
-                               removeProperty(key);
-                               key->release();
-                               result = true;
-                       } else {
-                               result = false;
-                       }
-               } else if (key->isEqualTo(kIONVRAMSyncNowPropertyKey) || key->isEqualTo(kIONVRAMForceSyncNowPropertyKey)) {
-                       tmpStr = OSDynamicCast(OSString, object);
-                       if (tmpStr != 0) {
-                               result = true;
-
-                               // We still want to throttle NVRAM commit rate for SyncNow. ForceSyncNow is provided as a really big hammer.
-
-                               syncInternal(key->isEqualTo(kIONVRAMSyncNowPropertyKey));
-                       } else {
-                               result = false;
-                       }
-               } else {
-                       result = setProperty(key, object);
-               }
+               result = setPropertyInternal(key, object);
        }
 
-       iter->release();
+       DEBUG_INFO("result=0x%08x\n", result);
 
-       if (result) {
-               return kIOReturnSuccess;
-       } else {
-               return kIOReturnError;
-       }
+       return result;
 }
 
 IOReturn
@@ -658,7 +1530,7 @@ IODTNVRAM::writeNVRAMProperty(IORegistryEntry *entry,
 OSDictionary *
 IODTNVRAM::getNVRAMPartitions(void)
 {
-       return _nvramPartitionLengths;
+       return _nvramPartitionLengths.get();
 }
 
 IOReturn
@@ -674,7 +1546,7 @@ IODTNVRAM::readNVRAMPartition(const OSSymbol *partitionID,
        partitionLengthNumber =
            (OSNumber *)_nvramPartitionLengths->getObject(partitionID);
 
-       if ((partitionOffsetNumber == 0) || (partitionLengthNumber == 0)) {
+       if ((partitionOffsetNumber == nullptr) || (partitionLengthNumber == nullptr)) {
                return kIOReturnNotFound;
        }
 
@@ -684,7 +1556,7 @@ IODTNVRAM::readNVRAMPartition(const OSSymbol *partitionID,
        if (os_add_overflow(offset, length, &end)) {
                return kIOReturnBadArgument;
        }
-       if ((buffer == 0) || (length == 0) || (end > partitionLength)) {
+       if ((buffer == nullptr) || (length == 0) || (end > partitionLength)) {
                return kIOReturnBadArgument;
        }
 
@@ -706,7 +1578,7 @@ IODTNVRAM::writeNVRAMPartition(const OSSymbol *partitionID,
        partitionLengthNumber =
            (OSNumber *)_nvramPartitionLengths->getObject(partitionID);
 
-       if ((partitionOffsetNumber == 0) || (partitionLengthNumber == 0)) {
+       if ((partitionOffsetNumber == nullptr) || (partitionLengthNumber == nullptr)) {
                return kIOReturnNotFound;
        }
 
@@ -716,14 +1588,14 @@ IODTNVRAM::writeNVRAMPartition(const OSSymbol *partitionID,
        if (os_add_overflow(offset, length, &end)) {
                return kIOReturnBadArgument;
        }
-       if ((buffer == 0) || (length == 0) || (end > partitionLength)) {
+       if ((buffer == nullptr) || (length == 0) || (end > partitionLength)) {
                return kIOReturnBadArgument;
        }
 
        bcopy(buffer, _nvramImage + partitionOffset + offset, length);
 
-       if (_nvramController != 0) {
-               _nvramController->write(0, _nvramImage, kIODTNVRAMImageSize);
+       if (_nvramController != nullptr) {
+               _nvramController->write(0, _nvramImage, _nvramSize);
        }
 
        return kIOReturnSuccess;
@@ -732,33 +1604,7 @@ IODTNVRAM::writeNVRAMPartition(const OSSymbol *partitionID,
 IOByteCount
 IODTNVRAM::savePanicInfo(UInt8 *buffer, IOByteCount length)
 {
-       if ((_piImage == 0) || (length <= 0)) {
-               return 0;
-       }
-
-       if (length > (_piPartitionSize - 4)) {
-               length = _piPartitionSize - 4;
-       }
-
-       // Save the Panic Info.
-       bcopy(buffer, _piImage + 4, length);
-
-       // Save the Panic Info length.
-       *(UInt32 *)_piImage = length;
-
-       if (_nvramController != 0) {
-               _nvramController->write(0, _nvramImage, kIODTNVRAMImageSize);
-       }
-       /*
-        * This prevents OF variables from being committed if the system has panicked
-        */
-       _systemPaniced = true;
-       /* The call to sync() forces the NVRAM controller to write the panic info
-        * partition to NVRAM.
-        */
-       sync();
-
-       return length;
+       return 0;
 }
 
 // Private methods
@@ -780,92 +1626,83 @@ IODTNVRAM::calculatePartitionChecksum(UInt8 *partitionHeader)
 }
 
 IOReturn
-IODTNVRAM::initOFVariables(void)
+IODTNVRAM::initVariables(void)
 {
-       UInt32            cnt;
-       UInt8             *propName, *propData;
-       UInt32            propNameLength, propDataLength;
-       const OSSymbol    *propSymbol;
-       OSObject          *propObject;
+       UInt32                      cnt;
+       UInt8                       *propName, *propData;
+       UInt32                      propNameLength, propDataLength, regionIndex;
+       OSSharedPtr<const OSSymbol> propSymbol;
+       OSSharedPtr<OSObject>       propObject;
+       NVRAMRegionInfo             *currentRegion;
+       NVRAMRegionInfo             variableRegions[] = { { NVRAM_CHRP_PARTITION_NAME_COMMON, _commonPartitionOffset, _commonPartitionSize, _commonDict, _commonImage},
+                                                         { NVRAM_CHRP_PARTITION_NAME_SYSTEM, _systemPartitionOffset, _systemPartitionSize, _systemDict, _systemImage} };
 
-       if (_ofImage == 0) {
-               return kIOReturnNotReady;
-       }
+       DEBUG_INFO("...\n");
 
-       _ofDict = OSDictionary::withCapacity(1);
-       _ofLock = IOLockAlloc();
-       if (!_ofDict || !_ofLock) {
-               return kIOReturnNoMemory;
-       }
+       for (regionIndex = 0; regionIndex < ARRAY_SIZE(variableRegions); regionIndex++) {
+               currentRegion = &variableRegions[regionIndex];
 
-       cnt = 0;
-       while (cnt < _ofPartitionSize) {
-               // Break if there is no name.
-               if (_ofImage[cnt] == '\0') {
-                       break;
+               if (currentRegion->size == 0) {
+                       continue;
                }
 
-               // Find the length of the name.
-               propName = _ofImage + cnt;
-               for (propNameLength = 0; (cnt + propNameLength) < _ofPartitionSize;
-                   propNameLength++) {
-                       if (_ofImage[cnt + propNameLength] == '=') {
+               currentRegion->dict = OSDictionary::withCapacity(1);
+
+               DEBUG_INFO("region = %s\n", currentRegion->name);
+               cnt = 0;
+               while (cnt < currentRegion->size) {
+                       // Break if there is no name.
+                       if (currentRegion->image[cnt] == '\0') {
                                break;
                        }
-               }
 
-               // Break if the name goes past the end of the partition.
-               if ((cnt + propNameLength) >= _ofPartitionSize) {
-                       break;
-               }
-               cnt += propNameLength + 1;
+                       // Find the length of the name.
+                       propName = currentRegion->image + cnt;
+                       for (propNameLength = 0; (cnt + propNameLength) < currentRegion->size;
+                           propNameLength++) {
+                               if (currentRegion->image[cnt + propNameLength] == '=') {
+                                       break;
+                               }
+                       }
 
-               propData = _ofImage + cnt;
-               for (propDataLength = 0; (cnt + propDataLength) < _ofPartitionSize;
-                   propDataLength++) {
-                       if (_ofImage[cnt + propDataLength] == '\0') {
+                       // Break if the name goes past the end of the partition.
+                       if ((cnt + propNameLength) >= currentRegion->size) {
                                break;
                        }
-               }
+                       cnt += propNameLength + 1;
 
-               // Break if the data goes past the end of the partition.
-               if ((cnt + propDataLength) >= _ofPartitionSize) {
-                       break;
-               }
-               cnt += propDataLength + 1;
+                       propData = currentRegion->image + cnt;
+                       for (propDataLength = 0; (cnt + propDataLength) < currentRegion->size;
+                           propDataLength++) {
+                               if (currentRegion->image[cnt + propDataLength] == '\0') {
+                                       break;
+                               }
+                       }
 
-               if (convertPropToObject(propName, propNameLength,
-                   propData, propDataLength,
-                   &propSymbol, &propObject)) {
-                       _ofDict->setObject(propSymbol, propObject);
-                       propSymbol->release();
-                       propObject->release();
+                       // 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());
+                       }
                }
        }
 
        // Create the boot-args property if it is not in the dictionary.
-       if (_ofDict->getObject("boot-args") == 0) {
+       if (_commonDict->getObject(kIONVRAMBootArgsKey) == nullptr) {
                propObject = OSString::withCStringNoCopy("");
-               if (propObject != 0) {
-                       _ofDict->setObject("boot-args", propObject);
-                       propObject->release();
+               if (propObject != nullptr) {
+                       _commonDict->setObject(kIONVRAMBootArgsKey, propObject.get());
                }
        }
 
-       if (_piImage != 0) {
-               propDataLength = *(UInt32 *)_piImage;
-               if ((propDataLength != 0) && (propDataLength <= (_piPartitionSize - 4))) {
-                       propObject = OSData::withBytes(_piImage + 4, propDataLength);
-                       _ofDict->setObject(kIODTNVRAMPanicInfoKey, propObject);
-                       propObject->release();
-
-                       // Clear the length from _piImage and mark dirty.
-                       *(UInt32 *)_piImage = 0;
-                       if (_nvramController != 0) {
-                               _nvramController->write(0, _nvramImage, kIODTNVRAMImageSize);
-                       }
-               }
-       }
+       DEBUG_INFO("%s _commonDict=%p _systemDict=%p\n", __FUNCTION__, _commonDict.get(), _systemDict.get());
 
        return kIOReturnSuccess;
 }
@@ -877,266 +1714,193 @@ IODTNVRAM::syncOFVariables(void)
 }
 
 IOReturn
-IODTNVRAM::syncVariables(void)
+IODTNVRAM::serializeVariables(void)
 {
-       bool                 ok;
-       UInt32               length, maxLength;
-       UInt8                *buffer, *tmpBuffer;
-       const OSSymbol       *tmpSymbol;
-       OSObject             *tmpObject;
-       OSCollectionIterator *iter;
-
-       IOLockAssert(_ofLock, kIOLockAssertOwned);
-
-       if ((_ofImage == 0) || (_ofDict == 0) || _systemPaniced) {
+       IOReturn                          ret;
+       bool                              ok;
+       UInt32                            length, maxLength, regionIndex;
+       UInt8                             *buffer, *tmpBuffer;
+       const OSSymbol                    *tmpSymbol;
+       OSObject                          *tmpObject;
+       OSSharedPtr<OSCollectionIterator> iter;
+       OSSharedPtr<OSNumber>             sizeUsed;
+       UInt32                            systemUsed = 0;
+       UInt32                            commonUsed = 0;
+       OSSharedPtr<OSData>               nvramImage;
+       NVRAMRegionInfo                   *currentRegion;
+       NVRAMRegionInfo                   variableRegions[] = { { NVRAM_CHRP_PARTITION_NAME_COMMON, _commonPartitionOffset, _commonPartitionSize, _commonDict, _commonImage},
+                                                               { NVRAM_CHRP_PARTITION_NAME_SYSTEM, _systemPartitionOffset, _systemPartitionSize, _systemDict, _systemImage} };
+
+       if (_systemPanicked) {
                return kIOReturnNotReady;
        }
 
-       buffer = tmpBuffer = IONew(UInt8, _ofPartitionSize);
-       if (buffer == 0) {
-               return kIOReturnNoMemory;
+       if (_nvramController == nullptr) {
+               DEBUG_ERROR("No _nvramController\n");
+               return kIOReturnNotReady;
        }
-       bzero(buffer, _ofPartitionSize);
 
-       ok = true;
-       maxLength = _ofPartitionSize;
+       DEBUG_INFO("...\n");
 
-       iter = OSCollectionIterator::withCollection(_ofDict);
-       if (iter == 0) {
-               ok = false;
-       }
+       NVRAMLOCK();
 
-       while (ok) {
-               tmpSymbol = OSDynamicCast(OSSymbol, iter->getNextObject());
-               if (tmpSymbol == 0) {
-                       break;
-               }
+       for (regionIndex = 0; regionIndex < ARRAY_SIZE(variableRegions); regionIndex++) {
+               currentRegion = &variableRegions[regionIndex];
 
-               // Don't save 'aapl,panic-info'.
-               if (tmpSymbol->isEqualTo(kIODTNVRAMPanicInfoKey)) {
+               if (currentRegion->size == 0) {
                        continue;
                }
 
-               tmpObject = _ofDict->getObject(tmpSymbol);
+               DEBUG_INFO("region = %s\n", currentRegion->name);
+               buffer = tmpBuffer = IONew(UInt8, currentRegion->size);
+               if (buffer == nullptr) {
+                       return kIOReturnNoMemory;
+               }
+               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;
+                       }
+               }
 
-               length = maxLength;
-               ok = convertObjectToProp(tmpBuffer, &length, tmpSymbol, tmpObject);
                if (ok) {
-                       tmpBuffer += length;
-                       maxLength -= length;
+                       bcopy(buffer, currentRegion->image, currentRegion->size);
                }
-       }
-       iter->release();
 
-       if (ok) {
-               bcopy(buffer, _ofImage, _ofPartitionSize);
+               IODelete(buffer, UInt8, currentRegion->size);
+
+               if ((strncmp(currentRegion->name, NVRAM_CHRP_PARTITION_NAME_SYSTEM, strlen(NVRAM_CHRP_PARTITION_NAME_SYSTEM)) == 0) &&
+                   (_systemService != nullptr)) {
+                       _systemService->setProperties(_systemDict.get());
+                       systemUsed = maxLength;
+               } else if ((strncmp(currentRegion->name, NVRAM_CHRP_PARTITION_NAME_COMMON, strlen(NVRAM_CHRP_PARTITION_NAME_COMMON)) == 0) &&
+                   (_commonService != nullptr)) {
+                       _commonService->setProperties(_commonDict.get());
+                       commonUsed = maxLength;
+               }
+
+               if (!ok) {
+                       return kIOReturnBadArgument;
+               }
        }
 
-       IODelete(buffer, UInt8, _ofPartitionSize);
+       nvramImage = OSData::withBytes(_nvramImage, _nvramSize);
 
-       if (!ok) {
-               return kIOReturnBadArgument;
+       NVRAMUNLOCK();
+
+       DEBUG_INFO("ok=%d\n", ok);
+
+       CONTROLLERLOCK();
+
+       if (_systemService) {
+               sizeUsed = OSNumber::withNumber(systemUsed, 32);
+               _nvramController->setProperty("SystemUsed", sizeUsed.get());
+               sizeUsed.reset();
        }
 
-       if (_nvramController != 0) {
-               return _nvramController->write(0, _nvramImage, kIODTNVRAMImageSize);
+       if (_commonService) {
+               sizeUsed = OSNumber::withNumber(commonUsed, 32);
+               _nvramController->setProperty("CommonUsed", sizeUsed.get());
+               sizeUsed.reset();
        }
 
-       return kIOReturnNotReady;
-}
+       ret = _nvramController->write(0, (uint8_t *)nvramImage->getBytesNoCopy(), nvramImage->getLength());
 
-struct OFVariable {
-       const char *variableName;
-       UInt32     variableType;
-       UInt32     variablePerm;
-       SInt32     variableOffset;
-};
-typedef struct OFVariable OFVariable;
+       CONTROLLERUNLOCK();
 
-enum {
-       kOWVariableOffsetNumber = 8,
-       kOWVariableOffsetString = 17
-};
+       return ret;
+}
 
-static const
-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},
-       {"boot-image", kOFVariableTypeData, kOFVariablePermUserWrite, -1},
-       {"com.apple.System.fp-state", kOFVariableTypeData, kOFVariablePermKernelOnly, -1},
-#if CONFIG_EMBEDDED
-       {"backlight-level", kOFVariableTypeData, kOFVariablePermUserWrite, -1},
-       {"com.apple.System.sep.art", kOFVariableTypeData, kOFVariablePermKernelOnly, -1},
-       {"com.apple.System.boot-nonce", kOFVariableTypeString, kOFVariablePermKernelOnly, -1},
-       {"darkboot", kOFVariableTypeBoolean, kOFVariablePermUserWrite, -1},
-       {"acc-mb-ld-lifetime", kOFVariableTypeNumber, kOFVariablePermKernelOnly, -1},
-       {"acc-cm-override-charger-count", kOFVariableTypeNumber, kOFVariablePermKernelOnly, -1},
-       {"acc-cm-override-count", kOFVariableTypeNumber, kOFVariablePermKernelOnly, -1},
-       {"enter-tdm-mode", kOFVariableTypeBoolean, kOFVariablePermUserWrite, -1},
-       {"nonce-seeds", kOFVariableTypeData, kOFVariablePermKernelOnly, -1},
-#endif
-       {0, kOFVariableTypeData, kOFVariablePermUserRead, -1}
-};
+UInt32
+IODTNVRAM::getOFVariableType(const char *propName) const
+{
+       return 0;
+}
 
 UInt32
 IODTNVRAM::getOFVariableType(const OSSymbol *propSymbol) const
 {
-       const OFVariable *ofVar;
+       return 0;
+}
 
-       ofVar = gOFVariables;
-       while (1) {
-               if ((ofVar->variableName == 0) ||
-                   propSymbol->isEqualTo(ofVar->variableName)) {
-                       break;
-               }
-               ofVar++;
-       }
 
-       return ofVar->variableType;
+UInt32
+IODTNVRAM::getOFVariablePerm(const char *propName) const
+{
+       return 0;
 }
 
 UInt32
 IODTNVRAM::getOFVariablePerm(const OSSymbol *propSymbol) const
 {
-       const OFVariable *ofVar;
-
-       ofVar = gOFVariables;
-       while (1) {
-               if ((ofVar->variableName == 0) ||
-                   propSymbol->isEqualTo(ofVar->variableName)) {
-                       break;
-               }
-               ofVar++;
-       }
-
-       return ofVar->variablePerm;
+       return 0;
 }
 
 bool
 IODTNVRAM::getOWVariableInfo(UInt32 variableNumber, const OSSymbol **propSymbol,
     UInt32 *propType, UInt32 *propOffset)
 {
-       const 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;
+       /* UNSUPPORTED */
+       return false;
 }
-
 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;
+       OSSharedPtr<const OSSymbol> tmpSymbol;
+       OSSharedPtr<OSNumber>       tmpNumber;
+       OSSharedPtr<OSString>       tmpString;
+       OSSharedPtr<OSObject>       tmpObject = nullptr;
 
-       // Create the symbol.
        propName[propNameLength] = '\0';
        tmpSymbol = OSSymbol::withCString((const char *)propName);
        propName[propNameLength] = '=';
-       if (tmpSymbol == 0) {
+       if (tmpSymbol == nullptr) {
                return false;
        }
 
-       propType = getOFVariableType(tmpSymbol);
-
-       // Create the object.
-       tmpObject = 0;
-       switch (propType) {
+       switch (getVariableType(tmpSymbol.get())) {
        case kOFVariableTypeBoolean:
                if (!strncmp("true", (const char *)propData, propDataLength)) {
-                       tmpObject = kOSBooleanTrue;
+                       tmpObject.reset(kOSBooleanTrue, OSRetain);
                } else if (!strncmp("false", (const char *)propData, propDataLength)) {
-                       tmpObject = kOSBooleanFalse;
+                       tmpObject.reset(kOSBooleanFalse, OSRetain);
                }
                break;
 
        case kOFVariableTypeNumber:
-               tmpNumber = OSNumber::withNumber(strtol((const char *)propData, 0, 0), 32);
-               if (tmpNumber != 0) {
+               tmpNumber = OSNumber::withNumber(strtol((const char *)propData, nullptr, 0), 32);
+               if (tmpNumber != nullptr) {
                        tmpObject = tmpNumber;
                }
                break;
 
        case kOFVariableTypeString:
                tmpString = OSString::withCString((const char *)propData);
-               if (tmpString != 0) {
+               if (tmpString != nullptr) {
                        tmpObject = tmpString;
                }
                break;
@@ -1144,66 +1908,87 @@ IODTNVRAM::convertPropToObject(UInt8 *propName, UInt32 propNameLength,
        case kOFVariableTypeData:
                tmpObject = unescapeBytesToData(propData, propDataLength);
                break;
+
+       default:
+               break;
        }
 
-       if (tmpObject == 0) {
-               tmpSymbol->release();
+       if (tmpObject == nullptr) {
+               tmpSymbol.reset();
                return false;
        }
 
-       *propSymbol = tmpSymbol;
-       *propObject = tmpObject;
+       *propSymbol = tmpSymbol.detach();
+       *propObject = tmpObject.detach();
 
        return true;
 }
 
+bool
+IODTNVRAM::convertPropToObject(UInt8 *propName, UInt32 propNameLength,
+    UInt8 *propData, UInt32 propDataLength,
+    OSSharedPtr<const OSSymbol>& propSymbol,
+    OSSharedPtr<OSObject>& propObject)
+{
+       const OSSymbol* propSymbolRaw = nullptr;
+       OSObject* propObjectRaw = nullptr;
+       bool result = convertPropToObject(propName, propNameLength, propData, propDataLength,
+           &propSymbolRaw, &propObjectRaw);
+       propSymbol.reset(propSymbolRaw, OSNoRetain);
+       propObject.reset(propObjectRaw, OSNoRetain);
+       return result;
+}
+
 bool
 IODTNVRAM::convertObjectToProp(UInt8 *buffer, UInt32 *length,
     const OSSymbol *propSymbol, OSObject *propObject)
 {
-       const UInt8    *propName;
-       UInt32         propNameLength, propDataLength, remaining;
-       UInt32         propType, tmpValue;
-       OSBoolean      *tmpBoolean = 0;
-       OSNumber       *tmpNumber = 0;
-       OSString       *tmpString = 0;
-       OSData         *tmpData = 0;
+       const UInt8          *propName;
+       UInt32               propNameLength, propDataLength, remaining;
+       IONVRAMVariableType  propType;
+       OSBoolean            *tmpBoolean = nullptr;
+       OSNumber             *tmpNumber = nullptr;
+       OSString             *tmpString = nullptr;
+       OSSharedPtr<OSData>  tmpData;
 
        propName = (const UInt8 *)propSymbol->getCStringNoCopy();
        propNameLength = propSymbol->getLength();
-       propType = getOFVariableType(propSymbol);
+       propType = getVariableType(propSymbol);
 
        // Get the size of the data.
        propDataLength = 0xFFFFFFFF;
        switch (propType) {
        case kOFVariableTypeBoolean:
                tmpBoolean = OSDynamicCast(OSBoolean, propObject);
-               if (tmpBoolean != 0) {
+               if (tmpBoolean != nullptr) {
                        propDataLength = 5;
                }
                break;
 
        case kOFVariableTypeNumber:
                tmpNumber = OSDynamicCast(OSNumber, propObject);
-               if (tmpNumber != 0) {
+               if (tmpNumber != nullptr) {
                        propDataLength = 10;
                }
                break;
 
        case kOFVariableTypeString:
                tmpString = OSDynamicCast(OSString, propObject);
-               if (tmpString != 0) {
+               if (tmpString != nullptr) {
                        propDataLength = tmpString->getLength();
                }
                break;
 
        case kOFVariableTypeData:
-               tmpData = OSDynamicCast(OSData, propObject);
-               if (tmpData != 0) {
-                       tmpData = escapeDataToData(tmpData);
+               tmpData.reset(OSDynamicCast(OSData, propObject), OSNoRetain);
+               if (tmpData != nullptr) {
+                       tmpData = escapeDataToData(tmpData.detach());
                        propDataLength = tmpData->getLength();
                }
                break;
+
+       default:
+               break;
        }
 
        // Make sure the propertySize is known and will fit.
@@ -1228,7 +2013,8 @@ IODTNVRAM::convertObjectToProp(UInt8 *buffer, UInt32 *length,
                break;
 
        case kOFVariableTypeNumber:
-               tmpValue = tmpNumber->unsigned32BitValue();
+       {
+               uint32_t tmpValue = tmpNumber->unsigned32BitValue();
                if (tmpValue == 0xFFFFFFFF) {
                        strlcpy((char *)buffer, "-1", remaining);
                } else if (tmpValue < 1000) {
@@ -1236,7 +2022,8 @@ IODTNVRAM::convertObjectToProp(UInt8 *buffer, UInt32 *length,
                } else {
                        snprintf((char *)buffer, remaining, "0x%x", (uint32_t)tmpValue);
                }
-               break;
+       }
+       break;
 
        case kOFVariableTypeString:
                strlcpy((char *)buffer, tmpString->getCStringNoCopy(), remaining);
@@ -1244,11 +2031,14 @@ IODTNVRAM::convertObjectToProp(UInt8 *buffer, UInt32 *length,
 
        case kOFVariableTypeData:
                bcopy(tmpData->getBytesNoCopy(), buffer, propDataLength);
-               tmpData->release();
+               tmpData.reset();
+               break;
+
+       default:
                break;
        }
 
-       propDataLength = strlen((const char *)buffer);
+       propDataLength = ((UInt32) strlen((const char *)buffer));
 
        *length = propNameLength + propDataLength + 2;
 
@@ -1262,7 +2052,7 @@ IODTNVRAM::generateOWChecksum(UInt8 *buffer)
        UInt32 cnt, checksum = 0;
        UInt16 *tmpBuffer = (UInt16 *)buffer;
 
-       for (cnt = 0; cnt < _ofPartitionSize / 2; cnt++) {
+       for (cnt = 0; cnt < _commonPartitionSize / 2; cnt++) {
                checksum += tmpBuffer[cnt];
        }
 
@@ -1275,7 +2065,7 @@ IODTNVRAM::validateOWChecksum(UInt8 *buffer)
        UInt32 cnt, checksum, sum = 0;
        UInt16 *tmpBuffer = (UInt16 *)buffer;
 
-       for (cnt = 0; cnt < _ofPartitionSize / 2; cnt++) {
+       for (cnt = 0; cnt < _commonPartitionSize / 2; cnt++) {
                sum += tmpBuffer[cnt];
        }
 
@@ -1291,85 +2081,7 @@ IODTNVRAM::validateOWChecksum(UInt8 *buffer)
 void
 IODTNVRAM::updateOWBootArgs(const OSSymbol *key, OSObject *value)
 {
-       bool        wasBootArgs, bootr = false;
-       UInt32      cnt;
-       OSString    *tmpString, *bootCommand, *bootArgs = 0;
-       const UInt8 *bootCommandData, *bootArgsData;
-       UInt8       *tmpData;
-       UInt32      bootCommandDataLength, bootArgsDataLength, tmpDataLength;
-
-       tmpString = OSDynamicCast(OSString, value);
-       if (tmpString == 0) {
-               return;
-       }
-
-       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 = (const 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 = (const UInt8 *)bootArgs->getCStringNoCopy();
-               bootArgsDataLength = bootArgs->getLength();
-               if (bootArgsData == 0) {
-                       return;
-               }
-
-               tmpDataLength = cnt + bootArgsDataLength;
-               tmpData = IONew(UInt8, tmpDataLength + 1);
-               if (tmpData == 0) {
-                       return;
-               }
-
-               cnt -= strlcpy((char *)tmpData, (const char *)bootCommandData, cnt);
-               strlcat((char *)tmpData, (const char *)bootArgsData, cnt);
-
-               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();
-               }
-       }
+       /* UNSUPPORTED */
 }
 
 bool
@@ -1396,14 +2108,14 @@ IODTNVRAM::writeNVRAMPropertyType0(IORegistryEntry *entry,
 }
 
 
-OSData *
+OSSharedPtr<OSData>
 IODTNVRAM::unescapeBytesToData(const UInt8 *bytes, UInt32 length)
 {
-       OSData *data = 0;
-       UInt32 totalLength = 0;
-       UInt32 cnt, cnt2;
-       UInt8  byte;
-       bool   ok;
+       OSSharedPtr<OSData> data;
+       UInt32              totalLength = 0;
+       UInt32              cnt, cnt2;
+       UInt8               byte;
+       bool                ok;
 
        // Calculate the actual length of the data.
        ok = true;
@@ -1426,7 +2138,7 @@ IODTNVRAM::unescapeBytesToData(const UInt8 *bytes, UInt32 length)
        if (ok) {
                // Create an empty OSData of the correct size.
                data = OSData::withCapacity(totalLength);
-               if (data != 0) {
+               if (data != nullptr) {
                        for (cnt = 0; cnt < length;) {
                                byte = bytes[cnt++];
                                if (byte == 0xFF) {
@@ -1444,20 +2156,20 @@ IODTNVRAM::unescapeBytesToData(const UInt8 *bytes, UInt32 length)
        return data;
 }
 
-OSData *
+OSSharedPtr<OSData>
 IODTNVRAM::escapeDataToData(OSData * value)
 {
-       OSData *       result;
-       const UInt8 *  startPtr;
-       const UInt8 *  endPtr;
-       const UInt8 *  wherePtr;
-       UInt8          byte;
-       bool           ok = true;
+       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(endPtr - wherePtr);
+       result = OSData::withCapacity((unsigned int) (endPtr - wherePtr));
        if (!result) {
                return result;
        }
@@ -1471,15 +2183,14 @@ IODTNVRAM::escapeDataToData(OSData * value)
                            wherePtr++) {
                        }
                        ok &= result->appendByte(0xff, 1);
-                       byte = (byte & 0x80) | (wherePtr - startPtr);
+                       byte = (byte & 0x80) | ((UInt8)(wherePtr - startPtr));
                }
                ok &= result->appendByte(byte, 1);
        }
        ok &= result->appendByte(0, 1);
 
        if (!ok) {
-               result->release();
-               result = 0;
+               result.reset();
        }
 
        return result;
@@ -1508,22 +2219,18 @@ IODTNVRAM::readNVRAMPropertyType1(IORegistryEntry *entry,
        const UInt8 *startPtr;
        const UInt8 *endPtr;
        const UInt8 *wherePtr;
-       const UInt8 *nvPath = 0;
-       const char  *nvName = 0;
-       const char  *resultName = 0;
-       const UInt8 *resultValue = 0;
+       const UInt8 *nvPath = nullptr;
+       const char  *nvName = nullptr;
+       const char  *resultName = nullptr;
+       const UInt8 *resultValue = nullptr;
        UInt32       resultValueLen = 0;
        UInt8       byte;
 
-       if (_ofDict == 0) {
-               return err;
-       }
-
-       IOLockLock(_ofLock);
-       data = OSDynamicCast(OSData, _ofDict->getObject(_registryPropertiesKey));
-       IOLockUnlock(_ofLock);
+       NVRAMLOCK();
+       data = OSDynamicCast(OSData, _commonDict->getObject(_registryPropertiesKey.get()));
+       NVRAMUNLOCK();
 
-       if (data == 0) {
+       if (data == nullptr) {
                return err;
        }
 
@@ -1537,35 +2244,32 @@ IODTNVRAM::readNVRAMPropertyType1(IORegistryEntry *entry,
                        continue;
                }
 
-               if (nvPath == 0) {
+               if (nvPath == nullptr) {
                        nvPath = startPtr;
-               } else if (nvName == 0) {
+               } else if (nvName == nullptr) {
                        nvName = (const char *) startPtr;
                } else {
-                       IORegistryEntry * compareEntry = IORegistryEntry::fromPath((const char *) nvPath, gIODTPlane);
-                       if (compareEntry) {
-                               compareEntry->release();
-                       }
+                       OSSharedPtr<IORegistryEntry> compareEntry = IORegistryEntry::fromPath((const char *) nvPath, gIODTPlane);
                        if (entry == compareEntry) {
                                bool appleProp = IsApplePropertyName(nvName);
                                if (!appleProp || !resultName) {
                                        resultName     = nvName;
                                        resultValue    = startPtr;
-                                       resultValueLen = wherePtr - startPtr - 1;
+                                       resultValueLen = (UInt32) (wherePtr - startPtr - 1);  // OSData getLength() is 32b
                                }
                                if (!appleProp) {
                                        break;
                                }
                        }
-                       nvPath = 0;
-                       nvName = 0;
+                       nvPath = nullptr;
+                       nvName = nullptr;
                }
                startPtr = wherePtr;
        }
        if (resultName) {
-               *name = OSSymbol::withCString(resultName);
-               *value = unescapeBytesToData(resultValue, resultValueLen);
-               if ((*name != 0) && (*value != 0)) {
+               *name = OSSymbol::withCString(resultName).detach();
+               *value = unescapeBytesToData(resultValue, resultValueLen).detach();
+               if ((*name != nullptr) && (*value != nullptr)) {
                        err = kIOReturnSuccess;
                } else {
                        err = kIOReturnNoMemory;
@@ -1579,31 +2283,26 @@ IODTNVRAM::writeNVRAMPropertyType1(IORegistryEntry *entry,
     const OSSymbol *propName,
     OSData *value)
 {
-       OSData       *oldData, *escapedData;
-       OSData       *data = 0;
-       const UInt8  *startPtr;
-       const UInt8  *propStart;
-       const UInt8  *endPtr;
-       const UInt8  *wherePtr;
-       const UInt8  *nvPath = 0;
-       const char   *nvName = 0;
-       const char * comp;
-       const char * name;
-       UInt8        byte;
-       bool         ok = true;
-       bool         settingAppleProp;
-
-       if (_ofDict == 0) {
-               return kIOReturnNoResources;
-       }
+       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
 
-       IOLockLock(_ofLock);
+       NVRAMLOCK();
 
-       oldData = OSDynamicCast(OSData, _ofDict->getObject(_registryPropertiesKey));
+       oldData.reset(OSDynamicCast(OSData, _commonDict->getObject(_registryPropertiesKey.get())), OSRetain);
        if (oldData) {
                startPtr = (const UInt8 *) oldData->getBytesNoCopy();
                endPtr = startPtr + oldData->getLength();
@@ -1615,28 +2314,26 @@ IODTNVRAM::writeNVRAMPropertyType1(IORegistryEntry *entry,
                        if (byte) {
                                continue;
                        }
-                       if (nvPath == 0) {
+                       if (nvPath == nullptr) {
                                nvPath = startPtr;
-                       } else if (nvName == 0) {
+                       } else if (nvName == nullptr) {
                                nvName = (const char *) startPtr;
                        } else {
-                               IORegistryEntry * compareEntry = IORegistryEntry::fromPath((const char *) nvPath, gIODTPlane);
-                               if (compareEntry) {
-                                       compareEntry->release();
-                               }
+                               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)
-                                               data = OSData::withBytes(propStart, nvPath - propStart);
+                                               // delete old property (nvPath -> wherePtr) source OSData len is 32b
+                                               data = OSData::withBytes(propStart, (UInt32)(nvPath - propStart));
                                                if (data) {
-                                                       ok &= data->appendBytes(wherePtr, endPtr - wherePtr);
+                                                       ok &= data->appendBytes(wherePtr, (UInt32)(endPtr - wherePtr));
                                                }
                                                break;
                                        }
                                }
-                               nvPath = 0;
-                               nvName = 0;
+                               nvPath = nullptr;
+                               nvName = nullptr;
                        }
 
                        startPtr = wherePtr;
@@ -1647,7 +2344,7 @@ IODTNVRAM::writeNVRAMPropertyType1(IORegistryEntry *entry,
 
        if (!data) {
                if (oldData) {
-                       data = OSData::withData(oldData);
+                       data = OSData::withData(oldData.get());
                } else {
                        data = OSData::withCapacity(16);
                }
@@ -1659,7 +2356,7 @@ IODTNVRAM::writeNVRAMPropertyType1(IORegistryEntry *entry,
        if (ok && value && value->getLength()) {
                do {
                        // get entries in path
-                       OSArray *array = OSArray::withCapacity(5);
+                       OSSharedPtr<OSArray> array = OSArray::withCapacity(5);
                        if (!array) {
                                ok = false;
                                break;
@@ -1683,49 +2380,43 @@ IODTNVRAM::writeNVRAMPropertyType1(IORegistryEntry *entry,
                                        ok &= data->appendByte('/', 1);
                                        comp = name;
                                }
-                               ok &= data->appendBytes(comp, strlen(comp));
+                               ok &= data->appendBytes(comp, (unsigned int) strnlen(comp, UINT16_MAX));
                        }
                        ok &= data->appendByte(0, 1);
-                       array->release();
-
                        // append prop name
                        ok &= data->appendBytes(propName->getCStringNoCopy(), propName->getLength() + 1);
 
                        // append escaped data
-                       escapedData = escapeDataToData(value);
-                       ok &= (escapedData != 0);
+                       OSSharedPtr<OSData> escapedData = escapeDataToData(value);
+                       ok &= (escapedData != nullptr);
                        if (ok) {
-                               ok &= data->appendBytes(escapedData);
+                               ok &= data->appendBytes(escapedData.get());
                        }
                } while (false);
        }
 
-       oldData->retain();
        if (ok) {
-               ok = _ofDict->setObject(_registryPropertiesKey, data);
+               ok = _commonDict->setObject(_registryPropertiesKey.get(), data.get());
        }
 
-       if (data) {
-               data->release();
-       }
+       NVRAMUNLOCK();
 
        if (ok) {
-               if (syncVariables() != kIOReturnSuccess) {
+               if (serializeVariables() != kIOReturnSuccess) {
+                       NVRAMLOCK();
                        if (oldData) {
-                               _ofDict->setObject(_registryPropertiesKey, oldData);
+                               _commonDict->setObject(_registryPropertiesKey.get(), oldData.get());
                        } else {
-                               _ofDict->removeObject(_registryPropertiesKey);
+                               _commonDict->removeObject(_registryPropertiesKey.get());
                        }
-                       (void) syncVariables();
+                       NVRAMUNLOCK();
+
+                       (void) serializeVariables();
                        ok = false;
                }
        }
 
-       if (oldData) {
-               oldData->release();
-       }
-
-       IOLockUnlock(_ofLock);
+       oldData.reset();
 
        return ok ? kIOReturnSuccess : kIOReturnNoMemory;
 }