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