2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
22 #include <libkern/c++/OSContainers.h>
23 #include <IOKit/IODeviceTreeSupport.h>
24 #include <IOKit/IORegistryEntry.h>
25 #include <IOKit/IOCatalogue.h>
26 #include <libkern/c++/OSUnserialize.h>
27 #include <libkern/OSByteOrder.h>
28 #include <libsa/catalogue.h>
31 #include <machine/machine_routines.h>
32 #include <mach/host_info.h>
33 #include <mach/kmod.h>
34 #include <libsa/mkext.h>
35 #include <libsa/vers_rsrc.h>
36 #include <mach-o/loader.h>
39 #include <IOKit/IOLib.h>
41 #include <IOKit/assert.h>
44 extern void IODTFreeLoaderInfo( char *key
, void *infoAddr
, int infoSize
);
45 // extern kern_return_t host_info(host_t host,
46 // host_flavor_t flavor,
48 // mach_msg_type_number_t *count);
49 extern int grade_binary(cpu_type_t exectype
, cpu_subtype_t execsubtype
);
50 // Return the address of the named Mach-O segment from the currently
51 // executing 32 bit kernel, or NULL.
52 extern struct segment_command
*getsegbyname(char *seg_name
);
53 // Return the address of the named section from the named Mach-O segment
54 // from the currently executing 32 bit kernel, or NULL.
55 extern struct section
*getsectbyname(char *segname
, char *sectname
);
61 #define VTYELLOW "\033[33m"
62 #define VTRESET "\033[0m"
68 /*********************************************************************
69 *********************************************************************/
70 static OSDictionary
* gStartupExtensions
= 0;
71 static OSArray
* gBootLoaderObjects
= 0;
72 extern OSArray
* gIOPrelinkedModules
;
74 OSDictionary
* getStartupExtensions(void) {
75 if (gStartupExtensions
) {
76 return gStartupExtensions
;
78 gStartupExtensions
= OSDictionary::withCapacity(1);
79 assert (gStartupExtensions
);
81 return gStartupExtensions
;
84 /* This array holds objects that are needed to be held around during
85 * boot before kextd starts up. Currently it contains OSData objects
86 * copied from OF entries for mkext archives in device ROMs. Because
87 * the Device Tree support code dumps these after initially handing
88 * them to us, we have to be able to clean them up later.
90 OSArray
* getBootLoaderObjects(void) {
91 if (gBootLoaderObjects
) {
92 return gBootLoaderObjects
;
94 gBootLoaderObjects
= OSArray::withCapacity(1);
95 assert (gBootLoaderObjects
);
97 return gBootLoaderObjects
;
100 /*********************************************************************
101 * This function checks that a driver dict has all the required
102 * entries and does a little bit of value checking too.
104 * index is nonnegative if the index of an entry from an mkext
106 *********************************************************************/
107 bool validateExtensionDict(OSDictionary
* extension
, int index
) {
110 bool not_a_dict
= false;
111 bool id_missing
= false;
112 bool is_kernel_resource
= false;
113 bool has_executable
= false;
114 OSString
* bundleIdentifier
= NULL
; // do not release
115 OSObject
* rawValue
= NULL
; // do not release
116 OSString
* stringValue
= NULL
; // do not release
117 OSBoolean
* booleanValue
= NULL
; // do not release
118 OSDictionary
* personalities
= NULL
; // do not release
119 OSDictionary
* libraries
= NULL
; // do not release
120 OSCollectionIterator
* keyIterator
= NULL
; // must release
121 OSString
* key
= NULL
; // do not release
123 VERS_version compatible_vers
;
125 // Info dict is a dictionary
126 if (!OSDynamicCast(OSDictionary
, extension
)) {
132 // CFBundleIdentifier is a string - REQUIRED
133 bundleIdentifier
= OSDynamicCast(OSString
,
134 extension
->getObject("CFBundleIdentifier"));
135 if (!bundleIdentifier
) {
141 // Length of CFBundleIdentifier is not >= KMOD_MAX_NAME
142 if (bundleIdentifier
->getLength() >= KMOD_MAX_NAME
) {
147 // CFBundlePackageType is "KEXT" - REQUIRED
148 stringValue
= OSDynamicCast(OSString
,
149 extension
->getObject("CFBundlePackageType"));
154 if (!stringValue
->isEqualTo("KEXT")) {
159 // CFBundleVersion is a string - REQUIRED
160 stringValue
= OSDynamicCast(OSString
,
161 extension
->getObject("CFBundleVersion"));
166 // CFBundleVersion is of valid form
167 vers
= VERS_parse_string(stringValue
->getCStringNoCopy());
173 // OSBundleCompatibleVersion is a string - OPTIONAL
174 rawValue
= extension
->getObject("OSBundleCompatibleVersion");
176 stringValue
= OSDynamicCast(OSString
, rawValue
);
182 // OSBundleCompatibleVersion is of valid form
183 compatible_vers
= VERS_parse_string(stringValue
->getCStringNoCopy());
184 if (compatible_vers
< 0) {
189 // OSBundleCompatibleVersion <= CFBundleVersion
190 if (compatible_vers
> vers
) {
196 // CFBundleExecutable is a string - OPTIONAL
197 rawValue
= extension
->getObject("CFBundleExecutable");
199 stringValue
= OSDynamicCast(OSString
, rawValue
);
200 if (!stringValue
|| stringValue
->getLength() == 0) {
204 has_executable
= true;
207 // OSKernelResource is a boolean value - OPTIONAL
208 rawValue
= extension
->getObject("OSKernelResource");
210 booleanValue
= OSDynamicCast(OSBoolean
, rawValue
);
215 is_kernel_resource
= booleanValue
->isTrue();
218 // IOKitPersonalities is a dictionary - OPTIONAL
219 rawValue
= extension
->getObject("IOKitPersonalities");
221 personalities
= OSDynamicCast(OSDictionary
, rawValue
);
222 if (!personalities
) {
227 keyIterator
= OSCollectionIterator::withCollection(personalities
);
229 IOLog("Error: Failed to allocate iterator for personalities.\n");
235 while ((key
= OSDynamicCast(OSString
, keyIterator
->getNextObject()))) {
236 OSDictionary
* personality
= NULL
; // do not release
238 // Each personality is a dictionary
239 personality
= OSDynamicCast(OSDictionary
,
240 personalities
->getObject(key
));
246 // IOClass exists as a string - REQUIRED
247 if (!OSDynamicCast(OSString
, personality
->getObject("IOClass"))) {
252 // IOProviderClass exists as a string - REQUIRED
253 if (!OSDynamicCast(OSString
,
254 personality
->getObject("IOProviderClass"))) {
260 // CFBundleIdentifier is a string - OPTIONAL - INSERT IF ABSENT!
261 rawValue
= personality
->getObject("CFBundleIdentifier");
263 personality
->setObject("CFBundleIdentifier", bundleIdentifier
);
265 OSString
* personalityID
= NULL
; // do not release
266 personalityID
= OSDynamicCast(OSString
, rawValue
);
267 if (!personalityID
) {
271 // Length of CFBundleIdentifier is not >= KMOD_MAX_NAME
272 if (personalityID
->getLength() >= KMOD_MAX_NAME
) {
279 // IOKitDebug is a number - OPTIONAL
280 rawValue
= personality
->getObject("IOKitDebug");
281 if (rawValue
&& !OSDynamicCast(OSNumber
, rawValue
)) {
287 keyIterator
->release();
292 // OSBundleLibraries is a dictionary - REQUIRED if
293 // not kernel resource & has executable
295 rawValue
= extension
->getObject("OSBundleLibraries");
296 if (!rawValue
&& !is_kernel_resource
&& has_executable
) {
302 libraries
= OSDynamicCast(OSDictionary
, rawValue
);
308 keyIterator
= OSCollectionIterator::withCollection(libraries
);
310 IOLog("Error: Failed to allocate iterator for libraries.\n");
316 while ((key
= OSDynamicCast(OSString
,
317 keyIterator
->getNextObject()))) {
319 OSString
* libraryVersion
= NULL
; // do not release
321 // Each key's length is not >= KMOD_MAX_NAME
322 if (key
->getLength() >= KMOD_MAX_NAME
) {
327 libraryVersion
= OSDynamicCast(OSString
,
328 libraries
->getObject(key
));
329 if (!libraryVersion
) {
334 // Each value is a valid version string
335 vers
= VERS_parse_string(libraryVersion
->getCStringNoCopy());
342 keyIterator
->release();
346 // OSBundleRequired is a legal value - *not* required at boot time
347 // so we can do install CDs and the like with mkext files containing
348 // all normally-used drivers.
349 rawValue
= extension
->getObject("OSBundleRequired");
351 stringValue
= OSDynamicCast(OSString
, rawValue
);
356 if (!stringValue
->isEqualTo("Root") &&
357 !stringValue
->isEqualTo("Local-Root") &&
358 !stringValue
->isEqualTo("Network-Root") &&
359 !stringValue
->isEqualTo("Safe Boot") &&
360 !stringValue
->isEqualTo("Console")) {
370 if (keyIterator
) keyIterator
->release();
375 IOLog(VTYELLOW
"mkext entry %d:." VTRESET
, index
);
377 IOLog(VTYELLOW
"kernel extension" VTRESET
);
379 IOLog(VTYELLOW
"info dictionary isn't a dictionary\n"
381 } else if (id_missing
) {
383 IOLog(VTYELLOW
"mkext entry %d:." VTRESET
, index
);
385 IOLog(VTYELLOW
"kernel extension" VTRESET
);
387 IOLog(VTYELLOW
"\"CFBundleIdentifier\" property is "
388 "missing or not a string\n"
391 IOLog(VTYELLOW
"kernel extension \"%s\": info dictionary is invalid\n"
392 VTRESET
, bundleIdentifier
->getCStringNoCopy());
401 /*********************************************************************
402 *********************************************************************/
403 OSDictionary
* compareExtensionVersions(
404 OSDictionary
* incumbent
,
405 OSDictionary
* candidate
) {
407 OSDictionary
* winner
= NULL
;
409 OSDictionary
* incumbentPlist
= NULL
;
410 OSDictionary
* candidatePlist
= NULL
;
411 OSString
* incumbentName
= NULL
;
412 OSString
* candidateName
= NULL
;
413 OSString
* incumbentVersionString
= NULL
;
414 OSString
* candidateVersionString
= NULL
;
415 VERS_version incumbent_vers
= 0;
416 VERS_version candidate_vers
= 0;
418 incumbentPlist
= OSDynamicCast(OSDictionary
,
419 incumbent
->getObject("plist"));
420 candidatePlist
= OSDynamicCast(OSDictionary
,
421 candidate
->getObject("plist"));
423 if (!incumbentPlist
|| !candidatePlist
) {
424 IOLog("compareExtensionVersions() called with invalid "
425 "extension dictionaries.\n");
431 incumbentName
= OSDynamicCast(OSString
,
432 incumbentPlist
->getObject("CFBundleIdentifier"));
433 candidateName
= OSDynamicCast(OSString
,
434 candidatePlist
->getObject("CFBundleIdentifier"));
435 incumbentVersionString
= OSDynamicCast(OSString
,
436 incumbentPlist
->getObject("CFBundleVersion"));
437 candidateVersionString
= OSDynamicCast(OSString
,
438 candidatePlist
->getObject("CFBundleVersion"));
440 if (!incumbentName
|| !candidateName
||
441 !incumbentVersionString
|| !candidateVersionString
) {
443 IOLog("compareExtensionVersions() called with invalid "
444 "extension dictionaries.\n");
450 if (strcmp(incumbentName
->getCStringNoCopy(),
451 candidateName
->getCStringNoCopy())) {
453 IOLog("compareExtensionVersions() called with different "
454 "extension names (%s and %s).\n",
455 incumbentName
->getCStringNoCopy(),
456 candidateName
->getCStringNoCopy());
462 incumbent_vers
= VERS_parse_string(incumbentVersionString
->getCStringNoCopy());
463 if (incumbent_vers
< 0) {
465 IOLog(VTYELLOW
"Error parsing version string for extension %s (%s)\n"
467 incumbentName
->getCStringNoCopy(),
468 incumbentVersionString
->getCStringNoCopy());
474 candidate_vers
= VERS_parse_string(candidateVersionString
->getCStringNoCopy());
475 if (candidate_vers
< 0) {
477 IOLog(VTYELLOW
"Error parsing version string for extension %s (%s)\n"
479 candidateName
->getCStringNoCopy(),
480 candidateVersionString
->getCStringNoCopy());
486 if (candidate_vers
> incumbent_vers
) {
487 IOLog(VTYELLOW
"Replacing extension \"%s\" with newer version "
488 "(%s -> %s).\n" VTRESET
,
489 incumbentName
->getCStringNoCopy(),
490 incumbentVersionString
->getCStringNoCopy(),
491 candidateVersionString
->getCStringNoCopy());
496 IOLog(VTYELLOW
"Skipping duplicate extension \"%s\" with older/same "
497 " version (%s -> %s).\n" VTRESET
,
498 candidateName
->getCStringNoCopy(),
499 candidateVersionString
->getCStringNoCopy(),
500 incumbentVersionString
->getCStringNoCopy());
508 // no cleanup, how nice
513 /*********************************************************************
514 * This function merges entries in the mergeFrom dictionary into the
515 * mergeInto dictionary. If it returns false, the two dictionaries are
516 * not altered. If it returns true, then mergeInto may have new
517 * entries; any keys that were already present in mergeInto are
518 * removed from mergeFrom, so that the caller can see what was
520 *********************************************************************/
521 bool mergeExtensionDictionaries(OSDictionary
* mergeInto
,
522 OSDictionary
* mergeFrom
) {
525 OSDictionary
* mergeIntoCopy
= NULL
; // must release
526 OSDictionary
* mergeFromCopy
= NULL
; // must release
527 OSCollectionIterator
* keyIterator
= NULL
; // must release
528 OSString
* key
; // don't release
530 /* Add 1 to count to guarantee copy can grow (grr).
532 mergeIntoCopy
= OSDictionary::withDictionary(mergeInto
,
533 mergeInto
->getCount() + 1);
534 if (!mergeIntoCopy
) {
535 IOLog("Error: Failed to copy 'into' extensions dictionary "
542 /* Add 1 to count to guarantee copy can grow (grr).
544 mergeFromCopy
= OSDictionary::withDictionary(mergeFrom
,
545 mergeFrom
->getCount() + 1);
546 if (!mergeFromCopy
) {
547 IOLog("Error: Failed to copy 'from' extensions dictionary "
554 keyIterator
= OSCollectionIterator::withCollection(mergeFrom
);
556 IOLog("Error: Failed to allocate iterator for extensions.\n");
564 * Loop through "from" dictionary, checking if the identifier already
565 * exists in the "into" dictionary and checking versions if it does.
567 while ((key
= OSDynamicCast(OSString
, keyIterator
->getNextObject()))) {
568 OSDictionary
* incumbentExt
= OSDynamicCast(OSDictionary
,
569 mergeIntoCopy
->getObject(key
));
570 OSDictionary
* candidateExt
= OSDynamicCast(OSDictionary
,
571 mergeFrom
->getObject(key
));
574 if (!mergeIntoCopy
->setObject(key
, candidateExt
)) {
576 /* This is a fatal error, so bail.
578 IOLog("mergeExtensionDictionaries(): Failed to add "
580 key
->getCStringNoCopy());
586 OSDictionary
* mostRecentExtension
=
587 compareExtensionVersions(incumbentExt
, candidateExt
);
589 if (mostRecentExtension
== incumbentExt
) {
590 mergeFromCopy
->removeObject(key
);
591 } else if (mostRecentExtension
== candidateExt
) {
593 if (!mergeIntoCopy
->setObject(key
, candidateExt
)) {
595 /* This is a fatal error, so bail.
597 IOLog("mergeExtensionDictionaries(): Failed to add "
599 key
->getCStringNoCopy());
604 } else /* should be NULL */ {
606 /* This is a nonfatal error, so continue doing others.
608 IOLog("mergeExtensionDictionaries(): Error comparing "
609 "versions of duplicate extensions %s.\n",
610 key
->getCStringNoCopy());
619 /* If successful, replace the contents of the original
620 * dictionaries with those of the modified copies.
623 mergeInto
->flushCollection();
624 mergeInto
->merge(mergeIntoCopy
);
625 mergeFrom
->flushCollection();
626 mergeFrom
->merge(mergeFromCopy
);
629 if (mergeIntoCopy
) mergeIntoCopy
->release();
630 if (mergeFromCopy
) mergeFromCopy
->release();
631 if (keyIterator
) keyIterator
->release();
638 * These bits are used to parse data made available by bootx.
640 #define BOOTX_KEXT_PREFIX "Driver-"
641 #define BOOTX_MULTIKEXT_PREFIX "DriversPackage-"
643 typedef struct MemoryMapFileInfo
{
648 typedef struct BootxDriverInfo
{
655 typedef struct MkextEntryInfo
{
656 vm_address_t base_address
;
657 mkext_file
* fileinfo
;
661 /*********************************************************************
662 * This private function reads the data for a single extension from
663 * the bootx memory-map's propery dict, returning a dictionary with
664 * keys "plist" for the extension's Info.plist as a parsed OSDictionary
665 * and "code" for the extension's executable code as an OSData.
666 *********************************************************************/
667 OSDictionary
* readExtension(OSDictionary
* propertyDict
,
668 const char * memory_map_name
) {
671 OSData
* bootxDriverDataObject
= NULL
;
672 OSDictionary
* driverPlist
= NULL
;
673 OSString
* driverName
= NULL
;
674 OSData
* driverCode
= NULL
;
675 OSString
* errorString
= NULL
;
676 OSDictionary
* driverDict
= NULL
;
678 MemoryMapFileInfo
* driverInfo
= 0;
679 BootxDriverInfo
* dataBuffer
;
681 kmod_info_t
* loaded_kmod
= NULL
;
683 bootxDriverDataObject
= OSDynamicCast(OSData
,
684 propertyDict
->getObject(memory_map_name
));
685 // don't release bootxDriverDataObject
687 if (!bootxDriverDataObject
) {
688 IOLog("Error: No driver data object "
689 "for device tree entry \"%s\".\n",
696 driverDict
= OSDictionary::withCapacity(2);
698 IOLog("Error: Couldn't allocate dictionary "
699 "for device tree entry \"%s\".\n", memory_map_name
);
705 driverInfo
= (MemoryMapFileInfo
*)
706 bootxDriverDataObject
->getBytesNoCopy(0,
707 sizeof(MemoryMapFileInfo
));
708 #if defined (__ppc__)
709 dataBuffer
= (BootxDriverInfo
*)ml_static_ptovirt(
711 #elif defined (__i386__)
712 dataBuffer
= (BootxDriverInfo
*)driverInfo
->paddr
;
713 dataBuffer
->plistAddr
= ml_static_ptovirt(dataBuffer
->plistAddr
);
714 if (dataBuffer
->moduleAddr
)
715 dataBuffer
->moduleAddr
= ml_static_ptovirt(dataBuffer
->moduleAddr
);
717 #error unsupported architecture
720 IOLog("Error: No data buffer "
721 "for device tree entry \"%s\".\n", memory_map_name
);
727 driverPlist
= OSDynamicCast(OSDictionary
,
728 OSUnserializeXML(dataBuffer
->plistAddr
, &errorString
));
730 IOLog("Error: Couldn't read XML property list "
731 "for device tree entry \"%s\".\n", memory_map_name
);
734 IOLog("XML parse error: %s.\n",
735 errorString
->getCStringNoCopy());
743 driverName
= OSDynamicCast(OSString
,
744 driverPlist
->getObject("CFBundleIdentifier")); // do not release
746 IOLog("Error: Device tree entry \"%s\" has "
747 "no \"CFBundleIdentifier\" property.\n", memory_map_name
);
753 /* Check if kmod is already loaded and is a real loadable one (has
756 loaded_kmod
= kmod_lookupbyname_locked(driverName
->getCStringNoCopy());
757 if (loaded_kmod
&& loaded_kmod
->address
) {
758 IOLog("Skipping new extension \"%s\"; an extension named "
759 "\"%s\" is already loaded.\n",
760 driverName
->getCStringNoCopy(),
767 if (!validateExtensionDict(driverPlist
, -1)) {
768 // validateExtensionsDict() logs an error
773 driverDict
->setObject("plist", driverPlist
);
775 /* It's perfectly okay for a KEXT to have no executable.
776 * Check that moduleAddr is nonzero before attempting to
779 * NOTE: The driverCode object is created "no-copy", so
780 * it doesn't own that memory. The memory must be freed
781 * separately from the OSData object (see
782 * clearStartupExtensionsAndLoaderInfo() at the end of this file).
784 if (dataBuffer
->moduleAddr
&& dataBuffer
->moduleLength
) {
785 driverCode
= OSData::withBytesNoCopy(dataBuffer
->moduleAddr
,
786 dataBuffer
->moduleLength
);
788 IOLog("Error: Couldn't allocate data object "
789 "to hold code for device tree entry \"%s\".\n",
797 driverDict
->setObject("code", driverCode
);
804 kfree((unsigned int)loaded_kmod
, sizeof(kmod_info_t
));
807 // do not release bootxDriverDataObject
808 // do not release driverName
811 driverPlist
->release();
814 errorString
->release();
817 driverCode
->release();
821 driverDict
->release();
829 /*********************************************************************
830 * Used to uncompress a single file entry in an mkext archive.
832 * The OSData returned does not own its memory! You must deallocate
833 * that memory using kmem_free() before releasing the OSData().
834 *********************************************************************/
835 static bool uncompressFile(u_int8_t
*base_address
, mkext_file
* fileinfo
,
836 /* out */ OSData
** file
) {
839 kern_return_t kern_result
;
840 u_int8_t
* uncompressed_file
= 0; // kmem_free() on error
841 OSData
* uncompressedFile
= 0; // returned
842 size_t uncompressed_size
= 0;
844 size_t offset
= OSSwapBigToHostInt32(fileinfo
->offset
);
845 size_t compsize
= OSSwapBigToHostInt32(fileinfo
->compsize
);
846 size_t realsize
= OSSwapBigToHostInt32(fileinfo
->realsize
);
847 time_t modifiedsecs
= OSSwapBigToHostInt32(fileinfo
->modifiedsecs
);
851 /* If these four fields are zero there's no file, but that isn't
854 if (offset
== 0 && compsize
== 0 &&
855 realsize
== 0 && modifiedsecs
== 0) {
859 // Add 1 for '\0' to terminate XML string!
860 kern_result
= kmem_alloc(kernel_map
, (vm_offset_t
*)&uncompressed_file
,
862 if (kern_result
!= KERN_SUCCESS
) {
863 IOLog("Error: Couldn't allocate data buffer "
864 "to uncompress file.\n");
870 uncompressedFile
= OSData::withBytesNoCopy(uncompressed_file
,
872 if (!uncompressedFile
) {
873 IOLog("Error: Couldn't allocate data object "
874 "to uncompress file.\n");
881 uncompressed_size
= decompress_lzss(uncompressed_file
,
882 base_address
+ offset
,
884 if (uncompressed_size
!= realsize
) {
885 IOLog("Error: Uncompressed file is not the length "
891 uncompressed_file
[uncompressed_size
] = '\0';
893 bcopy(base_address
+ offset
, uncompressed_file
,
895 uncompressed_file
[realsize
] = '\0';
898 *file
= uncompressedFile
;
902 if (uncompressed_file
) {
903 kmem_free(kernel_map
, (vm_address_t
)uncompressed_file
,
906 if (uncompressedFile
) {
907 uncompressedFile
->release();
914 bool uncompressModule(OSData
*compData
, /* out */ OSData
** file
) {
916 MkextEntryInfo
*info
= (MkextEntryInfo
*) compData
->getBytesNoCopy();
918 return uncompressFile((u_int8_t
*) info
->base_address
,
919 info
->fileinfo
, file
);
923 /*********************************************************************
924 * Does the work of pulling extensions out of an mkext archive located
926 *********************************************************************/
927 bool extractExtensionsFromArchive(MemoryMapFileInfo
* mkext_file_info
,
928 OSDictionary
* extensions
) {
932 u_int8_t
* crc_address
= 0;
934 mkext_header
* mkext_data
= 0; // don't free
935 mkext_kext
* onekext_data
= 0; // don't free
936 mkext_file
* plist_file
= 0; // don't free
937 mkext_file
* module_file
= 0; // don't free
938 kmod_info_t
* loaded_kmod
= 0; // must free
940 OSData
* driverPlistDataObject
= 0; // must release
941 OSDictionary
* driverPlist
= 0; // must release
942 OSData
* driverCode
= 0; // must release
943 OSDictionary
* driverDict
= 0; // must release
944 OSString
* moduleName
= 0; // don't release
945 OSString
* errorString
= NULL
; // must release
947 OSData
* moduleInfo
= 0; // must release
948 MkextEntryInfo module_info
;
951 #if defined (__ppc__)
952 mkext_data
= (mkext_header
*)mkext_file_info
->paddr
;
953 #elif defined (__i386__)
954 mkext_data
= (mkext_header
*)ml_static_ptovirt(mkext_file_info
->paddr
);
956 #error unsupported architecture
958 if (OSSwapBigToHostInt32(mkext_data
->magic
) != MKEXT_MAGIC
||
959 OSSwapBigToHostInt32(mkext_data
->signature
) != MKEXT_SIGN
) {
960 IOLog("Error: Extension archive has invalid magic or signature.\n");
966 if (OSSwapBigToHostInt32(mkext_data
->length
) != mkext_file_info
->length
) {
967 IOLog("Error: Mismatch between extension archive & "
968 "recorded length.\n");
974 crc_address
= (u_int8_t
*)&mkext_data
->version
;
975 checksum
= adler32(crc_address
,
976 (unsigned int)mkext_data
+
977 OSSwapBigToHostInt32(mkext_data
->length
) - (unsigned int)crc_address
);
979 if (OSSwapBigToHostInt32(mkext_data
->adler32
) != checksum
) {
980 IOLog("Error: Extension archive has a bad checksum.\n");
986 /* If the MKEXT archive isn't fat, check that the CPU type & subtype
987 * match that of the running kernel.
989 if (OSSwapBigToHostInt32(mkext_data
->cputype
) != (UInt32
)CPU_TYPE_ANY
) {
990 kern_return_t kresult
= KERN_FAILURE
;
991 host_basic_info_data_t hostinfo
;
992 host_info_t hostinfo_ptr
= (host_info_t
)&hostinfo
;
993 mach_msg_type_number_t count
= sizeof(hostinfo
)/sizeof(integer_t
);
995 kresult
= host_info((host_t
)1, HOST_BASIC_INFO
,
996 hostinfo_ptr
, &count
);
997 if (kresult
!= KERN_SUCCESS
) {
998 IOLog("Error: Couldn't get current host info.\n");
1003 if ((UInt32
)hostinfo
.cpu_type
!=
1004 OSSwapBigToHostInt32(mkext_data
->cputype
)) {
1006 IOLog("Error: Extension archive doesn't contain software "
1007 "for this computer's CPU type.\n");
1012 if (!grade_binary(OSSwapBigToHostInt32(mkext_data
->cputype
),
1013 OSSwapBigToHostInt32(mkext_data
->cpusubtype
))) {
1014 IOLog("Error: Extension archive doesn't contain software "
1015 "for this computer's CPU subtype.\n");
1022 for (unsigned int i
= 0;
1023 i
< OSSwapBigToHostInt32(mkext_data
->numkexts
);
1027 kfree((unsigned int)loaded_kmod
, sizeof(kmod_info_t
));
1031 if (driverPlistDataObject
) {
1032 kmem_free(kernel_map
,
1033 (unsigned int)driverPlistDataObject
->getBytesNoCopy(),
1034 driverPlistDataObject
->getLength());
1036 driverPlistDataObject
->release();
1037 driverPlistDataObject
= NULL
;
1040 driverPlist
->release();
1044 driverCode
->release();
1048 driverDict
->release();
1052 errorString
->release();
1056 onekext_data
= &mkext_data
->kext
[i
];
1057 plist_file
= &onekext_data
->plist
;
1058 module_file
= &onekext_data
->module;
1060 if (!uncompressFile((u_int8_t
*)mkext_data
, plist_file
,
1061 &driverPlistDataObject
)) {
1063 IOLog("Error: couldn't uncompress plist file "
1064 "from multikext archive entry %d.\n", i
);
1069 if (!driverPlistDataObject
) {
1070 IOLog("Error: No property list present "
1071 "for multikext archive entry %d.\n", i
);
1075 driverPlist
= OSDynamicCast(OSDictionary
,
1077 (char *)driverPlistDataObject
->getBytesNoCopy(),
1080 IOLog("Error: Couldn't read XML property list "
1081 "for multikext archive entry %d.\n", i
);
1084 IOLog("XML parse error: %s.\n",
1085 errorString
->getCStringNoCopy());
1091 if (!validateExtensionDict(driverPlist
, i
)) {
1092 // validateExtensionsDict() logs an error
1098 /* Get the extension's module name. This is used to record
1101 moduleName
= OSDynamicCast(OSString
,
1102 driverPlist
->getObject("CFBundleIdentifier")); // do not release
1104 IOLog("Error: Multikext archive entry %d has "
1105 "no \"CFBundleIdentifier\" property.\n", i
);
1107 continue; // assume a kext config error & continue
1110 /* Check if kmod is already loaded and is a real loadable one (has
1113 loaded_kmod
= kmod_lookupbyname_locked(moduleName
->getCStringNoCopy());
1114 if (loaded_kmod
&& loaded_kmod
->address
) {
1115 IOLog("Skipping new extension \"%s\"; an extension named "
1116 "\"%s\" is already loaded.\n",
1117 moduleName
->getCStringNoCopy(),
1123 driverDict
= OSDictionary::withCapacity(2);
1125 IOLog("Error: Couldn't allocate dictionary "
1126 "for multikext archive entry %d.\n", i
);
1132 driverDict
->setObject("plist", driverPlist
);
1135 * Prepare an entry to hold the mkext entry info for the
1136 * compressed binary module, if there is one. If all four fields
1137 * of the module entry are zero, there isn't one.
1139 if (!(loaded_kmod
&& loaded_kmod
->address
) && (OSSwapBigToHostInt32(module_file
->offset
) ||
1140 OSSwapBigToHostInt32(module_file
->compsize
) ||
1141 OSSwapBigToHostInt32(module_file
->realsize
) ||
1142 OSSwapBigToHostInt32(module_file
->modifiedsecs
))) {
1144 moduleInfo
= OSData::withCapacity(sizeof(MkextEntryInfo
));
1146 IOLog("Error: Couldn't allocate data object "
1147 "for multikext archive entry %d.\n", i
);
1153 module_info
.base_address
= (vm_address_t
)mkext_data
;
1154 module_info
.fileinfo
= module_file
;
1156 if (!moduleInfo
->appendBytes(&module_info
, sizeof(module_info
))) {
1157 IOLog("Error: Couldn't record info "
1158 "for multikext archive entry %d.\n", i
);
1164 driverDict
->setObject("compressedCode", moduleInfo
);
1167 OSDictionary
* incumbentExt
= OSDynamicCast(OSDictionary
,
1168 extensions
->getObject(moduleName
));
1170 if (!incumbentExt
) {
1171 extensions
->setObject(moduleName
, driverDict
);
1173 OSDictionary
* mostRecentExtension
=
1174 compareExtensionVersions(incumbentExt
, driverDict
);
1176 if (mostRecentExtension
== incumbentExt
) {
1177 /* Do nothing, we've got the most recent. */
1178 } else if (mostRecentExtension
== driverDict
) {
1179 if (!extensions
->setObject(moduleName
, driverDict
)) {
1181 /* This is a fatal error, so bail.
1183 IOLog("extractExtensionsFromArchive(): Failed to add "
1185 moduleName
->getCStringNoCopy());
1190 } else /* should be NULL */ {
1192 /* This is a nonfatal error, so continue.
1194 IOLog("extractExtensionsFromArchive(): Error comparing "
1195 "versions of duplicate extensions %s.\n",
1196 moduleName
->getCStringNoCopy());
1205 if (loaded_kmod
) kfree((unsigned int)loaded_kmod
, sizeof(kmod_info_t
));
1206 if (driverPlistDataObject
) {
1207 kmem_free(kernel_map
,
1208 (unsigned int)driverPlistDataObject
->getBytesNoCopy(),
1209 driverPlistDataObject
->getLength());
1210 driverPlistDataObject
->release();
1212 if (driverPlist
) driverPlist
->release();
1213 if (driverCode
) driverCode
->release();
1214 if (moduleInfo
) moduleInfo
->release();
1215 if (driverDict
) driverDict
->release();
1216 if (errorString
) errorString
->release();
1221 /*********************************************************************
1223 *********************************************************************/
1224 bool readExtensions(OSDictionary
* propertyDict
,
1225 const char * memory_map_name
,
1226 OSDictionary
* extensions
) {
1229 OSData
* mkextDataObject
= 0; // don't release
1230 MemoryMapFileInfo
* mkext_file_info
= 0; // don't free
1232 mkextDataObject
= OSDynamicCast(OSData
,
1233 propertyDict
->getObject(memory_map_name
));
1234 // don't release mkextDataObject
1236 if (!mkextDataObject
) {
1237 IOLog("Error: No mkext data object "
1238 "for device tree entry \"%s\".\n",
1245 mkext_file_info
= (MemoryMapFileInfo
*)mkextDataObject
->getBytesNoCopy();
1246 if (!mkext_file_info
) {
1251 result
= extractExtensionsFromArchive(mkext_file_info
, extensions
);
1255 if (!result
&& extensions
) {
1256 extensions
->flushCollection();
1263 /*********************************************************************
1264 * Adds the personalities for an extensions dictionary to the global
1266 *********************************************************************/
1267 bool addPersonalities(OSDictionary
* extensions
) {
1269 OSCollectionIterator
* keyIterator
= NULL
; // must release
1270 OSString
* key
; // don't release
1271 OSDictionary
* driverDict
= NULL
; // don't release
1272 OSDictionary
* driverPlist
= NULL
; // don't release
1273 OSDictionary
* thisDriverPersonalities
= NULL
; // don't release
1274 OSArray
* allDriverPersonalities
= NULL
; // must release
1276 allDriverPersonalities
= OSArray::withCapacity(1);
1277 if (!allDriverPersonalities
) {
1278 IOLog("Error: Couldn't allocate personality dictionary.\n");
1284 /* Record all personalities found so that they can be
1285 * added to the catalogue.
1286 * Note: Not all extensions have personalities.
1289 keyIterator
= OSCollectionIterator::withCollection(extensions
);
1291 IOLog("Error: Couldn't allocate iterator to record personalities.\n");
1297 while ( ( key
= OSDynamicCast(OSString
,
1298 keyIterator
->getNextObject() ))) {
1300 driverDict
= OSDynamicCast(OSDictionary
,
1301 extensions
->getObject(key
));
1302 driverPlist
= OSDynamicCast(OSDictionary
,
1303 driverDict
->getObject("plist"));
1304 thisDriverPersonalities
= OSDynamicCast(OSDictionary
,
1305 driverPlist
->getObject("IOKitPersonalities"));
1307 if (thisDriverPersonalities
) {
1308 OSCollectionIterator
* pIterator
;
1309 OSString
* locakKey
;
1310 pIterator
= OSCollectionIterator::withCollection(
1311 thisDriverPersonalities
);
1313 IOLog("Error: Couldn't allocate iterator "
1314 "to record extension personalities.\n");
1318 while ( (locakKey
= OSDynamicCast(OSString
,
1319 pIterator
->getNextObject())) ) {
1321 OSDictionary
* personality
= OSDynamicCast(
1323 thisDriverPersonalities
->getObject(locakKey
));
1325 allDriverPersonalities
->setObject(personality
);
1328 pIterator
->release();
1330 } /* extract personalities */
1333 /* Add all personalities found to the IOCatalogue,
1334 * but don't start matching.
1336 gIOCatalogue
->addDrivers(allDriverPersonalities
, false);
1340 if (allDriverPersonalities
) allDriverPersonalities
->release();
1341 if (keyIterator
) keyIterator
->release();
1347 /*********************************************************************
1348 * Called from IOCatalogue to add extensions from an mkext archive.
1349 * This function makes a copy of the mkext object passed in because
1350 * the device tree support code dumps it after calling us (indirectly
1351 * through the IOCatalogue).
1352 *********************************************************************/
1353 bool addExtensionsFromArchive(OSData
* mkextDataObject
) {
1356 OSDictionary
* startupExtensions
= NULL
; // don't release
1357 OSArray
* bootLoaderObjects
= NULL
; // don't release
1358 OSDictionary
* extensions
= NULL
; // must release
1359 MemoryMapFileInfo mkext_file_info
;
1360 OSCollectionIterator
* keyIterator
= NULL
; // must release
1361 OSString
* key
= NULL
; // don't release
1363 startupExtensions
= getStartupExtensions();
1364 if (!startupExtensions
) {
1365 IOLog("Can't record extension archive; there is no"
1366 " extensions dictionary.\n");
1372 bootLoaderObjects
= getBootLoaderObjects();
1373 if (! bootLoaderObjects
) {
1374 IOLog("Error: Couldn't allocate array to hold temporary objects.\n");
1380 extensions
= OSDictionary::withCapacity(2);
1382 IOLog("Error: Couldn't allocate dictionary to unpack "
1383 "extension archive.\n");
1389 mkext_file_info
.paddr
= (UInt32
)mkextDataObject
->getBytesNoCopy();
1390 mkext_file_info
.length
= mkextDataObject
->getLength();
1392 /* Save the local mkext data object so that we can deallocate it later.
1394 bootLoaderObjects
->setObject(mkextDataObject
);
1396 result
= extractExtensionsFromArchive(&mkext_file_info
, extensions
);
1398 IOLog("Error: Failed to extract extensions from archive.\n");
1404 result
= mergeExtensionDictionaries(startupExtensions
, extensions
);
1406 IOLog("Error: Failed to merge new extensions into existing set.\n");
1411 result
= addPersonalities(extensions
);
1413 IOLog("Error: Failed to add personalities for extensions extracted "
1423 IOLog("Error: Failed to record extensions from archive.\n");
1426 keyIterator
= OSCollectionIterator::withCollection(
1430 while ( (key
= OSDynamicCast(OSString
,
1431 keyIterator
->getNextObject())) ) {
1433 IOLog("Added extension \"%s\" from archive.\n",
1434 key
->getCStringNoCopy());
1437 keyIterator
->release();
1441 if (extensions
) extensions
->release();
1447 /*********************************************************************
1448 * This function builds dictionaries for the startup extensions
1449 * put into memory by bootx, recording each in the startup extensions
1450 * dictionary. The dictionary format is this:
1453 * "plist" = (the extension's Info.plist as an OSDictionary)
1454 * "code" = (an OSData containing the executable file)
1457 * This function returns true if any extensions were found and
1458 * recorded successfully, or if there are no start extensions,
1459 * and false if an unrecoverable error occurred. An error reading
1460 * a single extension is not considered fatal, and this function
1461 * will simply skip the problematic extension to try the next one.
1462 *********************************************************************/
1464 bool recordStartupExtensions(void) {
1466 OSDictionary
* startupExtensions
= NULL
; // must release
1467 OSDictionary
* existingExtensions
= NULL
; // don't release
1468 OSDictionary
* mkextExtensions
= NULL
; // must release
1469 IORegistryEntry
* bootxMemoryMap
= NULL
; // must release
1470 OSDictionary
* propertyDict
= NULL
; // must release
1471 OSCollectionIterator
* keyIterator
= NULL
; // must release
1472 OSString
* key
= NULL
; // don't release
1474 OSDictionary
* newDriverDict
= NULL
; // must release
1475 OSDictionary
* driverPlist
= NULL
; // don't release
1477 struct section
* infosect
;
1478 struct section
* symsect
;
1479 unsigned int prelinkedCount
= 0;
1481 existingExtensions
= getStartupExtensions();
1482 if (!existingExtensions
) {
1483 IOLog("Error: There is no dictionary for startup extensions.\n");
1489 startupExtensions
= OSDictionary::withCapacity(1);
1490 if (!startupExtensions
) {
1491 IOLog("Error: Couldn't allocate dictionary "
1492 "to record startup extensions.\n");
1499 // add any prelinked modules as startup extensions
1501 infosect
= getsectbyname("__PRELINK", "__info");
1502 symsect
= getsectbyname("__PRELINK", "__symtab");
1503 if (infosect
&& infosect
->addr
&& infosect
->size
1504 && symsect
&& symsect
->addr
&& symsect
->size
) do
1506 gIOPrelinkedModules
= OSDynamicCast(OSArray
,
1507 OSUnserializeXML((const char *) infosect
->addr
, NULL
));
1509 if (!gIOPrelinkedModules
)
1511 for( unsigned int idx
= 0;
1512 (propertyDict
= OSDynamicCast(OSDictionary
, gIOPrelinkedModules
->getObject(idx
)));
1515 enum { kPrelinkReservedCount
= 4 };
1517 /* Get the extension's module name. This is used to record
1518 * the extension. Do *not* release the moduleName.
1520 OSString
* moduleName
= OSDynamicCast(OSString
,
1521 propertyDict
->getObject("CFBundleIdentifier"));
1523 IOLog("Error: Prelinked module entry has "
1524 "no \"CFBundleIdentifier\" property.\n");
1529 /* Add the kext, & its plist.
1531 newDriverDict
= OSDictionary::withCapacity(4);
1532 assert(newDriverDict
);
1533 newDriverDict
->setObject("plist", propertyDict
);
1534 startupExtensions
->setObject(moduleName
, newDriverDict
);
1535 newDriverDict
->release();
1537 /* Add the code if present.
1539 OSData
* data
= OSDynamicCast(OSData
, propertyDict
->getObject("OSBundlePrelink"));
1541 if (data
->getLength() < (kPrelinkReservedCount
* sizeof(UInt32
))) {
1542 IOLog("Error: Prelinked module entry has "
1543 "invalid \"OSBundlePrelink\" property.\n");
1548 prelink
= (UInt32
*) data
->getBytesNoCopy();
1549 kmod_info_t
* kmod_info
= (kmod_info_t
*) OSReadBigInt32(prelink
, 0);
1550 // end of "file" is end of symbol sect
1551 data
= OSData::withBytesNoCopy((void *) kmod_info
->address
,
1552 symsect
->addr
+ symsect
->size
- kmod_info
->address
);
1553 newDriverDict
->setObject("code", data
);
1558 /* Add the symbols if present.
1560 OSNumber
* num
= OSDynamicCast(OSNumber
, propertyDict
->getObject("OSBundlePrelinkSymbols"));
1562 UInt32 offset
= num
->unsigned32BitValue();
1563 data
= OSData::withBytesNoCopy((void *) (symsect
->addr
+ offset
), symsect
->size
- offset
);
1564 newDriverDict
->setObject("code", data
);
1570 if (gIOPrelinkedModules
)
1571 IOLog("%d prelinked modules\n", prelinkedCount
);
1575 virt
= ml_static_ptovirt(infosect
->addr
);
1577 ml_static_mfree(virt
, infosect
->size
);
1579 newDriverDict
= NULL
;
1585 IORegistryEntry::fromPath(
1586 "/chosen/memory-map", // path
1589 // return value is retained so be sure to release it
1591 if (!bootxMemoryMap
) {
1592 IOLog("Error: Couldn't read booter memory map.\n");
1598 propertyDict
= bootxMemoryMap
->dictionaryWithProperties();
1599 if (!propertyDict
) {
1600 IOLog("Error: Couldn't get property dictionary "
1601 "from memory map.\n");
1607 keyIterator
= OSCollectionIterator::withCollection(propertyDict
);
1609 IOLog("Error: Couldn't allocate iterator for driver images.\n");
1615 while ( (key
= OSDynamicCast(OSString
,
1616 keyIterator
->getNextObject())) ) {
1617 /* Clear newDriverDict & mkextExtensions upon entry to the loop,
1618 * handling both successful and unsuccessful iterations.
1620 if (newDriverDict
) {
1621 newDriverDict
->release();
1622 newDriverDict
= NULL
;
1624 if (mkextExtensions
) {
1625 mkextExtensions
->release();
1626 mkextExtensions
= NULL
;
1629 const char * keyValue
= key
->getCStringNoCopy();
1631 if ( !strncmp(keyValue
, BOOTX_KEXT_PREFIX
,
1632 strlen(BOOTX_KEXT_PREFIX
)) ) {
1634 /* Read the extension from the bootx-supplied memory.
1636 newDriverDict
= readExtension(propertyDict
, keyValue
);
1637 if (!newDriverDict
) {
1638 IOLog("Error: Couldn't read data "
1639 "for device tree entry \"%s\".\n", keyValue
);
1645 /* Preprare to record the extension by getting its info plist.
1647 driverPlist
= OSDynamicCast(OSDictionary
,
1648 newDriverDict
->getObject("plist"));
1650 IOLog("Error: Extension in device tree entry \"%s\" "
1651 "has no property list.\n", keyValue
);
1657 /* Get the extension's module name. This is used to record
1658 * the extension. Do *not* release the moduleName.
1660 OSString
* moduleName
= OSDynamicCast(OSString
,
1661 driverPlist
->getObject("CFBundleIdentifier"));
1663 IOLog("Error: Device tree entry \"%s\" has "
1664 "no \"CFBundleIdentifier\" property.\n", keyValue
);
1670 /* All has gone well so far, so record the extension under
1671 * its module name, checking for an existing duplicate.
1673 * Do not release moduleName, as it's part of the extension's
1676 OSDictionary
* incumbentExt
= OSDynamicCast(OSDictionary
,
1677 startupExtensions
->getObject(moduleName
));
1679 if (!incumbentExt
) {
1680 startupExtensions
->setObject(moduleName
, newDriverDict
);
1682 OSDictionary
* mostRecentExtension
=
1683 compareExtensionVersions(incumbentExt
, newDriverDict
);
1685 if (mostRecentExtension
== incumbentExt
) {
1686 /* Do nothing, we've got the most recent. */
1687 } else if (mostRecentExtension
== newDriverDict
) {
1688 if (!startupExtensions
->setObject(moduleName
,
1691 /* This is a fatal error, so bail.
1693 IOLog("recordStartupExtensions(): Failed to add "
1695 moduleName
->getCStringNoCopy());
1700 } else /* should be NULL */ {
1702 /* This is a nonfatal error, so continue.
1704 IOLog("recordStartupExtensions(): Error comparing "
1705 "versions of duplicate extensions %s.\n",
1706 moduleName
->getCStringNoCopy());
1713 } else if ( !strncmp(keyValue
, BOOTX_MULTIKEXT_PREFIX
,
1714 strlen(BOOTX_MULTIKEXT_PREFIX
)) ) {
1716 mkextExtensions
= OSDictionary::withCapacity(10);
1717 if (!mkextExtensions
) {
1718 IOLog("Error: Couldn't allocate dictionary to unpack "
1719 "multi-extension archive.\n");
1722 goto finish
; // allocation failure is fatal for this routine
1724 if (!readExtensions(propertyDict
, keyValue
, mkextExtensions
)) {
1725 IOLog("Error: Couldn't unpack multi-extension archive.\n");
1729 if (!mergeExtensionDictionaries(startupExtensions
,
1732 IOLog("Error: Failed to merge new extensions into "
1736 goto finish
; // merge error is fatal for this routine
1741 // Do not release key.
1743 } /* while ( (key = OSDynamicCast(OSString, ...) ) ) */
1745 if (!mergeExtensionDictionaries(existingExtensions
, startupExtensions
)) {
1746 IOLog("Error: Failed to merge new extensions into existing set.\n");
1752 result
= addPersonalities(startupExtensions
);
1754 IOLog("Error: Failed to add personalities for extensions extracted "
1763 // reused so clear first!
1765 keyIterator
->release();
1770 IOLog("Error: Failed to record startup extensions.\n");
1774 keyIterator
= OSCollectionIterator::withCollection(
1778 while ( (key
= OSDynamicCast(OSString
,
1779 keyIterator
->getNextObject())) ) {
1781 IOLog("Found extension \"%s\".\n",
1782 key
->getCStringNoCopy());
1785 keyIterator
->release();
1791 if (newDriverDict
) newDriverDict
->release();
1792 if (propertyDict
) propertyDict
->release();
1793 if (bootxMemoryMap
) bootxMemoryMap
->release();
1794 if (mkextExtensions
) mkextExtensions
->release();
1795 if (startupExtensions
) startupExtensions
->release();
1801 /*********************************************************************
1802 * This function removes an entry from the dictionary of startup
1803 * extensions. It's used when an extension can't be loaded, for
1804 * whatever reason. For drivers, this allows another matching driver
1805 * to be loaded, so that, for example, a driver for the root device
1807 *********************************************************************/
1808 void removeStartupExtension(const char * extensionName
) {
1809 OSDictionary
* startupExtensions
= NULL
; // don't release
1810 OSDictionary
* extensionDict
= NULL
; // don't release
1811 OSDictionary
* extensionPlist
= NULL
; // don't release
1812 OSDictionary
* extensionPersonalities
= NULL
; // don't release
1813 OSDictionary
* personality
= NULL
; // don't release
1814 OSCollectionIterator
* keyIterator
= NULL
; // must release
1815 OSString
* key
= NULL
; // don't release
1817 startupExtensions
= getStartupExtensions();
1818 if (!startupExtensions
) goto finish
;
1821 /* Find the extension's entry in the dictionary of
1822 * startup extensions.
1824 extensionDict
= OSDynamicCast(OSDictionary
,
1825 startupExtensions
->getObject(extensionName
));
1826 if (!extensionDict
) goto finish
;
1828 extensionPlist
= OSDynamicCast(OSDictionary
,
1829 extensionDict
->getObject("plist"));
1830 if (!extensionPlist
) goto finish
;
1832 extensionPersonalities
= OSDynamicCast(OSDictionary
,
1833 extensionPlist
->getObject("IOKitPersonalities"));
1834 if (!extensionPersonalities
) goto finish
;
1836 /* If it was there, remove it from the catalogue proper
1837 * by calling removeDrivers(). Pass true for the second
1838 * argument to trigger a new round of matching, and
1839 * then remove the extension from the dictionary of startup
1842 keyIterator
= OSCollectionIterator::withCollection(
1843 extensionPersonalities
);
1845 IOLog("Error: Couldn't allocate iterator to scan"
1846 " personalities for %s.\n", extensionName
);
1850 while ((key
= OSDynamicCast(OSString
, keyIterator
->getNextObject()))) {
1851 personality
= OSDynamicCast(OSDictionary
,
1852 extensionPersonalities
->getObject(key
));
1856 gIOCatalogue
->removeDrivers(personality
, true);
1860 startupExtensions
->removeObject(extensionName
);
1864 if (keyIterator
) keyIterator
->release();
1868 /*********************************************************************
1869 * FIXME: This function invalidates the globals gStartupExtensions and
1870 * FIXME: ...gBootLoaderObjects without setting them to NULL. Since
1871 * FIXME: ...the code itself is immediately unloaded, there may not be
1872 * FIXME: ...any reason to worry about that!
1873 *********************************************************************/
1874 void clearStartupExtensionsAndLoaderInfo(void)
1876 OSDictionary
* startupExtensions
= NULL
; // must release
1877 OSArray
* bootLoaderObjects
= NULL
; // must release
1879 IORegistryEntry
* bootxMemoryMap
= NULL
; // must release
1880 OSDictionary
* propertyDict
= NULL
; // must release
1881 OSCollectionIterator
* keyIterator
= NULL
; // must release
1882 OSString
* key
= NULL
; // don't release
1885 * Drop any temporarily held data objects.
1887 bootLoaderObjects
= getBootLoaderObjects();
1888 if (bootLoaderObjects
) {
1889 bootLoaderObjects
->release();
1893 * If any "code" entries in driver dictionaries are accompanied
1894 * by "compressedCode" entries, then those data objects were
1895 * created based of of kmem_alloc()'ed memory, which must be
1898 startupExtensions
= getStartupExtensions();
1899 if (startupExtensions
) {
1901 OSCollectionIterator::withCollection(startupExtensions
);
1903 IOLog("Error: Couldn't allocate iterator for startup "
1906 goto memory_map
; // bail to the memory_map label
1909 while ( (key
= OSDynamicCast(OSString
,
1910 keyIterator
->getNextObject())) ) {
1912 OSDictionary
* driverDict
= 0;
1913 OSData
* codeData
= 0;
1915 driverDict
= OSDynamicCast(OSDictionary
,
1916 startupExtensions
->getObject(key
));
1918 codeData
= OSDynamicCast(OSData
,
1919 driverDict
->getObject("code"));
1922 driverDict
->getObject("compressedCode")) {
1924 kmem_free(kernel_map
,
1925 (unsigned int)codeData
->getBytesNoCopy(),
1926 codeData
->getLength());
1931 keyIterator
->release();
1932 startupExtensions
->release();
1938 * Go through the device tree's memory map and remove any driver
1942 IORegistryEntry::fromPath(
1943 "/chosen/memory-map", // path
1946 // return value is retained so be sure to release it
1948 if (!bootxMemoryMap
) {
1949 IOLog("Error: Couldn't read booter memory map.\n");
1954 propertyDict
= bootxMemoryMap
->dictionaryWithProperties();
1955 if (!propertyDict
) {
1956 IOLog("Error: Couldn't get property dictionary "
1957 "from memory map.\n");
1962 keyIterator
= OSCollectionIterator::withCollection(propertyDict
);
1964 IOLog("Error: Couldn't allocate iterator for driver images.\n");
1969 while ( (key
= OSDynamicCast(OSString
,
1970 keyIterator
->getNextObject())) ) {
1972 const char * keyValue
= key
->getCStringNoCopy();
1974 if ( !strncmp(keyValue
, BOOTX_KEXT_PREFIX
,
1975 strlen(BOOTX_KEXT_PREFIX
)) ||
1976 !strncmp(keyValue
, BOOTX_MULTIKEXT_PREFIX
,
1977 strlen(BOOTX_MULTIKEXT_PREFIX
)) ) {
1979 OSData
* bootxDriverDataObject
= NULL
;
1980 MemoryMapFileInfo
* driverInfo
= 0;
1982 bootxDriverDataObject
= OSDynamicCast(OSData
,
1983 propertyDict
->getObject(keyValue
));
1984 // don't release bootxDriverDataObject
1986 if (!bootxDriverDataObject
) {
1989 driverInfo
= (MemoryMapFileInfo
*)
1990 bootxDriverDataObject
->getBytesNoCopy(0,
1991 sizeof(MemoryMapFileInfo
));
1992 IODTFreeLoaderInfo((char *)keyValue
,
1993 (void *)driverInfo
->paddr
,
1994 (int)driverInfo
->length
);
1999 if (bootxMemoryMap
) bootxMemoryMap
->release();
2000 if (propertyDict
) propertyDict
->release();
2001 if (keyIterator
) keyIterator
->release();