]> git.saurik.com Git - apple/xnu.git/blame - libsa/catalogue.cpp
xnu-1228.0.2.tar.gz
[apple/xnu.git] / libsa / catalogue.cpp
CommitLineData
1c79356b 1/*
2d21ac55 2 * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
1c79356b 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 5 *
2d21ac55
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
8f6c56a5 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
8f6c56a5 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
27 */
28#include <libkern/c++/OSContainers.h>
29#include <IOKit/IODeviceTreeSupport.h>
30#include <IOKit/IORegistryEntry.h>
31#include <IOKit/IOCatalogue.h>
0c530ab8 32#include <IOKit/IOKitKeysPrivate.h>
1c79356b
A
33#include <libkern/c++/OSUnserialize.h>
34#include <libkern/OSByteOrder.h>
35#include <libsa/catalogue.h>
36
37extern "C" {
38#include <machine/machine_routines.h>
39#include <mach/host_info.h>
40#include <mach/kmod.h>
41#include <libsa/mkext.h>
42#include <libsa/vers_rsrc.h>
55e303ae 43#include <mach-o/loader.h>
1c79356b
A
44};
45
46#include <IOKit/IOLib.h>
47
48#include <IOKit/assert.h>
49
1c79356b
A
50extern "C" {
51extern void IODTFreeLoaderInfo( char *key, void *infoAddr, int infoSize );
91447636
A
52// extern kern_return_t host_info(host_t host,
53// host_flavor_t flavor,
54// host_info_t info,
55// mach_msg_type_number_t *count);
56extern int grade_binary(cpu_type_t exectype, cpu_subtype_t execsubtype);
57// Return the address of the named Mach-O segment from the currently
58// executing 32 bit kernel, or NULL.
59extern struct segment_command *getsegbyname(char *seg_name);
60// Return the address of the named section from the named Mach-O segment
61// from the currently executing 32 bit kernel, or NULL.
2d21ac55 62extern struct section *getsectbyname(const char *segname, const char *sectname);
1c79356b
A
63};
64
1c79356b
A
65#define LOG_DELAY()
66
55e303ae 67#if 0
1c79356b
A
68#define VTYELLOW "\033[33m"
69#define VTRESET "\033[0m"
55e303ae
A
70#else
71#define VTYELLOW ""
72#define VTRESET ""
73#endif
1c79356b
A
74
75/*********************************************************************
76*********************************************************************/
77static OSDictionary * gStartupExtensions = 0;
0b4e3aa0 78static OSArray * gBootLoaderObjects = 0;
55e303ae 79extern OSArray * gIOPrelinkedModules;
1c79356b
A
80
81OSDictionary * getStartupExtensions(void) {
82 if (gStartupExtensions) {
83 return gStartupExtensions;
84 }
85 gStartupExtensions = OSDictionary::withCapacity(1);
55e303ae
A
86 assert (gStartupExtensions);
87
1c79356b
A
88 return gStartupExtensions;
89}
90
0b4e3aa0
A
91/* This array holds objects that are needed to be held around during
92 * boot before kextd starts up. Currently it contains OSData objects
93 * copied from OF entries for mkext archives in device ROMs. Because
94 * the Device Tree support code dumps these after initially handing
95 * them to us, we have to be able to clean them up later.
96 */
97OSArray * getBootLoaderObjects(void) {
98 if (gBootLoaderObjects) {
99 return gBootLoaderObjects;
100 }
101 gBootLoaderObjects = OSArray::withCapacity(1);
55e303ae
A
102 assert (gBootLoaderObjects);
103
0b4e3aa0
A
104 return gBootLoaderObjects;
105}
106
1c79356b
A
107/*********************************************************************
108* This function checks that a driver dict has all the required
109* entries and does a little bit of value checking too.
55e303ae
A
110*
111* index is nonnegative if the index of an entry from an mkext
112* archive.
1c79356b 113*********************************************************************/
55e303ae 114bool validateExtensionDict(OSDictionary * extension, int index) {
1c79356b
A
115
116 bool result = true;
55e303ae
A
117 bool not_a_dict = false;
118 bool id_missing = false;
119 bool is_kernel_resource = false;
120 bool has_executable = false;
0c530ab8 121 bool ineligible_for_safe_boot = false;
55e303ae
A
122 OSString * bundleIdentifier = NULL; // do not release
123 OSObject * rawValue = NULL; // do not release
124 OSString * stringValue = NULL; // do not release
125 OSBoolean * booleanValue = NULL; // do not release
126 OSDictionary * personalities = NULL; // do not release
127 OSDictionary * libraries = NULL; // do not release
128 OSCollectionIterator * keyIterator = NULL; // must release
129 OSString * key = NULL; // do not release
130 VERS_version vers;
131 VERS_version compatible_vers;
0c530ab8 132 char namep[16]; // unused but needed for PE_parse_boot_arg()
1c79356b 133
55e303ae
A
134 // Info dict is a dictionary
135 if (!OSDynamicCast(OSDictionary, extension)) {
136 not_a_dict = true;
137 result = false;
138 goto finish;
139 }
140
141 // CFBundleIdentifier is a string - REQUIRED
142 bundleIdentifier = OSDynamicCast(OSString,
1c79356b 143 extension->getObject("CFBundleIdentifier"));
55e303ae
A
144 if (!bundleIdentifier) {
145 id_missing = true;
1c79356b
A
146 result = false;
147 goto finish;
148 }
149
55e303ae
A
150 // Length of CFBundleIdentifier is not >= KMOD_MAX_NAME
151 if (bundleIdentifier->getLength() >= KMOD_MAX_NAME) {
152 result = false;
153 goto finish;
154 }
155
156 // CFBundlePackageType is "KEXT" - REQUIRED
157 stringValue = OSDynamicCast(OSString,
158 extension->getObject("CFBundlePackageType"));
159 if (!stringValue) {
160 result = false;
161 goto finish;
162 }
163 if (!stringValue->isEqualTo("KEXT")) {
164 result = false;
165 goto finish;
166 }
167
168 // CFBundleVersion is a string - REQUIRED
1c79356b
A
169 stringValue = OSDynamicCast(OSString,
170 extension->getObject("CFBundleVersion"));
171 if (!stringValue) {
1c79356b
A
172 result = false;
173 goto finish;
174 }
55e303ae
A
175 // CFBundleVersion is of valid form
176 vers = VERS_parse_string(stringValue->getCStringNoCopy());
177 if (vers < 0) {
1c79356b
A
178 result = false;
179 goto finish;
180 }
181
55e303ae
A
182 // OSBundleCompatibleVersion is a string - OPTIONAL
183 rawValue = extension->getObject("OSBundleCompatibleVersion");
184 if (rawValue) {
185 stringValue = OSDynamicCast(OSString, rawValue);
186 if (!stringValue) {
187 result = false;
188 goto finish;
189 }
190
191 // OSBundleCompatibleVersion is of valid form
192 compatible_vers = VERS_parse_string(stringValue->getCStringNoCopy());
193 if (compatible_vers < 0) {
194 result = false;
195 goto finish;
196 }
197
198 // OSBundleCompatibleVersion <= CFBundleVersion
199 if (compatible_vers > vers) {
200 result = false;
201 goto finish;
202 }
203 }
204
205 // CFBundleExecutable is a string - OPTIONAL
206 rawValue = extension->getObject("CFBundleExecutable");
207 if (rawValue) {
208 stringValue = OSDynamicCast(OSString, rawValue);
209 if (!stringValue || stringValue->getLength() == 0) {
210 result = false;
211 goto finish;
212 }
213 has_executable = true;
214 }
215
216 // OSKernelResource is a boolean value - OPTIONAL
217 rawValue = extension->getObject("OSKernelResource");
218 if (rawValue) {
219 booleanValue = OSDynamicCast(OSBoolean, rawValue);
220 if (!booleanValue) {
221 result = false;
222 goto finish;
223 }
224 is_kernel_resource = booleanValue->isTrue();
225 }
226
227 // IOKitPersonalities is a dictionary - OPTIONAL
228 rawValue = extension->getObject("IOKitPersonalities");
229 if (rawValue) {
230 personalities = OSDynamicCast(OSDictionary, rawValue);
231 if (!personalities) {
232 result = false;
233 goto finish;
234 }
235
236 keyIterator = OSCollectionIterator::withCollection(personalities);
237 if (!keyIterator) {
238 IOLog("Error: Failed to allocate iterator for personalities.\n");
239 LOG_DELAY();
240 result = false;
241 goto finish;
242 }
243
244 while ((key = OSDynamicCast(OSString, keyIterator->getNextObject()))) {
245 OSDictionary * personality = NULL; // do not release
246
247 // Each personality is a dictionary
248 personality = OSDynamicCast(OSDictionary,
249 personalities->getObject(key));
250 if (!personality) {
251 result = false;
252 goto finish;
253 }
254
255 // IOClass exists as a string - REQUIRED
256 if (!OSDynamicCast(OSString, personality->getObject("IOClass"))) {
257 result = false;
258 goto finish;
259 }
260
261 // IOProviderClass exists as a string - REQUIRED
262 if (!OSDynamicCast(OSString,
263 personality->getObject("IOProviderClass"))) {
264
265 result = false;
266 goto finish;
267 }
268
269 // CFBundleIdentifier is a string - OPTIONAL - INSERT IF ABSENT!
270 rawValue = personality->getObject("CFBundleIdentifier");
271 if (!rawValue) {
272 personality->setObject("CFBundleIdentifier", bundleIdentifier);
273 } else {
274 OSString * personalityID = NULL; // do not release
275 personalityID = OSDynamicCast(OSString, rawValue);
276 if (!personalityID) {
277 result = false;
278 goto finish;
279 } else {
280 // Length of CFBundleIdentifier is not >= KMOD_MAX_NAME
281 if (personalityID->getLength() >= KMOD_MAX_NAME) {
282 result = false;
283 goto finish;
284 }
285 }
286 }
287
288 // IOKitDebug is a number - OPTIONAL
289 rawValue = personality->getObject("IOKitDebug");
290 if (rawValue && !OSDynamicCast(OSNumber, rawValue)) {
291 result = false;
292 goto finish;
293 }
294 }
295
296 keyIterator->release();
297 keyIterator = NULL;
298 }
299
300
301 // OSBundleLibraries is a dictionary - REQUIRED if
302 // not kernel resource & has executable
303 //
304 rawValue = extension->getObject("OSBundleLibraries");
305 if (!rawValue && !is_kernel_resource && has_executable) {
306 result = false;
307 goto finish;
308 }
309
310 if (rawValue) {
311 libraries = OSDynamicCast(OSDictionary, rawValue);
312 if (!libraries) {
313 result = false;
314 goto finish;
315 }
316
317 keyIterator = OSCollectionIterator::withCollection(libraries);
318 if (!keyIterator) {
319 IOLog("Error: Failed to allocate iterator for libraries.\n");
320 LOG_DELAY();
321 result = false;
322 goto finish;
323 }
324
325 while ((key = OSDynamicCast(OSString,
326 keyIterator->getNextObject()))) {
327
328 OSString * libraryVersion = NULL; // do not release
329
330 // Each key's length is not >= KMOD_MAX_NAME
331 if (key->getLength() >= KMOD_MAX_NAME) {
332 result = false;
333 goto finish;
334 }
335
336 libraryVersion = OSDynamicCast(OSString,
337 libraries->getObject(key));
338 if (!libraryVersion) {
339 result = false;
340 goto finish;
341 }
342
343 // Each value is a valid version string
344 vers = VERS_parse_string(libraryVersion->getCStringNoCopy());
345 if (vers < 0) {
346 result = false;
347 goto finish;
348 }
349 }
350
351 keyIterator->release();
352 keyIterator = NULL;
353 }
354
0c530ab8
A
355 // OSBundleRequired, if present, must have a legal value.
356 // If it is not present and if we are safe-booting,
357 // then the kext is not eligible.
358 //
55e303ae
A
359 rawValue = extension->getObject("OSBundleRequired");
360 if (rawValue) {
361 stringValue = OSDynamicCast(OSString, rawValue);
362 if (!stringValue) {
363 result = false;
364 goto finish;
365 }
366 if (!stringValue->isEqualTo("Root") &&
367 !stringValue->isEqualTo("Local-Root") &&
368 !stringValue->isEqualTo("Network-Root") &&
369 !stringValue->isEqualTo("Safe Boot") &&
370 !stringValue->isEqualTo("Console")) {
371
372 result = false;
373 goto finish;
374 }
375
0c530ab8
A
376 } else if (PE_parse_boot_arg("-x", namep)) { /* safe boot */
377 ineligible_for_safe_boot = true;
378 result = false;
379 goto finish;
55e303ae
A
380 }
381
1c79356b
A
382
383finish:
55e303ae
A
384 if (keyIterator) keyIterator->release();
385
386 if (!result) {
0c530ab8
A
387 if (ineligible_for_safe_boot) {
388 IOLog(VTYELLOW "Skipping extension \"%s\" during safe boot "
389 "(no OSBundleRequired property)\n"
390 VTRESET,
391 bundleIdentifier->getCStringNoCopy());
392 } else if (not_a_dict) {
55e303ae 393 if (index > -1) {
0c530ab8 394 IOLog(VTYELLOW "mkext entry %d: " VTRESET, index);
55e303ae 395 } else {
0c530ab8 396 IOLog(VTYELLOW "kernel extension " VTRESET);
55e303ae
A
397 }
398 IOLog(VTYELLOW "info dictionary isn't a dictionary\n"
399 VTRESET);
400 } else if (id_missing) {
401 if (index > -1) {
0c530ab8 402 IOLog(VTYELLOW "mkext entry %d: " VTRESET, index);
55e303ae 403 } else {
0c530ab8 404 IOLog(VTYELLOW "kernel extension " VTRESET);
55e303ae
A
405 }
406 IOLog(VTYELLOW "\"CFBundleIdentifier\" property is "
407 "missing or not a string\n"
408 VTRESET);
409 } else {
410 IOLog(VTYELLOW "kernel extension \"%s\": info dictionary is invalid\n"
411 VTRESET, bundleIdentifier->getCStringNoCopy());
412 }
413 LOG_DELAY();
414 }
1c79356b
A
415
416 return result;
417}
418
419
420/*********************************************************************
421*********************************************************************/
422OSDictionary * compareExtensionVersions(
423 OSDictionary * incumbent,
424 OSDictionary * candidate) {
425
426 OSDictionary * winner = NULL;
427
428 OSDictionary * incumbentPlist = NULL;
429 OSDictionary * candidatePlist = NULL;
430 OSString * incumbentName = NULL;
431 OSString * candidateName = NULL;
432 OSString * incumbentVersionString = NULL;
433 OSString * candidateVersionString = NULL;
55e303ae
A
434 VERS_version incumbent_vers = 0;
435 VERS_version candidate_vers = 0;
1c79356b
A
436
437 incumbentPlist = OSDynamicCast(OSDictionary,
438 incumbent->getObject("plist"));
439 candidatePlist = OSDynamicCast(OSDictionary,
440 candidate->getObject("plist"));
441
442 if (!incumbentPlist || !candidatePlist) {
443 IOLog("compareExtensionVersions() called with invalid "
444 "extension dictionaries.\n");
445 LOG_DELAY();
446 winner = NULL;
447 goto finish;
448 }
449
450 incumbentName = OSDynamicCast(OSString,
451 incumbentPlist->getObject("CFBundleIdentifier"));
452 candidateName = OSDynamicCast(OSString,
453 candidatePlist->getObject("CFBundleIdentifier"));
454 incumbentVersionString = OSDynamicCast(OSString,
455 incumbentPlist->getObject("CFBundleVersion"));
456 candidateVersionString = OSDynamicCast(OSString,
457 candidatePlist->getObject("CFBundleVersion"));
458
459 if (!incumbentName || !candidateName ||
460 !incumbentVersionString || !candidateVersionString) {
461
462 IOLog("compareExtensionVersions() called with invalid "
463 "extension dictionaries.\n");
464 LOG_DELAY();
465 winner = NULL;
466 goto finish;
467 }
468
469 if (strcmp(incumbentName->getCStringNoCopy(),
470 candidateName->getCStringNoCopy())) {
471
472 IOLog("compareExtensionVersions() called with different "
473 "extension names (%s and %s).\n",
474 incumbentName->getCStringNoCopy(),
475 candidateName->getCStringNoCopy());
476 LOG_DELAY();
477 winner = NULL;
478 goto finish;
479 }
480
55e303ae
A
481 incumbent_vers = VERS_parse_string(incumbentVersionString->getCStringNoCopy());
482 if (incumbent_vers < 0) {
1c79356b
A
483
484 IOLog(VTYELLOW "Error parsing version string for extension %s (%s)\n"
485 VTRESET,
486 incumbentName->getCStringNoCopy(),
487 incumbentVersionString->getCStringNoCopy());
488 LOG_DELAY();
489 winner = NULL;
490 goto finish;
491 }
492
55e303ae
A
493 candidate_vers = VERS_parse_string(candidateVersionString->getCStringNoCopy());
494 if (candidate_vers < 0) {
1c79356b
A
495
496 IOLog(VTYELLOW "Error parsing version string for extension %s (%s)\n"
497 VTRESET,
498 candidateName->getCStringNoCopy(),
499 candidateVersionString->getCStringNoCopy());
500 LOG_DELAY();
501 winner = NULL;
502 goto finish;
503 }
504
505 if (candidate_vers > incumbent_vers) {
506 IOLog(VTYELLOW "Replacing extension \"%s\" with newer version "
507 "(%s -> %s).\n" VTRESET,
508 incumbentName->getCStringNoCopy(),
509 incumbentVersionString->getCStringNoCopy(),
510 candidateVersionString->getCStringNoCopy());
511 LOG_DELAY();
512 winner = candidate;
513 goto finish;
514 } else {
515 IOLog(VTYELLOW "Skipping duplicate extension \"%s\" with older/same "
516 " version (%s -> %s).\n" VTRESET,
517 candidateName->getCStringNoCopy(),
518 candidateVersionString->getCStringNoCopy(),
519 incumbentVersionString->getCStringNoCopy());
520 LOG_DELAY();
521 winner = incumbent;
522 goto finish;
523 }
524
525finish:
526
527 // no cleanup, how nice
528 return winner;
529}
530
531
532/*********************************************************************
533* This function merges entries in the mergeFrom dictionary into the
534* mergeInto dictionary. If it returns false, the two dictionaries are
535* not altered. If it returns true, then mergeInto may have new
536* entries; any keys that were already present in mergeInto are
537* removed from mergeFrom, so that the caller can see what was
538* actually merged.
539*********************************************************************/
540bool mergeExtensionDictionaries(OSDictionary * mergeInto,
541 OSDictionary * mergeFrom) {
542
543 bool result = true;
544 OSDictionary * mergeIntoCopy = NULL; // must release
545 OSDictionary * mergeFromCopy = NULL; // must release
546 OSCollectionIterator * keyIterator = NULL; // must release
547 OSString * key; // don't release
548
549 /* Add 1 to count to guarantee copy can grow (grr).
550 */
551 mergeIntoCopy = OSDictionary::withDictionary(mergeInto,
552 mergeInto->getCount() + 1);
553 if (!mergeIntoCopy) {
554 IOLog("Error: Failed to copy 'into' extensions dictionary "
555 "for merge.\n");
556 LOG_DELAY();
557 result = false;
558 goto finish;
559 }
560
561 /* Add 1 to count to guarantee copy can grow (grr).
562 */
563 mergeFromCopy = OSDictionary::withDictionary(mergeFrom,
564 mergeFrom->getCount() + 1);
565 if (!mergeFromCopy) {
566 IOLog("Error: Failed to copy 'from' extensions dictionary "
567 "for merge.\n");
568 LOG_DELAY();
569 result = false;
570 goto finish;
571 }
572
573 keyIterator = OSCollectionIterator::withCollection(mergeFrom);
574 if (!keyIterator) {
575 IOLog("Error: Failed to allocate iterator for extensions.\n");
576 LOG_DELAY();
577 result = false;
578 goto finish;
579 }
580
581
582 /*****
583 * Loop through "from" dictionary, checking if the identifier already
584 * exists in the "into" dictionary and checking versions if it does.
585 */
586 while ((key = OSDynamicCast(OSString, keyIterator->getNextObject()))) {
587 OSDictionary * incumbentExt = OSDynamicCast(OSDictionary,
588 mergeIntoCopy->getObject(key));
589 OSDictionary * candidateExt = OSDynamicCast(OSDictionary,
590 mergeFrom->getObject(key));
591
592 if (!incumbentExt) {
593 if (!mergeIntoCopy->setObject(key, candidateExt)) {
594
595 /* This is a fatal error, so bail.
596 */
597 IOLog("mergeExtensionDictionaries(): Failed to add "
598 "identifier %s\n",
599 key->getCStringNoCopy());
600 LOG_DELAY();
601 result = false;
602 goto finish;
603 }
604 } else {
605 OSDictionary * mostRecentExtension =
606 compareExtensionVersions(incumbentExt, candidateExt);
607
608 if (mostRecentExtension == incumbentExt) {
609 mergeFromCopy->removeObject(key);
610 } else if (mostRecentExtension == candidateExt) {
611
612 if (!mergeIntoCopy->setObject(key, candidateExt)) {
613
614 /* This is a fatal error, so bail.
615 */
616 IOLog("mergeExtensionDictionaries(): Failed to add "
617 "identifier %s\n",
618 key->getCStringNoCopy());
619 LOG_DELAY();
620 result = false;
621 goto finish;
622 }
623 } else /* should be NULL */ {
624
625 /* This is a nonfatal error, so continue doing others.
626 */
627 IOLog("mergeExtensionDictionaries(): Error comparing "
628 "versions of duplicate extensions %s.\n",
629 key->getCStringNoCopy());
630 LOG_DELAY();
631 continue;
632 }
633 }
634 }
635
636finish:
637
638 /* If successful, replace the contents of the original
639 * dictionaries with those of the modified copies.
640 */
641 if (result) {
642 mergeInto->flushCollection();
643 mergeInto->merge(mergeIntoCopy);
644 mergeFrom->flushCollection();
645 mergeFrom->merge(mergeFromCopy);
646 }
647
648 if (mergeIntoCopy) mergeIntoCopy->release();
649 if (mergeFromCopy) mergeFromCopy->release();
650 if (keyIterator) keyIterator->release();
651
652 return result;
653}
654
655
656/****
657 * These bits are used to parse data made available by bootx.
658 */
659#define BOOTX_KEXT_PREFIX "Driver-"
660#define BOOTX_MULTIKEXT_PREFIX "DriversPackage-"
661
662typedef struct MemoryMapFileInfo {
663 UInt32 paddr;
664 UInt32 length;
665} MemoryMapFileInfo;
666
667typedef struct BootxDriverInfo {
668 char *plistAddr;
669 long plistLength;
670 void *moduleAddr;
671 long moduleLength;
672} BootxDriverInfo;
673
0b4e3aa0
A
674typedef struct MkextEntryInfo {
675 vm_address_t base_address;
676 mkext_file * fileinfo;
677} MkextEntryInfo;
678
1c79356b
A
679
680/*********************************************************************
681* This private function reads the data for a single extension from
682* the bootx memory-map's propery dict, returning a dictionary with
683* keys "plist" for the extension's Info.plist as a parsed OSDictionary
684* and "code" for the extension's executable code as an OSData.
685*********************************************************************/
686OSDictionary * readExtension(OSDictionary * propertyDict,
687 const char * memory_map_name) {
688
689 int error = 0;
690 OSData * bootxDriverDataObject = NULL;
691 OSDictionary * driverPlist = NULL;
692 OSString * driverName = NULL;
693 OSData * driverCode = NULL;
694 OSString * errorString = NULL;
695 OSDictionary * driverDict = NULL;
696
2d21ac55 697 const MemoryMapFileInfo * driverInfo = 0;
1c79356b
A
698 BootxDriverInfo * dataBuffer;
699
700 kmod_info_t * loaded_kmod = NULL;
701
1c79356b
A
702 bootxDriverDataObject = OSDynamicCast(OSData,
703 propertyDict->getObject(memory_map_name));
704 // don't release bootxDriverDataObject
705
706 if (!bootxDriverDataObject) {
707 IOLog("Error: No driver data object "
708 "for device tree entry \"%s\".\n",
709 memory_map_name);
710 LOG_DELAY();
711 error = 1;
712 goto finish;
713 }
714
715 driverDict = OSDictionary::withCapacity(2);
716 if (!driverDict) {
717 IOLog("Error: Couldn't allocate dictionary "
718 "for device tree entry \"%s\".\n", memory_map_name);
719 LOG_DELAY();
720 error = 1;
721 goto finish;
722 }
723
2d21ac55 724 driverInfo = (const MemoryMapFileInfo *)
1c79356b
A
725 bootxDriverDataObject->getBytesNoCopy(0,
726 sizeof(MemoryMapFileInfo));
2d21ac55 727#if defined (__ppc__) || defined (__arm__)
0c530ab8 728 dataBuffer = (BootxDriverInfo *)ml_static_ptovirt(driverInfo->paddr);
91447636 729#elif defined (__i386__)
0c530ab8
A
730 dataBuffer = (BootxDriverInfo *)ml_boot_ptovirt(driverInfo->paddr);
731 dataBuffer->plistAddr = (char *)ml_boot_ptovirt((vm_address_t)dataBuffer->plistAddr);
91447636 732 if (dataBuffer->moduleAddr)
0c530ab8 733 dataBuffer->moduleAddr = (void *)ml_boot_ptovirt((vm_address_t)dataBuffer->moduleAddr);
91447636
A
734#else
735#error unsupported architecture
736#endif
1c79356b
A
737 if (!dataBuffer) {
738 IOLog("Error: No data buffer "
739 "for device tree entry \"%s\".\n", memory_map_name);
740 LOG_DELAY();
741 error = 1;
742 goto finish;
743 }
744
745 driverPlist = OSDynamicCast(OSDictionary,
746 OSUnserializeXML(dataBuffer->plistAddr, &errorString));
747 if (!driverPlist) {
748 IOLog("Error: Couldn't read XML property list "
749 "for device tree entry \"%s\".\n", memory_map_name);
750 LOG_DELAY();
751 if (errorString) {
752 IOLog("XML parse error: %s.\n",
753 errorString->getCStringNoCopy());
754 LOG_DELAY();
755 }
756 error = 1;
757 goto finish;
758 }
759
760
761 driverName = OSDynamicCast(OSString,
762 driverPlist->getObject("CFBundleIdentifier")); // do not release
763 if (!driverName) {
764 IOLog("Error: Device tree entry \"%s\" has "
765 "no \"CFBundleIdentifier\" property.\n", memory_map_name);
766 LOG_DELAY();
767 error = 1;
768 goto finish;
769 }
770
771 /* Check if kmod is already loaded and is a real loadable one (has
772 * an address).
773 */
9bccf70c 774 loaded_kmod = kmod_lookupbyname_locked(driverName->getCStringNoCopy());
1c79356b
A
775 if (loaded_kmod && loaded_kmod->address) {
776 IOLog("Skipping new extension \"%s\"; an extension named "
777 "\"%s\" is already loaded.\n",
778 driverName->getCStringNoCopy(),
779 loaded_kmod->name);
780 LOG_DELAY();
781 error = 1;
782 goto finish;
783 }
784
55e303ae
A
785 if (!validateExtensionDict(driverPlist, -1)) {
786 // validateExtensionsDict() logs an error
1c79356b
A
787 error = 1;
788 goto finish;
789 }
790
791 driverDict->setObject("plist", driverPlist);
792
793 /* It's perfectly okay for a KEXT to have no executable.
794 * Check that moduleAddr is nonzero before attempting to
795 * get one.
0b4e3aa0
A
796 *
797 * NOTE: The driverCode object is created "no-copy", so
798 * it doesn't own that memory. The memory must be freed
799 * separately from the OSData object (see
800 * clearStartupExtensionsAndLoaderInfo() at the end of this file).
1c79356b
A
801 */
802 if (dataBuffer->moduleAddr && dataBuffer->moduleLength) {
0b4e3aa0 803 driverCode = OSData::withBytesNoCopy(dataBuffer->moduleAddr,
1c79356b
A
804 dataBuffer->moduleLength);
805 if (!driverCode) {
806 IOLog("Error: Couldn't allocate data object "
807 "to hold code for device tree entry \"%s\".\n",
808 memory_map_name);
809 LOG_DELAY();
810 error = 1;
811 goto finish;
812 }
813
814 if (driverCode) {
815 driverDict->setObject("code", driverCode);
816 }
817 }
818
819finish:
820
9bccf70c 821 if (loaded_kmod) {
0c530ab8 822 kfree(loaded_kmod, sizeof(kmod_info_t));
9bccf70c
A
823 }
824
1c79356b
A
825 // do not release bootxDriverDataObject
826 // do not release driverName
827
828 if (driverPlist) {
829 driverPlist->release();
830 }
831 if (errorString) {
832 errorString->release();
833 }
834 if (driverCode) {
835 driverCode->release();
836 }
837 if (error) {
838 if (driverDict) {
839 driverDict->release();
840 driverDict = NULL;
841 }
842 }
843 return driverDict;
844}
845
846
847/*********************************************************************
848* Used to uncompress a single file entry in an mkext archive.
0b4e3aa0
A
849*
850* The OSData returned does not own its memory! You must deallocate
851* that memory using kmem_free() before releasing the OSData().
1c79356b 852*********************************************************************/
0b4e3aa0
A
853static bool uncompressFile(u_int8_t *base_address, mkext_file * fileinfo,
854 /* out */ OSData ** file) {
1c79356b 855
0b4e3aa0
A
856 bool result = true;
857 kern_return_t kern_result;
858 u_int8_t * uncompressed_file = 0; // kmem_free() on error
859 OSData * uncompressedFile = 0; // returned
1c79356b
A
860 size_t uncompressed_size = 0;
861
862 size_t offset = OSSwapBigToHostInt32(fileinfo->offset);
863 size_t compsize = OSSwapBigToHostInt32(fileinfo->compsize);
864 size_t realsize = OSSwapBigToHostInt32(fileinfo->realsize);
865 time_t modifiedsecs = OSSwapBigToHostInt32(fileinfo->modifiedsecs);
866
867 *file = 0;
868
869 /* If these four fields are zero there's no file, but that isn't
870 * an error.
871 */
872 if (offset == 0 && compsize == 0 &&
873 realsize == 0 && modifiedsecs == 0) {
874 goto finish;
875 }
876
877 // Add 1 for '\0' to terminate XML string!
0b4e3aa0
A
878 kern_result = kmem_alloc(kernel_map, (vm_offset_t *)&uncompressed_file,
879 realsize + 1);
880 if (kern_result != KERN_SUCCESS) {
1c79356b
A
881 IOLog("Error: Couldn't allocate data buffer "
882 "to uncompress file.\n");
883 LOG_DELAY();
0b4e3aa0 884 result = false;
1c79356b
A
885 goto finish;
886 }
887
888 uncompressedFile = OSData::withBytesNoCopy(uncompressed_file,
889 realsize + 1);
890 if (!uncompressedFile) {
891 IOLog("Error: Couldn't allocate data object "
892 "to uncompress file.\n");
893 LOG_DELAY();
0b4e3aa0 894 result = false;
1c79356b
A
895 goto finish;
896 }
897
898 if (compsize != 0) {
899 uncompressed_size = decompress_lzss(uncompressed_file,
900 base_address + offset,
901 compsize);
902 if (uncompressed_size != realsize) {
903 IOLog("Error: Uncompressed file is not the length "
904 "recorded.\n");
905 LOG_DELAY();
0b4e3aa0 906 result = false;
1c79356b
A
907 goto finish;
908 }
9bccf70c 909 uncompressed_file[uncompressed_size] = '\0';
1c79356b
A
910 } else {
911 bcopy(base_address + offset, uncompressed_file,
9bccf70c
A
912 realsize);
913 uncompressed_file[realsize] = '\0';
1c79356b 914 }
1c79356b
A
915
916 *file = uncompressedFile;
917
918finish:
919 if (!result) {
0b4e3aa0
A
920 if (uncompressed_file) {
921 kmem_free(kernel_map, (vm_address_t)uncompressed_file,
922 realsize + 1);
923 }
1c79356b
A
924 if (uncompressedFile) {
925 uncompressedFile->release();
926 *file = 0;
927 }
928 }
929 return result;
930}
931
0b4e3aa0
A
932bool uncompressModule(OSData *compData, /* out */ OSData ** file) {
933
2d21ac55 934 const MkextEntryInfo *info = (const MkextEntryInfo *) compData->getBytesNoCopy();
0b4e3aa0
A
935
936 return uncompressFile((u_int8_t *) info->base_address,
937 info->fileinfo, file);
938}
939
1c79356b
A
940
941/*********************************************************************
942* Does the work of pulling extensions out of an mkext archive located
943* in memory.
944*********************************************************************/
2d21ac55
A
945bool extractExtensionsFromArchive(const MemoryMapFileInfo * mkext_file_info,
946 bool vaddr,
1c79356b
A
947 OSDictionary * extensions) {
948
949 bool result = true;
950
951 u_int8_t * crc_address = 0;
952 u_int32_t checksum;
953 mkext_header * mkext_data = 0; // don't free
954 mkext_kext * onekext_data = 0; // don't free
955 mkext_file * plist_file = 0; // don't free
956 mkext_file * module_file = 0; // don't free
9bccf70c
A
957 kmod_info_t * loaded_kmod = 0; // must free
958
1c79356b
A
959 OSData * driverPlistDataObject = 0; // must release
960 OSDictionary * driverPlist = 0; // must release
961 OSData * driverCode = 0; // must release
962 OSDictionary * driverDict = 0; // must release
963 OSString * moduleName = 0; // don't release
964 OSString * errorString = NULL; // must release
965
0b4e3aa0
A
966 OSData * moduleInfo = 0; // must release
967 MkextEntryInfo module_info;
968
2d21ac55
A
969 if (vaddr) {
970 // addExtensionsFromArchive passes a kernel virtual address
971 mkext_data = (mkext_header *)mkext_file_info->paddr;
972 } else {
973#if defined (__ppc__) || defined (__arm__)
974 mkext_data = (mkext_header *)ml_static_ptovirt(mkext_file_info->paddr);
91447636 975#elif defined (__i386__)
2d21ac55 976 mkext_data = (mkext_header *)ml_boot_ptovirt(mkext_file_info->paddr);
91447636
A
977#else
978#error unsupported architecture
979#endif
2d21ac55
A
980 }
981
1c79356b
A
982 if (OSSwapBigToHostInt32(mkext_data->magic) != MKEXT_MAGIC ||
983 OSSwapBigToHostInt32(mkext_data->signature) != MKEXT_SIGN) {
984 IOLog("Error: Extension archive has invalid magic or signature.\n");
985 LOG_DELAY();
986 result = false;
987 goto finish;
988 }
989
990 if (OSSwapBigToHostInt32(mkext_data->length) != mkext_file_info->length) {
991 IOLog("Error: Mismatch between extension archive & "
992 "recorded length.\n");
993 LOG_DELAY();
994 result = false;
995 goto finish;
996 }
997
998 crc_address = (u_int8_t *)&mkext_data->version;
999 checksum = adler32(crc_address,
1000 (unsigned int)mkext_data +
1001 OSSwapBigToHostInt32(mkext_data->length) - (unsigned int)crc_address);
1002
1003 if (OSSwapBigToHostInt32(mkext_data->adler32) != checksum) {
1004 IOLog("Error: Extension archive has a bad checksum.\n");
1005 LOG_DELAY();
1006 result = false;
1007 goto finish;
1008 }
1009
0c530ab8
A
1010 IORegistryEntry * root = IORegistryEntry::getRegistryRoot();
1011 assert(root);
1012 OSData * checksumObj = OSData::withBytes((void *)&checksum,
1013 sizeof(checksum));
1014 assert(checksumObj);
1015 if (checksumObj) {
1016 root->setProperty(kIOStartupMkextCRC, checksumObj);
1017 checksumObj->release();
1018 }
1019
1c79356b
A
1020 /* If the MKEXT archive isn't fat, check that the CPU type & subtype
1021 * match that of the running kernel.
1022 */
1023 if (OSSwapBigToHostInt32(mkext_data->cputype) != (UInt32)CPU_TYPE_ANY) {
1024 kern_return_t kresult = KERN_FAILURE;
1025 host_basic_info_data_t hostinfo;
1026 host_info_t hostinfo_ptr = (host_info_t)&hostinfo;
1027 mach_msg_type_number_t count = sizeof(hostinfo)/sizeof(integer_t);
1028
1029 kresult = host_info((host_t)1, HOST_BASIC_INFO,
1030 hostinfo_ptr, &count);
1031 if (kresult != KERN_SUCCESS) {
1032 IOLog("Error: Couldn't get current host info.\n");
1033 LOG_DELAY();
1034 result = false;
1035 goto finish;
1036 }
1037 if ((UInt32)hostinfo.cpu_type !=
1038 OSSwapBigToHostInt32(mkext_data->cputype)) {
1039
1040 IOLog("Error: Extension archive doesn't contain software "
1041 "for this computer's CPU type.\n");
1042 LOG_DELAY();
1043 result = false;
1044 goto finish;
1045 }
91447636
A
1046 if (!grade_binary(OSSwapBigToHostInt32(mkext_data->cputype),
1047 OSSwapBigToHostInt32(mkext_data->cpusubtype))) {
1c79356b
A
1048 IOLog("Error: Extension archive doesn't contain software "
1049 "for this computer's CPU subtype.\n");
1050 LOG_DELAY();
1051 result = false;
1052 goto finish;
1053 }
1054 }
1055
1056 for (unsigned int i = 0;
1057 i < OSSwapBigToHostInt32(mkext_data->numkexts);
1058 i++) {
1059
9bccf70c 1060 if (loaded_kmod) {
0c530ab8 1061 kfree(loaded_kmod, sizeof(kmod_info_t));
9bccf70c
A
1062 loaded_kmod = 0;
1063 }
1c79356b
A
1064
1065 if (driverPlistDataObject) {
55e303ae
A
1066 kmem_free(kernel_map,
1067 (unsigned int)driverPlistDataObject->getBytesNoCopy(),
1068 driverPlistDataObject->getLength());
1069
1c79356b
A
1070 driverPlistDataObject->release();
1071 driverPlistDataObject = NULL;
1072 }
1073 if (driverPlist) {
1074 driverPlist->release();
1075 driverPlist = NULL;
1076 }
1077 if (driverCode) {
1078 driverCode->release();
1079 driverCode = NULL;
1080 }
1081 if (driverDict) {
1082 driverDict->release();
1083 driverDict = NULL;
1084 }
1085 if (errorString) {
1086 errorString->release();
1087 errorString = NULL;
1088 }
1089
1090 onekext_data = &mkext_data->kext[i];
1091 plist_file = &onekext_data->plist;
1092 module_file = &onekext_data->module;
1093
1094 if (!uncompressFile((u_int8_t *)mkext_data, plist_file,
1095 &driverPlistDataObject)) {
1096
1097 IOLog("Error: couldn't uncompress plist file "
0b4e3aa0 1098 "from multikext archive entry %d.\n", i);
1c79356b 1099 LOG_DELAY();
0b4e3aa0 1100 continue;
1c79356b
A
1101 }
1102
1103 if (!driverPlistDataObject) {
1104 IOLog("Error: No property list present "
1105 "for multikext archive entry %d.\n", i);
1106 LOG_DELAY();
0b4e3aa0 1107 continue;
1c79356b
A
1108 } else {
1109 driverPlist = OSDynamicCast(OSDictionary,
1110 OSUnserializeXML(
2d21ac55 1111 (const char *)driverPlistDataObject->getBytesNoCopy(),
1c79356b
A
1112 &errorString));
1113 if (!driverPlist) {
1114 IOLog("Error: Couldn't read XML property list "
1115 "for multikext archive entry %d.\n", i);
1116 LOG_DELAY();
1117 if (errorString) {
1118 IOLog("XML parse error: %s.\n",
1119 errorString->getCStringNoCopy());
1120 LOG_DELAY();
1121 }
0b4e3aa0 1122 continue;
1c79356b
A
1123 }
1124
55e303ae
A
1125 if (!validateExtensionDict(driverPlist, i)) {
1126 // validateExtensionsDict() logs an error
0b4e3aa0 1127 continue;
1c79356b
A
1128 }
1129
1130 }
1131
1132 /* Get the extension's module name. This is used to record
1133 * the extension.
1134 */
1135 moduleName = OSDynamicCast(OSString,
1136 driverPlist->getObject("CFBundleIdentifier")); // do not release
1137 if (!moduleName) {
1138 IOLog("Error: Multikext archive entry %d has "
1139 "no \"CFBundleIdentifier\" property.\n", i);
1140 LOG_DELAY();
1141 continue; // assume a kext config error & continue
1142 }
1143
1144 /* Check if kmod is already loaded and is a real loadable one (has
1145 * an address).
1146 */
9bccf70c 1147 loaded_kmod = kmod_lookupbyname_locked(moduleName->getCStringNoCopy());
1c79356b
A
1148 if (loaded_kmod && loaded_kmod->address) {
1149 IOLog("Skipping new extension \"%s\"; an extension named "
1150 "\"%s\" is already loaded.\n",
1151 moduleName->getCStringNoCopy(),
1152 loaded_kmod->name);
1153 continue;
1154 }
1155
1156
1157 driverDict = OSDictionary::withCapacity(2);
1158 if (!driverDict) {
1159 IOLog("Error: Couldn't allocate dictionary "
1160 "for multikext archive entry %d.\n", i);
1161 LOG_DELAY();
1162 result = false;
1163 goto finish;
1164 }
1165
1166 driverDict->setObject("plist", driverPlist);
1167
0b4e3aa0
A
1168 /*****
1169 * Prepare an entry to hold the mkext entry info for the
1170 * compressed binary module, if there is one. If all four fields
1171 * of the module entry are zero, there isn't one.
1172 */
55e303ae 1173 if (!(loaded_kmod && loaded_kmod->address) && (OSSwapBigToHostInt32(module_file->offset) ||
0b4e3aa0
A
1174 OSSwapBigToHostInt32(module_file->compsize) ||
1175 OSSwapBigToHostInt32(module_file->realsize) ||
55e303ae 1176 OSSwapBigToHostInt32(module_file->modifiedsecs))) {
0b4e3aa0
A
1177
1178 moduleInfo = OSData::withCapacity(sizeof(MkextEntryInfo));
1179 if (!moduleInfo) {
1180 IOLog("Error: Couldn't allocate data object "
1181 "for multikext archive entry %d.\n", i);
1182 LOG_DELAY();
1183 result = false;
1184 goto finish;
1185 }
1186
1187 module_info.base_address = (vm_address_t)mkext_data;
1188 module_info.fileinfo = module_file;
1c79356b 1189
0b4e3aa0
A
1190 if (!moduleInfo->appendBytes(&module_info, sizeof(module_info))) {
1191 IOLog("Error: Couldn't record info "
1192 "for multikext archive entry %d.\n", i);
1193 LOG_DELAY();
1194 result = false;
1195 goto finish;
1196 }
1c79356b 1197
0b4e3aa0 1198 driverDict->setObject("compressedCode", moduleInfo);
1c79356b
A
1199 }
1200
1201 OSDictionary * incumbentExt = OSDynamicCast(OSDictionary,
1202 extensions->getObject(moduleName));
1203
1204 if (!incumbentExt) {
1205 extensions->setObject(moduleName, driverDict);
1206 } else {
1207 OSDictionary * mostRecentExtension =
1208 compareExtensionVersions(incumbentExt, driverDict);
1209
1210 if (mostRecentExtension == incumbentExt) {
1211 /* Do nothing, we've got the most recent. */
1212 } else if (mostRecentExtension == driverDict) {
1213 if (!extensions->setObject(moduleName, driverDict)) {
1214
1215 /* This is a fatal error, so bail.
1216 */
1217 IOLog("extractExtensionsFromArchive(): Failed to add "
1218 "identifier %s\n",
1219 moduleName->getCStringNoCopy());
1220 LOG_DELAY();
1221 result = false;
1222 goto finish;
1223 }
1224 } else /* should be NULL */ {
1225
1226 /* This is a nonfatal error, so continue.
1227 */
1228 IOLog("extractExtensionsFromArchive(): Error comparing "
1229 "versions of duplicate extensions %s.\n",
1230 moduleName->getCStringNoCopy());
1231 LOG_DELAY();
1232 continue;
1233 }
1234 }
1235 }
1236
1237finish:
1238
0c530ab8 1239 if (loaded_kmod) kfree(loaded_kmod, sizeof(kmod_info_t));
55e303ae
A
1240 if (driverPlistDataObject) {
1241 kmem_free(kernel_map,
1242 (unsigned int)driverPlistDataObject->getBytesNoCopy(),
1243 driverPlistDataObject->getLength());
1244 driverPlistDataObject->release();
1245 }
1c79356b 1246 if (driverPlist) driverPlist->release();
0b4e3aa0
A
1247 if (driverCode) driverCode->release();
1248 if (moduleInfo) moduleInfo->release();
1249 if (driverDict) driverDict->release();
1c79356b
A
1250 if (errorString) errorString->release();
1251
1252 return result;
1253}
1254
1c79356b 1255/*********************************************************************
0b4e3aa0 1256*
1c79356b
A
1257*********************************************************************/
1258bool readExtensions(OSDictionary * propertyDict,
1259 const char * memory_map_name,
1260 OSDictionary * extensions) {
1261
1262 bool result = true;
1263 OSData * mkextDataObject = 0; // don't release
2d21ac55 1264 const MemoryMapFileInfo * mkext_file_info = 0; // don't free
1c79356b
A
1265
1266 mkextDataObject = OSDynamicCast(OSData,
1267 propertyDict->getObject(memory_map_name));
1268 // don't release mkextDataObject
1269
1270 if (!mkextDataObject) {
1271 IOLog("Error: No mkext data object "
1272 "for device tree entry \"%s\".\n",
1273 memory_map_name);
1274 LOG_DELAY();
1275 result = false;
1276 goto finish;
1277 }
1278
2d21ac55 1279 mkext_file_info = (const MemoryMapFileInfo *)mkextDataObject->getBytesNoCopy();
1c79356b
A
1280 if (!mkext_file_info) {
1281 result = false;
1282 goto finish;
1283 }
1284
2d21ac55 1285 result = extractExtensionsFromArchive(mkext_file_info, false /*physical*/, extensions);
1c79356b
A
1286
1287finish:
1288
1289 if (!result && extensions) {
1290 extensions->flushCollection();
1291 }
1292
1c79356b
A
1293 return result;
1294}
1295
1296
1297/*********************************************************************
1298* Adds the personalities for an extensions dictionary to the global
1299* IOCatalogue.
1300*********************************************************************/
1301bool addPersonalities(OSDictionary * extensions) {
1302 bool result = true;
1303 OSCollectionIterator * keyIterator = NULL; // must release
1304 OSString * key; // don't release
1305 OSDictionary * driverDict = NULL; // don't release
1306 OSDictionary * driverPlist = NULL; // don't release
1307 OSDictionary * thisDriverPersonalities = NULL; // don't release
1308 OSArray * allDriverPersonalities = NULL; // must release
1309
1310 allDriverPersonalities = OSArray::withCapacity(1);
1311 if (!allDriverPersonalities) {
1312 IOLog("Error: Couldn't allocate personality dictionary.\n");
1313 LOG_DELAY();
1314 result = false;
1315 goto finish;
1316 }
1317
1318 /* Record all personalities found so that they can be
1319 * added to the catalogue.
1320 * Note: Not all extensions have personalities.
1321 */
1322
1323 keyIterator = OSCollectionIterator::withCollection(extensions);
1324 if (!keyIterator) {
1325 IOLog("Error: Couldn't allocate iterator to record personalities.\n");
1326 LOG_DELAY();
1327 result = false;
1328 goto finish;
1329 }
1330
1331 while ( ( key = OSDynamicCast(OSString,
1332 keyIterator->getNextObject() ))) {
1333
1334 driverDict = OSDynamicCast(OSDictionary,
1335 extensions->getObject(key));
1336 driverPlist = OSDynamicCast(OSDictionary,
1337 driverDict->getObject("plist"));
1338 thisDriverPersonalities = OSDynamicCast(OSDictionary,
1339 driverPlist->getObject("IOKitPersonalities"));
1340
1341 if (thisDriverPersonalities) {
1342 OSCollectionIterator * pIterator;
91447636 1343 OSString * locakKey;
1c79356b
A
1344 pIterator = OSCollectionIterator::withCollection(
1345 thisDriverPersonalities);
1346 if (!pIterator) {
1347 IOLog("Error: Couldn't allocate iterator "
1348 "to record extension personalities.\n");
1349 LOG_DELAY();
1350 continue;
1351 }
91447636 1352 while ( (locakKey = OSDynamicCast(OSString,
1c79356b
A
1353 pIterator->getNextObject())) ) {
1354
1355 OSDictionary * personality = OSDynamicCast(
1356 OSDictionary,
91447636 1357 thisDriverPersonalities->getObject(locakKey));
1c79356b
A
1358 if (personality) {
1359 allDriverPersonalities->setObject(personality);
1360 }
1361 }
1362 pIterator->release();
1363 }
1364 } /* extract personalities */
1365
1366
1367 /* Add all personalities found to the IOCatalogue,
1368 * but don't start matching.
1369 */
1370 gIOCatalogue->addDrivers(allDriverPersonalities, false);
1371
1372finish:
1373
1374 if (allDriverPersonalities) allDriverPersonalities->release();
1375 if (keyIterator) keyIterator->release();
1376
1377 return result;
1378}
1379
1380
1381/*********************************************************************
1382* Called from IOCatalogue to add extensions from an mkext archive.
0b4e3aa0
A
1383* This function makes a copy of the mkext object passed in because
1384* the device tree support code dumps it after calling us (indirectly
1385* through the IOCatalogue).
1c79356b
A
1386*********************************************************************/
1387bool addExtensionsFromArchive(OSData * mkextDataObject) {
1388 bool result = true;
1389
1390 OSDictionary * startupExtensions = NULL; // don't release
0b4e3aa0 1391 OSArray * bootLoaderObjects = NULL; // don't release
1c79356b
A
1392 OSDictionary * extensions = NULL; // must release
1393 MemoryMapFileInfo mkext_file_info;
1394 OSCollectionIterator * keyIterator = NULL; // must release
1395 OSString * key = NULL; // don't release
1396
1c79356b
A
1397 startupExtensions = getStartupExtensions();
1398 if (!startupExtensions) {
9bccf70c
A
1399 IOLog("Can't record extension archive; there is no"
1400 " extensions dictionary.\n");
1c79356b
A
1401 LOG_DELAY();
1402 result = false;
1403 goto finish;
1404 }
1405
0b4e3aa0
A
1406 bootLoaderObjects = getBootLoaderObjects();
1407 if (! bootLoaderObjects) {
1408 IOLog("Error: Couldn't allocate array to hold temporary objects.\n");
1409 LOG_DELAY();
1410 result = false;
1411 goto finish;
1412 }
1413
1c79356b
A
1414 extensions = OSDictionary::withCapacity(2);
1415 if (!extensions) {
1416 IOLog("Error: Couldn't allocate dictionary to unpack "
1417 "extension archive.\n");
1418 LOG_DELAY();
1419 result = false;
1420 goto finish;
1421 }
1422
55e303ae
A
1423 mkext_file_info.paddr = (UInt32)mkextDataObject->getBytesNoCopy();
1424 mkext_file_info.length = mkextDataObject->getLength();
0b4e3aa0
A
1425
1426 /* Save the local mkext data object so that we can deallocate it later.
1427 */
55e303ae 1428 bootLoaderObjects->setObject(mkextDataObject);
1c79356b 1429
2d21ac55 1430 result = extractExtensionsFromArchive(&mkext_file_info, true /*virtual*/, extensions);
1c79356b
A
1431 if (!result) {
1432 IOLog("Error: Failed to extract extensions from archive.\n");
1433 LOG_DELAY();
1434 result = false;
1435 goto finish;
1436 }
1437
1438 result = mergeExtensionDictionaries(startupExtensions, extensions);
1439 if (!result) {
1440 IOLog("Error: Failed to merge new extensions into existing set.\n");
1441 LOG_DELAY();
1442 goto finish;
1443 }
1444
1445 result = addPersonalities(extensions);
1446 if (!result) {
1447 IOLog("Error: Failed to add personalities for extensions extracted "
1448 "from archive.\n");
1449 LOG_DELAY();
1450 result = false;
1451 goto finish;
1452 }
1453
1454finish:
1455
1456 if (!result) {
1457 IOLog("Error: Failed to record extensions from archive.\n");
1458 LOG_DELAY();
1459 } else {
1460 keyIterator = OSCollectionIterator::withCollection(
1461 extensions);
1462
1463 if (keyIterator) {
1464 while ( (key = OSDynamicCast(OSString,
1465 keyIterator->getNextObject())) ) {
1466
1467 IOLog("Added extension \"%s\" from archive.\n",
1468 key->getCStringNoCopy());
1469 LOG_DELAY();
1470 }
1471 keyIterator->release();
1472 }
1473 }
1474
1475 if (extensions) extensions->release();
1476
1c79356b
A
1477 return result;
1478}
1479
1480
1481/*********************************************************************
1482* This function builds dictionaries for the startup extensions
1483* put into memory by bootx, recording each in the startup extensions
1484* dictionary. The dictionary format is this:
1485*
1486* {
1487* "plist" = (the extension's Info.plist as an OSDictionary)
1488* "code" = (an OSData containing the executable file)
1489* }
1490*
1491* This function returns true if any extensions were found and
1492* recorded successfully, or if there are no start extensions,
1493* and false if an unrecoverable error occurred. An error reading
1494* a single extension is not considered fatal, and this function
1495* will simply skip the problematic extension to try the next one.
1496*********************************************************************/
55e303ae 1497
1c79356b
A
1498bool recordStartupExtensions(void) {
1499 bool result = true;
1500 OSDictionary * startupExtensions = NULL; // must release
1501 OSDictionary * existingExtensions = NULL; // don't release
1502 OSDictionary * mkextExtensions = NULL; // must release
1503 IORegistryEntry * bootxMemoryMap = NULL; // must release
1504 OSDictionary * propertyDict = NULL; // must release
1505 OSCollectionIterator * keyIterator = NULL; // must release
1506 OSString * key = NULL; // don't release
1507
1508 OSDictionary * newDriverDict = NULL; // must release
1509 OSDictionary * driverPlist = NULL; // don't release
1510
55e303ae
A
1511 struct section * infosect;
1512 struct section * symsect;
1513 unsigned int prelinkedCount = 0;
1c79356b
A
1514
1515 existingExtensions = getStartupExtensions();
1516 if (!existingExtensions) {
1517 IOLog("Error: There is no dictionary for startup extensions.\n");
1518 LOG_DELAY();
1519 result = false;
1520 goto finish;
1521 }
1522
1523 startupExtensions = OSDictionary::withCapacity(1);
1524 if (!startupExtensions) {
1525 IOLog("Error: Couldn't allocate dictionary "
1526 "to record startup extensions.\n");
1527 LOG_DELAY();
1528 result = false;
1529 goto finish;
1530 }
1531
55e303ae
A
1532 // --
1533 // add any prelinked modules as startup extensions
1534
1535 infosect = getsectbyname("__PRELINK", "__info");
1536 symsect = getsectbyname("__PRELINK", "__symtab");
1537 if (infosect && infosect->addr && infosect->size
1538 && symsect && symsect->addr && symsect->size) do
1539 {
1540 gIOPrelinkedModules = OSDynamicCast(OSArray,
1541 OSUnserializeXML((const char *) infosect->addr, NULL));
1542
1543 if (!gIOPrelinkedModules)
1544 break;
1545 for( unsigned int idx = 0;
1546 (propertyDict = OSDynamicCast(OSDictionary, gIOPrelinkedModules->getObject(idx)));
1547 idx++)
1548 {
1549 enum { kPrelinkReservedCount = 4 };
1550
1551 /* Get the extension's module name. This is used to record
1552 * the extension. Do *not* release the moduleName.
1553 */
1554 OSString * moduleName = OSDynamicCast(OSString,
1555 propertyDict->getObject("CFBundleIdentifier"));
1556 if (!moduleName) {
1557 IOLog("Error: Prelinked module entry has "
1558 "no \"CFBundleIdentifier\" property.\n");
1559 LOG_DELAY();
1560 continue;
1561 }
1562
1563 /* Add the kext, & its plist.
1564 */
1565 newDriverDict = OSDictionary::withCapacity(4);
1566 assert(newDriverDict);
1567 newDriverDict->setObject("plist", propertyDict);
1568 startupExtensions->setObject(moduleName, newDriverDict);
1569 newDriverDict->release();
1570
1571 /* Add the code if present.
1572 */
1573 OSData * data = OSDynamicCast(OSData, propertyDict->getObject("OSBundlePrelink"));
1574 if (data) {
1575 if (data->getLength() < (kPrelinkReservedCount * sizeof(UInt32))) {
1576 IOLog("Error: Prelinked module entry has "
1577 "invalid \"OSBundlePrelink\" property.\n");
1578 LOG_DELAY();
1579 continue;
1580 }
2d21ac55
A
1581 const UInt32 * prelink;
1582 prelink = (const UInt32 *) data->getBytesNoCopy();
55e303ae
A
1583 kmod_info_t * kmod_info = (kmod_info_t *) OSReadBigInt32(prelink, 0);
1584 // end of "file" is end of symbol sect
1585 data = OSData::withBytesNoCopy((void *) kmod_info->address,
1586 symsect->addr + symsect->size - kmod_info->address);
1587 newDriverDict->setObject("code", data);
1588 data->release();
1589 prelinkedCount++;
1590 continue;
1591 }
1592 /* Add the symbols if present.
1593 */
1594 OSNumber * num = OSDynamicCast(OSNumber, propertyDict->getObject("OSBundlePrelinkSymbols"));
1595 if (num) {
1596 UInt32 offset = num->unsigned32BitValue();
1597 data = OSData::withBytesNoCopy((void *) (symsect->addr + offset), symsect->size - offset);
1598 newDriverDict->setObject("code", data);
1599 data->release();
1600 prelinkedCount++;
1601 continue;
1602 }
1603 }
1604 if (gIOPrelinkedModules)
1605 IOLog("%d prelinked modules\n", prelinkedCount);
1606
1607 // free __info
1608 vm_offset_t
1609 virt = ml_static_ptovirt(infosect->addr);
1610 if( virt) {
1611 ml_static_mfree(virt, infosect->size);
1612 }
1613 newDriverDict = NULL;
1614 }
1615 while (false);
1616 // --
1617
1c79356b
A
1618 bootxMemoryMap =
1619 IORegistryEntry::fromPath(
1620 "/chosen/memory-map", // path
1621 gIODTPlane // plane
1622 );
1623 // return value is retained so be sure to release it
1624
1625 if (!bootxMemoryMap) {
1626 IOLog("Error: Couldn't read booter memory map.\n");
1627 LOG_DELAY();
1628 result = false;
1629 goto finish;
1630 }
1631
1632 propertyDict = bootxMemoryMap->dictionaryWithProperties();
1633 if (!propertyDict) {
1634 IOLog("Error: Couldn't get property dictionary "
1635 "from memory map.\n");
1636 LOG_DELAY();
1637 result = false;
1638 goto finish;
1639 }
1640
1641 keyIterator = OSCollectionIterator::withCollection(propertyDict);
1642 if (!keyIterator) {
1643 IOLog("Error: Couldn't allocate iterator for driver images.\n");
1644 LOG_DELAY();
1645 result = false;
1646 goto finish;
1647 }
1648
1649 while ( (key = OSDynamicCast(OSString,
1650 keyIterator->getNextObject())) ) {
1c79356b
A
1651 /* Clear newDriverDict & mkextExtensions upon entry to the loop,
1652 * handling both successful and unsuccessful iterations.
1653 */
1654 if (newDriverDict) {
1655 newDriverDict->release();
1656 newDriverDict = NULL;
1657 }
1658 if (mkextExtensions) {
1659 mkextExtensions->release();
1660 mkextExtensions = NULL;
1661 }
1662
1663 const char * keyValue = key->getCStringNoCopy();
1664
1665 if ( !strncmp(keyValue, BOOTX_KEXT_PREFIX,
1666 strlen(BOOTX_KEXT_PREFIX)) ) {
1667
1668 /* Read the extension from the bootx-supplied memory.
1669 */
1670 newDriverDict = readExtension(propertyDict, keyValue);
1671 if (!newDriverDict) {
1672 IOLog("Error: Couldn't read data "
1673 "for device tree entry \"%s\".\n", keyValue);
1674 LOG_DELAY();
1675 continue;
1676 }
1677
1678
1679 /* Preprare to record the extension by getting its info plist.
1680 */
1681 driverPlist = OSDynamicCast(OSDictionary,
1682 newDriverDict->getObject("plist"));
1683 if (!driverPlist) {
1684 IOLog("Error: Extension in device tree entry \"%s\" "
1685 "has no property list.\n", keyValue);
1686 LOG_DELAY();
1687 continue;
1688 }
1689
1690
1691 /* Get the extension's module name. This is used to record
1692 * the extension. Do *not* release the moduleName.
1693 */
1694 OSString * moduleName = OSDynamicCast(OSString,
1695 driverPlist->getObject("CFBundleIdentifier"));
1696 if (!moduleName) {
1697 IOLog("Error: Device tree entry \"%s\" has "
1698 "no \"CFBundleIdentifier\" property.\n", keyValue);
1699 LOG_DELAY();
1700 continue;
1701 }
1702
1703
1704 /* All has gone well so far, so record the extension under
1705 * its module name, checking for an existing duplicate.
1706 *
1707 * Do not release moduleName, as it's part of the extension's
1708 * plist.
1709 */
1710 OSDictionary * incumbentExt = OSDynamicCast(OSDictionary,
1711 startupExtensions->getObject(moduleName));
1712
1713 if (!incumbentExt) {
1714 startupExtensions->setObject(moduleName, newDriverDict);
1715 } else {
1716 OSDictionary * mostRecentExtension =
1717 compareExtensionVersions(incumbentExt, newDriverDict);
1718
1719 if (mostRecentExtension == incumbentExt) {
1720 /* Do nothing, we've got the most recent. */
1721 } else if (mostRecentExtension == newDriverDict) {
1722 if (!startupExtensions->setObject(moduleName,
1723 newDriverDict)) {
1724
1725 /* This is a fatal error, so bail.
1726 */
1727 IOLog("recordStartupExtensions(): Failed to add "
1728 "identifier %s\n",
1729 moduleName->getCStringNoCopy());
1730 LOG_DELAY();
1731 result = false;
1732 goto finish;
1733 }
1734 } else /* should be NULL */ {
1735
1736 /* This is a nonfatal error, so continue.
1737 */
1738 IOLog("recordStartupExtensions(): Error comparing "
1739 "versions of duplicate extensions %s.\n",
1740 moduleName->getCStringNoCopy());
1741 LOG_DELAY();
1742 continue;
1743 }
1744 }
1745
1746
1747 } else if ( !strncmp(keyValue, BOOTX_MULTIKEXT_PREFIX,
1748 strlen(BOOTX_MULTIKEXT_PREFIX)) ) {
1749
1750 mkextExtensions = OSDictionary::withCapacity(10);
1751 if (!mkextExtensions) {
1752 IOLog("Error: Couldn't allocate dictionary to unpack "
1753 "multi-extension archive.\n");
1754 LOG_DELAY();
1755 result = false;
1756 goto finish; // allocation failure is fatal for this routine
1757 }
1758 if (!readExtensions(propertyDict, keyValue, mkextExtensions)) {
1759 IOLog("Error: Couldn't unpack multi-extension archive.\n");
1760 LOG_DELAY();
1761 continue;
1762 } else {
1763 if (!mergeExtensionDictionaries(startupExtensions,
1764 mkextExtensions)) {
1765
1766 IOLog("Error: Failed to merge new extensions into "
1767 "existing set.\n");
1768 LOG_DELAY();
1769 result = false;
1770 goto finish; // merge error is fatal for this routine
1771 }
1772 }
1773 }
1774
1775 // Do not release key.
1776
9bccf70c 1777 } /* while ( (key = OSDynamicCast(OSString, ...) ) ) */
1c79356b
A
1778
1779 if (!mergeExtensionDictionaries(existingExtensions, startupExtensions)) {
1780 IOLog("Error: Failed to merge new extensions into existing set.\n");
1781 LOG_DELAY();
1782 result = false;
1783 goto finish;
1784 }
1785
1786 result = addPersonalities(startupExtensions);
1787 if (!result) {
1788 IOLog("Error: Failed to add personalities for extensions extracted "
1789 "from archive.\n");
1790 LOG_DELAY();
1791 result = false;
1792 goto finish;
1793 }
1794
1795finish:
1796
1797 // reused so clear first!
1798 if (keyIterator) {
1799 keyIterator->release();
1800 keyIterator = 0;
1801 }
1802
1803 if (!result) {
1804 IOLog("Error: Failed to record startup extensions.\n");
1805 LOG_DELAY();
1806 } else {
0b4e3aa0 1807#if DEBUG
1c79356b
A
1808 keyIterator = OSCollectionIterator::withCollection(
1809 startupExtensions);
1810
1811 if (keyIterator) {
1812 while ( (key = OSDynamicCast(OSString,
1813 keyIterator->getNextObject())) ) {
1814
1815 IOLog("Found extension \"%s\".\n",
1816 key->getCStringNoCopy());
1817 LOG_DELAY();
1818 }
1819 keyIterator->release();
1820 keyIterator = 0;
1821 }
55e303ae 1822#endif /* DEBUG */
1c79356b
A
1823 }
1824
1825 if (newDriverDict) newDriverDict->release();
1826 if (propertyDict) propertyDict->release();
1827 if (bootxMemoryMap) bootxMemoryMap->release();
1828 if (mkextExtensions) mkextExtensions->release();
1829 if (startupExtensions) startupExtensions->release();
1830
1c79356b
A
1831 return result;
1832}
1833
1834
1835/*********************************************************************
1836* This function removes an entry from the dictionary of startup
1837* extensions. It's used when an extension can't be loaded, for
1838* whatever reason. For drivers, this allows another matching driver
1839* to be loaded, so that, for example, a driver for the root device
1840* can be found.
1841*********************************************************************/
1842void removeStartupExtension(const char * extensionName) {
1843 OSDictionary * startupExtensions = NULL; // don't release
1844 OSDictionary * extensionDict = NULL; // don't release
1845 OSDictionary * extensionPlist = NULL; // don't release
1846 OSDictionary * extensionPersonalities = NULL; // don't release
1847 OSDictionary * personality = NULL; // don't release
1848 OSCollectionIterator * keyIterator = NULL; // must release
1849 OSString * key = NULL; // don't release
1850
1c79356b
A
1851 startupExtensions = getStartupExtensions();
1852 if (!startupExtensions) goto finish;
1853
1854
1855 /* Find the extension's entry in the dictionary of
1856 * startup extensions.
1857 */
1858 extensionDict = OSDynamicCast(OSDictionary,
1859 startupExtensions->getObject(extensionName));
1860 if (!extensionDict) goto finish;
1861
1862 extensionPlist = OSDynamicCast(OSDictionary,
1863 extensionDict->getObject("plist"));
1864 if (!extensionPlist) goto finish;
1865
1866 extensionPersonalities = OSDynamicCast(OSDictionary,
1867 extensionPlist->getObject("IOKitPersonalities"));
1868 if (!extensionPersonalities) goto finish;
1869
1870 /* If it was there, remove it from the catalogue proper
1871 * by calling removeDrivers(). Pass true for the second
1872 * argument to trigger a new round of matching, and
1873 * then remove the extension from the dictionary of startup
1874 * extensions.
1875 */
1876 keyIterator = OSCollectionIterator::withCollection(
1877 extensionPersonalities);
1878 if (!keyIterator) {
9bccf70c
A
1879 IOLog("Error: Couldn't allocate iterator to scan"
1880 " personalities for %s.\n", extensionName);
1c79356b
A
1881 LOG_DELAY();
1882 }
1883
1884 while ((key = OSDynamicCast(OSString, keyIterator->getNextObject()))) {
1885 personality = OSDynamicCast(OSDictionary,
1886 extensionPersonalities->getObject(key));
1887
1888
1889 if (personality) {
1890 gIOCatalogue->removeDrivers(personality, true);
1891 }
1892 }
1893
1894 startupExtensions->removeObject(extensionName);
1895
1896finish:
1897
1898 if (keyIterator) keyIterator->release();
0b4e3aa0
A
1899 return;
1900}
1901
1902/*********************************************************************
1903* FIXME: This function invalidates the globals gStartupExtensions and
1904* FIXME: ...gBootLoaderObjects without setting them to NULL. Since
1905* FIXME: ...the code itself is immediately unloaded, there may not be
1906* FIXME: ...any reason to worry about that!
1907*********************************************************************/
1908void clearStartupExtensionsAndLoaderInfo(void)
1909{
1910 OSDictionary * startupExtensions = NULL; // must release
1911 OSArray * bootLoaderObjects = NULL; // must release
1912
1913 IORegistryEntry * bootxMemoryMap = NULL; // must release
1914 OSDictionary * propertyDict = NULL; // must release
1915 OSCollectionIterator * keyIterator = NULL; // must release
1916 OSString * key = NULL; // don't release
1917
1918 /*****
1919 * Drop any temporarily held data objects.
1920 */
1921 bootLoaderObjects = getBootLoaderObjects();
1922 if (bootLoaderObjects) {
1923 bootLoaderObjects->release();
1924 }
1925
1926 /****
1927 * If any "code" entries in driver dictionaries are accompanied
1928 * by "compressedCode" entries, then those data objects were
1929 * created based of of kmem_alloc()'ed memory, which must be
1930 * freed specially.
1931 */
1932 startupExtensions = getStartupExtensions();
1933 if (startupExtensions) {
1934 keyIterator =
1935 OSCollectionIterator::withCollection(startupExtensions);
1936 if (!keyIterator) {
1937 IOLog("Error: Couldn't allocate iterator for startup "
1938 "extensions.\n");
1939 LOG_DELAY();
1940 goto memory_map; // bail to the memory_map label
1941 }
1942
1943 while ( (key = OSDynamicCast(OSString,
1944 keyIterator->getNextObject())) ) {
1945
1946 OSDictionary * driverDict = 0;
1947 OSData * codeData = 0;
1948
1949 driverDict = OSDynamicCast(OSDictionary,
1950 startupExtensions->getObject(key));
1951 if (driverDict) {
1952 codeData = OSDynamicCast(OSData,
1953 driverDict->getObject("code"));
1954
1955 if (codeData &&
1956 driverDict->getObject("compressedCode")) {
1957
1958 kmem_free(kernel_map,
1959 (unsigned int)codeData->getBytesNoCopy(),
1960 codeData->getLength());
1961 }
1962 }
1963 }
1964
1965 keyIterator->release();
1966 startupExtensions->release();
1967 }
1968
1969memory_map:
1970
1971 /****
1972 * Go through the device tree's memory map and remove any driver
1973 * data entries.
1974 */
1975 bootxMemoryMap =
1976 IORegistryEntry::fromPath(
1977 "/chosen/memory-map", // path
1978 gIODTPlane // plane
1979 );
1980 // return value is retained so be sure to release it
1981
1982 if (!bootxMemoryMap) {
1983 IOLog("Error: Couldn't read booter memory map.\n");
1984 LOG_DELAY();
1985 goto finish;
1986 }
1987
1988 propertyDict = bootxMemoryMap->dictionaryWithProperties();
1989 if (!propertyDict) {
1990 IOLog("Error: Couldn't get property dictionary "
1991 "from memory map.\n");
1992 LOG_DELAY();
1993 goto finish;
1994 }
1995
1996 keyIterator = OSCollectionIterator::withCollection(propertyDict);
1997 if (!keyIterator) {
1998 IOLog("Error: Couldn't allocate iterator for driver images.\n");
1999 LOG_DELAY();
2000 goto finish;
2001 }
2002
2003 while ( (key = OSDynamicCast(OSString,
2004 keyIterator->getNextObject())) ) {
2005
2006 const char * keyValue = key->getCStringNoCopy();
2007
2008 if ( !strncmp(keyValue, BOOTX_KEXT_PREFIX,
2009 strlen(BOOTX_KEXT_PREFIX)) ||
2010 !strncmp(keyValue, BOOTX_MULTIKEXT_PREFIX,
2011 strlen(BOOTX_MULTIKEXT_PREFIX)) ) {
2012
2013 OSData * bootxDriverDataObject = NULL;
2d21ac55 2014 const MemoryMapFileInfo * driverInfo = 0;
0b4e3aa0
A
2015
2016 bootxDriverDataObject = OSDynamicCast(OSData,
2017 propertyDict->getObject(keyValue));
2018 // don't release bootxDriverDataObject
2019
2020 if (!bootxDriverDataObject) {
2021 continue;
2022 }
2d21ac55 2023 driverInfo = (const MemoryMapFileInfo *)
0b4e3aa0
A
2024 bootxDriverDataObject->getBytesNoCopy(0,
2025 sizeof(MemoryMapFileInfo));
2026 IODTFreeLoaderInfo((char *)keyValue,
2027 (void *)driverInfo->paddr,
2028 (int)driverInfo->length);
2029 }
2030 }
2031
2032finish:
2033 if (bootxMemoryMap) bootxMemoryMap->release();
2034 if (propertyDict) propertyDict->release();
2035 if (keyIterator) keyIterator->release();
1c79356b 2036
1c79356b
A
2037 return;
2038}