2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
25 #include <libkern/c++/OSContainers.h>
26 #include <IOKit/IODeviceTreeSupport.h>
27 #include <IOKit/IORegistryEntry.h>
28 #include <IOKit/IOCatalogue.h>
29 #include <libkern/c++/OSUnserialize.h>
30 #include <libkern/OSByteOrder.h>
31 #include <libsa/catalogue.h>
34 #include <machine/machine_routines.h>
35 #include <mach/host_info.h>
36 #include <mach/kmod.h>
37 #include <libsa/mkext.h>
38 #include <libsa/vers_rsrc.h>
41 #include <IOKit/IOLib.h>
43 #include <IOKit/assert.h>
46 extern void IODTFreeLoaderInfo( char *key
, void *infoAddr
, int infoSize
);
47 extern kern_return_t
host_info(host_t host
,
50 mach_msg_type_number_t
*count
);
51 extern int check_cpu_subtype(cpu_subtype_t cpu_subtype
);
57 #define VTYELLOW "\033[33m"
58 #define VTRESET "\033[0m"
61 /*********************************************************************
62 *********************************************************************/
63 static OSDictionary
* gStartupExtensions
= 0;
64 static OSArray
* gBootLoaderObjects
= 0;
66 OSDictionary
* getStartupExtensions(void) {
67 if (gStartupExtensions
) {
68 return gStartupExtensions
;
70 gStartupExtensions
= OSDictionary::withCapacity(1);
71 if (!gStartupExtensions
) {
72 IOLog("Error: Couldn't allocate "
73 "startup extensions dictionary.\n");
76 return gStartupExtensions
;
79 /* This array holds objects that are needed to be held around during
80 * boot before kextd starts up. Currently it contains OSData objects
81 * copied from OF entries for mkext archives in device ROMs. Because
82 * the Device Tree support code dumps these after initially handing
83 * them to us, we have to be able to clean them up later.
85 OSArray
* getBootLoaderObjects(void) {
86 if (gBootLoaderObjects
) {
87 return gBootLoaderObjects
;
89 gBootLoaderObjects
= OSArray::withCapacity(1);
90 if (! gBootLoaderObjects
) {
91 IOLog("Error: Couldn't allocate "
92 "bootstrap objects array.\n");
95 return gBootLoaderObjects
;
99 /*********************************************************************
100 * This function checks that a driver dict has all the required
101 * entries and does a little bit of value checking too.
102 *********************************************************************/
103 bool validateExtensionDict(OSDictionary
* extension
) {
106 OSString
* name
; // do not release
107 OSString
* stringValue
; // do not release
110 name
= OSDynamicCast(OSString
,
111 extension
->getObject("CFBundleIdentifier"));
113 IOLog(VTYELLOW
"Extension has no \"CFBundleIdentifier\" property.\n"
120 stringValue
= OSDynamicCast(OSString
,
121 extension
->getObject("CFBundleVersion"));
123 IOLog(VTYELLOW
"Extension \"%s\" has no \"CFBundleVersion\" "
124 "property.\n" VTRESET
,
125 name
->getCStringNoCopy());
130 if (!VERS_parse_string(stringValue
->getCStringNoCopy(),
132 IOLog(VTYELLOW
"Extension \"%s\" has an invalid "
133 "\"CFBundleVersion\" property.\n" VTRESET
,
134 name
->getCStringNoCopy());
142 // FIXME: Make return real result after kext conversion
149 /*********************************************************************
150 *********************************************************************/
151 OSDictionary
* compareExtensionVersions(
152 OSDictionary
* incumbent
,
153 OSDictionary
* candidate
) {
155 OSDictionary
* winner
= NULL
;
157 OSDictionary
* incumbentPlist
= NULL
;
158 OSDictionary
* candidatePlist
= NULL
;
159 OSString
* incumbentName
= NULL
;
160 OSString
* candidateName
= NULL
;
161 OSString
* incumbentVersionString
= NULL
;
162 OSString
* candidateVersionString
= NULL
;
163 UInt32 incumbent_vers
= 0;
164 UInt32 candidate_vers
= 0;
166 incumbentPlist
= OSDynamicCast(OSDictionary
,
167 incumbent
->getObject("plist"));
168 candidatePlist
= OSDynamicCast(OSDictionary
,
169 candidate
->getObject("plist"));
171 if (!incumbentPlist
|| !candidatePlist
) {
172 IOLog("compareExtensionVersions() called with invalid "
173 "extension dictionaries.\n");
179 incumbentName
= OSDynamicCast(OSString
,
180 incumbentPlist
->getObject("CFBundleIdentifier"));
181 candidateName
= OSDynamicCast(OSString
,
182 candidatePlist
->getObject("CFBundleIdentifier"));
183 incumbentVersionString
= OSDynamicCast(OSString
,
184 incumbentPlist
->getObject("CFBundleVersion"));
185 candidateVersionString
= OSDynamicCast(OSString
,
186 candidatePlist
->getObject("CFBundleVersion"));
188 if (!incumbentName
|| !candidateName
||
189 !incumbentVersionString
|| !candidateVersionString
) {
191 IOLog("compareExtensionVersions() called with invalid "
192 "extension dictionaries.\n");
198 if (strcmp(incumbentName
->getCStringNoCopy(),
199 candidateName
->getCStringNoCopy())) {
201 IOLog("compareExtensionVersions() called with different "
202 "extension names (%s and %s).\n",
203 incumbentName
->getCStringNoCopy(),
204 candidateName
->getCStringNoCopy());
210 if (!VERS_parse_string(incumbentVersionString
->getCStringNoCopy(),
213 IOLog(VTYELLOW
"Error parsing version string for extension %s (%s)\n"
215 incumbentName
->getCStringNoCopy(),
216 incumbentVersionString
->getCStringNoCopy());
222 if (!VERS_parse_string(candidateVersionString
->getCStringNoCopy(),
225 IOLog(VTYELLOW
"Error parsing version string for extension %s (%s)\n"
227 candidateName
->getCStringNoCopy(),
228 candidateVersionString
->getCStringNoCopy());
234 if (candidate_vers
> incumbent_vers
) {
235 IOLog(VTYELLOW
"Replacing extension \"%s\" with newer version "
236 "(%s -> %s).\n" VTRESET
,
237 incumbentName
->getCStringNoCopy(),
238 incumbentVersionString
->getCStringNoCopy(),
239 candidateVersionString
->getCStringNoCopy());
244 IOLog(VTYELLOW
"Skipping duplicate extension \"%s\" with older/same "
245 " version (%s -> %s).\n" VTRESET
,
246 candidateName
->getCStringNoCopy(),
247 candidateVersionString
->getCStringNoCopy(),
248 incumbentVersionString
->getCStringNoCopy());
256 // no cleanup, how nice
261 /*********************************************************************
262 * This function merges entries in the mergeFrom dictionary into the
263 * mergeInto dictionary. If it returns false, the two dictionaries are
264 * not altered. If it returns true, then mergeInto may have new
265 * entries; any keys that were already present in mergeInto are
266 * removed from mergeFrom, so that the caller can see what was
268 *********************************************************************/
269 bool mergeExtensionDictionaries(OSDictionary
* mergeInto
,
270 OSDictionary
* mergeFrom
) {
273 OSDictionary
* mergeIntoCopy
= NULL
; // must release
274 OSDictionary
* mergeFromCopy
= NULL
; // must release
275 OSCollectionIterator
* keyIterator
= NULL
; // must release
276 OSString
* key
; // don't release
278 /* Add 1 to count to guarantee copy can grow (grr).
280 mergeIntoCopy
= OSDictionary::withDictionary(mergeInto
,
281 mergeInto
->getCount() + 1);
282 if (!mergeIntoCopy
) {
283 IOLog("Error: Failed to copy 'into' extensions dictionary "
290 /* Add 1 to count to guarantee copy can grow (grr).
292 mergeFromCopy
= OSDictionary::withDictionary(mergeFrom
,
293 mergeFrom
->getCount() + 1);
294 if (!mergeFromCopy
) {
295 IOLog("Error: Failed to copy 'from' extensions dictionary "
302 keyIterator
= OSCollectionIterator::withCollection(mergeFrom
);
304 IOLog("Error: Failed to allocate iterator for extensions.\n");
312 * Loop through "from" dictionary, checking if the identifier already
313 * exists in the "into" dictionary and checking versions if it does.
315 while ((key
= OSDynamicCast(OSString
, keyIterator
->getNextObject()))) {
316 OSDictionary
* incumbentExt
= OSDynamicCast(OSDictionary
,
317 mergeIntoCopy
->getObject(key
));
318 OSDictionary
* candidateExt
= OSDynamicCast(OSDictionary
,
319 mergeFrom
->getObject(key
));
322 if (!mergeIntoCopy
->setObject(key
, candidateExt
)) {
324 /* This is a fatal error, so bail.
326 IOLog("mergeExtensionDictionaries(): Failed to add "
328 key
->getCStringNoCopy());
334 OSDictionary
* mostRecentExtension
=
335 compareExtensionVersions(incumbentExt
, candidateExt
);
337 if (mostRecentExtension
== incumbentExt
) {
338 mergeFromCopy
->removeObject(key
);
339 } else if (mostRecentExtension
== candidateExt
) {
341 if (!mergeIntoCopy
->setObject(key
, candidateExt
)) {
343 /* This is a fatal error, so bail.
345 IOLog("mergeExtensionDictionaries(): Failed to add "
347 key
->getCStringNoCopy());
352 } else /* should be NULL */ {
354 /* This is a nonfatal error, so continue doing others.
356 IOLog("mergeExtensionDictionaries(): Error comparing "
357 "versions of duplicate extensions %s.\n",
358 key
->getCStringNoCopy());
367 /* If successful, replace the contents of the original
368 * dictionaries with those of the modified copies.
371 mergeInto
->flushCollection();
372 mergeInto
->merge(mergeIntoCopy
);
373 mergeFrom
->flushCollection();
374 mergeFrom
->merge(mergeFromCopy
);
377 if (mergeIntoCopy
) mergeIntoCopy
->release();
378 if (mergeFromCopy
) mergeFromCopy
->release();
379 if (keyIterator
) keyIterator
->release();
386 * These bits are used to parse data made available by bootx.
388 #define BOOTX_KEXT_PREFIX "Driver-"
389 #define BOOTX_MULTIKEXT_PREFIX "DriversPackage-"
391 typedef struct MemoryMapFileInfo
{
396 typedef struct BootxDriverInfo
{
403 typedef struct MkextEntryInfo
{
404 vm_address_t base_address
;
405 mkext_file
* fileinfo
;
409 /*********************************************************************
410 * This private function reads the data for a single extension from
411 * the bootx memory-map's propery dict, returning a dictionary with
412 * keys "plist" for the extension's Info.plist as a parsed OSDictionary
413 * and "code" for the extension's executable code as an OSData.
414 *********************************************************************/
415 OSDictionary
* readExtension(OSDictionary
* propertyDict
,
416 const char * memory_map_name
) {
419 OSData
* bootxDriverDataObject
= NULL
;
420 OSDictionary
* driverPlist
= NULL
;
421 OSString
* driverName
= NULL
;
422 OSData
* driverCode
= NULL
;
423 OSString
* errorString
= NULL
;
424 OSDictionary
* driverDict
= NULL
;
426 MemoryMapFileInfo
* driverInfo
= 0;
427 BootxDriverInfo
* dataBuffer
;
429 kmod_info_t
* loaded_kmod
= NULL
;
431 bootxDriverDataObject
= OSDynamicCast(OSData
,
432 propertyDict
->getObject(memory_map_name
));
433 // don't release bootxDriverDataObject
435 if (!bootxDriverDataObject
) {
436 IOLog("Error: No driver data object "
437 "for device tree entry \"%s\".\n",
444 driverDict
= OSDictionary::withCapacity(2);
446 IOLog("Error: Couldn't allocate dictionary "
447 "for device tree entry \"%s\".\n", memory_map_name
);
453 driverInfo
= (MemoryMapFileInfo
*)
454 bootxDriverDataObject
->getBytesNoCopy(0,
455 sizeof(MemoryMapFileInfo
));
456 dataBuffer
= (BootxDriverInfo
*)ml_static_ptovirt(
459 IOLog("Error: No data buffer "
460 "for device tree entry \"%s\".\n", memory_map_name
);
466 driverPlist
= OSDynamicCast(OSDictionary
,
467 OSUnserializeXML(dataBuffer
->plistAddr
, &errorString
));
469 IOLog("Error: Couldn't read XML property list "
470 "for device tree entry \"%s\".\n", memory_map_name
);
473 IOLog("XML parse error: %s.\n",
474 errorString
->getCStringNoCopy());
482 driverName
= OSDynamicCast(OSString
,
483 driverPlist
->getObject("CFBundleIdentifier")); // do not release
485 IOLog("Error: Device tree entry \"%s\" has "
486 "no \"CFBundleIdentifier\" property.\n", memory_map_name
);
492 /* Check if kmod is already loaded and is a real loadable one (has
495 loaded_kmod
= kmod_lookupbyname_locked(driverName
->getCStringNoCopy());
496 if (loaded_kmod
&& loaded_kmod
->address
) {
497 IOLog("Skipping new extension \"%s\"; an extension named "
498 "\"%s\" is already loaded.\n",
499 driverName
->getCStringNoCopy(),
506 if (!validateExtensionDict(driverPlist
)) {
507 IOLog("Error: Failed to validate property list "
508 "for device tree entry \"%s\".\n", memory_map_name
);
514 driverDict
->setObject("plist", driverPlist
);
516 /* It's perfectly okay for a KEXT to have no executable.
517 * Check that moduleAddr is nonzero before attempting to
520 * NOTE: The driverCode object is created "no-copy", so
521 * it doesn't own that memory. The memory must be freed
522 * separately from the OSData object (see
523 * clearStartupExtensionsAndLoaderInfo() at the end of this file).
525 if (dataBuffer
->moduleAddr
&& dataBuffer
->moduleLength
) {
526 driverCode
= OSData::withBytesNoCopy(dataBuffer
->moduleAddr
,
527 dataBuffer
->moduleLength
);
529 IOLog("Error: Couldn't allocate data object "
530 "to hold code for device tree entry \"%s\".\n",
538 driverDict
->setObject("code", driverCode
);
545 kfree(loaded_kmod
, sizeof(kmod_info_t
));
548 // do not release bootxDriverDataObject
549 // do not release driverName
552 driverPlist
->release();
555 errorString
->release();
558 driverCode
->release();
562 driverDict
->release();
570 /*********************************************************************
571 * Used to uncompress a single file entry in an mkext archive.
573 * The OSData returned does not own its memory! You must deallocate
574 * that memory using kmem_free() before releasing the OSData().
575 *********************************************************************/
576 static bool uncompressFile(u_int8_t
*base_address
, mkext_file
* fileinfo
,
577 /* out */ OSData
** file
) {
580 kern_return_t kern_result
;
581 u_int8_t
* uncompressed_file
= 0; // kmem_free() on error
582 OSData
* uncompressedFile
= 0; // returned
583 size_t uncompressed_size
= 0;
585 size_t offset
= OSSwapBigToHostInt32(fileinfo
->offset
);
586 size_t compsize
= OSSwapBigToHostInt32(fileinfo
->compsize
);
587 size_t realsize
= OSSwapBigToHostInt32(fileinfo
->realsize
);
588 time_t modifiedsecs
= OSSwapBigToHostInt32(fileinfo
->modifiedsecs
);
592 /* If these four fields are zero there's no file, but that isn't
595 if (offset
== 0 && compsize
== 0 &&
596 realsize
== 0 && modifiedsecs
== 0) {
600 // Add 1 for '\0' to terminate XML string!
601 kern_result
= kmem_alloc(kernel_map
, (vm_offset_t
*)&uncompressed_file
,
603 if (kern_result
!= KERN_SUCCESS
) {
604 IOLog("Error: Couldn't allocate data buffer "
605 "to uncompress file.\n");
611 uncompressedFile
= OSData::withBytesNoCopy(uncompressed_file
,
613 if (!uncompressedFile
) {
614 IOLog("Error: Couldn't allocate data object "
615 "to uncompress file.\n");
622 uncompressed_size
= decompress_lzss(uncompressed_file
,
623 base_address
+ offset
,
625 if (uncompressed_size
!= realsize
) {
626 IOLog("Error: Uncompressed file is not the length "
632 uncompressed_file
[uncompressed_size
] = '\0';
634 bcopy(base_address
+ offset
, uncompressed_file
,
636 uncompressed_file
[realsize
] = '\0';
639 *file
= uncompressedFile
;
643 if (uncompressed_file
) {
644 kmem_free(kernel_map
, (vm_address_t
)uncompressed_file
,
647 if (uncompressedFile
) {
648 uncompressedFile
->release();
655 bool uncompressModule(OSData
*compData
, /* out */ OSData
** file
) {
657 MkextEntryInfo
*info
= (MkextEntryInfo
*) compData
->getBytesNoCopy();
659 return uncompressFile((u_int8_t
*) info
->base_address
,
660 info
->fileinfo
, file
);
664 /*********************************************************************
665 * Does the work of pulling extensions out of an mkext archive located
667 *********************************************************************/
668 bool extractExtensionsFromArchive(MemoryMapFileInfo
* mkext_file_info
,
669 OSDictionary
* extensions
) {
673 u_int8_t
* crc_address
= 0;
675 mkext_header
* mkext_data
= 0; // don't free
676 mkext_kext
* onekext_data
= 0; // don't free
677 mkext_file
* plist_file
= 0; // don't free
678 mkext_file
* module_file
= 0; // don't free
679 kmod_info_t
* loaded_kmod
= 0; // must free
681 OSData
* driverPlistDataObject
= 0; // must release
682 OSDictionary
* driverPlist
= 0; // must release
683 OSData
* driverCode
= 0; // must release
684 OSDictionary
* driverDict
= 0; // must release
685 OSString
* moduleName
= 0; // don't release
686 OSString
* errorString
= NULL
; // must release
688 OSData
* moduleInfo
= 0; // must release
689 MkextEntryInfo module_info
;
691 mkext_data
= (mkext_header
*)mkext_file_info
->paddr
;
693 if (OSSwapBigToHostInt32(mkext_data
->magic
) != MKEXT_MAGIC
||
694 OSSwapBigToHostInt32(mkext_data
->signature
) != MKEXT_SIGN
) {
695 IOLog("Error: Extension archive has invalid magic or signature.\n");
701 if (OSSwapBigToHostInt32(mkext_data
->length
) != mkext_file_info
->length
) {
702 IOLog("Error: Mismatch between extension archive & "
703 "recorded length.\n");
709 crc_address
= (u_int8_t
*)&mkext_data
->version
;
710 checksum
= adler32(crc_address
,
711 (unsigned int)mkext_data
+
712 OSSwapBigToHostInt32(mkext_data
->length
) - (unsigned int)crc_address
);
714 if (OSSwapBigToHostInt32(mkext_data
->adler32
) != checksum
) {
715 IOLog("Error: Extension archive has a bad checksum.\n");
721 /* If the MKEXT archive isn't fat, check that the CPU type & subtype
722 * match that of the running kernel.
724 if (OSSwapBigToHostInt32(mkext_data
->cputype
) != (UInt32
)CPU_TYPE_ANY
) {
725 kern_return_t kresult
= KERN_FAILURE
;
726 host_basic_info_data_t hostinfo
;
727 host_info_t hostinfo_ptr
= (host_info_t
)&hostinfo
;
728 mach_msg_type_number_t count
= sizeof(hostinfo
)/sizeof(integer_t
);
730 kresult
= host_info((host_t
)1, HOST_BASIC_INFO
,
731 hostinfo_ptr
, &count
);
732 if (kresult
!= KERN_SUCCESS
) {
733 IOLog("Error: Couldn't get current host info.\n");
738 if ((UInt32
)hostinfo
.cpu_type
!=
739 OSSwapBigToHostInt32(mkext_data
->cputype
)) {
741 IOLog("Error: Extension archive doesn't contain software "
742 "for this computer's CPU type.\n");
747 if (!check_cpu_subtype(OSSwapBigToHostInt32(mkext_data
->cpusubtype
))) {
748 IOLog("Error: Extension archive doesn't contain software "
749 "for this computer's CPU subtype.\n");
756 for (unsigned int i
= 0;
757 i
< OSSwapBigToHostInt32(mkext_data
->numkexts
);
761 kfree(loaded_kmod
, sizeof(kmod_info_t
));
765 if (driverPlistDataObject
) {
766 driverPlistDataObject
->release();
767 driverPlistDataObject
= NULL
;
770 driverPlist
->release();
774 driverCode
->release();
778 driverDict
->release();
782 errorString
->release();
786 onekext_data
= &mkext_data
->kext
[i
];
787 plist_file
= &onekext_data
->plist
;
788 module_file
= &onekext_data
->module;
790 if (!uncompressFile((u_int8_t
*)mkext_data
, plist_file
,
791 &driverPlistDataObject
)) {
793 IOLog("Error: couldn't uncompress plist file "
794 "from multikext archive entry %d.\n", i
);
799 if (!driverPlistDataObject
) {
800 IOLog("Error: No property list present "
801 "for multikext archive entry %d.\n", i
);
805 driverPlist
= OSDynamicCast(OSDictionary
,
807 (char *)driverPlistDataObject
->getBytesNoCopy(),
810 IOLog("Error: Couldn't read XML property list "
811 "for multikext archive entry %d.\n", i
);
814 IOLog("XML parse error: %s.\n",
815 errorString
->getCStringNoCopy());
821 if (!validateExtensionDict(driverPlist
)) {
822 IOLog("Error: Failed to validate property list "
823 "for multikext archive entry %d.\n", i
);
830 /* Get the extension's module name. This is used to record
833 moduleName
= OSDynamicCast(OSString
,
834 driverPlist
->getObject("CFBundleIdentifier")); // do not release
836 IOLog("Error: Multikext archive entry %d has "
837 "no \"CFBundleIdentifier\" property.\n", i
);
839 continue; // assume a kext config error & continue
842 /* Check if kmod is already loaded and is a real loadable one (has
845 loaded_kmod
= kmod_lookupbyname_locked(moduleName
->getCStringNoCopy());
846 if (loaded_kmod
&& loaded_kmod
->address
) {
847 IOLog("Skipping new extension \"%s\"; an extension named "
848 "\"%s\" is already loaded.\n",
849 moduleName
->getCStringNoCopy(),
855 driverDict
= OSDictionary::withCapacity(2);
857 IOLog("Error: Couldn't allocate dictionary "
858 "for multikext archive entry %d.\n", i
);
864 driverDict
->setObject("plist", driverPlist
);
867 * Prepare an entry to hold the mkext entry info for the
868 * compressed binary module, if there is one. If all four fields
869 * of the module entry are zero, there isn't one.
871 if (OSSwapBigToHostInt32(module_file
->offset
) ||
872 OSSwapBigToHostInt32(module_file
->compsize
) ||
873 OSSwapBigToHostInt32(module_file
->realsize
) ||
874 OSSwapBigToHostInt32(module_file
->modifiedsecs
)) {
876 moduleInfo
= OSData::withCapacity(sizeof(MkextEntryInfo
));
878 IOLog("Error: Couldn't allocate data object "
879 "for multikext archive entry %d.\n", i
);
885 module_info
.base_address
= (vm_address_t
)mkext_data
;
886 module_info
.fileinfo
= module_file
;
888 if (!moduleInfo
->appendBytes(&module_info
, sizeof(module_info
))) {
889 IOLog("Error: Couldn't record info "
890 "for multikext archive entry %d.\n", i
);
896 driverDict
->setObject("compressedCode", moduleInfo
);
899 OSDictionary
* incumbentExt
= OSDynamicCast(OSDictionary
,
900 extensions
->getObject(moduleName
));
903 extensions
->setObject(moduleName
, driverDict
);
905 OSDictionary
* mostRecentExtension
=
906 compareExtensionVersions(incumbentExt
, driverDict
);
908 if (mostRecentExtension
== incumbentExt
) {
909 /* Do nothing, we've got the most recent. */
910 } else if (mostRecentExtension
== driverDict
) {
911 if (!extensions
->setObject(moduleName
, driverDict
)) {
913 /* This is a fatal error, so bail.
915 IOLog("extractExtensionsFromArchive(): Failed to add "
917 moduleName
->getCStringNoCopy());
922 } else /* should be NULL */ {
924 /* This is a nonfatal error, so continue.
926 IOLog("extractExtensionsFromArchive(): Error comparing "
927 "versions of duplicate extensions %s.\n",
928 moduleName
->getCStringNoCopy());
937 if (loaded_kmod
) kfree(loaded_kmod
, sizeof(kmod_info_t
));
938 if (driverPlistDataObject
) driverPlistDataObject
->release();
939 if (driverPlist
) driverPlist
->release();
940 if (driverCode
) driverCode
->release();
941 if (moduleInfo
) moduleInfo
->release();
942 if (driverDict
) driverDict
->release();
943 if (errorString
) errorString
->release();
948 /*********************************************************************
950 *********************************************************************/
951 bool readExtensions(OSDictionary
* propertyDict
,
952 const char * memory_map_name
,
953 OSDictionary
* extensions
) {
956 OSData
* mkextDataObject
= 0; // don't release
957 MemoryMapFileInfo
* mkext_file_info
= 0; // don't free
959 mkextDataObject
= OSDynamicCast(OSData
,
960 propertyDict
->getObject(memory_map_name
));
961 // don't release mkextDataObject
963 if (!mkextDataObject
) {
964 IOLog("Error: No mkext data object "
965 "for device tree entry \"%s\".\n",
972 mkext_file_info
= (MemoryMapFileInfo
*)mkextDataObject
->getBytesNoCopy();
973 if (!mkext_file_info
) {
978 result
= extractExtensionsFromArchive(mkext_file_info
, extensions
);
982 if (!result
&& extensions
) {
983 extensions
->flushCollection();
990 /*********************************************************************
991 * Adds the personalities for an extensions dictionary to the global
993 *********************************************************************/
994 bool addPersonalities(OSDictionary
* extensions
) {
996 OSCollectionIterator
* keyIterator
= NULL
; // must release
997 OSString
* key
; // don't release
998 OSDictionary
* driverDict
= NULL
; // don't release
999 OSDictionary
* driverPlist
= NULL
; // don't release
1000 OSDictionary
* thisDriverPersonalities
= NULL
; // don't release
1001 OSArray
* allDriverPersonalities
= NULL
; // must release
1003 allDriverPersonalities
= OSArray::withCapacity(1);
1004 if (!allDriverPersonalities
) {
1005 IOLog("Error: Couldn't allocate personality dictionary.\n");
1011 /* Record all personalities found so that they can be
1012 * added to the catalogue.
1013 * Note: Not all extensions have personalities.
1016 keyIterator
= OSCollectionIterator::withCollection(extensions
);
1018 IOLog("Error: Couldn't allocate iterator to record personalities.\n");
1024 while ( ( key
= OSDynamicCast(OSString
,
1025 keyIterator
->getNextObject() ))) {
1027 driverDict
= OSDynamicCast(OSDictionary
,
1028 extensions
->getObject(key
));
1029 driverPlist
= OSDynamicCast(OSDictionary
,
1030 driverDict
->getObject("plist"));
1031 thisDriverPersonalities
= OSDynamicCast(OSDictionary
,
1032 driverPlist
->getObject("IOKitPersonalities"));
1034 if (thisDriverPersonalities
) {
1035 OSCollectionIterator
* pIterator
;
1037 pIterator
= OSCollectionIterator::withCollection(
1038 thisDriverPersonalities
);
1040 IOLog("Error: Couldn't allocate iterator "
1041 "to record extension personalities.\n");
1045 while ( (key
= OSDynamicCast(OSString
,
1046 pIterator
->getNextObject())) ) {
1048 OSDictionary
* personality
= OSDynamicCast(
1050 thisDriverPersonalities
->getObject(key
));
1052 allDriverPersonalities
->setObject(personality
);
1055 pIterator
->release();
1057 } /* extract personalities */
1060 /* Add all personalities found to the IOCatalogue,
1061 * but don't start matching.
1063 gIOCatalogue
->addDrivers(allDriverPersonalities
, false);
1067 if (allDriverPersonalities
) allDriverPersonalities
->release();
1068 if (keyIterator
) keyIterator
->release();
1074 /*********************************************************************
1075 * Called from IOCatalogue to add extensions from an mkext archive.
1076 * This function makes a copy of the mkext object passed in because
1077 * the device tree support code dumps it after calling us (indirectly
1078 * through the IOCatalogue).
1079 *********************************************************************/
1080 bool addExtensionsFromArchive(OSData
* mkextDataObject
) {
1083 OSDictionary
* startupExtensions
= NULL
; // don't release
1084 OSArray
* bootLoaderObjects
= NULL
; // don't release
1085 OSData
* localMkextDataObject
= NULL
; // don't release
1086 OSDictionary
* extensions
= NULL
; // must release
1087 MemoryMapFileInfo mkext_file_info
;
1088 OSCollectionIterator
* keyIterator
= NULL
; // must release
1089 OSString
* key
= NULL
; // don't release
1091 startupExtensions
= getStartupExtensions();
1092 if (!startupExtensions
) {
1093 IOLog("Can't record extension archive; there is no"
1094 " extensions dictionary.\n");
1100 bootLoaderObjects
= getBootLoaderObjects();
1101 if (! bootLoaderObjects
) {
1102 IOLog("Error: Couldn't allocate array to hold temporary objects.\n");
1108 extensions
= OSDictionary::withCapacity(2);
1110 IOLog("Error: Couldn't allocate dictionary to unpack "
1111 "extension archive.\n");
1117 /* The mkext we've been handed (or the data it references) can go away,
1118 * so we need to make a local copy to keep around as long as it might
1121 localMkextDataObject
= OSData::withData(mkextDataObject
);
1122 if (!localMkextDataObject
) {
1123 IOLog("Error: Couldn't copy extension archive.\n");
1129 mkext_file_info
.paddr
= (UInt32
)localMkextDataObject
->getBytesNoCopy();
1130 mkext_file_info
.length
= localMkextDataObject
->getLength();
1132 /* Save the local mkext data object so that we can deallocate it later.
1134 bootLoaderObjects
->setObject(localMkextDataObject
);
1135 localMkextDataObject
->release();
1137 result
= extractExtensionsFromArchive(&mkext_file_info
, extensions
);
1139 IOLog("Error: Failed to extract extensions from archive.\n");
1145 result
= mergeExtensionDictionaries(startupExtensions
, extensions
);
1147 IOLog("Error: Failed to merge new extensions into existing set.\n");
1152 result
= addPersonalities(extensions
);
1154 IOLog("Error: Failed to add personalities for extensions extracted "
1164 IOLog("Error: Failed to record extensions from archive.\n");
1167 keyIterator
= OSCollectionIterator::withCollection(
1171 while ( (key
= OSDynamicCast(OSString
,
1172 keyIterator
->getNextObject())) ) {
1174 IOLog("Added extension \"%s\" from archive.\n",
1175 key
->getCStringNoCopy());
1178 keyIterator
->release();
1182 if (extensions
) extensions
->release();
1188 /*********************************************************************
1189 * This function builds dictionaries for the startup extensions
1190 * put into memory by bootx, recording each in the startup extensions
1191 * dictionary. The dictionary format is this:
1194 * "plist" = (the extension's Info.plist as an OSDictionary)
1195 * "code" = (an OSData containing the executable file)
1198 * This function returns true if any extensions were found and
1199 * recorded successfully, or if there are no start extensions,
1200 * and false if an unrecoverable error occurred. An error reading
1201 * a single extension is not considered fatal, and this function
1202 * will simply skip the problematic extension to try the next one.
1203 *********************************************************************/
1204 bool recordStartupExtensions(void) {
1206 OSDictionary
* startupExtensions
= NULL
; // must release
1207 OSDictionary
* existingExtensions
= NULL
; // don't release
1208 OSDictionary
* mkextExtensions
= NULL
; // must release
1209 IORegistryEntry
* bootxMemoryMap
= NULL
; // must release
1210 OSDictionary
* propertyDict
= NULL
; // must release
1211 OSCollectionIterator
* keyIterator
= NULL
; // must release
1212 OSString
* key
= NULL
; // don't release
1214 OSDictionary
* newDriverDict
= NULL
; // must release
1215 OSDictionary
* driverPlist
= NULL
; // don't release
1217 IOLog("Recording startup extensions.\n");
1220 existingExtensions
= getStartupExtensions();
1221 if (!existingExtensions
) {
1222 IOLog("Error: There is no dictionary for startup extensions.\n");
1228 startupExtensions
= OSDictionary::withCapacity(1);
1229 if (!startupExtensions
) {
1230 IOLog("Error: Couldn't allocate dictionary "
1231 "to record startup extensions.\n");
1238 IORegistryEntry::fromPath(
1239 "/chosen/memory-map", // path
1242 // return value is retained so be sure to release it
1244 if (!bootxMemoryMap
) {
1245 IOLog("Error: Couldn't read booter memory map.\n");
1251 propertyDict
= bootxMemoryMap
->dictionaryWithProperties();
1252 if (!propertyDict
) {
1253 IOLog("Error: Couldn't get property dictionary "
1254 "from memory map.\n");
1260 keyIterator
= OSCollectionIterator::withCollection(propertyDict
);
1262 IOLog("Error: Couldn't allocate iterator for driver images.\n");
1268 while ( (key
= OSDynamicCast(OSString
,
1269 keyIterator
->getNextObject())) ) {
1270 /* Clear newDriverDict & mkextExtensions upon entry to the loop,
1271 * handling both successful and unsuccessful iterations.
1273 if (newDriverDict
) {
1274 newDriverDict
->release();
1275 newDriverDict
= NULL
;
1277 if (mkextExtensions
) {
1278 mkextExtensions
->release();
1279 mkextExtensions
= NULL
;
1282 const char * keyValue
= key
->getCStringNoCopy();
1284 if ( !strncmp(keyValue
, BOOTX_KEXT_PREFIX
,
1285 strlen(BOOTX_KEXT_PREFIX
)) ) {
1287 /* Read the extension from the bootx-supplied memory.
1289 newDriverDict
= readExtension(propertyDict
, keyValue
);
1290 if (!newDriverDict
) {
1291 IOLog("Error: Couldn't read data "
1292 "for device tree entry \"%s\".\n", keyValue
);
1298 /* Preprare to record the extension by getting its info plist.
1300 driverPlist
= OSDynamicCast(OSDictionary
,
1301 newDriverDict
->getObject("plist"));
1303 IOLog("Error: Extension in device tree entry \"%s\" "
1304 "has no property list.\n", keyValue
);
1310 /* Get the extension's module name. This is used to record
1311 * the extension. Do *not* release the moduleName.
1313 OSString
* moduleName
= OSDynamicCast(OSString
,
1314 driverPlist
->getObject("CFBundleIdentifier"));
1316 IOLog("Error: Device tree entry \"%s\" has "
1317 "no \"CFBundleIdentifier\" property.\n", keyValue
);
1323 /* All has gone well so far, so record the extension under
1324 * its module name, checking for an existing duplicate.
1326 * Do not release moduleName, as it's part of the extension's
1329 OSDictionary
* incumbentExt
= OSDynamicCast(OSDictionary
,
1330 startupExtensions
->getObject(moduleName
));
1332 if (!incumbentExt
) {
1333 startupExtensions
->setObject(moduleName
, newDriverDict
);
1335 OSDictionary
* mostRecentExtension
=
1336 compareExtensionVersions(incumbentExt
, newDriverDict
);
1338 if (mostRecentExtension
== incumbentExt
) {
1339 /* Do nothing, we've got the most recent. */
1340 } else if (mostRecentExtension
== newDriverDict
) {
1341 if (!startupExtensions
->setObject(moduleName
,
1344 /* This is a fatal error, so bail.
1346 IOLog("recordStartupExtensions(): Failed to add "
1348 moduleName
->getCStringNoCopy());
1353 } else /* should be NULL */ {
1355 /* This is a nonfatal error, so continue.
1357 IOLog("recordStartupExtensions(): Error comparing "
1358 "versions of duplicate extensions %s.\n",
1359 moduleName
->getCStringNoCopy());
1366 } else if ( !strncmp(keyValue
, BOOTX_MULTIKEXT_PREFIX
,
1367 strlen(BOOTX_MULTIKEXT_PREFIX
)) ) {
1369 mkextExtensions
= OSDictionary::withCapacity(10);
1370 if (!mkextExtensions
) {
1371 IOLog("Error: Couldn't allocate dictionary to unpack "
1372 "multi-extension archive.\n");
1375 goto finish
; // allocation failure is fatal for this routine
1377 if (!readExtensions(propertyDict
, keyValue
, mkextExtensions
)) {
1378 IOLog("Error: Couldn't unpack multi-extension archive.\n");
1382 if (!mergeExtensionDictionaries(startupExtensions
,
1385 IOLog("Error: Failed to merge new extensions into "
1389 goto finish
; // merge error is fatal for this routine
1394 // Do not release key.
1396 } /* while ( (key = OSDynamicCast(OSString, ...) ) ) */
1398 if (!mergeExtensionDictionaries(existingExtensions
, startupExtensions
)) {
1399 IOLog("Error: Failed to merge new extensions into existing set.\n");
1405 result
= addPersonalities(startupExtensions
);
1407 IOLog("Error: Failed to add personalities for extensions extracted "
1416 // reused so clear first!
1418 keyIterator
->release();
1423 IOLog("Error: Failed to record startup extensions.\n");
1427 keyIterator
= OSCollectionIterator::withCollection(
1431 while ( (key
= OSDynamicCast(OSString
,
1432 keyIterator
->getNextObject())) ) {
1434 IOLog("Found extension \"%s\".\n",
1435 key
->getCStringNoCopy());
1438 keyIterator
->release();
1444 if (newDriverDict
) newDriverDict
->release();
1445 if (propertyDict
) propertyDict
->release();
1446 if (bootxMemoryMap
) bootxMemoryMap
->release();
1447 if (mkextExtensions
) mkextExtensions
->release();
1448 if (startupExtensions
) startupExtensions
->release();
1454 /*********************************************************************
1455 * This function removes an entry from the dictionary of startup
1456 * extensions. It's used when an extension can't be loaded, for
1457 * whatever reason. For drivers, this allows another matching driver
1458 * to be loaded, so that, for example, a driver for the root device
1460 *********************************************************************/
1461 void removeStartupExtension(const char * extensionName
) {
1462 OSDictionary
* startupExtensions
= NULL
; // don't release
1463 OSDictionary
* extensionDict
= NULL
; // don't release
1464 OSDictionary
* extensionPlist
= NULL
; // don't release
1465 OSDictionary
* extensionPersonalities
= NULL
; // don't release
1466 OSDictionary
* personality
= NULL
; // don't release
1467 OSCollectionIterator
* keyIterator
= NULL
; // must release
1468 OSString
* key
= NULL
; // don't release
1470 startupExtensions
= getStartupExtensions();
1471 if (!startupExtensions
) goto finish
;
1474 /* Find the extension's entry in the dictionary of
1475 * startup extensions.
1477 extensionDict
= OSDynamicCast(OSDictionary
,
1478 startupExtensions
->getObject(extensionName
));
1479 if (!extensionDict
) goto finish
;
1481 extensionPlist
= OSDynamicCast(OSDictionary
,
1482 extensionDict
->getObject("plist"));
1483 if (!extensionPlist
) goto finish
;
1485 extensionPersonalities
= OSDynamicCast(OSDictionary
,
1486 extensionPlist
->getObject("IOKitPersonalities"));
1487 if (!extensionPersonalities
) goto finish
;
1489 /* If it was there, remove it from the catalogue proper
1490 * by calling removeDrivers(). Pass true for the second
1491 * argument to trigger a new round of matching, and
1492 * then remove the extension from the dictionary of startup
1495 keyIterator
= OSCollectionIterator::withCollection(
1496 extensionPersonalities
);
1498 IOLog("Error: Couldn't allocate iterator to scan"
1499 " personalities for %s.\n", extensionName
);
1503 while ((key
= OSDynamicCast(OSString
, keyIterator
->getNextObject()))) {
1504 personality
= OSDynamicCast(OSDictionary
,
1505 extensionPersonalities
->getObject(key
));
1509 gIOCatalogue
->removeDrivers(personality
, true);
1513 startupExtensions
->removeObject(extensionName
);
1517 if (keyIterator
) keyIterator
->release();
1521 /*********************************************************************
1522 * FIXME: This function invalidates the globals gStartupExtensions and
1523 * FIXME: ...gBootLoaderObjects without setting them to NULL. Since
1524 * FIXME: ...the code itself is immediately unloaded, there may not be
1525 * FIXME: ...any reason to worry about that!
1526 *********************************************************************/
1527 void clearStartupExtensionsAndLoaderInfo(void)
1529 OSDictionary
* startupExtensions
= NULL
; // must release
1530 OSArray
* bootLoaderObjects
= NULL
; // must release
1532 IORegistryEntry
* bootxMemoryMap
= NULL
; // must release
1533 OSDictionary
* propertyDict
= NULL
; // must release
1534 OSCollectionIterator
* keyIterator
= NULL
; // must release
1535 OSString
* key
= NULL
; // don't release
1538 * Drop any temporarily held data objects.
1540 bootLoaderObjects
= getBootLoaderObjects();
1541 if (bootLoaderObjects
) {
1542 bootLoaderObjects
->release();
1546 * If any "code" entries in driver dictionaries are accompanied
1547 * by "compressedCode" entries, then those data objects were
1548 * created based of of kmem_alloc()'ed memory, which must be
1551 startupExtensions
= getStartupExtensions();
1552 if (startupExtensions
) {
1554 OSCollectionIterator::withCollection(startupExtensions
);
1556 IOLog("Error: Couldn't allocate iterator for startup "
1559 goto memory_map
; // bail to the memory_map label
1562 while ( (key
= OSDynamicCast(OSString
,
1563 keyIterator
->getNextObject())) ) {
1565 OSDictionary
* driverDict
= 0;
1566 OSData
* codeData
= 0;
1568 driverDict
= OSDynamicCast(OSDictionary
,
1569 startupExtensions
->getObject(key
));
1571 codeData
= OSDynamicCast(OSData
,
1572 driverDict
->getObject("code"));
1575 driverDict
->getObject("compressedCode")) {
1577 kmem_free(kernel_map
,
1578 (unsigned int)codeData
->getBytesNoCopy(),
1579 codeData
->getLength());
1584 keyIterator
->release();
1585 startupExtensions
->release();
1591 * Go through the device tree's memory map and remove any driver
1595 IORegistryEntry::fromPath(
1596 "/chosen/memory-map", // path
1599 // return value is retained so be sure to release it
1601 if (!bootxMemoryMap
) {
1602 IOLog("Error: Couldn't read booter memory map.\n");
1607 propertyDict
= bootxMemoryMap
->dictionaryWithProperties();
1608 if (!propertyDict
) {
1609 IOLog("Error: Couldn't get property dictionary "
1610 "from memory map.\n");
1615 keyIterator
= OSCollectionIterator::withCollection(propertyDict
);
1617 IOLog("Error: Couldn't allocate iterator for driver images.\n");
1622 while ( (key
= OSDynamicCast(OSString
,
1623 keyIterator
->getNextObject())) ) {
1625 const char * keyValue
= key
->getCStringNoCopy();
1627 if ( !strncmp(keyValue
, BOOTX_KEXT_PREFIX
,
1628 strlen(BOOTX_KEXT_PREFIX
)) ||
1629 !strncmp(keyValue
, BOOTX_MULTIKEXT_PREFIX
,
1630 strlen(BOOTX_MULTIKEXT_PREFIX
)) ) {
1632 OSData
* bootxDriverDataObject
= NULL
;
1633 MemoryMapFileInfo
* driverInfo
= 0;
1635 bootxDriverDataObject
= OSDynamicCast(OSData
,
1636 propertyDict
->getObject(keyValue
));
1637 // don't release bootxDriverDataObject
1639 if (!bootxDriverDataObject
) {
1642 driverInfo
= (MemoryMapFileInfo
*)
1643 bootxDriverDataObject
->getBytesNoCopy(0,
1644 sizeof(MemoryMapFileInfo
));
1645 IODTFreeLoaderInfo((char *)keyValue
,
1646 (void *)driverInfo
->paddr
,
1647 (int)driverInfo
->length
);
1652 if (bootxMemoryMap
) bootxMemoryMap
->release();
1653 if (propertyDict
) propertyDict
->release();
1654 if (keyIterator
) keyIterator
->release();