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 } 1654