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