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