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