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