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 <kern/debug.h>
36 #include <pexpert/pexpert.h>
38 #define super IOService
40 #define kIONVRAMPrivilege kIOClientPrivilegeAdministrator
41 //#define kIONVRAMPrivilege kIOClientPrivilegeLocalUser
43 OSDefineMetaClassAndStructors(IODTNVRAM
, IOService
);
45 bool IODTNVRAM::init(IORegistryEntry
*old
, const IORegistryPlane
*plane
)
49 if (!super::init(old
, plane
)) return false;
51 dict
= OSDictionary::withCapacity(1);
52 if (dict
== 0) return false;
53 setPropertyTable(dict
);
55 _nvramImage
= IONew(UInt8
, kIODTNVRAMImageSize
);
56 if (_nvramImage
== 0) return false;
58 _nvramPartitionOffsets
= OSDictionary::withCapacity(1);
59 if (_nvramPartitionOffsets
== 0) return false;
61 _nvramPartitionLengths
= OSDictionary::withCapacity(1);
62 if (_nvramPartitionLengths
== 0) return false;
64 _registryPropertiesKey
= OSSymbol::withCStringNoCopy("aapl,pci");
65 if (_registryPropertiesKey
== 0) return false;
67 // <rdar://problem/9529235> race condition possible between
68 // IODTNVRAM and IONVRAMController (restore loses boot-args)
74 void IODTNVRAM::initProxyData(void)
76 IORegistryEntry
*entry
;
77 const char *key
= "nvram-proxy-data";
82 entry
= IORegistryEntry::fromPath("/chosen", gIODTPlane
);
84 prop
= entry
->getProperty(key
);
86 data
= OSDynamicCast(OSData
, prop
);
88 bytes
= data
->getBytesNoCopy();
90 bcopy(bytes
, _nvramImage
, data
->getLength());
96 entry
->removeProperty(key
);
101 void IODTNVRAM::registerNVRAMController(IONVRAMController
*nvram
)
103 if (_nvramController
!= 0) return;
105 _nvramController
= nvram
;
107 // <rdar://problem/9529235> race condition possible between
108 // IODTNVRAM and IONVRAMController (restore loses boot-args)
110 _nvramController
->read(0, _nvramImage
, kIODTNVRAMImageSize
);
115 void IODTNVRAM::initNVRAMImage(void)
117 char partitionID
[18];
118 UInt32 partitionOffset
, partitionLength
;
119 UInt32 freePartitionOffset
, freePartitionSize
;
120 UInt32 currentLength
, currentOffset
= 0;
121 OSNumber
*partitionOffsetNumber
, *partitionLengthNumber
;
123 // Find the offsets for the OF, XPRAM, NameRegistry and PanicInfo partitions.
124 _ofPartitionOffset
= 0xFFFFFFFF;
125 _piPartitionOffset
= 0xFFFFFFFF;
126 freePartitionOffset
= 0xFFFFFFFF;
127 freePartitionSize
= 0;
129 // Look through the partitions to find the OF, MacOS partitions.
130 while (currentOffset
< kIODTNVRAMImageSize
) {
131 currentLength
= ((UInt16
*)(_nvramImage
+ currentOffset
))[1] * 16;
133 partitionOffset
= currentOffset
+ 16;
134 partitionLength
= currentLength
- 16;
136 if (strncmp((const char *)_nvramImage
+ currentOffset
+ 4,
137 kIODTNVRAMOFPartitionName
, 12) == 0) {
138 _ofPartitionOffset
= partitionOffset
;
139 _ofPartitionSize
= partitionLength
;
140 } else if (strncmp((const char *)_nvramImage
+ currentOffset
+ 4,
141 kIODTNVRAMXPRAMPartitionName
, 12) == 0) {
142 } else if (strncmp((const char *)_nvramImage
+ currentOffset
+ 4,
143 kIODTNVRAMPanicInfoPartitonName
, 12) == 0) {
144 _piPartitionOffset
= partitionOffset
;
145 _piPartitionSize
= partitionLength
;
146 } else if (strncmp((const char *)_nvramImage
+ currentOffset
+ 4,
147 kIODTNVRAMFreePartitionName
, 12) == 0) {
148 freePartitionOffset
= currentOffset
;
149 freePartitionSize
= currentLength
;
151 // Construct the partition ID from the signature and name.
152 snprintf(partitionID
, sizeof(partitionID
), "0x%02x,",
153 *(UInt8
*)(_nvramImage
+ currentOffset
));
154 strncpy(partitionID
+ 5,
155 (const char *)(_nvramImage
+ currentOffset
+ 4), 12);
156 partitionID
[17] = '\0';
158 partitionOffsetNumber
= OSNumber::withNumber(partitionOffset
, 32);
159 partitionLengthNumber
= OSNumber::withNumber(partitionLength
, 32);
161 // Save the partition offset and length
162 _nvramPartitionOffsets
->setObject(partitionID
, partitionOffsetNumber
);
163 _nvramPartitionLengths
->setObject(partitionID
, partitionLengthNumber
);
165 partitionOffsetNumber
->release();
166 partitionLengthNumber
->release();
168 currentOffset
+= currentLength
;
171 if (_ofPartitionOffset
!= 0xFFFFFFFF)
172 _ofImage
= _nvramImage
+ _ofPartitionOffset
;
174 if (_piPartitionOffset
== 0xFFFFFFFF) {
175 if (freePartitionSize
> 0x20) {
176 // Set the signature to 0xa1.
177 _nvramImage
[freePartitionOffset
] = 0xa1;
178 // Set the checksum to 0.
179 _nvramImage
[freePartitionOffset
+ 1] = 0;
180 // Set the name for the Panic Info partition.
181 strncpy((char *)(_nvramImage
+ freePartitionOffset
+ 4),
182 kIODTNVRAMPanicInfoPartitonName
, 12);
184 // Calculate the partition offset and size.
185 _piPartitionOffset
= freePartitionOffset
+ 0x10;
186 _piPartitionSize
= 0x800;
187 if (_piPartitionSize
+ 0x20 > freePartitionSize
)
188 _piPartitionSize
= freePartitionSize
- 0x20;
190 _piImage
= _nvramImage
+ _piPartitionOffset
;
192 // Zero the new partition.
193 bzero(_piImage
, _piPartitionSize
);
195 // Set the partition size.
196 *(UInt16
*)(_nvramImage
+ freePartitionOffset
+ 2) =
197 (_piPartitionSize
/ 0x10) + 1;
199 // Set the partition checksum.
200 _nvramImage
[freePartitionOffset
+ 1] =
201 calculatePartitionChecksum(_nvramImage
+ freePartitionOffset
);
203 // Calculate the free partition offset and size.
204 freePartitionOffset
+= _piPartitionSize
+ 0x10;
205 freePartitionSize
-= _piPartitionSize
+ 0x10;
207 // Set the signature to 0x7f.
208 _nvramImage
[freePartitionOffset
] = 0x7f;
209 // Set the checksum to 0.
210 _nvramImage
[freePartitionOffset
+ 1] = 0;
211 // Set the name for the free partition.
212 strncpy((char *)(_nvramImage
+ freePartitionOffset
+ 4),
213 kIODTNVRAMFreePartitionName
, 12);
214 // Set the partition size.
215 *(UInt16
*)(_nvramImage
+ freePartitionOffset
+ 2) =
216 freePartitionSize
/ 0x10;
217 // Set the partition checksum.
218 _nvramImage
[freePartitionOffset
+ 1] =
219 calculatePartitionChecksum(_nvramImage
+ freePartitionOffset
);
221 // Set the nvram image as dirty.
222 _nvramImageDirty
= true;
225 _piImage
= _nvramImage
+ _piPartitionOffset
;
229 _freshInterval
= TRUE
; // we will allow sync() even before the first 15 minutes have passed.
234 void IODTNVRAM::sync(void)
236 if (!_nvramImageDirty
&& !_ofImageDirty
) return;
238 // Don't try to sync OF Variables if the system has already paniced.
239 if (!_systemPaniced
) syncOFVariables();
241 // Don't try to perform controller operations if none has been registered.
242 if (_nvramController
== 0) return;
244 _nvramController
->write(0, _nvramImage
, kIODTNVRAMImageSize
);
245 _nvramController
->sync();
247 _nvramImageDirty
= false;
250 bool IODTNVRAM::serializeProperties(OSSerialize
*s
) const
252 bool result
, hasPrivilege
;
256 OSCollectionIterator
*iter
= 0;
258 // Verify permissions.
259 hasPrivilege
= (kIOReturnSuccess
== IOUserClient::clientHasPrivilege(current_task(), kIONVRAMPrivilege
));
262 /* No nvram. Return an empty dictionary. */
263 dict
= OSDictionary::withCapacity(1);
264 if (dict
== 0) return false;
267 dict
= OSDictionary::withDictionary(_ofDict
);
268 IOLockUnlock(_ofLock
);
269 if (dict
== 0) return false;
271 /* Copy properties with client privilege. */
272 iter
= OSCollectionIterator::withCollection(dict
);
278 key
= OSDynamicCast(OSSymbol
, iter
->getNextObject());
281 variablePerm
= getOFVariablePerm(key
);
282 if ((hasPrivilege
|| (variablePerm
!= kOFVariablePermRootOnly
)) &&
283 ( ! (variablePerm
== kOFVariablePermKernelOnly
&& current_task() != kernel_task
) )) {}
284 else dict
->removeObject(key
);
288 result
= dict
->serialize(s
);
291 if (iter
!= 0) iter
->release();
296 OSObject
*IODTNVRAM::copyProperty(const OSSymbol
*aKey
) const
302 if (_ofDict
== 0) return 0;
304 // Verify permissions.
305 variablePerm
= getOFVariablePerm(aKey
);
306 result
= IOUserClient::clientHasPrivilege(current_task(), kIONVRAMPrivilege
);
307 if (result
!= kIOReturnSuccess
) {
308 if (variablePerm
== kOFVariablePermRootOnly
) return 0;
310 if (variablePerm
== kOFVariablePermKernelOnly
&& current_task() != kernel_task
) return 0;
313 theObject
= _ofDict
->getObject(aKey
);
314 if (theObject
) theObject
->retain();
315 IOLockUnlock(_ofLock
);
320 OSObject
*IODTNVRAM::copyProperty(const char *aKey
) const
322 const OSSymbol
*keySymbol
;
323 OSObject
*theObject
= 0;
325 keySymbol
= OSSymbol::withCString(aKey
);
326 if (keySymbol
!= 0) {
327 theObject
= copyProperty(keySymbol
);
328 keySymbol
->release();
334 OSObject
*IODTNVRAM::getProperty(const OSSymbol
*aKey
) const
338 theObject
= copyProperty(aKey
);
339 if (theObject
) theObject
->release();
344 OSObject
*IODTNVRAM::getProperty(const char *aKey
) const
348 theObject
= copyProperty(aKey
);
349 if (theObject
) theObject
->release();
354 bool IODTNVRAM::setProperty(const OSSymbol
*aKey
, OSObject
*anObject
)
357 UInt32 propType
, propPerm
;
359 OSObject
*propObject
= 0;
361 if (_ofDict
== 0) return false;
363 // Verify permissions.
364 propPerm
= getOFVariablePerm(aKey
);
365 result
= IOUserClient::clientHasPrivilege(current_task(), kIONVRAMPrivilege
);
366 if (result
!= kIOReturnSuccess
) {
367 if (propPerm
!= kOFVariablePermUserWrite
) return false;
369 if (propPerm
== kOFVariablePermKernelOnly
&& current_task() != kernel_task
) return 0;
371 // Don't allow change of 'aapl,panic-info'.
372 if (aKey
->isEqualTo(kIODTNVRAMPanicInfoKey
)) return false;
374 // Make sure the object is of the correct type.
375 propType
= getOFVariableType(aKey
);
377 case kOFVariableTypeBoolean
:
378 propObject
= OSDynamicCast(OSBoolean
, anObject
);
381 case kOFVariableTypeNumber
:
382 propObject
= OSDynamicCast(OSNumber
, anObject
);
385 case kOFVariableTypeString
:
386 propObject
= OSDynamicCast(OSString
, anObject
);
389 case kOFVariableTypeData
:
390 propObject
= OSDynamicCast(OSData
, anObject
);
391 if (propObject
== 0) {
392 tmpString
= OSDynamicCast(OSString
, anObject
);
393 if (tmpString
!= 0) {
394 propObject
= OSData::withBytes(tmpString
->getCStringNoCopy(),
395 tmpString
->getLength());
401 if (propObject
== 0) return false;
404 result
= _ofDict
->setObject(aKey
, propObject
);
405 IOLockUnlock(_ofLock
);
408 _ofImageDirty
= true;
414 void IODTNVRAM::removeProperty(const OSSymbol
*aKey
)
419 if (_ofDict
== 0) return;
421 // Verify permissions.
422 propPerm
= getOFVariablePerm(aKey
);
423 result
= IOUserClient::clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator
);
424 if (result
!= kIOReturnSuccess
) {
425 if (propPerm
!= kOFVariablePermUserWrite
) return;
427 if (propPerm
== kOFVariablePermKernelOnly
&& current_task() != kernel_task
) return;
429 // Don't allow change of 'aapl,panic-info'.
430 if (aKey
->isEqualTo(kIODTNVRAMPanicInfoKey
)) return;
432 // If the object exists, remove it from the dictionary.
435 result
= _ofDict
->getObject(aKey
) != 0;
437 _ofDict
->removeObject(aKey
);
438 _ofImageDirty
= true;
440 IOLockUnlock(_ofLock
);
443 IOReturn
IODTNVRAM::setProperties(OSObject
*properties
)
448 const OSString
*tmpStr
;
450 OSCollectionIterator
*iter
;
452 dict
= OSDynamicCast(OSDictionary
, properties
);
453 if (dict
== 0) return kIOReturnBadArgument
;
455 iter
= OSCollectionIterator::withCollection(dict
);
456 if (iter
== 0) return kIOReturnBadArgument
;
459 key
= OSDynamicCast(OSSymbol
, iter
->getNextObject());
462 object
= dict
->getObject(key
);
463 if (object
== 0) continue;
465 if (key
->isEqualTo(kIONVRAMDeletePropertyKey
)) {
466 tmpStr
= OSDynamicCast(OSString
, object
);
468 key
= OSSymbol::withString(tmpStr
);
475 } else if(key
->isEqualTo(kIONVRAMSyncNowPropertyKey
)) {
476 tmpStr
= OSDynamicCast(OSString
, object
);
479 result
= true; // We are not going to gaurantee sync, this is best effort
489 result
= setProperty(key
, object
);
496 if (result
) return kIOReturnSuccess
;
497 else return kIOReturnError
;
500 IOReturn
IODTNVRAM::readXPRAM(IOByteCount offset
, UInt8
*buffer
,
503 return kIOReturnUnsupported
;
506 IOReturn
IODTNVRAM::writeXPRAM(IOByteCount offset
, UInt8
*buffer
,
509 return kIOReturnUnsupported
;
512 IOReturn
IODTNVRAM::readNVRAMProperty(IORegistryEntry
*entry
,
513 const OSSymbol
**name
,
518 err
= readNVRAMPropertyType1(entry
, name
, value
);
523 IOReturn
IODTNVRAM::writeNVRAMProperty(IORegistryEntry
*entry
,
524 const OSSymbol
*name
,
529 err
= writeNVRAMPropertyType1(entry
, name
, value
);
534 OSDictionary
*IODTNVRAM::getNVRAMPartitions(void)
536 return _nvramPartitionLengths
;
539 IOReturn
IODTNVRAM::readNVRAMPartition(const OSSymbol
*partitionID
,
540 IOByteCount offset
, UInt8
*buffer
,
543 OSNumber
*partitionOffsetNumber
, *partitionLengthNumber
;
544 UInt32 partitionOffset
, partitionLength
;
546 partitionOffsetNumber
=
547 (OSNumber
*)_nvramPartitionOffsets
->getObject(partitionID
);
548 partitionLengthNumber
=
549 (OSNumber
*)_nvramPartitionLengths
->getObject(partitionID
);
551 if ((partitionOffsetNumber
== 0) || (partitionLengthNumber
== 0))
552 return kIOReturnNotFound
;
554 partitionOffset
= partitionOffsetNumber
->unsigned32BitValue();
555 partitionLength
= partitionLengthNumber
->unsigned32BitValue();
557 if ((buffer
== 0) || (length
== 0) ||
558 (offset
+ length
> partitionLength
))
559 return kIOReturnBadArgument
;
561 bcopy(_nvramImage
+ partitionOffset
+ offset
, buffer
, length
);
563 return kIOReturnSuccess
;
566 IOReturn
IODTNVRAM::writeNVRAMPartition(const OSSymbol
*partitionID
,
567 IOByteCount offset
, UInt8
*buffer
,
570 OSNumber
*partitionOffsetNumber
, *partitionLengthNumber
;
571 UInt32 partitionOffset
, partitionLength
;
573 partitionOffsetNumber
=
574 (OSNumber
*)_nvramPartitionOffsets
->getObject(partitionID
);
575 partitionLengthNumber
=
576 (OSNumber
*)_nvramPartitionLengths
->getObject(partitionID
);
578 if ((partitionOffsetNumber
== 0) || (partitionLengthNumber
== 0))
579 return kIOReturnNotFound
;
581 partitionOffset
= partitionOffsetNumber
->unsigned32BitValue();
582 partitionLength
= partitionLengthNumber
->unsigned32BitValue();
584 if ((buffer
== 0) || (length
== 0) ||
585 (offset
+ length
> partitionLength
))
586 return kIOReturnBadArgument
;
588 bcopy(buffer
, _nvramImage
+ partitionOffset
+ offset
, length
);
590 _nvramImageDirty
= true;
592 return kIOReturnSuccess
;
595 IOByteCount
IODTNVRAM::savePanicInfo(UInt8
*buffer
, IOByteCount length
)
597 if ((_piImage
== 0) || (length
<= 0)) return 0;
599 if (length
> (_piPartitionSize
- 4))
600 length
= _piPartitionSize
- 4;
602 // Save the Panic Info.
603 bcopy(buffer
, _piImage
+ 4, length
);
605 // Save the Panic Info length.
606 *(UInt32
*)_piImage
= length
;
608 _nvramImageDirty
= true;
610 * This prevents OF variables from being committed if the system has panicked
612 _systemPaniced
= true;
613 /* The call to sync() forces the NVRAM controller to write the panic info
614 * partition to NVRAM.
623 UInt8
IODTNVRAM::calculatePartitionChecksum(UInt8
*partitionHeader
)
625 UInt8 cnt
, isum
, csum
= 0;
627 for (cnt
= 0; cnt
< 0x10; cnt
++) {
628 isum
= csum
+ partitionHeader
[cnt
];
629 if (isum
< csum
) isum
++;
636 IOReturn
IODTNVRAM::initOFVariables(void)
639 UInt8
*propName
, *propData
;
640 UInt32 propNameLength
, propDataLength
;
641 const OSSymbol
*propSymbol
;
642 OSObject
*propObject
;
644 if (_ofImage
== 0) return kIOReturnNotReady
;
646 _ofDict
= OSDictionary::withCapacity(1);
647 _ofLock
= IOLockAlloc();
648 if (!_ofDict
|| !_ofLock
) return kIOReturnNoMemory
;
651 while (cnt
< _ofPartitionSize
) {
652 // Break if there is no name.
653 if (_ofImage
[cnt
] == '\0') break;
655 // Find the length of the name.
656 propName
= _ofImage
+ cnt
;
657 for (propNameLength
= 0; (cnt
+ propNameLength
) < _ofPartitionSize
;
659 if (_ofImage
[cnt
+ propNameLength
] == '=') break;
662 // Break if the name goes past the end of the partition.
663 if ((cnt
+ propNameLength
) >= _ofPartitionSize
) break;
664 cnt
+= propNameLength
+ 1;
666 propData
= _ofImage
+ cnt
;
667 for (propDataLength
= 0; (cnt
+ propDataLength
) < _ofPartitionSize
;
669 if (_ofImage
[cnt
+ propDataLength
] == '\0') break;
672 // Break if the data goes past the end of the partition.
673 if ((cnt
+ propDataLength
) >= _ofPartitionSize
) break;
674 cnt
+= propDataLength
+ 1;
676 if (convertPropToObject(propName
, propNameLength
,
677 propData
, propDataLength
,
678 &propSymbol
, &propObject
)) {
679 _ofDict
->setObject(propSymbol
, propObject
);
680 propSymbol
->release();
681 propObject
->release();
685 // Create the boot-args property if it is not in the dictionary.
686 if (_ofDict
->getObject("boot-args") == 0) {
687 propObject
= OSString::withCStringNoCopy("");
688 if (propObject
!= 0) {
689 _ofDict
->setObject("boot-args", propObject
);
690 propObject
->release();
694 // Create the 'aapl,panic-info' property if needed.
696 propDataLength
= *(UInt32
*)_piImage
;
697 if ((propDataLength
!= 0) && (propDataLength
<= (_piPartitionSize
- 4))) {
698 propObject
= OSData::withBytes(_piImage
+ 4, propDataLength
);
699 _ofDict
->setObject(kIODTNVRAMPanicInfoKey
, propObject
);
700 propObject
->release();
702 // Clear the length from _piImage and mark dirty.
703 *(UInt32
*)_piImage
= 0;
704 _nvramImageDirty
= true;
708 return kIOReturnSuccess
;
711 IOReturn
IODTNVRAM::syncOFVariables(void)
714 UInt32 length
, maxLength
;
715 UInt8
*buffer
, *tmpBuffer
;
716 const OSSymbol
*tmpSymbol
;
718 OSCollectionIterator
*iter
;
720 if ((_ofImage
== 0) || (_ofDict
== 0)) return kIOReturnNotReady
;
722 if (!_ofImageDirty
) return kIOReturnSuccess
;
724 buffer
= tmpBuffer
= IONew(UInt8
, _ofPartitionSize
);
725 if (buffer
== 0) return kIOReturnNoMemory
;
726 bzero(buffer
, _ofPartitionSize
);
729 maxLength
= _ofPartitionSize
;
732 iter
= OSCollectionIterator::withCollection(_ofDict
);
733 if (iter
== 0) ok
= false;
736 tmpSymbol
= OSDynamicCast(OSSymbol
, iter
->getNextObject());
737 if (tmpSymbol
== 0) break;
739 // Don't save 'aapl,panic-info'.
740 if (tmpSymbol
->isEqualTo(kIODTNVRAMPanicInfoKey
)) continue;
742 tmpObject
= _ofDict
->getObject(tmpSymbol
);
745 ok
= convertObjectToProp(tmpBuffer
, &length
, tmpSymbol
, tmpObject
);
752 IOLockUnlock(_ofLock
);
755 bcopy(buffer
, _ofImage
, _ofPartitionSize
);
758 IODelete(buffer
, UInt8
, _ofPartitionSize
);
760 if (!ok
) return kIOReturnBadArgument
;
762 _ofImageDirty
= false;
763 _nvramImageDirty
= true;
765 return kIOReturnSuccess
;
769 const char *variableName
;
772 SInt32 variableOffset
;
774 typedef struct OFVariable OFVariable
;
777 kOWVariableOffsetNumber
= 8,
778 kOWVariableOffsetString
= 17
781 OFVariable gOFVariables
[] = {
782 {"little-endian?", kOFVariableTypeBoolean
, kOFVariablePermUserRead
, 0},
783 {"real-mode?", kOFVariableTypeBoolean
, kOFVariablePermUserRead
, 1},
784 {"auto-boot?", kOFVariableTypeBoolean
, kOFVariablePermUserRead
, 2},
785 {"diag-switch?", kOFVariableTypeBoolean
, kOFVariablePermUserRead
, 3},
786 {"fcode-debug?", kOFVariableTypeBoolean
, kOFVariablePermUserRead
, 4},
787 {"oem-banner?", kOFVariableTypeBoolean
, kOFVariablePermUserRead
, 5},
788 {"oem-logo?", kOFVariableTypeBoolean
, kOFVariablePermUserRead
, 6},
789 {"use-nvramrc?", kOFVariableTypeBoolean
, kOFVariablePermUserRead
, 7},
790 {"use-generic?", kOFVariableTypeBoolean
, kOFVariablePermUserRead
, -1},
791 {"default-mac-address?", kOFVariableTypeBoolean
, kOFVariablePermUserRead
,-1},
792 {"real-base", kOFVariableTypeNumber
, kOFVariablePermUserRead
, 8},
793 {"real-size", kOFVariableTypeNumber
, kOFVariablePermUserRead
, 9},
794 {"virt-base", kOFVariableTypeNumber
, kOFVariablePermUserRead
, 10},
795 {"virt-size", kOFVariableTypeNumber
, kOFVariablePermUserRead
, 11},
796 {"load-base", kOFVariableTypeNumber
, kOFVariablePermUserRead
, 12},
797 {"pci-probe-list", kOFVariableTypeNumber
, kOFVariablePermUserRead
, 13},
798 {"pci-probe-mask", kOFVariableTypeNumber
, kOFVariablePermUserRead
, -1},
799 {"screen-#columns", kOFVariableTypeNumber
, kOFVariablePermUserRead
, 14},
800 {"screen-#rows", kOFVariableTypeNumber
, kOFVariablePermUserRead
, 15},
801 {"selftest-#megs", kOFVariableTypeNumber
, kOFVariablePermUserRead
, 16},
802 {"boot-device", kOFVariableTypeString
, kOFVariablePermUserRead
, 17},
803 {"boot-file", kOFVariableTypeString
, kOFVariablePermUserRead
, 18},
804 {"boot-screen", kOFVariableTypeString
, kOFVariablePermUserRead
, -1},
805 {"console-screen", kOFVariableTypeString
, kOFVariablePermUserRead
, -1},
806 {"diag-device", kOFVariableTypeString
, kOFVariablePermUserRead
, 19},
807 {"diag-file", kOFVariableTypeString
, kOFVariablePermUserRead
, 20},
808 {"input-device", kOFVariableTypeString
, kOFVariablePermUserRead
, 21},
809 {"output-device", kOFVariableTypeString
, kOFVariablePermUserRead
, 22},
810 {"input-device-1", kOFVariableTypeString
, kOFVariablePermUserRead
, -1},
811 {"output-device-1", kOFVariableTypeString
, kOFVariablePermUserRead
, -1},
812 {"mouse-device", kOFVariableTypeString
, kOFVariablePermUserRead
, -1},
813 {"oem-banner", kOFVariableTypeString
, kOFVariablePermUserRead
, 23},
814 {"oem-logo", kOFVariableTypeString
, kOFVariablePermUserRead
, 24},
815 {"nvramrc", kOFVariableTypeString
, kOFVariablePermUserRead
, 25},
816 {"boot-command", kOFVariableTypeString
, kOFVariablePermUserRead
, 26},
817 {"default-client-ip", kOFVariableTypeString
, kOFVariablePermUserRead
, -1},
818 {"default-server-ip", kOFVariableTypeString
, kOFVariablePermUserRead
, -1},
819 {"default-gateway-ip", kOFVariableTypeString
, kOFVariablePermUserRead
, -1},
820 {"default-subnet-mask", kOFVariableTypeString
, kOFVariablePermUserRead
, -1},
821 {"default-router-ip", kOFVariableTypeString
, kOFVariablePermUserRead
, -1},
822 {"boot-script", kOFVariableTypeString
, kOFVariablePermUserRead
, -1},
823 {"boot-args", kOFVariableTypeString
, kOFVariablePermUserRead
, -1},
824 {"aapl,pci", kOFVariableTypeData
, kOFVariablePermRootOnly
, -1},
825 {"security-mode", kOFVariableTypeString
, kOFVariablePermUserRead
, -1},
826 {"security-password", kOFVariableTypeData
, kOFVariablePermRootOnly
, -1},
827 {"boot-image", kOFVariableTypeData
, kOFVariablePermUserWrite
, -1},
828 {"com.apple.System.fp-state", kOFVariableTypeData
, kOFVariablePermKernelOnly
, -1},
829 {0, kOFVariableTypeData
, kOFVariablePermUserRead
, -1}
832 UInt32
IODTNVRAM::getOFVariableType(const OSSymbol
*propSymbol
) const
836 ofVar
= gOFVariables
;
838 if ((ofVar
->variableName
== 0) ||
839 propSymbol
->isEqualTo(ofVar
->variableName
)) break;
843 return ofVar
->variableType
;
846 UInt32
IODTNVRAM::getOFVariablePerm(const OSSymbol
*propSymbol
) const
850 ofVar
= gOFVariables
;
852 if ((ofVar
->variableName
== 0) ||
853 propSymbol
->isEqualTo(ofVar
->variableName
)) break;
857 return ofVar
->variablePerm
;
860 bool IODTNVRAM::getOWVariableInfo(UInt32 variableNumber
, const OSSymbol
**propSymbol
,
861 UInt32
*propType
, UInt32
*propOffset
)
865 ofVar
= gOFVariables
;
867 if (ofVar
->variableName
== 0) return false;
869 if (ofVar
->variableOffset
== (SInt32
) variableNumber
) break;
874 *propSymbol
= OSSymbol::withCStringNoCopy(ofVar
->variableName
);
875 *propType
= ofVar
->variableType
;
878 case kOFVariableTypeBoolean
:
879 *propOffset
= 1 << (31 - variableNumber
);
882 case kOFVariableTypeNumber
:
883 *propOffset
= variableNumber
- kOWVariableOffsetNumber
;
886 case kOFVariableTypeString
:
887 *propOffset
= variableNumber
- kOWVariableOffsetString
;
894 bool IODTNVRAM::convertPropToObject(UInt8
*propName
, UInt32 propNameLength
,
895 UInt8
*propData
, UInt32 propDataLength
,
896 const OSSymbol
**propSymbol
,
897 OSObject
**propObject
)
900 const OSSymbol
*tmpSymbol
;
905 // Create the symbol.
906 propName
[propNameLength
] = '\0';
907 tmpSymbol
= OSSymbol::withCString((const char *)propName
);
908 propName
[propNameLength
] = '=';
909 if (tmpSymbol
== 0) {
913 propType
= getOFVariableType(tmpSymbol
);
915 // Create the object.
918 case kOFVariableTypeBoolean
:
919 if (!strncmp("true", (const char *)propData
, propDataLength
)) {
920 tmpObject
= kOSBooleanTrue
;
921 } else if (!strncmp("false", (const char *)propData
, propDataLength
)) {
922 tmpObject
= kOSBooleanFalse
;
926 case kOFVariableTypeNumber
:
927 tmpNumber
= OSNumber::withNumber(strtol((const char *)propData
, 0, 0), 32);
928 if (tmpNumber
!= 0) tmpObject
= tmpNumber
;
931 case kOFVariableTypeString
:
932 tmpString
= OSString::withCString((const char *)propData
);
933 if (tmpString
!= 0) tmpObject
= tmpString
;
936 case kOFVariableTypeData
:
937 tmpObject
= unescapeBytesToData(propData
, propDataLength
);
941 if (tmpObject
== 0) {
942 tmpSymbol
->release();
946 *propSymbol
= tmpSymbol
;
947 *propObject
= tmpObject
;
952 bool IODTNVRAM::convertObjectToProp(UInt8
*buffer
, UInt32
*length
,
953 const OSSymbol
*propSymbol
, OSObject
*propObject
)
955 const UInt8
*propName
;
956 UInt32 propNameLength
, propDataLength
;
957 UInt32 propType
, tmpValue
;
958 OSBoolean
*tmpBoolean
= 0;
959 OSNumber
*tmpNumber
= 0;
960 OSString
*tmpString
= 0;
963 propName
= (const UInt8
*)propSymbol
->getCStringNoCopy();
964 propNameLength
= propSymbol
->getLength();
965 propType
= getOFVariableType(propSymbol
);
967 // Get the size of the data.
968 propDataLength
= 0xFFFFFFFF;
970 case kOFVariableTypeBoolean
:
971 tmpBoolean
= OSDynamicCast(OSBoolean
, propObject
);
972 if (tmpBoolean
!= 0) propDataLength
= 5;
975 case kOFVariableTypeNumber
:
976 tmpNumber
= OSDynamicCast(OSNumber
, propObject
);
977 if (tmpNumber
!= 0) propDataLength
= 10;
980 case kOFVariableTypeString
:
981 tmpString
= OSDynamicCast(OSString
, propObject
);
982 if (tmpString
!= 0) propDataLength
= tmpString
->getLength();
985 case kOFVariableTypeData
:
986 tmpData
= OSDynamicCast(OSData
, propObject
);
988 tmpData
= escapeDataToData(tmpData
);
989 propDataLength
= tmpData
->getLength();
994 // Make sure the propertySize is known and will fit.
995 if (propDataLength
== 0xFFFFFFFF) return false;
996 if ((propNameLength
+ propDataLength
+ 2) > *length
) return false;
998 // Copy the property name equal sign.
999 buffer
+= snprintf((char *)buffer
, *length
, "%s=", propName
);
1002 case kOFVariableTypeBoolean
:
1003 if (tmpBoolean
->getValue()) {
1004 strlcpy((char *)buffer
, "true", *length
- propNameLength
);
1006 strlcpy((char *)buffer
, "false", *length
- propNameLength
);
1010 case kOFVariableTypeNumber
:
1011 tmpValue
= tmpNumber
->unsigned32BitValue();
1012 if (tmpValue
== 0xFFFFFFFF) {
1013 strlcpy((char *)buffer
, "-1", *length
- propNameLength
);
1014 } else if (tmpValue
< 1000) {
1015 snprintf((char *)buffer
, *length
- propNameLength
, "%d", (uint32_t)tmpValue
);
1017 snprintf((char *)buffer
, *length
- propNameLength
, "0x%x", (uint32_t)tmpValue
);
1021 case kOFVariableTypeString
:
1022 strlcpy((char *)buffer
, tmpString
->getCStringNoCopy(), *length
- propNameLength
);
1025 case kOFVariableTypeData
:
1026 bcopy(tmpData
->getBytesNoCopy(), buffer
, propDataLength
);
1031 propDataLength
= strlen((const char *)buffer
);
1033 *length
= propNameLength
+ propDataLength
+ 2;
1039 UInt16
IODTNVRAM::generateOWChecksum(UInt8
*buffer
)
1041 UInt32 cnt
, checksum
= 0;
1042 UInt16
*tmpBuffer
= (UInt16
*)buffer
;
1044 for (cnt
= 0; cnt
< _ofPartitionSize
/ 2; cnt
++)
1045 checksum
+= tmpBuffer
[cnt
];
1047 return checksum
% 0x0000FFFF;
1050 bool IODTNVRAM::validateOWChecksum(UInt8
*buffer
)
1052 UInt32 cnt
, checksum
, sum
= 0;
1053 UInt16
*tmpBuffer
= (UInt16
*)buffer
;
1055 for (cnt
= 0; cnt
< _ofPartitionSize
/ 2; cnt
++)
1056 sum
+= tmpBuffer
[cnt
];
1058 checksum
= (sum
>> 16) + (sum
& 0x0000FFFF);
1059 if (checksum
== 0x10000) checksum
--;
1060 checksum
= (checksum
^ 0x0000FFFF) & 0x0000FFFF;
1062 return checksum
== 0;
1065 void IODTNVRAM::updateOWBootArgs(const OSSymbol
*key
, OSObject
*value
)
1067 bool wasBootArgs
, bootr
= false;
1069 OSString
*tmpString
, *bootCommand
, *bootArgs
= 0;
1070 const UInt8
*bootCommandData
, *bootArgsData
;
1072 UInt32 bootCommandDataLength
, bootArgsDataLength
, tmpDataLength
;
1074 tmpString
= OSDynamicCast(OSString
, value
);
1075 if (tmpString
== 0) return;
1077 if (key
->isEqualTo("boot-command")) {
1078 wasBootArgs
= false;
1079 bootCommand
= tmpString
;
1080 } else if (key
->isEqualTo("boot-args")) {
1082 bootArgs
= tmpString
;
1083 bootCommand
= OSDynamicCast(OSString
, _ofDict
->getObject("boot-command"));
1084 if (bootCommand
== 0) return;
1087 bootCommandData
= (const UInt8
*)bootCommand
->getCStringNoCopy();
1088 bootCommandDataLength
= bootCommand
->getLength();
1090 if (bootCommandData
== 0) return;
1092 for (cnt
= 0; cnt
< bootCommandDataLength
; cnt
++) {
1093 if ((bootCommandData
[cnt
] == 'b') &&
1094 !strncmp("bootr", (const char *)bootCommandData
+ cnt
, 5)) {
1096 while (bootCommandData
[cnt
] == ' ') cnt
++;
1102 _ofDict
->removeObject("boot-args");
1107 bootArgsData
= (const UInt8
*)bootArgs
->getCStringNoCopy();
1108 bootArgsDataLength
= bootArgs
->getLength();
1109 if (bootArgsData
== 0) return;
1111 tmpDataLength
= cnt
+ bootArgsDataLength
;
1112 tmpData
= IONew(UInt8
, tmpDataLength
+ 1);
1113 if (tmpData
== 0) return;
1115 cnt
-= strlcpy((char *)tmpData
, (const char *)bootCommandData
, cnt
);
1116 strlcat((char *)tmpData
, (const char *)bootArgsData
, cnt
);
1118 bootCommand
= OSString::withCString((const char *)tmpData
);
1119 if (bootCommand
!= 0) {
1120 _ofDict
->setObject("boot-command", bootCommand
);
1121 bootCommand
->release();
1124 IODelete(tmpData
, UInt8
, tmpDataLength
+ 1);
1126 bootArgs
= OSString::withCString((const char *)(bootCommandData
+ cnt
));
1127 if (bootArgs
!= 0) {
1128 _ofDict
->setObject("boot-args", bootArgs
);
1129 bootArgs
->release();
1134 bool IODTNVRAM::searchNVRAMProperty(IONVRAMDescriptor
*hdr
, UInt32
*where
)
1139 IOReturn
IODTNVRAM::readNVRAMPropertyType0(IORegistryEntry
*entry
,
1140 const OSSymbol
**name
,
1143 return kIOReturnUnsupported
;
1147 IOReturn
IODTNVRAM::writeNVRAMPropertyType0(IORegistryEntry
*entry
,
1148 const OSSymbol
*name
,
1151 return kIOReturnUnsupported
;
1155 OSData
*IODTNVRAM::unescapeBytesToData(const UInt8
*bytes
, UInt32 length
)
1158 UInt32 totalLength
= 0;
1163 // Calculate the actual length of the data.
1166 for (cnt
= 0; cnt
< length
;) {
1167 byte
= bytes
[cnt
++];
1169 byte
= bytes
[cnt
++];
1177 totalLength
+= cnt2
;
1181 // Create an empty OSData of the correct size.
1182 data
= OSData::withCapacity(totalLength
);
1184 for (cnt
= 0; cnt
< length
;) {
1185 byte
= bytes
[cnt
++];
1187 byte
= bytes
[cnt
++];
1189 byte
= (byte
& 0x80) ? 0xFF : 0x00;
1192 data
->appendByte(byte
, cnt2
);
1200 OSData
* IODTNVRAM::escapeDataToData(OSData
* value
)
1203 const UInt8
* startPtr
;
1204 const UInt8
* endPtr
;
1205 const UInt8
* wherePtr
;
1209 wherePtr
= (const UInt8
*) value
->getBytesNoCopy();
1210 endPtr
= wherePtr
+ value
->getLength();
1212 result
= OSData::withCapacity(endPtr
- wherePtr
);
1216 while (wherePtr
< endPtr
) {
1217 startPtr
= wherePtr
;
1219 if ((byte
== 0x00) || (byte
== 0xFF)) {
1221 ((wherePtr
- startPtr
) < 0x80) && (wherePtr
< endPtr
) && (byte
== *wherePtr
);
1223 ok
&= result
->appendByte(0xff, 1);
1224 byte
= (byte
& 0x80) | (wherePtr
- startPtr
);
1226 ok
&= result
->appendByte(byte
, 1);
1228 ok
&= result
->appendByte(0, 1);
1238 static bool IsApplePropertyName(const char * propName
)
1241 while ((c
= *propName
++)) {
1242 if ((c
>= 'A') && (c
<= 'Z'))
1249 IOReturn
IODTNVRAM::readNVRAMPropertyType1(IORegistryEntry
*entry
,
1250 const OSSymbol
**name
,
1253 IOReturn err
= kIOReturnNoResources
;
1255 const UInt8
*startPtr
;
1256 const UInt8
*endPtr
;
1257 const UInt8
*wherePtr
;
1258 const UInt8
*nvPath
= 0;
1259 const char *nvName
= 0;
1260 const char *resultName
= 0;
1261 const UInt8
*resultValue
= 0;
1262 UInt32 resultValueLen
= 0;
1265 if (_ofDict
== 0) return err
;
1267 IOLockLock(_ofLock
);
1268 data
= OSDynamicCast(OSData
, _ofDict
->getObject(_registryPropertiesKey
));
1269 IOLockUnlock(_ofLock
);
1271 if (data
== 0) return err
;
1273 startPtr
= (const UInt8
*) data
->getBytesNoCopy();
1274 endPtr
= startPtr
+ data
->getLength();
1276 wherePtr
= startPtr
;
1277 while (wherePtr
< endPtr
) {
1278 byte
= *(wherePtr
++);
1284 else if (nvName
== 0)
1285 nvName
= (const char *) startPtr
;
1287 IORegistryEntry
* compareEntry
= IORegistryEntry::fromPath((const char *) nvPath
, gIODTPlane
);
1289 compareEntry
->release();
1290 if (entry
== compareEntry
) {
1291 bool appleProp
= IsApplePropertyName(nvName
);
1292 if (!appleProp
|| !resultName
) {
1293 resultName
= nvName
;
1294 resultValue
= startPtr
;
1295 resultValueLen
= wherePtr
- startPtr
- 1;
1303 startPtr
= wherePtr
;
1306 *name
= OSSymbol::withCString(resultName
);
1307 *value
= unescapeBytesToData(resultValue
, resultValueLen
);
1308 if ((*name
!= 0) && (*value
!= 0))
1309 err
= kIOReturnSuccess
;
1311 err
= kIOReturnNoMemory
;
1316 IOReturn
IODTNVRAM::writeNVRAMPropertyType1(IORegistryEntry
*entry
,
1317 const OSSymbol
*propName
,
1322 const UInt8
*startPtr
;
1323 const UInt8
*propStart
;
1324 const UInt8
*endPtr
;
1325 const UInt8
*wherePtr
;
1326 const UInt8
*nvPath
= 0;
1327 const char *nvName
= 0;
1332 bool settingAppleProp
;
1334 if (_ofDict
== 0) return kIOReturnNoResources
;
1336 settingAppleProp
= IsApplePropertyName(propName
->getCStringNoCopy());
1338 // copy over existing properties for other entries
1340 IOLockLock(_ofLock
);
1342 oldData
= OSDynamicCast(OSData
, _ofDict
->getObject(_registryPropertiesKey
));
1344 startPtr
= (const UInt8
*) oldData
->getBytesNoCopy();
1345 endPtr
= startPtr
+ oldData
->getLength();
1347 propStart
= startPtr
;
1348 wherePtr
= startPtr
;
1349 while (wherePtr
< endPtr
) {
1350 byte
= *(wherePtr
++);
1355 else if (nvName
== 0)
1356 nvName
= (const char *) startPtr
;
1358 IORegistryEntry
* compareEntry
= IORegistryEntry::fromPath((const char *) nvPath
, gIODTPlane
);
1360 compareEntry
->release();
1361 if (entry
== compareEntry
) {
1362 if ((settingAppleProp
&& propName
->isEqualTo(nvName
))
1363 || (!settingAppleProp
&& !IsApplePropertyName(nvName
))) {
1364 // delete old property (nvPath -> wherePtr)
1365 data
= OSData::withBytes(propStart
, nvPath
- propStart
);
1367 ok
&= data
->appendBytes(wherePtr
, endPtr
- wherePtr
);
1375 startPtr
= wherePtr
;
1379 // make the new property
1383 data
= OSData::withData(oldData
);
1385 data
= OSData::withCapacity(16);
1386 if (!data
) ok
= false;
1389 if (ok
&& value
&& value
->getLength()) do {
1390 // get entries in path
1391 OSArray
*array
= OSArray::withCapacity(5);
1397 array
->setObject(entry
);
1398 while ((entry
= entry
->getParentEntry(gIODTPlane
)));
1401 for (int i
= array
->getCount() - 3;
1402 (entry
= (IORegistryEntry
*) array
->getObject(i
));
1405 name
= entry
->getName(gIODTPlane
);
1406 comp
= entry
->getLocation(gIODTPlane
);
1407 if (comp
) ok
&= data
->appendBytes("/@", 2);
1409 if (!name
) continue;
1410 ok
&= data
->appendByte('/', 1);
1413 ok
&= data
->appendBytes(comp
, strlen(comp
));
1415 ok
&= data
->appendByte(0, 1);
1419 ok
&= data
->appendBytes(propName
->getCStringNoCopy(), propName
->getLength() + 1);
1421 // append escaped data
1422 oldData
= escapeDataToData(value
);
1423 ok
&= (oldData
!= 0);
1424 if (ok
) ok
&= data
->appendBytes(oldData
);
1429 ok
= _ofDict
->setObject(_registryPropertiesKey
, data
);
1430 if (ok
) _ofImageDirty
= true;
1433 IOLockUnlock(_ofLock
);
1434 if (data
) data
->release();
1436 return ok
? kIOReturnSuccess
: kIOReturnNoMemory
;
1439 bool IODTNVRAM::safeToSync(void)
1445 // delta interval went by
1446 clock_get_uptime(&delta
);
1448 // Figure it in seconds.
1449 absolutetime_to_nanoseconds(delta
, &delta_ns
);
1450 delta_secs
= (SInt32
)(delta_ns
/ NSEC_PER_SEC
);
1452 if ((delta_secs
> (_lastDeviceSync
+ MIN_SYNC_NOW_INTERVAL
)) || _freshInterval
)
1454 _lastDeviceSync
= delta_secs
;
1455 _freshInterval
= FALSE
;