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