xref: /xnu-11215/iokit/Kernel/IONVRAM.cpp (revision 8149afcc)
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 }
1350