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