1 /*
2 * Copyright (c) 2021-2022 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 #include <libkern/c++/OSBoundedPtr.h>
30
31 #define NVRAM_CHRP_APPLE_HEADER_NAME_V1 "nvram"
32 #define NVRAM_CHRP_APPLE_HEADER_NAME_V2 "2nvram"
33
34 #define NVRAM_CHRP_PARTITION_NAME_COMMON_V1 "common"
35 #define NVRAM_CHRP_PARTITION_NAME_SYSTEM_V1 "system"
36 #define NVRAM_CHRP_PARTITION_NAME_COMMON_V2 "2common"
37 #define NVRAM_CHRP_PARTITION_NAME_SYSTEM_V2 "2system"
38
39 #define NVRAM_CHRP_LENGTH_BLOCK_SIZE 0x10 // CHRP length field is in 16 byte blocks
40
41 typedef struct chrp_nvram_header { //16 bytes
42 uint8_t sig;
43 uint8_t cksum; // checksum on sig, len, and name
44 uint16_t len; // total length of the partition in 16 byte blocks starting with the signature
45 // and ending with the last byte of data area, ie len includes its own header size
46 char name[12];
47 uint8_t data[0];
48 } chrp_nvram_header_t;
49
50 typedef struct apple_nvram_header { // 16 + 16 bytes
51 struct chrp_nvram_header chrp;
52 uint32_t adler;
53 uint32_t generation;
54 uint8_t padding[8];
55 } apple_nvram_header_t;
56
57 typedef struct {
58 NVRAMPartitionType type;
59 uint32_t offset;
60 uint32_t size;
61 } NVRAMRegionInfo;
62
63 class IONVRAMCHRPHandler : public IODTNVRAMFormatHandler, IOTypedOperatorsMixin<IONVRAMCHRPHandler>
64 {
65 private:
66 bool _newData;
67 bool _reload;
68 IONVRAMController *_nvramController;
69 IODTNVRAM *_provider;
70 NVRAMVersion _version;
71 uint32_t _generation;
72
73 uint8_t *_nvramImage;
74
75 uint32_t _commonPartitionOffset;
76 uint32_t _commonPartitionSize;
77
78 uint32_t _systemPartitionOffset;
79 uint32_t _systemPartitionSize;
80
81 OSSharedPtr<OSDictionary> _varDict;
82
83 uint32_t _commonUsed;
84 uint32_t _systemUsed;
85
86 IORWLock *_variableLock;
87 IOLock *_controllerLock;
88
89 uint32_t findCurrentBank(uint32_t *gen);
90 IOReturn unserializeImage(const uint8_t *image, IOByteCount length);
91 IOReturn serializeVariables(void);
92
93 IOReturn reloadInternal(void);
94 IOReturn setVariableInternal(const uuid_t varGuid, const char *variableName, OSObject *object);
95
96 static OSSharedPtr<OSData> unescapeBytesToData(const uint8_t *bytes, uint32_t length);
97 static OSSharedPtr<OSData> escapeDataToData(OSData * value);
98
99 static bool convertPropToObject(const uint8_t *propName, uint32_t propNameLength, const uint8_t *propData, uint32_t propDataLength,
100 LIBKERN_RETURNS_RETAINED const OSSymbol **propSymbol, LIBKERN_RETURNS_RETAINED OSObject **propObject);
101 static bool convertPropToObject(const uint8_t *propName, uint32_t propNameLength, const uint8_t *propData, uint32_t propDataLength,
102 OSSharedPtr<const OSSymbol>& propSymbol, OSSharedPtr<OSObject>& propObject);
103 static bool convertObjectToProp(uint8_t *buffer, uint32_t *length, const OSSymbol *propSymbol, OSObject *propObject);
104 static bool convertObjectToProp(uint8_t *buffer, uint32_t *length, const char *propSymbol, OSObject *propObject);
105
106 public:
107 virtual
108 ~IONVRAMCHRPHandler() APPLE_KEXT_OVERRIDE;
109 IONVRAMCHRPHandler();
110 static bool isValidImage(const uint8_t *image, IOByteCount length);
111 static IONVRAMCHRPHandler *init(IODTNVRAM *provider, const uint8_t *image, IOByteCount length);
112
113 virtual IOReturn unserializeVariables(void) APPLE_KEXT_OVERRIDE;
114 virtual IOReturn setVariable(const uuid_t varGuid, const char *variableName, OSObject *object) APPLE_KEXT_OVERRIDE;
115 virtual bool setController(IONVRAMController *controller) APPLE_KEXT_OVERRIDE;
116 virtual IOReturn sync(void) APPLE_KEXT_OVERRIDE;
117 virtual IOReturn flush(const uuid_t guid, IONVRAMOperation op) APPLE_KEXT_OVERRIDE;
118 virtual void reload(void) APPLE_KEXT_OVERRIDE;
119 virtual uint32_t getGeneration(void) const APPLE_KEXT_OVERRIDE;
120 virtual uint32_t getVersion(void) const APPLE_KEXT_OVERRIDE;
121 virtual uint32_t getSystemUsed(void) const APPLE_KEXT_OVERRIDE;
122 virtual uint32_t getCommonUsed(void) const APPLE_KEXT_OVERRIDE;
123 virtual bool getSystemPartitionActive(void) const APPLE_KEXT_OVERRIDE;
124 virtual IOReturn getVarDict(OSSharedPtr<OSDictionary> &varDictCopy) APPLE_KEXT_OVERRIDE;
125 };
126
127 static const char *
get_bank_version_string(int version)128 get_bank_version_string(int version)
129 {
130 switch (version) {
131 case kNVRAMVersion1:
132 return NVRAM_CHRP_APPLE_HEADER_NAME_V1;
133 case kNVRAMVersion2:
134 return NVRAM_CHRP_APPLE_HEADER_NAME_V2;
135 default:
136 return "Unknown";
137 }
138 }
139
140 static uint32_t
adler32(const uint8_t * buffer,size_t length)141 adler32(const uint8_t *buffer, size_t length)
142 {
143 uint32_t offset;
144 uint32_t adler, lowHalf, highHalf;
145
146 lowHalf = 1;
147 highHalf = 0;
148
149 for (offset = 0; offset < length; offset++) {
150 if ((offset % 5000) == 0) {
151 lowHalf %= 65521L;
152 highHalf %= 65521L;
153 }
154
155 lowHalf += buffer[offset];
156 highHalf += lowHalf;
157 }
158
159 lowHalf %= 65521L;
160 highHalf %= 65521L;
161
162 adler = (highHalf << 16) | lowHalf;
163
164 return adler;
165 }
166
167 static uint32_t
nvram_get_adler(uint8_t * buf,int version)168 nvram_get_adler(uint8_t *buf, int version)
169 {
170 return ((struct apple_nvram_header *)buf)->adler;
171 }
172
173 static uint32_t
adler32_with_version(const uint8_t * buf,size_t len,int version)174 adler32_with_version(const uint8_t *buf, size_t len, int version)
175 {
176 size_t offset;
177
178 switch (version) {
179 case kNVRAMVersion1:
180 case kNVRAMVersion2:
181 offset = offsetof(struct apple_nvram_header, generation);
182 break;
183 default:
184 return 0;
185 }
186
187 return adler32(buf + offset, len - offset);
188 }
189
190 static uint8_t
chrp_checksum(const struct chrp_nvram_header * hdr)191 chrp_checksum(const struct chrp_nvram_header *hdr)
192 {
193 uint16_t sum;
194 const uint8_t *p;
195 const uint8_t *begin = (const uint8_t *)hdr + offsetof(struct chrp_nvram_header, len);
196 const uint8_t *end = (const uint8_t *)hdr + offsetof(struct chrp_nvram_header, data);
197
198 // checksum the header (minus the checksum itself)
199 sum = hdr->sig;
200 for (p = begin; p < end; p++) {
201 sum += *p;
202 }
203 while (sum > 0xff) {
204 sum = (sum & 0xff) + (sum >> 8);
205 }
206
207 return sum & 0xff;
208 }
209
210 static IOReturn
nvram_validate_header_v1v2(const uint8_t * buf,uint32_t * generation,int version)211 nvram_validate_header_v1v2(const uint8_t * buf, uint32_t *generation, int version)
212 {
213 IOReturn result = kIOReturnError;
214 uint8_t checksum;
215 const char *header_string = get_bank_version_string(version);
216 struct chrp_nvram_header *chrp_header = (struct chrp_nvram_header *)buf;
217 uint32_t local_gen = 0;
218
219 require(buf != nullptr, exit);
220
221 // <rdar://problem/73454488> Recovery Mode [Internal Build] 18D52-->18E141 [J307/308 Only]
222 // we can only compare the first "nvram" parts of the name as some devices have additional junk from
223 // a previous build likely copying past bounds of the "nvram" name in the const section
224 if (memcmp(header_string, chrp_header->name, strlen(header_string)) == 0) {
225 checksum = chrp_checksum(chrp_header);
226 if (checksum == chrp_header->cksum) {
227 result = kIOReturnSuccess;
228 local_gen = ((struct apple_nvram_header*)buf)->generation;
229
230 DEBUG_INFO("Found %s gen=%u\n", header_string, local_gen);
231
232 if (generation) {
233 *generation = local_gen;
234 }
235 } else {
236 DEBUG_INFO("invalid checksum in header, found %#02x, expected %#02x\n", chrp_header->cksum, checksum);
237 }
238 } else {
239 DEBUG_INFO("invalid bank for \"%s\", name = %#02x %#02x %#02x %#02x\n", header_string,
240 chrp_header->name[0],
241 chrp_header->name[1],
242 chrp_header->name[2],
243 chrp_header->name[3]);
244 }
245
246 exit:
247 return result;
248 }
249
250 static void
nvram_set_apple_header(uint8_t * buf,size_t len,uint32_t generation,int version)251 nvram_set_apple_header(uint8_t *buf, size_t len, uint32_t generation, int version)
252 {
253 if (version == kNVRAMVersion1 ||
254 version == kNVRAMVersion2) {
255 struct apple_nvram_header *apple_hdr = (struct apple_nvram_header *)buf;
256 generation += 1;
257 apple_hdr->generation = generation;
258 apple_hdr->adler = adler32_with_version(buf, len, version);
259 }
260 }
261
262 static NVRAMVersion
validateNVRAMVersion(const uint8_t * buf,size_t len,uint32_t * generation)263 validateNVRAMVersion(const uint8_t *buf, size_t len, uint32_t *generation)
264 {
265 NVRAMVersion version = kNVRAMVersionUnknown;
266
267 if (nvram_validate_header_v1v2(buf, generation, kNVRAMVersion1) == kIOReturnSuccess) {
268 version = kNVRAMVersion1;
269 goto exit;
270 }
271
272 if (nvram_validate_header_v1v2(buf, generation, kNVRAMVersion2) == kIOReturnSuccess) {
273 version = kNVRAMVersion2;
274 goto exit;
275 }
276
277 DEBUG_INFO("Unable to determine version\n");
278
279 exit:
280 DEBUG_INFO("version=%u\n", version);
281 return version;
282 }
283
~IONVRAMCHRPHandler()284 IONVRAMCHRPHandler::~IONVRAMCHRPHandler()
285 {
286 }
287
288 bool
isValidImage(const uint8_t * image,IOByteCount length)289 IONVRAMCHRPHandler::isValidImage(const uint8_t *image, IOByteCount length)
290 {
291 return validateNVRAMVersion(image, length, nullptr) != kNVRAMVersionUnknown;
292 }
293
294 IONVRAMCHRPHandler*
init(IODTNVRAM * provider,const uint8_t * image,IOByteCount length)295 IONVRAMCHRPHandler::init(IODTNVRAM *provider, const uint8_t *image, IOByteCount length)
296 {
297 bool propertiesOk;
298
299 IONVRAMCHRPHandler *handler = new IONVRAMCHRPHandler();
300
301 handler->_provider = provider;
302
303 handler->_variableLock = IORWLockAlloc();
304 require(handler->_variableLock != nullptr, exit);
305
306 handler->_controllerLock = IOLockAlloc();
307 require(handler->_controllerLock != nullptr, exit);
308
309 propertiesOk = handler->getNVRAMProperties();
310 require_action(propertiesOk, exit, DEBUG_ERROR("Unable to get NVRAM properties\n"));
311 require_action(length == handler->_bankSize, exit, DEBUG_ERROR("length 0x%llx != _bankSize 0x%x\n", length, handler->_bankSize));
312
313 if ((image != nullptr) && (length != 0)) {
314 if (handler->unserializeImage(image, length) != kIOReturnSuccess) {
315 DEBUG_ALWAYS("Unable to unserialize image, len=%#x\n", (unsigned int)length);
316 }
317 }
318
319 return handler;
320
321 exit:
322 delete handler;
323
324 return nullptr;
325 }
326
IONVRAMCHRPHandler()327 IONVRAMCHRPHandler::IONVRAMCHRPHandler() :
328 _commonPartitionSize(0x800)
329 {
330 }
331
332 IOReturn
flush(const uuid_t guid,IONVRAMOperation op)333 IONVRAMCHRPHandler::flush(const uuid_t guid, IONVRAMOperation op)
334 {
335 IOReturn ret = kIOReturnSuccess;
336 bool flushSystem;
337 bool flushCommon;
338
339 flushSystem = getSystemPartitionActive() && (uuid_compare(guid, gAppleSystemVariableGuid) == 0);
340 flushCommon = uuid_compare(guid, gAppleNVRAMGuid) == 0;
341
342 DEBUG_INFO("flushSystem=%d, flushCommon=%d\n", flushSystem, flushCommon);
343
344 NVRAMWRITELOCK(_variableLock);
345 if (flushSystem || flushCommon) {
346 const OSSymbol *canonicalKey;
347 OSSharedPtr<OSDictionary> dictCopy;
348 OSSharedPtr<OSCollectionIterator> iter;
349 uuid_string_t uuidString;
350
351 dictCopy = OSDictionary::withDictionary(_varDict.get());
352 iter = OSCollectionIterator::withCollection(dictCopy.get());
353 require_action(dictCopy && iter, exit, ret = kIOReturnNoMemory);
354
355 while ((canonicalKey = OSDynamicCast(OSSymbol, iter->getNextObject()))) {
356 const char *varName;
357 uuid_t varGuid;
358 bool clear;
359
360 parseVariableName(canonicalKey->getCStringNoCopy(), &varGuid, &varName);
361
362 uuid_unparse(varGuid, uuidString);
363
364 clear = ((flushSystem && (uuid_compare(varGuid, gAppleSystemVariableGuid) == 0)) ||
365 (flushCommon && (uuid_compare(varGuid, gAppleSystemVariableGuid) != 0))) &&
366 verifyPermission(op, varGuid, varName, getSystemPartitionActive(), true);
367
368 if (clear) {
369 DEBUG_INFO("Clearing entry for %s:%s\n", uuidString, varName);
370 setVariableInternal(varGuid, varName, nullptr);
371 } else {
372 DEBUG_INFO("Keeping entry for %s:%s\n", uuidString, varName);
373 }
374 }
375 }
376
377 exit:
378 NVRAMRWUNLOCK(_variableLock);
379 return ret;
380 }
381
382 IOReturn
reloadInternal(void)383 IONVRAMCHRPHandler::reloadInternal(void)
384 {
385 uint32_t controllerBank;
386 uint32_t controllerGen;
387
388 NVRAMLOCKASSERTHELD(_controllerLock);
389
390 controllerBank = findCurrentBank(&controllerGen);
391
392 if (_currentBank != controllerBank) {
393 DEBUG_ERROR("_currentBank 0x%x != controllerBank 0x%x\n", _currentBank, controllerBank);
394 }
395
396 if (_generation != controllerGen) {
397 DEBUG_ERROR("_generation 0x%x != controllerGen 0x%x\n", _generation, controllerGen);
398 }
399
400 _currentBank = controllerBank;
401 _generation = controllerGen;
402
403 return kIOReturnSuccess;
404 }
405
406 void
reload(void)407 IONVRAMCHRPHandler::reload(void)
408 {
409 _reload = true;
410
411 DEBUG_INFO("reload marked\n");
412 }
413
414 IOReturn
unserializeImage(const uint8_t * image,IOByteCount length)415 IONVRAMCHRPHandler::unserializeImage(const uint8_t *image, IOByteCount length)
416 {
417 IOReturn ret = kIOReturnInvalid;
418 uint32_t partitionOffset, partitionLength;
419 uint32_t currentLength, currentOffset = 0;
420 uint32_t hdr_adler, calculated_adler;
421
422 _commonPartitionOffset = 0xFFFFFFFF;
423 _systemPartitionOffset = 0xFFFFFFFF;
424
425 _version = validateNVRAMVersion(image, _bankSize, &_generation);
426 require(_version != kNVRAMVersionUnknown, exit);
427
428 if (_nvramImage) {
429 IOFreeData(_nvramImage, _bankSize);
430 }
431
432 _nvramImage = IONewData(uint8_t, length);
433 _bankSize = (uint32_t)length;
434 bcopy(image, _nvramImage, _bankSize);
435
436 hdr_adler = nvram_get_adler(_nvramImage, _version);
437 calculated_adler = adler32_with_version(_nvramImage, _bankSize, _version);
438
439 if (hdr_adler != calculated_adler) {
440 panic("header adler %#08X != calculated_adler %#08X\n", hdr_adler, calculated_adler);
441 }
442
443 // Look through the partitions to find the common and system partitions.
444 while (currentOffset < _bankSize) {
445 bool common_partition;
446 bool system_partition;
447 const chrp_nvram_header_t * header = (chrp_nvram_header_t *)(_nvramImage + currentOffset);
448 const uint8_t common_v1_name[sizeof(header->name)] = {NVRAM_CHRP_PARTITION_NAME_COMMON_V1};
449 const uint8_t common_v2_name[sizeof(header->name)] = {NVRAM_CHRP_PARTITION_NAME_COMMON_V2};
450 const uint8_t system_v1_name[sizeof(header->name)] = {NVRAM_CHRP_PARTITION_NAME_SYSTEM_V1};
451 const uint8_t system_v2_name[sizeof(header->name)] = {NVRAM_CHRP_PARTITION_NAME_SYSTEM_V2};
452
453 currentLength = header->len * NVRAM_CHRP_LENGTH_BLOCK_SIZE;
454
455 if (currentLength < sizeof(chrp_nvram_header_t)) {
456 break;
457 }
458
459 partitionOffset = currentOffset + sizeof(chrp_nvram_header_t);
460 partitionLength = currentLength - sizeof(chrp_nvram_header_t);
461
462 if ((partitionOffset + partitionLength) > _bankSize) {
463 break;
464 }
465
466 common_partition = (memcmp(header->name, common_v1_name, sizeof(header->name)) == 0) ||
467 (memcmp(header->name, common_v2_name, sizeof(header->name)) == 0);
468 system_partition = (memcmp(header->name, system_v1_name, sizeof(header->name)) == 0) ||
469 (memcmp(header->name, system_v2_name, sizeof(header->name)) == 0);
470
471 if (common_partition) {
472 _commonPartitionOffset = partitionOffset;
473 _commonPartitionSize = partitionLength;
474 } else if (system_partition) {
475 _systemPartitionOffset = partitionOffset;
476 _systemPartitionSize = partitionLength;
477 }
478 currentOffset += currentLength;
479 }
480
481 ret = kIOReturnSuccess;
482
483 exit:
484 _varDict = OSDictionary::withCapacity(1);
485
486 DEBUG_ALWAYS("NVRAM : commonPartitionOffset - %#x, commonPartitionSize - %#x, systemPartitionOffset - %#x, systemPartitionSize - %#x\n",
487 _commonPartitionOffset, _commonPartitionSize, _systemPartitionOffset, _systemPartitionSize);
488
489 return ret;
490 }
491
492 IOReturn
unserializeVariables(void)493 IONVRAMCHRPHandler::unserializeVariables(void)
494 {
495 IOReturn ret = kIOReturnSuccess;
496 uint32_t cnt, cntStart;
497 const uint8_t *propName, *propData;
498 uint32_t propNameLength, propDataLength, regionIndex;
499 OSSharedPtr<const OSSymbol> propSymbol;
500 OSSharedPtr<OSObject> propObject;
501 NVRAMRegionInfo *currentRegion;
502 NVRAMRegionInfo variableRegions[] = { { kIONVRAMPartitionCommon, _commonPartitionOffset, _commonPartitionSize},
503 { kIONVRAMPartitionSystem, _systemPartitionOffset, _systemPartitionSize} };
504
505 DEBUG_INFO("...\n");
506
507 for (regionIndex = 0; regionIndex < ARRAY_SIZE(variableRegions); regionIndex++) {
508 currentRegion = &variableRegions[regionIndex];
509 const uint8_t * imageData = _nvramImage + currentRegion->offset;
510
511 if (currentRegion->size == 0) {
512 continue;
513 }
514
515 DEBUG_INFO("region = %d\n", currentRegion->type);
516 cnt = 0;
517 while (cnt < currentRegion->size) {
518 cntStart = cnt;
519 // Break if there is no name.
520 if (imageData[cnt] == '\0') {
521 break;
522 }
523
524 // Find the length of the name.
525 propName = imageData + cnt;
526 for (propNameLength = 0; (cnt + propNameLength) < currentRegion->size;
527 propNameLength++) {
528 if (imageData[cnt + propNameLength] == '=') {
529 break;
530 }
531 }
532
533 // Break if the name goes past the end of the partition.
534 if ((cnt + propNameLength) >= currentRegion->size) {
535 break;
536 }
537 cnt += propNameLength + 1;
538
539 propData = imageData + cnt;
540 for (propDataLength = 0; (cnt + propDataLength) < currentRegion->size;
541 propDataLength++) {
542 if (imageData[cnt + propDataLength] == '\0') {
543 break;
544 }
545 }
546
547 // Break if the data goes past the end of the partition.
548 if ((cnt + propDataLength) >= currentRegion->size) {
549 break;
550 }
551 cnt += propDataLength + 1;
552
553 if (convertPropToObject(propName, propNameLength, propData, propDataLength, propSymbol, propObject)) {
554 OSSharedPtr<const OSSymbol> canonicalKey;
555 const char *varName = propSymbol.get()->getCStringNoCopy();
556 uint32_t variableLength = cnt - cntStart;
557
558 DEBUG_INFO("adding %s, variableLength=%#x,dataLength=%#x\n", varName, variableLength, propDataLength);
559
560 if (currentRegion->type == kIONVRAMPartitionCommon) {
561 canonicalKey = keyWithGuidAndCString(gAppleNVRAMGuid, varName);
562 } else if (currentRegion->type == kIONVRAMPartitionSystem) {
563 canonicalKey = keyWithGuidAndCString(gAppleSystemVariableGuid, varName);
564 }
565
566 DEBUG_INFO("adding %s, dataLength=%u\n", varName, propDataLength);
567 _varDict->setObject(canonicalKey.get(), propObject.get());
568 if (_provider->_diags) {
569 _provider->_diags->logVariable(currentRegion->type,
570 kIONVRAMOperationInit, varName,
571 (void *)(uintptr_t)(cnt - cntStart));
572 }
573
574 if (currentRegion->type == kIONVRAMPartitionSystem) {
575 _systemUsed += variableLength;
576 } else if (currentRegion->type == kIONVRAMPartitionCommon) {
577 _commonUsed += variableLength;
578 }
579 }
580 }
581 }
582
583 DEBUG_ALWAYS("_commonSize %#x, _systemSize %#x\n", _commonPartitionSize, _systemPartitionSize);
584
585 ret = handleEphDM();
586 verify_noerr_action(ret, panic("handleEphDM failed with ret=%08x", ret));
587
588 DEBUG_INFO("_commonUsed %#x, _systemUsed %#x\n", _commonUsed, _systemUsed);
589
590 if (_provider->_diags) {
591 OSSharedPtr<OSNumber> val = OSNumber::withNumber(getSystemUsed(), 32);
592 _provider->_diags->setProperty(kNVRAMSystemUsedKey, val.get());
593 DEBUG_INFO("%s=%u\n", kNVRAMSystemUsedKey, getSystemUsed());
594
595 val = OSNumber::withNumber(getCommonUsed(), 32);
596 _provider->_diags->setProperty(kNVRAMCommonUsedKey, val.get());
597 DEBUG_INFO("%s=%u\n", kNVRAMCommonUsedKey, getCommonUsed());
598 }
599
600 // Create the boot-args property if it is not in the dictionary.
601 if (_provider->getProperty(kIONVRAMBootArgsKey) == nullptr) {
602 propSymbol = OSSymbol::withCString(kIONVRAMBootArgsKey);
603 propObject = OSString::withCStringNoCopy("");
604
605 _provider->setProperty(propSymbol.get(), propObject.get());
606 }
607
608 _newData = true;
609
610 DEBUG_INFO("%s _varDict=%p\n", __FUNCTION__, _varDict ? _varDict.get() : nullptr);
611
612 return ret;
613 }
614
615 IOReturn
serializeVariables(void)616 IONVRAMCHRPHandler::serializeVariables(void)
617 {
618 IOReturn ret;
619 bool ok = false;
620 uint32_t length, maxLength, regionIndex;
621 uint8_t *buffer, *tmpBuffer;
622 const OSSymbol *tmpSymbol;
623 OSObject *tmpObject;
624 OSSharedPtr<OSCollectionIterator> iter;
625 OSSharedPtr<OSNumber> generation;
626 uint8_t *nvramImage;
627 NVRAMRegionInfo *currentRegion;
628 NVRAMRegionInfo variableRegions[] = { { kIONVRAMPartitionCommon, _commonPartitionOffset, _commonPartitionSize},
629 { kIONVRAMPartitionSystem, _systemPartitionOffset, _systemPartitionSize} };
630 NVRAMLOCKASSERTHELD(_controllerLock);
631
632 require_action(_nvramController != nullptr, exit, (ret = kIOReturnNotReady, DEBUG_ERROR("No _nvramController\n")));
633 require_action(_newData == true, exit, (ret = kIOReturnSuccess, DEBUG_INFO("No _newData to sync\n")));
634 require_action(_bankSize != 0, exit, (ret = kIOReturnSuccess, DEBUG_INFO("No nvram size info\n")));
635 require_action(_nvramImage != nullptr, exit, (ret = kIOReturnSuccess, DEBUG_INFO("No nvram image info\n")));
636
637 nvramImage = IONewZeroData(uint8_t, _bankSize);
638 require_action(nvramImage != nullptr, exit, (ret = kIOReturnNoMemory, DEBUG_ERROR("Can't create NVRAM image copy\n")));
639
640 DEBUG_INFO("...\n");
641
642 bcopy(_nvramImage, nvramImage, _bankSize);
643
644 NVRAMREADLOCK(_variableLock);
645 for (regionIndex = 0; regionIndex < ARRAY_SIZE(variableRegions); regionIndex++) {
646 currentRegion = &variableRegions[regionIndex];
647
648 if (currentRegion->size == 0) {
649 continue;
650 }
651
652 DEBUG_INFO("region = %d\n", currentRegion->type);
653 buffer = tmpBuffer = nvramImage + currentRegion->offset;
654
655 bzero(buffer, currentRegion->size);
656
657 ok = true;
658 maxLength = currentRegion->size;
659
660 iter = OSCollectionIterator::withCollection(_varDict.get());
661 if (iter == nullptr) {
662 ok = false;
663 }
664
665 while (ok) {
666 uuid_t entryGuid;
667 const char *entryName;
668
669 tmpSymbol = OSDynamicCast(OSSymbol, iter->getNextObject());
670
671 if (tmpSymbol == nullptr) {
672 break;
673 }
674
675 DEBUG_INFO("_varDict entry %s\n", tmpSymbol->getCStringNoCopy());
676
677 parseVariableName(tmpSymbol, &entryGuid, &entryName);
678
679 if (getSystemPartitionActive()) {
680 if (currentRegion->type == kIONVRAMPartitionSystem) {
681 if (uuid_compare(entryGuid, gAppleSystemVariableGuid) != 0) {
682 DEBUG_INFO("Skipping %s because not system var\n", entryName);
683 continue;
684 }
685 } else if (currentRegion->type == kIONVRAMPartitionCommon) {
686 if (uuid_compare(entryGuid, gAppleSystemVariableGuid) == 0) {
687 DEBUG_INFO("Skipping %s for common region\n", entryName);
688 continue;
689 }
690 }
691 }
692
693 DEBUG_INFO("adding variable %s\n", entryName);
694
695 tmpObject = _varDict->getObject(tmpSymbol);
696
697 length = maxLength;
698 ok = convertObjectToProp(tmpBuffer, &length, entryName, tmpObject);
699 if (ok) {
700 tmpBuffer += length;
701 maxLength -= length;
702 }
703 }
704
705 if (!ok) {
706 ret = kIOReturnNoSpace;
707 IODeleteData(nvramImage, uint8_t, _bankSize);
708 break;
709 }
710
711 if (currentRegion->type == kIONVRAMPartitionSystem) {
712 _systemUsed = (uint32_t)(tmpBuffer - buffer);
713 } else if (currentRegion->type == kIONVRAMPartitionCommon) {
714 _commonUsed = (uint32_t)(tmpBuffer - buffer);
715 }
716 }
717 NVRAMRWUNLOCK(_variableLock);
718
719 DEBUG_INFO("ok=%d\n", ok);
720 require(ok, exit);
721
722 nvram_set_apple_header(nvramImage, _bankSize, ++_generation, _version);
723
724 _currentBank = (_currentBank + 1) % _bankCount;
725
726 ret = _nvramController->select(_currentBank);
727 DEBUG_IFERROR(ret, "_currentBank=%#x, select=%#x\n", _currentBank, ret);
728
729 ret = _nvramController->eraseBank();
730 DEBUG_IFERROR(ret, "eraseBank=%#x\n", ret);
731
732 ret = _nvramController->write(0, nvramImage, _bankSize);
733 DEBUG_IFERROR(ret, "write=%#x\n", ret);
734
735 _nvramController->sync();
736
737 if (_nvramImage) {
738 IODeleteData(_nvramImage, uint8_t, _bankSize);
739 }
740
741 _nvramImage = nvramImage;
742
743 _newData = false;
744
745 exit:
746 return ret;
747 }
748
749 IOReturn
setVariableInternal(const uuid_t varGuid,const char * variableName,OSObject * object)750 IONVRAMCHRPHandler::setVariableInternal(const uuid_t varGuid, const char *variableName, OSObject *object)
751 {
752 uint32_t newSize = 0;
753 uint32_t existingSize = 0;
754 bool remove = (object == nullptr);
755 OSObject *existing;
756 OSSharedPtr<const OSSymbol> canonicalKey;
757 bool systemVar;
758
759 // Anyone calling setVariableInternal should've already held the lock for write.
760 NVRAMRWLOCKASSERTEXCLUSIVE(_variableLock);
761
762 systemVar = (uuid_compare(varGuid, gAppleSystemVariableGuid) == 0);
763 canonicalKey = keyWithGuidAndCString(varGuid, variableName);
764
765 if ((existing = _varDict->getObject(canonicalKey.get()))) {
766 convertObjectToProp(nullptr, &existingSize, variableName, existing);
767 }
768
769 if (remove == false) {
770 convertObjectToProp(nullptr, &newSize, variableName, object);
771
772 DEBUG_INFO("setting %s, systemVar=%d, existingSize=%u, newSize=%u\n", canonicalKey.get()->getCStringNoCopy(), systemVar, existingSize, newSize);
773
774 if (systemVar) {
775 if ((newSize + _systemUsed - existingSize) > _systemPartitionSize) {
776 DEBUG_ERROR("No space left in system partition, need=%#x, _systemUsed=%#x, _systemPartitionSize=%#x\n",
777 newSize, _systemUsed, _systemPartitionSize);
778 return kIOReturnNoSpace;
779 } else {
780 _systemUsed = _systemUsed + newSize - existingSize;
781 }
782 } else {
783 if ((newSize + _commonUsed - existingSize) > _commonPartitionSize) {
784 DEBUG_ERROR("No space left in common partition, need=%#x, _commonUsed=%#x, _commonPartitionSize=%#x\n",
785 newSize, _commonUsed, _commonPartitionSize);
786 return kIOReturnNoSpace;
787 } else {
788 _commonUsed = _commonUsed + newSize - existingSize;
789 }
790 }
791
792 _varDict->setObject(canonicalKey.get(), object);
793
794 if (_provider->_diags) {
795 _provider->_diags->logVariable(getPartitionTypeForGUID(varGuid),
796 kIONVRAMOperationWrite, variableName,
797 (void *)(uintptr_t)newSize);
798 }
799 } else {
800 DEBUG_INFO("removing %s, systemVar=%d, existingSize=%u\n", canonicalKey.get()->getCStringNoCopy(), systemVar, existingSize);
801
802 if (systemVar) {
803 _systemUsed -= existingSize;
804 } else {
805 _commonUsed -= existingSize;
806 }
807
808 _varDict->removeObject(canonicalKey.get());
809
810 if (_provider->_diags) {
811 _provider->_diags->logVariable(getPartitionTypeForGUID(varGuid),
812 kIONVRAMOperationDelete, variableName,
813 nullptr);
814 }
815 }
816
817 if (_provider->_diags) {
818 OSSharedPtr<OSNumber> val = OSNumber::withNumber(getSystemUsed(), 32);
819 _provider->_diags->setProperty(kNVRAMSystemUsedKey, val.get());
820 DEBUG_INFO("%s=%u\n", kNVRAMSystemUsedKey, getSystemUsed());
821
822 val = OSNumber::withNumber(getCommonUsed(), 32);
823 _provider->_diags->setProperty(kNVRAMCommonUsedKey, val.get());
824 DEBUG_INFO("%s=%u\n", kNVRAMCommonUsedKey, getCommonUsed());
825 }
826
827 _newData = true;
828
829 return kIOReturnSuccess;
830 }
831
832 IOReturn
setVariable(const uuid_t varGuid,const char * variableName,OSObject * object)833 IONVRAMCHRPHandler::setVariable(const uuid_t varGuid, const char *variableName, OSObject *object)
834 {
835 uuid_t destGuid;
836 IOReturn ret = kIOReturnError;
837
838 if (getSystemPartitionActive()) {
839 // System region case, if they're using the GUID directly or it's on the system allow list
840 // force it to use the System GUID
841 if ((uuid_compare(varGuid, gAppleSystemVariableGuid) == 0) || variableInAllowList(variableName)) {
842 uuid_copy(destGuid, gAppleSystemVariableGuid);
843 } else {
844 uuid_copy(destGuid, varGuid);
845 }
846 } else {
847 // No system region, store System GUID as Common GUID
848 if ((uuid_compare(varGuid, gAppleSystemVariableGuid) == 0) || variableInAllowList(variableName)) {
849 uuid_copy(destGuid, gAppleNVRAMGuid);
850 } else {
851 uuid_copy(destGuid, varGuid);
852 }
853 }
854 NVRAMWRITELOCK(_variableLock);
855 ret = setVariableInternal(destGuid, variableName, object);
856 NVRAMRWUNLOCK(_variableLock);
857
858 return ret;
859 }
860
861 uint32_t
findCurrentBank(uint32_t * gen)862 IONVRAMCHRPHandler::findCurrentBank(uint32_t *gen)
863 {
864 struct apple_nvram_header storeHeader;
865 uint32_t maxGen = 0;
866 uint32_t currentBank = 0;
867
868 NVRAMLOCKASSERTHELD(_controllerLock);
869
870 for (unsigned int i = 0; i < _bankCount; i++) {
871 NVRAMVersion bankVer;
872 uint32_t bankGen = 0;
873
874 _nvramController->select(i);
875 _nvramController->read(0, (uint8_t *)&storeHeader, sizeof(storeHeader));
876 bankVer = validateNVRAMVersion((uint8_t *)&storeHeader, sizeof(storeHeader), &bankGen);
877
878 if ((bankVer != kNVRAMVersionUnknown) && (bankGen >= maxGen)) {
879 currentBank = i;
880 maxGen = bankGen;
881 }
882 }
883
884 DEBUG_ALWAYS("currentBank=%#x, gen=%#x\n", currentBank, maxGen);
885
886 *gen = maxGen;
887 return currentBank;
888 }
889
890 bool
setController(IONVRAMController * controller)891 IONVRAMCHRPHandler::setController(IONVRAMController *controller)
892 {
893 IOReturn ret;
894
895 NVRAMLOCK(_controllerLock);
896
897 if (_nvramController == NULL) {
898 _nvramController = controller;
899 }
900
901 DEBUG_INFO("Controller name: %s\n", _nvramController->getName());
902
903 ret = reloadInternal();
904 if (ret != kIOReturnSuccess) {
905 DEBUG_ERROR("reloadInternal failed, ret=0x%08x\n", ret);
906 }
907
908 NVRAMUNLOCK(_controllerLock);
909
910 return true;
911 }
912
913 IOReturn
sync(void)914 IONVRAMCHRPHandler::sync(void)
915 {
916 IOReturn ret;
917
918 NVRAMLOCK(_controllerLock);
919
920 if (_reload) {
921 ret = reloadInternal();
922 require_noerr_action(ret, exit, DEBUG_ERROR("Reload failed, ret=%#x", ret));
923
924 _reload = false;
925 }
926
927 ret = serializeVariables();
928 require_noerr_action(ret, exit, DEBUG_ERROR("serializeVariables failed, ret=%#x", ret));
929
930 exit:
931 NVRAMUNLOCK(_controllerLock);
932 return ret;
933 }
934
935 uint32_t
getGeneration(void) const936 IONVRAMCHRPHandler::getGeneration(void) const
937 {
938 return _generation;
939 }
940
941 uint32_t
getVersion(void) const942 IONVRAMCHRPHandler::getVersion(void) const
943 {
944 return _version;
945 }
946
947 uint32_t
getSystemUsed(void) const948 IONVRAMCHRPHandler::getSystemUsed(void) const
949 {
950 return _systemUsed;
951 }
952
953 uint32_t
getCommonUsed(void) const954 IONVRAMCHRPHandler::getCommonUsed(void) const
955 {
956 return _commonUsed;
957 }
958
959 bool
getSystemPartitionActive(void) const960 IONVRAMCHRPHandler::getSystemPartitionActive(void) const
961 {
962 return _systemPartitionSize != 0;
963 }
964
965 OSSharedPtr<OSData>
unescapeBytesToData(const uint8_t * bytes,uint32_t length)966 IONVRAMCHRPHandler::unescapeBytesToData(const uint8_t *bytes, uint32_t length)
967 {
968 OSSharedPtr<OSData> data;
969 uint32_t totalLength = 0;
970 uint32_t offset, offset2;
971 uint8_t byte;
972 bool ok;
973
974 // Calculate the actual length of the data.
975 ok = true;
976 totalLength = 0;
977 for (offset = 0; offset < length;) {
978 byte = bytes[offset++];
979 if (byte == 0xFF) {
980 byte = bytes[offset++];
981 if (byte == 0x00) {
982 ok = false;
983 break;
984 }
985 offset2 = byte & 0x7F;
986 } else {
987 offset2 = 1;
988 }
989 totalLength += offset2;
990 }
991
992 if (ok) {
993 // Create an empty OSData of the correct size.
994 data = OSData::withCapacity(totalLength);
995 if (data != nullptr) {
996 for (offset = 0; offset < length;) {
997 byte = bytes[offset++];
998 if (byte == 0xFF) {
999 byte = bytes[offset++];
1000 offset2 = byte & 0x7F;
1001 byte = (byte & 0x80) ? 0xFF : 0x00;
1002 } else {
1003 offset2 = 1;
1004 }
1005 data->appendByte(byte, offset2);
1006 }
1007 }
1008 }
1009
1010 return data;
1011 }
1012
1013 OSSharedPtr<OSData>
escapeDataToData(OSData * value)1014 IONVRAMCHRPHandler::escapeDataToData(OSData * value)
1015 {
1016 OSSharedPtr<OSData> result;
1017 OSBoundedPtr<const uint8_t> startPtr;
1018 const uint8_t *endPtr;
1019 const uint8_t *valueBytesPtr;
1020 OSBoundedPtr<const uint8_t> wherePtr;
1021 uint8_t byte;
1022 bool ok = true;
1023
1024 valueBytesPtr = (const uint8_t *) value->getBytesNoCopy();
1025 endPtr = valueBytesPtr + value->getLength();
1026 wherePtr = OSBoundedPtr<const uint8_t>(valueBytesPtr, valueBytesPtr, endPtr);
1027
1028 result = OSData::withCapacity((unsigned int)(endPtr - wherePtr));
1029 if (!result) {
1030 return result;
1031 }
1032
1033 while (wherePtr < endPtr) {
1034 startPtr = wherePtr;
1035 byte = *wherePtr++;
1036 if ((byte == 0x00) || (byte == 0xFF)) {
1037 for (;
1038 ((wherePtr - startPtr) < 0x7F) && (wherePtr < endPtr) && (byte == *wherePtr);
1039 wherePtr++) {
1040 }
1041 ok &= result->appendByte(0xff, 1);
1042 byte = (byte & 0x80) | ((uint8_t)(wherePtr - startPtr));
1043 }
1044 ok &= result->appendByte(byte, 1);
1045 }
1046 ok &= result->appendByte(0, 1);
1047
1048 if (!ok) {
1049 result.reset();
1050 }
1051
1052 return result;
1053 }
1054
1055 bool
convertPropToObject(const uint8_t * propName,uint32_t propNameLength,const uint8_t * propData,uint32_t propDataLength,const OSSymbol ** propSymbol,OSObject ** propObject)1056 IONVRAMCHRPHandler::convertPropToObject(const uint8_t *propName, uint32_t propNameLength,
1057 const uint8_t *propData, uint32_t propDataLength,
1058 const OSSymbol **propSymbol,
1059 OSObject **propObject)
1060 {
1061 OSSharedPtr<const OSString> delimitedName;
1062 OSSharedPtr<const OSSymbol> tmpSymbol;
1063 OSSharedPtr<OSNumber> tmpNumber;
1064 OSSharedPtr<OSString> tmpString;
1065 OSSharedPtr<OSObject> tmpObject = nullptr;
1066
1067 delimitedName = OSString::withCString((const char *)propName, propNameLength);
1068 tmpSymbol = OSSymbol::withString(delimitedName.get());
1069
1070 if (tmpSymbol == nullptr) {
1071 return false;
1072 }
1073
1074 switch (getVariableType(tmpSymbol.get())) {
1075 case kOFVariableTypeBoolean:
1076 if (!strncmp("true", (const char *)propData, propDataLength)) {
1077 tmpObject.reset(kOSBooleanTrue, OSRetain);
1078 } else if (!strncmp("false", (const char *)propData, propDataLength)) {
1079 tmpObject.reset(kOSBooleanFalse, OSRetain);
1080 }
1081 break;
1082
1083 case kOFVariableTypeNumber:
1084 tmpNumber = OSNumber::withNumber(strtol((const char *)propData, nullptr, 0), 32);
1085 if (tmpNumber != nullptr) {
1086 tmpObject = tmpNumber;
1087 }
1088 break;
1089
1090 case kOFVariableTypeString:
1091 tmpString = OSString::withCString((const char *)propData, propDataLength);
1092 if (tmpString != nullptr) {
1093 tmpObject = tmpString;
1094 }
1095 break;
1096
1097 case kOFVariableTypeData:
1098 tmpObject = unescapeBytesToData(propData, propDataLength);
1099 break;
1100
1101 default:
1102 break;
1103 }
1104
1105 if (tmpObject == nullptr) {
1106 tmpSymbol.reset();
1107 return false;
1108 }
1109
1110 *propSymbol = tmpSymbol.detach();
1111 *propObject = tmpObject.detach();
1112
1113 return true;
1114 }
1115
1116 bool
convertPropToObject(const uint8_t * propName,uint32_t propNameLength,const uint8_t * propData,uint32_t propDataLength,OSSharedPtr<const OSSymbol> & propSymbol,OSSharedPtr<OSObject> & propObject)1117 IONVRAMCHRPHandler::convertPropToObject(const uint8_t *propName, uint32_t propNameLength,
1118 const uint8_t *propData, uint32_t propDataLength,
1119 OSSharedPtr<const OSSymbol>& propSymbol,
1120 OSSharedPtr<OSObject>& propObject)
1121 {
1122 const OSSymbol* propSymbolRaw = nullptr;
1123 OSObject* propObjectRaw = nullptr;
1124
1125 bool ok = convertPropToObject(propName, propNameLength, propData, propDataLength,
1126 &propSymbolRaw, &propObjectRaw);
1127
1128 propSymbol.reset(propSymbolRaw, OSNoRetain);
1129 propObject.reset(propObjectRaw, OSNoRetain);
1130
1131 return ok;
1132 }
1133
1134 bool
convertObjectToProp(uint8_t * buffer,uint32_t * length,const OSSymbol * propSymbol,OSObject * propObject)1135 IONVRAMCHRPHandler::convertObjectToProp(uint8_t *buffer, uint32_t *length,
1136 const OSSymbol *propSymbol, OSObject *propObject)
1137 {
1138 return convertObjectToProp(buffer, length, propSymbol->getCStringNoCopy(), propObject);
1139 }
1140
1141 bool
convertObjectToProp(uint8_t * buffer,uint32_t * length,const char * propName,OSObject * propObject)1142 IONVRAMCHRPHandler::convertObjectToProp(uint8_t *buffer, uint32_t *length,
1143 const char *propName, OSObject *propObject)
1144 {
1145 uint32_t propNameLength, propDataLength, remaining, offset;
1146 IONVRAMVariableType propType;
1147 OSBoolean *tmpBoolean = nullptr;
1148 OSNumber *tmpNumber = nullptr;
1149 OSString *tmpString = nullptr;
1150 OSSharedPtr<OSData> tmpData;
1151
1152 propNameLength = (uint32_t)strlen(propName);
1153 propType = getVariableType(propName);
1154 offset = 0;
1155 remaining = 0;
1156
1157 // Get the size of the data.
1158 propDataLength = 0xFFFFFFFF;
1159 switch (propType) {
1160 case kOFVariableTypeBoolean:
1161 tmpBoolean = OSDynamicCast(OSBoolean, propObject);
1162 if (tmpBoolean != nullptr) {
1163 propDataLength = 5;
1164 }
1165 break;
1166
1167 case kOFVariableTypeNumber:
1168 tmpNumber = OSDynamicCast(OSNumber, propObject);
1169 if (tmpNumber != nullptr) {
1170 propDataLength = 10;
1171 }
1172 break;
1173
1174 case kOFVariableTypeString:
1175 tmpString = OSDynamicCast(OSString, propObject);
1176 if (tmpString != nullptr) {
1177 propDataLength = tmpString->getLength();
1178 }
1179 break;
1180
1181 case kOFVariableTypeData:
1182 tmpData.reset(OSDynamicCast(OSData, propObject), OSNoRetain);
1183 if (tmpData != nullptr) {
1184 tmpData = escapeDataToData(tmpData.detach());
1185 // escapeDataToData() adds the NULL byte to the data
1186 // subtract 1 here to keep offset consistent with the other cases
1187 propDataLength = tmpData->getLength() - 1;
1188 }
1189 break;
1190
1191 default:
1192 break;
1193 }
1194
1195 // Make sure the propertySize is known and will fit.
1196 if (propDataLength == 0xFFFFFFFF) {
1197 return false;
1198 }
1199
1200 if (buffer) {
1201 // name + '=' + data + '\0'
1202 if ((propNameLength + propDataLength + 2) > *length) {
1203 return false;
1204 }
1205
1206 remaining = *length;
1207 }
1208
1209 *length = 0;
1210
1211 // Copy the property name equal sign.
1212 offset += snprintf((char *)buffer, remaining, "%s=", propName);
1213 if (buffer) {
1214 if (remaining > offset) {
1215 buffer += offset;
1216 remaining = remaining - offset;
1217 } else {
1218 return false;
1219 }
1220 }
1221
1222 switch (propType) {
1223 case kOFVariableTypeBoolean:
1224 if (tmpBoolean->getValue()) {
1225 offset += strlcpy((char *)buffer, "true", remaining);
1226 } else {
1227 offset += strlcpy((char *)buffer, "false", remaining);
1228 }
1229 break;
1230
1231 case kOFVariableTypeNumber:
1232 {
1233 uint32_t tmpValue = tmpNumber->unsigned32BitValue();
1234 if (tmpValue == 0xFFFFFFFF) {
1235 offset += strlcpy((char *)buffer, "-1", remaining);
1236 } else if (tmpValue < 1000) {
1237 offset += snprintf((char *)buffer, remaining, "%d", (uint32_t)tmpValue);
1238 } else {
1239 offset += snprintf((char *)buffer, remaining, "%#x", (uint32_t)tmpValue);
1240 }
1241 }
1242 break;
1243
1244 case kOFVariableTypeString:
1245 offset += strlcpy((char *)buffer, tmpString->getCStringNoCopy(), remaining);
1246 break;
1247
1248 case kOFVariableTypeData:
1249 if (buffer) {
1250 bcopy(tmpData->getBytesNoCopy(), buffer, propDataLength);
1251 }
1252 tmpData.reset();
1253 offset += propDataLength;
1254 break;
1255
1256 default:
1257 break;
1258 }
1259
1260 *length = offset + 1;
1261
1262 return true;
1263 }
1264
1265 IOReturn
getVarDict(OSSharedPtr<OSDictionary> & varDictCopy)1266 IONVRAMCHRPHandler::getVarDict(OSSharedPtr<OSDictionary> &varDictCopy)
1267 {
1268 IOReturn ret = kIOReturnNotFound;
1269
1270 NVRAMREADLOCK(_variableLock);
1271 if (_varDict) {
1272 varDictCopy = OSDictionary::withDictionary(_varDict.get());
1273 if (varDictCopy) {
1274 if (OSDictionary::withCapacity(varDictCopy->getCount()) != nullptr) {
1275 ret = kIOReturnSuccess;
1276 }
1277 }
1278 }
1279 NVRAMRWUNLOCK(_variableLock);
1280
1281 return ret;
1282 }
1283