2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
22 #include <libkern/c++/OSContainers.h>
23 #include <IOKit/IODeviceTreeSupport.h>
24 #include <IOKit/IORegistryEntry.h>
25 #include <IOKit/IOCatalogue.h>
26 #include <libkern/c++/OSUnserialize.h>
27 #include <libkern/OSByteOrder.h>
28 #include <libsa/catalogue.h>
31 #include <machine/machine_routines.h>
32 #include <mach/host_info.h>
33 #include <mach/kmod.h>
34 #include <libsa/mkext.h>
35 #include <libsa/vers_rsrc.h>
38 #include <IOKit/IOLib.h>
40 #include <IOKit/assert.h>
44 extern void IODTFreeLoaderInfo( char *key
, void *infoAddr
, int infoSize
);
45 extern kern_return_t
host_info(host_t host
,
48 mach_msg_type_number_t
*count
);
49 extern int check_cpu_subtype(cpu_subtype_t cpu_subtype
);
51 extern IOLock
* kld_lock
;
57 #define VTYELLOW "\033[33m"
58 #define VTRESET "\033[0m"
61 /*********************************************************************
62 *********************************************************************/
63 static OSDictionary
* gStartupExtensions
= 0;
65 OSDictionary
* getStartupExtensions(void) {
66 if (gStartupExtensions
) {
67 return gStartupExtensions
;
69 gStartupExtensions
= OSDictionary::withCapacity(1);
70 if (!gStartupExtensions
) {
71 IOLog("Error: Couldn't allocate "
72 "startup extensions dictionary.\n");
75 return gStartupExtensions
;
79 /*********************************************************************
80 * This function checks that a driver dict has all the required
81 * entries and does a little bit of value checking too.
82 *********************************************************************/
83 bool validateExtensionDict(OSDictionary
* extension
) {
86 OSString
* name
; // do not release
87 OSString
* stringValue
; // do not release
90 name
= OSDynamicCast(OSString
,
91 extension
->getObject("CFBundleIdentifier"));
93 IOLog(VTYELLOW
"Extension has no \"CFBundleIdentifier\" property.\n"
100 stringValue
= OSDynamicCast(OSString
,
101 extension
->getObject("CFBundleVersion"));
103 IOLog(VTYELLOW
"Extension \"%s\" has no \"CFBundleVersion\" "
104 "property.\n" VTRESET
,
105 name
->getCStringNoCopy());
110 if (!VERS_parse_string(stringValue
->getCStringNoCopy(),
112 IOLog(VTYELLOW
"Extension \"%s\" has an invalid "
113 "\"CFBundleVersion\" property.\n" VTRESET
,
114 name
->getCStringNoCopy());
122 // FIXME: Make return real result after kext conversion
129 /*********************************************************************
130 *********************************************************************/
131 OSDictionary
* compareExtensionVersions(
132 OSDictionary
* incumbent
,
133 OSDictionary
* candidate
) {
135 OSDictionary
* winner
= NULL
;
137 OSDictionary
* incumbentPlist
= NULL
;
138 OSDictionary
* candidatePlist
= NULL
;
139 OSString
* incumbentName
= NULL
;
140 OSString
* candidateName
= NULL
;
141 OSString
* incumbentVersionString
= NULL
;
142 OSString
* candidateVersionString
= NULL
;
143 UInt32 incumbent_vers
= 0;
144 UInt32 candidate_vers
= 0;
146 incumbentPlist
= OSDynamicCast(OSDictionary
,
147 incumbent
->getObject("plist"));
148 candidatePlist
= OSDynamicCast(OSDictionary
,
149 candidate
->getObject("plist"));
151 if (!incumbentPlist
|| !candidatePlist
) {
152 IOLog("compareExtensionVersions() called with invalid "
153 "extension dictionaries.\n");
159 incumbentName
= OSDynamicCast(OSString
,
160 incumbentPlist
->getObject("CFBundleIdentifier"));
161 candidateName
= OSDynamicCast(OSString
,
162 candidatePlist
->getObject("CFBundleIdentifier"));
163 incumbentVersionString
= OSDynamicCast(OSString
,
164 incumbentPlist
->getObject("CFBundleVersion"));
165 candidateVersionString
= OSDynamicCast(OSString
,
166 candidatePlist
->getObject("CFBundleVersion"));
168 if (!incumbentName
|| !candidateName
||
169 !incumbentVersionString
|| !candidateVersionString
) {
171 IOLog("compareExtensionVersions() called with invalid "
172 "extension dictionaries.\n");
178 if (strcmp(incumbentName
->getCStringNoCopy(),
179 candidateName
->getCStringNoCopy())) {
181 IOLog("compareExtensionVersions() called with different "
182 "extension names (%s and %s).\n",
183 incumbentName
->getCStringNoCopy(),
184 candidateName
->getCStringNoCopy());
190 if (!VERS_parse_string(incumbentVersionString
->getCStringNoCopy(),
193 IOLog(VTYELLOW
"Error parsing version string for extension %s (%s)\n"
195 incumbentName
->getCStringNoCopy(),
196 incumbentVersionString
->getCStringNoCopy());
202 if (!VERS_parse_string(candidateVersionString
->getCStringNoCopy(),
205 IOLog(VTYELLOW
"Error parsing version string for extension %s (%s)\n"
207 candidateName
->getCStringNoCopy(),
208 candidateVersionString
->getCStringNoCopy());
214 if (candidate_vers
> incumbent_vers
) {
215 IOLog(VTYELLOW
"Replacing extension \"%s\" with newer version "
216 "(%s -> %s).\n" VTRESET
,
217 incumbentName
->getCStringNoCopy(),
218 incumbentVersionString
->getCStringNoCopy(),
219 candidateVersionString
->getCStringNoCopy());
224 IOLog(VTYELLOW
"Skipping duplicate extension \"%s\" with older/same "
225 " version (%s -> %s).\n" VTRESET
,
226 candidateName
->getCStringNoCopy(),
227 candidateVersionString
->getCStringNoCopy(),
228 incumbentVersionString
->getCStringNoCopy());
236 // no cleanup, how nice
241 /*********************************************************************
242 * This function merges entries in the mergeFrom dictionary into the
243 * mergeInto dictionary. If it returns false, the two dictionaries are
244 * not altered. If it returns true, then mergeInto may have new
245 * entries; any keys that were already present in mergeInto are
246 * removed from mergeFrom, so that the caller can see what was
248 *********************************************************************/
249 bool mergeExtensionDictionaries(OSDictionary
* mergeInto
,
250 OSDictionary
* mergeFrom
) {
253 OSDictionary
* mergeIntoCopy
= NULL
; // must release
254 OSDictionary
* mergeFromCopy
= NULL
; // must release
255 OSCollectionIterator
* keyIterator
= NULL
; // must release
256 OSString
* key
; // don't release
258 /* Add 1 to count to guarantee copy can grow (grr).
260 mergeIntoCopy
= OSDictionary::withDictionary(mergeInto
,
261 mergeInto
->getCount() + 1);
262 if (!mergeIntoCopy
) {
263 IOLog("Error: Failed to copy 'into' extensions dictionary "
270 /* Add 1 to count to guarantee copy can grow (grr).
272 mergeFromCopy
= OSDictionary::withDictionary(mergeFrom
,
273 mergeFrom
->getCount() + 1);
274 if (!mergeFromCopy
) {
275 IOLog("Error: Failed to copy 'from' extensions dictionary "
282 keyIterator
= OSCollectionIterator::withCollection(mergeFrom
);
284 IOLog("Error: Failed to allocate iterator for extensions.\n");
292 * Loop through "from" dictionary, checking if the identifier already
293 * exists in the "into" dictionary and checking versions if it does.
295 while ((key
= OSDynamicCast(OSString
, keyIterator
->getNextObject()))) {
296 OSDictionary
* incumbentExt
= OSDynamicCast(OSDictionary
,
297 mergeIntoCopy
->getObject(key
));
298 OSDictionary
* candidateExt
= OSDynamicCast(OSDictionary
,
299 mergeFrom
->getObject(key
));
302 if (!mergeIntoCopy
->setObject(key
, candidateExt
)) {
304 /* This is a fatal error, so bail.
306 IOLog("mergeExtensionDictionaries(): Failed to add "
308 key
->getCStringNoCopy());
314 OSDictionary
* mostRecentExtension
=
315 compareExtensionVersions(incumbentExt
, candidateExt
);
317 if (mostRecentExtension
== incumbentExt
) {
318 mergeFromCopy
->removeObject(key
);
319 } else if (mostRecentExtension
== candidateExt
) {
321 if (!mergeIntoCopy
->setObject(key
, candidateExt
)) {
323 /* This is a fatal error, so bail.
325 IOLog("mergeExtensionDictionaries(): Failed to add "
327 key
->getCStringNoCopy());
332 } else /* should be NULL */ {
334 /* This is a nonfatal error, so continue doing others.
336 IOLog("mergeExtensionDictionaries(): Error comparing "
337 "versions of duplicate extensions %s.\n",
338 key
->getCStringNoCopy());
347 /* If successful, replace the contents of the original
348 * dictionaries with those of the modified copies.
351 mergeInto
->flushCollection();
352 mergeInto
->merge(mergeIntoCopy
);
353 mergeFrom
->flushCollection();
354 mergeFrom
->merge(mergeFromCopy
);
357 if (mergeIntoCopy
) mergeIntoCopy
->release();
358 if (mergeFromCopy
) mergeFromCopy
->release();
359 if (keyIterator
) keyIterator
->release();
366 * These bits are used to parse data made available by bootx.
368 #define BOOTX_KEXT_PREFIX "Driver-"
369 #define BOOTX_MULTIKEXT_PREFIX "DriversPackage-"
371 typedef struct MemoryMapFileInfo
{
376 typedef struct BootxDriverInfo
{
384 /*********************************************************************
385 * This private function reads the data for a single extension from
386 * the bootx memory-map's propery dict, returning a dictionary with
387 * keys "plist" for the extension's Info.plist as a parsed OSDictionary
388 * and "code" for the extension's executable code as an OSData.
389 *********************************************************************/
390 OSDictionary
* readExtension(OSDictionary
* propertyDict
,
391 const char * memory_map_name
) {
394 OSData
* bootxDriverDataObject
= NULL
;
395 OSDictionary
* driverPlist
= NULL
;
396 OSString
* driverName
= NULL
;
397 OSData
* driverCode
= NULL
;
398 OSString
* errorString
= NULL
;
399 OSDictionary
* driverDict
= NULL
;
401 MemoryMapFileInfo
* driverInfo
= 0;
402 BootxDriverInfo
* dataBuffer
;
404 kmod_info_t
* loaded_kmod
= NULL
;
407 bootxDriverDataObject
= OSDynamicCast(OSData
,
408 propertyDict
->getObject(memory_map_name
));
409 // don't release bootxDriverDataObject
411 if (!bootxDriverDataObject
) {
412 IOLog("Error: No driver data object "
413 "for device tree entry \"%s\".\n",
420 driverDict
= OSDictionary::withCapacity(2);
422 IOLog("Error: Couldn't allocate dictionary "
423 "for device tree entry \"%s\".\n", memory_map_name
);
429 driverInfo
= (MemoryMapFileInfo
*)
430 bootxDriverDataObject
->getBytesNoCopy(0,
431 sizeof(MemoryMapFileInfo
));
432 dataBuffer
= (BootxDriverInfo
*)ml_static_ptovirt(
435 IOLog("Error: No data buffer "
436 "for device tree entry \"%s\".\n", memory_map_name
);
442 driverPlist
= OSDynamicCast(OSDictionary
,
443 OSUnserializeXML(dataBuffer
->plistAddr
, &errorString
));
445 IOLog("Error: Couldn't read XML property list "
446 "for device tree entry \"%s\".\n", memory_map_name
);
449 IOLog("XML parse error: %s.\n",
450 errorString
->getCStringNoCopy());
458 driverName
= OSDynamicCast(OSString
,
459 driverPlist
->getObject("CFBundleIdentifier")); // do not release
461 IOLog("Error: Device tree entry \"%s\" has "
462 "no \"CFBundleIdentifier\" property.\n", memory_map_name
);
468 /* Check if kmod is already loaded and is a real loadable one (has
471 loaded_kmod
= kmod_lookupbyname(driverName
->getCStringNoCopy());
472 if (loaded_kmod
&& loaded_kmod
->address
) {
473 IOLog("Skipping new extension \"%s\"; an extension named "
474 "\"%s\" is already loaded.\n",
475 driverName
->getCStringNoCopy(),
482 if (!validateExtensionDict(driverPlist
)) {
483 IOLog("Error: Failed to validate property list "
484 "for device tree entry \"%s\".\n", memory_map_name
);
490 driverDict
->setObject("plist", driverPlist
);
492 /* It's perfectly okay for a KEXT to have no executable.
493 * Check that moduleAddr is nonzero before attempting to
496 if (dataBuffer
->moduleAddr
&& dataBuffer
->moduleLength
) {
497 driverCode
= OSData::withBytes(dataBuffer
->moduleAddr
,
498 dataBuffer
->moduleLength
);
500 IOLog("Error: Couldn't allocate data object "
501 "to hold code for device tree entry \"%s\".\n",
509 driverDict
->setObject("code", driverCode
);
515 /* Free the memory for this extension that was set up
518 IODTFreeLoaderInfo(memory_map_name
, (void *)driverInfo
->paddr
,
519 (int)driverInfo
->length
);
521 // do not release bootxDriverDataObject
522 // do not release driverName
525 driverPlist
->release();
528 errorString
->release();
531 driverCode
->release();
535 driverDict
->release();
543 /*********************************************************************
544 * Used to uncompress a single file entry in an mkext archive.
545 *********************************************************************/
546 int uncompressFile(u_int8_t
* base_address
,
547 mkext_file
* fileinfo
,
548 /* out */ OSData
** file
) {
551 u_int8_t
* uncompressed_file
= 0; // don't free; owned by OSData obj
552 OSData
* uncompressedFile
= 0; // don't release
553 size_t uncompressed_size
= 0;
555 size_t offset
= OSSwapBigToHostInt32(fileinfo
->offset
);
556 size_t compsize
= OSSwapBigToHostInt32(fileinfo
->compsize
);
557 size_t realsize
= OSSwapBigToHostInt32(fileinfo
->realsize
);
558 time_t modifiedsecs
= OSSwapBigToHostInt32(fileinfo
->modifiedsecs
);
562 /* If these four fields are zero there's no file, but that isn't
565 if (offset
== 0 && compsize
== 0 &&
566 realsize
== 0 && modifiedsecs
== 0) {
570 // Add 1 for '\0' to terminate XML string!
571 uncompressed_file
= (u_int8_t
*)kalloc(realsize
+ 1);
572 if (!uncompressed_file
) {
573 IOLog("Error: Couldn't allocate data buffer "
574 "to uncompress file.\n");
580 uncompressedFile
= OSData::withBytesNoCopy(uncompressed_file
,
582 if (!uncompressedFile
) {
583 IOLog("Error: Couldn't allocate data object "
584 "to uncompress file.\n");
591 uncompressed_size
= decompress_lzss(uncompressed_file
,
592 base_address
+ offset
,
594 if (uncompressed_size
!= realsize
) {
595 IOLog("Error: Uncompressed file is not the length "
602 bcopy(base_address
+ offset
, uncompressed_file
,
605 uncompressed_file
[uncompressed_size
] = '\0';
607 *file
= uncompressedFile
;
611 if (uncompressedFile
) {
612 uncompressedFile
->release();
620 /*********************************************************************
621 * Does the work of pulling extensions out of an mkext archive located
623 *********************************************************************/
624 bool extractExtensionsFromArchive(MemoryMapFileInfo
* mkext_file_info
,
625 OSDictionary
* extensions
) {
629 u_int8_t
* crc_address
= 0;
631 mkext_header
* mkext_data
= 0; // don't free
632 mkext_kext
* onekext_data
= 0; // don't free
633 mkext_file
* plist_file
= 0; // don't free
634 mkext_file
* module_file
= 0; // don't free
635 OSData
* driverPlistDataObject
= 0; // must release
636 OSDictionary
* driverPlist
= 0; // must release
637 OSData
* driverCode
= 0; // must release
638 OSDictionary
* driverDict
= 0; // must release
639 OSString
* moduleName
= 0; // don't release
640 OSString
* errorString
= NULL
; // must release
642 mkext_data
= (mkext_header
*)mkext_file_info
->paddr
;
644 if (OSSwapBigToHostInt32(mkext_data
->magic
) != MKEXT_MAGIC
||
645 OSSwapBigToHostInt32(mkext_data
->signature
) != MKEXT_SIGN
) {
646 IOLog("Error: Extension archive has invalid magic or signature.\n");
652 if (OSSwapBigToHostInt32(mkext_data
->length
) != mkext_file_info
->length
) {
653 IOLog("Error: Mismatch between extension archive & "
654 "recorded length.\n");
660 crc_address
= (u_int8_t
*)&mkext_data
->version
;
661 checksum
= adler32(crc_address
,
662 (unsigned int)mkext_data
+
663 OSSwapBigToHostInt32(mkext_data
->length
) - (unsigned int)crc_address
);
665 if (OSSwapBigToHostInt32(mkext_data
->adler32
) != checksum
) {
666 IOLog("Error: Extension archive has a bad checksum.\n");
672 /* If the MKEXT archive isn't fat, check that the CPU type & subtype
673 * match that of the running kernel.
675 if (OSSwapBigToHostInt32(mkext_data
->cputype
) != (UInt32
)CPU_TYPE_ANY
) {
676 kern_return_t kresult
= KERN_FAILURE
;
677 host_basic_info_data_t hostinfo
;
678 host_info_t hostinfo_ptr
= (host_info_t
)&hostinfo
;
679 mach_msg_type_number_t count
= sizeof(hostinfo
)/sizeof(integer_t
);
681 kresult
= host_info((host_t
)1, HOST_BASIC_INFO
,
682 hostinfo_ptr
, &count
);
683 if (kresult
!= KERN_SUCCESS
) {
684 IOLog("Error: Couldn't get current host info.\n");
689 if ((UInt32
)hostinfo
.cpu_type
!=
690 OSSwapBigToHostInt32(mkext_data
->cputype
)) {
692 IOLog("Error: Extension archive doesn't contain software "
693 "for this computer's CPU type.\n");
698 if (!check_cpu_subtype(OSSwapBigToHostInt32(mkext_data
->cpusubtype
))) {
699 IOLog("Error: Extension archive doesn't contain software "
700 "for this computer's CPU subtype.\n");
707 for (unsigned int i
= 0;
708 i
< OSSwapBigToHostInt32(mkext_data
->numkexts
);
711 kmod_info_t
* loaded_kmod
= 0;
713 if (driverPlistDataObject
) {
714 driverPlistDataObject
->release();
715 driverPlistDataObject
= NULL
;
718 driverPlist
->release();
722 driverCode
->release();
726 driverDict
->release();
730 errorString
->release();
734 onekext_data
= &mkext_data
->kext
[i
];
735 plist_file
= &onekext_data
->plist
;
736 module_file
= &onekext_data
->module;
738 if (!uncompressFile((u_int8_t
*)mkext_data
, plist_file
,
739 &driverPlistDataObject
)) {
741 IOLog("Error: couldn't uncompress plist file "
742 "%d from multikext archive.\n", i
);
745 goto finish
; // or just continue?
748 if (!driverPlistDataObject
) {
749 IOLog("Error: No property list present "
750 "for multikext archive entry %d.\n", i
);
753 goto finish
; // or just continue?
755 driverPlist
= OSDynamicCast(OSDictionary
,
757 (char *)driverPlistDataObject
->getBytesNoCopy(),
760 IOLog("Error: Couldn't read XML property list "
761 "for multikext archive entry %d.\n", i
);
764 IOLog("XML parse error: %s.\n",
765 errorString
->getCStringNoCopy());
769 goto finish
; // or just continue?
772 if (!validateExtensionDict(driverPlist
)) {
773 IOLog("Error: Failed to validate property list "
774 "for multikext archive entry %d.\n", i
);
782 /* Get the extension's module name. This is used to record
785 moduleName
= OSDynamicCast(OSString
,
786 driverPlist
->getObject("CFBundleIdentifier")); // do not release
788 IOLog("Error: Multikext archive entry %d has "
789 "no \"CFBundleIdentifier\" property.\n", i
);
791 continue; // assume a kext config error & continue
794 /* Check if kmod is already loaded and is a real loadable one (has
797 loaded_kmod
= kmod_lookupbyname(moduleName
->getCStringNoCopy());
798 if (loaded_kmod
&& loaded_kmod
->address
) {
799 IOLog("Skipping new extension \"%s\"; an extension named "
800 "\"%s\" is already loaded.\n",
801 moduleName
->getCStringNoCopy(),
807 driverDict
= OSDictionary::withCapacity(2);
809 IOLog("Error: Couldn't allocate dictionary "
810 "for multikext archive entry %d.\n", i
);
816 driverDict
->setObject("plist", driverPlist
);
818 if (!uncompressFile((u_int8_t
*)mkext_data
, module_file
,
821 IOLog("Error: couldn't uncompress module file "
822 "%d from multikext archive.\n", i
);
825 goto finish
; // or just continue?
828 /* It's okay for there to be no module
831 driverDict
->setObject("code", driverCode
);
834 OSDictionary
* incumbentExt
= OSDynamicCast(OSDictionary
,
835 extensions
->getObject(moduleName
));
838 extensions
->setObject(moduleName
, driverDict
);
840 OSDictionary
* mostRecentExtension
=
841 compareExtensionVersions(incumbentExt
, driverDict
);
843 if (mostRecentExtension
== incumbentExt
) {
844 /* Do nothing, we've got the most recent. */
845 } else if (mostRecentExtension
== driverDict
) {
846 if (!extensions
->setObject(moduleName
, driverDict
)) {
848 /* This is a fatal error, so bail.
850 IOLog("extractExtensionsFromArchive(): Failed to add "
852 moduleName
->getCStringNoCopy());
857 } else /* should be NULL */ {
859 /* This is a nonfatal error, so continue.
861 IOLog("extractExtensionsFromArchive(): Error comparing "
862 "versions of duplicate extensions %s.\n",
863 moduleName
->getCStringNoCopy());
872 if (driverPlistDataObject
) driverPlistDataObject
->release();
873 if (driverPlist
) driverPlist
->release();
874 if (driverCode
) driverCode
->release();
875 if (driverDict
) driverDict
->release();
876 if (errorString
) errorString
->release();
882 /*********************************************************************
883 * Unlike with single KEXTs, a failure to read any member of a
884 * multi-KEXT archive is considered a failure for all. We want to
885 * take no chances unpacking a single, compressed archive of drivers.
886 *********************************************************************/
887 bool readExtensions(OSDictionary
* propertyDict
,
888 const char * memory_map_name
,
889 OSDictionary
* extensions
) {
892 OSData
* mkextDataObject
= 0; // don't release
893 MemoryMapFileInfo
* mkext_file_info
= 0; // don't free
895 mkextDataObject
= OSDynamicCast(OSData
,
896 propertyDict
->getObject(memory_map_name
));
897 // don't release mkextDataObject
899 if (!mkextDataObject
) {
900 IOLog("Error: No mkext data object "
901 "for device tree entry \"%s\".\n",
908 mkext_file_info
= (MemoryMapFileInfo
*)mkextDataObject
->getBytesNoCopy();
909 if (!mkext_file_info
) {
914 result
= extractExtensionsFromArchive(mkext_file_info
, extensions
);
918 if (!result
&& extensions
) {
919 extensions
->flushCollection();
922 IODTFreeLoaderInfo(memory_map_name
, (void *)mkext_file_info
->paddr
,
923 (int)mkext_file_info
->length
);
929 /*********************************************************************
930 * Adds the personalities for an extensions dictionary to the global
932 *********************************************************************/
933 bool addPersonalities(OSDictionary
* extensions
) {
935 OSCollectionIterator
* keyIterator
= NULL
; // must release
936 OSString
* key
; // don't release
937 OSDictionary
* driverDict
= NULL
; // don't release
938 OSDictionary
* driverPlist
= NULL
; // don't release
939 OSDictionary
* thisDriverPersonalities
= NULL
; // don't release
940 OSArray
* allDriverPersonalities
= NULL
; // must release
942 allDriverPersonalities
= OSArray::withCapacity(1);
943 if (!allDriverPersonalities
) {
944 IOLog("Error: Couldn't allocate personality dictionary.\n");
950 /* Record all personalities found so that they can be
951 * added to the catalogue.
952 * Note: Not all extensions have personalities.
955 keyIterator
= OSCollectionIterator::withCollection(extensions
);
957 IOLog("Error: Couldn't allocate iterator to record personalities.\n");
963 while ( ( key
= OSDynamicCast(OSString
,
964 keyIterator
->getNextObject() ))) {
966 driverDict
= OSDynamicCast(OSDictionary
,
967 extensions
->getObject(key
));
968 driverPlist
= OSDynamicCast(OSDictionary
,
969 driverDict
->getObject("plist"));
970 thisDriverPersonalities
= OSDynamicCast(OSDictionary
,
971 driverPlist
->getObject("IOKitPersonalities"));
973 if (thisDriverPersonalities
) {
974 OSCollectionIterator
* pIterator
;
976 pIterator
= OSCollectionIterator::withCollection(
977 thisDriverPersonalities
);
979 IOLog("Error: Couldn't allocate iterator "
980 "to record extension personalities.\n");
984 while ( (key
= OSDynamicCast(OSString
,
985 pIterator
->getNextObject())) ) {
987 OSDictionary
* personality
= OSDynamicCast(
989 thisDriverPersonalities
->getObject(key
));
991 allDriverPersonalities
->setObject(personality
);
994 pIterator
->release();
996 } /* extract personalities */
999 /* Add all personalities found to the IOCatalogue,
1000 * but don't start matching.
1002 gIOCatalogue
->addDrivers(allDriverPersonalities
, false);
1006 if (allDriverPersonalities
) allDriverPersonalities
->release();
1007 if (keyIterator
) keyIterator
->release();
1013 /*********************************************************************
1014 * Called from IOCatalogue to add extensions from an mkext archive.
1015 *********************************************************************/
1016 bool addExtensionsFromArchive(OSData
* mkextDataObject
) {
1019 OSDictionary
* startupExtensions
= NULL
; // don't release
1020 OSDictionary
* extensions
= NULL
; // must release
1021 MemoryMapFileInfo mkext_file_info
;
1022 OSCollectionIterator
* keyIterator
= NULL
; // must release
1023 OSString
* key
= NULL
; // don't release
1025 IOLockLock(kld_lock
);
1027 startupExtensions
= getStartupExtensions();
1028 if (!startupExtensions
) {
1029 IOLog("Can't record extension archive; there is no
1030 extensions dictionary.\n");
1036 extensions
= OSDictionary::withCapacity(2);
1038 IOLog("Error: Couldn't allocate dictionary to unpack "
1039 "extension archive.\n");
1045 mkext_file_info
.paddr
= (UInt32
)mkextDataObject
->getBytesNoCopy();
1046 mkext_file_info
.length
= mkextDataObject
->getLength();
1048 result
= extractExtensionsFromArchive(&mkext_file_info
, extensions
);
1050 IOLog("Error: Failed to extract extensions from archive.\n");
1056 result
= mergeExtensionDictionaries(startupExtensions
, extensions
);
1058 IOLog("Error: Failed to merge new extensions into existing set.\n");
1063 result
= addPersonalities(extensions
);
1065 IOLog("Error: Failed to add personalities for extensions extracted "
1075 IOLog("Error: Failed to record extensions from archive.\n");
1078 keyIterator
= OSCollectionIterator::withCollection(
1082 while ( (key
= OSDynamicCast(OSString
,
1083 keyIterator
->getNextObject())) ) {
1085 IOLog("Added extension \"%s\" from archive.\n",
1086 key
->getCStringNoCopy());
1089 keyIterator
->release();
1093 if (extensions
) extensions
->release();
1095 IOLockUnlock(kld_lock
);
1101 /*********************************************************************
1102 * This function builds dictionaries for the startup extensions
1103 * put into memory by bootx, recording each in the startup extensions
1104 * dictionary. The dictionary format is this:
1107 * "plist" = (the extension's Info.plist as an OSDictionary)
1108 * "code" = (an OSData containing the executable file)
1111 * This function returns true if any extensions were found and
1112 * recorded successfully, or if there are no start extensions,
1113 * and false if an unrecoverable error occurred. An error reading
1114 * a single extension is not considered fatal, and this function
1115 * will simply skip the problematic extension to try the next one.
1116 *********************************************************************/
1117 bool recordStartupExtensions(void) {
1119 OSDictionary
* startupExtensions
= NULL
; // must release
1120 OSDictionary
* existingExtensions
= NULL
; // don't release
1121 OSDictionary
* mkextExtensions
= NULL
; // must release
1122 IORegistryEntry
* bootxMemoryMap
= NULL
; // must release
1123 OSDictionary
* propertyDict
= NULL
; // must release
1124 OSCollectionIterator
* keyIterator
= NULL
; // must release
1125 OSString
* key
= NULL
; // don't release
1127 OSDictionary
* newDriverDict
= NULL
; // must release
1128 OSDictionary
* driverPlist
= NULL
; // don't release
1130 IOLockLock(kld_lock
);
1132 IOLog("Recording startup extensions.\n");
1135 existingExtensions
= getStartupExtensions();
1136 if (!existingExtensions
) {
1137 IOLog("Error: There is no dictionary for startup extensions.\n");
1143 startupExtensions
= OSDictionary::withCapacity(1);
1144 if (!startupExtensions
) {
1145 IOLog("Error: Couldn't allocate dictionary "
1146 "to record startup extensions.\n");
1153 IORegistryEntry::fromPath(
1154 "/chosen/memory-map", // path
1157 // return value is retained so be sure to release it
1159 if (!bootxMemoryMap
) {
1160 IOLog("Error: Couldn't read booter memory map.\n");
1166 propertyDict
= bootxMemoryMap
->dictionaryWithProperties();
1167 if (!propertyDict
) {
1168 IOLog("Error: Couldn't get property dictionary "
1169 "from memory map.\n");
1175 keyIterator
= OSCollectionIterator::withCollection(propertyDict
);
1177 IOLog("Error: Couldn't allocate iterator for driver images.\n");
1183 while ( (key
= OSDynamicCast(OSString
,
1184 keyIterator
->getNextObject())) ) {
1186 /* Clear newDriverDict & mkextExtensions upon entry to the loop,
1187 * handling both successful and unsuccessful iterations.
1189 if (newDriverDict
) {
1190 newDriverDict
->release();
1191 newDriverDict
= NULL
;
1193 if (mkextExtensions
) {
1194 mkextExtensions
->release();
1195 mkextExtensions
= NULL
;
1198 const char * keyValue
= key
->getCStringNoCopy();
1200 if ( !strncmp(keyValue
, BOOTX_KEXT_PREFIX
,
1201 strlen(BOOTX_KEXT_PREFIX
)) ) {
1203 /* Read the extension from the bootx-supplied memory.
1205 newDriverDict
= readExtension(propertyDict
, keyValue
);
1206 if (!newDriverDict
) {
1207 IOLog("Error: Couldn't read data "
1208 "for device tree entry \"%s\".\n", keyValue
);
1214 /* Preprare to record the extension by getting its info plist.
1216 driverPlist
= OSDynamicCast(OSDictionary
,
1217 newDriverDict
->getObject("plist"));
1219 IOLog("Error: Extension in device tree entry \"%s\" "
1220 "has no property list.\n", keyValue
);
1226 /* Get the extension's module name. This is used to record
1227 * the extension. Do *not* release the moduleName.
1229 OSString
* moduleName
= OSDynamicCast(OSString
,
1230 driverPlist
->getObject("CFBundleIdentifier"));
1232 IOLog("Error: Device tree entry \"%s\" has "
1233 "no \"CFBundleIdentifier\" property.\n", keyValue
);
1239 /* All has gone well so far, so record the extension under
1240 * its module name, checking for an existing duplicate.
1242 * Do not release moduleName, as it's part of the extension's
1245 OSDictionary
* incumbentExt
= OSDynamicCast(OSDictionary
,
1246 startupExtensions
->getObject(moduleName
));
1248 if (!incumbentExt
) {
1249 startupExtensions
->setObject(moduleName
, newDriverDict
);
1251 OSDictionary
* mostRecentExtension
=
1252 compareExtensionVersions(incumbentExt
, newDriverDict
);
1254 if (mostRecentExtension
== incumbentExt
) {
1255 /* Do nothing, we've got the most recent. */
1256 } else if (mostRecentExtension
== newDriverDict
) {
1257 if (!startupExtensions
->setObject(moduleName
,
1260 /* This is a fatal error, so bail.
1262 IOLog("recordStartupExtensions(): Failed to add "
1264 moduleName
->getCStringNoCopy());
1269 } else /* should be NULL */ {
1271 /* This is a nonfatal error, so continue.
1273 IOLog("recordStartupExtensions(): Error comparing "
1274 "versions of duplicate extensions %s.\n",
1275 moduleName
->getCStringNoCopy());
1282 } else if ( !strncmp(keyValue
, BOOTX_MULTIKEXT_PREFIX
,
1283 strlen(BOOTX_MULTIKEXT_PREFIX
)) ) {
1285 mkextExtensions
= OSDictionary::withCapacity(10);
1286 if (!mkextExtensions
) {
1287 IOLog("Error: Couldn't allocate dictionary to unpack "
1288 "multi-extension archive.\n");
1291 goto finish
; // allocation failure is fatal for this routine
1293 if (!readExtensions(propertyDict
, keyValue
, mkextExtensions
)) {
1294 IOLog("Error: Couldn't unpack multi-extension archive.\n");
1298 if (!mergeExtensionDictionaries(startupExtensions
,
1301 IOLog("Error: Failed to merge new extensions into "
1305 goto finish
; // merge error is fatal for this routine
1310 // Do not release key.
1312 } /* while ( (key = OSDynamicCast(OSString, ... */
1314 if (!mergeExtensionDictionaries(existingExtensions
, startupExtensions
)) {
1315 IOLog("Error: Failed to merge new extensions into existing set.\n");
1321 result
= addPersonalities(startupExtensions
);
1323 IOLog("Error: Failed to add personalities for extensions extracted "
1332 // reused so clear first!
1334 keyIterator
->release();
1339 IOLog("Error: Failed to record startup extensions.\n");
1342 keyIterator
= OSCollectionIterator::withCollection(
1346 while ( (key
= OSDynamicCast(OSString
,
1347 keyIterator
->getNextObject())) ) {
1349 IOLog("Found extension \"%s\".\n",
1350 key
->getCStringNoCopy());
1353 keyIterator
->release();
1358 if (newDriverDict
) newDriverDict
->release();
1359 if (propertyDict
) propertyDict
->release();
1360 if (bootxMemoryMap
) bootxMemoryMap
->release();
1361 if (mkextExtensions
) mkextExtensions
->release();
1362 if (startupExtensions
) startupExtensions
->release();
1364 IOLockUnlock(kld_lock
);
1369 /*********************************************************************
1370 * This function removes an entry from the dictionary of startup
1371 * extensions. It's used when an extension can't be loaded, for
1372 * whatever reason. For drivers, this allows another matching driver
1373 * to be loaded, so that, for example, a driver for the root device
1375 *********************************************************************/
1376 void removeStartupExtension(const char * extensionName
) {
1377 OSDictionary
* startupExtensions
= NULL
; // don't release
1378 OSDictionary
* extensionDict
= NULL
; // don't release
1379 OSDictionary
* extensionPlist
= NULL
; // don't release
1380 OSDictionary
* extensionPersonalities
= NULL
; // don't release
1381 OSDictionary
* personality
= NULL
; // don't release
1382 OSCollectionIterator
* keyIterator
= NULL
; // must release
1383 OSString
* key
= NULL
; // don't release
1385 IOLockLock(kld_lock
);
1387 startupExtensions
= getStartupExtensions();
1388 if (!startupExtensions
) goto finish
;
1391 /* Find the extension's entry in the dictionary of
1392 * startup extensions.
1394 extensionDict
= OSDynamicCast(OSDictionary
,
1395 startupExtensions
->getObject(extensionName
));
1396 if (!extensionDict
) goto finish
;
1398 extensionPlist
= OSDynamicCast(OSDictionary
,
1399 extensionDict
->getObject("plist"));
1400 if (!extensionPlist
) goto finish
;
1402 extensionPersonalities
= OSDynamicCast(OSDictionary
,
1403 extensionPlist
->getObject("IOKitPersonalities"));
1404 if (!extensionPersonalities
) goto finish
;
1406 /* If it was there, remove it from the catalogue proper
1407 * by calling removeDrivers(). Pass true for the second
1408 * argument to trigger a new round of matching, and
1409 * then remove the extension from the dictionary of startup
1412 keyIterator
= OSCollectionIterator::withCollection(
1413 extensionPersonalities
);
1415 IOLog("Error: Couldn't allocate iterator to scan
1416 personalities for %s.\n", extensionName
);
1420 while ((key
= OSDynamicCast(OSString
, keyIterator
->getNextObject()))) {
1421 personality
= OSDynamicCast(OSDictionary
,
1422 extensionPersonalities
->getObject(key
));
1426 gIOCatalogue
->removeDrivers(personality
, true);
1430 startupExtensions
->removeObject(extensionName
);
1434 if (keyIterator
) keyIterator
->release();
1436 IOLockUnlock(kld_lock
);