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