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
;