1 /* 2 * Copyright (c) 1998-2006 Apple Computer, Inc. All rights reserved. 3 * Copyright (c) 2007-2021 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 <os/system_event_log.h> 42 #include <sys/csr.h> 43 44 #define super IOService 45 46 OSDefineMetaClassAndStructors(IODTNVRAM, IOService); 47 48 class IONVRAMCHRPHandler; 49 class IONVRAMV3Handler; 50 51 #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) 52 53 #define MAX_VAR_NAME_SIZE 63 54 55 #define kNVRAMBankSizeKey "nvram-bank-size" 56 #define kNVRAMBankCountKey "nvram-bank-count" 57 #define kNVRAMCurrentBankKey "nvram-current-bank" 58 59 #define kCurrentGenerationCountKey "Generation" 60 #define kCurrentNVRAMVersionKey "Version" 61 62 #define kNVRAMCommonUsedKey "CommonUsed" 63 #define kNVRAMSystemUsedKey "SystemUsed" 64 65 #define kIONVRAMPrivilege kIOClientPrivilegeAdministrator 66 67 #define MIN_SYNC_NOW_INTERVAL 15*60 /* Minimum 15 Minutes interval mandated */ 68 69 #if defined(DEBUG) || defined(DEVELOPMENT) 70 #define DEBUG_IFERROR(err, fmt, args...) \ 71 ({ \ 72 if ((err != kIOReturnSuccess) || gNVRAMLogging) \ 73 IOLog("%s:%s:%u - " fmt, __FILE_NAME__, __FUNCTION__, __LINE__, ##args); \ 74 }) 75 76 #define DEBUG_INFO(fmt, args...) \ 77 ({ \ 78 if (gNVRAMLogging) \ 79 IOLog("%s:%s:%u - " fmt, __FILE_NAME__, __FUNCTION__, __LINE__, ##args); \ 80 }) 81 82 #define DEBUG_ALWAYS(fmt, args...) \ 83 ({ \ 84 IOLog("%s:%s:%u - " fmt, __FILE_NAME__, __FUNCTION__, __LINE__, ##args); \ 85 }) 86 #else 87 #define DEBUG_IFERROR(err, fmt, args...) (void)NULL 88 #define DEBUG_INFO(fmt, args...) (void)NULL 89 #define DEBUG_ALWAYS(fmt, args...) (void)NULL 90 #endif 91 92 #define DEBUG_ERROR DEBUG_ALWAYS 93 94 #define SAFE_TO_LOCK() (preemption_enabled() && !panic_active()) 95 96 #define CONTROLLERLOCK() \ 97 ({ \ 98 if (SAFE_TO_LOCK()) \ 99 IOLockLock(_controllerLock); \ 100 }) 101 102 #define CONTROLLERUNLOCK() \ 103 ({ \ 104 if (SAFE_TO_LOCK()) \ 105 IOLockUnlock(_controllerLock); \ 106 }) 107 108 #define NVRAMREADLOCK() \ 109 ({ \ 110 if (SAFE_TO_LOCK()) \ 111 IORWLockRead(_variableLock); \ 112 }) 113 114 #define NVRAMWRITELOCK() \ 115 ({ \ 116 if (SAFE_TO_LOCK()) \ 117 IORWLockWrite(_variableLock); \ 118 }) 119 120 #define NVRAMUNLOCK() \ 121 ({ \ 122 if (SAFE_TO_LOCK()) \ 123 IORWLockUnlock(_variableLock); \ 124 }) 125 126 #define NVRAMLOCKASSERTHELD() \ 127 ({ \ 128 if (SAFE_TO_LOCK()) \ 129 IORWLockAssert(_variableLock, kIORWLockAssertHeld); \ 130 }) 131 132 #define NVRAMLOCKASSERTEXCLUSIVE() \ 133 ({ \ 134 if (SAFE_TO_LOCK()) \ 135 IORWLockAssert(_variableLock, kIORWLockAssertWrite); \ 136 }) 137 138 #define ENTITLED_MODIFY_ONLY ((1 << kIONVRAMOperationWrite) | (1 << kIONVRAMOperationDelete) | (1 << kIONVRAMOperationObliterate) | (1 << kIONVRAMOperationReset)) 139 140 enum NVRAMVersion { 141 kNVRAMVersionUnknown, 142 kNVRAMVersion1, // Legacy, banks, 0x800 common partition size 143 kNVRAMVersion2, // V1 but with (0x2000 - sizeof(struct apple_nvram_header) - sizeof(struct chrp_nvram_header)) common region 144 kNVRAMVersion3, // New EFI based format 145 kNVRAMVersionMax 146 }; 147 148 // Guid for Apple System Boot variables 149 // 40A0DDD2-77F8-4392-B4A3-1E7304206516 150 UUID_DEFINE(gAppleSystemVariableGuid, 0x40, 0xA0, 0xDD, 0xD2, 0x77, 0xF8, 0x43, 0x92, 0xB4, 0xA3, 0x1E, 0x73, 0x04, 0x20, 0x65, 0x16); 151 152 // Apple NVRAM Variable namespace (APPLE_VENDOR_OS_VARIABLE_GUID) 153 // 7C436110-AB2A-4BBB-A880-FE41995C9F82 154 UUID_DEFINE(gAppleNVRAMGuid, 0x7C, 0x43, 0x61, 0x10, 0xAB, 0x2A, 0x4B, 0xBB, 0xA8, 0x80, 0xFE, 0x41, 0x99, 0x5C, 0x9F, 0x82); 155 156 static TUNABLE(bool, gNVRAMLogging, "nvram-log", false); 157 static bool gInternalBuild = false; 158 159 // allowlist variables from macboot that need to be set/get from system region if present 160 static const char * const gNVRAMSystemList[] = { IONVRAMSystemVariableList, nullptr }; 161 162 typedef struct { 163 const char *name; 164 IONVRAMVariableType type; 165 } VariableTypeEntry; 166 167 static const 168 VariableTypeEntry gVariableTypes[] = { 169 {"auto-boot?", kOFVariableTypeBoolean}, 170 {"boot-args", kOFVariableTypeString}, 171 {"boot-command", kOFVariableTypeString}, 172 {"boot-device", kOFVariableTypeString}, 173 {"boot-file", kOFVariableTypeString}, 174 {"boot-screen", kOFVariableTypeString}, 175 {"boot-script", kOFVariableTypeString}, 176 {"console-screen", kOFVariableTypeString}, 177 {"default-client-ip", kOFVariableTypeString}, 178 {"default-gateway-ip", kOFVariableTypeString}, 179 {"default-mac-address?", kOFVariableTypeBoolean}, 180 {"default-router-ip", kOFVariableTypeString}, 181 {"default-server-ip", kOFVariableTypeString}, 182 {"default-subnet-mask", kOFVariableTypeString}, 183 {"diag-device", kOFVariableTypeString}, 184 {"diag-file", kOFVariableTypeString}, 185 {"diag-switch?", kOFVariableTypeBoolean}, 186 {"fcode-debug?", kOFVariableTypeBoolean}, 187 {"input-device", kOFVariableTypeString}, 188 {"input-device-1", kOFVariableTypeString}, 189 {"little-endian?", kOFVariableTypeBoolean}, 190 {"load-base", kOFVariableTypeNumber}, 191 {"mouse-device", kOFVariableTypeString}, 192 {"nvramrc", kOFVariableTypeString}, 193 {"oem-banner", kOFVariableTypeString}, 194 {"oem-banner?", kOFVariableTypeBoolean}, 195 {"oem-logo", kOFVariableTypeString}, 196 {"oem-logo?", kOFVariableTypeBoolean}, 197 {"output-device", kOFVariableTypeString}, 198 {"output-device-1", kOFVariableTypeString}, 199 {"pci-probe-list", kOFVariableTypeNumber}, 200 {"pci-probe-mask", kOFVariableTypeNumber}, 201 {"real-base", kOFVariableTypeNumber}, 202 {"real-mode?", kOFVariableTypeBoolean}, 203 {"real-size", kOFVariableTypeNumber}, 204 {"screen-#columns", kOFVariableTypeNumber}, 205 {"screen-#rows", kOFVariableTypeNumber}, 206 {"security-mode", kOFVariableTypeString}, 207 {"selftest-#megs", kOFVariableTypeNumber}, 208 {"use-generic?", kOFVariableTypeBoolean}, 209 {"use-nvramrc?", kOFVariableTypeBoolean}, 210 {"virt-base", kOFVariableTypeNumber}, 211 {"virt-size", kOFVariableTypeNumber}, 212 213 #if !defined(__x86_64__) 214 {"acc-cm-override-charger-count", kOFVariableTypeNumber}, 215 {"acc-cm-override-count", kOFVariableTypeNumber}, 216 {"acc-mb-ld-lifetime", kOFVariableTypeNumber}, 217 {"com.apple.System.boot-nonce", kOFVariableTypeString}, 218 {"darkboot", kOFVariableTypeBoolean}, 219 {"enter-tdm-mode", kOFVariableTypeBoolean}, 220 #endif /* !defined(__x86_64__) */ 221 {nullptr, kOFVariableTypeData} // Default type to return 222 }; 223 224 union VariablePermission { 225 struct { 226 uint64_t UserWrite :1; 227 uint64_t RootRequired :1; 228 uint64_t KernelOnly :1; 229 uint64_t ResetNVRAMOnlyDelete :1; 230 uint64_t NeverAllowedToDelete :1; 231 uint64_t SystemReadHidden :1; 232 uint64_t FullAccess :1; 233 uint64_t Reserved:57; 234 } Bits; 235 uint64_t Uint64; 236 }; 237 238 typedef struct { 239 const char *name; 240 VariablePermission p; 241 } VariablePermissionEntry; 242 243 static const 244 VariablePermissionEntry gVariablePermissions[] = { 245 {"aapl,pci", .p.Bits.RootRequired = 1}, 246 {"battery-health", .p.Bits.RootRequired = 1, 247 .p.Bits.NeverAllowedToDelete = 1}, 248 {"boot-image", .p.Bits.UserWrite = 1}, 249 {"com.apple.System.fp-state", .p.Bits.KernelOnly = 1}, 250 {"fm-account-masked", .p.Bits.RootRequired = 1, 251 .p.Bits.NeverAllowedToDelete = 1}, 252 {"fm-activation-locked", .p.Bits.RootRequired = 1, 253 .p.Bits.NeverAllowedToDelete = 1}, 254 {"fm-spkeys", .p.Bits.RootRequired = 1, 255 .p.Bits.NeverAllowedToDelete = 1}, 256 {"fm-spstatus", .p.Bits.RootRequired = 1, 257 .p.Bits.NeverAllowedToDelete = 1}, 258 {"policy-nonce-digests", .p.Bits.ResetNVRAMOnlyDelete = 1}, // Deleting this via user triggered obliterate leave J273a unable to boot 259 {"recoveryos-passcode-blob", .p.Bits.SystemReadHidden = 1}, 260 {"security-password", .p.Bits.RootRequired = 1}, 261 {"system-passcode-lock-blob", .p.Bits.SystemReadHidden = 1}, 262 263 #if !defined(__x86_64__) 264 {"acc-cm-override-charger-count", .p.Bits.KernelOnly = 1}, 265 {"acc-cm-override-count", .p.Bits.KernelOnly = 1}, 266 {"acc-mb-ld-lifetime", .p.Bits.KernelOnly = 1}, 267 {"backlight-level", .p.Bits.UserWrite = 1}, 268 {"backlight-nits", .p.Bits.UserWrite = 1}, 269 {"com.apple.System.boot-nonce", .p.Bits.KernelOnly = 1}, 270 {"com.apple.System.sep.art", .p.Bits.KernelOnly = 1}, 271 {"darkboot", .p.Bits.UserWrite = 1}, 272 {"nonce-seeds", .p.Bits.KernelOnly = 1}, 273 #endif /* !defined(__x86_64__) */ 274 // Variables used for testing permissions 275 {"testSysReadHidden", .p.Bits.SystemReadHidden = 1}, 276 {"testKernelOnly", .p.Bits.KernelOnly = 1}, 277 {"testResetOnlyDel", .p.Bits.ResetNVRAMOnlyDelete = 1}, 278 {"testNeverDel", .p.Bits.NeverAllowedToDelete = 1}, 279 {"testUserWrite", .p.Bits.UserWrite = 1}, 280 {"testRootReq", .p.Bits.RootRequired = 1}, 281 {nullptr, {.Bits.FullAccess = 1}} // Default access 282 }; 283 284 typedef struct { 285 const uint8_t checkOp; 286 const uuid_t *varGuid; 287 const char *varName; 288 const char *varEntitlement; 289 } VariableEntitlementEntry; 290 291 // variable-guid pair entries that require entitlement check to do specified nvram operations 292 static const 293 VariableEntitlementEntry gVariableEntitlements[] = { 294 {ENTITLED_MODIFY_ONLY, &gAppleNVRAMGuid, "ownership-warning", "com.apple.private.iokit.ddl-write"}, 295 // Variable used for testing entitlement 296 {ENTITLED_MODIFY_ONLY, &gAppleNVRAMGuid, "testEntitlement", "com.apple.private.iokit.testentitlement"}, 297 {0, &UUID_NULL, nullptr, nullptr} 298 }; 299 300 static NVRAMPartitionType 301 getPartitionTypeForGUID(const uuid_t guid) 302 { 303 if (uuid_compare(guid, gAppleSystemVariableGuid) == 0) { 304 return kIONVRAMPartitionSystem; 305 } else { 306 return kIONVRAMPartitionCommon; 307 } 308 } 309 310 static IONVRAMVariableType 311 getVariableType(const char *propName) 312 { 313 const VariableTypeEntry *entry; 314 315 entry = gVariableTypes; 316 while (entry->name != nullptr) { 317 if (strcmp(entry->name, propName) == 0) { 318 break; 319 } 320 entry++; 321 } 322 323 return entry->type; 324 } 325 326 static IONVRAMVariableType 327 getVariableType(const OSSymbol *propSymbol) 328 { 329 return getVariableType(propSymbol->getCStringNoCopy()); 330 } 331 332 static VariablePermission 333 getVariablePermission(const char *propName) 334 { 335 const VariablePermissionEntry *entry; 336 337 entry = gVariablePermissions; 338 while (entry->name != nullptr) { 339 if (strcmp(entry->name, propName) == 0) { 340 break; 341 } 342 entry++; 343 } 344 345 return entry->p; 346 } 347 348 static bool 349 variableInAllowList(const char *varName) 350 { 351 unsigned int i = 0; 352 353 while (gNVRAMSystemList[i] != nullptr) { 354 if (strcmp(varName, gNVRAMSystemList[i]) == 0) { 355 return true; 356 } 357 i++; 358 } 359 360 return false; 361 } 362 363 static bool 364 verifyWriteSizeLimit(const uuid_t varGuid, const char *variableName, size_t propDataSize) 365 { 366 if (variableInAllowList(variableName)) { 367 if (strnstr(variableName, "breadcrumbs", strlen(variableName)) != NULL) { 368 return propDataSize <= 1024; 369 } else { 370 return propDataSize <= 768; 371 } 372 } 373 374 return true; 375 } 376 377 #if defined(DEBUG) || defined(DEVELOPMENT) 378 static const char * 379 getNVRAMOpString(IONVRAMOperation op) 380 { 381 switch (op) { 382 case kIONVRAMOperationRead: 383 return "Read"; 384 case kIONVRAMOperationWrite: 385 return "Write"; 386 case kIONVRAMOperationDelete: 387 return "Delete"; 388 case kIONVRAMOperationObliterate: 389 return "Obliterate"; 390 case kIONVRAMOperationReset: 391 return "Reset"; 392 case kIONVRAMOperationInit: 393 return "Init"; 394 default: 395 return "Unknown"; 396 } 397 } 398 #endif 399 400 /* 401 * Parse a variable name of the form "GUID:name". 402 * If the name cannot be parsed, substitute the Apple global variable GUID. 403 * Returns TRUE if a GUID was found in the name, FALSE otherwise. 404 * The guidResult and nameResult arguments may be nullptr if you just want 405 * to check the format of the string. 406 */ 407 static bool 408 parseVariableName(const char *key, uuid_t *guidResult, const char **nameResult) 409 { 410 uuid_string_t temp = {0}; 411 size_t keyLen = strlen(key); 412 bool ok = false; 413 const char *name = key; 414 uuid_t guid; 415 416 if (keyLen > sizeof(temp)) { 417 // check for at least UUID + ":" + more 418 memcpy(temp, key, sizeof(temp) - 1); 419 420 if ((uuid_parse(temp, guid) == 0) && 421 (key[sizeof(temp) - 1] == ':')) { 422 name = key + sizeof(temp); 423 ok = true; 424 } 425 } 426 427 if (guidResult) { 428 ok ? uuid_copy(*guidResult, guid) : uuid_copy(*guidResult, gAppleNVRAMGuid); 429 } 430 if (nameResult) { 431 *nameResult = name; 432 } 433 434 return ok; 435 } 436 437 static bool 438 parseVariableName(const OSSymbol *key, uuid_t *guidResult, const char **nameResult) 439 { 440 return parseVariableName(key->getCStringNoCopy(), guidResult, nameResult); 441 } 442 443 /** 444 * @brief Translates(if needed) varGuid and stores it in destGuid 445 * 446 * @param varGuid guid to translate 447 * @param variableName variable name attached to the guid 448 * @param destGuid translated guid is saved here 449 * @param systemActive boolean to indicate if it has system partition size > 0 450 */ 451 static void 452 translateGUID(const uuid_t varGuid, const char *variableName, uuid_t destGuid, bool systemActive) 453 { 454 if (varGuid == nullptr || variableName == nullptr || destGuid == nullptr) { 455 DEBUG_ERROR("nullptr passed as an argument\n"); 456 return; 457 } 458 459 bool systemGuid = uuid_compare(varGuid, gAppleSystemVariableGuid) == 0; 460 461 if (systemActive) { 462 if (variableInAllowList(variableName)) { 463 if (!systemGuid) { 464 DEBUG_ERROR("System GUID not supplied for %s\n", variableName); 465 } 466 DEBUG_INFO("Using system GUID due to allow list\n"); 467 uuid_copy(destGuid, gAppleSystemVariableGuid); 468 } else if (systemGuid) { 469 DEBUG_INFO("System GUID used\n"); 470 uuid_copy(destGuid, gAppleSystemVariableGuid); 471 } else { 472 DEBUG_INFO("Use given guid\n"); 473 uuid_copy(destGuid, varGuid); 474 } 475 } else if (systemGuid) { 476 DEBUG_INFO("Overriding to Apple guid\n"); 477 uuid_copy(destGuid, gAppleNVRAMGuid); 478 } else { 479 DEBUG_INFO("Use given guid\n"); 480 uuid_copy(destGuid, varGuid); 481 } 482 } 483 484 /** 485 * @brief Checks if the variable-guid(translated) pair is present in gVariableEntitlements and if so, 486 * does it have the required entitlement for the NVRAM operation passed in 487 * 488 * @param varGuid guid for the variable to be checked, this gets translated by translateGUID 489 * @param varName variable name 490 * @param op NVRAM operation 491 * @param systemActive used to pass into translateGUID to get the correct guid to check against 492 * @param veChecked if variable entitlement is checked, this is set to true 493 * @return true if variable wasn't present in gVariableEntitlements, 494 * entitlement check wasn't required for operation passed in, 495 * or if entitlement check returned true 496 * @return false if varName/varGuid/veChecked was NULL or if entitlement check returned false 497 */ 498 static bool 499 verifyVarEntitlement(const uuid_t varGuid, const char *varName, IONVRAMOperation op, bool systemActive, bool *veChecked) 500 { 501 if (varGuid == nullptr || varName == nullptr || veChecked == nullptr) { 502 DEBUG_ERROR("nullptr passed as an argument\n"); 503 return false; 504 } 505 506 uuid_t translatedGuid; 507 const VariableEntitlementEntry *entry; 508 *veChecked = false; 509 510 entry = gVariableEntitlements; 511 while ((entry != nullptr) && (entry->varName != nullptr)) { 512 translateGUID(varGuid, varName, translatedGuid, systemActive); 513 if ((strcmp(entry->varName, varName) == 0) && (uuid_compare(translatedGuid, *(entry->varGuid)) == 0)) { 514 // check if task entitlement check is required for this operation 515 if (entry->checkOp & (1 << op)) { 516 *veChecked = true; 517 return IOCurrentTaskHasEntitlement(entry->varEntitlement); 518 } 519 break; 520 } 521 entry++; 522 } 523 524 return true; 525 } 526 527 static bool 528 verifyPermission(IONVRAMOperation op, const uuid_t varGuid, const char *varName, const bool systemActive) 529 { 530 VariablePermission perm; 531 bool kernel, varEntitled, writeEntitled = false, readEntitled = false, allowList, systemGuid = false, systemEntitled = false, systemInternalEntitled = false, systemAllow, systemReadHiddenAllow = false; 532 bool admin = false; 533 bool ok = false; 534 535 if (verifyVarEntitlement(varGuid, varName, op, systemActive, &varEntitled) == false) { 536 goto exit; 537 } 538 539 perm = getVariablePermission(varName); 540 541 kernel = current_task() == kernel_task; 542 543 if (perm.Bits.KernelOnly) { 544 DEBUG_INFO("KernelOnly access for %s, kernel=%d\n", varName, kernel); 545 ok = kernel; 546 goto exit; 547 } 548 549 allowList = variableInAllowList(varName); 550 systemGuid = uuid_compare(varGuid, gAppleSystemVariableGuid) == 0; 551 admin = IOUserClient::clientHasPrivilege(current_task(), kIONVRAMPrivilege) == kIOReturnSuccess; 552 writeEntitled = IOCurrentTaskHasEntitlement(kIONVRAMWriteAccessKey); 553 readEntitled = IOCurrentTaskHasEntitlement(kIONVRAMReadAccessKey); 554 systemEntitled = IOCurrentTaskHasEntitlement(kIONVRAMSystemAllowKey); 555 systemInternalEntitled = IOCurrentTaskHasEntitlement(kIONVRAMSystemInternalAllowKey); 556 systemReadHiddenAllow = IOCurrentTaskHasEntitlement(kIONVRAMSystemHiddenAllowKey); 557 558 systemAllow = systemEntitled || (systemInternalEntitled && gInternalBuild) || kernel; 559 560 switch (op) { 561 case kIONVRAMOperationRead: 562 if (systemGuid && perm.Bits.SystemReadHidden) { 563 ok = systemReadHiddenAllow; 564 } else if (kernel || admin || readEntitled || perm.Bits.FullAccess) { 565 ok = true; 566 } 567 break; 568 569 case kIONVRAMOperationWrite: 570 if (kernel || perm.Bits.UserWrite || admin || writeEntitled || varEntitled) { 571 if (systemGuid) { 572 if (allowList) { 573 if (!systemAllow) { 574 DEBUG_ERROR("Allowed write to system region when NOT entitled for %s\n", varName); 575 } 576 } else if (!systemAllow) { 577 DEBUG_ERROR("Not entitled for system region writes for %s\n", varName); 578 break; 579 } 580 } 581 ok = true; 582 } 583 break; 584 585 case kIONVRAMOperationDelete: 586 case kIONVRAMOperationObliterate: 587 case kIONVRAMOperationReset: 588 if (perm.Bits.NeverAllowedToDelete) { 589 DEBUG_INFO("Never allowed to delete %s\n", varName); 590 break; 591 } else if ((op == kIONVRAMOperationObliterate) && perm.Bits.ResetNVRAMOnlyDelete) { 592 DEBUG_INFO("Not allowed to obliterate %s\n", varName); 593 break; 594 } else if ((op == kIONVRAMOperationDelete) && perm.Bits.ResetNVRAMOnlyDelete) { 595 DEBUG_INFO("Only allowed to delete %s via NVRAM reset\n", varName); 596 break; 597 } 598 599 if (kernel || perm.Bits.UserWrite || admin || writeEntitled || varEntitled) { 600 if (systemGuid) { 601 if (allowList) { 602 if (!systemAllow) { 603 DEBUG_ERROR("Allowed delete to system region when NOT entitled for %s\n", varName); 604 } 605 } else if (!systemAllow) { 606 DEBUG_ERROR("Not entitled for system region deletes for %s\n", varName); 607 break; 608 } 609 } 610 ok = true; 611 } 612 break; 613 614 case kIONVRAMOperationInit: 615 break; 616 } 617 618 exit: 619 DEBUG_INFO("Permission for %s of %s %s: kern=%d, adm=%d, wE=%d, rE=%d, sG=%d, sEd=%d, sIEd=%d, sRHA=%d, UW=%d, vE=%d\n", getNVRAMOpString(op), varName, ok ? "granted" : "denied", 620 kernel, admin, writeEntitled, readEntitled, systemGuid, systemEntitled, systemInternalEntitled, systemReadHiddenAllow, perm.Bits.UserWrite, varEntitled); 621 622 return ok; 623 } 624 625 static bool 626 verifyPermission(IONVRAMOperation op, const OSSymbol *canonicalKey, const bool systemActive) 627 { 628 const char *varName; 629 uuid_t varGuid; 630 631 parseVariableName(canonicalKey->getCStringNoCopy(), &varGuid, &varName); 632 633 return verifyPermission(op, varGuid, varName, systemActive); 634 } 635 636 static bool 637 skipKey(const OSSymbol *aKey) 638 { 639 return aKey->isEqualTo(kIORegistryEntryAllowableSetPropertiesKey) || 640 aKey->isEqualTo(kIORegistryEntryDefaultLockingSetPropertiesKey) || 641 aKey->isEqualTo(kIOClassNameOverrideKey) || 642 aKey->isEqualTo(kIOBSDNameKey) || 643 aKey->isEqualTo(kIOBSDNamesKey) || 644 aKey->isEqualTo(kIOBSDMajorKey) || 645 aKey->isEqualTo(kIOBSDMinorKey) || 646 aKey->isEqualTo(kIOBSDUnitKey) || 647 aKey->isEqualTo(kIOUserServicePropertiesKey) || 648 aKey->isEqualTo(kIOMatchCategoryKey); 649 } 650 651 static OSSharedPtr<const OSSymbol> 652 keyWithGuidAndCString(const uuid_t guid, const char * cstring) 653 { 654 size_t length; 655 OSSharedPtr<const OSSymbol> symbolObj; 656 char *canonicalString; 657 658 length = sizeof(uuid_string_t) - 1 + sizeof(':') + strlen(cstring) + 1; 659 660 canonicalString = (char *) IOMallocData(length); 661 if (canonicalString == nullptr) { 662 return NULL; 663 } 664 665 uuid_unparse(guid, *((uuid_string_t*)canonicalString)); 666 canonicalString[sizeof(uuid_string_t) - 1] = ':'; 667 668 strlcpy(&canonicalString[sizeof(uuid_string_t)], cstring, length - sizeof(uuid_string_t)); 669 670 symbolObj = OSSymbol::withCString(canonicalString); 671 IOFreeData(canonicalString, length); 672 673 return symbolObj; 674 } 675 676 static void 677 dumpDict(const OSDictionary *dict) 678 { 679 const OSSymbol *key; 680 OSSharedPtr<OSCollectionIterator> iter; 681 unsigned int count = 0; 682 683 iter = OSCollectionIterator::withCollection(dict); 684 if (iter == nullptr) { 685 DEBUG_ERROR("failed to create iterator\n"); 686 goto exit; 687 } 688 689 DEBUG_INFO("Dumping dict...\n"); 690 while ((key = OSDynamicCast(OSSymbol, iter->getNextObject()))) { 691 count++; 692 DEBUG_INFO("%u: %s\n", count, key->getCStringNoCopy()); 693 } 694 695 exit: 696 return; 697 } 698 699 // ************************** IODTNVRAMPlatformNotifier **************************** 700 // private IOService based class for passing notifications to IODTNVRAM 701 702 class IODTNVRAMPlatformNotifier : public IOService 703 { 704 OSDeclareDefaultStructors(IODTNVRAMPlatformNotifier) 705 private: 706 IODTNVRAM *_provider; 707 708 public: 709 bool start(IOService * provider) APPLE_KEXT_OVERRIDE; 710 711 virtual IOReturn callPlatformFunction( const OSSymbol * functionName, 712 bool waitForFunction, 713 void *param1, void *param2, 714 void *param3, void *param4 ) APPLE_KEXT_OVERRIDE; 715 }; 716 717 OSDefineMetaClassAndStructors(IODTNVRAMPlatformNotifier, IOService) 718 719 bool 720 IODTNVRAMPlatformNotifier::start(IOService * provider) 721 { 722 OSSharedPtr<OSSerializer> serializer; 723 OSSharedPtr<OSNumber> value = OSNumber::withNumber(1000, 32); 724 725 _provider = OSDynamicCast(IODTNVRAM, provider); 726 require(_provider != nullptr, error); 727 728 setProperty(gIOPlatformWakeActionKey, value.get()); 729 730 require(super::start(provider), error); 731 732 registerService(); 733 734 return true; 735 736 error: 737 stop(provider); 738 739 return false; 740 } 741 742 #include <IOKit/IOHibernatePrivate.h> 743 #include <IOKit/pwr_mgt/RootDomain.h> 744 static const OSSharedPtr<const OSSymbol> gIOHibernateStateKey = OSSymbol::withCString(kIOHibernateStateKey); 745 746 static uint32_t 747 hibernateState(void) 748 { 749 OSSharedPtr<OSData> data = OSDynamicPtrCast<OSData>(IOService::getPMRootDomain()->copyProperty(gIOHibernateStateKey.get()->getCStringNoCopy())); 750 uint32_t hibernateState = 0; 751 if ((data != NULL) && (data->getLength() == sizeof(hibernateState))) { 752 memcpy(&hibernateState, data->getBytesNoCopy(), sizeof(hibernateState)); 753 } 754 return hibernateState; 755 } 756 757 IOReturn 758 IODTNVRAMPlatformNotifier::callPlatformFunction( const OSSymbol * functionName, 759 bool waitForFunction, 760 void *param1, void *param2, 761 void *param3, void *param4 ) 762 { 763 if ((functionName == gIOPlatformWakeActionKey) && 764 (hibernateState() == kIOHibernateStateWakingFromHibernate)) { 765 DEBUG_INFO("waking from hibernate\n"); 766 _provider->reload(); 767 return kIOReturnSuccess; 768 } 769 770 return super::callPlatformFunction(functionName, waitForFunction, param1, param2, param3, param4); 771 } 772 773 774 // ************************** IODTNVRAMDiags **************************** 775 // private IOService based class for passing notifications to IODTNVRAM 776 #define kIODTNVRAMDiagsStatsKey "Stats" 777 #define kIODTNVRAMDiagsInitKey "Init" 778 #define kIODTNVRAMDiagsReadKey "Read" 779 #define kIODTNVRAMDiagsWriteKey "Write" 780 #define kIODTNVRAMDiagsDeleteKey "Delete" 781 #define kIODTNVRAMDiagsNameKey "Name" 782 #define kIODTNVRAMDiagsSizeKey "Size" 783 #define kIODTNVRAMDiagsPresentKey "Present" 784 785 // private IOService based class for publishing diagnostic info for IODTNVRAM 786 class IODTNVRAMDiags : public IOService 787 { 788 OSDeclareDefaultStructors(IODTNVRAMDiags) 789 private: 790 IODTNVRAM *_provider; 791 IORWLock *_variableLock; 792 OSSharedPtr<OSDictionary> _stats; 793 794 bool serializeStats(void *, OSSerialize * serializer); 795 796 public: 797 bool start(IOService * provider) APPLE_KEXT_OVERRIDE; 798 void logVariable(NVRAMPartitionType region, IONVRAMOperation op, const char *name, void *data); 799 }; 800 801 OSDefineMetaClassAndStructors(IODTNVRAMDiags, IOService) 802 803 bool 804 IODTNVRAMDiags::start(IOService * provider) 805 { 806 OSSharedPtr<OSSerializer> serializer; 807 808 _provider = OSDynamicCast(IODTNVRAM, provider); 809 require(_provider != nullptr, error); 810 811 require(super::start(provider), error); 812 813 _variableLock = IORWLockAlloc(); 814 require(_variableLock != nullptr, error); 815 816 _stats = OSDictionary::withCapacity(1); 817 require(_stats != nullptr, error); 818 819 serializer = OSSerializer::forTarget(this, OSMemberFunctionCast(OSSerializerCallback, this, &IODTNVRAMDiags::serializeStats)); 820 require(serializer != nullptr, error); 821 822 setProperty(kIODTNVRAMDiagsStatsKey, serializer.get()); 823 824 registerService(); 825 826 return true; 827 828 error: 829 stop(provider); 830 831 return false; 832 } 833 834 void 835 IODTNVRAMDiags::logVariable(NVRAMPartitionType region, IONVRAMOperation op, const char *name, void *data) 836 { 837 // "Stats" : OSDictionary 838 // - "XX:varName" : OSDictionary, XX is the region value prefix to distinguish which dictionary the variable is in 839 // - "Init" : OSBoolean True/present if variable present at initialization 840 // - "Read" : OSNumber count 841 // - "Write" : OSNumber count 842 // - "Delete" : OSNumber count 843 // - "Size" : OSNumber size, latest size from either init or write 844 // - "Present" : OSBoolean True/False if variable is present or not 845 char *entryKey; 846 size_t entryKeySize; 847 OSSharedPtr<OSDictionary> existingEntry; 848 OSSharedPtr<OSNumber> currentCount; 849 OSSharedPtr<OSNumber> varSize; 850 const char *opCountKey = nullptr; 851 852 entryKeySize = strlen("XX:") + strlen(name) + 1; 853 entryKey = IONewData(char, entryKeySize); 854 require(entryKey, exit); 855 856 snprintf(entryKey, entryKeySize, "%02X:%s", region, name); 857 858 NVRAMWRITELOCK(); 859 existingEntry.reset(OSDynamicCast(OSDictionary, _stats->getObject(entryKey)), OSRetain); 860 861 if (existingEntry == nullptr) { 862 existingEntry = OSDictionary::withCapacity(4); 863 } 864 865 switch (op) { 866 case kIONVRAMOperationRead: 867 opCountKey = kIODTNVRAMDiagsReadKey; 868 if (existingEntry->getObject(kIODTNVRAMDiagsPresentKey) == nullptr) { 869 existingEntry->setObject(kIODTNVRAMDiagsPresentKey, kOSBooleanFalse); 870 } 871 break; 872 case kIONVRAMOperationWrite: 873 opCountKey = kIODTNVRAMDiagsWriteKey; 874 varSize = OSNumber::withNumber((size_t)data, 64); 875 existingEntry->setObject(kIODTNVRAMDiagsSizeKey, varSize); 876 existingEntry->setObject(kIODTNVRAMDiagsPresentKey, kOSBooleanTrue); 877 break; 878 case kIONVRAMOperationDelete: 879 case kIONVRAMOperationObliterate: 880 case kIONVRAMOperationReset: 881 opCountKey = kIODTNVRAMDiagsDeleteKey; 882 existingEntry->setObject(kIODTNVRAMDiagsPresentKey, kOSBooleanFalse); 883 break; 884 case kIONVRAMOperationInit: 885 varSize = OSNumber::withNumber((size_t)data, 64); 886 existingEntry->setObject(kIODTNVRAMDiagsInitKey, varSize); 887 existingEntry->setObject(kIODTNVRAMDiagsSizeKey, varSize); 888 existingEntry->setObject(kIODTNVRAMDiagsPresentKey, kOSBooleanTrue); 889 break; 890 default: 891 goto unlock; 892 } 893 894 if (opCountKey) { 895 currentCount.reset(OSDynamicCast(OSNumber, existingEntry->getObject(opCountKey)), OSRetain); 896 897 if (currentCount == nullptr) { 898 currentCount = OSNumber::withNumber(1, 64); 899 } else { 900 currentCount->addValue(1); 901 } 902 903 existingEntry->setObject(opCountKey, currentCount); 904 } 905 906 _stats->setObject(entryKey, existingEntry); 907 908 unlock: 909 NVRAMUNLOCK(); 910 911 exit: 912 IODeleteData(entryKey, char, entryKeySize); 913 914 return; 915 } 916 917 bool 918 IODTNVRAMDiags::serializeStats(void *, OSSerialize * serializer) 919 { 920 bool ok; 921 922 NVRAMREADLOCK(); 923 ok = _stats->serialize(serializer); 924 NVRAMUNLOCK(); 925 926 return ok; 927 } 928 929 // ************************** IODTNVRAMVariables **************************** 930 931 // private IOService based class for publishing distinct dictionary properties on 932 // for easy ioreg access since the serializeProperties call is overloaded and is used 933 // as variable access 934 class IODTNVRAMVariables : public IOService 935 { 936 OSDeclareDefaultStructors(IODTNVRAMVariables) 937 private: 938 IODTNVRAM *_provider; 939 uuid_t _guid; 940 bool _systemActive; 941 942 public: 943 bool init(const uuid_t guid, const bool systemActive); 944 virtual bool start(IOService * provider) APPLE_KEXT_OVERRIDE; 945 946 virtual bool serializeProperties(OSSerialize *s) const APPLE_KEXT_OVERRIDE; 947 virtual OSPtr<OSObject> copyProperty(const OSSymbol *aKey) const APPLE_KEXT_OVERRIDE; 948 virtual OSObject *getProperty(const OSSymbol *aKey) const APPLE_KEXT_OVERRIDE; 949 virtual bool setProperty(const OSSymbol *aKey, OSObject *anObject) APPLE_KEXT_OVERRIDE; 950 virtual IOReturn setProperties(OSObject *properties) APPLE_KEXT_OVERRIDE; 951 virtual void removeProperty(const OSSymbol *aKey) APPLE_KEXT_OVERRIDE; 952 }; 953 954 OSDefineMetaClassAndStructors(IODTNVRAMVariables, IOService) 955 956 bool 957 IODTNVRAMVariables::init(const uuid_t guid, const bool systemActive) 958 { 959 require(super::init(), fail); 960 961 uuid_copy(_guid, guid); 962 _systemActive = systemActive; 963 964 return true; 965 966 fail: 967 return false; 968 } 969 970 bool 971 IODTNVRAMVariables::start(IOService * provider) 972 { 973 _provider = OSDynamicCast(IODTNVRAM, provider); 974 if (_provider == nullptr) { 975 goto error; 976 } 977 978 if (!super::start(provider)) { 979 goto error; 980 } 981 982 registerService(); 983 984 return true; 985 986 error: 987 stop(provider); 988 989 return false; 990 } 991 992 bool 993 IODTNVRAMVariables::serializeProperties(OSSerialize *s) const 994 { 995 const OSSymbol *key; 996 OSSharedPtr<OSDictionary> dict; 997 OSSharedPtr<OSCollectionIterator> iter; 998 OSSharedPtr<OSDictionary> localVariables = _provider->_varDict; 999 bool ok = false; 1000 1001 dict = OSDictionary::withCapacity(localVariables->getCount()); 1002 if (dict == nullptr) { 1003 DEBUG_ERROR("No dictionary\n"); 1004 goto exit; 1005 } 1006 1007 iter = OSCollectionIterator::withCollection(localVariables.get()); 1008 if (iter == nullptr) { 1009 DEBUG_ERROR("failed to create iterator\n"); 1010 goto exit; 1011 } 1012 1013 while ((key = OSDynamicCast(OSSymbol, iter->getNextObject()))) { 1014 if (verifyPermission(kIONVRAMOperationRead, key, _systemActive)) { 1015 uuid_t guid; 1016 const char *name; 1017 1018 parseVariableName(key, &guid, &name); 1019 1020 if (uuid_compare(_guid, guid) == 0) { 1021 OSSharedPtr<const OSSymbol> sym = OSSymbol::withCString(name); 1022 dict->setObject(sym.get(), localVariables->getObject(key)); 1023 } 1024 } 1025 } 1026 1027 ok = dict->serialize(s); 1028 1029 exit: 1030 DEBUG_INFO("ok=%d\n", ok); 1031 return ok; 1032 } 1033 1034 OSPtr<OSObject> 1035 IODTNVRAMVariables::copyProperty(const OSSymbol *aKey) const 1036 { 1037 if (_provider && !skipKey(aKey)) { 1038 DEBUG_INFO("aKey=%s\n", aKey->getCStringNoCopy()); 1039 1040 return _provider->copyPropertyWithGUIDAndName(_guid, aKey->getCStringNoCopy()); 1041 } else { 1042 return nullptr; 1043 } 1044 } 1045 1046 OSObject * 1047 IODTNVRAMVariables::getProperty(const OSSymbol *aKey) const 1048 { 1049 OSSharedPtr<OSObject> theObject = copyProperty(aKey); 1050 1051 return theObject.get(); 1052 } 1053 1054 bool 1055 IODTNVRAMVariables::setProperty(const OSSymbol *aKey, OSObject *anObject) 1056 { 1057 if (_provider) { 1058 return _provider->setPropertyWithGUIDAndName(_guid, aKey->getCStringNoCopy(), anObject) == kIOReturnSuccess; 1059 } else { 1060 return false; 1061 } 1062 } 1063 1064 IOReturn 1065 IODTNVRAMVariables::setProperties(OSObject *properties) 1066 { 1067 IOReturn ret = kIOReturnSuccess; 1068 OSObject *object; 1069 const OSSymbol *key; 1070 OSDictionary *dict; 1071 OSSharedPtr<OSCollectionIterator> iter; 1072 1073 dict = OSDynamicCast(OSDictionary, properties); 1074 if (dict == nullptr) { 1075 DEBUG_ERROR("Not a dictionary\n"); 1076 return kIOReturnBadArgument; 1077 } 1078 1079 iter = OSCollectionIterator::withCollection(dict); 1080 if (iter == nullptr) { 1081 DEBUG_ERROR("Couldn't create iterator\n"); 1082 return kIOReturnBadArgument; 1083 } 1084 1085 while (ret == kIOReturnSuccess) { 1086 key = OSDynamicCast(OSSymbol, iter->getNextObject()); 1087 if (key == nullptr) { 1088 break; 1089 } 1090 1091 object = dict->getObject(key); 1092 if (object == nullptr) { 1093 continue; 1094 } 1095 1096 ret = _provider->setPropertyWithGUIDAndName(_guid, key->getCStringNoCopy(), object); 1097 } 1098 1099 DEBUG_INFO("ret=%#08x\n", ret); 1100 1101 return ret; 1102 } 1103 1104 void 1105 IODTNVRAMVariables::removeProperty(const OSSymbol *aKey) 1106 { 1107 _provider->removePropertyWithGUIDAndName(_guid, aKey->getCStringNoCopy()); 1108 } 1109 1110 // ************************** Format Handlers *************************** 1111 class IODTNVRAMFormatHandler 1112 { 1113 protected: 1114 uint32_t _bankSize; 1115 uint32_t _bankCount; 1116 uint32_t _currentBank; 1117 1118 public: 1119 virtual 1120 ~IODTNVRAMFormatHandler(); 1121 virtual bool getNVRAMProperties(void); 1122 virtual IOReturn unserializeVariables(void) = 0; 1123 virtual IOReturn setVariable(const uuid_t varGuid, const char *variableName, OSObject *object) = 0; 1124 virtual bool setController(IONVRAMController *_nvramController) = 0; 1125 virtual bool sync(void) = 0; 1126 virtual IOReturn flush(const uuid_t guid, IONVRAMOperation op) = 0; 1127 virtual void reload(void) = 0; 1128 virtual uint32_t getGeneration(void) const = 0; 1129 virtual uint32_t getVersion(void) const = 0; 1130 virtual uint32_t getSystemUsed(void) const = 0; 1131 virtual uint32_t getCommonUsed(void) const = 0; 1132 virtual bool getSystemPartitionActive(void) const = 0; 1133 }; 1134 1135 IODTNVRAMFormatHandler::~IODTNVRAMFormatHandler() 1136 { 1137 } 1138 1139 bool 1140 IODTNVRAMFormatHandler::getNVRAMProperties() 1141 { 1142 bool ok = false; 1143 OSSharedPtr<IORegistryEntry> entry; 1144 OSSharedPtr<OSObject> prop; 1145 OSData * data; 1146 1147 entry = IORegistryEntry::fromPath("/chosen", gIODTPlane); 1148 require_action(entry, exit, DEBUG_ERROR("Unable to find chosen node\n")); 1149 1150 prop = entry->copyProperty(kNVRAMBankSizeKey); 1151 require_action(prop, exit, DEBUG_ERROR("Unable to find %s property\n", kNVRAMBankSizeKey)); 1152 1153 data = OSDynamicCast(OSData, prop.get()); 1154 require(data, exit); 1155 1156 _bankSize = *((uint32_t *)data->getBytesNoCopy()); 1157 1158 prop = entry->copyProperty(kNVRAMBankCountKey); 1159 require_action(prop, exit, DEBUG_ERROR("Unable to find %s property\n", kNVRAMBankCountKey)); 1160 1161 data = OSDynamicCast(OSData, prop.get()); 1162 require(data, exit); 1163 1164 _bankCount = *((uint32_t *)data->getBytesNoCopy()); 1165 1166 prop = entry->copyProperty(kNVRAMCurrentBankKey); 1167 require_action(prop, exit, DEBUG_ERROR("Unable to find %s property\n", kNVRAMCurrentBankKey)); 1168 1169 data = OSDynamicCast(OSData, prop.get()); 1170 require(data, exit); 1171 1172 _currentBank = *((uint32_t *)data->getBytesNoCopy()); 1173 1174 ok = true; 1175 1176 DEBUG_ALWAYS("_bankSize=%#X, _bankCount=%#X, _currentBank=%#X\n", _bankSize, _bankCount, _currentBank); 1177 1178 exit: 1179 return ok; 1180 } 1181 1182 #include "IONVRAMCHRPHandler.cpp" 1183 1184 #include "IONVRAMV3Handler.cpp" 1185 1186 // **************************** IODTNVRAM ********************************* 1187 1188 bool 1189 IODTNVRAM::init(IORegistryEntry *old, const IORegistryPlane *plane) 1190 { 1191 OSSharedPtr<OSDictionary> dict; 1192 1193 DEBUG_INFO("...\n"); 1194 1195 require(super::init(old, plane), fail); 1196 1197 #if XNU_TARGET_OS_OSX 1198 #if CONFIG_CSR 1199 gInternalBuild = (csr_check(CSR_ALLOW_APPLE_INTERNAL) == 0); 1200 DEBUG_INFO("gInternalBuild = %d\n", gInternalBuild); 1201 #endif // CONFIG_CSR 1202 #endif // XNU_TARGET_OS_OSX 1203 1204 _variableLock = IORWLockAlloc(); 1205 require(_variableLock != nullptr, fail); 1206 1207 _controllerLock = IOLockAlloc(); 1208 require(_controllerLock != nullptr, fail); 1209 1210 // Clear the IORegistryEntry property table 1211 dict = OSDictionary::withCapacity(1); 1212 require(dict != nullptr, fail); 1213 1214 setPropertyTable(dict.get()); 1215 dict.reset(); 1216 1217 return true; 1218 1219 fail: 1220 return false; 1221 } 1222 1223 bool 1224 IODTNVRAM::start(IOService *provider) 1225 { 1226 OSSharedPtr<OSNumber> version; 1227 1228 DEBUG_INFO("...\n"); 1229 1230 require(super::start(provider), fail); 1231 1232 // Check if our overridden init function was called 1233 // If not, skip any additional initialization being done here. 1234 // This is not an error we just need to successfully exit this function to allow 1235 // AppleEFIRuntime to proceed and take over operation 1236 require_action(_controllerLock != nullptr, no_common, DEBUG_INFO("x86 init\n")); 1237 1238 _diags = new IODTNVRAMDiags; 1239 if (!_diags || !_diags->init()) { 1240 DEBUG_ERROR("Unable to create/init the diags service\n"); 1241 OSSafeReleaseNULL(_diags); 1242 goto fail; 1243 } 1244 1245 if (!_diags->attach(this)) { 1246 DEBUG_ERROR("Unable to attach the diags service!\n"); 1247 OSSafeReleaseNULL(_diags); 1248 goto fail; 1249 } 1250 1251 if (!_diags->start(this)) { 1252 DEBUG_ERROR("Unable to start the diags service!\n"); 1253 _diags->detach(this); 1254 OSSafeReleaseNULL(_diags); 1255 goto fail; 1256 } 1257 1258 _notifier = new IODTNVRAMPlatformNotifier; 1259 if (!_notifier || !_notifier->init()) { 1260 DEBUG_ERROR("Unable to create/init the notifier service\n"); 1261 OSSafeReleaseNULL(_notifier); 1262 goto fail; 1263 } 1264 1265 if (!_notifier->attach(this)) { 1266 DEBUG_ERROR("Unable to attach the notifier service!\n"); 1267 OSSafeReleaseNULL(_notifier); 1268 goto fail; 1269 } 1270 1271 if (!_notifier->start(this)) { 1272 DEBUG_ERROR("Unable to start the notifier service!\n"); 1273 _notifier->detach(this); 1274 OSSafeReleaseNULL(_notifier); 1275 goto fail; 1276 } 1277 1278 // This will load the proxied variable data which will call back into 1279 // IODTNVRAM for the variable sets which will also update the system/common services 1280 initImageFormat(); 1281 1282 version = OSNumber::withNumber(_format->getVersion(), 32); 1283 _diags->setProperty(kCurrentNVRAMVersionKey, version.get()); 1284 1285 if (_format->getSystemUsed()) { 1286 _systemService = new IODTNVRAMVariables; 1287 1288 if (!_systemService || !_systemService->init(gAppleSystemVariableGuid, _format->getSystemPartitionActive())) { 1289 DEBUG_ERROR("Unable to start the system service!\n"); 1290 OSSafeReleaseNULL(_systemService); 1291 goto no_system; 1292 } 1293 1294 _systemService->setName("options-system"); 1295 1296 if (!_systemService->attach(this)) { 1297 DEBUG_ERROR("Unable to attach the system service!\n"); 1298 OSSafeReleaseNULL(_systemService); 1299 goto no_system; 1300 } 1301 1302 if (!_systemService->start(this)) { 1303 DEBUG_ERROR("Unable to start the system service!\n"); 1304 _systemService->detach(this); 1305 OSSafeReleaseNULL(_systemService); 1306 goto no_system; 1307 } 1308 } 1309 1310 no_system: 1311 _commonService = new IODTNVRAMVariables; 1312 1313 if (!_commonService || !_commonService->init(gAppleNVRAMGuid, _format->getSystemPartitionActive())) { 1314 DEBUG_ERROR("Unable to start the common service!\n"); 1315 OSSafeReleaseNULL(_commonService); 1316 goto no_common; 1317 } 1318 1319 _commonService->setName("options-common"); 1320 1321 if (!_commonService->attach(this)) { 1322 DEBUG_ERROR("Unable to attach the common service!\n"); 1323 OSSafeReleaseNULL(_commonService); 1324 goto no_common; 1325 } 1326 1327 if (!_commonService->start(this)) { 1328 DEBUG_ERROR("Unable to start the common service!\n"); 1329 _commonService->detach(this); 1330 OSSafeReleaseNULL(_commonService); 1331 goto no_common; 1332 } 1333 1334 no_common: 1335 return true; 1336 1337 fail: 1338 stop(provider); 1339 return false; 1340 } 1341 1342 void 1343 IODTNVRAM::initImageFormat(void) 1344 { 1345 OSSharedPtr<IORegistryEntry> entry; 1346 OSSharedPtr<OSObject> prop; 1347 const char *proxyDataKey = "nvram-proxy-data"; 1348 const char *bankSizeKey = "nvram-bank-size"; 1349 OSData *data = nullptr; 1350 uint32_t size = 0; 1351 const uint8_t *image = nullptr; 1352 1353 entry = IORegistryEntry::fromPath("/chosen", gIODTPlane); 1354 1355 require(entry != nullptr, skip); 1356 1357 prop = entry->copyProperty(bankSizeKey); 1358 require(prop != nullptr, skip); 1359 1360 data = OSDynamicCast(OSData, prop.get()); 1361 require(data != nullptr, skip); 1362 1363 size = *((uint32_t*)data->getBytesNoCopy()); 1364 DEBUG_ALWAYS("NVRAM size is %u bytes\n", size); 1365 1366 prop = entry->copyProperty(proxyDataKey); 1367 require(prop != nullptr, skip); 1368 1369 data = OSDynamicCast(OSData, prop.get()); 1370 require_action(data != nullptr, skip, DEBUG_ERROR("No proxy data!\n")); 1371 1372 image = (const uint8_t *)data->getBytesNoCopy(); 1373 1374 skip: 1375 if (IONVRAMV3Handler::isValidImage(image, size)) { 1376 _format = IONVRAMV3Handler::init(this, image, size, _varDict); 1377 require_action(_format, skip, panic("IONVRAMV3Handler creation failed\n")); 1378 } else { 1379 _format = IONVRAMCHRPHandler::init(this, image, size, _varDict); 1380 require_action(_format, skip, panic("IONVRAMCHRPHandler creation failed\n")); 1381 } 1382 1383 _format->unserializeVariables(); 1384 1385 dumpDict(_varDict.get()); 1386 1387 #if defined(RELEASE) 1388 if (entry != nullptr) { 1389 entry->removeProperty(proxyDataKey); 1390 } 1391 #endif 1392 1393 _lastDeviceSync = 0; 1394 _freshInterval = true; 1395 } 1396 1397 void 1398 IODTNVRAM::registerNVRAMController(IONVRAMController *controller) 1399 { 1400 DEBUG_INFO("setting controller\n"); 1401 1402 NVRAMWRITELOCK(); 1403 CONTROLLERLOCK(); 1404 1405 _format->setController(controller); 1406 1407 CONTROLLERUNLOCK(); 1408 NVRAMUNLOCK(); 1409 1410 return; 1411 } 1412 1413 bool 1414 IODTNVRAM::safeToSync(void) 1415 { 1416 AbsoluteTime delta; 1417 UInt64 delta_ns; 1418 SInt32 delta_secs; 1419 1420 // delta interval went by 1421 clock_get_uptime(&delta); 1422 1423 // Figure it in seconds. 1424 absolutetime_to_nanoseconds(delta, &delta_ns); 1425 delta_secs = (SInt32)(delta_ns / NSEC_PER_SEC); 1426 1427 if ((delta_secs > (_lastDeviceSync + MIN_SYNC_NOW_INTERVAL)) || _freshInterval) { 1428 _lastDeviceSync = delta_secs; 1429 _freshInterval = false; 1430 return true; 1431 } 1432 1433 return false; 1434 } 1435 1436 void 1437 IODTNVRAM::syncInternal(bool rateLimit) 1438 { 1439 DEBUG_INFO("rateLimit=%d\n", rateLimit); 1440 1441 if (!SAFE_TO_LOCK()) { 1442 DEBUG_INFO("cannot lock\n"); 1443 return; 1444 } 1445 1446 // Rate limit requests to sync. Drivers that need this rate limiting will 1447 // shadow the data and only write to flash when they get a sync call 1448 if (rateLimit) { 1449 if (safeToSync() == false) { 1450 DEBUG_INFO("safeToSync()=false\n"); 1451 return; 1452 } 1453 } 1454 1455 DEBUG_INFO("Calling sync()\n"); 1456 record_system_event(SYSTEM_EVENT_TYPE_INFO, SYSTEM_EVENT_SUBSYSTEM_NVRAM, "sync", "triggered"); 1457 1458 NVRAMREADLOCK(); 1459 CONTROLLERLOCK(); 1460 1461 _format->sync(); 1462 1463 CONTROLLERUNLOCK(); 1464 NVRAMUNLOCK(); 1465 1466 if (_diags) { 1467 OSSharedPtr<OSNumber> generation = OSNumber::withNumber(_format->getGeneration(), 32); 1468 _diags->setProperty(kCurrentGenerationCountKey, generation.get()); 1469 } 1470 } 1471 1472 void 1473 IODTNVRAM::sync(void) 1474 { 1475 syncInternal(false); 1476 } 1477 1478 void 1479 IODTNVRAM::reload(void) 1480 { 1481 _format->reload(); 1482 } 1483 1484 bool 1485 IODTNVRAM::serializeProperties(OSSerialize *s) const 1486 { 1487 const OSSymbol *canonicalKey; 1488 OSSharedPtr<OSDictionary> localVarDict, returnDict; 1489 OSSharedPtr<OSCollectionIterator> iter; 1490 bool ok = false; 1491 unsigned int totalCapacity = 0; 1492 uuid_t varGuid; 1493 const char * varName; 1494 1495 NVRAMREADLOCK(); 1496 if (_varDict) { 1497 localVarDict = OSDictionary::withDictionary(_varDict.get()); 1498 } 1499 NVRAMUNLOCK(); 1500 1501 if (localVarDict != nullptr) { 1502 totalCapacity = localVarDict->getCapacity(); 1503 } 1504 1505 returnDict = OSDictionary::withCapacity(totalCapacity); 1506 1507 if (returnDict == nullptr) { 1508 DEBUG_ERROR("No dictionary\n"); 1509 goto exit; 1510 } 1511 1512 // Copy system entries first if present then copy unique other entries 1513 iter = OSCollectionIterator::withCollection(localVarDict.get()); 1514 if (iter == nullptr) { 1515 DEBUG_ERROR("failed to create iterator\n"); 1516 goto exit; 1517 } 1518 1519 while ((canonicalKey = OSDynamicCast(OSSymbol, iter->getNextObject()))) { 1520 parseVariableName(canonicalKey, &varGuid, &varName); 1521 1522 if ((uuid_compare(varGuid, gAppleSystemVariableGuid) == 0) && 1523 verifyPermission(kIONVRAMOperationRead, varGuid, varName, _format->getSystemPartitionActive())) { 1524 OSSharedPtr<const OSSymbol> returnKey = OSSymbol::withCString(varName); 1525 returnDict->setObject(returnKey.get(), localVarDict->getObject(canonicalKey)); 1526 } 1527 } 1528 1529 iter.reset(); 1530 1531 iter = OSCollectionIterator::withCollection(localVarDict.get()); 1532 if (iter == nullptr) { 1533 DEBUG_ERROR("failed to create iterator\n"); 1534 goto exit; 1535 } 1536 1537 while ((canonicalKey = OSDynamicCast(OSSymbol, iter->getNextObject()))) { 1538 parseVariableName(canonicalKey, &varGuid, &varName); 1539 1540 if (uuid_compare(varGuid, gAppleNVRAMGuid) == 0) { 1541 if (returnDict->getObject(varName) != nullptr) { 1542 // Skip non uniques 1543 continue; 1544 } 1545 1546 if (verifyPermission(kIONVRAMOperationRead, varGuid, varName, _format->getSystemPartitionActive())) { 1547 OSSharedPtr<const OSSymbol> returnKey = OSSymbol::withCString(varName); 1548 returnDict->setObject(returnKey.get(), localVarDict->getObject(canonicalKey)); 1549 } 1550 } 1551 } 1552 1553 ok = returnDict->serialize(s); 1554 1555 exit: 1556 DEBUG_INFO("ok=%d\n", ok); 1557 1558 return ok; 1559 } 1560 1561 IOReturn 1562 IODTNVRAM::flushGUID(const uuid_t guid, IONVRAMOperation op) 1563 { 1564 IOReturn ret = kIOReturnSuccess; 1565 1566 if (_format->getSystemPartitionActive() && (uuid_compare(guid, gAppleSystemVariableGuid) == 0)) { 1567 ret = _format->flush(guid, op); 1568 1569 DEBUG_INFO("system variables flushed, ret=%08x\n", ret); 1570 } else if (uuid_compare(guid, gAppleNVRAMGuid) == 0) { 1571 ret = _format->flush(guid, op); 1572 1573 DEBUG_INFO("common variables flushed, ret=%08x\n", ret); 1574 } 1575 1576 return ret; 1577 } 1578 1579 bool 1580 IODTNVRAM::handleSpecialVariables(const char *name, const uuid_t guid, const OSObject *obj, IOReturn *error) 1581 { 1582 IOReturn ret = kIOReturnSuccess; 1583 bool special = false; 1584 1585 NVRAMLOCKASSERTEXCLUSIVE(); 1586 1587 // ResetNVRam flushes both regions in one call 1588 // Obliterate can flush either separately 1589 if (strcmp(name, "ObliterateNVRam") == 0) { 1590 special = true; 1591 ret = flushGUID(guid, kIONVRAMOperationObliterate); 1592 } else if (strcmp(name, "ResetNVRam") == 0) { 1593 special = true; 1594 ret = flushGUID(gAppleSystemVariableGuid, kIONVRAMOperationReset); 1595 1596 if (ret != kIOReturnSuccess) { 1597 goto exit; 1598 } 1599 1600 ret = flushGUID(gAppleNVRAMGuid, kIONVRAMOperationReset); 1601 } 1602 1603 exit: 1604 if (error) { 1605 *error = ret; 1606 } 1607 1608 return special; 1609 } 1610 1611 OSSharedPtr<OSObject> 1612 IODTNVRAM::copyPropertyWithGUIDAndName(const uuid_t guid, const char *name) const 1613 { 1614 OSSharedPtr<const OSSymbol> canonicalKey; 1615 OSSharedPtr<OSObject> theObject; 1616 uuid_t newGuid; 1617 1618 if (_varDict == nullptr) { 1619 DEBUG_INFO("No dictionary\n"); 1620 goto exit; 1621 } 1622 1623 if (!verifyPermission(kIONVRAMOperationRead, guid, name, _format->getSystemPartitionActive())) { 1624 DEBUG_INFO("Not privileged\n"); 1625 goto exit; 1626 } 1627 1628 translateGUID(guid, name, newGuid, _format->getSystemPartitionActive()); 1629 1630 canonicalKey = keyWithGuidAndCString(newGuid, name); 1631 1632 NVRAMREADLOCK(); 1633 theObject.reset(_varDict->getObject(canonicalKey.get()), OSRetain); 1634 NVRAMUNLOCK(); 1635 1636 if (_diags) { 1637 _diags->logVariable(getPartitionTypeForGUID(newGuid), kIONVRAMOperationRead, name, NULL); 1638 } 1639 1640 if (theObject != nullptr) { 1641 DEBUG_INFO("%s has object\n", canonicalKey.get()->getCStringNoCopy()); 1642 } else { 1643 DEBUG_INFO("%s no entry\n", canonicalKey.get()->getCStringNoCopy()); 1644 } 1645 1646 exit: 1647 return theObject; 1648 } 1649 1650 OSSharedPtr<OSObject> 1651 IODTNVRAM::copyProperty(const OSSymbol *aKey) const 1652 { 1653 const char *variableName; 1654 uuid_t varGuid; 1655 1656 if (skipKey(aKey)) { 1657 return nullptr; 1658 } 1659 DEBUG_INFO("aKey=%s\n", aKey->getCStringNoCopy()); 1660 1661 parseVariableName(aKey->getCStringNoCopy(), &varGuid, &variableName); 1662 1663 return copyPropertyWithGUIDAndName(varGuid, variableName); 1664 } 1665 1666 OSSharedPtr<OSObject> 1667 IODTNVRAM::copyProperty(const char *aKey) const 1668 { 1669 OSSharedPtr<const OSSymbol> keySymbol; 1670 OSSharedPtr<OSObject> theObject; 1671 1672 keySymbol = OSSymbol::withCString(aKey); 1673 if (keySymbol != nullptr) { 1674 theObject = copyProperty(keySymbol.get()); 1675 } 1676 1677 return theObject; 1678 } 1679 1680 OSObject * 1681 IODTNVRAM::getProperty(const OSSymbol *aKey) const 1682 { 1683 // The shared pointer gets released at the end of the function, 1684 // and returns a view into theObject. 1685 OSSharedPtr<OSObject> theObject = copyProperty(aKey); 1686 1687 return theObject.get(); 1688 } 1689 1690 OSObject * 1691 IODTNVRAM::getProperty(const char *aKey) const 1692 { 1693 // The shared pointer gets released at the end of the function, 1694 // and returns a view into theObject. 1695 OSSharedPtr<OSObject> theObject = copyProperty(aKey); 1696 1697 return theObject.get(); 1698 } 1699 1700 IOReturn 1701 IODTNVRAM::setPropertyWithGUIDAndName(const uuid_t guid, const char *name, OSObject *anObject) 1702 { 1703 IOReturn ret = kIOReturnSuccess; 1704 bool remove = false; 1705 OSString *tmpString = nullptr; 1706 OSSharedPtr<OSObject> propObject; 1707 OSSharedPtr<OSObject> sharedObject(anObject, OSRetain); 1708 bool deletePropertyKey, syncNowPropertyKey, forceSyncNowPropertyKey; 1709 bool ok; 1710 size_t propDataSize = 0; 1711 uuid_t newGuid; 1712 1713 deletePropertyKey = strncmp(name, kIONVRAMDeletePropertyKey, sizeof(kIONVRAMDeletePropertyKey)) == 0; 1714 syncNowPropertyKey = strncmp(name, kIONVRAMSyncNowPropertyKey, sizeof(kIONVRAMSyncNowPropertyKey)) == 0; 1715 forceSyncNowPropertyKey = strncmp(name, kIONVRAMForceSyncNowPropertyKey, sizeof(kIONVRAMForceSyncNowPropertyKey)) == 0; 1716 1717 if (deletePropertyKey) { 1718 tmpString = OSDynamicCast(OSString, anObject); 1719 if (tmpString != nullptr) { 1720 const char *variableName; 1721 uuid_t valueVarGuid; 1722 bool guidProvided; 1723 IOReturn removeRet; 1724 1725 guidProvided = parseVariableName(tmpString->getCStringNoCopy(), &valueVarGuid, &variableName); 1726 1727 // nvram tool will provide a "nvram -d var" or "nvram -d guid:var" as 1728 // kIONVRAMDeletePropertyKey=var or kIONVRAMDeletePropertyKey=guid:var 1729 // that will come into this function as (gAppleNVRAMGuid, varname, nullptr) 1730 // if we provide the "-z" flag to the nvram tool this function will come in as 1731 // (gAppleSystemVariableGuid, varname, nullptr). We are reparsing the value string, 1732 // if there is a GUID provided with the value then use that GUID otherwise use the 1733 // guid that was provided via the node selection or default. 1734 if (guidProvided == false) { 1735 DEBUG_INFO("Removing with API provided GUID\n"); 1736 removeRet = removePropertyWithGUIDAndName(guid, variableName); 1737 } else { 1738 DEBUG_INFO("Removing with value provided GUID\n"); 1739 removeRet = removePropertyWithGUIDAndName(valueVarGuid, variableName); 1740 } 1741 1742 DEBUG_INFO("kIONVRAMDeletePropertyKey found, removeRet=%#08x\n", removeRet); 1743 } else { 1744 DEBUG_INFO("kIONVRAMDeletePropertyKey value needs to be an OSString\n"); 1745 ret = kIOReturnError; 1746 } 1747 goto exit; 1748 } else if (syncNowPropertyKey || forceSyncNowPropertyKey) { 1749 tmpString = OSDynamicCast(OSString, anObject); 1750 DEBUG_INFO("NVRAM sync key %s found\n", name); 1751 if (tmpString != nullptr) { 1752 // We still want to throttle NVRAM commit rate for SyncNow. ForceSyncNow is provided as a really big hammer. 1753 syncInternal(syncNowPropertyKey); 1754 } else { 1755 DEBUG_INFO("%s value needs to be an OSString\n", name); 1756 ret = kIOReturnError; 1757 } 1758 goto exit; 1759 } 1760 1761 if (!verifyPermission(kIONVRAMOperationWrite, guid, name, _format->getSystemPartitionActive())) { 1762 DEBUG_INFO("Not privileged\n"); 1763 ret = kIOReturnNotPrivileged; 1764 goto exit; 1765 } 1766 1767 // Make sure the object is of the correct type. 1768 switch (getVariableType(name)) { 1769 case kOFVariableTypeBoolean: 1770 propObject = OSDynamicPtrCast<OSBoolean>(sharedObject); 1771 if (propObject) { 1772 record_system_event(SYSTEM_EVENT_TYPE_INFO, SYSTEM_EVENT_SUBSYSTEM_NVRAM, "write", "%s to %d", name, ((OSBoolean *)propObject.get())->getValue()); 1773 } 1774 break; 1775 1776 case kOFVariableTypeNumber: 1777 propObject = OSDynamicPtrCast<OSNumber>(sharedObject); 1778 if (propObject) { 1779 record_system_event(SYSTEM_EVENT_TYPE_INFO, SYSTEM_EVENT_SUBSYSTEM_NVRAM, "write", "%s to %#llx", name, ((OSNumber *)propObject.get())->unsigned64BitValue()); 1780 } 1781 break; 1782 1783 case kOFVariableTypeString: 1784 propObject = OSDynamicPtrCast<OSString>(sharedObject); 1785 if (propObject != nullptr) { 1786 record_system_event(SYSTEM_EVENT_TYPE_INFO, SYSTEM_EVENT_SUBSYSTEM_NVRAM, "write", "%s to %s", name, ((OSString *)propObject.get())->getCStringNoCopy()); 1787 1788 propDataSize = (OSDynamicPtrCast<OSString>(propObject))->getLength(); 1789 1790 if ((strncmp(name, kIONVRAMBootArgsKey, sizeof(kIONVRAMBootArgsKey)) == 0) && (propDataSize >= BOOT_LINE_LENGTH)) { 1791 DEBUG_ERROR("boot-args size too large for BOOT_LINE_LENGTH, propDataSize=%zu\n", propDataSize); 1792 ret = kIOReturnNoSpace; 1793 goto exit; 1794 } 1795 } 1796 break; 1797 1798 case kOFVariableTypeData: 1799 propObject = OSDynamicPtrCast<OSData>(sharedObject); 1800 if (propObject == nullptr) { 1801 tmpString = OSDynamicCast(OSString, sharedObject.get()); 1802 if (tmpString != nullptr) { 1803 propObject = OSData::withBytes(tmpString->getCStringNoCopy(), 1804 tmpString->getLength()); 1805 } 1806 } 1807 1808 if (propObject != nullptr) { 1809 propDataSize = (OSDynamicPtrCast<OSData>(propObject))->getLength(); 1810 record_system_event(SYSTEM_EVENT_TYPE_INFO, SYSTEM_EVENT_SUBSYSTEM_NVRAM, "write", "%s with data size %#x", name, ((OSData *)propObject.get())->getLength()); 1811 } 1812 1813 #if defined(XNU_TARGET_OS_OSX) 1814 if ((propObject != nullptr) && ((OSDynamicPtrCast<OSData>(propObject))->getLength() == 0)) { 1815 remove = true; 1816 } 1817 #endif /* defined(XNU_TARGET_OS_OSX) */ 1818 break; 1819 default: 1820 break; 1821 } 1822 1823 if (propObject == nullptr) { 1824 DEBUG_INFO("No property object\n"); 1825 ret = kIOReturnBadArgument; 1826 goto exit; 1827 } 1828 1829 if (!verifyWriteSizeLimit(guid, name, propDataSize)) { 1830 DEBUG_ERROR("Property data size of %zu too long for %s\n", propDataSize, name); 1831 ret = kIOReturnNoSpace; 1832 goto exit; 1833 } 1834 1835 NVRAMWRITELOCK(); 1836 ok = handleSpecialVariables(name, guid, propObject.get(), &ret); 1837 NVRAMUNLOCK(); 1838 1839 if (ok) { 1840 goto exit; 1841 } 1842 1843 if (remove == false) { 1844 DEBUG_INFO("Adding object\n"); 1845 1846 translateGUID(guid, name, newGuid, _format->getSystemPartitionActive()); 1847 1848 NVRAMWRITELOCK(); 1849 1850 ret = _format->setVariable(newGuid, name, propObject.get()); 1851 1852 NVRAMUNLOCK(); 1853 } else { 1854 DEBUG_INFO("Removing object\n"); 1855 ret = removePropertyWithGUIDAndName(guid, name); 1856 } 1857 1858 if (tmpString) { 1859 propObject.reset(); 1860 } 1861 1862 exit: 1863 DEBUG_INFO("ret=%#08x\n", ret); 1864 1865 return ret; 1866 } 1867 1868 IOReturn 1869 IODTNVRAM::setPropertyInternal(const OSSymbol *aKey, OSObject *anObject) 1870 { 1871 const char *variableName; 1872 uuid_t varGuid; 1873 1874 DEBUG_INFO("aKey=%s\n", aKey->getCStringNoCopy()); 1875 1876 parseVariableName(aKey->getCStringNoCopy(), &varGuid, &variableName); 1877 1878 return setPropertyWithGUIDAndName(varGuid, variableName, anObject); 1879 } 1880 1881 bool 1882 IODTNVRAM::setProperty(const OSSymbol *aKey, OSObject *anObject) 1883 { 1884 return setPropertyInternal(aKey, anObject) == kIOReturnSuccess; 1885 } 1886 1887 void 1888 IODTNVRAM::removeProperty(const OSSymbol *aKey) 1889 { 1890 IOReturn ret; 1891 1892 ret = removePropertyInternal(aKey); 1893 1894 if (ret != kIOReturnSuccess) { 1895 DEBUG_INFO("removePropertyInternal failed, ret=%#08x\n", ret); 1896 } 1897 } 1898 1899 IOReturn 1900 IODTNVRAM::removePropertyWithGUIDAndName(const uuid_t guid, const char *name) 1901 { 1902 IOReturn ret; 1903 uuid_t newGuid; 1904 1905 DEBUG_INFO("name=%s\n", name); 1906 1907 if (_varDict == nullptr) { 1908 DEBUG_INFO("No dictionary\n"); 1909 ret = kIOReturnNotFound; 1910 goto exit; 1911 } 1912 1913 if (!verifyPermission(kIONVRAMOperationDelete, guid, name, _format->getSystemPartitionActive())) { 1914 DEBUG_INFO("Not privileged\n"); 1915 ret = kIOReturnNotPrivileged; 1916 goto exit; 1917 } 1918 1919 translateGUID(guid, name, newGuid, _format->getSystemPartitionActive()); 1920 1921 NVRAMWRITELOCK(); 1922 1923 ret = _format->setVariable(newGuid, name, nullptr); 1924 1925 if (ret != kIOReturnSuccess) { 1926 DEBUG_INFO("%s not found\n", name); 1927 ret = kIOReturnNotFound; 1928 } 1929 1930 NVRAMUNLOCK(); 1931 1932 record_system_event(SYSTEM_EVENT_TYPE_INFO, SYSTEM_EVENT_SUBSYSTEM_NVRAM, "delete", "%s", name); 1933 1934 exit: 1935 return ret; 1936 } 1937 1938 IOReturn 1939 IODTNVRAM::removePropertyInternal(const OSSymbol *aKey) 1940 { 1941 IOReturn ret; 1942 const char *variableName; 1943 uuid_t varGuid; 1944 1945 DEBUG_INFO("aKey=%s\n", aKey->getCStringNoCopy()); 1946 1947 parseVariableName(aKey->getCStringNoCopy(), &varGuid, &variableName); 1948 1949 ret = removePropertyWithGUIDAndName(varGuid, variableName); 1950 1951 return ret; 1952 } 1953 1954 IOReturn 1955 IODTNVRAM::setProperties(OSObject *properties) 1956 { 1957 IOReturn ret = kIOReturnSuccess; 1958 OSObject *object; 1959 const OSSymbol *key; 1960 OSDictionary *dict; 1961 OSSharedPtr<OSCollectionIterator> iter; 1962 1963 dict = OSDynamicCast(OSDictionary, properties); 1964 if (dict == nullptr) { 1965 DEBUG_ERROR("Not a dictionary\n"); 1966 return kIOReturnBadArgument; 1967 } 1968 1969 iter = OSCollectionIterator::withCollection(dict); 1970 if (iter == nullptr) { 1971 DEBUG_ERROR("Couldn't create iterator\n"); 1972 return kIOReturnBadArgument; 1973 } 1974 1975 while (ret == kIOReturnSuccess) { 1976 key = OSDynamicCast(OSSymbol, iter->getNextObject()); 1977 if (key == nullptr) { 1978 break; 1979 } 1980 1981 object = dict->getObject(key); 1982 if (object == nullptr) { 1983 continue; 1984 } 1985 1986 ret = setPropertyInternal(key, object); 1987 } 1988 1989 DEBUG_INFO("ret=%#08x\n", ret); 1990 1991 return ret; 1992 } 1993 1994 // ********************** Deprecated ******************** 1995 1996 IOReturn 1997 IODTNVRAM::readXPRAM(IOByteCount offset, uint8_t *buffer, 1998 IOByteCount length) 1999 { 2000 return kIOReturnUnsupported; 2001 } 2002 2003 IOReturn 2004 IODTNVRAM::writeXPRAM(IOByteCount offset, uint8_t *buffer, 2005 IOByteCount length) 2006 { 2007 return kIOReturnUnsupported; 2008 } 2009 2010 IOReturn 2011 IODTNVRAM::readNVRAMProperty(IORegistryEntry *entry, 2012 const OSSymbol **name, 2013 OSData **value) 2014 { 2015 return kIOReturnUnsupported; 2016 } 2017 2018 IOReturn 2019 IODTNVRAM::writeNVRAMProperty(IORegistryEntry *entry, 2020 const OSSymbol *name, 2021 OSData *value) 2022 { 2023 return kIOReturnUnsupported; 2024 } 2025 2026 OSDictionary * 2027 IODTNVRAM::getNVRAMPartitions(void) 2028 { 2029 return NULL; 2030 } 2031 2032 IOReturn 2033 IODTNVRAM::readNVRAMPartition(const OSSymbol *partitionID, 2034 IOByteCount offset, uint8_t *buffer, 2035 IOByteCount length) 2036 { 2037 return kIOReturnUnsupported; 2038 } 2039 2040 IOReturn 2041 IODTNVRAM::writeNVRAMPartition(const OSSymbol *partitionID, 2042 IOByteCount offset, uint8_t *buffer, 2043 IOByteCount length) 2044 { 2045 return kIOReturnUnsupported; 2046 } 2047 2048 IOByteCount 2049 IODTNVRAM::savePanicInfo(uint8_t *buffer, IOByteCount length) 2050 { 2051 return 0; 2052 } 2053