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