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