]> git.saurik.com Git - apple/xnu.git/blobdiff - iokit/Kernel/IONVRAM.cpp
xnu-7195.101.1.tar.gz
[apple/xnu.git] / iokit / Kernel / IONVRAM.cpp
index 69725d4036657eaf7c4a6ca8da913764f24fd422..06d2efcdbad7a48add563e25a5b956581d7fada8 100644 (file)
@@ -40,6 +40,7 @@
 #include <kern/debug.h>
 #include <pexpert/boot.h>
 #include <pexpert/pexpert.h>
+#include <sys/csr.h>
 
 #define super IOService
 
 // From Apple CHRP Spec
 #define NVRAM_CHRP_SIG_SYSTEM    0x70
 #define NVRAM_CHRP_SIG_CONFIG    0x71
-#define NVRAM_CHRP_SIG_FREESPACE 0x7F
 
-#define NVRAM_CHRP_PARTITION_NAME_COMMON        "common"
-#define NVRAM_CHRP_PARTITION_NAME_SYSTEM        "system"
-#define NVRAM_CHRP_PARTITION_NAME_SYSTEM_LEGACY "secure"
-#define NVRAM_CHRP_PARTITION_NAME_FREESPACE     "\x77\x77\x77\x77\x77\x77\x77\x77\x77\x77\x77\x77"
+#define NVRAM_CHRP_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
 
@@ -112,26 +112,43 @@ OSDefineMetaClassAndStructors(IODTNVRAM, IOService);
                IOLockUnlock(_controllerLock);       \
 })
 
-#define NVRAMLOCK()                              \
-({                                               \
+#define NVRAMREADLOCK()                             \
+({                                                  \
        if (preemption_enabled() && !panic_active()) \
-               IOLockLock(_variableLock);           \
+               IORWLockRead(_variableLock);         \
 })
 
-#define NVRAMUNLOCK()                            \
-({                                               \
+#define NVRAMWRITELOCK()                            \
+({                                                  \
        if (preemption_enabled() && !panic_active()) \
-               IOLockUnlock(_variableLock);         \
+               IORWLockWrite(_variableLock);        \
 })
 
-#define NVRAMLOCKASSERT()                                    \
-({                                                           \
-       if (preemption_enabled() && !panic_active())             \
-               IOLockAssert(_variableLock, kIOLockAssertOwned); \
+#define NVRAMUNLOCK()                               \
+({                                                  \
+       if (preemption_enabled() && !panic_active()) \
+               IORWLockUnlock(_variableLock);       \
+})
+
+#define NVRAMLOCKASSERTHELD()                                      \
+({                                                                 \
+       if (preemption_enabled() && !panic_active())                \
+               IORWLockAssert(_variableLock, kIORWLockAssertHeld); \
 })
 
+#define NVRAMLOCKASSERTEXCLUSIVE()                                  \
+({                                                                  \
+       if (preemption_enabled() && !panic_active())                 \
+               IORWLockAssert(_variableLock, kIORWLockAssertWrite); \
+})
+
+enum NVRAMPartitionType {
+       kIONVRAMPartitionSystem,
+       kIONVRAMPartitionCommon
+};
+
 typedef struct {
-       const char                *name;
+       NVRAMPartitionType        type;
        UInt32                    offset;
        UInt32                    size;
        OSSharedPtr<OSDictionary> &dict;
@@ -147,130 +164,29 @@ UUID_DEFINE(gAppleSystemVariableGuid, 0x40, 0xA0, 0xDD, 0xD2, 0x77, 0xF8, 0x43,
 UUID_DEFINE(gAppleNVRAMGuid, 0x7C, 0x43, 0x61, 0x10, 0xAB, 0x2A, 0x4B, 0xBB, 0xA8, 0x80, 0xFE, 0x41, 0x99, 0x5C, 0x9F, 0x82);
 
 static bool gNVRAMLogging = false;
+static bool gInternalBuild = false;
 
 // allowlist variables from macboot that need to be set/get from system region if present
 static const char * const gNVRAMSystemList[] = {
-       "adbe-tunable",
-       "adbe-tunables",
-       "adfe-tunables",
-       "alamo-path",
-       "alt-boot-volume",
-       "ASMB",
-       "atc0",
-       "atc1",
+       "allow-root-hash-mismatch",
        "auto-boot",
        "auto-boot-halt-stage",
-       "auto-boot-once",
-       "auto-boot-usb",
-       "auxkc-path",
-       "backlight-level",
-       "backlight-nits",
        "base-system-path",
        "boot-args",
-       "boot-breadcrumbs",
        "boot-command",
-       "boot-device",
        "boot-image",
-       "boot-partition",
-       "boot-path",
-       "boot-ramdisk",
-       "boot-script",
-       "boot-volume",
        "bootdelay",
-       "bt1addr",
-       "btaddr",
-       "cam-use-ext-ldo",
-       "CLCG_override",
        "com.apple.System.boot-nonce",
-       "com.apple.System.rtc-offset",
-       "com.apple.System.tz0-size",
-       "core-bin-offset",
-       "cpu-bin-offset",
        "darkboot",
-       "DClr_override",
-       "dcp-auto-boot",
-       "debug-gg",
-       "debug-soc",
-       "debug-uarts",
-       "diags-path",
-       "disable-boot-wdt",
-       "display-color-space",
-       "display-timing",
-       "display-vsh-comp",
-       "dpcd-max-brightness",
-       "dtdump",
-       "dtdump-path",
-       "e75",
        "emu",
-       "enable-auth-debug",
-       "enable-jop",
-       "enable-marconi",
-       "enable-upgrade-fallback",
-       "enforce-iuob",
-       "eth1addr",
-       "ethaddr",
-       "failboot-breadcrumbs",
-       "fixed-lcm-boost",
-       "force-ctrr-lock",
-       "force-upgrade-fail",
-       "fuos-path",
-       "hib-ui-force",
-       "hibhack-test-hmac",
-       "iboot-data",
-       "iboot-failure-reason",
-       "iboot-failure-reason-str",
-       "iboot-failure-volume",
-       "iboot1-precommitted",
-       "idle-off",
-       "is-tethered",
-       "kaslr-off",
-       "kaslr-slide",
-       "kis-rsm",
-       "knobs",
-       "loadaddr",
-       "memmapdump",
-       "mipi-bridge-cmd-verify",
-       "mipi-bridge-poll-cmd-fifo",
-       "no-ctrr",
-       "one-time-boot-command",
-       "osenvironment",
-       "ota-breadcrumbs",
-       "ota-outcome",
-       "panicmedic",
-       "panicmedic-threshold",
-       "panicmedic-timestamps",
-       "phleet-path",
-       "pinot-panel-id",
-       "pintoaddr",
+       "one-time-boot-command", // Needed for diags customer install flows
        "policy-nonce-digests",
-       "preserve-debuggability",
        "prevent-restores", // Keep for factory <rdar://problem/70476321>
        "prev-lang:kbd",
-       "ramrod-kickstart-aces",
-       "rbdaddr0",
-       "rbm-path",
-       "reconfig-behavior",
-       "reconfig-breakpoints",
-       "recovery-boot-mode",
-       "recovery-breadcrumbs",
-       "restored-host-timeout",
        "root-live-fs",
-       "rtos-path",
-       "soc-bin-offset",
-       "StartupMute",
-       "StartupMuteAccessibility",
-       "storage-prev-assert",
-       "storage-prev-assert-stored",
-       "summit-panel-id",
        "SystemAudioVolume",
        "SystemAudioVolumeExtension",
        "SystemAudioVolumeSaved",
-       "tz0-size-override",
-       "upgrade-fallback-boot-command",
-       "upgrade-retry",
-       "usb-enabled",
-       "wifi1addr",
-       "wifiaddr",
        nullptr
 };
 
@@ -361,7 +277,7 @@ VariablePermissionEntry gVariablePermissions[] = {
         .p.Bits.NeverAllowedToDelete = 1},
        {"boot-image", .p.Bits.UserWrite = 1},
        {"com.apple.System.fp-state", .p.Bits.KernelOnly = 1},
-       {"policy-nonce-digests", .p.Bits.ResetNVRAMOnlyDelete = 1},
+       {"policy-nonce-digests", .p.Bits.ResetNVRAMOnlyDelete = 1}, // Deleting this via user triggered obliterate leave J273a unable to boot
        {"security-password", .p.Bits.RootRequired = 1},
 
 #if !defined(__x86_64__)
@@ -369,6 +285,7 @@ VariablePermissionEntry gVariablePermissions[] = {
        {"acc-cm-override-count", .p.Bits.KernelOnly = 1},
        {"acc-mb-ld-lifetime", .p.Bits.KernelOnly = 1},
        {"backlight-level", .p.Bits.UserWrite = 1},
+       {"backlight-nits", .p.Bits.UserWrite = 1},
        {"com.apple.System.boot-nonce", .p.Bits.KernelOnly = 1},
        {"com.apple.System.sep.art", .p.Bits.KernelOnly = 1},
        {"darkboot", .p.Bits.UserWrite = 1},
@@ -445,11 +362,33 @@ verifyWriteSizeLimit(const uuid_t *varGuid, const char *variableName, size_t pro
        return true;
 }
 
+#if defined(DEBUG) || defined(DEVELOPMENT)
+static const char *
+getNVRAMOpString(IONVRAMOperation op)
+{
+       switch (op) {
+       case kIONVRAMOperationRead:
+               return "Read";
+       case kIONVRAMOperationWrite:
+               return "Write";
+       case kIONVRAMOperationDelete:
+               return "Delete";
+       case kIONVRAMOperationObliterate:
+               return "Obliterate";
+       case kIONVRAMOperationReset:
+               return "Reset";
+       default:
+               return "Unknown";
+       }
+}
+#endif
+
 static bool
 verifyPermission(IONVRAMOperation op, const uuid_t *varGuid, const char *varName)
 {
        VariablePermission perm;
-       bool kernel, admin, writeEntitled, readEntitled, allowList, systemGuid, systemEntitled;
+       bool kernel, admin, writeEntitled, readEntitled, allowList, systemGuid, systemEntitled, systemInternalEntitled, systemAllow;
+       bool ok = false;
 
        perm = getVariablePermission(varName);
 
@@ -457,20 +396,24 @@ verifyPermission(IONVRAMOperation op, const uuid_t *varGuid, const char *varName
 
        if (perm.Bits.KernelOnly) {
                DEBUG_INFO("KernelOnly access for %s, kernel=%d\n", varName, kernel);
-               return 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) || kernel;
+       allowList              = variableInAllowList(varName);
+       systemGuid             = uuid_compare(*varGuid, gAppleSystemVariableGuid) == 0;
+       admin                  = IOUserClient::clientHasPrivilege(current_task(), kIONVRAMPrivilege) == kIOReturnSuccess;
+       writeEntitled          = IOTaskHasEntitlement(current_task(), kIONVRAMWriteAccessKey);
+       readEntitled           = IOTaskHasEntitlement(current_task(), kIONVRAMReadAccessKey);
+       systemEntitled         = IOTaskHasEntitlement(current_task(), kIONVRAMSystemAllowKey);
+       systemInternalEntitled = IOTaskHasEntitlement(current_task(), kIONVRAMSystemInternalAllowKey);
+
+       systemAllow = systemEntitled || (systemInternalEntitled && gInternalBuild) || kernel;
 
        switch (op) {
        case kIONVRAMOperationRead:
                if (kernel || admin || readEntitled || perm.Bits.FullAccess) {
-                       return true;
+                       ok = true;
                }
                break;
 
@@ -478,15 +421,15 @@ verifyPermission(IONVRAMOperation op, const uuid_t *varGuid, const char *varName
                if (kernel || perm.Bits.UserWrite || admin || writeEntitled) {
                        if (systemGuid) {
                                if (allowList) {
-                                       if (!systemEntitled) {
+                                       if (!systemAllow) {
                                                DEBUG_ERROR("Allowed write to system region when NOT entitled for %s\n", varName);
                                        }
-                               } else if (!systemEntitled) {
+                               } else if (!systemAllow) {
                                        DEBUG_ERROR("Not entitled for system region writes for %s\n", varName);
                                        break;
                                }
                        }
-                       return true;
+                       ok = true;
                }
                break;
 
@@ -499,27 +442,31 @@ verifyPermission(IONVRAMOperation op, const uuid_t *varGuid, const char *varName
                } 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 (!systemEntitled) {
+                                       if (!systemAllow) {
                                                DEBUG_ERROR("Allowed delete to system region when NOT entitled for %s\n", varName);
                                        }
-                               } else if (!systemEntitled) {
+                               } else if (!systemAllow) {
                                        DEBUG_ERROR("Not entitled for system region deletes for %s\n", varName);
                                        break;
                                }
                        }
-                       return true;
+                       ok = true;
                }
                break;
        }
 
-       DEBUG_INFO("Permission for %s denied, kernel=%d, admin=%d, writeEntitled=%d, readEntitled=%d, systemGuid=%d, systemEntitled=%d\n",
-           varName, kernel, admin, writeEntitled, readEntitled, systemGuid, systemEntitled);
-       return false;
+exit:
+       DEBUG_INFO("Permission for %s of %s %s: kernel=%d, admin=%d, writeEntitled=%d, readEntitled=%d, systemGuid=%d, systemEntitled=%d, systemInternalEntitled=%d, UserWrite=%d\n",
+           getNVRAMOpString(op), varName, ok ? "granted" : "denied", kernel, admin, writeEntitled, readEntitled, systemGuid, systemEntitled, systemInternalEntitled, perm.Bits.UserWrite);
+       return ok;
 }
 
 static bool
@@ -540,7 +487,7 @@ parseVariableName(const char *key, uuid_t *guidResult, const char **nameResult)
 {
        uuid_string_t temp    = {0};
        size_t        keyLen  = strlen(key);
-       bool          result  = false;
+       bool          ok      = false;
        const char    *name   = key;
        uuid_t        guid;
 
@@ -551,12 +498,12 @@ parseVariableName(const char *key, uuid_t *guidResult, const char **nameResult)
                if ((uuid_parse(temp, guid) == 0) &&
                    (key[sizeof(temp) - 1] == ':')) {
                        name = key + sizeof(temp);
-                       result = true;
+                       ok     = true;
                }
        }
 
        if (guidResult) {
-               result ? uuid_copy(*guidResult, guid) : uuid_copy(*guidResult, gAppleNVRAMGuid);
+               ok ? uuid_copy(*guidResult, guid) : uuid_copy(*guidResult, gAppleNVRAMGuid);
        }
        if (nameResult) {
                *nameResult = name;
@@ -565,6 +512,19 @@ parseVariableName(const char *key, uuid_t *guidResult, const char **nameResult)
        return false;
 }
 
+static bool
+skipKey(const OSSymbol *aKey)
+{
+       return aKey->isEqualTo(kIOClassNameOverrideKey) ||
+              aKey->isEqualTo(kIOBSDNameKey) ||
+              aKey->isEqualTo(kIOBSDNamesKey) ||
+              aKey->isEqualTo(kIOBSDMajorKey) ||
+              aKey->isEqualTo(kIOBSDMinorKey) ||
+              aKey->isEqualTo(kIOBSDUnitKey);
+}
+
+// ************************** IODTNVRAMVariables ****************************
+
 // private IOService based class for publishing distinct dictionary properties on
 // for easy ioreg access since the serializeProperties call is overloaded and is used
 // as variable access
@@ -573,14 +533,20 @@ class IODTNVRAMVariables : public IOService
        OSDeclareDefaultStructors(IODTNVRAMVariables)
 private:
        IODTNVRAM        *_provider;
-       OSDictionary     *_properties;
+       OSDictionary     *_variables;
        uuid_t           _guid;
 
 public:
-       bool             init(const uuid_t *guid);
-       virtual bool     start(IOService * provider) APPLE_KEXT_OVERRIDE;
-       virtual IOReturn setProperties(OSObject * properties) APPLE_KEXT_OVERRIDE;
-       virtual bool     serializeProperties(OSSerialize *s) const APPLE_KEXT_OVERRIDE;
+       bool                    init(const uuid_t *guid);
+       virtual bool            start(IOService * provider) APPLE_KEXT_OVERRIDE;
+       virtual IOReturn        setVariables(OSObject * properties);
+
+       virtual bool            serializeProperties(OSSerialize *s) const APPLE_KEXT_OVERRIDE;
+       virtual OSPtr<OSObject> copyProperty(const OSSymbol *aKey) const APPLE_KEXT_OVERRIDE;
+       virtual OSObject        *getProperty(const OSSymbol *aKey) const APPLE_KEXT_OVERRIDE;
+       virtual bool            setProperty(const OSSymbol *aKey, OSObject *anObject) APPLE_KEXT_OVERRIDE;
+       virtual IOReturn        setProperties(OSObject *properties) APPLE_KEXT_OVERRIDE;
+       virtual void            removeProperty(const OSSymbol *aKey) APPLE_KEXT_OVERRIDE;
 };
 
 OSDefineMetaClassAndStructors(IODTNVRAMVariables, IOService)
@@ -588,23 +554,30 @@ OSDefineMetaClassAndStructors(IODTNVRAMVariables, IOService)
 bool
 IODTNVRAMVariables::init(const uuid_t *guid)
 {
-       require(super::init(), error);
-       require(guid, error);
+       if (!super::init()) {
+               return false;
+       }
+
+       if (guid == nullptr) {
+               return false;
+       }
 
        uuid_copy(_guid, *guid);
 
        return true;
-
-error:
-       return false;
 }
 
 bool
 IODTNVRAMVariables::start(IOService * provider)
 {
-       require(IOService::start(provider), error);
+       if (!IOService::start(provider)) {
+               goto error;
+       }
 
-       require(_provider = OSDynamicCast(IODTNVRAM, provider), error);
+       _provider = OSDynamicCast(IODTNVRAM, provider);
+       if (_provider == nullptr) {
+               goto error;
+       }
 
        registerService();
 
@@ -617,15 +590,15 @@ error:
 }
 
 IOReturn
-IODTNVRAMVariables::setProperties(OSObject * properties)
+IODTNVRAMVariables::setVariables(OSObject * variables)
 {
-       if (OSDynamicCast(OSDictionary, properties)) {
-               OSSafeReleaseNULL(_properties);
-               _properties = OSDynamicCast(OSDictionary, properties);
-               properties->retain();
+       if (OSDynamicCast(OSDictionary, variables)) {
+               OSSafeReleaseNULL(_variables);
+               _variables = OSDynamicCast(OSDictionary, variables);
+               variables->retain();
        }
 
-       return IOService::setProperties(properties);
+       return kIOReturnSuccess;
 }
 
 bool
@@ -634,30 +607,123 @@ IODTNVRAMVariables::serializeProperties(OSSerialize *s) const
        const OSSymbol                    *key;
        OSSharedPtr<OSDictionary>         dict;
        OSSharedPtr<OSCollectionIterator> iter;
-       OSSharedPtr<OSDictionary>         localProperties(_properties, OSRetain);
-       bool                              result = false;
+       OSSharedPtr<OSDictionary>         localVariables(_variables, OSRetain);
+       bool                              ok = false;
 
-       require(localProperties != nullptr, exit);
+       if (localVariables == nullptr) {
+               goto exit;
+       }
 
-       dict = OSDictionary::withCapacity(localProperties->getCount());
-       require_action(dict, exit, DEBUG_ERROR("No dictionary\n"));
+       dict = OSDictionary::withCapacity(localVariables->getCount());
+       if (dict == nullptr) {
+               DEBUG_ERROR("No dictionary\n");
+               goto exit;
+       }
 
-       iter = OSCollectionIterator::withCollection(localProperties.get());
-       require_action(iter, exit, DEBUG_ERROR("failed to create iterator\n"));
+       iter = OSCollectionIterator::withCollection(localVariables.get());
+       if (iter == nullptr) {
+               DEBUG_ERROR("failed to create iterator\n");
+               goto exit;
+       }
 
        while ((key = OSDynamicCast(OSSymbol, iter->getNextObject()))) {
                if (verifyPermission(kIONVRAMOperationRead, &_guid, key)) {
-                       dict->setObject(key, localProperties->getObject(key));
+                       dict->setObject(key, localVariables->getObject(key));
                }
        }
 
-       result = dict->serialize(s);
+       ok = dict->serialize(s);
 
 exit:
-       DEBUG_INFO("result=%d\n", result);
-       return result;
+       DEBUG_INFO("ok=%d\n", ok);
+       return ok;
+}
+
+OSPtr<OSObject>
+IODTNVRAMVariables::copyProperty(const OSSymbol *aKey) const
+{
+       if (_provider && !skipKey(aKey)) {
+               DEBUG_INFO("aKey=%s\n", aKey->getCStringNoCopy());
+
+               return _provider->copyPropertyWithGUIDAndName(&_guid, aKey->getCStringNoCopy());
+       } else {
+               return nullptr;
+       }
 }
 
+OSObject *
+IODTNVRAMVariables::getProperty(const OSSymbol *aKey) const
+{
+       OSSharedPtr<OSObject> theObject = copyProperty(aKey);
+
+       return theObject.get();
+}
+
+bool
+IODTNVRAMVariables::setProperty(const OSSymbol *aKey, OSObject *anObject)
+{
+       if (_provider) {
+               return _provider->setPropertyWithGUIDAndName(&_guid, aKey->getCStringNoCopy(), anObject);
+       } else {
+               return false;
+       }
+}
+
+IOReturn
+IODTNVRAMVariables::setProperties(OSObject *properties)
+{
+       IOReturn                          ret = kIOReturnSuccess;
+       OSObject                          *object;
+       const OSSymbol                    *key;
+       OSDictionary                      *dict;
+       OSSharedPtr<OSCollectionIterator> iter;
+
+       if (_provider) {
+               dict = OSDynamicCast(OSDictionary, properties);
+               if (dict == nullptr) {
+                       DEBUG_ERROR("Not a dictionary\n");
+                       return kIOReturnBadArgument;
+               }
+
+               iter = OSCollectionIterator::withCollection(dict);
+               if (iter == nullptr) {
+                       DEBUG_ERROR("Couldn't create iterator\n");
+                       return kIOReturnBadArgument;
+               }
+
+               while (ret == kIOReturnSuccess) {
+                       key = OSDynamicCast(OSSymbol, iter->getNextObject());
+                       if (key == nullptr) {
+                               break;
+                       }
+
+                       object = dict->getObject(key);
+                       if (object == nullptr) {
+                               continue;
+                       }
+
+                       ret = setProperty(key, object);
+               }
+       } else {
+               ret = kIOReturnNotReady;
+       }
+
+       DEBUG_INFO("ret=%#08x\n", ret);
+
+       return ret;
+}
+
+void
+IODTNVRAMVariables::removeProperty(const OSSymbol *aKey)
+{
+       if (_provider) {
+               _provider->removePropertyWithGUIDAndName(&_guid, aKey->getCStringNoCopy());
+       }
+}
+
+
+// **************************** IODTNVRAM *********************************
+
 bool
 IODTNVRAM::init(IORegistryEntry *old, const IORegistryPlane *plane)
 {
@@ -667,7 +733,17 @@ IODTNVRAM::init(IORegistryEntry *old, const IORegistryPlane *plane)
                return false;
        }
 
-       _variableLock = IOLockAlloc();
+       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);
+#endif // CONFIG_CSR
+#endif // XNU_TARGET_OS_OSX
+
+       DEBUG_INFO("gInternalBuild = %d\n", gInternalBuild);
+
+       _variableLock = IORWLockAlloc();
        if (!_variableLock) {
                return false;
        }
@@ -677,8 +753,6 @@ IODTNVRAM::init(IORegistryEntry *old, const IORegistryPlane *plane)
                return false;
        }
 
-       PE_parse_boot_argn("nvram-log", &gNVRAMLogging, sizeof(gNVRAMLogging));
-
        dict =  OSDictionary::withCapacity(1);
        if (dict == nullptr) {
                return false;
@@ -789,12 +863,14 @@ IODTNVRAM::registerNVRAMController(IONVRAMController *nvram)
 
        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("Proxied NVRAM data\n");
+               DEBUG_INFO("Reading non-proxied NVRAM data\n");
                _nvramController->read(0, _nvramImage, _nvramSize);
                initNVRAMImage();
        }
@@ -850,7 +926,7 @@ no_system:
 
 no_common:
        ret = serializeVariables();
-       DEBUG_INFO("serializeVariables ret=0x%08x\n", ret);
+       DEBUG_INFO("serializeVariables ret=%#08x\n", ret);
 }
 
 void
@@ -867,8 +943,11 @@ IODTNVRAM::initNVRAMImage(void)
        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;
 
@@ -883,9 +962,10 @@ IODTNVRAM::initNVRAMImage(void)
                        break;
                }
 
-               common_partition = memcmp(header->name, NVRAM_CHRP_PARTITION_NAME_COMMON, strlen(NVRAM_CHRP_PARTITION_NAME_COMMON)) == 0;
-               system_partition = (memcmp(header->name, NVRAM_CHRP_PARTITION_NAME_SYSTEM, strlen(NVRAM_CHRP_PARTITION_NAME_SYSTEM)) == 0) ||
-                   (memcmp(header->name, NVRAM_CHRP_PARTITION_NAME_SYSTEM_LEGACY, strlen(NVRAM_CHRP_PARTITION_NAME_SYSTEM_LEGACY)) == 0);
+               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;
@@ -897,8 +977,8 @@ IODTNVRAM::initNVRAMImage(void)
                        OSSharedPtr<OSNumber> partitionOffsetNumber, partitionLengthNumber;
 
                        // Construct the partition ID from the signature and name.
-                       snprintf(partitionID, sizeof(partitionID), "0x%02x,", header->sig);
-                       strncpy(partitionID + 5, header->name, sizeof(header->name));
+                       snprintf(partitionID, sizeof(partitionID), "%#02x,", header->sig);
+                       memcpy(partitionID + 5, header->name, sizeof(header->name));
                        partitionID[17] = '\0';
 
                        partitionOffsetNumber = OSNumber::withNumber(partitionOffset, 32);
@@ -919,7 +999,7 @@ IODTNVRAM::initNVRAMImage(void)
                _systemImage = _nvramImage + _systemPartitionOffset;
        }
 
-       DEBUG_ALWAYS("NVRAM : ofPartitionOffset - 0x%x, ofPartitionSize - 0x%x, systemPartitionOffset - 0x%x, systemPartitionSize - 0x%x\n",
+       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;
@@ -963,10 +1043,10 @@ IODTNVRAM::serializeProperties(OSSerialize *s) const
        const OSSymbol                    *key;
        OSSharedPtr<OSDictionary>         systemDict, commonDict, dict;
        OSSharedPtr<OSCollectionIterator> iter;
-       bool                              result = false;
+       bool                              ok = false;
        unsigned int                      totalCapacity = 0;
 
-       NVRAMLOCK();
+       NVRAMREADLOCK();
        if (_commonDict) {
                commonDict = OSDictionary::withDictionary(_commonDict.get());
        }
@@ -1021,12 +1101,12 @@ IODTNVRAM::serializeProperties(OSSerialize *s) const
                }
        }
 
-       result = dict->serialize(s);
+       ok = dict->serialize(s);
 
 exit:
-       DEBUG_INFO("result=%d\n", result);
+       DEBUG_INFO("ok=%d\n", ok);
 
-       return result;
+       return ok;
 }
 
 IOReturn
@@ -1048,89 +1128,89 @@ IODTNVRAM::chooseDictionary(IONVRAMOperation operation, const uuid_t *varGuid, c
                        DEBUG_INFO("Using common dictionary\n");
                        *dict = _commonDict.get();
                }
-       } else {
+               return kIOReturnSuccess;
+       } else if (_commonDict != nullptr) {
                DEBUG_INFO("Defaulting to common dictionary\n");
                *dict = _commonDict.get();
+               return kIOReturnSuccess;
        }
 
-       return kIOReturnSuccess;
+       return kIOReturnNotFound;
 }
 
-bool
-IODTNVRAM::handleSpecialVariables(const char *name, uuid_t *guid, OSObject *obj, IOReturn *error)
+IOReturn
+IODTNVRAM::flushDict(const uuid_t *guid, IONVRAMOperation op)
 {
        IOReturn err = kIOReturnSuccess;
-       bool special = false;
 
-       NVRAMLOCKASSERT();
+       if ((_systemDict != nullptr) && (uuid_compare(*guid, gAppleSystemVariableGuid) == 0)) {
+               const OSSymbol *key;
+               OSSharedPtr<OSDictionary> newDict;
+               OSSharedPtr<OSCollectionIterator> iter;
 
-       if (strcmp(name, "ResetNVRam") == 0) {
-               DEBUG_INFO("%s requested\n", name);
+               newDict = OSDictionary::withCapacity(_systemDict->getCapacity());
+               iter = OSCollectionIterator::withCollection(_systemDict.get());
+               if ((newDict == nullptr) || (iter == nullptr)) {
+                       err = kIOReturnNoMemory;
+                       goto exit;
+               }
 
-               if (uuid_compare(*guid, gAppleSystemVariableGuid) == 0) {
-                       if (_systemDict != nullptr) {
-                               _systemDict->flushCollection();
+               while ((key = OSDynamicCast(OSSymbol, iter->getNextObject()))) {
+                       if (!verifyPermission(op, &gAppleSystemVariableGuid, key)) {
+                               newDict->setObject(key, _systemDict->getObject(key));
                        }
-
-                       _commonDict->flushCollection();
-                       DEBUG_INFO("system & common dictionary flushed\n");
                }
 
-               special = true;
-       } else if (strcmp(name, "ObliterateNVRam") == 0) {
-               DEBUG_INFO("%s requested\n", name);
+               _systemDict = newDict;
 
-               if ((_systemDict != nullptr) && (uuid_compare(*guid, gAppleSystemVariableGuid) == 0)) {
-                       const OSSymbol *key;
-                       OSSharedPtr<OSDictionary> newDict;
-                       OSSharedPtr<OSCollectionIterator> iter;
+               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(_systemDict->getCapacity());
-                       iter = OSCollectionIterator::withCollection(newDict.get());
-                       if ((newDict == nullptr) || (iter == nullptr)) {
-                               err = kIOReturnNoMemory;
-                               goto exit;
-                       }
-
-                       while ((key = OSDynamicCast(OSSymbol, iter->getNextObject()))) {
-                               const OSSymbol *key = OSDynamicCast(OSSymbol, iter->getNextObject());
-                               if (key == nullptr) {
-                                       err = kIOReturnNoMemory;
-                                       goto exit;
-                               }
+               newDict = OSDictionary::withCapacity(_commonDict->getCapacity());
+               iter = OSCollectionIterator::withCollection(_commonDict.get());
+               if ((newDict == nullptr) || (iter == nullptr)) {
+                       err = kIOReturnNoMemory;
+                       goto exit;
+               }
 
-                               if (!verifyPermission(kIONVRAMOperationObliterate, &gAppleSystemVariableGuid, key)) {
-                                       newDict->setObject(key, _systemDict->getObject(key));
-                               }
+               while ((key = OSDynamicCast(OSSymbol, iter->getNextObject()))) {
+                       if (!verifyPermission(op, &gAppleNVRAMGuid, key)) {
+                               newDict->setObject(key, _commonDict->getObject(key));
                        }
+               }
 
-                       _systemDict = newDict;
+               _commonDict = newDict;
 
-                       DEBUG_INFO("system dictionary flushed\n");
-               } else if (_commonDict != nullptr) {
-                       const OSSymbol *key;
-                       OSSharedPtr<OSDictionary> newDict;
-                       OSSharedPtr<OSCollectionIterator> iter;
+               DEBUG_INFO("common dictionary flushed\n");
+       }
 
-                       newDict = OSDictionary::withCapacity(_commonDict->getCapacity());
-                       iter = OSCollectionIterator::withCollection(newDict.get());
-                       if ((newDict == nullptr) || (iter == nullptr)) {
-                               err = kIOReturnNoMemory;
-                               goto exit;
-                       }
+exit:
+       return err;
+}
 
-                       while ((key = OSDynamicCast(OSSymbol, iter->getNextObject()))) {
-                               if (!verifyPermission(kIONVRAMOperationObliterate, &gAppleNVRAMGuid, key)) {
-                                       newDict->setObject(key, _commonDict->getObject(key));
-                               }
-                       }
+bool
+IODTNVRAM::handleSpecialVariables(const char *name, const uuid_t *guid, const OSObject *obj, IOReturn *error)
+{
+       IOReturn err = kIOReturnSuccess;
+       bool special = false;
 
-                       _commonDict = newDict;
+       NVRAMLOCKASSERTEXCLUSIVE();
 
-                       DEBUG_INFO("common dictionary flushed\n");
+       // ResetNVRam flushes both regions in one call
+       // Obliterate can flush either separately
+       if (strcmp(name, "ObliterateNVRam") == 0) {
+               err = flushDict(guid, kIONVRAMOperationObliterate);
+       } else if (strcmp(name, "ResetNVRam") == 0) {
+               err = flushDict(&gAppleSystemVariableGuid, kIONVRAMOperationReset);
+
+               if (err != kIOReturnSuccess) {
+                       goto exit;
                }
 
-               special = true;
+               err = flushDict(&gAppleNVRAMGuid, kIONVRAMOperationReset);
        }
 
 exit:
@@ -1142,39 +1222,25 @@ exit:
 }
 
 OSSharedPtr<OSObject>
-IODTNVRAM::copyProperty(const OSSymbol *aKey) const
+IODTNVRAM::copyPropertyWithGUIDAndName(const uuid_t *guid, const char *name) const
 {
        IOReturn              result;
-       const char            *variableName;
-       uuid_t                varGuid;
        OSDictionary          *dict;
        OSSharedPtr<OSObject> theObject = nullptr;
 
-       if (aKey->isEqualTo(kIOBSDNameKey) ||
-           aKey->isEqualTo(kIOBSDNamesKey) ||
-           aKey->isEqualTo(kIOBSDMajorKey) ||
-           aKey->isEqualTo(kIOBSDMinorKey) ||
-           aKey->isEqualTo(kIOBSDUnitKey)) {
-               // These will never match.
-               // Check here and exit to avoid logging spam
-               return nullptr;
-       }
-       DEBUG_INFO("aKey=%s\n", aKey->getCStringNoCopy());
-
-       parseVariableName(aKey->getCStringNoCopy(), &varGuid, &variableName);
-
-       result = chooseDictionary(kIONVRAMOperationRead, &varGuid, variableName, &dict);
+       result = chooseDictionary(kIONVRAMOperationRead, guid, name, &dict);
        if (result != kIOReturnSuccess) {
+               DEBUG_INFO("No dictionary\n");
                goto exit;
        }
 
-       if (!verifyPermission(kIONVRAMOperationRead, &varGuid, variableName)) {
+       if (!verifyPermission(kIONVRAMOperationRead, guid, name)) {
                DEBUG_INFO("Not privileged\n");
                goto exit;
        }
 
-       NVRAMLOCK();
-       theObject.reset(dict->getObject(variableName), OSRetain);
+       NVRAMREADLOCK();
+       theObject.reset(dict->getObject(name), OSRetain);
        NVRAMUNLOCK();
 
        if (theObject != nullptr) {
@@ -1185,6 +1251,22 @@ exit:
        return theObject;
 }
 
+OSSharedPtr<OSObject>
+IODTNVRAM::copyProperty(const OSSymbol *aKey) const
+{
+       const char            *variableName;
+       uuid_t                varGuid;
+
+       if (skipKey(aKey)) {
+               return nullptr;
+       }
+       DEBUG_INFO("aKey=%s\n", aKey->getCStringNoCopy());
+
+       parseVariableName(aKey->getCStringNoCopy(), &varGuid, &variableName);
+
+       return copyPropertyWithGUIDAndName(&varGuid, variableName);
+}
+
 OSSharedPtr<OSObject>
 IODTNVRAM::copyProperty(const char *aKey) const
 {
@@ -1220,64 +1302,64 @@ IODTNVRAM::getProperty(const char *aKey) const
 }
 
 IOReturn
-IODTNVRAM::setPropertyInternal(const OSSymbol *aKey, OSObject *anObject)
+IODTNVRAM::setPropertyWithGUIDAndName(const uuid_t *guid, const char *name, OSObject *anObject)
 {
-       IOReturn              result = kIOReturnSuccess;
+       IOReturn              ret = kIOReturnSuccess;
        bool                  remove = false;
        OSString              *tmpString = nullptr;
        OSSharedPtr<OSObject> propObject, oldObject;
        OSSharedPtr<OSObject> sharedObject(anObject, OSRetain);
-       const char            *variableName;
-       uuid_t                varGuid;
        OSDictionary          *dict;
        bool                  deletePropertyKey, syncNowPropertyKey, forceSyncNowPropertyKey;
        bool                  ok;
        size_t                propDataSize = 0;
 
-       DEBUG_INFO("aKey=%s\n", aKey->getCStringNoCopy());
-
-       parseVariableName(aKey->getCStringNoCopy(), &varGuid, &variableName);
-       deletePropertyKey = strncmp(variableName, kIONVRAMDeletePropertyKey, sizeof(kIONVRAMDeletePropertyKey)) == 0;
-       syncNowPropertyKey = strncmp(variableName, kIONVRAMSyncNowPropertyKey, sizeof(kIONVRAMSyncNowPropertyKey)) == 0;
-       forceSyncNowPropertyKey = strncmp(variableName, kIONVRAMForceSyncNowPropertyKey, sizeof(kIONVRAMForceSyncNowPropertyKey)) == 0;
+       deletePropertyKey = strncmp(name, kIONVRAMDeletePropertyKey, sizeof(kIONVRAMDeletePropertyKey)) == 0;
+       syncNowPropertyKey = strncmp(name, kIONVRAMSyncNowPropertyKey, sizeof(kIONVRAMSyncNowPropertyKey)) == 0;
+       forceSyncNowPropertyKey = strncmp(name, kIONVRAMForceSyncNowPropertyKey, sizeof(kIONVRAMForceSyncNowPropertyKey)) == 0;
 
        if (deletePropertyKey) {
                tmpString = OSDynamicCast(OSString, anObject);
                if (tmpString != nullptr) {
+                       const char *variableName;
+                       uuid_t     varGuid;
+
                        DEBUG_INFO("kIONVRAMDeletePropertyKey found\n");
-                       OSSharedPtr<const OSSymbol> sharedKey = OSSymbol::withString(tmpString);
-                       removeProperty(sharedKey.get());
+
+                       parseVariableName(tmpString->getCStringNoCopy(), &varGuid, &variableName);
+                       removePropertyWithGUIDAndName(&varGuid, variableName);
                } else {
                        DEBUG_INFO("kIONVRAMDeletePropertyKey value needs to be an OSString\n");
-                       result = kIOReturnError;
+                       ret = kIOReturnError;
                }
                goto exit;
        } else if (syncNowPropertyKey || forceSyncNowPropertyKey) {
                tmpString = OSDynamicCast(OSString, anObject);
-               DEBUG_INFO("NVRAM sync key %s found\n", aKey->getCStringNoCopy());
+               DEBUG_INFO("NVRAM sync key %s found\n", name);
                if (tmpString != nullptr) {
                        // We still want to throttle NVRAM commit rate for SyncNow. ForceSyncNow is provided as a really big hammer.
                        syncInternal(syncNowPropertyKey);
                } else {
-                       DEBUG_INFO("%s value needs to be an OSString\n", variableName);
-                       result = kIOReturnError;
+                       DEBUG_INFO("%s value needs to be an OSString\n", name);
+                       ret = kIOReturnError;
                }
                goto exit;
        }
 
-       result = chooseDictionary(kIONVRAMOperationWrite, &varGuid, variableName, &dict);
-       if (result != kIOReturnSuccess) {
+       ret = chooseDictionary(kIONVRAMOperationWrite, guid, name, &dict);
+       if (ret != kIOReturnSuccess) {
+               DEBUG_INFO("No dictionary\n");
                goto exit;
        }
 
-       if (!verifyPermission(kIONVRAMOperationWrite, &varGuid, variableName)) {
+       if (!verifyPermission(kIONVRAMOperationWrite, guid, name)) {
                DEBUG_INFO("Not privileged\n");
-               result = kIOReturnNotPrivileged;
+               ret = kIOReturnNotPrivileged;
                goto exit;
        }
 
        // Make sure the object is of the correct type.
-       switch (getVariableType(variableName)) {
+       switch (getVariableType(name)) {
        case kOFVariableTypeBoolean:
                propObject = OSDynamicPtrCast<OSBoolean>(sharedObject);
                break;
@@ -1291,9 +1373,9 @@ IODTNVRAM::setPropertyInternal(const OSSymbol *aKey, OSObject *anObject)
                if (propObject != nullptr) {
                        propDataSize = (OSDynamicPtrCast<OSString>(propObject))->getLength();
 
-                       if (aKey->isEqualTo(kIONVRAMBootArgsKey) && (propDataSize >= BOOT_LINE_LENGTH)) {
+                       if ((strncmp(name, kIONVRAMBootArgsKey, sizeof(kIONVRAMBootArgsKey)) == 0) && (propDataSize >= BOOT_LINE_LENGTH)) {
                                DEBUG_ERROR("boot-args size too large for BOOT_LINE_LENGTH, propDataSize=%zu\n", propDataSize);
-                               result = kIOReturnNoSpace;
+                               ret = kIOReturnNoSpace;
                                goto exit;
                        }
                }
@@ -1325,18 +1407,18 @@ IODTNVRAM::setPropertyInternal(const OSSymbol *aKey, OSObject *anObject)
 
        if (propObject == nullptr) {
                DEBUG_INFO("No property object\n");
-               result = kIOReturnBadArgument;
+               ret = kIOReturnBadArgument;
                goto exit;
        }
 
-       if (!verifyWriteSizeLimit(&varGuid, variableName, propDataSize)) {
-               DEBUG_ERROR("Property data size of %zu too long for %s\n", propDataSize, variableName);
-               result = kIOReturnNoSpace;
+       if (!verifyWriteSizeLimit(guid, name, propDataSize)) {
+               DEBUG_ERROR("Property data size of %zu too long for %s\n", propDataSize, name);
+               ret = kIOReturnNoSpace;
                goto exit;
        }
 
-       NVRAMLOCK();
-       ok = handleSpecialVariables(variableName, &varGuid, propObject.get(), &result);
+       NVRAMWRITELOCK();
+       ok = handleSpecialVariables(name, guid, propObject.get(), &ret);
        NVRAMUNLOCK();
 
        if (ok) {
@@ -1344,39 +1426,42 @@ IODTNVRAM::setPropertyInternal(const OSSymbol *aKey, OSObject *anObject)
                goto exit;
        }
 
-       NVRAMLOCK();
-       oldObject.reset(dict->getObject(variableName), OSRetain);
+       NVRAMREADLOCK();
+       oldObject.reset(dict->getObject(name), OSRetain);
+       NVRAMUNLOCK();
+
        if (remove == false) {
                DEBUG_INFO("Adding object\n");
-               if (!dict->setObject(variableName, propObject.get())) {
-                       result = kIOReturnBadArgument;
+               NVRAMWRITELOCK();
+               if (!dict->setObject(name, propObject.get())) {
+                       ret = kIOReturnBadArgument;
                }
+               NVRAMUNLOCK();
        } else {
                DEBUG_INFO("Removing object\n");
                // Check for existence so we can decide whether we need to sync variables
                if (oldObject) {
-                       result = removePropertyInternal(aKey);
+                       ret = removePropertyWithGUIDAndName(guid, name);
                } else {
-                       result = kIOReturnNotFound;
+                       ret = kIOReturnNotFound;
                }
        }
-       NVRAMUNLOCK();
 
-       if (result == kIOReturnSuccess) {
-               result = serializeVariables();
-               if (result != kIOReturnSuccess) {
-                       DEBUG_ERROR("serializeVariables failed, result=0x%08x\n", result);
+       if (ret == kIOReturnSuccess) {
+               ret = serializeVariables();
+               if (ret != kIOReturnSuccess) {
+                       DEBUG_ERROR("serializeVariables failed, ret=%#08x\n", ret);
 
-                       NVRAMLOCK();
+                       NVRAMWRITELOCK();
                        if (oldObject) {
-                               dict->setObject(variableName, oldObject.get());
+                               dict->setObject(name, oldObject.get());
                        } else {
-                               dict->removeObject(variableName);
+                               dict->removeObject(name);
                        }
                        NVRAMUNLOCK();
 
                        (void) serializeVariables();
-                       result = kIOReturnNoMemory;
+                       ret = kIOReturnNoMemory;
                }
        }
 
@@ -1388,9 +1473,22 @@ IODTNVRAM::setPropertyInternal(const OSSymbol *aKey, OSObject *anObject)
        }
 
 exit:
-       DEBUG_INFO("result=0x%08x\n", result);
+       DEBUG_INFO("ret=%#08x\n", ret);
 
-       return result;
+       return ret;
+}
+
+IOReturn
+IODTNVRAM::setPropertyInternal(const OSSymbol *aKey, OSObject *anObject)
+{
+       const char            *variableName;
+       uuid_t                varGuid;
+
+       DEBUG_INFO("aKey=%s\n", aKey->getCStringNoCopy());
+
+       parseVariableName(aKey->getCStringNoCopy(), &varGuid, &variableName);
+
+       return setPropertyWithGUIDAndName(&varGuid, variableName, anObject);
 }
 
 bool
@@ -1404,55 +1502,77 @@ IODTNVRAM::removeProperty(const OSSymbol *aKey)
 {
        IOReturn ret;
 
-       NVRAMLOCK();
        ret = removePropertyInternal(aKey);
-       NVRAMUNLOCK();
 
        if (ret == kIOReturnSuccess) {
                serializeVariables();
        } else {
-               DEBUG_INFO("removePropertyInternal failed, ret=0x%08x\n", ret);
+               DEBUG_INFO("removePropertyInternal failed, ret=%#08x\n", ret);
        }
 }
 
 IOReturn
-IODTNVRAM::removePropertyInternal(const OSSymbol *aKey)
+IODTNVRAM::removePropertyWithGUIDAndName(const uuid_t *guid, const char *name)
 {
-       IOReturn     result;
-       const char   *variableName;
-       uuid_t       varGuid;
+       IOReturn     ret;
        OSDictionary *dict;
+       bool removed = false;
 
-       DEBUG_INFO("aKey=%s\n", aKey->getCStringNoCopy());
-
-       NVRAMLOCKASSERT();
-
-       parseVariableName(aKey->getCStringNoCopy(), &varGuid, &variableName);
+       DEBUG_INFO("name=%s\n", name);
 
-       result = chooseDictionary(kIONVRAMOperationDelete, &varGuid, variableName, &dict);
-       if (result != kIOReturnSuccess) {
+       ret = chooseDictionary(kIONVRAMOperationDelete, guid, name, &dict);
+       if (ret != kIOReturnSuccess) {
+               DEBUG_INFO("No dictionary\n");
                goto exit;
        }
 
-       if (!verifyPermission(kIONVRAMOperationDelete, &varGuid, variableName)) {
+       if (!verifyPermission(kIONVRAMOperationDelete, guid, name)) {
                DEBUG_INFO("Not priveleged\n");
-               result = kIOReturnNotPrivileged;
+               ret = kIOReturnNotPrivileged;
                goto exit;
        }
 
+       NVRAMWRITELOCK();
+
        // If the object exists, remove it from the dictionary.
-       if (dict->getObject(variableName) != nullptr) {
-               dict->removeObject(variableName);
+       if (dict->getObject(name) != nullptr) {
+               dict->removeObject(name);
+               removed = true;
+       } else {
+               DEBUG_INFO("%s not found\n", name);
+       }
+
+       NVRAMUNLOCK();
+
+       if (removed) {
+               ret = serializeVariables();
+               DEBUG_INFO("serializeVariables ret=0x%08x\n", ret);
        }
 
 exit:
-       return result;
+       return ret;
+}
+
+IOReturn
+IODTNVRAM::removePropertyInternal(const OSSymbol *aKey)
+{
+       IOReturn     ret;
+       const char   *variableName;
+       uuid_t       varGuid;
+
+       DEBUG_INFO("aKey=%s\n", aKey->getCStringNoCopy());
+
+       parseVariableName(aKey->getCStringNoCopy(), &varGuid, &variableName);
+
+       ret = removePropertyWithGUIDAndName(&varGuid, variableName);
+
+       return ret;
 }
 
 IOReturn
 IODTNVRAM::setProperties(OSObject *properties)
 {
-       IOReturn                          result = kIOReturnSuccess;
+       IOReturn                          ret = kIOReturnSuccess;
        OSObject                          *object;
        const OSSymbol                    *key;
        OSDictionary                      *dict;
@@ -1470,7 +1590,7 @@ IODTNVRAM::setProperties(OSObject *properties)
                return kIOReturnBadArgument;
        }
 
-       while (result == kIOReturnSuccess) {
+       while (ret == kIOReturnSuccess) {
                key = OSDynamicCast(OSSymbol, iter->getNextObject());
                if (key == nullptr) {
                        break;
@@ -1481,12 +1601,12 @@ IODTNVRAM::setProperties(OSObject *properties)
                        continue;
                }
 
-               result = setPropertyInternal(key, object);
+               ret = setPropertyInternal(key, object);
        }
 
-       DEBUG_INFO("result=0x%08x\n", result);
+       DEBUG_INFO("ret=%#08x\n", ret);
 
-       return result;
+       return ret;
 }
 
 IOReturn
@@ -1634,8 +1754,8 @@ IODTNVRAM::initVariables(void)
        OSSharedPtr<const OSSymbol> propSymbol;
        OSSharedPtr<OSObject>       propObject;
        NVRAMRegionInfo             *currentRegion;
-       NVRAMRegionInfo             variableRegions[] = { { NVRAM_CHRP_PARTITION_NAME_COMMON, _commonPartitionOffset, _commonPartitionSize, _commonDict, _commonImage},
-                                                         { NVRAM_CHRP_PARTITION_NAME_SYSTEM, _systemPartitionOffset, _systemPartitionSize, _systemDict, _systemImage} };
+       NVRAMRegionInfo             variableRegions[] = { { kIONVRAMPartitionCommon, _commonPartitionOffset, _commonPartitionSize, _commonDict, _commonImage},
+                                                         { kIONVRAMPartitionSystem, _systemPartitionOffset, _systemPartitionSize, _systemDict, _systemImage} };
 
        DEBUG_INFO("...\n");
 
@@ -1648,7 +1768,7 @@ IODTNVRAM::initVariables(void)
 
                currentRegion->dict = OSDictionary::withCapacity(1);
 
-               DEBUG_INFO("region = %s\n", currentRegion->name);
+               DEBUG_INFO("region = %d\n", currentRegion->type);
                cnt = 0;
                while (cnt < currentRegion->size) {
                        // Break if there is no name.
@@ -1695,14 +1815,23 @@ IODTNVRAM::initVariables(void)
        }
 
        // Create the boot-args property if it is not in the dictionary.
-       if (_commonDict->getObject(kIONVRAMBootArgsKey) == nullptr) {
-               propObject = OSString::withCStringNoCopy("");
-               if (propObject != nullptr) {
-                       _commonDict->setObject(kIONVRAMBootArgsKey, propObject.get());
+       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.get(), _systemDict.get());
+       DEBUG_INFO("%s _commonDict=%p _systemDict=%p\n", __FUNCTION__, _commonDict ? _commonDict.get() : nullptr, _systemDict ? _systemDict.get() : nullptr);
 
        return kIOReturnSuccess;
 }
@@ -1728,8 +1857,8 @@ IODTNVRAM::serializeVariables(void)
        UInt32                            commonUsed = 0;
        OSSharedPtr<OSData>               nvramImage;
        NVRAMRegionInfo                   *currentRegion;
-       NVRAMRegionInfo                   variableRegions[] = { { NVRAM_CHRP_PARTITION_NAME_COMMON, _commonPartitionOffset, _commonPartitionSize, _commonDict, _commonImage},
-                                                               { NVRAM_CHRP_PARTITION_NAME_SYSTEM, _systemPartitionOffset, _systemPartitionSize, _systemDict, _systemImage} };
+       NVRAMRegionInfo                   variableRegions[] = { { kIONVRAMPartitionCommon, _commonPartitionOffset, _commonPartitionSize, _commonDict, _commonImage},
+                                                               { kIONVRAMPartitionSystem, _systemPartitionOffset, _systemPartitionSize, _systemDict, _systemImage} };
 
        if (_systemPanicked) {
                return kIOReturnNotReady;
@@ -1742,7 +1871,7 @@ IODTNVRAM::serializeVariables(void)
 
        DEBUG_INFO("...\n");
 
-       NVRAMLOCK();
+       NVRAMREADLOCK();
 
        for (regionIndex = 0; regionIndex < ARRAY_SIZE(variableRegions); regionIndex++) {
                currentRegion = &variableRegions[regionIndex];
@@ -1751,10 +1880,12 @@ IODTNVRAM::serializeVariables(void)
                        continue;
                }
 
-               DEBUG_INFO("region = %s\n", currentRegion->name);
+               DEBUG_INFO("region = %d\n", currentRegion->type);
                buffer = tmpBuffer = IONew(UInt8, currentRegion->size);
                if (buffer == nullptr) {
-                       return kIOReturnNoMemory;
+                       ok = false;
+                       ret = kIOReturnNoMemory;
+                       break;
                }
                bzero(buffer, currentRegion->size);
 
@@ -1790,44 +1921,48 @@ IODTNVRAM::serializeVariables(void)
 
                IODelete(buffer, UInt8, currentRegion->size);
 
-               if ((strncmp(currentRegion->name, NVRAM_CHRP_PARTITION_NAME_SYSTEM, strlen(NVRAM_CHRP_PARTITION_NAME_SYSTEM)) == 0) &&
+               if ((currentRegion->type == kIONVRAMPartitionSystem) &&
                    (_systemService != nullptr)) {
-                       _systemService->setProperties(_systemDict.get());
-                       systemUsed = maxLength;
-               } else if ((strncmp(currentRegion->name, NVRAM_CHRP_PARTITION_NAME_COMMON, strlen(NVRAM_CHRP_PARTITION_NAME_COMMON)) == 0) &&
+                       _systemService->setVariables(_systemDict.get());
+                       systemUsed = (uint32_t)(tmpBuffer - buffer);
+               } else if ((currentRegion->type == kIONVRAMPartitionCommon) &&
                    (_commonService != nullptr)) {
-                       _commonService->setProperties(_commonDict.get());
-                       commonUsed = maxLength;
+                       _commonService->setVariables(_commonDict.get());
+                       commonUsed = (uint32_t)(tmpBuffer - buffer);
                }
 
                if (!ok) {
-                       return kIOReturnBadArgument;
+                       ret = kIOReturnBadArgument;
+                       break;
                }
        }
 
-       nvramImage = OSData::withBytes(_nvramImage, _nvramSize);
-
        NVRAMUNLOCK();
 
        DEBUG_INFO("ok=%d\n", ok);
 
-       CONTROLLERLOCK();
+       if (ok) {
+               nvramImage = OSData::withBytes(_nvramImage, _nvramSize);
+               CONTROLLERLOCK();
 
-       if (_systemService) {
-               sizeUsed = OSNumber::withNumber(systemUsed, 32);
-               _nvramController->setProperty("SystemUsed", sizeUsed.get());
-               sizeUsed.reset();
-       }
+               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());
-               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());
+               ret = _nvramController->write(0, (uint8_t *)nvramImage->getBytesNoCopy(), nvramImage->getLength());
 
-       CONTROLLERUNLOCK();
+               CONTROLLERUNLOCK();
+       }
 
        return ret;
 }
@@ -1932,11 +2067,11 @@ IODTNVRAM::convertPropToObject(UInt8 *propName, UInt32 propNameLength,
 {
        const OSSymbol* propSymbolRaw = nullptr;
        OSObject* propObjectRaw = nullptr;
-       bool result = convertPropToObject(propName, propNameLength, propData, propDataLength,
+       bool ok = convertPropToObject(propName, propNameLength, propData, propDataLength,
            &propSymbolRaw, &propObjectRaw);
        propSymbol.reset(propSymbolRaw, OSNoRetain);
        propObject.reset(propObjectRaw, OSNoRetain);
-       return result;
+       return ok;
 }
 
 bool
@@ -2020,7 +2155,7 @@ IODTNVRAM::convertObjectToProp(UInt8 *buffer, UInt32 *length,
                } else if (tmpValue < 1000) {
                        snprintf((char *)buffer, remaining, "%d", (uint32_t)tmpValue);
                } else {
-                       snprintf((char *)buffer, remaining, "0x%x", (uint32_t)tmpValue);
+                       snprintf((char *)buffer, remaining, "%#x", (uint32_t)tmpValue);
                }
        }
        break;
@@ -2226,7 +2361,7 @@ IODTNVRAM::readNVRAMPropertyType1(IORegistryEntry *entry,
        UInt32       resultValueLen = 0;
        UInt8       byte;
 
-       NVRAMLOCK();
+       NVRAMREADLOCK();
        data = OSDynamicCast(OSData, _commonDict->getObject(_registryPropertiesKey.get()));
        NVRAMUNLOCK();
 
@@ -2300,7 +2435,7 @@ IODTNVRAM::writeNVRAMPropertyType1(IORegistryEntry *entry,
 
        // copy over existing properties for other entries
 
-       NVRAMLOCK();
+       NVRAMWRITELOCK();
 
        oldData.reset(OSDynamicCast(OSData, _commonDict->getObject(_registryPropertiesKey.get())), OSRetain);
        if (oldData) {
@@ -2403,7 +2538,7 @@ IODTNVRAM::writeNVRAMPropertyType1(IORegistryEntry *entry,
 
        if (ok) {
                if (serializeVariables() != kIOReturnSuccess) {
-                       NVRAMLOCK();
+                       NVRAMWRITELOCK();
                        if (oldData) {
                                _commonDict->setObject(_registryPropertiesKey.get(), oldData.get());
                        } else {