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