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