2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
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
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
30 #include <libkern/c++/OSContainers.h>
31 #include <IOKit/IODeviceTreeSupport.h>
32 #include <IOKit/IORegistryEntry.h>
33 #include <IOKit/IOCatalogue.h>
34 #include <libkern/c++/OSUnserialize.h>
35 #include <libkern/OSByteOrder.h>
36 #include <libsa/catalogue.h>
39 #include <machine/machine_routines.h>
40 #include <mach/host_info.h>
41 #include <mach/kmod.h>
42 #include <libsa/mkext.h>
43 #include <libsa/vers_rsrc.h>
44 #include <mach-o/loader.h>
47 #include <IOKit/IOLib.h>
49 #include <IOKit/assert.h>
52 extern void IODTFreeLoaderInfo( char *key
, void *infoAddr
, int infoSize
);
53 // extern kern_return_t host_info(host_t host,
54 // host_flavor_t flavor,
56 // mach_msg_type_number_t *count);
57 extern int grade_binary(cpu_type_t exectype
, cpu_subtype_t execsubtype
);
58 // Return the address of the named Mach-O segment from the currently
59 // executing 32 bit kernel, or NULL.
60 extern struct segment_command
*getsegbyname(char *seg_name
);
61 // Return the address of the named section from the named Mach-O segment
62 // from the currently executing 32 bit kernel, or NULL.
63 extern struct section
*getsectbyname(char *segname
, char *sectname
);
69 #define VTYELLOW "\033[33m"
70 #define VTRESET "\033[0m"
76 /*********************************************************************
77 *********************************************************************/
78 static OSDictionary
* gStartupExtensions
= 0;
79 static OSArray
* gBootLoaderObjects
= 0;
80 extern OSArray
* gIOPrelinkedModules
;
82 OSDictionary
* getStartupExtensions(void) {
83 if (gStartupExtensions
) {
84 return gStartupExtensions
;
86 gStartupExtensions
= OSDictionary::withCapacity(1);
87 assert (gStartupExtensions
);
89 return gStartupExtensions
;
92 /* This array holds objects that are needed to be held around during
93 * boot before kextd starts up. Currently it contains OSData objects
94 * copied from OF entries for mkext archives in device ROMs. Because
95 * the Device Tree support code dumps these after initially handing
96 * them to us, we have to be able to clean them up later.
98 OSArray
* getBootLoaderObjects(void) {
99 if (gBootLoaderObjects
) {
100 return gBootLoaderObjects
;
102 gBootLoaderObjects
= OSArray::withCapacity(1);
103 assert (gBootLoaderObjects
);
105 return gBootLoaderObjects
;
108 /*********************************************************************
109 * This function checks that a driver dict has all the required
110 * entries and does a little bit of value checking too.
112 * index is nonnegative if the index of an entry from an mkext
114 *********************************************************************/
115 bool validateExtensionDict(OSDictionary
* extension
, int index
) {
118 bool not_a_dict
= false;
119 bool id_missing
= false;
120 bool is_kernel_resource
= false;
121 bool has_executable
= false;
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
131 VERS_version compatible_vers
;
133 // Info dict is a dictionary
134 if (!OSDynamicCast(OSDictionary
, extension
)) {
140 // CFBundleIdentifier is a string - REQUIRED
141 bundleIdentifier
= OSDynamicCast(OSString
,
142 extension
->getObject("CFBundleIdentifier"));
143 if (!bundleIdentifier
) {
149 // Length of CFBundleIdentifier is not >= KMOD_MAX_NAME
150 if (bundleIdentifier
->getLength() >= KMOD_MAX_NAME
) {
155 // CFBundlePackageType is "KEXT" - REQUIRED
156 stringValue
= OSDynamicCast(OSString
,
157 extension
->getObject("CFBundlePackageType"));
162 if (!stringValue
->isEqualTo("KEXT")) {
167 // CFBundleVersion is a string - REQUIRED
168 stringValue
= OSDynamicCast(OSString
,
169 extension
->getObject("CFBundleVersion"));
174 // CFBundleVersion is of valid form
175 vers
= VERS_parse_string(stringValue
->getCStringNoCopy());
181 // OSBundleCompatibleVersion is a string - OPTIONAL
182 rawValue
= extension
->getObject("OSBundleCompatibleVersion");
184 stringValue
= OSDynamicCast(OSString
, rawValue
);
190 // OSBundleCompatibleVersion is of valid form
191 compatible_vers
= VERS_parse_string(stringValue
->getCStringNoCopy());
192 if (compatible_vers
< 0) {
197 // OSBundleCompatibleVersion <= CFBundleVersion
198 if (compatible_vers
> vers
) {
204 // CFBundleExecutable is a string - OPTIONAL
205 rawValue
= extension
->getObject("CFBundleExecutable");
207 stringValue
= OSDynamicCast(OSString
, rawValue
);
208 if (!stringValue
|| stringValue
->getLength() == 0) {
212 has_executable
= true;
215 // OSKernelResource is a boolean value - OPTIONAL
216 rawValue
= extension
->getObject("OSKernelResource");
218 booleanValue
= OSDynamicCast(OSBoolean
, rawValue
);
223 is_kernel_resource
= booleanValue
->isTrue();
226 // IOKitPersonalities is a dictionary - OPTIONAL
227 rawValue
= extension
->getObject("IOKitPersonalities");
229 personalities
= OSDynamicCast(OSDictionary
, rawValue
);
230 if (!personalities
) {
235 keyIterator
= OSCollectionIterator::withCollection(personalities
);
237 IOLog("Error: Failed to allocate iterator for personalities.\n");
243 while ((key
= OSDynamicCast(OSString
, keyIterator
->getNextObject()))) {
244 OSDictionary
* personality
= NULL
; // do not release
246 // Each personality is a dictionary
247 personality
= OSDynamicCast(OSDictionary
,
248 personalities
->getObject(key
));
254 // IOClass exists as a string - REQUIRED
255 if (!OSDynamicCast(OSString
, personality
->getObject("IOClass"))) {
260 // IOProviderClass exists as a string - REQUIRED
261 if (!OSDynamicCast(OSString
,
262 personality
->getObject("IOProviderClass"))) {
268 // CFBundleIdentifier is a string - OPTIONAL - INSERT IF ABSENT!
269 rawValue
= personality
->getObject("CFBundleIdentifier");
271 personality
->setObject("CFBundleIdentifier", bundleIdentifier
);
273 OSString
* personalityID
= NULL
; // do not release
274 personalityID
= OSDynamicCast(OSString
, rawValue
);
275 if (!personalityID
) {
279 // Length of CFBundleIdentifier is not >= KMOD_MAX_NAME
280 if (personalityID
->getLength() >= KMOD_MAX_NAME
) {
287 // IOKitDebug is a number - OPTIONAL
288 rawValue
= personality
->getObject("IOKitDebug");
289 if (rawValue
&& !OSDynamicCast(OSNumber
, rawValue
)) {
295 keyIterator
->release();
300 // OSBundleLibraries is a dictionary - REQUIRED if
301 // not kernel resource & has executable
303 rawValue
= extension
->getObject("OSBundleLibraries");
304 if (!rawValue
&& !is_kernel_resource
&& has_executable
) {
310 libraries
= OSDynamicCast(OSDictionary
, rawValue
);
316 keyIterator
= OSCollectionIterator::withCollection(libraries
);
318 IOLog("Error: Failed to allocate iterator for libraries.\n");
324 while ((key
= OSDynamicCast(OSString
,
325 keyIterator
->getNextObject()))) {
327 OSString
* libraryVersion
= NULL
; // do not release
329 // Each key's length is not >= KMOD_MAX_NAME
330 if (key
->getLength() >= KMOD_MAX_NAME
) {
335 libraryVersion
= OSDynamicCast(OSString
,
336 libraries
->getObject(key
));
337 if (!libraryVersion
) {
342 // Each value is a valid version string
343 vers
= VERS_parse_string(libraryVersion
->getCStringNoCopy());
350 keyIterator
->release();
354 // OSBundleRequired is a legal value - *not* required at boot time
355 // so we can do install CDs and the like with mkext files containing
356 // all normally-used drivers.
357 rawValue
= extension
->getObject("OSBundleRequired");
359 stringValue
= OSDynamicCast(OSString
, rawValue
);
364 if (!stringValue
->isEqualTo("Root") &&
365 !stringValue
->isEqualTo("Local-Root") &&
366 !stringValue
->isEqualTo("Network-Root") &&
367 !stringValue
->isEqualTo("Safe Boot") &&
368 !stringValue
->isEqualTo("Console")) {
378 if (keyIterator
) keyIterator
->release();
383 IOLog(VTYELLOW
"mkext entry %d:." VTRESET
, index
);
385 IOLog(VTYELLOW
"kernel extension" VTRESET
);
387 IOLog(VTYELLOW
"info dictionary isn't a dictionary\n"
389 } else if (id_missing
) {
391 IOLog(VTYELLOW
"mkext entry %d:." VTRESET
, index
);
393 IOLog(VTYELLOW
"kernel extension" VTRESET
);
395 IOLog(VTYELLOW
"\"CFBundleIdentifier\" property is "
396 "missing or not a string\n"
399 IOLog(VTYELLOW
"kernel extension \"%s\": info dictionary is invalid\n"
400 VTRESET
, bundleIdentifier
->getCStringNoCopy());
409 /*********************************************************************
410 *********************************************************************/
411 OSDictionary
* compareExtensionVersions(
412 OSDictionary
* incumbent
,
413 OSDictionary
* candidate
) {
415 OSDictionary
* winner
= NULL
;
417 OSDictionary
* incumbentPlist
= NULL
;
418 OSDictionary
* candidatePlist
= NULL
;
419 OSString
* incumbentName
= NULL
;
420 OSString
* candidateName
= NULL
;
421 OSString
* incumbentVersionString
= NULL
;
422 OSString
* candidateVersionString
= NULL
;
423 VERS_version incumbent_vers
= 0;
424 VERS_version candidate_vers
= 0;
426 incumbentPlist
= OSDynamicCast(OSDictionary
,
427 incumbent
->getObject("plist"));
428 candidatePlist
= OSDynamicCast(OSDictionary
,
429 candidate
->getObject("plist"));
431 if (!incumbentPlist
|| !candidatePlist
) {
432 IOLog("compareExtensionVersions() called with invalid "
433 "extension dictionaries.\n");
439 incumbentName
= OSDynamicCast(OSString
,
440 incumbentPlist
->getObject("CFBundleIdentifier"));
441 candidateName
= OSDynamicCast(OSString
,
442 candidatePlist
->getObject("CFBundleIdentifier"));
443 incumbentVersionString
= OSDynamicCast(OSString
,
444 incumbentPlist
->getObject("CFBundleVersion"));
445 candidateVersionString
= OSDynamicCast(OSString
,
446 candidatePlist
->getObject("CFBundleVersion"));
448 if (!incumbentName
|| !candidateName
||
449 !incumbentVersionString
|| !candidateVersionString
) {
451 IOLog("compareExtensionVersions() called with invalid "
452 "extension dictionaries.\n");
458 if (strcmp(incumbentName
->getCStringNoCopy(),
459 candidateName
->getCStringNoCopy())) {
461 IOLog("compareExtensionVersions() called with different "
462 "extension names (%s and %s).\n",
463 incumbentName
->getCStringNoCopy(),
464 candidateName
->getCStringNoCopy());
470 incumbent_vers
= VERS_parse_string(incumbentVersionString
->getCStringNoCopy());
471 if (incumbent_vers
< 0) {
473 IOLog(VTYELLOW
"Error parsing version string for extension %s (%s)\n"
475 incumbentName
->getCStringNoCopy(),
476 incumbentVersionString
->getCStringNoCopy());
482 candidate_vers
= VERS_parse_string(candidateVersionString
->getCStringNoCopy());
483 if (candidate_vers
< 0) {
485 IOLog(VTYELLOW
"Error parsing version string for extension %s (%s)\n"
487 candidateName
->getCStringNoCopy(),
488 candidateVersionString
->getCStringNoCopy());
494 if (candidate_vers
> incumbent_vers
) {
495 IOLog(VTYELLOW
"Replacing extension \"%s\" with newer version "
496 "(%s -> %s).\n" VTRESET
,
497 incumbentName
->getCStringNoCopy(),
498 incumbentVersionString
->getCStringNoCopy(),
499 candidateVersionString
->getCStringNoCopy());
504 IOLog(VTYELLOW
"Skipping duplicate extension \"%s\" with older/same "
505 " version (%s -> %s).\n" VTRESET
,
506 candidateName
->getCStringNoCopy(),
507 candidateVersionString
->getCStringNoCopy(),
508 incumbentVersionString
->getCStringNoCopy());
516 // no cleanup, how nice
521 /*********************************************************************
522 * This function merges entries in the mergeFrom dictionary into the
523 * mergeInto dictionary. If it returns false, the two dictionaries are
524 * not altered. If it returns true, then mergeInto may have new
525 * entries; any keys that were already present in mergeInto are
526 * removed from mergeFrom, so that the caller can see what was
528 *********************************************************************/
529 bool mergeExtensionDictionaries(OSDictionary
* mergeInto
,
530 OSDictionary
* mergeFrom
) {
533 OSDictionary
* mergeIntoCopy
= NULL
; // must release
534 OSDictionary
* mergeFromCopy
= NULL
; // must release
535 OSCollectionIterator
* keyIterator
= NULL
; // must release
536 OSString
* key
; // don't release
538 /* Add 1 to count to guarantee copy can grow (grr).
540 mergeIntoCopy
= OSDictionary::withDictionary(mergeInto
,
541 mergeInto
->getCount() + 1);
542 if (!mergeIntoCopy
) {
543 IOLog("Error: Failed to copy 'into' extensions dictionary "
550 /* Add 1 to count to guarantee copy can grow (grr).
552 mergeFromCopy
= OSDictionary::withDictionary(mergeFrom
,
553 mergeFrom
->getCount() + 1);
554 if (!mergeFromCopy
) {
555 IOLog("Error: Failed to copy 'from' extensions dictionary "
562 keyIterator
= OSCollectionIterator::withCollection(mergeFrom
);
564 IOLog("Error: Failed to allocate iterator for extensions.\n");
572 * Loop through "from" dictionary, checking if the identifier already
573 * exists in the "into" dictionary and checking versions if it does.
575 while ((key
= OSDynamicCast(OSString
, keyIterator
->getNextObject()))) {
576 OSDictionary
* incumbentExt
= OSDynamicCast(OSDictionary
,
577 mergeIntoCopy
->getObject(key
));
578 OSDictionary
* candidateExt
= OSDynamicCast(OSDictionary
,
579 mergeFrom
->getObject(key
));
582 if (!mergeIntoCopy
->setObject(key
, candidateExt
)) {
584 /* This is a fatal error, so bail.
586 IOLog("mergeExtensionDictionaries(): Failed to add "
588 key
->getCStringNoCopy());
594 OSDictionary
* mostRecentExtension
=
595 compareExtensionVersions(incumbentExt
, candidateExt
);
597 if (mostRecentExtension
== incumbentExt
) {
598 mergeFromCopy
->removeObject(key
);
599 } else if (mostRecentExtension
== candidateExt
) {
601 if (!mergeIntoCopy
->setObject(key
, candidateExt
)) {
603 /* This is a fatal error, so bail.
605 IOLog("mergeExtensionDictionaries(): Failed to add "
607 key
->getCStringNoCopy());
612 } else /* should be NULL */ {
614 /* This is a nonfatal error, so continue doing others.
616 IOLog("mergeExtensionDictionaries(): Error comparing "
617 "versions of duplicate extensions %s.\n",
618 key
->getCStringNoCopy());
627 /* If successful, replace the contents of the original
628 * dictionaries with those of the modified copies.
631 mergeInto
->flushCollection();
632 mergeInto
->merge(mergeIntoCopy
);
633 mergeFrom
->flushCollection();
634 mergeFrom
->merge(mergeFromCopy
);
637 if (mergeIntoCopy
) mergeIntoCopy
->release();
638 if (mergeFromCopy
) mergeFromCopy
->release();
639 if (keyIterator
) keyIterator
->release();
646 * These bits are used to parse data made available by bootx.
648 #define BOOTX_KEXT_PREFIX "Driver-"
649 #define BOOTX_MULTIKEXT_PREFIX "DriversPackage-"
651 typedef struct MemoryMapFileInfo
{
656 typedef struct BootxDriverInfo
{
663 typedef struct MkextEntryInfo
{
664 vm_address_t base_address
;
665 mkext_file
* fileinfo
;
669 /*********************************************************************
670 * This private function reads the data for a single extension from
671 * the bootx memory-map's propery dict, returning a dictionary with
672 * keys "plist" for the extension's Info.plist as a parsed OSDictionary
673 * and "code" for the extension's executable code as an OSData.
674 *********************************************************************/
675 OSDictionary
* readExtension(OSDictionary
* propertyDict
,
676 const char * memory_map_name
) {
679 OSData
* bootxDriverDataObject
= NULL
;
680 OSDictionary
* driverPlist
= NULL
;
681 OSString
* driverName
= NULL
;
682 OSData
* driverCode
= NULL
;
683 OSString
* errorString
= NULL
;
684 OSDictionary
* driverDict
= NULL
;
686 MemoryMapFileInfo
* driverInfo
= 0;
687 BootxDriverInfo
* dataBuffer
;
689 kmod_info_t
* loaded_kmod
= NULL
;
691 bootxDriverDataObject
= OSDynamicCast(OSData
,
692 propertyDict
->getObject(memory_map_name
));
693 // don't release bootxDriverDataObject
695 if (!bootxDriverDataObject
) {
696 IOLog("Error: No driver data object "
697 "for device tree entry \"%s\".\n",
704 driverDict
= OSDictionary::withCapacity(2);
706 IOLog("Error: Couldn't allocate dictionary "
707 "for device tree entry \"%s\".\n", memory_map_name
);
713 driverInfo
= (MemoryMapFileInfo
*)
714 bootxDriverDataObject
->getBytesNoCopy(0,
715 sizeof(MemoryMapFileInfo
));
716 #if defined (__ppc__)
717 dataBuffer
= (BootxDriverInfo
*)ml_static_ptovirt(
719 #elif defined (__i386__)
720 dataBuffer
= (BootxDriverInfo
*)driverInfo
->paddr
;
721 dataBuffer
->plistAddr
= ml_static_ptovirt(dataBuffer
->plistAddr
);
722 if (dataBuffer
->moduleAddr
)
723 dataBuffer
->moduleAddr
= ml_static_ptovirt(dataBuffer
->moduleAddr
);
725 #error unsupported architecture
728 IOLog("Error: No data buffer "
729 "for device tree entry \"%s\".\n", memory_map_name
);
735 driverPlist
= OSDynamicCast(OSDictionary
,
736 OSUnserializeXML(dataBuffer
->plistAddr
, &errorString
));
738 IOLog("Error: Couldn't read XML property list "
739 "for device tree entry \"%s\".\n", memory_map_name
);
742 IOLog("XML parse error: %s.\n",
743 errorString
->getCStringNoCopy());
751 driverName
= OSDynamicCast(OSString
,
752 driverPlist
->getObject("CFBundleIdentifier")); // do not release
754 IOLog("Error: Device tree entry \"%s\" has "
755 "no \"CFBundleIdentifier\" property.\n", memory_map_name
);
761 /* Check if kmod is already loaded and is a real loadable one (has
764 loaded_kmod
= kmod_lookupbyname_locked(driverName
->getCStringNoCopy());
765 if (loaded_kmod
&& loaded_kmod
->address
) {
766 IOLog("Skipping new extension \"%s\"; an extension named "
767 "\"%s\" is already loaded.\n",
768 driverName
->getCStringNoCopy(),
775 if (!validateExtensionDict(driverPlist
, -1)) {
776 // validateExtensionsDict() logs an error
781 driverDict
->setObject("plist", driverPlist
);
783 /* It's perfectly okay for a KEXT to have no executable.
784 * Check that moduleAddr is nonzero before attempting to
787 * NOTE: The driverCode object is created "no-copy", so
788 * it doesn't own that memory. The memory must be freed
789 * separately from the OSData object (see
790 * clearStartupExtensionsAndLoaderInfo() at the end of this file).
792 if (dataBuffer
->moduleAddr
&& dataBuffer
->moduleLength
) {
793 driverCode
= OSData::withBytesNoCopy(dataBuffer
->moduleAddr
,
794 dataBuffer
->moduleLength
);
796 IOLog("Error: Couldn't allocate data object "
797 "to hold code for device tree entry \"%s\".\n",
805 driverDict
->setObject("code", driverCode
);
812 kfree((unsigned int)loaded_kmod
, sizeof(kmod_info_t
));
815 // do not release bootxDriverDataObject
816 // do not release driverName
819 driverPlist
->release();
822 errorString
->release();
825 driverCode
->release();
829 driverDict
->release();
837 /*********************************************************************
838 * Used to uncompress a single file entry in an mkext archive.
840 * The OSData returned does not own its memory! You must deallocate
841 * that memory using kmem_free() before releasing the OSData().
842 *********************************************************************/
843 static bool uncompressFile(u_int8_t
*base_address
, mkext_file
* fileinfo
,
844 /* out */ OSData
** file
) {
847 kern_return_t kern_result
;
848 u_int8_t
* uncompressed_file
= 0; // kmem_free() on error
849 OSData
* uncompressedFile
= 0; // returned
850 size_t uncompressed_size
= 0;
852 size_t offset
= OSSwapBigToHostInt32(fileinfo
->offset
);
853 size_t compsize
= OSSwapBigToHostInt32(fileinfo
->compsize
);
854 size_t realsize
= OSSwapBigToHostInt32(fileinfo
->realsize
);
855 time_t modifiedsecs
= OSSwapBigToHostInt32(fileinfo
->modifiedsecs
);
859 /* If these four fields are zero there's no file, but that isn't
862 if (offset
== 0 && compsize
== 0 &&
863 realsize
== 0 && modifiedsecs
== 0) {
867 // Add 1 for '\0' to terminate XML string!
868 kern_result
= kmem_alloc(kernel_map
, (vm_offset_t
*)&uncompressed_file
,
870 if (kern_result
!= KERN_SUCCESS
) {
871 IOLog("Error: Couldn't allocate data buffer "
872 "to uncompress file.\n");
878 uncompressedFile
= OSData::withBytesNoCopy(uncompressed_file
,
880 if (!uncompressedFile
) {
881 IOLog("Error: Couldn't allocate data object "
882 "to uncompress file.\n");
889 uncompressed_size
= decompress_lzss(uncompressed_file
,
890 base_address
+ offset
,
892 if (uncompressed_size
!= realsize
) {
893 IOLog("Error: Uncompressed file is not the length "
899 uncompressed_file
[uncompressed_size
] = '\0';
901 bcopy(base_address
+ offset
, uncompressed_file
,
903 uncompressed_file
[realsize
] = '\0';
906 *file
= uncompressedFile
;
910 if (uncompressed_file
) {
911 kmem_free(kernel_map
, (vm_address_t
)uncompressed_file
,
914 if (uncompressedFile
) {
915 uncompressedFile
->release();
922 bool uncompressModule(OSData
*compData
, /* out */ OSData
** file
) {
924 MkextEntryInfo
*info
= (MkextEntryInfo
*) compData
->getBytesNoCopy();
926 return uncompressFile((u_int8_t
*) info
->base_address
,
927 info
->fileinfo
, file
);
931 /*********************************************************************
932 * Does the work of pulling extensions out of an mkext archive located
934 *********************************************************************/
935 bool extractExtensionsFromArchive(MemoryMapFileInfo
* mkext_file_info
,
936 OSDictionary
* extensions
) {
940 u_int8_t
* crc_address
= 0;
942 mkext_header
* mkext_data
= 0; // don't free
943 mkext_kext
* onekext_data
= 0; // don't free
944 mkext_file
* plist_file
= 0; // don't free
945 mkext_file
* module_file
= 0; // don't free
946 kmod_info_t
* loaded_kmod
= 0; // must free
948 OSData
* driverPlistDataObject
= 0; // must release
949 OSDictionary
* driverPlist
= 0; // must release
950 OSData
* driverCode
= 0; // must release
951 OSDictionary
* driverDict
= 0; // must release
952 OSString
* moduleName
= 0; // don't release
953 OSString
* errorString
= NULL
; // must release
955 OSData
* moduleInfo
= 0; // must release
956 MkextEntryInfo module_info
;
959 #if defined (__ppc__)
960 mkext_data
= (mkext_header
*)mkext_file_info
->paddr
;
961 #elif defined (__i386__)
962 mkext_data
= (mkext_header
*)ml_static_ptovirt(mkext_file_info
->paddr
);
964 #error unsupported architecture
966 if (OSSwapBigToHostInt32(mkext_data
->magic
) != MKEXT_MAGIC
||
967 OSSwapBigToHostInt32(mkext_data
->signature
) != MKEXT_SIGN
) {
968 IOLog("Error: Extension archive has invalid magic or signature.\n");
974 if (OSSwapBigToHostInt32(mkext_data
->length
) != mkext_file_info
->length
) {
975 IOLog("Error: Mismatch between extension archive & "
976 "recorded length.\n");
982 crc_address
= (u_int8_t
*)&mkext_data
->version
;
983 checksum
= adler32(crc_address
,
984 (unsigned int)mkext_data
+
985 OSSwapBigToHostInt32(mkext_data
->length
) - (unsigned int)crc_address
);
987 if (OSSwapBigToHostInt32(mkext_data
->adler32
) != checksum
) {
988 IOLog("Error: Extension archive has a bad checksum.\n");
994 /* If the MKEXT archive isn't fat, check that the CPU type & subtype
995 * match that of the running kernel.
997 if (OSSwapBigToHostInt32(mkext_data
->cputype
) != (UInt32
)CPU_TYPE_ANY
) {
998 kern_return_t kresult
= KERN_FAILURE
;
999 host_basic_info_data_t hostinfo
;
1000 host_info_t hostinfo_ptr
= (host_info_t
)&hostinfo
;
1001 mach_msg_type_number_t count
= sizeof(hostinfo
)/sizeof(integer_t
);
1003 kresult
= host_info((host_t
)1, HOST_BASIC_INFO
,
1004 hostinfo_ptr
, &count
);
1005 if (kresult
!= KERN_SUCCESS
) {
1006 IOLog("Error: Couldn't get current host info.\n");
1011 if ((UInt32
)hostinfo
.cpu_type
!=
1012 OSSwapBigToHostInt32(mkext_data
->cputype
)) {
1014 IOLog("Error: Extension archive doesn't contain software "
1015 "for this computer's CPU type.\n");
1020 if (!grade_binary(OSSwapBigToHostInt32(mkext_data
->cputype
),
1021 OSSwapBigToHostInt32(mkext_data
->cpusubtype
))) {
1022 IOLog("Error: Extension archive doesn't contain software "
1023 "for this computer's CPU subtype.\n");
1030 for (unsigned int i
= 0;
1031 i
< OSSwapBigToHostInt32(mkext_data
->numkexts
);
1035 kfree((unsigned int)loaded_kmod
, sizeof(kmod_info_t
));
1039 if (driverPlistDataObject
) {
1040 kmem_free(kernel_map
,
1041 (unsigned int)driverPlistDataObject
->getBytesNoCopy(),
1042 driverPlistDataObject
->getLength());
1044 driverPlistDataObject
->release();
1045 driverPlistDataObject
= NULL
;
1048 driverPlist
->release();
1052 driverCode
->release();
1056 driverDict
->release();
1060 errorString
->release();
1064 onekext_data
= &mkext_data
->kext
[i
];
1065 plist_file
= &onekext_data
->plist
;
1066 module_file
= &onekext_data
->module;
1068 if (!uncompressFile((u_int8_t
*)mkext_data
, plist_file
,
1069 &driverPlistDataObject
)) {
1071 IOLog("Error: couldn't uncompress plist file "
1072 "from multikext archive entry %d.\n", i
);
1077 if (!driverPlistDataObject
) {
1078 IOLog("Error: No property list present "
1079 "for multikext archive entry %d.\n", i
);
1083 driverPlist
= OSDynamicCast(OSDictionary
,
1085 (char *)driverPlistDataObject
->getBytesNoCopy(),
1088 IOLog("Error: Couldn't read XML property list "
1089 "for multikext archive entry %d.\n", i
);
1092 IOLog("XML parse error: %s.\n",
1093 errorString
->getCStringNoCopy());
1099 if (!validateExtensionDict(driverPlist
, i
)) {
1100 // validateExtensionsDict() logs an error
1106 /* Get the extension's module name. This is used to record
1109 moduleName
= OSDynamicCast(OSString
,
1110 driverPlist
->getObject("CFBundleIdentifier")); // do not release
1112 IOLog("Error: Multikext archive entry %d has "
1113 "no \"CFBundleIdentifier\" property.\n", i
);
1115 continue; // assume a kext config error & continue
1118 /* Check if kmod is already loaded and is a real loadable one (has
1121 loaded_kmod
= kmod_lookupbyname_locked(moduleName
->getCStringNoCopy());
1122 if (loaded_kmod
&& loaded_kmod
->address
) {
1123 IOLog("Skipping new extension \"%s\"; an extension named "
1124 "\"%s\" is already loaded.\n",
1125 moduleName
->getCStringNoCopy(),
1131 driverDict
= OSDictionary::withCapacity(2);
1133 IOLog("Error: Couldn't allocate dictionary "
1134 "for multikext archive entry %d.\n", i
);
1140 driverDict
->setObject("plist", driverPlist
);
1143 * Prepare an entry to hold the mkext entry info for the
1144 * compressed binary module, if there is one. If all four fields
1145 * of the module entry are zero, there isn't one.
1147 if (!(loaded_kmod
&& loaded_kmod
->address
) && (OSSwapBigToHostInt32(module_file
->offset
) ||
1148 OSSwapBigToHostInt32(module_file
->compsize
) ||
1149 OSSwapBigToHostInt32(module_file
->realsize
) ||
1150 OSSwapBigToHostInt32(module_file
->modifiedsecs
))) {
1152 moduleInfo
= OSData::withCapacity(sizeof(MkextEntryInfo
));
1154 IOLog("Error: Couldn't allocate data object "
1155 "for multikext archive entry %d.\n", i
);
1161 module_info
.base_address
= (vm_address_t
)mkext_data
;
1162 module_info
.fileinfo
= module_file
;
1164 if (!moduleInfo
->appendBytes(&module_info
, sizeof(module_info
))) {
1165 IOLog("Error: Couldn't record info "
1166 "for multikext archive entry %d.\n", i
);
1172 driverDict
->setObject("compressedCode", moduleInfo
);
1175 OSDictionary
* incumbentExt
= OSDynamicCast(OSDictionary
,
1176 extensions
->getObject(moduleName
));
1178 if (!incumbentExt
) {
1179 extensions
->setObject(moduleName
, driverDict
);
1181 OSDictionary
* mostRecentExtension
=
1182 compareExtensionVersions(incumbentExt
, driverDict
);
1184 if (mostRecentExtension
== incumbentExt
) {
1185 /* Do nothing, we've got the most recent. */
1186 } else if (mostRecentExtension
== driverDict
) {
1187 if (!extensions
->setObject(moduleName
, driverDict
)) {
1189 /* This is a fatal error, so bail.
1191 IOLog("extractExtensionsFromArchive(): Failed to add "
1193 moduleName
->getCStringNoCopy());
1198 } else /* should be NULL */ {
1200 /* This is a nonfatal error, so continue.
1202 IOLog("extractExtensionsFromArchive(): Error comparing "
1203 "versions of duplicate extensions %s.\n",
1204 moduleName
->getCStringNoCopy());
1213 if (loaded_kmod
) kfree((unsigned int)loaded_kmod
, sizeof(kmod_info_t
));
1214 if (driverPlistDataObject
) {
1215 kmem_free(kernel_map
,
1216 (unsigned int)driverPlistDataObject
->getBytesNoCopy(),
1217 driverPlistDataObject
->getLength());
1218 driverPlistDataObject
->release();
1220 if (driverPlist
) driverPlist
->release();
1221 if (driverCode
) driverCode
->release();
1222 if (moduleInfo
) moduleInfo
->release();
1223 if (driverDict
) driverDict
->release();
1224 if (errorString
) errorString
->release();
1229 /*********************************************************************
1231 *********************************************************************/
1232 bool readExtensions(OSDictionary
* propertyDict
,
1233 const char * memory_map_name
,
1234 OSDictionary
* extensions
) {
1237 OSData
* mkextDataObject
= 0; // don't release
1238 MemoryMapFileInfo
* mkext_file_info
= 0; // don't free
1240 mkextDataObject
= OSDynamicCast(OSData
,
1241 propertyDict
->getObject(memory_map_name
));
1242 // don't release mkextDataObject
1244 if (!mkextDataObject
) {
1245 IOLog("Error: No mkext data object "
1246 "for device tree entry \"%s\".\n",
1253 mkext_file_info
= (MemoryMapFileInfo
*)mkextDataObject
->getBytesNoCopy();
1254 if (!mkext_file_info
) {
1259 result
= extractExtensionsFromArchive(mkext_file_info
, extensions
);
1263 if (!result
&& extensions
) {
1264 extensions
->flushCollection();
1271 /*********************************************************************
1272 * Adds the personalities for an extensions dictionary to the global
1274 *********************************************************************/
1275 bool addPersonalities(OSDictionary
* extensions
) {
1277 OSCollectionIterator
* keyIterator
= NULL
; // must release
1278 OSString
* key
; // don't release
1279 OSDictionary
* driverDict
= NULL
; // don't release
1280 OSDictionary
* driverPlist
= NULL
; // don't release
1281 OSDictionary
* thisDriverPersonalities
= NULL
; // don't release
1282 OSArray
* allDriverPersonalities
= NULL
; // must release
1284 allDriverPersonalities
= OSArray::withCapacity(1);
1285 if (!allDriverPersonalities
) {
1286 IOLog("Error: Couldn't allocate personality dictionary.\n");
1292 /* Record all personalities found so that they can be
1293 * added to the catalogue.
1294 * Note: Not all extensions have personalities.
1297 keyIterator
= OSCollectionIterator::withCollection(extensions
);
1299 IOLog("Error: Couldn't allocate iterator to record personalities.\n");
1305 while ( ( key
= OSDynamicCast(OSString
,
1306 keyIterator
->getNextObject() ))) {
1308 driverDict
= OSDynamicCast(OSDictionary
,
1309 extensions
->getObject(key
));
1310 driverPlist
= OSDynamicCast(OSDictionary
,
1311 driverDict
->getObject("plist"));
1312 thisDriverPersonalities
= OSDynamicCast(OSDictionary
,
1313 driverPlist
->getObject("IOKitPersonalities"));
1315 if (thisDriverPersonalities
) {
1316 OSCollectionIterator
* pIterator
;
1317 OSString
* locakKey
;
1318 pIterator
= OSCollectionIterator::withCollection(
1319 thisDriverPersonalities
);
1321 IOLog("Error: Couldn't allocate iterator "
1322 "to record extension personalities.\n");
1326 while ( (locakKey
= OSDynamicCast(OSString
,
1327 pIterator
->getNextObject())) ) {
1329 OSDictionary
* personality
= OSDynamicCast(
1331 thisDriverPersonalities
->getObject(locakKey
));
1333 allDriverPersonalities
->setObject(personality
);
1336 pIterator
->release();
1338 } /* extract personalities */
1341 /* Add all personalities found to the IOCatalogue,
1342 * but don't start matching.
1344 gIOCatalogue
->addDrivers(allDriverPersonalities
, false);
1348 if (allDriverPersonalities
) allDriverPersonalities
->release();
1349 if (keyIterator
) keyIterator
->release();
1355 /*********************************************************************
1356 * Called from IOCatalogue to add extensions from an mkext archive.
1357 * This function makes a copy of the mkext object passed in because
1358 * the device tree support code dumps it after calling us (indirectly
1359 * through the IOCatalogue).
1360 *********************************************************************/
1361 bool addExtensionsFromArchive(OSData
* mkextDataObject
) {
1364 OSDictionary
* startupExtensions
= NULL
; // don't release
1365 OSArray
* bootLoaderObjects
= NULL
; // don't release
1366 OSDictionary
* extensions
= NULL
; // must release
1367 MemoryMapFileInfo mkext_file_info
;
1368 OSCollectionIterator
* keyIterator
= NULL
; // must release
1369 OSString
* key
= NULL
; // don't release
1371 startupExtensions
= getStartupExtensions();
1372 if (!startupExtensions
) {
1373 IOLog("Can't record extension archive; there is no"
1374 " extensions dictionary.\n");
1380 bootLoaderObjects
= getBootLoaderObjects();
1381 if (! bootLoaderObjects
) {
1382 IOLog("Error: Couldn't allocate array to hold temporary objects.\n");
1388 extensions
= OSDictionary::withCapacity(2);
1390 IOLog("Error: Couldn't allocate dictionary to unpack "
1391 "extension archive.\n");
1397 mkext_file_info
.paddr
= (UInt32
)mkextDataObject
->getBytesNoCopy();
1398 mkext_file_info
.length
= mkextDataObject
->getLength();
1400 /* Save the local mkext data object so that we can deallocate it later.
1402 bootLoaderObjects
->setObject(mkextDataObject
);
1404 result
= extractExtensionsFromArchive(&mkext_file_info
, extensions
);
1406 IOLog("Error: Failed to extract extensions from archive.\n");
1412 result
= mergeExtensionDictionaries(startupExtensions
, extensions
);
1414 IOLog("Error: Failed to merge new extensions into existing set.\n");
1419 result
= addPersonalities(extensions
);
1421 IOLog("Error: Failed to add personalities for extensions extracted "
1431 IOLog("Error: Failed to record extensions from archive.\n");
1434 keyIterator
= OSCollectionIterator::withCollection(
1438 while ( (key
= OSDynamicCast(OSString
,
1439 keyIterator
->getNextObject())) ) {
1441 IOLog("Added extension \"%s\" from archive.\n",
1442 key
->getCStringNoCopy());
1445 keyIterator
->release();
1449 if (extensions
) extensions
->release();
1455 /*********************************************************************
1456 * This function builds dictionaries for the startup extensions
1457 * put into memory by bootx, recording each in the startup extensions
1458 * dictionary. The dictionary format is this:
1461 * "plist" = (the extension's Info.plist as an OSDictionary)
1462 * "code" = (an OSData containing the executable file)
1465 * This function returns true if any extensions were found and
1466 * recorded successfully, or if there are no start extensions,
1467 * and false if an unrecoverable error occurred. An error reading
1468 * a single extension is not considered fatal, and this function
1469 * will simply skip the problematic extension to try the next one.
1470 *********************************************************************/
1472 bool recordStartupExtensions(void) {
1474 OSDictionary
* startupExtensions
= NULL
; // must release
1475 OSDictionary
* existingExtensions
= NULL
; // don't release
1476 OSDictionary
* mkextExtensions
= NULL
; // must release
1477 IORegistryEntry
* bootxMemoryMap
= NULL
; // must release
1478 OSDictionary
* propertyDict
= NULL
; // must release
1479 OSCollectionIterator
* keyIterator
= NULL
; // must release
1480 OSString
* key
= NULL
; // don't release
1482 OSDictionary
* newDriverDict
= NULL
; // must release
1483 OSDictionary
* driverPlist
= NULL
; // don't release
1485 struct section
* infosect
;
1486 struct section
* symsect
;
1487 unsigned int prelinkedCount
= 0;
1489 existingExtensions
= getStartupExtensions();
1490 if (!existingExtensions
) {
1491 IOLog("Error: There is no dictionary for startup extensions.\n");
1497 startupExtensions
= OSDictionary::withCapacity(1);
1498 if (!startupExtensions
) {
1499 IOLog("Error: Couldn't allocate dictionary "
1500 "to record startup extensions.\n");
1507 // add any prelinked modules as startup extensions
1509 infosect
= getsectbyname("__PRELINK", "__info");
1510 symsect
= getsectbyname("__PRELINK", "__symtab");
1511 if (infosect
&& infosect
->addr
&& infosect
->size
1512 && symsect
&& symsect
->addr
&& symsect
->size
) do
1514 gIOPrelinkedModules
= OSDynamicCast(OSArray
,
1515 OSUnserializeXML((const char *) infosect
->addr
, NULL
));
1517 if (!gIOPrelinkedModules
)
1519 for( unsigned int idx
= 0;
1520 (propertyDict
= OSDynamicCast(OSDictionary
, gIOPrelinkedModules
->getObject(idx
)));
1523 enum { kPrelinkReservedCount
= 4 };
1525 /* Get the extension's module name. This is used to record
1526 * the extension. Do *not* release the moduleName.
1528 OSString
* moduleName
= OSDynamicCast(OSString
,
1529 propertyDict
->getObject("CFBundleIdentifier"));
1531 IOLog("Error: Prelinked module entry has "
1532 "no \"CFBundleIdentifier\" property.\n");
1537 /* Add the kext, & its plist.
1539 newDriverDict
= OSDictionary::withCapacity(4);
1540 assert(newDriverDict
);
1541 newDriverDict
->setObject("plist", propertyDict
);
1542 startupExtensions
->setObject(moduleName
, newDriverDict
);
1543 newDriverDict
->release();
1545 /* Add the code if present.
1547 OSData
* data
= OSDynamicCast(OSData
, propertyDict
->getObject("OSBundlePrelink"));
1549 if (data
->getLength() < (kPrelinkReservedCount
* sizeof(UInt32
))) {
1550 IOLog("Error: Prelinked module entry has "
1551 "invalid \"OSBundlePrelink\" property.\n");
1556 prelink
= (UInt32
*) data
->getBytesNoCopy();
1557 kmod_info_t
* kmod_info
= (kmod_info_t
*) OSReadBigInt32(prelink
, 0);
1558 // end of "file" is end of symbol sect
1559 data
= OSData::withBytesNoCopy((void *) kmod_info
->address
,
1560 symsect
->addr
+ symsect
->size
- kmod_info
->address
);
1561 newDriverDict
->setObject("code", data
);
1566 /* Add the symbols if present.
1568 OSNumber
* num
= OSDynamicCast(OSNumber
, propertyDict
->getObject("OSBundlePrelinkSymbols"));
1570 UInt32 offset
= num
->unsigned32BitValue();
1571 data
= OSData::withBytesNoCopy((void *) (symsect
->addr
+ offset
), symsect
->size
- offset
);
1572 newDriverDict
->setObject("code", data
);
1578 if (gIOPrelinkedModules
)
1579 IOLog("%d prelinked modules\n", prelinkedCount
);
1583 virt
= ml_static_ptovirt(infosect
->addr
);
1585 ml_static_mfree(virt
, infosect
->size
);
1587 newDriverDict
= NULL
;
1593 IORegistryEntry::fromPath(
1594 "/chosen/memory-map", // path
1597 // return value is retained so be sure to release it
1599 if (!bootxMemoryMap
) {
1600 IOLog("Error: Couldn't read booter memory map.\n");
1606 propertyDict
= bootxMemoryMap
->dictionaryWithProperties();
1607 if (!propertyDict
) {
1608 IOLog("Error: Couldn't get property dictionary "
1609 "from memory map.\n");
1615 keyIterator
= OSCollectionIterator::withCollection(propertyDict
);
1617 IOLog("Error: Couldn't allocate iterator for driver images.\n");
1623 while ( (key
= OSDynamicCast(OSString
,
1624 keyIterator
->getNextObject())) ) {
1625 /* Clear newDriverDict & mkextExtensions upon entry to the loop,
1626 * handling both successful and unsuccessful iterations.
1628 if (newDriverDict
) {
1629 newDriverDict
->release();
1630 newDriverDict
= NULL
;
1632 if (mkextExtensions
) {
1633 mkextExtensions
->release();
1634 mkextExtensions
= NULL
;
1637 const char * keyValue
= key
->getCStringNoCopy();
1639 if ( !strncmp(keyValue
, BOOTX_KEXT_PREFIX
,
1640 strlen(BOOTX_KEXT_PREFIX
)) ) {
1642 /* Read the extension from the bootx-supplied memory.
1644 newDriverDict
= readExtension(propertyDict
, keyValue
);
1645 if (!newDriverDict
) {
1646 IOLog("Error: Couldn't read data "
1647 "for device tree entry \"%s\".\n", keyValue
);
1653 /* Preprare to record the extension by getting its info plist.
1655 driverPlist
= OSDynamicCast(OSDictionary
,
1656 newDriverDict
->getObject("plist"));
1658 IOLog("Error: Extension in device tree entry \"%s\" "
1659 "has no property list.\n", keyValue
);
1665 /* Get the extension's module name. This is used to record
1666 * the extension. Do *not* release the moduleName.
1668 OSString
* moduleName
= OSDynamicCast(OSString
,
1669 driverPlist
->getObject("CFBundleIdentifier"));
1671 IOLog("Error: Device tree entry \"%s\" has "
1672 "no \"CFBundleIdentifier\" property.\n", keyValue
);
1678 /* All has gone well so far, so record the extension under
1679 * its module name, checking for an existing duplicate.
1681 * Do not release moduleName, as it's part of the extension's
1684 OSDictionary
* incumbentExt
= OSDynamicCast(OSDictionary
,
1685 startupExtensions
->getObject(moduleName
));
1687 if (!incumbentExt
) {
1688 startupExtensions
->setObject(moduleName
, newDriverDict
);
1690 OSDictionary
* mostRecentExtension
=
1691 compareExtensionVersions(incumbentExt
, newDriverDict
);
1693 if (mostRecentExtension
== incumbentExt
) {
1694 /* Do nothing, we've got the most recent. */
1695 } else if (mostRecentExtension
== newDriverDict
) {
1696 if (!startupExtensions
->setObject(moduleName
,
1699 /* This is a fatal error, so bail.
1701 IOLog("recordStartupExtensions(): Failed to add "
1703 moduleName
->getCStringNoCopy());
1708 } else /* should be NULL */ {
1710 /* This is a nonfatal error, so continue.
1712 IOLog("recordStartupExtensions(): Error comparing "
1713 "versions of duplicate extensions %s.\n",
1714 moduleName
->getCStringNoCopy());
1721 } else if ( !strncmp(keyValue
, BOOTX_MULTIKEXT_PREFIX
,
1722 strlen(BOOTX_MULTIKEXT_PREFIX
)) ) {
1724 mkextExtensions
= OSDictionary::withCapacity(10);
1725 if (!mkextExtensions
) {
1726 IOLog("Error: Couldn't allocate dictionary to unpack "
1727 "multi-extension archive.\n");
1730 goto finish
; // allocation failure is fatal for this routine
1732 if (!readExtensions(propertyDict
, keyValue
, mkextExtensions
)) {
1733 IOLog("Error: Couldn't unpack multi-extension archive.\n");
1737 if (!mergeExtensionDictionaries(startupExtensions
,
1740 IOLog("Error: Failed to merge new extensions into "
1744 goto finish
; // merge error is fatal for this routine
1749 // Do not release key.
1751 } /* while ( (key = OSDynamicCast(OSString, ...) ) ) */
1753 if (!mergeExtensionDictionaries(existingExtensions
, startupExtensions
)) {
1754 IOLog("Error: Failed to merge new extensions into existing set.\n");
1760 result
= addPersonalities(startupExtensions
);
1762 IOLog("Error: Failed to add personalities for extensions extracted "
1771 // reused so clear first!
1773 keyIterator
->release();
1778 IOLog("Error: Failed to record startup extensions.\n");
1782 keyIterator
= OSCollectionIterator::withCollection(
1786 while ( (key
= OSDynamicCast(OSString
,
1787 keyIterator
->getNextObject())) ) {
1789 IOLog("Found extension \"%s\".\n",
1790 key
->getCStringNoCopy());
1793 keyIterator
->release();
1799 if (newDriverDict
) newDriverDict
->release();
1800 if (propertyDict
) propertyDict
->release();
1801 if (bootxMemoryMap
) bootxMemoryMap
->release();
1802 if (mkextExtensions
) mkextExtensions
->release();
1803 if (startupExtensions
) startupExtensions
->release();
1809 /*********************************************************************
1810 * This function removes an entry from the dictionary of startup
1811 * extensions. It's used when an extension can't be loaded, for
1812 * whatever reason. For drivers, this allows another matching driver
1813 * to be loaded, so that, for example, a driver for the root device
1815 *********************************************************************/
1816 void removeStartupExtension(const char * extensionName
) {
1817 OSDictionary
* startupExtensions
= NULL
; // don't release
1818 OSDictionary
* extensionDict
= NULL
; // don't release
1819 OSDictionary
* extensionPlist
= NULL
; // don't release
1820 OSDictionary
* extensionPersonalities
= NULL
; // don't release
1821 OSDictionary
* personality
= NULL
; // don't release
1822 OSCollectionIterator
* keyIterator
= NULL
; // must release
1823 OSString
* key
= NULL
; // don't release
1825 startupExtensions
= getStartupExtensions();
1826 if (!startupExtensions
) goto finish
;
1829 /* Find the extension's entry in the dictionary of
1830 * startup extensions.
1832 extensionDict
= OSDynamicCast(OSDictionary
,
1833 startupExtensions
->getObject(extensionName
));
1834 if (!extensionDict
) goto finish
;
1836 extensionPlist
= OSDynamicCast(OSDictionary
,
1837 extensionDict
->getObject("plist"));
1838 if (!extensionPlist
) goto finish
;
1840 extensionPersonalities
= OSDynamicCast(OSDictionary
,
1841 extensionPlist
->getObject("IOKitPersonalities"));
1842 if (!extensionPersonalities
) goto finish
;
1844 /* If it was there, remove it from the catalogue proper
1845 * by calling removeDrivers(). Pass true for the second
1846 * argument to trigger a new round of matching, and
1847 * then remove the extension from the dictionary of startup
1850 keyIterator
= OSCollectionIterator::withCollection(
1851 extensionPersonalities
);
1853 IOLog("Error: Couldn't allocate iterator to scan"
1854 " personalities for %s.\n", extensionName
);
1858 while ((key
= OSDynamicCast(OSString
, keyIterator
->getNextObject()))) {
1859 personality
= OSDynamicCast(OSDictionary
,
1860 extensionPersonalities
->getObject(key
));
1864 gIOCatalogue
->removeDrivers(personality
, true);
1868 startupExtensions
->removeObject(extensionName
);
1872 if (keyIterator
) keyIterator
->release();
1876 /*********************************************************************
1877 * FIXME: This function invalidates the globals gStartupExtensions and
1878 * FIXME: ...gBootLoaderObjects without setting them to NULL. Since
1879 * FIXME: ...the code itself is immediately unloaded, there may not be
1880 * FIXME: ...any reason to worry about that!
1881 *********************************************************************/
1882 void clearStartupExtensionsAndLoaderInfo(void)
1884 OSDictionary
* startupExtensions
= NULL
; // must release
1885 OSArray
* bootLoaderObjects
= NULL
; // must release
1887 IORegistryEntry
* bootxMemoryMap
= NULL
; // must release
1888 OSDictionary
* propertyDict
= NULL
; // must release
1889 OSCollectionIterator
* keyIterator
= NULL
; // must release
1890 OSString
* key
= NULL
; // don't release
1893 * Drop any temporarily held data objects.
1895 bootLoaderObjects
= getBootLoaderObjects();
1896 if (bootLoaderObjects
) {
1897 bootLoaderObjects
->release();
1901 * If any "code" entries in driver dictionaries are accompanied
1902 * by "compressedCode" entries, then those data objects were
1903 * created based of of kmem_alloc()'ed memory, which must be
1906 startupExtensions
= getStartupExtensions();
1907 if (startupExtensions
) {
1909 OSCollectionIterator::withCollection(startupExtensions
);
1911 IOLog("Error: Couldn't allocate iterator for startup "
1914 goto memory_map
; // bail to the memory_map label
1917 while ( (key
= OSDynamicCast(OSString
,
1918 keyIterator
->getNextObject())) ) {
1920 OSDictionary
* driverDict
= 0;
1921 OSData
* codeData
= 0;
1923 driverDict
= OSDynamicCast(OSDictionary
,
1924 startupExtensions
->getObject(key
));
1926 codeData
= OSDynamicCast(OSData
,
1927 driverDict
->getObject("code"));
1930 driverDict
->getObject("compressedCode")) {
1932 kmem_free(kernel_map
,
1933 (unsigned int)codeData
->getBytesNoCopy(),
1934 codeData
->getLength());
1939 keyIterator
->release();
1940 startupExtensions
->release();
1946 * Go through the device tree's memory map and remove any driver
1950 IORegistryEntry::fromPath(
1951 "/chosen/memory-map", // path
1954 // return value is retained so be sure to release it
1956 if (!bootxMemoryMap
) {
1957 IOLog("Error: Couldn't read booter memory map.\n");
1962 propertyDict
= bootxMemoryMap
->dictionaryWithProperties();
1963 if (!propertyDict
) {
1964 IOLog("Error: Couldn't get property dictionary "
1965 "from memory map.\n");
1970 keyIterator
= OSCollectionIterator::withCollection(propertyDict
);
1972 IOLog("Error: Couldn't allocate iterator for driver images.\n");
1977 while ( (key
= OSDynamicCast(OSString
,
1978 keyIterator
->getNextObject())) ) {
1980 const char * keyValue
= key
->getCStringNoCopy();
1982 if ( !strncmp(keyValue
, BOOTX_KEXT_PREFIX
,
1983 strlen(BOOTX_KEXT_PREFIX
)) ||
1984 !strncmp(keyValue
, BOOTX_MULTIKEXT_PREFIX
,
1985 strlen(BOOTX_MULTIKEXT_PREFIX
)) ) {
1987 OSData
* bootxDriverDataObject
= NULL
;
1988 MemoryMapFileInfo
* driverInfo
= 0;
1990 bootxDriverDataObject
= OSDynamicCast(OSData
,
1991 propertyDict
->getObject(keyValue
));
1992 // don't release bootxDriverDataObject
1994 if (!bootxDriverDataObject
) {
1997 driverInfo
= (MemoryMapFileInfo
*)
1998 bootxDriverDataObject
->getBytesNoCopy(0,
1999 sizeof(MemoryMapFileInfo
));
2000 IODTFreeLoaderInfo((char *)keyValue
,
2001 (void *)driverInfo
->paddr
,
2002 (int)driverInfo
->length
);
2007 if (bootxMemoryMap
) bootxMemoryMap
->release();
2008 if (propertyDict
) propertyDict
->release();
2009 if (keyIterator
) keyIterator
->release();