]> git.saurik.com Git - apple/xnu.git/blob - iokit/Kernel/IONVRAM.cpp
xnu-201.19.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 (_xpramImage == 0) return kIOReturnUnsupported;
284
285 if ((buffer == 0) || (length <= 0) || (offset < 0) ||
286 (offset + length > kIODTNVRAMXPRAMSize))
287 return kIOReturnBadArgument;
288
289 bcopy(_nvramImage + _xpramPartitionOffset + offset, buffer, length);
290
291 return kIOReturnSuccess;
292 }
293
294 IOReturn IODTNVRAM::writeXPRAM(IOByteCount offset, UInt8 *buffer,
295 IOByteCount length)
296 {
297 if (_xpramImage == 0) return kIOReturnUnsupported;
298
299 if ((buffer == 0) || (length <= 0) || (offset < 0) ||
300 (offset + length > kIODTNVRAMXPRAMSize))
301 return kIOReturnBadArgument;
302
303 bcopy(buffer, _nvramImage + _xpramPartitionOffset + offset, length);
304
305 _nvramImageDirty = true;
306
307 return kIOReturnSuccess;
308 }
309
310 IOReturn IODTNVRAM::readNVRAMProperty(IORegistryEntry *entry,
311 const OSSymbol **name,
312 OSData **value)
313 {
314 IOReturn err;
315
316 if (getPlatform()->getBootROMType())
317 err = readNVRAMPropertyType1(entry, name, value);
318 else
319 err = readNVRAMPropertyType0(entry, name, value);
320
321 return err;
322 }
323
324 IOReturn IODTNVRAM::writeNVRAMProperty(IORegistryEntry *entry,
325 const OSSymbol *name,
326 OSData *value)
327 {
328 IOReturn err;
329
330 if (getPlatform()->getBootROMType())
331 err = writeNVRAMPropertyType1(entry, name, value);
332 else
333 err = writeNVRAMPropertyType0(entry, name, value);
334
335 return err;
336 }
337
338
339
340 // Private methods for Open Firmware variable access.
341
342 struct OWVariablesHeader {
343 UInt16 owMagic;
344 UInt8 owVersion;
345 UInt8 owPages;
346 UInt16 owChecksum;
347 UInt16 owHere;
348 UInt16 owTop;
349 UInt16 owNext;
350 UInt32 owFlags;
351 UInt32 owNumbers[9];
352 struct {
353 UInt16 offset;
354 UInt16 length;
355 } owStrings[10];
356 };
357 typedef struct OWVariablesHeader OWVariablesHeader;
358
359 IOReturn IODTNVRAM::initOFVariables(void)
360 {
361 UInt32 cnt, propOffset, propType;
362 UInt8 *propName, *propData;
363 UInt32 propNameLength, propDataLength;
364 const OSSymbol *propSymbol;
365 OSObject *propObject;
366 OWVariablesHeader *owHeader;
367
368 if (_ofImage == 0) return kIOReturnNotReady;
369
370 _ofDict = OSDictionary::withCapacity(1);
371 if (_ofDict == 0) return kIOReturnNoMemory;
372
373 if (getPlatform()->getBootROMType()) {
374 cnt = 0;
375 while (cnt < _ofPartitionSize) {
376 // Break if there is no name.
377 if (_ofImage[cnt] == '\0') break;
378
379 // Find the length of the name.
380 propName = _ofImage + cnt;
381 for (propNameLength = 0; (cnt + propNameLength) < _ofPartitionSize;
382 propNameLength++) {
383 if (_ofImage[cnt + propNameLength] == '=') break;
384 }
385
386 // Break if the name goes past the end of the partition.
387 if ((cnt + propNameLength) >= _ofPartitionSize) break;
388 cnt += propNameLength + 1;
389
390 propData = _ofImage + cnt;
391 for (propDataLength = 0; (cnt + propDataLength) < _ofPartitionSize;
392 propDataLength++) {
393 if (_ofImage[cnt + propDataLength] == '\0') break;
394 }
395
396 // Break if the data goes past the end of the partition.
397 if ((cnt + propDataLength) >= _ofPartitionSize) break;
398 cnt += propDataLength + 1;
399
400 if (convertPropToObject(propName, propNameLength,
401 propData, propDataLength,
402 &propSymbol, &propObject)) {
403 _ofDict->setObject(propSymbol, propObject);
404 propSymbol->release();
405 propObject->release();
406 }
407 }
408
409 // Create the boot-args property if it is not in the dictionary.
410 if (_ofDict->getObject("boot-args") == 0) {
411 propObject = OSString::withCStringNoCopy("");
412 if (propObject != 0) {
413 _ofDict->setObject("boot-args", propObject);
414 propObject->release();
415 }
416 }
417 } else {
418 owHeader = (OWVariablesHeader *)_ofImage;
419 if (!validateOWChecksum(_ofImage)) {
420 _ofDict->release();
421 _ofDict = 0;
422 return kIOReturnBadMedia;
423 }
424
425 cnt = 0;
426 while (1) {
427 if (!getOWVariableInfo(cnt++, &propSymbol, &propType, &propOffset))
428 break;
429
430 switch (propType) {
431 case kOFVariableTypeBoolean :
432 propObject = OSBoolean::withBoolean(owHeader->owFlags & propOffset);
433 break;
434
435 case kOFVariableTypeNumber :
436 propObject = OSNumber::withNumber(owHeader->owNumbers[propOffset], 32);
437 break;
438
439 case kOFVariableTypeString :
440 propData = _ofImage + owHeader->owStrings[propOffset].offset -
441 _ofPartitionOffset;
442 propDataLength = owHeader->owStrings[propOffset].length;
443 propName = IONew(UInt8, propDataLength + 1);
444 if (propName != 0) {
445 strncpy((char *)propName, (const char *)propData, propDataLength);
446 propName[propDataLength] = '\0';
447 propObject = OSString::withCString((const char *)propName);
448 IODelete(propName, UInt8, propDataLength + 1);
449 }
450 break;
451 }
452
453 if (propObject == 0) break;
454
455 _ofDict->setObject(propSymbol, propObject);
456 propSymbol->release();
457 propObject->release();
458 }
459
460 // Create the boot-args property.
461 propSymbol = OSSymbol::withCString("boot-command");
462 if (propSymbol != 0) {
463 propObject = _ofDict->getObject(propSymbol);
464 if (propObject != 0) {
465 updateOWBootArgs(propSymbol, propObject);
466 }
467 propSymbol->release();
468 }
469 }
470
471 return kIOReturnSuccess;
472 }
473
474 IOReturn IODTNVRAM::syncOFVariables(void)
475 {
476 bool ok;
477 UInt32 cnt, length, maxLength;
478 UInt32 curOffset, tmpOffset, tmpType, tmpDataLength;
479 UInt8 *buffer, *tmpBuffer, *tmpData;
480 const OSSymbol *tmpSymbol;
481 OSObject *tmpObject;
482 OSBoolean *tmpBoolean;
483 OSNumber *tmpNumber;
484 OSString *tmpString;
485 OSCollectionIterator *iter;
486 OWVariablesHeader *owHeader, *owHeaderOld;
487
488 if ((_ofImage == 0) || (_ofDict == 0)) return kIOReturnNotReady;
489
490 if (!_ofImageDirty) return kIOReturnSuccess;
491
492 if (getPlatform()->getBootROMType()) {
493 buffer = tmpBuffer = IONew(UInt8, _ofPartitionSize);
494 if (buffer == 0) return kIOReturnNoMemory;
495 bzero(buffer, _ofPartitionSize);
496
497 ok = true;
498 maxLength = _ofPartitionSize;
499
500 iter = OSCollectionIterator::withCollection(_ofDict);
501 if (iter == 0) ok = false;
502
503 while (ok) {
504 tmpSymbol = OSDynamicCast(OSSymbol, iter->getNextObject());
505 if (tmpSymbol == 0) break;
506
507 tmpObject = _ofDict->getObject(tmpSymbol);
508
509 length = maxLength;
510 ok = convertObjectToProp(tmpBuffer, &length, tmpSymbol, tmpObject);
511 if (ok) {
512 tmpBuffer += length;
513 maxLength -= length;
514 }
515 }
516 iter->release();
517
518 if (ok) {
519 bcopy(buffer, _ofImage, _ofPartitionSize);
520 }
521
522 IODelete(buffer, UInt8, _ofPartitionSize);
523
524 if (!ok) return kIOReturnBadArgument;
525 } else {
526 buffer = IONew(UInt8, _ofPartitionSize);
527 if (buffer == 0) return kIOReturnNoMemory;
528 bzero(buffer, _ofPartitionSize);
529
530 owHeader = (OWVariablesHeader *)buffer;
531 owHeaderOld = (OWVariablesHeader *)_ofImage;
532
533 owHeader->owMagic = owHeaderOld->owMagic;
534 owHeader->owVersion = owHeaderOld->owVersion;
535 owHeader->owPages = owHeaderOld->owPages;
536
537 curOffset = _ofPartitionSize;
538
539 ok = true;
540 cnt = 0;
541 while (ok) {
542 if (!getOWVariableInfo(cnt++, &tmpSymbol, &tmpType, &tmpOffset))
543 break;
544
545 tmpObject = _ofDict->getObject(tmpSymbol);
546
547 switch (tmpType) {
548 case kOFVariableTypeBoolean :
549 tmpBoolean = OSDynamicCast(OSBoolean, tmpObject);
550 if (tmpBoolean->getValue()) owHeader->owFlags |= tmpOffset;
551 break;
552
553 case kOFVariableTypeNumber :
554 tmpNumber = OSDynamicCast(OSNumber, tmpObject);
555 owHeader->owNumbers[tmpOffset] = tmpNumber->unsigned32BitValue();
556 break;
557
558 case kOFVariableTypeString :
559 tmpString = OSDynamicCast(OSString, tmpObject);
560 tmpData = (UInt8 *) tmpString->getCStringNoCopy();
561 tmpDataLength = tmpString->getLength();
562
563 if ((curOffset - tmpDataLength) < sizeof(OWVariablesHeader)) {
564 ok = false;
565 break;
566 }
567
568 owHeader->owStrings[tmpOffset].length = tmpDataLength;
569 curOffset -= tmpDataLength;
570 owHeader->owStrings[tmpOffset].offset = curOffset + _ofPartitionOffset;
571 if (tmpDataLength != 0)
572 bcopy(tmpData, buffer + curOffset, tmpDataLength);
573 break;
574 }
575 }
576
577 if (ok) {
578 owHeader->owHere = _ofPartitionOffset + sizeof(OWVariablesHeader);
579 owHeader->owTop = _ofPartitionOffset + curOffset;
580 owHeader->owNext = 0;
581
582 owHeader->owChecksum = 0;
583 owHeader->owChecksum = ~generateOWChecksum(buffer);
584
585 bcopy(buffer, _ofImage, _ofPartitionSize);
586 }
587
588 IODelete(buffer, UInt8, _ofPartitionSize);
589
590 if (!ok) return kIOReturnBadArgument;
591 }
592
593 _ofImageDirty = false;
594 _nvramImageDirty = true;
595
596 return kIOReturnSuccess;
597 }
598
599 struct OFVariable {
600 char *variableName;
601 UInt32 variableType;
602 UInt32 variablePerm;
603 SInt32 variableOffset;
604 };
605 typedef struct OFVariable OFVariable;
606
607 enum {
608 kOWVariableOffsetNumber = 8,
609 kOWVariableOffsetString = 17
610 };
611
612 OFVariable gOFVariables[] = {
613 {"little-endian?", kOFVariableTypeBoolean, kOFVariablePermUserRead, 0},
614 {"real-mode?", kOFVariableTypeBoolean, kOFVariablePermUserRead, 1},
615 {"auto-boot?", kOFVariableTypeBoolean, kOFVariablePermUserRead, 2},
616 {"diag-switch?", kOFVariableTypeBoolean, kOFVariablePermUserRead, 3},
617 {"fcode-debug?", kOFVariableTypeBoolean, kOFVariablePermUserRead, 4},
618 {"oem-banner?", kOFVariableTypeBoolean, kOFVariablePermUserRead, 5},
619 {"oem-logo?", kOFVariableTypeBoolean, kOFVariablePermUserRead, 6},
620 {"use-nvramrc?", kOFVariableTypeBoolean, kOFVariablePermUserRead, 7},
621 {"use-generic?", kOFVariableTypeBoolean, kOFVariablePermUserRead, -1},
622 {"default-mac-address?", kOFVariableTypeBoolean, kOFVariablePermUserRead,-1},
623 {"real-base", kOFVariableTypeNumber, kOFVariablePermUserRead, 8},
624 {"real-size", kOFVariableTypeNumber, kOFVariablePermUserRead, 9},
625 {"virt-base", kOFVariableTypeNumber, kOFVariablePermUserRead, 10},
626 {"virt-size", kOFVariableTypeNumber, kOFVariablePermUserRead, 11},
627 {"load-base", kOFVariableTypeNumber, kOFVariablePermUserRead, 12},
628 {"pci-probe-list", kOFVariableTypeNumber, kOFVariablePermUserRead, 13},
629 {"pci-probe-mask", kOFVariableTypeNumber, kOFVariablePermUserRead, -1},
630 {"screen-#columns", kOFVariableTypeNumber, kOFVariablePermUserRead, 14},
631 {"screen-#rows", kOFVariableTypeNumber, kOFVariablePermUserRead, 15},
632 {"selftest-#megs", kOFVariableTypeNumber, kOFVariablePermUserRead, 16},
633 {"boot-device", kOFVariableTypeString, kOFVariablePermUserRead, 17},
634 {"boot-file", kOFVariableTypeString, kOFVariablePermUserRead, 18},
635 {"boot-screen", kOFVariableTypeString, kOFVariablePermUserRead, -1},
636 {"console-screen", kOFVariableTypeString, kOFVariablePermUserRead, -1},
637 {"diag-device", kOFVariableTypeString, kOFVariablePermUserRead, 19},
638 {"diag-file", kOFVariableTypeString, kOFVariablePermUserRead, 20},
639 {"input-device", kOFVariableTypeString, kOFVariablePermUserRead, 21},
640 {"output-device", kOFVariableTypeString, kOFVariablePermUserRead, 22},
641 {"input-device-1", kOFVariableTypeString, kOFVariablePermUserRead, -1},
642 {"output-device-1", kOFVariableTypeString, kOFVariablePermUserRead, -1},
643 {"mouse-device", kOFVariableTypeString, kOFVariablePermUserRead, -1},
644 {"oem-banner", kOFVariableTypeString, kOFVariablePermUserRead, 23},
645 {"oem-logo", kOFVariableTypeString, kOFVariablePermUserRead, 24},
646 {"nvramrc", kOFVariableTypeString, kOFVariablePermUserRead, 25},
647 {"boot-command", kOFVariableTypeString, kOFVariablePermUserRead, 26},
648 {"default-client-ip", kOFVariableTypeString, kOFVariablePermUserRead, -1},
649 {"default-server-ip", kOFVariableTypeString, kOFVariablePermUserRead, -1},
650 {"default-gateway-ip", kOFVariableTypeString, kOFVariablePermUserRead, -1},
651 {"default-subnet-mask", kOFVariableTypeString, kOFVariablePermUserRead, -1},
652 {"default-router-ip", kOFVariableTypeString, kOFVariablePermUserRead, -1},
653 {"boot-script", kOFVariableTypeString, kOFVariablePermUserRead, -1},
654 {"boot-args", kOFVariableTypeString, kOFVariablePermUserRead, -1},
655 {"aapl,pci", kOFVariableTypeData, kOFVariablePermRootOnly, -1},
656 {"security-mode", kOFVariableTypeString, kOFVariablePermUserRead, -1},
657 {"security-password", kOFVariableTypeData, kOFVariablePermRootOnly, -1},
658 {0, kOFVariableTypeData, kOFVariablePermUserRead, -1}
659 };
660
661 UInt32 IODTNVRAM::getOFVariableType(const OSSymbol *propSymbol) const
662 {
663 OFVariable *ofVar;
664
665 ofVar = gOFVariables;
666 while (1) {
667 if ((ofVar->variableName == 0) ||
668 propSymbol->isEqualTo(ofVar->variableName)) break;
669 ofVar++;
670 }
671
672 return ofVar->variableType;
673 }
674
675 UInt32 IODTNVRAM::getOFVariablePerm(const OSSymbol *propSymbol) const
676 {
677 OFVariable *ofVar;
678
679 ofVar = gOFVariables;
680 while (1) {
681 if ((ofVar->variableName == 0) ||
682 propSymbol->isEqualTo(ofVar->variableName)) break;
683 ofVar++;
684 }
685
686 return ofVar->variablePerm;
687 }
688
689 bool IODTNVRAM::getOWVariableInfo(UInt32 variableNumber, const OSSymbol **propSymbol,
690 UInt32 *propType, UInt32 *propOffset)
691 {
692 OFVariable *ofVar;
693
694 ofVar = gOFVariables;
695 while (1) {
696 if (ofVar->variableName == 0) return false;
697
698 if (ofVar->variableOffset == (SInt32) variableNumber) break;
699
700 ofVar++;
701 }
702
703 *propSymbol = OSSymbol::withCStringNoCopy(ofVar->variableName);
704 *propType = ofVar->variableType;
705
706 switch (*propType) {
707 case kOFVariableTypeBoolean :
708 *propOffset = 1 << (31 - variableNumber);
709 break;
710
711 case kOFVariableTypeNumber :
712 *propOffset = variableNumber - kOWVariableOffsetNumber;
713 break;
714
715 case kOFVariableTypeString :
716 *propOffset = variableNumber - kOWVariableOffsetString;
717 break;
718 }
719
720 return true;
721 }
722
723 bool IODTNVRAM::convertPropToObject(UInt8 *propName, UInt32 propNameLength,
724 UInt8 *propData, UInt32 propDataLength,
725 const OSSymbol **propSymbol,
726 OSObject **propObject)
727 {
728 UInt32 propType;
729 const OSSymbol *tmpSymbol;
730 OSObject *tmpObject;
731 OSNumber *tmpNumber;
732 OSString *tmpString;
733
734 // Create the symbol.
735 propName[propNameLength] = '\0';
736 tmpSymbol = OSSymbol::withCString((const char *)propName);
737 propName[propNameLength] = '=';
738 if (tmpSymbol == 0) {
739 return false;
740 }
741
742 propType = getOFVariableType(tmpSymbol);
743
744 // Create the object.
745 tmpObject = 0;
746 switch (propType) {
747 case kOFVariableTypeBoolean :
748 if (!strncmp("true", (const char *)propData, propDataLength)) {
749 tmpObject = kOSBooleanTrue;
750 } else if (!strncmp("false", (const char *)propData, propDataLength)) {
751 tmpObject = kOSBooleanFalse;
752 }
753 break;
754
755 case kOFVariableTypeNumber :
756 tmpNumber = OSNumber::withNumber(strtol((const char *)propData, 0, 0), 32);
757 if (tmpNumber != 0) tmpObject = tmpNumber;
758 break;
759
760 case kOFVariableTypeString :
761 tmpString = OSString::withCString((const char *)propData);
762 if (tmpString != 0) tmpObject = tmpString;
763 break;
764
765 case kOFVariableTypeData :
766 tmpObject = unescapeBytesToData(propData, propDataLength);
767 break;
768 }
769
770 if (tmpObject == 0) {
771 tmpSymbol->release();
772 return false;
773 }
774
775 *propSymbol = tmpSymbol;
776 *propObject = tmpObject;
777
778 return true;
779 }
780
781 bool IODTNVRAM::convertObjectToProp(UInt8 *buffer, UInt32 *length,
782 const OSSymbol *propSymbol, OSObject *propObject)
783 {
784 UInt8 *propName;
785 UInt32 propNameLength, propDataLength;
786 UInt32 propType, tmpValue;
787 OSBoolean *tmpBoolean = 0;
788 OSNumber *tmpNumber = 0;
789 OSString *tmpString = 0;
790 OSData *tmpData = 0;
791
792 propName = (UInt8 *)propSymbol->getCStringNoCopy();
793 propNameLength = propSymbol->getLength();
794 propType = getOFVariableType(propSymbol);
795
796 // Get the size of the data.
797 propDataLength = 0xFFFFFFFF;
798 switch (propType) {
799 case kOFVariableTypeBoolean :
800 tmpBoolean = OSDynamicCast(OSBoolean, propObject);
801 if (tmpBoolean != 0) propDataLength = 5;
802 break;
803
804 case kOFVariableTypeNumber :
805 tmpNumber = OSDynamicCast(OSNumber, propObject);
806 if (tmpNumber != 0) propDataLength = 10;
807 break;
808
809 case kOFVariableTypeString :
810 tmpString = OSDynamicCast(OSString, propObject);
811 if (tmpString != 0) propDataLength = tmpString->getLength();
812 break;
813
814 case kOFVariableTypeData :
815 tmpData = OSDynamicCast(OSData, propObject);
816 if (tmpData != 0) {
817 tmpData = escapeDataToData(tmpData);
818 propDataLength = tmpData->getLength();
819 }
820 break;
821 }
822
823 // Make sure the propertySize is known and will fit.
824 if (propDataLength == 0xFFFFFFFF) return false;
825 if ((propNameLength + propDataLength + 2) > *length) return false;
826
827 // Copy the property name equal sign.
828 sprintf((char *)buffer, "%s=", propName);
829 buffer += propNameLength + 1;
830
831 switch (propType) {
832 case kOFVariableTypeBoolean :
833 if (tmpBoolean->getValue()) {
834 strcpy((char *)buffer, "true");
835 } else {
836 strcpy((char *)buffer, "false");
837 }
838 break;
839
840 case kOFVariableTypeNumber :
841 tmpValue = tmpNumber->unsigned32BitValue();
842 if (tmpValue == 0xFFFFFFFF) {
843 strcpy((char *)buffer, "-1");
844 } else if (tmpValue < 1000) {
845 sprintf((char *)buffer, "%ld", tmpValue);
846 } else {
847 sprintf((char *)buffer, "0x%lx", tmpValue);
848 }
849 break;
850
851 case kOFVariableTypeString :
852 strcpy((char *)buffer, tmpString->getCStringNoCopy());
853 break;
854
855 case kOFVariableTypeData :
856 bcopy(tmpData->getBytesNoCopy(), buffer, propDataLength);
857 tmpData->release();
858 break;
859 }
860
861 propDataLength = strlen((const char *)buffer);
862
863 *length = propNameLength + propDataLength + 2;
864
865 return true;
866 }
867
868
869 UInt16 IODTNVRAM::generateOWChecksum(UInt8 *buffer)
870 {
871 UInt32 cnt, checksum = 0;
872 UInt16 *tmpBuffer = (UInt16 *)buffer;
873
874 for (cnt = 0; cnt < _ofPartitionSize / 2; cnt++)
875 checksum += tmpBuffer[cnt];
876
877 return checksum % 0x0000FFFF;
878 }
879
880 bool IODTNVRAM::validateOWChecksum(UInt8 *buffer)
881 {
882 UInt32 cnt, checksum, sum = 0;
883 UInt16 *tmpBuffer = (UInt16 *)buffer;
884
885 for (cnt = 0; cnt < _ofPartitionSize / 2; cnt++)
886 sum += tmpBuffer[cnt];
887
888 checksum = (sum >> 16) + (sum & 0x0000FFFF);
889 if (checksum == 0x10000) checksum--;
890 checksum = (checksum ^ 0x0000FFFF) & 0x0000FFFF;
891
892 return checksum == 0;
893 }
894
895 void IODTNVRAM::updateOWBootArgs(const OSSymbol *key, OSObject *value)
896 {
897 bool wasBootArgs, bootr = false;
898 UInt32 cnt;
899 OSString *tmpString, *bootCommand, *bootArgs = 0;
900 UInt8 *bootCommandData, *bootArgsData, *tmpData;
901 UInt32 bootCommandDataLength, bootArgsDataLength, tmpDataLength;
902
903 tmpString = OSDynamicCast(OSString, value);
904 if (tmpString == 0) return;
905
906 if (key->isEqualTo("boot-command")) {
907 wasBootArgs = false;
908 bootCommand = tmpString;
909 } else if (key->isEqualTo("boot-args")) {
910 wasBootArgs = true;
911 bootArgs = tmpString;
912 bootCommand = OSDynamicCast(OSString, _ofDict->getObject("boot-command"));
913 if (bootCommand == 0) return;
914 } else return;
915
916 bootCommandData = (UInt8 *)bootCommand->getCStringNoCopy();
917 bootCommandDataLength = bootCommand->getLength();
918
919 if (bootCommandData == 0) return;
920
921 for (cnt = 0; cnt < bootCommandDataLength; cnt++) {
922 if ((bootCommandData[cnt] == 'b') &&
923 !strncmp("bootr", (const char *)bootCommandData + cnt, 5)) {
924 cnt += 5;
925 while (bootCommandData[cnt] == ' ') cnt++;
926 bootr = true;
927 break;
928 }
929 }
930 if (!bootr) {
931 _ofDict->removeObject("boot-args");
932 return;
933 }
934
935 if (wasBootArgs) {
936 bootArgsData = (UInt8 *)bootArgs->getCStringNoCopy();
937 bootArgsDataLength = bootArgs->getLength();
938 if (bootArgsData == 0) return;
939
940 tmpDataLength = cnt + bootArgsDataLength;
941 tmpData = IONew(UInt8, tmpDataLength + 1);
942 if (tmpData == 0) return;
943
944 strncpy((char *)tmpData, (const char *)bootCommandData, cnt);
945 tmpData[cnt] = '\0';
946 strcat((char *)tmpData, (const char *)bootArgsData);
947
948 bootCommand = OSString::withCString((const char *)tmpData);
949 if (bootCommand != 0) {
950 _ofDict->setObject("boot-command", bootCommand);
951 bootCommand->release();
952 }
953
954 IODelete(tmpData, UInt8, tmpDataLength + 1);
955 } else {
956 bootArgs = OSString::withCString((const char *)(bootCommandData + cnt));
957 if (bootArgs != 0) {
958 _ofDict->setObject("boot-args", bootArgs);
959 bootArgs->release();
960 }
961 }
962 }
963
964
965 // Private methods for Name Registry access.
966
967 enum {
968 kMaxNVNameLength = 4,
969 kMaxNVDataLength = 8
970 };
971
972 #pragma options align=mac68k
973 struct NVRAMProperty
974 {
975 IONVRAMDescriptor header;
976 UInt8 nameLength;
977 UInt8 name[ kMaxNVNameLength ];
978 UInt8 dataLength;
979 UInt8 data[ kMaxNVDataLength ];
980 };
981 #pragma options align=reset
982
983 bool IODTNVRAM::searchNVRAMProperty(IONVRAMDescriptor *hdr, UInt32 *where)
984 {
985 UInt32 offset;
986 SInt32 nvEnd;
987
988 nvEnd = *((UInt16 *)_nrImage);
989 if(getPlatform()->getBootROMType()) {
990 // on NewWorld, offset to partition start
991 nvEnd -= 0x100;
992 } else {
993 // on old world, absolute
994 nvEnd -= _nrPartitionOffset;
995 }
996 if((nvEnd < 0) || (nvEnd >= kIODTNVRAMNameRegistrySize))
997 nvEnd = 2;
998
999 offset = 2;
1000 while ((offset + sizeof(NVRAMProperty)) <= (UInt32)nvEnd) {
1001 if (bcmp(_nrImage + offset, hdr, sizeof(*hdr)) == 0) {
1002 *where = offset;
1003 return true;
1004 }
1005 offset += sizeof(NVRAMProperty);
1006 }
1007
1008 if ((nvEnd + sizeof(NVRAMProperty)) <= kIODTNVRAMNameRegistrySize)
1009 *where = nvEnd;
1010 else
1011 *where = 0;
1012
1013 return false;
1014 }
1015
1016 IOReturn IODTNVRAM::readNVRAMPropertyType0(IORegistryEntry *entry,
1017 const OSSymbol **name,
1018 OSData **value)
1019 {
1020 IONVRAMDescriptor hdr;
1021 NVRAMProperty *prop;
1022 IOByteCount length;
1023 UInt32 offset;
1024 IOReturn err;
1025 char nameBuf[kMaxNVNameLength + 1];
1026
1027 if (_nrImage == 0) return kIOReturnUnsupported;
1028 if ((entry == 0) || (name == 0) || (value == 0)) return kIOReturnBadArgument;
1029
1030 err = IODTMakeNVDescriptor(entry, &hdr);
1031 if (err != kIOReturnSuccess) return err;
1032
1033 if (searchNVRAMProperty(&hdr, &offset)) {
1034 prop = (NVRAMProperty *)(_nrImage + offset);
1035
1036 length = prop->nameLength;
1037 if (length > kMaxNVNameLength) length = kMaxNVNameLength;
1038 strncpy(nameBuf, (const char *)prop->name, length);
1039 nameBuf[length] = 0;
1040 *name = OSSymbol::withCString(nameBuf);
1041
1042 length = prop->dataLength;
1043 if (length > kMaxNVDataLength) length = kMaxNVDataLength;
1044 *value = OSData::withBytes(prop->data, length);
1045
1046 if ((*name != 0) && (*value != 0)) return kIOReturnSuccess;
1047 else return kIOReturnNoMemory;
1048 }
1049
1050 return kIOReturnNoResources;
1051 }
1052
1053 IOReturn IODTNVRAM::writeNVRAMPropertyType0(IORegistryEntry *entry,
1054 const OSSymbol *name,
1055 OSData *value)
1056 {
1057 IONVRAMDescriptor hdr;
1058 NVRAMProperty *prop;
1059 IOByteCount nameLength;
1060 IOByteCount dataLength;
1061 UInt32 offset;
1062 IOReturn err;
1063 UInt16 nvLength;
1064 bool exists;
1065
1066 if (_nrImage == 0) return kIOReturnUnsupported;
1067 if ((entry == 0) || (name == 0) || (value == 0)) return kIOReturnBadArgument;
1068
1069 nameLength = name->getLength();
1070 dataLength = value->getLength();
1071 if (nameLength > kMaxNVNameLength) return kIOReturnNoSpace;
1072 if (dataLength > kMaxNVDataLength) return kIOReturnNoSpace;
1073
1074 err = IODTMakeNVDescriptor(entry, &hdr);
1075 if (err != kIOReturnSuccess) return err;
1076
1077 exists = searchNVRAMProperty(&hdr, &offset);
1078 if (offset == 0) return kIOReturnNoMemory;
1079
1080 prop = (NVRAMProperty *)(_nrImage + offset);
1081 if (!exists) bcopy(&hdr, &prop->header, sizeof(hdr));
1082
1083 prop->nameLength = nameLength;
1084 bcopy(name->getCStringNoCopy(), prop->name, nameLength);
1085 prop->dataLength = dataLength;
1086 bcopy(value->getBytesNoCopy(), prop->data, dataLength);
1087
1088 if (!exists) {
1089 nvLength = offset + sizeof(NVRAMProperty);
1090 if (getPlatform()->getBootROMType())
1091 nvLength += 0x100;
1092 else
1093 nvLength += _nrPartitionOffset;
1094 *((UInt16 *)_nrImage) = nvLength;
1095 }
1096
1097 _nvramImageDirty = true;
1098
1099 return err;
1100 }
1101
1102 OSData *IODTNVRAM::unescapeBytesToData(UInt8 *bytes, UInt32 length)
1103 {
1104 OSData *data = 0;
1105 UInt32 totalLength = 0;
1106 UInt32 cnt, cnt2;
1107 UInt8 byte;
1108 bool ok;
1109
1110 // Calculate the actual length of the data.
1111 ok = true;
1112 totalLength = 0;
1113 for (cnt = 0; cnt < length;) {
1114 byte = bytes[cnt++];
1115 if (byte == 0xFF) {
1116 byte = bytes[cnt++];
1117 if (byte == 0x00) {
1118 ok = false;
1119 break;
1120 }
1121 cnt2 = byte & 0x7F;
1122 } else
1123 cnt2 = 1;
1124 totalLength += cnt2;
1125 }
1126
1127 if (ok) {
1128 // Create an empty OSData of the correct size.
1129 data = OSData::withCapacity(totalLength);
1130 if (data != 0) {
1131 for (cnt = 0; cnt < length;) {
1132 byte = bytes[cnt++];
1133 if (byte == 0xFF) {
1134 byte = bytes[cnt++];
1135 cnt2 = byte & 0x7F;
1136 byte = (byte & 0x80) ? 0xFF : 0x00;
1137 } else
1138 cnt2 = 1;
1139 data->appendByte(byte, cnt2);
1140 }
1141 }
1142 }
1143
1144 return data;
1145 }
1146
1147 OSData * IODTNVRAM::escapeDataToData(OSData * value)
1148 {
1149 OSData * result;
1150 UInt8 * start;
1151 UInt8 * end;
1152 UInt8 * where;
1153 UInt8 byte;
1154 bool ok = true;
1155
1156 where = (UInt8 *) value->getBytesNoCopy();
1157 end = where + value->getLength();
1158
1159 result = OSData::withCapacity(end - where);
1160 if (!result)
1161 return result;
1162
1163 while (where < end) {
1164 start = where;
1165 byte = *where++;
1166 if ((byte == 0x00) || (byte == 0xFF)) {
1167 for (;
1168 ((where - start) < 0x80) && (where < end) && (byte == *where);
1169 where++) {}
1170 ok &= result->appendByte(0xff, 1);
1171 byte = (byte & 0x80) | (where - start);
1172 }
1173 ok &= result->appendByte(byte, 1);
1174 }
1175 ok &= result->appendByte(0, 1);
1176
1177 if (!ok) {
1178 result->release();
1179 result = 0;
1180 }
1181
1182 return result;
1183 }
1184
1185 IOReturn IODTNVRAM::readNVRAMPropertyType1(IORegistryEntry *entry,
1186 const OSSymbol **name,
1187 OSData **value)
1188 {
1189 IOReturn err = kIOReturnNoResources;
1190 OSData *data;
1191 UInt8 *start;
1192 UInt8 *end;
1193 UInt8 *where;
1194 UInt8 *nvPath = 0;
1195 UInt8 *nvName = 0;
1196 UInt8 byte;
1197
1198 if (_ofDict == 0) return err;
1199 data = OSDynamicCast(OSData, _ofDict->getObject(_registryPropertiesKey));
1200 if (data == 0) return err;
1201
1202 start = (UInt8 *) data->getBytesNoCopy();
1203 end = start + data->getLength();
1204
1205 where = start;
1206 while (where < end) {
1207 byte = *(where++);
1208 if (byte)
1209 continue;
1210
1211 if (nvPath == 0)
1212 nvPath = start;
1213 else if (nvName == 0)
1214 nvName = start;
1215 else if (entry ==
1216 IORegistryEntry::fromPath((const char *) nvPath, gIODTPlane)) {
1217 *name = OSSymbol::withCString((const char *) nvName);
1218 *value = unescapeBytesToData(start, where - start - 1);
1219 if ((*name != 0) && (*value != 0))
1220 err = kIOReturnSuccess;
1221 else
1222 err = kIOReturnNoMemory;
1223 break;
1224 } else
1225 nvPath = nvName = 0;
1226
1227 start = where;
1228 }
1229
1230 return err;
1231 }
1232
1233 IOReturn IODTNVRAM::writeNVRAMPropertyType1(IORegistryEntry *entry,
1234 const OSSymbol *propName,
1235 OSData *value)
1236 {
1237 OSData *oldData;
1238 OSData *data = 0;
1239 UInt8 *start;
1240 UInt8 *propStart;
1241 UInt8 *end;
1242 UInt8 *where;
1243 UInt8 *nvPath = 0;
1244 UInt8 *nvName = 0;
1245 const char * comp;
1246 const char * name;
1247 UInt8 byte;
1248 bool ok = true;
1249
1250 if (_ofDict == 0) return kIOReturnNoResources;
1251
1252 // copy over existing properties for other entries
1253
1254 oldData = OSDynamicCast(OSData, _ofDict->getObject(_registryPropertiesKey));
1255 if (oldData) {
1256 start = (UInt8 *) oldData->getBytesNoCopy();
1257 end = start + oldData->getLength();
1258
1259 propStart = start;
1260 where = start;
1261 while (where < end) {
1262 byte = *(where++);
1263 if (byte)
1264 continue;
1265 if (nvPath == 0)
1266 nvPath = start;
1267 else if (nvName == 0)
1268 nvName = start;
1269 else if (entry ==
1270 IORegistryEntry::fromPath((const char *) nvPath, gIODTPlane)) {
1271 // delete old property (nvPath -> where)
1272 data = OSData::withBytes(propStart, nvPath - propStart);
1273 if (data)
1274 ok &= data->appendBytes(where, end - where);
1275 break;
1276 } else
1277 nvPath = nvName = 0;
1278
1279 start = where;
1280 }
1281 }
1282
1283 // make the new property
1284
1285 if (!data) {
1286 if (oldData)
1287 data = OSData::withData(oldData);
1288 else
1289 data = OSData::withCapacity(16);
1290 if (!data)
1291 return kIOReturnNoMemory;
1292 }
1293
1294 // get entries in path
1295 OSArray *array = OSArray::withCapacity(5);
1296 if (!array) {
1297 data->release();
1298 return kIOReturnNoMemory;
1299 }
1300 do
1301 array->setObject(entry);
1302 while ((entry = entry->getParentEntry(gIODTPlane)));
1303
1304 // append path
1305 for (int i = array->getCount() - 3;
1306 (entry = (IORegistryEntry *) array->getObject(i));
1307 i--) {
1308
1309 name = entry->getName(gIODTPlane);
1310 comp = entry->getLocation(gIODTPlane);
1311 if( comp && (0 == strcmp("pci", name))
1312 && (0 == strcmp("80000000", comp))) {
1313 // yosemite hack
1314 comp = "/pci@80000000";
1315 } else {
1316 if (comp)
1317 ok &= data->appendBytes("/@", 2);
1318 else {
1319 if (!name)
1320 continue;
1321 ok &= data->appendByte('/', 1);
1322 comp = name;
1323 }
1324 }
1325 ok &= data->appendBytes(comp, strlen(comp));
1326 }
1327 ok &= data->appendByte(0, 1);
1328 array->release();
1329
1330 // append prop name
1331 ok &= data->appendBytes(propName->getCStringNoCopy(), propName->getLength() + 1);
1332
1333 // append escaped data
1334 oldData = escapeDataToData(value);
1335 ok &= (oldData != 0);
1336 if (ok)
1337 ok &= data->appendBytes(oldData);
1338
1339 if (ok) {
1340 ok = _ofDict->setObject(_registryPropertiesKey, data);
1341 if (ok)
1342 _ofImageDirty = true;
1343 }
1344 data->release();
1345
1346 return ok ? kIOReturnSuccess : kIOReturnNoMemory;
1347 }