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