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