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