2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_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. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
23 #include <libkern/c++/OSContainers.h>
24 #include <IOKit/IODeviceTreeSupport.h>
25 #include <IOKit/IORegistryEntry.h>
26 #include <IOKit/IOCatalogue.h>
27 #include <libkern/c++/OSUnserialize.h>
28 #include <libkern/OSByteOrder.h>
29 #include <libsa/catalogue.h>
32 #include <machine/machine_routines.h>
33 #include <mach/host_info.h>
34 #include <mach/kmod.h>
35 #include <libsa/mkext.h>
36 #include <libsa/vers_rsrc.h>
37 #include <mach-o/loader.h>
40 #include <IOKit/IOLib.h>
42 #include <IOKit/assert.h>
45 extern void IODTFreeLoaderInfo( char *key
, void *infoAddr
, int infoSize
);
46 // extern kern_return_t host_info(host_t host,
47 // host_flavor_t flavor,
49 // mach_msg_type_number_t *count);
50 extern int grade_binary(cpu_type_t exectype
, cpu_subtype_t execsubtype
);
51 // Return the address of the named Mach-O segment from the currently
52 // executing 32 bit kernel, or NULL.
53 extern struct segment_command
*getsegbyname(char *seg_name
);
54 // Return the address of the named section from the named Mach-O segment
55 // from the currently executing 32 bit kernel, or NULL.
56 extern struct section
*getsectbyname(char *segname
, char *sectname
);
62 #define VTYELLOW "\033[33m"
63 #define VTRESET "\033[0m"
69 /*********************************************************************
70 *********************************************************************/
71 static OSDictionary
* gStartupExtensions
= 0;
72 static OSArray
* gBootLoaderObjects
= 0;
73 extern OSArray
* gIOPrelinkedModules
;
75 OSDictionary
* getStartupExtensions(void) {
76 if (gStartupExtensions
) {
77 return gStartupExtensions
;
79 gStartupExtensions
= OSDictionary::withCapacity(1);
80 assert (gStartupExtensions
);
82 return gStartupExtensions
;
85 /* This array holds objects that are needed to be held around during
86 * boot before kextd starts up. Currently it contains OSData objects
87 * copied from OF entries for mkext archives in device ROMs. Because
88 * the Device Tree support code dumps these after initially handing
89 * them to us, we have to be able to clean them up later.
91 OSArray
* getBootLoaderObjects(void) {
92 if (gBootLoaderObjects
) {
93 return gBootLoaderObjects
;
95 gBootLoaderObjects
= OSArray::withCapacity(1);
96 assert (gBootLoaderObjects
);
98 return gBootLoaderObjects
;
101 /*********************************************************************
102 * This function checks that a driver dict has all the required
103 * entries and does a little bit of value checking too.
105 * index is nonnegative if the index of an entry from an mkext
107 *********************************************************************/
108 bool validateExtensionDict(OSDictionary
* extension
, int index
) {
111 bool not_a_dict
= false;
112 bool id_missing
= false;
113 bool is_kernel_resource
= false;
114 bool has_executable
= false;
115 OSString
* bundleIdentifier
= NULL
; // do not release
116 OSObject
* rawValue
= NULL
; // do not release
117 OSString
* stringValue
= NULL
; // do not release
118 OSBoolean
* booleanValue
= NULL
; // do not release
119 OSDictionary
* personalities
= NULL
; // do not release
120 OSDictionary
* libraries
= NULL
; // do not release
121 OSCollectionIterator
* keyIterator
= NULL
; // must release
122 OSString
* key
= NULL
; // do not release
124 VERS_version compatible_vers
;
126 // Info dict is a dictionary
127 if (!OSDynamicCast(OSDictionary
, extension
)) {
133 // CFBundleIdentifier is a string - REQUIRED
134 bundleIdentifier
= OSDynamicCast(OSString
,
135 extension
->getObject("CFBundleIdentifier"));
136 if (!bundleIdentifier
) {
142 // Length of CFBundleIdentifier is not >= KMOD_MAX_NAME
143 if (bundleIdentifier
->getLength() >= KMOD_MAX_NAME
) {
148 // CFBundlePackageType is "KEXT" - REQUIRED
149 stringValue
= OSDynamicCast(OSString
,
150 extension
->getObject("CFBundlePackageType"));
155 if (!stringValue
->isEqualTo("KEXT")) {
160 // CFBundleVersion is a string - REQUIRED
161 stringValue
= OSDynamicCast(OSString
,
162 extension
->getObject("CFBundleVersion"));
167 // CFBundleVersion is of valid form
168 vers
= VERS_parse_string(stringValue
->getCStringNoCopy());
174 // OSBundleCompatibleVersion is a string - OPTIONAL
175 rawValue
= extension
->getObject("OSBundleCompatibleVersion");
177 stringValue
= OSDynamicCast(OSString
, rawValue
);
183 // OSBundleCompatibleVersion is of valid form
184 compatible_vers
= VERS_parse_string(stringValue
->getCStringNoCopy());
185 if (compatible_vers
< 0) {
190 // OSBundleCompatibleVersion <= CFBundleVersion
191 if (compatible_vers
> vers
) {
197 // CFBundleExecutable is a string - OPTIONAL
198 rawValue
= extension
->getObject("CFBundleExecutable");
200 stringValue
= OSDynamicCast(OSString
, rawValue
);
201 if (!stringValue
|| stringValue
->getLength() == 0) {
205 has_executable
= true;
208 // OSKernelResource is a boolean value - OPTIONAL
209 rawValue
= extension
->getObject("OSKernelResource");
211 booleanValue
= OSDynamicCast(OSBoolean
, rawValue
);
216 is_kernel_resource
= booleanValue
->isTrue();
219 // IOKitPersonalities is a dictionary - OPTIONAL
220 rawValue
= extension
->getObject("IOKitPersonalities");
222 personalities
= OSDynamicCast(OSDictionary
, rawValue
);
223 if (!personalities
) {
228 keyIterator
= OSCollectionIterator::withCollection(personalities
);
230 IOLog("Error: Failed to allocate iterator for personalities.\n");
236 while ((key
= OSDynamicCast(OSString
, keyIterator
->getNextObject()))) {
237 OSDictionary
* personality
= NULL
; // do not release
239 // Each personality is a dictionary
240 personality
= OSDynamicCast(OSDictionary
,
241 personalities
->getObject(key
));
247 // IOClass exists as a string - REQUIRED
248 if (!OSDynamicCast(OSString
, personality
->getObject("IOClass"))) {
253 // IOProviderClass exists as a string - REQUIRED
254 if (!OSDynamicCast(OSString
,
255 personality
->getObject("IOProviderClass"))) {
261 // CFBundleIdentifier is a string - OPTIONAL - INSERT IF ABSENT!
262 rawValue
= personality
->getObject("CFBundleIdentifier");
264 personality
->setObject("CFBundleIdentifier", bundleIdentifier
);
266 OSString
* personalityID
= NULL
; // do not release
267 personalityID
= OSDynamicCast(OSString
, rawValue
);
268 if (!personalityID
) {
272 // Length of CFBundleIdentifier is not >= KMOD_MAX_NAME
273 if (personalityID
->getLength() >= KMOD_MAX_NAME
) {
280 // IOKitDebug is a number - OPTIONAL
281 rawValue
= personality
->getObject("IOKitDebug");
282 if (rawValue
&& !OSDynamicCast(OSNumber
, rawValue
)) {
288 keyIterator
->release();
293 // OSBundleLibraries is a dictionary - REQUIRED if
294 // not kernel resource & has executable
296 rawValue
= extension
->getObject("OSBundleLibraries");
297 if (!rawValue
&& !is_kernel_resource
&& has_executable
) {
303 libraries
= OSDynamicCast(OSDictionary
, rawValue
);
309 keyIterator
= OSCollectionIterator::withCollection(libraries
);
311 IOLog("Error: Failed to allocate iterator for libraries.\n");
317 while ((key
= OSDynamicCast(OSString
,
318 keyIterator
->getNextObject()))) {
320 OSString
* libraryVersion
= NULL
; // do not release
322 // Each key's length is not >= KMOD_MAX_NAME
323 if (key
->getLength() >= KMOD_MAX_NAME
) {
328 libraryVersion
= OSDynamicCast(OSString
,
329 libraries
->getObject(key
));
330 if (!libraryVersion
) {
335 // Each value is a valid version string
336 vers
= VERS_parse_string(libraryVersion
->getCStringNoCopy());
343 keyIterator
->release();
347 // OSBundleRequired is a legal value - *not* required at boot time
348 // so we can do install CDs and the like with mkext files containing
349 // all normally-used drivers.
350 rawValue
= extension
->getObject("OSBundleRequired");
352 stringValue
= OSDynamicCast(OSString
, rawValue
);
357 if (!stringValue
->isEqualTo("Root") &&
358 !stringValue
->isEqualTo("Local-Root") &&
359 !stringValue
->isEqualTo("Network-Root") &&
360 !stringValue
->isEqualTo("Safe Boot") &&
361 !stringValue
->isEqualTo("Console")) {
371 if (keyIterator
) keyIterator
->release();
376 IOLog(VTYELLOW
"mkext entry %d:." VTRESET
, index
);
378 IOLog(VTYELLOW
"kernel extension" VTRESET
);
380 IOLog(VTYELLOW
"info dictionary isn't a dictionary\n"
382 } else if (id_missing
) {
384 IOLog(VTYELLOW
"mkext entry %d:." VTRESET
, index
);
386 IOLog(VTYELLOW
"kernel extension" VTRESET
);
388 IOLog(VTYELLOW
"\"CFBundleIdentifier\" property is "
389 "missing or not a string\n"
392 IOLog(VTYELLOW
"kernel extension \"%s\": info dictionary is invalid\n"
393 VTRESET
, bundleIdentifier
->getCStringNoCopy());
402 /*********************************************************************
403 *********************************************************************/
404 OSDictionary
* compareExtensionVersions(
405 OSDictionary
* incumbent
,
406 OSDictionary
* candidate
) {
408 OSDictionary
* winner
= NULL
;
410 OSDictionary
* incumbentPlist
= NULL
;
411 OSDictionary
* candidatePlist
= NULL
;
412 OSString
* incumbentName
= NULL
;
413 OSString
* candidateName
= NULL
;
414 OSString
* incumbentVersionString
= NULL
;
415 OSString
* candidateVersionString
= NULL
;
416 VERS_version incumbent_vers
= 0;
417 VERS_version candidate_vers
= 0;
419 incumbentPlist
= OSDynamicCast(OSDictionary
,
420 incumbent
->getObject("plist"));
421 candidatePlist
= OSDynamicCast(OSDictionary
,
422 candidate
->getObject("plist"));
424 if (!incumbentPlist
|| !candidatePlist
) {
425 IOLog("compareExtensionVersions() called with invalid "
426 "extension dictionaries.\n");
432 incumbentName
= OSDynamicCast(OSString
,
433 incumbentPlist
->getObject("CFBundleIdentifier"));
434 candidateName
= OSDynamicCast(OSString
,
435 candidatePlist
->getObject("CFBundleIdentifier"));
436 incumbentVersionString
= OSDynamicCast(OSString
,
437 incumbentPlist
->getObject("CFBundleVersion"));
438 candidateVersionString
= OSDynamicCast(OSString
,
439 candidatePlist
->getObject("CFBundleVersion"));
441 if (!incumbentName
|| !candidateName
||
442 !incumbentVersionString
|| !candidateVersionString
) {
444 IOLog("compareExtensionVersions() called with invalid "
445 "extension dictionaries.\n");
451 if (strcmp(incumbentName
->getCStringNoCopy(),
452 candidateName
->getCStringNoCopy())) {
454 IOLog("compareExtensionVersions() called with different "
455 "extension names (%s and %s).\n",
456 incumbentName
->getCStringNoCopy(),
457 candidateName
->getCStringNoCopy());
463 incumbent_vers
= VERS_parse_string(incumbentVersionString
->getCStringNoCopy());
464 if (incumbent_vers
< 0) {
466 IOLog(VTYELLOW
"Error parsing version string for extension %s (%s)\n"
468 incumbentName
->getCStringNoCopy(),
469 incumbentVersionString
->getCStringNoCopy());
475 candidate_vers
= VERS_parse_string(candidateVersionString
->getCStringNoCopy());
476 if (candidate_vers
< 0) {
478 IOLog(VTYELLOW
"Error parsing version string for extension %s (%s)\n"
480 candidateName
->getCStringNoCopy(),
481 candidateVersionString
->getCStringNoCopy());
487 if (candidate_vers
> incumbent_vers
) {
488 IOLog(VTYELLOW
"Replacing extension \"%s\" with newer version "
489 "(%s -> %s).\n" VTRESET
,
490 incumbentName
->getCStringNoCopy(),
491 incumbentVersionString
->getCStringNoCopy(),
492 candidateVersionString
->getCStringNoCopy());
497 IOLog(VTYELLOW
"Skipping duplicate extension \"%s\" with older/same "
498 " version (%s -> %s).\n" VTRESET
,
499 candidateName
->getCStringNoCopy(),
500 candidateVersionString
->getCStringNoCopy(),
501 incumbentVersionString
->getCStringNoCopy());
509 // no cleanup, how nice
514 /*********************************************************************
515 * This function merges entries in the mergeFrom dictionary into the
516 * mergeInto dictionary. If it returns false, the two dictionaries are
517 * not altered. If it returns true, then mergeInto may have new
518 * entries; any keys that were already present in mergeInto are
519 * removed from mergeFrom, so that the caller can see what was
521 *********************************************************************/
522 bool mergeExtensionDictionaries(OSDictionary
* mergeInto
,
523 OSDictionary
* mergeFrom
) {
526 OSDictionary
* mergeIntoCopy
= NULL
; // must release
527 OSDictionary
* mergeFromCopy
= NULL
; // must release
528 OSCollectionIterator
* keyIterator
= NULL
; // must release
529 OSString
* key
; // don't release
531 /* Add 1 to count to guarantee copy can grow (grr).
533 mergeIntoCopy
= OSDictionary::withDictionary(mergeInto
,
534 mergeInto
->getCount() + 1);
535 if (!mergeIntoCopy
) {
536 IOLog("Error: Failed to copy 'into' extensions dictionary "
543 /* Add 1 to count to guarantee copy can grow (grr).
545 mergeFromCopy
= OSDictionary::withDictionary(mergeFrom
,
546 mergeFrom
->getCount() + 1);
547 if (!mergeFromCopy
) {
548 IOLog("Error: Failed to copy 'from' extensions dictionary "
555 keyIterator
= OSCollectionIterator::withCollection(mergeFrom
);
557 IOLog("Error: Failed to allocate iterator for extensions.\n");
565 * Loop through "from" dictionary, checking if the identifier already
566 * exists in the "into" dictionary and checking versions if it does.
568 while ((key
= OSDynamicCast(OSString
, keyIterator
->getNextObject()))) {
569 OSDictionary
* incumbentExt
= OSDynamicCast(OSDictionary
,
570 mergeIntoCopy
->getObject(key
));
571 OSDictionary
* candidateExt
= OSDynamicCast(OSDictionary
,
572 mergeFrom
->getObject(key
));
575 if (!mergeIntoCopy
->setObject(key
, candidateExt
)) {
577 /* This is a fatal error, so bail.
579 IOLog("mergeExtensionDictionaries(): Failed to add "
581 key
->getCStringNoCopy());
587 OSDictionary
* mostRecentExtension
=
588 compareExtensionVersions(incumbentExt
, candidateExt
);
590 if (mostRecentExtension
== incumbentExt
) {
591 mergeFromCopy
->removeObject(key
);
592 } else if (mostRecentExtension
== candidateExt
) {
594 if (!mergeIntoCopy
->setObject(key
, candidateExt
)) {
596 /* This is a fatal error, so bail.
598 IOLog("mergeExtensionDictionaries(): Failed to add "
600 key
->getCStringNoCopy());
605 } else /* should be NULL */ {
607 /* This is a nonfatal error, so continue doing others.
609 IOLog("mergeExtensionDictionaries(): Error comparing "
610 "versions of duplicate extensions %s.\n",
611 key
->getCStringNoCopy());
620 /* If successful, replace the contents of the original
621 * dictionaries with those of the modified copies.
624 mergeInto
->flushCollection();
625 mergeInto
->merge(mergeIntoCopy
);
626 mergeFrom
->flushCollection();
627 mergeFrom
->merge(mergeFromCopy
);
630 if (mergeIntoCopy
) mergeIntoCopy
->release();
631 if (mergeFromCopy
) mergeFromCopy
->release();
632 if (keyIterator
) keyIterator
->release();
639 * These bits are used to parse data made available by bootx.
641 #define BOOTX_KEXT_PREFIX "Driver-"
642 #define BOOTX_MULTIKEXT_PREFIX "DriversPackage-"
644 typedef struct MemoryMapFileInfo
{
649 typedef struct BootxDriverInfo
{
656 typedef struct MkextEntryInfo
{
657 vm_address_t base_address
;
658 mkext_file
* fileinfo
;
662 /*********************************************************************
663 * This private function reads the data for a single extension from
664 * the bootx memory-map's propery dict, returning a dictionary with
665 * keys "plist" for the extension's Info.plist as a parsed OSDictionary
666 * and "code" for the extension's executable code as an OSData.
667 *********************************************************************/
668 OSDictionary
* readExtension(OSDictionary
* propertyDict
,
669 const char * memory_map_name
) {
672 OSData
* bootxDriverDataObject
= NULL
;
673 OSDictionary
* driverPlist
= NULL
;
674 OSString
* driverName
= NULL
;
675 OSData
* driverCode
= NULL
;
676 OSString
* errorString
= NULL
;
677 OSDictionary
* driverDict
= NULL
;
679 MemoryMapFileInfo
* driverInfo
= 0;
680 BootxDriverInfo
* dataBuffer
;
682 kmod_info_t
* loaded_kmod
= NULL
;
684 bootxDriverDataObject
= OSDynamicCast(OSData
,
685 propertyDict
->getObject(memory_map_name
));
686 // don't release bootxDriverDataObject
688 if (!bootxDriverDataObject
) {
689 IOLog("Error: No driver data object "
690 "for device tree entry \"%s\".\n",
697 driverDict
= OSDictionary::withCapacity(2);
699 IOLog("Error: Couldn't allocate dictionary "
700 "for device tree entry \"%s\".\n", memory_map_name
);
706 driverInfo
= (MemoryMapFileInfo
*)
707 bootxDriverDataObject
->getBytesNoCopy(0,
708 sizeof(MemoryMapFileInfo
));
709 #if defined (__ppc__)
710 dataBuffer
= (BootxDriverInfo
*)ml_static_ptovirt(
712 #elif defined (__i386__)
713 dataBuffer
= (BootxDriverInfo
*)driverInfo
->paddr
;
714 dataBuffer
->plistAddr
= ml_static_ptovirt(dataBuffer
->plistAddr
);
715 if (dataBuffer
->moduleAddr
)
716 dataBuffer
->moduleAddr
= ml_static_ptovirt(dataBuffer
->moduleAddr
);
718 #error unsupported architecture
721 IOLog("Error: No data buffer "
722 "for device tree entry \"%s\".\n", memory_map_name
);
728 driverPlist
= OSDynamicCast(OSDictionary
,
729 OSUnserializeXML(dataBuffer
->plistAddr
, &errorString
));
731 IOLog("Error: Couldn't read XML property list "
732 "for device tree entry \"%s\".\n", memory_map_name
);
735 IOLog("XML parse error: %s.\n",
736 errorString
->getCStringNoCopy());
744 driverName
= OSDynamicCast(OSString
,
745 driverPlist
->getObject("CFBundleIdentifier")); // do not release
747 IOLog("Error: Device tree entry \"%s\" has "
748 "no \"CFBundleIdentifier\" property.\n", memory_map_name
);
754 /* Check if kmod is already loaded and is a real loadable one (has
757 loaded_kmod
= kmod_lookupbyname_locked(driverName
->getCStringNoCopy());
758 if (loaded_kmod
&& loaded_kmod
->address
) {
759 IOLog("Skipping new extension \"%s\"; an extension named "
760 "\"%s\" is already loaded.\n",
761 driverName
->getCStringNoCopy(),
768 if (!validateExtensionDict(driverPlist
, -1)) {
769 // validateExtensionsDict() logs an error
774 driverDict
->setObject("plist", driverPlist
);
776 /* It's perfectly okay for a KEXT to have no executable.
777 * Check that moduleAddr is nonzero before attempting to
780 * NOTE: The driverCode object is created "no-copy", so
781 * it doesn't own that memory. The memory must be freed
782 * separately from the OSData object (see
783 * clearStartupExtensionsAndLoaderInfo() at the end of this file).
785 if (dataBuffer
->moduleAddr
&& dataBuffer
->moduleLength
) {
786 driverCode
= OSData::withBytesNoCopy(dataBuffer
->moduleAddr
,
787 dataBuffer
->moduleLength
);
789 IOLog("Error: Couldn't allocate data object "
790 "to hold code for device tree entry \"%s\".\n",
798 driverDict
->setObject("code", driverCode
);
805 kfree((unsigned int)loaded_kmod
, sizeof(kmod_info_t
));
808 // do not release bootxDriverDataObject
809 // do not release driverName
812 driverPlist
->release();
815 errorString
->release();
818 driverCode
->release();
822 driverDict
->release();
830 /*********************************************************************
831 * Used to uncompress a single file entry in an mkext archive.
833 * The OSData returned does not own its memory! You must deallocate
834 * that memory using kmem_free() before releasing the OSData().
835 *********************************************************************/
836 static bool uncompressFile(u_int8_t
*base_address
, mkext_file
* fileinfo
,
837 /* out */ OSData
** file
) {
840 kern_return_t kern_result
;
841 u_int8_t
* uncompressed_file
= 0; // kmem_free() on error
842 OSData
* uncompressedFile
= 0; // returned
843 size_t uncompressed_size
= 0;
845 size_t offset
= OSSwapBigToHostInt32(fileinfo
->offset
);
846 size_t compsize
= OSSwapBigToHostInt32(fileinfo
->compsize
);
847 size_t realsize
= OSSwapBigToHostInt32(fileinfo
->realsize
);
848 time_t modifiedsecs
= OSSwapBigToHostInt32(fileinfo
->modifiedsecs
);
852 /* If these four fields are zero there's no file, but that isn't
855 if (offset
== 0 && compsize
== 0 &&
856 realsize
== 0 && modifiedsecs
== 0) {
860 // Add 1 for '\0' to terminate XML string!
861 kern_result
= kmem_alloc(kernel_map
, (vm_offset_t
*)&uncompressed_file
,
863 if (kern_result
!= KERN_SUCCESS
) {
864 IOLog("Error: Couldn't allocate data buffer "
865 "to uncompress file.\n");
871 uncompressedFile
= OSData::withBytesNoCopy(uncompressed_file
,
873 if (!uncompressedFile
) {
874 IOLog("Error: Couldn't allocate data object "
875 "to uncompress file.\n");
882 uncompressed_size
= decompress_lzss(uncompressed_file
,
883 base_address
+ offset
,
885 if (uncompressed_size
!= realsize
) {
886 IOLog("Error: Uncompressed file is not the length "
892 uncompressed_file
[uncompressed_size
] = '\0';
894 bcopy(base_address
+ offset
, uncompressed_file
,
896 uncompressed_file
[realsize
] = '\0';
899 *file
= uncompressedFile
;
903 if (uncompressed_file
) {
904 kmem_free(kernel_map
, (vm_address_t
)uncompressed_file
,
907 if (uncompressedFile
) {
908 uncompressedFile
->release();
915 bool uncompressModule(OSData
*compData
, /* out */ OSData
** file
) {
917 MkextEntryInfo
*info
= (MkextEntryInfo
*) compData
->getBytesNoCopy();
919 return uncompressFile((u_int8_t
*) info
->base_address
,
920 info
->fileinfo
, file
);
924 /*********************************************************************
925 * Does the work of pulling extensions out of an mkext archive located
927 *********************************************************************/
928 bool extractExtensionsFromArchive(MemoryMapFileInfo
* mkext_file_info
,
929 OSDictionary
* extensions
) {
933 u_int8_t
* crc_address
= 0;
935 mkext_header
* mkext_data
= 0; // don't free
936 mkext_kext
* onekext_data
= 0; // don't free
937 mkext_file
* plist_file
= 0; // don't free
938 mkext_file
* module_file
= 0; // don't free
939 kmod_info_t
* loaded_kmod
= 0; // must free
941 OSData
* driverPlistDataObject
= 0; // must release
942 OSDictionary
* driverPlist
= 0; // must release
943 OSData
* driverCode
= 0; // must release
944 OSDictionary
* driverDict
= 0; // must release
945 OSString
* moduleName
= 0; // don't release
946 OSString
* errorString
= NULL
; // must release
948 OSData
* moduleInfo
= 0; // must release
949 MkextEntryInfo module_info
;
952 #if defined (__ppc__)
953 mkext_data
= (mkext_header
*)mkext_file_info
->paddr
;
954 #elif defined (__i386__)
955 mkext_data
= (mkext_header
*)ml_static_ptovirt(mkext_file_info
->paddr
);
957 #error unsupported architecture
959 if (OSSwapBigToHostInt32(mkext_data
->magic
) != MKEXT_MAGIC
||
960 OSSwapBigToHostInt32(mkext_data
->signature
) != MKEXT_SIGN
) {
961 IOLog("Error: Extension archive has invalid magic or signature.\n");
967 if (OSSwapBigToHostInt32(mkext_data
->length
) != mkext_file_info
->length
) {
968 IOLog("Error: Mismatch between extension archive & "
969 "recorded length.\n");
975 crc_address
= (u_int8_t
*)&mkext_data
->version
;
976 checksum
= adler32(crc_address
,
977 (unsigned int)mkext_data
+
978 OSSwapBigToHostInt32(mkext_data
->length
) - (unsigned int)crc_address
);
980 if (OSSwapBigToHostInt32(mkext_data
->adler32
) != checksum
) {
981 IOLog("Error: Extension archive has a bad checksum.\n");
987 /* If the MKEXT archive isn't fat, check that the CPU type & subtype
988 * match that of the running kernel.
990 if (OSSwapBigToHostInt32(mkext_data
->cputype
) != (UInt32
)CPU_TYPE_ANY
) {
991 kern_return_t kresult
= KERN_FAILURE
;
992 host_basic_info_data_t hostinfo
;
993 host_info_t hostinfo_ptr
= (host_info_t
)&hostinfo
;
994 mach_msg_type_number_t count
= sizeof(hostinfo
)/sizeof(integer_t
);
996 kresult
= host_info((host_t
)1, HOST_BASIC_INFO
,
997 hostinfo_ptr
, &count
);
998 if (kresult
!= KERN_SUCCESS
) {
999 IOLog("Error: Couldn't get current host info.\n");
1004 if ((UInt32
)hostinfo
.cpu_type
!=
1005 OSSwapBigToHostInt32(mkext_data
->cputype
)) {
1007 IOLog("Error: Extension archive doesn't contain software "
1008 "for this computer's CPU type.\n");
1013 if (!grade_binary(OSSwapBigToHostInt32(mkext_data
->cputype
),
1014 OSSwapBigToHostInt32(mkext_data
->cpusubtype
))) {
1015 IOLog("Error: Extension archive doesn't contain software "
1016 "for this computer's CPU subtype.\n");
1023 for (unsigned int i
= 0;
1024 i
< OSSwapBigToHostInt32(mkext_data
->numkexts
);
1028 kfree((unsigned int)loaded_kmod
, sizeof(kmod_info_t
));
1032 if (driverPlistDataObject
) {
1033 kmem_free(kernel_map
,
1034 (unsigned int)driverPlistDataObject
->getBytesNoCopy(),
1035 driverPlistDataObject
->getLength());
1037 driverPlistDataObject
->release();
1038 driverPlistDataObject
= NULL
;
1041 driverPlist
->release();
1045 driverCode
->release();
1049 driverDict
->release();
1053 errorString
->release();
1057 onekext_data
= &mkext_data
->kext
[i
];
1058 plist_file
= &onekext_data
->plist
;
1059 module_file
= &onekext_data
->module;
1061 if (!uncompressFile((u_int8_t
*)mkext_data
, plist_file
,
1062 &driverPlistDataObject
)) {
1064 IOLog("Error: couldn't uncompress plist file "
1065 "from multikext archive entry %d.\n", i
);
1070 if (!driverPlistDataObject
) {
1071 IOLog("Error: No property list present "
1072 "for multikext archive entry %d.\n", i
);
1076 driverPlist
= OSDynamicCast(OSDictionary
,
1078 (char *)driverPlistDataObject
->getBytesNoCopy(),
1081 IOLog("Error: Couldn't read XML property list "
1082 "for multikext archive entry %d.\n", i
);
1085 IOLog("XML parse error: %s.\n",
1086 errorString
->getCStringNoCopy());
1092 if (!validateExtensionDict(driverPlist
, i
)) {
1093 // validateExtensionsDict() logs an error
1099 /* Get the extension's module name. This is used to record
1102 moduleName
= OSDynamicCast(OSString
,
1103 driverPlist
->getObject("CFBundleIdentifier")); // do not release
1105 IOLog("Error: Multikext archive entry %d has "
1106 "no \"CFBundleIdentifier\" property.\n", i
);
1108 continue; // assume a kext config error & continue
1111 /* Check if kmod is already loaded and is a real loadable one (has
1114 loaded_kmod
= kmod_lookupbyname_locked(moduleName
->getCStringNoCopy());
1115 if (loaded_kmod
&& loaded_kmod
->address
) {
1116 IOLog("Skipping new extension \"%s\"; an extension named "
1117 "\"%s\" is already loaded.\n",
1118 moduleName
->getCStringNoCopy(),
1124 driverDict
= OSDictionary::withCapacity(2);
1126 IOLog("Error: Couldn't allocate dictionary "
1127 "for multikext archive entry %d.\n", i
);
1133 driverDict
->setObject("plist", driverPlist
);
1136 * Prepare an entry to hold the mkext entry info for the
1137 * compressed binary module, if there is one. If all four fields
1138 * of the module entry are zero, there isn't one.
1140 if (!(loaded_kmod
&& loaded_kmod
->address
) && (OSSwapBigToHostInt32(module_file
->offset
) ||
1141 OSSwapBigToHostInt32(module_file
->compsize
) ||
1142 OSSwapBigToHostInt32(module_file
->realsize
) ||
1143 OSSwapBigToHostInt32(module_file
->modifiedsecs
))) {
1145 moduleInfo
= OSData::withCapacity(sizeof(MkextEntryInfo
));
1147 IOLog("Error: Couldn't allocate data object "
1148 "for multikext archive entry %d.\n", i
);
1154 module_info
.base_address
= (vm_address_t
)mkext_data
;
1155 module_info
.fileinfo
= module_file
;
1157 if (!moduleInfo
->appendBytes(&module_info
, sizeof(module_info
))) {
1158 IOLog("Error: Couldn't record info "
1159 "for multikext archive entry %d.\n", i
);
1165 driverDict
->setObject("compressedCode", moduleInfo
);
1168 OSDictionary
* incumbentExt
= OSDynamicCast(OSDictionary
,
1169 extensions
->getObject(moduleName
));
1171 if (!incumbentExt
) {
1172 extensions
->setObject(moduleName
, driverDict
);
1174 OSDictionary
* mostRecentExtension
=
1175 compareExtensionVersions(incumbentExt
, driverDict
);
1177 if (mostRecentExtension
== incumbentExt
) {
1178 /* Do nothing, we've got the most recent. */
1179 } else if (mostRecentExtension
== driverDict
) {
1180 if (!extensions
->setObject(moduleName
, driverDict
)) {
1182 /* This is a fatal error, so bail.
1184 IOLog("extractExtensionsFromArchive(): Failed to add "
1186 moduleName
->getCStringNoCopy());
1191 } else /* should be NULL */ {
1193 /* This is a nonfatal error, so continue.
1195 IOLog("extractExtensionsFromArchive(): Error comparing "
1196 "versions of duplicate extensions %s.\n",
1197 moduleName
->getCStringNoCopy());
1206 if (loaded_kmod
) kfree((unsigned int)loaded_kmod
, sizeof(kmod_info_t
));
1207 if (driverPlistDataObject
) {
1208 kmem_free(kernel_map
,
1209 (unsigned int)driverPlistDataObject
->getBytesNoCopy(),
1210 driverPlistDataObject
->getLength());
1211 driverPlistDataObject
->release();
1213 if (driverPlist
) driverPlist
->release();
1214 if (driverCode
) driverCode
->release();
1215 if (moduleInfo
) moduleInfo
->release();
1216 if (driverDict
) driverDict
->release();
1217 if (errorString
) errorString
->release();
1222 /*********************************************************************
1224 *********************************************************************/
1225 bool readExtensions(OSDictionary
* propertyDict
,
1226 const char * memory_map_name
,
1227 OSDictionary
* extensions
) {
1230 OSData
* mkextDataObject
= 0; // don't release
1231 MemoryMapFileInfo
* mkext_file_info
= 0; // don't free
1233 mkextDataObject
= OSDynamicCast(OSData
,
1234 propertyDict
->getObject(memory_map_name
));
1235 // don't release mkextDataObject
1237 if (!mkextDataObject
) {
1238 IOLog("Error: No mkext data object "
1239 "for device tree entry \"%s\".\n",
1246 mkext_file_info
= (MemoryMapFileInfo
*)mkextDataObject
->getBytesNoCopy();
1247 if (!mkext_file_info
) {
1252 result
= extractExtensionsFromArchive(mkext_file_info
, extensions
);
1256 if (!result
&& extensions
) {
1257 extensions
->flushCollection();
1264 /*********************************************************************
1265 * Adds the personalities for an extensions dictionary to the global
1267 *********************************************************************/
1268 bool addPersonalities(OSDictionary
* extensions
) {
1270 OSCollectionIterator
* keyIterator
= NULL
; // must release
1271 OSString
* key
; // don't release
1272 OSDictionary
* driverDict
= NULL
; // don't release
1273 OSDictionary
* driverPlist
= NULL
; // don't release
1274 OSDictionary
* thisDriverPersonalities
= NULL
; // don't release
1275 OSArray
* allDriverPersonalities
= NULL
; // must release
1277 allDriverPersonalities
= OSArray::withCapacity(1);
1278 if (!allDriverPersonalities
) {
1279 IOLog("Error: Couldn't allocate personality dictionary.\n");
1285 /* Record all personalities found so that they can be
1286 * added to the catalogue.
1287 * Note: Not all extensions have personalities.
1290 keyIterator
= OSCollectionIterator::withCollection(extensions
);
1292 IOLog("Error: Couldn't allocate iterator to record personalities.\n");
1298 while ( ( key
= OSDynamicCast(OSString
,
1299 keyIterator
->getNextObject() ))) {
1301 driverDict
= OSDynamicCast(OSDictionary
,
1302 extensions
->getObject(key
));
1303 driverPlist
= OSDynamicCast(OSDictionary
,
1304 driverDict
->getObject("plist"));
1305 thisDriverPersonalities
= OSDynamicCast(OSDictionary
,
1306 driverPlist
->getObject("IOKitPersonalities"));
1308 if (thisDriverPersonalities
) {
1309 OSCollectionIterator
* pIterator
;
1310 OSString
* locakKey
;
1311 pIterator
= OSCollectionIterator::withCollection(
1312 thisDriverPersonalities
);
1314 IOLog("Error: Couldn't allocate iterator "
1315 "to record extension personalities.\n");
1319 while ( (locakKey
= OSDynamicCast(OSString
,
1320 pIterator
->getNextObject())) ) {
1322 OSDictionary
* personality
= OSDynamicCast(
1324 thisDriverPersonalities
->getObject(locakKey
));
1326 allDriverPersonalities
->setObject(personality
);
1329 pIterator
->release();
1331 } /* extract personalities */
1334 /* Add all personalities found to the IOCatalogue,
1335 * but don't start matching.
1337 gIOCatalogue
->addDrivers(allDriverPersonalities
, false);
1341 if (allDriverPersonalities
) allDriverPersonalities
->release();
1342 if (keyIterator
) keyIterator
->release();
1348 /*********************************************************************
1349 * Called from IOCatalogue to add extensions from an mkext archive.
1350 * This function makes a copy of the mkext object passed in because
1351 * the device tree support code dumps it after calling us (indirectly
1352 * through the IOCatalogue).
1353 *********************************************************************/
1354 bool addExtensionsFromArchive(OSData
* mkextDataObject
) {
1357 OSDictionary
* startupExtensions
= NULL
; // don't release
1358 OSArray
* bootLoaderObjects
= NULL
; // don't release
1359 OSDictionary
* extensions
= NULL
; // must release
1360 MemoryMapFileInfo mkext_file_info
;
1361 OSCollectionIterator
* keyIterator
= NULL
; // must release
1362 OSString
* key
= NULL
; // don't release
1364 startupExtensions
= getStartupExtensions();
1365 if (!startupExtensions
) {
1366 IOLog("Can't record extension archive; there is no"
1367 " extensions dictionary.\n");
1373 bootLoaderObjects
= getBootLoaderObjects();
1374 if (! bootLoaderObjects
) {
1375 IOLog("Error: Couldn't allocate array to hold temporary objects.\n");
1381 extensions
= OSDictionary::withCapacity(2);
1383 IOLog("Error: Couldn't allocate dictionary to unpack "
1384 "extension archive.\n");
1390 mkext_file_info
.paddr
= (UInt32
)mkextDataObject
->getBytesNoCopy();
1391 mkext_file_info
.length
= mkextDataObject
->getLength();
1393 /* Save the local mkext data object so that we can deallocate it later.
1395 bootLoaderObjects
->setObject(mkextDataObject
);
1397 result
= extractExtensionsFromArchive(&mkext_file_info
, extensions
);
1399 IOLog("Error: Failed to extract extensions from archive.\n");
1405 result
= mergeExtensionDictionaries(startupExtensions
, extensions
);
1407 IOLog("Error: Failed to merge new extensions into existing set.\n");
1412 result
= addPersonalities(extensions
);
1414 IOLog("Error: Failed to add personalities for extensions extracted "
1424 IOLog("Error: Failed to record extensions from archive.\n");
1427 keyIterator
= OSCollectionIterator::withCollection(
1431 while ( (key
= OSDynamicCast(OSString
,
1432 keyIterator
->getNextObject())) ) {
1434 IOLog("Added extension \"%s\" from archive.\n",
1435 key
->getCStringNoCopy());
1438 keyIterator
->release();
1442 if (extensions
) extensions
->release();
1448 /*********************************************************************
1449 * This function builds dictionaries for the startup extensions
1450 * put into memory by bootx, recording each in the startup extensions
1451 * dictionary. The dictionary format is this:
1454 * "plist" = (the extension's Info.plist as an OSDictionary)
1455 * "code" = (an OSData containing the executable file)
1458 * This function returns true if any extensions were found and
1459 * recorded successfully, or if there are no start extensions,
1460 * and false if an unrecoverable error occurred. An error reading
1461 * a single extension is not considered fatal, and this function
1462 * will simply skip the problematic extension to try the next one.
1463 *********************************************************************/
1465 bool recordStartupExtensions(void) {
1467 OSDictionary
* startupExtensions
= NULL
; // must release
1468 OSDictionary
* existingExtensions
= NULL
; // don't release
1469 OSDictionary
* mkextExtensions
= NULL
; // must release
1470 IORegistryEntry
* bootxMemoryMap
= NULL
; // must release
1471 OSDictionary
* propertyDict
= NULL
; // must release
1472 OSCollectionIterator
* keyIterator
= NULL
; // must release
1473 OSString
* key
= NULL
; // don't release
1475 OSDictionary
* newDriverDict
= NULL
; // must release
1476 OSDictionary
* driverPlist
= NULL
; // don't release
1478 struct section
* infosect
;
1479 struct section
* symsect
;
1480 unsigned int prelinkedCount
= 0;
1482 existingExtensions
= getStartupExtensions();
1483 if (!existingExtensions
) {
1484 IOLog("Error: There is no dictionary for startup extensions.\n");
1490 startupExtensions
= OSDictionary::withCapacity(1);
1491 if (!startupExtensions
) {
1492 IOLog("Error: Couldn't allocate dictionary "
1493 "to record startup extensions.\n");
1500 // add any prelinked modules as startup extensions
1502 infosect
= getsectbyname("__PRELINK", "__info");
1503 symsect
= getsectbyname("__PRELINK", "__symtab");
1504 if (infosect
&& infosect
->addr
&& infosect
->size
1505 && symsect
&& symsect
->addr
&& symsect
->size
) do
1507 gIOPrelinkedModules
= OSDynamicCast(OSArray
,
1508 OSUnserializeXML((const char *) infosect
->addr
, NULL
));
1510 if (!gIOPrelinkedModules
)
1512 for( unsigned int idx
= 0;
1513 (propertyDict
= OSDynamicCast(OSDictionary
, gIOPrelinkedModules
->getObject(idx
)));
1516 enum { kPrelinkReservedCount
= 4 };
1518 /* Get the extension's module name. This is used to record
1519 * the extension. Do *not* release the moduleName.
1521 OSString
* moduleName
= OSDynamicCast(OSString
,
1522 propertyDict
->getObject("CFBundleIdentifier"));
1524 IOLog("Error: Prelinked module entry has "
1525 "no \"CFBundleIdentifier\" property.\n");
1530 /* Add the kext, & its plist.
1532 newDriverDict
= OSDictionary::withCapacity(4);
1533 assert(newDriverDict
);
1534 newDriverDict
->setObject("plist", propertyDict
);
1535 startupExtensions
->setObject(moduleName
, newDriverDict
);
1536 newDriverDict
->release();
1538 /* Add the code if present.
1540 OSData
* data
= OSDynamicCast(OSData
, propertyDict
->getObject("OSBundlePrelink"));
1542 if (data
->getLength() < (kPrelinkReservedCount
* sizeof(UInt32
))) {
1543 IOLog("Error: Prelinked module entry has "
1544 "invalid \"OSBundlePrelink\" property.\n");
1549 prelink
= (UInt32
*) data
->getBytesNoCopy();
1550 kmod_info_t
* kmod_info
= (kmod_info_t
*) OSReadBigInt32(prelink
, 0);
1551 // end of "file" is end of symbol sect
1552 data
= OSData::withBytesNoCopy((void *) kmod_info
->address
,
1553 symsect
->addr
+ symsect
->size
- kmod_info
->address
);
1554 newDriverDict
->setObject("code", data
);
1559 /* Add the symbols if present.
1561 OSNumber
* num
= OSDynamicCast(OSNumber
, propertyDict
->getObject("OSBundlePrelinkSymbols"));
1563 UInt32 offset
= num
->unsigned32BitValue();
1564 data
= OSData::withBytesNoCopy((void *) (symsect
->addr
+ offset
), symsect
->size
- offset
);
1565 newDriverDict
->setObject("code", data
);
1571 if (gIOPrelinkedModules
)
1572 IOLog("%d prelinked modules\n", prelinkedCount
);
1576 virt
= ml_static_ptovirt(infosect
->addr
);
1578 ml_static_mfree(virt
, infosect
->size
);
1580 newDriverDict
= NULL
;
1586 IORegistryEntry::fromPath(
1587 "/chosen/memory-map", // path
1590 // return value is retained so be sure to release it
1592 if (!bootxMemoryMap
) {
1593 IOLog("Error: Couldn't read booter memory map.\n");
1599 propertyDict
= bootxMemoryMap
->dictionaryWithProperties();
1600 if (!propertyDict
) {
1601 IOLog("Error: Couldn't get property dictionary "
1602 "from memory map.\n");
1608 keyIterator
= OSCollectionIterator::withCollection(propertyDict
);
1610 IOLog("Error: Couldn't allocate iterator for driver images.\n");
1616 while ( (key
= OSDynamicCast(OSString
,
1617 keyIterator
->getNextObject())) ) {
1618 /* Clear newDriverDict & mkextExtensions upon entry to the loop,
1619 * handling both successful and unsuccessful iterations.
1621 if (newDriverDict
) {
1622 newDriverDict
->release();
1623 newDriverDict
= NULL
;
1625 if (mkextExtensions
) {
1626 mkextExtensions
->release();
1627 mkextExtensions
= NULL
;
1630 const char * keyValue
= key
->getCStringNoCopy();
1632 if ( !strncmp(keyValue
, BOOTX_KEXT_PREFIX
,
1633 strlen(BOOTX_KEXT_PREFIX
)) ) {
1635 /* Read the extension from the bootx-supplied memory.
1637 newDriverDict
= readExtension(propertyDict
, keyValue
);
1638 if (!newDriverDict
) {
1639 IOLog("Error: Couldn't read data "
1640 "for device tree entry \"%s\".\n", keyValue
);
1646 /* Preprare to record the extension by getting its info plist.
1648 driverPlist
= OSDynamicCast(OSDictionary
,
1649 newDriverDict
->getObject("plist"));
1651 IOLog("Error: Extension in device tree entry \"%s\" "
1652 "has no property list.\n", keyValue
);
1658 /* Get the extension's module name. This is used to record
1659 * the extension. Do *not* release the moduleName.
1661 OSString
* moduleName
= OSDynamicCast(OSString
,
1662 driverPlist
->getObject("CFBundleIdentifier"));
1664 IOLog("Error: Device tree entry \"%s\" has "
1665 "no \"CFBundleIdentifier\" property.\n", keyValue
);
1671 /* All has gone well so far, so record the extension under
1672 * its module name, checking for an existing duplicate.
1674 * Do not release moduleName, as it's part of the extension's
1677 OSDictionary
* incumbentExt
= OSDynamicCast(OSDictionary
,
1678 startupExtensions
->getObject(moduleName
));
1680 if (!incumbentExt
) {
1681 startupExtensions
->setObject(moduleName
, newDriverDict
);
1683 OSDictionary
* mostRecentExtension
=
1684 compareExtensionVersions(incumbentExt
, newDriverDict
);
1686 if (mostRecentExtension
== incumbentExt
) {
1687 /* Do nothing, we've got the most recent. */
1688 } else if (mostRecentExtension
== newDriverDict
) {
1689 if (!startupExtensions
->setObject(moduleName
,
1692 /* This is a fatal error, so bail.
1694 IOLog("recordStartupExtensions(): Failed to add "
1696 moduleName
->getCStringNoCopy());
1701 } else /* should be NULL */ {
1703 /* This is a nonfatal error, so continue.
1705 IOLog("recordStartupExtensions(): Error comparing "
1706 "versions of duplicate extensions %s.\n",
1707 moduleName
->getCStringNoCopy());
1714 } else if ( !strncmp(keyValue
, BOOTX_MULTIKEXT_PREFIX
,
1715 strlen(BOOTX_MULTIKEXT_PREFIX
)) ) {
1717 mkextExtensions
= OSDictionary::withCapacity(10);
1718 if (!mkextExtensions
) {
1719 IOLog("Error: Couldn't allocate dictionary to unpack "
1720 "multi-extension archive.\n");
1723 goto finish
; // allocation failure is fatal for this routine
1725 if (!readExtensions(propertyDict
, keyValue
, mkextExtensions
)) {
1726 IOLog("Error: Couldn't unpack multi-extension archive.\n");
1730 if (!mergeExtensionDictionaries(startupExtensions
,
1733 IOLog("Error: Failed to merge new extensions into "
1737 goto finish
; // merge error is fatal for this routine
1742 // Do not release key.
1744 } /* while ( (key = OSDynamicCast(OSString, ...) ) ) */
1746 if (!mergeExtensionDictionaries(existingExtensions
, startupExtensions
)) {
1747 IOLog("Error: Failed to merge new extensions into existing set.\n");
1753 result
= addPersonalities(startupExtensions
);
1755 IOLog("Error: Failed to add personalities for extensions extracted "
1764 // reused so clear first!
1766 keyIterator
->release();
1771 IOLog("Error: Failed to record startup extensions.\n");
1775 keyIterator
= OSCollectionIterator::withCollection(
1779 while ( (key
= OSDynamicCast(OSString
,
1780 keyIterator
->getNextObject())) ) {
1782 IOLog("Found extension \"%s\".\n",
1783 key
->getCStringNoCopy());
1786 keyIterator
->release();
1792 if (newDriverDict
) newDriverDict
->release();
1793 if (propertyDict
) propertyDict
->release();
1794 if (bootxMemoryMap
) bootxMemoryMap
->release();
1795 if (mkextExtensions
) mkextExtensions
->release();
1796 if (startupExtensions
) startupExtensions
->release();
1802 /*********************************************************************
1803 * This function removes an entry from the dictionary of startup
1804 * extensions. It's used when an extension can't be loaded, for
1805 * whatever reason. For drivers, this allows another matching driver
1806 * to be loaded, so that, for example, a driver for the root device
1808 *********************************************************************/
1809 void removeStartupExtension(const char * extensionName
) {
1810 OSDictionary
* startupExtensions
= NULL
; // don't release
1811 OSDictionary
* extensionDict
= NULL
; // don't release
1812 OSDictionary
* extensionPlist
= NULL
; // don't release
1813 OSDictionary
* extensionPersonalities
= NULL
; // don't release
1814 OSDictionary
* personality
= NULL
; // don't release
1815 OSCollectionIterator
* keyIterator
= NULL
; // must release
1816 OSString
* key
= NULL
; // don't release
1818 startupExtensions
= getStartupExtensions();
1819 if (!startupExtensions
) goto finish
;
1822 /* Find the extension's entry in the dictionary of
1823 * startup extensions.
1825 extensionDict
= OSDynamicCast(OSDictionary
,
1826 startupExtensions
->getObject(extensionName
));
1827 if (!extensionDict
) goto finish
;
1829 extensionPlist
= OSDynamicCast(OSDictionary
,
1830 extensionDict
->getObject("plist"));
1831 if (!extensionPlist
) goto finish
;
1833 extensionPersonalities
= OSDynamicCast(OSDictionary
,
1834 extensionPlist
->getObject("IOKitPersonalities"));
1835 if (!extensionPersonalities
) goto finish
;
1837 /* If it was there, remove it from the catalogue proper
1838 * by calling removeDrivers(). Pass true for the second
1839 * argument to trigger a new round of matching, and
1840 * then remove the extension from the dictionary of startup
1843 keyIterator
= OSCollectionIterator::withCollection(
1844 extensionPersonalities
);
1846 IOLog("Error: Couldn't allocate iterator to scan"
1847 " personalities for %s.\n", extensionName
);
1851 while ((key
= OSDynamicCast(OSString
, keyIterator
->getNextObject()))) {
1852 personality
= OSDynamicCast(OSDictionary
,
1853 extensionPersonalities
->getObject(key
));
1857 gIOCatalogue
->removeDrivers(personality
, true);
1861 startupExtensions
->removeObject(extensionName
);
1865 if (keyIterator
) keyIterator
->release();
1869 /*********************************************************************
1870 * FIXME: This function invalidates the globals gStartupExtensions and
1871 * FIXME: ...gBootLoaderObjects without setting them to NULL. Since
1872 * FIXME: ...the code itself is immediately unloaded, there may not be
1873 * FIXME: ...any reason to worry about that!
1874 *********************************************************************/
1875 void clearStartupExtensionsAndLoaderInfo(void)
1877 OSDictionary
* startupExtensions
= NULL
; // must release
1878 OSArray
* bootLoaderObjects
= NULL
; // must release
1880 IORegistryEntry
* bootxMemoryMap
= NULL
; // must release
1881 OSDictionary
* propertyDict
= NULL
; // must release
1882 OSCollectionIterator
* keyIterator
= NULL
; // must release
1883 OSString
* key
= NULL
; // don't release
1886 * Drop any temporarily held data objects.
1888 bootLoaderObjects
= getBootLoaderObjects();
1889 if (bootLoaderObjects
) {
1890 bootLoaderObjects
->release();
1894 * If any "code" entries in driver dictionaries are accompanied
1895 * by "compressedCode" entries, then those data objects were
1896 * created based of of kmem_alloc()'ed memory, which must be
1899 startupExtensions
= getStartupExtensions();
1900 if (startupExtensions
) {
1902 OSCollectionIterator::withCollection(startupExtensions
);
1904 IOLog("Error: Couldn't allocate iterator for startup "
1907 goto memory_map
; // bail to the memory_map label
1910 while ( (key
= OSDynamicCast(OSString
,
1911 keyIterator
->getNextObject())) ) {
1913 OSDictionary
* driverDict
= 0;
1914 OSData
* codeData
= 0;
1916 driverDict
= OSDynamicCast(OSDictionary
,
1917 startupExtensions
->getObject(key
));
1919 codeData
= OSDynamicCast(OSData
,
1920 driverDict
->getObject("code"));
1923 driverDict
->getObject("compressedCode")) {
1925 kmem_free(kernel_map
,
1926 (unsigned int)codeData
->getBytesNoCopy(),
1927 codeData
->getLength());
1932 keyIterator
->release();
1933 startupExtensions
->release();
1939 * Go through the device tree's memory map and remove any driver
1943 IORegistryEntry::fromPath(
1944 "/chosen/memory-map", // path
1947 // return value is retained so be sure to release it
1949 if (!bootxMemoryMap
) {
1950 IOLog("Error: Couldn't read booter memory map.\n");
1955 propertyDict
= bootxMemoryMap
->dictionaryWithProperties();
1956 if (!propertyDict
) {
1957 IOLog("Error: Couldn't get property dictionary "
1958 "from memory map.\n");
1963 keyIterator
= OSCollectionIterator::withCollection(propertyDict
);
1965 IOLog("Error: Couldn't allocate iterator for driver images.\n");
1970 while ( (key
= OSDynamicCast(OSString
,
1971 keyIterator
->getNextObject())) ) {
1973 const char * keyValue
= key
->getCStringNoCopy();
1975 if ( !strncmp(keyValue
, BOOTX_KEXT_PREFIX
,
1976 strlen(BOOTX_KEXT_PREFIX
)) ||
1977 !strncmp(keyValue
, BOOTX_MULTIKEXT_PREFIX
,
1978 strlen(BOOTX_MULTIKEXT_PREFIX
)) ) {
1980 OSData
* bootxDriverDataObject
= NULL
;
1981 MemoryMapFileInfo
* driverInfo
= 0;
1983 bootxDriverDataObject
= OSDynamicCast(OSData
,
1984 propertyDict
->getObject(keyValue
));
1985 // don't release bootxDriverDataObject
1987 if (!bootxDriverDataObject
) {
1990 driverInfo
= (MemoryMapFileInfo
*)
1991 bootxDriverDataObject
->getBytesNoCopy(0,
1992 sizeof(MemoryMapFileInfo
));
1993 IODTFreeLoaderInfo((char *)keyValue
,
1994 (void *)driverInfo
->paddr
,
1995 (int)driverInfo
->length
);
2000 if (bootxMemoryMap
) bootxMemoryMap
->release();
2001 if (propertyDict
) propertyDict
->release();
2002 if (keyIterator
) keyIterator
->release();