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