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