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