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