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>
43 extern void IODTFreeLoaderInfo( char *key
, void *infoAddr
, int infoSize
);
44 extern kern_return_t
host_info(host_t host
,
47 mach_msg_type_number_t
*count
);
48 extern int check_cpu_subtype(cpu_subtype_t cpu_subtype
);
54 #define VTYELLOW "\033[33m"
55 #define VTRESET "\033[0m"
58 /*********************************************************************
59 *********************************************************************/
60 static OSDictionary
* gStartupExtensions
= 0;
61 static OSArray
* gBootLoaderObjects
= 0;
63 OSDictionary
* getStartupExtensions(void) {
64 if (gStartupExtensions
) {
65 return gStartupExtensions
;
67 gStartupExtensions
= OSDictionary::withCapacity(1);
68 if (!gStartupExtensions
) {
69 IOLog("Error: Couldn't allocate "
70 "startup extensions dictionary.\n");
73 return gStartupExtensions
;
76 /* This array holds objects that are needed to be held around during
77 * boot before kextd starts up. Currently it contains OSData objects
78 * copied from OF entries for mkext archives in device ROMs. Because
79 * the Device Tree support code dumps these after initially handing
80 * them to us, we have to be able to clean them up later.
82 OSArray
* getBootLoaderObjects(void) {
83 if (gBootLoaderObjects
) {
84 return gBootLoaderObjects
;
86 gBootLoaderObjects
= OSArray::withCapacity(1);
87 if (! gBootLoaderObjects
) {
88 IOLog("Error: Couldn't allocate "
89 "bootstrap objects array.\n");
92 return gBootLoaderObjects
;
96 /*********************************************************************
97 * This function checks that a driver dict has all the required
98 * entries and does a little bit of value checking too.
99 *********************************************************************/
100 bool validateExtensionDict(OSDictionary
* extension
) {
103 OSString
* name
; // do not release
104 OSString
* stringValue
; // do not release
107 name
= OSDynamicCast(OSString
,
108 extension
->getObject("CFBundleIdentifier"));
110 IOLog(VTYELLOW
"Extension has no \"CFBundleIdentifier\" property.\n"
117 stringValue
= OSDynamicCast(OSString
,
118 extension
->getObject("CFBundleVersion"));
120 IOLog(VTYELLOW
"Extension \"%s\" has no \"CFBundleVersion\" "
121 "property.\n" VTRESET
,
122 name
->getCStringNoCopy());
127 if (!VERS_parse_string(stringValue
->getCStringNoCopy(),
129 IOLog(VTYELLOW
"Extension \"%s\" has an invalid "
130 "\"CFBundleVersion\" property.\n" VTRESET
,
131 name
->getCStringNoCopy());
139 // FIXME: Make return real result after kext conversion
146 /*********************************************************************
147 *********************************************************************/
148 OSDictionary
* compareExtensionVersions(
149 OSDictionary
* incumbent
,
150 OSDictionary
* candidate
) {
152 OSDictionary
* winner
= NULL
;
154 OSDictionary
* incumbentPlist
= NULL
;
155 OSDictionary
* candidatePlist
= NULL
;
156 OSString
* incumbentName
= NULL
;
157 OSString
* candidateName
= NULL
;
158 OSString
* incumbentVersionString
= NULL
;
159 OSString
* candidateVersionString
= NULL
;
160 UInt32 incumbent_vers
= 0;
161 UInt32 candidate_vers
= 0;
163 incumbentPlist
= OSDynamicCast(OSDictionary
,
164 incumbent
->getObject("plist"));
165 candidatePlist
= OSDynamicCast(OSDictionary
,
166 candidate
->getObject("plist"));
168 if (!incumbentPlist
|| !candidatePlist
) {
169 IOLog("compareExtensionVersions() called with invalid "
170 "extension dictionaries.\n");
176 incumbentName
= OSDynamicCast(OSString
,
177 incumbentPlist
->getObject("CFBundleIdentifier"));
178 candidateName
= OSDynamicCast(OSString
,
179 candidatePlist
->getObject("CFBundleIdentifier"));
180 incumbentVersionString
= OSDynamicCast(OSString
,
181 incumbentPlist
->getObject("CFBundleVersion"));
182 candidateVersionString
= OSDynamicCast(OSString
,
183 candidatePlist
->getObject("CFBundleVersion"));
185 if (!incumbentName
|| !candidateName
||
186 !incumbentVersionString
|| !candidateVersionString
) {
188 IOLog("compareExtensionVersions() called with invalid "
189 "extension dictionaries.\n");
195 if (strcmp(incumbentName
->getCStringNoCopy(),
196 candidateName
->getCStringNoCopy())) {
198 IOLog("compareExtensionVersions() called with different "
199 "extension names (%s and %s).\n",
200 incumbentName
->getCStringNoCopy(),
201 candidateName
->getCStringNoCopy());
207 if (!VERS_parse_string(incumbentVersionString
->getCStringNoCopy(),
210 IOLog(VTYELLOW
"Error parsing version string for extension %s (%s)\n"
212 incumbentName
->getCStringNoCopy(),
213 incumbentVersionString
->getCStringNoCopy());
219 if (!VERS_parse_string(candidateVersionString
->getCStringNoCopy(),
222 IOLog(VTYELLOW
"Error parsing version string for extension %s (%s)\n"
224 candidateName
->getCStringNoCopy(),
225 candidateVersionString
->getCStringNoCopy());
231 if (candidate_vers
> incumbent_vers
) {
232 IOLog(VTYELLOW
"Replacing extension \"%s\" with newer version "
233 "(%s -> %s).\n" VTRESET
,
234 incumbentName
->getCStringNoCopy(),
235 incumbentVersionString
->getCStringNoCopy(),
236 candidateVersionString
->getCStringNoCopy());
241 IOLog(VTYELLOW
"Skipping duplicate extension \"%s\" with older/same "
242 " version (%s -> %s).\n" VTRESET
,
243 candidateName
->getCStringNoCopy(),
244 candidateVersionString
->getCStringNoCopy(),
245 incumbentVersionString
->getCStringNoCopy());
253 // no cleanup, how nice
258 /*********************************************************************
259 * This function merges entries in the mergeFrom dictionary into the
260 * mergeInto dictionary. If it returns false, the two dictionaries are
261 * not altered. If it returns true, then mergeInto may have new
262 * entries; any keys that were already present in mergeInto are
263 * removed from mergeFrom, so that the caller can see what was
265 *********************************************************************/
266 bool mergeExtensionDictionaries(OSDictionary
* mergeInto
,
267 OSDictionary
* mergeFrom
) {
270 OSDictionary
* mergeIntoCopy
= NULL
; // must release
271 OSDictionary
* mergeFromCopy
= NULL
; // must release
272 OSCollectionIterator
* keyIterator
= NULL
; // must release
273 OSString
* key
; // don't release
275 /* Add 1 to count to guarantee copy can grow (grr).
277 mergeIntoCopy
= OSDictionary::withDictionary(mergeInto
,
278 mergeInto
->getCount() + 1);
279 if (!mergeIntoCopy
) {
280 IOLog("Error: Failed to copy 'into' extensions dictionary "
287 /* Add 1 to count to guarantee copy can grow (grr).
289 mergeFromCopy
= OSDictionary::withDictionary(mergeFrom
,
290 mergeFrom
->getCount() + 1);
291 if (!mergeFromCopy
) {
292 IOLog("Error: Failed to copy 'from' extensions dictionary "
299 keyIterator
= OSCollectionIterator::withCollection(mergeFrom
);
301 IOLog("Error: Failed to allocate iterator for extensions.\n");
309 * Loop through "from" dictionary, checking if the identifier already
310 * exists in the "into" dictionary and checking versions if it does.
312 while ((key
= OSDynamicCast(OSString
, keyIterator
->getNextObject()))) {
313 OSDictionary
* incumbentExt
= OSDynamicCast(OSDictionary
,
314 mergeIntoCopy
->getObject(key
));
315 OSDictionary
* candidateExt
= OSDynamicCast(OSDictionary
,
316 mergeFrom
->getObject(key
));
319 if (!mergeIntoCopy
->setObject(key
, candidateExt
)) {
321 /* This is a fatal error, so bail.
323 IOLog("mergeExtensionDictionaries(): Failed to add "
325 key
->getCStringNoCopy());
331 OSDictionary
* mostRecentExtension
=
332 compareExtensionVersions(incumbentExt
, candidateExt
);
334 if (mostRecentExtension
== incumbentExt
) {
335 mergeFromCopy
->removeObject(key
);
336 } else if (mostRecentExtension
== candidateExt
) {
338 if (!mergeIntoCopy
->setObject(key
, candidateExt
)) {
340 /* This is a fatal error, so bail.
342 IOLog("mergeExtensionDictionaries(): Failed to add "
344 key
->getCStringNoCopy());
349 } else /* should be NULL */ {
351 /* This is a nonfatal error, so continue doing others.
353 IOLog("mergeExtensionDictionaries(): Error comparing "
354 "versions of duplicate extensions %s.\n",
355 key
->getCStringNoCopy());
364 /* If successful, replace the contents of the original
365 * dictionaries with those of the modified copies.
368 mergeInto
->flushCollection();
369 mergeInto
->merge(mergeIntoCopy
);
370 mergeFrom
->flushCollection();
371 mergeFrom
->merge(mergeFromCopy
);
374 if (mergeIntoCopy
) mergeIntoCopy
->release();
375 if (mergeFromCopy
) mergeFromCopy
->release();
376 if (keyIterator
) keyIterator
->release();
383 * These bits are used to parse data made available by bootx.
385 #define BOOTX_KEXT_PREFIX "Driver-"
386 #define BOOTX_MULTIKEXT_PREFIX "DriversPackage-"
388 typedef struct MemoryMapFileInfo
{
393 typedef struct BootxDriverInfo
{
400 typedef struct MkextEntryInfo
{
401 vm_address_t base_address
;
402 mkext_file
* fileinfo
;
406 /*********************************************************************
407 * This private function reads the data for a single extension from
408 * the bootx memory-map's propery dict, returning a dictionary with
409 * keys "plist" for the extension's Info.plist as a parsed OSDictionary
410 * and "code" for the extension's executable code as an OSData.
411 *********************************************************************/
412 OSDictionary
* readExtension(OSDictionary
* propertyDict
,
413 const char * memory_map_name
) {
416 OSData
* bootxDriverDataObject
= NULL
;
417 OSDictionary
* driverPlist
= NULL
;
418 OSString
* driverName
= NULL
;
419 OSData
* driverCode
= NULL
;
420 OSString
* errorString
= NULL
;
421 OSDictionary
* driverDict
= NULL
;
423 MemoryMapFileInfo
* driverInfo
= 0;
424 BootxDriverInfo
* dataBuffer
;
426 kmod_info_t
* loaded_kmod
= NULL
;
428 bootxDriverDataObject
= OSDynamicCast(OSData
,
429 propertyDict
->getObject(memory_map_name
));
430 // don't release bootxDriverDataObject
432 if (!bootxDriverDataObject
) {
433 IOLog("Error: No driver data object "
434 "for device tree entry \"%s\".\n",
441 driverDict
= OSDictionary::withCapacity(2);
443 IOLog("Error: Couldn't allocate dictionary "
444 "for device tree entry \"%s\".\n", memory_map_name
);
450 driverInfo
= (MemoryMapFileInfo
*)
451 bootxDriverDataObject
->getBytesNoCopy(0,
452 sizeof(MemoryMapFileInfo
));
453 dataBuffer
= (BootxDriverInfo
*)ml_static_ptovirt(
456 IOLog("Error: No data buffer "
457 "for device tree entry \"%s\".\n", memory_map_name
);
463 driverPlist
= OSDynamicCast(OSDictionary
,
464 OSUnserializeXML(dataBuffer
->plistAddr
, &errorString
));
466 IOLog("Error: Couldn't read XML property list "
467 "for device tree entry \"%s\".\n", memory_map_name
);
470 IOLog("XML parse error: %s.\n",
471 errorString
->getCStringNoCopy());
479 driverName
= OSDynamicCast(OSString
,
480 driverPlist
->getObject("CFBundleIdentifier")); // do not release
482 IOLog("Error: Device tree entry \"%s\" has "
483 "no \"CFBundleIdentifier\" property.\n", memory_map_name
);
489 /* Check if kmod is already loaded and is a real loadable one (has
492 loaded_kmod
= kmod_lookupbyname_locked(driverName
->getCStringNoCopy());
493 if (loaded_kmod
&& loaded_kmod
->address
) {
494 IOLog("Skipping new extension \"%s\"; an extension named "
495 "\"%s\" is already loaded.\n",
496 driverName
->getCStringNoCopy(),
503 if (!validateExtensionDict(driverPlist
)) {
504 IOLog("Error: Failed to validate property list "
505 "for device tree entry \"%s\".\n", memory_map_name
);
511 driverDict
->setObject("plist", driverPlist
);
513 /* It's perfectly okay for a KEXT to have no executable.
514 * Check that moduleAddr is nonzero before attempting to
517 * NOTE: The driverCode object is created "no-copy", so
518 * it doesn't own that memory. The memory must be freed
519 * separately from the OSData object (see
520 * clearStartupExtensionsAndLoaderInfo() at the end of this file).
522 if (dataBuffer
->moduleAddr
&& dataBuffer
->moduleLength
) {
523 driverCode
= OSData::withBytesNoCopy(dataBuffer
->moduleAddr
,
524 dataBuffer
->moduleLength
);
526 IOLog("Error: Couldn't allocate data object "
527 "to hold code for device tree entry \"%s\".\n",
535 driverDict
->setObject("code", driverCode
);
542 kfree(loaded_kmod
, sizeof(kmod_info_t
));
545 // do not release bootxDriverDataObject
546 // do not release driverName
549 driverPlist
->release();
552 errorString
->release();
555 driverCode
->release();
559 driverDict
->release();
567 /*********************************************************************
568 * Used to uncompress a single file entry in an mkext archive.
570 * The OSData returned does not own its memory! You must deallocate
571 * that memory using kmem_free() before releasing the OSData().
572 *********************************************************************/
573 static bool uncompressFile(u_int8_t
*base_address
, mkext_file
* fileinfo
,
574 /* out */ OSData
** file
) {
577 kern_return_t kern_result
;
578 u_int8_t
* uncompressed_file
= 0; // kmem_free() on error
579 OSData
* uncompressedFile
= 0; // returned
580 size_t uncompressed_size
= 0;
582 size_t offset
= OSSwapBigToHostInt32(fileinfo
->offset
);
583 size_t compsize
= OSSwapBigToHostInt32(fileinfo
->compsize
);
584 size_t realsize
= OSSwapBigToHostInt32(fileinfo
->realsize
);
585 time_t modifiedsecs
= OSSwapBigToHostInt32(fileinfo
->modifiedsecs
);
589 /* If these four fields are zero there's no file, but that isn't
592 if (offset
== 0 && compsize
== 0 &&
593 realsize
== 0 && modifiedsecs
== 0) {
597 // Add 1 for '\0' to terminate XML string!
598 kern_result
= kmem_alloc(kernel_map
, (vm_offset_t
*)&uncompressed_file
,
600 if (kern_result
!= KERN_SUCCESS
) {
601 IOLog("Error: Couldn't allocate data buffer "
602 "to uncompress file.\n");
608 uncompressedFile
= OSData::withBytesNoCopy(uncompressed_file
,
610 if (!uncompressedFile
) {
611 IOLog("Error: Couldn't allocate data object "
612 "to uncompress file.\n");
619 uncompressed_size
= decompress_lzss(uncompressed_file
,
620 base_address
+ offset
,
622 if (uncompressed_size
!= realsize
) {
623 IOLog("Error: Uncompressed file is not the length "
629 uncompressed_file
[uncompressed_size
] = '\0';
631 bcopy(base_address
+ offset
, uncompressed_file
,
633 uncompressed_file
[realsize
] = '\0';
636 *file
= uncompressedFile
;
640 if (uncompressed_file
) {
641 kmem_free(kernel_map
, (vm_address_t
)uncompressed_file
,
644 if (uncompressedFile
) {
645 uncompressedFile
->release();
652 bool uncompressModule(OSData
*compData
, /* out */ OSData
** file
) {
654 MkextEntryInfo
*info
= (MkextEntryInfo
*) compData
->getBytesNoCopy();
656 return uncompressFile((u_int8_t
*) info
->base_address
,
657 info
->fileinfo
, file
);
661 /*********************************************************************
662 * Does the work of pulling extensions out of an mkext archive located
664 *********************************************************************/
665 bool extractExtensionsFromArchive(MemoryMapFileInfo
* mkext_file_info
,
666 OSDictionary
* extensions
) {
670 u_int8_t
* crc_address
= 0;
672 mkext_header
* mkext_data
= 0; // don't free
673 mkext_kext
* onekext_data
= 0; // don't free
674 mkext_file
* plist_file
= 0; // don't free
675 mkext_file
* module_file
= 0; // don't free
676 kmod_info_t
* loaded_kmod
= 0; // must free
678 OSData
* driverPlistDataObject
= 0; // must release
679 OSDictionary
* driverPlist
= 0; // must release
680 OSData
* driverCode
= 0; // must release
681 OSDictionary
* driverDict
= 0; // must release
682 OSString
* moduleName
= 0; // don't release
683 OSString
* errorString
= NULL
; // must release
685 OSData
* moduleInfo
= 0; // must release
686 MkextEntryInfo module_info
;
688 mkext_data
= (mkext_header
*)mkext_file_info
->paddr
;
690 if (OSSwapBigToHostInt32(mkext_data
->magic
) != MKEXT_MAGIC
||
691 OSSwapBigToHostInt32(mkext_data
->signature
) != MKEXT_SIGN
) {
692 IOLog("Error: Extension archive has invalid magic or signature.\n");
698 if (OSSwapBigToHostInt32(mkext_data
->length
) != mkext_file_info
->length
) {
699 IOLog("Error: Mismatch between extension archive & "
700 "recorded length.\n");
706 crc_address
= (u_int8_t
*)&mkext_data
->version
;
707 checksum
= adler32(crc_address
,
708 (unsigned int)mkext_data
+
709 OSSwapBigToHostInt32(mkext_data
->length
) - (unsigned int)crc_address
);
711 if (OSSwapBigToHostInt32(mkext_data
->adler32
) != checksum
) {
712 IOLog("Error: Extension archive has a bad checksum.\n");
718 /* If the MKEXT archive isn't fat, check that the CPU type & subtype
719 * match that of the running kernel.
721 if (OSSwapBigToHostInt32(mkext_data
->cputype
) != (UInt32
)CPU_TYPE_ANY
) {
722 kern_return_t kresult
= KERN_FAILURE
;
723 host_basic_info_data_t hostinfo
;
724 host_info_t hostinfo_ptr
= (host_info_t
)&hostinfo
;
725 mach_msg_type_number_t count
= sizeof(hostinfo
)/sizeof(integer_t
);
727 kresult
= host_info((host_t
)1, HOST_BASIC_INFO
,
728 hostinfo_ptr
, &count
);
729 if (kresult
!= KERN_SUCCESS
) {
730 IOLog("Error: Couldn't get current host info.\n");
735 if ((UInt32
)hostinfo
.cpu_type
!=
736 OSSwapBigToHostInt32(mkext_data
->cputype
)) {
738 IOLog("Error: Extension archive doesn't contain software "
739 "for this computer's CPU type.\n");
744 if (!check_cpu_subtype(OSSwapBigToHostInt32(mkext_data
->cpusubtype
))) {
745 IOLog("Error: Extension archive doesn't contain software "
746 "for this computer's CPU subtype.\n");
753 for (unsigned int i
= 0;
754 i
< OSSwapBigToHostInt32(mkext_data
->numkexts
);
758 kfree(loaded_kmod
, sizeof(kmod_info_t
));
762 if (driverPlistDataObject
) {
763 driverPlistDataObject
->release();
764 driverPlistDataObject
= NULL
;
767 driverPlist
->release();
771 driverCode
->release();
775 driverDict
->release();
779 errorString
->release();
783 onekext_data
= &mkext_data
->kext
[i
];
784 plist_file
= &onekext_data
->plist
;
785 module_file
= &onekext_data
->module;
787 if (!uncompressFile((u_int8_t
*)mkext_data
, plist_file
,
788 &driverPlistDataObject
)) {
790 IOLog("Error: couldn't uncompress plist file "
791 "from multikext archive entry %d.\n", i
);
796 if (!driverPlistDataObject
) {
797 IOLog("Error: No property list present "
798 "for multikext archive entry %d.\n", i
);
802 driverPlist
= OSDynamicCast(OSDictionary
,
804 (char *)driverPlistDataObject
->getBytesNoCopy(),
807 IOLog("Error: Couldn't read XML property list "
808 "for multikext archive entry %d.\n", i
);
811 IOLog("XML parse error: %s.\n",
812 errorString
->getCStringNoCopy());
818 if (!validateExtensionDict(driverPlist
)) {
819 IOLog("Error: Failed to validate property list "
820 "for multikext archive entry %d.\n", i
);
827 /* Get the extension's module name. This is used to record
830 moduleName
= OSDynamicCast(OSString
,
831 driverPlist
->getObject("CFBundleIdentifier")); // do not release
833 IOLog("Error: Multikext archive entry %d has "
834 "no \"CFBundleIdentifier\" property.\n", i
);
836 continue; // assume a kext config error & continue
839 /* Check if kmod is already loaded and is a real loadable one (has
842 loaded_kmod
= kmod_lookupbyname_locked(moduleName
->getCStringNoCopy());
843 if (loaded_kmod
&& loaded_kmod
->address
) {
844 IOLog("Skipping new extension \"%s\"; an extension named "
845 "\"%s\" is already loaded.\n",
846 moduleName
->getCStringNoCopy(),
852 driverDict
= OSDictionary::withCapacity(2);
854 IOLog("Error: Couldn't allocate dictionary "
855 "for multikext archive entry %d.\n", i
);
861 driverDict
->setObject("plist", driverPlist
);
864 * Prepare an entry to hold the mkext entry info for the
865 * compressed binary module, if there is one. If all four fields
866 * of the module entry are zero, there isn't one.
868 if (OSSwapBigToHostInt32(module_file
->offset
) ||
869 OSSwapBigToHostInt32(module_file
->compsize
) ||
870 OSSwapBigToHostInt32(module_file
->realsize
) ||
871 OSSwapBigToHostInt32(module_file
->modifiedsecs
)) {
873 moduleInfo
= OSData::withCapacity(sizeof(MkextEntryInfo
));
875 IOLog("Error: Couldn't allocate data object "
876 "for multikext archive entry %d.\n", i
);
882 module_info
.base_address
= (vm_address_t
)mkext_data
;
883 module_info
.fileinfo
= module_file
;
885 if (!moduleInfo
->appendBytes(&module_info
, sizeof(module_info
))) {
886 IOLog("Error: Couldn't record info "
887 "for multikext archive entry %d.\n", i
);
893 driverDict
->setObject("compressedCode", moduleInfo
);
896 OSDictionary
* incumbentExt
= OSDynamicCast(OSDictionary
,
897 extensions
->getObject(moduleName
));
900 extensions
->setObject(moduleName
, driverDict
);
902 OSDictionary
* mostRecentExtension
=
903 compareExtensionVersions(incumbentExt
, driverDict
);
905 if (mostRecentExtension
== incumbentExt
) {
906 /* Do nothing, we've got the most recent. */
907 } else if (mostRecentExtension
== driverDict
) {
908 if (!extensions
->setObject(moduleName
, driverDict
)) {
910 /* This is a fatal error, so bail.
912 IOLog("extractExtensionsFromArchive(): Failed to add "
914 moduleName
->getCStringNoCopy());
919 } else /* should be NULL */ {
921 /* This is a nonfatal error, so continue.
923 IOLog("extractExtensionsFromArchive(): Error comparing "
924 "versions of duplicate extensions %s.\n",
925 moduleName
->getCStringNoCopy());
934 if (loaded_kmod
) kfree(loaded_kmod
, sizeof(kmod_info_t
));
935 if (driverPlistDataObject
) driverPlistDataObject
->release();
936 if (driverPlist
) driverPlist
->release();
937 if (driverCode
) driverCode
->release();
938 if (moduleInfo
) moduleInfo
->release();
939 if (driverDict
) driverDict
->release();
940 if (errorString
) errorString
->release();
945 /*********************************************************************
947 *********************************************************************/
948 bool readExtensions(OSDictionary
* propertyDict
,
949 const char * memory_map_name
,
950 OSDictionary
* extensions
) {
953 OSData
* mkextDataObject
= 0; // don't release
954 MemoryMapFileInfo
* mkext_file_info
= 0; // don't free
956 mkextDataObject
= OSDynamicCast(OSData
,
957 propertyDict
->getObject(memory_map_name
));
958 // don't release mkextDataObject
960 if (!mkextDataObject
) {
961 IOLog("Error: No mkext data object "
962 "for device tree entry \"%s\".\n",
969 mkext_file_info
= (MemoryMapFileInfo
*)mkextDataObject
->getBytesNoCopy();
970 if (!mkext_file_info
) {
975 result
= extractExtensionsFromArchive(mkext_file_info
, extensions
);
979 if (!result
&& extensions
) {
980 extensions
->flushCollection();
987 /*********************************************************************
988 * Adds the personalities for an extensions dictionary to the global
990 *********************************************************************/
991 bool addPersonalities(OSDictionary
* extensions
) {
993 OSCollectionIterator
* keyIterator
= NULL
; // must release
994 OSString
* key
; // don't release
995 OSDictionary
* driverDict
= NULL
; // don't release
996 OSDictionary
* driverPlist
= NULL
; // don't release
997 OSDictionary
* thisDriverPersonalities
= NULL
; // don't release
998 OSArray
* allDriverPersonalities
= NULL
; // must release
1000 allDriverPersonalities
= OSArray::withCapacity(1);
1001 if (!allDriverPersonalities
) {
1002 IOLog("Error: Couldn't allocate personality dictionary.\n");
1008 /* Record all personalities found so that they can be
1009 * added to the catalogue.
1010 * Note: Not all extensions have personalities.
1013 keyIterator
= OSCollectionIterator::withCollection(extensions
);
1015 IOLog("Error: Couldn't allocate iterator to record personalities.\n");
1021 while ( ( key
= OSDynamicCast(OSString
,
1022 keyIterator
->getNextObject() ))) {
1024 driverDict
= OSDynamicCast(OSDictionary
,
1025 extensions
->getObject(key
));
1026 driverPlist
= OSDynamicCast(OSDictionary
,
1027 driverDict
->getObject("plist"));
1028 thisDriverPersonalities
= OSDynamicCast(OSDictionary
,
1029 driverPlist
->getObject("IOKitPersonalities"));
1031 if (thisDriverPersonalities
) {
1032 OSCollectionIterator
* pIterator
;
1034 pIterator
= OSCollectionIterator::withCollection(
1035 thisDriverPersonalities
);
1037 IOLog("Error: Couldn't allocate iterator "
1038 "to record extension personalities.\n");
1042 while ( (key
= OSDynamicCast(OSString
,
1043 pIterator
->getNextObject())) ) {
1045 OSDictionary
* personality
= OSDynamicCast(
1047 thisDriverPersonalities
->getObject(key
));
1049 allDriverPersonalities
->setObject(personality
);
1052 pIterator
->release();
1054 } /* extract personalities */
1057 /* Add all personalities found to the IOCatalogue,
1058 * but don't start matching.
1060 gIOCatalogue
->addDrivers(allDriverPersonalities
, false);
1064 if (allDriverPersonalities
) allDriverPersonalities
->release();
1065 if (keyIterator
) keyIterator
->release();
1071 /*********************************************************************
1072 * Called from IOCatalogue to add extensions from an mkext archive.
1073 * This function makes a copy of the mkext object passed in because
1074 * the device tree support code dumps it after calling us (indirectly
1075 * through the IOCatalogue).
1076 *********************************************************************/
1077 bool addExtensionsFromArchive(OSData
* mkextDataObject
) {
1080 OSDictionary
* startupExtensions
= NULL
; // don't release
1081 OSArray
* bootLoaderObjects
= NULL
; // don't release
1082 OSData
* localMkextDataObject
= NULL
; // don't release
1083 OSDictionary
* extensions
= NULL
; // must release
1084 MemoryMapFileInfo mkext_file_info
;
1085 OSCollectionIterator
* keyIterator
= NULL
; // must release
1086 OSString
* key
= NULL
; // don't release
1088 startupExtensions
= getStartupExtensions();
1089 if (!startupExtensions
) {
1090 IOLog("Can't record extension archive; there is no"
1091 " extensions dictionary.\n");
1097 bootLoaderObjects
= getBootLoaderObjects();
1098 if (! bootLoaderObjects
) {
1099 IOLog("Error: Couldn't allocate array to hold temporary objects.\n");
1105 extensions
= OSDictionary::withCapacity(2);
1107 IOLog("Error: Couldn't allocate dictionary to unpack "
1108 "extension archive.\n");
1114 /* The mkext we've been handed (or the data it references) can go away,
1115 * so we need to make a local copy to keep around as long as it might
1118 localMkextDataObject
= OSData::withData(mkextDataObject
);
1119 if (!localMkextDataObject
) {
1120 IOLog("Error: Couldn't copy extension archive.\n");
1126 mkext_file_info
.paddr
= (UInt32
)localMkextDataObject
->getBytesNoCopy();
1127 mkext_file_info
.length
= localMkextDataObject
->getLength();
1129 /* Save the local mkext data object so that we can deallocate it later.
1131 bootLoaderObjects
->setObject(localMkextDataObject
);
1132 localMkextDataObject
->release();
1134 result
= extractExtensionsFromArchive(&mkext_file_info
, extensions
);
1136 IOLog("Error: Failed to extract extensions from archive.\n");
1142 result
= mergeExtensionDictionaries(startupExtensions
, extensions
);
1144 IOLog("Error: Failed to merge new extensions into existing set.\n");
1149 result
= addPersonalities(extensions
);
1151 IOLog("Error: Failed to add personalities for extensions extracted "
1161 IOLog("Error: Failed to record extensions from archive.\n");
1164 keyIterator
= OSCollectionIterator::withCollection(
1168 while ( (key
= OSDynamicCast(OSString
,
1169 keyIterator
->getNextObject())) ) {
1171 IOLog("Added extension \"%s\" from archive.\n",
1172 key
->getCStringNoCopy());
1175 keyIterator
->release();
1179 if (extensions
) extensions
->release();
1185 /*********************************************************************
1186 * This function builds dictionaries for the startup extensions
1187 * put into memory by bootx, recording each in the startup extensions
1188 * dictionary. The dictionary format is this:
1191 * "plist" = (the extension's Info.plist as an OSDictionary)
1192 * "code" = (an OSData containing the executable file)
1195 * This function returns true if any extensions were found and
1196 * recorded successfully, or if there are no start extensions,
1197 * and false if an unrecoverable error occurred. An error reading
1198 * a single extension is not considered fatal, and this function
1199 * will simply skip the problematic extension to try the next one.
1200 *********************************************************************/
1201 bool recordStartupExtensions(void) {
1203 OSDictionary
* startupExtensions
= NULL
; // must release
1204 OSDictionary
* existingExtensions
= NULL
; // don't release
1205 OSDictionary
* mkextExtensions
= NULL
; // must release
1206 IORegistryEntry
* bootxMemoryMap
= NULL
; // must release
1207 OSDictionary
* propertyDict
= NULL
; // must release
1208 OSCollectionIterator
* keyIterator
= NULL
; // must release
1209 OSString
* key
= NULL
; // don't release
1211 OSDictionary
* newDriverDict
= NULL
; // must release
1212 OSDictionary
* driverPlist
= NULL
; // don't release
1214 IOLog("Recording startup extensions.\n");
1217 existingExtensions
= getStartupExtensions();
1218 if (!existingExtensions
) {
1219 IOLog("Error: There is no dictionary for startup extensions.\n");
1225 startupExtensions
= OSDictionary::withCapacity(1);
1226 if (!startupExtensions
) {
1227 IOLog("Error: Couldn't allocate dictionary "
1228 "to record startup extensions.\n");
1235 IORegistryEntry::fromPath(
1236 "/chosen/memory-map", // path
1239 // return value is retained so be sure to release it
1241 if (!bootxMemoryMap
) {
1242 IOLog("Error: Couldn't read booter memory map.\n");
1248 propertyDict
= bootxMemoryMap
->dictionaryWithProperties();
1249 if (!propertyDict
) {
1250 IOLog("Error: Couldn't get property dictionary "
1251 "from memory map.\n");
1257 keyIterator
= OSCollectionIterator::withCollection(propertyDict
);
1259 IOLog("Error: Couldn't allocate iterator for driver images.\n");
1265 while ( (key
= OSDynamicCast(OSString
,
1266 keyIterator
->getNextObject())) ) {
1267 /* Clear newDriverDict & mkextExtensions upon entry to the loop,
1268 * handling both successful and unsuccessful iterations.
1270 if (newDriverDict
) {
1271 newDriverDict
->release();
1272 newDriverDict
= NULL
;
1274 if (mkextExtensions
) {
1275 mkextExtensions
->release();
1276 mkextExtensions
= NULL
;
1279 const char * keyValue
= key
->getCStringNoCopy();
1281 if ( !strncmp(keyValue
, BOOTX_KEXT_PREFIX
,
1282 strlen(BOOTX_KEXT_PREFIX
)) ) {
1284 /* Read the extension from the bootx-supplied memory.
1286 newDriverDict
= readExtension(propertyDict
, keyValue
);
1287 if (!newDriverDict
) {
1288 IOLog("Error: Couldn't read data "
1289 "for device tree entry \"%s\".\n", keyValue
);
1295 /* Preprare to record the extension by getting its info plist.
1297 driverPlist
= OSDynamicCast(OSDictionary
,
1298 newDriverDict
->getObject("plist"));
1300 IOLog("Error: Extension in device tree entry \"%s\" "
1301 "has no property list.\n", keyValue
);
1307 /* Get the extension's module name. This is used to record
1308 * the extension. Do *not* release the moduleName.
1310 OSString
* moduleName
= OSDynamicCast(OSString
,
1311 driverPlist
->getObject("CFBundleIdentifier"));
1313 IOLog("Error: Device tree entry \"%s\" has "
1314 "no \"CFBundleIdentifier\" property.\n", keyValue
);
1320 /* All has gone well so far, so record the extension under
1321 * its module name, checking for an existing duplicate.
1323 * Do not release moduleName, as it's part of the extension's
1326 OSDictionary
* incumbentExt
= OSDynamicCast(OSDictionary
,
1327 startupExtensions
->getObject(moduleName
));
1329 if (!incumbentExt
) {
1330 startupExtensions
->setObject(moduleName
, newDriverDict
);
1332 OSDictionary
* mostRecentExtension
=
1333 compareExtensionVersions(incumbentExt
, newDriverDict
);
1335 if (mostRecentExtension
== incumbentExt
) {
1336 /* Do nothing, we've got the most recent. */
1337 } else if (mostRecentExtension
== newDriverDict
) {
1338 if (!startupExtensions
->setObject(moduleName
,
1341 /* This is a fatal error, so bail.
1343 IOLog("recordStartupExtensions(): Failed to add "
1345 moduleName
->getCStringNoCopy());
1350 } else /* should be NULL */ {
1352 /* This is a nonfatal error, so continue.
1354 IOLog("recordStartupExtensions(): Error comparing "
1355 "versions of duplicate extensions %s.\n",
1356 moduleName
->getCStringNoCopy());
1363 } else if ( !strncmp(keyValue
, BOOTX_MULTIKEXT_PREFIX
,
1364 strlen(BOOTX_MULTIKEXT_PREFIX
)) ) {
1366 mkextExtensions
= OSDictionary::withCapacity(10);
1367 if (!mkextExtensions
) {
1368 IOLog("Error: Couldn't allocate dictionary to unpack "
1369 "multi-extension archive.\n");
1372 goto finish
; // allocation failure is fatal for this routine
1374 if (!readExtensions(propertyDict
, keyValue
, mkextExtensions
)) {
1375 IOLog("Error: Couldn't unpack multi-extension archive.\n");
1379 if (!mergeExtensionDictionaries(startupExtensions
,
1382 IOLog("Error: Failed to merge new extensions into "
1386 goto finish
; // merge error is fatal for this routine
1391 // Do not release key.
1393 } /* while ( (key = OSDynamicCast(OSString, ...) ) ) */
1395 if (!mergeExtensionDictionaries(existingExtensions
, startupExtensions
)) {
1396 IOLog("Error: Failed to merge new extensions into existing set.\n");
1402 result
= addPersonalities(startupExtensions
);
1404 IOLog("Error: Failed to add personalities for extensions extracted "
1413 // reused so clear first!
1415 keyIterator
->release();
1420 IOLog("Error: Failed to record startup extensions.\n");
1424 keyIterator
= OSCollectionIterator::withCollection(
1428 while ( (key
= OSDynamicCast(OSString
,
1429 keyIterator
->getNextObject())) ) {
1431 IOLog("Found extension \"%s\".\n",
1432 key
->getCStringNoCopy());
1435 keyIterator
->release();
1441 if (newDriverDict
) newDriverDict
->release();
1442 if (propertyDict
) propertyDict
->release();
1443 if (bootxMemoryMap
) bootxMemoryMap
->release();
1444 if (mkextExtensions
) mkextExtensions
->release();
1445 if (startupExtensions
) startupExtensions
->release();
1451 /*********************************************************************
1452 * This function removes an entry from the dictionary of startup
1453 * extensions. It's used when an extension can't be loaded, for
1454 * whatever reason. For drivers, this allows another matching driver
1455 * to be loaded, so that, for example, a driver for the root device
1457 *********************************************************************/
1458 void removeStartupExtension(const char * extensionName
) {
1459 OSDictionary
* startupExtensions
= NULL
; // don't release
1460 OSDictionary
* extensionDict
= NULL
; // don't release
1461 OSDictionary
* extensionPlist
= NULL
; // don't release
1462 OSDictionary
* extensionPersonalities
= NULL
; // don't release
1463 OSDictionary
* personality
= NULL
; // don't release
1464 OSCollectionIterator
* keyIterator
= NULL
; // must release
1465 OSString
* key
= NULL
; // don't release
1467 startupExtensions
= getStartupExtensions();
1468 if (!startupExtensions
) goto finish
;
1471 /* Find the extension's entry in the dictionary of
1472 * startup extensions.
1474 extensionDict
= OSDynamicCast(OSDictionary
,
1475 startupExtensions
->getObject(extensionName
));
1476 if (!extensionDict
) goto finish
;
1478 extensionPlist
= OSDynamicCast(OSDictionary
,
1479 extensionDict
->getObject("plist"));
1480 if (!extensionPlist
) goto finish
;
1482 extensionPersonalities
= OSDynamicCast(OSDictionary
,
1483 extensionPlist
->getObject("IOKitPersonalities"));
1484 if (!extensionPersonalities
) goto finish
;
1486 /* If it was there, remove it from the catalogue proper
1487 * by calling removeDrivers(). Pass true for the second
1488 * argument to trigger a new round of matching, and
1489 * then remove the extension from the dictionary of startup
1492 keyIterator
= OSCollectionIterator::withCollection(
1493 extensionPersonalities
);
1495 IOLog("Error: Couldn't allocate iterator to scan"
1496 " personalities for %s.\n", extensionName
);
1500 while ((key
= OSDynamicCast(OSString
, keyIterator
->getNextObject()))) {
1501 personality
= OSDynamicCast(OSDictionary
,
1502 extensionPersonalities
->getObject(key
));
1506 gIOCatalogue
->removeDrivers(personality
, true);
1510 startupExtensions
->removeObject(extensionName
);
1514 if (keyIterator
) keyIterator
->release();
1518 /*********************************************************************
1519 * FIXME: This function invalidates the globals gStartupExtensions and
1520 * FIXME: ...gBootLoaderObjects without setting them to NULL. Since
1521 * FIXME: ...the code itself is immediately unloaded, there may not be
1522 * FIXME: ...any reason to worry about that!
1523 *********************************************************************/
1524 void clearStartupExtensionsAndLoaderInfo(void)
1526 OSDictionary
* startupExtensions
= NULL
; // must release
1527 OSArray
* bootLoaderObjects
= NULL
; // must release
1529 IORegistryEntry
* bootxMemoryMap
= NULL
; // must release
1530 OSDictionary
* propertyDict
= NULL
; // must release
1531 OSCollectionIterator
* keyIterator
= NULL
; // must release
1532 OSString
* key
= NULL
; // don't release
1535 * Drop any temporarily held data objects.
1537 bootLoaderObjects
= getBootLoaderObjects();
1538 if (bootLoaderObjects
) {
1539 bootLoaderObjects
->release();
1543 * If any "code" entries in driver dictionaries are accompanied
1544 * by "compressedCode" entries, then those data objects were
1545 * created based of of kmem_alloc()'ed memory, which must be
1548 startupExtensions
= getStartupExtensions();
1549 if (startupExtensions
) {
1551 OSCollectionIterator::withCollection(startupExtensions
);
1553 IOLog("Error: Couldn't allocate iterator for startup "
1556 goto memory_map
; // bail to the memory_map label
1559 while ( (key
= OSDynamicCast(OSString
,
1560 keyIterator
->getNextObject())) ) {
1562 OSDictionary
* driverDict
= 0;
1563 OSData
* codeData
= 0;
1565 driverDict
= OSDynamicCast(OSDictionary
,
1566 startupExtensions
->getObject(key
));
1568 codeData
= OSDynamicCast(OSData
,
1569 driverDict
->getObject("code"));
1572 driverDict
->getObject("compressedCode")) {
1574 kmem_free(kernel_map
,
1575 (unsigned int)codeData
->getBytesNoCopy(),
1576 codeData
->getLength());
1581 keyIterator
->release();
1582 startupExtensions
->release();
1588 * Go through the device tree's memory map and remove any driver
1592 IORegistryEntry::fromPath(
1593 "/chosen/memory-map", // path
1596 // return value is retained so be sure to release it
1598 if (!bootxMemoryMap
) {
1599 IOLog("Error: Couldn't read booter memory map.\n");
1604 propertyDict
= bootxMemoryMap
->dictionaryWithProperties();
1605 if (!propertyDict
) {
1606 IOLog("Error: Couldn't get property dictionary "
1607 "from memory map.\n");
1612 keyIterator
= OSCollectionIterator::withCollection(propertyDict
);
1614 IOLog("Error: Couldn't allocate iterator for driver images.\n");
1619 while ( (key
= OSDynamicCast(OSString
,
1620 keyIterator
->getNextObject())) ) {
1622 const char * keyValue
= key
->getCStringNoCopy();
1624 if ( !strncmp(keyValue
, BOOTX_KEXT_PREFIX
,
1625 strlen(BOOTX_KEXT_PREFIX
)) ||
1626 !strncmp(keyValue
, BOOTX_MULTIKEXT_PREFIX
,
1627 strlen(BOOTX_MULTIKEXT_PREFIX
)) ) {
1629 OSData
* bootxDriverDataObject
= NULL
;
1630 MemoryMapFileInfo
* driverInfo
= 0;
1632 bootxDriverDataObject
= OSDynamicCast(OSData
,
1633 propertyDict
->getObject(keyValue
));
1634 // don't release bootxDriverDataObject
1636 if (!bootxDriverDataObject
) {
1639 driverInfo
= (MemoryMapFileInfo
*)
1640 bootxDriverDataObject
->getBytesNoCopy(0,
1641 sizeof(MemoryMapFileInfo
));
1642 IODTFreeLoaderInfo((char *)keyValue
,
1643 (void *)driverInfo
->paddr
,
1644 (int)driverInfo
->length
);
1649 if (bootxMemoryMap
) bootxMemoryMap
->release();
1650 if (propertyDict
) propertyDict
->release();
1651 if (keyIterator
) keyIterator
->release();