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