The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/iokit/Kernel/IONVRAM.cpp

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: b826ce313ab8eda959bc1f7e1cb0d7fb


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.