2 * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_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. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
28 #include <libkern/c++/OSContainers.h>
29 #include <IOKit/IODeviceTreeSupport.h>
30 #include <IOKit/IORegistryEntry.h>
31 #include <IOKit/IOCatalogue.h>
32 #include <IOKit/IOKitKeysPrivate.h>
33 #include <libkern/c++/OSUnserialize.h>
34 #include <libkern/OSByteOrder.h>
35 #include <libsa/catalogue.h>
38 #include <machine/machine_routines.h>
39 #include <mach/host_info.h>
40 #include <mach/kmod.h>
41 #include <libsa/mkext.h>
42 #include <libsa/vers_rsrc.h>
43 #include <mach-o/loader.h>
46 #include <IOKit/IOLib.h>
48 #include <IOKit/assert.h>
51 extern void IODTFreeLoaderInfo( char *key
, void *infoAddr
, int infoSize
);
52 // extern kern_return_t host_info(host_t host,
53 // host_flavor_t flavor,
55 // mach_msg_type_number_t *count);
56 extern int grade_binary(cpu_type_t exectype
, cpu_subtype_t execsubtype
);
57 // Return the address of the named Mach-O segment from the currently
58 // executing 32 bit kernel, or NULL.
59 extern struct segment_command
*getsegbyname(char *seg_name
);
60 // Return the address of the named section from the named Mach-O segment
61 // from the currently executing 32 bit kernel, or NULL.
62 extern struct section
*getsectbyname(const char *segname
, const char *sectname
);
68 #define VTYELLOW "\033[33m"
69 #define VTRESET "\033[0m"
75 /*********************************************************************
76 *********************************************************************/
77 static OSDictionary
* gStartupExtensions
= 0;
78 static OSArray
* gBootLoaderObjects
= 0;
79 extern OSArray
* gIOPrelinkedModules
;
81 OSDictionary
* getStartupExtensions(void) {
82 if (gStartupExtensions
) {
83 return gStartupExtensions
;
85 gStartupExtensions
= OSDictionary::withCapacity(1);
86 assert (gStartupExtensions
);
88 return gStartupExtensions
;
91 /* This array holds objects that are needed to be held around during
92 * boot before kextd starts up. Currently it contains OSData objects
93 * copied from OF entries for mkext archives in device ROMs. Because
94 * the Device Tree support code dumps these after initially handing
95 * them to us, we have to be able to clean them up later.
97 OSArray
* getBootLoaderObjects(void) {
98 if (gBootLoaderObjects
) {
99 return gBootLoaderObjects
;
101 gBootLoaderObjects
= OSArray::withCapacity(1);
102 assert (gBootLoaderObjects
);
104 return gBootLoaderObjects
;
107 /*********************************************************************
108 * This function checks that a driver dict has all the required
109 * entries and does a little bit of value checking too.
111 * index is nonnegative if the index of an entry from an mkext
113 *********************************************************************/
114 bool validateExtensionDict(OSDictionary
* extension
, int index
) {
117 bool not_a_dict
= false;
118 bool id_missing
= false;
119 bool is_kernel_resource
= false;
120 bool has_executable
= false;
121 bool ineligible_for_safe_boot
= false;
122 OSString
* bundleIdentifier
= NULL
; // do not release
123 OSObject
* rawValue
= NULL
; // do not release
124 OSString
* stringValue
= NULL
; // do not release
125 OSBoolean
* booleanValue
= NULL
; // do not release
126 OSDictionary
* personalities
= NULL
; // do not release
127 OSDictionary
* libraries
= NULL
; // do not release
128 OSCollectionIterator
* keyIterator
= NULL
; // must release
129 OSString
* key
= NULL
; // do not release
131 VERS_version compatible_vers
;
132 char namep
[16]; // unused but needed for PE_parse_boot_arg()
134 // Info dict is a dictionary
135 if (!OSDynamicCast(OSDictionary
, extension
)) {
141 // CFBundleIdentifier is a string - REQUIRED
142 bundleIdentifier
= OSDynamicCast(OSString
,
143 extension
->getObject("CFBundleIdentifier"));
144 if (!bundleIdentifier
) {
150 // Length of CFBundleIdentifier is not >= KMOD_MAX_NAME
151 if (bundleIdentifier
->getLength() >= KMOD_MAX_NAME
) {
156 // CFBundlePackageType is "KEXT" - REQUIRED
157 stringValue
= OSDynamicCast(OSString
,
158 extension
->getObject("CFBundlePackageType"));
163 if (!stringValue
->isEqualTo("KEXT")) {
168 // CFBundleVersion is a string - REQUIRED
169 stringValue
= OSDynamicCast(OSString
,
170 extension
->getObject("CFBundleVersion"));
175 // CFBundleVersion is of valid form
176 vers
= VERS_parse_string(stringValue
->getCStringNoCopy());
182 // OSBundleCompatibleVersion is a string - OPTIONAL
183 rawValue
= extension
->getObject("OSBundleCompatibleVersion");
185 stringValue
= OSDynamicCast(OSString
, rawValue
);
191 // OSBundleCompatibleVersion is of valid form
192 compatible_vers
= VERS_parse_string(stringValue
->getCStringNoCopy());
193 if (compatible_vers
< 0) {
198 // OSBundleCompatibleVersion <= CFBundleVersion
199 if (compatible_vers
> vers
) {
205 // CFBundleExecutable is a string - OPTIONAL
206 rawValue
= extension
->getObject("CFBundleExecutable");
208 stringValue
= OSDynamicCast(OSString
, rawValue
);
209 if (!stringValue
|| stringValue
->getLength() == 0) {
213 has_executable
= true;
216 // OSKernelResource is a boolean value - OPTIONAL
217 rawValue
= extension
->getObject("OSKernelResource");
219 booleanValue
= OSDynamicCast(OSBoolean
, rawValue
);
224 is_kernel_resource
= booleanValue
->isTrue();
227 // IOKitPersonalities is a dictionary - OPTIONAL
228 rawValue
= extension
->getObject("IOKitPersonalities");
230 personalities
= OSDynamicCast(OSDictionary
, rawValue
);
231 if (!personalities
) {
236 keyIterator
= OSCollectionIterator::withCollection(personalities
);
238 IOLog("Error: Failed to allocate iterator for personalities.\n");
244 while ((key
= OSDynamicCast(OSString
, keyIterator
->getNextObject()))) {
245 OSDictionary
* personality
= NULL
; // do not release
247 // Each personality is a dictionary
248 personality
= OSDynamicCast(OSDictionary
,
249 personalities
->getObject(key
));
255 // IOClass exists as a string - REQUIRED
256 if (!OSDynamicCast(OSString
, personality
->getObject("IOClass"))) {
261 // IOProviderClass exists as a string - REQUIRED
262 if (!OSDynamicCast(OSString
,
263 personality
->getObject("IOProviderClass"))) {
269 // CFBundleIdentifier is a string - OPTIONAL - INSERT IF ABSENT!
270 rawValue
= personality
->getObject("CFBundleIdentifier");
272 personality
->setObject("CFBundleIdentifier", bundleIdentifier
);
274 OSString
* personalityID
= NULL
; // do not release
275 personalityID
= OSDynamicCast(OSString
, rawValue
);
276 if (!personalityID
) {
280 // Length of CFBundleIdentifier is not >= KMOD_MAX_NAME
281 if (personalityID
->getLength() >= KMOD_MAX_NAME
) {
288 // IOKitDebug is a number - OPTIONAL
289 rawValue
= personality
->getObject("IOKitDebug");
290 if (rawValue
&& !OSDynamicCast(OSNumber
, rawValue
)) {
296 keyIterator
->release();
301 // OSBundleLibraries is a dictionary - REQUIRED if
302 // not kernel resource & has executable
304 rawValue
= extension
->getObject("OSBundleLibraries");
305 if (!rawValue
&& !is_kernel_resource
&& has_executable
) {
311 libraries
= OSDynamicCast(OSDictionary
, rawValue
);
317 keyIterator
= OSCollectionIterator::withCollection(libraries
);
319 IOLog("Error: Failed to allocate iterator for libraries.\n");
325 while ((key
= OSDynamicCast(OSString
,
326 keyIterator
->getNextObject()))) {
328 OSString
* libraryVersion
= NULL
; // do not release
330 // Each key's length is not >= KMOD_MAX_NAME
331 if (key
->getLength() >= KMOD_MAX_NAME
) {
336 libraryVersion
= OSDynamicCast(OSString
,
337 libraries
->getObject(key
));
338 if (!libraryVersion
) {
343 // Each value is a valid version string
344 vers
= VERS_parse_string(libraryVersion
->getCStringNoCopy());
351 keyIterator
->release();
355 // OSBundleRequired, if present, must have a legal value.
356 // If it is not present and if we are safe-booting,
357 // then the kext is not eligible.
359 rawValue
= extension
->getObject("OSBundleRequired");
361 stringValue
= OSDynamicCast(OSString
, rawValue
);
366 if (!stringValue
->isEqualTo("Root") &&
367 !stringValue
->isEqualTo("Local-Root") &&
368 !stringValue
->isEqualTo("Network-Root") &&
369 !stringValue
->isEqualTo("Safe Boot") &&
370 !stringValue
->isEqualTo("Console")) {
376 } else if (PE_parse_boot_argn("-x", namep
, sizeof (namep
))) { /* safe boot */
377 ineligible_for_safe_boot
= true;
384 if (keyIterator
) keyIterator
->release();
387 if (ineligible_for_safe_boot
) {
388 IOLog(VTYELLOW
"Skipping extension \"%s\" during safe boot "
389 "(no OSBundleRequired property)\n"
391 bundleIdentifier
->getCStringNoCopy());
392 } else if (not_a_dict
) {
394 IOLog(VTYELLOW
"mkext entry %d: " VTRESET
, index
);
396 IOLog(VTYELLOW
"kernel extension " VTRESET
);
398 IOLog(VTYELLOW
"info dictionary isn't a dictionary\n"
400 } else if (id_missing
) {
402 IOLog(VTYELLOW
"mkext entry %d: " VTRESET
, index
);
404 IOLog(VTYELLOW
"kernel extension " VTRESET
);
406 IOLog(VTYELLOW
"\"CFBundleIdentifier\" property is "
407 "missing or not a string\n"
410 IOLog(VTYELLOW
"kernel extension \"%s\": info dictionary is invalid\n"
411 VTRESET
, bundleIdentifier
->getCStringNoCopy());
420 /*********************************************************************
421 *********************************************************************/
422 OSDictionary
* compareExtensionVersions(
423 OSDictionary
* incumbent
,
424 OSDictionary
* candidate
) {
426 OSDictionary
* winner
= NULL
;
428 OSDictionary
* incumbentPlist
= NULL
;
429 OSDictionary
* candidatePlist
= NULL
;
430 OSString
* incumbentName
= NULL
;
431 OSString
* candidateName
= NULL
;
432 OSString
* incumbentVersionString
= NULL
;
433 OSString
* candidateVersionString
= NULL
;
434 VERS_version incumbent_vers
= 0;
435 VERS_version candidate_vers
= 0;
437 incumbentPlist
= OSDynamicCast(OSDictionary
,
438 incumbent
->getObject("plist"));
439 candidatePlist
= OSDynamicCast(OSDictionary
,
440 candidate
->getObject("plist"));
442 if (!incumbentPlist
|| !candidatePlist
) {
443 IOLog("compareExtensionVersions() called with invalid "
444 "extension dictionaries.\n");
450 incumbentName
= OSDynamicCast(OSString
,
451 incumbentPlist
->getObject("CFBundleIdentifier"));
452 candidateName
= OSDynamicCast(OSString
,
453 candidatePlist
->getObject("CFBundleIdentifier"));
454 incumbentVersionString
= OSDynamicCast(OSString
,
455 incumbentPlist
->getObject("CFBundleVersion"));
456 candidateVersionString
= OSDynamicCast(OSString
,
457 candidatePlist
->getObject("CFBundleVersion"));
459 if (!incumbentName
|| !candidateName
||
460 !incumbentVersionString
|| !candidateVersionString
) {
462 IOLog("compareExtensionVersions() called with invalid "
463 "extension dictionaries.\n");
469 if (strcmp(incumbentName
->getCStringNoCopy(),
470 candidateName
->getCStringNoCopy())) {
472 IOLog("compareExtensionVersions() called with different "
473 "extension names (%s and %s).\n",
474 incumbentName
->getCStringNoCopy(),
475 candidateName
->getCStringNoCopy());
481 incumbent_vers
= VERS_parse_string(incumbentVersionString
->getCStringNoCopy());
482 if (incumbent_vers
< 0) {
484 IOLog(VTYELLOW
"Error parsing version string for extension %s (%s)\n"
486 incumbentName
->getCStringNoCopy(),
487 incumbentVersionString
->getCStringNoCopy());
493 candidate_vers
= VERS_parse_string(candidateVersionString
->getCStringNoCopy());
494 if (candidate_vers
< 0) {
496 IOLog(VTYELLOW
"Error parsing version string for extension %s (%s)\n"
498 candidateName
->getCStringNoCopy(),
499 candidateVersionString
->getCStringNoCopy());
505 if (0 == strcmp("com.apple.driver.AppleIntelCPUPowerManagement",
506 incumbentName
->getCStringNoCopy())) {
507 /* Special rules. Always favor version 51.0.0 exactly at the
508 * expense of all other versions newer or older.
510 if(0 == strcmp(incumbentVersionString
->getCStringNoCopy(), "51.0.0")) {
511 IOLog(VTYELLOW
"Skipping duplicate extension \"%s\" with "
512 " version (%s -> %s).\n" VTRESET
,
513 candidateName
->getCStringNoCopy(),
514 candidateVersionString
->getCStringNoCopy(),
515 incumbentVersionString
->getCStringNoCopy());
518 } else if (0 == strcmp(candidateVersionString
->getCStringNoCopy(), "51.0.0")) {
519 IOLog(VTYELLOW
"Skipping duplicate extension \"%s\" with "
520 " version (%s -> %s).\n" VTRESET
,
521 candidateName
->getCStringNoCopy(),
522 incumbentVersionString
->getCStringNoCopy(),
523 candidateVersionString
->getCStringNoCopy());
529 if (candidate_vers
> incumbent_vers
) {
530 IOLog(VTYELLOW
"Replacing extension \"%s\" with newer version "
531 "(%s -> %s).\n" VTRESET
,
532 incumbentName
->getCStringNoCopy(),
533 incumbentVersionString
->getCStringNoCopy(),
534 candidateVersionString
->getCStringNoCopy());
539 IOLog(VTYELLOW
"Skipping duplicate extension \"%s\" with older/same "
540 " version (%s -> %s).\n" VTRESET
,
541 candidateName
->getCStringNoCopy(),
542 candidateVersionString
->getCStringNoCopy(),
543 incumbentVersionString
->getCStringNoCopy());
551 // no cleanup, how nice
556 /*********************************************************************
557 * This function merges entries in the mergeFrom dictionary into the
558 * mergeInto dictionary. If it returns false, the two dictionaries are
559 * not altered. If it returns true, then mergeInto may have new
560 * entries; any keys that were already present in mergeInto are
561 * removed from mergeFrom, so that the caller can see what was
563 *********************************************************************/
564 bool mergeExtensionDictionaries(OSDictionary
* mergeInto
,
565 OSDictionary
* mergeFrom
) {
568 OSDictionary
* mergeIntoCopy
= NULL
; // must release
569 OSDictionary
* mergeFromCopy
= NULL
; // must release
570 OSCollectionIterator
* keyIterator
= NULL
; // must release
571 OSString
* key
; // don't release
573 /* Add 1 to count to guarantee copy can grow (grr).
575 mergeIntoCopy
= OSDictionary::withDictionary(mergeInto
,
576 mergeInto
->getCount() + 1);
577 if (!mergeIntoCopy
) {
578 IOLog("Error: Failed to copy 'into' extensions dictionary "
585 /* Add 1 to count to guarantee copy can grow (grr).
587 mergeFromCopy
= OSDictionary::withDictionary(mergeFrom
,
588 mergeFrom
->getCount() + 1);
589 if (!mergeFromCopy
) {
590 IOLog("Error: Failed to copy 'from' extensions dictionary "
597 keyIterator
= OSCollectionIterator::withCollection(mergeFrom
);
599 IOLog("Error: Failed to allocate iterator for extensions.\n");
607 * Loop through "from" dictionary, checking if the identifier already
608 * exists in the "into" dictionary and checking versions if it does.
610 while ((key
= OSDynamicCast(OSString
, keyIterator
->getNextObject()))) {
611 OSDictionary
* incumbentExt
= OSDynamicCast(OSDictionary
,
612 mergeIntoCopy
->getObject(key
));
613 OSDictionary
* candidateExt
= OSDynamicCast(OSDictionary
,
614 mergeFrom
->getObject(key
));
617 if (!mergeIntoCopy
->setObject(key
, candidateExt
)) {
619 /* This is a fatal error, so bail.
621 IOLog("mergeExtensionDictionaries(): Failed to add "
623 key
->getCStringNoCopy());
629 OSDictionary
* mostRecentExtension
=
630 compareExtensionVersions(incumbentExt
, candidateExt
);
632 if (mostRecentExtension
== incumbentExt
) {
633 mergeFromCopy
->removeObject(key
);
634 } else if (mostRecentExtension
== candidateExt
) {
636 if (!mergeIntoCopy
->setObject(key
, candidateExt
)) {
638 /* This is a fatal error, so bail.
640 IOLog("mergeExtensionDictionaries(): Failed to add "
642 key
->getCStringNoCopy());
647 } else /* should be NULL */ {
649 /* This is a nonfatal error, so continue doing others.
651 IOLog("mergeExtensionDictionaries(): Error comparing "
652 "versions of duplicate extensions %s.\n",
653 key
->getCStringNoCopy());
662 /* If successful, replace the contents of the original
663 * dictionaries with those of the modified copies.
666 mergeInto
->flushCollection();
667 mergeInto
->merge(mergeIntoCopy
);
668 mergeFrom
->flushCollection();
669 mergeFrom
->merge(mergeFromCopy
);
672 if (mergeIntoCopy
) mergeIntoCopy
->release();
673 if (mergeFromCopy
) mergeFromCopy
->release();
674 if (keyIterator
) keyIterator
->release();
681 * These bits are used to parse data made available by bootx.
683 #define BOOTX_KEXT_PREFIX "Driver-"
684 #define BOOTX_MULTIKEXT_PREFIX "DriversPackage-"
686 typedef struct MemoryMapFileInfo
{
691 typedef struct BootxDriverInfo
{
698 typedef struct MkextEntryInfo
{
699 vm_address_t base_address
;
700 mkext_file
* fileinfo
;
704 /*********************************************************************
705 * This private function reads the data for a single extension from
706 * the bootx memory-map's propery dict, returning a dictionary with
707 * keys "plist" for the extension's Info.plist as a parsed OSDictionary
708 * and "code" for the extension's executable code as an OSData.
709 *********************************************************************/
710 OSDictionary
* readExtension(OSDictionary
* propertyDict
,
711 const char * memory_map_name
) {
714 OSData
* bootxDriverDataObject
= NULL
;
715 OSDictionary
* driverPlist
= NULL
;
716 OSString
* driverName
= NULL
;
717 OSData
* driverCode
= NULL
;
718 OSString
* errorString
= NULL
;
719 OSDictionary
* driverDict
= NULL
;
721 const MemoryMapFileInfo
* driverInfo
= 0;
722 BootxDriverInfo
* dataBuffer
;
724 kmod_info_t
* loaded_kmod
= NULL
;
726 bootxDriverDataObject
= OSDynamicCast(OSData
,
727 propertyDict
->getObject(memory_map_name
));
728 // don't release bootxDriverDataObject
730 if (!bootxDriverDataObject
) {
731 IOLog("Error: No driver data object "
732 "for device tree entry \"%s\".\n",
739 driverDict
= OSDictionary::withCapacity(2);
741 IOLog("Error: Couldn't allocate dictionary "
742 "for device tree entry \"%s\".\n", memory_map_name
);
748 driverInfo
= (const MemoryMapFileInfo
*)
749 bootxDriverDataObject
->getBytesNoCopy(0,
750 sizeof(MemoryMapFileInfo
));
751 #if defined (__ppc__) || defined (__arm__)
752 dataBuffer
= (BootxDriverInfo
*)ml_static_ptovirt(driverInfo
->paddr
);
753 #elif defined (__i386__)
754 dataBuffer
= (BootxDriverInfo
*)ml_boot_ptovirt(driverInfo
->paddr
);
755 dataBuffer
->plistAddr
= (char *)ml_boot_ptovirt((vm_address_t
)dataBuffer
->plistAddr
);
756 if (dataBuffer
->moduleAddr
)
757 dataBuffer
->moduleAddr
= (void *)ml_boot_ptovirt((vm_address_t
)dataBuffer
->moduleAddr
);
759 #error unsupported architecture
762 IOLog("Error: No data buffer "
763 "for device tree entry \"%s\".\n", memory_map_name
);
769 driverPlist
= OSDynamicCast(OSDictionary
,
770 OSUnserializeXML(dataBuffer
->plistAddr
, &errorString
));
772 IOLog("Error: Couldn't read XML property list "
773 "for device tree entry \"%s\".\n", memory_map_name
);
776 IOLog("XML parse error: %s.\n",
777 errorString
->getCStringNoCopy());
785 driverName
= OSDynamicCast(OSString
,
786 driverPlist
->getObject("CFBundleIdentifier")); // do not release
788 IOLog("Error: Device tree entry \"%s\" has "
789 "no \"CFBundleIdentifier\" property.\n", memory_map_name
);
795 /* Check if kmod is already loaded and is a real loadable one (has
798 loaded_kmod
= kmod_lookupbyname_locked(driverName
->getCStringNoCopy());
799 if (loaded_kmod
&& loaded_kmod
->address
) {
800 IOLog("Skipping new extension \"%s\"; an extension named "
801 "\"%s\" is already loaded.\n",
802 driverName
->getCStringNoCopy(),
809 if (!validateExtensionDict(driverPlist
, -1)) {
810 // validateExtensionsDict() logs an error
815 driverDict
->setObject("plist", driverPlist
);
817 /* It's perfectly okay for a KEXT to have no executable.
818 * Check that moduleAddr is nonzero before attempting to
821 * NOTE: The driverCode object is created "no-copy", so
822 * it doesn't own that memory. The memory must be freed
823 * separately from the OSData object (see
824 * clearStartupExtensionsAndLoaderInfo() at the end of this file).
826 if (dataBuffer
->moduleAddr
&& dataBuffer
->moduleLength
) {
827 driverCode
= OSData::withBytesNoCopy(dataBuffer
->moduleAddr
,
828 dataBuffer
->moduleLength
);
830 IOLog("Error: Couldn't allocate data object "
831 "to hold code for device tree entry \"%s\".\n",
839 driverDict
->setObject("code", driverCode
);
846 kfree(loaded_kmod
, sizeof(kmod_info_t
));
849 // do not release bootxDriverDataObject
850 // do not release driverName
853 driverPlist
->release();
856 errorString
->release();
859 driverCode
->release();
863 driverDict
->release();
871 /*********************************************************************
872 * Used to uncompress a single file entry in an mkext archive.
874 * The OSData returned does not own its memory! You must deallocate
875 * that memory using kmem_free() before releasing the OSData().
876 *********************************************************************/
877 static bool uncompressFile(u_int8_t
*base_address
, mkext_file
* fileinfo
,
878 /* out */ OSData
** file
) {
881 kern_return_t kern_result
;
882 u_int8_t
* uncompressed_file
= 0; // kmem_free() on error
883 OSData
* uncompressedFile
= 0; // returned
884 size_t uncompressed_size
= 0;
886 size_t offset
= OSSwapBigToHostInt32(fileinfo
->offset
);
887 size_t compsize
= OSSwapBigToHostInt32(fileinfo
->compsize
);
888 size_t realsize
= OSSwapBigToHostInt32(fileinfo
->realsize
);
889 time_t modifiedsecs
= OSSwapBigToHostInt32(fileinfo
->modifiedsecs
);
893 /* If these four fields are zero there's no file, but that isn't
896 if (offset
== 0 && compsize
== 0 &&
897 realsize
== 0 && modifiedsecs
== 0) {
901 // Add 1 for '\0' to terminate XML string!
902 kern_result
= kmem_alloc(kernel_map
, (vm_offset_t
*)&uncompressed_file
,
904 if (kern_result
!= KERN_SUCCESS
) {
905 IOLog("Error: Couldn't allocate data buffer "
906 "to uncompress file.\n");
912 uncompressedFile
= OSData::withBytesNoCopy(uncompressed_file
,
914 if (!uncompressedFile
) {
915 IOLog("Error: Couldn't allocate data object "
916 "to uncompress file.\n");
923 uncompressed_size
= decompress_lzss(uncompressed_file
,
924 base_address
+ offset
,
926 if (uncompressed_size
!= realsize
) {
927 IOLog("Error: Uncompressed file is not the length "
933 uncompressed_file
[uncompressed_size
] = '\0';
935 bcopy(base_address
+ offset
, uncompressed_file
,
937 uncompressed_file
[realsize
] = '\0';
940 *file
= uncompressedFile
;
944 if (uncompressed_file
) {
945 kmem_free(kernel_map
, (vm_address_t
)uncompressed_file
,
948 if (uncompressedFile
) {
949 uncompressedFile
->release();
956 bool uncompressModule(OSData
*compData
, /* out */ OSData
** file
) {
958 const MkextEntryInfo
*info
= (const MkextEntryInfo
*) compData
->getBytesNoCopy();
960 return uncompressFile((u_int8_t
*) info
->base_address
,
961 info
->fileinfo
, file
);
965 /*********************************************************************
966 * Does the work of pulling extensions out of an mkext archive located
968 *********************************************************************/
969 bool extractExtensionsFromArchive(const MemoryMapFileInfo
* mkext_file_info
,
971 OSDictionary
* extensions
) {
975 u_int8_t
* crc_address
= 0;
977 mkext_header
* mkext_data
= 0; // don't free
978 mkext_kext
* onekext_data
= 0; // don't free
979 mkext_file
* plist_file
= 0; // don't free
980 mkext_file
* module_file
= 0; // don't free
981 kmod_info_t
* loaded_kmod
= 0; // must free
983 OSData
* driverPlistDataObject
= 0; // must release
984 OSDictionary
* driverPlist
= 0; // must release
985 OSData
* driverCode
= 0; // must release
986 OSDictionary
* driverDict
= 0; // must release
987 OSString
* moduleName
= 0; // don't release
988 OSString
* errorString
= NULL
; // must release
990 OSData
* moduleInfo
= 0; // must release
991 MkextEntryInfo module_info
;
993 IORegistryEntry
* root
;
994 OSData
* checksumObj
;
997 // addExtensionsFromArchive passes a kernel virtual address
998 mkext_data
= (mkext_header
*)mkext_file_info
->paddr
;
1000 #if defined (__ppc__) || defined (__arm__)
1001 mkext_data
= (mkext_header
*)ml_static_ptovirt(mkext_file_info
->paddr
);
1002 #elif defined (__i386__)
1003 mkext_data
= (mkext_header
*)ml_boot_ptovirt(mkext_file_info
->paddr
);
1005 #error unsupported architecture
1009 if (OSSwapBigToHostInt32(mkext_data
->magic
) != MKEXT_MAGIC
||
1010 OSSwapBigToHostInt32(mkext_data
->signature
) != MKEXT_SIGN
) {
1011 IOLog("Error: Extension archive has invalid magic or signature.\n");
1017 if (OSSwapBigToHostInt32(mkext_data
->length
) != mkext_file_info
->length
) {
1018 IOLog("Error: Mismatch between extension archive & "
1019 "recorded length.\n");
1025 crc_address
= (u_int8_t
*)&mkext_data
->version
;
1026 checksum
= adler32(crc_address
,
1027 (unsigned int)mkext_data
+
1028 OSSwapBigToHostInt32(mkext_data
->length
) - (unsigned int)crc_address
);
1030 if (OSSwapBigToHostInt32(mkext_data
->adler32
) != checksum
) {
1031 IOLog("Error: Extension archive has a bad checksum.\n");
1037 root
= IORegistryEntry::getRegistryRoot();
1039 checksumObj
= OSData::withBytes((void *)&checksum
,
1041 assert(checksumObj
);
1043 root
->setProperty(kIOStartupMkextCRC
, checksumObj
);
1044 checksumObj
->release();
1047 /* If the MKEXT archive isn't fat, check that the CPU type & subtype
1048 * match that of the running kernel.
1050 if (OSSwapBigToHostInt32(mkext_data
->cputype
) != (UInt32
)CPU_TYPE_ANY
) {
1051 kern_return_t kresult
= KERN_FAILURE
;
1052 host_basic_info_data_t hostinfo
;
1053 host_info_t hostinfo_ptr
= (host_info_t
)&hostinfo
;
1054 mach_msg_type_number_t count
= sizeof(hostinfo
)/sizeof(integer_t
);
1056 kresult
= host_info((host_t
)1, HOST_BASIC_INFO
,
1057 hostinfo_ptr
, &count
);
1058 if (kresult
!= KERN_SUCCESS
) {
1059 IOLog("Error: Couldn't get current host info.\n");
1064 if ((UInt32
)hostinfo
.cpu_type
!=
1065 OSSwapBigToHostInt32(mkext_data
->cputype
)) {
1067 IOLog("Error: Extension archive doesn't contain software "
1068 "for this computer's CPU type.\n");
1073 if (!grade_binary(OSSwapBigToHostInt32(mkext_data
->cputype
),
1074 OSSwapBigToHostInt32(mkext_data
->cpusubtype
))) {
1075 IOLog("Error: Extension archive doesn't contain software "
1076 "for this computer's CPU subtype.\n");
1083 for (unsigned int i
= 0;
1084 i
< OSSwapBigToHostInt32(mkext_data
->numkexts
);
1088 kfree(loaded_kmod
, sizeof(kmod_info_t
));
1092 if (driverPlistDataObject
) {
1093 kmem_free(kernel_map
,
1094 (unsigned int)driverPlistDataObject
->getBytesNoCopy(),
1095 driverPlistDataObject
->getLength());
1097 driverPlistDataObject
->release();
1098 driverPlistDataObject
= NULL
;
1101 driverPlist
->release();
1105 driverCode
->release();
1109 driverDict
->release();
1113 errorString
->release();
1117 onekext_data
= &mkext_data
->kext
[i
];
1118 plist_file
= &onekext_data
->plist
;
1119 module_file
= &onekext_data
->module;
1121 if (!uncompressFile((u_int8_t
*)mkext_data
, plist_file
,
1122 &driverPlistDataObject
)) {
1124 IOLog("Error: couldn't uncompress plist file "
1125 "from multikext archive entry %d.\n", i
);
1130 if (!driverPlistDataObject
) {
1131 IOLog("Error: No property list present "
1132 "for multikext archive entry %d.\n", i
);
1136 driverPlist
= OSDynamicCast(OSDictionary
,
1138 (const char *)driverPlistDataObject
->getBytesNoCopy(),
1141 IOLog("Error: Couldn't read XML property list "
1142 "for multikext archive entry %d.\n", i
);
1145 IOLog("XML parse error: %s.\n",
1146 errorString
->getCStringNoCopy());
1152 if (!validateExtensionDict(driverPlist
, i
)) {
1153 // validateExtensionsDict() logs an error
1159 /* Get the extension's module name. This is used to record
1162 moduleName
= OSDynamicCast(OSString
,
1163 driverPlist
->getObject("CFBundleIdentifier")); // do not release
1165 IOLog("Error: Multikext archive entry %d has "
1166 "no \"CFBundleIdentifier\" property.\n", i
);
1168 continue; // assume a kext config error & continue
1171 /* Check if kmod is already loaded and is a real loadable one (has
1174 loaded_kmod
= kmod_lookupbyname_locked(moduleName
->getCStringNoCopy());
1175 if (loaded_kmod
&& loaded_kmod
->address
) {
1176 IOLog("Skipping new extension \"%s\"; an extension named "
1177 "\"%s\" is already loaded.\n",
1178 moduleName
->getCStringNoCopy(),
1184 driverDict
= OSDictionary::withCapacity(2);
1186 IOLog("Error: Couldn't allocate dictionary "
1187 "for multikext archive entry %d.\n", i
);
1193 driverDict
->setObject("plist", driverPlist
);
1196 * Prepare an entry to hold the mkext entry info for the
1197 * compressed binary module, if there is one. If all four fields
1198 * of the module entry are zero, there isn't one.
1200 if (!(loaded_kmod
&& loaded_kmod
->address
) && (OSSwapBigToHostInt32(module_file
->offset
) ||
1201 OSSwapBigToHostInt32(module_file
->compsize
) ||
1202 OSSwapBigToHostInt32(module_file
->realsize
) ||
1203 OSSwapBigToHostInt32(module_file
->modifiedsecs
))) {
1205 moduleInfo
= OSData::withCapacity(sizeof(MkextEntryInfo
));
1207 IOLog("Error: Couldn't allocate data object "
1208 "for multikext archive entry %d.\n", i
);
1214 module_info
.base_address
= (vm_address_t
)mkext_data
;
1215 module_info
.fileinfo
= module_file
;
1217 if (!moduleInfo
->appendBytes(&module_info
, sizeof(module_info
))) {
1218 IOLog("Error: Couldn't record info "
1219 "for multikext archive entry %d.\n", i
);
1225 driverDict
->setObject("compressedCode", moduleInfo
);
1228 OSDictionary
* incumbentExt
= OSDynamicCast(OSDictionary
,
1229 extensions
->getObject(moduleName
));
1231 if (!incumbentExt
) {
1232 extensions
->setObject(moduleName
, driverDict
);
1234 OSDictionary
* mostRecentExtension
=
1235 compareExtensionVersions(incumbentExt
, driverDict
);
1237 if (mostRecentExtension
== incumbentExt
) {
1238 /* Do nothing, we've got the most recent. */
1239 } else if (mostRecentExtension
== driverDict
) {
1240 if (!extensions
->setObject(moduleName
, driverDict
)) {
1242 /* This is a fatal error, so bail.
1244 IOLog("extractExtensionsFromArchive(): Failed to add "
1246 moduleName
->getCStringNoCopy());
1251 } else /* should be NULL */ {
1253 /* This is a nonfatal error, so continue.
1255 IOLog("extractExtensionsFromArchive(): Error comparing "
1256 "versions of duplicate extensions %s.\n",
1257 moduleName
->getCStringNoCopy());
1266 if (loaded_kmod
) kfree(loaded_kmod
, sizeof(kmod_info_t
));
1267 if (driverPlistDataObject
) {
1268 kmem_free(kernel_map
,
1269 (unsigned int)driverPlistDataObject
->getBytesNoCopy(),
1270 driverPlistDataObject
->getLength());
1271 driverPlistDataObject
->release();
1273 if (driverPlist
) driverPlist
->release();
1274 if (driverCode
) driverCode
->release();
1275 if (moduleInfo
) moduleInfo
->release();
1276 if (driverDict
) driverDict
->release();
1277 if (errorString
) errorString
->release();
1282 /*********************************************************************
1284 *********************************************************************/
1285 bool readExtensions(OSDictionary
* propertyDict
,
1286 const char * memory_map_name
,
1287 OSDictionary
* extensions
) {
1290 OSData
* mkextDataObject
= 0; // don't release
1291 const MemoryMapFileInfo
* mkext_file_info
= 0; // don't free
1293 mkextDataObject
= OSDynamicCast(OSData
,
1294 propertyDict
->getObject(memory_map_name
));
1295 // don't release mkextDataObject
1297 if (!mkextDataObject
) {
1298 IOLog("Error: No mkext data object "
1299 "for device tree entry \"%s\".\n",
1306 mkext_file_info
= (const MemoryMapFileInfo
*)mkextDataObject
->getBytesNoCopy();
1307 if (!mkext_file_info
) {
1312 result
= extractExtensionsFromArchive(mkext_file_info
, false /*physical*/, extensions
);
1316 if (!result
&& extensions
) {
1317 extensions
->flushCollection();
1324 /*********************************************************************
1325 * Adds the personalities for an extensions dictionary to the global
1327 *********************************************************************/
1328 bool addPersonalities(OSDictionary
* extensions
) {
1330 OSCollectionIterator
* keyIterator
= NULL
; // must release
1331 OSString
* key
; // don't release
1332 OSDictionary
* driverDict
= NULL
; // don't release
1333 OSDictionary
* driverPlist
= NULL
; // don't release
1334 OSDictionary
* thisDriverPersonalities
= NULL
; // don't release
1335 OSArray
* allDriverPersonalities
= NULL
; // must release
1337 allDriverPersonalities
= OSArray::withCapacity(1);
1338 if (!allDriverPersonalities
) {
1339 IOLog("Error: Couldn't allocate personality dictionary.\n");
1345 /* Record all personalities found so that they can be
1346 * added to the catalogue.
1347 * Note: Not all extensions have personalities.
1350 keyIterator
= OSCollectionIterator::withCollection(extensions
);
1352 IOLog("Error: Couldn't allocate iterator to record personalities.\n");
1358 while ( ( key
= OSDynamicCast(OSString
,
1359 keyIterator
->getNextObject() ))) {
1361 driverDict
= OSDynamicCast(OSDictionary
,
1362 extensions
->getObject(key
));
1363 driverPlist
= OSDynamicCast(OSDictionary
,
1364 driverDict
->getObject("plist"));
1365 thisDriverPersonalities
= OSDynamicCast(OSDictionary
,
1366 driverPlist
->getObject("IOKitPersonalities"));
1368 if (thisDriverPersonalities
) {
1369 OSCollectionIterator
* pIterator
;
1370 OSString
* locakKey
;
1371 pIterator
= OSCollectionIterator::withCollection(
1372 thisDriverPersonalities
);
1374 IOLog("Error: Couldn't allocate iterator "
1375 "to record extension personalities.\n");
1379 while ( (locakKey
= OSDynamicCast(OSString
,
1380 pIterator
->getNextObject())) ) {
1382 OSDictionary
* personality
= OSDynamicCast(
1384 thisDriverPersonalities
->getObject(locakKey
));
1386 allDriverPersonalities
->setObject(personality
);
1389 pIterator
->release();
1391 } /* extract personalities */
1394 /* Add all personalities found to the IOCatalogue,
1395 * but don't start matching.
1397 gIOCatalogue
->addDrivers(allDriverPersonalities
, false);
1401 if (allDriverPersonalities
) allDriverPersonalities
->release();
1402 if (keyIterator
) keyIterator
->release();
1408 /*********************************************************************
1409 * Called from IOCatalogue to add extensions from an mkext archive.
1410 * This function makes a copy of the mkext object passed in because
1411 * the device tree support code dumps it after calling us (indirectly
1412 * through the IOCatalogue).
1413 *********************************************************************/
1414 bool addExtensionsFromArchive(OSData
* mkextDataObject
) {
1417 OSDictionary
* startupExtensions
= NULL
; // don't release
1418 OSArray
* bootLoaderObjects
= NULL
; // don't release
1419 OSDictionary
* extensions
= NULL
; // must release
1420 MemoryMapFileInfo mkext_file_info
;
1421 OSCollectionIterator
* keyIterator
= NULL
; // must release
1422 OSString
* key
= NULL
; // don't release
1424 startupExtensions
= getStartupExtensions();
1425 if (!startupExtensions
) {
1426 IOLog("Can't record extension archive; there is no"
1427 " extensions dictionary.\n");
1433 bootLoaderObjects
= getBootLoaderObjects();
1434 if (! bootLoaderObjects
) {
1435 IOLog("Error: Couldn't allocate array to hold temporary objects.\n");
1441 extensions
= OSDictionary::withCapacity(2);
1443 IOLog("Error: Couldn't allocate dictionary to unpack "
1444 "extension archive.\n");
1450 mkext_file_info
.paddr
= (UInt32
)mkextDataObject
->getBytesNoCopy();
1451 mkext_file_info
.length
= mkextDataObject
->getLength();
1453 /* Save the local mkext data object so that we can deallocate it later.
1455 bootLoaderObjects
->setObject(mkextDataObject
);
1457 result
= extractExtensionsFromArchive(&mkext_file_info
, true /*virtual*/, extensions
);
1459 IOLog("Error: Failed to extract extensions from archive.\n");
1465 result
= mergeExtensionDictionaries(startupExtensions
, extensions
);
1467 IOLog("Error: Failed to merge new extensions into existing set.\n");
1472 result
= addPersonalities(extensions
);
1474 IOLog("Error: Failed to add personalities for extensions extracted "
1484 IOLog("Error: Failed to record extensions from archive.\n");
1487 keyIterator
= OSCollectionIterator::withCollection(
1491 while ( (key
= OSDynamicCast(OSString
,
1492 keyIterator
->getNextObject())) ) {
1494 IOLog("Added extension \"%s\" from archive.\n",
1495 key
->getCStringNoCopy());
1498 keyIterator
->release();
1502 if (extensions
) extensions
->release();
1508 /*********************************************************************
1509 * This function builds dictionaries for the startup extensions
1510 * put into memory by bootx, recording each in the startup extensions
1511 * dictionary. The dictionary format is this:
1514 * "plist" = (the extension's Info.plist as an OSDictionary)
1515 * "code" = (an OSData containing the executable file)
1518 * This function returns true if any extensions were found and
1519 * recorded successfully, or if there are no start extensions,
1520 * and false if an unrecoverable error occurred. An error reading
1521 * a single extension is not considered fatal, and this function
1522 * will simply skip the problematic extension to try the next one.
1523 *********************************************************************/
1525 bool recordStartupExtensions(void) {
1527 OSDictionary
* startupExtensions
= NULL
; // must release
1528 OSDictionary
* existingExtensions
= NULL
; // don't release
1529 OSDictionary
* mkextExtensions
= NULL
; // must release
1530 IORegistryEntry
* bootxMemoryMap
= NULL
; // must release
1531 OSDictionary
* propertyDict
= NULL
; // must release
1532 OSCollectionIterator
* keyIterator
= NULL
; // must release
1533 OSString
* key
= NULL
; // don't release
1535 OSDictionary
* newDriverDict
= NULL
; // must release
1536 OSDictionary
* driverPlist
= NULL
; // don't release
1538 struct section
* infosect
;
1539 struct section
* symsect
;
1540 unsigned int prelinkedCount
= 0;
1542 existingExtensions
= getStartupExtensions();
1543 if (!existingExtensions
) {
1544 IOLog("Error: There is no dictionary for startup extensions.\n");
1550 startupExtensions
= OSDictionary::withCapacity(1);
1551 if (!startupExtensions
) {
1552 IOLog("Error: Couldn't allocate dictionary "
1553 "to record startup extensions.\n");
1560 // add any prelinked modules as startup extensions
1562 infosect
= getsectbyname("__PRELINK", "__info");
1563 symsect
= getsectbyname("__PRELINK", "__symtab");
1564 if (infosect
&& infosect
->addr
&& infosect
->size
1565 && symsect
&& symsect
->addr
&& symsect
->size
) do
1567 gIOPrelinkedModules
= OSDynamicCast(OSArray
,
1568 OSUnserializeXML((const char *) infosect
->addr
, NULL
));
1570 if (!gIOPrelinkedModules
)
1572 for( unsigned int idx
= 0;
1573 (propertyDict
= OSDynamicCast(OSDictionary
, gIOPrelinkedModules
->getObject(idx
)));
1576 enum { kPrelinkReservedCount
= 4 };
1578 /* Get the extension's module name. This is used to record
1579 * the extension. Do *not* release the moduleName.
1581 OSString
* moduleName
= OSDynamicCast(OSString
,
1582 propertyDict
->getObject("CFBundleIdentifier"));
1584 IOLog("Error: Prelinked module entry has "
1585 "no \"CFBundleIdentifier\" property.\n");
1590 /* Add the kext, & its plist.
1592 newDriverDict
= OSDictionary::withCapacity(4);
1593 assert(newDriverDict
);
1594 newDriverDict
->setObject("plist", propertyDict
);
1595 startupExtensions
->setObject(moduleName
, newDriverDict
);
1596 newDriverDict
->release();
1598 /* Add the code if present.
1600 OSData
* data
= OSDynamicCast(OSData
, propertyDict
->getObject("OSBundlePrelink"));
1602 if (data
->getLength() < (kPrelinkReservedCount
* sizeof(UInt32
))) {
1603 IOLog("Error: Prelinked module entry has "
1604 "invalid \"OSBundlePrelink\" property.\n");
1608 const UInt32
* prelink
;
1609 prelink
= (const UInt32
*) data
->getBytesNoCopy();
1610 kmod_info_t
* kmod_info
= (kmod_info_t
*) OSReadBigInt32(prelink
, 0);
1611 // end of "file" is end of symbol sect
1612 data
= OSData::withBytesNoCopy((void *) kmod_info
->address
,
1613 symsect
->addr
+ symsect
->size
- kmod_info
->address
);
1614 newDriverDict
->setObject("code", data
);
1619 /* Add the symbols if present.
1621 OSNumber
* num
= OSDynamicCast(OSNumber
, propertyDict
->getObject("OSBundlePrelinkSymbols"));
1623 UInt32 offset
= num
->unsigned32BitValue();
1624 data
= OSData::withBytesNoCopy((void *) (symsect
->addr
+ offset
), symsect
->size
- offset
);
1625 newDriverDict
->setObject("code", data
);
1631 if (gIOPrelinkedModules
)
1632 IOLog("%d prelinked modules\n", prelinkedCount
);
1636 virt
= ml_static_ptovirt(infosect
->addr
);
1638 ml_static_mfree(virt
, infosect
->size
);
1640 newDriverDict
= NULL
;
1646 IORegistryEntry::fromPath(
1647 "/chosen/memory-map", // path
1650 // return value is retained so be sure to release it
1652 if (!bootxMemoryMap
) {
1653 IOLog("Error: Couldn't read booter memory map.\n");
1659 propertyDict
= bootxMemoryMap
->dictionaryWithProperties();
1660 if (!propertyDict
) {
1661 IOLog("Error: Couldn't get property dictionary "
1662 "from memory map.\n");
1668 keyIterator
= OSCollectionIterator::withCollection(propertyDict
);
1670 IOLog("Error: Couldn't allocate iterator for driver images.\n");
1676 while ( (key
= OSDynamicCast(OSString
,
1677 keyIterator
->getNextObject())) ) {
1678 /* Clear newDriverDict & mkextExtensions upon entry to the loop,
1679 * handling both successful and unsuccessful iterations.
1681 if (newDriverDict
) {
1682 newDriverDict
->release();
1683 newDriverDict
= NULL
;
1685 if (mkextExtensions
) {
1686 mkextExtensions
->release();
1687 mkextExtensions
= NULL
;
1690 const char * keyValue
= key
->getCStringNoCopy();
1692 if ( !strncmp(keyValue
, BOOTX_KEXT_PREFIX
,
1693 strlen(BOOTX_KEXT_PREFIX
)) ) {
1695 /* Read the extension from the bootx-supplied memory.
1697 newDriverDict
= readExtension(propertyDict
, keyValue
);
1698 if (!newDriverDict
) {
1699 IOLog("Error: Couldn't read data "
1700 "for device tree entry \"%s\".\n", keyValue
);
1706 /* Preprare to record the extension by getting its info plist.
1708 driverPlist
= OSDynamicCast(OSDictionary
,
1709 newDriverDict
->getObject("plist"));
1711 IOLog("Error: Extension in device tree entry \"%s\" "
1712 "has no property list.\n", keyValue
);
1718 /* Get the extension's module name. This is used to record
1719 * the extension. Do *not* release the moduleName.
1721 OSString
* moduleName
= OSDynamicCast(OSString
,
1722 driverPlist
->getObject("CFBundleIdentifier"));
1724 IOLog("Error: Device tree entry \"%s\" has "
1725 "no \"CFBundleIdentifier\" property.\n", keyValue
);
1731 /* All has gone well so far, so record the extension under
1732 * its module name, checking for an existing duplicate.
1734 * Do not release moduleName, as it's part of the extension's
1737 OSDictionary
* incumbentExt
= OSDynamicCast(OSDictionary
,
1738 startupExtensions
->getObject(moduleName
));
1740 if (!incumbentExt
) {
1741 startupExtensions
->setObject(moduleName
, newDriverDict
);
1743 OSDictionary
* mostRecentExtension
=
1744 compareExtensionVersions(incumbentExt
, newDriverDict
);
1746 if (mostRecentExtension
== incumbentExt
) {
1747 /* Do nothing, we've got the most recent. */
1748 } else if (mostRecentExtension
== newDriverDict
) {
1749 if (!startupExtensions
->setObject(moduleName
,
1752 /* This is a fatal error, so bail.
1754 IOLog("recordStartupExtensions(): Failed to add "
1756 moduleName
->getCStringNoCopy());
1761 } else /* should be NULL */ {
1763 /* This is a nonfatal error, so continue.
1765 IOLog("recordStartupExtensions(): Error comparing "
1766 "versions of duplicate extensions %s.\n",
1767 moduleName
->getCStringNoCopy());
1774 } else if ( !strncmp(keyValue
, BOOTX_MULTIKEXT_PREFIX
,
1775 strlen(BOOTX_MULTIKEXT_PREFIX
)) ) {
1777 mkextExtensions
= OSDictionary::withCapacity(10);
1778 if (!mkextExtensions
) {
1779 IOLog("Error: Couldn't allocate dictionary to unpack "
1780 "multi-extension archive.\n");
1783 goto finish
; // allocation failure is fatal for this routine
1785 if (!readExtensions(propertyDict
, keyValue
, mkextExtensions
)) {
1786 IOLog("Error: Couldn't unpack multi-extension archive.\n");
1790 if (!mergeExtensionDictionaries(startupExtensions
,
1793 IOLog("Error: Failed to merge new extensions into "
1797 goto finish
; // merge error is fatal for this routine
1802 // Do not release key.
1804 } /* while ( (key = OSDynamicCast(OSString, ...) ) ) */
1806 if (!mergeExtensionDictionaries(existingExtensions
, startupExtensions
)) {
1807 IOLog("Error: Failed to merge new extensions into existing set.\n");
1813 result
= addPersonalities(startupExtensions
);
1815 IOLog("Error: Failed to add personalities for extensions extracted "
1824 // reused so clear first!
1826 keyIterator
->release();
1831 IOLog("Error: Failed to record startup extensions.\n");
1835 keyIterator
= OSCollectionIterator::withCollection(
1839 while ( (key
= OSDynamicCast(OSString
,
1840 keyIterator
->getNextObject())) ) {
1842 IOLog("Found extension \"%s\".\n",
1843 key
->getCStringNoCopy());
1846 keyIterator
->release();
1852 if (newDriverDict
) newDriverDict
->release();
1853 if (propertyDict
) propertyDict
->release();
1854 if (bootxMemoryMap
) bootxMemoryMap
->release();
1855 if (mkextExtensions
) mkextExtensions
->release();
1856 if (startupExtensions
) startupExtensions
->release();
1862 /*********************************************************************
1863 * This function removes an entry from the dictionary of startup
1864 * extensions. It's used when an extension can't be loaded, for
1865 * whatever reason. For drivers, this allows another matching driver
1866 * to be loaded, so that, for example, a driver for the root device
1868 *********************************************************************/
1869 void removeStartupExtension(const char * extensionName
) {
1870 OSDictionary
* startupExtensions
= NULL
; // don't release
1871 OSDictionary
* extensionDict
= NULL
; // don't release
1872 OSDictionary
* extensionPlist
= NULL
; // don't release
1873 OSDictionary
* extensionPersonalities
= NULL
; // don't release
1874 OSDictionary
* personality
= NULL
; // don't release
1875 OSCollectionIterator
* keyIterator
= NULL
; // must release
1876 OSString
* key
= NULL
; // don't release
1878 startupExtensions
= getStartupExtensions();
1879 if (!startupExtensions
) goto finish
;
1882 /* Find the extension's entry in the dictionary of
1883 * startup extensions.
1885 extensionDict
= OSDynamicCast(OSDictionary
,
1886 startupExtensions
->getObject(extensionName
));
1887 if (!extensionDict
) goto finish
;
1889 extensionPlist
= OSDynamicCast(OSDictionary
,
1890 extensionDict
->getObject("plist"));
1891 if (!extensionPlist
) goto finish
;
1893 extensionPersonalities
= OSDynamicCast(OSDictionary
,
1894 extensionPlist
->getObject("IOKitPersonalities"));
1895 if (!extensionPersonalities
) goto finish
;
1897 /* If it was there, remove it from the catalogue proper
1898 * by calling removeDrivers(). Pass true for the second
1899 * argument to trigger a new round of matching, and
1900 * then remove the extension from the dictionary of startup
1903 keyIterator
= OSCollectionIterator::withCollection(
1904 extensionPersonalities
);
1906 IOLog("Error: Couldn't allocate iterator to scan"
1907 " personalities for %s.\n", extensionName
);
1911 while ((key
= OSDynamicCast(OSString
, keyIterator
->getNextObject()))) {
1912 personality
= OSDynamicCast(OSDictionary
,
1913 extensionPersonalities
->getObject(key
));
1917 gIOCatalogue
->removeDrivers(personality
, true);
1921 startupExtensions
->removeObject(extensionName
);
1925 if (keyIterator
) keyIterator
->release();
1929 /*********************************************************************
1930 * FIXME: This function invalidates the globals gStartupExtensions and
1931 * FIXME: ...gBootLoaderObjects without setting them to NULL. Since
1932 * FIXME: ...the code itself is immediately unloaded, there may not be
1933 * FIXME: ...any reason to worry about that!
1934 *********************************************************************/
1935 void clearStartupExtensionsAndLoaderInfo(void)
1937 OSDictionary
* startupExtensions
= NULL
; // must release
1938 OSArray
* bootLoaderObjects
= NULL
; // must release
1940 IORegistryEntry
* bootxMemoryMap
= NULL
; // must release
1941 OSDictionary
* propertyDict
= NULL
; // must release
1942 OSCollectionIterator
* keyIterator
= NULL
; // must release
1943 OSString
* key
= NULL
; // don't release
1946 * Drop any temporarily held data objects.
1948 bootLoaderObjects
= getBootLoaderObjects();
1949 if (bootLoaderObjects
) {
1950 bootLoaderObjects
->release();
1954 * If any "code" entries in driver dictionaries are accompanied
1955 * by "compressedCode" entries, then those data objects were
1956 * created based of of kmem_alloc()'ed memory, which must be
1959 startupExtensions
= getStartupExtensions();
1960 if (startupExtensions
) {
1962 OSCollectionIterator::withCollection(startupExtensions
);
1964 IOLog("Error: Couldn't allocate iterator for startup "
1967 goto memory_map
; // bail to the memory_map label
1970 while ( (key
= OSDynamicCast(OSString
,
1971 keyIterator
->getNextObject())) ) {
1973 OSDictionary
* driverDict
= 0;
1974 OSData
* codeData
= 0;
1976 driverDict
= OSDynamicCast(OSDictionary
,
1977 startupExtensions
->getObject(key
));
1979 codeData
= OSDynamicCast(OSData
,
1980 driverDict
->getObject("code"));
1983 driverDict
->getObject("compressedCode")) {
1985 kmem_free(kernel_map
,
1986 (unsigned int)codeData
->getBytesNoCopy(),
1987 codeData
->getLength());
1992 keyIterator
->release();
1993 startupExtensions
->release();
1999 * Go through the device tree's memory map and remove any driver
2003 IORegistryEntry::fromPath(
2004 "/chosen/memory-map", // path
2007 // return value is retained so be sure to release it
2009 if (!bootxMemoryMap
) {
2010 IOLog("Error: Couldn't read booter memory map.\n");
2015 propertyDict
= bootxMemoryMap
->dictionaryWithProperties();
2016 if (!propertyDict
) {
2017 IOLog("Error: Couldn't get property dictionary "
2018 "from memory map.\n");
2023 keyIterator
= OSCollectionIterator::withCollection(propertyDict
);
2025 IOLog("Error: Couldn't allocate iterator for driver images.\n");
2030 while ( (key
= OSDynamicCast(OSString
,
2031 keyIterator
->getNextObject())) ) {
2033 const char * keyValue
= key
->getCStringNoCopy();
2035 if ( !strncmp(keyValue
, BOOTX_KEXT_PREFIX
,
2036 strlen(BOOTX_KEXT_PREFIX
)) ||
2037 !strncmp(keyValue
, BOOTX_MULTIKEXT_PREFIX
,
2038 strlen(BOOTX_MULTIKEXT_PREFIX
)) ) {
2040 OSData
* bootxDriverDataObject
= NULL
;
2041 const MemoryMapFileInfo
* driverInfo
= 0;
2043 bootxDriverDataObject
= OSDynamicCast(OSData
,
2044 propertyDict
->getObject(keyValue
));
2045 // don't release bootxDriverDataObject
2047 if (!bootxDriverDataObject
) {
2050 driverInfo
= (const MemoryMapFileInfo
*)
2051 bootxDriverDataObject
->getBytesNoCopy(0,
2052 sizeof(MemoryMapFileInfo
));
2053 IODTFreeLoaderInfo((char *)keyValue
,
2054 (void *)driverInfo
->paddr
,
2055 (int)driverInfo
->length
);
2060 if (bootxMemoryMap
) bootxMemoryMap
->release();
2061 if (propertyDict
) propertyDict
->release();
2062 if (keyIterator
) keyIterator
->release();