xref: /xnu-8792.61.2/iokit/Kernel/IONVRAM.cpp (revision 42e220869062b56f8d7d0726fd4c88954f87902c)
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