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 #define IOKIT_ENABLE_SHARED_PTR 31 32 #include <AssertMacros.h> 33 #include <IOKit/IOLib.h> 34 #include <IOKit/IONVRAM.h> 35 #include <IOKit/IOPlatformExpert.h> 36 #include <IOKit/IOUserClient.h> 37 #include <IOKit/IOKitKeys.h> 38 #include <IOKit/IOKitKeysPrivate.h> 39 #include <IOKit/IOBSD.h> 40 #include <kern/debug.h> 41 #include <pexpert/boot.h> 42 #include <pexpert/pexpert.h> 43 44 #define super IOService 45 46 #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) 47 48 // Internal values 49 #define NVRAM_CHRP_SIG_APPLE 0x5A 50 #define NVRAM_CHRP_APPLE_HEADER_NAME "nvram" 51 52 // From Apple CHRP Spec 53 #define NVRAM_CHRP_SIG_SYSTEM 0x70 54 #define NVRAM_CHRP_SIG_CONFIG 0x71 55 #define NVRAM_CHRP_SIG_FREESPACE 0x7F 56 57 #define NVRAM_CHRP_PARTITION_NAME_COMMON "common" 58 #define NVRAM_CHRP_PARTITION_NAME_SYSTEM "system" 59 #define NVRAM_CHRP_PARTITION_NAME_SYSTEM_LEGACY "secure" 60 #define NVRAM_CHRP_PARTITION_NAME_FREESPACE "\x77\x77\x77\x77\x77\x77\x77\x77\x77\x77\x77\x77" 61 62 #define NVRAM_CHRP_LENGTH_BLOCK_SIZE 0x10 // CHRP length field is in 16 byte blocks 63 64 typedef struct chrp_nvram_header { //16 bytes 65 uint8_t sig; 66 uint8_t cksum; // checksum on sig, len, and name 67 uint16_t len; // total length of the partition in 16 byte blocks starting with the signature 68 // and ending with the last byte of data area, ie len includes its own header size 69 char name[12]; 70 uint8_t data[0]; 71 } chrp_nvram_header_t; 72 73 typedef struct apple_nvram_header { // 16 + 16 bytes 74 struct chrp_nvram_header chrp; 75 uint32_t adler; 76 uint32_t generation; 77 uint8_t padding[8]; 78 } apple_nvram_header_t; 79 80 81 #define kIONVRAMPrivilege kIOClientPrivilegeAdministrator 82 83 OSDefineMetaClassAndStructors(IODTNVRAM, IOService); 84 85 #if defined(DEBUG) || defined(DEVELOPMENT) 86 #define DEBUG_INFO(fmt, args...) \ 87 ({ \ 88 if (gNVRAMLogging) \ 89 IOLog("IONVRAM::%s:%u - " fmt, __FUNCTION__, __LINE__, ##args); \ 90 }) 91 92 #define DEBUG_ALWAYS(fmt, args...) \ 93 ({ \ 94 IOLog("IONVRAM::%s:%u - " fmt, __FUNCTION__, __LINE__, ##args); \ 95 }) 96 #else 97 #define DEBUG_INFO(fmt, args...) 98 #define DEBUG_ALWAYS(fmt, args...) 99 #endif 100 101 #define DEBUG_ERROR DEBUG_ALWAYS 102 103 #define NVRAMLOCK() \ 104 ({ \ 105 if (preemption_enabled() && !panic_active()) \ 106 IOLockLock(_variableLock); \ 107 }) 108 109 #define NVRAMUNLOCK() \ 110 ({ \ 111 if (preemption_enabled() && !panic_active()) \ 112 IOLockUnlock(_variableLock); \ 113 }) 114 115 #define NVRAMLOCKASSERT() \ 116 ({ \ 117 if (preemption_enabled() && !panic_active()) \ 118 IOLockAssert(_variableLock, kIOLockAssertOwned); \ 119 }) 120 121 typedef struct { 122 const char *name; 123 UInt32 offset; 124 UInt32 size; 125 OSSharedPtr<OSDictionary> &dict; 126 UInt8 *image; 127 } NVRAMRegionInfo; 128 129 // Guid for Apple System Boot variables 130 // 40A0DDD2-77F8-4392-B4A3-1E7304206516 131 UUID_DEFINE(gAppleSystemVariableGuid, 0x40, 0xA0, 0xDD, 0xD2, 0x77, 0xF8, 0x43, 0x92, 0xB4, 0xA3, 0x1E, 0x73, 0x04, 0x20, 0x65, 0x16); 132 133 // Apple NVRAM Variable namespace (APPLE_VENDOR_OS_VARIABLE_GUID) 134 // 7C436110-AB2A-4BBB-A880-FE41995C9F82 135 UUID_DEFINE(gAppleNVRAMGuid, 0x7C, 0x43, 0x61, 0x10, 0xAB, 0x2A, 0x4B, 0xBB, 0xA8, 0x80, 0xFE, 0x41, 0x99, 0x5C, 0x9F, 0x82); 136 137 static bool gNVRAMLogging = false; 138 139 // allowlist variables from macboot that need to be set/get from system region if present 140 static const char * const gNVRAMSystemList[] = { 141 "adbe-tunable", 142 "adbe-tunables", 143 "adfe-tunables", 144 "alamo-path", 145 "alt-boot-volume", 146 "ASMB", 147 "atc0", 148 "atc1", 149 "auto-boot", 150 "auto-boot-halt-stage", 151 "auto-boot-once", 152 "auto-boot-usb", 153 "auxkc-path", 154 "backlight-level", 155 "backlight-nits", 156 "base-system-path", 157 "boot-args", 158 "boot-breadcrumbs", 159 "boot-command", 160 "boot-device", 161 "boot-image", 162 "boot-partition", 163 "boot-path", 164 "boot-ramdisk", 165 "boot-script", 166 "boot-volume", 167 "bootdelay", 168 "bt1addr", 169 "btaddr", 170 "cam-use-ext-ldo", 171 "CLCG_override", 172 "com.apple.System.boot-nonce", 173 "com.apple.System.rtc-offset", 174 "com.apple.System.tz0-size", 175 "core-bin-offset", 176 "cpu-bin-offset", 177 "darkboot", 178 "DClr_override", 179 "dcp-auto-boot", 180 "debug-gg", 181 "debug-soc", 182 "debug-uarts", 183 "diags-path", 184 "disable-boot-wdt", 185 "display-color-space", 186 "display-timing", 187 "display-vsh-comp", 188 "dpcd-max-brightness", 189 "dtdump", 190 "dtdump-path", 191 "e75", 192 "emu", 193 "enable-auth-debug", 194 "enable-jop", 195 "enable-marconi", 196 "enable-upgrade-fallback", 197 "enforce-iuob", 198 "eth1addr", 199 "ethaddr", 200 "failboot-breadcrumbs", 201 "fixed-lcm-boost", 202 "force-ctrr-lock", 203 "force-upgrade-fail", 204 "fuos-path", 205 "hib-ui-force", 206 "hibhack-test-hmac", 207 "iboot-data", 208 "iboot-failure-reason", 209 "iboot-failure-reason-str", 210 "iboot-failure-volume", 211 "iboot1-precommitted", 212 "idle-off", 213 "is-tethered", 214 "kaslr-off", 215 "kaslr-slide", 216 "kis-rsm", 217 "knobs", 218 "loadaddr", 219 "memmapdump", 220 "mipi-bridge-cmd-verify", 221 "mipi-bridge-poll-cmd-fifo", 222 "no-ctrr", 223 "one-time-boot-command", 224 "osenvironment", 225 "ota-breadcrumbs", 226 "ota-outcome", 227 "panicmedic", 228 "panicmedic-threshold", 229 "panicmedic-timestamps", 230 "phleet-path", 231 "pinot-panel-id", 232 "pintoaddr", 233 "policy-nonce-digests", 234 "preserve-debuggability", 235 "prevent-restores", // Keep for factory <rdar://problem/70476321> 236 "prev-lang:kbd", 237 "ramrod-kickstart-aces", 238 "rbdaddr0", 239 "rbm-path", 240 "reconfig-behavior", 241 "reconfig-breakpoints", 242 "recovery-boot-mode", 243 "recovery-breadcrumbs", 244 "restored-host-timeout", 245 "root-live-fs", 246 "rtos-path", 247 "soc-bin-offset", 248 "StartupMute", 249 "StartupMuteAccessibility", 250 "storage-prev-assert", 251 "storage-prev-assert-stored", 252 "summit-panel-id", 253 "SystemAudioVolume", 254 "SystemAudioVolumeExtension", 255 "SystemAudioVolumeSaved", 256 "tz0-size-override", 257 "upgrade-fallback-boot-command", 258 "upgrade-retry", 259 "usb-enabled", 260 "wifi1addr", 261 "wifiaddr", 262 nullptr 263 }; 264 265 typedef struct { 266 const char *name; 267 IONVRAMVariableType type; 268 } VariableTypeEntry; 269 270 static const 271 VariableTypeEntry gVariableTypes[] = { 272 {"auto-boot?", kOFVariableTypeBoolean}, 273 {"boot-args", kOFVariableTypeString}, 274 {"boot-command", kOFVariableTypeString}, 275 {"boot-device", kOFVariableTypeString}, 276 {"boot-file", kOFVariableTypeString}, 277 {"boot-screen", kOFVariableTypeString}, 278 {"boot-script", kOFVariableTypeString}, 279 {"console-screen", kOFVariableTypeString}, 280 {"default-client-ip", kOFVariableTypeString}, 281 {"default-gateway-ip", kOFVariableTypeString}, 282 {"default-mac-address?", kOFVariableTypeBoolean}, 283 {"default-router-ip", kOFVariableTypeString}, 284 {"default-server-ip", kOFVariableTypeString}, 285 {"default-subnet-mask", kOFVariableTypeString}, 286 {"diag-device", kOFVariableTypeString}, 287 {"diag-file", kOFVariableTypeString}, 288 {"diag-switch?", kOFVariableTypeBoolean}, 289 {"fcode-debug?", kOFVariableTypeBoolean}, 290 {"input-device", kOFVariableTypeString}, 291 {"input-device-1", kOFVariableTypeString}, 292 {"little-endian?", kOFVariableTypeBoolean}, 293 {"load-base", kOFVariableTypeNumber}, 294 {"mouse-device", kOFVariableTypeString}, 295 {"nvramrc", kOFVariableTypeString}, 296 {"oem-banner", kOFVariableTypeString}, 297 {"oem-banner?", kOFVariableTypeBoolean}, 298 {"oem-logo", kOFVariableTypeString}, 299 {"oem-logo?", kOFVariableTypeBoolean}, 300 {"output-device", kOFVariableTypeString}, 301 {"output-device-1", kOFVariableTypeString}, 302 {"pci-probe-list", kOFVariableTypeNumber}, 303 {"pci-probe-mask", kOFVariableTypeNumber}, 304 {"real-base", kOFVariableTypeNumber}, 305 {"real-mode?", kOFVariableTypeBoolean}, 306 {"real-size", kOFVariableTypeNumber}, 307 {"screen-#columns", kOFVariableTypeNumber}, 308 {"screen-#rows", kOFVariableTypeNumber}, 309 {"security-mode", kOFVariableTypeString}, 310 {"selftest-#megs", kOFVariableTypeNumber}, 311 {"use-generic?", kOFVariableTypeBoolean}, 312 {"use-nvramrc?", kOFVariableTypeBoolean}, 313 {"virt-base", kOFVariableTypeNumber}, 314 {"virt-size", kOFVariableTypeNumber}, 315 316 #if !defined(__x86_64__) 317 {"acc-cm-override-charger-count", kOFVariableTypeNumber}, 318 {"acc-cm-override-count", kOFVariableTypeNumber}, 319 {"acc-mb-ld-lifetime", kOFVariableTypeNumber}, 320 {"com.apple.System.boot-nonce", kOFVariableTypeString}, 321 {"darkboot", kOFVariableTypeBoolean}, 322 {"enter-tdm-mode", kOFVariableTypeBoolean}, 323 #endif /* !defined(__x86_64__) */ 324 {nullptr, kOFVariableTypeData} // Default type to return 325 }; 326 327 union VariablePermission { 328 struct { 329 uint64_t UserWrite :1; 330 uint64_t RootRequired :1; 331 uint64_t KernelOnly :1; 332 uint64_t ResetNVRAMOnlyDelete :1; 333 uint64_t NeverAllowedToDelete :1; 334 uint64_t FullAccess :1; 335 uint64_t Reserved:58; 336 } Bits; 337 uint64_t Uint64; 338 }; 339 340 typedef struct { 341 const char *name; 342 VariablePermission p; 343 } VariablePermissionEntry; 344 345 static const 346 VariablePermissionEntry gVariablePermissions[] = { 347 {"aapl,pci", .p.Bits.RootRequired = 1}, 348 {"battery-health", .p.Bits.RootRequired = 1, 349 .p.Bits.NeverAllowedToDelete = 1}, 350 {"boot-image", .p.Bits.UserWrite = 1}, 351 {"com.apple.System.fp-state", .p.Bits.KernelOnly = 1}, 352 {"policy-nonce-digests", .p.Bits.ResetNVRAMOnlyDelete = 1}, 353 {"security-password", .p.Bits.RootRequired = 1}, 354 355 #if !defined(__x86_64__) 356 {"acc-cm-override-charger-count", .p.Bits.KernelOnly = 1}, 357 {"acc-cm-override-count", .p.Bits.KernelOnly = 1}, 358 {"acc-mb-ld-lifetime", .p.Bits.KernelOnly = 1}, 359 {"backlight-level", .p.Bits.UserWrite = 1}, 360 {"com.apple.System.boot-nonce", .p.Bits.KernelOnly = 1}, 361 {"com.apple.System.sep.art", .p.Bits.KernelOnly = 1}, 362 {"darkboot", .p.Bits.UserWrite = 1}, 363 {"nonce-seeds", .p.Bits.KernelOnly = 1}, 364 #endif /* !defined(__x86_64__) */ 365 366 {nullptr, {.Bits.FullAccess = 1}} // Default access 367 }; 368 369 static IONVRAMVariableType 370 getVariableType(const char *propName) 371 { 372 const VariableTypeEntry *entry; 373 374 entry = gVariableTypes; 375 while (entry->name != nullptr) { 376 if (strcmp(entry->name, propName) == 0) { 377 break; 378 } 379 entry++; 380 } 381 382 return entry->type; 383 } 384 385 static IONVRAMVariableType 386 getVariableType(const OSSymbol *propSymbol) 387 { 388 return getVariableType(propSymbol->getCStringNoCopy()); 389 } 390 391 static VariablePermission 392 getVariablePermission(const char *propName) 393 { 394 const VariablePermissionEntry *entry; 395 396 entry = gVariablePermissions; 397 while (entry->name != nullptr) { 398 if (strcmp(entry->name, propName) == 0) { 399 break; 400 } 401 entry++; 402 } 403 404 return entry->p; 405 } 406 407 static bool 408 variableInAllowList(const char *varName) 409 { 410 unsigned int i = 0; 411 412 while (gNVRAMSystemList[i] != nullptr) { 413 if (strcmp(varName, gNVRAMSystemList[i]) == 0) { 414 return true; 415 } 416 i++; 417 } 418 419 return false; 420 } 421 422 static bool 423 verifyWriteSizeLimit(const uuid_t *varGuid, const char *variableName, size_t propDataSize) 424 { 425 if (variableInAllowList(variableName)) { 426 if (strnstr(variableName, "breadcrumbs", strlen(variableName)) != NULL) { 427 return propDataSize <= 1024; 428 } else { 429 return propDataSize <= 768; 430 } 431 } 432 433 return true; 434 } 435 436 static bool 437 verifyPermission(IONVRAMOperation op, const uuid_t *varGuid, const char *varName) 438 { 439 VariablePermission perm; 440 bool kernel, admin, writeEntitled, readEntitled, allowList, systemGuid, systemEntitled; 441 442 perm = getVariablePermission(varName); 443 444 kernel = current_task() == kernel_task; 445 446 if (perm.Bits.KernelOnly) { 447 DEBUG_INFO("KernelOnly access for %s, kernel=%d\n", varName, kernel); 448 return kernel; 449 } 450 451 allowList = variableInAllowList(varName); 452 systemGuid = uuid_compare(*varGuid, gAppleSystemVariableGuid) == 0; 453 admin = IOUserClient::clientHasPrivilege(current_task(), kIONVRAMPrivilege) == kIOReturnSuccess; 454 writeEntitled = IOTaskHasEntitlement(current_task(), kIONVRAMWriteAccessKey); 455 readEntitled = IOTaskHasEntitlement(current_task(), kIONVRAMReadAccessKey); 456 systemEntitled = IOTaskHasEntitlement(current_task(), kIONVRAMSystemAllowKey) || kernel; 457 458 switch (op) { 459 case kIONVRAMOperationRead: 460 if (kernel || admin || readEntitled || perm.Bits.FullAccess) { 461 return true; 462 } 463 break; 464 465 case kIONVRAMOperationWrite: 466 if (kernel || perm.Bits.UserWrite || admin || writeEntitled) { 467 if (systemGuid) { 468 if (allowList) { 469 if (!systemEntitled) { 470 DEBUG_ERROR("Allowed write to system region when NOT entitled for %s\n", varName); 471 } 472 } else if (!systemEntitled) { 473 DEBUG_ERROR("Not entitled for system region writes for %s\n", varName); 474 break; 475 } 476 } 477 return true; 478 } 479 break; 480 481 case kIONVRAMOperationDelete: 482 case kIONVRAMOperationObliterate: 483 case kIONVRAMOperationReset: 484 if (perm.Bits.NeverAllowedToDelete) { 485 DEBUG_INFO("Never allowed to delete %s\n", varName); 486 break; 487 } else if ((op == kIONVRAMOperationObliterate) && perm.Bits.ResetNVRAMOnlyDelete) { 488 DEBUG_INFO("Not allowed to obliterate %s\n", varName); 489 break; 490 } 491 492 if (kernel || perm.Bits.UserWrite || admin || writeEntitled) { 493 if (systemGuid) { 494 if (allowList) { 495 if (!systemEntitled) { 496 DEBUG_ERROR("Allowed delete to system region when NOT entitled for %s\n", varName); 497 } 498 } else if (!systemEntitled) { 499 DEBUG_ERROR("Not entitled for system region deletes for %s\n", varName); 500 break; 501 } 502 } 503 return true; 504 } 505 break; 506 } 507 508 DEBUG_INFO("Permission for %s denied, kernel=%d, admin=%d, writeEntitled=%d, readEntitled=%d, systemGuid=%d, systemEntitled=%d\n", 509 varName, kernel, admin, writeEntitled, readEntitled, systemGuid, systemEntitled); 510 return false; 511 } 512 513 static bool 514 verifyPermission(IONVRAMOperation op, const uuid_t *varGuid, const OSSymbol *varName) 515 { 516 return verifyPermission(op, varGuid, varName->getCStringNoCopy()); 517 } 518 519 /* 520 * Parse a variable name of the form "GUID:name". 521 * If the name cannot be parsed, substitute the Apple global variable GUID. 522 * Returns TRUE if a GUID was found in the name, FALSE otherwise. 523 * The guidResult and nameResult arguments may be nullptr if you just want 524 * to check the format of the string. 525 */ 526 static bool 527 parseVariableName(const char *key, uuid_t *guidResult, const char **nameResult) 528 { 529 uuid_string_t temp = {0}; 530 size_t keyLen = strlen(key); 531 bool result = false; 532 const char *name = key; 533 uuid_t guid; 534 535 if (keyLen > sizeof(temp)) { 536 // check for at least UUID + ":" + more 537 memcpy(temp, key, sizeof(temp) - 1); 538 539 if ((uuid_parse(temp, guid) == 0) && 540 (key[sizeof(temp) - 1] == ':')) { 541 name = key + sizeof(temp); 542 result = true; 543 } 544 } 545 546 if (guidResult) { 547 result ? uuid_copy(*guidResult, guid) : uuid_copy(*guidResult, gAppleNVRAMGuid); 548 } 549 if (nameResult) { 550 *nameResult = name; 551 } 552 553 return false; 554 } 555 556 // private IOService based class for publishing distinct dictionary properties on 557 // for easy ioreg access since the serializeProperties call is overloaded and is used 558 // as variable access 559 class IODTNVRAMVariables : public IOService 560 { 561 OSDeclareDefaultStructors(IODTNVRAMVariables) 562 private: 563 IODTNVRAM *_provider; 564 OSDictionary *_properties; 565 uuid_t _guid; 566 567 public: 568 bool init(const uuid_t *guid); 569 virtual bool start(IOService * provider) APPLE_KEXT_OVERRIDE; 570 virtual IOReturn setProperties(OSObject * properties) APPLE_KEXT_OVERRIDE; 571 virtual bool serializeProperties(OSSerialize *s) const APPLE_KEXT_OVERRIDE; 572 }; 573 574 OSDefineMetaClassAndStructors(IODTNVRAMVariables, IOService) 575 576 bool 577 IODTNVRAMVariables::init(const uuid_t *guid) 578 { 579 require(super::init(), error); 580 require(guid, error); 581 582 uuid_copy(_guid, *guid); 583 584 return true; 585 586 error: 587 return false; 588 } 589 590 bool 591 IODTNVRAMVariables::start(IOService * provider) 592 { 593 require(IOService::start(provider), error); 594 595 require(_provider = OSDynamicCast(IODTNVRAM, provider), error); 596 597 registerService(); 598 599 return true; 600 601 error: 602 stop(provider); 603 604 return false; 605 } 606 607 IOReturn 608 IODTNVRAMVariables::setProperties(OSObject * properties) 609 { 610 if (OSDynamicCast(OSDictionary, properties)) { 611 OSSafeReleaseNULL(_properties); 612 _properties = OSDynamicCast(OSDictionary, properties); 613 properties->retain(); 614 } 615 616 return IOService::setProperties(properties); 617 } 618 619 bool 620 IODTNVRAMVariables::serializeProperties(OSSerialize *s) const 621 { 622 const OSSymbol *key; 623 OSSharedPtr<OSDictionary> dict; 624 OSSharedPtr<OSCollectionIterator> iter; 625 OSSharedPtr<OSDictionary> localProperties(_properties, OSRetain); 626 bool result = false; 627 628 require(localProperties != nullptr, exit); 629 630 dict = OSDictionary::withCapacity(localProperties->getCount()); 631 require_action(dict, exit, DEBUG_ERROR("No dictionary\n")); 632 633 iter = OSCollectionIterator::withCollection(localProperties.get()); 634 require_action(iter, exit, DEBUG_ERROR("failed to create iterator\n")); 635 636 while ((key = OSDynamicCast(OSSymbol, iter->getNextObject()))) { 637 if (verifyPermission(kIONVRAMOperationRead, &_guid, key)) { 638 dict->setObject(key, localProperties->getObject(key)); 639 } 640 } 641 642 result = dict->serialize(s); 643 644 exit: 645 DEBUG_INFO("result=%d\n", result); 646 return result; 647 } 648 649 bool 650 IODTNVRAM::init(IORegistryEntry *old, const IORegistryPlane *plane) 651 { 652 OSSharedPtr<OSDictionary> dict; 653 654 if (!super::init(old, plane)) { 655 return false; 656 } 657 658 _variableLock = IOLockAlloc(); 659 if (!_variableLock) { 660 return false; 661 } 662 663 PE_parse_boot_argn("nvram-log", &gNVRAMLogging, sizeof(gNVRAMLogging)); 664 665 dict = OSDictionary::withCapacity(1); 666 if (dict == nullptr) { 667 return false; 668 } 669 setPropertyTable(dict.get()); 670 dict.reset(); 671 672 _nvramSize = getNVRAMSize(); 673 if (_nvramSize == 0) { 674 DEBUG_ERROR("NVRAM : Error - default size not specified in DT\n"); 675 return false; 676 } 677 // partition offsets are UInt16 (bytes / 0x10) + 1 678 if (_nvramSize > 0xFFFF * 0x10) { 679 DEBUG_ERROR("NVRAM : truncating _nvramSize from %ld\n", (long) _nvramSize); 680 _nvramSize = 0xFFFF * 0x10; 681 } 682 _nvramImage = IONew(UInt8, _nvramSize); 683 if (_nvramImage == nullptr) { 684 return false; 685 } 686 687 _nvramPartitionOffsets = OSDictionary::withCapacity(1); 688 if (_nvramPartitionOffsets == nullptr) { 689 return false; 690 } 691 692 _nvramPartitionLengths = OSDictionary::withCapacity(1); 693 if (_nvramPartitionLengths == nullptr) { 694 return false; 695 } 696 697 _registryPropertiesKey = OSSymbol::withCStringNoCopy("aapl,pci"); 698 if (_registryPropertiesKey == nullptr) { 699 return false; 700 } 701 702 // <rdar://problem/9529235> race condition possible between 703 // IODTNVRAM and IONVRAMController (restore loses boot-args) 704 initProxyData(); 705 706 // Require at least the common partition to be present and error free 707 if (_commonDict == nullptr) { 708 return false; 709 } 710 711 return true; 712 } 713 714 void 715 IODTNVRAM::initProxyData(void) 716 { 717 OSSharedPtr<IORegistryEntry> entry; 718 const char *key = "nvram-proxy-data"; 719 OSData *data; 720 const void *bytes; 721 722 entry = IORegistryEntry::fromPath("/chosen", gIODTPlane); 723 if (entry != nullptr) { 724 OSSharedPtr<OSObject> prop = entry->copyProperty(key); 725 if (prop != nullptr) { 726 data = OSDynamicCast(OSData, prop.get()); 727 if (data != nullptr) { 728 bytes = data->getBytesNoCopy(); 729 if ((bytes != nullptr) && (data->getLength() <= _nvramSize)) { 730 bcopy(bytes, _nvramImage, data->getLength()); 731 initNVRAMImage(); 732 _isProxied = true; 733 } 734 } 735 } 736 entry->removeProperty(key); 737 } 738 } 739 740 UInt32 741 IODTNVRAM::getNVRAMSize(void) 742 { 743 OSSharedPtr<IORegistryEntry> entry; 744 const char *key = "nvram-total-size"; 745 OSData *data; 746 UInt32 size = 0; 747 748 entry = IORegistryEntry::fromPath("/chosen", gIODTPlane); 749 if (entry != nullptr) { 750 OSSharedPtr<OSObject> prop = entry->copyProperty(key); 751 if (prop != nullptr) { 752 data = OSDynamicCast(OSData, prop.get()); 753 if (data != nullptr) { 754 size = *((UInt32*)data->getBytesNoCopy()); 755 DEBUG_ALWAYS("NVRAM size is %u bytes\n", (unsigned int) size); 756 } 757 } 758 } 759 return size; 760 } 761 762 763 void 764 IODTNVRAM::registerNVRAMController(IONVRAMController *nvram) 765 { 766 if (_nvramController != nullptr) { 767 DEBUG_ERROR("Duplicate controller set\n"); 768 return; 769 } 770 771 DEBUG_INFO("setting controller\n"); 772 773 _nvramController = nvram; 774 775 // <rdar://problem/9529235> race condition possible between 776 // IODTNVRAM and IONVRAMController (restore loses boot-args) 777 if (!_isProxied) { 778 DEBUG_INFO("Proxied NVRAM data\n"); 779 _nvramController->read(0, _nvramImage, _nvramSize); 780 initNVRAMImage(); 781 } 782 783 if (_systemPartitionSize) { 784 _systemService = new IODTNVRAMVariables; 785 786 if (!_systemService || !_systemService->init(&gAppleSystemVariableGuid)) { 787 DEBUG_ERROR("Unable to start the system service!\n"); 788 goto no_system; 789 } 790 791 _systemService->setName("options-system"); 792 793 if (!_systemService->attach(this)) { 794 DEBUG_ERROR("Unable to attach the system service!\n"); 795 OSSafeReleaseNULL(_systemService); 796 goto no_system; 797 } 798 799 if (!_systemService->start(this)) { 800 DEBUG_ERROR("Unable to start the system service!\n"); 801 _systemService->detach(this); 802 OSSafeReleaseNULL(_systemService); 803 goto no_system; 804 } 805 } 806 807 no_system: 808 if (_commonPartitionSize) { 809 _commonService = new IODTNVRAMVariables; 810 811 if (!_commonService || !_commonService->init(&gAppleNVRAMGuid)) { 812 DEBUG_ERROR("Unable to start the common service!\n"); 813 goto no_common; 814 } 815 816 _commonService->setName("options-common"); 817 818 if (!_commonService->attach(this)) { 819 DEBUG_ERROR("Unable to attach the common service!\n"); 820 OSSafeReleaseNULL(_commonService); 821 goto no_common; 822 } 823 824 if (!_commonService->start(this)) { 825 DEBUG_ERROR("Unable to start the common service!\n"); 826 _systemService->detach(this); 827 OSSafeReleaseNULL(_commonService); 828 goto no_common; 829 } 830 } 831 832 no_common: 833 NVRAMLOCK(); 834 (void) syncVariables(); 835 NVRAMUNLOCK(); 836 } 837 838 void 839 IODTNVRAM::initNVRAMImage(void) 840 { 841 char partitionID[18]; 842 UInt32 partitionOffset, partitionLength; 843 UInt32 currentLength, currentOffset = 0; 844 845 _commonPartitionOffset = 0xFFFFFFFF; 846 _systemPartitionOffset = 0xFFFFFFFF; 847 848 // Look through the partitions to find the OF and System partitions. 849 while (currentOffset < _nvramSize) { 850 bool common_partition; 851 bool system_partition; 852 853 chrp_nvram_header_t * header = (chrp_nvram_header_t *)(_nvramImage + currentOffset); 854 855 currentLength = header->len * NVRAM_CHRP_LENGTH_BLOCK_SIZE; 856 857 if (currentLength < sizeof(chrp_nvram_header_t)) { 858 break; 859 } 860 861 partitionOffset = currentOffset + sizeof(chrp_nvram_header_t); 862 partitionLength = currentLength - sizeof(chrp_nvram_header_t); 863 864 if ((partitionOffset + partitionLength) > _nvramSize) { 865 break; 866 } 867 868 common_partition = memcmp(header->name, NVRAM_CHRP_PARTITION_NAME_COMMON, strlen(NVRAM_CHRP_PARTITION_NAME_COMMON)) == 0; 869 system_partition = (memcmp(header->name, NVRAM_CHRP_PARTITION_NAME_SYSTEM, strlen(NVRAM_CHRP_PARTITION_NAME_SYSTEM)) == 0) || 870 (memcmp(header->name, NVRAM_CHRP_PARTITION_NAME_SYSTEM_LEGACY, strlen(NVRAM_CHRP_PARTITION_NAME_SYSTEM_LEGACY)) == 0); 871 872 if (common_partition) { 873 _commonPartitionOffset = partitionOffset; 874 _commonPartitionSize = partitionLength; 875 } else if (system_partition) { 876 _systemPartitionOffset = partitionOffset; 877 _systemPartitionSize = partitionLength; 878 } else { 879 OSSharedPtr<OSNumber> partitionOffsetNumber, partitionLengthNumber; 880 881 // Construct the partition ID from the signature and name. 882 snprintf(partitionID, sizeof(partitionID), "0x%02x,", header->sig); 883 strncpy(partitionID + 5, header->name, sizeof(header->name)); 884 partitionID[17] = '\0'; 885 886 partitionOffsetNumber = OSNumber::withNumber(partitionOffset, 32); 887 partitionLengthNumber = OSNumber::withNumber(partitionLength, 32); 888 889 // Save the partition offset and length 890 _nvramPartitionOffsets->setObject(partitionID, partitionOffsetNumber.get()); 891 _nvramPartitionLengths->setObject(partitionID, partitionLengthNumber.get()); 892 } 893 currentOffset += currentLength; 894 } 895 896 if (_commonPartitionOffset != 0xFFFFFFFF) { 897 _commonImage = _nvramImage + _commonPartitionOffset; 898 } 899 900 if (_systemPartitionOffset != 0xFFFFFFFF) { 901 _systemImage = _nvramImage + _systemPartitionOffset; 902 } 903 904 DEBUG_ALWAYS("NVRAM : ofPartitionOffset - 0x%x, ofPartitionSize - 0x%x, systemPartitionOffset - 0x%x, systemPartitionSize - 0x%x\n", 905 (unsigned int) _commonPartitionOffset, (unsigned int) _commonPartitionSize, (unsigned int) _systemPartitionOffset, (unsigned int) _systemPartitionSize); 906 907 _lastDeviceSync = 0; 908 _freshInterval = TRUE; // we will allow sync() even before the first 15 minutes have passed. 909 910 initVariables(); 911 } 912 913 void 914 IODTNVRAM::syncInternal(bool rateLimit) 915 { 916 DEBUG_INFO("rateLimit=%d\n", rateLimit); 917 918 // Don't try to perform controller operations if none has been registered. 919 if (_nvramController == nullptr) { 920 return; 921 } 922 923 // Rate limit requests to sync. Drivers that need this rate limiting will 924 // shadow the data and only write to flash when they get a sync call 925 if (rateLimit && !safeToSync()) { 926 return; 927 } 928 929 DEBUG_INFO("Calling sync()\n"); 930 NVRAMLOCK(); 931 _nvramController->sync(); 932 NVRAMUNLOCK(); 933 } 934 935 void 936 IODTNVRAM::sync(void) 937 { 938 syncInternal(false); 939 } 940 941 bool 942 IODTNVRAM::serializeProperties(OSSerialize *s) const 943 { 944 const OSSymbol *key; 945 OSSharedPtr<OSDictionary> dict; 946 OSSharedPtr<OSCollectionIterator> iter; 947 bool result = false; 948 unsigned int totalCapacity = 0; 949 950 NVRAMLOCK(); 951 if (_commonDict) { 952 totalCapacity += _commonDict->getCapacity(); 953 } 954 955 if (_systemDict) { 956 totalCapacity += _systemDict->getCapacity(); 957 } 958 959 dict = OSDictionary::withCapacity(totalCapacity); 960 961 if (dict == nullptr) { 962 DEBUG_ERROR("No dictionary\n"); 963 goto unlock; 964 } 965 966 // Copy system entries first if present then copy unique common entries 967 if (_systemDict != nullptr) { 968 iter = OSCollectionIterator::withCollection(_systemDict.get()); 969 if (iter == nullptr) { 970 DEBUG_ERROR("failed to create iterator\n"); 971 goto unlock; 972 } 973 974 while ((key = OSDynamicCast(OSSymbol, iter->getNextObject()))) { 975 if (verifyPermission(kIONVRAMOperationRead, &gAppleSystemVariableGuid, key)) { 976 dict->setObject(key, _systemDict->getObject(key)); 977 } 978 } 979 980 iter.reset(); 981 } 982 983 if (_commonDict != nullptr) { 984 iter = OSCollectionIterator::withCollection(_commonDict.get()); 985 if (iter == nullptr) { 986 DEBUG_ERROR("failed to create common iterator\n"); 987 goto unlock; 988 } 989 990 while ((key = OSDynamicCast(OSSymbol, iter->getNextObject()))) { 991 if (dict->getObject(key) != nullptr) { 992 // Skip non uniques 993 continue; 994 } 995 if (verifyPermission(kIONVRAMOperationRead, &gAppleNVRAMGuid, key)) { 996 dict->setObject(key, _commonDict->getObject(key)); 997 } 998 } 999 } 1000 1001 result = dict->serialize(s); 1002 1003 unlock: 1004 NVRAMUNLOCK(); 1005 1006 DEBUG_INFO("result=%d\n", result); 1007 1008 return result; 1009 } 1010 1011 IOReturn 1012 IODTNVRAM::chooseDictionary(IONVRAMOperation operation, const uuid_t *varGuid, const char *variableName, OSDictionary **dict) const 1013 { 1014 if (_systemDict != nullptr) { 1015 bool systemGuid = uuid_compare(*varGuid, gAppleSystemVariableGuid) == 0; 1016 1017 if (variableInAllowList(variableName)) { 1018 DEBUG_INFO("Using system dictionary due to allow list\n"); 1019 if (!systemGuid) { 1020 DEBUG_ERROR("System GUID NOT used for %s\n", variableName); 1021 } 1022 *dict = _systemDict.get(); 1023 } else if (systemGuid) { 1024 DEBUG_INFO("Using system dictionary via GUID\n"); 1025 *dict = _systemDict.get(); 1026 } else { 1027 DEBUG_INFO("Using common dictionary\n"); 1028 *dict = _commonDict.get(); 1029 } 1030 } else { 1031 DEBUG_INFO("Defaulting to common dictionary\n"); 1032 *dict = _commonDict.get(); 1033 } 1034 1035 return kIOReturnSuccess; 1036 } 1037 1038 bool 1039 IODTNVRAM::handleSpecialVariables(const char *name, uuid_t *guid, OSObject *obj, IOReturn *error) 1040 { 1041 IOReturn err = kIOReturnSuccess; 1042 bool special = false; 1043 1044 NVRAMLOCKASSERT(); 1045 1046 if (strcmp(name, "ResetNVRam") == 0) { 1047 DEBUG_INFO("%s requested\n", name); 1048 1049 if (uuid_compare(*guid, gAppleSystemVariableGuid) == 0) { 1050 if (_systemDict != nullptr) { 1051 _systemDict->flushCollection(); 1052 } 1053 1054 _commonDict->flushCollection(); 1055 DEBUG_INFO("system & common dictionary flushed\n"); 1056 1057 err = syncVariables(); 1058 } 1059 1060 special = true; 1061 } else if (strcmp(name, "ObliterateNVRam") == 0) { 1062 DEBUG_INFO("%s requested\n", name); 1063 1064 if ((_systemDict != nullptr) && (uuid_compare(*guid, gAppleSystemVariableGuid) == 0)) { 1065 const OSSymbol *key; 1066 OSSharedPtr<OSDictionary> newDict; 1067 OSSharedPtr<OSCollectionIterator> iter; 1068 1069 newDict = OSDictionary::withCapacity(_systemDict->getCapacity()); 1070 iter = OSCollectionIterator::withCollection(newDict.get()); 1071 if ((newDict == nullptr) || (iter == nullptr)) { 1072 err = kIOReturnNoMemory; 1073 goto exit; 1074 } 1075 1076 while ((key = OSDynamicCast(OSSymbol, iter->getNextObject()))) { 1077 const OSSymbol *key = OSDynamicCast(OSSymbol, iter->getNextObject()); 1078 if (key == nullptr) { 1079 err = kIOReturnNoMemory; 1080 goto exit; 1081 } 1082 1083 if (!verifyPermission(kIONVRAMOperationObliterate, &gAppleSystemVariableGuid, key)) { 1084 newDict->setObject(key, _systemDict->getObject(key)); 1085 } 1086 } 1087 1088 _systemDict = newDict; 1089 1090 DEBUG_INFO("system dictionary flushed\n"); 1091 } else if (_commonDict != nullptr) { 1092 const OSSymbol *key; 1093 OSSharedPtr<OSDictionary> newDict; 1094 OSSharedPtr<OSCollectionIterator> iter; 1095 1096 newDict = OSDictionary::withCapacity(_commonDict->getCapacity()); 1097 iter = OSCollectionIterator::withCollection(newDict.get()); 1098 if ((newDict == nullptr) || (iter == nullptr)) { 1099 err = kIOReturnNoMemory; 1100 goto exit; 1101 } 1102 1103 while ((key = OSDynamicCast(OSSymbol, iter->getNextObject()))) { 1104 if (!verifyPermission(kIONVRAMOperationObliterate, &gAppleNVRAMGuid, key)) { 1105 newDict->setObject(key, _commonDict->getObject(key)); 1106 } 1107 } 1108 1109 _commonDict = newDict; 1110 1111 DEBUG_INFO("common dictionary flushed\n"); 1112 } 1113 1114 special = true; 1115 err = syncVariables(); 1116 } 1117 1118 exit: 1119 if (error) { 1120 *error = err; 1121 } 1122 1123 return special; 1124 } 1125 1126 OSSharedPtr<OSObject> 1127 IODTNVRAM::copyProperty(const OSSymbol *aKey) const 1128 { 1129 IOReturn result; 1130 const char *variableName; 1131 uuid_t varGuid; 1132 OSDictionary *dict; 1133 OSSharedPtr<OSObject> theObject = nullptr; 1134 1135 DEBUG_INFO("aKey=%s\n", aKey->getCStringNoCopy()); 1136 1137 parseVariableName(aKey->getCStringNoCopy(), &varGuid, &variableName); 1138 1139 result = chooseDictionary(kIONVRAMOperationRead, &varGuid, variableName, &dict); 1140 if (result != kIOReturnSuccess) { 1141 goto exit; 1142 } 1143 1144 if (!verifyPermission(kIONVRAMOperationRead, &varGuid, variableName)) { 1145 DEBUG_INFO("Not privileged\n"); 1146 goto exit; 1147 } 1148 1149 NVRAMLOCK(); 1150 theObject.reset(dict->getObject(variableName), OSRetain); 1151 NVRAMUNLOCK(); 1152 1153 if (theObject != nullptr) { 1154 DEBUG_INFO("found data\n"); 1155 } 1156 1157 exit: 1158 return theObject; 1159 } 1160 1161 OSSharedPtr<OSObject> 1162 IODTNVRAM::copyProperty(const char *aKey) const 1163 { 1164 OSSharedPtr<const OSSymbol> keySymbol; 1165 OSSharedPtr<OSObject> theObject; 1166 1167 keySymbol = OSSymbol::withCString(aKey); 1168 if (keySymbol != nullptr) { 1169 theObject = copyProperty(keySymbol.get()); 1170 } 1171 1172 return theObject; 1173 } 1174 1175 OSObject * 1176 IODTNVRAM::getProperty(const OSSymbol *aKey) const 1177 { 1178 // The shared pointer gets released at the end of the function, 1179 // and returns a view into theObject. 1180 OSSharedPtr<OSObject> theObject = copyProperty(aKey); 1181 1182 return theObject.get(); 1183 } 1184 1185 OSObject * 1186 IODTNVRAM::getProperty(const char *aKey) const 1187 { 1188 // The shared pointer gets released at the end of the function, 1189 // and returns a view into theObject. 1190 OSSharedPtr<OSObject> theObject = copyProperty(aKey); 1191 1192 return theObject.get(); 1193 } 1194 1195 IOReturn 1196 IODTNVRAM::setPropertyInternal(const OSSymbol *aKey, OSObject *anObject) 1197 { 1198 IOReturn result = kIOReturnSuccess; 1199 bool remove = false; 1200 OSString *tmpString = nullptr; 1201 OSSharedPtr<OSObject> propObject, oldObject; 1202 OSSharedPtr<OSObject> sharedObject(anObject, OSRetain); 1203 const char *variableName; 1204 uuid_t varGuid; 1205 OSDictionary *dict; 1206 bool deletePropertyKey, syncNowPropertyKey, forceSyncNowPropertyKey; 1207 size_t propDataSize = 0; 1208 1209 DEBUG_INFO("aKey=%s\n", aKey->getCStringNoCopy()); 1210 1211 parseVariableName(aKey->getCStringNoCopy(), &varGuid, &variableName); 1212 deletePropertyKey = strncmp(variableName, kIONVRAMDeletePropertyKey, sizeof(kIONVRAMDeletePropertyKey)) == 0; 1213 syncNowPropertyKey = strncmp(variableName, kIONVRAMSyncNowPropertyKey, sizeof(kIONVRAMSyncNowPropertyKey)) == 0; 1214 forceSyncNowPropertyKey = strncmp(variableName, kIONVRAMForceSyncNowPropertyKey, sizeof(kIONVRAMForceSyncNowPropertyKey)) == 0; 1215 1216 if (deletePropertyKey) { 1217 tmpString = OSDynamicCast(OSString, anObject); 1218 if (tmpString != nullptr) { 1219 DEBUG_INFO("kIONVRAMDeletePropertyKey found\n"); 1220 OSSharedPtr<const OSSymbol> sharedKey = OSSymbol::withString(tmpString); 1221 removeProperty(sharedKey.get()); 1222 } else { 1223 DEBUG_INFO("kIONVRAMDeletePropertyKey value needs to be an OSString\n"); 1224 result = kIOReturnError; 1225 } 1226 goto exit; 1227 } else if (syncNowPropertyKey || forceSyncNowPropertyKey) { 1228 tmpString = OSDynamicCast(OSString, anObject); 1229 DEBUG_INFO("NVRAM sync key %s found\n", aKey->getCStringNoCopy()); 1230 if (tmpString != nullptr) { 1231 // We still want to throttle NVRAM commit rate for SyncNow. ForceSyncNow is provided as a really big hammer. 1232 syncInternal(syncNowPropertyKey); 1233 } else { 1234 DEBUG_INFO("%s value needs to be an OSString\n", variableName); 1235 result = kIOReturnError; 1236 } 1237 goto exit; 1238 } 1239 1240 result = chooseDictionary(kIONVRAMOperationWrite, &varGuid, variableName, &dict); 1241 if (result != kIOReturnSuccess) { 1242 goto exit; 1243 } 1244 1245 if (!verifyPermission(kIONVRAMOperationWrite, &varGuid, variableName)) { 1246 DEBUG_INFO("Not privileged\n"); 1247 result = kIOReturnNotPrivileged; 1248 goto exit; 1249 } 1250 1251 // Make sure the object is of the correct type. 1252 switch (getVariableType(variableName)) { 1253 case kOFVariableTypeBoolean: 1254 propObject = OSDynamicPtrCast<OSBoolean>(sharedObject); 1255 break; 1256 1257 case kOFVariableTypeNumber: 1258 propObject = OSDynamicPtrCast<OSNumber>(sharedObject); 1259 break; 1260 1261 case kOFVariableTypeString: 1262 propObject = OSDynamicPtrCast<OSString>(sharedObject); 1263 if (propObject != nullptr) { 1264 propDataSize = (OSDynamicPtrCast<OSString>(propObject))->getLength(); 1265 1266 if (aKey->isEqualTo(kIONVRAMBootArgsKey) && (propDataSize >= BOOT_LINE_LENGTH)) { 1267 DEBUG_ERROR("boot-args size too large for BOOT_LINE_LENGTH, propDataSize=%zu\n", propDataSize); 1268 result = kIOReturnNoSpace; 1269 goto exit; 1270 } 1271 } 1272 break; 1273 1274 case kOFVariableTypeData: 1275 propObject = OSDynamicPtrCast<OSData>(sharedObject); 1276 if (propObject == nullptr) { 1277 tmpString = OSDynamicCast(OSString, sharedObject.get()); 1278 if (tmpString != nullptr) { 1279 propObject = OSData::withBytes(tmpString->getCStringNoCopy(), 1280 tmpString->getLength()); 1281 } 1282 } 1283 1284 if (propObject != nullptr) { 1285 propDataSize = (OSDynamicPtrCast<OSData>(propObject))->getLength(); 1286 } 1287 1288 #if defined(XNU_TARGET_OS_OSX) 1289 if ((propObject != nullptr) && ((OSDynamicPtrCast<OSData>(propObject))->getLength() == 0)) { 1290 remove = true; 1291 } 1292 #endif /* defined(XNU_TARGET_OS_OSX) */ 1293 break; 1294 default: 1295 break; 1296 } 1297 1298 if (propObject == nullptr) { 1299 DEBUG_INFO("No property object\n"); 1300 result = kIOReturnBadArgument; 1301 goto exit; 1302 } 1303 1304 if (!verifyWriteSizeLimit(&varGuid, variableName, propDataSize)) { 1305 DEBUG_ERROR("Property data size of %zu too long for %s\n", propDataSize, variableName); 1306 result = kIOReturnNoSpace; 1307 goto exit; 1308 } 1309 1310 NVRAMLOCK(); 1311 1312 if (handleSpecialVariables(variableName, &varGuid, propObject.get(), &result)) { 1313 goto unlock; 1314 } 1315 1316 oldObject.reset(dict->getObject(variableName), OSRetain); 1317 if (remove == false) { 1318 DEBUG_INFO("Adding object\n"); 1319 if (!dict->setObject(variableName, propObject.get())) { 1320 result = kIOReturnBadArgument; 1321 } 1322 } else { 1323 DEBUG_INFO("Removing object\n"); 1324 // Check for existence so we can decide whether we need to sync variables 1325 if (oldObject) { 1326 result = removePropertyInternal(aKey); 1327 } else { 1328 result = kIOReturnNotFound; 1329 } 1330 } 1331 1332 if (result == kIOReturnSuccess) { 1333 result = syncVariables(); 1334 if (result != kIOReturnSuccess) { 1335 DEBUG_ERROR("syncVariables failed, result=0x%08x\n", result); 1336 if (oldObject) { 1337 dict->setObject(variableName, oldObject.get()); 1338 } else { 1339 dict->removeObject(variableName); 1340 } 1341 (void) syncVariables(); 1342 result = kIOReturnNoMemory; 1343 } 1344 } 1345 1346 if (oldObject) { 1347 oldObject.reset(); 1348 } 1349 if (tmpString) { 1350 propObject.reset(); 1351 } 1352 1353 unlock: 1354 NVRAMUNLOCK(); 1355 1356 exit: 1357 DEBUG_INFO("result=0x%08x\n", result); 1358 1359 return result; 1360 } 1361 1362 bool 1363 IODTNVRAM::setProperty(const OSSymbol *aKey, OSObject *anObject) 1364 { 1365 return setPropertyInternal(aKey, anObject) == kIOReturnSuccess; 1366 } 1367 1368 void 1369 IODTNVRAM::removeProperty(const OSSymbol *aKey) 1370 { 1371 IOReturn ret; 1372 1373 NVRAMLOCK(); 1374 1375 ret = removePropertyInternal(aKey); 1376 1377 NVRAMUNLOCK(); 1378 1379 if (ret != kIOReturnSuccess) { 1380 DEBUG_INFO("removePropertyInternal failed, ret=0x%08x\n", ret); 1381 } 1382 } 1383 1384 IOReturn 1385 IODTNVRAM::removePropertyInternal(const OSSymbol *aKey) 1386 { 1387 IOReturn result; 1388 const char *variableName; 1389 uuid_t varGuid; 1390 OSDictionary *dict; 1391 1392 DEBUG_INFO("aKey=%s\n", aKey->getCStringNoCopy()); 1393 1394 NVRAMLOCKASSERT(); 1395 1396 parseVariableName(aKey->getCStringNoCopy(), &varGuid, &variableName); 1397 1398 result = chooseDictionary(kIONVRAMOperationDelete, &varGuid, variableName, &dict); 1399 if (result != kIOReturnSuccess) { 1400 goto exit; 1401 } 1402 1403 if (!verifyPermission(kIONVRAMOperationDelete, &varGuid, variableName)) { 1404 DEBUG_INFO("Not priveleged\n"); 1405 result = kIOReturnNotPrivileged; 1406 goto exit; 1407 } 1408 1409 // If the object exists, remove it from the dictionary. 1410 if (dict->getObject(variableName) != nullptr) { 1411 dict->removeObject(variableName); 1412 result = syncVariables(); 1413 } 1414 1415 exit: 1416 return result; 1417 } 1418 1419 IOReturn 1420 IODTNVRAM::setProperties(OSObject *properties) 1421 { 1422 IOReturn result = kIOReturnSuccess; 1423 OSObject *object; 1424 const OSSymbol *key; 1425 OSDictionary *dict; 1426 OSSharedPtr<OSCollectionIterator> iter; 1427 1428 dict = OSDynamicCast(OSDictionary, properties); 1429 if (dict == nullptr) { 1430 DEBUG_ERROR("Not a dictionary\n"); 1431 return kIOReturnBadArgument; 1432 } 1433 1434 iter = OSCollectionIterator::withCollection(dict); 1435 if (iter == nullptr) { 1436 DEBUG_ERROR("Couldn't create iterator\n"); 1437 return kIOReturnBadArgument; 1438 } 1439 1440 while (result == kIOReturnSuccess) { 1441 key = OSDynamicCast(OSSymbol, iter->getNextObject()); 1442 if (key == nullptr) { 1443 break; 1444 } 1445 1446 object = dict->getObject(key); 1447 if (object == nullptr) { 1448 continue; 1449 } 1450 1451 result = setPropertyInternal(key, object); 1452 } 1453 1454 DEBUG_INFO("result=0x%08x\n", result); 1455 1456 return result; 1457 } 1458 1459 IOReturn 1460 IODTNVRAM::readXPRAM(IOByteCount offset, UInt8 *buffer, 1461 IOByteCount length) 1462 { 1463 return kIOReturnUnsupported; 1464 } 1465 1466 IOReturn 1467 IODTNVRAM::writeXPRAM(IOByteCount offset, UInt8 *buffer, 1468 IOByteCount length) 1469 { 1470 return kIOReturnUnsupported; 1471 } 1472 1473 IOReturn 1474 IODTNVRAM::readNVRAMProperty(IORegistryEntry *entry, 1475 const OSSymbol **name, 1476 OSData **value) 1477 { 1478 IOReturn err; 1479 1480 err = readNVRAMPropertyType1(entry, name, value); 1481 1482 return err; 1483 } 1484 1485 IOReturn 1486 IODTNVRAM::writeNVRAMProperty(IORegistryEntry *entry, 1487 const OSSymbol *name, 1488 OSData *value) 1489 { 1490 IOReturn err; 1491 1492 err = writeNVRAMPropertyType1(entry, name, value); 1493 1494 return err; 1495 } 1496 1497 OSDictionary * 1498 IODTNVRAM::getNVRAMPartitions(void) 1499 { 1500 return _nvramPartitionLengths.get(); 1501 } 1502 1503 IOReturn 1504 IODTNVRAM::readNVRAMPartition(const OSSymbol *partitionID, 1505 IOByteCount offset, UInt8 *buffer, 1506 IOByteCount length) 1507 { 1508 OSNumber *partitionOffsetNumber, *partitionLengthNumber; 1509 UInt32 partitionOffset, partitionLength, end; 1510 1511 partitionOffsetNumber = 1512 (OSNumber *)_nvramPartitionOffsets->getObject(partitionID); 1513 partitionLengthNumber = 1514 (OSNumber *)_nvramPartitionLengths->getObject(partitionID); 1515 1516 if ((partitionOffsetNumber == nullptr) || (partitionLengthNumber == nullptr)) { 1517 return kIOReturnNotFound; 1518 } 1519 1520 partitionOffset = partitionOffsetNumber->unsigned32BitValue(); 1521 partitionLength = partitionLengthNumber->unsigned32BitValue(); 1522 1523 if (os_add_overflow(offset, length, &end)) { 1524 return kIOReturnBadArgument; 1525 } 1526 if ((buffer == nullptr) || (length == 0) || (end > partitionLength)) { 1527 return kIOReturnBadArgument; 1528 } 1529 1530 bcopy(_nvramImage + partitionOffset + offset, buffer, length); 1531 1532 return kIOReturnSuccess; 1533 } 1534 1535 IOReturn 1536 IODTNVRAM::writeNVRAMPartition(const OSSymbol *partitionID, 1537 IOByteCount offset, UInt8 *buffer, 1538 IOByteCount length) 1539 { 1540 OSNumber *partitionOffsetNumber, *partitionLengthNumber; 1541 UInt32 partitionOffset, partitionLength, end; 1542 1543 partitionOffsetNumber = 1544 (OSNumber *)_nvramPartitionOffsets->getObject(partitionID); 1545 partitionLengthNumber = 1546 (OSNumber *)_nvramPartitionLengths->getObject(partitionID); 1547 1548 if ((partitionOffsetNumber == nullptr) || (partitionLengthNumber == nullptr)) { 1549 return kIOReturnNotFound; 1550 } 1551 1552 partitionOffset = partitionOffsetNumber->unsigned32BitValue(); 1553 partitionLength = partitionLengthNumber->unsigned32BitValue(); 1554 1555 if (os_add_overflow(offset, length, &end)) { 1556 return kIOReturnBadArgument; 1557 } 1558 if ((buffer == nullptr) || (length == 0) || (end > partitionLength)) { 1559 return kIOReturnBadArgument; 1560 } 1561 1562 bcopy(buffer, _nvramImage + partitionOffset + offset, length); 1563 1564 if (_nvramController != nullptr) { 1565 _nvramController->write(0, _nvramImage, _nvramSize); 1566 } 1567 1568 return kIOReturnSuccess; 1569 } 1570 1571 IOByteCount 1572 IODTNVRAM::savePanicInfo(UInt8 *buffer, IOByteCount length) 1573 { 1574 return 0; 1575 } 1576 1577 // Private methods 1578 1579 UInt8 1580 IODTNVRAM::calculatePartitionChecksum(UInt8 *partitionHeader) 1581 { 1582 UInt8 cnt, isum, csum = 0; 1583 1584 for (cnt = 0; cnt < 0x10; cnt++) { 1585 isum = csum + partitionHeader[cnt]; 1586 if (isum < csum) { 1587 isum++; 1588 } 1589 csum = isum; 1590 } 1591 1592 return csum; 1593 } 1594 1595 IOReturn 1596 IODTNVRAM::initVariables(void) 1597 { 1598 UInt32 cnt; 1599 UInt8 *propName, *propData; 1600 UInt32 propNameLength, propDataLength, regionIndex; 1601 OSSharedPtr<const OSSymbol> propSymbol; 1602 OSSharedPtr<OSObject> propObject; 1603 NVRAMRegionInfo *currentRegion; 1604 1605 NVRAMRegionInfo variableRegions[] = { { NVRAM_CHRP_PARTITION_NAME_COMMON, _commonPartitionOffset, _commonPartitionSize, _commonDict, _commonImage}, 1606 { NVRAM_CHRP_PARTITION_NAME_SYSTEM, _systemPartitionOffset, _systemPartitionSize, _systemDict, _systemImage} }; 1607 1608 DEBUG_INFO("...\n"); 1609 1610 for (regionIndex = 0; regionIndex < ARRAY_SIZE(variableRegions); regionIndex++) { 1611 currentRegion = &variableRegions[regionIndex]; 1612 1613 if (currentRegion->size == 0) { 1614 continue; 1615 } 1616 1617 currentRegion->dict = OSDictionary::withCapacity(1); 1618 1619 DEBUG_INFO("region = %s\n", currentRegion->name); 1620 cnt = 0; 1621 while (cnt < currentRegion->size) { 1622 // Break if there is no name. 1623 if (currentRegion->image[cnt] == '\0') { 1624 break; 1625 } 1626 1627 // Find the length of the name. 1628 propName = currentRegion->image + cnt; 1629 for (propNameLength = 0; (cnt + propNameLength) < currentRegion->size; 1630 propNameLength++) { 1631 if (currentRegion->image[cnt + propNameLength] == '=') { 1632 break; 1633 } 1634 } 1635 1636 // Break if the name goes past the end of the partition. 1637 if ((cnt + propNameLength) >= currentRegion->size) { 1638 break; 1639 } 1640 cnt += propNameLength + 1; 1641 1642 propData = currentRegion->image + cnt; 1643 for (propDataLength = 0; (cnt + propDataLength) < currentRegion->size; 1644 propDataLength++) { 1645 if (currentRegion->image[cnt + propDataLength] == '\0') { 1646 break; 1647 } 1648 } 1649 1650 // Break if the data goes past the end of the partition. 1651 if ((cnt + propDataLength) >= currentRegion->size) { 1652 break; 1653 } 1654 cnt += propDataLength + 1; 1655 1656 if (convertPropToObject(propName, propNameLength, 1657 propData, propDataLength, 1658 propSymbol, propObject)) { 1659 DEBUG_INFO("adding %s, dataLength=%u\n", propSymbol.get()->getCStringNoCopy(), (unsigned int)propDataLength); 1660 currentRegion->dict.get()->setObject(propSymbol.get(), propObject.get()); 1661 } 1662 } 1663 } 1664 1665 // Create the boot-args property if it is not in the dictionary. 1666 if (_commonDict->getObject(kIONVRAMBootArgsKey) == nullptr) { 1667 propObject = OSString::withCStringNoCopy(""); 1668 if (propObject != nullptr) { 1669 _commonDict->setObject(kIONVRAMBootArgsKey, propObject.get()); 1670 } 1671 } 1672 1673 DEBUG_INFO("%s _commonDict=%p _systemDict=%p\n", __FUNCTION__, _commonDict.get(), _systemDict.get()); 1674 1675 return kIOReturnSuccess; 1676 } 1677 1678 IOReturn 1679 IODTNVRAM::syncOFVariables(void) 1680 { 1681 return kIOReturnUnsupported; 1682 } 1683 1684 IOReturn 1685 IODTNVRAM::syncVariables(void) 1686 { 1687 bool ok; 1688 UInt32 length, maxLength, regionIndex; 1689 UInt8 *buffer, *tmpBuffer; 1690 const OSSymbol *tmpSymbol; 1691 OSObject *tmpObject; 1692 OSSharedPtr<OSCollectionIterator> iter; 1693 NVRAMRegionInfo *currentRegion; 1694 1695 NVRAMRegionInfo variableRegions[] = { { NVRAM_CHRP_PARTITION_NAME_COMMON, _commonPartitionOffset, _commonPartitionSize, _commonDict, _commonImage}, 1696 { NVRAM_CHRP_PARTITION_NAME_SYSTEM, _systemPartitionOffset, _systemPartitionSize, _systemDict, _systemImage} }; 1697 1698 NVRAMLOCKASSERT(); 1699 1700 if (_systemPanicked) { 1701 return kIOReturnNotReady; 1702 } 1703 1704 if (_nvramController == nullptr) { 1705 DEBUG_ERROR("No _nvramController\n"); 1706 return kIOReturnNotReady; 1707 } 1708 1709 DEBUG_INFO("...\n"); 1710 1711 for (regionIndex = 0; regionIndex < ARRAY_SIZE(variableRegions); regionIndex++) { 1712 OSSharedPtr<OSNumber> sizeUsed; 1713 currentRegion = &variableRegions[regionIndex]; 1714 1715 if (currentRegion->size == 0) { 1716 continue; 1717 } 1718 1719 DEBUG_INFO("region = %s\n", currentRegion->name); 1720 buffer = tmpBuffer = IONew(UInt8, currentRegion->size); 1721 if (buffer == nullptr) { 1722 return kIOReturnNoMemory; 1723 } 1724 bzero(buffer, currentRegion->size); 1725 1726 ok = true; 1727 maxLength = currentRegion->size; 1728 1729 iter = OSCollectionIterator::withCollection(currentRegion->dict.get()); 1730 if (iter == nullptr) { 1731 ok = false; 1732 } 1733 1734 while (ok) { 1735 tmpSymbol = OSDynamicCast(OSSymbol, iter->getNextObject()); 1736 if (tmpSymbol == nullptr) { 1737 break; 1738 } 1739 1740 DEBUG_INFO("adding variable %s\n", tmpSymbol->getCStringNoCopy()); 1741 1742 tmpObject = currentRegion->dict->getObject(tmpSymbol); 1743 1744 length = maxLength; 1745 ok = convertObjectToProp(tmpBuffer, &length, tmpSymbol, tmpObject); 1746 if (ok) { 1747 tmpBuffer += length; 1748 maxLength -= length; 1749 } 1750 } 1751 1752 if (ok) { 1753 bcopy(buffer, currentRegion->image, currentRegion->size); 1754 } 1755 1756 IODelete(buffer, UInt8, currentRegion->size); 1757 1758 sizeUsed = OSNumber::withNumber(maxLength, 32); 1759 _nvramController->setProperty(currentRegion->name, sizeUsed.get()); 1760 sizeUsed.reset(); 1761 1762 if ((strncmp(currentRegion->name, NVRAM_CHRP_PARTITION_NAME_SYSTEM, strlen(NVRAM_CHRP_PARTITION_NAME_SYSTEM)) == 0) && 1763 (_systemService != nullptr)) { 1764 _systemService->setProperties(_systemDict.get()); 1765 } else if ((strncmp(currentRegion->name, NVRAM_CHRP_PARTITION_NAME_COMMON, strlen(NVRAM_CHRP_PARTITION_NAME_COMMON)) == 0) && 1766 (_commonService != nullptr)) { 1767 _commonService->setProperties(_commonDict.get()); 1768 } 1769 1770 if (!ok) { 1771 return kIOReturnBadArgument; 1772 } 1773 } 1774 1775 DEBUG_INFO("ok=%d\n", ok); 1776 1777 return _nvramController->write(0, _nvramImage, _nvramSize); 1778 } 1779 1780 UInt32 1781 IODTNVRAM::getOFVariableType(const char *propName) const 1782 { 1783 return 0; 1784 } 1785 1786 UInt32 1787 IODTNVRAM::getOFVariableType(const OSSymbol *propSymbol) const 1788 { 1789 return 0; 1790 } 1791 1792 1793 UInt32 1794 IODTNVRAM::getOFVariablePerm(const char *propName) const 1795 { 1796 return 0; 1797 } 1798 1799 UInt32 1800 IODTNVRAM::getOFVariablePerm(const OSSymbol *propSymbol) const 1801 { 1802 return 0; 1803 } 1804 1805 bool 1806 IODTNVRAM::getOWVariableInfo(UInt32 variableNumber, const OSSymbol **propSymbol, 1807 UInt32 *propType, UInt32 *propOffset) 1808 { 1809 /* UNSUPPORTED */ 1810 return false; 1811 } 1812 bool 1813 IODTNVRAM::convertPropToObject(UInt8 *propName, UInt32 propNameLength, 1814 UInt8 *propData, UInt32 propDataLength, 1815 const OSSymbol **propSymbol, 1816 OSObject **propObject) 1817 { 1818 OSSharedPtr<const OSSymbol> tmpSymbol; 1819 OSSharedPtr<OSNumber> tmpNumber; 1820 OSSharedPtr<OSString> tmpString; 1821 OSSharedPtr<OSObject> tmpObject = nullptr; 1822 1823 propName[propNameLength] = '\0'; 1824 tmpSymbol = OSSymbol::withCString((const char *)propName); 1825 propName[propNameLength] = '='; 1826 if (tmpSymbol == nullptr) { 1827 return false; 1828 } 1829 1830 switch (getVariableType(tmpSymbol.get())) { 1831 case kOFVariableTypeBoolean: 1832 if (!strncmp("true", (const char *)propData, propDataLength)) { 1833 tmpObject.reset(kOSBooleanTrue, OSRetain); 1834 } else if (!strncmp("false", (const char *)propData, propDataLength)) { 1835 tmpObject.reset(kOSBooleanFalse, OSRetain); 1836 } 1837 break; 1838 1839 case kOFVariableTypeNumber: 1840 tmpNumber = OSNumber::withNumber(strtol((const char *)propData, nullptr, 0), 32); 1841 if (tmpNumber != nullptr) { 1842 tmpObject = tmpNumber; 1843 } 1844 break; 1845 1846 case kOFVariableTypeString: 1847 tmpString = OSString::withCString((const char *)propData); 1848 if (tmpString != nullptr) { 1849 tmpObject = tmpString; 1850 } 1851 break; 1852 1853 case kOFVariableTypeData: 1854 tmpObject = unescapeBytesToData(propData, propDataLength); 1855 break; 1856 1857 default: 1858 break; 1859 } 1860 1861 if (tmpObject == nullptr) { 1862 tmpSymbol.reset(); 1863 return false; 1864 } 1865 1866 *propSymbol = tmpSymbol.detach(); 1867 *propObject = tmpObject.detach(); 1868 1869 return true; 1870 } 1871 1872 bool 1873 IODTNVRAM::convertPropToObject(UInt8 *propName, UInt32 propNameLength, 1874 UInt8 *propData, UInt32 propDataLength, 1875 OSSharedPtr<const OSSymbol>& propSymbol, 1876 OSSharedPtr<OSObject>& propObject) 1877 { 1878 const OSSymbol* propSymbolRaw = nullptr; 1879 OSObject* propObjectRaw = nullptr; 1880 bool result = convertPropToObject(propName, propNameLength, propData, propDataLength, 1881 &propSymbolRaw, &propObjectRaw); 1882 propSymbol.reset(propSymbolRaw, OSNoRetain); 1883 propObject.reset(propObjectRaw, OSNoRetain); 1884 return result; 1885 } 1886 1887 bool 1888 IODTNVRAM::convertObjectToProp(UInt8 *buffer, UInt32 *length, 1889 const OSSymbol *propSymbol, OSObject *propObject) 1890 { 1891 const UInt8 *propName; 1892 UInt32 propNameLength, propDataLength, remaining; 1893 IONVRAMVariableType propType; 1894 OSBoolean *tmpBoolean = nullptr; 1895 OSNumber *tmpNumber = nullptr; 1896 OSString *tmpString = nullptr; 1897 OSSharedPtr<OSData> tmpData; 1898 1899 propName = (const UInt8 *)propSymbol->getCStringNoCopy(); 1900 propNameLength = propSymbol->getLength(); 1901 propType = getVariableType(propSymbol); 1902 1903 // Get the size of the data. 1904 propDataLength = 0xFFFFFFFF; 1905 switch (propType) { 1906 case kOFVariableTypeBoolean: 1907 tmpBoolean = OSDynamicCast(OSBoolean, propObject); 1908 if (tmpBoolean != nullptr) { 1909 propDataLength = 5; 1910 } 1911 break; 1912 1913 case kOFVariableTypeNumber: 1914 tmpNumber = OSDynamicCast(OSNumber, propObject); 1915 if (tmpNumber != nullptr) { 1916 propDataLength = 10; 1917 } 1918 break; 1919 1920 case kOFVariableTypeString: 1921 tmpString = OSDynamicCast(OSString, propObject); 1922 if (tmpString != nullptr) { 1923 propDataLength = tmpString->getLength(); 1924 } 1925 break; 1926 1927 case kOFVariableTypeData: 1928 tmpData.reset(OSDynamicCast(OSData, propObject), OSNoRetain); 1929 if (tmpData != nullptr) { 1930 tmpData = escapeDataToData(tmpData.detach()); 1931 propDataLength = tmpData->getLength(); 1932 } 1933 break; 1934 1935 default: 1936 break; 1937 } 1938 1939 // Make sure the propertySize is known and will fit. 1940 if (propDataLength == 0xFFFFFFFF) { 1941 return false; 1942 } 1943 if ((propNameLength + propDataLength + 2) > *length) { 1944 return false; 1945 } 1946 1947 // Copy the property name equal sign. 1948 buffer += snprintf((char *)buffer, *length, "%s=", propName); 1949 remaining = *length - propNameLength - 1; 1950 1951 switch (propType) { 1952 case kOFVariableTypeBoolean: 1953 if (tmpBoolean->getValue()) { 1954 strlcpy((char *)buffer, "true", remaining); 1955 } else { 1956 strlcpy((char *)buffer, "false", remaining); 1957 } 1958 break; 1959 1960 case kOFVariableTypeNumber: 1961 { 1962 uint32_t tmpValue = tmpNumber->unsigned32BitValue(); 1963 if (tmpValue == 0xFFFFFFFF) { 1964 strlcpy((char *)buffer, "-1", remaining); 1965 } else if (tmpValue < 1000) { 1966 snprintf((char *)buffer, remaining, "%d", (uint32_t)tmpValue); 1967 } else { 1968 snprintf((char *)buffer, remaining, "0x%x", (uint32_t)tmpValue); 1969 } 1970 } 1971 break; 1972 1973 case kOFVariableTypeString: 1974 strlcpy((char *)buffer, tmpString->getCStringNoCopy(), remaining); 1975 break; 1976 1977 case kOFVariableTypeData: 1978 bcopy(tmpData->getBytesNoCopy(), buffer, propDataLength); 1979 tmpData.reset(); 1980 break; 1981 1982 default: 1983 break; 1984 } 1985 1986 propDataLength = ((UInt32) strlen((const char *)buffer)); 1987 1988 *length = propNameLength + propDataLength + 2; 1989 1990 return true; 1991 } 1992 1993 1994 UInt16 1995 IODTNVRAM::generateOWChecksum(UInt8 *buffer) 1996 { 1997 UInt32 cnt, checksum = 0; 1998 UInt16 *tmpBuffer = (UInt16 *)buffer; 1999 2000 for (cnt = 0; cnt < _commonPartitionSize / 2; cnt++) { 2001 checksum += tmpBuffer[cnt]; 2002 } 2003 2004 return checksum % 0x0000FFFF; 2005 } 2006 2007 bool 2008 IODTNVRAM::validateOWChecksum(UInt8 *buffer) 2009 { 2010 UInt32 cnt, checksum, sum = 0; 2011 UInt16 *tmpBuffer = (UInt16 *)buffer; 2012 2013 for (cnt = 0; cnt < _commonPartitionSize / 2; cnt++) { 2014 sum += tmpBuffer[cnt]; 2015 } 2016 2017 checksum = (sum >> 16) + (sum & 0x0000FFFF); 2018 if (checksum == 0x10000) { 2019 checksum--; 2020 } 2021 checksum = (checksum ^ 0x0000FFFF) & 0x0000FFFF; 2022 2023 return checksum == 0; 2024 } 2025 2026 void 2027 IODTNVRAM::updateOWBootArgs(const OSSymbol *key, OSObject *value) 2028 { 2029 /* UNSUPPORTED */ 2030 } 2031 2032 bool 2033 IODTNVRAM::searchNVRAMProperty(IONVRAMDescriptor *hdr, UInt32 *where) 2034 { 2035 return false; 2036 } 2037 2038 IOReturn 2039 IODTNVRAM::readNVRAMPropertyType0(IORegistryEntry *entry, 2040 const OSSymbol **name, 2041 OSData **value) 2042 { 2043 return kIOReturnUnsupported; 2044 } 2045 2046 2047 IOReturn 2048 IODTNVRAM::writeNVRAMPropertyType0(IORegistryEntry *entry, 2049 const OSSymbol *name, 2050 OSData *value) 2051 { 2052 return kIOReturnUnsupported; 2053 } 2054 2055 2056 OSSharedPtr<OSData> 2057 IODTNVRAM::unescapeBytesToData(const UInt8 *bytes, UInt32 length) 2058 { 2059 OSSharedPtr<OSData> data; 2060 UInt32 totalLength = 0; 2061 UInt32 cnt, cnt2; 2062 UInt8 byte; 2063 bool ok; 2064 2065 // Calculate the actual length of the data. 2066 ok = true; 2067 totalLength = 0; 2068 for (cnt = 0; cnt < length;) { 2069 byte = bytes[cnt++]; 2070 if (byte == 0xFF) { 2071 byte = bytes[cnt++]; 2072 if (byte == 0x00) { 2073 ok = false; 2074 break; 2075 } 2076 cnt2 = byte & 0x7F; 2077 } else { 2078 cnt2 = 1; 2079 } 2080 totalLength += cnt2; 2081 } 2082 2083 if (ok) { 2084 // Create an empty OSData of the correct size. 2085 data = OSData::withCapacity(totalLength); 2086 if (data != nullptr) { 2087 for (cnt = 0; cnt < length;) { 2088 byte = bytes[cnt++]; 2089 if (byte == 0xFF) { 2090 byte = bytes[cnt++]; 2091 cnt2 = byte & 0x7F; 2092 byte = (byte & 0x80) ? 0xFF : 0x00; 2093 } else { 2094 cnt2 = 1; 2095 } 2096 data->appendByte(byte, cnt2); 2097 } 2098 } 2099 } 2100 2101 return data; 2102 } 2103 2104 OSSharedPtr<OSData> 2105 IODTNVRAM::escapeDataToData(OSData * value) 2106 { 2107 OSSharedPtr<OSData> result; 2108 const UInt8 *startPtr; 2109 const UInt8 *endPtr; 2110 const UInt8 *wherePtr; 2111 UInt8 byte; 2112 bool ok = true; 2113 2114 wherePtr = (const UInt8 *) value->getBytesNoCopy(); 2115 endPtr = wherePtr + value->getLength(); 2116 2117 result = OSData::withCapacity((unsigned int) (endPtr - wherePtr)); 2118 if (!result) { 2119 return result; 2120 } 2121 2122 while (wherePtr < endPtr) { 2123 startPtr = wherePtr; 2124 byte = *wherePtr++; 2125 if ((byte == 0x00) || (byte == 0xFF)) { 2126 for (; 2127 ((wherePtr - startPtr) < 0x80) && (wherePtr < endPtr) && (byte == *wherePtr); 2128 wherePtr++) { 2129 } 2130 ok &= result->appendByte(0xff, 1); 2131 byte = (byte & 0x80) | ((UInt8)(wherePtr - startPtr)); 2132 } 2133 ok &= result->appendByte(byte, 1); 2134 } 2135 ok &= result->appendByte(0, 1); 2136 2137 if (!ok) { 2138 result.reset(); 2139 } 2140 2141 return result; 2142 } 2143 2144 static bool 2145 IsApplePropertyName(const char * propName) 2146 { 2147 char c; 2148 while ((c = *propName++)) { 2149 if ((c >= 'A') && (c <= 'Z')) { 2150 break; 2151 } 2152 } 2153 2154 return c == 0; 2155 } 2156 2157 IOReturn 2158 IODTNVRAM::readNVRAMPropertyType1(IORegistryEntry *entry, 2159 const OSSymbol **name, 2160 OSData **value) 2161 { 2162 IOReturn err = kIOReturnNoResources; 2163 OSData *data; 2164 const UInt8 *startPtr; 2165 const UInt8 *endPtr; 2166 const UInt8 *wherePtr; 2167 const UInt8 *nvPath = nullptr; 2168 const char *nvName = nullptr; 2169 const char *resultName = nullptr; 2170 const UInt8 *resultValue = nullptr; 2171 UInt32 resultValueLen = 0; 2172 UInt8 byte; 2173 2174 NVRAMLOCK(); 2175 data = OSDynamicCast(OSData, _commonDict->getObject(_registryPropertiesKey.get())); 2176 NVRAMUNLOCK(); 2177 2178 if (data == nullptr) { 2179 return err; 2180 } 2181 2182 startPtr = (const UInt8 *) data->getBytesNoCopy(); 2183 endPtr = startPtr + data->getLength(); 2184 2185 wherePtr = startPtr; 2186 while (wherePtr < endPtr) { 2187 byte = *(wherePtr++); 2188 if (byte) { 2189 continue; 2190 } 2191 2192 if (nvPath == nullptr) { 2193 nvPath = startPtr; 2194 } else if (nvName == nullptr) { 2195 nvName = (const char *) startPtr; 2196 } else { 2197 OSSharedPtr<IORegistryEntry> compareEntry = IORegistryEntry::fromPath((const char *) nvPath, gIODTPlane); 2198 if (entry == compareEntry) { 2199 bool appleProp = IsApplePropertyName(nvName); 2200 if (!appleProp || !resultName) { 2201 resultName = nvName; 2202 resultValue = startPtr; 2203 resultValueLen = (UInt32) (wherePtr - startPtr - 1); // OSData getLength() is 32b 2204 } 2205 if (!appleProp) { 2206 break; 2207 } 2208 } 2209 nvPath = nullptr; 2210 nvName = nullptr; 2211 } 2212 startPtr = wherePtr; 2213 } 2214 if (resultName) { 2215 *name = OSSymbol::withCString(resultName).detach(); 2216 *value = unescapeBytesToData(resultValue, resultValueLen).detach(); 2217 if ((*name != nullptr) && (*value != nullptr)) { 2218 err = kIOReturnSuccess; 2219 } else { 2220 err = kIOReturnNoMemory; 2221 } 2222 } 2223 return err; 2224 } 2225 2226 IOReturn 2227 IODTNVRAM::writeNVRAMPropertyType1(IORegistryEntry *entry, 2228 const OSSymbol *propName, 2229 OSData *value) 2230 { 2231 OSSharedPtr<OSData> data, oldData; 2232 const UInt8 *startPtr; 2233 const UInt8 *propStart; 2234 const UInt8 *endPtr; 2235 const UInt8 *wherePtr; 2236 const UInt8 *nvPath = nullptr; 2237 const char *nvName = nullptr; 2238 const char *comp; 2239 const char *name; 2240 UInt8 byte; 2241 bool ok = true; 2242 bool settingAppleProp; 2243 2244 settingAppleProp = IsApplePropertyName(propName->getCStringNoCopy()); 2245 2246 // copy over existing properties for other entries 2247 2248 NVRAMLOCK(); 2249 2250 oldData.reset(OSDynamicCast(OSData, _commonDict->getObject(_registryPropertiesKey.get())), OSRetain); 2251 if (oldData) { 2252 startPtr = (const UInt8 *) oldData->getBytesNoCopy(); 2253 endPtr = startPtr + oldData->getLength(); 2254 2255 propStart = startPtr; 2256 wherePtr = startPtr; 2257 while (wherePtr < endPtr) { 2258 byte = *(wherePtr++); 2259 if (byte) { 2260 continue; 2261 } 2262 if (nvPath == nullptr) { 2263 nvPath = startPtr; 2264 } else if (nvName == nullptr) { 2265 nvName = (const char *) startPtr; 2266 } else { 2267 OSSharedPtr<IORegistryEntry> compareEntry = IORegistryEntry::fromPath((const char *) nvPath, gIODTPlane); 2268 2269 if (entry == compareEntry) { 2270 if ((settingAppleProp && propName->isEqualTo(nvName)) 2271 || (!settingAppleProp && !IsApplePropertyName(nvName))) { 2272 // delete old property (nvPath -> wherePtr) source OSData len is 32b 2273 data = OSData::withBytes(propStart, (UInt32)(nvPath - propStart)); 2274 if (data) { 2275 ok &= data->appendBytes(wherePtr, (UInt32)(endPtr - wherePtr)); 2276 } 2277 break; 2278 } 2279 } 2280 nvPath = nullptr; 2281 nvName = nullptr; 2282 } 2283 2284 startPtr = wherePtr; 2285 } 2286 } 2287 2288 // make the new property 2289 2290 if (!data) { 2291 if (oldData) { 2292 data = OSData::withData(oldData.get()); 2293 } else { 2294 data = OSData::withCapacity(16); 2295 } 2296 if (!data) { 2297 ok = false; 2298 } 2299 } 2300 2301 if (ok && value && value->getLength()) { 2302 do { 2303 // get entries in path 2304 OSSharedPtr<OSArray> array = OSArray::withCapacity(5); 2305 if (!array) { 2306 ok = false; 2307 break; 2308 } 2309 do{ 2310 array->setObject(entry); 2311 } while ((entry = entry->getParentEntry(gIODTPlane))); 2312 2313 // append path 2314 for (int i = array->getCount() - 3; 2315 (entry = (IORegistryEntry *) array->getObject(i)); 2316 i--) { 2317 name = entry->getName(gIODTPlane); 2318 comp = entry->getLocation(gIODTPlane); 2319 if (comp) { 2320 ok &= data->appendBytes("/@", 2); 2321 } else { 2322 if (!name) { 2323 continue; 2324 } 2325 ok &= data->appendByte('/', 1); 2326 comp = name; 2327 } 2328 ok &= data->appendBytes(comp, (unsigned int) strnlen(comp, UINT16_MAX)); 2329 } 2330 ok &= data->appendByte(0, 1); 2331 // append prop name 2332 ok &= data->appendBytes(propName->getCStringNoCopy(), propName->getLength() + 1); 2333 2334 // append escaped data 2335 OSSharedPtr<OSData> escapedData = escapeDataToData(value); 2336 ok &= (escapedData != nullptr); 2337 if (ok) { 2338 ok &= data->appendBytes(escapedData.get()); 2339 } 2340 } while (false); 2341 } 2342 2343 if (ok) { 2344 ok = _commonDict->setObject(_registryPropertiesKey.get(), data.get()); 2345 } 2346 2347 if (ok) { 2348 if (syncVariables() != kIOReturnSuccess) { 2349 if (oldData) { 2350 _commonDict->setObject(_registryPropertiesKey.get(), oldData.get()); 2351 } else { 2352 _commonDict->removeObject(_registryPropertiesKey.get()); 2353 } 2354 (void) syncVariables(); 2355 ok = false; 2356 } 2357 } 2358 2359 oldData.reset(); 2360 2361 NVRAMUNLOCK(); 2362 2363 return ok ? kIOReturnSuccess : kIOReturnNoMemory; 2364 } 2365 2366 bool 2367 IODTNVRAM::safeToSync(void) 2368 { 2369 AbsoluteTime delta; 2370 UInt64 delta_ns; 2371 SInt32 delta_secs; 2372 2373 // delta interval went by 2374 clock_get_uptime(&delta); 2375 2376 // Figure it in seconds. 2377 absolutetime_to_nanoseconds(delta, &delta_ns); 2378 delta_secs = (SInt32)(delta_ns / NSEC_PER_SEC); 2379 2380 if ((delta_secs > (_lastDeviceSync + MIN_SYNC_NOW_INTERVAL)) || _freshInterval) { 2381 _lastDeviceSync = delta_secs; 2382 _freshInterval = FALSE; 2383 return TRUE; 2384 } 2385 2386 return FALSE; 2387 } 2388