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

