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