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 #include <IOKit/IOLib.h>
31 #include <IOKit/IONVRAM.h>
32 #include <IOKit/IOPlatformExpert.h>
33 #include <IOKit/IOUserClient.h>
34 #include <IOKit/IOKitKeys.h>
35 #include <IOKit/IOKitKeysPrivate.h>
36 #include <kern/debug.h>
37 #include <pexpert/boot.h>
38 #include <pexpert/pexpert.h>
41 #define super IOService
43 #define kIONVRAMPrivilege kIOClientPrivilegeAdministrator
44 //#define kIONVRAMPrivilege kIOClientPrivilegeLocalUser
46 OSDefineMetaClassAndStructors(IODTNVRAM
, IOService
);
49 IODTNVRAM::init(IORegistryEntry
*old
, const IORegistryPlane
*plane
)
53 if (!super::init(old
, plane
)) {
57 dict
= OSDictionary::withCapacity(1);
61 setPropertyTable(dict
);
64 _nvramImage
= IONew(UInt8
, kIODTNVRAMImageSize
);
65 if (_nvramImage
== NULL
) {
69 _nvramPartitionOffsets
= OSDictionary::withCapacity(1);
70 if (_nvramPartitionOffsets
== NULL
) {
74 _nvramPartitionLengths
= OSDictionary::withCapacity(1);
75 if (_nvramPartitionLengths
== NULL
) {
79 _registryPropertiesKey
= OSSymbol::withCStringNoCopy("aapl,pci");
80 if (_registryPropertiesKey
== NULL
) {
84 // <rdar://problem/9529235> race condition possible between
85 // IODTNVRAM and IONVRAMController (restore loses boot-args)
92 IODTNVRAM::initProxyData(void)
94 IORegistryEntry
*entry
;
95 const char *key
= "nvram-proxy-data";
100 entry
= IORegistryEntry::fromPath("/chosen", gIODTPlane
);
102 prop
= entry
->getProperty(key
);
104 data
= OSDynamicCast(OSData
, prop
);
106 bytes
= data
->getBytesNoCopy();
107 if ((bytes
!= NULL
) && (data
->getLength() <= kIODTNVRAMImageSize
)) {
108 bcopy(bytes
, _nvramImage
, data
->getLength());
114 entry
->removeProperty(key
);
120 IODTNVRAM::registerNVRAMController(IONVRAMController
*nvram
)
122 if (_nvramController
!= NULL
) {
126 _nvramController
= nvram
;
128 // <rdar://problem/9529235> race condition possible between
129 // IODTNVRAM and IONVRAMController (restore loses boot-args)
131 _nvramController
->read(0, _nvramImage
, kIODTNVRAMImageSize
);
133 } else if (_ofLock
) {
135 (void) syncVariables();
136 IOLockUnlock(_ofLock
);
141 IODTNVRAM::initNVRAMImage(void)
143 char partitionID
[18];
144 UInt32 partitionOffset
, partitionLength
;
145 UInt32 freePartitionOffset
, freePartitionSize
;
146 UInt32 currentLength
, currentOffset
= 0;
147 OSNumber
*partitionOffsetNumber
, *partitionLengthNumber
;
149 // Find the offsets for the OF, XPRAM, NameRegistry and PanicInfo partitions.
150 _ofPartitionOffset
= 0xFFFFFFFF;
151 _piPartitionOffset
= 0xFFFFFFFF;
152 freePartitionOffset
= 0xFFFFFFFF;
153 freePartitionSize
= 0;
155 // Look through the partitions to find the OF, MacOS partitions.
156 while (currentOffset
< kIODTNVRAMImageSize
) {
157 currentLength
= ((UInt16
*)(_nvramImage
+ currentOffset
))[1] * 16;
159 if (currentLength
< 16) {
162 partitionOffset
= currentOffset
+ 16;
163 partitionLength
= currentLength
- 16;
164 if ((partitionOffset
+ partitionLength
) > kIODTNVRAMImageSize
) {
168 if (strncmp((const char *)_nvramImage
+ currentOffset
+ 4,
169 kIODTNVRAMOFPartitionName
, 12) == 0) {
170 _ofPartitionOffset
= partitionOffset
;
171 _ofPartitionSize
= partitionLength
;
172 } else if (strncmp((const char *)_nvramImage
+ currentOffset
+ 4,
173 kIODTNVRAMXPRAMPartitionName
, 12) == 0) {
174 } else if (strncmp((const char *)_nvramImage
+ currentOffset
+ 4,
175 kIODTNVRAMPanicInfoPartitonName
, 12) == 0) {
176 _piPartitionOffset
= partitionOffset
;
177 _piPartitionSize
= partitionLength
;
178 } else if (strncmp((const char *)_nvramImage
+ currentOffset
+ 4,
179 kIODTNVRAMFreePartitionName
, 12) == 0) {
180 freePartitionOffset
= currentOffset
;
181 freePartitionSize
= currentLength
;
183 // Construct the partition ID from the signature and name.
184 snprintf(partitionID
, sizeof(partitionID
), "0x%02x,",
185 *(UInt8
*)(_nvramImage
+ currentOffset
));
186 strncpy(partitionID
+ 5,
187 (const char *)(_nvramImage
+ currentOffset
+ 4), 12);
188 partitionID
[17] = '\0';
190 partitionOffsetNumber
= OSNumber::withNumber(partitionOffset
, 32);
191 partitionLengthNumber
= OSNumber::withNumber(partitionLength
, 32);
193 // Save the partition offset and length
194 _nvramPartitionOffsets
->setObject(partitionID
, partitionOffsetNumber
);
195 _nvramPartitionLengths
->setObject(partitionID
, partitionLengthNumber
);
197 partitionOffsetNumber
->release();
198 partitionLengthNumber
->release();
200 currentOffset
+= currentLength
;
203 if (_ofPartitionOffset
!= 0xFFFFFFFF) {
204 _ofImage
= _nvramImage
+ _ofPartitionOffset
;
207 if (_piPartitionOffset
== 0xFFFFFFFF) {
208 if (freePartitionSize
> 0x20) {
209 // Set the signature to 0xa1.
210 _nvramImage
[freePartitionOffset
] = 0xa1;
211 // Set the checksum to 0.
212 _nvramImage
[freePartitionOffset
+ 1] = 0;
213 // Set the name for the Panic Info partition.
214 strncpy((char *)(_nvramImage
+ freePartitionOffset
+ 4),
215 kIODTNVRAMPanicInfoPartitonName
, 12);
217 // Calculate the partition offset and size.
218 _piPartitionOffset
= freePartitionOffset
+ 0x10;
219 _piPartitionSize
= 0x800;
220 if (_piPartitionSize
+ 0x20 > freePartitionSize
) {
221 _piPartitionSize
= freePartitionSize
- 0x20;
224 _piImage
= _nvramImage
+ _piPartitionOffset
;
226 // Zero the new partition.
227 bzero(_piImage
, _piPartitionSize
);
229 // Set the partition size.
230 *(UInt16
*)(_nvramImage
+ freePartitionOffset
+ 2) =
231 (_piPartitionSize
/ 0x10) + 1;
233 // Set the partition checksum.
234 _nvramImage
[freePartitionOffset
+ 1] =
235 calculatePartitionChecksum(_nvramImage
+ freePartitionOffset
);
237 // Calculate the free partition offset and size.
238 freePartitionOffset
+= _piPartitionSize
+ 0x10;
239 freePartitionSize
-= _piPartitionSize
+ 0x10;
241 // Set the signature to 0x7f.
242 _nvramImage
[freePartitionOffset
] = 0x7f;
243 // Set the checksum to 0.
244 _nvramImage
[freePartitionOffset
+ 1] = 0;
245 // Set the name for the free partition.
246 strncpy((char *)(_nvramImage
+ freePartitionOffset
+ 4),
247 kIODTNVRAMFreePartitionName
, 12);
248 // Set the partition size.
249 *(UInt16
*)(_nvramImage
+ freePartitionOffset
+ 2) =
250 freePartitionSize
/ 0x10;
251 // Set the partition checksum.
252 _nvramImage
[freePartitionOffset
+ 1] =
253 calculatePartitionChecksum(_nvramImage
+ freePartitionOffset
);
255 if (_nvramController
!= NULL
) {
256 _nvramController
->write(0, _nvramImage
, kIODTNVRAMImageSize
);
260 _piImage
= _nvramImage
+ _piPartitionOffset
;
264 _freshInterval
= TRUE
; // we will allow sync() even before the first 15 minutes have passed.
270 IODTNVRAM::syncInternal(bool rateLimit
)
272 // Don't try to perform controller operations if none has been registered.
273 if (_nvramController
== NULL
) {
277 // Rate limit requests to sync. Drivers that need this rate limiting will
278 // shadow the data and only write to flash when they get a sync call
279 if (rateLimit
&& !safeToSync()) {
283 _nvramController
->sync();
287 IODTNVRAM::sync(void)
293 IODTNVRAM::serializeProperties(OSSerialize
*s
) const
295 bool result
, hasPrivilege
;
299 OSCollectionIterator
*iter
= NULL
;
301 // Verify permissions.
302 hasPrivilege
= (kIOReturnSuccess
== IOUserClient::clientHasPrivilege(current_task(), kIONVRAMPrivilege
));
304 if (_ofDict
== NULL
) {
305 /* No nvram. Return an empty dictionary. */
306 dict
= OSDictionary::withCapacity(1);
312 dict
= OSDictionary::withDictionary(_ofDict
);
313 IOLockUnlock(_ofLock
);
318 /* Copy properties with client privilege. */
319 iter
= OSCollectionIterator::withCollection(dict
);
325 key
= OSDynamicCast(OSSymbol
, iter
->getNextObject());
330 variablePerm
= getOFVariablePerm(key
);
331 if ((hasPrivilege
|| (variablePerm
!= kOFVariablePermRootOnly
)) &&
332 (!(variablePerm
== kOFVariablePermKernelOnly
&& current_task() != kernel_task
))) {
334 dict
->removeObject(key
);
340 result
= dict
->serialize(s
);
351 IODTNVRAM::copyProperty(const OSSymbol
*aKey
) const
357 if (_ofDict
== NULL
) {
361 // Verify permissions.
362 variablePerm
= getOFVariablePerm(aKey
);
363 result
= IOUserClient::clientHasPrivilege(current_task(), kIONVRAMPrivilege
);
364 if (result
!= kIOReturnSuccess
) {
365 if (variablePerm
== kOFVariablePermRootOnly
) {
369 if (variablePerm
== kOFVariablePermKernelOnly
&& current_task() != kernel_task
) {
374 theObject
= _ofDict
->getObject(aKey
);
378 IOLockUnlock(_ofLock
);
384 IODTNVRAM::copyProperty(const char *aKey
) const
386 const OSSymbol
*keySymbol
;
387 OSObject
*theObject
= NULL
;
389 keySymbol
= OSSymbol::withCString(aKey
);
390 if (keySymbol
!= NULL
) {
391 theObject
= copyProperty(keySymbol
);
392 keySymbol
->release();
399 IODTNVRAM::getProperty(const OSSymbol
*aKey
) const
403 theObject
= copyProperty(aKey
);
405 theObject
->release();
412 IODTNVRAM::getProperty(const char *aKey
) const
416 theObject
= copyProperty(aKey
);
418 theObject
->release();
425 IODTNVRAM::setPropertyInternal(const OSSymbol
*aKey
, OSObject
*anObject
)
427 IOReturn result
= kIOReturnSuccess
;
428 UInt32 propType
, propPerm
;
429 OSString
*tmpString
= NULL
;
430 OSObject
*propObject
= NULL
, *oldObject
;
432 if (_ofDict
== NULL
) {
436 // Verify permissions.
437 propPerm
= getOFVariablePerm(aKey
);
438 if (IOUserClient::clientHasPrivilege(current_task(), kIONVRAMPrivilege
) != kIOReturnSuccess
) {
439 if (propPerm
!= kOFVariablePermUserWrite
) {
440 return kIOReturnNotPrivileged
;
443 if (propPerm
== kOFVariablePermKernelOnly
&& current_task() != kernel_task
) {
444 return kIOReturnNotPrivileged
;
447 // Don't allow change of 'aapl,panic-info'.
448 if (aKey
->isEqualTo(kIODTNVRAMPanicInfoKey
)) {
449 return kIOReturnUnsupported
;
452 // Make sure the object is of the correct type.
453 propType
= getOFVariableType(aKey
);
455 case kOFVariableTypeBoolean
:
456 propObject
= OSDynamicCast(OSBoolean
, anObject
);
459 case kOFVariableTypeNumber
:
460 propObject
= OSDynamicCast(OSNumber
, anObject
);
463 case kOFVariableTypeString
:
464 propObject
= OSDynamicCast(OSString
, anObject
);
465 if (propObject
!= NULL
&& aKey
->isEqualTo(kIONVRAMBootArgsKey
) && ((OSString
*)propObject
)->getLength() >= BOOT_LINE_LENGTH
) {
466 return kIOReturnNoSpace
;
470 case kOFVariableTypeData
:
471 propObject
= OSDynamicCast(OSData
, anObject
);
472 if (propObject
== NULL
) {
473 tmpString
= OSDynamicCast(OSString
, anObject
);
474 if (tmpString
!= NULL
) {
475 propObject
= OSData::withBytes(tmpString
->getCStringNoCopy(),
476 tmpString
->getLength());
482 if (propObject
== NULL
) {
483 return kIOReturnBadArgument
;
488 oldObject
= _ofDict
->getObject(aKey
);
492 if (!_ofDict
->setObject(aKey
, propObject
)) {
493 result
= kIOReturnBadArgument
;
496 if (result
== kIOReturnSuccess
) {
497 if (syncVariables() != kIOReturnSuccess
) {
499 _ofDict
->setObject(aKey
, oldObject
);
501 _ofDict
->removeObject(aKey
);
503 (void) syncVariables();
504 result
= kIOReturnNoMemory
;
509 oldObject
->release();
512 propObject
->release();
515 IOLockUnlock(_ofLock
);
521 IODTNVRAM::setProperty(const OSSymbol
*aKey
, OSObject
*anObject
)
523 return setPropertyInternal(aKey
, anObject
) == kIOReturnSuccess
;
527 IODTNVRAM::removeProperty(const OSSymbol
*aKey
)
532 if (_ofDict
== NULL
) {
536 // Verify permissions.
537 propPerm
= getOFVariablePerm(aKey
);
538 result
= IOUserClient::clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator
);
539 if (result
!= kIOReturnSuccess
) {
540 if (propPerm
!= kOFVariablePermUserWrite
) {
544 if (propPerm
== kOFVariablePermKernelOnly
&& current_task() != kernel_task
) {
548 // Don't allow change of 'aapl,panic-info'.
549 if (aKey
->isEqualTo(kIODTNVRAMPanicInfoKey
)) {
553 // If the object exists, remove it from the dictionary.
556 result
= _ofDict
->getObject(aKey
) != NULL
;
558 _ofDict
->removeObject(aKey
);
562 (void) syncVariables();
565 IOLockUnlock(_ofLock
);
569 IODTNVRAM::setProperties(OSObject
*properties
)
571 IOReturn res
= kIOReturnSuccess
;
574 const OSString
*tmpStr
;
576 OSCollectionIterator
*iter
;
578 dict
= OSDynamicCast(OSDictionary
, properties
);
580 return kIOReturnBadArgument
;
583 iter
= OSCollectionIterator::withCollection(dict
);
585 return kIOReturnBadArgument
;
588 while (res
== kIOReturnSuccess
) {
589 key
= OSDynamicCast(OSSymbol
, iter
->getNextObject());
594 object
= dict
->getObject(key
);
595 if (object
== NULL
) {
599 if (key
->isEqualTo(kIONVRAMDeletePropertyKey
)) {
600 tmpStr
= OSDynamicCast(OSString
, object
);
601 if (tmpStr
!= NULL
) {
602 key
= OSSymbol::withString(tmpStr
);
606 res
= kIOReturnError
;
608 } else if (key
->isEqualTo(kIONVRAMSyncNowPropertyKey
) || key
->isEqualTo(kIONVRAMForceSyncNowPropertyKey
)) {
609 tmpStr
= OSDynamicCast(OSString
, object
);
610 if (tmpStr
!= NULL
) {
611 // We still want to throttle NVRAM commit rate for SyncNow. ForceSyncNow is provided as a really big hammer.
612 syncInternal(key
->isEqualTo(kIONVRAMSyncNowPropertyKey
));
614 res
= kIOReturnError
;
617 if (!setProperty(key
, object
)) {
618 res
= kIOReturnNoSpace
;
629 IODTNVRAM::readXPRAM(IOByteCount offset
, UInt8
*buffer
,
632 return kIOReturnUnsupported
;
636 IODTNVRAM::writeXPRAM(IOByteCount offset
, UInt8
*buffer
,
639 return kIOReturnUnsupported
;
643 IODTNVRAM::readNVRAMProperty(IORegistryEntry
*entry
,
644 const OSSymbol
**name
,
649 err
= readNVRAMPropertyType1(entry
, name
, value
);
655 IODTNVRAM::writeNVRAMProperty(IORegistryEntry
*entry
,
656 const OSSymbol
*name
,
661 err
= writeNVRAMPropertyType1(entry
, name
, value
);
667 IODTNVRAM::getNVRAMPartitions(void)
669 return _nvramPartitionLengths
;
673 IODTNVRAM::readNVRAMPartition(const OSSymbol
*partitionID
,
674 IOByteCount offset
, UInt8
*buffer
,
677 OSNumber
*partitionOffsetNumber
, *partitionLengthNumber
;
678 UInt32 partitionOffset
, partitionLength
, end
;
680 partitionOffsetNumber
=
681 (OSNumber
*)_nvramPartitionOffsets
->getObject(partitionID
);
682 partitionLengthNumber
=
683 (OSNumber
*)_nvramPartitionLengths
->getObject(partitionID
);
685 if ((partitionOffsetNumber
== NULL
) || (partitionLengthNumber
== NULL
)) {
686 return kIOReturnNotFound
;
689 partitionOffset
= partitionOffsetNumber
->unsigned32BitValue();
690 partitionLength
= partitionLengthNumber
->unsigned32BitValue();
692 if (os_add_overflow(offset
, length
, &end
)) {
693 return kIOReturnBadArgument
;
695 if ((buffer
== NULL
) || (length
== 0) || (end
> partitionLength
)) {
696 return kIOReturnBadArgument
;
699 bcopy(_nvramImage
+ partitionOffset
+ offset
, buffer
, length
);
701 return kIOReturnSuccess
;
705 IODTNVRAM::writeNVRAMPartition(const OSSymbol
*partitionID
,
706 IOByteCount offset
, UInt8
*buffer
,
709 OSNumber
*partitionOffsetNumber
, *partitionLengthNumber
;
710 UInt32 partitionOffset
, partitionLength
, end
;
712 partitionOffsetNumber
=
713 (OSNumber
*)_nvramPartitionOffsets
->getObject(partitionID
);
714 partitionLengthNumber
=
715 (OSNumber
*)_nvramPartitionLengths
->getObject(partitionID
);
717 if ((partitionOffsetNumber
== NULL
) || (partitionLengthNumber
== NULL
)) {
718 return kIOReturnNotFound
;
721 partitionOffset
= partitionOffsetNumber
->unsigned32BitValue();
722 partitionLength
= partitionLengthNumber
->unsigned32BitValue();
724 if (os_add_overflow(offset
, length
, &end
)) {
725 return kIOReturnBadArgument
;
727 if ((buffer
== NULL
) || (length
== 0) || (end
> partitionLength
)) {
728 return kIOReturnBadArgument
;
731 bcopy(buffer
, _nvramImage
+ partitionOffset
+ offset
, length
);
733 if (_nvramController
!= NULL
) {
734 _nvramController
->write(0, _nvramImage
, kIODTNVRAMImageSize
);
737 return kIOReturnSuccess
;
741 IODTNVRAM::savePanicInfo(UInt8
*buffer
, IOByteCount length
)
743 if ((_piImage
== NULL
) || (length
<= 0)) {
747 if (length
> (_piPartitionSize
- 4)) {
748 length
= _piPartitionSize
- 4;
751 // Save the Panic Info.
752 bcopy(buffer
, _piImage
+ 4, length
);
754 // Save the Panic Info length.
755 *(UInt32
*)_piImage
= length
;
757 if (_nvramController
!= NULL
) {
758 _nvramController
->write(0, _nvramImage
, kIODTNVRAMImageSize
);
761 * This prevents OF variables from being committed if the system has panicked
763 _systemPaniced
= true;
764 /* The call to sync() forces the NVRAM controller to write the panic info
765 * partition to NVRAM.
775 IODTNVRAM::calculatePartitionChecksum(UInt8
*partitionHeader
)
777 UInt8 cnt
, isum
, csum
= 0;
779 for (cnt
= 0; cnt
< 0x10; cnt
++) {
780 isum
= csum
+ partitionHeader
[cnt
];
791 IODTNVRAM::initOFVariables(void)
794 UInt8
*propName
, *propData
;
795 UInt32 propNameLength
, propDataLength
;
796 const OSSymbol
*propSymbol
;
797 OSObject
*propObject
;
799 if (_ofImage
== NULL
) {
800 return kIOReturnNotReady
;
803 _ofDict
= OSDictionary::withCapacity(1);
804 _ofLock
= IOLockAlloc();
805 if (!_ofDict
|| !_ofLock
) {
806 return kIOReturnNoMemory
;
810 while (cnt
< _ofPartitionSize
) {
811 // Break if there is no name.
812 if (_ofImage
[cnt
] == '\0') {
816 // Find the length of the name.
817 propName
= _ofImage
+ cnt
;
818 for (propNameLength
= 0; (cnt
+ propNameLength
) < _ofPartitionSize
;
820 if (_ofImage
[cnt
+ propNameLength
] == '=') {
825 // Break if the name goes past the end of the partition.
826 if ((cnt
+ propNameLength
) >= _ofPartitionSize
) {
829 cnt
+= propNameLength
+ 1;
831 propData
= _ofImage
+ cnt
;
832 for (propDataLength
= 0; (cnt
+ propDataLength
) < _ofPartitionSize
;
834 if (_ofImage
[cnt
+ propDataLength
] == '\0') {
839 // Break if the data goes past the end of the partition.
840 if ((cnt
+ propDataLength
) >= _ofPartitionSize
) {
843 cnt
+= propDataLength
+ 1;
845 if (convertPropToObject(propName
, propNameLength
,
846 propData
, propDataLength
,
847 &propSymbol
, &propObject
)) {
848 _ofDict
->setObject(propSymbol
, propObject
);
849 propSymbol
->release();
850 propObject
->release();
854 // Create the boot-args property if it is not in the dictionary.
855 if (_ofDict
->getObject(kIONVRAMBootArgsKey
) == NULL
) {
856 propObject
= OSString::withCStringNoCopy("");
857 if (propObject
!= NULL
) {
858 _ofDict
->setObject(kIONVRAMBootArgsKey
, propObject
);
859 propObject
->release();
863 if (_piImage
!= NULL
) {
864 propDataLength
= *(UInt32
*)_piImage
;
865 if ((propDataLength
!= 0) && (propDataLength
<= (_piPartitionSize
- 4))) {
866 propObject
= OSData::withBytes(_piImage
+ 4, propDataLength
);
867 _ofDict
->setObject(kIODTNVRAMPanicInfoKey
, propObject
);
868 propObject
->release();
870 // Clear the length from _piImage and mark dirty.
871 *(UInt32
*)_piImage
= 0;
872 if (_nvramController
!= NULL
) {
873 _nvramController
->write(0, _nvramImage
, kIODTNVRAMImageSize
);
878 return kIOReturnSuccess
;
882 IODTNVRAM::syncOFVariables(void)
884 return kIOReturnUnsupported
;
888 IODTNVRAM::syncVariables(void)
891 UInt32 length
, maxLength
;
892 UInt8
*buffer
, *tmpBuffer
;
893 const OSSymbol
*tmpSymbol
;
895 OSCollectionIterator
*iter
;
897 IOLockAssert(_ofLock
, kIOLockAssertOwned
);
899 if ((_ofImage
== NULL
) || (_ofDict
== NULL
) || _systemPaniced
) {
900 return kIOReturnNotReady
;
903 buffer
= tmpBuffer
= IONew(UInt8
, _ofPartitionSize
);
904 if (buffer
== NULL
) {
905 return kIOReturnNoMemory
;
907 bzero(buffer
, _ofPartitionSize
);
910 maxLength
= _ofPartitionSize
;
912 iter
= OSCollectionIterator::withCollection(_ofDict
);
918 tmpSymbol
= OSDynamicCast(OSSymbol
, iter
->getNextObject());
919 if (tmpSymbol
== NULL
) {
923 // Don't save 'aapl,panic-info'.
924 if (tmpSymbol
->isEqualTo(kIODTNVRAMPanicInfoKey
)) {
928 tmpObject
= _ofDict
->getObject(tmpSymbol
);
931 ok
= convertObjectToProp(tmpBuffer
, &length
, tmpSymbol
, tmpObject
);
940 bcopy(buffer
, _ofImage
, _ofPartitionSize
);
943 IODelete(buffer
, UInt8
, _ofPartitionSize
);
946 return kIOReturnBadArgument
;
949 if (_nvramController
!= NULL
) {
950 return _nvramController
->write(0, _nvramImage
, kIODTNVRAMImageSize
);
953 return kIOReturnNotReady
;
957 const char *variableName
;
960 SInt32 variableOffset
;
962 typedef struct OFVariable OFVariable
;
965 kOWVariableOffsetNumber
= 8,
966 kOWVariableOffsetString
= 17
970 OFVariable gOFVariables
[] = {
971 {"little-endian?", kOFVariableTypeBoolean
, kOFVariablePermUserRead
, 0},
972 {"real-mode?", kOFVariableTypeBoolean
, kOFVariablePermUserRead
, 1},
973 {"auto-boot?", kOFVariableTypeBoolean
, kOFVariablePermUserRead
, 2},
974 {"diag-switch?", kOFVariableTypeBoolean
, kOFVariablePermUserRead
, 3},
975 {"fcode-debug?", kOFVariableTypeBoolean
, kOFVariablePermUserRead
, 4},
976 {"oem-banner?", kOFVariableTypeBoolean
, kOFVariablePermUserRead
, 5},
977 {"oem-logo?", kOFVariableTypeBoolean
, kOFVariablePermUserRead
, 6},
978 {"use-nvramrc?", kOFVariableTypeBoolean
, kOFVariablePermUserRead
, 7},
979 {"use-generic?", kOFVariableTypeBoolean
, kOFVariablePermUserRead
, -1},
980 {"default-mac-address?", kOFVariableTypeBoolean
, kOFVariablePermUserRead
, -1},
981 {"real-base", kOFVariableTypeNumber
, kOFVariablePermUserRead
, 8},
982 {"real-size", kOFVariableTypeNumber
, kOFVariablePermUserRead
, 9},
983 {"virt-base", kOFVariableTypeNumber
, kOFVariablePermUserRead
, 10},
984 {"virt-size", kOFVariableTypeNumber
, kOFVariablePermUserRead
, 11},
985 {"load-base", kOFVariableTypeNumber
, kOFVariablePermUserRead
, 12},
986 {"pci-probe-list", kOFVariableTypeNumber
, kOFVariablePermUserRead
, 13},
987 {"pci-probe-mask", kOFVariableTypeNumber
, kOFVariablePermUserRead
, -1},
988 {"screen-#columns", kOFVariableTypeNumber
, kOFVariablePermUserRead
, 14},
989 {"screen-#rows", kOFVariableTypeNumber
, kOFVariablePermUserRead
, 15},
990 {"selftest-#megs", kOFVariableTypeNumber
, kOFVariablePermUserRead
, 16},
991 {"boot-device", kOFVariableTypeString
, kOFVariablePermUserRead
, 17},
992 {"boot-file", kOFVariableTypeString
, kOFVariablePermUserRead
, 18},
993 {"boot-screen", kOFVariableTypeString
, kOFVariablePermUserRead
, -1},
994 {"console-screen", kOFVariableTypeString
, kOFVariablePermUserRead
, -1},
995 {"diag-device", kOFVariableTypeString
, kOFVariablePermUserRead
, 19},
996 {"diag-file", kOFVariableTypeString
, kOFVariablePermUserRead
, 20},
997 {"input-device", kOFVariableTypeString
, kOFVariablePermUserRead
, 21},
998 {"output-device", kOFVariableTypeString
, kOFVariablePermUserRead
, 22},
999 {"input-device-1", kOFVariableTypeString
, kOFVariablePermUserRead
, -1},
1000 {"output-device-1", kOFVariableTypeString
, kOFVariablePermUserRead
, -1},
1001 {"mouse-device", kOFVariableTypeString
, kOFVariablePermUserRead
, -1},
1002 {"oem-banner", kOFVariableTypeString
, kOFVariablePermUserRead
, 23},
1003 {"oem-logo", kOFVariableTypeString
, kOFVariablePermUserRead
, 24},
1004 {"nvramrc", kOFVariableTypeString
, kOFVariablePermUserRead
, 25},
1005 {"boot-command", kOFVariableTypeString
, kOFVariablePermUserRead
, 26},
1006 {"default-client-ip", kOFVariableTypeString
, kOFVariablePermUserRead
, -1},
1007 {"default-server-ip", kOFVariableTypeString
, kOFVariablePermUserRead
, -1},
1008 {"default-gateway-ip", kOFVariableTypeString
, kOFVariablePermUserRead
, -1},
1009 {"default-subnet-mask", kOFVariableTypeString
, kOFVariablePermUserRead
, -1},
1010 {"default-router-ip", kOFVariableTypeString
, kOFVariablePermUserRead
, -1},
1011 {"boot-script", kOFVariableTypeString
, kOFVariablePermUserRead
, -1},
1012 {"boot-args", kOFVariableTypeString
, kOFVariablePermUserRead
, -1},
1013 {"aapl,pci", kOFVariableTypeData
, kOFVariablePermRootOnly
, -1},
1014 {"security-mode", kOFVariableTypeString
, kOFVariablePermUserRead
, -1},
1015 {"security-password", kOFVariableTypeData
, kOFVariablePermRootOnly
, -1},
1016 {"boot-image", kOFVariableTypeData
, kOFVariablePermUserWrite
, -1},
1017 {"com.apple.System.fp-state", kOFVariableTypeData
, kOFVariablePermKernelOnly
, -1},
1019 {"backlight-level", kOFVariableTypeData
, kOFVariablePermUserWrite
, -1},
1020 {"com.apple.System.sep.art", kOFVariableTypeData
, kOFVariablePermKernelOnly
, -1},
1021 {"com.apple.System.boot-nonce", kOFVariableTypeString
, kOFVariablePermKernelOnly
, -1},
1022 {"darkboot", kOFVariableTypeBoolean
, kOFVariablePermUserWrite
, -1},
1023 {"acc-mb-ld-lifetime", kOFVariableTypeNumber
, kOFVariablePermKernelOnly
, -1},
1024 {"acc-cm-override-charger-count", kOFVariableTypeNumber
, kOFVariablePermKernelOnly
, -1},
1025 {"acc-cm-override-count", kOFVariableTypeNumber
, kOFVariablePermKernelOnly
, -1},
1026 {"enter-tdm-mode", kOFVariableTypeBoolean
, kOFVariablePermUserWrite
, -1},
1027 {"nonce-seeds", kOFVariableTypeData
, kOFVariablePermKernelOnly
, -1},
1029 {NULL
, kOFVariableTypeData
, kOFVariablePermUserRead
, -1}
1033 IODTNVRAM::getOFVariableType(const OSSymbol
*propSymbol
) const
1035 const OFVariable
*ofVar
;
1037 ofVar
= gOFVariables
;
1039 if ((ofVar
->variableName
== NULL
) ||
1040 propSymbol
->isEqualTo(ofVar
->variableName
)) {
1046 return ofVar
->variableType
;
1050 IODTNVRAM::getOFVariablePerm(const OSSymbol
*propSymbol
) const
1052 const OFVariable
*ofVar
;
1054 ofVar
= gOFVariables
;
1056 if ((ofVar
->variableName
== NULL
) ||
1057 propSymbol
->isEqualTo(ofVar
->variableName
)) {
1063 return ofVar
->variablePerm
;
1067 IODTNVRAM::getOWVariableInfo(UInt32 variableNumber
, const OSSymbol
**propSymbol
,
1068 UInt32
*propType
, UInt32
*propOffset
)
1075 IODTNVRAM::convertPropToObject(UInt8
*propName
, UInt32 propNameLength
,
1076 UInt8
*propData
, UInt32 propDataLength
,
1077 const OSSymbol
**propSymbol
,
1078 OSObject
**propObject
)
1081 const OSSymbol
*tmpSymbol
;
1082 OSObject
*tmpObject
;
1083 OSNumber
*tmpNumber
;
1084 OSString
*tmpString
;
1086 // Create the symbol.
1087 propName
[propNameLength
] = '\0';
1088 tmpSymbol
= OSSymbol::withCString((const char *)propName
);
1089 propName
[propNameLength
] = '=';
1090 if (tmpSymbol
== NULL
) {
1094 propType
= getOFVariableType(tmpSymbol
);
1096 // Create the object.
1099 case kOFVariableTypeBoolean
:
1100 if (!strncmp("true", (const char *)propData
, propDataLength
)) {
1101 tmpObject
= kOSBooleanTrue
;
1102 } else if (!strncmp("false", (const char *)propData
, propDataLength
)) {
1103 tmpObject
= kOSBooleanFalse
;
1107 case kOFVariableTypeNumber
:
1108 tmpNumber
= OSNumber::withNumber(strtol((const char *)propData
, NULL
, 0), 32);
1109 if (tmpNumber
!= NULL
) {
1110 tmpObject
= tmpNumber
;
1114 case kOFVariableTypeString
:
1115 tmpString
= OSString::withCString((const char *)propData
);
1116 if (tmpString
!= NULL
) {
1117 tmpObject
= tmpString
;
1121 case kOFVariableTypeData
:
1122 tmpObject
= unescapeBytesToData(propData
, propDataLength
);
1126 if (tmpObject
== NULL
) {
1127 tmpSymbol
->release();
1131 *propSymbol
= tmpSymbol
;
1132 *propObject
= tmpObject
;
1138 IODTNVRAM::convertObjectToProp(UInt8
*buffer
, UInt32
*length
,
1139 const OSSymbol
*propSymbol
, OSObject
*propObject
)
1141 const UInt8
*propName
;
1142 UInt32 propNameLength
, propDataLength
, remaining
;
1143 UInt32 propType
, tmpValue
;
1144 OSBoolean
*tmpBoolean
= NULL
;
1145 OSNumber
*tmpNumber
= NULL
;
1146 OSString
*tmpString
= NULL
;
1147 OSData
*tmpData
= NULL
;
1149 propName
= (const UInt8
*)propSymbol
->getCStringNoCopy();
1150 propNameLength
= propSymbol
->getLength();
1151 propType
= getOFVariableType(propSymbol
);
1153 // Get the size of the data.
1154 propDataLength
= 0xFFFFFFFF;
1156 case kOFVariableTypeBoolean
:
1157 tmpBoolean
= OSDynamicCast(OSBoolean
, propObject
);
1158 if (tmpBoolean
!= NULL
) {
1163 case kOFVariableTypeNumber
:
1164 tmpNumber
= OSDynamicCast(OSNumber
, propObject
);
1165 if (tmpNumber
!= NULL
) {
1166 propDataLength
= 10;
1170 case kOFVariableTypeString
:
1171 tmpString
= OSDynamicCast(OSString
, propObject
);
1172 if (tmpString
!= NULL
) {
1173 propDataLength
= tmpString
->getLength();
1177 case kOFVariableTypeData
:
1178 tmpData
= OSDynamicCast(OSData
, propObject
);
1179 if (tmpData
!= NULL
) {
1180 tmpData
= escapeDataToData(tmpData
);
1181 propDataLength
= tmpData
->getLength();
1186 // Make sure the propertySize is known and will fit.
1187 if (propDataLength
== 0xFFFFFFFF) {
1190 if ((propNameLength
+ propDataLength
+ 2) > *length
) {
1194 // Copy the property name equal sign.
1195 buffer
+= snprintf((char *)buffer
, *length
, "%s=", propName
);
1196 remaining
= *length
- propNameLength
- 1;
1199 case kOFVariableTypeBoolean
:
1200 if (tmpBoolean
->getValue()) {
1201 strlcpy((char *)buffer
, "true", remaining
);
1203 strlcpy((char *)buffer
, "false", remaining
);
1207 case kOFVariableTypeNumber
:
1208 tmpValue
= tmpNumber
->unsigned32BitValue();
1209 if (tmpValue
== 0xFFFFFFFF) {
1210 strlcpy((char *)buffer
, "-1", remaining
);
1211 } else if (tmpValue
< 1000) {
1212 snprintf((char *)buffer
, remaining
, "%d", (uint32_t)tmpValue
);
1214 snprintf((char *)buffer
, remaining
, "0x%x", (uint32_t)tmpValue
);
1218 case kOFVariableTypeString
:
1219 strlcpy((char *)buffer
, tmpString
->getCStringNoCopy(), remaining
);
1222 case kOFVariableTypeData
:
1223 bcopy(tmpData
->getBytesNoCopy(), buffer
, propDataLength
);
1228 propDataLength
= strlen((const char *)buffer
);
1230 *length
= propNameLength
+ propDataLength
+ 2;
1237 IODTNVRAM::generateOWChecksum(UInt8
*buffer
)
1239 UInt32 cnt
, checksum
= 0;
1240 UInt16
*tmpBuffer
= (UInt16
*)buffer
;
1242 for (cnt
= 0; cnt
< _ofPartitionSize
/ 2; cnt
++) {
1243 checksum
+= tmpBuffer
[cnt
];
1246 return checksum
% 0x0000FFFF;
1250 IODTNVRAM::validateOWChecksum(UInt8
*buffer
)
1252 UInt32 cnt
, checksum
, sum
= 0;
1253 UInt16
*tmpBuffer
= (UInt16
*)buffer
;
1255 for (cnt
= 0; cnt
< _ofPartitionSize
/ 2; cnt
++) {
1256 sum
+= tmpBuffer
[cnt
];
1259 checksum
= (sum
>> 16) + (sum
& 0x0000FFFF);
1260 if (checksum
== 0x10000) {
1263 checksum
= (checksum
^ 0x0000FFFF) & 0x0000FFFF;
1265 return checksum
== 0;
1269 IODTNVRAM::updateOWBootArgs(const OSSymbol
*key
, OSObject
*value
)
1275 IODTNVRAM::searchNVRAMProperty(IONVRAMDescriptor
*hdr
, UInt32
*where
)
1281 IODTNVRAM::readNVRAMPropertyType0(IORegistryEntry
*entry
,
1282 const OSSymbol
**name
,
1285 return kIOReturnUnsupported
;
1290 IODTNVRAM::writeNVRAMPropertyType0(IORegistryEntry
*entry
,
1291 const OSSymbol
*name
,
1294 return kIOReturnUnsupported
;
1299 IODTNVRAM::unescapeBytesToData(const UInt8
*bytes
, UInt32 length
)
1301 OSData
*data
= NULL
;
1302 UInt32 totalLength
= 0;
1307 // Calculate the actual length of the data.
1310 for (cnt
= 0; cnt
< length
;) {
1311 byte
= bytes
[cnt
++];
1313 byte
= bytes
[cnt
++];
1322 totalLength
+= cnt2
;
1326 // Create an empty OSData of the correct size.
1327 data
= OSData::withCapacity(totalLength
);
1329 for (cnt
= 0; cnt
< length
;) {
1330 byte
= bytes
[cnt
++];
1332 byte
= bytes
[cnt
++];
1334 byte
= (byte
& 0x80) ? 0xFF : 0x00;
1338 data
->appendByte(byte
, cnt2
);
1347 IODTNVRAM::escapeDataToData(OSData
* value
)
1350 const UInt8
* startPtr
;
1351 const UInt8
* endPtr
;
1352 const UInt8
* wherePtr
;
1356 wherePtr
= (const UInt8
*) value
->getBytesNoCopy();
1357 endPtr
= wherePtr
+ value
->getLength();
1359 result
= OSData::withCapacity(endPtr
- wherePtr
);
1364 while (wherePtr
< endPtr
) {
1365 startPtr
= wherePtr
;
1367 if ((byte
== 0x00) || (byte
== 0xFF)) {
1369 ((wherePtr
- startPtr
) < 0x80) && (wherePtr
< endPtr
) && (byte
== *wherePtr
);
1372 ok
&= result
->appendByte(0xff, 1);
1373 byte
= (byte
& 0x80) | (wherePtr
- startPtr
);
1375 ok
&= result
->appendByte(byte
, 1);
1377 ok
&= result
->appendByte(0, 1);
1388 IsApplePropertyName(const char * propName
)
1391 while ((c
= *propName
++)) {
1392 if ((c
>= 'A') && (c
<= 'Z')) {
1401 IODTNVRAM::readNVRAMPropertyType1(IORegistryEntry
*entry
,
1402 const OSSymbol
**name
,
1405 IOReturn err
= kIOReturnNoResources
;
1407 const UInt8
*startPtr
;
1408 const UInt8
*endPtr
;
1409 const UInt8
*wherePtr
;
1410 const UInt8
*nvPath
= NULL
;
1411 const char *nvName
= NULL
;
1412 const char *resultName
= NULL
;
1413 const UInt8
*resultValue
= NULL
;
1414 UInt32 resultValueLen
= 0;
1417 if (_ofDict
== NULL
) {
1421 IOLockLock(_ofLock
);
1422 data
= OSDynamicCast(OSData
, _ofDict
->getObject(_registryPropertiesKey
));
1423 IOLockUnlock(_ofLock
);
1429 startPtr
= (const UInt8
*) data
->getBytesNoCopy();
1430 endPtr
= startPtr
+ data
->getLength();
1432 wherePtr
= startPtr
;
1433 while (wherePtr
< endPtr
) {
1434 byte
= *(wherePtr
++);
1439 if (nvPath
== NULL
) {
1441 } else if (nvName
== NULL
) {
1442 nvName
= (const char *) startPtr
;
1444 IORegistryEntry
* compareEntry
= IORegistryEntry::fromPath((const char *) nvPath
, gIODTPlane
);
1446 compareEntry
->release();
1448 if (entry
== compareEntry
) {
1449 bool appleProp
= IsApplePropertyName(nvName
);
1450 if (!appleProp
|| !resultName
) {
1451 resultName
= nvName
;
1452 resultValue
= startPtr
;
1453 resultValueLen
= wherePtr
- startPtr
- 1;
1462 startPtr
= wherePtr
;
1465 *name
= OSSymbol::withCString(resultName
);
1466 *value
= unescapeBytesToData(resultValue
, resultValueLen
);
1467 if ((*name
!= NULL
) && (*value
!= NULL
)) {
1468 err
= kIOReturnSuccess
;
1470 err
= kIOReturnNoMemory
;
1477 IODTNVRAM::writeNVRAMPropertyType1(IORegistryEntry
*entry
,
1478 const OSSymbol
*propName
,
1481 OSData
*oldData
, *escapedData
;
1482 OSData
*data
= NULL
;
1483 const UInt8
*startPtr
;
1484 const UInt8
*propStart
;
1485 const UInt8
*endPtr
;
1486 const UInt8
*wherePtr
;
1487 const UInt8
*nvPath
= NULL
;
1488 const char *nvName
= NULL
;
1493 bool settingAppleProp
;
1495 if (_ofDict
== NULL
) {
1496 return kIOReturnNoResources
;
1499 settingAppleProp
= IsApplePropertyName(propName
->getCStringNoCopy());
1501 // copy over existing properties for other entries
1503 IOLockLock(_ofLock
);
1505 oldData
= OSDynamicCast(OSData
, _ofDict
->getObject(_registryPropertiesKey
));
1507 startPtr
= (const UInt8
*) oldData
->getBytesNoCopy();
1508 endPtr
= startPtr
+ oldData
->getLength();
1510 propStart
= startPtr
;
1511 wherePtr
= startPtr
;
1512 while (wherePtr
< endPtr
) {
1513 byte
= *(wherePtr
++);
1517 if (nvPath
== NULL
) {
1519 } else if (nvName
== NULL
) {
1520 nvName
= (const char *) startPtr
;
1522 IORegistryEntry
* compareEntry
= IORegistryEntry::fromPath((const char *) nvPath
, gIODTPlane
);
1524 compareEntry
->release();
1526 if (entry
== compareEntry
) {
1527 if ((settingAppleProp
&& propName
->isEqualTo(nvName
))
1528 || (!settingAppleProp
&& !IsApplePropertyName(nvName
))) {
1529 // delete old property (nvPath -> wherePtr)
1530 data
= OSData::withBytes(propStart
, nvPath
- propStart
);
1532 ok
&= data
->appendBytes(wherePtr
, endPtr
- wherePtr
);
1541 startPtr
= wherePtr
;
1545 // make the new property
1549 data
= OSData::withData(oldData
);
1551 data
= OSData::withCapacity(16);
1558 if (ok
&& value
&& value
->getLength()) {
1560 // get entries in path
1561 OSArray
*array
= OSArray::withCapacity(5);
1567 array
->setObject(entry
);
1568 } while ((entry
= entry
->getParentEntry(gIODTPlane
)));
1571 for (int i
= array
->getCount() - 3;
1572 (entry
= (IORegistryEntry
*) array
->getObject(i
));
1574 name
= entry
->getName(gIODTPlane
);
1575 comp
= entry
->getLocation(gIODTPlane
);
1577 ok
&= data
->appendBytes("/@", 2);
1582 ok
&= data
->appendByte('/', 1);
1585 ok
&= data
->appendBytes(comp
, strlen(comp
));
1587 ok
&= data
->appendByte(0, 1);
1591 ok
&= data
->appendBytes(propName
->getCStringNoCopy(), propName
->getLength() + 1);
1593 // append escaped data
1594 escapedData
= escapeDataToData(value
);
1595 ok
&= (escapedData
!= NULL
);
1597 ok
&= data
->appendBytes(escapedData
);
1604 ok
= _ofDict
->setObject(_registryPropertiesKey
, data
);
1612 if (syncVariables() != kIOReturnSuccess
) {
1614 _ofDict
->setObject(_registryPropertiesKey
, oldData
);
1616 _ofDict
->removeObject(_registryPropertiesKey
);
1618 (void) syncVariables();
1627 IOLockUnlock(_ofLock
);
1629 return ok
? kIOReturnSuccess
: kIOReturnNoMemory
;
1633 IODTNVRAM::safeToSync(void)
1639 // delta interval went by
1640 clock_get_uptime(&delta
);
1642 // Figure it in seconds.
1643 absolutetime_to_nanoseconds(delta
, &delta_ns
);
1644 delta_secs
= (SInt32
)(delta_ns
/ NSEC_PER_SEC
);
1646 if ((delta_secs
> (_lastDeviceSync
+ MIN_SYNC_NOW_INTERVAL
)) || _freshInterval
) {
1647 _lastDeviceSync
= delta_secs
;
1648 _freshInterval
= FALSE
;