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