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