2  * Copyright (c) 1998-2006 Apple Computer, Inc. All rights reserved. 
   3  * Copyright (c) 2007-2012 Apple Inc. All rights reserved. 
   5  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 
   7  * This file contains Original Code and/or Modifications of Original Code 
   8  * as defined in and that are subject to the Apple Public Source License 
   9  * Version 2.0 (the 'License'). You may not use this file except in 
  10  * compliance with the License. The rights granted to you under the License 
  11  * may not be used to create, or enable the creation or redistribution of, 
  12  * unlawful or unlicensed copies of an Apple operating system, or to 
  13  * circumvent, violate, or enable the circumvention or violation of, any 
  14  * terms of an Apple operating system software license agreement. 
  16  * Please obtain a copy of the License at 
  17  * http://www.opensource.apple.com/apsl/ and read it before using this file. 
  19  * The Original Code and all software distributed under the License are 
  20  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  21  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  22  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 
  23  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  24  * Please see the License for the specific language governing rights and 
  25  * limitations under the License. 
  27  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 
  30 #define IOKIT_ENABLE_SHARED_PTR 
  32 #include <AssertMacros.h> 
  33 #include <IOKit/IOLib.h> 
  34 #include <IOKit/IONVRAM.h> 
  35 #include <IOKit/IOPlatformExpert.h> 
  36 #include <IOKit/IOUserClient.h> 
  37 #include <IOKit/IOKitKeys.h> 
  38 #include <IOKit/IOKitKeysPrivate.h> 
  39 #include <IOKit/IOBSD.h> 
  40 #include <kern/debug.h> 
  41 #include <pexpert/boot.h> 
  42 #include <pexpert/pexpert.h> 
  45 #define super IOService 
  47 #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) 
  50 #define NVRAM_CHRP_SIG_APPLE             0x5A 
  51 #define NVRAM_CHRP_APPLE_HEADER_NAME     "nvram" 
  53 // From Apple CHRP Spec 
  54 #define NVRAM_CHRP_SIG_SYSTEM    0x70 
  55 #define NVRAM_CHRP_SIG_CONFIG    0x71 
  57 #define NVRAM_CHRP_PARTITION_NAME_COMMON_V1   "common" 
  58 #define NVRAM_CHRP_PARTITION_NAME_SYSTEM_V1   "system" 
  59 #define NVRAM_CHRP_PARTITION_NAME_COMMON_V2   "2common" 
  60 #define NVRAM_CHRP_PARTITION_NAME_SYSTEM_V2   "2system" 
  62 #define NVRAM_CHRP_LENGTH_BLOCK_SIZE 0x10 // CHRP length field is in 16 byte blocks 
  64 typedef struct chrp_nvram_header 
{ //16 bytes 
  66         uint8_t  cksum
; // checksum on sig, len, and name 
  67         uint16_t len
;   // total length of the partition in 16 byte blocks starting with the signature 
  68         // and ending with the last byte of data area, ie len includes its own header size 
  71 } chrp_nvram_header_t
; 
  73 typedef struct apple_nvram_header 
{  // 16 + 16 bytes 
  74         struct   chrp_nvram_header chrp
; 
  78 } apple_nvram_header_t
; 
  81 #define kIONVRAMPrivilege       kIOClientPrivilegeAdministrator 
  83 OSDefineMetaClassAndStructors(IODTNVRAM
, IOService
); 
  85 #if defined(DEBUG) || defined(DEVELOPMENT) 
  86 #define DEBUG_INFO(fmt, args...)                                    \ 
  89         IOLog("IONVRAM::%s:%u - " fmt, __FUNCTION__, __LINE__, ##args); \ 
  92 #define DEBUG_ALWAYS(fmt, args...)                                  \ 
  94         IOLog("IONVRAM::%s:%u - " fmt, __FUNCTION__, __LINE__, ##args); \ 
  97 #define DEBUG_INFO(fmt, args...) 
  98 #define DEBUG_ALWAYS(fmt, args...) 
 101 #define DEBUG_ERROR DEBUG_ALWAYS 
 103 #define CONTROLLERLOCK()                             \ 
 105         if (preemption_enabled() && !panic_active()) \ 
 106                 IOLockLock(_controllerLock);         \ 
 109 #define CONTROLLERUNLOCK()                           \ 
 111         if (preemption_enabled() && !panic_active()) \ 
 112                 IOLockUnlock(_controllerLock);       \ 
 115 #define NVRAMREADLOCK()                             \ 
 117         if (preemption_enabled() && !panic_active()) \ 
 118                 IORWLockRead(_variableLock);         \ 
 121 #define NVRAMWRITELOCK()                            \ 
 123         if (preemption_enabled() && !panic_active()) \ 
 124                 IORWLockWrite(_variableLock);        \ 
 127 #define NVRAMUNLOCK()                               \ 
 129         if (preemption_enabled() && !panic_active()) \ 
 130                 IORWLockUnlock(_variableLock);       \ 
 133 #define NVRAMLOCKASSERTHELD()                                      \ 
 135         if (preemption_enabled() && !panic_active())                \ 
 136                 IORWLockAssert(_variableLock, kIORWLockAssertHeld); \ 
 139 #define NVRAMLOCKASSERTEXCLUSIVE()                                  \ 
 141         if (preemption_enabled() && !panic_active())                 \ 
 142                 IORWLockAssert(_variableLock, kIORWLockAssertWrite); \ 
 145 enum NVRAMPartitionType 
{ 
 146         kIONVRAMPartitionSystem
, 
 147         kIONVRAMPartitionCommon
 
 151         NVRAMPartitionType        type
; 
 154         OSSharedPtr
<OSDictionary
> &dict
; 
 158 // Guid for Apple System Boot variables 
 159 // 40A0DDD2-77F8-4392-B4A3-1E7304206516 
 160 UUID_DEFINE(gAppleSystemVariableGuid
, 0x40, 0xA0, 0xDD, 0xD2, 0x77, 0xF8, 0x43, 0x92, 0xB4, 0xA3, 0x1E, 0x73, 0x04, 0x20, 0x65, 0x16); 
 162 // Apple NVRAM Variable namespace (APPLE_VENDOR_OS_VARIABLE_GUID) 
 163 // 7C436110-AB2A-4BBB-A880-FE41995C9F82 
 164 UUID_DEFINE(gAppleNVRAMGuid
, 0x7C, 0x43, 0x61, 0x10, 0xAB, 0x2A, 0x4B, 0xBB, 0xA8, 0x80, 0xFE, 0x41, 0x99, 0x5C, 0x9F, 0x82); 
 166 static bool gNVRAMLogging 
= false; 
 167 static bool gInternalBuild 
= false; 
 169 // allowlist variables from macboot that need to be set/get from system region if present 
 170 static const char * const gNVRAMSystemList
[] = { 
 171         "allow-root-hash-mismatch", 
 173         "auto-boot-halt-stage", 
 179         "com.apple.System.boot-nonce", 
 182         "one-time-boot-command", // Needed for diags customer install flows 
 183         "policy-nonce-digests", 
 184         "prevent-restores", // Keep for factory <rdar://problem/70476321> 
 188         "SystemAudioVolumeExtension", 
 189         "SystemAudioVolumeSaved", 
 195         IONVRAMVariableType type
; 
 199 VariableTypeEntry gVariableTypes
[] = { 
 200         {"auto-boot?", kOFVariableTypeBoolean
}, 
 201         {"boot-args", kOFVariableTypeString
}, 
 202         {"boot-command", kOFVariableTypeString
}, 
 203         {"boot-device", kOFVariableTypeString
}, 
 204         {"boot-file", kOFVariableTypeString
}, 
 205         {"boot-screen", kOFVariableTypeString
}, 
 206         {"boot-script", kOFVariableTypeString
}, 
 207         {"console-screen", kOFVariableTypeString
}, 
 208         {"default-client-ip", kOFVariableTypeString
}, 
 209         {"default-gateway-ip", kOFVariableTypeString
}, 
 210         {"default-mac-address?", kOFVariableTypeBoolean
}, 
 211         {"default-router-ip", kOFVariableTypeString
}, 
 212         {"default-server-ip", kOFVariableTypeString
}, 
 213         {"default-subnet-mask", kOFVariableTypeString
}, 
 214         {"diag-device", kOFVariableTypeString
}, 
 215         {"diag-file", kOFVariableTypeString
}, 
 216         {"diag-switch?", kOFVariableTypeBoolean
}, 
 217         {"fcode-debug?", kOFVariableTypeBoolean
}, 
 218         {"input-device", kOFVariableTypeString
}, 
 219         {"input-device-1", kOFVariableTypeString
}, 
 220         {"little-endian?", kOFVariableTypeBoolean
}, 
 221         {"load-base", kOFVariableTypeNumber
}, 
 222         {"mouse-device", kOFVariableTypeString
}, 
 223         {"nvramrc", kOFVariableTypeString
}, 
 224         {"oem-banner", kOFVariableTypeString
}, 
 225         {"oem-banner?", kOFVariableTypeBoolean
}, 
 226         {"oem-logo", kOFVariableTypeString
}, 
 227         {"oem-logo?", kOFVariableTypeBoolean
}, 
 228         {"output-device", kOFVariableTypeString
}, 
 229         {"output-device-1", kOFVariableTypeString
}, 
 230         {"pci-probe-list", kOFVariableTypeNumber
}, 
 231         {"pci-probe-mask", kOFVariableTypeNumber
}, 
 232         {"real-base", kOFVariableTypeNumber
}, 
 233         {"real-mode?", kOFVariableTypeBoolean
}, 
 234         {"real-size", kOFVariableTypeNumber
}, 
 235         {"screen-#columns", kOFVariableTypeNumber
}, 
 236         {"screen-#rows", kOFVariableTypeNumber
}, 
 237         {"security-mode", kOFVariableTypeString
}, 
 238         {"selftest-#megs", kOFVariableTypeNumber
}, 
 239         {"use-generic?", kOFVariableTypeBoolean
}, 
 240         {"use-nvramrc?", kOFVariableTypeBoolean
}, 
 241         {"virt-base", kOFVariableTypeNumber
}, 
 242         {"virt-size", kOFVariableTypeNumber
}, 
 244 #if !defined(__x86_64__) 
 245         {"acc-cm-override-charger-count", kOFVariableTypeNumber
}, 
 246         {"acc-cm-override-count", kOFVariableTypeNumber
}, 
 247         {"acc-mb-ld-lifetime", kOFVariableTypeNumber
}, 
 248         {"com.apple.System.boot-nonce", kOFVariableTypeString
}, 
 249         {"darkboot", kOFVariableTypeBoolean
}, 
 250         {"enter-tdm-mode", kOFVariableTypeBoolean
}, 
 251 #endif /* !defined(__x86_64__) */ 
 252         {nullptr, kOFVariableTypeData
} // Default type to return 
 255 union VariablePermission 
{ 
 257                 uint64_t UserWrite            
:1; 
 258                 uint64_t RootRequired         
:1; 
 259                 uint64_t KernelOnly           
:1; 
 260                 uint64_t ResetNVRAMOnlyDelete 
:1; 
 261                 uint64_t NeverAllowedToDelete 
:1; 
 262                 uint64_t FullAccess           
:1; 
 263                 uint64_t Reserved
:58; 
 270         VariablePermission p
; 
 271 } VariablePermissionEntry
; 
 274 VariablePermissionEntry gVariablePermissions
[] = { 
 275         {"aapl,pci", .p
.Bits
.RootRequired 
= 1}, 
 276         {"battery-health", .p
.Bits
.RootRequired 
= 1, 
 277          .p
.Bits
.NeverAllowedToDelete 
= 1}, 
 278         {"boot-image", .p
.Bits
.UserWrite 
= 1}, 
 279         {"com.apple.System.fp-state", .p
.Bits
.KernelOnly 
= 1}, 
 280         {"policy-nonce-digests", .p
.Bits
.ResetNVRAMOnlyDelete 
= 1}, // Deleting this via user triggered obliterate leave J273a unable to boot 
 281         {"security-password", .p
.Bits
.RootRequired 
= 1}, 
 283 #if !defined(__x86_64__) 
 284         {"acc-cm-override-charger-count", .p
.Bits
.KernelOnly 
= 1}, 
 285         {"acc-cm-override-count", .p
.Bits
.KernelOnly 
= 1}, 
 286         {"acc-mb-ld-lifetime", .p
.Bits
.KernelOnly 
= 1}, 
 287         {"backlight-level", .p
.Bits
.UserWrite 
= 1}, 
 288         {"backlight-nits", .p
.Bits
.UserWrite 
= 1}, 
 289         {"com.apple.System.boot-nonce", .p
.Bits
.KernelOnly 
= 1}, 
 290         {"com.apple.System.sep.art", .p
.Bits
.KernelOnly 
= 1}, 
 291         {"darkboot", .p
.Bits
.UserWrite 
= 1}, 
 292         {"nonce-seeds", .p
.Bits
.KernelOnly 
= 1}, 
 293 #endif /* !defined(__x86_64__) */ 
 295         {nullptr, {.Bits
.FullAccess 
= 1}} // Default access 
 298 static IONVRAMVariableType
 
 299 getVariableType(const char *propName
) 
 301         const VariableTypeEntry 
*entry
; 
 303         entry 
= gVariableTypes
; 
 304         while (entry
->name 
!= nullptr) { 
 305                 if (strcmp(entry
->name
, propName
) == 0) { 
 314 static IONVRAMVariableType
 
 315 getVariableType(const OSSymbol 
*propSymbol
) 
 317         return getVariableType(propSymbol
->getCStringNoCopy()); 
 320 static VariablePermission
 
 321 getVariablePermission(const char *propName
) 
 323         const VariablePermissionEntry 
*entry
; 
 325         entry 
= gVariablePermissions
; 
 326         while (entry
->name 
!= nullptr) { 
 327                 if (strcmp(entry
->name
, propName
) == 0) { 
 337 variableInAllowList(const char *varName
) 
 341         while (gNVRAMSystemList
[i
] != nullptr) { 
 342                 if (strcmp(varName
, gNVRAMSystemList
[i
]) == 0) { 
 352 verifyWriteSizeLimit(const uuid_t 
*varGuid
, const char *variableName
, size_t propDataSize
) 
 354         if (variableInAllowList(variableName
)) { 
 355                 if (strnstr(variableName
, "breadcrumbs", strlen(variableName
)) != NULL
) { 
 356                         return propDataSize 
<= 1024; 
 358                         return propDataSize 
<= 768; 
 365 #if defined(DEBUG) || defined(DEVELOPMENT) 
 367 getNVRAMOpString(IONVRAMOperation op
) 
 370         case kIONVRAMOperationRead
: 
 372         case kIONVRAMOperationWrite
: 
 374         case kIONVRAMOperationDelete
: 
 376         case kIONVRAMOperationObliterate
: 
 378         case kIONVRAMOperationReset
: 
 387 verifyPermission(IONVRAMOperation op
, const uuid_t 
*varGuid
, const char *varName
) 
 389         VariablePermission perm
; 
 390         bool kernel
, admin
, writeEntitled
, readEntitled
, allowList
, systemGuid
, systemEntitled
, systemInternalEntitled
, systemAllow
; 
 393         perm 
= getVariablePermission(varName
); 
 395         kernel 
= current_task() == kernel_task
; 
 397         if (perm
.Bits
.KernelOnly
) { 
 398                 DEBUG_INFO("KernelOnly access for %s, kernel=%d\n", varName
, kernel
); 
 403         allowList              
= variableInAllowList(varName
); 
 404         systemGuid             
= uuid_compare(*varGuid
, gAppleSystemVariableGuid
) == 0; 
 405         admin                  
= IOUserClient::clientHasPrivilege(current_task(), kIONVRAMPrivilege
) == kIOReturnSuccess
; 
 406         writeEntitled          
= IOTaskHasEntitlement(current_task(), kIONVRAMWriteAccessKey
); 
 407         readEntitled           
= IOTaskHasEntitlement(current_task(), kIONVRAMReadAccessKey
); 
 408         systemEntitled         
= IOTaskHasEntitlement(current_task(), kIONVRAMSystemAllowKey
); 
 409         systemInternalEntitled 
= IOTaskHasEntitlement(current_task(), kIONVRAMSystemInternalAllowKey
); 
 411         systemAllow 
= systemEntitled 
|| (systemInternalEntitled 
&& gInternalBuild
) || kernel
; 
 414         case kIONVRAMOperationRead
: 
 415                 if (kernel 
|| admin 
|| readEntitled 
|| perm
.Bits
.FullAccess
) { 
 420         case kIONVRAMOperationWrite
: 
 421                 if (kernel 
|| perm
.Bits
.UserWrite 
|| admin 
|| writeEntitled
) { 
 425                                                 DEBUG_ERROR("Allowed write to system region when NOT entitled for %s\n", varName
); 
 427                                 } else if (!systemAllow
) { 
 428                                         DEBUG_ERROR("Not entitled for system region writes for %s\n", varName
); 
 436         case kIONVRAMOperationDelete
: 
 437         case kIONVRAMOperationObliterate
: 
 438         case kIONVRAMOperationReset
: 
 439                 if (perm
.Bits
.NeverAllowedToDelete
) { 
 440                         DEBUG_INFO("Never allowed to delete %s\n", varName
); 
 442                 } else if ((op 
== kIONVRAMOperationObliterate
) && perm
.Bits
.ResetNVRAMOnlyDelete
) { 
 443                         DEBUG_INFO("Not allowed to obliterate %s\n", varName
); 
 445                 } else if ((op 
== kIONVRAMOperationDelete
) && perm
.Bits
.ResetNVRAMOnlyDelete
) { 
 446                         DEBUG_INFO("Only allowed to delete %s via NVRAM reset\n", varName
); 
 450                 if (kernel 
|| perm
.Bits
.UserWrite 
|| admin 
|| writeEntitled
) { 
 454                                                 DEBUG_ERROR("Allowed delete to system region when NOT entitled for %s\n", varName
); 
 456                                 } else if (!systemAllow
) { 
 457                                         DEBUG_ERROR("Not entitled for system region deletes for %s\n", varName
); 
 467         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", 
 468             getNVRAMOpString(op
), varName
, ok 
? "granted" : "denied", kernel
, admin
, writeEntitled
, readEntitled
, systemGuid
, systemEntitled
, systemInternalEntitled
, perm
.Bits
.UserWrite
); 
 473 verifyPermission(IONVRAMOperation op
, const uuid_t 
*varGuid
, const OSSymbol 
*varName
) 
 475         return verifyPermission(op
, varGuid
, varName
->getCStringNoCopy()); 
 479  * Parse a variable name of the form "GUID:name". 
 480  * If the name cannot be parsed, substitute the Apple global variable GUID. 
 481  * Returns TRUE if a GUID was found in the name, FALSE otherwise. 
 482  * The guidResult and nameResult arguments may be nullptr if you just want 
 483  * to check the format of the string. 
 486 parseVariableName(const char *key
, uuid_t 
*guidResult
, const char **nameResult
) 
 488         uuid_string_t temp    
= {0}; 
 489         size_t        keyLen  
= strlen(key
); 
 491         const char    *name   
= key
; 
 494         if (keyLen 
> sizeof(temp
)) { 
 495                 // check for at least UUID + ":" + more 
 496                 memcpy(temp
, key
, sizeof(temp
) - 1); 
 498                 if ((uuid_parse(temp
, guid
) == 0) && 
 499                     (key
[sizeof(temp
) - 1] == ':')) { 
 500                         name 
= key 
+ sizeof(temp
); 
 506                 ok 
? uuid_copy(*guidResult
, guid
) : uuid_copy(*guidResult
, gAppleNVRAMGuid
); 
 516 skipKey(const OSSymbol 
*aKey
) 
 518         return aKey
->isEqualTo(kIOClassNameOverrideKey
) || 
 519                aKey
->isEqualTo(kIOBSDNameKey
) || 
 520                aKey
->isEqualTo(kIOBSDNamesKey
) || 
 521                aKey
->isEqualTo(kIOBSDMajorKey
) || 
 522                aKey
->isEqualTo(kIOBSDMinorKey
) || 
 523                aKey
->isEqualTo(kIOBSDUnitKey
); 
 526 // ************************** IODTNVRAMVariables **************************** 
 528 // private IOService based class for publishing distinct dictionary properties on 
 529 // for easy ioreg access since the serializeProperties call is overloaded and is used 
 530 // as variable access 
 531 class IODTNVRAMVariables 
: public IOService
 
 533         OSDeclareDefaultStructors(IODTNVRAMVariables
) 
 535         IODTNVRAM        
*_provider
; 
 536         OSDictionary     
*_variables
; 
 540         bool                    init(const uuid_t 
*guid
); 
 541         virtual bool            start(IOService 
* provider
) APPLE_KEXT_OVERRIDE
; 
 542         virtual IOReturn        
setVariables(OSObject 
* properties
); 
 544         virtual bool            serializeProperties(OSSerialize 
*s
) const APPLE_KEXT_OVERRIDE
; 
 545         virtual OSPtr
<OSObject
> copyProperty(const OSSymbol 
*aKey
) const APPLE_KEXT_OVERRIDE
; 
 546         virtual OSObject        
*getProperty(const OSSymbol 
*aKey
) const APPLE_KEXT_OVERRIDE
; 
 547         virtual bool            setProperty(const OSSymbol 
*aKey
, OSObject 
*anObject
) APPLE_KEXT_OVERRIDE
; 
 548         virtual IOReturn        
setProperties(OSObject 
*properties
) APPLE_KEXT_OVERRIDE
; 
 549         virtual void            removeProperty(const OSSymbol 
*aKey
) APPLE_KEXT_OVERRIDE
; 
 552 OSDefineMetaClassAndStructors(IODTNVRAMVariables
, IOService
) 
 555 IODTNVRAMVariables::init(const uuid_t 
*guid
) 
 557         if (!super::init()) { 
 561         if (guid 
== nullptr) { 
 565         uuid_copy(_guid
, *guid
); 
 571 IODTNVRAMVariables::start(IOService 
* provider
) 
 573         if (!IOService::start(provider
)) { 
 577         _provider 
= OSDynamicCast(IODTNVRAM
, provider
); 
 578         if (_provider 
== nullptr) { 
 593 IODTNVRAMVariables::setVariables(OSObject 
* variables
) 
 595         if (OSDynamicCast(OSDictionary
, variables
)) { 
 596                 OSSafeReleaseNULL(_variables
); 
 597                 _variables 
= OSDynamicCast(OSDictionary
, variables
); 
 601         return kIOReturnSuccess
; 
 605 IODTNVRAMVariables::serializeProperties(OSSerialize 
*s
) const 
 608         OSSharedPtr
<OSDictionary
>         dict
; 
 609         OSSharedPtr
<OSCollectionIterator
> iter
; 
 610         OSSharedPtr
<OSDictionary
>         localVariables(_variables
, OSRetain
); 
 613         if (localVariables 
== nullptr) { 
 617         dict 
= OSDictionary::withCapacity(localVariables
->getCount()); 
 618         if (dict 
== nullptr) { 
 619                 DEBUG_ERROR("No dictionary\n"); 
 623         iter 
= OSCollectionIterator::withCollection(localVariables
.get()); 
 624         if (iter 
== nullptr) { 
 625                 DEBUG_ERROR("failed to create iterator\n"); 
 629         while ((key 
= OSDynamicCast(OSSymbol
, iter
->getNextObject()))) { 
 630                 if (verifyPermission(kIONVRAMOperationRead
, &_guid
, key
)) { 
 631                         dict
->setObject(key
, localVariables
->getObject(key
)); 
 635         ok 
= dict
->serialize(s
); 
 638         DEBUG_INFO("ok=%d\n", ok
); 
 643 IODTNVRAMVariables::copyProperty(const OSSymbol 
*aKey
) const 
 645         if (_provider 
&& !skipKey(aKey
)) { 
 646                 DEBUG_INFO("aKey=%s\n", aKey
->getCStringNoCopy()); 
 648                 return _provider
->copyPropertyWithGUIDAndName(&_guid
, aKey
->getCStringNoCopy()); 
 655 IODTNVRAMVariables::getProperty(const OSSymbol 
*aKey
) const 
 657         OSSharedPtr
<OSObject
> theObject 
= copyProperty(aKey
); 
 659         return theObject
.get(); 
 663 IODTNVRAMVariables::setProperty(const OSSymbol 
*aKey
, OSObject 
*anObject
) 
 666                 return _provider
->setPropertyWithGUIDAndName(&_guid
, aKey
->getCStringNoCopy(), anObject
); 
 673 IODTNVRAMVariables::setProperties(OSObject 
*properties
) 
 675         IOReturn                          ret 
= kIOReturnSuccess
; 
 679         OSSharedPtr
<OSCollectionIterator
> iter
; 
 682                 dict 
= OSDynamicCast(OSDictionary
, properties
); 
 683                 if (dict 
== nullptr) { 
 684                         DEBUG_ERROR("Not a dictionary\n"); 
 685                         return kIOReturnBadArgument
; 
 688                 iter 
= OSCollectionIterator::withCollection(dict
); 
 689                 if (iter 
== nullptr) { 
 690                         DEBUG_ERROR("Couldn't create iterator\n"); 
 691                         return kIOReturnBadArgument
; 
 694                 while (ret 
== kIOReturnSuccess
) { 
 695                         key 
= OSDynamicCast(OSSymbol
, iter
->getNextObject()); 
 696                         if (key 
== nullptr) { 
 700                         object 
= dict
->getObject(key
); 
 701                         if (object 
== nullptr) { 
 705                         ret 
= setProperty(key
, object
); 
 708                 ret 
= kIOReturnNotReady
; 
 711         DEBUG_INFO("ret=%#08x\n", ret
); 
 717 IODTNVRAMVariables::removeProperty(const OSSymbol 
*aKey
) 
 720                 _provider
->removePropertyWithGUIDAndName(&_guid
, aKey
->getCStringNoCopy()); 
 725 // **************************** IODTNVRAM ********************************* 
 728 IODTNVRAM::init(IORegistryEntry 
*old
, const IORegistryPlane 
*plane
) 
 730         OSSharedPtr
<OSDictionary
> dict
; 
 732         if (!super::init(old
, plane
)) { 
 736         PE_parse_boot_argn("nvram-log", &gNVRAMLogging
, sizeof(gNVRAMLogging
)); 
 738 #if XNU_TARGET_OS_OSX 
 740         gInternalBuild 
= (csr_check(CSR_ALLOW_APPLE_INTERNAL
) == 0); 
 742 #endif // XNU_TARGET_OS_OSX 
 744         DEBUG_INFO("gInternalBuild = %d\n", gInternalBuild
); 
 746         _variableLock 
= IORWLockAlloc(); 
 747         if (!_variableLock
) { 
 751         _controllerLock 
= IOLockAlloc(); 
 752         if (!_controllerLock
) { 
 756         dict 
=  OSDictionary::withCapacity(1); 
 757         if (dict 
== nullptr) { 
 760         setPropertyTable(dict
.get()); 
 763         _nvramSize 
= getNVRAMSize(); 
 764         if (_nvramSize 
== 0) { 
 765                 DEBUG_ERROR("NVRAM : Error - default size not specified in DT\n"); 
 768         // partition offsets are UInt16 (bytes / 0x10) + 1 
 769         if (_nvramSize 
> 0xFFFF * 0x10) { 
 770                 DEBUG_ERROR("NVRAM : truncating _nvramSize from %ld\n", (long) _nvramSize
); 
 771                 _nvramSize 
= 0xFFFF * 0x10; 
 773         _nvramImage 
= IONew(UInt8
, _nvramSize
); 
 774         if (_nvramImage 
== nullptr) { 
 778         _nvramPartitionOffsets 
= OSDictionary::withCapacity(1); 
 779         if (_nvramPartitionOffsets 
== nullptr) { 
 783         _nvramPartitionLengths 
= OSDictionary::withCapacity(1); 
 784         if (_nvramPartitionLengths 
== nullptr) { 
 788         _registryPropertiesKey 
= OSSymbol::withCStringNoCopy("aapl,pci"); 
 789         if (_registryPropertiesKey 
== nullptr) { 
 793         // <rdar://problem/9529235> race condition possible between 
 794         // IODTNVRAM and IONVRAMController (restore loses boot-args) 
 797         // Require at least the common partition to be present and error free 
 798         if (_commonDict 
== nullptr) { 
 806 IODTNVRAM::initProxyData(void) 
 808         OSSharedPtr
<IORegistryEntry
> entry
; 
 809         const char                   *key 
= "nvram-proxy-data"; 
 813         entry 
= IORegistryEntry::fromPath("/chosen", gIODTPlane
); 
 814         if (entry 
!= nullptr) { 
 815                 OSSharedPtr
<OSObject
> prop 
= entry
->copyProperty(key
); 
 816                 if (prop 
!= nullptr) { 
 817                         data 
= OSDynamicCast(OSData
, prop
.get()); 
 818                         if (data 
!= nullptr) { 
 819                                 bytes 
= data
->getBytesNoCopy(); 
 820                                 if ((bytes 
!= nullptr) && (data
->getLength() <= _nvramSize
)) { 
 821                                         bcopy(bytes
, _nvramImage
, data
->getLength()); 
 827                 entry
->removeProperty(key
); 
 832 IODTNVRAM::getNVRAMSize(void) 
 834         OSSharedPtr
<IORegistryEntry
> entry
; 
 835         const char                   *key 
= "nvram-total-size"; 
 839         entry 
= IORegistryEntry::fromPath("/chosen", gIODTPlane
); 
 840         if (entry 
!= nullptr) { 
 841                 OSSharedPtr
<OSObject
> prop 
= entry
->copyProperty(key
); 
 842                 if (prop 
!= nullptr) { 
 843                         data 
= OSDynamicCast(OSData
, prop
.get()); 
 844                         if (data 
!= nullptr) { 
 845                                 size 
= *((UInt32
*)data
->getBytesNoCopy()); 
 846                                 DEBUG_ALWAYS("NVRAM size is %u bytes\n", (unsigned int) size
); 
 855 IODTNVRAM::registerNVRAMController(IONVRAMController 
*nvram
) 
 859         if (_nvramController 
!= nullptr) { 
 860                 DEBUG_ERROR("Duplicate controller set\n"); 
 864         DEBUG_INFO("setting controller\n"); 
 867         _nvramController 
= nvram
; 
 870         // <rdar://problem/9529235> race condition possible between 
 871         // IODTNVRAM and IONVRAMController (restore loses boot-args) 
 873                 DEBUG_INFO("Reading non-proxied NVRAM data\n"); 
 874                 _nvramController
->read(0, _nvramImage
, _nvramSize
); 
 878         if (_systemPartitionSize
) { 
 879                 _systemService 
= new IODTNVRAMVariables
; 
 881                 if (!_systemService 
|| !_systemService
->init(&gAppleSystemVariableGuid
)) { 
 882                         DEBUG_ERROR("Unable to start the system service!\n"); 
 886                 _systemService
->setName("options-system"); 
 888                 if (!_systemService
->attach(this)) { 
 889                         DEBUG_ERROR("Unable to attach the system service!\n"); 
 890                         OSSafeReleaseNULL(_systemService
); 
 894                 if (!_systemService
->start(this)) { 
 895                         DEBUG_ERROR("Unable to start the system service!\n"); 
 896                         _systemService
->detach(this); 
 897                         OSSafeReleaseNULL(_systemService
); 
 903         if (_commonPartitionSize
) { 
 904                 _commonService 
= new IODTNVRAMVariables
; 
 906                 if (!_commonService 
|| !_commonService
->init(&gAppleNVRAMGuid
)) { 
 907                         DEBUG_ERROR("Unable to start the common service!\n"); 
 911                 _commonService
->setName("options-common"); 
 913                 if (!_commonService
->attach(this)) { 
 914                         DEBUG_ERROR("Unable to attach the common service!\n"); 
 915                         OSSafeReleaseNULL(_commonService
); 
 919                 if (!_commonService
->start(this)) { 
 920                         DEBUG_ERROR("Unable to start the common service!\n"); 
 921                         _commonService
->detach(this); 
 922                         OSSafeReleaseNULL(_commonService
); 
 928         ret 
= serializeVariables(); 
 929         DEBUG_INFO("serializeVariables ret=%#08x\n", ret
); 
 933 IODTNVRAM::initNVRAMImage(void) 
 935         char   partitionID
[18]; 
 936         UInt32 partitionOffset
, partitionLength
; 
 937         UInt32 currentLength
, currentOffset 
= 0; 
 939         _commonPartitionOffset 
= 0xFFFFFFFF; 
 940         _systemPartitionOffset 
= 0xFFFFFFFF; 
 942         // Look through the partitions to find the OF and System partitions. 
 943         while (currentOffset 
< _nvramSize
) { 
 944                 bool common_partition
; 
 945                 bool system_partition
; 
 946                 chrp_nvram_header_t 
* header 
= (chrp_nvram_header_t 
*)(_nvramImage 
+ currentOffset
); 
 947                 const uint8_t common_v1_name
[sizeof(header
->name
)] = {NVRAM_CHRP_PARTITION_NAME_COMMON_V1
}; 
 948                 const uint8_t common_v2_name
[sizeof(header
->name
)] = {NVRAM_CHRP_PARTITION_NAME_COMMON_V2
}; 
 949                 const uint8_t system_v1_name
[sizeof(header
->name
)] = {NVRAM_CHRP_PARTITION_NAME_SYSTEM_V1
}; 
 950                 const uint8_t system_v2_name
[sizeof(header
->name
)] = {NVRAM_CHRP_PARTITION_NAME_SYSTEM_V2
}; 
 952                 currentLength 
= header
->len 
* NVRAM_CHRP_LENGTH_BLOCK_SIZE
; 
 954                 if (currentLength 
< sizeof(chrp_nvram_header_t
)) { 
 958                 partitionOffset 
= currentOffset 
+ sizeof(chrp_nvram_header_t
); 
 959                 partitionLength 
= currentLength 
- sizeof(chrp_nvram_header_t
); 
 961                 if ((partitionOffset 
+ partitionLength
) > _nvramSize
) { 
 965                 common_partition 
= (memcmp(header
->name
, common_v1_name
, sizeof(header
->name
)) == 0) || 
 966                     (memcmp(header
->name
, common_v2_name
, sizeof(header
->name
)) == 0); 
 967                 system_partition 
= (memcmp(header
->name
, system_v1_name
, sizeof(header
->name
)) == 0) || 
 968                     (memcmp(header
->name
, system_v2_name
, sizeof(header
->name
)) == 0); 
 970                 if (common_partition
) { 
 971                         _commonPartitionOffset 
= partitionOffset
; 
 972                         _commonPartitionSize 
= partitionLength
; 
 973                 } else if (system_partition
) { 
 974                         _systemPartitionOffset 
= partitionOffset
; 
 975                         _systemPartitionSize 
= partitionLength
; 
 977                         OSSharedPtr
<OSNumber
> partitionOffsetNumber
, partitionLengthNumber
; 
 979                         // Construct the partition ID from the signature and name. 
 980                         snprintf(partitionID
, sizeof(partitionID
), "%#02x,", header
->sig
); 
 981                         memcpy(partitionID 
+ 5, header
->name
, sizeof(header
->name
)); 
 982                         partitionID
[17] = '\0'; 
 984                         partitionOffsetNumber 
= OSNumber::withNumber(partitionOffset
, 32); 
 985                         partitionLengthNumber 
= OSNumber::withNumber(partitionLength
, 32); 
 987                         // Save the partition offset and length 
 988                         _nvramPartitionOffsets
->setObject(partitionID
, partitionOffsetNumber
.get()); 
 989                         _nvramPartitionLengths
->setObject(partitionID
, partitionLengthNumber
.get()); 
 991                 currentOffset 
+= currentLength
; 
 994         if (_commonPartitionOffset 
!= 0xFFFFFFFF) { 
 995                 _commonImage 
= _nvramImage 
+ _commonPartitionOffset
; 
 998         if (_systemPartitionOffset 
!= 0xFFFFFFFF) { 
 999                 _systemImage 
= _nvramImage 
+ _systemPartitionOffset
; 
1002         DEBUG_ALWAYS("NVRAM : commonPartitionOffset - %#x, commonPartitionSize - %#x, systemPartitionOffset - %#x, systemPartitionSize - %#x\n", 
1003             (unsigned int) _commonPartitionOffset
, (unsigned int) _commonPartitionSize
, (unsigned int) _systemPartitionOffset
, (unsigned int) _systemPartitionSize
); 
1005         _lastDeviceSync 
= 0; 
1006         _freshInterval 
= TRUE
;          // we will allow sync() even before the first 15 minutes have passed. 
1012 IODTNVRAM::syncInternal(bool rateLimit
) 
1014         DEBUG_INFO("rateLimit=%d\n", rateLimit
); 
1016         // Don't try to perform controller operations if none has been registered. 
1017         if (_nvramController 
== nullptr) { 
1021         // Rate limit requests to sync. Drivers that need this rate limiting will 
1022         // shadow the data and only write to flash when they get a sync call 
1023         if (rateLimit 
&& !safeToSync()) { 
1027         DEBUG_INFO("Calling sync()\n"); 
1030         _nvramController
->sync(); 
1035 IODTNVRAM::sync(void) 
1037         syncInternal(false); 
1041 IODTNVRAM::serializeProperties(OSSerialize 
*s
) const 
1043         const OSSymbol                    
*key
; 
1044         OSSharedPtr
<OSDictionary
>         systemDict
, commonDict
, dict
; 
1045         OSSharedPtr
<OSCollectionIterator
> iter
; 
1047         unsigned int                      totalCapacity 
= 0; 
1051                 commonDict 
= OSDictionary::withDictionary(_commonDict
.get()); 
1055                 systemDict 
= OSDictionary::withDictionary(_systemDict
.get()); 
1059         totalCapacity 
+= (commonDict 
!= nullptr) ? commonDict
->getCapacity() : 0; 
1060         totalCapacity 
+= (systemDict 
!= nullptr) ? systemDict
->getCapacity() : 0; 
1062         dict 
= OSDictionary::withCapacity(totalCapacity
); 
1064         if (dict 
== nullptr) { 
1065                 DEBUG_ERROR("No dictionary\n"); 
1069         // Copy system entries first if present then copy unique common entries 
1070         if (systemDict 
!= nullptr) { 
1071                 iter 
= OSCollectionIterator::withCollection(systemDict
.get()); 
1072                 if (iter 
== nullptr) { 
1073                         DEBUG_ERROR("failed to create iterator\n"); 
1077                 while ((key 
= OSDynamicCast(OSSymbol
, iter
->getNextObject()))) { 
1078                         if (verifyPermission(kIONVRAMOperationRead
, &gAppleSystemVariableGuid
, key
)) { 
1079                                 dict
->setObject(key
, systemDict
->getObject(key
)); 
1086         if (commonDict 
!= nullptr) { 
1087                 iter 
= OSCollectionIterator::withCollection(commonDict
.get()); 
1088                 if (iter 
== nullptr) { 
1089                         DEBUG_ERROR("failed to create common iterator\n"); 
1093                 while ((key 
= OSDynamicCast(OSSymbol
, iter
->getNextObject()))) { 
1094                         if (dict
->getObject(key
) != nullptr) { 
1098                         if (verifyPermission(kIONVRAMOperationRead
, &gAppleNVRAMGuid
, key
)) { 
1099                                 dict
->setObject(key
, commonDict
->getObject(key
)); 
1104         ok 
= dict
->serialize(s
); 
1107         DEBUG_INFO("ok=%d\n", ok
); 
1113 IODTNVRAM::chooseDictionary(IONVRAMOperation operation
, const uuid_t 
*varGuid
, const char *variableName
, OSDictionary 
**dict
) const 
1115         if (_systemDict 
!= nullptr) { 
1116                 bool systemGuid 
= uuid_compare(*varGuid
, gAppleSystemVariableGuid
) == 0; 
1118                 if (variableInAllowList(variableName
)) { 
1119                         DEBUG_INFO("Using system dictionary due to allow list\n"); 
1121                                 DEBUG_ERROR("System GUID NOT used for %s\n", variableName
); 
1123                         *dict 
= _systemDict
.get(); 
1124                 } else if (systemGuid
) { 
1125                         DEBUG_INFO("Using system dictionary via GUID\n"); 
1126                         *dict 
= _systemDict
.get(); 
1128                         DEBUG_INFO("Using common dictionary\n"); 
1129                         *dict 
= _commonDict
.get(); 
1131                 return kIOReturnSuccess
; 
1132         } else if (_commonDict 
!= nullptr) { 
1133                 DEBUG_INFO("Defaulting to common dictionary\n"); 
1134                 *dict 
= _commonDict
.get(); 
1135                 return kIOReturnSuccess
; 
1138         return kIOReturnNotFound
; 
1142 IODTNVRAM::flushDict(const uuid_t 
*guid
, IONVRAMOperation op
) 
1144         IOReturn err 
= kIOReturnSuccess
; 
1146         if ((_systemDict 
!= nullptr) && (uuid_compare(*guid
, gAppleSystemVariableGuid
) == 0)) { 
1147                 const OSSymbol 
*key
; 
1148                 OSSharedPtr
<OSDictionary
> newDict
; 
1149                 OSSharedPtr
<OSCollectionIterator
> iter
; 
1151                 newDict 
= OSDictionary::withCapacity(_systemDict
->getCapacity()); 
1152                 iter 
= OSCollectionIterator::withCollection(_systemDict
.get()); 
1153                 if ((newDict 
== nullptr) || (iter 
== nullptr)) { 
1154                         err 
= kIOReturnNoMemory
; 
1158                 while ((key 
= OSDynamicCast(OSSymbol
, iter
->getNextObject()))) { 
1159                         if (!verifyPermission(op
, &gAppleSystemVariableGuid
, key
)) { 
1160                                 newDict
->setObject(key
, _systemDict
->getObject(key
)); 
1164                 _systemDict 
= newDict
; 
1166                 DEBUG_INFO("system dictionary flushed\n"); 
1167         } else if ((_commonDict 
!= nullptr) && (uuid_compare(*guid
, gAppleNVRAMGuid
) == 0)) { 
1168                 const OSSymbol 
*key
; 
1169                 OSSharedPtr
<OSDictionary
> newDict
; 
1170                 OSSharedPtr
<OSCollectionIterator
> iter
; 
1172                 newDict 
= OSDictionary::withCapacity(_commonDict
->getCapacity()); 
1173                 iter 
= OSCollectionIterator::withCollection(_commonDict
.get()); 
1174                 if ((newDict 
== nullptr) || (iter 
== nullptr)) { 
1175                         err 
= kIOReturnNoMemory
; 
1179                 while ((key 
= OSDynamicCast(OSSymbol
, iter
->getNextObject()))) { 
1180                         if (!verifyPermission(op
, &gAppleNVRAMGuid
, key
)) { 
1181                                 newDict
->setObject(key
, _commonDict
->getObject(key
)); 
1185                 _commonDict 
= newDict
; 
1187                 DEBUG_INFO("common dictionary flushed\n"); 
1195 IODTNVRAM::handleSpecialVariables(const char *name
, const uuid_t 
*guid
, const OSObject 
*obj
, IOReturn 
*error
) 
1197         IOReturn err 
= kIOReturnSuccess
; 
1198         bool special 
= false; 
1200         NVRAMLOCKASSERTEXCLUSIVE(); 
1202         // ResetNVRam flushes both regions in one call 
1203         // Obliterate can flush either separately 
1204         if (strcmp(name
, "ObliterateNVRam") == 0) { 
1205                 err 
= flushDict(guid
, kIONVRAMOperationObliterate
); 
1206         } else if (strcmp(name
, "ResetNVRam") == 0) { 
1207                 err 
= flushDict(&gAppleSystemVariableGuid
, kIONVRAMOperationReset
); 
1209                 if (err 
!= kIOReturnSuccess
) { 
1213                 err 
= flushDict(&gAppleNVRAMGuid
, kIONVRAMOperationReset
); 
1224 OSSharedPtr
<OSObject
> 
1225 IODTNVRAM::copyPropertyWithGUIDAndName(const uuid_t 
*guid
, const char *name
) const 
1229         OSSharedPtr
<OSObject
> theObject 
= nullptr; 
1231         result 
= chooseDictionary(kIONVRAMOperationRead
, guid
, name
, &dict
); 
1232         if (result 
!= kIOReturnSuccess
) { 
1233                 DEBUG_INFO("No dictionary\n"); 
1237         if (!verifyPermission(kIONVRAMOperationRead
, guid
, name
)) { 
1238                 DEBUG_INFO("Not privileged\n"); 
1243         theObject
.reset(dict
->getObject(name
), OSRetain
); 
1246         if (theObject 
!= nullptr) { 
1247                 DEBUG_INFO("found data\n"); 
1254 OSSharedPtr
<OSObject
> 
1255 IODTNVRAM::copyProperty(const OSSymbol 
*aKey
) const 
1257         const char            *variableName
; 
1260         if (skipKey(aKey
)) { 
1263         DEBUG_INFO("aKey=%s\n", aKey
->getCStringNoCopy()); 
1265         parseVariableName(aKey
->getCStringNoCopy(), &varGuid
, &variableName
); 
1267         return copyPropertyWithGUIDAndName(&varGuid
, variableName
); 
1270 OSSharedPtr
<OSObject
> 
1271 IODTNVRAM::copyProperty(const char *aKey
) const 
1273         OSSharedPtr
<const OSSymbol
> keySymbol
; 
1274         OSSharedPtr
<OSObject
>       theObject
; 
1276         keySymbol 
= OSSymbol::withCString(aKey
); 
1277         if (keySymbol 
!= nullptr) { 
1278                 theObject 
= copyProperty(keySymbol
.get()); 
1285 IODTNVRAM::getProperty(const OSSymbol 
*aKey
) const 
1287         // The shared pointer gets released at the end of the function, 
1288         // and returns a view into theObject. 
1289         OSSharedPtr
<OSObject
> theObject 
= copyProperty(aKey
); 
1291         return theObject
.get(); 
1295 IODTNVRAM::getProperty(const char *aKey
) const 
1297         // The shared pointer gets released at the end of the function, 
1298         // and returns a view into theObject. 
1299         OSSharedPtr
<OSObject
> theObject 
= copyProperty(aKey
); 
1301         return theObject
.get(); 
1305 IODTNVRAM::setPropertyWithGUIDAndName(const uuid_t 
*guid
, const char *name
, OSObject 
*anObject
) 
1307         IOReturn              ret 
= kIOReturnSuccess
; 
1308         bool                  remove 
= false; 
1309         OSString              
*tmpString 
= nullptr; 
1310         OSSharedPtr
<OSObject
> propObject
, oldObject
; 
1311         OSSharedPtr
<OSObject
> sharedObject(anObject
, OSRetain
); 
1313         bool                  deletePropertyKey
, syncNowPropertyKey
, forceSyncNowPropertyKey
; 
1315         size_t                propDataSize 
= 0; 
1317         deletePropertyKey 
= strncmp(name
, kIONVRAMDeletePropertyKey
, sizeof(kIONVRAMDeletePropertyKey
)) == 0; 
1318         syncNowPropertyKey 
= strncmp(name
, kIONVRAMSyncNowPropertyKey
, sizeof(kIONVRAMSyncNowPropertyKey
)) == 0; 
1319         forceSyncNowPropertyKey 
= strncmp(name
, kIONVRAMForceSyncNowPropertyKey
, sizeof(kIONVRAMForceSyncNowPropertyKey
)) == 0; 
1321         if (deletePropertyKey
) { 
1322                 tmpString 
= OSDynamicCast(OSString
, anObject
); 
1323                 if (tmpString 
!= nullptr) { 
1324                         const char *variableName
; 
1327                         DEBUG_INFO("kIONVRAMDeletePropertyKey found\n"); 
1329                         parseVariableName(tmpString
->getCStringNoCopy(), &varGuid
, &variableName
); 
1330                         removePropertyWithGUIDAndName(&varGuid
, variableName
); 
1332                         DEBUG_INFO("kIONVRAMDeletePropertyKey value needs to be an OSString\n"); 
1333                         ret 
= kIOReturnError
; 
1336         } else if (syncNowPropertyKey 
|| forceSyncNowPropertyKey
) { 
1337                 tmpString 
= OSDynamicCast(OSString
, anObject
); 
1338                 DEBUG_INFO("NVRAM sync key %s found\n", name
); 
1339                 if (tmpString 
!= nullptr) { 
1340                         // We still want to throttle NVRAM commit rate for SyncNow. ForceSyncNow is provided as a really big hammer. 
1341                         syncInternal(syncNowPropertyKey
); 
1343                         DEBUG_INFO("%s value needs to be an OSString\n", name
); 
1344                         ret 
= kIOReturnError
; 
1349         ret 
= chooseDictionary(kIONVRAMOperationWrite
, guid
, name
, &dict
); 
1350         if (ret 
!= kIOReturnSuccess
) { 
1351                 DEBUG_INFO("No dictionary\n"); 
1355         if (!verifyPermission(kIONVRAMOperationWrite
, guid
, name
)) { 
1356                 DEBUG_INFO("Not privileged\n"); 
1357                 ret 
= kIOReturnNotPrivileged
; 
1361         // Make sure the object is of the correct type. 
1362         switch (getVariableType(name
)) { 
1363         case kOFVariableTypeBoolean
: 
1364                 propObject 
= OSDynamicPtrCast
<OSBoolean
>(sharedObject
); 
1367         case kOFVariableTypeNumber
: 
1368                 propObject 
= OSDynamicPtrCast
<OSNumber
>(sharedObject
); 
1371         case kOFVariableTypeString
: 
1372                 propObject 
= OSDynamicPtrCast
<OSString
>(sharedObject
); 
1373                 if (propObject 
!= nullptr) { 
1374                         propDataSize 
= (OSDynamicPtrCast
<OSString
>(propObject
))->getLength(); 
1376                         if ((strncmp(name
, kIONVRAMBootArgsKey
, sizeof(kIONVRAMBootArgsKey
)) == 0) && (propDataSize 
>= BOOT_LINE_LENGTH
)) { 
1377                                 DEBUG_ERROR("boot-args size too large for BOOT_LINE_LENGTH, propDataSize=%zu\n", propDataSize
); 
1378                                 ret 
= kIOReturnNoSpace
; 
1384         case kOFVariableTypeData
: 
1385                 propObject 
= OSDynamicPtrCast
<OSData
>(sharedObject
); 
1386                 if (propObject 
== nullptr) { 
1387                         tmpString 
= OSDynamicCast(OSString
, sharedObject
.get()); 
1388                         if (tmpString 
!= nullptr) { 
1389                                 propObject 
= OSData::withBytes(tmpString
->getCStringNoCopy(), 
1390                                     tmpString
->getLength()); 
1394                 if (propObject 
!= nullptr) { 
1395                         propDataSize 
= (OSDynamicPtrCast
<OSData
>(propObject
))->getLength(); 
1398 #if defined(XNU_TARGET_OS_OSX) 
1399                 if ((propObject 
!= nullptr) && ((OSDynamicPtrCast
<OSData
>(propObject
))->getLength() == 0)) { 
1402 #endif /* defined(XNU_TARGET_OS_OSX) */ 
1408         if (propObject 
== nullptr) { 
1409                 DEBUG_INFO("No property object\n"); 
1410                 ret 
= kIOReturnBadArgument
; 
1414         if (!verifyWriteSizeLimit(guid
, name
, propDataSize
)) { 
1415                 DEBUG_ERROR("Property data size of %zu too long for %s\n", propDataSize
, name
); 
1416                 ret 
= kIOReturnNoSpace
; 
1421         ok 
= handleSpecialVariables(name
, guid
, propObject
.get(), &ret
); 
1425                 serializeVariables(); 
1430         oldObject
.reset(dict
->getObject(name
), OSRetain
); 
1433         if (remove 
== false) { 
1434                 DEBUG_INFO("Adding object\n"); 
1436                 if (!dict
->setObject(name
, propObject
.get())) { 
1437                         ret 
= kIOReturnBadArgument
; 
1441                 DEBUG_INFO("Removing object\n"); 
1442                 // Check for existence so we can decide whether we need to sync variables 
1444                         ret 
= removePropertyWithGUIDAndName(guid
, name
); 
1446                         ret 
= kIOReturnNotFound
; 
1450         if (ret 
== kIOReturnSuccess
) { 
1451                 ret 
= serializeVariables(); 
1452                 if (ret 
!= kIOReturnSuccess
) { 
1453                         DEBUG_ERROR("serializeVariables failed, ret=%#08x\n", ret
); 
1457                                 dict
->setObject(name
, oldObject
.get()); 
1459                                 dict
->removeObject(name
); 
1463                         (void) serializeVariables(); 
1464                         ret 
= kIOReturnNoMemory
; 
1476         DEBUG_INFO("ret=%#08x\n", ret
); 
1482 IODTNVRAM::setPropertyInternal(const OSSymbol 
*aKey
, OSObject 
*anObject
) 
1484         const char            *variableName
; 
1487         DEBUG_INFO("aKey=%s\n", aKey
->getCStringNoCopy()); 
1489         parseVariableName(aKey
->getCStringNoCopy(), &varGuid
, &variableName
); 
1491         return setPropertyWithGUIDAndName(&varGuid
, variableName
, anObject
); 
1495 IODTNVRAM::setProperty(const OSSymbol 
*aKey
, OSObject 
*anObject
) 
1497         return setPropertyInternal(aKey
, anObject
) == kIOReturnSuccess
; 
1501 IODTNVRAM::removeProperty(const OSSymbol 
*aKey
) 
1505         ret 
= removePropertyInternal(aKey
); 
1507         if (ret 
== kIOReturnSuccess
) { 
1508                 serializeVariables(); 
1510                 DEBUG_INFO("removePropertyInternal failed, ret=%#08x\n", ret
); 
1515 IODTNVRAM::removePropertyWithGUIDAndName(const uuid_t 
*guid
, const char *name
) 
1519         bool removed 
= false; 
1521         DEBUG_INFO("name=%s\n", name
); 
1523         ret 
= chooseDictionary(kIONVRAMOperationDelete
, guid
, name
, &dict
); 
1524         if (ret 
!= kIOReturnSuccess
) { 
1525                 DEBUG_INFO("No dictionary\n"); 
1529         if (!verifyPermission(kIONVRAMOperationDelete
, guid
, name
)) { 
1530                 DEBUG_INFO("Not priveleged\n"); 
1531                 ret 
= kIOReturnNotPrivileged
; 
1537         // If the object exists, remove it from the dictionary. 
1538         if (dict
->getObject(name
) != nullptr) { 
1539                 dict
->removeObject(name
); 
1542                 DEBUG_INFO("%s not found\n", name
); 
1548                 ret 
= serializeVariables(); 
1549                 DEBUG_INFO("serializeVariables ret=0x%08x\n", ret
); 
1557 IODTNVRAM::removePropertyInternal(const OSSymbol 
*aKey
) 
1560         const char   *variableName
; 
1563         DEBUG_INFO("aKey=%s\n", aKey
->getCStringNoCopy()); 
1565         parseVariableName(aKey
->getCStringNoCopy(), &varGuid
, &variableName
); 
1567         ret 
= removePropertyWithGUIDAndName(&varGuid
, variableName
); 
1573 IODTNVRAM::setProperties(OSObject 
*properties
) 
1575         IOReturn                          ret 
= kIOReturnSuccess
; 
1577         const OSSymbol                    
*key
; 
1579         OSSharedPtr
<OSCollectionIterator
> iter
; 
1581         dict 
= OSDynamicCast(OSDictionary
, properties
); 
1582         if (dict 
== nullptr) { 
1583                 DEBUG_ERROR("Not a dictionary\n"); 
1584                 return kIOReturnBadArgument
; 
1587         iter 
= OSCollectionIterator::withCollection(dict
); 
1588         if (iter 
== nullptr) { 
1589                 DEBUG_ERROR("Couldn't create iterator\n"); 
1590                 return kIOReturnBadArgument
; 
1593         while (ret 
== kIOReturnSuccess
) { 
1594                 key 
= OSDynamicCast(OSSymbol
, iter
->getNextObject()); 
1595                 if (key 
== nullptr) { 
1599                 object 
= dict
->getObject(key
); 
1600                 if (object 
== nullptr) { 
1604                 ret 
= setPropertyInternal(key
, object
); 
1607         DEBUG_INFO("ret=%#08x\n", ret
); 
1613 IODTNVRAM::readXPRAM(IOByteCount offset
, UInt8 
*buffer
, 
1616         return kIOReturnUnsupported
; 
1620 IODTNVRAM::writeXPRAM(IOByteCount offset
, UInt8 
*buffer
, 
1623         return kIOReturnUnsupported
; 
1627 IODTNVRAM::readNVRAMProperty(IORegistryEntry 
*entry
, 
1628     const OSSymbol 
**name
, 
1633         err 
= readNVRAMPropertyType1(entry
, name
, value
); 
1639 IODTNVRAM::writeNVRAMProperty(IORegistryEntry 
*entry
, 
1640     const OSSymbol 
*name
, 
1645         err 
= writeNVRAMPropertyType1(entry
, name
, value
); 
1651 IODTNVRAM::getNVRAMPartitions(void) 
1653         return _nvramPartitionLengths
.get(); 
1657 IODTNVRAM::readNVRAMPartition(const OSSymbol 
*partitionID
, 
1658     IOByteCount offset
, UInt8 
*buffer
, 
1661         OSNumber 
*partitionOffsetNumber
, *partitionLengthNumber
; 
1662         UInt32   partitionOffset
, partitionLength
, end
; 
1664         partitionOffsetNumber 
= 
1665             (OSNumber 
*)_nvramPartitionOffsets
->getObject(partitionID
); 
1666         partitionLengthNumber 
= 
1667             (OSNumber 
*)_nvramPartitionLengths
->getObject(partitionID
); 
1669         if ((partitionOffsetNumber 
== nullptr) || (partitionLengthNumber 
== nullptr)) { 
1670                 return kIOReturnNotFound
; 
1673         partitionOffset 
= partitionOffsetNumber
->unsigned32BitValue(); 
1674         partitionLength 
= partitionLengthNumber
->unsigned32BitValue(); 
1676         if (os_add_overflow(offset
, length
, &end
)) { 
1677                 return kIOReturnBadArgument
; 
1679         if ((buffer 
== nullptr) || (length 
== 0) || (end 
> partitionLength
)) { 
1680                 return kIOReturnBadArgument
; 
1683         bcopy(_nvramImage 
+ partitionOffset 
+ offset
, buffer
, length
); 
1685         return kIOReturnSuccess
; 
1689 IODTNVRAM::writeNVRAMPartition(const OSSymbol 
*partitionID
, 
1690     IOByteCount offset
, UInt8 
*buffer
, 
1693         OSNumber 
*partitionOffsetNumber
, *partitionLengthNumber
; 
1694         UInt32   partitionOffset
, partitionLength
, end
; 
1696         partitionOffsetNumber 
= 
1697             (OSNumber 
*)_nvramPartitionOffsets
->getObject(partitionID
); 
1698         partitionLengthNumber 
= 
1699             (OSNumber 
*)_nvramPartitionLengths
->getObject(partitionID
); 
1701         if ((partitionOffsetNumber 
== nullptr) || (partitionLengthNumber 
== nullptr)) { 
1702                 return kIOReturnNotFound
; 
1705         partitionOffset 
= partitionOffsetNumber
->unsigned32BitValue(); 
1706         partitionLength 
= partitionLengthNumber
->unsigned32BitValue(); 
1708         if (os_add_overflow(offset
, length
, &end
)) { 
1709                 return kIOReturnBadArgument
; 
1711         if ((buffer 
== nullptr) || (length 
== 0) || (end 
> partitionLength
)) { 
1712                 return kIOReturnBadArgument
; 
1715         bcopy(buffer
, _nvramImage 
+ partitionOffset 
+ offset
, length
); 
1717         if (_nvramController 
!= nullptr) { 
1718                 _nvramController
->write(0, _nvramImage
, _nvramSize
); 
1721         return kIOReturnSuccess
; 
1725 IODTNVRAM::savePanicInfo(UInt8 
*buffer
, IOByteCount length
) 
1733 IODTNVRAM::calculatePartitionChecksum(UInt8 
*partitionHeader
) 
1735         UInt8 cnt
, isum
, csum 
= 0; 
1737         for (cnt 
= 0; cnt 
< 0x10; cnt
++) { 
1738                 isum 
= csum 
+ partitionHeader
[cnt
]; 
1749 IODTNVRAM::initVariables(void) 
1752         UInt8                       
*propName
, *propData
; 
1753         UInt32                      propNameLength
, propDataLength
, regionIndex
; 
1754         OSSharedPtr
<const OSSymbol
> propSymbol
; 
1755         OSSharedPtr
<OSObject
>       propObject
; 
1756         NVRAMRegionInfo             
*currentRegion
; 
1757         NVRAMRegionInfo             variableRegions
[] = { { kIONVRAMPartitionCommon
, _commonPartitionOffset
, _commonPartitionSize
, _commonDict
, _commonImage
}, 
1758                                                           { kIONVRAMPartitionSystem
, _systemPartitionOffset
, _systemPartitionSize
, _systemDict
, _systemImage
} }; 
1760         DEBUG_INFO("...\n"); 
1762         for (regionIndex 
= 0; regionIndex 
< ARRAY_SIZE(variableRegions
); regionIndex
++) { 
1763                 currentRegion 
= &variableRegions
[regionIndex
]; 
1765                 if (currentRegion
->size 
== 0) { 
1769                 currentRegion
->dict 
= OSDictionary::withCapacity(1); 
1771                 DEBUG_INFO("region = %d\n", currentRegion
->type
); 
1773                 while (cnt 
< currentRegion
->size
) { 
1774                         // Break if there is no name. 
1775                         if (currentRegion
->image
[cnt
] == '\0') { 
1779                         // Find the length of the name. 
1780                         propName 
= currentRegion
->image 
+ cnt
; 
1781                         for (propNameLength 
= 0; (cnt 
+ propNameLength
) < currentRegion
->size
; 
1783                                 if (currentRegion
->image
[cnt 
+ propNameLength
] == '=') { 
1788                         // Break if the name goes past the end of the partition. 
1789                         if ((cnt 
+ propNameLength
) >= currentRegion
->size
) { 
1792                         cnt 
+= propNameLength 
+ 1; 
1794                         propData 
= currentRegion
->image 
+ cnt
; 
1795                         for (propDataLength 
= 0; (cnt 
+ propDataLength
) < currentRegion
->size
; 
1797                                 if (currentRegion
->image
[cnt 
+ propDataLength
] == '\0') { 
1802                         // Break if the data goes past the end of the partition. 
1803                         if ((cnt 
+ propDataLength
) >= currentRegion
->size
) { 
1806                         cnt 
+= propDataLength 
+ 1; 
1808                         if (convertPropToObject(propName
, propNameLength
, 
1809                             propData
, propDataLength
, 
1810                             propSymbol
, propObject
)) { 
1811                                 DEBUG_INFO("adding %s, dataLength=%u\n", propSymbol
.get()->getCStringNoCopy(), (unsigned int)propDataLength
); 
1812                                 currentRegion
->dict
.get()->setObject(propSymbol
.get(), propObject
.get()); 
1817         // Create the boot-args property if it is not in the dictionary. 
1818         if (_systemDict 
!= nullptr) { 
1819                 if (_systemDict
->getObject(kIONVRAMBootArgsKey
) == nullptr) { 
1820                         propObject 
= OSString::withCStringNoCopy(""); 
1821                         if (propObject 
!= nullptr) { 
1822                                 _systemDict
->setObject(kIONVRAMBootArgsKey
, propObject
.get()); 
1825         } else if (_commonDict 
!= nullptr) { 
1826                 if (_commonDict
->getObject(kIONVRAMBootArgsKey
) == nullptr) { 
1827                         propObject 
= OSString::withCStringNoCopy(""); 
1828                         if (propObject 
!= nullptr) { 
1829                                 _commonDict
->setObject(kIONVRAMBootArgsKey
, propObject
.get()); 
1834         DEBUG_INFO("%s _commonDict=%p _systemDict=%p\n", __FUNCTION__
, _commonDict 
? _commonDict
.get() : nullptr, _systemDict 
? _systemDict
.get() : nullptr); 
1836         return kIOReturnSuccess
; 
1840 IODTNVRAM::syncOFVariables(void) 
1842         return kIOReturnUnsupported
; 
1846 IODTNVRAM::serializeVariables(void) 
1850         UInt32                            length
, maxLength
, regionIndex
; 
1851         UInt8                             
*buffer
, *tmpBuffer
; 
1852         const OSSymbol                    
*tmpSymbol
; 
1853         OSObject                          
*tmpObject
; 
1854         OSSharedPtr
<OSCollectionIterator
> iter
; 
1855         OSSharedPtr
<OSNumber
>             sizeUsed
; 
1856         UInt32                            systemUsed 
= 0; 
1857         UInt32                            commonUsed 
= 0; 
1858         OSSharedPtr
<OSData
>               nvramImage
; 
1859         NVRAMRegionInfo                   
*currentRegion
; 
1860         NVRAMRegionInfo                   variableRegions
[] = { { kIONVRAMPartitionCommon
, _commonPartitionOffset
, _commonPartitionSize
, _commonDict
, _commonImage
}, 
1861                                                                 { kIONVRAMPartitionSystem
, _systemPartitionOffset
, _systemPartitionSize
, _systemDict
, _systemImage
} }; 
1863         if (_systemPanicked
) { 
1864                 return kIOReturnNotReady
; 
1867         if (_nvramController 
== nullptr) { 
1868                 DEBUG_ERROR("No _nvramController\n"); 
1869                 return kIOReturnNotReady
; 
1872         DEBUG_INFO("...\n"); 
1876         for (regionIndex 
= 0; regionIndex 
< ARRAY_SIZE(variableRegions
); regionIndex
++) { 
1877                 currentRegion 
= &variableRegions
[regionIndex
]; 
1879                 if (currentRegion
->size 
== 0) { 
1883                 DEBUG_INFO("region = %d\n", currentRegion
->type
); 
1884                 buffer 
= tmpBuffer 
= IONew(UInt8
, currentRegion
->size
); 
1885                 if (buffer 
== nullptr) { 
1887                         ret 
= kIOReturnNoMemory
; 
1890                 bzero(buffer
, currentRegion
->size
); 
1893                 maxLength 
= currentRegion
->size
; 
1895                 iter 
= OSCollectionIterator::withCollection(currentRegion
->dict
.get()); 
1896                 if (iter 
== nullptr) { 
1901                         tmpSymbol 
= OSDynamicCast(OSSymbol
, iter
->getNextObject()); 
1902                         if (tmpSymbol 
== nullptr) { 
1906                         DEBUG_INFO("adding variable %s\n", tmpSymbol
->getCStringNoCopy()); 
1908                         tmpObject 
= currentRegion
->dict
->getObject(tmpSymbol
); 
1911                         ok 
= convertObjectToProp(tmpBuffer
, &length
, tmpSymbol
, tmpObject
); 
1913                                 tmpBuffer 
+= length
; 
1914                                 maxLength 
-= length
; 
1919                         bcopy(buffer
, currentRegion
->image
, currentRegion
->size
); 
1922                 IODelete(buffer
, UInt8
, currentRegion
->size
); 
1924                 if ((currentRegion
->type 
== kIONVRAMPartitionSystem
) && 
1925                     (_systemService 
!= nullptr)) { 
1926                         _systemService
->setVariables(_systemDict
.get()); 
1927                         systemUsed 
= (uint32_t)(tmpBuffer 
- buffer
); 
1928                 } else if ((currentRegion
->type 
== kIONVRAMPartitionCommon
) && 
1929                     (_commonService 
!= nullptr)) { 
1930                         _commonService
->setVariables(_commonDict
.get()); 
1931                         commonUsed 
= (uint32_t)(tmpBuffer 
- buffer
); 
1935                         ret 
= kIOReturnBadArgument
; 
1942         DEBUG_INFO("ok=%d\n", ok
); 
1945                 nvramImage 
= OSData::withBytes(_nvramImage
, _nvramSize
); 
1948                 if (_systemService
) { 
1949                         sizeUsed 
= OSNumber::withNumber(systemUsed
, 32); 
1950                         _nvramController
->setProperty("SystemUsed", sizeUsed
.get()); 
1951                         DEBUG_INFO("SystemUsed=%u\n", (unsigned int)commonUsed
); 
1955                 if (_commonService
) { 
1956                         sizeUsed 
= OSNumber::withNumber(commonUsed
, 32); 
1957                         _nvramController
->setProperty("CommonUsed", sizeUsed
.get()); 
1958                         DEBUG_INFO("CommonUsed=%u\n", (unsigned int)commonUsed
); 
1962                 ret 
= _nvramController
->write(0, (uint8_t *)nvramImage
->getBytesNoCopy(), nvramImage
->getLength()); 
1971 IODTNVRAM::getOFVariableType(const char *propName
) const 
1977 IODTNVRAM::getOFVariableType(const OSSymbol 
*propSymbol
) const 
1984 IODTNVRAM::getOFVariablePerm(const char *propName
) const 
1990 IODTNVRAM::getOFVariablePerm(const OSSymbol 
*propSymbol
) const 
1996 IODTNVRAM::getOWVariableInfo(UInt32 variableNumber
, const OSSymbol 
**propSymbol
, 
1997     UInt32 
*propType
, UInt32 
*propOffset
) 
2003 IODTNVRAM::convertPropToObject(UInt8 
*propName
, UInt32 propNameLength
, 
2004     UInt8 
*propData
, UInt32 propDataLength
, 
2005     const OSSymbol 
**propSymbol
, 
2006     OSObject 
**propObject
) 
2008         OSSharedPtr
<const OSSymbol
> tmpSymbol
; 
2009         OSSharedPtr
<OSNumber
>       tmpNumber
; 
2010         OSSharedPtr
<OSString
>       tmpString
; 
2011         OSSharedPtr
<OSObject
>       tmpObject 
= nullptr; 
2013         propName
[propNameLength
] = '\0'; 
2014         tmpSymbol 
= OSSymbol::withCString((const char *)propName
); 
2015         propName
[propNameLength
] = '='; 
2016         if (tmpSymbol 
== nullptr) { 
2020         switch (getVariableType(tmpSymbol
.get())) { 
2021         case kOFVariableTypeBoolean
: 
2022                 if (!strncmp("true", (const char *)propData
, propDataLength
)) { 
2023                         tmpObject
.reset(kOSBooleanTrue
, OSRetain
); 
2024                 } else if (!strncmp("false", (const char *)propData
, propDataLength
)) { 
2025                         tmpObject
.reset(kOSBooleanFalse
, OSRetain
); 
2029         case kOFVariableTypeNumber
: 
2030                 tmpNumber 
= OSNumber::withNumber(strtol((const char *)propData
, nullptr, 0), 32); 
2031                 if (tmpNumber 
!= nullptr) { 
2032                         tmpObject 
= tmpNumber
; 
2036         case kOFVariableTypeString
: 
2037                 tmpString 
= OSString::withCString((const char *)propData
); 
2038                 if (tmpString 
!= nullptr) { 
2039                         tmpObject 
= tmpString
; 
2043         case kOFVariableTypeData
: 
2044                 tmpObject 
= unescapeBytesToData(propData
, propDataLength
); 
2051         if (tmpObject 
== nullptr) { 
2056         *propSymbol 
= tmpSymbol
.detach(); 
2057         *propObject 
= tmpObject
.detach(); 
2063 IODTNVRAM::convertPropToObject(UInt8 
*propName
, UInt32 propNameLength
, 
2064     UInt8 
*propData
, UInt32 propDataLength
, 
2065     OSSharedPtr
<const OSSymbol
>& propSymbol
, 
2066     OSSharedPtr
<OSObject
>& propObject
) 
2068         const OSSymbol
* propSymbolRaw 
= nullptr; 
2069         OSObject
* propObjectRaw 
= nullptr; 
2070         bool ok 
= convertPropToObject(propName
, propNameLength
, propData
, propDataLength
, 
2071             &propSymbolRaw
, &propObjectRaw
); 
2072         propSymbol
.reset(propSymbolRaw
, OSNoRetain
); 
2073         propObject
.reset(propObjectRaw
, OSNoRetain
); 
2078 IODTNVRAM::convertObjectToProp(UInt8 
*buffer
, UInt32 
*length
, 
2079     const OSSymbol 
*propSymbol
, OSObject 
*propObject
) 
2081         const UInt8          
*propName
; 
2082         UInt32               propNameLength
, propDataLength
, remaining
; 
2083         IONVRAMVariableType  propType
; 
2084         OSBoolean            
*tmpBoolean 
= nullptr; 
2085         OSNumber             
*tmpNumber 
= nullptr; 
2086         OSString             
*tmpString 
= nullptr; 
2087         OSSharedPtr
<OSData
>  tmpData
; 
2089         propName 
= (const UInt8 
*)propSymbol
->getCStringNoCopy(); 
2090         propNameLength 
= propSymbol
->getLength(); 
2091         propType 
= getVariableType(propSymbol
); 
2093         // Get the size of the data. 
2094         propDataLength 
= 0xFFFFFFFF; 
2096         case kOFVariableTypeBoolean
: 
2097                 tmpBoolean 
= OSDynamicCast(OSBoolean
, propObject
); 
2098                 if (tmpBoolean 
!= nullptr) { 
2103         case kOFVariableTypeNumber
: 
2104                 tmpNumber 
= OSDynamicCast(OSNumber
, propObject
); 
2105                 if (tmpNumber 
!= nullptr) { 
2106                         propDataLength 
= 10; 
2110         case kOFVariableTypeString
: 
2111                 tmpString 
= OSDynamicCast(OSString
, propObject
); 
2112                 if (tmpString 
!= nullptr) { 
2113                         propDataLength 
= tmpString
->getLength(); 
2117         case kOFVariableTypeData
: 
2118                 tmpData
.reset(OSDynamicCast(OSData
, propObject
), OSNoRetain
); 
2119                 if (tmpData 
!= nullptr) { 
2120                         tmpData 
= escapeDataToData(tmpData
.detach()); 
2121                         propDataLength 
= tmpData
->getLength(); 
2129         // Make sure the propertySize is known and will fit. 
2130         if (propDataLength 
== 0xFFFFFFFF) { 
2133         if ((propNameLength 
+ propDataLength 
+ 2) > *length
) { 
2137         // Copy the property name equal sign. 
2138         buffer 
+= snprintf((char *)buffer
, *length
, "%s=", propName
); 
2139         remaining 
= *length 
- propNameLength 
- 1; 
2142         case kOFVariableTypeBoolean
: 
2143                 if (tmpBoolean
->getValue()) { 
2144                         strlcpy((char *)buffer
, "true", remaining
); 
2146                         strlcpy((char *)buffer
, "false", remaining
); 
2150         case kOFVariableTypeNumber
: 
2152                 uint32_t tmpValue 
= tmpNumber
->unsigned32BitValue(); 
2153                 if (tmpValue 
== 0xFFFFFFFF) { 
2154                         strlcpy((char *)buffer
, "-1", remaining
); 
2155                 } else if (tmpValue 
< 1000) { 
2156                         snprintf((char *)buffer
, remaining
, "%d", (uint32_t)tmpValue
); 
2158                         snprintf((char *)buffer
, remaining
, "%#x", (uint32_t)tmpValue
); 
2163         case kOFVariableTypeString
: 
2164                 strlcpy((char *)buffer
, tmpString
->getCStringNoCopy(), remaining
); 
2167         case kOFVariableTypeData
: 
2168                 bcopy(tmpData
->getBytesNoCopy(), buffer
, propDataLength
); 
2176         propDataLength 
= ((UInt32
) strlen((const char *)buffer
)); 
2178         *length 
= propNameLength 
+ propDataLength 
+ 2; 
2185 IODTNVRAM::generateOWChecksum(UInt8 
*buffer
) 
2187         UInt32 cnt
, checksum 
= 0; 
2188         UInt16 
*tmpBuffer 
= (UInt16 
*)buffer
; 
2190         for (cnt 
= 0; cnt 
< _commonPartitionSize 
/ 2; cnt
++) { 
2191                 checksum 
+= tmpBuffer
[cnt
]; 
2194         return checksum 
% 0x0000FFFF; 
2198 IODTNVRAM::validateOWChecksum(UInt8 
*buffer
) 
2200         UInt32 cnt
, checksum
, sum 
= 0; 
2201         UInt16 
*tmpBuffer 
= (UInt16 
*)buffer
; 
2203         for (cnt 
= 0; cnt 
< _commonPartitionSize 
/ 2; cnt
++) { 
2204                 sum 
+= tmpBuffer
[cnt
]; 
2207         checksum 
= (sum 
>> 16) + (sum 
& 0x0000FFFF); 
2208         if (checksum 
== 0x10000) { 
2211         checksum 
= (checksum 
^ 0x0000FFFF) & 0x0000FFFF; 
2213         return checksum 
== 0; 
2217 IODTNVRAM::updateOWBootArgs(const OSSymbol 
*key
, OSObject 
*value
) 
2223 IODTNVRAM::searchNVRAMProperty(IONVRAMDescriptor 
*hdr
, UInt32 
*where
) 
2229 IODTNVRAM::readNVRAMPropertyType0(IORegistryEntry 
*entry
, 
2230     const OSSymbol 
**name
, 
2233         return kIOReturnUnsupported
; 
2238 IODTNVRAM::writeNVRAMPropertyType0(IORegistryEntry 
*entry
, 
2239     const OSSymbol 
*name
, 
2242         return kIOReturnUnsupported
; 
2247 IODTNVRAM::unescapeBytesToData(const UInt8 
*bytes
, UInt32 length
) 
2249         OSSharedPtr
<OSData
> data
; 
2250         UInt32              totalLength 
= 0; 
2255         // Calculate the actual length of the data. 
2258         for (cnt 
= 0; cnt 
< length
;) { 
2259                 byte 
= bytes
[cnt
++]; 
2261                         byte 
= bytes
[cnt
++]; 
2270                 totalLength 
+= cnt2
; 
2274                 // Create an empty OSData of the correct size. 
2275                 data 
= OSData::withCapacity(totalLength
); 
2276                 if (data 
!= nullptr) { 
2277                         for (cnt 
= 0; cnt 
< length
;) { 
2278                                 byte 
= bytes
[cnt
++]; 
2280                                         byte 
= bytes
[cnt
++]; 
2282                                         byte 
= (byte 
& 0x80) ? 0xFF : 0x00; 
2286                                 data
->appendByte(byte
, cnt2
); 
2295 IODTNVRAM::escapeDataToData(OSData 
* value
) 
2297         OSSharedPtr
<OSData
> result
; 
2298         const UInt8         
*startPtr
; 
2299         const UInt8         
*endPtr
; 
2300         const UInt8         
*wherePtr
; 
2304         wherePtr 
= (const UInt8 
*) value
->getBytesNoCopy(); 
2305         endPtr 
= wherePtr 
+ value
->getLength(); 
2307         result 
= OSData::withCapacity((unsigned int) (endPtr 
- wherePtr
)); 
2312         while (wherePtr 
< endPtr
) { 
2313                 startPtr 
= wherePtr
; 
2315                 if ((byte 
== 0x00) || (byte 
== 0xFF)) { 
2317                             ((wherePtr 
- startPtr
) < 0x80) && (wherePtr 
< endPtr
) && (byte 
== *wherePtr
); 
2320                         ok 
&= result
->appendByte(0xff, 1); 
2321                         byte 
= (byte 
& 0x80) | ((UInt8
)(wherePtr 
- startPtr
)); 
2323                 ok 
&= result
->appendByte(byte
, 1); 
2325         ok 
&= result
->appendByte(0, 1); 
2335 IsApplePropertyName(const char * propName
) 
2338         while ((c 
= *propName
++)) { 
2339                 if ((c 
>= 'A') && (c 
<= 'Z')) { 
2348 IODTNVRAM::readNVRAMPropertyType1(IORegistryEntry 
*entry
, 
2349     const OSSymbol 
**name
, 
2352         IOReturn    err 
= kIOReturnNoResources
; 
2354         const UInt8 
*startPtr
; 
2355         const UInt8 
*endPtr
; 
2356         const UInt8 
*wherePtr
; 
2357         const UInt8 
*nvPath 
= nullptr; 
2358         const char  *nvName 
= nullptr; 
2359         const char  *resultName 
= nullptr; 
2360         const UInt8 
*resultValue 
= nullptr; 
2361         UInt32       resultValueLen 
= 0; 
2365         data 
= OSDynamicCast(OSData
, _commonDict
->getObject(_registryPropertiesKey
.get())); 
2368         if (data 
== nullptr) { 
2372         startPtr 
= (const UInt8 
*) data
->getBytesNoCopy(); 
2373         endPtr 
= startPtr 
+ data
->getLength(); 
2375         wherePtr 
= startPtr
; 
2376         while (wherePtr 
< endPtr
) { 
2377                 byte 
= *(wherePtr
++); 
2382                 if (nvPath 
== nullptr) { 
2384                 } else if (nvName 
== nullptr) { 
2385                         nvName 
= (const char *) startPtr
; 
2387                         OSSharedPtr
<IORegistryEntry
> compareEntry 
= IORegistryEntry::fromPath((const char *) nvPath
, gIODTPlane
); 
2388                         if (entry 
== compareEntry
) { 
2389                                 bool appleProp 
= IsApplePropertyName(nvName
); 
2390                                 if (!appleProp 
|| !resultName
) { 
2391                                         resultName     
= nvName
; 
2392                                         resultValue    
= startPtr
; 
2393                                         resultValueLen 
= (UInt32
) (wherePtr 
- startPtr 
- 1);  // OSData getLength() is 32b 
2402                 startPtr 
= wherePtr
; 
2405                 *name 
= OSSymbol::withCString(resultName
).detach(); 
2406                 *value 
= unescapeBytesToData(resultValue
, resultValueLen
).detach(); 
2407                 if ((*name 
!= nullptr) && (*value 
!= nullptr)) { 
2408                         err 
= kIOReturnSuccess
; 
2410                         err 
= kIOReturnNoMemory
; 
2417 IODTNVRAM::writeNVRAMPropertyType1(IORegistryEntry 
*entry
, 
2418     const OSSymbol 
*propName
, 
2421         OSSharedPtr
<OSData
> data
, oldData
; 
2422         const UInt8         
*startPtr
; 
2423         const UInt8         
*propStart
; 
2424         const UInt8         
*endPtr
; 
2425         const UInt8         
*wherePtr
; 
2426         const UInt8         
*nvPath 
= nullptr; 
2427         const char          *nvName 
= nullptr; 
2432         bool                settingAppleProp
; 
2434         settingAppleProp 
= IsApplePropertyName(propName
->getCStringNoCopy()); 
2436         // copy over existing properties for other entries 
2440         oldData
.reset(OSDynamicCast(OSData
, _commonDict
->getObject(_registryPropertiesKey
.get())), OSRetain
); 
2442                 startPtr 
= (const UInt8 
*) oldData
->getBytesNoCopy(); 
2443                 endPtr 
= startPtr 
+ oldData
->getLength(); 
2445                 propStart 
= startPtr
; 
2446                 wherePtr 
= startPtr
; 
2447                 while (wherePtr 
< endPtr
) { 
2448                         byte 
= *(wherePtr
++); 
2452                         if (nvPath 
== nullptr) { 
2454                         } else if (nvName 
== nullptr) { 
2455                                 nvName 
= (const char *) startPtr
; 
2457                                 OSSharedPtr
<IORegistryEntry
> compareEntry 
= IORegistryEntry::fromPath((const char *) nvPath
, gIODTPlane
); 
2459                                 if (entry 
== compareEntry
) { 
2460                                         if ((settingAppleProp 
&& propName
->isEqualTo(nvName
)) 
2461                                             || (!settingAppleProp 
&& !IsApplePropertyName(nvName
))) { 
2462                                                 // delete old property (nvPath -> wherePtr) source OSData len is 32b 
2463                                                 data 
= OSData::withBytes(propStart
, (UInt32
)(nvPath 
- propStart
)); 
2465                                                         ok 
&= data
->appendBytes(wherePtr
, (UInt32
)(endPtr 
- wherePtr
)); 
2474                         startPtr 
= wherePtr
; 
2478         // make the new property 
2482                         data 
= OSData::withData(oldData
.get()); 
2484                         data 
= OSData::withCapacity(16); 
2491         if (ok 
&& value 
&& value
->getLength()) { 
2493                         // get entries in path 
2494                         OSSharedPtr
<OSArray
> array 
= OSArray::withCapacity(5); 
2500                                 array
->setObject(entry
); 
2501                         } while ((entry 
= entry
->getParentEntry(gIODTPlane
))); 
2504                         for (int i 
= array
->getCount() - 3; 
2505                             (entry 
= (IORegistryEntry 
*) array
->getObject(i
)); 
2507                                 name 
= entry
->getName(gIODTPlane
); 
2508                                 comp 
= entry
->getLocation(gIODTPlane
); 
2510                                         ok 
&= data
->appendBytes("/@", 2); 
2515                                         ok 
&= data
->appendByte('/', 1); 
2518                                 ok 
&= data
->appendBytes(comp
, (unsigned int) strnlen(comp
, UINT16_MAX
)); 
2520                         ok 
&= data
->appendByte(0, 1); 
2522                         ok 
&= data
->appendBytes(propName
->getCStringNoCopy(), propName
->getLength() + 1); 
2524                         // append escaped data 
2525                         OSSharedPtr
<OSData
> escapedData 
= escapeDataToData(value
); 
2526                         ok 
&= (escapedData 
!= nullptr); 
2528                                 ok 
&= data
->appendBytes(escapedData
.get()); 
2534                 ok 
= _commonDict
->setObject(_registryPropertiesKey
.get(), data
.get()); 
2540                 if (serializeVariables() != kIOReturnSuccess
) { 
2543                                 _commonDict
->setObject(_registryPropertiesKey
.get(), oldData
.get()); 
2545                                 _commonDict
->removeObject(_registryPropertiesKey
.get()); 
2549                         (void) serializeVariables(); 
2556         return ok 
? kIOReturnSuccess 
: kIOReturnNoMemory
; 
2560 IODTNVRAM::safeToSync(void) 
2566         // delta interval went by 
2567         clock_get_uptime(&delta
); 
2569         // Figure it in seconds. 
2570         absolutetime_to_nanoseconds(delta
, &delta_ns
); 
2571         delta_secs 
= (SInt32
)(delta_ns 
/ NSEC_PER_SEC
); 
2573         if ((delta_secs 
> (_lastDeviceSync 
+ MIN_SYNC_NOW_INTERVAL
)) || _freshInterval
) { 
2574                 _lastDeviceSync 
= delta_secs
; 
2575                 _freshInterval 
= FALSE
;