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
43OSDefineMetaClassAndStructors(IODTNVRAM, IOService);
44
45bool 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
70void 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
211void 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
224bool 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
263OSObject *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
281OSObject *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
295bool 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
362void 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
392IOReturn 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
435IOReturn 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
449IOReturn 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
465IOReturn 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
479IOReturn 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
493OSDictionary *IODTNVRAM::getNVRAMPartitions(void)
494{
495  return _nvramPartitionLengths;
496}
497
498IOReturn 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
525IOReturn 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
554UInt32 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
582UInt8 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
595struct 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};
610typedef struct OWVariablesHeader OWVariablesHeader;
611
612IOReturn 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
741IOReturn 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
870struct OFVariable {
871  const char *variableName;
872  UInt32     variableType;
873  UInt32     variablePerm;
874  SInt32     variableOffset;
875};
876typedef struct OFVariable OFVariable;
877
878enum {
879  kOWVariableOffsetNumber = 8,
880  kOWVariableOffsetString = 17
881};
882
883OFVariable 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
937UInt32 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
951UInt32 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
965bool 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
999bool 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
1057bool 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, "%ld", tmpValue);
1121    } else {
1122      snprintf((char *)buffer, *length - propNameLength, "0x%lx", 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
1144UInt16 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
1155bool 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
1170void 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
1242enum {
1243  kMaxNVNameLength = 4,
1244  kMaxNVDataLength = 8
1245};
1246
1247#pragma options align=mac68k
1248struct NVRAMProperty
1249{
1250  IONVRAMDescriptor   header;
1251  UInt8               nameLength;
1252  UInt8               name[ kMaxNVNameLength ];
1253  UInt8               dataLength;
1254  UInt8               data[ kMaxNVDataLength ];
1255};
1256#pragma options align=reset
1257
1258bool IODTNVRAM::searchNVRAMProperty(IONVRAMDescriptor *hdr, UInt32 *where)
1259{
1260  UInt32 offset;
1261  SInt32 nvEnd;
1262
1263  nvEnd = *((UInt16 *)_nrImage);
1264  if(getPlatform()->getBootROMType()) {
1265    // on NewWorld, offset to partition start
1266    nvEnd -= 0x100;
1267  } else {
1268    // on old world, absolute
1269    nvEnd -= _nrPartitionOffset;
1270  }
1271  if((nvEnd < 0) || (nvEnd >= kIODTNVRAMNameRegistrySize))
1272    nvEnd = 2;
1273
1274  offset = 2;
1275  while ((offset + sizeof(NVRAMProperty)) <= (UInt32)nvEnd) {
1276    if (bcmp(_nrImage + offset, hdr, sizeof(*hdr)) == 0) {
1277      *where = offset;
1278      return true;
1279    }
1280    offset += sizeof(NVRAMProperty);
1281  }
1282
1283  if ((nvEnd + sizeof(NVRAMProperty)) <= kIODTNVRAMNameRegistrySize)
1284    *where = nvEnd;
1285  else
1286    *where = 0;
1287
1288  return false;
1289}
1290
1291IOReturn IODTNVRAM::readNVRAMPropertyType0(IORegistryEntry *entry,
1292					   const OSSymbol **name,
1293					   OSData **value)
1294{
1295  IONVRAMDescriptor hdr;
1296  NVRAMProperty     *prop;
1297  IOByteCount       length;
1298  UInt32            offset;
1299  IOReturn          err;
1300  char              nameBuf[kMaxNVNameLength + 1];
1301
1302  if (_nrImage == 0) return kIOReturnUnsupported;
1303  if ((entry == 0) || (name == 0) || (value == 0)) return kIOReturnBadArgument;
1304
1305  err = IODTMakeNVDescriptor(entry, &hdr);
1306  if (err != kIOReturnSuccess) return err;
1307
1308  if (searchNVRAMProperty(&hdr, &offset)) {
1309    prop = (NVRAMProperty *)(_nrImage + offset);
1310
1311    length = prop->nameLength;
1312    if (length > kMaxNVNameLength) length = kMaxNVNameLength;
1313    strncpy(nameBuf, (const char *)prop->name, length);
1314    nameBuf[length] = 0;
1315    *name = OSSymbol::withCString(nameBuf);
1316
1317    length = prop->dataLength;
1318    if (length > kMaxNVDataLength) length = kMaxNVDataLength;
1319    *value = OSData::withBytes(prop->data, length);
1320
1321    if ((*name != 0) && (*value != 0)) return kIOReturnSuccess;
1322    else return kIOReturnNoMemory;
1323  }
1324
1325  return kIOReturnNoResources;
1326}
1327
1328IOReturn IODTNVRAM::writeNVRAMPropertyType0(IORegistryEntry *entry,
1329					    const OSSymbol *name,
1330					    OSData *value)
1331{
1332  IONVRAMDescriptor hdr;
1333  NVRAMProperty     *prop;
1334  IOByteCount       nameLength;
1335  IOByteCount       dataLength;
1336  UInt32            offset;
1337  IOReturn          err;
1338  UInt16            nvLength;
1339  bool              exists;
1340
1341  if (_nrImage == 0) return kIOReturnUnsupported;
1342  if ((entry == 0) || (name == 0) || (value == 0)) return kIOReturnBadArgument;
1343
1344  nameLength = name->getLength();
1345  dataLength = value->getLength();
1346  if (nameLength > kMaxNVNameLength) return kIOReturnNoSpace;
1347  if (dataLength > kMaxNVDataLength) return kIOReturnNoSpace;
1348
1349  err = IODTMakeNVDescriptor(entry, &hdr);
1350  if (err != kIOReturnSuccess) return err;
1351
1352  exists = searchNVRAMProperty(&hdr, &offset);
1353  if (offset == 0) return kIOReturnNoMemory;
1354
1355  prop = (NVRAMProperty *)(_nrImage + offset);
1356  if (!exists) bcopy(&hdr, &prop->header, sizeof(hdr));
1357
1358  prop->nameLength = nameLength;
1359  bcopy(name->getCStringNoCopy(), prop->name, nameLength);
1360  prop->dataLength = dataLength;
1361  bcopy(value->getBytesNoCopy(), prop->data, dataLength);
1362
1363  if (!exists) {
1364    nvLength = offset + sizeof(NVRAMProperty);
1365    if (getPlatform()->getBootROMType())
1366      nvLength += 0x100;
1367    else
1368      nvLength += _nrPartitionOffset;
1369    *((UInt16 *)_nrImage) = nvLength;
1370  }
1371
1372  _nvramImageDirty = true;
1373
1374  return err;
1375}
1376
1377OSData *IODTNVRAM::unescapeBytesToData(const UInt8 *bytes, UInt32 length)
1378{
1379  OSData *data = 0;
1380  UInt32 totalLength = 0;
1381  UInt32 cnt, cnt2;
1382  UInt8  byte;
1383  bool   ok;
1384
1385  // Calculate the actual length of the data.
1386  ok = true;
1387  totalLength = 0;
1388  for (cnt = 0; cnt < length;) {
1389    byte = bytes[cnt++];
1390    if (byte == 0xFF) {
1391      byte = bytes[cnt++];
1392      if (byte == 0x00) {
1393        ok = false;
1394        break;
1395      }
1396      cnt2 = byte & 0x7F;
1397    } else
1398      cnt2 = 1;
1399    totalLength += cnt2;
1400  }
1401
1402  if (ok) {
1403    // Create an empty OSData of the correct size.
1404    data = OSData::withCapacity(totalLength);
1405    if (data != 0) {
1406      for (cnt = 0; cnt < length;) {
1407        byte = bytes[cnt++];
1408        if (byte == 0xFF) {
1409          byte = bytes[cnt++];
1410          cnt2 = byte & 0x7F;
1411          byte = (byte & 0x80) ? 0xFF : 0x00;
1412        } else
1413          cnt2 = 1;
1414        data->appendByte(byte, cnt2);
1415      }
1416    }
1417  }
1418
1419  return data;
1420}
1421
1422OSData * IODTNVRAM::escapeDataToData(OSData * value)
1423{
1424  OSData *       result;
1425  const UInt8 *  startPtr;
1426  const UInt8 *  endPtr;
1427  const UInt8 *  wherePtr;
1428  UInt8          byte;
1429  bool	         ok = true;
1430
1431  wherePtr = (const UInt8 *) value->getBytesNoCopy();
1432  endPtr = wherePtr + value->getLength();
1433
1434  result = OSData::withCapacity(endPtr - wherePtr);
1435  if (!result)
1436    return result;
1437
1438  while (wherePtr < endPtr) {
1439    startPtr = wherePtr;
1440    byte = *wherePtr++;
1441    if ((byte == 0x00) || (byte == 0xFF)) {
1442      for (;
1443            ((wherePtr - startPtr) < 0x80) && (wherePtr < endPtr) && (byte == *wherePtr);
1444            wherePtr++)	{}
1445      ok &= result->appendByte(0xff, 1);
1446      byte = (byte & 0x80) | (wherePtr - startPtr);
1447    }
1448    ok &= result->appendByte(byte, 1);
1449  }
1450  ok &= result->appendByte(0, 1);
1451
1452  if (!ok) {
1453    result->release();
1454    result = 0;
1455  }
1456
1457  return result;
1458}
1459
1460static bool IsApplePropertyName(const char * propName)
1461{
1462  char c;
1463  while ((c = *propName++)) {
1464    if ((c >= 'A') && (c <= 'Z'))
1465      break;
1466  }
1467
1468  return (c == 0);
1469}
1470
1471IOReturn IODTNVRAM::readNVRAMPropertyType1(IORegistryEntry *entry,
1472					   const OSSymbol **name,
1473					   OSData **value)
1474{
1475  IOReturn    err = kIOReturnNoResources;
1476  OSData      *data;
1477  const UInt8 *startPtr;
1478  const UInt8 *endPtr;
1479  const UInt8 *wherePtr;
1480  const UInt8 *nvPath = 0;
1481  const char  *nvName = 0;
1482  const char  *resultName = 0;
1483  const UInt8 *resultValue = 0;
1484  UInt32       resultValueLen = 0;
1485  UInt8       byte;
1486
1487  if (_ofDict == 0) return err;
1488  data = OSDynamicCast(OSData, _ofDict->getObject(_registryPropertiesKey));
1489  if (data == 0) return err;
1490
1491  startPtr = (const UInt8 *) data->getBytesNoCopy();
1492  endPtr = startPtr + data->getLength();
1493
1494  wherePtr = startPtr;
1495  while (wherePtr < endPtr) {
1496    byte = *(wherePtr++);
1497    if (byte)
1498      continue;
1499
1500    if (nvPath == 0)
1501      nvPath = startPtr;
1502    else if (nvName == 0)
1503      nvName = (const char *) startPtr;
1504    else {
1505      IORegistryEntry * compareEntry = IORegistryEntry::fromPath((const char *) nvPath, gIODTPlane);
1506      if (compareEntry)
1507        compareEntry->release();
1508      if (entry == compareEntry) {
1509        bool appleProp = IsApplePropertyName(nvName);
1510        if (!appleProp || !resultName) {
1511          resultName     = nvName;
1512          resultValue    = startPtr;
1513          resultValueLen = wherePtr - startPtr - 1;
1514        }
1515        if (!appleProp)
1516          break;
1517      }
1518      nvPath = 0;
1519      nvName = 0;
1520    }
1521    startPtr = wherePtr;
1522  }
1523  if (resultName) {
1524    *name = OSSymbol::withCString(resultName);
1525    *value = unescapeBytesToData(resultValue, resultValueLen);
1526    if ((*name != 0) && (*value != 0))
1527      err = kIOReturnSuccess;
1528    else
1529      err = kIOReturnNoMemory;
1530  }
1531  return err;
1532}
1533
1534IOReturn IODTNVRAM::writeNVRAMPropertyType1(IORegistryEntry *entry,
1535					    const OSSymbol *propName,
1536					    OSData *value)
1537{
1538  OSData       *oldData;
1539  OSData       *data = 0;
1540  const UInt8  *startPtr;
1541  const UInt8  *propStart;
1542  const UInt8  *endPtr;
1543  const UInt8  *wherePtr;
1544  const UInt8  *nvPath = 0;
1545  const char   *nvName = 0;
1546  const char * comp;
1547  const char * name;
1548  UInt8        byte;
1549  bool         ok = true;
1550  bool         settingAppleProp;
1551
1552  if (_ofDict == 0) return kIOReturnNoResources;
1553
1554  settingAppleProp = IsApplePropertyName(propName->getCStringNoCopy());
1555
1556  // copy over existing properties for other entries
1557
1558  oldData = OSDynamicCast(OSData, _ofDict->getObject(_registryPropertiesKey));
1559  if (oldData) {
1560    startPtr = (const UInt8 *) oldData->getBytesNoCopy();
1561    endPtr = startPtr + oldData->getLength();
1562
1563    propStart = startPtr;
1564    wherePtr = startPtr;
1565    while (wherePtr < endPtr) {
1566      byte = *(wherePtr++);
1567      if (byte)
1568        continue;
1569      if (nvPath == 0)
1570        nvPath = startPtr;
1571      else if (nvName == 0)
1572        nvName = (const char *) startPtr;
1573      else {
1574        IORegistryEntry * compareEntry = IORegistryEntry::fromPath((const char *) nvPath, gIODTPlane);
1575        if (compareEntry)
1576          compareEntry->release();
1577        if (entry == compareEntry) {
1578          if ((settingAppleProp && propName->isEqualTo(nvName))
1579           || (!settingAppleProp && !IsApplePropertyName(nvName))) {
1580             // delete old property (nvPath -> wherePtr)
1581             data = OSData::withBytes(propStart, nvPath - propStart);
1582             if (data)
1583               ok &= data->appendBytes(wherePtr, endPtr - wherePtr);
1584             break;
1585          }
1586        }
1587        nvPath = 0;
1588        nvName = 0;
1589      }
1590
1591      startPtr = wherePtr;
1592    }
1593  }
1594
1595  // make the new property
1596
1597  if (!data) {
1598    if (oldData)
1599      data = OSData::withData(oldData);
1600    else
1601      data = OSData::withCapacity(16);
1602    if (!data)
1603      return kIOReturnNoMemory;
1604  }
1605
1606  if (value && value->getLength()) {
1607		// get entries in path
1608		OSArray *array = OSArray::withCapacity(5);
1609		if (!array) {
1610			data->release();
1611			return kIOReturnNoMemory;
1612		}
1613		do
1614			array->setObject(entry);
1615		while ((entry = entry->getParentEntry(gIODTPlane)));
1616
1617		// append path
1618		for (int i = array->getCount() - 3;
1619					(entry = (IORegistryEntry *) array->getObject(i));
1620					i--) {
1621
1622			name = entry->getName(gIODTPlane);
1623			comp = entry->getLocation(gIODTPlane);
1624			if( comp && (0 == strncmp("pci", name, sizeof("pci")))
1625			 && (0 == strncmp("80000000", comp, sizeof("80000000")))) {
1626				// yosemite hack
1627				comp = "/pci@80000000";
1628			} else {
1629				if (comp)
1630					ok &= data->appendBytes("/@", 2);
1631				else {
1632					if (!name)
1633						continue;
1634					ok &= data->appendByte('/', 1);
1635					comp = name;
1636				}
1637			}
1638			ok &= data->appendBytes(comp, strlen(comp));
1639		}
1640		ok &= data->appendByte(0, 1);
1641		array->release();
1642
1643		// append prop name
1644		ok &= data->appendBytes(propName->getCStringNoCopy(), propName->getLength() + 1);
1645
1646		// append escaped data
1647		oldData = escapeDataToData(value);
1648		ok &= (oldData != 0);
1649		if (ok)
1650			ok &= data->appendBytes(oldData);
1651	}
1652  if (ok) {
1653    ok = _ofDict->setObject(_registryPropertiesKey, data);
1654    if (ok)
1655      _ofImageDirty = true;
1656  }
1657  data->release();
1658
1659  return ok ? kIOReturnSuccess : kIOReturnNoMemory;
1660}
1661