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