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