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