xref: /xnu-11215/iokit/Kernel/IONVRAM.cpp (revision a3bb9fcc)
1 /*
2  * Copyright (c) 1998-2006 Apple Computer, Inc. All rights reserved.
3  * Copyright (c) 2007-2012 Apple Inc. All rights reserved.
4  *
5  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6  *
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.
15  *
16  * Please obtain a copy of the License at
17  * http://www.opensource.apple.com/apsl/ and read it before using this file.
18  *
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.
26  *
27  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
28  */
29 
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>
37 
38 #define super IOService
39 
40 #define kIONVRAMPrivilege	kIOClientPrivilegeAdministrator
41 //#define kIONVRAMPrivilege	kIOClientPrivilegeLocalUser
42 
43 OSDefineMetaClassAndStructors(IODTNVRAM, IOService);
44 
45 bool IODTNVRAM::init(IORegistryEntry *old, const IORegistryPlane *plane)
46 {
47   OSDictionary *dict;
48 
49   if (!super::init(old, plane)) return false;
50 
51   dict =  OSDictionary::withCapacity(1);
52   if (dict == 0) return false;
53   setPropertyTable(dict);
54 
55   _nvramImage = IONew(UInt8, kIODTNVRAMImageSize);
56   if (_nvramImage == 0) return false;
57 
58   _nvramPartitionOffsets = OSDictionary::withCapacity(1);
59   if (_nvramPartitionOffsets == 0) return false;
60 
61   _nvramPartitionLengths = OSDictionary::withCapacity(1);
62   if (_nvramPartitionLengths == 0) return false;
63 
64   _registryPropertiesKey = OSSymbol::withCStringNoCopy("aapl,pci");
65   if (_registryPropertiesKey == 0) return false;
66 
67   // <rdar://problem/9529235> race condition possible between
68   // IODTNVRAM and IONVRAMController (restore loses boot-args)
69   initProxyData();
70 
71   return true;
72 }
73 
74 void IODTNVRAM::initProxyData(void)
75 {
76   IORegistryEntry *entry;
77   const char *key = "nvram-proxy-data";
78   OSObject *prop;
79   OSData *data;
80   const void *bytes;
81 
82   entry = IORegistryEntry::fromPath("/chosen", gIODTPlane);
83   if (entry != 0) {
84     prop = entry->getProperty(key);
85     if (prop != 0) {
86       data = OSDynamicCast(OSData, prop);
87       if (data != 0) {
88         bytes = data->getBytesNoCopy();
89         if (bytes != 0) {
90           bcopy(bytes, _nvramImage, data->getLength());
91           initNVRAMImage();
92           _isProxied = true;
93         }
94       }
95     }
96     entry->removeProperty(key);
97     entry->release();
98   }
99 }
100 
101 void IODTNVRAM::registerNVRAMController(IONVRAMController *nvram)
102 {
103   if (_nvramController != 0) return;
104 
105   _nvramController = nvram;
106 
107   // <rdar://problem/9529235> race condition possible between
108   // IODTNVRAM and IONVRAMController (restore loses boot-args)
109   if (!_isProxied) {
110     _nvramController->read(0, _nvramImage, kIODTNVRAMImageSize);
111     initNVRAMImage();
112   }
113 }
114 
115 void IODTNVRAM::initNVRAMImage(void)
116 {
117   char   partitionID[18];
118   UInt32 partitionOffset, partitionLength;
119   UInt32 freePartitionOffset, freePartitionSize;
120   UInt32 currentLength, currentOffset = 0;
121   OSNumber *partitionOffsetNumber, *partitionLengthNumber;
122 
123   // Find the offsets for the OF, XPRAM, NameRegistry and PanicInfo partitions.
124   _ofPartitionOffset = 0xFFFFFFFF;
125   _piPartitionOffset = 0xFFFFFFFF;
126   freePartitionOffset = 0xFFFFFFFF;
127   freePartitionSize = 0;
128 
129   // Look through the partitions to find the OF, MacOS partitions.
130   while (currentOffset < kIODTNVRAMImageSize) {
131     currentLength = ((UInt16 *)(_nvramImage + currentOffset))[1] * 16;
132 
133     partitionOffset = currentOffset + 16;
134     partitionLength = currentLength - 16;
135 
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;
150     } else {
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';
157 
158       partitionOffsetNumber = OSNumber::withNumber(partitionOffset, 32);
159       partitionLengthNumber = OSNumber::withNumber(partitionLength, 32);
160 
161       // Save the partition offset and length
162       _nvramPartitionOffsets->setObject(partitionID, partitionOffsetNumber);
163       _nvramPartitionLengths->setObject(partitionID, partitionLengthNumber);
164 
165       partitionOffsetNumber->release();
166       partitionLengthNumber->release();
167     }
168     currentOffset += currentLength;
169   }
170 
171   if (_ofPartitionOffset != 0xFFFFFFFF)
172     _ofImage    = _nvramImage + _ofPartitionOffset;
173 
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);
183 
184       // Calculate the partition offset and size.
185       _piPartitionOffset = freePartitionOffset + 0x10;
186       _piPartitionSize = 0x800;
187       if (_piPartitionSize + 0x20 > freePartitionSize)
188 	_piPartitionSize = freePartitionSize - 0x20;
189 
190       _piImage = _nvramImage + _piPartitionOffset;
191 
192       // Zero the new partition.
193       bzero(_piImage, _piPartitionSize);
194 
195       // Set the partition size.
196       *(UInt16 *)(_nvramImage + freePartitionOffset + 2) =
197 	(_piPartitionSize / 0x10) + 1;
198 
199       // Set the partition checksum.
200       _nvramImage[freePartitionOffset + 1] =
201 	calculatePartitionChecksum(_nvramImage + freePartitionOffset);
202 
203       // Calculate the free partition offset and size.
204       freePartitionOffset += _piPartitionSize + 0x10;
205       freePartitionSize -= _piPartitionSize + 0x10;
206 
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);
220 
221       // Set the nvram image as dirty.
222       _nvramImageDirty = true;
223     }
224   } else {
225     _piImage = _nvramImage + _piPartitionOffset;
226   }
227 
228   _lastDeviceSync = 0;
229   _freshInterval = TRUE;		// we will allow sync() even before the first 15 minutes have passed.
230 
231   initOFVariables();
232 }
233 
234 void IODTNVRAM::sync(void)
235 {
236   if (!_nvramImageDirty && !_ofImageDirty) return;
237 
238   // Don't try to sync OF Variables if the system has already paniced.
239   if (!_systemPaniced) syncOFVariables();
240 
241   // Don't try to perform controller operations if none has been registered.
242   if (_nvramController == 0) return;
243 
244   _nvramController->write(0, _nvramImage, kIODTNVRAMImageSize);
245   _nvramController->sync();
246 
247   _nvramImageDirty = false;
248 }
249 
250 bool IODTNVRAM::serializeProperties(OSSerialize *s) const
251 {
252   bool                 result, hasPrivilege;
253   UInt32               variablePerm;
254   const OSSymbol       *key;
255   OSDictionary         *dict;
256   OSCollectionIterator *iter = 0;
257 
258   // Verify permissions.
259   hasPrivilege = (kIOReturnSuccess == IOUserClient::clientHasPrivilege(current_task(), kIONVRAMPrivilege));
260 
261   if (_ofDict == 0) {
262     /* No nvram. Return an empty dictionary. */
263     dict = OSDictionary::withCapacity(1);
264     if (dict == 0) return false;
265   } else {
266     IOLockLock(_ofLock);
267     dict = OSDictionary::withDictionary(_ofDict);
268     IOLockUnlock(_ofLock);
269     if (dict == 0) return false;
270 
271     /* Copy properties with client privilege. */
272     iter = OSCollectionIterator::withCollection(dict);
273     if (iter == 0) {
274       dict->release();
275       return false;
276     }
277     while (1) {
278       key = OSDynamicCast(OSSymbol, iter->getNextObject());
279       if (key == 0) break;
280 
281       variablePerm = getOFVariablePerm(key);
282       if ((hasPrivilege || (variablePerm != kOFVariablePermRootOnly)) &&
283 	  ( ! (variablePerm == kOFVariablePermKernelOnly && current_task() != kernel_task) )) {}
284       else dict->removeObject(key);
285     }
286   }
287 
288   result = dict->serialize(s);
289 
290   dict->release();
291   if (iter != 0) iter->release();
292 
293   return result;
294 }
295 
296 OSObject *IODTNVRAM::copyProperty(const OSSymbol *aKey) const
297 {
298   IOReturn result;
299   UInt32   variablePerm;
300   OSObject *theObject;
301 
302   if (_ofDict == 0) return 0;
303 
304   // Verify permissions.
305   variablePerm = getOFVariablePerm(aKey);
306   result = IOUserClient::clientHasPrivilege(current_task(), kIONVRAMPrivilege);
307   if (result != kIOReturnSuccess) {
308     if (variablePerm == kOFVariablePermRootOnly) return 0;
309   }
310   if (variablePerm == kOFVariablePermKernelOnly && current_task() != kernel_task) return 0;
311 
312   IOLockLock(_ofLock);
313   theObject = _ofDict->getObject(aKey);
314   if (theObject) theObject->retain();
315   IOLockUnlock(_ofLock);
316 
317   return theObject;
318 }
319 
320 OSObject *IODTNVRAM::copyProperty(const char *aKey) const
321 {
322   const OSSymbol *keySymbol;
323   OSObject *theObject = 0;
324 
325   keySymbol = OSSymbol::withCString(aKey);
326   if (keySymbol != 0) {
327     theObject = copyProperty(keySymbol);
328     keySymbol->release();
329   }
330 
331   return theObject;
332 }
333 
334 OSObject *IODTNVRAM::getProperty(const OSSymbol *aKey) const
335 {
336   OSObject *theObject;
337 
338   theObject = copyProperty(aKey);
339   if (theObject) theObject->release();
340 
341   return theObject;
342 }
343 
344 OSObject *IODTNVRAM::getProperty(const char *aKey) const
345 {
346   OSObject *theObject;
347 
348   theObject = copyProperty(aKey);
349   if (theObject) theObject->release();
350 
351   return theObject;
352 }
353 
354 bool IODTNVRAM::setProperty(const OSSymbol *aKey, OSObject *anObject)
355 {
356   bool     result;
357   UInt32   propType, propPerm;
358   OSString *tmpString;
359   OSObject *propObject = 0;
360 
361   if (_ofDict == 0) return false;
362 
363   // Verify permissions.
364   propPerm = getOFVariablePerm(aKey);
365   result = IOUserClient::clientHasPrivilege(current_task(), kIONVRAMPrivilege);
366   if (result != kIOReturnSuccess) {
367     if (propPerm != kOFVariablePermUserWrite) return false;
368   }
369   if (propPerm == kOFVariablePermKernelOnly && current_task() != kernel_task) return 0;
370 
371   // Don't allow change of 'aapl,panic-info'.
372   if (aKey->isEqualTo(kIODTNVRAMPanicInfoKey)) return false;
373 
374   // Make sure the object is of the correct type.
375   propType = getOFVariableType(aKey);
376   switch (propType) {
377   case kOFVariableTypeBoolean :
378     propObject = OSDynamicCast(OSBoolean, anObject);
379     break;
380 
381   case kOFVariableTypeNumber :
382     propObject = OSDynamicCast(OSNumber, anObject);
383     break;
384 
385   case kOFVariableTypeString :
386     propObject = OSDynamicCast(OSString, anObject);
387     break;
388 
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());
396       }
397     }
398     break;
399   }
400 
401   if (propObject == 0) return false;
402 
403   IOLockLock(_ofLock);
404   result = _ofDict->setObject(aKey, propObject);
405   IOLockUnlock(_ofLock);
406 
407   if (result) {
408     _ofImageDirty = true;
409   }
410 
411   return result;
412 }
413 
414 void IODTNVRAM::removeProperty(const OSSymbol *aKey)
415 {
416   bool     result;
417   UInt32   propPerm;
418 
419   if (_ofDict == 0) return;
420 
421   // Verify permissions.
422   propPerm = getOFVariablePerm(aKey);
423   result = IOUserClient::clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator);
424   if (result != kIOReturnSuccess) {
425     if (propPerm != kOFVariablePermUserWrite) return;
426   }
427   if (propPerm == kOFVariablePermKernelOnly && current_task() != kernel_task) return;
428 
429   // Don't allow change of 'aapl,panic-info'.
430   if (aKey->isEqualTo(kIODTNVRAMPanicInfoKey)) return;
431 
432   // If the object exists, remove it from the dictionary.
433 
434   IOLockLock(_ofLock);
435   result = _ofDict->getObject(aKey) != 0;
436   if (result) {
437     _ofDict->removeObject(aKey);
438     _ofImageDirty = true;
439   }
440   IOLockUnlock(_ofLock);
441 }
442 
443 IOReturn IODTNVRAM::setProperties(OSObject *properties)
444 {
445   bool                 result = true;
446   OSObject             *object;
447   const OSSymbol       *key;
448   const OSString       *tmpStr;
449   OSDictionary         *dict;
450   OSCollectionIterator *iter;
451 
452   dict = OSDynamicCast(OSDictionary, properties);
453   if (dict == 0) return kIOReturnBadArgument;
454 
455   iter = OSCollectionIterator::withCollection(dict);
456   if (iter == 0) return kIOReturnBadArgument;
457 
458   while (result) {
459     key = OSDynamicCast(OSSymbol, iter->getNextObject());
460     if (key == 0) break;
461 
462     object = dict->getObject(key);
463     if (object == 0) continue;
464 
465     if (key->isEqualTo(kIONVRAMDeletePropertyKey)) {
466 		tmpStr = OSDynamicCast(OSString, object);
467 		if (tmpStr != 0) {
468 			key = OSSymbol::withString(tmpStr);
469 			removeProperty(key);
470 			key->release();
471 			result = true;
472 		} else {
473 			result = false;
474 		}
475     } else if(key->isEqualTo(kIONVRAMSyncNowPropertyKey)) {
476 		tmpStr = OSDynamicCast(OSString, object);
477 		if (tmpStr != 0) {
478 
479 			result = true; // We are not going to gaurantee sync, this is best effort
480 
481 			if(safeToSync())
482 				sync();
483 
484 		} else {
485 			result = false;
486 		}
487 	}
488 	else {
489 		result = setProperty(key, object);
490     }
491 
492   }
493 
494   iter->release();
495 
496   if (result) return kIOReturnSuccess;
497   else return kIOReturnError;
498 }
499 
500 IOReturn IODTNVRAM::readXPRAM(IOByteCount offset, UInt8 *buffer,
501 			      IOByteCount length)
502 {
503   return kIOReturnUnsupported;
504 }
505 
506 IOReturn IODTNVRAM::writeXPRAM(IOByteCount offset, UInt8 *buffer,
507 			       IOByteCount length)
508 {
509   return kIOReturnUnsupported;
510 }
511 
512 IOReturn IODTNVRAM::readNVRAMProperty(IORegistryEntry *entry,
513 				      const OSSymbol **name,
514 				      OSData **value)
515 {
516   IOReturn err;
517 
518   err = readNVRAMPropertyType1(entry, name, value);
519 
520   return err;
521 }
522 
523 IOReturn IODTNVRAM::writeNVRAMProperty(IORegistryEntry *entry,
524 				       const OSSymbol *name,
525 				       OSData *value)
526 {
527   IOReturn err;
528 
529   err = writeNVRAMPropertyType1(entry, name, value);
530 
531   return err;
532 }
533 
534 OSDictionary *IODTNVRAM::getNVRAMPartitions(void)
535 {
536   return _nvramPartitionLengths;
537 }
538 
539 IOReturn IODTNVRAM::readNVRAMPartition(const OSSymbol *partitionID,
540 				       IOByteCount offset, UInt8 *buffer,
541 				       IOByteCount length)
542 {
543   OSNumber *partitionOffsetNumber, *partitionLengthNumber;
544   UInt32   partitionOffset, partitionLength;
545 
546   partitionOffsetNumber =
547     (OSNumber *)_nvramPartitionOffsets->getObject(partitionID);
548   partitionLengthNumber =
549     (OSNumber *)_nvramPartitionLengths->getObject(partitionID);
550 
551   if ((partitionOffsetNumber == 0) || (partitionLengthNumber == 0))
552     return kIOReturnNotFound;
553 
554   partitionOffset = partitionOffsetNumber->unsigned32BitValue();
555   partitionLength = partitionLengthNumber->unsigned32BitValue();
556 
557   if ((buffer == 0) || (length == 0) ||
558       (offset + length > partitionLength))
559     return kIOReturnBadArgument;
560 
561   bcopy(_nvramImage + partitionOffset + offset, buffer, length);
562 
563   return kIOReturnSuccess;
564 }
565 
566 IOReturn IODTNVRAM::writeNVRAMPartition(const OSSymbol *partitionID,
567 					IOByteCount offset, UInt8 *buffer,
568 					IOByteCount length)
569 {
570   OSNumber *partitionOffsetNumber, *partitionLengthNumber;
571   UInt32   partitionOffset, partitionLength;
572 
573   partitionOffsetNumber =
574     (OSNumber *)_nvramPartitionOffsets->getObject(partitionID);
575   partitionLengthNumber =
576     (OSNumber *)_nvramPartitionLengths->getObject(partitionID);
577 
578   if ((partitionOffsetNumber == 0) || (partitionLengthNumber == 0))
579     return kIOReturnNotFound;
580 
581   partitionOffset = partitionOffsetNumber->unsigned32BitValue();
582   partitionLength = partitionLengthNumber->unsigned32BitValue();
583 
584   if ((buffer == 0) || (length == 0) ||
585       (offset + length > partitionLength))
586     return kIOReturnBadArgument;
587 
588   bcopy(buffer, _nvramImage + partitionOffset + offset, length);
589 
590   _nvramImageDirty = true;
591 
592   return kIOReturnSuccess;
593 }
594 
595 IOByteCount IODTNVRAM::savePanicInfo(UInt8 *buffer, IOByteCount length)
596 {
597   if ((_piImage == 0) || (length <= 0)) return 0;
598 
599   if (length > (_piPartitionSize - 4))
600     length = _piPartitionSize - 4;
601 
602   // Save the Panic Info.
603   bcopy(buffer, _piImage + 4, length);
604 
605   // Save the Panic Info length.
606   *(UInt32 *)_piImage = length;
607 
608   _nvramImageDirty = true;
609   /*
610    * This prevents OF variables from being committed if the system has panicked
611    */
612   _systemPaniced = true;
613   /* The call to sync() forces the NVRAM controller to write the panic info
614    * partition to NVRAM.
615    */
616   sync();
617 
618   return length;
619 }
620 
621 // Private methods
622 
623 UInt8 IODTNVRAM::calculatePartitionChecksum(UInt8 *partitionHeader)
624 {
625   UInt8 cnt, isum, csum = 0;
626 
627   for (cnt = 0; cnt < 0x10; cnt++) {
628     isum = csum + partitionHeader[cnt];
629     if (isum < csum) isum++;
630     csum = isum;
631   }
632 
633   return csum;
634 }
635 
636 IOReturn IODTNVRAM::initOFVariables(void)
637 {
638   UInt32            cnt;
639   UInt8             *propName, *propData;
640   UInt32            propNameLength, propDataLength;
641   const OSSymbol    *propSymbol;
642   OSObject          *propObject;
643 
644   if (_ofImage == 0) return kIOReturnNotReady;
645 
646   _ofDict = OSDictionary::withCapacity(1);
647   _ofLock = IOLockAlloc();
648   if (!_ofDict || !_ofLock) return kIOReturnNoMemory;
649 
650   cnt = 0;
651   while (cnt < _ofPartitionSize) {
652     // Break if there is no name.
653     if (_ofImage[cnt] == '\0') break;
654 
655     // Find the length of the name.
656     propName = _ofImage + cnt;
657     for (propNameLength = 0; (cnt + propNameLength) < _ofPartitionSize;
658 	 propNameLength++) {
659       if (_ofImage[cnt + propNameLength] == '=') break;
660     }
661 
662     // Break if the name goes past the end of the partition.
663     if ((cnt + propNameLength) >= _ofPartitionSize) break;
664     cnt += propNameLength + 1;
665 
666     propData = _ofImage + cnt;
667     for (propDataLength = 0; (cnt + propDataLength) < _ofPartitionSize;
668 	 propDataLength++) {
669       if (_ofImage[cnt + propDataLength] == '\0') break;
670     }
671 
672     // Break if the data goes past the end of the partition.
673     if ((cnt + propDataLength) >= _ofPartitionSize) break;
674     cnt += propDataLength + 1;
675 
676     if (convertPropToObject(propName, propNameLength,
677 			    propData, propDataLength,
678 			    &propSymbol, &propObject)) {
679       _ofDict->setObject(propSymbol, propObject);
680       propSymbol->release();
681       propObject->release();
682     }
683   }
684 
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();
691     }
692   }
693 
694   // Create the 'aapl,panic-info' property if needed.
695   if (_piImage != 0) {
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();
701 
702       // Clear the length from _piImage and mark dirty.
703       *(UInt32 *)_piImage = 0;
704       _nvramImageDirty = true;
705     }
706   }
707 
708   return kIOReturnSuccess;
709 }
710 
711 IOReturn IODTNVRAM::syncOFVariables(void)
712 {
713   bool                 ok;
714   UInt32               length, maxLength;
715   UInt8                *buffer, *tmpBuffer;
716   const OSSymbol       *tmpSymbol;
717   OSObject             *tmpObject;
718   OSCollectionIterator *iter;
719 
720   if ((_ofImage == 0) || (_ofDict == 0)) return kIOReturnNotReady;
721 
722   if (!_ofImageDirty) return kIOReturnSuccess;
723 
724   buffer = tmpBuffer = IONew(UInt8, _ofPartitionSize);
725   if (buffer == 0) return kIOReturnNoMemory;
726   bzero(buffer, _ofPartitionSize);
727 
728   ok = true;
729   maxLength = _ofPartitionSize;
730 
731   IOLockLock(_ofLock);
732   iter = OSCollectionIterator::withCollection(_ofDict);
733   if (iter == 0) ok = false;
734 
735   while (ok) {
736     tmpSymbol = OSDynamicCast(OSSymbol, iter->getNextObject());
737     if (tmpSymbol == 0) break;
738 
739     // Don't save 'aapl,panic-info'.
740     if (tmpSymbol->isEqualTo(kIODTNVRAMPanicInfoKey)) continue;
741 
742     tmpObject = _ofDict->getObject(tmpSymbol);
743 
744     length = maxLength;
745     ok = convertObjectToProp(tmpBuffer, &length, tmpSymbol, tmpObject);
746     if (ok) {
747       tmpBuffer += length;
748       maxLength -= length;
749     }
750   }
751   iter->release();
752   IOLockUnlock(_ofLock);
753 
754   if (ok) {
755     bcopy(buffer, _ofImage, _ofPartitionSize);
756   }
757 
758   IODelete(buffer, UInt8, _ofPartitionSize);
759 
760   if (!ok) return kIOReturnBadArgument;
761 
762   _ofImageDirty = false;
763   _nvramImageDirty = true;
764 
765   return kIOReturnSuccess;
766 }
767 
768 struct OFVariable {
769   const char *variableName;
770   UInt32     variableType;
771   UInt32     variablePerm;
772   SInt32     variableOffset;
773 };
774 typedef struct OFVariable OFVariable;
775 
776 enum {
777   kOWVariableOffsetNumber = 8,
778   kOWVariableOffsetString = 17
779 };
780 
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}
830 };
831 
832 UInt32 IODTNVRAM::getOFVariableType(const OSSymbol *propSymbol) const
833 {
834   OFVariable *ofVar;
835 
836   ofVar = gOFVariables;
837   while (1) {
838     if ((ofVar->variableName == 0) ||
839 	propSymbol->isEqualTo(ofVar->variableName)) break;
840     ofVar++;
841   }
842 
843   return ofVar->variableType;
844 }
845 
846 UInt32 IODTNVRAM::getOFVariablePerm(const OSSymbol *propSymbol) const
847 {
848   OFVariable *ofVar;
849 
850   ofVar = gOFVariables;
851   while (1) {
852     if ((ofVar->variableName == 0) ||
853 	propSymbol->isEqualTo(ofVar->variableName)) break;
854     ofVar++;
855   }
856 
857   return ofVar->variablePerm;
858 }
859 
860 bool IODTNVRAM::getOWVariableInfo(UInt32 variableNumber, const OSSymbol **propSymbol,
861 				  UInt32 *propType, UInt32 *propOffset)
862 {
863   OFVariable *ofVar;
864 
865   ofVar = gOFVariables;
866   while (1) {
867     if (ofVar->variableName == 0) return false;
868 
869     if (ofVar->variableOffset == (SInt32) variableNumber) break;
870 
871     ofVar++;
872   }
873 
874   *propSymbol = OSSymbol::withCStringNoCopy(ofVar->variableName);
875   *propType = ofVar->variableType;
876 
877   switch (*propType) {
878   case kOFVariableTypeBoolean :
879     *propOffset = 1 << (31 - variableNumber);
880     break;
881 
882   case kOFVariableTypeNumber :
883     *propOffset = variableNumber - kOWVariableOffsetNumber;
884     break;
885 
886   case kOFVariableTypeString :
887     *propOffset = variableNumber - kOWVariableOffsetString;
888     break;
889   }
890 
891   return true;
892 }
893 
894 bool IODTNVRAM::convertPropToObject(UInt8 *propName, UInt32 propNameLength,
895 				    UInt8 *propData, UInt32 propDataLength,
896 				    const OSSymbol **propSymbol,
897 				    OSObject **propObject)
898 {
899   UInt32         propType;
900   const OSSymbol *tmpSymbol;
901   OSObject       *tmpObject;
902   OSNumber       *tmpNumber;
903   OSString       *tmpString;
904 
905   // Create the symbol.
906   propName[propNameLength] = '\0';
907   tmpSymbol = OSSymbol::withCString((const char *)propName);
908   propName[propNameLength] = '=';
909   if (tmpSymbol == 0) {
910     return false;
911   }
912 
913   propType = getOFVariableType(tmpSymbol);
914 
915   // Create the object.
916   tmpObject = 0;
917   switch (propType) {
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;
923     }
924     break;
925 
926   case kOFVariableTypeNumber :
927     tmpNumber = OSNumber::withNumber(strtol((const char *)propData, 0, 0), 32);
928     if (tmpNumber != 0) tmpObject = tmpNumber;
929     break;
930 
931   case kOFVariableTypeString :
932     tmpString = OSString::withCString((const char *)propData);
933     if (tmpString != 0) tmpObject = tmpString;
934     break;
935 
936   case kOFVariableTypeData :
937     tmpObject = unescapeBytesToData(propData, propDataLength);
938     break;
939   }
940 
941   if (tmpObject == 0) {
942     tmpSymbol->release();
943     return false;
944   }
945 
946   *propSymbol = tmpSymbol;
947   *propObject = tmpObject;
948 
949   return true;
950 }
951 
952 bool IODTNVRAM::convertObjectToProp(UInt8 *buffer, UInt32 *length,
953 				    const OSSymbol *propSymbol, OSObject *propObject)
954 {
955   const UInt8    *propName;
956   UInt32         propNameLength, propDataLength;
957   UInt32         propType, tmpValue;
958   OSBoolean      *tmpBoolean = 0;
959   OSNumber       *tmpNumber = 0;
960   OSString       *tmpString = 0;
961   OSData         *tmpData = 0;
962 
963   propName = (const UInt8 *)propSymbol->getCStringNoCopy();
964   propNameLength = propSymbol->getLength();
965   propType = getOFVariableType(propSymbol);
966 
967   // Get the size of the data.
968   propDataLength = 0xFFFFFFFF;
969   switch (propType) {
970   case kOFVariableTypeBoolean :
971     tmpBoolean = OSDynamicCast(OSBoolean, propObject);
972     if (tmpBoolean != 0) propDataLength = 5;
973     break;
974 
975   case kOFVariableTypeNumber :
976     tmpNumber = OSDynamicCast(OSNumber, propObject);
977     if (tmpNumber != 0) propDataLength = 10;
978     break;
979 
980   case kOFVariableTypeString :
981     tmpString = OSDynamicCast(OSString, propObject);
982     if (tmpString != 0) propDataLength = tmpString->getLength();
983     break;
984 
985   case kOFVariableTypeData :
986     tmpData = OSDynamicCast(OSData, propObject);
987     if (tmpData != 0) {
988       tmpData = escapeDataToData(tmpData);
989       propDataLength = tmpData->getLength();
990     }
991     break;
992   }
993 
994   // Make sure the propertySize is known and will fit.
995   if (propDataLength == 0xFFFFFFFF) return false;
996   if ((propNameLength + propDataLength + 2) > *length) return false;
997 
998   // Copy the property name equal sign.
999   buffer += snprintf((char *)buffer, *length, "%s=", propName);
1000 
1001   switch (propType) {
1002   case kOFVariableTypeBoolean :
1003     if (tmpBoolean->getValue()) {
1004       strlcpy((char *)buffer, "true", *length - propNameLength);
1005     } else {
1006       strlcpy((char *)buffer, "false", *length - propNameLength);
1007     }
1008     break;
1009 
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);
1016     } else {
1017       snprintf((char *)buffer, *length - propNameLength, "0x%x", (uint32_t)tmpValue);
1018     }
1019     break;
1020 
1021   case kOFVariableTypeString :
1022     strlcpy((char *)buffer, tmpString->getCStringNoCopy(), *length - propNameLength);
1023     break;
1024 
1025   case kOFVariableTypeData :
1026     bcopy(tmpData->getBytesNoCopy(), buffer, propDataLength);
1027     tmpData->release();
1028     break;
1029   }
1030 
1031   propDataLength = strlen((const char *)buffer);
1032 
1033   *length = propNameLength + propDataLength + 2;
1034 
1035   return true;
1036 }
1037 
1038 
1039 UInt16 IODTNVRAM::generateOWChecksum(UInt8 *buffer)
1040 {
1041   UInt32 cnt, checksum = 0;
1042   UInt16 *tmpBuffer = (UInt16 *)buffer;
1043 
1044   for (cnt = 0; cnt < _ofPartitionSize / 2; cnt++)
1045     checksum += tmpBuffer[cnt];
1046 
1047   return checksum % 0x0000FFFF;
1048 }
1049 
1050 bool IODTNVRAM::validateOWChecksum(UInt8 *buffer)
1051 {
1052   UInt32 cnt, checksum, sum = 0;
1053   UInt16 *tmpBuffer = (UInt16 *)buffer;
1054 
1055   for (cnt = 0; cnt < _ofPartitionSize / 2; cnt++)
1056     sum += tmpBuffer[cnt];
1057 
1058   checksum = (sum >> 16) + (sum & 0x0000FFFF);
1059   if (checksum == 0x10000) checksum--;
1060   checksum = (checksum ^ 0x0000FFFF) & 0x0000FFFF;
1061 
1062   return checksum == 0;
1063 }
1064 
1065 void IODTNVRAM::updateOWBootArgs(const OSSymbol *key, OSObject *value)
1066 {
1067   bool        wasBootArgs, bootr = false;
1068   UInt32      cnt;
1069   OSString    *tmpString, *bootCommand, *bootArgs = 0;
1070   const UInt8 *bootCommandData, *bootArgsData;
1071   UInt8       *tmpData;
1072   UInt32      bootCommandDataLength, bootArgsDataLength, tmpDataLength;
1073 
1074   tmpString = OSDynamicCast(OSString, value);
1075   if (tmpString == 0) return;
1076 
1077   if (key->isEqualTo("boot-command")) {
1078     wasBootArgs = false;
1079     bootCommand = tmpString;
1080   } else if (key->isEqualTo("boot-args")) {
1081     wasBootArgs = true;
1082     bootArgs = tmpString;
1083     bootCommand = OSDynamicCast(OSString, _ofDict->getObject("boot-command"));
1084     if (bootCommand == 0) return;
1085   } else return;
1086 
1087   bootCommandData = (const UInt8 *)bootCommand->getCStringNoCopy();
1088   bootCommandDataLength = bootCommand->getLength();
1089 
1090   if (bootCommandData == 0) return;
1091 
1092   for (cnt = 0; cnt < bootCommandDataLength; cnt++) {
1093     if ((bootCommandData[cnt] == 'b') &&
1094 	!strncmp("bootr", (const char *)bootCommandData + cnt, 5)) {
1095       cnt += 5;
1096       while (bootCommandData[cnt] == ' ') cnt++;
1097       bootr = true;
1098       break;
1099     }
1100   }
1101   if (!bootr) {
1102     _ofDict->removeObject("boot-args");
1103     return;
1104   }
1105 
1106   if (wasBootArgs) {
1107     bootArgsData = (const UInt8 *)bootArgs->getCStringNoCopy();
1108     bootArgsDataLength = bootArgs->getLength();
1109     if (bootArgsData == 0) return;
1110 
1111     tmpDataLength = cnt + bootArgsDataLength;
1112     tmpData = IONew(UInt8, tmpDataLength + 1);
1113     if (tmpData == 0) return;
1114 
1115     cnt -= strlcpy((char *)tmpData, (const char *)bootCommandData, cnt);
1116     strlcat((char *)tmpData, (const char *)bootArgsData, cnt);
1117 
1118     bootCommand = OSString::withCString((const char *)tmpData);
1119     if (bootCommand != 0) {
1120       _ofDict->setObject("boot-command", bootCommand);
1121       bootCommand->release();
1122     }
1123 
1124     IODelete(tmpData, UInt8, tmpDataLength + 1);
1125   } else {
1126     bootArgs = OSString::withCString((const char *)(bootCommandData + cnt));
1127     if (bootArgs != 0) {
1128       _ofDict->setObject("boot-args", bootArgs);
1129       bootArgs->release();
1130     }
1131   }
1132 }
1133 
1134 bool IODTNVRAM::searchNVRAMProperty(IONVRAMDescriptor *hdr, UInt32 *where)
1135 {
1136   return false;
1137 }
1138 
1139 IOReturn IODTNVRAM::readNVRAMPropertyType0(IORegistryEntry *entry,
1140 					   const OSSymbol **name,
1141 					   OSData **value)
1142 {
1143   return kIOReturnUnsupported;
1144 }
1145 
1146 
1147 IOReturn IODTNVRAM::writeNVRAMPropertyType0(IORegistryEntry *entry,
1148 					    const OSSymbol *name,
1149 					    OSData *value)
1150 {
1151   return kIOReturnUnsupported;
1152 }
1153 
1154 
1155 OSData *IODTNVRAM::unescapeBytesToData(const UInt8 *bytes, UInt32 length)
1156 {
1157   OSData *data = 0;
1158   UInt32 totalLength = 0;
1159   UInt32 cnt, cnt2;
1160   UInt8  byte;
1161   bool   ok;
1162 
1163   // Calculate the actual length of the data.
1164   ok = true;
1165   totalLength = 0;
1166   for (cnt = 0; cnt < length;) {
1167     byte = bytes[cnt++];
1168     if (byte == 0xFF) {
1169       byte = bytes[cnt++];
1170       if (byte == 0x00) {
1171         ok = false;
1172         break;
1173       }
1174       cnt2 = byte & 0x7F;
1175     } else
1176       cnt2 = 1;
1177     totalLength += cnt2;
1178   }
1179 
1180   if (ok) {
1181     // Create an empty OSData of the correct size.
1182     data = OSData::withCapacity(totalLength);
1183     if (data != 0) {
1184       for (cnt = 0; cnt < length;) {
1185         byte = bytes[cnt++];
1186         if (byte == 0xFF) {
1187           byte = bytes[cnt++];
1188           cnt2 = byte & 0x7F;
1189           byte = (byte & 0x80) ? 0xFF : 0x00;
1190         } else
1191           cnt2 = 1;
1192         data->appendByte(byte, cnt2);
1193       }
1194     }
1195   }
1196 
1197   return data;
1198 }
1199 
1200 OSData * IODTNVRAM::escapeDataToData(OSData * value)
1201 {
1202   OSData *       result;
1203   const UInt8 *  startPtr;
1204   const UInt8 *  endPtr;
1205   const UInt8 *  wherePtr;
1206   UInt8          byte;
1207   bool	         ok = true;
1208 
1209   wherePtr = (const UInt8 *) value->getBytesNoCopy();
1210   endPtr = wherePtr + value->getLength();
1211 
1212   result = OSData::withCapacity(endPtr - wherePtr);
1213   if (!result)
1214     return result;
1215 
1216   while (wherePtr < endPtr) {
1217     startPtr = wherePtr;
1218     byte = *wherePtr++;
1219     if ((byte == 0x00) || (byte == 0xFF)) {
1220       for (;
1221             ((wherePtr - startPtr) < 0x80) && (wherePtr < endPtr) && (byte == *wherePtr);
1222             wherePtr++)	{}
1223       ok &= result->appendByte(0xff, 1);
1224       byte = (byte & 0x80) | (wherePtr - startPtr);
1225     }
1226     ok &= result->appendByte(byte, 1);
1227   }
1228   ok &= result->appendByte(0, 1);
1229 
1230   if (!ok) {
1231     result->release();
1232     result = 0;
1233   }
1234 
1235   return result;
1236 }
1237 
1238 static bool IsApplePropertyName(const char * propName)
1239 {
1240   char c;
1241   while ((c = *propName++)) {
1242     if ((c >= 'A') && (c <= 'Z'))
1243       break;
1244   }
1245 
1246   return (c == 0);
1247 }
1248 
1249 IOReturn IODTNVRAM::readNVRAMPropertyType1(IORegistryEntry *entry,
1250 					   const OSSymbol **name,
1251 					   OSData **value)
1252 {
1253   IOReturn    err = kIOReturnNoResources;
1254   OSData      *data;
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;
1263   UInt8       byte;
1264 
1265   if (_ofDict == 0) return err;
1266 
1267   IOLockLock(_ofLock);
1268   data = OSDynamicCast(OSData, _ofDict->getObject(_registryPropertiesKey));
1269   IOLockUnlock(_ofLock);
1270 
1271   if (data == 0) return err;
1272 
1273   startPtr = (const UInt8 *) data->getBytesNoCopy();
1274   endPtr = startPtr + data->getLength();
1275 
1276   wherePtr = startPtr;
1277   while (wherePtr < endPtr) {
1278     byte = *(wherePtr++);
1279     if (byte)
1280       continue;
1281 
1282     if (nvPath == 0)
1283       nvPath = startPtr;
1284     else if (nvName == 0)
1285       nvName = (const char *) startPtr;
1286     else {
1287       IORegistryEntry * compareEntry = IORegistryEntry::fromPath((const char *) nvPath, gIODTPlane);
1288       if (compareEntry)
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;
1296         }
1297         if (!appleProp)
1298           break;
1299       }
1300       nvPath = 0;
1301       nvName = 0;
1302     }
1303     startPtr = wherePtr;
1304   }
1305   if (resultName) {
1306     *name = OSSymbol::withCString(resultName);
1307     *value = unescapeBytesToData(resultValue, resultValueLen);
1308     if ((*name != 0) && (*value != 0))
1309       err = kIOReturnSuccess;
1310     else
1311       err = kIOReturnNoMemory;
1312   }
1313   return err;
1314 }
1315 
1316 IOReturn IODTNVRAM::writeNVRAMPropertyType1(IORegistryEntry *entry,
1317 					    const OSSymbol *propName,
1318 					    OSData *value)
1319 {
1320   OSData       *oldData;
1321   OSData       *data = 0;
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;
1328   const char * comp;
1329   const char * name;
1330   UInt8        byte;
1331   bool         ok = true;
1332   bool         settingAppleProp;
1333 
1334   if (_ofDict == 0) return kIOReturnNoResources;
1335 
1336   settingAppleProp = IsApplePropertyName(propName->getCStringNoCopy());
1337 
1338   // copy over existing properties for other entries
1339 
1340   IOLockLock(_ofLock);
1341 
1342   oldData = OSDynamicCast(OSData, _ofDict->getObject(_registryPropertiesKey));
1343   if (oldData) {
1344     startPtr = (const UInt8 *) oldData->getBytesNoCopy();
1345     endPtr = startPtr + oldData->getLength();
1346 
1347     propStart = startPtr;
1348     wherePtr = startPtr;
1349     while (wherePtr < endPtr) {
1350       byte = *(wherePtr++);
1351       if (byte)
1352         continue;
1353       if (nvPath == 0)
1354         nvPath = startPtr;
1355       else if (nvName == 0)
1356         nvName = (const char *) startPtr;
1357       else {
1358         IORegistryEntry * compareEntry = IORegistryEntry::fromPath((const char *) nvPath, gIODTPlane);
1359         if (compareEntry)
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);
1366              if (data)
1367                ok &= data->appendBytes(wherePtr, endPtr - wherePtr);
1368              break;
1369           }
1370         }
1371         nvPath = 0;
1372         nvName = 0;
1373       }
1374 
1375       startPtr = wherePtr;
1376     }
1377   }
1378 
1379   // make the new property
1380 
1381   if (!data) {
1382     if (oldData)
1383       data = OSData::withData(oldData);
1384     else
1385       data = OSData::withCapacity(16);
1386     if (!data) ok = false;
1387   }
1388 
1389   if (ok && value && value->getLength()) do {
1390     // get entries in path
1391     OSArray *array = OSArray::withCapacity(5);
1392     if (!array) {
1393       ok = false;
1394       break;
1395     }
1396     do
1397       array->setObject(entry);
1398     while ((entry = entry->getParentEntry(gIODTPlane)));
1399 
1400     // append path
1401     for (int i = array->getCount() - 3;
1402 	 (entry = (IORegistryEntry *) array->getObject(i));
1403 	 i--) {
1404 
1405       name = entry->getName(gIODTPlane);
1406       comp = entry->getLocation(gIODTPlane);
1407       if (comp) ok &= data->appendBytes("/@", 2);
1408       else {
1409 	if (!name) continue;
1410 	ok &= data->appendByte('/', 1);
1411 	comp = name;
1412       }
1413       ok &= data->appendBytes(comp, strlen(comp));
1414     }
1415     ok &= data->appendByte(0, 1);
1416     array->release();
1417 
1418     // append prop name
1419     ok &= data->appendBytes(propName->getCStringNoCopy(), propName->getLength() + 1);
1420 
1421     // append escaped data
1422     oldData = escapeDataToData(value);
1423     ok &= (oldData != 0);
1424     if (ok) ok &= data->appendBytes(oldData);
1425 
1426   } while (false);
1427 
1428   if (ok) {
1429     ok = _ofDict->setObject(_registryPropertiesKey, data);
1430     if (ok) _ofImageDirty = true;
1431   }
1432 
1433   IOLockUnlock(_ofLock);
1434   if (data) data->release();
1435 
1436   return ok ? kIOReturnSuccess : kIOReturnNoMemory;
1437 }
1438 
1439 bool IODTNVRAM::safeToSync(void)
1440 {
1441     AbsoluteTime delta;
1442     UInt64       delta_ns;
1443     SInt32       delta_secs;
1444 
1445 	// delta interval went by
1446 	clock_get_uptime(&delta);
1447 
1448     // Figure it in seconds.
1449     absolutetime_to_nanoseconds(delta, &delta_ns);
1450     delta_secs = (SInt32)(delta_ns / NSEC_PER_SEC);
1451 
1452 	if ((delta_secs > (_lastDeviceSync + MIN_SYNC_NOW_INTERVAL)) || _freshInterval)
1453 	{
1454 		_lastDeviceSync = delta_secs;
1455 		_freshInterval = FALSE;
1456 		return TRUE;
1457 	}
1458 
1459 	return FALSE;
1460 }
1461