]> git.saurik.com Git - apple/xnu.git/blob - iokit/Kernel/IONVRAM.cpp
xnu-4903.270.47.tar.gz
[apple/xnu.git] / iokit / Kernel / IONVRAM.cpp
1 /*
2 * Copyright (c) 1998-2006 Apple Computer, Inc. All rights reserved.
3 * Copyright (c) 2007-2012 Apple Inc. All rights reserved.
4 *
5 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 *
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. The rights granted to you under the License
11 * may not be used to create, or enable the creation or redistribution of,
12 * unlawful or unlicensed copies of an Apple operating system, or to
13 * circumvent, violate, or enable the circumvention or violation of, any
14 * terms of an Apple operating system software license agreement.
15 *
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 *
19 * The Original Code and all software distributed under the License are
20 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
21 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
22 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
24 * Please see the License for the specific language governing rights and
25 * limitations under the License.
26 *
27 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
28 */
29
30 #include <IOKit/IOLib.h>
31 #include <IOKit/IONVRAM.h>
32 #include <IOKit/IOPlatformExpert.h>
33 #include <IOKit/IOUserClient.h>
34 #include <IOKit/IOKitKeys.h>
35 #include <IOKit/IOKitKeysPrivate.h>
36 #include <kern/debug.h>
37 #include <pexpert/pexpert.h>
38
39 #define super IOService
40
41 #define kIONVRAMPrivilege kIOClientPrivilegeAdministrator
42 //#define kIONVRAMPrivilege kIOClientPrivilegeLocalUser
43
44 OSDefineMetaClassAndStructors(IODTNVRAM, IOService);
45
46 bool
47 IODTNVRAM::init(IORegistryEntry *old, const IORegistryPlane *plane)
48 {
49 OSDictionary *dict;
50
51 if (!super::init(old, plane)) {
52 return false;
53 }
54
55 dict = OSDictionary::withCapacity(1);
56 if (dict == 0) {
57 return false;
58 }
59 setPropertyTable(dict);
60
61 _nvramImage = IONew(UInt8, kIODTNVRAMImageSize);
62 if (_nvramImage == 0) {
63 return false;
64 }
65
66 _nvramPartitionOffsets = OSDictionary::withCapacity(1);
67 if (_nvramPartitionOffsets == 0) {
68 return false;
69 }
70
71 _nvramPartitionLengths = OSDictionary::withCapacity(1);
72 if (_nvramPartitionLengths == 0) {
73 return false;
74 }
75
76 _registryPropertiesKey = OSSymbol::withCStringNoCopy("aapl,pci");
77 if (_registryPropertiesKey == 0) {
78 return false;
79 }
80
81 // <rdar://problem/9529235> race condition possible between
82 // IODTNVRAM and IONVRAMController (restore loses boot-args)
83 initProxyData();
84
85 return true;
86 }
87
88 void
89 IODTNVRAM::initProxyData(void)
90 {
91 IORegistryEntry *entry;
92 const char *key = "nvram-proxy-data";
93 OSObject *prop;
94 OSData *data;
95 const void *bytes;
96
97 entry = IORegistryEntry::fromPath("/chosen", gIODTPlane);
98 if (entry != 0) {
99 prop = entry->getProperty(key);
100 if (prop != 0) {
101 data = OSDynamicCast(OSData, prop);
102 if (data != 0) {
103 bytes = data->getBytesNoCopy();
104 if ((bytes != 0) && (data->getLength() <= kIODTNVRAMImageSize)) {
105 bcopy(bytes, _nvramImage, data->getLength());
106 initNVRAMImage();
107 _isProxied = true;
108 }
109 }
110 }
111 entry->removeProperty(key);
112 entry->release();
113 }
114 }
115
116 void
117 IODTNVRAM::registerNVRAMController(IONVRAMController *nvram)
118 {
119 if (_nvramController != 0) {
120 return;
121 }
122
123 _nvramController = nvram;
124
125 // <rdar://problem/9529235> race condition possible between
126 // IODTNVRAM and IONVRAMController (restore loses boot-args)
127 if (!_isProxied) {
128 _nvramController->read(0, _nvramImage, kIODTNVRAMImageSize);
129 initNVRAMImage();
130 } else {
131 IOLockLock(_ofLock);
132 (void) syncVariables();
133 IOLockUnlock(_ofLock);
134 }
135 }
136
137 void
138 IODTNVRAM::initNVRAMImage(void)
139 {
140 char partitionID[18];
141 UInt32 partitionOffset, partitionLength;
142 UInt32 freePartitionOffset, freePartitionSize;
143 UInt32 currentLength, currentOffset = 0;
144 OSNumber *partitionOffsetNumber, *partitionLengthNumber;
145
146 // Find the offsets for the OF, XPRAM, NameRegistry and PanicInfo partitions.
147 _ofPartitionOffset = 0xFFFFFFFF;
148 _piPartitionOffset = 0xFFFFFFFF;
149 freePartitionOffset = 0xFFFFFFFF;
150 freePartitionSize = 0;
151
152 // Look through the partitions to find the OF, MacOS partitions.
153 while (currentOffset < kIODTNVRAMImageSize) {
154 currentLength = ((UInt16 *)(_nvramImage + currentOffset))[1] * 16;
155
156 if (currentLength < 16) {
157 break;
158 }
159 partitionOffset = currentOffset + 16;
160 partitionLength = currentLength - 16;
161 if ((partitionOffset + partitionLength) > kIODTNVRAMImageSize) {
162 break;
163 }
164
165 if (strncmp((const char *)_nvramImage + currentOffset + 4,
166 kIODTNVRAMOFPartitionName, 12) == 0) {
167 _ofPartitionOffset = partitionOffset;
168 _ofPartitionSize = partitionLength;
169 } else if (strncmp((const char *)_nvramImage + currentOffset + 4,
170 kIODTNVRAMXPRAMPartitionName, 12) == 0) {
171 } else if (strncmp((const char *)_nvramImage + currentOffset + 4,
172 kIODTNVRAMPanicInfoPartitonName, 12) == 0) {
173 _piPartitionOffset = partitionOffset;
174 _piPartitionSize = partitionLength;
175 } else if (strncmp((const char *)_nvramImage + currentOffset + 4,
176 kIODTNVRAMFreePartitionName, 12) == 0) {
177 freePartitionOffset = currentOffset;
178 freePartitionSize = currentLength;
179 } else {
180 // Construct the partition ID from the signature and name.
181 snprintf(partitionID, sizeof(partitionID), "0x%02x,",
182 *(UInt8 *)(_nvramImage + currentOffset));
183 strncpy(partitionID + 5,
184 (const char *)(_nvramImage + currentOffset + 4), 12);
185 partitionID[17] = '\0';
186
187 partitionOffsetNumber = OSNumber::withNumber(partitionOffset, 32);
188 partitionLengthNumber = OSNumber::withNumber(partitionLength, 32);
189
190 // Save the partition offset and length
191 _nvramPartitionOffsets->setObject(partitionID, partitionOffsetNumber);
192 _nvramPartitionLengths->setObject(partitionID, partitionLengthNumber);
193
194 partitionOffsetNumber->release();
195 partitionLengthNumber->release();
196 }
197 currentOffset += currentLength;
198 }
199
200 if (_ofPartitionOffset != 0xFFFFFFFF) {
201 _ofImage = _nvramImage + _ofPartitionOffset;
202 }
203
204 if (_piPartitionOffset == 0xFFFFFFFF) {
205 if (freePartitionSize > 0x20) {
206 // Set the signature to 0xa1.
207 _nvramImage[freePartitionOffset] = 0xa1;
208 // Set the checksum to 0.
209 _nvramImage[freePartitionOffset + 1] = 0;
210 // Set the name for the Panic Info partition.
211 strncpy((char *)(_nvramImage + freePartitionOffset + 4),
212 kIODTNVRAMPanicInfoPartitonName, 12);
213
214 // Calculate the partition offset and size.
215 _piPartitionOffset = freePartitionOffset + 0x10;
216 _piPartitionSize = 0x800;
217 if (_piPartitionSize + 0x20 > freePartitionSize) {
218 _piPartitionSize = freePartitionSize - 0x20;
219 }
220
221 _piImage = _nvramImage + _piPartitionOffset;
222
223 // Zero the new partition.
224 bzero(_piImage, _piPartitionSize);
225
226 // Set the partition size.
227 *(UInt16 *)(_nvramImage + freePartitionOffset + 2) =
228 (_piPartitionSize / 0x10) + 1;
229
230 // Set the partition checksum.
231 _nvramImage[freePartitionOffset + 1] =
232 calculatePartitionChecksum(_nvramImage + freePartitionOffset);
233
234 // Calculate the free partition offset and size.
235 freePartitionOffset += _piPartitionSize + 0x10;
236 freePartitionSize -= _piPartitionSize + 0x10;
237
238 // Set the signature to 0x7f.
239 _nvramImage[freePartitionOffset] = 0x7f;
240 // Set the checksum to 0.
241 _nvramImage[freePartitionOffset + 1] = 0;
242 // Set the name for the free partition.
243 strncpy((char *)(_nvramImage + freePartitionOffset + 4),
244 kIODTNVRAMFreePartitionName, 12);
245 // Set the partition size.
246 *(UInt16 *)(_nvramImage + freePartitionOffset + 2) =
247 freePartitionSize / 0x10;
248 // Set the partition checksum.
249 _nvramImage[freePartitionOffset + 1] =
250 calculatePartitionChecksum(_nvramImage + freePartitionOffset);
251
252 if (_nvramController != 0) {
253 _nvramController->write(0, _nvramImage, kIODTNVRAMImageSize);
254 }
255 }
256 } else {
257 _piImage = _nvramImage + _piPartitionOffset;
258 }
259
260 _lastDeviceSync = 0;
261 _freshInterval = TRUE; // we will allow sync() even before the first 15 minutes have passed.
262
263 initOFVariables();
264 }
265
266 void
267 IODTNVRAM::syncInternal(bool rateLimit)
268 {
269 // Don't try to perform controller operations if none has been registered.
270 if (_nvramController == 0) {
271 return;
272 }
273
274 // Rate limit requests to sync. Drivers that need this rate limiting will
275 // shadow the data and only write to flash when they get a sync call
276 if (rateLimit && !safeToSync()) {
277 return;
278 }
279
280 _nvramController->sync();
281 }
282
283 void
284 IODTNVRAM::sync(void)
285 {
286 syncInternal(false);
287 }
288
289 bool
290 IODTNVRAM::serializeProperties(OSSerialize *s) const
291 {
292 bool result, hasPrivilege;
293 UInt32 variablePerm;
294 const OSSymbol *key;
295 OSDictionary *dict;
296 OSCollectionIterator *iter = 0;
297
298 // Verify permissions.
299 hasPrivilege = (kIOReturnSuccess == IOUserClient::clientHasPrivilege(current_task(), kIONVRAMPrivilege));
300
301 if (_ofDict == 0) {
302 /* No nvram. Return an empty dictionary. */
303 dict = OSDictionary::withCapacity(1);
304 if (dict == 0) {
305 return false;
306 }
307 } else {
308 IOLockLock(_ofLock);
309 dict = OSDictionary::withDictionary(_ofDict);
310 IOLockUnlock(_ofLock);
311 if (dict == 0) {
312 return false;
313 }
314
315 /* Copy properties with client privilege. */
316 iter = OSCollectionIterator::withCollection(dict);
317 if (iter == 0) {
318 dict->release();
319 return false;
320 }
321 while (1) {
322 key = OSDynamicCast(OSSymbol, iter->getNextObject());
323 if (key == 0) {
324 break;
325 }
326
327 variablePerm = getOFVariablePerm(key);
328 if ((hasPrivilege || (variablePerm != kOFVariablePermRootOnly)) &&
329 (!(variablePerm == kOFVariablePermKernelOnly && current_task() != kernel_task))) {
330 } else {
331 dict->removeObject(key);
332 iter->reset();
333 }
334 }
335 }
336
337 result = dict->serialize(s);
338
339 dict->release();
340 if (iter != 0) {
341 iter->release();
342 }
343
344 return result;
345 }
346
347 OSObject *
348 IODTNVRAM::copyProperty(const OSSymbol *aKey) const
349 {
350 IOReturn result;
351 UInt32 variablePerm;
352 OSObject *theObject;
353
354 if (_ofDict == 0) {
355 return 0;
356 }
357
358 // Verify permissions.
359 variablePerm = getOFVariablePerm(aKey);
360 result = IOUserClient::clientHasPrivilege(current_task(), kIONVRAMPrivilege);
361 if (result != kIOReturnSuccess) {
362 if (variablePerm == kOFVariablePermRootOnly) {
363 return 0;
364 }
365 }
366 if (variablePerm == kOFVariablePermKernelOnly && current_task() != kernel_task) {
367 return 0;
368 }
369
370 IOLockLock(_ofLock);
371 theObject = _ofDict->getObject(aKey);
372 if (theObject) {
373 theObject->retain();
374 }
375 IOLockUnlock(_ofLock);
376
377 return theObject;
378 }
379
380 OSObject *
381 IODTNVRAM::copyProperty(const char *aKey) const
382 {
383 const OSSymbol *keySymbol;
384 OSObject *theObject = 0;
385
386 keySymbol = OSSymbol::withCString(aKey);
387 if (keySymbol != 0) {
388 theObject = copyProperty(keySymbol);
389 keySymbol->release();
390 }
391
392 return theObject;
393 }
394
395 OSObject *
396 IODTNVRAM::getProperty(const OSSymbol *aKey) const
397 {
398 OSObject *theObject;
399
400 theObject = copyProperty(aKey);
401 if (theObject) {
402 theObject->release();
403 }
404
405 return theObject;
406 }
407
408 OSObject *
409 IODTNVRAM::getProperty(const char *aKey) const
410 {
411 OSObject *theObject;
412
413 theObject = copyProperty(aKey);
414 if (theObject) {
415 theObject->release();
416 }
417
418 return theObject;
419 }
420
421 bool
422 IODTNVRAM::setProperty(const OSSymbol *aKey, OSObject *anObject)
423 {
424 bool result;
425 UInt32 propType, propPerm;
426 OSString *tmpString = 0;
427 OSObject *propObject = 0, *oldObject;
428
429 if (_ofDict == 0) {
430 return false;
431 }
432
433 // Verify permissions.
434 propPerm = getOFVariablePerm(aKey);
435 if (IOUserClient::clientHasPrivilege(current_task(), kIONVRAMPrivilege) != kIOReturnSuccess) {
436 if (propPerm != kOFVariablePermUserWrite) {
437 return false;
438 }
439 }
440 if (propPerm == kOFVariablePermKernelOnly && current_task() != kernel_task) {
441 return 0;
442 }
443
444 // Don't allow change of 'aapl,panic-info'.
445 if (aKey->isEqualTo(kIODTNVRAMPanicInfoKey)) {
446 return false;
447 }
448
449 // Make sure the object is of the correct type.
450 propType = getOFVariableType(aKey);
451 switch (propType) {
452 case kOFVariableTypeBoolean:
453 propObject = OSDynamicCast(OSBoolean, anObject);
454 break;
455
456 case kOFVariableTypeNumber:
457 propObject = OSDynamicCast(OSNumber, anObject);
458 break;
459
460 case kOFVariableTypeString:
461 propObject = OSDynamicCast(OSString, anObject);
462 break;
463
464 case kOFVariableTypeData:
465 propObject = OSDynamicCast(OSData, anObject);
466 if (propObject == 0) {
467 tmpString = OSDynamicCast(OSString, anObject);
468 if (tmpString != 0) {
469 propObject = OSData::withBytes(tmpString->getCStringNoCopy(),
470 tmpString->getLength());
471 }
472 }
473 break;
474 }
475
476 if (propObject == 0) {
477 return false;
478 }
479
480 IOLockLock(_ofLock);
481
482 oldObject = _ofDict->getObject(aKey);
483 if (oldObject) {
484 oldObject->retain();
485 }
486 result = _ofDict->setObject(aKey, propObject);
487
488 if (result) {
489 if (syncVariables() != kIOReturnSuccess) {
490 if (oldObject) {
491 _ofDict->setObject(aKey, oldObject);
492 } else {
493 _ofDict->removeObject(aKey);
494 }
495 (void) syncVariables();
496 result = false;
497 }
498 }
499
500 if (oldObject) {
501 oldObject->release();
502 }
503 if (tmpString) {
504 propObject->release();
505 }
506
507 IOLockUnlock(_ofLock);
508
509 return result;
510 }
511
512 void
513 IODTNVRAM::removeProperty(const OSSymbol *aKey)
514 {
515 bool result;
516 UInt32 propPerm;
517
518 if (_ofDict == 0) {
519 return;
520 }
521
522 // Verify permissions.
523 propPerm = getOFVariablePerm(aKey);
524 result = IOUserClient::clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator);
525 if (result != kIOReturnSuccess) {
526 if (propPerm != kOFVariablePermUserWrite) {
527 return;
528 }
529 }
530 if (propPerm == kOFVariablePermKernelOnly && current_task() != kernel_task) {
531 return;
532 }
533
534 // Don't allow change of 'aapl,panic-info'.
535 if (aKey->isEqualTo(kIODTNVRAMPanicInfoKey)) {
536 return;
537 }
538
539 // If the object exists, remove it from the dictionary.
540
541 IOLockLock(_ofLock);
542 result = _ofDict->getObject(aKey) != 0;
543 if (result) {
544 _ofDict->removeObject(aKey);
545 }
546
547 if (result) {
548 (void) syncVariables();
549 }
550
551 IOLockUnlock(_ofLock);
552 }
553
554 IOReturn
555 IODTNVRAM::setProperties(OSObject *properties)
556 {
557 bool result = true;
558 OSObject *object;
559 const OSSymbol *key;
560 const OSString *tmpStr;
561 OSDictionary *dict;
562 OSCollectionIterator *iter;
563
564 dict = OSDynamicCast(OSDictionary, properties);
565 if (dict == 0) {
566 return kIOReturnBadArgument;
567 }
568
569 iter = OSCollectionIterator::withCollection(dict);
570 if (iter == 0) {
571 return kIOReturnBadArgument;
572 }
573
574 while (result) {
575 key = OSDynamicCast(OSSymbol, iter->getNextObject());
576 if (key == 0) {
577 break;
578 }
579
580 object = dict->getObject(key);
581 if (object == 0) {
582 continue;
583 }
584
585 if (key->isEqualTo(kIONVRAMDeletePropertyKey)) {
586 tmpStr = OSDynamicCast(OSString, object);
587 if (tmpStr != 0) {
588 key = OSSymbol::withString(tmpStr);
589 removeProperty(key);
590 key->release();
591 result = true;
592 } else {
593 result = false;
594 }
595 } else if (key->isEqualTo(kIONVRAMSyncNowPropertyKey) || key->isEqualTo(kIONVRAMForceSyncNowPropertyKey)) {
596 tmpStr = OSDynamicCast(OSString, object);
597 if (tmpStr != 0) {
598 result = true;
599
600 // We still want to throttle NVRAM commit rate for SyncNow. ForceSyncNow is provided as a really big hammer.
601
602 syncInternal(key->isEqualTo(kIONVRAMSyncNowPropertyKey));
603 } else {
604 result = false;
605 }
606 } else {
607 result = setProperty(key, object);
608 }
609 }
610
611 iter->release();
612
613 if (result) {
614 return kIOReturnSuccess;
615 } else {
616 return kIOReturnError;
617 }
618 }
619
620 IOReturn
621 IODTNVRAM::readXPRAM(IOByteCount offset, UInt8 *buffer,
622 IOByteCount length)
623 {
624 return kIOReturnUnsupported;
625 }
626
627 IOReturn
628 IODTNVRAM::writeXPRAM(IOByteCount offset, UInt8 *buffer,
629 IOByteCount length)
630 {
631 return kIOReturnUnsupported;
632 }
633
634 IOReturn
635 IODTNVRAM::readNVRAMProperty(IORegistryEntry *entry,
636 const OSSymbol **name,
637 OSData **value)
638 {
639 IOReturn err;
640
641 err = readNVRAMPropertyType1(entry, name, value);
642
643 return err;
644 }
645
646 IOReturn
647 IODTNVRAM::writeNVRAMProperty(IORegistryEntry *entry,
648 const OSSymbol *name,
649 OSData *value)
650 {
651 IOReturn err;
652
653 err = writeNVRAMPropertyType1(entry, name, value);
654
655 return err;
656 }
657
658 OSDictionary *
659 IODTNVRAM::getNVRAMPartitions(void)
660 {
661 return _nvramPartitionLengths;
662 }
663
664 IOReturn
665 IODTNVRAM::readNVRAMPartition(const OSSymbol *partitionID,
666 IOByteCount offset, UInt8 *buffer,
667 IOByteCount length)
668 {
669 OSNumber *partitionOffsetNumber, *partitionLengthNumber;
670 UInt32 partitionOffset, partitionLength, end;
671
672 partitionOffsetNumber =
673 (OSNumber *)_nvramPartitionOffsets->getObject(partitionID);
674 partitionLengthNumber =
675 (OSNumber *)_nvramPartitionLengths->getObject(partitionID);
676
677 if ((partitionOffsetNumber == 0) || (partitionLengthNumber == 0)) {
678 return kIOReturnNotFound;
679 }
680
681 partitionOffset = partitionOffsetNumber->unsigned32BitValue();
682 partitionLength = partitionLengthNumber->unsigned32BitValue();
683
684 if (os_add_overflow(offset, length, &end)) {
685 return kIOReturnBadArgument;
686 }
687 if ((buffer == 0) || (length == 0) || (end > partitionLength)) {
688 return kIOReturnBadArgument;
689 }
690
691 bcopy(_nvramImage + partitionOffset + offset, buffer, length);
692
693 return kIOReturnSuccess;
694 }
695
696 IOReturn
697 IODTNVRAM::writeNVRAMPartition(const OSSymbol *partitionID,
698 IOByteCount offset, UInt8 *buffer,
699 IOByteCount length)
700 {
701 OSNumber *partitionOffsetNumber, *partitionLengthNumber;
702 UInt32 partitionOffset, partitionLength, end;
703
704 partitionOffsetNumber =
705 (OSNumber *)_nvramPartitionOffsets->getObject(partitionID);
706 partitionLengthNumber =
707 (OSNumber *)_nvramPartitionLengths->getObject(partitionID);
708
709 if ((partitionOffsetNumber == 0) || (partitionLengthNumber == 0)) {
710 return kIOReturnNotFound;
711 }
712
713 partitionOffset = partitionOffsetNumber->unsigned32BitValue();
714 partitionLength = partitionLengthNumber->unsigned32BitValue();
715
716 if (os_add_overflow(offset, length, &end)) {
717 return kIOReturnBadArgument;
718 }
719 if ((buffer == 0) || (length == 0) || (end > partitionLength)) {
720 return kIOReturnBadArgument;
721 }
722
723 bcopy(buffer, _nvramImage + partitionOffset + offset, length);
724
725 if (_nvramController != 0) {
726 _nvramController->write(0, _nvramImage, kIODTNVRAMImageSize);
727 }
728
729 return kIOReturnSuccess;
730 }
731
732 IOByteCount
733 IODTNVRAM::savePanicInfo(UInt8 *buffer, IOByteCount length)
734 {
735 if ((_piImage == 0) || (length <= 0)) {
736 return 0;
737 }
738
739 if (length > (_piPartitionSize - 4)) {
740 length = _piPartitionSize - 4;
741 }
742
743 // Save the Panic Info.
744 bcopy(buffer, _piImage + 4, length);
745
746 // Save the Panic Info length.
747 *(UInt32 *)_piImage = length;
748
749 if (_nvramController != 0) {
750 _nvramController->write(0, _nvramImage, kIODTNVRAMImageSize);
751 }
752 /*
753 * This prevents OF variables from being committed if the system has panicked
754 */
755 _systemPaniced = true;
756 /* The call to sync() forces the NVRAM controller to write the panic info
757 * partition to NVRAM.
758 */
759 sync();
760
761 return length;
762 }
763
764 // Private methods
765
766 UInt8
767 IODTNVRAM::calculatePartitionChecksum(UInt8 *partitionHeader)
768 {
769 UInt8 cnt, isum, csum = 0;
770
771 for (cnt = 0; cnt < 0x10; cnt++) {
772 isum = csum + partitionHeader[cnt];
773 if (isum < csum) {
774 isum++;
775 }
776 csum = isum;
777 }
778
779 return csum;
780 }
781
782 IOReturn
783 IODTNVRAM::initOFVariables(void)
784 {
785 UInt32 cnt;
786 UInt8 *propName, *propData;
787 UInt32 propNameLength, propDataLength;
788 const OSSymbol *propSymbol;
789 OSObject *propObject;
790
791 if (_ofImage == 0) {
792 return kIOReturnNotReady;
793 }
794
795 _ofDict = OSDictionary::withCapacity(1);
796 _ofLock = IOLockAlloc();
797 if (!_ofDict || !_ofLock) {
798 return kIOReturnNoMemory;
799 }
800
801 cnt = 0;
802 while (cnt < _ofPartitionSize) {
803 // Break if there is no name.
804 if (_ofImage[cnt] == '\0') {
805 break;
806 }
807
808 // Find the length of the name.
809 propName = _ofImage + cnt;
810 for (propNameLength = 0; (cnt + propNameLength) < _ofPartitionSize;
811 propNameLength++) {
812 if (_ofImage[cnt + propNameLength] == '=') {
813 break;
814 }
815 }
816
817 // Break if the name goes past the end of the partition.
818 if ((cnt + propNameLength) >= _ofPartitionSize) {
819 break;
820 }
821 cnt += propNameLength + 1;
822
823 propData = _ofImage + cnt;
824 for (propDataLength = 0; (cnt + propDataLength) < _ofPartitionSize;
825 propDataLength++) {
826 if (_ofImage[cnt + propDataLength] == '\0') {
827 break;
828 }
829 }
830
831 // Break if the data goes past the end of the partition.
832 if ((cnt + propDataLength) >= _ofPartitionSize) {
833 break;
834 }
835 cnt += propDataLength + 1;
836
837 if (convertPropToObject(propName, propNameLength,
838 propData, propDataLength,
839 &propSymbol, &propObject)) {
840 _ofDict->setObject(propSymbol, propObject);
841 propSymbol->release();
842 propObject->release();
843 }
844 }
845
846 // Create the boot-args property if it is not in the dictionary.
847 if (_ofDict->getObject("boot-args") == 0) {
848 propObject = OSString::withCStringNoCopy("");
849 if (propObject != 0) {
850 _ofDict->setObject("boot-args", propObject);
851 propObject->release();
852 }
853 }
854
855 if (_piImage != 0) {
856 propDataLength = *(UInt32 *)_piImage;
857 if ((propDataLength != 0) && (propDataLength <= (_piPartitionSize - 4))) {
858 propObject = OSData::withBytes(_piImage + 4, propDataLength);
859 _ofDict->setObject(kIODTNVRAMPanicInfoKey, propObject);
860 propObject->release();
861
862 // Clear the length from _piImage and mark dirty.
863 *(UInt32 *)_piImage = 0;
864 if (_nvramController != 0) {
865 _nvramController->write(0, _nvramImage, kIODTNVRAMImageSize);
866 }
867 }
868 }
869
870 return kIOReturnSuccess;
871 }
872
873 IOReturn
874 IODTNVRAM::syncOFVariables(void)
875 {
876 return kIOReturnUnsupported;
877 }
878
879 IOReturn
880 IODTNVRAM::syncVariables(void)
881 {
882 bool ok;
883 UInt32 length, maxLength;
884 UInt8 *buffer, *tmpBuffer;
885 const OSSymbol *tmpSymbol;
886 OSObject *tmpObject;
887 OSCollectionIterator *iter;
888
889 IOLockAssert(_ofLock, kIOLockAssertOwned);
890
891 if ((_ofImage == 0) || (_ofDict == 0) || _systemPaniced) {
892 return kIOReturnNotReady;
893 }
894
895 buffer = tmpBuffer = IONew(UInt8, _ofPartitionSize);
896 if (buffer == 0) {
897 return kIOReturnNoMemory;
898 }
899 bzero(buffer, _ofPartitionSize);
900
901 ok = true;
902 maxLength = _ofPartitionSize;
903
904 iter = OSCollectionIterator::withCollection(_ofDict);
905 if (iter == 0) {
906 ok = false;
907 }
908
909 while (ok) {
910 tmpSymbol = OSDynamicCast(OSSymbol, iter->getNextObject());
911 if (tmpSymbol == 0) {
912 break;
913 }
914
915 // Don't save 'aapl,panic-info'.
916 if (tmpSymbol->isEqualTo(kIODTNVRAMPanicInfoKey)) {
917 continue;
918 }
919
920 tmpObject = _ofDict->getObject(tmpSymbol);
921
922 length = maxLength;
923 ok = convertObjectToProp(tmpBuffer, &length, tmpSymbol, tmpObject);
924 if (ok) {
925 tmpBuffer += length;
926 maxLength -= length;
927 }
928 }
929 iter->release();
930
931 if (ok) {
932 bcopy(buffer, _ofImage, _ofPartitionSize);
933 }
934
935 IODelete(buffer, UInt8, _ofPartitionSize);
936
937 if (!ok) {
938 return kIOReturnBadArgument;
939 }
940
941 if (_nvramController != 0) {
942 return _nvramController->write(0, _nvramImage, kIODTNVRAMImageSize);
943 }
944
945 return kIOReturnNotReady;
946 }
947
948 struct OFVariable {
949 const char *variableName;
950 UInt32 variableType;
951 UInt32 variablePerm;
952 SInt32 variableOffset;
953 };
954 typedef struct OFVariable OFVariable;
955
956 enum {
957 kOWVariableOffsetNumber = 8,
958 kOWVariableOffsetString = 17
959 };
960
961 static const
962 OFVariable gOFVariables[] = {
963 {"little-endian?", kOFVariableTypeBoolean, kOFVariablePermUserRead, 0},
964 {"real-mode?", kOFVariableTypeBoolean, kOFVariablePermUserRead, 1},
965 {"auto-boot?", kOFVariableTypeBoolean, kOFVariablePermUserRead, 2},
966 {"diag-switch?", kOFVariableTypeBoolean, kOFVariablePermUserRead, 3},
967 {"fcode-debug?", kOFVariableTypeBoolean, kOFVariablePermUserRead, 4},
968 {"oem-banner?", kOFVariableTypeBoolean, kOFVariablePermUserRead, 5},
969 {"oem-logo?", kOFVariableTypeBoolean, kOFVariablePermUserRead, 6},
970 {"use-nvramrc?", kOFVariableTypeBoolean, kOFVariablePermUserRead, 7},
971 {"use-generic?", kOFVariableTypeBoolean, kOFVariablePermUserRead, -1},
972 {"default-mac-address?", kOFVariableTypeBoolean, kOFVariablePermUserRead, -1},
973 {"real-base", kOFVariableTypeNumber, kOFVariablePermUserRead, 8},
974 {"real-size", kOFVariableTypeNumber, kOFVariablePermUserRead, 9},
975 {"virt-base", kOFVariableTypeNumber, kOFVariablePermUserRead, 10},
976 {"virt-size", kOFVariableTypeNumber, kOFVariablePermUserRead, 11},
977 {"load-base", kOFVariableTypeNumber, kOFVariablePermUserRead, 12},
978 {"pci-probe-list", kOFVariableTypeNumber, kOFVariablePermUserRead, 13},
979 {"pci-probe-mask", kOFVariableTypeNumber, kOFVariablePermUserRead, -1},
980 {"screen-#columns", kOFVariableTypeNumber, kOFVariablePermUserRead, 14},
981 {"screen-#rows", kOFVariableTypeNumber, kOFVariablePermUserRead, 15},
982 {"selftest-#megs", kOFVariableTypeNumber, kOFVariablePermUserRead, 16},
983 {"boot-device", kOFVariableTypeString, kOFVariablePermUserRead, 17},
984 {"boot-file", kOFVariableTypeString, kOFVariablePermUserRead, 18},
985 {"boot-screen", kOFVariableTypeString, kOFVariablePermUserRead, -1},
986 {"console-screen", kOFVariableTypeString, kOFVariablePermUserRead, -1},
987 {"diag-device", kOFVariableTypeString, kOFVariablePermUserRead, 19},
988 {"diag-file", kOFVariableTypeString, kOFVariablePermUserRead, 20},
989 {"input-device", kOFVariableTypeString, kOFVariablePermUserRead, 21},
990 {"output-device", kOFVariableTypeString, kOFVariablePermUserRead, 22},
991 {"input-device-1", kOFVariableTypeString, kOFVariablePermUserRead, -1},
992 {"output-device-1", kOFVariableTypeString, kOFVariablePermUserRead, -1},
993 {"mouse-device", kOFVariableTypeString, kOFVariablePermUserRead, -1},
994 {"oem-banner", kOFVariableTypeString, kOFVariablePermUserRead, 23},
995 {"oem-logo", kOFVariableTypeString, kOFVariablePermUserRead, 24},
996 {"nvramrc", kOFVariableTypeString, kOFVariablePermUserRead, 25},
997 {"boot-command", kOFVariableTypeString, kOFVariablePermUserRead, 26},
998 {"default-client-ip", kOFVariableTypeString, kOFVariablePermUserRead, -1},
999 {"default-server-ip", kOFVariableTypeString, kOFVariablePermUserRead, -1},
1000 {"default-gateway-ip", kOFVariableTypeString, kOFVariablePermUserRead, -1},
1001 {"default-subnet-mask", kOFVariableTypeString, kOFVariablePermUserRead, -1},
1002 {"default-router-ip", kOFVariableTypeString, kOFVariablePermUserRead, -1},
1003 {"boot-script", kOFVariableTypeString, kOFVariablePermUserRead, -1},
1004 {"boot-args", kOFVariableTypeString, kOFVariablePermUserRead, -1},
1005 {"aapl,pci", kOFVariableTypeData, kOFVariablePermRootOnly, -1},
1006 {"security-mode", kOFVariableTypeString, kOFVariablePermUserRead, -1},
1007 {"security-password", kOFVariableTypeData, kOFVariablePermRootOnly, -1},
1008 {"boot-image", kOFVariableTypeData, kOFVariablePermUserWrite, -1},
1009 {"com.apple.System.fp-state", kOFVariableTypeData, kOFVariablePermKernelOnly, -1},
1010 #if CONFIG_EMBEDDED
1011 {"backlight-level", kOFVariableTypeData, kOFVariablePermUserWrite, -1},
1012 {"com.apple.System.sep.art", kOFVariableTypeData, kOFVariablePermKernelOnly, -1},
1013 {"com.apple.System.boot-nonce", kOFVariableTypeString, kOFVariablePermKernelOnly, -1},
1014 {"darkboot", kOFVariableTypeBoolean, kOFVariablePermUserWrite, -1},
1015 {"acc-mb-ld-lifetime", kOFVariableTypeNumber, kOFVariablePermKernelOnly, -1},
1016 {"acc-cm-override-charger-count", kOFVariableTypeNumber, kOFVariablePermKernelOnly, -1},
1017 {"acc-cm-override-count", kOFVariableTypeNumber, kOFVariablePermKernelOnly, -1},
1018 {"enter-tdm-mode", kOFVariableTypeBoolean, kOFVariablePermUserWrite, -1},
1019 {"nonce-seeds", kOFVariableTypeData, kOFVariablePermKernelOnly, -1},
1020 #endif
1021 {0, kOFVariableTypeData, kOFVariablePermUserRead, -1}
1022 };
1023
1024 UInt32
1025 IODTNVRAM::getOFVariableType(const OSSymbol *propSymbol) const
1026 {
1027 const OFVariable *ofVar;
1028
1029 ofVar = gOFVariables;
1030 while (1) {
1031 if ((ofVar->variableName == 0) ||
1032 propSymbol->isEqualTo(ofVar->variableName)) {
1033 break;
1034 }
1035 ofVar++;
1036 }
1037
1038 return ofVar->variableType;
1039 }
1040
1041 UInt32
1042 IODTNVRAM::getOFVariablePerm(const OSSymbol *propSymbol) const
1043 {
1044 const OFVariable *ofVar;
1045
1046 ofVar = gOFVariables;
1047 while (1) {
1048 if ((ofVar->variableName == 0) ||
1049 propSymbol->isEqualTo(ofVar->variableName)) {
1050 break;
1051 }
1052 ofVar++;
1053 }
1054
1055 return ofVar->variablePerm;
1056 }
1057
1058 bool
1059 IODTNVRAM::getOWVariableInfo(UInt32 variableNumber, const OSSymbol **propSymbol,
1060 UInt32 *propType, UInt32 *propOffset)
1061 {
1062 const OFVariable *ofVar;
1063
1064 ofVar = gOFVariables;
1065 while (1) {
1066 if (ofVar->variableName == 0) {
1067 return false;
1068 }
1069
1070 if (ofVar->variableOffset == (SInt32) variableNumber) {
1071 break;
1072 }
1073
1074 ofVar++;
1075 }
1076
1077 *propSymbol = OSSymbol::withCStringNoCopy(ofVar->variableName);
1078 *propType = ofVar->variableType;
1079
1080 switch (*propType) {
1081 case kOFVariableTypeBoolean:
1082 *propOffset = 1 << (31 - variableNumber);
1083 break;
1084
1085 case kOFVariableTypeNumber:
1086 *propOffset = variableNumber - kOWVariableOffsetNumber;
1087 break;
1088
1089 case kOFVariableTypeString:
1090 *propOffset = variableNumber - kOWVariableOffsetString;
1091 break;
1092 }
1093
1094 return true;
1095 }
1096
1097 bool
1098 IODTNVRAM::convertPropToObject(UInt8 *propName, UInt32 propNameLength,
1099 UInt8 *propData, UInt32 propDataLength,
1100 const OSSymbol **propSymbol,
1101 OSObject **propObject)
1102 {
1103 UInt32 propType;
1104 const OSSymbol *tmpSymbol;
1105 OSObject *tmpObject;
1106 OSNumber *tmpNumber;
1107 OSString *tmpString;
1108
1109 // Create the symbol.
1110 propName[propNameLength] = '\0';
1111 tmpSymbol = OSSymbol::withCString((const char *)propName);
1112 propName[propNameLength] = '=';
1113 if (tmpSymbol == 0) {
1114 return false;
1115 }
1116
1117 propType = getOFVariableType(tmpSymbol);
1118
1119 // Create the object.
1120 tmpObject = 0;
1121 switch (propType) {
1122 case kOFVariableTypeBoolean:
1123 if (!strncmp("true", (const char *)propData, propDataLength)) {
1124 tmpObject = kOSBooleanTrue;
1125 } else if (!strncmp("false", (const char *)propData, propDataLength)) {
1126 tmpObject = kOSBooleanFalse;
1127 }
1128 break;
1129
1130 case kOFVariableTypeNumber:
1131 tmpNumber = OSNumber::withNumber(strtol((const char *)propData, 0, 0), 32);
1132 if (tmpNumber != 0) {
1133 tmpObject = tmpNumber;
1134 }
1135 break;
1136
1137 case kOFVariableTypeString:
1138 tmpString = OSString::withCString((const char *)propData);
1139 if (tmpString != 0) {
1140 tmpObject = tmpString;
1141 }
1142 break;
1143
1144 case kOFVariableTypeData:
1145 tmpObject = unescapeBytesToData(propData, propDataLength);
1146 break;
1147 }
1148
1149 if (tmpObject == 0) {
1150 tmpSymbol->release();
1151 return false;
1152 }
1153
1154 *propSymbol = tmpSymbol;
1155 *propObject = tmpObject;
1156
1157 return true;
1158 }
1159
1160 bool
1161 IODTNVRAM::convertObjectToProp(UInt8 *buffer, UInt32 *length,
1162 const OSSymbol *propSymbol, OSObject *propObject)
1163 {
1164 const UInt8 *propName;
1165 UInt32 propNameLength, propDataLength, remaining;
1166 UInt32 propType, tmpValue;
1167 OSBoolean *tmpBoolean = 0;
1168 OSNumber *tmpNumber = 0;
1169 OSString *tmpString = 0;
1170 OSData *tmpData = 0;
1171
1172 propName = (const UInt8 *)propSymbol->getCStringNoCopy();
1173 propNameLength = propSymbol->getLength();
1174 propType = getOFVariableType(propSymbol);
1175
1176 // Get the size of the data.
1177 propDataLength = 0xFFFFFFFF;
1178 switch (propType) {
1179 case kOFVariableTypeBoolean:
1180 tmpBoolean = OSDynamicCast(OSBoolean, propObject);
1181 if (tmpBoolean != 0) {
1182 propDataLength = 5;
1183 }
1184 break;
1185
1186 case kOFVariableTypeNumber:
1187 tmpNumber = OSDynamicCast(OSNumber, propObject);
1188 if (tmpNumber != 0) {
1189 propDataLength = 10;
1190 }
1191 break;
1192
1193 case kOFVariableTypeString:
1194 tmpString = OSDynamicCast(OSString, propObject);
1195 if (tmpString != 0) {
1196 propDataLength = tmpString->getLength();
1197 }
1198 break;
1199
1200 case kOFVariableTypeData:
1201 tmpData = OSDynamicCast(OSData, propObject);
1202 if (tmpData != 0) {
1203 tmpData = escapeDataToData(tmpData);
1204 propDataLength = tmpData->getLength();
1205 }
1206 break;
1207 }
1208
1209 // Make sure the propertySize is known and will fit.
1210 if (propDataLength == 0xFFFFFFFF) {
1211 return false;
1212 }
1213 if ((propNameLength + propDataLength + 2) > *length) {
1214 return false;
1215 }
1216
1217 // Copy the property name equal sign.
1218 buffer += snprintf((char *)buffer, *length, "%s=", propName);
1219 remaining = *length - propNameLength - 1;
1220
1221 switch (propType) {
1222 case kOFVariableTypeBoolean:
1223 if (tmpBoolean->getValue()) {
1224 strlcpy((char *)buffer, "true", remaining);
1225 } else {
1226 strlcpy((char *)buffer, "false", remaining);
1227 }
1228 break;
1229
1230 case kOFVariableTypeNumber:
1231 tmpValue = tmpNumber->unsigned32BitValue();
1232 if (tmpValue == 0xFFFFFFFF) {
1233 strlcpy((char *)buffer, "-1", remaining);
1234 } else if (tmpValue < 1000) {
1235 snprintf((char *)buffer, remaining, "%d", (uint32_t)tmpValue);
1236 } else {
1237 snprintf((char *)buffer, remaining, "0x%x", (uint32_t)tmpValue);
1238 }
1239 break;
1240
1241 case kOFVariableTypeString:
1242 strlcpy((char *)buffer, tmpString->getCStringNoCopy(), remaining);
1243 break;
1244
1245 case kOFVariableTypeData:
1246 bcopy(tmpData->getBytesNoCopy(), buffer, propDataLength);
1247 tmpData->release();
1248 break;
1249 }
1250
1251 propDataLength = strlen((const char *)buffer);
1252
1253 *length = propNameLength + propDataLength + 2;
1254
1255 return true;
1256 }
1257
1258
1259 UInt16
1260 IODTNVRAM::generateOWChecksum(UInt8 *buffer)
1261 {
1262 UInt32 cnt, checksum = 0;
1263 UInt16 *tmpBuffer = (UInt16 *)buffer;
1264
1265 for (cnt = 0; cnt < _ofPartitionSize / 2; cnt++) {
1266 checksum += tmpBuffer[cnt];
1267 }
1268
1269 return checksum % 0x0000FFFF;
1270 }
1271
1272 bool
1273 IODTNVRAM::validateOWChecksum(UInt8 *buffer)
1274 {
1275 UInt32 cnt, checksum, sum = 0;
1276 UInt16 *tmpBuffer = (UInt16 *)buffer;
1277
1278 for (cnt = 0; cnt < _ofPartitionSize / 2; cnt++) {
1279 sum += tmpBuffer[cnt];
1280 }
1281
1282 checksum = (sum >> 16) + (sum & 0x0000FFFF);
1283 if (checksum == 0x10000) {
1284 checksum--;
1285 }
1286 checksum = (checksum ^ 0x0000FFFF) & 0x0000FFFF;
1287
1288 return checksum == 0;
1289 }
1290
1291 void
1292 IODTNVRAM::updateOWBootArgs(const OSSymbol *key, OSObject *value)
1293 {
1294 bool wasBootArgs, bootr = false;
1295 UInt32 cnt;
1296 OSString *tmpString, *bootCommand, *bootArgs = 0;
1297 const UInt8 *bootCommandData, *bootArgsData;
1298 UInt8 *tmpData;
1299 UInt32 bootCommandDataLength, bootArgsDataLength, tmpDataLength;
1300
1301 tmpString = OSDynamicCast(OSString, value);
1302 if (tmpString == 0) {
1303 return;
1304 }
1305
1306 if (key->isEqualTo("boot-command")) {
1307 wasBootArgs = false;
1308 bootCommand = tmpString;
1309 } else if (key->isEqualTo("boot-args")) {
1310 wasBootArgs = true;
1311 bootArgs = tmpString;
1312 bootCommand = OSDynamicCast(OSString, _ofDict->getObject("boot-command"));
1313 if (bootCommand == 0) {
1314 return;
1315 }
1316 } else {
1317 return;
1318 }
1319
1320 bootCommandData = (const UInt8 *)bootCommand->getCStringNoCopy();
1321 bootCommandDataLength = bootCommand->getLength();
1322
1323 if (bootCommandData == 0) {
1324 return;
1325 }
1326
1327 for (cnt = 0; cnt < bootCommandDataLength; cnt++) {
1328 if ((bootCommandData[cnt] == 'b') &&
1329 !strncmp("bootr", (const char *)bootCommandData + cnt, 5)) {
1330 cnt += 5;
1331 while (bootCommandData[cnt] == ' ') {
1332 cnt++;
1333 }
1334 bootr = true;
1335 break;
1336 }
1337 }
1338 if (!bootr) {
1339 _ofDict->removeObject("boot-args");
1340 return;
1341 }
1342
1343 if (wasBootArgs) {
1344 bootArgsData = (const UInt8 *)bootArgs->getCStringNoCopy();
1345 bootArgsDataLength = bootArgs->getLength();
1346 if (bootArgsData == 0) {
1347 return;
1348 }
1349
1350 tmpDataLength = cnt + bootArgsDataLength;
1351 tmpData = IONew(UInt8, tmpDataLength + 1);
1352 if (tmpData == 0) {
1353 return;
1354 }
1355
1356 cnt -= strlcpy((char *)tmpData, (const char *)bootCommandData, cnt);
1357 strlcat((char *)tmpData, (const char *)bootArgsData, cnt);
1358
1359 bootCommand = OSString::withCString((const char *)tmpData);
1360 if (bootCommand != 0) {
1361 _ofDict->setObject("boot-command", bootCommand);
1362 bootCommand->release();
1363 }
1364
1365 IODelete(tmpData, UInt8, tmpDataLength + 1);
1366 } else {
1367 bootArgs = OSString::withCString((const char *)(bootCommandData + cnt));
1368 if (bootArgs != 0) {
1369 _ofDict->setObject("boot-args", bootArgs);
1370 bootArgs->release();
1371 }
1372 }
1373 }
1374
1375 bool
1376 IODTNVRAM::searchNVRAMProperty(IONVRAMDescriptor *hdr, UInt32 *where)
1377 {
1378 return false;
1379 }
1380
1381 IOReturn
1382 IODTNVRAM::readNVRAMPropertyType0(IORegistryEntry *entry,
1383 const OSSymbol **name,
1384 OSData **value)
1385 {
1386 return kIOReturnUnsupported;
1387 }
1388
1389
1390 IOReturn
1391 IODTNVRAM::writeNVRAMPropertyType0(IORegistryEntry *entry,
1392 const OSSymbol *name,
1393 OSData *value)
1394 {
1395 return kIOReturnUnsupported;
1396 }
1397
1398
1399 OSData *
1400 IODTNVRAM::unescapeBytesToData(const UInt8 *bytes, UInt32 length)
1401 {
1402 OSData *data = 0;
1403 UInt32 totalLength = 0;
1404 UInt32 cnt, cnt2;
1405 UInt8 byte;
1406 bool ok;
1407
1408 // Calculate the actual length of the data.
1409 ok = true;
1410 totalLength = 0;
1411 for (cnt = 0; cnt < length;) {
1412 byte = bytes[cnt++];
1413 if (byte == 0xFF) {
1414 byte = bytes[cnt++];
1415 if (byte == 0x00) {
1416 ok = false;
1417 break;
1418 }
1419 cnt2 = byte & 0x7F;
1420 } else {
1421 cnt2 = 1;
1422 }
1423 totalLength += cnt2;
1424 }
1425
1426 if (ok) {
1427 // Create an empty OSData of the correct size.
1428 data = OSData::withCapacity(totalLength);
1429 if (data != 0) {
1430 for (cnt = 0; cnt < length;) {
1431 byte = bytes[cnt++];
1432 if (byte == 0xFF) {
1433 byte = bytes[cnt++];
1434 cnt2 = byte & 0x7F;
1435 byte = (byte & 0x80) ? 0xFF : 0x00;
1436 } else {
1437 cnt2 = 1;
1438 }
1439 data->appendByte(byte, cnt2);
1440 }
1441 }
1442 }
1443
1444 return data;
1445 }
1446
1447 OSData *
1448 IODTNVRAM::escapeDataToData(OSData * value)
1449 {
1450 OSData * result;
1451 const UInt8 * startPtr;
1452 const UInt8 * endPtr;
1453 const UInt8 * wherePtr;
1454 UInt8 byte;
1455 bool ok = true;
1456
1457 wherePtr = (const UInt8 *) value->getBytesNoCopy();
1458 endPtr = wherePtr + value->getLength();
1459
1460 result = OSData::withCapacity(endPtr - wherePtr);
1461 if (!result) {
1462 return result;
1463 }
1464
1465 while (wherePtr < endPtr) {
1466 startPtr = wherePtr;
1467 byte = *wherePtr++;
1468 if ((byte == 0x00) || (byte == 0xFF)) {
1469 for (;
1470 ((wherePtr - startPtr) < 0x80) && (wherePtr < endPtr) && (byte == *wherePtr);
1471 wherePtr++) {
1472 }
1473 ok &= result->appendByte(0xff, 1);
1474 byte = (byte & 0x80) | (wherePtr - startPtr);
1475 }
1476 ok &= result->appendByte(byte, 1);
1477 }
1478 ok &= result->appendByte(0, 1);
1479
1480 if (!ok) {
1481 result->release();
1482 result = 0;
1483 }
1484
1485 return result;
1486 }
1487
1488 static bool
1489 IsApplePropertyName(const char * propName)
1490 {
1491 char c;
1492 while ((c = *propName++)) {
1493 if ((c >= 'A') && (c <= 'Z')) {
1494 break;
1495 }
1496 }
1497
1498 return c == 0;
1499 }
1500
1501 IOReturn
1502 IODTNVRAM::readNVRAMPropertyType1(IORegistryEntry *entry,
1503 const OSSymbol **name,
1504 OSData **value)
1505 {
1506 IOReturn err = kIOReturnNoResources;
1507 OSData *data;
1508 const UInt8 *startPtr;
1509 const UInt8 *endPtr;
1510 const UInt8 *wherePtr;
1511 const UInt8 *nvPath = 0;
1512 const char *nvName = 0;
1513 const char *resultName = 0;
1514 const UInt8 *resultValue = 0;
1515 UInt32 resultValueLen = 0;
1516 UInt8 byte;
1517
1518 if (_ofDict == 0) {
1519 return err;
1520 }
1521
1522 IOLockLock(_ofLock);
1523 data = OSDynamicCast(OSData, _ofDict->getObject(_registryPropertiesKey));
1524 IOLockUnlock(_ofLock);
1525
1526 if (data == 0) {
1527 return err;
1528 }
1529
1530 startPtr = (const UInt8 *) data->getBytesNoCopy();
1531 endPtr = startPtr + data->getLength();
1532
1533 wherePtr = startPtr;
1534 while (wherePtr < endPtr) {
1535 byte = *(wherePtr++);
1536 if (byte) {
1537 continue;
1538 }
1539
1540 if (nvPath == 0) {
1541 nvPath = startPtr;
1542 } else if (nvName == 0) {
1543 nvName = (const char *) startPtr;
1544 } else {
1545 IORegistryEntry * compareEntry = IORegistryEntry::fromPath((const char *) nvPath, gIODTPlane);
1546 if (compareEntry) {
1547 compareEntry->release();
1548 }
1549 if (entry == compareEntry) {
1550 bool appleProp = IsApplePropertyName(nvName);
1551 if (!appleProp || !resultName) {
1552 resultName = nvName;
1553 resultValue = startPtr;
1554 resultValueLen = wherePtr - startPtr - 1;
1555 }
1556 if (!appleProp) {
1557 break;
1558 }
1559 }
1560 nvPath = 0;
1561 nvName = 0;
1562 }
1563 startPtr = wherePtr;
1564 }
1565 if (resultName) {
1566 *name = OSSymbol::withCString(resultName);
1567 *value = unescapeBytesToData(resultValue, resultValueLen);
1568 if ((*name != 0) && (*value != 0)) {
1569 err = kIOReturnSuccess;
1570 } else {
1571 err = kIOReturnNoMemory;
1572 }
1573 }
1574 return err;
1575 }
1576
1577 IOReturn
1578 IODTNVRAM::writeNVRAMPropertyType1(IORegistryEntry *entry,
1579 const OSSymbol *propName,
1580 OSData *value)
1581 {
1582 OSData *oldData, *escapedData;
1583 OSData *data = 0;
1584 const UInt8 *startPtr;
1585 const UInt8 *propStart;
1586 const UInt8 *endPtr;
1587 const UInt8 *wherePtr;
1588 const UInt8 *nvPath = 0;
1589 const char *nvName = 0;
1590 const char * comp;
1591 const char * name;
1592 UInt8 byte;
1593 bool ok = true;
1594 bool settingAppleProp;
1595
1596 if (_ofDict == 0) {
1597 return kIOReturnNoResources;
1598 }
1599
1600 settingAppleProp = IsApplePropertyName(propName->getCStringNoCopy());
1601
1602 // copy over existing properties for other entries
1603
1604 IOLockLock(_ofLock);
1605
1606 oldData = OSDynamicCast(OSData, _ofDict->getObject(_registryPropertiesKey));
1607 if (oldData) {
1608 startPtr = (const UInt8 *) oldData->getBytesNoCopy();
1609 endPtr = startPtr + oldData->getLength();
1610
1611 propStart = startPtr;
1612 wherePtr = startPtr;
1613 while (wherePtr < endPtr) {
1614 byte = *(wherePtr++);
1615 if (byte) {
1616 continue;
1617 }
1618 if (nvPath == 0) {
1619 nvPath = startPtr;
1620 } else if (nvName == 0) {
1621 nvName = (const char *) startPtr;
1622 } else {
1623 IORegistryEntry * compareEntry = IORegistryEntry::fromPath((const char *) nvPath, gIODTPlane);
1624 if (compareEntry) {
1625 compareEntry->release();
1626 }
1627 if (entry == compareEntry) {
1628 if ((settingAppleProp && propName->isEqualTo(nvName))
1629 || (!settingAppleProp && !IsApplePropertyName(nvName))) {
1630 // delete old property (nvPath -> wherePtr)
1631 data = OSData::withBytes(propStart, nvPath - propStart);
1632 if (data) {
1633 ok &= data->appendBytes(wherePtr, endPtr - wherePtr);
1634 }
1635 break;
1636 }
1637 }
1638 nvPath = 0;
1639 nvName = 0;
1640 }
1641
1642 startPtr = wherePtr;
1643 }
1644 }
1645
1646 // make the new property
1647
1648 if (!data) {
1649 if (oldData) {
1650 data = OSData::withData(oldData);
1651 } else {
1652 data = OSData::withCapacity(16);
1653 }
1654 if (!data) {
1655 ok = false;
1656 }
1657 }
1658
1659 if (ok && value && value->getLength()) {
1660 do {
1661 // get entries in path
1662 OSArray *array = OSArray::withCapacity(5);
1663 if (!array) {
1664 ok = false;
1665 break;
1666 }
1667 do{
1668 array->setObject(entry);
1669 } while ((entry = entry->getParentEntry(gIODTPlane)));
1670
1671 // append path
1672 for (int i = array->getCount() - 3;
1673 (entry = (IORegistryEntry *) array->getObject(i));
1674 i--) {
1675 name = entry->getName(gIODTPlane);
1676 comp = entry->getLocation(gIODTPlane);
1677 if (comp) {
1678 ok &= data->appendBytes("/@", 2);
1679 } else {
1680 if (!name) {
1681 continue;
1682 }
1683 ok &= data->appendByte('/', 1);
1684 comp = name;
1685 }
1686 ok &= data->appendBytes(comp, strlen(comp));
1687 }
1688 ok &= data->appendByte(0, 1);
1689 array->release();
1690
1691 // append prop name
1692 ok &= data->appendBytes(propName->getCStringNoCopy(), propName->getLength() + 1);
1693
1694 // append escaped data
1695 escapedData = escapeDataToData(value);
1696 ok &= (escapedData != 0);
1697 if (ok) {
1698 ok &= data->appendBytes(escapedData);
1699 }
1700 } while (false);
1701 }
1702
1703 oldData->retain();
1704 if (ok) {
1705 ok = _ofDict->setObject(_registryPropertiesKey, data);
1706 }
1707
1708 if (data) {
1709 data->release();
1710 }
1711
1712 if (ok) {
1713 if (syncVariables() != kIOReturnSuccess) {
1714 if (oldData) {
1715 _ofDict->setObject(_registryPropertiesKey, oldData);
1716 } else {
1717 _ofDict->removeObject(_registryPropertiesKey);
1718 }
1719 (void) syncVariables();
1720 ok = false;
1721 }
1722 }
1723
1724 if (oldData) {
1725 oldData->release();
1726 }
1727
1728 IOLockUnlock(_ofLock);
1729
1730 return ok ? kIOReturnSuccess : kIOReturnNoMemory;
1731 }
1732
1733 bool
1734 IODTNVRAM::safeToSync(void)
1735 {
1736 AbsoluteTime delta;
1737 UInt64 delta_ns;
1738 SInt32 delta_secs;
1739
1740 // delta interval went by
1741 clock_get_uptime(&delta);
1742
1743 // Figure it in seconds.
1744 absolutetime_to_nanoseconds(delta, &delta_ns);
1745 delta_secs = (SInt32)(delta_ns / NSEC_PER_SEC);
1746
1747 if ((delta_secs > (_lastDeviceSync + MIN_SYNC_NOW_INTERVAL)) || _freshInterval) {
1748 _lastDeviceSync = delta_secs;
1749 _freshInterval = FALSE;
1750 return TRUE;
1751 }
1752
1753 return FALSE;
1754 }