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