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/pexpert.h>
41 #include <security/mac.h>
42 #include <security/mac_framework.h>
46 #define super IOService
48 #define kIONVRAMPrivilege kIOClientPrivilegeAdministrator
49 //#define kIONVRAMPrivilege kIOClientPrivilegeLocalUser
51 OSDefineMetaClassAndStructors(IODTNVRAM
, IOService
);
53 bool IODTNVRAM::init(IORegistryEntry
*old
, const IORegistryPlane
*plane
)
57 if (!super::init(old
, plane
)) return false;
59 dict
= OSDictionary::withCapacity(1);
60 if (dict
== 0) return false;
61 setPropertyTable(dict
);
63 _nvramImage
= IONew(UInt8
, kIODTNVRAMImageSize
);
64 if (_nvramImage
== 0) return false;
66 _nvramPartitionOffsets
= OSDictionary::withCapacity(1);
67 if (_nvramPartitionOffsets
== 0) return false;
69 _nvramPartitionLengths
= OSDictionary::withCapacity(1);
70 if (_nvramPartitionLengths
== 0) return false;
72 _registryPropertiesKey
= OSSymbol::withCStringNoCopy("aapl,pci");
73 if (_registryPropertiesKey
== 0) return false;
75 // <rdar://problem/9529235> race condition possible between
76 // IODTNVRAM and IONVRAMController (restore loses boot-args)
82 void IODTNVRAM::initProxyData(void)
84 IORegistryEntry
*entry
;
85 const char *key
= "nvram-proxy-data";
90 entry
= IORegistryEntry::fromPath("/chosen", gIODTPlane
);
92 prop
= entry
->getProperty(key
);
94 data
= OSDynamicCast(OSData
, prop
);
96 bytes
= data
->getBytesNoCopy();
97 if ((bytes
!= 0) && (data
->getLength() <= kIODTNVRAMImageSize
)) {
98 bcopy(bytes
, _nvramImage
, data
->getLength());
104 entry
->removeProperty(key
);
109 void IODTNVRAM::registerNVRAMController(IONVRAMController
*nvram
)
111 if (_nvramController
!= 0) return;
113 _nvramController
= nvram
;
115 // <rdar://problem/9529235> race condition possible between
116 // IODTNVRAM and IONVRAMController (restore loses boot-args)
118 _nvramController
->read(0, _nvramImage
, kIODTNVRAMImageSize
);
125 void IODTNVRAM::initNVRAMImage(void)
127 char partitionID
[18];
128 UInt32 partitionOffset
, partitionLength
;
129 UInt32 freePartitionOffset
, freePartitionSize
;
130 UInt32 currentLength
, currentOffset
= 0;
131 OSNumber
*partitionOffsetNumber
, *partitionLengthNumber
;
133 // Find the offsets for the OF, XPRAM, NameRegistry and PanicInfo partitions.
134 _ofPartitionOffset
= 0xFFFFFFFF;
135 _piPartitionOffset
= 0xFFFFFFFF;
136 freePartitionOffset
= 0xFFFFFFFF;
137 freePartitionSize
= 0;
139 // Look through the partitions to find the OF, MacOS partitions.
140 while (currentOffset
< kIODTNVRAMImageSize
) {
141 currentLength
= ((UInt16
*)(_nvramImage
+ currentOffset
))[1] * 16;
143 partitionOffset
= currentOffset
+ 16;
144 partitionLength
= currentLength
- 16;
146 if (strncmp((const char *)_nvramImage
+ currentOffset
+ 4,
147 kIODTNVRAMOFPartitionName
, 12) == 0) {
148 _ofPartitionOffset
= partitionOffset
;
149 _ofPartitionSize
= partitionLength
;
150 } else if (strncmp((const char *)_nvramImage
+ currentOffset
+ 4,
151 kIODTNVRAMXPRAMPartitionName
, 12) == 0) {
152 } else if (strncmp((const char *)_nvramImage
+ currentOffset
+ 4,
153 kIODTNVRAMPanicInfoPartitonName
, 12) == 0) {
154 _piPartitionOffset
= partitionOffset
;
155 _piPartitionSize
= partitionLength
;
156 } else if (strncmp((const char *)_nvramImage
+ currentOffset
+ 4,
157 kIODTNVRAMFreePartitionName
, 12) == 0) {
158 freePartitionOffset
= currentOffset
;
159 freePartitionSize
= currentLength
;
161 // Construct the partition ID from the signature and name.
162 snprintf(partitionID
, sizeof(partitionID
), "0x%02x,",
163 *(UInt8
*)(_nvramImage
+ currentOffset
));
164 strncpy(partitionID
+ 5,
165 (const char *)(_nvramImage
+ currentOffset
+ 4), 12);
166 partitionID
[17] = '\0';
168 partitionOffsetNumber
= OSNumber::withNumber(partitionOffset
, 32);
169 partitionLengthNumber
= OSNumber::withNumber(partitionLength
, 32);
171 // Save the partition offset and length
172 _nvramPartitionOffsets
->setObject(partitionID
, partitionOffsetNumber
);
173 _nvramPartitionLengths
->setObject(partitionID
, partitionLengthNumber
);
175 partitionOffsetNumber
->release();
176 partitionLengthNumber
->release();
178 currentOffset
+= currentLength
;
181 if (_ofPartitionOffset
!= 0xFFFFFFFF)
182 _ofImage
= _nvramImage
+ _ofPartitionOffset
;
184 if (_piPartitionOffset
== 0xFFFFFFFF) {
185 if (freePartitionSize
> 0x20) {
186 // Set the signature to 0xa1.
187 _nvramImage
[freePartitionOffset
] = 0xa1;
188 // Set the checksum to 0.
189 _nvramImage
[freePartitionOffset
+ 1] = 0;
190 // Set the name for the Panic Info partition.
191 strncpy((char *)(_nvramImage
+ freePartitionOffset
+ 4),
192 kIODTNVRAMPanicInfoPartitonName
, 12);
194 // Calculate the partition offset and size.
195 _piPartitionOffset
= freePartitionOffset
+ 0x10;
196 _piPartitionSize
= 0x800;
197 if (_piPartitionSize
+ 0x20 > freePartitionSize
)
198 _piPartitionSize
= freePartitionSize
- 0x20;
200 _piImage
= _nvramImage
+ _piPartitionOffset
;
202 // Zero the new partition.
203 bzero(_piImage
, _piPartitionSize
);
205 // Set the partition size.
206 *(UInt16
*)(_nvramImage
+ freePartitionOffset
+ 2) =
207 (_piPartitionSize
/ 0x10) + 1;
209 // Set the partition checksum.
210 _nvramImage
[freePartitionOffset
+ 1] =
211 calculatePartitionChecksum(_nvramImage
+ freePartitionOffset
);
213 // Calculate the free partition offset and size.
214 freePartitionOffset
+= _piPartitionSize
+ 0x10;
215 freePartitionSize
-= _piPartitionSize
+ 0x10;
217 // Set the signature to 0x7f.
218 _nvramImage
[freePartitionOffset
] = 0x7f;
219 // Set the checksum to 0.
220 _nvramImage
[freePartitionOffset
+ 1] = 0;
221 // Set the name for the free partition.
222 strncpy((char *)(_nvramImage
+ freePartitionOffset
+ 4),
223 kIODTNVRAMFreePartitionName
, 12);
224 // Set the partition size.
225 *(UInt16
*)(_nvramImage
+ freePartitionOffset
+ 2) =
226 freePartitionSize
/ 0x10;
227 // Set the partition checksum.
228 _nvramImage
[freePartitionOffset
+ 1] =
229 calculatePartitionChecksum(_nvramImage
+ freePartitionOffset
);
231 if (_nvramController
!= 0) {
232 _nvramController
->write(0, _nvramImage
, kIODTNVRAMImageSize
);
236 _piImage
= _nvramImage
+ _piPartitionOffset
;
240 _freshInterval
= TRUE
; // we will allow sync() even before the first 15 minutes have passed.
245 void IODTNVRAM::syncInternal(bool rateLimit
)
247 // Don't try to perform controller operations if none has been registered.
248 if (_nvramController
== 0) return;
250 // Rate limit requests to sync. Drivers that need this rate limiting will
251 // shadow the data and only write to flash when they get a sync call
252 if (rateLimit
&& !safeToSync()) return;
254 _nvramController
->sync();
257 void IODTNVRAM::sync(void)
262 bool IODTNVRAM::serializeProperties(OSSerialize
*s
) const
264 bool result
, hasPrivilege
;
268 OSCollectionIterator
*iter
= 0;
270 // Verify permissions.
271 hasPrivilege
= (kIOReturnSuccess
== IOUserClient::clientHasPrivilege(current_task(), kIONVRAMPrivilege
));
274 /* No nvram. Return an empty dictionary. */
275 dict
= OSDictionary::withCapacity(1);
276 if (dict
== 0) return false;
279 dict
= OSDictionary::withDictionary(_ofDict
);
280 IOLockUnlock(_ofLock
);
281 if (dict
== 0) return false;
283 /* Copy properties with client privilege. */
284 iter
= OSCollectionIterator::withCollection(dict
);
290 key
= OSDynamicCast(OSSymbol
, iter
->getNextObject());
293 variablePerm
= getOFVariablePerm(key
);
294 if ((hasPrivilege
|| (variablePerm
!= kOFVariablePermRootOnly
)) &&
295 ( ! (variablePerm
== kOFVariablePermKernelOnly
&& current_task() != kernel_task
) )
297 && (current_task() == kernel_task
|| mac_iokit_check_nvram_get(kauth_cred_get(), key
->getCStringNoCopy()) == 0)
301 dict
->removeObject(key
);
307 result
= dict
->serialize(s
);
310 if (iter
!= 0) iter
->release();
315 OSObject
*IODTNVRAM::copyProperty(const OSSymbol
*aKey
) const
321 if (_ofDict
== 0) return 0;
323 // Verify permissions.
324 variablePerm
= getOFVariablePerm(aKey
);
325 result
= IOUserClient::clientHasPrivilege(current_task(), kIONVRAMPrivilege
);
326 if (result
!= kIOReturnSuccess
) {
327 if (variablePerm
== kOFVariablePermRootOnly
) return 0;
329 if (variablePerm
== kOFVariablePermKernelOnly
&& current_task() != kernel_task
) return 0;
332 if (current_task() != kernel_task
&&
333 mac_iokit_check_nvram_get(kauth_cred_get(), aKey
->getCStringNoCopy()) != 0)
338 theObject
= _ofDict
->getObject(aKey
);
339 if (theObject
) theObject
->retain();
340 IOLockUnlock(_ofLock
);
345 OSObject
*IODTNVRAM::copyProperty(const char *aKey
) const
347 const OSSymbol
*keySymbol
;
348 OSObject
*theObject
= 0;
350 keySymbol
= OSSymbol::withCString(aKey
);
351 if (keySymbol
!= 0) {
352 theObject
= copyProperty(keySymbol
);
353 keySymbol
->release();
359 OSObject
*IODTNVRAM::getProperty(const OSSymbol
*aKey
) const
363 theObject
= copyProperty(aKey
);
364 if (theObject
) theObject
->release();
369 OSObject
*IODTNVRAM::getProperty(const char *aKey
) const
373 theObject
= copyProperty(aKey
);
374 if (theObject
) theObject
->release();
379 bool IODTNVRAM::setProperty(const OSSymbol
*aKey
, OSObject
*anObject
)
382 UInt32 propType
, propPerm
;
384 OSObject
*propObject
= 0;
386 if (_ofDict
== 0) return false;
388 // Verify permissions.
389 propPerm
= getOFVariablePerm(aKey
);
390 result
= IOUserClient::clientHasPrivilege(current_task(), kIONVRAMPrivilege
);
391 if (result
!= kIOReturnSuccess
) {
392 if (propPerm
!= kOFVariablePermUserWrite
) return false;
394 if (propPerm
== kOFVariablePermKernelOnly
&& current_task() != kernel_task
) return 0;
396 // Don't allow change of 'aapl,panic-info'.
397 if (aKey
->isEqualTo(kIODTNVRAMPanicInfoKey
)) return false;
400 if (current_task() != kernel_task
&&
401 mac_iokit_check_nvram_set(kauth_cred_get(), aKey
->getCStringNoCopy(), anObject
) != 0)
405 // Make sure the object is of the correct type.
406 propType
= getOFVariableType(aKey
);
408 case kOFVariableTypeBoolean
:
409 propObject
= OSDynamicCast(OSBoolean
, anObject
);
412 case kOFVariableTypeNumber
:
413 propObject
= OSDynamicCast(OSNumber
, anObject
);
416 case kOFVariableTypeString
:
417 propObject
= OSDynamicCast(OSString
, anObject
);
420 case kOFVariableTypeData
:
421 propObject
= OSDynamicCast(OSData
, anObject
);
422 if (propObject
== 0) {
423 tmpString
= OSDynamicCast(OSString
, anObject
);
424 if (tmpString
!= 0) {
425 propObject
= OSData::withBytes(tmpString
->getCStringNoCopy(),
426 tmpString
->getLength());
432 if (propObject
== 0) return false;
435 result
= _ofDict
->setObject(aKey
, propObject
);
436 IOLockUnlock(_ofLock
);
445 void IODTNVRAM::removeProperty(const OSSymbol
*aKey
)
450 if (_ofDict
== 0) return;
452 // Verify permissions.
453 propPerm
= getOFVariablePerm(aKey
);
454 result
= IOUserClient::clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator
);
455 if (result
!= kIOReturnSuccess
) {
456 if (propPerm
!= kOFVariablePermUserWrite
) return;
458 if (propPerm
== kOFVariablePermKernelOnly
&& current_task() != kernel_task
) return;
460 // Don't allow change of 'aapl,panic-info'.
461 if (aKey
->isEqualTo(kIODTNVRAMPanicInfoKey
)) return;
464 if (current_task() != kernel_task
&&
465 mac_iokit_check_nvram_delete(kauth_cred_get(), aKey
->getCStringNoCopy()) != 0)
469 // If the object exists, remove it from the dictionary.
472 result
= _ofDict
->getObject(aKey
) != 0;
474 _ofDict
->removeObject(aKey
);
476 IOLockUnlock(_ofLock
);
483 IOReturn
IODTNVRAM::setProperties(OSObject
*properties
)
488 const OSString
*tmpStr
;
490 OSCollectionIterator
*iter
;
492 dict
= OSDynamicCast(OSDictionary
, properties
);
493 if (dict
== 0) return kIOReturnBadArgument
;
495 iter
= OSCollectionIterator::withCollection(dict
);
496 if (iter
== 0) return kIOReturnBadArgument
;
499 key
= OSDynamicCast(OSSymbol
, iter
->getNextObject());
502 object
= dict
->getObject(key
);
503 if (object
== 0) continue;
505 if (key
->isEqualTo(kIONVRAMDeletePropertyKey
)) {
506 tmpStr
= OSDynamicCast(OSString
, object
);
508 key
= OSSymbol::withString(tmpStr
);
515 } else if(key
->isEqualTo(kIONVRAMSyncNowPropertyKey
) || key
->isEqualTo(kIONVRAMForceSyncNowPropertyKey
)) {
516 tmpStr
= OSDynamicCast(OSString
, object
);
521 // We still want to throttle NVRAM commit rate for SyncNow. ForceSyncNow is provided as a really big hammer.
523 syncInternal(key
->isEqualTo(kIONVRAMSyncNowPropertyKey
));
530 result
= setProperty(key
, object
);
537 if (result
) return kIOReturnSuccess
;
538 else return kIOReturnError
;
541 IOReturn
IODTNVRAM::readXPRAM(IOByteCount offset
, UInt8
*buffer
,
544 return kIOReturnUnsupported
;
547 IOReturn
IODTNVRAM::writeXPRAM(IOByteCount offset
, UInt8
*buffer
,
550 return kIOReturnUnsupported
;
553 IOReturn
IODTNVRAM::readNVRAMProperty(IORegistryEntry
*entry
,
554 const OSSymbol
**name
,
559 err
= readNVRAMPropertyType1(entry
, name
, value
);
564 IOReturn
IODTNVRAM::writeNVRAMProperty(IORegistryEntry
*entry
,
565 const OSSymbol
*name
,
570 err
= writeNVRAMPropertyType1(entry
, name
, value
);
575 OSDictionary
*IODTNVRAM::getNVRAMPartitions(void)
577 return _nvramPartitionLengths
;
580 IOReturn
IODTNVRAM::readNVRAMPartition(const OSSymbol
*partitionID
,
581 IOByteCount offset
, UInt8
*buffer
,
584 OSNumber
*partitionOffsetNumber
, *partitionLengthNumber
;
585 UInt32 partitionOffset
, partitionLength
;
587 partitionOffsetNumber
=
588 (OSNumber
*)_nvramPartitionOffsets
->getObject(partitionID
);
589 partitionLengthNumber
=
590 (OSNumber
*)_nvramPartitionLengths
->getObject(partitionID
);
592 if ((partitionOffsetNumber
== 0) || (partitionLengthNumber
== 0))
593 return kIOReturnNotFound
;
595 partitionOffset
= partitionOffsetNumber
->unsigned32BitValue();
596 partitionLength
= partitionLengthNumber
->unsigned32BitValue();
598 if ((buffer
== 0) || (length
== 0) ||
599 (offset
+ length
> partitionLength
))
600 return kIOReturnBadArgument
;
602 bcopy(_nvramImage
+ partitionOffset
+ offset
, buffer
, length
);
604 return kIOReturnSuccess
;
607 IOReturn
IODTNVRAM::writeNVRAMPartition(const OSSymbol
*partitionID
,
608 IOByteCount offset
, UInt8
*buffer
,
611 OSNumber
*partitionOffsetNumber
, *partitionLengthNumber
;
612 UInt32 partitionOffset
, partitionLength
;
614 partitionOffsetNumber
=
615 (OSNumber
*)_nvramPartitionOffsets
->getObject(partitionID
);
616 partitionLengthNumber
=
617 (OSNumber
*)_nvramPartitionLengths
->getObject(partitionID
);
619 if ((partitionOffsetNumber
== 0) || (partitionLengthNumber
== 0))
620 return kIOReturnNotFound
;
622 partitionOffset
= partitionOffsetNumber
->unsigned32BitValue();
623 partitionLength
= partitionLengthNumber
->unsigned32BitValue();
625 if ((buffer
== 0) || (length
== 0) ||
626 (offset
+ length
> partitionLength
))
627 return kIOReturnBadArgument
;
629 bcopy(buffer
, _nvramImage
+ partitionOffset
+ offset
, length
);
631 if (_nvramController
!= 0) {
632 _nvramController
->write(0, _nvramImage
, kIODTNVRAMImageSize
);
635 return kIOReturnSuccess
;
638 IOByteCount
IODTNVRAM::savePanicInfo(UInt8
*buffer
, IOByteCount length
)
640 if ((_piImage
== 0) || (length
<= 0)) return 0;
642 if (length
> (_piPartitionSize
- 4))
643 length
= _piPartitionSize
- 4;
645 // Save the Panic Info.
646 bcopy(buffer
, _piImage
+ 4, length
);
648 // Save the Panic Info length.
649 *(UInt32
*)_piImage
= length
;
651 if (_nvramController
!= 0) {
652 _nvramController
->write(0, _nvramImage
, kIODTNVRAMImageSize
);
655 * This prevents OF variables from being committed if the system has panicked
657 _systemPaniced
= true;
658 /* The call to sync() forces the NVRAM controller to write the panic info
659 * partition to NVRAM.
668 UInt8
IODTNVRAM::calculatePartitionChecksum(UInt8
*partitionHeader
)
670 UInt8 cnt
, isum
, csum
= 0;
672 for (cnt
= 0; cnt
< 0x10; cnt
++) {
673 isum
= csum
+ partitionHeader
[cnt
];
674 if (isum
< csum
) isum
++;
681 IOReturn
IODTNVRAM::initOFVariables(void)
684 UInt8
*propName
, *propData
;
685 UInt32 propNameLength
, propDataLength
;
686 const OSSymbol
*propSymbol
;
687 OSObject
*propObject
;
689 if (_ofImage
== 0) return kIOReturnNotReady
;
691 _ofDict
= OSDictionary::withCapacity(1);
692 _ofLock
= IOLockAlloc();
693 if (!_ofDict
|| !_ofLock
) return kIOReturnNoMemory
;
696 while (cnt
< _ofPartitionSize
) {
697 // Break if there is no name.
698 if (_ofImage
[cnt
] == '\0') break;
700 // Find the length of the name.
701 propName
= _ofImage
+ cnt
;
702 for (propNameLength
= 0; (cnt
+ propNameLength
) < _ofPartitionSize
;
704 if (_ofImage
[cnt
+ propNameLength
] == '=') break;
707 // Break if the name goes past the end of the partition.
708 if ((cnt
+ propNameLength
) >= _ofPartitionSize
) break;
709 cnt
+= propNameLength
+ 1;
711 propData
= _ofImage
+ cnt
;
712 for (propDataLength
= 0; (cnt
+ propDataLength
) < _ofPartitionSize
;
714 if (_ofImage
[cnt
+ propDataLength
] == '\0') break;
717 // Break if the data goes past the end of the partition.
718 if ((cnt
+ propDataLength
) >= _ofPartitionSize
) break;
719 cnt
+= propDataLength
+ 1;
721 if (convertPropToObject(propName
, propNameLength
,
722 propData
, propDataLength
,
723 &propSymbol
, &propObject
)) {
724 _ofDict
->setObject(propSymbol
, propObject
);
725 propSymbol
->release();
726 propObject
->release();
730 // Create the boot-args property if it is not in the dictionary.
731 if (_ofDict
->getObject("boot-args") == 0) {
732 propObject
= OSString::withCStringNoCopy("");
733 if (propObject
!= 0) {
734 _ofDict
->setObject("boot-args", propObject
);
735 propObject
->release();
739 // Create the 'aapl,panic-info' property if needed.
741 propDataLength
= *(UInt32
*)_piImage
;
742 if ((propDataLength
!= 0) && (propDataLength
<= (_piPartitionSize
- 4))) {
743 propObject
= OSData::withBytes(_piImage
+ 4, propDataLength
);
744 _ofDict
->setObject(kIODTNVRAMPanicInfoKey
, propObject
);
745 propObject
->release();
747 // Clear the length from _piImage and mark dirty.
748 *(UInt32
*)_piImage
= 0;
749 if (_nvramController
!= 0) {
750 _nvramController
->write(0, _nvramImage
, kIODTNVRAMImageSize
);
755 return kIOReturnSuccess
;
758 IOReturn
IODTNVRAM::syncOFVariables(void)
761 UInt32 length
, maxLength
;
762 UInt8
*buffer
, *tmpBuffer
;
763 const OSSymbol
*tmpSymbol
;
765 OSCollectionIterator
*iter
;
767 if ((_ofImage
== 0) || (_ofDict
== 0) || _systemPaniced
) return kIOReturnNotReady
;
769 buffer
= tmpBuffer
= IONew(UInt8
, _ofPartitionSize
);
770 if (buffer
== 0) return kIOReturnNoMemory
;
771 bzero(buffer
, _ofPartitionSize
);
774 maxLength
= _ofPartitionSize
;
777 iter
= OSCollectionIterator::withCollection(_ofDict
);
778 if (iter
== 0) ok
= false;
781 tmpSymbol
= OSDynamicCast(OSSymbol
, iter
->getNextObject());
782 if (tmpSymbol
== 0) break;
784 // Don't save 'aapl,panic-info'.
785 if (tmpSymbol
->isEqualTo(kIODTNVRAMPanicInfoKey
)) continue;
787 tmpObject
= _ofDict
->getObject(tmpSymbol
);
790 ok
= convertObjectToProp(tmpBuffer
, &length
, tmpSymbol
, tmpObject
);
797 IOLockUnlock(_ofLock
);
800 bcopy(buffer
, _ofImage
, _ofPartitionSize
);
803 IODelete(buffer
, UInt8
, _ofPartitionSize
);
805 if (!ok
) return kIOReturnBadArgument
;
807 if (_nvramController
!= 0) {
808 _nvramController
->write(0, _nvramImage
, kIODTNVRAMImageSize
);
811 return kIOReturnSuccess
;
815 const char *variableName
;
818 SInt32 variableOffset
;
820 typedef struct OFVariable OFVariable
;
823 kOWVariableOffsetNumber
= 8,
824 kOWVariableOffsetString
= 17
827 OFVariable gOFVariables
[] = {
828 {"little-endian?", kOFVariableTypeBoolean
, kOFVariablePermUserRead
, 0},
829 {"real-mode?", kOFVariableTypeBoolean
, kOFVariablePermUserRead
, 1},
830 {"auto-boot?", kOFVariableTypeBoolean
, kOFVariablePermUserRead
, 2},
831 {"diag-switch?", kOFVariableTypeBoolean
, kOFVariablePermUserRead
, 3},
832 {"fcode-debug?", kOFVariableTypeBoolean
, kOFVariablePermUserRead
, 4},
833 {"oem-banner?", kOFVariableTypeBoolean
, kOFVariablePermUserRead
, 5},
834 {"oem-logo?", kOFVariableTypeBoolean
, kOFVariablePermUserRead
, 6},
835 {"use-nvramrc?", kOFVariableTypeBoolean
, kOFVariablePermUserRead
, 7},
836 {"use-generic?", kOFVariableTypeBoolean
, kOFVariablePermUserRead
, -1},
837 {"default-mac-address?", kOFVariableTypeBoolean
, kOFVariablePermUserRead
,-1},
838 {"real-base", kOFVariableTypeNumber
, kOFVariablePermUserRead
, 8},
839 {"real-size", kOFVariableTypeNumber
, kOFVariablePermUserRead
, 9},
840 {"virt-base", kOFVariableTypeNumber
, kOFVariablePermUserRead
, 10},
841 {"virt-size", kOFVariableTypeNumber
, kOFVariablePermUserRead
, 11},
842 {"load-base", kOFVariableTypeNumber
, kOFVariablePermUserRead
, 12},
843 {"pci-probe-list", kOFVariableTypeNumber
, kOFVariablePermUserRead
, 13},
844 {"pci-probe-mask", kOFVariableTypeNumber
, kOFVariablePermUserRead
, -1},
845 {"screen-#columns", kOFVariableTypeNumber
, kOFVariablePermUserRead
, 14},
846 {"screen-#rows", kOFVariableTypeNumber
, kOFVariablePermUserRead
, 15},
847 {"selftest-#megs", kOFVariableTypeNumber
, kOFVariablePermUserRead
, 16},
848 {"boot-device", kOFVariableTypeString
, kOFVariablePermUserRead
, 17},
849 {"boot-file", kOFVariableTypeString
, kOFVariablePermUserRead
, 18},
850 {"boot-screen", kOFVariableTypeString
, kOFVariablePermUserRead
, -1},
851 {"console-screen", kOFVariableTypeString
, kOFVariablePermUserRead
, -1},
852 {"diag-device", kOFVariableTypeString
, kOFVariablePermUserRead
, 19},
853 {"diag-file", kOFVariableTypeString
, kOFVariablePermUserRead
, 20},
854 {"input-device", kOFVariableTypeString
, kOFVariablePermUserRead
, 21},
855 {"output-device", kOFVariableTypeString
, kOFVariablePermUserRead
, 22},
856 {"input-device-1", kOFVariableTypeString
, kOFVariablePermUserRead
, -1},
857 {"output-device-1", kOFVariableTypeString
, kOFVariablePermUserRead
, -1},
858 {"mouse-device", kOFVariableTypeString
, kOFVariablePermUserRead
, -1},
859 {"oem-banner", kOFVariableTypeString
, kOFVariablePermUserRead
, 23},
860 {"oem-logo", kOFVariableTypeString
, kOFVariablePermUserRead
, 24},
861 {"nvramrc", kOFVariableTypeString
, kOFVariablePermUserRead
, 25},
862 {"boot-command", kOFVariableTypeString
, kOFVariablePermUserRead
, 26},
863 {"default-client-ip", kOFVariableTypeString
, kOFVariablePermUserRead
, -1},
864 {"default-server-ip", kOFVariableTypeString
, kOFVariablePermUserRead
, -1},
865 {"default-gateway-ip", kOFVariableTypeString
, kOFVariablePermUserRead
, -1},
866 {"default-subnet-mask", kOFVariableTypeString
, kOFVariablePermUserRead
, -1},
867 {"default-router-ip", kOFVariableTypeString
, kOFVariablePermUserRead
, -1},
868 {"boot-script", kOFVariableTypeString
, kOFVariablePermUserRead
, -1},
869 {"boot-args", kOFVariableTypeString
, kOFVariablePermUserRead
, -1},
870 {"aapl,pci", kOFVariableTypeData
, kOFVariablePermRootOnly
, -1},
871 {"security-mode", kOFVariableTypeString
, kOFVariablePermUserRead
, -1},
872 {"security-password", kOFVariableTypeData
, kOFVariablePermRootOnly
, -1},
873 {"boot-image", kOFVariableTypeData
, kOFVariablePermUserWrite
, -1},
874 {"com.apple.System.fp-state", kOFVariableTypeData
, kOFVariablePermKernelOnly
, -1},
875 {0, kOFVariableTypeData
, kOFVariablePermUserRead
, -1}
878 UInt32
IODTNVRAM::getOFVariableType(const OSSymbol
*propSymbol
) const
882 ofVar
= gOFVariables
;
884 if ((ofVar
->variableName
== 0) ||
885 propSymbol
->isEqualTo(ofVar
->variableName
)) break;
889 return ofVar
->variableType
;
892 UInt32
IODTNVRAM::getOFVariablePerm(const OSSymbol
*propSymbol
) const
896 ofVar
= gOFVariables
;
898 if ((ofVar
->variableName
== 0) ||
899 propSymbol
->isEqualTo(ofVar
->variableName
)) break;
903 return ofVar
->variablePerm
;
906 bool IODTNVRAM::getOWVariableInfo(UInt32 variableNumber
, const OSSymbol
**propSymbol
,
907 UInt32
*propType
, UInt32
*propOffset
)
911 ofVar
= gOFVariables
;
913 if (ofVar
->variableName
== 0) return false;
915 if (ofVar
->variableOffset
== (SInt32
) variableNumber
) break;
920 *propSymbol
= OSSymbol::withCStringNoCopy(ofVar
->variableName
);
921 *propType
= ofVar
->variableType
;
924 case kOFVariableTypeBoolean
:
925 *propOffset
= 1 << (31 - variableNumber
);
928 case kOFVariableTypeNumber
:
929 *propOffset
= variableNumber
- kOWVariableOffsetNumber
;
932 case kOFVariableTypeString
:
933 *propOffset
= variableNumber
- kOWVariableOffsetString
;
940 bool IODTNVRAM::convertPropToObject(UInt8
*propName
, UInt32 propNameLength
,
941 UInt8
*propData
, UInt32 propDataLength
,
942 const OSSymbol
**propSymbol
,
943 OSObject
**propObject
)
946 const OSSymbol
*tmpSymbol
;
951 // Create the symbol.
952 propName
[propNameLength
] = '\0';
953 tmpSymbol
= OSSymbol::withCString((const char *)propName
);
954 propName
[propNameLength
] = '=';
955 if (tmpSymbol
== 0) {
959 propType
= getOFVariableType(tmpSymbol
);
961 // Create the object.
964 case kOFVariableTypeBoolean
:
965 if (!strncmp("true", (const char *)propData
, propDataLength
)) {
966 tmpObject
= kOSBooleanTrue
;
967 } else if (!strncmp("false", (const char *)propData
, propDataLength
)) {
968 tmpObject
= kOSBooleanFalse
;
972 case kOFVariableTypeNumber
:
973 tmpNumber
= OSNumber::withNumber(strtol((const char *)propData
, 0, 0), 32);
974 if (tmpNumber
!= 0) tmpObject
= tmpNumber
;
977 case kOFVariableTypeString
:
978 tmpString
= OSString::withCString((const char *)propData
);
979 if (tmpString
!= 0) tmpObject
= tmpString
;
982 case kOFVariableTypeData
:
983 tmpObject
= unescapeBytesToData(propData
, propDataLength
);
987 if (tmpObject
== 0) {
988 tmpSymbol
->release();
992 *propSymbol
= tmpSymbol
;
993 *propObject
= tmpObject
;
998 bool IODTNVRAM::convertObjectToProp(UInt8
*buffer
, UInt32
*length
,
999 const OSSymbol
*propSymbol
, OSObject
*propObject
)
1001 const UInt8
*propName
;
1002 UInt32 propNameLength
, propDataLength
;
1003 UInt32 propType
, tmpValue
;
1004 OSBoolean
*tmpBoolean
= 0;
1005 OSNumber
*tmpNumber
= 0;
1006 OSString
*tmpString
= 0;
1007 OSData
*tmpData
= 0;
1009 propName
= (const UInt8
*)propSymbol
->getCStringNoCopy();
1010 propNameLength
= propSymbol
->getLength();
1011 propType
= getOFVariableType(propSymbol
);
1013 // Get the size of the data.
1014 propDataLength
= 0xFFFFFFFF;
1016 case kOFVariableTypeBoolean
:
1017 tmpBoolean
= OSDynamicCast(OSBoolean
, propObject
);
1018 if (tmpBoolean
!= 0) propDataLength
= 5;
1021 case kOFVariableTypeNumber
:
1022 tmpNumber
= OSDynamicCast(OSNumber
, propObject
);
1023 if (tmpNumber
!= 0) propDataLength
= 10;
1026 case kOFVariableTypeString
:
1027 tmpString
= OSDynamicCast(OSString
, propObject
);
1028 if (tmpString
!= 0) propDataLength
= tmpString
->getLength();
1031 case kOFVariableTypeData
:
1032 tmpData
= OSDynamicCast(OSData
, propObject
);
1034 tmpData
= escapeDataToData(tmpData
);
1035 propDataLength
= tmpData
->getLength();
1040 // Make sure the propertySize is known and will fit.
1041 if (propDataLength
== 0xFFFFFFFF) return false;
1042 if ((propNameLength
+ propDataLength
+ 2) > *length
) return false;
1044 // Copy the property name equal sign.
1045 buffer
+= snprintf((char *)buffer
, *length
, "%s=", propName
);
1048 case kOFVariableTypeBoolean
:
1049 if (tmpBoolean
->getValue()) {
1050 strlcpy((char *)buffer
, "true", *length
- propNameLength
);
1052 strlcpy((char *)buffer
, "false", *length
- propNameLength
);
1056 case kOFVariableTypeNumber
:
1057 tmpValue
= tmpNumber
->unsigned32BitValue();
1058 if (tmpValue
== 0xFFFFFFFF) {
1059 strlcpy((char *)buffer
, "-1", *length
- propNameLength
);
1060 } else if (tmpValue
< 1000) {
1061 snprintf((char *)buffer
, *length
- propNameLength
, "%d", (uint32_t)tmpValue
);
1063 snprintf((char *)buffer
, *length
- propNameLength
, "0x%x", (uint32_t)tmpValue
);
1067 case kOFVariableTypeString
:
1068 strlcpy((char *)buffer
, tmpString
->getCStringNoCopy(), *length
- propNameLength
);
1071 case kOFVariableTypeData
:
1072 bcopy(tmpData
->getBytesNoCopy(), buffer
, propDataLength
);
1077 propDataLength
= strlen((const char *)buffer
);
1079 *length
= propNameLength
+ propDataLength
+ 2;
1085 UInt16
IODTNVRAM::generateOWChecksum(UInt8
*buffer
)
1087 UInt32 cnt
, checksum
= 0;
1088 UInt16
*tmpBuffer
= (UInt16
*)buffer
;
1090 for (cnt
= 0; cnt
< _ofPartitionSize
/ 2; cnt
++)
1091 checksum
+= tmpBuffer
[cnt
];
1093 return checksum
% 0x0000FFFF;
1096 bool IODTNVRAM::validateOWChecksum(UInt8
*buffer
)
1098 UInt32 cnt
, checksum
, sum
= 0;
1099 UInt16
*tmpBuffer
= (UInt16
*)buffer
;
1101 for (cnt
= 0; cnt
< _ofPartitionSize
/ 2; cnt
++)
1102 sum
+= tmpBuffer
[cnt
];
1104 checksum
= (sum
>> 16) + (sum
& 0x0000FFFF);
1105 if (checksum
== 0x10000) checksum
--;
1106 checksum
= (checksum
^ 0x0000FFFF) & 0x0000FFFF;
1108 return checksum
== 0;
1111 void IODTNVRAM::updateOWBootArgs(const OSSymbol
*key
, OSObject
*value
)
1113 bool wasBootArgs
, bootr
= false;
1115 OSString
*tmpString
, *bootCommand
, *bootArgs
= 0;
1116 const UInt8
*bootCommandData
, *bootArgsData
;
1118 UInt32 bootCommandDataLength
, bootArgsDataLength
, tmpDataLength
;
1120 tmpString
= OSDynamicCast(OSString
, value
);
1121 if (tmpString
== 0) return;
1123 if (key
->isEqualTo("boot-command")) {
1124 wasBootArgs
= false;
1125 bootCommand
= tmpString
;
1126 } else if (key
->isEqualTo("boot-args")) {
1128 bootArgs
= tmpString
;
1129 bootCommand
= OSDynamicCast(OSString
, _ofDict
->getObject("boot-command"));
1130 if (bootCommand
== 0) return;
1133 bootCommandData
= (const UInt8
*)bootCommand
->getCStringNoCopy();
1134 bootCommandDataLength
= bootCommand
->getLength();
1136 if (bootCommandData
== 0) return;
1138 for (cnt
= 0; cnt
< bootCommandDataLength
; cnt
++) {
1139 if ((bootCommandData
[cnt
] == 'b') &&
1140 !strncmp("bootr", (const char *)bootCommandData
+ cnt
, 5)) {
1142 while (bootCommandData
[cnt
] == ' ') cnt
++;
1148 _ofDict
->removeObject("boot-args");
1153 bootArgsData
= (const UInt8
*)bootArgs
->getCStringNoCopy();
1154 bootArgsDataLength
= bootArgs
->getLength();
1155 if (bootArgsData
== 0) return;
1157 tmpDataLength
= cnt
+ bootArgsDataLength
;
1158 tmpData
= IONew(UInt8
, tmpDataLength
+ 1);
1159 if (tmpData
== 0) return;
1161 cnt
-= strlcpy((char *)tmpData
, (const char *)bootCommandData
, cnt
);
1162 strlcat((char *)tmpData
, (const char *)bootArgsData
, cnt
);
1164 bootCommand
= OSString::withCString((const char *)tmpData
);
1165 if (bootCommand
!= 0) {
1166 _ofDict
->setObject("boot-command", bootCommand
);
1167 bootCommand
->release();
1170 IODelete(tmpData
, UInt8
, tmpDataLength
+ 1);
1172 bootArgs
= OSString::withCString((const char *)(bootCommandData
+ cnt
));
1173 if (bootArgs
!= 0) {
1174 _ofDict
->setObject("boot-args", bootArgs
);
1175 bootArgs
->release();
1180 bool IODTNVRAM::searchNVRAMProperty(IONVRAMDescriptor
*hdr
, UInt32
*where
)
1185 IOReturn
IODTNVRAM::readNVRAMPropertyType0(IORegistryEntry
*entry
,
1186 const OSSymbol
**name
,
1189 return kIOReturnUnsupported
;
1193 IOReturn
IODTNVRAM::writeNVRAMPropertyType0(IORegistryEntry
*entry
,
1194 const OSSymbol
*name
,
1197 return kIOReturnUnsupported
;
1201 OSData
*IODTNVRAM::unescapeBytesToData(const UInt8
*bytes
, UInt32 length
)
1204 UInt32 totalLength
= 0;
1209 // Calculate the actual length of the data.
1212 for (cnt
= 0; cnt
< length
;) {
1213 byte
= bytes
[cnt
++];
1215 byte
= bytes
[cnt
++];
1223 totalLength
+= cnt2
;
1227 // Create an empty OSData of the correct size.
1228 data
= OSData::withCapacity(totalLength
);
1230 for (cnt
= 0; cnt
< length
;) {
1231 byte
= bytes
[cnt
++];
1233 byte
= bytes
[cnt
++];
1235 byte
= (byte
& 0x80) ? 0xFF : 0x00;
1238 data
->appendByte(byte
, cnt2
);
1246 OSData
* IODTNVRAM::escapeDataToData(OSData
* value
)
1249 const UInt8
* startPtr
;
1250 const UInt8
* endPtr
;
1251 const UInt8
* wherePtr
;
1255 wherePtr
= (const UInt8
*) value
->getBytesNoCopy();
1256 endPtr
= wherePtr
+ value
->getLength();
1258 result
= OSData::withCapacity(endPtr
- wherePtr
);
1262 while (wherePtr
< endPtr
) {
1263 startPtr
= wherePtr
;
1265 if ((byte
== 0x00) || (byte
== 0xFF)) {
1267 ((wherePtr
- startPtr
) < 0x80) && (wherePtr
< endPtr
) && (byte
== *wherePtr
);
1269 ok
&= result
->appendByte(0xff, 1);
1270 byte
= (byte
& 0x80) | (wherePtr
- startPtr
);
1272 ok
&= result
->appendByte(byte
, 1);
1274 ok
&= result
->appendByte(0, 1);
1284 static bool IsApplePropertyName(const char * propName
)
1287 while ((c
= *propName
++)) {
1288 if ((c
>= 'A') && (c
<= 'Z'))
1295 IOReturn
IODTNVRAM::readNVRAMPropertyType1(IORegistryEntry
*entry
,
1296 const OSSymbol
**name
,
1299 IOReturn err
= kIOReturnNoResources
;
1301 const UInt8
*startPtr
;
1302 const UInt8
*endPtr
;
1303 const UInt8
*wherePtr
;
1304 const UInt8
*nvPath
= 0;
1305 const char *nvName
= 0;
1306 const char *resultName
= 0;
1307 const UInt8
*resultValue
= 0;
1308 UInt32 resultValueLen
= 0;
1311 if (_ofDict
== 0) return err
;
1313 IOLockLock(_ofLock
);
1314 data
= OSDynamicCast(OSData
, _ofDict
->getObject(_registryPropertiesKey
));
1315 IOLockUnlock(_ofLock
);
1317 if (data
== 0) return err
;
1319 startPtr
= (const UInt8
*) data
->getBytesNoCopy();
1320 endPtr
= startPtr
+ data
->getLength();
1322 wherePtr
= startPtr
;
1323 while (wherePtr
< endPtr
) {
1324 byte
= *(wherePtr
++);
1330 else if (nvName
== 0)
1331 nvName
= (const char *) startPtr
;
1333 IORegistryEntry
* compareEntry
= IORegistryEntry::fromPath((const char *) nvPath
, gIODTPlane
);
1335 compareEntry
->release();
1336 if (entry
== compareEntry
) {
1337 bool appleProp
= IsApplePropertyName(nvName
);
1338 if (!appleProp
|| !resultName
) {
1339 resultName
= nvName
;
1340 resultValue
= startPtr
;
1341 resultValueLen
= wherePtr
- startPtr
- 1;
1349 startPtr
= wherePtr
;
1352 *name
= OSSymbol::withCString(resultName
);
1353 *value
= unescapeBytesToData(resultValue
, resultValueLen
);
1354 if ((*name
!= 0) && (*value
!= 0))
1355 err
= kIOReturnSuccess
;
1357 err
= kIOReturnNoMemory
;
1362 IOReturn
IODTNVRAM::writeNVRAMPropertyType1(IORegistryEntry
*entry
,
1363 const OSSymbol
*propName
,
1368 const UInt8
*startPtr
;
1369 const UInt8
*propStart
;
1370 const UInt8
*endPtr
;
1371 const UInt8
*wherePtr
;
1372 const UInt8
*nvPath
= 0;
1373 const char *nvName
= 0;
1378 bool settingAppleProp
;
1380 if (_ofDict
== 0) return kIOReturnNoResources
;
1382 settingAppleProp
= IsApplePropertyName(propName
->getCStringNoCopy());
1384 // copy over existing properties for other entries
1386 IOLockLock(_ofLock
);
1388 oldData
= OSDynamicCast(OSData
, _ofDict
->getObject(_registryPropertiesKey
));
1390 startPtr
= (const UInt8
*) oldData
->getBytesNoCopy();
1391 endPtr
= startPtr
+ oldData
->getLength();
1393 propStart
= startPtr
;
1394 wherePtr
= startPtr
;
1395 while (wherePtr
< endPtr
) {
1396 byte
= *(wherePtr
++);
1401 else if (nvName
== 0)
1402 nvName
= (const char *) startPtr
;
1404 IORegistryEntry
* compareEntry
= IORegistryEntry::fromPath((const char *) nvPath
, gIODTPlane
);
1406 compareEntry
->release();
1407 if (entry
== compareEntry
) {
1408 if ((settingAppleProp
&& propName
->isEqualTo(nvName
))
1409 || (!settingAppleProp
&& !IsApplePropertyName(nvName
))) {
1410 // delete old property (nvPath -> wherePtr)
1411 data
= OSData::withBytes(propStart
, nvPath
- propStart
);
1413 ok
&= data
->appendBytes(wherePtr
, endPtr
- wherePtr
);
1421 startPtr
= wherePtr
;
1425 // make the new property
1429 data
= OSData::withData(oldData
);
1431 data
= OSData::withCapacity(16);
1432 if (!data
) ok
= false;
1435 if (ok
&& value
&& value
->getLength()) do {
1436 // get entries in path
1437 OSArray
*array
= OSArray::withCapacity(5);
1443 array
->setObject(entry
);
1444 while ((entry
= entry
->getParentEntry(gIODTPlane
)));
1447 for (int i
= array
->getCount() - 3;
1448 (entry
= (IORegistryEntry
*) array
->getObject(i
));
1451 name
= entry
->getName(gIODTPlane
);
1452 comp
= entry
->getLocation(gIODTPlane
);
1453 if (comp
) ok
&= data
->appendBytes("/@", 2);
1455 if (!name
) continue;
1456 ok
&= data
->appendByte('/', 1);
1459 ok
&= data
->appendBytes(comp
, strlen(comp
));
1461 ok
&= data
->appendByte(0, 1);
1465 ok
&= data
->appendBytes(propName
->getCStringNoCopy(), propName
->getLength() + 1);
1467 // append escaped data
1468 oldData
= escapeDataToData(value
);
1469 ok
&= (oldData
!= 0);
1470 if (ok
) ok
&= data
->appendBytes(oldData
);
1475 ok
= _ofDict
->setObject(_registryPropertiesKey
, data
);
1478 IOLockUnlock(_ofLock
);
1479 if (data
) data
->release();
1481 if (ok
) syncOFVariables();
1483 return ok
? kIOReturnSuccess
: kIOReturnNoMemory
;
1486 bool IODTNVRAM::safeToSync(void)
1492 // delta interval went by
1493 clock_get_uptime(&delta
);
1495 // Figure it in seconds.
1496 absolutetime_to_nanoseconds(delta
, &delta_ns
);
1497 delta_secs
= (SInt32
)(delta_ns
/ NSEC_PER_SEC
);
1499 if ((delta_secs
> (_lastDeviceSync
+ MIN_SYNC_NOW_INTERVAL
)) || _freshInterval
)
1501 _lastDeviceSync
= delta_secs
;
1502 _freshInterval
= FALSE
;