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