2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
25 #include <libkern/c++/OSContainers.h>
26 #include <IOKit/IODeviceTreeSupport.h>
27 #include <IOKit/IORegistryEntry.h>
28 #include <IOKit/IOCatalogue.h>
29 #include <libkern/c++/OSUnserialize.h>
30 #include <libkern/OSByteOrder.h>
31 #include <libsa/catalogue.h>
34 #include <machine/machine_routines.h>
35 #include <mach/host_info.h>
36 #include <mach/kmod.h>
37 #include <libsa/mkext.h>
38 #include <libsa/vers_rsrc.h>
39 #include <mach-o/loader.h>
42 #include <IOKit/IOLib.h>
44 #include <IOKit/assert.h>
47 extern void IODTFreeLoaderInfo( char *key
, void *infoAddr
, int infoSize
);
48 extern kern_return_t
host_info(host_t host
,
51 mach_msg_type_number_t
*count
);
52 extern int check_cpu_subtype(cpu_subtype_t cpu_subtype
);
53 extern struct section
*
57 extern struct segment_command
*
58 getsegbyname(char *seg_name
);
64 #define VTYELLOW "\033[33m"
65 #define VTRESET "\033[0m"
71 /*********************************************************************
72 *********************************************************************/
73 static OSDictionary
* gStartupExtensions
= 0;
74 static OSArray
* gBootLoaderObjects
= 0;
75 extern OSArray
* gIOPrelinkedModules
;
77 OSDictionary
* getStartupExtensions(void) {
78 if (gStartupExtensions
) {
79 return gStartupExtensions
;
81 gStartupExtensions
= OSDictionary::withCapacity(1);
82 assert (gStartupExtensions
);
84 return gStartupExtensions
;
87 /* This array holds objects that are needed to be held around during
88 * boot before kextd starts up. Currently it contains OSData objects
89 * copied from OF entries for mkext archives in device ROMs. Because
90 * the Device Tree support code dumps these after initially handing
91 * them to us, we have to be able to clean them up later.
93 OSArray
* getBootLoaderObjects(void) {
94 if (gBootLoaderObjects
) {
95 return gBootLoaderObjects
;
97 gBootLoaderObjects
= OSArray::withCapacity(1);
98 assert (gBootLoaderObjects
);
100 return gBootLoaderObjects
;
103 /*********************************************************************
104 * This function checks that a driver dict has all the required
105 * entries and does a little bit of value checking too.
107 * index is nonnegative if the index of an entry from an mkext
109 *********************************************************************/
110 bool validateExtensionDict(OSDictionary
* extension
, int index
) {
113 bool not_a_dict
= false;
114 bool id_missing
= false;
115 bool is_kernel_resource
= false;
116 bool has_executable
= false;
117 OSString
* bundleIdentifier
= NULL
; // do not release
118 OSObject
* rawValue
= NULL
; // do not release
119 OSString
* stringValue
= NULL
; // do not release
120 OSBoolean
* booleanValue
= NULL
; // do not release
121 OSDictionary
* personalities
= NULL
; // do not release
122 OSDictionary
* libraries
= NULL
; // do not release
123 OSCollectionIterator
* keyIterator
= NULL
; // must release
124 OSString
* key
= NULL
; // do not release
126 VERS_version compatible_vers
;
128 // Info dict is a dictionary
129 if (!OSDynamicCast(OSDictionary
, extension
)) {
135 // CFBundleIdentifier is a string - REQUIRED
136 bundleIdentifier
= OSDynamicCast(OSString
,
137 extension
->getObject("CFBundleIdentifier"));
138 if (!bundleIdentifier
) {
144 // Length of CFBundleIdentifier is not >= KMOD_MAX_NAME
145 if (bundleIdentifier
->getLength() >= KMOD_MAX_NAME
) {
150 // CFBundlePackageType is "KEXT" - REQUIRED
151 stringValue
= OSDynamicCast(OSString
,
152 extension
->getObject("CFBundlePackageType"));
157 if (!stringValue
->isEqualTo("KEXT")) {
162 // CFBundleVersion is a string - REQUIRED
163 stringValue
= OSDynamicCast(OSString
,
164 extension
->getObject("CFBundleVersion"));
169 // CFBundleVersion is of valid form
170 vers
= VERS_parse_string(stringValue
->getCStringNoCopy());
176 // OSBundleCompatibleVersion is a string - OPTIONAL
177 rawValue
= extension
->getObject("OSBundleCompatibleVersion");
179 stringValue
= OSDynamicCast(OSString
, rawValue
);
185 // OSBundleCompatibleVersion is of valid form
186 compatible_vers
= VERS_parse_string(stringValue
->getCStringNoCopy());
187 if (compatible_vers
< 0) {
192 // OSBundleCompatibleVersion <= CFBundleVersion
193 if (compatible_vers
> vers
) {
199 // CFBundleExecutable is a string - OPTIONAL
200 rawValue
= extension
->getObject("CFBundleExecutable");
202 stringValue
= OSDynamicCast(OSString
, rawValue
);
203 if (!stringValue
|| stringValue
->getLength() == 0) {
207 has_executable
= true;
210 // OSKernelResource is a boolean value - OPTIONAL
211 rawValue
= extension
->getObject("OSKernelResource");
213 booleanValue
= OSDynamicCast(OSBoolean
, rawValue
);
218 is_kernel_resource
= booleanValue
->isTrue();
221 // IOKitPersonalities is a dictionary - OPTIONAL
222 rawValue
= extension
->getObject("IOKitPersonalities");
224 personalities
= OSDynamicCast(OSDictionary
, rawValue
);
225 if (!personalities
) {
230 keyIterator
= OSCollectionIterator::withCollection(personalities
);
232 IOLog("Error: Failed to allocate iterator for personalities.\n");
238 while ((key
= OSDynamicCast(OSString
, keyIterator
->getNextObject()))) {
239 OSDictionary
* personality
= NULL
; // do not release
241 // Each personality is a dictionary
242 personality
= OSDynamicCast(OSDictionary
,
243 personalities
->getObject(key
));
249 // IOClass exists as a string - REQUIRED
250 if (!OSDynamicCast(OSString
, personality
->getObject("IOClass"))) {
255 // IOProviderClass exists as a string - REQUIRED
256 if (!OSDynamicCast(OSString
,
257 personality
->getObject("IOProviderClass"))) {
263 // CFBundleIdentifier is a string - OPTIONAL - INSERT IF ABSENT!
264 rawValue
= personality
->getObject("CFBundleIdentifier");
266 personality
->setObject("CFBundleIdentifier", bundleIdentifier
);
268 OSString
* personalityID
= NULL
; // do not release
269 personalityID
= OSDynamicCast(OSString
, rawValue
);
270 if (!personalityID
) {
274 // Length of CFBundleIdentifier is not >= KMOD_MAX_NAME
275 if (personalityID
->getLength() >= KMOD_MAX_NAME
) {
282 // IOKitDebug is a number - OPTIONAL
283 rawValue
= personality
->getObject("IOKitDebug");
284 if (rawValue
&& !OSDynamicCast(OSNumber
, rawValue
)) {
290 keyIterator
->release();
295 // OSBundleLibraries is a dictionary - REQUIRED if
296 // not kernel resource & has executable
298 rawValue
= extension
->getObject("OSBundleLibraries");
299 if (!rawValue
&& !is_kernel_resource
&& has_executable
) {
305 libraries
= OSDynamicCast(OSDictionary
, rawValue
);
311 keyIterator
= OSCollectionIterator::withCollection(libraries
);
313 IOLog("Error: Failed to allocate iterator for libraries.\n");
319 while ((key
= OSDynamicCast(OSString
,
320 keyIterator
->getNextObject()))) {
322 OSString
* libraryVersion
= NULL
; // do not release
324 // Each key's length is not >= KMOD_MAX_NAME
325 if (key
->getLength() >= KMOD_MAX_NAME
) {
330 libraryVersion
= OSDynamicCast(OSString
,
331 libraries
->getObject(key
));
332 if (!libraryVersion
) {
337 // Each value is a valid version string
338 vers
= VERS_parse_string(libraryVersion
->getCStringNoCopy());
345 keyIterator
->release();
349 // OSBundleRequired is a legal value - *not* required at boot time
350 // so we can do install CDs and the like with mkext files containing
351 // all normally-used drivers.
352 rawValue
= extension
->getObject("OSBundleRequired");
354 stringValue
= OSDynamicCast(OSString
, rawValue
);
359 if (!stringValue
->isEqualTo("Root") &&
360 !stringValue
->isEqualTo("Local-Root") &&
361 !stringValue
->isEqualTo("Network-Root") &&
362 !stringValue
->isEqualTo("Safe Boot") &&
363 !stringValue
->isEqualTo("Console")) {
373 if (keyIterator
) keyIterator
->release();
378 IOLog(VTYELLOW
"mkext entry %d:." VTRESET
, index
);
380 IOLog(VTYELLOW
"kernel extension" VTRESET
);
382 IOLog(VTYELLOW
"info dictionary isn't a dictionary\n"
384 } else if (id_missing
) {
386 IOLog(VTYELLOW
"mkext entry %d:." VTRESET
, index
);
388 IOLog(VTYELLOW
"kernel extension" VTRESET
);
390 IOLog(VTYELLOW
"\"CFBundleIdentifier\" property is "
391 "missing or not a string\n"
394 IOLog(VTYELLOW
"kernel extension \"%s\": info dictionary is invalid\n"
395 VTRESET
, bundleIdentifier
->getCStringNoCopy());
404 /*********************************************************************
405 *********************************************************************/
406 OSDictionary
* compareExtensionVersions(
407 OSDictionary
* incumbent
,
408 OSDictionary
* candidate
) {
410 OSDictionary
* winner
= NULL
;
412 OSDictionary
* incumbentPlist
= NULL
;
413 OSDictionary
* candidatePlist
= NULL
;
414 OSString
* incumbentName
= NULL
;
415 OSString
* candidateName
= NULL
;
416 OSString
* incumbentVersionString
= NULL
;
417 OSString
* candidateVersionString
= NULL
;
418 VERS_version incumbent_vers
= 0;
419 VERS_version candidate_vers
= 0;
421 incumbentPlist
= OSDynamicCast(OSDictionary
,
422 incumbent
->getObject("plist"));
423 candidatePlist
= OSDynamicCast(OSDictionary
,
424 candidate
->getObject("plist"));
426 if (!incumbentPlist
|| !candidatePlist
) {
427 IOLog("compareExtensionVersions() called with invalid "
428 "extension dictionaries.\n");
434 incumbentName
= OSDynamicCast(OSString
,
435 incumbentPlist
->getObject("CFBundleIdentifier"));
436 candidateName
= OSDynamicCast(OSString
,
437 candidatePlist
->getObject("CFBundleIdentifier"));
438 incumbentVersionString
= OSDynamicCast(OSString
,
439 incumbentPlist
->getObject("CFBundleVersion"));
440 candidateVersionString
= OSDynamicCast(OSString
,
441 candidatePlist
->getObject("CFBundleVersion"));
443 if (!incumbentName
|| !candidateName
||
444 !incumbentVersionString
|| !candidateVersionString
) {
446 IOLog("compareExtensionVersions() called with invalid "
447 "extension dictionaries.\n");
453 if (strcmp(incumbentName
->getCStringNoCopy(),
454 candidateName
->getCStringNoCopy())) {
456 IOLog("compareExtensionVersions() called with different "
457 "extension names (%s and %s).\n",
458 incumbentName
->getCStringNoCopy(),
459 candidateName
->getCStringNoCopy());
465 incumbent_vers
= VERS_parse_string(incumbentVersionString
->getCStringNoCopy());
466 if (incumbent_vers
< 0) {
468 IOLog(VTYELLOW
"Error parsing version string for extension %s (%s)\n"
470 incumbentName
->getCStringNoCopy(),
471 incumbentVersionString
->getCStringNoCopy());
477 candidate_vers
= VERS_parse_string(candidateVersionString
->getCStringNoCopy());
478 if (candidate_vers
< 0) {
480 IOLog(VTYELLOW
"Error parsing version string for extension %s (%s)\n"
482 candidateName
->getCStringNoCopy(),
483 candidateVersionString
->getCStringNoCopy());
489 if (candidate_vers
> incumbent_vers
) {
490 IOLog(VTYELLOW
"Replacing extension \"%s\" with newer version "
491 "(%s -> %s).\n" VTRESET
,
492 incumbentName
->getCStringNoCopy(),
493 incumbentVersionString
->getCStringNoCopy(),
494 candidateVersionString
->getCStringNoCopy());
499 IOLog(VTYELLOW
"Skipping duplicate extension \"%s\" with older/same "
500 " version (%s -> %s).\n" VTRESET
,
501 candidateName
->getCStringNoCopy(),
502 candidateVersionString
->getCStringNoCopy(),
503 incumbentVersionString
->getCStringNoCopy());
511 // no cleanup, how nice
516 /*********************************************************************
517 * This function merges entries in the mergeFrom dictionary into the
518 * mergeInto dictionary. If it returns false, the two dictionaries are
519 * not altered. If it returns true, then mergeInto may have new
520 * entries; any keys that were already present in mergeInto are
521 * removed from mergeFrom, so that the caller can see what was
523 *********************************************************************/
524 bool mergeExtensionDictionaries(OSDictionary
* mergeInto
,
525 OSDictionary
* mergeFrom
) {
528 OSDictionary
* mergeIntoCopy
= NULL
; // must release
529 OSDictionary
* mergeFromCopy
= NULL
; // must release
530 OSCollectionIterator
* keyIterator
= NULL
; // must release
531 OSString
* key
; // don't release
533 /* Add 1 to count to guarantee copy can grow (grr).
535 mergeIntoCopy
= OSDictionary::withDictionary(mergeInto
,
536 mergeInto
->getCount() + 1);
537 if (!mergeIntoCopy
) {
538 IOLog("Error: Failed to copy 'into' extensions dictionary "
545 /* Add 1 to count to guarantee copy can grow (grr).
547 mergeFromCopy
= OSDictionary::withDictionary(mergeFrom
,
548 mergeFrom
->getCount() + 1);
549 if (!mergeFromCopy
) {
550 IOLog("Error: Failed to copy 'from' extensions dictionary "
557 keyIterator
= OSCollectionIterator::withCollection(mergeFrom
);
559 IOLog("Error: Failed to allocate iterator for extensions.\n");
567 * Loop through "from" dictionary, checking if the identifier already
568 * exists in the "into" dictionary and checking versions if it does.
570 while ((key
= OSDynamicCast(OSString
, keyIterator
->getNextObject()))) {
571 OSDictionary
* incumbentExt
= OSDynamicCast(OSDictionary
,
572 mergeIntoCopy
->getObject(key
));
573 OSDictionary
* candidateExt
= OSDynamicCast(OSDictionary
,
574 mergeFrom
->getObject(key
));
577 if (!mergeIntoCopy
->setObject(key
, candidateExt
)) {
579 /* This is a fatal error, so bail.
581 IOLog("mergeExtensionDictionaries(): Failed to add "
583 key
->getCStringNoCopy());
589 OSDictionary
* mostRecentExtension
=
590 compareExtensionVersions(incumbentExt
, candidateExt
);
592 if (mostRecentExtension
== incumbentExt
) {
593 mergeFromCopy
->removeObject(key
);
594 } else if (mostRecentExtension
== candidateExt
) {
596 if (!mergeIntoCopy
->setObject(key
, candidateExt
)) {
598 /* This is a fatal error, so bail.
600 IOLog("mergeExtensionDictionaries(): Failed to add "
602 key
->getCStringNoCopy());
607 } else /* should be NULL */ {
609 /* This is a nonfatal error, so continue doing others.
611 IOLog("mergeExtensionDictionaries(): Error comparing "
612 "versions of duplicate extensions %s.\n",
613 key
->getCStringNoCopy());
622 /* If successful, replace the contents of the original
623 * dictionaries with those of the modified copies.
626 mergeInto
->flushCollection();
627 mergeInto
->merge(mergeIntoCopy
);
628 mergeFrom
->flushCollection();
629 mergeFrom
->merge(mergeFromCopy
);
632 if (mergeIntoCopy
) mergeIntoCopy
->release();
633 if (mergeFromCopy
) mergeFromCopy
->release();
634 if (keyIterator
) keyIterator
->release();
641 * These bits are used to parse data made available by bootx.
643 #define BOOTX_KEXT_PREFIX "Driver-"
644 #define BOOTX_MULTIKEXT_PREFIX "DriversPackage-"
646 typedef struct MemoryMapFileInfo
{
651 typedef struct BootxDriverInfo
{
658 typedef struct MkextEntryInfo
{
659 vm_address_t base_address
;
660 mkext_file
* fileinfo
;
664 /*********************************************************************
665 * This private function reads the data for a single extension from
666 * the bootx memory-map's propery dict, returning a dictionary with
667 * keys "plist" for the extension's Info.plist as a parsed OSDictionary
668 * and "code" for the extension's executable code as an OSData.
669 *********************************************************************/
670 OSDictionary
* readExtension(OSDictionary
* propertyDict
,
671 const char * memory_map_name
) {
674 OSData
* bootxDriverDataObject
= NULL
;
675 OSDictionary
* driverPlist
= NULL
;
676 OSString
* driverName
= NULL
;
677 OSData
* driverCode
= NULL
;
678 OSString
* errorString
= NULL
;
679 OSDictionary
* driverDict
= NULL
;
681 MemoryMapFileInfo
* driverInfo
= 0;
682 BootxDriverInfo
* dataBuffer
;
684 kmod_info_t
* loaded_kmod
= NULL
;
686 bootxDriverDataObject
= OSDynamicCast(OSData
,
687 propertyDict
->getObject(memory_map_name
));
688 // don't release bootxDriverDataObject
690 if (!bootxDriverDataObject
) {
691 IOLog("Error: No driver data object "
692 "for device tree entry \"%s\".\n",
699 driverDict
= OSDictionary::withCapacity(2);
701 IOLog("Error: Couldn't allocate dictionary "
702 "for device tree entry \"%s\".\n", memory_map_name
);
708 driverInfo
= (MemoryMapFileInfo
*)
709 bootxDriverDataObject
->getBytesNoCopy(0,
710 sizeof(MemoryMapFileInfo
));
711 dataBuffer
= (BootxDriverInfo
*)ml_static_ptovirt(
714 IOLog("Error: No data buffer "
715 "for device tree entry \"%s\".\n", memory_map_name
);
721 driverPlist
= OSDynamicCast(OSDictionary
,
722 OSUnserializeXML(dataBuffer
->plistAddr
, &errorString
));
724 IOLog("Error: Couldn't read XML property list "
725 "for device tree entry \"%s\".\n", memory_map_name
);
728 IOLog("XML parse error: %s.\n",
729 errorString
->getCStringNoCopy());
737 driverName
= OSDynamicCast(OSString
,
738 driverPlist
->getObject("CFBundleIdentifier")); // do not release
740 IOLog("Error: Device tree entry \"%s\" has "
741 "no \"CFBundleIdentifier\" property.\n", memory_map_name
);
747 /* Check if kmod is already loaded and is a real loadable one (has
750 loaded_kmod
= kmod_lookupbyname_locked(driverName
->getCStringNoCopy());
751 if (loaded_kmod
&& loaded_kmod
->address
) {
752 IOLog("Skipping new extension \"%s\"; an extension named "
753 "\"%s\" is already loaded.\n",
754 driverName
->getCStringNoCopy(),
761 if (!validateExtensionDict(driverPlist
, -1)) {
762 // validateExtensionsDict() logs an error
767 driverDict
->setObject("plist", driverPlist
);
769 /* It's perfectly okay for a KEXT to have no executable.
770 * Check that moduleAddr is nonzero before attempting to
773 * NOTE: The driverCode object is created "no-copy", so
774 * it doesn't own that memory. The memory must be freed
775 * separately from the OSData object (see
776 * clearStartupExtensionsAndLoaderInfo() at the end of this file).
778 if (dataBuffer
->moduleAddr
&& dataBuffer
->moduleLength
) {
779 driverCode
= OSData::withBytesNoCopy(dataBuffer
->moduleAddr
,
780 dataBuffer
->moduleLength
);
782 IOLog("Error: Couldn't allocate data object "
783 "to hold code for device tree entry \"%s\".\n",
791 driverDict
->setObject("code", driverCode
);
798 kfree((unsigned int)loaded_kmod
, sizeof(kmod_info_t
));
801 // do not release bootxDriverDataObject
802 // do not release driverName
805 driverPlist
->release();
808 errorString
->release();
811 driverCode
->release();
815 driverDict
->release();
823 /*********************************************************************
824 * Used to uncompress a single file entry in an mkext archive.
826 * The OSData returned does not own its memory! You must deallocate
827 * that memory using kmem_free() before releasing the OSData().
828 *********************************************************************/
829 static bool uncompressFile(u_int8_t
*base_address
, mkext_file
* fileinfo
,
830 /* out */ OSData
** file
) {
833 kern_return_t kern_result
;
834 u_int8_t
* uncompressed_file
= 0; // kmem_free() on error
835 OSData
* uncompressedFile
= 0; // returned
836 size_t uncompressed_size
= 0;
838 size_t offset
= OSSwapBigToHostInt32(fileinfo
->offset
);
839 size_t compsize
= OSSwapBigToHostInt32(fileinfo
->compsize
);
840 size_t realsize
= OSSwapBigToHostInt32(fileinfo
->realsize
);
841 time_t modifiedsecs
= OSSwapBigToHostInt32(fileinfo
->modifiedsecs
);
845 /* If these four fields are zero there's no file, but that isn't
848 if (offset
== 0 && compsize
== 0 &&
849 realsize
== 0 && modifiedsecs
== 0) {
853 // Add 1 for '\0' to terminate XML string!
854 kern_result
= kmem_alloc(kernel_map
, (vm_offset_t
*)&uncompressed_file
,
856 if (kern_result
!= KERN_SUCCESS
) {
857 IOLog("Error: Couldn't allocate data buffer "
858 "to uncompress file.\n");
864 uncompressedFile
= OSData::withBytesNoCopy(uncompressed_file
,
866 if (!uncompressedFile
) {
867 IOLog("Error: Couldn't allocate data object "
868 "to uncompress file.\n");
875 uncompressed_size
= decompress_lzss(uncompressed_file
,
876 base_address
+ offset
,
878 if (uncompressed_size
!= realsize
) {
879 IOLog("Error: Uncompressed file is not the length "
885 uncompressed_file
[uncompressed_size
] = '\0';
887 bcopy(base_address
+ offset
, uncompressed_file
,
889 uncompressed_file
[realsize
] = '\0';
892 *file
= uncompressedFile
;
896 if (uncompressed_file
) {
897 kmem_free(kernel_map
, (vm_address_t
)uncompressed_file
,
900 if (uncompressedFile
) {
901 uncompressedFile
->release();
908 bool uncompressModule(OSData
*compData
, /* out */ OSData
** file
) {
910 MkextEntryInfo
*info
= (MkextEntryInfo
*) compData
->getBytesNoCopy();
912 return uncompressFile((u_int8_t
*) info
->base_address
,
913 info
->fileinfo
, file
);
917 /*********************************************************************
918 * Does the work of pulling extensions out of an mkext archive located
920 *********************************************************************/
921 bool extractExtensionsFromArchive(MemoryMapFileInfo
* mkext_file_info
,
922 OSDictionary
* extensions
) {
926 u_int8_t
* crc_address
= 0;
928 mkext_header
* mkext_data
= 0; // don't free
929 mkext_kext
* onekext_data
= 0; // don't free
930 mkext_file
* plist_file
= 0; // don't free
931 mkext_file
* module_file
= 0; // don't free
932 kmod_info_t
* loaded_kmod
= 0; // must free
934 OSData
* driverPlistDataObject
= 0; // must release
935 OSDictionary
* driverPlist
= 0; // must release
936 OSData
* driverCode
= 0; // must release
937 OSDictionary
* driverDict
= 0; // must release
938 OSString
* moduleName
= 0; // don't release
939 OSString
* errorString
= NULL
; // must release
941 OSData
* moduleInfo
= 0; // must release
942 MkextEntryInfo module_info
;
944 mkext_data
= (mkext_header
*)mkext_file_info
->paddr
;
946 if (OSSwapBigToHostInt32(mkext_data
->magic
) != MKEXT_MAGIC
||
947 OSSwapBigToHostInt32(mkext_data
->signature
) != MKEXT_SIGN
) {
948 IOLog("Error: Extension archive has invalid magic or signature.\n");
954 if (OSSwapBigToHostInt32(mkext_data
->length
) != mkext_file_info
->length
) {
955 IOLog("Error: Mismatch between extension archive & "
956 "recorded length.\n");
962 crc_address
= (u_int8_t
*)&mkext_data
->version
;
963 checksum
= adler32(crc_address
,
964 (unsigned int)mkext_data
+
965 OSSwapBigToHostInt32(mkext_data
->length
) - (unsigned int)crc_address
);
967 if (OSSwapBigToHostInt32(mkext_data
->adler32
) != checksum
) {
968 IOLog("Error: Extension archive has a bad checksum.\n");
974 /* If the MKEXT archive isn't fat, check that the CPU type & subtype
975 * match that of the running kernel.
977 if (OSSwapBigToHostInt32(mkext_data
->cputype
) != (UInt32
)CPU_TYPE_ANY
) {
978 kern_return_t kresult
= KERN_FAILURE
;
979 host_basic_info_data_t hostinfo
;
980 host_info_t hostinfo_ptr
= (host_info_t
)&hostinfo
;
981 mach_msg_type_number_t count
= sizeof(hostinfo
)/sizeof(integer_t
);
983 kresult
= host_info((host_t
)1, HOST_BASIC_INFO
,
984 hostinfo_ptr
, &count
);
985 if (kresult
!= KERN_SUCCESS
) {
986 IOLog("Error: Couldn't get current host info.\n");
991 if ((UInt32
)hostinfo
.cpu_type
!=
992 OSSwapBigToHostInt32(mkext_data
->cputype
)) {
994 IOLog("Error: Extension archive doesn't contain software "
995 "for this computer's CPU type.\n");
1000 if (!check_cpu_subtype(OSSwapBigToHostInt32(mkext_data
->cpusubtype
))) {
1001 IOLog("Error: Extension archive doesn't contain software "
1002 "for this computer's CPU subtype.\n");
1009 for (unsigned int i
= 0;
1010 i
< OSSwapBigToHostInt32(mkext_data
->numkexts
);
1014 kfree((unsigned int)loaded_kmod
, sizeof(kmod_info_t
));
1018 if (driverPlistDataObject
) {
1019 kmem_free(kernel_map
,
1020 (unsigned int)driverPlistDataObject
->getBytesNoCopy(),
1021 driverPlistDataObject
->getLength());
1023 driverPlistDataObject
->release();
1024 driverPlistDataObject
= NULL
;
1027 driverPlist
->release();
1031 driverCode
->release();
1035 driverDict
->release();
1039 errorString
->release();
1043 onekext_data
= &mkext_data
->kext
[i
];
1044 plist_file
= &onekext_data
->plist
;
1045 module_file
= &onekext_data
->module;
1047 if (!uncompressFile((u_int8_t
*)mkext_data
, plist_file
,
1048 &driverPlistDataObject
)) {
1050 IOLog("Error: couldn't uncompress plist file "
1051 "from multikext archive entry %d.\n", i
);
1056 if (!driverPlistDataObject
) {
1057 IOLog("Error: No property list present "
1058 "for multikext archive entry %d.\n", i
);
1062 driverPlist
= OSDynamicCast(OSDictionary
,
1064 (char *)driverPlistDataObject
->getBytesNoCopy(),
1067 IOLog("Error: Couldn't read XML property list "
1068 "for multikext archive entry %d.\n", i
);
1071 IOLog("XML parse error: %s.\n",
1072 errorString
->getCStringNoCopy());
1078 if (!validateExtensionDict(driverPlist
, i
)) {
1079 // validateExtensionsDict() logs an error
1085 /* Get the extension's module name. This is used to record
1088 moduleName
= OSDynamicCast(OSString
,
1089 driverPlist
->getObject("CFBundleIdentifier")); // do not release
1091 IOLog("Error: Multikext archive entry %d has "
1092 "no \"CFBundleIdentifier\" property.\n", i
);
1094 continue; // assume a kext config error & continue
1097 /* Check if kmod is already loaded and is a real loadable one (has
1100 loaded_kmod
= kmod_lookupbyname_locked(moduleName
->getCStringNoCopy());
1101 if (loaded_kmod
&& loaded_kmod
->address
) {
1102 IOLog("Skipping new extension \"%s\"; an extension named "
1103 "\"%s\" is already loaded.\n",
1104 moduleName
->getCStringNoCopy(),
1110 driverDict
= OSDictionary::withCapacity(2);
1112 IOLog("Error: Couldn't allocate dictionary "
1113 "for multikext archive entry %d.\n", i
);
1119 driverDict
->setObject("plist", driverPlist
);
1122 * Prepare an entry to hold the mkext entry info for the
1123 * compressed binary module, if there is one. If all four fields
1124 * of the module entry are zero, there isn't one.
1126 if (!(loaded_kmod
&& loaded_kmod
->address
) && (OSSwapBigToHostInt32(module_file
->offset
) ||
1127 OSSwapBigToHostInt32(module_file
->compsize
) ||
1128 OSSwapBigToHostInt32(module_file
->realsize
) ||
1129 OSSwapBigToHostInt32(module_file
->modifiedsecs
))) {
1131 moduleInfo
= OSData::withCapacity(sizeof(MkextEntryInfo
));
1133 IOLog("Error: Couldn't allocate data object "
1134 "for multikext archive entry %d.\n", i
);
1140 module_info
.base_address
= (vm_address_t
)mkext_data
;
1141 module_info
.fileinfo
= module_file
;
1143 if (!moduleInfo
->appendBytes(&module_info
, sizeof(module_info
))) {
1144 IOLog("Error: Couldn't record info "
1145 "for multikext archive entry %d.\n", i
);
1151 driverDict
->setObject("compressedCode", moduleInfo
);
1154 OSDictionary
* incumbentExt
= OSDynamicCast(OSDictionary
,
1155 extensions
->getObject(moduleName
));
1157 if (!incumbentExt
) {
1158 extensions
->setObject(moduleName
, driverDict
);
1160 OSDictionary
* mostRecentExtension
=
1161 compareExtensionVersions(incumbentExt
, driverDict
);
1163 if (mostRecentExtension
== incumbentExt
) {
1164 /* Do nothing, we've got the most recent. */
1165 } else if (mostRecentExtension
== driverDict
) {
1166 if (!extensions
->setObject(moduleName
, driverDict
)) {
1168 /* This is a fatal error, so bail.
1170 IOLog("extractExtensionsFromArchive(): Failed to add "
1172 moduleName
->getCStringNoCopy());
1177 } else /* should be NULL */ {
1179 /* This is a nonfatal error, so continue.
1181 IOLog("extractExtensionsFromArchive(): Error comparing "
1182 "versions of duplicate extensions %s.\n",
1183 moduleName
->getCStringNoCopy());
1192 if (loaded_kmod
) kfree((unsigned int)loaded_kmod
, sizeof(kmod_info_t
));
1193 if (driverPlistDataObject
) {
1194 kmem_free(kernel_map
,
1195 (unsigned int)driverPlistDataObject
->getBytesNoCopy(),
1196 driverPlistDataObject
->getLength());
1197 driverPlistDataObject
->release();
1199 if (driverPlist
) driverPlist
->release();
1200 if (driverCode
) driverCode
->release();
1201 if (moduleInfo
) moduleInfo
->release();
1202 if (driverDict
) driverDict
->release();
1203 if (errorString
) errorString
->release();
1208 /*********************************************************************
1210 *********************************************************************/
1211 bool readExtensions(OSDictionary
* propertyDict
,
1212 const char * memory_map_name
,
1213 OSDictionary
* extensions
) {
1216 OSData
* mkextDataObject
= 0; // don't release
1217 MemoryMapFileInfo
* mkext_file_info
= 0; // don't free
1219 mkextDataObject
= OSDynamicCast(OSData
,
1220 propertyDict
->getObject(memory_map_name
));
1221 // don't release mkextDataObject
1223 if (!mkextDataObject
) {
1224 IOLog("Error: No mkext data object "
1225 "for device tree entry \"%s\".\n",
1232 mkext_file_info
= (MemoryMapFileInfo
*)mkextDataObject
->getBytesNoCopy();
1233 if (!mkext_file_info
) {
1238 result
= extractExtensionsFromArchive(mkext_file_info
, extensions
);
1242 if (!result
&& extensions
) {
1243 extensions
->flushCollection();
1250 /*********************************************************************
1251 * Adds the personalities for an extensions dictionary to the global
1253 *********************************************************************/
1254 bool addPersonalities(OSDictionary
* extensions
) {
1256 OSCollectionIterator
* keyIterator
= NULL
; // must release
1257 OSString
* key
; // don't release
1258 OSDictionary
* driverDict
= NULL
; // don't release
1259 OSDictionary
* driverPlist
= NULL
; // don't release
1260 OSDictionary
* thisDriverPersonalities
= NULL
; // don't release
1261 OSArray
* allDriverPersonalities
= NULL
; // must release
1263 allDriverPersonalities
= OSArray::withCapacity(1);
1264 if (!allDriverPersonalities
) {
1265 IOLog("Error: Couldn't allocate personality dictionary.\n");
1271 /* Record all personalities found so that they can be
1272 * added to the catalogue.
1273 * Note: Not all extensions have personalities.
1276 keyIterator
= OSCollectionIterator::withCollection(extensions
);
1278 IOLog("Error: Couldn't allocate iterator to record personalities.\n");
1284 while ( ( key
= OSDynamicCast(OSString
,
1285 keyIterator
->getNextObject() ))) {
1287 driverDict
= OSDynamicCast(OSDictionary
,
1288 extensions
->getObject(key
));
1289 driverPlist
= OSDynamicCast(OSDictionary
,
1290 driverDict
->getObject("plist"));
1291 thisDriverPersonalities
= OSDynamicCast(OSDictionary
,
1292 driverPlist
->getObject("IOKitPersonalities"));
1294 if (thisDriverPersonalities
) {
1295 OSCollectionIterator
* pIterator
;
1297 pIterator
= OSCollectionIterator::withCollection(
1298 thisDriverPersonalities
);
1300 IOLog("Error: Couldn't allocate iterator "
1301 "to record extension personalities.\n");
1305 while ( (key
= OSDynamicCast(OSString
,
1306 pIterator
->getNextObject())) ) {
1308 OSDictionary
* personality
= OSDynamicCast(
1310 thisDriverPersonalities
->getObject(key
));
1312 allDriverPersonalities
->setObject(personality
);
1315 pIterator
->release();
1317 } /* extract personalities */
1320 /* Add all personalities found to the IOCatalogue,
1321 * but don't start matching.
1323 gIOCatalogue
->addDrivers(allDriverPersonalities
, false);
1327 if (allDriverPersonalities
) allDriverPersonalities
->release();
1328 if (keyIterator
) keyIterator
->release();
1334 /*********************************************************************
1335 * Called from IOCatalogue to add extensions from an mkext archive.
1336 * This function makes a copy of the mkext object passed in because
1337 * the device tree support code dumps it after calling us (indirectly
1338 * through the IOCatalogue).
1339 *********************************************************************/
1340 bool addExtensionsFromArchive(OSData
* mkextDataObject
) {
1343 OSDictionary
* startupExtensions
= NULL
; // don't release
1344 OSArray
* bootLoaderObjects
= NULL
; // don't release
1345 OSDictionary
* extensions
= NULL
; // must release
1346 MemoryMapFileInfo mkext_file_info
;
1347 OSCollectionIterator
* keyIterator
= NULL
; // must release
1348 OSString
* key
= NULL
; // don't release
1350 startupExtensions
= getStartupExtensions();
1351 if (!startupExtensions
) {
1352 IOLog("Can't record extension archive; there is no"
1353 " extensions dictionary.\n");
1359 bootLoaderObjects
= getBootLoaderObjects();
1360 if (! bootLoaderObjects
) {
1361 IOLog("Error: Couldn't allocate array to hold temporary objects.\n");
1367 extensions
= OSDictionary::withCapacity(2);
1369 IOLog("Error: Couldn't allocate dictionary to unpack "
1370 "extension archive.\n");
1376 mkext_file_info
.paddr
= (UInt32
)mkextDataObject
->getBytesNoCopy();
1377 mkext_file_info
.length
= mkextDataObject
->getLength();
1379 /* Save the local mkext data object so that we can deallocate it later.
1381 bootLoaderObjects
->setObject(mkextDataObject
);
1383 result
= extractExtensionsFromArchive(&mkext_file_info
, extensions
);
1385 IOLog("Error: Failed to extract extensions from archive.\n");
1391 result
= mergeExtensionDictionaries(startupExtensions
, extensions
);
1393 IOLog("Error: Failed to merge new extensions into existing set.\n");
1398 result
= addPersonalities(extensions
);
1400 IOLog("Error: Failed to add personalities for extensions extracted "
1410 IOLog("Error: Failed to record extensions from archive.\n");
1413 keyIterator
= OSCollectionIterator::withCollection(
1417 while ( (key
= OSDynamicCast(OSString
,
1418 keyIterator
->getNextObject())) ) {
1420 IOLog("Added extension \"%s\" from archive.\n",
1421 key
->getCStringNoCopy());
1424 keyIterator
->release();
1428 if (extensions
) extensions
->release();
1434 /*********************************************************************
1435 * This function builds dictionaries for the startup extensions
1436 * put into memory by bootx, recording each in the startup extensions
1437 * dictionary. The dictionary format is this:
1440 * "plist" = (the extension's Info.plist as an OSDictionary)
1441 * "code" = (an OSData containing the executable file)
1444 * This function returns true if any extensions were found and
1445 * recorded successfully, or if there are no start extensions,
1446 * and false if an unrecoverable error occurred. An error reading
1447 * a single extension is not considered fatal, and this function
1448 * will simply skip the problematic extension to try the next one.
1449 *********************************************************************/
1451 bool recordStartupExtensions(void) {
1453 OSDictionary
* startupExtensions
= NULL
; // must release
1454 OSDictionary
* existingExtensions
= NULL
; // don't release
1455 OSDictionary
* mkextExtensions
= NULL
; // must release
1456 IORegistryEntry
* bootxMemoryMap
= NULL
; // must release
1457 OSDictionary
* propertyDict
= NULL
; // must release
1458 OSCollectionIterator
* keyIterator
= NULL
; // must release
1459 OSString
* key
= NULL
; // don't release
1461 OSDictionary
* newDriverDict
= NULL
; // must release
1462 OSDictionary
* driverPlist
= NULL
; // don't release
1464 struct section
* infosect
;
1465 struct section
* symsect
;
1466 unsigned int prelinkedCount
= 0;
1468 existingExtensions
= getStartupExtensions();
1469 if (!existingExtensions
) {
1470 IOLog("Error: There is no dictionary for startup extensions.\n");
1476 startupExtensions
= OSDictionary::withCapacity(1);
1477 if (!startupExtensions
) {
1478 IOLog("Error: Couldn't allocate dictionary "
1479 "to record startup extensions.\n");
1486 // add any prelinked modules as startup extensions
1488 infosect
= getsectbyname("__PRELINK", "__info");
1489 symsect
= getsectbyname("__PRELINK", "__symtab");
1490 if (infosect
&& infosect
->addr
&& infosect
->size
1491 && symsect
&& symsect
->addr
&& symsect
->size
) do
1493 gIOPrelinkedModules
= OSDynamicCast(OSArray
,
1494 OSUnserializeXML((const char *) infosect
->addr
, NULL
));
1496 if (!gIOPrelinkedModules
)
1498 for( unsigned int idx
= 0;
1499 (propertyDict
= OSDynamicCast(OSDictionary
, gIOPrelinkedModules
->getObject(idx
)));
1502 enum { kPrelinkReservedCount
= 4 };
1504 /* Get the extension's module name. This is used to record
1505 * the extension. Do *not* release the moduleName.
1507 OSString
* moduleName
= OSDynamicCast(OSString
,
1508 propertyDict
->getObject("CFBundleIdentifier"));
1510 IOLog("Error: Prelinked module entry has "
1511 "no \"CFBundleIdentifier\" property.\n");
1516 /* Add the kext, & its plist.
1518 newDriverDict
= OSDictionary::withCapacity(4);
1519 assert(newDriverDict
);
1520 newDriverDict
->setObject("plist", propertyDict
);
1521 startupExtensions
->setObject(moduleName
, newDriverDict
);
1522 newDriverDict
->release();
1524 /* Add the code if present.
1526 OSData
* data
= OSDynamicCast(OSData
, propertyDict
->getObject("OSBundlePrelink"));
1528 if (data
->getLength() < (kPrelinkReservedCount
* sizeof(UInt32
))) {
1529 IOLog("Error: Prelinked module entry has "
1530 "invalid \"OSBundlePrelink\" property.\n");
1535 prelink
= (UInt32
*) data
->getBytesNoCopy();
1536 kmod_info_t
* kmod_info
= (kmod_info_t
*) OSReadBigInt32(prelink
, 0);
1537 // end of "file" is end of symbol sect
1538 data
= OSData::withBytesNoCopy((void *) kmod_info
->address
,
1539 symsect
->addr
+ symsect
->size
- kmod_info
->address
);
1540 newDriverDict
->setObject("code", data
);
1545 /* Add the symbols if present.
1547 OSNumber
* num
= OSDynamicCast(OSNumber
, propertyDict
->getObject("OSBundlePrelinkSymbols"));
1549 UInt32 offset
= num
->unsigned32BitValue();
1550 data
= OSData::withBytesNoCopy((void *) (symsect
->addr
+ offset
), symsect
->size
- offset
);
1551 newDriverDict
->setObject("code", data
);
1557 if (gIOPrelinkedModules
)
1558 IOLog("%d prelinked modules\n", prelinkedCount
);
1562 virt
= ml_static_ptovirt(infosect
->addr
);
1564 ml_static_mfree(virt
, infosect
->size
);
1566 newDriverDict
= NULL
;
1572 IORegistryEntry::fromPath(
1573 "/chosen/memory-map", // path
1576 // return value is retained so be sure to release it
1578 if (!bootxMemoryMap
) {
1579 IOLog("Error: Couldn't read booter memory map.\n");
1585 propertyDict
= bootxMemoryMap
->dictionaryWithProperties();
1586 if (!propertyDict
) {
1587 IOLog("Error: Couldn't get property dictionary "
1588 "from memory map.\n");
1594 keyIterator
= OSCollectionIterator::withCollection(propertyDict
);
1596 IOLog("Error: Couldn't allocate iterator for driver images.\n");
1602 while ( (key
= OSDynamicCast(OSString
,
1603 keyIterator
->getNextObject())) ) {
1604 /* Clear newDriverDict & mkextExtensions upon entry to the loop,
1605 * handling both successful and unsuccessful iterations.
1607 if (newDriverDict
) {
1608 newDriverDict
->release();
1609 newDriverDict
= NULL
;
1611 if (mkextExtensions
) {
1612 mkextExtensions
->release();
1613 mkextExtensions
= NULL
;
1616 const char * keyValue
= key
->getCStringNoCopy();
1618 if ( !strncmp(keyValue
, BOOTX_KEXT_PREFIX
,
1619 strlen(BOOTX_KEXT_PREFIX
)) ) {
1621 /* Read the extension from the bootx-supplied memory.
1623 newDriverDict
= readExtension(propertyDict
, keyValue
);
1624 if (!newDriverDict
) {
1625 IOLog("Error: Couldn't read data "
1626 "for device tree entry \"%s\".\n", keyValue
);
1632 /* Preprare to record the extension by getting its info plist.
1634 driverPlist
= OSDynamicCast(OSDictionary
,
1635 newDriverDict
->getObject("plist"));
1637 IOLog("Error: Extension in device tree entry \"%s\" "
1638 "has no property list.\n", keyValue
);
1644 /* Get the extension's module name. This is used to record
1645 * the extension. Do *not* release the moduleName.
1647 OSString
* moduleName
= OSDynamicCast(OSString
,
1648 driverPlist
->getObject("CFBundleIdentifier"));
1650 IOLog("Error: Device tree entry \"%s\" has "
1651 "no \"CFBundleIdentifier\" property.\n", keyValue
);
1657 /* All has gone well so far, so record the extension under
1658 * its module name, checking for an existing duplicate.
1660 * Do not release moduleName, as it's part of the extension's
1663 OSDictionary
* incumbentExt
= OSDynamicCast(OSDictionary
,
1664 startupExtensions
->getObject(moduleName
));
1666 if (!incumbentExt
) {
1667 startupExtensions
->setObject(moduleName
, newDriverDict
);
1669 OSDictionary
* mostRecentExtension
=
1670 compareExtensionVersions(incumbentExt
, newDriverDict
);
1672 if (mostRecentExtension
== incumbentExt
) {
1673 /* Do nothing, we've got the most recent. */
1674 } else if (mostRecentExtension
== newDriverDict
) {
1675 if (!startupExtensions
->setObject(moduleName
,
1678 /* This is a fatal error, so bail.
1680 IOLog("recordStartupExtensions(): Failed to add "
1682 moduleName
->getCStringNoCopy());
1687 } else /* should be NULL */ {
1689 /* This is a nonfatal error, so continue.
1691 IOLog("recordStartupExtensions(): Error comparing "
1692 "versions of duplicate extensions %s.\n",
1693 moduleName
->getCStringNoCopy());
1700 } else if ( !strncmp(keyValue
, BOOTX_MULTIKEXT_PREFIX
,
1701 strlen(BOOTX_MULTIKEXT_PREFIX
)) ) {
1703 mkextExtensions
= OSDictionary::withCapacity(10);
1704 if (!mkextExtensions
) {
1705 IOLog("Error: Couldn't allocate dictionary to unpack "
1706 "multi-extension archive.\n");
1709 goto finish
; // allocation failure is fatal for this routine
1711 if (!readExtensions(propertyDict
, keyValue
, mkextExtensions
)) {
1712 IOLog("Error: Couldn't unpack multi-extension archive.\n");
1716 if (!mergeExtensionDictionaries(startupExtensions
,
1719 IOLog("Error: Failed to merge new extensions into "
1723 goto finish
; // merge error is fatal for this routine
1728 // Do not release key.
1730 } /* while ( (key = OSDynamicCast(OSString, ...) ) ) */
1732 if (!mergeExtensionDictionaries(existingExtensions
, startupExtensions
)) {
1733 IOLog("Error: Failed to merge new extensions into existing set.\n");
1739 result
= addPersonalities(startupExtensions
);
1741 IOLog("Error: Failed to add personalities for extensions extracted "
1750 // reused so clear first!
1752 keyIterator
->release();
1757 IOLog("Error: Failed to record startup extensions.\n");
1761 keyIterator
= OSCollectionIterator::withCollection(
1765 while ( (key
= OSDynamicCast(OSString
,
1766 keyIterator
->getNextObject())) ) {
1768 IOLog("Found extension \"%s\".\n",
1769 key
->getCStringNoCopy());
1772 keyIterator
->release();
1778 if (newDriverDict
) newDriverDict
->release();
1779 if (propertyDict
) propertyDict
->release();
1780 if (bootxMemoryMap
) bootxMemoryMap
->release();
1781 if (mkextExtensions
) mkextExtensions
->release();
1782 if (startupExtensions
) startupExtensions
->release();
1788 /*********************************************************************
1789 * This function removes an entry from the dictionary of startup
1790 * extensions. It's used when an extension can't be loaded, for
1791 * whatever reason. For drivers, this allows another matching driver
1792 * to be loaded, so that, for example, a driver for the root device
1794 *********************************************************************/
1795 void removeStartupExtension(const char * extensionName
) {
1796 OSDictionary
* startupExtensions
= NULL
; // don't release
1797 OSDictionary
* extensionDict
= NULL
; // don't release
1798 OSDictionary
* extensionPlist
= NULL
; // don't release
1799 OSDictionary
* extensionPersonalities
= NULL
; // don't release
1800 OSDictionary
* personality
= NULL
; // don't release
1801 OSCollectionIterator
* keyIterator
= NULL
; // must release
1802 OSString
* key
= NULL
; // don't release
1804 startupExtensions
= getStartupExtensions();
1805 if (!startupExtensions
) goto finish
;
1808 /* Find the extension's entry in the dictionary of
1809 * startup extensions.
1811 extensionDict
= OSDynamicCast(OSDictionary
,
1812 startupExtensions
->getObject(extensionName
));
1813 if (!extensionDict
) goto finish
;
1815 extensionPlist
= OSDynamicCast(OSDictionary
,
1816 extensionDict
->getObject("plist"));
1817 if (!extensionPlist
) goto finish
;
1819 extensionPersonalities
= OSDynamicCast(OSDictionary
,
1820 extensionPlist
->getObject("IOKitPersonalities"));
1821 if (!extensionPersonalities
) goto finish
;
1823 /* If it was there, remove it from the catalogue proper
1824 * by calling removeDrivers(). Pass true for the second
1825 * argument to trigger a new round of matching, and
1826 * then remove the extension from the dictionary of startup
1829 keyIterator
= OSCollectionIterator::withCollection(
1830 extensionPersonalities
);
1832 IOLog("Error: Couldn't allocate iterator to scan"
1833 " personalities for %s.\n", extensionName
);
1837 while ((key
= OSDynamicCast(OSString
, keyIterator
->getNextObject()))) {
1838 personality
= OSDynamicCast(OSDictionary
,
1839 extensionPersonalities
->getObject(key
));
1843 gIOCatalogue
->removeDrivers(personality
, true);
1847 startupExtensions
->removeObject(extensionName
);
1851 if (keyIterator
) keyIterator
->release();
1855 /*********************************************************************
1856 * FIXME: This function invalidates the globals gStartupExtensions and
1857 * FIXME: ...gBootLoaderObjects without setting them to NULL. Since
1858 * FIXME: ...the code itself is immediately unloaded, there may not be
1859 * FIXME: ...any reason to worry about that!
1860 *********************************************************************/
1861 void clearStartupExtensionsAndLoaderInfo(void)
1863 OSDictionary
* startupExtensions
= NULL
; // must release
1864 OSArray
* bootLoaderObjects
= NULL
; // must release
1866 IORegistryEntry
* bootxMemoryMap
= NULL
; // must release
1867 OSDictionary
* propertyDict
= NULL
; // must release
1868 OSCollectionIterator
* keyIterator
= NULL
; // must release
1869 OSString
* key
= NULL
; // don't release
1872 * Drop any temporarily held data objects.
1874 bootLoaderObjects
= getBootLoaderObjects();
1875 if (bootLoaderObjects
) {
1876 bootLoaderObjects
->release();
1880 * If any "code" entries in driver dictionaries are accompanied
1881 * by "compressedCode" entries, then those data objects were
1882 * created based of of kmem_alloc()'ed memory, which must be
1885 startupExtensions
= getStartupExtensions();
1886 if (startupExtensions
) {
1888 OSCollectionIterator::withCollection(startupExtensions
);
1890 IOLog("Error: Couldn't allocate iterator for startup "
1893 goto memory_map
; // bail to the memory_map label
1896 while ( (key
= OSDynamicCast(OSString
,
1897 keyIterator
->getNextObject())) ) {
1899 OSDictionary
* driverDict
= 0;
1900 OSData
* codeData
= 0;
1902 driverDict
= OSDynamicCast(OSDictionary
,
1903 startupExtensions
->getObject(key
));
1905 codeData
= OSDynamicCast(OSData
,
1906 driverDict
->getObject("code"));
1909 driverDict
->getObject("compressedCode")) {
1911 kmem_free(kernel_map
,
1912 (unsigned int)codeData
->getBytesNoCopy(),
1913 codeData
->getLength());
1918 keyIterator
->release();
1919 startupExtensions
->release();
1925 * Go through the device tree's memory map and remove any driver
1929 IORegistryEntry::fromPath(
1930 "/chosen/memory-map", // path
1933 // return value is retained so be sure to release it
1935 if (!bootxMemoryMap
) {
1936 IOLog("Error: Couldn't read booter memory map.\n");
1941 propertyDict
= bootxMemoryMap
->dictionaryWithProperties();
1942 if (!propertyDict
) {
1943 IOLog("Error: Couldn't get property dictionary "
1944 "from memory map.\n");
1949 keyIterator
= OSCollectionIterator::withCollection(propertyDict
);
1951 IOLog("Error: Couldn't allocate iterator for driver images.\n");
1956 while ( (key
= OSDynamicCast(OSString
,
1957 keyIterator
->getNextObject())) ) {
1959 const char * keyValue
= key
->getCStringNoCopy();
1961 if ( !strncmp(keyValue
, BOOTX_KEXT_PREFIX
,
1962 strlen(BOOTX_KEXT_PREFIX
)) ||
1963 !strncmp(keyValue
, BOOTX_MULTIKEXT_PREFIX
,
1964 strlen(BOOTX_MULTIKEXT_PREFIX
)) ) {
1966 OSData
* bootxDriverDataObject
= NULL
;
1967 MemoryMapFileInfo
* driverInfo
= 0;
1969 bootxDriverDataObject
= OSDynamicCast(OSData
,
1970 propertyDict
->getObject(keyValue
));
1971 // don't release bootxDriverDataObject
1973 if (!bootxDriverDataObject
) {
1976 driverInfo
= (MemoryMapFileInfo
*)
1977 bootxDriverDataObject
->getBytesNoCopy(0,
1978 sizeof(MemoryMapFileInfo
));
1979 IODTFreeLoaderInfo((char *)keyValue
,
1980 (void *)driverInfo
->paddr
,
1981 (int)driverInfo
->length
);
1986 if (bootxMemoryMap
) bootxMemoryMap
->release();
1987 if (propertyDict
) propertyDict
->release();
1988 if (keyIterator
) keyIterator
->release();