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 _xpramPartitionOffset
= 0xFFFFFFFF;
126 _nrPartitionOffset
= 0xFFFFFFFF;
127 _piPartitionOffset
= 0xFFFFFFFF;
128 freePartitionOffset
= 0xFFFFFFFF;
129 freePartitionSize
= 0;
130 if (getPlatform()->getBootROMType()) {
131 // Look through the partitions to find the OF, MacOS partitions.
132 while (currentOffset
< kIODTNVRAMImageSize
) {
133 currentLength
= ((UInt16
*)(_nvramImage
+ currentOffset
))[1] * 16;
135 partitionOffset
= currentOffset
+ 16;
136 partitionLength
= currentLength
- 16;
138 if (strncmp((const char *)_nvramImage
+ currentOffset
+ 4,
139 kIODTNVRAMOFPartitionName
, 12) == 0) {
140 _ofPartitionOffset
= partitionOffset
;
141 _ofPartitionSize
= partitionLength
;
142 } else if (strncmp((const char *)_nvramImage
+ currentOffset
+ 4,
143 kIODTNVRAMXPRAMPartitionName
, 12) == 0) {
144 _xpramPartitionOffset
= partitionOffset
;
145 _xpramPartitionSize
= kIODTNVRAMXPRAMSize
;
146 _nrPartitionOffset
= _xpramPartitionOffset
+ _xpramPartitionSize
;
147 _nrPartitionSize
= partitionLength
- _xpramPartitionSize
;
148 } else if (strncmp((const char *)_nvramImage
+ currentOffset
+ 4,
149 kIODTNVRAMPanicInfoPartitonName
, 12) == 0) {
150 _piPartitionOffset
= partitionOffset
;
151 _piPartitionSize
= partitionLength
;
152 } else if (strncmp((const char *)_nvramImage
+ currentOffset
+ 4,
153 kIODTNVRAMFreePartitionName
, 12) == 0) {
154 freePartitionOffset
= currentOffset
;
155 freePartitionSize
= currentLength
;
157 // Construct the partition ID from the signature and name.
158 snprintf(partitionID
, sizeof(partitionID
), "0x%02x,",
159 *(UInt8
*)(_nvramImage
+ currentOffset
));
160 strncpy(partitionID
+ 5,
161 (const char *)(_nvramImage
+ currentOffset
+ 4), 12);
162 partitionID
[17] = '\0';
164 partitionOffsetNumber
= OSNumber::withNumber(partitionOffset
, 32);
165 partitionLengthNumber
= OSNumber::withNumber(partitionLength
, 32);
167 // Save the partition offset and length
168 _nvramPartitionOffsets
->setObject(partitionID
, partitionOffsetNumber
);
169 _nvramPartitionLengths
->setObject(partitionID
, partitionLengthNumber
);
171 partitionOffsetNumber
->release();
172 partitionLengthNumber
->release();
174 currentOffset
+= currentLength
;
177 // Use the fixed address for old world machines.
178 _ofPartitionOffset
= 0x1800;
179 _ofPartitionSize
= 0x0800;
180 _xpramPartitionOffset
= 0x1300;
181 _xpramPartitionSize
= 0x0100;
182 _nrPartitionOffset
= 0x1400;
183 _nrPartitionSize
= 0x0400;
186 if (_ofPartitionOffset
!= 0xFFFFFFFF)
187 _ofImage
= _nvramImage
+ _ofPartitionOffset
;
188 if (_xpramPartitionOffset
!= 0xFFFFFFFF)
189 _xpramImage
= _nvramImage
+ _xpramPartitionOffset
;
190 if (_nrPartitionOffset
!= 0xFFFFFFFF)
191 _nrImage
= _nvramImage
+ _nrPartitionOffset
;
193 if (_piPartitionOffset
== 0xFFFFFFFF) {
194 if (freePartitionSize
> 0x20) {
195 // Set the signature to 0xa1.
196 _nvramImage
[freePartitionOffset
] = 0xa1;
197 // Set the checksum to 0.
198 _nvramImage
[freePartitionOffset
+ 1] = 0;
199 // Set the name for the Panic Info partition.
200 strncpy((char *)(_nvramImage
+ freePartitionOffset
+ 4),
201 kIODTNVRAMPanicInfoPartitonName
, 12);
203 // Calculate the partition offset and size.
204 _piPartitionOffset
= freePartitionOffset
+ 0x10;
205 _piPartitionSize
= 0x800;
206 if (_piPartitionSize
+ 0x20 > freePartitionSize
)
207 _piPartitionSize
= freePartitionSize
- 0x20;
209 _piImage
= _nvramImage
+ _piPartitionOffset
;
211 // Zero the new partition.
212 bzero(_piImage
, _piPartitionSize
);
214 // Set the partition size.
215 *(UInt16
*)(_nvramImage
+ freePartitionOffset
+ 2) =
216 (_piPartitionSize
/ 0x10) + 1;
218 // Set the partition checksum.
219 _nvramImage
[freePartitionOffset
+ 1] =
220 calculatePartitionChecksum(_nvramImage
+ freePartitionOffset
);
222 // Calculate the free partition offset and size.
223 freePartitionOffset
+= _piPartitionSize
+ 0x10;
224 freePartitionSize
-= _piPartitionSize
+ 0x10;
226 // Set the signature to 0x7f.
227 _nvramImage
[freePartitionOffset
] = 0x7f;
228 // Set the checksum to 0.
229 _nvramImage
[freePartitionOffset
+ 1] = 0;
230 // Set the name for the free partition.
231 strncpy((char *)(_nvramImage
+ freePartitionOffset
+ 4),
232 kIODTNVRAMFreePartitionName
, 12);
233 // Set the partition size.
234 *(UInt16
*)(_nvramImage
+ freePartitionOffset
+ 2) =
235 freePartitionSize
/ 0x10;
236 // Set the partition checksum.
237 _nvramImage
[freePartitionOffset
+ 1] =
238 calculatePartitionChecksum(_nvramImage
+ freePartitionOffset
);
240 // Set the nvram image as dirty.
241 _nvramImageDirty
= true;
244 _piImage
= _nvramImage
+ _piPartitionOffset
;
248 _freshInterval
= TRUE
; // we will allow sync() even before the first 15 minutes have passed.
253 void IODTNVRAM::sync(void)
255 if (!_nvramImageDirty
&& !_ofImageDirty
) return;
257 // Don't try to sync OF Variables if the system has already paniced.
258 if (!_systemPaniced
) syncOFVariables();
260 // Don't try to perform controller operations if none has been registered.
261 if (_nvramController
== 0) return;
263 _nvramController
->write(0, _nvramImage
, kIODTNVRAMImageSize
);
264 _nvramController
->sync();
266 _nvramImageDirty
= false;
269 bool IODTNVRAM::serializeProperties(OSSerialize
*s
) const
271 bool result
, hasPrivilege
;
275 OSCollectionIterator
*iter
= 0;
277 // Verify permissions.
278 hasPrivilege
= (kIOReturnSuccess
== IOUserClient::clientHasPrivilege(current_task(), kIONVRAMPrivilege
));
280 dict
= OSDictionary::withCapacity(1);
281 if (dict
== 0) return false;
284 /* No nvram. Return an empty dictionary. */
286 /* Copy properties with client privilege. */
287 iter
= OSCollectionIterator::withCollection(_ofDict
);
293 key
= OSDynamicCast(OSSymbol
, iter
->getNextObject());
296 variablePerm
= getOFVariablePerm(key
);
297 if ((hasPrivilege
|| (variablePerm
!= kOFVariablePermRootOnly
)) &&
298 ( ! (variablePerm
== kOFVariablePermKernelOnly
&& current_task() != kernel_task
) )) {
299 dict
->setObject(key
, _ofDict
->getObject(key
));
304 result
= dict
->serialize(s
);
307 if (iter
!= 0) iter
->release();
312 OSObject
*IODTNVRAM::getProperty(const OSSymbol
*aKey
) const
317 if (_ofDict
== 0) return 0;
319 // Verify permissions.
320 variablePerm
= getOFVariablePerm(aKey
);
321 result
= IOUserClient::clientHasPrivilege(current_task(), kIONVRAMPrivilege
);
322 if (result
!= kIOReturnSuccess
) {
323 if (variablePerm
== kOFVariablePermRootOnly
) return 0;
325 if (variablePerm
== kOFVariablePermKernelOnly
&& current_task() != kernel_task
) return 0;
327 return _ofDict
->getObject(aKey
);
330 OSObject
*IODTNVRAM::getProperty(const char *aKey
) const
332 const OSSymbol
*keySymbol
;
333 OSObject
*theObject
= 0;
335 keySymbol
= OSSymbol::withCStringNoCopy(aKey
);
336 if (keySymbol
!= 0) {
337 theObject
= getProperty(keySymbol
);
338 keySymbol
->release();
344 bool IODTNVRAM::setProperty(const OSSymbol
*aKey
, OSObject
*anObject
)
347 UInt32 propType
, propPerm
;
349 OSObject
*propObject
= 0;
351 if (_ofDict
== 0) return false;
353 // Verify permissions.
354 propPerm
= getOFVariablePerm(aKey
);
355 result
= IOUserClient::clientHasPrivilege(current_task(), kIONVRAMPrivilege
);
356 if (result
!= kIOReturnSuccess
) {
357 if (propPerm
!= kOFVariablePermUserWrite
) return false;
359 if (propPerm
== kOFVariablePermKernelOnly
&& current_task() != kernel_task
) return 0;
361 // Don't allow creation of new properties on old world machines.
362 if (getPlatform()->getBootROMType() == 0) {
363 if (_ofDict
->getObject(aKey
) == 0) return false;
366 // Don't allow change of 'aapl,panic-info'.
367 if (aKey
->isEqualTo(kIODTNVRAMPanicInfoKey
)) return false;
369 // Make sure the object is of the correct type.
370 propType
= getOFVariableType(aKey
);
372 case kOFVariableTypeBoolean
:
373 propObject
= OSDynamicCast(OSBoolean
, anObject
);
376 case kOFVariableTypeNumber
:
377 propObject
= OSDynamicCast(OSNumber
, anObject
);
380 case kOFVariableTypeString
:
381 propObject
= OSDynamicCast(OSString
, anObject
);
384 case kOFVariableTypeData
:
385 propObject
= OSDynamicCast(OSData
, anObject
);
386 if (propObject
== 0) {
387 tmpString
= OSDynamicCast(OSString
, anObject
);
388 if (tmpString
!= 0) {
389 propObject
= OSData::withBytes(tmpString
->getCStringNoCopy(),
390 tmpString
->getLength());
396 if (propObject
== 0) return false;
398 result
= _ofDict
->setObject(aKey
, propObject
);
401 if (getPlatform()->getBootROMType() == 0) {
402 updateOWBootArgs(aKey
, propObject
);
405 _ofImageDirty
= true;
411 void IODTNVRAM::removeProperty(const OSSymbol
*aKey
)
416 if (_ofDict
== 0) return;
418 // Verify permissions.
419 propPerm
= getOFVariablePerm(aKey
);
420 result
= IOUserClient::clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator
);
421 if (result
!= kIOReturnSuccess
) {
422 if (propPerm
!= kOFVariablePermUserWrite
) return;
424 if (propPerm
== kOFVariablePermKernelOnly
&& current_task() != kernel_task
) return;
426 // Don't allow removal of properties on old world machines.
427 if (getPlatform()->getBootROMType() == 0) 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.
433 result
= _ofDict
->getObject(aKey
) != 0;
435 _ofDict
->removeObject(aKey
);
437 _ofImageDirty
= true;
441 IOReturn
IODTNVRAM::setProperties(OSObject
*properties
)
446 const OSString
*tmpStr
;
448 OSCollectionIterator
*iter
;
450 dict
= OSDynamicCast(OSDictionary
, properties
);
451 if (dict
== 0) return kIOReturnBadArgument
;
453 iter
= OSCollectionIterator::withCollection(dict
);
454 if (iter
== 0) return kIOReturnBadArgument
;
457 key
= OSDynamicCast(OSSymbol
, iter
->getNextObject());
460 object
= dict
->getObject(key
);
461 if (object
== 0) continue;
463 if (key
->isEqualTo(kIONVRAMDeletePropertyKey
)) {
464 tmpStr
= OSDynamicCast(OSString
, object
);
466 key
= OSSymbol::withString(tmpStr
);
473 } else if(key
->isEqualTo(kIONVRAMSyncNowPropertyKey
)) {
474 tmpStr
= OSDynamicCast(OSString
, object
);
477 result
= true; // We are not going to gaurantee sync, this is best effort
487 result
= setProperty(key
, object
);
494 if (result
) return kIOReturnSuccess
;
495 else return kIOReturnError
;
498 IOReturn
IODTNVRAM::readXPRAM(IOByteCount offset
, UInt8
*buffer
,
501 if (_xpramImage
== 0) return kIOReturnUnsupported
;
503 if ((buffer
== 0) || (length
== 0) ||
504 (offset
+ length
> kIODTNVRAMXPRAMSize
))
505 return kIOReturnBadArgument
;
507 bcopy(_nvramImage
+ _xpramPartitionOffset
+ offset
, buffer
, length
);
509 return kIOReturnSuccess
;
512 IOReturn
IODTNVRAM::writeXPRAM(IOByteCount offset
, UInt8
*buffer
,
515 if (_xpramImage
== 0) return kIOReturnUnsupported
;
517 if ((buffer
== 0) || (length
== 0) ||
518 (offset
+ length
> kIODTNVRAMXPRAMSize
))
519 return kIOReturnBadArgument
;
521 bcopy(buffer
, _nvramImage
+ _xpramPartitionOffset
+ offset
, length
);
523 _nvramImageDirty
= true;
525 return kIOReturnSuccess
;
528 IOReturn
IODTNVRAM::readNVRAMProperty(IORegistryEntry
*entry
,
529 const OSSymbol
**name
,
534 if (getPlatform()->getBootROMType())
535 err
= readNVRAMPropertyType1(entry
, name
, value
);
537 err
= readNVRAMPropertyType0(entry
, name
, value
);
542 IOReturn
IODTNVRAM::writeNVRAMProperty(IORegistryEntry
*entry
,
543 const OSSymbol
*name
,
548 if (getPlatform()->getBootROMType())
549 err
= writeNVRAMPropertyType1(entry
, name
, value
);
551 err
= writeNVRAMPropertyType0(entry
, name
, value
);
556 OSDictionary
*IODTNVRAM::getNVRAMPartitions(void)
558 return _nvramPartitionLengths
;
561 IOReturn
IODTNVRAM::readNVRAMPartition(const OSSymbol
*partitionID
,
562 IOByteCount offset
, UInt8
*buffer
,
565 OSNumber
*partitionOffsetNumber
, *partitionLengthNumber
;
566 UInt32 partitionOffset
, partitionLength
;
568 partitionOffsetNumber
=
569 (OSNumber
*)_nvramPartitionOffsets
->getObject(partitionID
);
570 partitionLengthNumber
=
571 (OSNumber
*)_nvramPartitionLengths
->getObject(partitionID
);
573 if ((partitionOffsetNumber
== 0) || (partitionLengthNumber
== 0))
574 return kIOReturnNotFound
;
576 partitionOffset
= partitionOffsetNumber
->unsigned32BitValue();
577 partitionLength
= partitionLengthNumber
->unsigned32BitValue();
579 if ((buffer
== 0) || (length
== 0) ||
580 (offset
+ length
> partitionLength
))
581 return kIOReturnBadArgument
;
583 bcopy(_nvramImage
+ partitionOffset
+ offset
, buffer
, length
);
585 return kIOReturnSuccess
;
588 IOReturn
IODTNVRAM::writeNVRAMPartition(const OSSymbol
*partitionID
,
589 IOByteCount offset
, UInt8
*buffer
,
592 OSNumber
*partitionOffsetNumber
, *partitionLengthNumber
;
593 UInt32 partitionOffset
, partitionLength
;
595 partitionOffsetNumber
=
596 (OSNumber
*)_nvramPartitionOffsets
->getObject(partitionID
);
597 partitionLengthNumber
=
598 (OSNumber
*)_nvramPartitionLengths
->getObject(partitionID
);
600 if ((partitionOffsetNumber
== 0) || (partitionLengthNumber
== 0))
601 return kIOReturnNotFound
;
603 partitionOffset
= partitionOffsetNumber
->unsigned32BitValue();
604 partitionLength
= partitionLengthNumber
->unsigned32BitValue();
606 if ((buffer
== 0) || (length
== 0) ||
607 (offset
+ length
> partitionLength
))
608 return kIOReturnBadArgument
;
610 bcopy(buffer
, _nvramImage
+ partitionOffset
+ offset
, length
);
612 _nvramImageDirty
= true;
614 return kIOReturnSuccess
;
617 IOByteCount
IODTNVRAM::savePanicInfo(UInt8
*buffer
, IOByteCount length
)
619 if ((_piImage
== 0) || (length
<= 0)) return 0;
621 if (length
> (_piPartitionSize
- 4))
622 length
= _piPartitionSize
- 4;
624 // Save the Panic Info.
625 bcopy(buffer
, _piImage
+ 4, length
);
627 // Save the Panic Info length.
628 *(UInt32
*)_piImage
= length
;
630 _nvramImageDirty
= true;
632 * This prevents OF variables from being committed if the system has panicked
634 _systemPaniced
= true;
635 /* The call to sync() forces the NVRAM controller to write the panic info
636 * partition to NVRAM.
645 UInt8
IODTNVRAM::calculatePartitionChecksum(UInt8
*partitionHeader
)
647 UInt8 cnt
, isum
, csum
= 0;
649 for (cnt
= 0; cnt
< 0x10; cnt
++) {
650 isum
= csum
+ partitionHeader
[cnt
];
651 if (isum
< csum
) isum
++;
658 struct OWVariablesHeader
{
673 typedef struct OWVariablesHeader OWVariablesHeader
;
675 IOReturn
IODTNVRAM::initOFVariables(void)
677 UInt32 cnt
, propOffset
, propType
;
678 UInt8
*propName
, *propData
;
679 UInt32 propNameLength
, propDataLength
;
680 const OSSymbol
*propSymbol
;
681 OSObject
*propObject
;
682 OWVariablesHeader
*owHeader
;
684 if (_ofImage
== 0) return kIOReturnNotReady
;
686 _ofDict
= OSDictionary::withCapacity(1);
687 if (_ofDict
== 0) return kIOReturnNoMemory
;
689 if (getPlatform()->getBootROMType()) {
691 while (cnt
< _ofPartitionSize
) {
692 // Break if there is no name.
693 if (_ofImage
[cnt
] == '\0') break;
695 // Find the length of the name.
696 propName
= _ofImage
+ cnt
;
697 for (propNameLength
= 0; (cnt
+ propNameLength
) < _ofPartitionSize
;
699 if (_ofImage
[cnt
+ propNameLength
] == '=') break;
702 // Break if the name goes past the end of the partition.
703 if ((cnt
+ propNameLength
) >= _ofPartitionSize
) break;
704 cnt
+= propNameLength
+ 1;
706 propData
= _ofImage
+ cnt
;
707 for (propDataLength
= 0; (cnt
+ propDataLength
) < _ofPartitionSize
;
709 if (_ofImage
[cnt
+ propDataLength
] == '\0') break;
712 // Break if the data goes past the end of the partition.
713 if ((cnt
+ propDataLength
) >= _ofPartitionSize
) break;
714 cnt
+= propDataLength
+ 1;
716 if (convertPropToObject(propName
, propNameLength
,
717 propData
, propDataLength
,
718 &propSymbol
, &propObject
)) {
719 _ofDict
->setObject(propSymbol
, propObject
);
720 propSymbol
->release();
721 propObject
->release();
725 // Create the boot-args property if it is not in the dictionary.
726 if (_ofDict
->getObject("boot-args") == 0) {
727 propObject
= OSString::withCStringNoCopy("");
728 if (propObject
!= 0) {
729 _ofDict
->setObject("boot-args", propObject
);
730 propObject
->release();
734 // Create the 'aapl,panic-info' property if needed.
736 propDataLength
= *(UInt32
*)_piImage
;
737 if ((propDataLength
!= 0) && (propDataLength
<= (_piPartitionSize
- 4))) {
738 propObject
= OSData::withBytes(_piImage
+ 4, propDataLength
);
739 _ofDict
->setObject(kIODTNVRAMPanicInfoKey
, propObject
);
740 propObject
->release();
742 // Clear the length from _piImage and mark dirty.
743 *(UInt32
*)_piImage
= 0;
744 _nvramImageDirty
= true;
748 owHeader
= (OWVariablesHeader
*)_ofImage
;
749 if (!validateOWChecksum(_ofImage
)) {
752 return kIOReturnBadMedia
;
757 if (!getOWVariableInfo(cnt
++, &propSymbol
, &propType
, &propOffset
))
761 case kOFVariableTypeBoolean
:
762 propObject
= OSBoolean::withBoolean(owHeader
->owFlags
& propOffset
);
765 case kOFVariableTypeNumber
:
766 propObject
= OSNumber::withNumber(owHeader
->owNumbers
[propOffset
], 32);
769 case kOFVariableTypeString
:
770 propData
= _ofImage
+ owHeader
->owStrings
[propOffset
].offset
-
772 propDataLength
= owHeader
->owStrings
[propOffset
].length
;
773 propName
= IONew(UInt8
, propDataLength
+ 1);
775 strncpy((char *)propName
, (const char *)propData
, propDataLength
);
776 propName
[propDataLength
] = '\0';
777 propObject
= OSString::withCString((const char *)propName
);
778 IODelete(propName
, UInt8
, propDataLength
+ 1);
783 if (propObject
== 0) break;
785 _ofDict
->setObject(propSymbol
, propObject
);
786 propSymbol
->release();
787 propObject
->release();
790 // Create the boot-args property.
791 propSymbol
= OSSymbol::withCString("boot-command");
792 if (propSymbol
!= 0) {
793 propObject
= _ofDict
->getObject(propSymbol
);
794 if (propObject
!= 0) {
795 updateOWBootArgs(propSymbol
, propObject
);
797 propSymbol
->release();
801 return kIOReturnSuccess
;
804 IOReturn
IODTNVRAM::syncOFVariables(void)
807 UInt32 cnt
, length
, maxLength
;
808 UInt32 curOffset
, tmpOffset
, tmpType
, tmpDataLength
;
809 UInt8
*buffer
, *tmpBuffer
;
810 const UInt8
*tmpData
;
811 const OSSymbol
*tmpSymbol
;
813 OSBoolean
*tmpBoolean
;
816 OSCollectionIterator
*iter
;
817 OWVariablesHeader
*owHeader
, *owHeaderOld
;
819 if ((_ofImage
== 0) || (_ofDict
== 0)) return kIOReturnNotReady
;
821 if (!_ofImageDirty
) return kIOReturnSuccess
;
823 if (getPlatform()->getBootROMType()) {
824 buffer
= tmpBuffer
= IONew(UInt8
, _ofPartitionSize
);
825 if (buffer
== 0) return kIOReturnNoMemory
;
826 bzero(buffer
, _ofPartitionSize
);
829 maxLength
= _ofPartitionSize
;
831 iter
= OSCollectionIterator::withCollection(_ofDict
);
832 if (iter
== 0) ok
= false;
835 tmpSymbol
= OSDynamicCast(OSSymbol
, iter
->getNextObject());
836 if (tmpSymbol
== 0) break;
838 // Don't save 'aapl,panic-info'.
839 if (tmpSymbol
->isEqualTo(kIODTNVRAMPanicInfoKey
)) continue;
841 tmpObject
= _ofDict
->getObject(tmpSymbol
);
844 ok
= convertObjectToProp(tmpBuffer
, &length
, tmpSymbol
, tmpObject
);
853 bcopy(buffer
, _ofImage
, _ofPartitionSize
);
856 IODelete(buffer
, UInt8
, _ofPartitionSize
);
858 if (!ok
) return kIOReturnBadArgument
;
860 buffer
= IONew(UInt8
, _ofPartitionSize
);
861 if (buffer
== 0) return kIOReturnNoMemory
;
862 bzero(buffer
, _ofPartitionSize
);
864 owHeader
= (OWVariablesHeader
*)buffer
;
865 owHeaderOld
= (OWVariablesHeader
*)_ofImage
;
867 owHeader
->owMagic
= owHeaderOld
->owMagic
;
868 owHeader
->owVersion
= owHeaderOld
->owVersion
;
869 owHeader
->owPages
= owHeaderOld
->owPages
;
871 curOffset
= _ofPartitionSize
;
876 if (!getOWVariableInfo(cnt
++, &tmpSymbol
, &tmpType
, &tmpOffset
))
879 tmpObject
= _ofDict
->getObject(tmpSymbol
);
882 case kOFVariableTypeBoolean
:
883 tmpBoolean
= OSDynamicCast(OSBoolean
, tmpObject
);
884 if (tmpBoolean
->getValue()) owHeader
->owFlags
|= tmpOffset
;
887 case kOFVariableTypeNumber
:
888 tmpNumber
= OSDynamicCast(OSNumber
, tmpObject
);
889 owHeader
->owNumbers
[tmpOffset
] = tmpNumber
->unsigned32BitValue();
892 case kOFVariableTypeString
:
893 tmpString
= OSDynamicCast(OSString
, tmpObject
);
894 tmpData
= (const UInt8
*)tmpString
->getCStringNoCopy();
895 tmpDataLength
= tmpString
->getLength();
897 if ((curOffset
- tmpDataLength
) < sizeof(OWVariablesHeader
)) {
902 owHeader
->owStrings
[tmpOffset
].length
= tmpDataLength
;
903 curOffset
-= tmpDataLength
;
904 owHeader
->owStrings
[tmpOffset
].offset
= curOffset
+ _ofPartitionOffset
;
905 if (tmpDataLength
!= 0)
906 bcopy(tmpData
, buffer
+ curOffset
, tmpDataLength
);
912 owHeader
->owHere
= _ofPartitionOffset
+ sizeof(OWVariablesHeader
);
913 owHeader
->owTop
= _ofPartitionOffset
+ curOffset
;
914 owHeader
->owNext
= 0;
916 owHeader
->owChecksum
= 0;
917 owHeader
->owChecksum
= ~generateOWChecksum(buffer
);
919 bcopy(buffer
, _ofImage
, _ofPartitionSize
);
922 IODelete(buffer
, UInt8
, _ofPartitionSize
);
924 if (!ok
) return kIOReturnBadArgument
;
927 _ofImageDirty
= false;
928 _nvramImageDirty
= true;
930 return kIOReturnSuccess
;
934 const char *variableName
;
937 SInt32 variableOffset
;
939 typedef struct OFVariable OFVariable
;
942 kOWVariableOffsetNumber
= 8,
943 kOWVariableOffsetString
= 17
946 OFVariable gOFVariables
[] = {
947 {"little-endian?", kOFVariableTypeBoolean
, kOFVariablePermUserRead
, 0},
948 {"real-mode?", kOFVariableTypeBoolean
, kOFVariablePermUserRead
, 1},
949 {"auto-boot?", kOFVariableTypeBoolean
, kOFVariablePermUserRead
, 2},
950 {"diag-switch?", kOFVariableTypeBoolean
, kOFVariablePermUserRead
, 3},
951 {"fcode-debug?", kOFVariableTypeBoolean
, kOFVariablePermUserRead
, 4},
952 {"oem-banner?", kOFVariableTypeBoolean
, kOFVariablePermUserRead
, 5},
953 {"oem-logo?", kOFVariableTypeBoolean
, kOFVariablePermUserRead
, 6},
954 {"use-nvramrc?", kOFVariableTypeBoolean
, kOFVariablePermUserRead
, 7},
955 {"use-generic?", kOFVariableTypeBoolean
, kOFVariablePermUserRead
, -1},
956 {"default-mac-address?", kOFVariableTypeBoolean
, kOFVariablePermUserRead
,-1},
957 {"real-base", kOFVariableTypeNumber
, kOFVariablePermUserRead
, 8},
958 {"real-size", kOFVariableTypeNumber
, kOFVariablePermUserRead
, 9},
959 {"virt-base", kOFVariableTypeNumber
, kOFVariablePermUserRead
, 10},
960 {"virt-size", kOFVariableTypeNumber
, kOFVariablePermUserRead
, 11},
961 {"load-base", kOFVariableTypeNumber
, kOFVariablePermUserRead
, 12},
962 {"pci-probe-list", kOFVariableTypeNumber
, kOFVariablePermUserRead
, 13},
963 {"pci-probe-mask", kOFVariableTypeNumber
, kOFVariablePermUserRead
, -1},
964 {"screen-#columns", kOFVariableTypeNumber
, kOFVariablePermUserRead
, 14},
965 {"screen-#rows", kOFVariableTypeNumber
, kOFVariablePermUserRead
, 15},
966 {"selftest-#megs", kOFVariableTypeNumber
, kOFVariablePermUserRead
, 16},
967 {"boot-device", kOFVariableTypeString
, kOFVariablePermUserRead
, 17},
968 {"boot-file", kOFVariableTypeString
, kOFVariablePermUserRead
, 18},
969 {"boot-screen", kOFVariableTypeString
, kOFVariablePermUserRead
, -1},
970 {"console-screen", kOFVariableTypeString
, kOFVariablePermUserRead
, -1},
971 {"diag-device", kOFVariableTypeString
, kOFVariablePermUserRead
, 19},
972 {"diag-file", kOFVariableTypeString
, kOFVariablePermUserRead
, 20},
973 {"input-device", kOFVariableTypeString
, kOFVariablePermUserRead
, 21},
974 {"output-device", kOFVariableTypeString
, kOFVariablePermUserRead
, 22},
975 {"input-device-1", kOFVariableTypeString
, kOFVariablePermUserRead
, -1},
976 {"output-device-1", kOFVariableTypeString
, kOFVariablePermUserRead
, -1},
977 {"mouse-device", kOFVariableTypeString
, kOFVariablePermUserRead
, -1},
978 {"oem-banner", kOFVariableTypeString
, kOFVariablePermUserRead
, 23},
979 {"oem-logo", kOFVariableTypeString
, kOFVariablePermUserRead
, 24},
980 {"nvramrc", kOFVariableTypeString
, kOFVariablePermUserRead
, 25},
981 {"boot-command", kOFVariableTypeString
, kOFVariablePermUserRead
, 26},
982 {"default-client-ip", kOFVariableTypeString
, kOFVariablePermUserRead
, -1},
983 {"default-server-ip", kOFVariableTypeString
, kOFVariablePermUserRead
, -1},
984 {"default-gateway-ip", kOFVariableTypeString
, kOFVariablePermUserRead
, -1},
985 {"default-subnet-mask", kOFVariableTypeString
, kOFVariablePermUserRead
, -1},
986 {"default-router-ip", kOFVariableTypeString
, kOFVariablePermUserRead
, -1},
987 {"boot-script", kOFVariableTypeString
, kOFVariablePermUserRead
, -1},
988 {"boot-args", kOFVariableTypeString
, kOFVariablePermUserRead
, -1},
989 {"aapl,pci", kOFVariableTypeData
, kOFVariablePermRootOnly
, -1},
990 {"security-mode", kOFVariableTypeString
, kOFVariablePermUserRead
, -1},
991 {"security-password", kOFVariableTypeData
, kOFVariablePermRootOnly
, -1},
992 {"boot-image", kOFVariableTypeData
, kOFVariablePermUserWrite
, -1},
993 {"com.apple.System.fp-state", kOFVariableTypeData
, kOFVariablePermKernelOnly
, -1},
994 {0, kOFVariableTypeData
, kOFVariablePermUserRead
, -1}
997 UInt32
IODTNVRAM::getOFVariableType(const OSSymbol
*propSymbol
) const
1001 ofVar
= gOFVariables
;
1003 if ((ofVar
->variableName
== 0) ||
1004 propSymbol
->isEqualTo(ofVar
->variableName
)) break;
1008 return ofVar
->variableType
;
1011 UInt32
IODTNVRAM::getOFVariablePerm(const OSSymbol
*propSymbol
) const
1015 ofVar
= gOFVariables
;
1017 if ((ofVar
->variableName
== 0) ||
1018 propSymbol
->isEqualTo(ofVar
->variableName
)) break;
1022 return ofVar
->variablePerm
;
1025 bool IODTNVRAM::getOWVariableInfo(UInt32 variableNumber
, const OSSymbol
**propSymbol
,
1026 UInt32
*propType
, UInt32
*propOffset
)
1030 ofVar
= gOFVariables
;
1032 if (ofVar
->variableName
== 0) return false;
1034 if (ofVar
->variableOffset
== (SInt32
) variableNumber
) break;
1039 *propSymbol
= OSSymbol::withCStringNoCopy(ofVar
->variableName
);
1040 *propType
= ofVar
->variableType
;
1042 switch (*propType
) {
1043 case kOFVariableTypeBoolean
:
1044 *propOffset
= 1 << (31 - variableNumber
);
1047 case kOFVariableTypeNumber
:
1048 *propOffset
= variableNumber
- kOWVariableOffsetNumber
;
1051 case kOFVariableTypeString
:
1052 *propOffset
= variableNumber
- kOWVariableOffsetString
;
1059 bool IODTNVRAM::convertPropToObject(UInt8
*propName
, UInt32 propNameLength
,
1060 UInt8
*propData
, UInt32 propDataLength
,
1061 const OSSymbol
**propSymbol
,
1062 OSObject
**propObject
)
1065 const OSSymbol
*tmpSymbol
;
1066 OSObject
*tmpObject
;
1067 OSNumber
*tmpNumber
;
1068 OSString
*tmpString
;
1070 // Create the symbol.
1071 propName
[propNameLength
] = '\0';
1072 tmpSymbol
= OSSymbol::withCString((const char *)propName
);
1073 propName
[propNameLength
] = '=';
1074 if (tmpSymbol
== 0) {
1078 propType
= getOFVariableType(tmpSymbol
);
1080 // Create the object.
1083 case kOFVariableTypeBoolean
:
1084 if (!strncmp("true", (const char *)propData
, propDataLength
)) {
1085 tmpObject
= kOSBooleanTrue
;
1086 } else if (!strncmp("false", (const char *)propData
, propDataLength
)) {
1087 tmpObject
= kOSBooleanFalse
;
1091 case kOFVariableTypeNumber
:
1092 tmpNumber
= OSNumber::withNumber(strtol((const char *)propData
, 0, 0), 32);
1093 if (tmpNumber
!= 0) tmpObject
= tmpNumber
;
1096 case kOFVariableTypeString
:
1097 tmpString
= OSString::withCString((const char *)propData
);
1098 if (tmpString
!= 0) tmpObject
= tmpString
;
1101 case kOFVariableTypeData
:
1102 tmpObject
= unescapeBytesToData(propData
, propDataLength
);
1106 if (tmpObject
== 0) {
1107 tmpSymbol
->release();
1111 *propSymbol
= tmpSymbol
;
1112 *propObject
= tmpObject
;
1117 bool IODTNVRAM::convertObjectToProp(UInt8
*buffer
, UInt32
*length
,
1118 const OSSymbol
*propSymbol
, OSObject
*propObject
)
1120 const UInt8
*propName
;
1121 UInt32 propNameLength
, propDataLength
;
1122 UInt32 propType
, tmpValue
;
1123 OSBoolean
*tmpBoolean
= 0;
1124 OSNumber
*tmpNumber
= 0;
1125 OSString
*tmpString
= 0;
1126 OSData
*tmpData
= 0;
1128 propName
= (const UInt8
*)propSymbol
->getCStringNoCopy();
1129 propNameLength
= propSymbol
->getLength();
1130 propType
= getOFVariableType(propSymbol
);
1132 // Get the size of the data.
1133 propDataLength
= 0xFFFFFFFF;
1135 case kOFVariableTypeBoolean
:
1136 tmpBoolean
= OSDynamicCast(OSBoolean
, propObject
);
1137 if (tmpBoolean
!= 0) propDataLength
= 5;
1140 case kOFVariableTypeNumber
:
1141 tmpNumber
= OSDynamicCast(OSNumber
, propObject
);
1142 if (tmpNumber
!= 0) propDataLength
= 10;
1145 case kOFVariableTypeString
:
1146 tmpString
= OSDynamicCast(OSString
, propObject
);
1147 if (tmpString
!= 0) propDataLength
= tmpString
->getLength();
1150 case kOFVariableTypeData
:
1151 tmpData
= OSDynamicCast(OSData
, propObject
);
1153 tmpData
= escapeDataToData(tmpData
);
1154 propDataLength
= tmpData
->getLength();
1159 // Make sure the propertySize is known and will fit.
1160 if (propDataLength
== 0xFFFFFFFF) return false;
1161 if ((propNameLength
+ propDataLength
+ 2) > *length
) return false;
1163 // Copy the property name equal sign.
1164 buffer
+= snprintf((char *)buffer
, *length
, "%s=", propName
);
1167 case kOFVariableTypeBoolean
:
1168 if (tmpBoolean
->getValue()) {
1169 strlcpy((char *)buffer
, "true", *length
- propNameLength
);
1171 strlcpy((char *)buffer
, "false", *length
- propNameLength
);
1175 case kOFVariableTypeNumber
:
1176 tmpValue
= tmpNumber
->unsigned32BitValue();
1177 if (tmpValue
== 0xFFFFFFFF) {
1178 strlcpy((char *)buffer
, "-1", *length
- propNameLength
);
1179 } else if (tmpValue
< 1000) {
1180 snprintf((char *)buffer
, *length
- propNameLength
, "%d", (uint32_t)tmpValue
);
1182 snprintf((char *)buffer
, *length
- propNameLength
, "0x%x", (uint32_t)tmpValue
);
1186 case kOFVariableTypeString
:
1187 strlcpy((char *)buffer
, tmpString
->getCStringNoCopy(), *length
- propNameLength
);
1190 case kOFVariableTypeData
:
1191 bcopy(tmpData
->getBytesNoCopy(), buffer
, propDataLength
);
1196 propDataLength
= strlen((const char *)buffer
);
1198 *length
= propNameLength
+ propDataLength
+ 2;
1204 UInt16
IODTNVRAM::generateOWChecksum(UInt8
*buffer
)
1206 UInt32 cnt
, checksum
= 0;
1207 UInt16
*tmpBuffer
= (UInt16
*)buffer
;
1209 for (cnt
= 0; cnt
< _ofPartitionSize
/ 2; cnt
++)
1210 checksum
+= tmpBuffer
[cnt
];
1212 return checksum
% 0x0000FFFF;
1215 bool IODTNVRAM::validateOWChecksum(UInt8
*buffer
)
1217 UInt32 cnt
, checksum
, sum
= 0;
1218 UInt16
*tmpBuffer
= (UInt16
*)buffer
;
1220 for (cnt
= 0; cnt
< _ofPartitionSize
/ 2; cnt
++)
1221 sum
+= tmpBuffer
[cnt
];
1223 checksum
= (sum
>> 16) + (sum
& 0x0000FFFF);
1224 if (checksum
== 0x10000) checksum
--;
1225 checksum
= (checksum
^ 0x0000FFFF) & 0x0000FFFF;
1227 return checksum
== 0;
1230 void IODTNVRAM::updateOWBootArgs(const OSSymbol
*key
, OSObject
*value
)
1232 bool wasBootArgs
, bootr
= false;
1234 OSString
*tmpString
, *bootCommand
, *bootArgs
= 0;
1235 const UInt8
*bootCommandData
, *bootArgsData
;
1237 UInt32 bootCommandDataLength
, bootArgsDataLength
, tmpDataLength
;
1239 tmpString
= OSDynamicCast(OSString
, value
);
1240 if (tmpString
== 0) return;
1242 if (key
->isEqualTo("boot-command")) {
1243 wasBootArgs
= false;
1244 bootCommand
= tmpString
;
1245 } else if (key
->isEqualTo("boot-args")) {
1247 bootArgs
= tmpString
;
1248 bootCommand
= OSDynamicCast(OSString
, _ofDict
->getObject("boot-command"));
1249 if (bootCommand
== 0) return;
1252 bootCommandData
= (const UInt8
*)bootCommand
->getCStringNoCopy();
1253 bootCommandDataLength
= bootCommand
->getLength();
1255 if (bootCommandData
== 0) return;
1257 for (cnt
= 0; cnt
< bootCommandDataLength
; cnt
++) {
1258 if ((bootCommandData
[cnt
] == 'b') &&
1259 !strncmp("bootr", (const char *)bootCommandData
+ cnt
, 5)) {
1261 while (bootCommandData
[cnt
] == ' ') cnt
++;
1267 _ofDict
->removeObject("boot-args");
1272 bootArgsData
= (const UInt8
*)bootArgs
->getCStringNoCopy();
1273 bootArgsDataLength
= bootArgs
->getLength();
1274 if (bootArgsData
== 0) return;
1276 tmpDataLength
= cnt
+ bootArgsDataLength
;
1277 tmpData
= IONew(UInt8
, tmpDataLength
+ 1);
1278 if (tmpData
== 0) return;
1280 cnt
-= strlcpy((char *)tmpData
, (const char *)bootCommandData
, cnt
);
1281 strlcat((char *)tmpData
, (const char *)bootArgsData
, cnt
);
1283 bootCommand
= OSString::withCString((const char *)tmpData
);
1284 if (bootCommand
!= 0) {
1285 _ofDict
->setObject("boot-command", bootCommand
);
1286 bootCommand
->release();
1289 IODelete(tmpData
, UInt8
, tmpDataLength
+ 1);
1291 bootArgs
= OSString::withCString((const char *)(bootCommandData
+ cnt
));
1292 if (bootArgs
!= 0) {
1293 _ofDict
->setObject("boot-args", bootArgs
);
1294 bootArgs
->release();
1300 // Private methods for Name Registry access.
1303 kMaxNVNameLength
= 4,
1304 kMaxNVDataLength
= 8
1307 struct NVRAMProperty
1309 IONVRAMDescriptor header
;
1311 UInt8 name
[ kMaxNVNameLength
];
1313 UInt8 data
[ kMaxNVDataLength
];
1316 bool IODTNVRAM::searchNVRAMProperty(IONVRAMDescriptor
*hdr
, UInt32
*where
)
1321 nvEnd
= *((UInt16
*)_nrImage
);
1322 if(getPlatform()->getBootROMType()) {
1323 // on NewWorld, offset to partition start
1326 // on old world, absolute
1327 nvEnd
-= _nrPartitionOffset
;
1329 if((nvEnd
< 0) || (nvEnd
>= kIODTNVRAMNameRegistrySize
))
1333 while ((offset
+ sizeof(NVRAMProperty
)) <= (UInt32
)nvEnd
) {
1334 if (bcmp(_nrImage
+ offset
, hdr
, sizeof(*hdr
)) == 0) {
1338 offset
+= sizeof(NVRAMProperty
);
1341 if ((nvEnd
+ sizeof(NVRAMProperty
)) <= kIODTNVRAMNameRegistrySize
)
1349 IOReturn
IODTNVRAM::readNVRAMPropertyType0(IORegistryEntry
*entry
,
1350 const OSSymbol
**name
,
1353 IONVRAMDescriptor hdr
;
1354 NVRAMProperty
*prop
;
1358 char nameBuf
[kMaxNVNameLength
+ 1];
1360 if (_nrImage
== 0) return kIOReturnUnsupported
;
1361 if ((entry
== 0) || (name
== 0) || (value
== 0)) return kIOReturnBadArgument
;
1363 err
= IODTMakeNVDescriptor(entry
, &hdr
);
1364 if (err
!= kIOReturnSuccess
) return err
;
1366 if (searchNVRAMProperty(&hdr
, &offset
)) {
1367 prop
= (NVRAMProperty
*)(_nrImage
+ offset
);
1369 length
= prop
->nameLength
;
1370 if (length
> kMaxNVNameLength
) length
= kMaxNVNameLength
;
1371 strncpy(nameBuf
, (const char *)prop
->name
, length
);
1372 nameBuf
[length
] = 0;
1373 *name
= OSSymbol::withCString(nameBuf
);
1375 length
= prop
->dataLength
;
1376 if (length
> kMaxNVDataLength
) length
= kMaxNVDataLength
;
1377 *value
= OSData::withBytes(prop
->data
, length
);
1379 if ((*name
!= 0) && (*value
!= 0)) return kIOReturnSuccess
;
1380 else return kIOReturnNoMemory
;
1383 return kIOReturnNoResources
;
1386 IOReturn
IODTNVRAM::writeNVRAMPropertyType0(IORegistryEntry
*entry
,
1387 const OSSymbol
*name
,
1390 IONVRAMDescriptor hdr
;
1391 NVRAMProperty
*prop
;
1392 IOByteCount nameLength
;
1393 IOByteCount dataLength
;
1399 if (_nrImage
== 0) return kIOReturnUnsupported
;
1400 if ((entry
== 0) || (name
== 0) || (value
== 0)) return kIOReturnBadArgument
;
1402 nameLength
= name
->getLength();
1403 dataLength
= value
->getLength();
1404 if (nameLength
> kMaxNVNameLength
) return kIOReturnNoSpace
;
1405 if (dataLength
> kMaxNVDataLength
) return kIOReturnNoSpace
;
1407 err
= IODTMakeNVDescriptor(entry
, &hdr
);
1408 if (err
!= kIOReturnSuccess
) return err
;
1410 exists
= searchNVRAMProperty(&hdr
, &offset
);
1411 if (offset
== 0) return kIOReturnNoMemory
;
1413 prop
= (NVRAMProperty
*)(_nrImage
+ offset
);
1414 if (!exists
) bcopy(&hdr
, &prop
->header
, sizeof(hdr
));
1416 prop
->nameLength
= nameLength
;
1417 bcopy(name
->getCStringNoCopy(), prop
->name
, nameLength
);
1418 prop
->dataLength
= dataLength
;
1419 bcopy(value
->getBytesNoCopy(), prop
->data
, dataLength
);
1422 nvLength
= offset
+ sizeof(NVRAMProperty
);
1423 if (getPlatform()->getBootROMType())
1426 nvLength
+= _nrPartitionOffset
;
1427 *((UInt16
*)_nrImage
) = nvLength
;
1430 _nvramImageDirty
= true;
1435 OSData
*IODTNVRAM::unescapeBytesToData(const UInt8
*bytes
, UInt32 length
)
1438 UInt32 totalLength
= 0;
1443 // Calculate the actual length of the data.
1446 for (cnt
= 0; cnt
< length
;) {
1447 byte
= bytes
[cnt
++];
1449 byte
= bytes
[cnt
++];
1457 totalLength
+= cnt2
;
1461 // Create an empty OSData of the correct size.
1462 data
= OSData::withCapacity(totalLength
);
1464 for (cnt
= 0; cnt
< length
;) {
1465 byte
= bytes
[cnt
++];
1467 byte
= bytes
[cnt
++];
1469 byte
= (byte
& 0x80) ? 0xFF : 0x00;
1472 data
->appendByte(byte
, cnt2
);
1480 OSData
* IODTNVRAM::escapeDataToData(OSData
* value
)
1483 const UInt8
* startPtr
;
1484 const UInt8
* endPtr
;
1485 const UInt8
* wherePtr
;
1489 wherePtr
= (const UInt8
*) value
->getBytesNoCopy();
1490 endPtr
= wherePtr
+ value
->getLength();
1492 result
= OSData::withCapacity(endPtr
- wherePtr
);
1496 while (wherePtr
< endPtr
) {
1497 startPtr
= wherePtr
;
1499 if ((byte
== 0x00) || (byte
== 0xFF)) {
1501 ((wherePtr
- startPtr
) < 0x80) && (wherePtr
< endPtr
) && (byte
== *wherePtr
);
1503 ok
&= result
->appendByte(0xff, 1);
1504 byte
= (byte
& 0x80) | (wherePtr
- startPtr
);
1506 ok
&= result
->appendByte(byte
, 1);
1508 ok
&= result
->appendByte(0, 1);
1518 static bool IsApplePropertyName(const char * propName
)
1521 while ((c
= *propName
++)) {
1522 if ((c
>= 'A') && (c
<= 'Z'))
1529 IOReturn
IODTNVRAM::readNVRAMPropertyType1(IORegistryEntry
*entry
,
1530 const OSSymbol
**name
,
1533 IOReturn err
= kIOReturnNoResources
;
1535 const UInt8
*startPtr
;
1536 const UInt8
*endPtr
;
1537 const UInt8
*wherePtr
;
1538 const UInt8
*nvPath
= 0;
1539 const char *nvName
= 0;
1540 const char *resultName
= 0;
1541 const UInt8
*resultValue
= 0;
1542 UInt32 resultValueLen
= 0;
1545 if (_ofDict
== 0) return err
;
1546 data
= OSDynamicCast(OSData
, _ofDict
->getObject(_registryPropertiesKey
));
1547 if (data
== 0) return err
;
1549 startPtr
= (const UInt8
*) data
->getBytesNoCopy();
1550 endPtr
= startPtr
+ data
->getLength();
1552 wherePtr
= startPtr
;
1553 while (wherePtr
< endPtr
) {
1554 byte
= *(wherePtr
++);
1560 else if (nvName
== 0)
1561 nvName
= (const char *) startPtr
;
1563 IORegistryEntry
* compareEntry
= IORegistryEntry::fromPath((const char *) nvPath
, gIODTPlane
);
1565 compareEntry
->release();
1566 if (entry
== compareEntry
) {
1567 bool appleProp
= IsApplePropertyName(nvName
);
1568 if (!appleProp
|| !resultName
) {
1569 resultName
= nvName
;
1570 resultValue
= startPtr
;
1571 resultValueLen
= wherePtr
- startPtr
- 1;
1579 startPtr
= wherePtr
;
1582 *name
= OSSymbol::withCString(resultName
);
1583 *value
= unescapeBytesToData(resultValue
, resultValueLen
);
1584 if ((*name
!= 0) && (*value
!= 0))
1585 err
= kIOReturnSuccess
;
1587 err
= kIOReturnNoMemory
;
1592 IOReturn
IODTNVRAM::writeNVRAMPropertyType1(IORegistryEntry
*entry
,
1593 const OSSymbol
*propName
,
1598 const UInt8
*startPtr
;
1599 const UInt8
*propStart
;
1600 const UInt8
*endPtr
;
1601 const UInt8
*wherePtr
;
1602 const UInt8
*nvPath
= 0;
1603 const char *nvName
= 0;
1608 bool settingAppleProp
;
1610 if (_ofDict
== 0) return kIOReturnNoResources
;
1612 settingAppleProp
= IsApplePropertyName(propName
->getCStringNoCopy());
1614 // copy over existing properties for other entries
1616 oldData
= OSDynamicCast(OSData
, _ofDict
->getObject(_registryPropertiesKey
));
1618 startPtr
= (const UInt8
*) oldData
->getBytesNoCopy();
1619 endPtr
= startPtr
+ oldData
->getLength();
1621 propStart
= startPtr
;
1622 wherePtr
= startPtr
;
1623 while (wherePtr
< endPtr
) {
1624 byte
= *(wherePtr
++);
1629 else if (nvName
== 0)
1630 nvName
= (const char *) startPtr
;
1632 IORegistryEntry
* compareEntry
= IORegistryEntry::fromPath((const char *) nvPath
, gIODTPlane
);
1634 compareEntry
->release();
1635 if (entry
== compareEntry
) {
1636 if ((settingAppleProp
&& propName
->isEqualTo(nvName
))
1637 || (!settingAppleProp
&& !IsApplePropertyName(nvName
))) {
1638 // delete old property (nvPath -> wherePtr)
1639 data
= OSData::withBytes(propStart
, nvPath
- propStart
);
1641 ok
&= data
->appendBytes(wherePtr
, endPtr
- wherePtr
);
1649 startPtr
= wherePtr
;
1653 // make the new property
1657 data
= OSData::withData(oldData
);
1659 data
= OSData::withCapacity(16);
1661 return kIOReturnNoMemory
;
1664 if (value
&& value
->getLength()) {
1665 // get entries in path
1666 OSArray
*array
= OSArray::withCapacity(5);
1669 return kIOReturnNoMemory
;
1672 array
->setObject(entry
);
1673 while ((entry
= entry
->getParentEntry(gIODTPlane
)));
1676 for (int i
= array
->getCount() - 3;
1677 (entry
= (IORegistryEntry
*) array
->getObject(i
));
1680 name
= entry
->getName(gIODTPlane
);
1681 comp
= entry
->getLocation(gIODTPlane
);
1682 if( comp
&& (0 == strncmp("pci", name
, sizeof("pci")))
1683 && (0 == strncmp("80000000", comp
, sizeof("80000000")))) {
1685 comp
= "/pci@80000000";
1688 ok
&= data
->appendBytes("/@", 2);
1692 ok
&= data
->appendByte('/', 1);
1696 ok
&= data
->appendBytes(comp
, strlen(comp
));
1698 ok
&= data
->appendByte(0, 1);
1702 ok
&= data
->appendBytes(propName
->getCStringNoCopy(), propName
->getLength() + 1);
1704 // append escaped data
1705 oldData
= escapeDataToData(value
);
1706 ok
&= (oldData
!= 0);
1708 ok
&= data
->appendBytes(oldData
);
1711 ok
= _ofDict
->setObject(_registryPropertiesKey
, data
);
1713 _ofImageDirty
= true;
1717 return ok
? kIOReturnSuccess
: kIOReturnNoMemory
;
1720 bool IODTNVRAM::safeToSync(void)
1726 // delta interval went by
1727 clock_get_uptime(&delta
);
1729 // Figure it in seconds.
1730 absolutetime_to_nanoseconds(delta
, &delta_ns
);
1731 delta_secs
= (SInt32
)(delta_ns
/ NSEC_PER_SEC
);
1733 if ((delta_secs
> (_lastDeviceSync
+ MIN_SYNC_NOW_INTERVAL
)) || _freshInterval
)
1735 _lastDeviceSync
= delta_secs
;
1736 _freshInterval
= FALSE
;