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