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 <IOKit/IOKitKeysPrivate.h>
27 #include <libkern/c++/OSUnserialize.h>
28 #include <libkern/OSByteOrder.h>
29 #include <libsa/catalogue.h>
32 #include <machine/machine_routines.h>
33 #include <mach/host_info.h>
34 #include <mach/kmod.h>
35 #include <libsa/mkext.h>
36 #include <libsa/vers_rsrc.h>
37 #include <mach-o/loader.h>
40 #include <IOKit/IOLib.h>
42 #include <IOKit/assert.h>
45 extern void IODTFreeLoaderInfo( char *key
, void *infoAddr
, int infoSize
);
46 // extern kern_return_t host_info(host_t host,
47 // host_flavor_t flavor,
49 // mach_msg_type_number_t *count);
50 extern int grade_binary(cpu_type_t exectype
, cpu_subtype_t execsubtype
);
51 // Return the address of the named Mach-O segment from the currently
52 // executing 32 bit kernel, or NULL.
53 extern struct segment_command
*getsegbyname(char *seg_name
);
54 // Return the address of the named section from the named Mach-O segment
55 // from the currently executing 32 bit kernel, or NULL.
56 extern struct section
*getsectbyname(char *segname
, char *sectname
);
62 #define VTYELLOW "\033[33m"
63 #define VTRESET "\033[0m"
69 /*********************************************************************
70 *********************************************************************/
71 static OSDictionary
* gStartupExtensions
= 0;
72 static OSArray
* gBootLoaderObjects
= 0;
73 extern OSArray
* gIOPrelinkedModules
;
75 OSDictionary
* getStartupExtensions(void) {
76 if (gStartupExtensions
) {
77 return gStartupExtensions
;
79 gStartupExtensions
= OSDictionary::withCapacity(1);
80 assert (gStartupExtensions
);
82 return gStartupExtensions
;
85 /* This array holds objects that are needed to be held around during
86 * boot before kextd starts up. Currently it contains OSData objects
87 * copied from OF entries for mkext archives in device ROMs. Because
88 * the Device Tree support code dumps these after initially handing
89 * them to us, we have to be able to clean them up later.
91 OSArray
* getBootLoaderObjects(void) {
92 if (gBootLoaderObjects
) {
93 return gBootLoaderObjects
;
95 gBootLoaderObjects
= OSArray::withCapacity(1);
96 assert (gBootLoaderObjects
);
98 return gBootLoaderObjects
;
101 /*********************************************************************
102 * This function checks that a driver dict has all the required
103 * entries and does a little bit of value checking too.
105 * index is nonnegative if the index of an entry from an mkext
107 *********************************************************************/
108 bool validateExtensionDict(OSDictionary
* extension
, int index
) {
111 bool not_a_dict
= false;
112 bool id_missing
= false;
113 bool is_kernel_resource
= false;
114 bool has_executable
= false;
115 bool ineligible_for_safe_boot
= false;
116 OSString
* bundleIdentifier
= NULL
; // do not release
117 OSObject
* rawValue
= NULL
; // do not release
118 OSString
* stringValue
= NULL
; // do not release
119 OSBoolean
* booleanValue
= NULL
; // do not release
120 OSDictionary
* personalities
= NULL
; // do not release
121 OSDictionary
* libraries
= NULL
; // do not release
122 OSCollectionIterator
* keyIterator
= NULL
; // must release
123 OSString
* key
= NULL
; // do not release
125 VERS_version compatible_vers
;
126 char namep
[16]; // unused but needed for PE_parse_boot_arg()
128 // Info dict is a dictionary
129 if (!OSDynamicCast(OSDictionary
, extension
)) {
135 // CFBundleIdentifier is a string - REQUIRED
136 bundleIdentifier
= OSDynamicCast(OSString
,
137 extension
->getObject("CFBundleIdentifier"));
138 if (!bundleIdentifier
) {
144 // Length of CFBundleIdentifier is not >= KMOD_MAX_NAME
145 if (bundleIdentifier
->getLength() >= KMOD_MAX_NAME
) {
150 // CFBundlePackageType is "KEXT" - REQUIRED
151 stringValue
= OSDynamicCast(OSString
,
152 extension
->getObject("CFBundlePackageType"));
157 if (!stringValue
->isEqualTo("KEXT")) {
162 // CFBundleVersion is a string - REQUIRED
163 stringValue
= OSDynamicCast(OSString
,
164 extension
->getObject("CFBundleVersion"));
169 // CFBundleVersion is of valid form
170 vers
= VERS_parse_string(stringValue
->getCStringNoCopy());
176 // OSBundleCompatibleVersion is a string - OPTIONAL
177 rawValue
= extension
->getObject("OSBundleCompatibleVersion");
179 stringValue
= OSDynamicCast(OSString
, rawValue
);
185 // OSBundleCompatibleVersion is of valid form
186 compatible_vers
= VERS_parse_string(stringValue
->getCStringNoCopy());
187 if (compatible_vers
< 0) {
192 // OSBundleCompatibleVersion <= CFBundleVersion
193 if (compatible_vers
> vers
) {
199 // CFBundleExecutable is a string - OPTIONAL
200 rawValue
= extension
->getObject("CFBundleExecutable");
202 stringValue
= OSDynamicCast(OSString
, rawValue
);
203 if (!stringValue
|| stringValue
->getLength() == 0) {
207 has_executable
= true;
210 // OSKernelResource is a boolean value - OPTIONAL
211 rawValue
= extension
->getObject("OSKernelResource");
213 booleanValue
= OSDynamicCast(OSBoolean
, rawValue
);
218 is_kernel_resource
= booleanValue
->isTrue();
221 // IOKitPersonalities is a dictionary - OPTIONAL
222 rawValue
= extension
->getObject("IOKitPersonalities");
224 personalities
= OSDynamicCast(OSDictionary
, rawValue
);
225 if (!personalities
) {
230 keyIterator
= OSCollectionIterator::withCollection(personalities
);
232 IOLog("Error: Failed to allocate iterator for personalities.\n");
238 while ((key
= OSDynamicCast(OSString
, keyIterator
->getNextObject()))) {
239 OSDictionary
* personality
= NULL
; // do not release
241 // Each personality is a dictionary
242 personality
= OSDynamicCast(OSDictionary
,
243 personalities
->getObject(key
));
249 // IOClass exists as a string - REQUIRED
250 if (!OSDynamicCast(OSString
, personality
->getObject("IOClass"))) {
255 // IOProviderClass exists as a string - REQUIRED
256 if (!OSDynamicCast(OSString
,
257 personality
->getObject("IOProviderClass"))) {
263 // CFBundleIdentifier is a string - OPTIONAL - INSERT IF ABSENT!
264 rawValue
= personality
->getObject("CFBundleIdentifier");
266 personality
->setObject("CFBundleIdentifier", bundleIdentifier
);
268 OSString
* personalityID
= NULL
; // do not release
269 personalityID
= OSDynamicCast(OSString
, rawValue
);
270 if (!personalityID
) {
274 // Length of CFBundleIdentifier is not >= KMOD_MAX_NAME
275 if (personalityID
->getLength() >= KMOD_MAX_NAME
) {
282 // IOKitDebug is a number - OPTIONAL
283 rawValue
= personality
->getObject("IOKitDebug");
284 if (rawValue
&& !OSDynamicCast(OSNumber
, rawValue
)) {
290 keyIterator
->release();
295 // OSBundleLibraries is a dictionary - REQUIRED if
296 // not kernel resource & has executable
298 rawValue
= extension
->getObject("OSBundleLibraries");
299 if (!rawValue
&& !is_kernel_resource
&& has_executable
) {
305 libraries
= OSDynamicCast(OSDictionary
, rawValue
);
311 keyIterator
= OSCollectionIterator::withCollection(libraries
);
313 IOLog("Error: Failed to allocate iterator for libraries.\n");
319 while ((key
= OSDynamicCast(OSString
,
320 keyIterator
->getNextObject()))) {
322 OSString
* libraryVersion
= NULL
; // do not release
324 // Each key's length is not >= KMOD_MAX_NAME
325 if (key
->getLength() >= KMOD_MAX_NAME
) {
330 libraryVersion
= OSDynamicCast(OSString
,
331 libraries
->getObject(key
));
332 if (!libraryVersion
) {
337 // Each value is a valid version string
338 vers
= VERS_parse_string(libraryVersion
->getCStringNoCopy());
345 keyIterator
->release();
349 // OSBundleRequired, if present, must have a legal value.
350 // If it is not present and if we are safe-booting,
351 // then the kext is not eligible.
353 rawValue
= extension
->getObject("OSBundleRequired");
355 stringValue
= OSDynamicCast(OSString
, rawValue
);
360 if (!stringValue
->isEqualTo("Root") &&
361 !stringValue
->isEqualTo("Local-Root") &&
362 !stringValue
->isEqualTo("Network-Root") &&
363 !stringValue
->isEqualTo("Safe Boot") &&
364 !stringValue
->isEqualTo("Console")) {
370 } else if (PE_parse_boot_arg("-x", namep
)) { /* safe boot */
371 ineligible_for_safe_boot
= true;
378 if (keyIterator
) keyIterator
->release();
381 if (ineligible_for_safe_boot
) {
382 IOLog(VTYELLOW
"Skipping extension \"%s\" during safe boot "
383 "(no OSBundleRequired property)\n"
385 bundleIdentifier
->getCStringNoCopy());
386 } else if (not_a_dict
) {
388 IOLog(VTYELLOW
"mkext entry %d: " VTRESET
, index
);
390 IOLog(VTYELLOW
"kernel extension " VTRESET
);
392 IOLog(VTYELLOW
"info dictionary isn't a dictionary\n"
394 } else if (id_missing
) {
396 IOLog(VTYELLOW
"mkext entry %d: " VTRESET
, index
);
398 IOLog(VTYELLOW
"kernel extension " VTRESET
);
400 IOLog(VTYELLOW
"\"CFBundleIdentifier\" property is "
401 "missing or not a string\n"
404 IOLog(VTYELLOW
"kernel extension \"%s\": info dictionary is invalid\n"
405 VTRESET
, bundleIdentifier
->getCStringNoCopy());
414 /*********************************************************************
415 *********************************************************************/
416 OSDictionary
* compareExtensionVersions(
417 OSDictionary
* incumbent
,
418 OSDictionary
* candidate
) {
420 OSDictionary
* winner
= NULL
;
422 OSDictionary
* incumbentPlist
= NULL
;
423 OSDictionary
* candidatePlist
= NULL
;
424 OSString
* incumbentName
= NULL
;
425 OSString
* candidateName
= NULL
;
426 OSString
* incumbentVersionString
= NULL
;
427 OSString
* candidateVersionString
= NULL
;
428 VERS_version incumbent_vers
= 0;
429 VERS_version candidate_vers
= 0;
431 incumbentPlist
= OSDynamicCast(OSDictionary
,
432 incumbent
->getObject("plist"));
433 candidatePlist
= OSDynamicCast(OSDictionary
,
434 candidate
->getObject("plist"));
436 if (!incumbentPlist
|| !candidatePlist
) {
437 IOLog("compareExtensionVersions() called with invalid "
438 "extension dictionaries.\n");
444 incumbentName
= OSDynamicCast(OSString
,
445 incumbentPlist
->getObject("CFBundleIdentifier"));
446 candidateName
= OSDynamicCast(OSString
,
447 candidatePlist
->getObject("CFBundleIdentifier"));
448 incumbentVersionString
= OSDynamicCast(OSString
,
449 incumbentPlist
->getObject("CFBundleVersion"));
450 candidateVersionString
= OSDynamicCast(OSString
,
451 candidatePlist
->getObject("CFBundleVersion"));
453 if (!incumbentName
|| !candidateName
||
454 !incumbentVersionString
|| !candidateVersionString
) {
456 IOLog("compareExtensionVersions() called with invalid "
457 "extension dictionaries.\n");
463 if (strcmp(incumbentName
->getCStringNoCopy(),
464 candidateName
->getCStringNoCopy())) {
466 IOLog("compareExtensionVersions() called with different "
467 "extension names (%s and %s).\n",
468 incumbentName
->getCStringNoCopy(),
469 candidateName
->getCStringNoCopy());
475 incumbent_vers
= VERS_parse_string(incumbentVersionString
->getCStringNoCopy());
476 if (incumbent_vers
< 0) {
478 IOLog(VTYELLOW
"Error parsing version string for extension %s (%s)\n"
480 incumbentName
->getCStringNoCopy(),
481 incumbentVersionString
->getCStringNoCopy());
487 candidate_vers
= VERS_parse_string(candidateVersionString
->getCStringNoCopy());
488 if (candidate_vers
< 0) {
490 IOLog(VTYELLOW
"Error parsing version string for extension %s (%s)\n"
492 candidateName
->getCStringNoCopy(),
493 candidateVersionString
->getCStringNoCopy());
499 if (candidate_vers
> incumbent_vers
) {
500 IOLog(VTYELLOW
"Replacing extension \"%s\" with newer version "
501 "(%s -> %s).\n" VTRESET
,
502 incumbentName
->getCStringNoCopy(),
503 incumbentVersionString
->getCStringNoCopy(),
504 candidateVersionString
->getCStringNoCopy());
509 IOLog(VTYELLOW
"Skipping duplicate extension \"%s\" with older/same "
510 " version (%s -> %s).\n" VTRESET
,
511 candidateName
->getCStringNoCopy(),
512 candidateVersionString
->getCStringNoCopy(),
513 incumbentVersionString
->getCStringNoCopy());
521 // no cleanup, how nice
526 /*********************************************************************
527 * This function merges entries in the mergeFrom dictionary into the
528 * mergeInto dictionary. If it returns false, the two dictionaries are
529 * not altered. If it returns true, then mergeInto may have new
530 * entries; any keys that were already present in mergeInto are
531 * removed from mergeFrom, so that the caller can see what was
533 *********************************************************************/
534 bool mergeExtensionDictionaries(OSDictionary
* mergeInto
,
535 OSDictionary
* mergeFrom
) {
538 OSDictionary
* mergeIntoCopy
= NULL
; // must release
539 OSDictionary
* mergeFromCopy
= NULL
; // must release
540 OSCollectionIterator
* keyIterator
= NULL
; // must release
541 OSString
* key
; // don't release
543 /* Add 1 to count to guarantee copy can grow (grr).
545 mergeIntoCopy
= OSDictionary::withDictionary(mergeInto
,
546 mergeInto
->getCount() + 1);
547 if (!mergeIntoCopy
) {
548 IOLog("Error: Failed to copy 'into' extensions dictionary "
555 /* Add 1 to count to guarantee copy can grow (grr).
557 mergeFromCopy
= OSDictionary::withDictionary(mergeFrom
,
558 mergeFrom
->getCount() + 1);
559 if (!mergeFromCopy
) {
560 IOLog("Error: Failed to copy 'from' extensions dictionary "
567 keyIterator
= OSCollectionIterator::withCollection(mergeFrom
);
569 IOLog("Error: Failed to allocate iterator for extensions.\n");
577 * Loop through "from" dictionary, checking if the identifier already
578 * exists in the "into" dictionary and checking versions if it does.
580 while ((key
= OSDynamicCast(OSString
, keyIterator
->getNextObject()))) {
581 OSDictionary
* incumbentExt
= OSDynamicCast(OSDictionary
,
582 mergeIntoCopy
->getObject(key
));
583 OSDictionary
* candidateExt
= OSDynamicCast(OSDictionary
,
584 mergeFrom
->getObject(key
));
587 if (!mergeIntoCopy
->setObject(key
, candidateExt
)) {
589 /* This is a fatal error, so bail.
591 IOLog("mergeExtensionDictionaries(): Failed to add "
593 key
->getCStringNoCopy());
599 OSDictionary
* mostRecentExtension
=
600 compareExtensionVersions(incumbentExt
, candidateExt
);
602 if (mostRecentExtension
== incumbentExt
) {
603 mergeFromCopy
->removeObject(key
);
604 } else if (mostRecentExtension
== candidateExt
) {
606 if (!mergeIntoCopy
->setObject(key
, candidateExt
)) {
608 /* This is a fatal error, so bail.
610 IOLog("mergeExtensionDictionaries(): Failed to add "
612 key
->getCStringNoCopy());
617 } else /* should be NULL */ {
619 /* This is a nonfatal error, so continue doing others.
621 IOLog("mergeExtensionDictionaries(): Error comparing "
622 "versions of duplicate extensions %s.\n",
623 key
->getCStringNoCopy());
632 /* If successful, replace the contents of the original
633 * dictionaries with those of the modified copies.
636 mergeInto
->flushCollection();
637 mergeInto
->merge(mergeIntoCopy
);
638 mergeFrom
->flushCollection();
639 mergeFrom
->merge(mergeFromCopy
);
642 if (mergeIntoCopy
) mergeIntoCopy
->release();
643 if (mergeFromCopy
) mergeFromCopy
->release();
644 if (keyIterator
) keyIterator
->release();
651 * These bits are used to parse data made available by bootx.
653 #define BOOTX_KEXT_PREFIX "Driver-"
654 #define BOOTX_MULTIKEXT_PREFIX "DriversPackage-"
656 typedef struct MemoryMapFileInfo
{
661 typedef struct BootxDriverInfo
{
668 typedef struct MkextEntryInfo
{
669 vm_address_t base_address
;
670 mkext_file
* fileinfo
;
674 /*********************************************************************
675 * This private function reads the data for a single extension from
676 * the bootx memory-map's propery dict, returning a dictionary with
677 * keys "plist" for the extension's Info.plist as a parsed OSDictionary
678 * and "code" for the extension's executable code as an OSData.
679 *********************************************************************/
680 OSDictionary
* readExtension(OSDictionary
* propertyDict
,
681 const char * memory_map_name
) {
684 OSData
* bootxDriverDataObject
= NULL
;
685 OSDictionary
* driverPlist
= NULL
;
686 OSString
* driverName
= NULL
;
687 OSData
* driverCode
= NULL
;
688 OSString
* errorString
= NULL
;
689 OSDictionary
* driverDict
= NULL
;
691 MemoryMapFileInfo
* driverInfo
= 0;
692 BootxDriverInfo
* dataBuffer
;
694 kmod_info_t
* loaded_kmod
= NULL
;
696 bootxDriverDataObject
= OSDynamicCast(OSData
,
697 propertyDict
->getObject(memory_map_name
));
698 // don't release bootxDriverDataObject
700 if (!bootxDriverDataObject
) {
701 IOLog("Error: No driver data object "
702 "for device tree entry \"%s\".\n",
709 driverDict
= OSDictionary::withCapacity(2);
711 IOLog("Error: Couldn't allocate dictionary "
712 "for device tree entry \"%s\".\n", memory_map_name
);
718 driverInfo
= (MemoryMapFileInfo
*)
719 bootxDriverDataObject
->getBytesNoCopy(0,
720 sizeof(MemoryMapFileInfo
));
721 #if defined (__ppc__)
722 dataBuffer
= (BootxDriverInfo
*)ml_static_ptovirt(driverInfo
->paddr
);
723 #elif defined (__i386__)
724 dataBuffer
= (BootxDriverInfo
*)ml_boot_ptovirt(driverInfo
->paddr
);
725 dataBuffer
->plistAddr
= (char *)ml_boot_ptovirt((vm_address_t
)dataBuffer
->plistAddr
);
726 if (dataBuffer
->moduleAddr
)
727 dataBuffer
->moduleAddr
= (void *)ml_boot_ptovirt((vm_address_t
)dataBuffer
->moduleAddr
);
729 #error unsupported architecture
732 IOLog("Error: No data buffer "
733 "for device tree entry \"%s\".\n", memory_map_name
);
739 driverPlist
= OSDynamicCast(OSDictionary
,
740 OSUnserializeXML(dataBuffer
->plistAddr
, &errorString
));
742 IOLog("Error: Couldn't read XML property list "
743 "for device tree entry \"%s\".\n", memory_map_name
);
746 IOLog("XML parse error: %s.\n",
747 errorString
->getCStringNoCopy());
755 driverName
= OSDynamicCast(OSString
,
756 driverPlist
->getObject("CFBundleIdentifier")); // do not release
758 IOLog("Error: Device tree entry \"%s\" has "
759 "no \"CFBundleIdentifier\" property.\n", memory_map_name
);
765 /* Check if kmod is already loaded and is a real loadable one (has
768 loaded_kmod
= kmod_lookupbyname_locked(driverName
->getCStringNoCopy());
769 if (loaded_kmod
&& loaded_kmod
->address
) {
770 IOLog("Skipping new extension \"%s\"; an extension named "
771 "\"%s\" is already loaded.\n",
772 driverName
->getCStringNoCopy(),
779 if (!validateExtensionDict(driverPlist
, -1)) {
780 // validateExtensionsDict() logs an error
785 driverDict
->setObject("plist", driverPlist
);
787 /* It's perfectly okay for a KEXT to have no executable.
788 * Check that moduleAddr is nonzero before attempting to
791 * NOTE: The driverCode object is created "no-copy", so
792 * it doesn't own that memory. The memory must be freed
793 * separately from the OSData object (see
794 * clearStartupExtensionsAndLoaderInfo() at the end of this file).
796 if (dataBuffer
->moduleAddr
&& dataBuffer
->moduleLength
) {
797 driverCode
= OSData::withBytesNoCopy(dataBuffer
->moduleAddr
,
798 dataBuffer
->moduleLength
);
800 IOLog("Error: Couldn't allocate data object "
801 "to hold code for device tree entry \"%s\".\n",
809 driverDict
->setObject("code", driverCode
);
816 kfree(loaded_kmod
, sizeof(kmod_info_t
));
819 // do not release bootxDriverDataObject
820 // do not release driverName
823 driverPlist
->release();
826 errorString
->release();
829 driverCode
->release();
833 driverDict
->release();
841 /*********************************************************************
842 * Used to uncompress a single file entry in an mkext archive.
844 * The OSData returned does not own its memory! You must deallocate
845 * that memory using kmem_free() before releasing the OSData().
846 *********************************************************************/
847 static bool uncompressFile(u_int8_t
*base_address
, mkext_file
* fileinfo
,
848 /* out */ OSData
** file
) {
851 kern_return_t kern_result
;
852 u_int8_t
* uncompressed_file
= 0; // kmem_free() on error
853 OSData
* uncompressedFile
= 0; // returned
854 size_t uncompressed_size
= 0;
856 size_t offset
= OSSwapBigToHostInt32(fileinfo
->offset
);
857 size_t compsize
= OSSwapBigToHostInt32(fileinfo
->compsize
);
858 size_t realsize
= OSSwapBigToHostInt32(fileinfo
->realsize
);
859 time_t modifiedsecs
= OSSwapBigToHostInt32(fileinfo
->modifiedsecs
);
863 /* If these four fields are zero there's no file, but that isn't
866 if (offset
== 0 && compsize
== 0 &&
867 realsize
== 0 && modifiedsecs
== 0) {
871 // Add 1 for '\0' to terminate XML string!
872 kern_result
= kmem_alloc(kernel_map
, (vm_offset_t
*)&uncompressed_file
,
874 if (kern_result
!= KERN_SUCCESS
) {
875 IOLog("Error: Couldn't allocate data buffer "
876 "to uncompress file.\n");
882 uncompressedFile
= OSData::withBytesNoCopy(uncompressed_file
,
884 if (!uncompressedFile
) {
885 IOLog("Error: Couldn't allocate data object "
886 "to uncompress file.\n");
893 uncompressed_size
= decompress_lzss(uncompressed_file
,
894 base_address
+ offset
,
896 if (uncompressed_size
!= realsize
) {
897 IOLog("Error: Uncompressed file is not the length "
903 uncompressed_file
[uncompressed_size
] = '\0';
905 bcopy(base_address
+ offset
, uncompressed_file
,
907 uncompressed_file
[realsize
] = '\0';
910 *file
= uncompressedFile
;
914 if (uncompressed_file
) {
915 kmem_free(kernel_map
, (vm_address_t
)uncompressed_file
,
918 if (uncompressedFile
) {
919 uncompressedFile
->release();
926 bool uncompressModule(OSData
*compData
, /* out */ OSData
** file
) {
928 MkextEntryInfo
*info
= (MkextEntryInfo
*) compData
->getBytesNoCopy();
930 return uncompressFile((u_int8_t
*) info
->base_address
,
931 info
->fileinfo
, file
);
935 /*********************************************************************
936 * Does the work of pulling extensions out of an mkext archive located
938 *********************************************************************/
939 bool extractExtensionsFromArchive(MemoryMapFileInfo
* mkext_file_info
,
940 OSDictionary
* extensions
) {
944 u_int8_t
* crc_address
= 0;
946 mkext_header
* mkext_data
= 0; // don't free
947 mkext_kext
* onekext_data
= 0; // don't free
948 mkext_file
* plist_file
= 0; // don't free
949 mkext_file
* module_file
= 0; // don't free
950 kmod_info_t
* loaded_kmod
= 0; // must free
952 OSData
* driverPlistDataObject
= 0; // must release
953 OSDictionary
* driverPlist
= 0; // must release
954 OSData
* driverCode
= 0; // must release
955 OSDictionary
* driverDict
= 0; // must release
956 OSString
* moduleName
= 0; // don't release
957 OSString
* errorString
= NULL
; // must release
959 OSData
* moduleInfo
= 0; // must release
960 MkextEntryInfo module_info
;
963 #if defined (__ppc__)
964 mkext_data
= (mkext_header
*)mkext_file_info
->paddr
;
965 #elif defined (__i386__)
966 mkext_data
= (mkext_header
*)ml_boot_ptovirt(mkext_file_info
->paddr
);
968 #error unsupported architecture
970 if (OSSwapBigToHostInt32(mkext_data
->magic
) != MKEXT_MAGIC
||
971 OSSwapBigToHostInt32(mkext_data
->signature
) != MKEXT_SIGN
) {
972 IOLog("Error: Extension archive has invalid magic or signature.\n");
978 if (OSSwapBigToHostInt32(mkext_data
->length
) != mkext_file_info
->length
) {
979 IOLog("Error: Mismatch between extension archive & "
980 "recorded length.\n");
986 crc_address
= (u_int8_t
*)&mkext_data
->version
;
987 checksum
= adler32(crc_address
,
988 (unsigned int)mkext_data
+
989 OSSwapBigToHostInt32(mkext_data
->length
) - (unsigned int)crc_address
);
991 if (OSSwapBigToHostInt32(mkext_data
->adler32
) != checksum
) {
992 IOLog("Error: Extension archive has a bad checksum.\n");
998 IORegistryEntry
* root
= IORegistryEntry::getRegistryRoot();
1000 OSData
* checksumObj
= OSData::withBytes((void *)&checksum
,
1002 assert(checksumObj
);
1004 root
->setProperty(kIOStartupMkextCRC
, checksumObj
);
1005 checksumObj
->release();
1008 /* If the MKEXT archive isn't fat, check that the CPU type & subtype
1009 * match that of the running kernel.
1011 if (OSSwapBigToHostInt32(mkext_data
->cputype
) != (UInt32
)CPU_TYPE_ANY
) {
1012 kern_return_t kresult
= KERN_FAILURE
;
1013 host_basic_info_data_t hostinfo
;
1014 host_info_t hostinfo_ptr
= (host_info_t
)&hostinfo
;
1015 mach_msg_type_number_t count
= sizeof(hostinfo
)/sizeof(integer_t
);
1017 kresult
= host_info((host_t
)1, HOST_BASIC_INFO
,
1018 hostinfo_ptr
, &count
);
1019 if (kresult
!= KERN_SUCCESS
) {
1020 IOLog("Error: Couldn't get current host info.\n");
1025 if ((UInt32
)hostinfo
.cpu_type
!=
1026 OSSwapBigToHostInt32(mkext_data
->cputype
)) {
1028 IOLog("Error: Extension archive doesn't contain software "
1029 "for this computer's CPU type.\n");
1034 if (!grade_binary(OSSwapBigToHostInt32(mkext_data
->cputype
),
1035 OSSwapBigToHostInt32(mkext_data
->cpusubtype
))) {
1036 IOLog("Error: Extension archive doesn't contain software "
1037 "for this computer's CPU subtype.\n");
1044 for (unsigned int i
= 0;
1045 i
< OSSwapBigToHostInt32(mkext_data
->numkexts
);
1049 kfree(loaded_kmod
, sizeof(kmod_info_t
));
1053 if (driverPlistDataObject
) {
1054 kmem_free(kernel_map
,
1055 (unsigned int)driverPlistDataObject
->getBytesNoCopy(),
1056 driverPlistDataObject
->getLength());
1058 driverPlistDataObject
->release();
1059 driverPlistDataObject
= NULL
;
1062 driverPlist
->release();
1066 driverCode
->release();
1070 driverDict
->release();
1074 errorString
->release();
1078 onekext_data
= &mkext_data
->kext
[i
];
1079 plist_file
= &onekext_data
->plist
;
1080 module_file
= &onekext_data
->module;
1082 if (!uncompressFile((u_int8_t
*)mkext_data
, plist_file
,
1083 &driverPlistDataObject
)) {
1085 IOLog("Error: couldn't uncompress plist file "
1086 "from multikext archive entry %d.\n", i
);
1091 if (!driverPlistDataObject
) {
1092 IOLog("Error: No property list present "
1093 "for multikext archive entry %d.\n", i
);
1097 driverPlist
= OSDynamicCast(OSDictionary
,
1099 (char *)driverPlistDataObject
->getBytesNoCopy(),
1102 IOLog("Error: Couldn't read XML property list "
1103 "for multikext archive entry %d.\n", i
);
1106 IOLog("XML parse error: %s.\n",
1107 errorString
->getCStringNoCopy());
1113 if (!validateExtensionDict(driverPlist
, i
)) {
1114 // validateExtensionsDict() logs an error
1120 /* Get the extension's module name. This is used to record
1123 moduleName
= OSDynamicCast(OSString
,
1124 driverPlist
->getObject("CFBundleIdentifier")); // do not release
1126 IOLog("Error: Multikext archive entry %d has "
1127 "no \"CFBundleIdentifier\" property.\n", i
);
1129 continue; // assume a kext config error & continue
1132 /* Check if kmod is already loaded and is a real loadable one (has
1135 loaded_kmod
= kmod_lookupbyname_locked(moduleName
->getCStringNoCopy());
1136 if (loaded_kmod
&& loaded_kmod
->address
) {
1137 IOLog("Skipping new extension \"%s\"; an extension named "
1138 "\"%s\" is already loaded.\n",
1139 moduleName
->getCStringNoCopy(),
1145 driverDict
= OSDictionary::withCapacity(2);
1147 IOLog("Error: Couldn't allocate dictionary "
1148 "for multikext archive entry %d.\n", i
);
1154 driverDict
->setObject("plist", driverPlist
);
1157 * Prepare an entry to hold the mkext entry info for the
1158 * compressed binary module, if there is one. If all four fields
1159 * of the module entry are zero, there isn't one.
1161 if (!(loaded_kmod
&& loaded_kmod
->address
) && (OSSwapBigToHostInt32(module_file
->offset
) ||
1162 OSSwapBigToHostInt32(module_file
->compsize
) ||
1163 OSSwapBigToHostInt32(module_file
->realsize
) ||
1164 OSSwapBigToHostInt32(module_file
->modifiedsecs
))) {
1166 moduleInfo
= OSData::withCapacity(sizeof(MkextEntryInfo
));
1168 IOLog("Error: Couldn't allocate data object "
1169 "for multikext archive entry %d.\n", i
);
1175 module_info
.base_address
= (vm_address_t
)mkext_data
;
1176 module_info
.fileinfo
= module_file
;
1178 if (!moduleInfo
->appendBytes(&module_info
, sizeof(module_info
))) {
1179 IOLog("Error: Couldn't record info "
1180 "for multikext archive entry %d.\n", i
);
1186 driverDict
->setObject("compressedCode", moduleInfo
);
1189 OSDictionary
* incumbentExt
= OSDynamicCast(OSDictionary
,
1190 extensions
->getObject(moduleName
));
1192 if (!incumbentExt
) {
1193 extensions
->setObject(moduleName
, driverDict
);
1195 OSDictionary
* mostRecentExtension
=
1196 compareExtensionVersions(incumbentExt
, driverDict
);
1198 if (mostRecentExtension
== incumbentExt
) {
1199 /* Do nothing, we've got the most recent. */
1200 } else if (mostRecentExtension
== driverDict
) {
1201 if (!extensions
->setObject(moduleName
, driverDict
)) {
1203 /* This is a fatal error, so bail.
1205 IOLog("extractExtensionsFromArchive(): Failed to add "
1207 moduleName
->getCStringNoCopy());
1212 } else /* should be NULL */ {
1214 /* This is a nonfatal error, so continue.
1216 IOLog("extractExtensionsFromArchive(): Error comparing "
1217 "versions of duplicate extensions %s.\n",
1218 moduleName
->getCStringNoCopy());
1227 if (loaded_kmod
) kfree(loaded_kmod
, sizeof(kmod_info_t
));
1228 if (driverPlistDataObject
) {
1229 kmem_free(kernel_map
,
1230 (unsigned int)driverPlistDataObject
->getBytesNoCopy(),
1231 driverPlistDataObject
->getLength());
1232 driverPlistDataObject
->release();
1234 if (driverPlist
) driverPlist
->release();
1235 if (driverCode
) driverCode
->release();
1236 if (moduleInfo
) moduleInfo
->release();
1237 if (driverDict
) driverDict
->release();
1238 if (errorString
) errorString
->release();
1243 /*********************************************************************
1245 *********************************************************************/
1246 bool readExtensions(OSDictionary
* propertyDict
,
1247 const char * memory_map_name
,
1248 OSDictionary
* extensions
) {
1251 OSData
* mkextDataObject
= 0; // don't release
1252 MemoryMapFileInfo
* mkext_file_info
= 0; // don't free
1254 mkextDataObject
= OSDynamicCast(OSData
,
1255 propertyDict
->getObject(memory_map_name
));
1256 // don't release mkextDataObject
1258 if (!mkextDataObject
) {
1259 IOLog("Error: No mkext data object "
1260 "for device tree entry \"%s\".\n",
1267 mkext_file_info
= (MemoryMapFileInfo
*)mkextDataObject
->getBytesNoCopy();
1268 if (!mkext_file_info
) {
1273 result
= extractExtensionsFromArchive(mkext_file_info
, extensions
);
1277 if (!result
&& extensions
) {
1278 extensions
->flushCollection();
1285 /*********************************************************************
1286 * Adds the personalities for an extensions dictionary to the global
1288 *********************************************************************/
1289 bool addPersonalities(OSDictionary
* extensions
) {
1291 OSCollectionIterator
* keyIterator
= NULL
; // must release
1292 OSString
* key
; // don't release
1293 OSDictionary
* driverDict
= NULL
; // don't release
1294 OSDictionary
* driverPlist
= NULL
; // don't release
1295 OSDictionary
* thisDriverPersonalities
= NULL
; // don't release
1296 OSArray
* allDriverPersonalities
= NULL
; // must release
1298 allDriverPersonalities
= OSArray::withCapacity(1);
1299 if (!allDriverPersonalities
) {
1300 IOLog("Error: Couldn't allocate personality dictionary.\n");
1306 /* Record all personalities found so that they can be
1307 * added to the catalogue.
1308 * Note: Not all extensions have personalities.
1311 keyIterator
= OSCollectionIterator::withCollection(extensions
);
1313 IOLog("Error: Couldn't allocate iterator to record personalities.\n");
1319 while ( ( key
= OSDynamicCast(OSString
,
1320 keyIterator
->getNextObject() ))) {
1322 driverDict
= OSDynamicCast(OSDictionary
,
1323 extensions
->getObject(key
));
1324 driverPlist
= OSDynamicCast(OSDictionary
,
1325 driverDict
->getObject("plist"));
1326 thisDriverPersonalities
= OSDynamicCast(OSDictionary
,
1327 driverPlist
->getObject("IOKitPersonalities"));
1329 if (thisDriverPersonalities
) {
1330 OSCollectionIterator
* pIterator
;
1331 OSString
* locakKey
;
1332 pIterator
= OSCollectionIterator::withCollection(
1333 thisDriverPersonalities
);
1335 IOLog("Error: Couldn't allocate iterator "
1336 "to record extension personalities.\n");
1340 while ( (locakKey
= OSDynamicCast(OSString
,
1341 pIterator
->getNextObject())) ) {
1343 OSDictionary
* personality
= OSDynamicCast(
1345 thisDriverPersonalities
->getObject(locakKey
));
1347 allDriverPersonalities
->setObject(personality
);
1350 pIterator
->release();
1352 } /* extract personalities */
1355 /* Add all personalities found to the IOCatalogue,
1356 * but don't start matching.
1358 gIOCatalogue
->addDrivers(allDriverPersonalities
, false);
1362 if (allDriverPersonalities
) allDriverPersonalities
->release();
1363 if (keyIterator
) keyIterator
->release();
1369 /*********************************************************************
1370 * Called from IOCatalogue to add extensions from an mkext archive.
1371 * This function makes a copy of the mkext object passed in because
1372 * the device tree support code dumps it after calling us (indirectly
1373 * through the IOCatalogue).
1374 *********************************************************************/
1375 bool addExtensionsFromArchive(OSData
* mkextDataObject
) {
1378 OSDictionary
* startupExtensions
= NULL
; // don't release
1379 OSArray
* bootLoaderObjects
= NULL
; // don't release
1380 OSDictionary
* extensions
= NULL
; // must release
1381 MemoryMapFileInfo mkext_file_info
;
1382 OSCollectionIterator
* keyIterator
= NULL
; // must release
1383 OSString
* key
= NULL
; // don't release
1385 startupExtensions
= getStartupExtensions();
1386 if (!startupExtensions
) {
1387 IOLog("Can't record extension archive; there is no"
1388 " extensions dictionary.\n");
1394 bootLoaderObjects
= getBootLoaderObjects();
1395 if (! bootLoaderObjects
) {
1396 IOLog("Error: Couldn't allocate array to hold temporary objects.\n");
1402 extensions
= OSDictionary::withCapacity(2);
1404 IOLog("Error: Couldn't allocate dictionary to unpack "
1405 "extension archive.\n");
1411 mkext_file_info
.paddr
= (UInt32
)mkextDataObject
->getBytesNoCopy();
1412 mkext_file_info
.length
= mkextDataObject
->getLength();
1414 /* Save the local mkext data object so that we can deallocate it later.
1416 bootLoaderObjects
->setObject(mkextDataObject
);
1418 result
= extractExtensionsFromArchive(&mkext_file_info
, extensions
);
1420 IOLog("Error: Failed to extract extensions from archive.\n");
1426 result
= mergeExtensionDictionaries(startupExtensions
, extensions
);
1428 IOLog("Error: Failed to merge new extensions into existing set.\n");
1433 result
= addPersonalities(extensions
);
1435 IOLog("Error: Failed to add personalities for extensions extracted "
1445 IOLog("Error: Failed to record extensions from archive.\n");
1448 keyIterator
= OSCollectionIterator::withCollection(
1452 while ( (key
= OSDynamicCast(OSString
,
1453 keyIterator
->getNextObject())) ) {
1455 IOLog("Added extension \"%s\" from archive.\n",
1456 key
->getCStringNoCopy());
1459 keyIterator
->release();
1463 if (extensions
) extensions
->release();
1469 /*********************************************************************
1470 * This function builds dictionaries for the startup extensions
1471 * put into memory by bootx, recording each in the startup extensions
1472 * dictionary. The dictionary format is this:
1475 * "plist" = (the extension's Info.plist as an OSDictionary)
1476 * "code" = (an OSData containing the executable file)
1479 * This function returns true if any extensions were found and
1480 * recorded successfully, or if there are no start extensions,
1481 * and false if an unrecoverable error occurred. An error reading
1482 * a single extension is not considered fatal, and this function
1483 * will simply skip the problematic extension to try the next one.
1484 *********************************************************************/
1486 bool recordStartupExtensions(void) {
1488 OSDictionary
* startupExtensions
= NULL
; // must release
1489 OSDictionary
* existingExtensions
= NULL
; // don't release
1490 OSDictionary
* mkextExtensions
= NULL
; // must release
1491 IORegistryEntry
* bootxMemoryMap
= NULL
; // must release
1492 OSDictionary
* propertyDict
= NULL
; // must release
1493 OSCollectionIterator
* keyIterator
= NULL
; // must release
1494 OSString
* key
= NULL
; // don't release
1496 OSDictionary
* newDriverDict
= NULL
; // must release
1497 OSDictionary
* driverPlist
= NULL
; // don't release
1499 struct section
* infosect
;
1500 struct section
* symsect
;
1501 unsigned int prelinkedCount
= 0;
1503 existingExtensions
= getStartupExtensions();
1504 if (!existingExtensions
) {
1505 IOLog("Error: There is no dictionary for startup extensions.\n");
1511 startupExtensions
= OSDictionary::withCapacity(1);
1512 if (!startupExtensions
) {
1513 IOLog("Error: Couldn't allocate dictionary "
1514 "to record startup extensions.\n");
1521 // add any prelinked modules as startup extensions
1523 infosect
= getsectbyname("__PRELINK", "__info");
1524 symsect
= getsectbyname("__PRELINK", "__symtab");
1525 if (infosect
&& infosect
->addr
&& infosect
->size
1526 && symsect
&& symsect
->addr
&& symsect
->size
) do
1528 gIOPrelinkedModules
= OSDynamicCast(OSArray
,
1529 OSUnserializeXML((const char *) infosect
->addr
, NULL
));
1531 if (!gIOPrelinkedModules
)
1533 for( unsigned int idx
= 0;
1534 (propertyDict
= OSDynamicCast(OSDictionary
, gIOPrelinkedModules
->getObject(idx
)));
1537 enum { kPrelinkReservedCount
= 4 };
1539 /* Get the extension's module name. This is used to record
1540 * the extension. Do *not* release the moduleName.
1542 OSString
* moduleName
= OSDynamicCast(OSString
,
1543 propertyDict
->getObject("CFBundleIdentifier"));
1545 IOLog("Error: Prelinked module entry has "
1546 "no \"CFBundleIdentifier\" property.\n");
1551 /* Add the kext, & its plist.
1553 newDriverDict
= OSDictionary::withCapacity(4);
1554 assert(newDriverDict
);
1555 newDriverDict
->setObject("plist", propertyDict
);
1556 startupExtensions
->setObject(moduleName
, newDriverDict
);
1557 newDriverDict
->release();
1559 /* Add the code if present.
1561 OSData
* data
= OSDynamicCast(OSData
, propertyDict
->getObject("OSBundlePrelink"));
1563 if (data
->getLength() < (kPrelinkReservedCount
* sizeof(UInt32
))) {
1564 IOLog("Error: Prelinked module entry has "
1565 "invalid \"OSBundlePrelink\" property.\n");
1570 prelink
= (UInt32
*) data
->getBytesNoCopy();
1571 kmod_info_t
* kmod_info
= (kmod_info_t
*) OSReadBigInt32(prelink
, 0);
1572 // end of "file" is end of symbol sect
1573 data
= OSData::withBytesNoCopy((void *) kmod_info
->address
,
1574 symsect
->addr
+ symsect
->size
- kmod_info
->address
);
1575 newDriverDict
->setObject("code", data
);
1580 /* Add the symbols if present.
1582 OSNumber
* num
= OSDynamicCast(OSNumber
, propertyDict
->getObject("OSBundlePrelinkSymbols"));
1584 UInt32 offset
= num
->unsigned32BitValue();
1585 data
= OSData::withBytesNoCopy((void *) (symsect
->addr
+ offset
), symsect
->size
- offset
);
1586 newDriverDict
->setObject("code", data
);
1592 if (gIOPrelinkedModules
)
1593 IOLog("%d prelinked modules\n", prelinkedCount
);
1597 virt
= ml_static_ptovirt(infosect
->addr
);
1599 ml_static_mfree(virt
, infosect
->size
);
1601 newDriverDict
= NULL
;
1607 IORegistryEntry::fromPath(
1608 "/chosen/memory-map", // path
1611 // return value is retained so be sure to release it
1613 if (!bootxMemoryMap
) {
1614 IOLog("Error: Couldn't read booter memory map.\n");
1620 propertyDict
= bootxMemoryMap
->dictionaryWithProperties();
1621 if (!propertyDict
) {
1622 IOLog("Error: Couldn't get property dictionary "
1623 "from memory map.\n");
1629 keyIterator
= OSCollectionIterator::withCollection(propertyDict
);
1631 IOLog("Error: Couldn't allocate iterator for driver images.\n");
1637 while ( (key
= OSDynamicCast(OSString
,
1638 keyIterator
->getNextObject())) ) {
1639 /* Clear newDriverDict & mkextExtensions upon entry to the loop,
1640 * handling both successful and unsuccessful iterations.
1642 if (newDriverDict
) {
1643 newDriverDict
->release();
1644 newDriverDict
= NULL
;
1646 if (mkextExtensions
) {
1647 mkextExtensions
->release();
1648 mkextExtensions
= NULL
;
1651 const char * keyValue
= key
->getCStringNoCopy();
1653 if ( !strncmp(keyValue
, BOOTX_KEXT_PREFIX
,
1654 strlen(BOOTX_KEXT_PREFIX
)) ) {
1656 /* Read the extension from the bootx-supplied memory.
1658 newDriverDict
= readExtension(propertyDict
, keyValue
);
1659 if (!newDriverDict
) {
1660 IOLog("Error: Couldn't read data "
1661 "for device tree entry \"%s\".\n", keyValue
);
1667 /* Preprare to record the extension by getting its info plist.
1669 driverPlist
= OSDynamicCast(OSDictionary
,
1670 newDriverDict
->getObject("plist"));
1672 IOLog("Error: Extension in device tree entry \"%s\" "
1673 "has no property list.\n", keyValue
);
1679 /* Get the extension's module name. This is used to record
1680 * the extension. Do *not* release the moduleName.
1682 OSString
* moduleName
= OSDynamicCast(OSString
,
1683 driverPlist
->getObject("CFBundleIdentifier"));
1685 IOLog("Error: Device tree entry \"%s\" has "
1686 "no \"CFBundleIdentifier\" property.\n", keyValue
);
1692 /* All has gone well so far, so record the extension under
1693 * its module name, checking for an existing duplicate.
1695 * Do not release moduleName, as it's part of the extension's
1698 OSDictionary
* incumbentExt
= OSDynamicCast(OSDictionary
,
1699 startupExtensions
->getObject(moduleName
));
1701 if (!incumbentExt
) {
1702 startupExtensions
->setObject(moduleName
, newDriverDict
);
1704 OSDictionary
* mostRecentExtension
=
1705 compareExtensionVersions(incumbentExt
, newDriverDict
);
1707 if (mostRecentExtension
== incumbentExt
) {
1708 /* Do nothing, we've got the most recent. */
1709 } else if (mostRecentExtension
== newDriverDict
) {
1710 if (!startupExtensions
->setObject(moduleName
,
1713 /* This is a fatal error, so bail.
1715 IOLog("recordStartupExtensions(): Failed to add "
1717 moduleName
->getCStringNoCopy());
1722 } else /* should be NULL */ {
1724 /* This is a nonfatal error, so continue.
1726 IOLog("recordStartupExtensions(): Error comparing "
1727 "versions of duplicate extensions %s.\n",
1728 moduleName
->getCStringNoCopy());
1735 } else if ( !strncmp(keyValue
, BOOTX_MULTIKEXT_PREFIX
,
1736 strlen(BOOTX_MULTIKEXT_PREFIX
)) ) {
1738 mkextExtensions
= OSDictionary::withCapacity(10);
1739 if (!mkextExtensions
) {
1740 IOLog("Error: Couldn't allocate dictionary to unpack "
1741 "multi-extension archive.\n");
1744 goto finish
; // allocation failure is fatal for this routine
1746 if (!readExtensions(propertyDict
, keyValue
, mkextExtensions
)) {
1747 IOLog("Error: Couldn't unpack multi-extension archive.\n");
1751 if (!mergeExtensionDictionaries(startupExtensions
,
1754 IOLog("Error: Failed to merge new extensions into "
1758 goto finish
; // merge error is fatal for this routine
1763 // Do not release key.
1765 } /* while ( (key = OSDynamicCast(OSString, ...) ) ) */
1767 if (!mergeExtensionDictionaries(existingExtensions
, startupExtensions
)) {
1768 IOLog("Error: Failed to merge new extensions into existing set.\n");
1774 result
= addPersonalities(startupExtensions
);
1776 IOLog("Error: Failed to add personalities for extensions extracted "
1785 // reused so clear first!
1787 keyIterator
->release();
1792 IOLog("Error: Failed to record startup extensions.\n");
1796 keyIterator
= OSCollectionIterator::withCollection(
1800 while ( (key
= OSDynamicCast(OSString
,
1801 keyIterator
->getNextObject())) ) {
1803 IOLog("Found extension \"%s\".\n",
1804 key
->getCStringNoCopy());
1807 keyIterator
->release();
1813 if (newDriverDict
) newDriverDict
->release();
1814 if (propertyDict
) propertyDict
->release();
1815 if (bootxMemoryMap
) bootxMemoryMap
->release();
1816 if (mkextExtensions
) mkextExtensions
->release();
1817 if (startupExtensions
) startupExtensions
->release();
1823 /*********************************************************************
1824 * This function removes an entry from the dictionary of startup
1825 * extensions. It's used when an extension can't be loaded, for
1826 * whatever reason. For drivers, this allows another matching driver
1827 * to be loaded, so that, for example, a driver for the root device
1829 *********************************************************************/
1830 void removeStartupExtension(const char * extensionName
) {
1831 OSDictionary
* startupExtensions
= NULL
; // don't release
1832 OSDictionary
* extensionDict
= NULL
; // don't release
1833 OSDictionary
* extensionPlist
= NULL
; // don't release
1834 OSDictionary
* extensionPersonalities
= NULL
; // don't release
1835 OSDictionary
* personality
= NULL
; // don't release
1836 OSCollectionIterator
* keyIterator
= NULL
; // must release
1837 OSString
* key
= NULL
; // don't release
1839 startupExtensions
= getStartupExtensions();
1840 if (!startupExtensions
) goto finish
;
1843 /* Find the extension's entry in the dictionary of
1844 * startup extensions.
1846 extensionDict
= OSDynamicCast(OSDictionary
,
1847 startupExtensions
->getObject(extensionName
));
1848 if (!extensionDict
) goto finish
;
1850 extensionPlist
= OSDynamicCast(OSDictionary
,
1851 extensionDict
->getObject("plist"));
1852 if (!extensionPlist
) goto finish
;
1854 extensionPersonalities
= OSDynamicCast(OSDictionary
,
1855 extensionPlist
->getObject("IOKitPersonalities"));
1856 if (!extensionPersonalities
) goto finish
;
1858 /* If it was there, remove it from the catalogue proper
1859 * by calling removeDrivers(). Pass true for the second
1860 * argument to trigger a new round of matching, and
1861 * then remove the extension from the dictionary of startup
1864 keyIterator
= OSCollectionIterator::withCollection(
1865 extensionPersonalities
);
1867 IOLog("Error: Couldn't allocate iterator to scan"
1868 " personalities for %s.\n", extensionName
);
1872 while ((key
= OSDynamicCast(OSString
, keyIterator
->getNextObject()))) {
1873 personality
= OSDynamicCast(OSDictionary
,
1874 extensionPersonalities
->getObject(key
));
1878 gIOCatalogue
->removeDrivers(personality
, true);
1882 startupExtensions
->removeObject(extensionName
);
1886 if (keyIterator
) keyIterator
->release();
1890 /*********************************************************************
1891 * FIXME: This function invalidates the globals gStartupExtensions and
1892 * FIXME: ...gBootLoaderObjects without setting them to NULL. Since
1893 * FIXME: ...the code itself is immediately unloaded, there may not be
1894 * FIXME: ...any reason to worry about that!
1895 *********************************************************************/
1896 void clearStartupExtensionsAndLoaderInfo(void)
1898 OSDictionary
* startupExtensions
= NULL
; // must release
1899 OSArray
* bootLoaderObjects
= NULL
; // must release
1901 IORegistryEntry
* bootxMemoryMap
= NULL
; // must release
1902 OSDictionary
* propertyDict
= NULL
; // must release
1903 OSCollectionIterator
* keyIterator
= NULL
; // must release
1904 OSString
* key
= NULL
; // don't release
1907 * Drop any temporarily held data objects.
1909 bootLoaderObjects
= getBootLoaderObjects();
1910 if (bootLoaderObjects
) {
1911 bootLoaderObjects
->release();
1915 * If any "code" entries in driver dictionaries are accompanied
1916 * by "compressedCode" entries, then those data objects were
1917 * created based of of kmem_alloc()'ed memory, which must be
1920 startupExtensions
= getStartupExtensions();
1921 if (startupExtensions
) {
1923 OSCollectionIterator::withCollection(startupExtensions
);
1925 IOLog("Error: Couldn't allocate iterator for startup "
1928 goto memory_map
; // bail to the memory_map label
1931 while ( (key
= OSDynamicCast(OSString
,
1932 keyIterator
->getNextObject())) ) {
1934 OSDictionary
* driverDict
= 0;
1935 OSData
* codeData
= 0;
1937 driverDict
= OSDynamicCast(OSDictionary
,
1938 startupExtensions
->getObject(key
));
1940 codeData
= OSDynamicCast(OSData
,
1941 driverDict
->getObject("code"));
1944 driverDict
->getObject("compressedCode")) {
1946 kmem_free(kernel_map
,
1947 (unsigned int)codeData
->getBytesNoCopy(),
1948 codeData
->getLength());
1953 keyIterator
->release();
1954 startupExtensions
->release();
1960 * Go through the device tree's memory map and remove any driver
1964 IORegistryEntry::fromPath(
1965 "/chosen/memory-map", // path
1968 // return value is retained so be sure to release it
1970 if (!bootxMemoryMap
) {
1971 IOLog("Error: Couldn't read booter memory map.\n");
1976 propertyDict
= bootxMemoryMap
->dictionaryWithProperties();
1977 if (!propertyDict
) {
1978 IOLog("Error: Couldn't get property dictionary "
1979 "from memory map.\n");
1984 keyIterator
= OSCollectionIterator::withCollection(propertyDict
);
1986 IOLog("Error: Couldn't allocate iterator for driver images.\n");
1991 while ( (key
= OSDynamicCast(OSString
,
1992 keyIterator
->getNextObject())) ) {
1994 const char * keyValue
= key
->getCStringNoCopy();
1996 if ( !strncmp(keyValue
, BOOTX_KEXT_PREFIX
,
1997 strlen(BOOTX_KEXT_PREFIX
)) ||
1998 !strncmp(keyValue
, BOOTX_MULTIKEXT_PREFIX
,
1999 strlen(BOOTX_MULTIKEXT_PREFIX
)) ) {
2001 OSData
* bootxDriverDataObject
= NULL
;
2002 MemoryMapFileInfo
* driverInfo
= 0;
2004 bootxDriverDataObject
= OSDynamicCast(OSData
,
2005 propertyDict
->getObject(keyValue
));
2006 // don't release bootxDriverDataObject
2008 if (!bootxDriverDataObject
) {
2011 driverInfo
= (MemoryMapFileInfo
*)
2012 bootxDriverDataObject
->getBytesNoCopy(0,
2013 sizeof(MemoryMapFileInfo
));
2014 IODTFreeLoaderInfo((char *)keyValue
,
2015 (void *)driverInfo
->paddr
,
2016 (int)driverInfo
->length
);
2021 if (bootxMemoryMap
) bootxMemoryMap
->release();
2022 if (propertyDict
) propertyDict
->release();
2023 if (keyIterator
) keyIterator
->release();