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