Loading...
iokit/Kernel/IONVRAM.cpp xnu-12377.121.6 xnu-7195.141.2
--- xnu/xnu-12377.121.6/iokit/Kernel/IONVRAM.cpp
+++ xnu/xnu-7195.141.2/iokit/Kernel/IONVRAM.cpp
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 1998-2006 Apple Computer, Inc. All rights reserved.
- * Copyright (c) 2007-2021 Apple Inc. All rights reserved.
+ * Copyright (c) 2007-2012 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  *
@@ -38,151 +38,122 @@
 #include <IOKit/IOKitKeysPrivate.h>
 #include <IOKit/IOBSD.h>
 #include <kern/debug.h>
-#include <os/system_event_log.h>
 #include <pexpert/boot.h>
+#include <pexpert/pexpert.h>
 #include <sys/csr.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_PARTITION_NAME_COMMON_V1   "common"
+#define NVRAM_CHRP_PARTITION_NAME_SYSTEM_V1   "system"
+#define NVRAM_CHRP_PARTITION_NAME_COMMON_V2   "2common"
+#define NVRAM_CHRP_PARTITION_NAME_SYSTEM_V2   "2system"
+
+#define NVRAM_CHRP_LENGTH_BLOCK_SIZE 0x10 // CHRP length field is in 16 byte blocks
+
+typedef struct chrp_nvram_header { //16 bytes
+	uint8_t  sig;
+	uint8_t  cksum; // checksum on sig, len, and name
+	uint16_t len;   // total length of the partition in 16 byte blocks starting with the signature
+	// and ending with the last byte of data area, ie len includes its own header size
+	char     name[12];
+	uint8_t  data[0];
+} chrp_nvram_header_t;
+
+typedef struct apple_nvram_header {  // 16 + 16 bytes
+	struct   chrp_nvram_header chrp;
+	uint32_t adler;
+	uint32_t generation;
+	uint8_t  padding[8];
+} apple_nvram_header_t;
+
+
+#define kIONVRAMPrivilege       kIOClientPrivilegeAdministrator
+
 OSDefineMetaClassAndStructors(IODTNVRAM, IOService);
 
-class IONVRAMCHRPHandler;
-class IONVRAMV3Handler;
-
-#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
-
-#define MAX_VAR_NAME_SIZE     63
-
-#define kNVRAMBankSizeKey     "nvram-bank-size"
-#define kNVRAMBankCountKey    "nvram-bank-count"
-#define kNVRAMCurrentBankKey  "nvram-current-bank"
-#define kNVRAMClearTestVarKey "clear-test-vars"
-
-#define kCurrentGenerationCountKey "Generation"
-#define kCurrentNVRAMVersionKey    "Version"
-
-#define kNVRAMCommonUsedKey    "CommonUsed"
-#define kNVRAMSystemUsedKey    "SystemUsed"
-
-#define kIONVRAMPrivilege       kIOClientPrivilegeAdministrator
-
-#define MIN_SYNC_NOW_INTERVAL 15*60 /* Minimum 15 Minutes interval mandated */
-
-enum IONVRAMLogging {
-	kIONVRAMNoLogs      = 0,
-	kIONVRAMInfoLogs    = 1,
-	kIONVRAMErrorLogs   = 2,
-	kIONVRAMDataHexDump = 4
-};
-
-#define IS_LOG_BIT_SET(level) ((gNVRAMLogging & (level)) != 0)
-
 #if defined(DEBUG) || defined(DEVELOPMENT)
-#define DEBUG_IFERROR(err, fmt, args...)                                     \
-({                                                                           \
-	if ((err != kIOReturnSuccess) || IS_LOG_BIT_SET(kIONVRAMErrorLogs))      \
-	IOLog("%s:%s:%u - " fmt, __FILE_NAME__, __FUNCTION__, __LINE__, ##args); \
+#define DEBUG_INFO(fmt, args...)                                    \
+({                                                                  \
+	if (gNVRAMLogging)                                              \
+	IOLog("IONVRAM::%s:%u - " fmt, __FUNCTION__, __LINE__, ##args); \
 })
 
-#define DEBUG_INFO_IF(log, fmt, args...)                                     \
-({                                                                           \
-	if ((log) && IS_LOG_BIT_SET(kIONVRAMInfoLogs))                           \
-	IOLog("%s:%s:%u - " fmt, __FILE_NAME__, __FUNCTION__, __LINE__, ##args); \
-})
-
-#define DEBUG_INFO(fmt, args...)                                             \
-({                                                                           \
-	if (IS_LOG_BIT_SET(kIONVRAMInfoLogs))                                    \
-	IOLog("%s:%s:%u - " fmt, __FILE_NAME__, __FUNCTION__, __LINE__, ##args); \
-})
-
-#define DEBUG_ALWAYS(fmt, args...)                                           \
-({                                                                           \
-	IOLog("%s:%s:%u - " fmt, __FILE_NAME__, __FUNCTION__, __LINE__, ##args); \
+#define DEBUG_ALWAYS(fmt, args...)                                  \
+({                                                                  \
+	IOLog("IONVRAM::%s:%u - " fmt, __FUNCTION__, __LINE__, ##args); \
 })
 #else
-#define DEBUG_IFERROR(err, fmt, args...) (void)NULL
-#define DEBUG_INFO(fmt, args...) (void)NULL
-#define DEBUG_ALWAYS(fmt, args...) (void)NULL
-#define DEBUG_INFO_IF(fmt, args...) (void)NULL
+#define DEBUG_INFO(fmt, args...)
+#define DEBUG_ALWAYS(fmt, args...)
 #endif
 
 #define DEBUG_ERROR DEBUG_ALWAYS
 
-#define SAFE_TO_LOCK() (preemption_enabled() && !panic_active())
-
-#define NVRAMLOCK(lock)       \
-({                            \
-	if (SAFE_TO_LOCK())       \
-	        IOLockLock(lock); \
+#define CONTROLLERLOCK()                             \
+({                                                   \
+	if (preemption_enabled() && !panic_active()) \
+	        IOLockLock(_controllerLock);         \
 })
 
-#define NVRAMUNLOCK(lock)       \
-({                              \
-	if (SAFE_TO_LOCK())         \
-	        IOLockUnlock(lock); \
+#define CONTROLLERUNLOCK()                           \
+({                                                   \
+	if (preemption_enabled() && !panic_active()) \
+	        IOLockUnlock(_controllerLock);       \
 })
 
-#define NVRAMLOCKASSERTHELD(lock)                   \
+#define NVRAMREADLOCK()                             \
 ({                                                  \
-	if (SAFE_TO_LOCK())                             \
-	        IOLockAssert(lock, kIOLockAssertOwned); \
+	if (preemption_enabled() && !panic_active()) \
+	        IORWLockRead(_variableLock);         \
 })
 
-#define NVRAMREADLOCK(lock)     \
-({                              \
-	if (SAFE_TO_LOCK())         \
-	        IORWLockRead(lock); \
+#define NVRAMWRITELOCK()                            \
+({                                                  \
+	if (preemption_enabled() && !panic_active()) \
+	        IORWLockWrite(_variableLock);        \
 })
 
-#define NVRAMWRITELOCK(lock)     \
-({                               \
-	if (SAFE_TO_LOCK())          \
-	        IORWLockWrite(lock); \
+#define NVRAMUNLOCK()                               \
+({                                                  \
+	if (preemption_enabled() && !panic_active()) \
+	        IORWLockUnlock(_variableLock);       \
 })
 
-#define NVRAMRWUNLOCK(lock)       \
-({                                \
-	if (SAFE_TO_LOCK())           \
-	        IORWLockUnlock(lock); \
+#define NVRAMLOCKASSERTHELD()                                      \
+({                                                                 \
+	if (preemption_enabled() && !panic_active())                \
+	        IORWLockAssert(_variableLock, kIORWLockAssertHeld); \
 })
 
-#define NVRAMRWUNLOCKANDWRITE(lock) \
-({                                  \
-	NVRAMRWUNLOCK(lock);            \
-	NVRAMWRITELOCK(lock);           \
+#define NVRAMLOCKASSERTEXCLUSIVE()                                  \
+({                                                                  \
+	if (preemption_enabled() && !panic_active())                 \
+	        IORWLockAssert(_variableLock, kIORWLockAssertWrite); \
 })
 
-#define NVRAMRWLOCKASSERTHELD(lock)                    \
-({                                                     \
-	if (SAFE_TO_LOCK())                                \
-	        IORWLockAssert(lock, kIORWLockAssertHeld); \
-})
-
-#define NVRAMRWLOCKASSERTEXCLUSIVE(lock)                \
-({                                                      \
-	if (SAFE_TO_LOCK())                                 \
-	        IORWLockAssert(lock, kIORWLockAssertWrite); \
-})
-
-// MOD = Write, Delete
-// RST = Reset, Obliterate
-// RD  = Read
-// DEL = Delete
-#define OP_RD          ((1 << kIONVRAMOperationRead))
-#define OP_RST         ((1 << kIONVRAMOperationObliterate) | (1 << kIONVRAMOperationReset))
-#define OP_DEL         ((1 << kIONVRAMOperationDelete))
-#define OP_MOD         ((1 << kIONVRAMOperationWrite)      | OP_DEL)
-#define OP_MOD_RD      (OP_RD  | OP_MOD)
-#define OP_MOD_RST     (OP_MOD | OP_RST)
-
-enum NVRAMVersion {
-	kNVRAMVersionUnknown,
-	kNVRAMVersion1,       // Legacy, banks, 0x800 common partition size
-	kNVRAMVersion2,       // V1 but with (0x2000 - sizeof(struct apple_nvram_header) - sizeof(struct chrp_nvram_header)) common region
-	kNVRAMVersion3,       // New EFI based format
-	kNVRAMVersionMax
+enum NVRAMPartitionType {
+	kIONVRAMPartitionSystem,
+	kIONVRAMPartitionCommon
 };
+
+typedef struct {
+	NVRAMPartitionType        type;
+	UInt32                    offset;
+	UInt32                    size;
+	OSSharedPtr<OSDictionary> &dict;
+	UInt8                     *image;
+} NVRAMRegionInfo;
 
 // Guid for Apple System Boot variables
 // 40A0DDD2-77F8-4392-B4A3-1E7304206516
@@ -192,28 +163,33 @@
 // 7C436110-AB2A-4BBB-A880-FE41995C9F82
 UUID_DEFINE(gAppleNVRAMGuid, 0x7C, 0x43, 0x61, 0x10, 0xAB, 0x2A, 0x4B, 0xBB, 0xA8, 0x80, 0xFE, 0x41, 0x99, 0x5C, 0x9F, 0x82);
 
-// Wifi NVRAM namespace
-// 36C28AB5-6566-4C50-9EBD-CBB920F83843
-UUID_DEFINE(gAppleWifiGuid, 0x36, 0xC2, 0x8A, 0xB5, 0x65, 0x66, 0x4C, 0x50, 0x9E, 0xBD, 0xCB, 0xB9, 0x20, 0xF8, 0x38, 0x43);
-
-// Prefix for kernel-only variables
-#define KERNEL_ONLY_VAR_NAME_PREFIX "krn."
-
-static TUNABLE(uint8_t, gNVRAMLogging, "nvram-log", kIONVRAMNoLogs);
-static TUNABLE(bool, gRestoreBoot, "-restore", false);
+static bool gNVRAMLogging = false;
 static bool gInternalBuild = false;
 
-// IONVRAMSystemVariableListInternal:
-// Used for internal builds only
-// "force-lock-bits" used by fwam over ssh nvram to device so they are unable to use entitlements
-// "stress-rack" used in SEG stress-rack restore prdocs
-#define IONVRAMSystemVariableListInternal IONVRAMSystemVariableList, \
-	                                      "force-lock-bits", \
-	                                      "stress-rack"
-
 // allowlist variables from macboot that need to be set/get from system region if present
-static const char * const gNVRAMSystemList[] = { IONVRAMSystemVariableList, nullptr };
-static const char * const gNVRAMSystemListInternal[] = { IONVRAMSystemVariableListInternal, nullptr };
+static const char * const gNVRAMSystemList[] = {
+	"allow-root-hash-mismatch",
+	"auto-boot",
+	"auto-boot-halt-stage",
+	"base-system-path",
+	"boot-args",
+	"boot-command",
+	"boot-image",
+	"bootdelay",
+	"com.apple.System.boot-nonce",
+	"darkboot",
+	"emu",
+	"one-time-boot-command", // Needed for diags customer install flows
+	"policy-nonce-digests",
+	"prevent-restores", // Keep for factory <rdar://problem/70476321>
+	"prev-lang:kbd",
+	"root-live-fs",
+	"StartupMute", // Set by customers via nvram tool
+	"SystemAudioVolume",
+	"SystemAudioVolumeExtension",
+	"SystemAudioVolumeSaved",
+	nullptr
+};
 
 typedef struct {
 	const char *name;
@@ -243,7 +219,6 @@
 	{"input-device", kOFVariableTypeString},
 	{"input-device-1", kOFVariableTypeString},
 	{"little-endian?", kOFVariableTypeBoolean},
-	{"ldm", kOFVariableTypeBoolean},
 	{"load-base", kOFVariableTypeNumber},
 	{"mouse-device", kOFVariableTypeString},
 	{"nvramrc", kOFVariableTypeString},
@@ -266,11 +241,7 @@
 	{"use-nvramrc?", kOFVariableTypeBoolean},
 	{"virt-base", kOFVariableTypeNumber},
 	{"virt-size", kOFVariableTypeNumber},
-	// Variables used for testing
-	{"test-bool", kOFVariableTypeBoolean},
-	{"test-num", kOFVariableTypeNumber},
-	{"test-str", kOFVariableTypeString},
-	{"test-data", kOFVariableTypeData},
+
 #if !defined(__x86_64__)
 	{"acc-cm-override-charger-count", kOFVariableTypeNumber},
 	{"acc-cm-override-count", kOFVariableTypeNumber},
@@ -291,9 +262,6 @@
 		uint64_t NeverAllowedToDelete :1;
 		uint64_t SystemReadHidden     :1;
 		uint64_t FullAccess           :1;
-		uint64_t InternalOnly         :1;
-		uint64_t TestingOnly          :1;
-		uint64_t RestoreModifyOnly    :1;
 		uint64_t Reserved:57;
 	} Bits;
 	uint64_t Uint64;
@@ -311,15 +279,6 @@
 	 .p.Bits.NeverAllowedToDelete = 1},
 	{"boot-image", .p.Bits.UserWrite = 1},
 	{"com.apple.System.fp-state", .p.Bits.KernelOnly = 1},
-	{"enable-ephdm", .p.Bits.RestoreModifyOnly = 1},
-	{"fm-account-masked", .p.Bits.RootRequired = 1,
-	 .p.Bits.NeverAllowedToDelete = 1},
-	{"fm-activation-locked", .p.Bits.RootRequired = 1,
-	 .p.Bits.NeverAllowedToDelete = 1},
-	{"fm-spkeys", .p.Bits.RootRequired = 1,
-	 .p.Bits.NeverAllowedToDelete = 1},
-	{"fm-spstatus", .p.Bits.RootRequired = 1,
-	 .p.Bits.NeverAllowedToDelete = 1},
 	{"policy-nonce-digests", .p.Bits.ResetNVRAMOnlyDelete = 1}, // Deleting this via user triggered obliterate leave J273a unable to boot
 	{"recoveryos-passcode-blob", .p.Bits.SystemReadHidden = 1},
 	{"security-password", .p.Bits.RootRequired = 1},
@@ -331,79 +290,14 @@
 	{"acc-mb-ld-lifetime", .p.Bits.KernelOnly = 1},
 	{"backlight-level", .p.Bits.UserWrite = 1},
 	{"backlight-nits", .p.Bits.UserWrite = 1},
-	{"ldm", .p.Bits.KernelOnly = 1},
 	{"com.apple.System.boot-nonce", .p.Bits.KernelOnly = 1},
 	{"com.apple.System.sep.art", .p.Bits.KernelOnly = 1},
 	{"darkboot", .p.Bits.UserWrite = 1},
 	{"nonce-seeds", .p.Bits.KernelOnly = 1},
 #endif /* !defined(__x86_64__) */
-	// Variables used for testing permissions
-	{"testSysReadHidden", .p.Bits.SystemReadHidden = 1,
-	 .p.Bits.TestingOnly = 1},
-	{"testKernelOnly", .p.Bits.KernelOnly = 1,
-	 .p.Bits.TestingOnly = 1},
-	{"testResetOnlyDel", .p.Bits.ResetNVRAMOnlyDelete = 1,
-	 .p.Bits.TestingOnly = 1},
-	{"testNeverDel", .p.Bits.NeverAllowedToDelete = 1,
-	 .p.Bits.TestingOnly = 1},
-	{"testUserWrite", .p.Bits.UserWrite = 1,
-	 .p.Bits.TestingOnly = 1},
-	{"testRootReq", .p.Bits.RootRequired = 1,
-	 .p.Bits.TestingOnly = 1},
-	{"reclaim-int", .p.Bits.InternalOnly = 1},
+
 	{nullptr, {.Bits.FullAccess = 1}} // Default access
 };
-
-typedef struct {
-	const uint8_t checkOp;
-	const uuid_t  *varGuid;
-	const char    *varName;
-	const char    *varEntitlement;
-} VariableEntitlementEntry;
-
-// variable-guid pair entries that require entitlement check to do specified nvram operations
-static const
-VariableEntitlementEntry gVariableEntitlements[] = {
-	{OP_MOD_RST, &gAppleNVRAMGuid, "ownership-warning", "com.apple.private.iokit.ddl-write"},
-	{OP_MOD, &gAppleSystemVariableGuid, "BluetoothInfo", "com.apple.private.iokit.nvram-bluetooth"},
-	{OP_MOD, &gAppleSystemVariableGuid, "BluetoothUHEDevices", "com.apple.private.iokit.nvram-bluetooth"},
-	{OP_MOD, &gAppleNVRAMGuid, "bluetoothExternalDongleFailed", "com.apple.private.iokit.nvram-bluetooth"},
-	{OP_MOD, &gAppleNVRAMGuid, "bluetoothInternalControllerInfo", "com.apple.private.iokit.nvram-bluetooth"},
-	{OP_RD, &gAppleSystemVariableGuid, "current-network", "com.apple.private.security.nvram.wifi-psks"},
-	{OP_RD, &gAppleWifiGuid, "current-network", "com.apple.private.security.nvram.wifi-psks"},
-	{OP_RD, &gAppleSystemVariableGuid, "preferred-networks", "com.apple.private.security.nvram.wifi-psks"},
-	{OP_RD, &gAppleWifiGuid, "preferred-networks", "com.apple.private.security.nvram.wifi-psks"},
-	{OP_RD, &gAppleSystemVariableGuid, "preferred-count", "com.apple.private.security.nvram.wifi-psks"},
-	{OP_RD, &gAppleWifiGuid, "preferred-count", "com.apple.private.security.nvram.wifi-psks"},
-	{OP_MOD_RD, &gAppleSystemVariableGuid, "fmm-mobileme-token-FMM", "com.apple.private.security.nvram.fmm"},
-	{OP_MOD_RD, &gAppleNVRAMGuid, "fmm-mobileme-token-FMM", "com.apple.private.security.nvram.fmm"},
-	{OP_MOD_RD, &gAppleSystemVariableGuid, "fmm-mobileme-token-FMM-BridgeHasAccount", "com.apple.private.security.nvram.fmm"},
-	{OP_MOD_RD, &gAppleNVRAMGuid, "fmm-mobileme-token-FMM-BridgeHasAccount", "com.apple.private.security.nvram.fmm"},
-	{OP_MOD_RD, &gAppleSystemVariableGuid, "fmm-computer-name", "com.apple.private.security.nvram.fmm"},
-	{OP_MOD_RD, &gAppleNVRAMGuid, "fmm-computer-name", "com.apple.private.security.nvram.fmm"},
-	{OP_MOD, &gAppleSystemVariableGuid, "rdma-enable", "com.apple.private.iokit.rdma"},
-	{OP_MOD, &gAppleNVRAMGuid, "rdma-enable", "com.apple.private.iokit.rdma"},
-	// Variables used for testing entitlement
-	{OP_MOD_RST, &gAppleNVRAMGuid, "testEntModRst", "com.apple.private.iokit.testEntModRst"},
-	{OP_MOD_RST, &gAppleSystemVariableGuid, "testEntModRstSys", "com.apple.private.iokit.testEntModRst"},
-	{OP_RST, &gAppleNVRAMGuid, "testEntRst", "com.apple.private.iokit.testEntRst"},
-	{OP_RST, &gAppleSystemVariableGuid, "testEntRstSys", "com.apple.private.iokit.testEntRst"},
-	{OP_RD, &gAppleNVRAMGuid, "testEntRd", "com.apple.private.iokit.testEntRd"},
-	{OP_RD, &gAppleSystemVariableGuid, "testEntRdSys", "com.apple.private.iokit.testEntRd"},
-	{OP_DEL, &gAppleNVRAMGuid, "testEntDel", "com.apple.private.iokit.testEntDel"},
-	{OP_DEL, &gAppleSystemVariableGuid, "testEntDelSys", "com.apple.private.iokit.testEntDel"},
-	{0, &UUID_NULL, nullptr, nullptr}
-};
-
-static NVRAMPartitionType
-getPartitionTypeForGUID(const uuid_t guid)
-{
-	if (uuid_compare(guid, gAppleSystemVariableGuid) == 0) {
-		return kIONVRAMPartitionSystem;
-	} else {
-		return kIONVRAMPartitionCommon;
-	}
-}
 
 static IONVRAMVariableType
 getVariableType(const char *propName)
@@ -447,10 +341,9 @@
 variableInAllowList(const char *varName)
 {
 	unsigned int i = 0;
-	const char * const *list = gInternalBuild ? gNVRAMSystemListInternal : gNVRAMSystemList;
-
-	while (list[i] != nullptr) {
-		if (strcmp(varName, list[i]) == 0) {
+
+	while (gNVRAMSystemList[i] != nullptr) {
+		if (strcmp(varName, gNVRAMSystemList[i]) == 0) {
 			return true;
 		}
 		i++;
@@ -460,10 +353,14 @@
 }
 
 static bool
-verifyWriteSizeLimit(const uuid_t varGuid, const char *variableName, size_t propDataSize)
+verifyWriteSizeLimit(const uuid_t *varGuid, const char *variableName, size_t propDataSize)
 {
 	if (variableInAllowList(variableName)) {
-		return propDataSize <= BOOT_LINE_LENGTH;
+		if (strnstr(variableName, "breadcrumbs", strlen(variableName)) != NULL) {
+			return propDataSize <= 1024;
+		} else {
+			return propDataSize <= 768;
+		}
 	}
 
 	return true;
@@ -484,13 +381,107 @@
 		return "Obliterate";
 	case kIONVRAMOperationReset:
 		return "Reset";
-	case kIONVRAMOperationInit:
-		return "Init";
 	default:
 		return "Unknown";
 	}
 }
 #endif
+
+static bool
+verifyPermission(IONVRAMOperation op, const uuid_t *varGuid, const char *varName)
+{
+	VariablePermission perm;
+	bool kernel, writeEntitled, readEntitled, allowList, systemGuid, systemEntitled, systemInternalEntitled, systemAllow, systemReadHiddenAllow;
+	bool admin = false;
+	bool ok = false;
+
+	perm = getVariablePermission(varName);
+
+	kernel = current_task() == kernel_task;
+
+	if (perm.Bits.KernelOnly) {
+		DEBUG_INFO("KernelOnly access for %s, kernel=%d\n", varName, kernel);
+		ok = kernel;
+		goto exit;
+	}
+
+	allowList              = variableInAllowList(varName);
+	systemGuid             = uuid_compare(*varGuid, gAppleSystemVariableGuid) == 0;
+	admin                  = IOUserClient::clientHasPrivilege(current_task(), kIONVRAMPrivilege) == kIOReturnSuccess;
+	writeEntitled          = IOTaskHasEntitlement(current_task(), kIONVRAMWriteAccessKey);
+	readEntitled           = IOTaskHasEntitlement(current_task(), kIONVRAMReadAccessKey);
+	systemEntitled         = IOTaskHasEntitlement(current_task(), kIONVRAMSystemAllowKey);
+	systemInternalEntitled = IOTaskHasEntitlement(current_task(), kIONVRAMSystemInternalAllowKey);
+	systemReadHiddenAllow  = IOTaskHasEntitlement(current_task(), kIONVRAMSystemHiddenAllowKey);
+
+	systemAllow = systemEntitled || (systemInternalEntitled && gInternalBuild) || kernel;
+
+	switch (op) {
+	case kIONVRAMOperationRead:
+		if (systemGuid && perm.Bits.SystemReadHidden) {
+			ok = systemReadHiddenAllow;
+		} else if (kernel || admin || readEntitled || perm.Bits.FullAccess) {
+			ok = true;
+		}
+		break;
+
+	case kIONVRAMOperationWrite:
+		if (kernel || perm.Bits.UserWrite || admin || writeEntitled) {
+			if (systemGuid) {
+				if (allowList) {
+					if (!systemAllow) {
+						DEBUG_ERROR("Allowed write to system region when NOT entitled for %s\n", varName);
+					}
+				} else if (!systemAllow) {
+					DEBUG_ERROR("Not entitled for system region writes for %s\n", varName);
+					break;
+				}
+			}
+			ok = true;
+		}
+		break;
+
+	case kIONVRAMOperationDelete:
+	case kIONVRAMOperationObliterate:
+	case kIONVRAMOperationReset:
+		if (perm.Bits.NeverAllowedToDelete) {
+			DEBUG_INFO("Never allowed to delete %s\n", varName);
+			break;
+		} else if ((op == kIONVRAMOperationObliterate) && perm.Bits.ResetNVRAMOnlyDelete) {
+			DEBUG_INFO("Not allowed to obliterate %s\n", varName);
+			break;
+		} else if ((op == kIONVRAMOperationDelete) && perm.Bits.ResetNVRAMOnlyDelete) {
+			DEBUG_INFO("Only allowed to delete %s via NVRAM reset\n", varName);
+			break;
+		}
+
+		if (kernel || perm.Bits.UserWrite || admin || writeEntitled) {
+			if (systemGuid) {
+				if (allowList) {
+					if (!systemAllow) {
+						DEBUG_ERROR("Allowed delete to system region when NOT entitled for %s\n", varName);
+					}
+				} else if (!systemAllow) {
+					DEBUG_ERROR("Not entitled for system region deletes for %s\n", varName);
+					break;
+				}
+			}
+			ok = true;
+		}
+		break;
+	}
+
+exit:
+	DEBUG_INFO("Permission for %s of %s %s: kernel=%d, admin=%d, writeEntitled=%d, readEntitled=%d, systemGuid=%d, systemEntitled=%d, systemInternalEntitled=%d, systemReadHiddenAllow=%d, UserWrite=%d\n",
+	    getNVRAMOpString(op), varName, ok ? "granted" : "denied", kernel, admin, writeEntitled, readEntitled, systemGuid, systemEntitled, systemInternalEntitled, systemReadHiddenAllow, perm.Bits.UserWrite);
+	return ok;
+}
+
+static bool
+verifyPermission(IONVRAMOperation op, const uuid_t *varGuid, const OSSymbol *varName)
+{
+	return verifyPermission(op, varGuid, varName->getCStringNoCopy());
+}
 
 /*
  * Parse a variable name of the form "GUID:name".
@@ -526,568 +517,18 @@
 		*nameResult = name;
 	}
 
-	return ok;
-}
-
-static bool
-parseVariableName(const OSSymbol *key, uuid_t *guidResult, const char **nameResult)
-{
-	return parseVariableName(key->getCStringNoCopy(), guidResult, nameResult);
-}
-
-/**
- * @brief Translates(if needed) varGuid and stores it in destGuid
- *
- * @param varGuid       guid to translate
- * @param variableName  variable name attached to the guid
- * @param destGuid      translated guid is saved here
- * @param systemActive  boolean to indicate if it has system partition size > 0
- */
-static void
-translateGUID(const uuid_t varGuid, const char *variableName, uuid_t destGuid, bool systemActive, bool log)
-{
-	if (varGuid == nullptr || variableName == nullptr || destGuid == nullptr) {
-		DEBUG_ERROR("nullptr passed as an argument\n");
-		return;
-	}
-
-	bool systemGuid = uuid_compare(varGuid, gAppleSystemVariableGuid) == 0;
-
-	if (systemActive) {
-		if (variableInAllowList(variableName)) {
-			DEBUG_INFO_IF(log, "Using system GUID due to allow list\n");
-			uuid_copy(destGuid, gAppleSystemVariableGuid);
-		} else if (systemGuid) {
-			DEBUG_INFO_IF(log, "System GUID used\n");
-			uuid_copy(destGuid, gAppleSystemVariableGuid);
-		} else {
-			DEBUG_INFO_IF(log, "Use given guid\n");
-			uuid_copy(destGuid, varGuid);
-		}
-	} else if (systemGuid) {
-		DEBUG_INFO_IF(log, "Overriding to Apple guid\n");
-		uuid_copy(destGuid, gAppleNVRAMGuid);
-	} else {
-		DEBUG_INFO_IF(log, "Use given guid\n");
-		uuid_copy(destGuid, varGuid);
-	}
-}
-
-/**
- * @brief Checks if the variable-guid(translated) pair is present in gVariableEntitlements and if so,
- *        does it have the required entitlement for the NVRAM operation passed in
- *
- * @param varGuid       guid for the variable to be checked, this gets translated by translateGUID
- * @param varName       variable name
- * @param op            NVRAM operation
- * @param systemActive  used to pass into translateGUID to get the correct guid to check against
- * @param veChecked     if variable entitlement is checked, this is set to true
- * @return true         if variable wasn't present in gVariableEntitlements,
- *                      entitlement check wasn't required for operation passed in,
- *                      or if entitlement check returned true
- * @return false        if varName/varGuid/veChecked was NULL or if entitlement check returned false
- */
-static bool
-verifyVarEntitlement(const uuid_t varGuid, const char *varName, IONVRAMOperation op, bool systemActive, bool *veChecked, bool log)
-{
-	if (varGuid == nullptr || varName == nullptr || veChecked == nullptr) {
-		DEBUG_ERROR("nullptr passed as an argument\n");
-		return false;
-	}
-
-	uuid_t translatedGuid;
-	const VariableEntitlementEntry *entry;
-	*veChecked = false;
-
-	translateGUID(varGuid, varName, translatedGuid, systemActive, log);
-
-	entry = gVariableEntitlements;
-	while ((entry != nullptr) && (entry->varName != nullptr)) {
-		if ((strcmp(entry->varName, varName) == 0) && (uuid_compare(translatedGuid, *(entry->varGuid)) == 0)) {
-			// check if task entitlement check is required for this operation
-			if (entry->checkOp & (1 << op)) {
-				*veChecked = true;
-				DEBUG_INFO_IF(log, "Checking entitlement %s for %s for operation %s\n", entry->varEntitlement, varName, getNVRAMOpString(op));
-				return IOCurrentTaskHasEntitlement(entry->varEntitlement);
-			}
-			break;
-		}
-		entry++;
-	}
-
-	return true;
-}
-
-static bool
-kernelOnlyVar(const char *varName)
-{
-	if (strncmp(varName, KERNEL_ONLY_VAR_NAME_PREFIX, sizeof(KERNEL_ONLY_VAR_NAME_PREFIX) - 1) == 0) {
-		return true;
-	}
-
 	return false;
-}
-
-static bool
-verifyPermission(IONVRAMOperation op, const uuid_t varGuid, const char *varName, const bool systemActive, bool log)
-{
-	VariablePermission perm;
-	bool kernel, varEntitled, writeEntitled = false, readEntitled = false, allowList, systemGuid = false, systemEntitled = false, systemInternalEntitled = false, systemAllow, systemReadHiddenAllow = false;
-	bool admin = false;
-	bool ok = false;
-
-	if (verifyVarEntitlement(varGuid, varName, op, systemActive, &varEntitled, log) == false) {
-		goto exit;
-	}
-
-	perm = getVariablePermission(varName);
-
-	kernel = current_task() == kernel_task;
-	if (perm.Bits.KernelOnly || kernelOnlyVar(varName)) {
-		DEBUG_INFO_IF(log, "KernelOnly access for %s, kernel=%d\n", varName, kernel);
-		ok = kernel;
-		goto exit;
-	}
-
-	if (perm.Bits.RestoreModifyOnly && (OP_MOD & (1 << op))) {
-		DEBUG_INFO_IF(log, "RestoreModifyOnly access for %s, gRestoreBoot=%d\n", varName, gRestoreBoot);
-		ok = gRestoreBoot;
-		goto exit;
-	}
-
-	if (perm.Bits.InternalOnly && !gInternalBuild) {
-		DEBUG_INFO_IF(log, "InternalOnly access for %s, gInternalBuild=%d\n", varName, gInternalBuild);
-		goto exit;
-	}
-
-	allowList              = variableInAllowList(varName);
-	systemGuid             = uuid_compare(varGuid, gAppleSystemVariableGuid) == 0;
-	admin                  = IOUserClient::clientHasPrivilege(current_task(), kIONVRAMPrivilege) == kIOReturnSuccess;
-	writeEntitled          = IOCurrentTaskHasEntitlement(kIONVRAMWriteAccessKey);
-	readEntitled           = IOCurrentTaskHasEntitlement(kIONVRAMReadAccessKey);
-	systemEntitled         = IOCurrentTaskHasEntitlement(kIONVRAMSystemAllowKey);
-	systemInternalEntitled = IOCurrentTaskHasEntitlement(kIONVRAMSystemInternalAllowKey);
-	systemReadHiddenAllow  = IOCurrentTaskHasEntitlement(kIONVRAMSystemHiddenAllowKey);
-
-	systemAllow = systemEntitled || (systemInternalEntitled && gInternalBuild) || kernel;
-
-	switch (op) {
-	case kIONVRAMOperationRead:
-		if (systemGuid && perm.Bits.SystemReadHidden) {
-			ok = systemReadHiddenAllow;
-		} else if (kernel || admin || readEntitled || perm.Bits.FullAccess || varEntitled) {
-			ok = true;
-		}
-		break;
-
-	case kIONVRAMOperationWrite:
-		if (kernel || perm.Bits.UserWrite || admin || writeEntitled || varEntitled) {
-			if (systemGuid) {
-				if (allowList) {
-					if (!systemAllow) {
-						DEBUG_ERROR("Allowed write to system region when NOT entitled for %s\n", varName);
-					}
-				} else if (varEntitled) {
-					DEBUG_INFO_IF(log, "Allowed write to system region using variable specific entitlement for %s\n", varName);
-				} else if (!systemAllow) {
-					DEBUG_ERROR("Not entitled for system region writes for %s\n", varName);
-					break;
-				}
-			}
-			ok = true;
-		}
-		break;
-
-	case kIONVRAMOperationDelete:
-	case kIONVRAMOperationObliterate:
-	case kIONVRAMOperationReset:
-		if (perm.Bits.NeverAllowedToDelete) {
-			DEBUG_INFO_IF(log, "Never allowed to delete %s\n", varName);
-			break;
-		} else if ((op == kIONVRAMOperationObliterate) && perm.Bits.ResetNVRAMOnlyDelete) {
-			DEBUG_INFO_IF(log, "Not allowed to obliterate %s\n", varName);
-			break;
-		} else if ((op == kIONVRAMOperationDelete) && perm.Bits.ResetNVRAMOnlyDelete) {
-			DEBUG_INFO_IF(log, "Only allowed to delete %s via NVRAM reset\n", varName);
-			break;
-		}
-
-		if (kernel || perm.Bits.UserWrite || admin || writeEntitled || varEntitled) {
-			if (systemGuid) {
-				if (allowList) {
-					if (!systemAllow) {
-						DEBUG_ERROR("Allowed delete to system region when NOT entitled for %s\n", varName);
-					}
-				} else if (varEntitled) {
-					DEBUG_INFO_IF(log, "Allowed delete to system region using variable specific entitlement for %s\n", varName);
-				} else if (!systemAllow) {
-					DEBUG_ERROR("Not entitled for system region deletes for %s\n", varName);
-					break;
-				}
-			}
-			ok = true;
-		}
-		break;
-
-	case kIONVRAMOperationInit:
-		break;
-	}
-
-exit:
-	DEBUG_INFO_IF(log, "Permission for %s of %s %s: I=%d R=%d kern=%d, adm=%d, wE=%d, rE=%d, sG=%d, sEd=%d, sIEd=%d, sRHA=%d, UW=%d, vE=%d\n", getNVRAMOpString(op), varName, ok ? "granted" : "denied",
-	    gInternalBuild, gRestoreBoot, kernel, admin, writeEntitled, readEntitled, systemGuid, systemEntitled, systemInternalEntitled, systemReadHiddenAllow, perm.Bits.UserWrite, varEntitled);
-
-	return ok;
-}
-
-static bool
-verifyPermission(IONVRAMOperation op, const OSSymbol *canonicalKey, const bool systemActive)
-{
-	const char *varName;
-	uuid_t varGuid;
-
-	parseVariableName(canonicalKey->getCStringNoCopy(), &varGuid, &varName);
-
-	return verifyPermission(op, varGuid, varName, systemActive, true);
 }
 
 static bool
 skipKey(const OSSymbol *aKey)
 {
-	return aKey->isEqualTo(kIORegistryEntryAllowableSetPropertiesKey) ||
-	       aKey->isEqualTo(kIORegistryEntryDefaultLockingSetPropertiesKey) ||
-	       aKey->isEqualTo(kIOClassNameOverrideKey) ||
+	return aKey->isEqualTo(kIOClassNameOverrideKey) ||
 	       aKey->isEqualTo(kIOBSDNameKey) ||
 	       aKey->isEqualTo(kIOBSDNamesKey) ||
 	       aKey->isEqualTo(kIOBSDMajorKey) ||
 	       aKey->isEqualTo(kIOBSDMinorKey) ||
-	       aKey->isEqualTo(kIOBSDUnitKey) ||
-	       aKey->isEqualTo(kIOUserServicePropertiesKey) ||
-	       aKey->isEqualTo(kIOExclaveAssignedKey) ||
-	       aKey->isEqualTo(kIOMatchCategoryKey) ||
-	       aKey->isEqualTo(kIOBusyInterest);
-}
-
-static OSSharedPtr<const OSSymbol>
-keyWithGuidAndCString(const uuid_t guid, const char * cstring)
-{
-	size_t                      length;
-	OSSharedPtr<const OSSymbol> symbolObj;
-	char                        *canonicalString;
-
-	length = sizeof(uuid_string_t) - 1 + sizeof(':') + strlen(cstring) + 1;
-
-	canonicalString = (char *) IOMallocZeroData(length);
-	if (canonicalString == nullptr) {
-		return NULL;
-	}
-
-	uuid_unparse(guid, *((uuid_string_t*)canonicalString));
-	canonicalString[sizeof(uuid_string_t) - 1] = ':';
-
-	strlcpy(&canonicalString[sizeof(uuid_string_t)], cstring, length - sizeof(uuid_string_t));
-
-	symbolObj = OSSymbol::withCString(canonicalString);
-	IOFreeData(canonicalString, length);
-
-	return symbolObj;
-}
-
-static void
-dumpDict(OSSharedPtr<OSDictionary> dict)
-{
-	const OSSymbol                    *key;
-	OSSharedPtr<OSCollectionIterator> iter;
-	unsigned int                      count = 0;
-
-	iter = OSCollectionIterator::withCollection(dict.get());
-	require_action(iter, exit, DEBUG_ERROR("Failed to create iterator\n"));
-
-	DEBUG_INFO("Dumping dict...\n");
-	while ((key = OSDynamicCast(OSSymbol, iter->getNextObject()))) {
-		count++;
-		DEBUG_INFO("%u: %s\n", count, key->getCStringNoCopy());
-	}
-exit:
-	return;
-}
-
-static void
-dumpData(const char *name, OSSharedPtr<OSData> propData)
-{
-	if (!IS_LOG_BIT_SET(kIONVRAMDataHexDump) || !propData) {
-		return;
-	}
-
-	uint8_t *dataBuf = (uint8_t *)propData->getBytesNoCopy();
-	size_t propDataSize = propData->getLength();
-
-	if (dataBuf == nullptr || propDataSize == 0) {
-		return;
-	}
-
-	IOLog("%s:%s:%u - %s: ", __FILE_NAME__, __FUNCTION__, __LINE__, name);
-	for (size_t i = 0; i < propDataSize; i++) {
-		// if printable character, use that
-		if ((dataBuf[i] >= 0x20 && dataBuf[i] <= 0x7e) && dataBuf[i] != '%') {
-			IOLog("%c", dataBuf[i]);
-		} else {
-			IOLog("%%%02x", dataBuf[i]);
-		}
-	}
-	IOLog("\n");
-}
-
-
-typedef struct {
-	const char            *name;
-	OSSharedPtr<OSObject> value;
-} ephDMAllowListEntry;
-
-// common region variables to preserve on ephemeral boot
-static
-ephDMAllowListEntry ephDMEntries[] = {
-	// Mobile Obliteration clears the following variables after it runs
-	{ .name = "oblit-begins" },
-	{ .name = "orig-oblit" },
-	{ .name = "oblit-failure" },
-	{ .name = "oblit-inprogress" },
-	{ .name = "obliteration" },
-	// darwin-init is used for configuring internal builds
-	{ .name = "darwin-init" },
-	{ .name = "darwin-init-system" }
-};
-
-// ************************** IODTNVRAMPlatformNotifier ****************************
-// private IOService based class for passing notifications to IODTNVRAM
-
-class IODTNVRAMPlatformNotifier : public IOService
-{
-	OSDeclareDefaultStructors(IODTNVRAMPlatformNotifier)
-private:
-	IODTNVRAM *_provider;
-
-public:
-	bool start(IOService * provider) APPLE_KEXT_OVERRIDE;
-
-	virtual IOReturn callPlatformFunction( const OSSymbol * functionName,
-	    bool waitForFunction,
-	    void *param1, void *param2,
-	    void *param3, void *param4 ) APPLE_KEXT_OVERRIDE;
-};
-
-OSDefineMetaClassAndStructors(IODTNVRAMPlatformNotifier, IOService)
-
-bool
-IODTNVRAMPlatformNotifier::start(IOService * provider)
-{
-	OSSharedPtr<OSSerializer> serializer;
-	OSSharedPtr<OSNumber> value = OSNumber::withNumber(1000, 32);
-
-	_provider = OSDynamicCast(IODTNVRAM, provider);
-	require(_provider != nullptr, error);
-
-	setProperty(gIOPlatformWakeActionKey, value.get());
-
-	require(super::start(provider), error);
-
-	registerService();
-
-	return true;
-
-error:
-	stop(provider);
-
-	return false;
-}
-
-#include <IOKit/IOHibernatePrivate.h>
-#include <IOKit/pwr_mgt/RootDomain.h>
-static const OSSharedPtr<const OSSymbol> gIOHibernateStateKey = OSSymbol::withCString(kIOHibernateStateKey);
-
-static uint32_t
-hibernateState(void)
-{
-	OSSharedPtr<OSData> data = OSDynamicPtrCast<OSData>(IOService::getPMRootDomain()->copyProperty(gIOHibernateStateKey.get()->getCStringNoCopy()));
-	uint32_t hibernateState = 0;
-	if ((data != NULL) && (data->getLength() == sizeof(hibernateState))) {
-		memcpy(&hibernateState, data->getBytesNoCopy(), sizeof(hibernateState));
-	}
-	return hibernateState;
-}
-
-IOReturn
-IODTNVRAMPlatformNotifier::callPlatformFunction( const OSSymbol * functionName,
-    bool waitForFunction,
-    void *param1, void *param2,
-    void *param3, void *param4 )
-{
-	if ((functionName == gIOPlatformWakeActionKey) &&
-	    (hibernateState() == kIOHibernateStateWakingFromHibernate)) {
-		DEBUG_INFO("waking from hibernate\n");
-		_provider->reload();
-		return kIOReturnSuccess;
-	}
-
-	return super::callPlatformFunction(functionName, waitForFunction, param1, param2, param3, param4);
-}
-
-
-// ************************** IODTNVRAMDiags ****************************
-// private IOService based class for passing notifications to IODTNVRAM
-#define kIODTNVRAMDiagsStatsKey   "Stats"
-#define kIODTNVRAMDiagsInitKey    "Init"
-#define kIODTNVRAMDiagsReadKey    "Read"
-#define kIODTNVRAMDiagsWriteKey   "Write"
-#define kIODTNVRAMDiagsDeleteKey  "Delete"
-#define kIODTNVRAMDiagsNameKey    "Name"
-#define kIODTNVRAMDiagsSizeKey    "Size"
-#define kIODTNVRAMDiagsPresentKey "Present"
-
-// private IOService based class for publishing diagnostic info for IODTNVRAM
-class IODTNVRAMDiags : public IOService
-{
-	OSDeclareDefaultStructors(IODTNVRAMDiags)
-private:
-	IODTNVRAM                 *_provider;
-	IORWLock                  *_diagLock;
-	OSSharedPtr<OSDictionary> _stats;
-
-	bool serializeStats(void *, OSSerialize * serializer);
-
-public:
-	bool start(IOService * provider) APPLE_KEXT_OVERRIDE;
-	void logVariable(NVRAMPartitionType region, IONVRAMOperation op, const char *name, void *data = nullptr, void *offset = nullptr);
-};
-
-OSDefineMetaClassAndStructors(IODTNVRAMDiags, IOService)
-
-bool
-IODTNVRAMDiags::start(IOService * provider)
-{
-	OSSharedPtr<OSSerializer> serializer;
-
-	_provider = OSDynamicCast(IODTNVRAM, provider);
-	require(_provider != nullptr, error);
-
-	require(super::start(provider), error);
-
-	_diagLock = IORWLockAlloc();
-	require(_diagLock != nullptr, error);
-
-	_stats = OSDictionary::withCapacity(1);
-	require(_stats != nullptr, error);
-
-	serializer = OSSerializer::forTarget(this, OSMemberFunctionCast(OSSerializerCallback, this, &IODTNVRAMDiags::serializeStats));
-	require(serializer != nullptr, error);
-
-	setProperty(kIODTNVRAMDiagsStatsKey, serializer.get());
-
-	registerService();
-
-	return true;
-
-error:
-	stop(provider);
-
-	return false;
-}
-
-void
-IODTNVRAMDiags::logVariable(NVRAMPartitionType region, IONVRAMOperation op, const char *name, void *data, void *offset)
-{
-	// "Stats"        : OSDictionary
-	// - "XX:varName" : OSDictionary, XX is the region value prefix to distinguish which dictionary the variable is in
-	//   - "Init"     : OSNumber variable offset (in the proxy image passed via EDT) if variable is present at initialization (unserialize)
-	//   - "Read"     : OSNumber count
-	//   - "Write"    : OSNumber count
-	//   - "Delete"   : OSNumber count
-	//   - "Size"     : OSNumber data size, latest size from either init or write
-	//   - "Present"  : OSBoolean True/False if variable is present or not
-	char                      *entryKey;
-	size_t                    entryKeySize;
-	OSSharedPtr<OSDictionary> existingEntry;
-	OSSharedPtr<OSNumber>     currentCount;
-	OSSharedPtr<OSNumber>     varSize;
-	OSSharedPtr<OSNumber>     varOffset;
-	const char                *opCountKey = nullptr;
-
-	entryKeySize = strlen("XX:") + strlen(name) +  1;
-	entryKey = IONewData(char, entryKeySize);
-	require(entryKey, exit);
-
-	snprintf(entryKey, entryKeySize, "%02X:%s", region, name);
-
-	NVRAMWRITELOCK(_diagLock);
-	existingEntry.reset(OSDynamicCast(OSDictionary, _stats->getObject(entryKey)), OSRetain);
-
-	if (existingEntry == nullptr) {
-		existingEntry = OSDictionary::withCapacity(4);
-	}
-
-	switch (op) {
-	case kIONVRAMOperationRead:
-		opCountKey = kIODTNVRAMDiagsReadKey;
-		if (existingEntry->getObject(kIODTNVRAMDiagsPresentKey) == nullptr) {
-			existingEntry->setObject(kIODTNVRAMDiagsPresentKey, kOSBooleanFalse);
-		}
-		break;
-	case kIONVRAMOperationWrite:
-		opCountKey = kIODTNVRAMDiagsWriteKey;
-		varSize = OSNumber::withNumber((size_t)data, 64);
-		existingEntry->setObject(kIODTNVRAMDiagsSizeKey, varSize);
-		existingEntry->setObject(kIODTNVRAMDiagsPresentKey, kOSBooleanTrue);
-		break;
-	case kIONVRAMOperationDelete:
-	case kIONVRAMOperationObliterate:
-	case kIONVRAMOperationReset:
-		opCountKey = kIODTNVRAMDiagsDeleteKey;
-		existingEntry->setObject(kIODTNVRAMDiagsPresentKey, kOSBooleanFalse);
-		break;
-	case kIONVRAMOperationInit:
-		varSize = OSNumber::withNumber((size_t)data, 64);
-		varOffset = OSNumber::withNumber((size_t)offset, 64);
-		existingEntry->setObject(kIODTNVRAMDiagsInitKey, varOffset);
-		existingEntry->setObject(kIODTNVRAMDiagsSizeKey, varSize);
-		existingEntry->setObject(kIODTNVRAMDiagsPresentKey, kOSBooleanTrue);
-		break;
-	default:
-		goto unlock;
-	}
-
-	if (opCountKey) {
-		currentCount.reset(OSDynamicCast(OSNumber, existingEntry->getObject(opCountKey)), OSRetain);
-
-		if (currentCount == nullptr) {
-			currentCount = OSNumber::withNumber(1, 64);
-		} else {
-			currentCount->addValue(1);
-		}
-
-		existingEntry->setObject(opCountKey, currentCount);
-	}
-
-	_stats->setObject(entryKey, existingEntry);
-
-unlock:
-	NVRAMRWUNLOCK(_diagLock);
-
-exit:
-	IODeleteData(entryKey, char, entryKeySize);
-
-	return;
-}
-
-bool
-IODTNVRAMDiags::serializeStats(void *, OSSerialize * serializer)
-{
-	bool ok;
-
-	NVRAMREADLOCK(_diagLock);
-	ok = _stats->serialize(serializer);
-	NVRAMRWUNLOCK(_diagLock);
-
-	return ok;
+	       aKey->isEqualTo(kIOBSDUnitKey);
 }
 
 // ************************** IODTNVRAMVariables ****************************
@@ -1100,12 +541,13 @@
 	OSDeclareDefaultStructors(IODTNVRAMVariables)
 private:
 	IODTNVRAM        *_provider;
+	OSDictionary     *_variables;
 	uuid_t           _guid;
-	bool             _systemActive;
 
 public:
-	bool                    init(const uuid_t guid, const bool systemActive);
+	bool                    init(const uuid_t *guid);
 	virtual bool            start(IOService * provider) APPLE_KEXT_OVERRIDE;
+	virtual IOReturn        setVariables(OSObject * properties);
 
 	virtual bool            serializeProperties(OSSerialize *s) const APPLE_KEXT_OVERRIDE;
 	virtual OSPtr<OSObject> copyProperty(const OSSymbol *aKey) const APPLE_KEXT_OVERRIDE;
@@ -1118,31 +560,33 @@
 OSDefineMetaClassAndStructors(IODTNVRAMVariables, IOService)
 
 bool
-IODTNVRAMVariables::init(const uuid_t guid, const bool systemActive)
-{
-	require(super::init(), fail);
-
-	uuid_copy(_guid, guid);
-	_systemActive = systemActive;
+IODTNVRAMVariables::init(const uuid_t *guid)
+{
+	if (!super::init()) {
+		return false;
+	}
+
+	if (guid == nullptr) {
+		return false;
+	}
+
+	uuid_copy(_guid, *guid);
 
 	return true;
-
-fail:
-	return false;
 }
 
 bool
 IODTNVRAMVariables::start(IOService * provider)
 {
+	if (!IOService::start(provider)) {
+		goto error;
+	}
+
 	_provider = OSDynamicCast(IODTNVRAM, provider);
 	if (_provider == nullptr) {
 		goto error;
 	}
 
-	if (!super::start(provider)) {
-		goto error;
-	}
-
 	registerService();
 
 	return true;
@@ -1151,6 +595,18 @@
 	stop(provider);
 
 	return false;
+}
+
+IOReturn
+IODTNVRAMVariables::setVariables(OSObject * variables)
+{
+	if (OSDynamicCast(OSDictionary, variables)) {
+		OSSafeReleaseNULL(_variables);
+		_variables = OSDynamicCast(OSDictionary, variables);
+		variables->retain();
+	}
+
+	return kIOReturnSuccess;
 }
 
 bool
@@ -1159,30 +615,28 @@
 	const OSSymbol                    *key;
 	OSSharedPtr<OSDictionary>         dict;
 	OSSharedPtr<OSCollectionIterator> iter;
-	OSSharedPtr<OSDictionary>         localVariables;
+	OSSharedPtr<OSDictionary>         localVariables(_variables, OSRetain);
 	bool                              ok = false;
-	IOReturn                          status;
-
-	status = _provider->getVarDict(localVariables);
-	require_noerr_action(status, exit, DEBUG_ERROR("Failed to get variable dictionary\n"));
+
+	if (localVariables == nullptr) {
+		goto exit;
+	}
 
 	dict = OSDictionary::withCapacity(localVariables->getCount());
-	require_action(dict, exit, DEBUG_ERROR("Failed to create dict\n"));
+	if (dict == nullptr) {
+		DEBUG_ERROR("No dictionary\n");
+		goto exit;
+	}
 
 	iter = OSCollectionIterator::withCollection(localVariables.get());
-	require_action(iter, exit, DEBUG_ERROR("Failed to create iterator\n"));
+	if (iter == nullptr) {
+		DEBUG_ERROR("failed to create iterator\n");
+		goto exit;
+	}
 
 	while ((key = OSDynamicCast(OSSymbol, iter->getNextObject()))) {
-		if (verifyPermission(kIONVRAMOperationRead, key, _systemActive)) {
-			uuid_t guid;
-			const char *name;
-
-			parseVariableName(key, &guid, &name);
-
-			if (uuid_compare(_guid, guid) == 0) {
-				OSSharedPtr<const OSSymbol> sym = OSSymbol::withCString(name);
-				dict->setObject(sym.get(), localVariables->getObject(key));
-			}
+		if (verifyPermission(kIONVRAMOperationRead, &_guid, key)) {
+			dict->setObject(key, localVariables->getObject(key));
 		}
 	}
 
@@ -1199,7 +653,7 @@
 	if (_provider && !skipKey(aKey)) {
 		DEBUG_INFO("aKey=%s\n", aKey->getCStringNoCopy());
 
-		return _provider->copyPropertyWithGUIDAndName(_guid, aKey->getCStringNoCopy());
+		return _provider->copyPropertyWithGUIDAndName(&_guid, aKey->getCStringNoCopy());
 	} else {
 		return nullptr;
 	}
@@ -1217,7 +671,7 @@
 IODTNVRAMVariables::setProperty(const OSSymbol *aKey, OSObject *anObject)
 {
 	if (_provider) {
-		return _provider->setPropertyWithGUIDAndName(_guid, aKey->getCStringNoCopy(), anObject) == kIOReturnSuccess;
+		return _provider->setPropertyWithGUIDAndName(&_guid, aKey->getCStringNoCopy(), anObject);
 	} else {
 		return false;
 	}
@@ -1232,30 +686,34 @@
 	OSDictionary                      *dict;
 	OSSharedPtr<OSCollectionIterator> iter;
 
-	dict = OSDynamicCast(OSDictionary, properties);
-	if (dict == nullptr) {
-		DEBUG_ERROR("Not a dictionary\n");
-		return kIOReturnBadArgument;
-	}
-
-	iter = OSCollectionIterator::withCollection(dict);
-	if (iter == nullptr) {
-		DEBUG_ERROR("Couldn't create iterator\n");
-		return kIOReturnBadArgument;
-	}
-
-	while (ret == kIOReturnSuccess) {
-		key = OSDynamicCast(OSSymbol, iter->getNextObject());
-		if (key == nullptr) {
-			break;
-		}
-
-		object = dict->getObject(key);
-		if (object == nullptr) {
-			continue;
-		}
-
-		ret = _provider->setPropertyWithGUIDAndName(_guid, key->getCStringNoCopy(), object);
+	if (_provider) {
+		dict = OSDynamicCast(OSDictionary, properties);
+		if (dict == nullptr) {
+			DEBUG_ERROR("Not a dictionary\n");
+			return kIOReturnBadArgument;
+		}
+
+		iter = OSCollectionIterator::withCollection(dict);
+		if (iter == nullptr) {
+			DEBUG_ERROR("Couldn't create iterator\n");
+			return kIOReturnBadArgument;
+		}
+
+		while (ret == kIOReturnSuccess) {
+			key = OSDynamicCast(OSSymbol, iter->getNextObject());
+			if (key == nullptr) {
+				break;
+			}
+
+			object = dict->getObject(key);
+			if (object == nullptr) {
+				continue;
+			}
+
+			ret = setProperty(key, object);
+		}
+	} else {
+		ret = kIOReturnNotReady;
 	}
 
 	DEBUG_INFO("ret=%#08x\n", ret);
@@ -1266,147 +724,11 @@
 void
 IODTNVRAMVariables::removeProperty(const OSSymbol *aKey)
 {
-	_provider->removePropertyWithGUIDAndName(_guid, aKey->getCStringNoCopy());
-}
-
-// ************************** Format Handlers ***************************
-class IODTNVRAMFormatHandler
-{
-protected:
-	uint32_t _bankSize;
-	uint32_t _bankCount;
-	uint32_t _currentBank;
-
-public:
-	virtual
-	~IODTNVRAMFormatHandler();
-	virtual bool     getNVRAMProperties(void);
-	virtual IOReturn unserializeVariables(void) = 0;
-	virtual IOReturn setVariable(const uuid_t varGuid, const char *variableName, OSObject *object) = 0;
-	virtual bool     setController(IONVRAMController *_nvramController) = 0;
-	virtual IOReturn sync(void) = 0;
-	virtual IOReturn flush(const uuid_t guid, IONVRAMOperation op) = 0;
-	virtual void     reload(void) = 0;
-	virtual uint32_t getGeneration(void) const = 0;
-	virtual uint32_t getVersion(void) const = 0;
-	virtual uint32_t getSystemUsed(void) const = 0;
-	virtual uint32_t getCommonUsed(void) const = 0;
-	virtual bool     getSystemPartitionActive(void) const = 0;
-	virtual IOReturn getVarDict(OSSharedPtr<OSDictionary> &varDictCopy) = 0;
-	IOReturn handleEphDM(void);
-};
-
-IODTNVRAMFormatHandler::~IODTNVRAMFormatHandler()
-{
-}
-
-bool
-IODTNVRAMFormatHandler::getNVRAMProperties()
-{
-	bool                         ok    = false;
-	OSSharedPtr<IORegistryEntry> entry;
-	OSSharedPtr<OSObject>        prop;
-	OSData *                     data;
-
-	entry = IORegistryEntry::fromPath("/chosen", gIODTPlane);
-	require_action(entry, exit, DEBUG_ERROR("Unable to find chosen node\n"));
-
-	prop = entry->copyProperty(kNVRAMBankSizeKey);
-	require_action(prop, exit, DEBUG_ERROR("Unable to find %s property\n", kNVRAMBankSizeKey));
-
-	data = OSDynamicCast(OSData, prop.get());
-	require(data, exit);
-
-	_bankSize = *((uint32_t *)data->getBytesNoCopy());
-
-	prop = entry->copyProperty(kNVRAMBankCountKey);
-	require_action(prop, exit, DEBUG_ERROR("Unable to find %s property\n", kNVRAMBankCountKey));
-
-	data = OSDynamicCast(OSData, prop.get());
-	require(data, exit);
-
-	_bankCount = *((uint32_t *)data->getBytesNoCopy());
-
-	prop = entry->copyProperty(kNVRAMCurrentBankKey);
-	require_action(prop, exit, DEBUG_ERROR("Unable to find %s property\n", kNVRAMCurrentBankKey));
-
-	data = OSDynamicCast(OSData, prop.get());
-	require(data, exit);
-
-	_currentBank = *((uint32_t *)data->getBytesNoCopy());
-
-	ok = true;
-
-	DEBUG_ALWAYS("_bankSize=%#X, _bankCount=%#X, _currentBank=%#X\n", _bankSize, _bankCount, _currentBank);
-
-exit:
-	return ok;
-}
-
-IOReturn
-IODTNVRAMFormatHandler::handleEphDM(void)
-{
-	OSSharedPtr<IORegistryEntry> entry;
-	OSData*                      data;
-	OSSharedPtr<OSObject>        prop;
-	uint32_t                     ephDM = 0;
-	IOReturn                     ret = kIOReturnSuccess;
-	OSSharedPtr<const OSSymbol>  canonicalKey;
-	uint32_t                     skip = 0;
-	OSSharedPtr<OSDictionary>    varDict;
-
-	// For ephemeral data mode, NVRAM needs to be cleared on every boot
-	// For system region supported targets, iBoot clears the system region
-	// For other targets, iBoot clears all the persistent variables
-	// So xnu only needs to clear the common region
-	entry = IORegistryEntry::fromPath("/product", gIODTPlane);
-	if (entry) {
-		prop = entry->copyProperty("ephemeral-data-mode");
-		if (prop) {
-			data = OSDynamicCast(OSData, prop.get());
-			if (data) {
-				ephDM = *((uint32_t *)data->getBytesNoCopy());
-			}
-		}
-	}
-
-	require_action(ephDM != 0, exit, DEBUG_ALWAYS("ephemeral-data-mode not supported\n"));
-	require_action(getSystemPartitionActive(), exit, DEBUG_ALWAYS("No system region, no need to clear\n"));
-
-	if (PE_parse_boot_argn("epdm-skip-nvram", &skip, sizeof(skip))) {
-		require_action(!(gInternalBuild && (skip == 1)), exit, DEBUG_ALWAYS("Internal build + epdm-skip-nvram set to true, skip nvram clearing\n"));
-	}
-
-	// Get the current variable dictionary
-	ret = getVarDict(varDict);
-	require_noerr_action(ret, exit, DEBUG_ERROR("Failed to get variable dictionary for EphDM handling\n"));
-
-	// Go through the allowlist and stash the values
-	for (uint32_t entry = 0; entry < ARRAY_SIZE(ephDMEntries); entry++) {
-		canonicalKey = keyWithGuidAndCString(gAppleNVRAMGuid, ephDMEntries[entry].name);
-		ephDMEntries[entry].value.reset(OSDynamicCast(OSData, varDict->getObject(canonicalKey.get())), OSRetain);
-	}
-
-	DEBUG_ALWAYS("Obliterating common region\n");
-	ret = flush(gAppleNVRAMGuid, kIONVRAMOperationObliterate);
-	require_noerr_action(ret, exit, DEBUG_ERROR("Flushing common region failed, ret=%#08x\n", ret));
-
-	// Now write the allowlist variables back
-	for (uint32_t entry = 0; entry < ARRAY_SIZE(ephDMEntries); entry++) {
-		if (ephDMEntries[entry].value.get() == nullptr) {
-			continue;
-		}
-		ret = setVariable(gAppleNVRAMGuid, ephDMEntries[entry].name, ephDMEntries[entry].value.get());
-		require_noerr_action(ret, exit, DEBUG_ERROR("Setting allowlist variable %s failed, ret=%#08x\n", ephDMEntries[entry].name, ret));
-	}
-
-exit:
-	return ret;
-}
-
-#include "IONVRAMCHRPHandler.cpp"
-
-#include "IONVRAMV3Handler.cpp"
+	if (_provider) {
+		_provider->removePropertyWithGUIDAndName(&_guid, aKey->getCStringNoCopy());
+	}
+}
+
 
 // **************************** IODTNVRAM *********************************
 
@@ -1415,98 +737,157 @@
 {
 	OSSharedPtr<OSDictionary> dict;
 
-	DEBUG_INFO("...\n");
-	require(super::init(old, plane), fail);
-	x86Device = false;
-
-#if CONFIG_CSR && XNU_TARGET_OS_OSX
+	if (!super::init(old, plane)) {
+		return false;
+	}
+
+	PE_parse_boot_argn("nvram-log", &gNVRAMLogging, sizeof(gNVRAMLogging));
+
+#if XNU_TARGET_OS_OSX
+#if CONFIG_CSR
 	gInternalBuild = (csr_check(CSR_ALLOW_APPLE_INTERNAL) == 0);
-#elif defined(DEBUG) || defined(DEVELOPMENT)
-	gInternalBuild = true;
-#endif
+#endif // CONFIG_CSR
+#endif // XNU_TARGET_OS_OSX
+
 	DEBUG_INFO("gInternalBuild = %d\n", gInternalBuild);
 
-	// Clear the IORegistryEntry property table
+	_variableLock = IORWLockAlloc();
+	if (!_variableLock) {
+		return false;
+	}
+
+	_controllerLock = IOLockAlloc();
+	if (!_controllerLock) {
+		return false;
+	}
+
 	dict =  OSDictionary::withCapacity(1);
-	require(dict != nullptr, fail);
-
+	if (dict == nullptr) {
+		return false;
+	}
 	setPropertyTable(dict.get());
 	dict.reset();
 
+	_nvramSize = getNVRAMSize();
+	if (_nvramSize == 0) {
+		DEBUG_ERROR("NVRAM : Error - default size not specified in DT\n");
+		return false;
+	}
+	// partition offsets are UInt16 (bytes / 0x10) + 1
+	if (_nvramSize > 0xFFFF * 0x10) {
+		DEBUG_ERROR("NVRAM : truncating _nvramSize from %ld\n", (long) _nvramSize);
+		_nvramSize = 0xFFFF * 0x10;
+	}
+	_nvramImage = IONew(UInt8, _nvramSize);
+	if (_nvramImage == nullptr) {
+		return false;
+	}
+
+	_nvramPartitionOffsets = OSDictionary::withCapacity(1);
+	if (_nvramPartitionOffsets == nullptr) {
+		return false;
+	}
+
+	_nvramPartitionLengths = OSDictionary::withCapacity(1);
+	if (_nvramPartitionLengths == nullptr) {
+		return false;
+	}
+
+	_registryPropertiesKey = OSSymbol::withCStringNoCopy("aapl,pci");
+	if (_registryPropertiesKey == nullptr) {
+		return false;
+	}
+
+	// <rdar://problem/9529235> race condition possible between
+	// 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;
-
-fail:
-	return false;
-}
-
-bool
-IODTNVRAM::start(IOService *provider)
-{
-	OSSharedPtr<OSNumber> version;
-
-	DEBUG_ALWAYS("...\n");
-
-	require(super::start(provider), fail);
-
-	// Check if our overridden init function was called
-	// If not, skip any additional initialization being done here.
-	// This is not an error we just need to successfully exit this function to allow
-	// AppleEFIRuntime to proceed and take over operation
-	require_action(x86Device == false, no_common, DEBUG_INFO("x86 init\n"));
-
-	_diags = new IODTNVRAMDiags;
-	if (!_diags || !_diags->init()) {
-		DEBUG_ERROR("Unable to create/init the diags service\n");
-		OSSafeReleaseNULL(_diags);
-		goto fail;
-	}
-
-	if (!_diags->attach(this)) {
-		DEBUG_ERROR("Unable to attach the diags service!\n");
-		OSSafeReleaseNULL(_diags);
-		goto fail;
-	}
-
-	if (!_diags->start(this)) {
-		DEBUG_ERROR("Unable to start the diags service!\n");
-		_diags->detach(this);
-		OSSafeReleaseNULL(_diags);
-		goto fail;
-	}
-
-	_notifier = new IODTNVRAMPlatformNotifier;
-	if (!_notifier || !_notifier->init()) {
-		DEBUG_ERROR("Unable to create/init the notifier service\n");
-		OSSafeReleaseNULL(_notifier);
-		goto fail;
-	}
-
-	if (!_notifier->attach(this)) {
-		DEBUG_ERROR("Unable to attach the notifier service!\n");
-		OSSafeReleaseNULL(_notifier);
-		goto fail;
-	}
-
-	if (!_notifier->start(this)) {
-		DEBUG_ERROR("Unable to start the notifier service!\n");
-		_notifier->detach(this);
-		OSSafeReleaseNULL(_notifier);
-		goto fail;
-	}
-
-	// This will load the proxied variable data which will call back into
-	// IODTNVRAM for the variable sets which will also update the system/common services
-	initImageFormat();
-
-	version = OSNumber::withNumber(_format->getVersion(), 32);
-	_diags->setProperty(kCurrentNVRAMVersionKey, version.get());
-
-	if (_format->getSystemUsed()) {
+}
+
+void
+IODTNVRAM::initProxyData(void)
+{
+	OSSharedPtr<IORegistryEntry> entry;
+	const char                   *key = "nvram-proxy-data";
+	OSData                       *data;
+	const void                   *bytes;
+
+	entry = IORegistryEntry::fromPath("/chosen", gIODTPlane);
+	if (entry != nullptr) {
+		OSSharedPtr<OSObject> prop = entry->copyProperty(key);
+		if (prop != nullptr) {
+			data = OSDynamicCast(OSData, prop.get());
+			if (data != nullptr) {
+				bytes = data->getBytesNoCopy();
+				if ((bytes != nullptr) && (data->getLength() <= _nvramSize)) {
+					bcopy(bytes, _nvramImage, data->getLength());
+					initNVRAMImage();
+					_isProxied = true;
+				}
+			}
+		}
+		entry->removeProperty(key);
+	}
+}
+
+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)
+{
+	IOReturn ret;
+
+	if (_nvramController != nullptr) {
+		DEBUG_ERROR("Duplicate controller set\n");
+		return;
+	}
+
+	DEBUG_INFO("setting controller\n");
+
+	CONTROLLERLOCK();
+	_nvramController = nvram;
+	CONTROLLERUNLOCK();
+
+	// <rdar://problem/9529235> race condition possible between
+	// IODTNVRAM and IONVRAMController (restore loses boot-args)
+	if (!_isProxied) {
+		DEBUG_INFO("Reading non-proxied NVRAM data\n");
+		_nvramController->read(0, _nvramImage, _nvramSize);
+		initNVRAMImage();
+	}
+
+	if (_systemPartitionSize) {
 		_systemService = new IODTNVRAMVariables;
 
-		if (!_systemService || !_systemService->init(gAppleSystemVariableGuid, _format->getSystemPartitionActive())) {
+		if (!_systemService || !_systemService->init(&gAppleSystemVariableGuid)) {
 			DEBUG_ERROR("Unable to start the system service!\n");
-			OSSafeReleaseNULL(_systemService);
 			goto no_system;
 		}
 
@@ -1527,345 +908,351 @@
 	}
 
 no_system:
-	_commonService = new IODTNVRAMVariables;
-
-	if (!_commonService || !_commonService->init(gAppleNVRAMGuid, _format->getSystemPartitionActive())) {
-		DEBUG_ERROR("Unable to start the common service!\n");
-		OSSafeReleaseNULL(_commonService);
-		goto no_common;
-	}
-
-	_commonService->setName("options-common");
-
-	if (!_commonService->attach(this)) {
-		DEBUG_ERROR("Unable to attach the common service!\n");
-		OSSafeReleaseNULL(_commonService);
-		goto no_common;
-	}
-
-	if (!_commonService->start(this)) {
-		DEBUG_ERROR("Unable to start the common service!\n");
-		_commonService->detach(this);
-		OSSafeReleaseNULL(_commonService);
-		goto no_common;
+	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:
-	return true;
-
-fail:
-	stop(provider);
-	return false;
+	ret = serializeVariables();
+	DEBUG_INFO("serializeVariables ret=%#08x\n", ret);
 }
 
 void
-IODTNVRAM::initImageFormat(void)
-{
-	OSSharedPtr<IORegistryEntry> entry;
-	OSSharedPtr<OSObject>        prop;
-	const char                   *proxyDataKey = "nvram-proxy-data";
-	const char                   *bankSizeKey = "nvram-bank-size";
-	OSData                       *data = nullptr;
-	uint32_t                     size = 0;
-	const uint8_t                *image = nullptr;
-	OSSharedPtr<OSDictionary>    localVariables;
-	IOReturn                     status;
-
-	entry = IORegistryEntry::fromPath("/chosen", gIODTPlane);
-
-	require(entry != nullptr, skip);
-
-	prop = entry->copyProperty(bankSizeKey);
-	require(prop != nullptr, skip);
-
-	data = OSDynamicCast(OSData, prop.get());
-	require(data != nullptr, skip);
-
-	size = *((uint32_t*)data->getBytesNoCopy());
-	require_action(size != 0, skip, panic("NVRAM size is 0 bytes, possibly due to bad config with iBoot + xnu mismatch"));
-	DEBUG_ALWAYS("NVRAM size is %u bytes\n", size);
-
-	prop = entry->copyProperty(proxyDataKey);
-	require(prop != nullptr, skip);
-
-	data = OSDynamicCast(OSData, prop.get());
-	require_action(data != nullptr, skip, DEBUG_ERROR("No proxy data!\n"));
-
-	image = (const uint8_t *)data->getBytesNoCopy();
-
-skip:
-	if (IONVRAMV3Handler::isValidImage(image, size)) {
-		_format = IONVRAMV3Handler::init(this, image, size);
-		require_action(_format, skip, panic("IONVRAMV3Handler creation failed\n"));
-	} else {
-		_format = IONVRAMCHRPHandler::init(this, image, size);
-		require_action(_format, skip, panic("IONVRAMCHRPHandler creation failed\n"));
-	}
-
-	status = _format->unserializeVariables();
-	verify_noerr_action(status, DEBUG_ERROR("Failed to unserialize variables, status=%08x\n", status));
-
-	status = _format->getVarDict(localVariables);
-	verify_noerr_action(status, DEBUG_ERROR("Failed to get variable dictionary, status=%08x\n", status));
-
-	dumpDict(localVariables);
-
-#if defined(RELEASE)
-	if (entry != nullptr) {
-		entry->removeProperty(proxyDataKey);
-	}
-#endif
+IODTNVRAM::initNVRAMImage(void)
+{
+	char   partitionID[18];
+	UInt32 partitionOffset, partitionLength;
+	UInt32 currentLength, currentOffset = 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);
+		const uint8_t common_v1_name[sizeof(header->name)] = {NVRAM_CHRP_PARTITION_NAME_COMMON_V1};
+		const uint8_t common_v2_name[sizeof(header->name)] = {NVRAM_CHRP_PARTITION_NAME_COMMON_V2};
+		const uint8_t system_v1_name[sizeof(header->name)] = {NVRAM_CHRP_PARTITION_NAME_SYSTEM_V1};
+		const uint8_t system_v2_name[sizeof(header->name)] = {NVRAM_CHRP_PARTITION_NAME_SYSTEM_V2};
+
+		currentLength = header->len * NVRAM_CHRP_LENGTH_BLOCK_SIZE;
+
+		if (currentLength < sizeof(chrp_nvram_header_t)) {
+			break;
+		}
+
+		partitionOffset = currentOffset + sizeof(chrp_nvram_header_t);
+		partitionLength = currentLength - sizeof(chrp_nvram_header_t);
+
+		if ((partitionOffset + partitionLength) > _nvramSize) {
+			break;
+		}
+
+		common_partition = (memcmp(header->name, common_v1_name, sizeof(header->name)) == 0) ||
+		    (memcmp(header->name, common_v2_name, sizeof(header->name)) == 0);
+		system_partition = (memcmp(header->name, system_v1_name, sizeof(header->name)) == 0) ||
+		    (memcmp(header->name, system_v2_name, sizeof(header->name)) == 0);
+
+		if (common_partition) {
+			_commonPartitionOffset = partitionOffset;
+			_commonPartitionSize = partitionLength;
+		} else if (system_partition) {
+			_systemPartitionOffset = partitionOffset;
+			_systemPartitionSize = partitionLength;
+		} else {
+			OSSharedPtr<OSNumber> partitionOffsetNumber, partitionLengthNumber;
+
+			// Construct the partition ID from the signature and name.
+			snprintf(partitionID, sizeof(partitionID), "%#02x,", header->sig);
+			memcpy(partitionID + 5, header->name, sizeof(header->name));
+			partitionID[17] = '\0';
+
+			partitionOffsetNumber = OSNumber::withNumber(partitionOffset, 32);
+			partitionLengthNumber = OSNumber::withNumber(partitionLength, 32);
+
+			// Save the partition offset and length
+			_nvramPartitionOffsets->setObject(partitionID, partitionOffsetNumber.get());
+			_nvramPartitionLengths->setObject(partitionID, partitionLengthNumber.get());
+		}
+		currentOffset += currentLength;
+	}
+
+	if (_commonPartitionOffset != 0xFFFFFFFF) {
+		_commonImage = _nvramImage + _commonPartitionOffset;
+	}
+
+	if (_systemPartitionOffset != 0xFFFFFFFF) {
+		_systemImage = _nvramImage + _systemPartitionOffset;
+	}
+
+	DEBUG_ALWAYS("NVRAM : commonPartitionOffset - %#x, commonPartitionSize - %#x, systemPartitionOffset - %#x, systemPartitionSize - %#x\n",
+	    (unsigned int) _commonPartitionOffset, (unsigned int) _commonPartitionSize, (unsigned int) _systemPartitionOffset, (unsigned int) _systemPartitionSize);
 
 	_lastDeviceSync = 0;
-	_freshInterval = true;
+	_freshInterval = TRUE;          // we will allow sync() even before the first 15 minutes have passed.
+
+	initVariables();
 }
 
 void
-IODTNVRAM::registerNVRAMController(IONVRAMController *controller)
-{
-	DEBUG_INFO("setting controller\n");
-
-	require_action(_format != nullptr, exit, DEBUG_ERROR("Handler not initialized yet\n"));
-	_format->setController(controller);
-
-exit:
-	return;
-}
-
-bool
-IODTNVRAM::safeToSync(void)
-{
-	AbsoluteTime delta;
-	UInt64       delta_ns;
-	SInt32       delta_secs;
-
-	// delta interval went by
-	clock_get_uptime(&delta);
-
-	// Figure it in seconds.
-	absolutetime_to_nanoseconds(delta, &delta_ns);
-	delta_secs = (SInt32)(delta_ns / NSEC_PER_SEC);
-
-	if ((delta_secs > (_lastDeviceSync + MIN_SYNC_NOW_INTERVAL)) || _freshInterval) {
-		_lastDeviceSync = delta_secs;
-		_freshInterval = false;
-		return true;
-	}
-
-	return false;
-}
-
-IOReturn
 IODTNVRAM::syncInternal(bool rateLimit)
 {
-	IOReturn ret = kIOReturnSuccess;
-
 	DEBUG_INFO("rateLimit=%d\n", rateLimit);
 
-	if (!SAFE_TO_LOCK()) {
-		DEBUG_INFO("cannot lock\n");
-		goto exit;
-	}
-
-	require_action(_format != nullptr, exit, (ret = kIOReturnNotReady, DEBUG_ERROR("Handler not initialized yet\n")));
+	// Don't try to perform controller operations if none has been registered.
+	if (_nvramController == nullptr) {
+		return;
+	}
 
 	// Rate limit requests to sync. Drivers that need this rate limiting will
 	// shadow the data and only write to flash when they get a sync call
-	if (rateLimit) {
-		if (safeToSync() == false) {
-			DEBUG_INFO("safeToSync()=false\n");
+	if (rateLimit && !safeToSync()) {
+		return;
+	}
+
+	DEBUG_INFO("Calling sync()\n");
+
+	CONTROLLERLOCK();
+	_nvramController->sync();
+	CONTROLLERUNLOCK();
+}
+
+void
+IODTNVRAM::sync(void)
+{
+	syncInternal(false);
+}
+
+bool
+IODTNVRAM::serializeProperties(OSSerialize *s) const
+{
+	const OSSymbol                    *key;
+	OSSharedPtr<OSDictionary>         systemDict, commonDict, dict;
+	OSSharedPtr<OSCollectionIterator> iter;
+	bool                              ok = false;
+	unsigned int                      totalCapacity = 0;
+
+	NVRAMREADLOCK();
+	if (_commonDict) {
+		commonDict = OSDictionary::withDictionary(_commonDict.get());
+	}
+
+	if (_systemDict) {
+		systemDict = OSDictionary::withDictionary(_systemDict.get());
+	}
+	NVRAMUNLOCK();
+
+	totalCapacity += (commonDict != nullptr) ? commonDict->getCapacity() : 0;
+	totalCapacity += (systemDict != nullptr) ? systemDict->getCapacity() : 0;
+
+	dict = OSDictionary::withCapacity(totalCapacity);
+
+	if (dict == nullptr) {
+		DEBUG_ERROR("No dictionary\n");
+		goto exit;
+	}
+
+	// Copy system entries first if present then copy unique common entries
+	if (systemDict != nullptr) {
+		iter = OSCollectionIterator::withCollection(systemDict.get());
+		if (iter == nullptr) {
+			DEBUG_ERROR("failed to create iterator\n");
 			goto exit;
 		}
-	}
-
-	DEBUG_INFO("Calling sync()\n");
-	record_system_event(SYSTEM_EVENT_TYPE_INFO, SYSTEM_EVENT_SUBSYSTEM_NVRAM, "sync", "triggered");
-
-	ret = _format->sync();
-
-	record_system_event(SYSTEM_EVENT_TYPE_INFO, SYSTEM_EVENT_SUBSYSTEM_NVRAM, "sync", "completed with ret=%08x", ret);
-
-	if (_diags) {
-		OSSharedPtr<OSNumber> generation = OSNumber::withNumber(_format->getGeneration(), 32);
-		_diags->setProperty(kCurrentGenerationCountKey, generation.get());
-	}
-
-exit:
-	return ret;
-}
-
-IOReturn
-IODTNVRAM::sync(void)
-{
-	return syncInternal(false);
-}
-
-void
-IODTNVRAM::reload(void)
-{
-	_format->reload();
-}
-
-IOReturn
-IODTNVRAM::getVarDict(OSSharedPtr<OSDictionary> &varDictCopy)
-{
-	return _format->getVarDict(varDictCopy);
-}
-
-OSPtr<OSDictionary>
-IODTNVRAM::dictionaryWithProperties(void) const
-{
-	const OSSymbol                    *canonicalKey;
-	OSSharedPtr<OSDictionary>         localVarDict, returnDict;
-	OSSharedPtr<OSCollectionIterator> iter;
-	uuid_t                            varGuid;
-	const char *                      varName;
-	IOReturn                          status;
-	require_action(_format, exit, DEBUG_ERROR("Handler not initialized yet\n"));
-
-	status = _format->getVarDict(localVarDict);
-	require_noerr_action(status, exit, DEBUG_ERROR("Failed to get variable dictionary\n"));
-
-	returnDict = OSDictionary::withCapacity(localVarDict->getCapacity());
-	require_action(returnDict, exit, DEBUG_ERROR("Failed to create return dict\n"));
-
-	// Copy system entries first if present then copy unique other entries
-	iter = OSCollectionIterator::withCollection(localVarDict.get());
-	require_action(iter, exit, DEBUG_ERROR("Failed to create iterator\n"));
-
-	while ((canonicalKey = OSDynamicCast(OSSymbol, iter->getNextObject()))) {
-		parseVariableName(canonicalKey, &varGuid, &varName);
-
-		if ((uuid_compare(varGuid, gAppleSystemVariableGuid) == 0) &&
-		    verifyPermission(kIONVRAMOperationRead, varGuid, varName, _format->getSystemPartitionActive(), false)) {
-			OSSharedPtr<const OSSymbol> returnKey = OSSymbol::withCString(varName);
-			returnDict->setObject(returnKey.get(), localVarDict->getObject(canonicalKey));
-		}
-	}
-
-	iter.reset();
-
-	iter = OSCollectionIterator::withCollection(localVarDict.get());
-	require_action(iter, exit, DEBUG_ERROR("Failed to create iterator\n"));
-
-	while ((canonicalKey = OSDynamicCast(OSSymbol, iter->getNextObject()))) {
-		parseVariableName(canonicalKey, &varGuid, &varName);
-
-		if (uuid_compare(varGuid, gAppleNVRAMGuid) == 0) {
-			if (returnDict->getObject(varName) != nullptr) {
+
+		while ((key = OSDynamicCast(OSSymbol, iter->getNextObject()))) {
+			if (verifyPermission(kIONVRAMOperationRead, &gAppleSystemVariableGuid, key)) {
+				dict->setObject(key, systemDict->getObject(key));
+			}
+		}
+
+		iter.reset();
+	}
+
+	if (commonDict != nullptr) {
+		iter = OSCollectionIterator::withCollection(commonDict.get());
+		if (iter == nullptr) {
+			DEBUG_ERROR("failed to create common iterator\n");
+			goto exit;
+		}
+
+		while ((key = OSDynamicCast(OSSymbol, iter->getNextObject()))) {
+			if (dict->getObject(key) != nullptr) {
 				// Skip non uniques
 				continue;
 			}
-
-			if (verifyPermission(kIONVRAMOperationRead, varGuid, varName, _format->getSystemPartitionActive(), false)) {
-				OSSharedPtr<const OSSymbol> returnKey = OSSymbol::withCString(varName);
-				returnDict->setObject(returnKey.get(), localVarDict->getObject(canonicalKey));
-			}
-		}
-	}
+			if (verifyPermission(kIONVRAMOperationRead, &gAppleNVRAMGuid, key)) {
+				dict->setObject(key, commonDict->getObject(key));
+			}
+		}
+	}
+
+	ok = dict->serialize(s);
+
 exit:
-	return returnDict;
+	DEBUG_INFO("ok=%d\n", ok);
+
+	return ok;
+}
+
+IOReturn
+IODTNVRAM::chooseDictionary(IONVRAMOperation operation, const uuid_t *varGuid, const char *variableName, OSDictionary **dict) const
+{
+	if (_systemDict != nullptr) {
+		bool systemGuid = uuid_compare(*varGuid, gAppleSystemVariableGuid) == 0;
+
+		if (variableInAllowList(variableName)) {
+			DEBUG_INFO("Using system dictionary due to allow list\n");
+			if (!systemGuid) {
+				DEBUG_ERROR("System GUID NOT used for %s\n", variableName);
+			}
+			*dict = _systemDict.get();
+		} else if (systemGuid) {
+			DEBUG_INFO("Using system dictionary via GUID\n");
+			*dict = _systemDict.get();
+		} else {
+			DEBUG_INFO("Using common dictionary\n");
+			*dict = _commonDict.get();
+		}
+		return kIOReturnSuccess;
+	} else if (_commonDict != nullptr) {
+		DEBUG_INFO("Defaulting to common dictionary\n");
+		*dict = _commonDict.get();
+		return kIOReturnSuccess;
+	}
+
+	return kIOReturnNotFound;
+}
+
+IOReturn
+IODTNVRAM::flushDict(const uuid_t *guid, IONVRAMOperation op)
+{
+	IOReturn err = kIOReturnSuccess;
+
+	if ((_systemDict != nullptr) && (uuid_compare(*guid, gAppleSystemVariableGuid) == 0)) {
+		const OSSymbol *key;
+		OSSharedPtr<OSDictionary> newDict;
+		OSSharedPtr<OSCollectionIterator> iter;
+
+		newDict = OSDictionary::withCapacity(_systemDict->getCapacity());
+		iter = OSCollectionIterator::withCollection(_systemDict.get());
+		if ((newDict == nullptr) || (iter == nullptr)) {
+			err = kIOReturnNoMemory;
+			goto exit;
+		}
+
+		while ((key = OSDynamicCast(OSSymbol, iter->getNextObject()))) {
+			if (!verifyPermission(op, &gAppleSystemVariableGuid, key)) {
+				newDict->setObject(key, _systemDict->getObject(key));
+			}
+		}
+
+		_systemDict = newDict;
+
+		DEBUG_INFO("system dictionary flushed\n");
+	} else if ((_commonDict != nullptr) && (uuid_compare(*guid, gAppleNVRAMGuid) == 0)) {
+		const OSSymbol *key;
+		OSSharedPtr<OSDictionary> newDict;
+		OSSharedPtr<OSCollectionIterator> iter;
+
+		newDict = OSDictionary::withCapacity(_commonDict->getCapacity());
+		iter = OSCollectionIterator::withCollection(_commonDict.get());
+		if ((newDict == nullptr) || (iter == nullptr)) {
+			err = kIOReturnNoMemory;
+			goto exit;
+		}
+
+		while ((key = OSDynamicCast(OSSymbol, iter->getNextObject()))) {
+			if (!verifyPermission(op, &gAppleNVRAMGuid, key)) {
+				newDict->setObject(key, _commonDict->getObject(key));
+			}
+		}
+
+		_commonDict = newDict;
+
+		DEBUG_INFO("common dictionary flushed\n");
+	}
+
+exit:
+	return err;
 }
 
 bool
-IODTNVRAM::serializeProperties(OSSerialize *s) const
-{
-	bool ok = false;
-	OSSharedPtr<OSDictionary> dict;
-
-	dict = dictionaryWithProperties();
-	if (dict) {
-		ok = dict->serialize(s);
-	}
-
-	DEBUG_INFO("ok=%d\n", ok);
-	return ok;
-}
-
-IOReturn
-IODTNVRAM::flushGUID(const uuid_t guid, IONVRAMOperation op)
-{
-	IOReturn ret = kIOReturnSuccess;
-
-	require_action(_format != nullptr, exit, (ret = kIOReturnNotReady, DEBUG_ERROR("Handler not initialized yet\n")));
-
-	if (_format->getSystemPartitionActive() && (uuid_compare(guid, gAppleSystemVariableGuid) == 0)) {
-		ret = _format->flush(guid, op);
-
-		DEBUG_INFO("system variables flushed, ret=%08x\n", ret);
-	} else if (uuid_compare(guid, gAppleNVRAMGuid) == 0) {
-		ret = _format->flush(guid, op);
-
-		DEBUG_INFO("common variables flushed, ret=%08x\n", ret);
-	}
-
-exit:
-	return ret;
-}
-
-bool
-IODTNVRAM::handleSpecialVariables(const char *name, const uuid_t guid, const OSObject *obj, IOReturn *error)
-{
-	IOReturn ret = kIOReturnSuccess;
+IODTNVRAM::handleSpecialVariables(const char *name, const uuid_t *guid, const OSObject *obj, IOReturn *error)
+{
+	IOReturn err = kIOReturnSuccess;
 	bool special = false;
+
+	NVRAMLOCKASSERTEXCLUSIVE();
 
 	// ResetNVRam flushes both regions in one call
 	// Obliterate can flush either separately
 	if (strcmp(name, "ObliterateNVRam") == 0) {
-		special = true;
-		ret = flushGUID(guid, kIONVRAMOperationObliterate);
+		err = flushDict(guid, kIONVRAMOperationObliterate);
 	} else if (strcmp(name, "ResetNVRam") == 0) {
-		special = true;
-		ret = flushGUID(gAppleSystemVariableGuid, kIONVRAMOperationReset);
-
-		if (ret != kIOReturnSuccess) {
+		err = flushDict(&gAppleSystemVariableGuid, kIONVRAMOperationReset);
+
+		if (err != kIOReturnSuccess) {
 			goto exit;
 		}
 
-		ret = flushGUID(gAppleNVRAMGuid, kIONVRAMOperationReset);
+		err = flushDict(&gAppleNVRAMGuid, kIONVRAMOperationReset);
 	}
 
 exit:
 	if (error) {
-		*error = ret;
+		*error = err;
 	}
 
 	return special;
 }
 
 OSSharedPtr<OSObject>
-IODTNVRAM::copyPropertyWithGUIDAndName(const uuid_t guid, const char *name) const
-{
-	OSSharedPtr<const OSSymbol> canonicalKey;
-	OSSharedPtr<OSObject>       theObject;
-	uuid_t                      newGuid;
-	OSSharedPtr<OSDictionary>   localVarDict;
-	IOReturn                    status;
-
-	require_action(_format, exit, DEBUG_ERROR("Handler not initialized yet\n"));
-
-	status = _format->getVarDict(localVarDict);
-	require_noerr_action(status, exit, DEBUG_ERROR("Failed to get variable dictionary\n"));
-
-	if (!verifyPermission(kIONVRAMOperationRead, guid, name, _format->getSystemPartitionActive(), true)) {
+IODTNVRAM::copyPropertyWithGUIDAndName(const uuid_t *guid, const char *name) const
+{
+	IOReturn              result;
+	OSDictionary          *dict;
+	OSSharedPtr<OSObject> theObject = nullptr;
+
+	result = chooseDictionary(kIONVRAMOperationRead, guid, name, &dict);
+	if (result != kIOReturnSuccess) {
+		DEBUG_INFO("No dictionary\n");
+		goto exit;
+	}
+
+	if (!verifyPermission(kIONVRAMOperationRead, guid, name)) {
 		DEBUG_INFO("Not privileged\n");
 		goto exit;
 	}
 
-	translateGUID(guid, name, newGuid, _format->getSystemPartitionActive(), true);
-
-	canonicalKey = keyWithGuidAndCString(newGuid, name);
-
-	theObject.reset(localVarDict->getObject(canonicalKey.get()), OSRetain);
-
-	if (_diags) {
-		_diags->logVariable(getPartitionTypeForGUID(newGuid), kIONVRAMOperationRead, name);
-	}
+	NVRAMREADLOCK();
+	theObject.reset(dict->getObject(name), OSRetain);
+	NVRAMUNLOCK();
 
 	if (theObject != nullptr) {
-		DEBUG_INFO("%s has object\n", canonicalKey.get()->getCStringNoCopy());
-	} else {
-		DEBUG_INFO("%s no entry\n", canonicalKey.get()->getCStringNoCopy());
+		DEBUG_INFO("found data\n");
 	}
 
 exit:
@@ -1885,7 +1272,7 @@
 
 	parseVariableName(aKey->getCStringNoCopy(), &varGuid, &variableName);
 
-	return copyPropertyWithGUIDAndName(varGuid, variableName);
+	return copyPropertyWithGUIDAndName(&varGuid, variableName);
 }
 
 OSSharedPtr<OSObject>
@@ -1923,83 +1310,34 @@
 }
 
 IOReturn
-IODTNVRAM::clearTestVars(const uuid_t guid)
-{
-	const VariablePermissionEntry *entry;
-	IOReturn ret = kIOReturnSuccess;
-	uuid_t newGuid;
-
-	entry = gVariablePermissions;
-	require_action(gInternalBuild, exit, DEBUG_INFO("Internal build only\n"));
-	require_action(_format != nullptr, exit, (ret = kIOReturnNotReady, DEBUG_ERROR("Handler not initialized yet\n")));
-
-	while ((entry != nullptr) && (entry->name != nullptr)) {
-		if (entry->p.Bits.TestingOnly) {
-			translateGUID(guid, entry->name, newGuid, _format->getSystemPartitionActive(), true);
-			ret = _format->setVariable(newGuid, entry->name, nullptr);
-		}
-		entry++;
-	}
-
-exit:
-	return ret;
-}
-
-IOReturn
-IODTNVRAM::setPropertyWithGUIDAndName(const uuid_t guid, const char *name, OSObject *anObject)
+IODTNVRAM::setPropertyWithGUIDAndName(const uuid_t *guid, const char *name, OSObject *anObject)
 {
 	IOReturn              ret = kIOReturnSuccess;
 	bool                  remove = false;
 	OSString              *tmpString = nullptr;
-	OSSharedPtr<OSObject> propObject;
+	OSSharedPtr<OSObject> propObject, oldObject;
 	OSSharedPtr<OSObject> sharedObject(anObject, OSRetain);
-	bool                  deletePropertyKey, syncNowPropertyKey, forceSyncNowPropertyKey, deletePropertyKeyWRet;
+	OSDictionary          *dict;
+	bool                  deletePropertyKey, syncNowPropertyKey, forceSyncNowPropertyKey;
 	bool                  ok;
 	size_t                propDataSize = 0;
-	uuid_t                newGuid;
-
-	require_action(_format != nullptr, exit, (ret = kIOReturnNotReady, DEBUG_ERROR("Handler not initialized yet\n")));
-
-	if (strncmp(name, kNVRAMClearTestVarKey, sizeof(kNVRAMClearTestVarKey)) == 0) {
-		ret = clearTestVars(guid);
-		goto exit;
-	}
 
 	deletePropertyKey = strncmp(name, kIONVRAMDeletePropertyKey, sizeof(kIONVRAMDeletePropertyKey)) == 0;
-	deletePropertyKeyWRet = strncmp(name, kIONVRAMDeletePropertyKeyWRet, sizeof(kIONVRAMDeletePropertyKeyWRet)) == 0;
 	syncNowPropertyKey = strncmp(name, kIONVRAMSyncNowPropertyKey, sizeof(kIONVRAMSyncNowPropertyKey)) == 0;
 	forceSyncNowPropertyKey = strncmp(name, kIONVRAMForceSyncNowPropertyKey, sizeof(kIONVRAMForceSyncNowPropertyKey)) == 0;
 
-	if (deletePropertyKey || deletePropertyKeyWRet) {
+	if (deletePropertyKey) {
 		tmpString = OSDynamicCast(OSString, anObject);
 		if (tmpString != nullptr) {
 			const char *variableName;
-			uuid_t     valueVarGuid;
-			bool       guidProvided;
-			IOReturn   removeRet;
-
-			guidProvided = parseVariableName(tmpString->getCStringNoCopy(), &valueVarGuid, &variableName);
-
-			// nvram tool will provide a "nvram -d var" or "nvram -d guid:var" as
-			// kIONVRAMDeletePropertyKey=var or kIONVRAMDeletePropertyKey=guid:var
-			// that will come into this function as (gAppleNVRAMGuid, varname, nullptr)
-			// if we provide the "-z" flag to the nvram tool this function will come in as
-			// (gAppleSystemVariableGuid, varname, nullptr). We are reparsing the value string,
-			// if there is a GUID provided with the value then use that GUID otherwise use the
-			// guid that was provided via the node selection or default.
-			if (guidProvided == false) {
-				DEBUG_INFO("Removing with API provided GUID\n");
-				removeRet = removePropertyWithGUIDAndName(guid, variableName);
-			} else {
-				DEBUG_INFO("Removing with value provided GUID\n");
-				removeRet = removePropertyWithGUIDAndName(valueVarGuid, variableName);
-			}
-			if (deletePropertyKeyWRet) {
-				ret = removeRet;
-			}
-			DEBUG_INFO("%s found, removeRet=%#08x\n", deletePropertyKeyWRet ? "deletePropertyKeyWRet" : "deletePropertyKey", removeRet);
+			uuid_t     varGuid;
+
+			DEBUG_INFO("kIONVRAMDeletePropertyKey found\n");
+
+			parseVariableName(tmpString->getCStringNoCopy(), &varGuid, &variableName);
+			removePropertyWithGUIDAndName(&varGuid, variableName);
 		} else {
-			DEBUG_INFO("%s value needs to be an OSString\n", deletePropertyKeyWRet ? "deletePropertyKeyWRet" : "deletePropertyKey");
+			DEBUG_INFO("kIONVRAMDeletePropertyKey value needs to be an OSString\n");
 			ret = kIOReturnError;
 		}
 		goto exit;
@@ -2008,7 +1346,7 @@
 		DEBUG_INFO("NVRAM sync key %s found\n", name);
 		if (tmpString != nullptr) {
 			// We still want to throttle NVRAM commit rate for SyncNow. ForceSyncNow is provided as a really big hammer.
-			ret = syncInternal(syncNowPropertyKey);
+			syncInternal(syncNowPropertyKey);
 		} else {
 			DEBUG_INFO("%s value needs to be an OSString\n", name);
 			ret = kIOReturnError;
@@ -2016,7 +1354,13 @@
 		goto exit;
 	}
 
-	if (!verifyPermission(kIONVRAMOperationWrite, guid, name, _format->getSystemPartitionActive(), true)) {
+	ret = chooseDictionary(kIONVRAMOperationWrite, guid, name, &dict);
+	if (ret != kIOReturnSuccess) {
+		DEBUG_INFO("No dictionary\n");
+		goto exit;
+	}
+
+	if (!verifyPermission(kIONVRAMOperationWrite, guid, name)) {
 		DEBUG_INFO("Not privileged\n");
 		ret = kIOReturnNotPrivileged;
 		goto exit;
@@ -2026,23 +1370,15 @@
 	switch (getVariableType(name)) {
 	case kOFVariableTypeBoolean:
 		propObject = OSDynamicPtrCast<OSBoolean>(sharedObject);
-		if (propObject) {
-			record_system_event(SYSTEM_EVENT_TYPE_INFO, SYSTEM_EVENT_SUBSYSTEM_NVRAM, "write", "%s as bool to %d", name, ((OSBoolean *)propObject.get())->getValue());
-		}
 		break;
 
 	case kOFVariableTypeNumber:
 		propObject = OSDynamicPtrCast<OSNumber>(sharedObject);
-		if (propObject) {
-			record_system_event(SYSTEM_EVENT_TYPE_INFO, SYSTEM_EVENT_SUBSYSTEM_NVRAM, "write", "%s as number to %#llx", name, ((OSNumber *)propObject.get())->unsigned64BitValue());
-		}
 		break;
 
 	case kOFVariableTypeString:
 		propObject = OSDynamicPtrCast<OSString>(sharedObject);
 		if (propObject != nullptr) {
-			record_system_event(SYSTEM_EVENT_TYPE_INFO, SYSTEM_EVENT_SUBSYSTEM_NVRAM, "write", "%s as string to %s", name, ((OSString *)propObject.get())->getCStringNoCopy());
-
 			propDataSize = (OSDynamicPtrCast<OSString>(propObject))->getLength();
 
 			if ((strncmp(name, kIONVRAMBootArgsKey, sizeof(kIONVRAMBootArgsKey)) == 0) && (propDataSize >= BOOT_LINE_LENGTH)) {
@@ -2064,10 +1400,7 @@
 		}
 
 		if (propObject != nullptr) {
-			OSSharedPtr<OSData> propData = OSDynamicPtrCast<OSData>(propObject);
-			propDataSize = propData->getLength();
-			record_system_event(SYSTEM_EVENT_TYPE_INFO, SYSTEM_EVENT_SUBSYSTEM_NVRAM, "write", "%s as data with size %zu", name, propDataSize);
-			dumpData(name, propData);
+			propDataSize = (OSDynamicPtrCast<OSData>(propObject))->getLength();
 		}
 
 #if defined(XNU_TARGET_OS_OSX)
@@ -2081,7 +1414,7 @@
 	}
 
 	if (propObject == nullptr) {
-		DEBUG_ERROR("No property object\n");
+		DEBUG_INFO("No property object\n");
 		ret = kIOReturnBadArgument;
 		goto exit;
 	}
@@ -2092,22 +1425,57 @@
 		goto exit;
 	}
 
+	NVRAMWRITELOCK();
 	ok = handleSpecialVariables(name, guid, propObject.get(), &ret);
+	NVRAMUNLOCK();
 
 	if (ok) {
+		serializeVariables();
 		goto exit;
 	}
+
+	NVRAMREADLOCK();
+	oldObject.reset(dict->getObject(name), OSRetain);
+	NVRAMUNLOCK();
 
 	if (remove == false) {
 		DEBUG_INFO("Adding object\n");
-
-		translateGUID(guid, name, newGuid, _format->getSystemPartitionActive(), true);
-		ret = _format->setVariable(newGuid, name, propObject.get());
+		NVRAMWRITELOCK();
+		if (!dict->setObject(name, propObject.get())) {
+			ret = kIOReturnBadArgument;
+		}
+		NVRAMUNLOCK();
 	} else {
 		DEBUG_INFO("Removing object\n");
-		ret = removePropertyWithGUIDAndName(guid, name);
-	}
-
+		// Check for existence so we can decide whether we need to sync variables
+		if (oldObject) {
+			ret = removePropertyWithGUIDAndName(guid, name);
+		} else {
+			ret = kIOReturnNotFound;
+		}
+	}
+
+	if (ret == kIOReturnSuccess) {
+		ret = serializeVariables();
+		if (ret != kIOReturnSuccess) {
+			DEBUG_ERROR("serializeVariables failed, ret=%#08x\n", ret);
+
+			NVRAMWRITELOCK();
+			if (oldObject) {
+				dict->setObject(name, oldObject.get());
+			} else {
+				dict->removeObject(name);
+			}
+			NVRAMUNLOCK();
+
+			(void) serializeVariables();
+			ret = kIOReturnNoMemory;
+		}
+	}
+
+	if (oldObject) {
+		oldObject.reset();
+	}
 	if (tmpString) {
 		propObject.reset();
 	}
@@ -2121,14 +1489,14 @@
 IOReturn
 IODTNVRAM::setPropertyInternal(const OSSymbol *aKey, OSObject *anObject)
 {
-	const char *variableName;
-	uuid_t     varGuid;
+	const char            *variableName;
+	uuid_t                varGuid;
 
 	DEBUG_INFO("aKey=%s\n", aKey->getCStringNoCopy());
 
 	parseVariableName(aKey->getCStringNoCopy(), &varGuid, &variableName);
 
-	return setPropertyWithGUIDAndName(varGuid, variableName, anObject);
+	return setPropertyWithGUIDAndName(&varGuid, variableName, anObject);
 }
 
 bool
@@ -2144,35 +1512,50 @@
 
 	ret = removePropertyInternal(aKey);
 
+	if (ret == kIOReturnSuccess) {
+		serializeVariables();
+	} else {
+		DEBUG_INFO("removePropertyInternal failed, ret=%#08x\n", ret);
+	}
+}
+
+IOReturn
+IODTNVRAM::removePropertyWithGUIDAndName(const uuid_t *guid, const char *name)
+{
+	IOReturn     ret;
+	OSDictionary *dict;
+	bool removed = false;
+
+	DEBUG_INFO("name=%s\n", name);
+
+	ret = chooseDictionary(kIONVRAMOperationDelete, guid, name, &dict);
 	if (ret != kIOReturnSuccess) {
-		DEBUG_INFO("removePropertyInternal failed, ret=%#08x\n", ret);
-	}
-}
-
-IOReturn
-IODTNVRAM::removePropertyWithGUIDAndName(const uuid_t guid, const char *name)
-{
-	IOReturn ret;
-	uuid_t   newGuid;
-
-	DEBUG_INFO("name=%s\n", name);
-	require_action(_format != nullptr, exit, (ret = kIOReturnNotReady, DEBUG_ERROR("Handler not initialized yet\n")));
-
-	if (!verifyPermission(kIONVRAMOperationDelete, guid, name, _format->getSystemPartitionActive(), true)) {
-		DEBUG_INFO("Not privileged\n");
+		DEBUG_INFO("No dictionary\n");
+		goto exit;
+	}
+
+	if (!verifyPermission(kIONVRAMOperationDelete, guid, name)) {
+		DEBUG_INFO("Not priveleged\n");
 		ret = kIOReturnNotPrivileged;
 		goto exit;
 	}
 
-	translateGUID(guid, name, newGuid, _format->getSystemPartitionActive(), true);
-	ret = _format->setVariable(newGuid, name, nullptr);
-
-	if (ret != kIOReturnSuccess) {
+	NVRAMWRITELOCK();
+
+	// If the object exists, remove it from the dictionary.
+	if (dict->getObject(name) != nullptr) {
+		dict->removeObject(name);
+		removed = true;
+	} else {
 		DEBUG_INFO("%s not found\n", name);
-		ret = kIOReturnNotFound;
-	}
-
-	record_system_event(SYSTEM_EVENT_TYPE_INFO, SYSTEM_EVENT_SUBSYSTEM_NVRAM, "delete", "%s", name);
+	}
+
+	NVRAMUNLOCK();
+
+	if (removed) {
+		ret = serializeVariables();
+		DEBUG_INFO("serializeVariables ret=0x%08x\n", ret);
+	}
 
 exit:
 	return ret;
@@ -2181,15 +1564,15 @@
 IOReturn
 IODTNVRAM::removePropertyInternal(const OSSymbol *aKey)
 {
-	IOReturn   ret;
-	const char *variableName;
-	uuid_t     varGuid;
+	IOReturn     ret;
+	const char   *variableName;
+	uuid_t       varGuid;
 
 	DEBUG_INFO("aKey=%s\n", aKey->getCStringNoCopy());
 
 	parseVariableName(aKey->getCStringNoCopy(), &varGuid, &variableName);
 
-	ret = removePropertyWithGUIDAndName(varGuid, variableName);
+	ret = removePropertyWithGUIDAndName(&varGuid, variableName);
 
 	return ret;
 }
@@ -2234,17 +1617,15 @@
 	return ret;
 }
 
-// ********************** Deprecated ********************
-
 IOReturn
-IODTNVRAM::readXPRAM(IOByteCount offset, uint8_t *buffer,
+IODTNVRAM::readXPRAM(IOByteCount offset, UInt8 *buffer,
     IOByteCount length)
 {
 	return kIOReturnUnsupported;
 }
 
 IOReturn
-IODTNVRAM::writeXPRAM(IOByteCount offset, uint8_t *buffer,
+IODTNVRAM::writeXPRAM(IOByteCount offset, UInt8 *buffer,
     IOByteCount length)
 {
 	return kIOReturnUnsupported;
@@ -2255,7 +1636,11 @@
     const OSSymbol **name,
     OSData **value)
 {
-	return kIOReturnUnsupported;
+	IOReturn err;
+
+	err = readNVRAMPropertyType1(entry, name, value);
+
+	return err;
 }
 
 IOReturn
@@ -2263,33 +1648,941 @@
     const OSSymbol *name,
     OSData *value)
 {
-	return kIOReturnUnsupported;
+	IOReturn err;
+
+	err = writeNVRAMPropertyType1(entry, name, value);
+
+	return err;
 }
 
 OSDictionary *
 IODTNVRAM::getNVRAMPartitions(void)
 {
-	return NULL;
+	return _nvramPartitionLengths.get();
 }
 
 IOReturn
 IODTNVRAM::readNVRAMPartition(const OSSymbol *partitionID,
-    IOByteCount offset, uint8_t *buffer,
+    IOByteCount offset, UInt8 *buffer,
     IOByteCount length)
 {
-	return kIOReturnUnsupported;
+	OSNumber *partitionOffsetNumber, *partitionLengthNumber;
+	UInt32   partitionOffset, partitionLength, end;
+
+	partitionOffsetNumber =
+	    (OSNumber *)_nvramPartitionOffsets->getObject(partitionID);
+	partitionLengthNumber =
+	    (OSNumber *)_nvramPartitionLengths->getObject(partitionID);
+
+	if ((partitionOffsetNumber == nullptr) || (partitionLengthNumber == nullptr)) {
+		return kIOReturnNotFound;
+	}
+
+	partitionOffset = partitionOffsetNumber->unsigned32BitValue();
+	partitionLength = partitionLengthNumber->unsigned32BitValue();
+
+	if (os_add_overflow(offset, length, &end)) {
+		return kIOReturnBadArgument;
+	}
+	if ((buffer == nullptr) || (length == 0) || (end > partitionLength)) {
+		return kIOReturnBadArgument;
+	}
+
+	bcopy(_nvramImage + partitionOffset + offset, buffer, length);
+
+	return kIOReturnSuccess;
 }
 
 IOReturn
 IODTNVRAM::writeNVRAMPartition(const OSSymbol *partitionID,
-    IOByteCount offset, uint8_t *buffer,
+    IOByteCount offset, UInt8 *buffer,
     IOByteCount length)
 {
+	OSNumber *partitionOffsetNumber, *partitionLengthNumber;
+	UInt32   partitionOffset, partitionLength, end;
+
+	partitionOffsetNumber =
+	    (OSNumber *)_nvramPartitionOffsets->getObject(partitionID);
+	partitionLengthNumber =
+	    (OSNumber *)_nvramPartitionLengths->getObject(partitionID);
+
+	if ((partitionOffsetNumber == nullptr) || (partitionLengthNumber == nullptr)) {
+		return kIOReturnNotFound;
+	}
+
+	partitionOffset = partitionOffsetNumber->unsigned32BitValue();
+	partitionLength = partitionLengthNumber->unsigned32BitValue();
+
+	if (os_add_overflow(offset, length, &end)) {
+		return kIOReturnBadArgument;
+	}
+	if ((buffer == nullptr) || (length == 0) || (end > partitionLength)) {
+		return kIOReturnBadArgument;
+	}
+
+	bcopy(buffer, _nvramImage + partitionOffset + offset, length);
+
+	if (_nvramController != nullptr) {
+		_nvramController->write(0, _nvramImage, _nvramSize);
+	}
+
+	return kIOReturnSuccess;
+}
+
+IOByteCount
+IODTNVRAM::savePanicInfo(UInt8 *buffer, IOByteCount length)
+{
+	return 0;
+}
+
+// Private methods
+
+UInt8
+IODTNVRAM::calculatePartitionChecksum(UInt8 *partitionHeader)
+{
+	UInt8 cnt, isum, csum = 0;
+
+	for (cnt = 0; cnt < 0x10; cnt++) {
+		isum = csum + partitionHeader[cnt];
+		if (isum < csum) {
+			isum++;
+		}
+		csum = isum;
+	}
+
+	return csum;
+}
+
+IOReturn
+IODTNVRAM::initVariables(void)
+{
+	UInt32                      cnt;
+	UInt8                       *propName, *propData;
+	UInt32                      propNameLength, propDataLength, regionIndex;
+	OSSharedPtr<const OSSymbol> propSymbol;
+	OSSharedPtr<OSObject>       propObject;
+	NVRAMRegionInfo             *currentRegion;
+	NVRAMRegionInfo             variableRegions[] = { { kIONVRAMPartitionCommon, _commonPartitionOffset, _commonPartitionSize, _commonDict, _commonImage},
+							  { kIONVRAMPartitionSystem, _systemPartitionOffset, _systemPartitionSize, _systemDict, _systemImage} };
+
+	DEBUG_INFO("...\n");
+
+	for (regionIndex = 0; regionIndex < ARRAY_SIZE(variableRegions); regionIndex++) {
+		currentRegion = &variableRegions[regionIndex];
+
+		if (currentRegion->size == 0) {
+			continue;
+		}
+
+		currentRegion->dict = OSDictionary::withCapacity(1);
+
+		DEBUG_INFO("region = %d\n", currentRegion->type);
+		cnt = 0;
+		while (cnt < currentRegion->size) {
+			// Break if there is no name.
+			if (currentRegion->image[cnt] == '\0') {
+				break;
+			}
+
+			// Find the length of the name.
+			propName = currentRegion->image + cnt;
+			for (propNameLength = 0; (cnt + propNameLength) < currentRegion->size;
+			    propNameLength++) {
+				if (currentRegion->image[cnt + propNameLength] == '=') {
+					break;
+				}
+			}
+
+			// Break if the name goes past the end of the partition.
+			if ((cnt + propNameLength) >= currentRegion->size) {
+				break;
+			}
+			cnt += propNameLength + 1;
+
+			propData = currentRegion->image + cnt;
+			for (propDataLength = 0; (cnt + propDataLength) < currentRegion->size;
+			    propDataLength++) {
+				if (currentRegion->image[cnt + propDataLength] == '\0') {
+					break;
+				}
+			}
+
+			// Break if the data goes past the end of the partition.
+			if ((cnt + propDataLength) >= currentRegion->size) {
+				break;
+			}
+			cnt += propDataLength + 1;
+
+			if (convertPropToObject(propName, propNameLength,
+			    propData, propDataLength,
+			    propSymbol, propObject)) {
+				DEBUG_INFO("adding %s, dataLength=%u\n", propSymbol.get()->getCStringNoCopy(), (unsigned int)propDataLength);
+				currentRegion->dict.get()->setObject(propSymbol.get(), propObject.get());
+			}
+		}
+	}
+
+	// Create the boot-args property if it is not in the dictionary.
+	if (_systemDict != nullptr) {
+		if (_systemDict->getObject(kIONVRAMBootArgsKey) == nullptr) {
+			propObject = OSString::withCStringNoCopy("");
+			if (propObject != nullptr) {
+				_systemDict->setObject(kIONVRAMBootArgsKey, propObject.get());
+			}
+		}
+	} else if (_commonDict != nullptr) {
+		if (_commonDict->getObject(kIONVRAMBootArgsKey) == nullptr) {
+			propObject = OSString::withCStringNoCopy("");
+			if (propObject != nullptr) {
+				_commonDict->setObject(kIONVRAMBootArgsKey, propObject.get());
+			}
+		}
+	}
+
+	DEBUG_INFO("%s _commonDict=%p _systemDict=%p\n", __FUNCTION__, _commonDict ? _commonDict.get() : nullptr, _systemDict ? _systemDict.get() : nullptr);
+
+	return kIOReturnSuccess;
+}
+
+IOReturn
+IODTNVRAM::syncOFVariables(void)
+{
 	return kIOReturnUnsupported;
 }
 
-IOByteCount
-IODTNVRAM::savePanicInfo(uint8_t *buffer, IOByteCount length)
+IOReturn
+IODTNVRAM::serializeVariables(void)
+{
+	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[] = { { kIONVRAMPartitionCommon, _commonPartitionOffset, _commonPartitionSize, _commonDict, _commonImage},
+								{ kIONVRAMPartitionSystem, _systemPartitionOffset, _systemPartitionSize, _systemDict, _systemImage} };
+
+	if (_systemPanicked) {
+		return kIOReturnNotReady;
+	}
+
+	if (_nvramController == nullptr) {
+		DEBUG_ERROR("No _nvramController\n");
+		return kIOReturnNotReady;
+	}
+
+	DEBUG_INFO("...\n");
+
+	NVRAMREADLOCK();
+
+	for (regionIndex = 0; regionIndex < ARRAY_SIZE(variableRegions); regionIndex++) {
+		currentRegion = &variableRegions[regionIndex];
+
+		if (currentRegion->size == 0) {
+			continue;
+		}
+
+		DEBUG_INFO("region = %d\n", currentRegion->type);
+		buffer = tmpBuffer = IONew(UInt8, currentRegion->size);
+		if (buffer == nullptr) {
+			ok = false;
+			ret = kIOReturnNoMemory;
+			break;
+		}
+		bzero(buffer, currentRegion->size);
+
+		ok = true;
+		maxLength = currentRegion->size;
+
+		iter = OSCollectionIterator::withCollection(currentRegion->dict.get());
+		if (iter == nullptr) {
+			ok = false;
+		}
+
+		while (ok) {
+			tmpSymbol = OSDynamicCast(OSSymbol, iter->getNextObject());
+			if (tmpSymbol == nullptr) {
+				break;
+			}
+
+			DEBUG_INFO("adding variable %s\n", tmpSymbol->getCStringNoCopy());
+
+			tmpObject = currentRegion->dict->getObject(tmpSymbol);
+
+			length = maxLength;
+			ok = convertObjectToProp(tmpBuffer, &length, tmpSymbol, tmpObject);
+			if (ok) {
+				tmpBuffer += length;
+				maxLength -= length;
+			}
+		}
+
+		if (ok) {
+			bcopy(buffer, currentRegion->image, currentRegion->size);
+		}
+
+		if ((currentRegion->type == kIONVRAMPartitionSystem) &&
+		    (_systemService != nullptr)) {
+			_systemService->setVariables(_systemDict.get());
+			systemUsed = (uint32_t)(tmpBuffer - buffer);
+		} else if ((currentRegion->type == kIONVRAMPartitionCommon) &&
+		    (_commonService != nullptr)) {
+			_commonService->setVariables(_commonDict.get());
+			commonUsed = (uint32_t)(tmpBuffer - buffer);
+		}
+
+		IODelete(buffer, UInt8, currentRegion->size);
+
+		if (!ok) {
+			ret = kIOReturnBadArgument;
+			break;
+		}
+	}
+
+	NVRAMUNLOCK();
+
+	DEBUG_INFO("ok=%d\n", ok);
+
+	if (ok) {
+		nvramImage = OSData::withBytes(_nvramImage, _nvramSize);
+		CONTROLLERLOCK();
+
+		if (_systemService) {
+			sizeUsed = OSNumber::withNumber(systemUsed, 32);
+			_nvramController->setProperty("SystemUsed", sizeUsed.get());
+			DEBUG_INFO("SystemUsed=%u\n", (unsigned int)commonUsed);
+			sizeUsed.reset();
+		}
+
+		if (_commonService) {
+			sizeUsed = OSNumber::withNumber(commonUsed, 32);
+			_nvramController->setProperty("CommonUsed", sizeUsed.get());
+			DEBUG_INFO("CommonUsed=%u\n", (unsigned int)commonUsed);
+			sizeUsed.reset();
+		}
+
+		ret = _nvramController->write(0, (uint8_t *)nvramImage->getBytesNoCopy(), nvramImage->getLength());
+
+		CONTROLLERUNLOCK();
+	}
+
+	return ret;
+}
+
+UInt32
+IODTNVRAM::getOFVariableType(const char *propName) const
 {
 	return 0;
 }
+
+UInt32
+IODTNVRAM::getOFVariableType(const OSSymbol *propSymbol) const
+{
+	return 0;
+}
+
+
+UInt32
+IODTNVRAM::getOFVariablePerm(const char *propName) const
+{
+	return 0;
+}
+
+UInt32
+IODTNVRAM::getOFVariablePerm(const OSSymbol *propSymbol) const
+{
+	return 0;
+}
+
+bool
+IODTNVRAM::getOWVariableInfo(UInt32 variableNumber, const OSSymbol **propSymbol,
+    UInt32 *propType, UInt32 *propOffset)
+{
+	/* UNSUPPORTED */
+	return false;
+}
+bool
+IODTNVRAM::convertPropToObject(UInt8 *propName, UInt32 propNameLength,
+    UInt8 *propData, UInt32 propDataLength,
+    const OSSymbol **propSymbol,
+    OSObject **propObject)
+{
+	OSSharedPtr<const OSSymbol> tmpSymbol;
+	OSSharedPtr<OSNumber>       tmpNumber;
+	OSSharedPtr<OSString>       tmpString;
+	OSSharedPtr<OSObject>       tmpObject = nullptr;
+
+	propName[propNameLength] = '\0';
+	tmpSymbol = OSSymbol::withCString((const char *)propName);
+	propName[propNameLength] = '=';
+	if (tmpSymbol == nullptr) {
+		return false;
+	}
+
+	switch (getVariableType(tmpSymbol.get())) {
+	case kOFVariableTypeBoolean:
+		if (!strncmp("true", (const char *)propData, propDataLength)) {
+			tmpObject.reset(kOSBooleanTrue, OSRetain);
+		} else if (!strncmp("false", (const char *)propData, propDataLength)) {
+			tmpObject.reset(kOSBooleanFalse, OSRetain);
+		}
+		break;
+
+	case kOFVariableTypeNumber:
+		tmpNumber = OSNumber::withNumber(strtol((const char *)propData, nullptr, 0), 32);
+		if (tmpNumber != nullptr) {
+			tmpObject = tmpNumber;
+		}
+		break;
+
+	case kOFVariableTypeString:
+		tmpString = OSString::withCString((const char *)propData);
+		if (tmpString != nullptr) {
+			tmpObject = tmpString;
+		}
+		break;
+
+	case kOFVariableTypeData:
+		tmpObject = unescapeBytesToData(propData, propDataLength);
+		break;
+
+	default:
+		break;
+	}
+
+	if (tmpObject == nullptr) {
+		tmpSymbol.reset();
+		return false;
+	}
+
+	*propSymbol = tmpSymbol.detach();
+	*propObject = tmpObject.detach();
+
+	return true;
+}
+
+bool
+IODTNVRAM::convertPropToObject(UInt8 *propName, UInt32 propNameLength,
+    UInt8 *propData, UInt32 propDataLength,
+    OSSharedPtr<const OSSymbol>& propSymbol,
+    OSSharedPtr<OSObject>& propObject)
+{
+	const OSSymbol* propSymbolRaw = nullptr;
+	OSObject* propObjectRaw = nullptr;
+	bool ok = convertPropToObject(propName, propNameLength, propData, propDataLength,
+	    &propSymbolRaw, &propObjectRaw);
+	propSymbol.reset(propSymbolRaw, OSNoRetain);
+	propObject.reset(propObjectRaw, OSNoRetain);
+	return ok;
+}
+
+bool
+IODTNVRAM::convertObjectToProp(UInt8 *buffer, UInt32 *length,
+    const OSSymbol *propSymbol, OSObject *propObject)
+{
+	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 = getVariableType(propSymbol);
+
+	// Get the size of the data.
+	propDataLength = 0xFFFFFFFF;
+	switch (propType) {
+	case kOFVariableTypeBoolean:
+		tmpBoolean = OSDynamicCast(OSBoolean, propObject);
+		if (tmpBoolean != nullptr) {
+			propDataLength = 5;
+		}
+		break;
+
+	case kOFVariableTypeNumber:
+		tmpNumber = OSDynamicCast(OSNumber, propObject);
+		if (tmpNumber != nullptr) {
+			propDataLength = 10;
+		}
+		break;
+
+	case kOFVariableTypeString:
+		tmpString = OSDynamicCast(OSString, propObject);
+		if (tmpString != nullptr) {
+			propDataLength = tmpString->getLength();
+		}
+		break;
+
+	case kOFVariableTypeData:
+		tmpData.reset(OSDynamicCast(OSData, propObject), OSNoRetain);
+		if (tmpData != nullptr) {
+			tmpData = escapeDataToData(tmpData.detach());
+			propDataLength = tmpData->getLength();
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	// Make sure the propertySize is known and will fit.
+	if (propDataLength == 0xFFFFFFFF) {
+		return false;
+	}
+	if ((propNameLength + propDataLength + 2) > *length) {
+		return false;
+	}
+
+	// Copy the property name equal sign.
+	buffer += snprintf((char *)buffer, *length, "%s=", propName);
+	remaining = *length - propNameLength - 1;
+
+	switch (propType) {
+	case kOFVariableTypeBoolean:
+		if (tmpBoolean->getValue()) {
+			strlcpy((char *)buffer, "true", remaining);
+		} else {
+			strlcpy((char *)buffer, "false", remaining);
+		}
+		break;
+
+	case kOFVariableTypeNumber:
+	{
+		uint32_t tmpValue = tmpNumber->unsigned32BitValue();
+		if (tmpValue == 0xFFFFFFFF) {
+			strlcpy((char *)buffer, "-1", remaining);
+		} else if (tmpValue < 1000) {
+			snprintf((char *)buffer, remaining, "%d", (uint32_t)tmpValue);
+		} else {
+			snprintf((char *)buffer, remaining, "%#x", (uint32_t)tmpValue);
+		}
+	}
+	break;
+
+	case kOFVariableTypeString:
+		strlcpy((char *)buffer, tmpString->getCStringNoCopy(), remaining);
+		break;
+
+	case kOFVariableTypeData:
+		bcopy(tmpData->getBytesNoCopy(), buffer, propDataLength);
+		tmpData.reset();
+		break;
+
+	default:
+		break;
+	}
+
+	propDataLength = ((UInt32) strlen((const char *)buffer));
+
+	*length = propNameLength + propDataLength + 2;
+
+	return true;
+}
+
+
+UInt16
+IODTNVRAM::generateOWChecksum(UInt8 *buffer)
+{
+	UInt32 cnt, checksum = 0;
+	UInt16 *tmpBuffer = (UInt16 *)buffer;
+
+	for (cnt = 0; cnt < _commonPartitionSize / 2; cnt++) {
+		checksum += tmpBuffer[cnt];
+	}
+
+	return checksum % 0x0000FFFF;
+}
+
+bool
+IODTNVRAM::validateOWChecksum(UInt8 *buffer)
+{
+	UInt32 cnt, checksum, sum = 0;
+	UInt16 *tmpBuffer = (UInt16 *)buffer;
+
+	for (cnt = 0; cnt < _commonPartitionSize / 2; cnt++) {
+		sum += tmpBuffer[cnt];
+	}
+
+	checksum = (sum >> 16) + (sum & 0x0000FFFF);
+	if (checksum == 0x10000) {
+		checksum--;
+	}
+	checksum = (checksum ^ 0x0000FFFF) & 0x0000FFFF;
+
+	return checksum == 0;
+}
+
+void
+IODTNVRAM::updateOWBootArgs(const OSSymbol *key, OSObject *value)
+{
+	/* UNSUPPORTED */
+}
+
+bool
+IODTNVRAM::searchNVRAMProperty(IONVRAMDescriptor *hdr, UInt32 *where)
+{
+	return false;
+}
+
+IOReturn
+IODTNVRAM::readNVRAMPropertyType0(IORegistryEntry *entry,
+    const OSSymbol **name,
+    OSData **value)
+{
+	return kIOReturnUnsupported;
+}
+
+
+IOReturn
+IODTNVRAM::writeNVRAMPropertyType0(IORegistryEntry *entry,
+    const OSSymbol *name,
+    OSData *value)
+{
+	return kIOReturnUnsupported;
+}
+
+
+OSSharedPtr<OSData>
+IODTNVRAM::unescapeBytesToData(const UInt8 *bytes, UInt32 length)
+{
+	OSSharedPtr<OSData> data;
+	UInt32              totalLength = 0;
+	UInt32              cnt, cnt2;
+	UInt8               byte;
+	bool                ok;
+
+	// Calculate the actual length of the data.
+	ok = true;
+	totalLength = 0;
+	for (cnt = 0; cnt < length;) {
+		byte = bytes[cnt++];
+		if (byte == 0xFF) {
+			byte = bytes[cnt++];
+			if (byte == 0x00) {
+				ok = false;
+				break;
+			}
+			cnt2 = byte & 0x7F;
+		} else {
+			cnt2 = 1;
+		}
+		totalLength += cnt2;
+	}
+
+	if (ok) {
+		// Create an empty OSData of the correct size.
+		data = OSData::withCapacity(totalLength);
+		if (data != nullptr) {
+			for (cnt = 0; cnt < length;) {
+				byte = bytes[cnt++];
+				if (byte == 0xFF) {
+					byte = bytes[cnt++];
+					cnt2 = byte & 0x7F;
+					byte = (byte & 0x80) ? 0xFF : 0x00;
+				} else {
+					cnt2 = 1;
+				}
+				data->appendByte(byte, cnt2);
+			}
+		}
+	}
+
+	return data;
+}
+
+OSSharedPtr<OSData>
+IODTNVRAM::escapeDataToData(OSData * value)
+{
+	OSSharedPtr<OSData> result;
+	const UInt8         *startPtr;
+	const UInt8         *endPtr;
+	const UInt8         *wherePtr;
+	UInt8               byte;
+	bool                ok = true;
+
+	wherePtr = (const UInt8 *) value->getBytesNoCopy();
+	endPtr = wherePtr + value->getLength();
+
+	result = OSData::withCapacity((unsigned int) (endPtr - wherePtr));
+	if (!result) {
+		return result;
+	}
+
+	while (wherePtr < endPtr) {
+		startPtr = wherePtr;
+		byte = *wherePtr++;
+		if ((byte == 0x00) || (byte == 0xFF)) {
+			for (;
+			    ((wherePtr - startPtr) < 0x80) && (wherePtr < endPtr) && (byte == *wherePtr);
+			    wherePtr++) {
+			}
+			ok &= result->appendByte(0xff, 1);
+			byte = (byte & 0x80) | ((UInt8)(wherePtr - startPtr));
+		}
+		ok &= result->appendByte(byte, 1);
+	}
+	ok &= result->appendByte(0, 1);
+
+	if (!ok) {
+		result.reset();
+	}
+
+	return result;
+}
+
+static bool
+IsApplePropertyName(const char * propName)
+{
+	char c;
+	while ((c = *propName++)) {
+		if ((c >= 'A') && (c <= 'Z')) {
+			break;
+		}
+	}
+
+	return c == 0;
+}
+
+IOReturn
+IODTNVRAM::readNVRAMPropertyType1(IORegistryEntry *entry,
+    const OSSymbol **name,
+    OSData **value)
+{
+	IOReturn    err = kIOReturnNoResources;
+	OSData      *data;
+	const UInt8 *startPtr;
+	const UInt8 *endPtr;
+	const UInt8 *wherePtr;
+	const UInt8 *nvPath = nullptr;
+	const char  *nvName = nullptr;
+	const char  *resultName = nullptr;
+	const UInt8 *resultValue = nullptr;
+	UInt32       resultValueLen = 0;
+	UInt8       byte;
+
+	NVRAMREADLOCK();
+	data = OSDynamicCast(OSData, _commonDict->getObject(_registryPropertiesKey.get()));
+	NVRAMUNLOCK();
+
+	if (data == nullptr) {
+		return err;
+	}
+
+	startPtr = (const UInt8 *) data->getBytesNoCopy();
+	endPtr = startPtr + data->getLength();
+
+	wherePtr = startPtr;
+	while (wherePtr < endPtr) {
+		byte = *(wherePtr++);
+		if (byte) {
+			continue;
+		}
+
+		if (nvPath == nullptr) {
+			nvPath = startPtr;
+		} else if (nvName == nullptr) {
+			nvName = (const char *) startPtr;
+		} else {
+			OSSharedPtr<IORegistryEntry> compareEntry = IORegistryEntry::fromPath((const char *) nvPath, gIODTPlane);
+			if (entry == compareEntry) {
+				bool appleProp = IsApplePropertyName(nvName);
+				if (!appleProp || !resultName) {
+					resultName     = nvName;
+					resultValue    = startPtr;
+					resultValueLen = (UInt32) (wherePtr - startPtr - 1);  // OSData getLength() is 32b
+				}
+				if (!appleProp) {
+					break;
+				}
+			}
+			nvPath = nullptr;
+			nvName = nullptr;
+		}
+		startPtr = wherePtr;
+	}
+	if (resultName) {
+		*name = OSSymbol::withCString(resultName).detach();
+		*value = unescapeBytesToData(resultValue, resultValueLen).detach();
+		if ((*name != nullptr) && (*value != nullptr)) {
+			err = kIOReturnSuccess;
+		} else {
+			err = kIOReturnNoMemory;
+		}
+	}
+	return err;
+}
+
+IOReturn
+IODTNVRAM::writeNVRAMPropertyType1(IORegistryEntry *entry,
+    const OSSymbol *propName,
+    OSData *value)
+{
+	OSSharedPtr<OSData> data, oldData;
+	const UInt8         *startPtr;
+	const UInt8         *propStart;
+	const UInt8         *endPtr;
+	const UInt8         *wherePtr;
+	const UInt8         *nvPath = nullptr;
+	const char          *nvName = nullptr;
+	const char          *comp;
+	const char          *name;
+	UInt8               byte;
+	bool                ok = true;
+	bool                settingAppleProp;
+
+	settingAppleProp = IsApplePropertyName(propName->getCStringNoCopy());
+
+	// copy over existing properties for other entries
+
+	NVRAMWRITELOCK();
+
+	oldData.reset(OSDynamicCast(OSData, _commonDict->getObject(_registryPropertiesKey.get())), OSRetain);
+	if (oldData) {
+		startPtr = (const UInt8 *) oldData->getBytesNoCopy();
+		endPtr = startPtr + oldData->getLength();
+
+		propStart = startPtr;
+		wherePtr = startPtr;
+		while (wherePtr < endPtr) {
+			byte = *(wherePtr++);
+			if (byte) {
+				continue;
+			}
+			if (nvPath == nullptr) {
+				nvPath = startPtr;
+			} else if (nvName == nullptr) {
+				nvName = (const char *) startPtr;
+			} else {
+				OSSharedPtr<IORegistryEntry> compareEntry = IORegistryEntry::fromPath((const char *) nvPath, gIODTPlane);
+
+				if (entry == compareEntry) {
+					if ((settingAppleProp && propName->isEqualTo(nvName))
+					    || (!settingAppleProp && !IsApplePropertyName(nvName))) {
+						// delete old property (nvPath -> wherePtr) source OSData len is 32b
+						data = OSData::withBytes(propStart, (UInt32)(nvPath - propStart));
+						if (data) {
+							ok &= data->appendBytes(wherePtr, (UInt32)(endPtr - wherePtr));
+						}
+						break;
+					}
+				}
+				nvPath = nullptr;
+				nvName = nullptr;
+			}
+
+			startPtr = wherePtr;
+		}
+	}
+
+	// make the new property
+
+	if (!data) {
+		if (oldData) {
+			data = OSData::withData(oldData.get());
+		} else {
+			data = OSData::withCapacity(16);
+		}
+		if (!data) {
+			ok = false;
+		}
+	}
+
+	if (ok && value && value->getLength()) {
+		do {
+			// get entries in path
+			OSSharedPtr<OSArray> array = OSArray::withCapacity(5);
+			if (!array) {
+				ok = false;
+				break;
+			}
+			do{
+				array->setObject(entry);
+			} while ((entry = entry->getParentEntry(gIODTPlane)));
+
+			// append path
+			for (int i = array->getCount() - 3;
+			    (entry = (IORegistryEntry *) array->getObject(i));
+			    i--) {
+				name = entry->getName(gIODTPlane);
+				comp = entry->getLocation(gIODTPlane);
+				if (comp) {
+					ok &= data->appendBytes("/@", 2);
+				} else {
+					if (!name) {
+						continue;
+					}
+					ok &= data->appendByte('/', 1);
+					comp = name;
+				}
+				ok &= data->appendBytes(comp, (unsigned int) strnlen(comp, UINT16_MAX));
+			}
+			ok &= data->appendByte(0, 1);
+			// append prop name
+			ok &= data->appendBytes(propName->getCStringNoCopy(), propName->getLength() + 1);
+
+			// append escaped data
+			OSSharedPtr<OSData> escapedData = escapeDataToData(value);
+			ok &= (escapedData != nullptr);
+			if (ok) {
+				ok &= data->appendBytes(escapedData.get());
+			}
+		} while (false);
+	}
+
+	if (ok) {
+		ok = _commonDict->setObject(_registryPropertiesKey.get(), data.get());
+	}
+
+	NVRAMUNLOCK();
+
+	if (ok) {
+		if (serializeVariables() != kIOReturnSuccess) {
+			NVRAMWRITELOCK();
+			if (oldData) {
+				_commonDict->setObject(_registryPropertiesKey.get(), oldData.get());
+			} else {
+				_commonDict->removeObject(_registryPropertiesKey.get());
+			}
+			NVRAMUNLOCK();
+
+			(void) serializeVariables();
+			ok = false;
+		}
+	}
+
+	oldData.reset();
+
+	return ok ? kIOReturnSuccess : kIOReturnNoMemory;
+}
+
+bool
+IODTNVRAM::safeToSync(void)
+{
+	AbsoluteTime delta;
+	UInt64       delta_ns;
+	SInt32       delta_secs;
+
+	// delta interval went by
+	clock_get_uptime(&delta);
+
+	// Figure it in seconds.
+	absolutetime_to_nanoseconds(delta, &delta_ns);
+	delta_secs = (SInt32)(delta_ns / NSEC_PER_SEC);
+
+	if ((delta_secs > (_lastDeviceSync + MIN_SYNC_NOW_INTERVAL)) || _freshInterval) {
+		_lastDeviceSync = delta_secs;
+		_freshInterval = FALSE;
+		return TRUE;
+	}
+
+	return FALSE;
+}