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