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