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