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