The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/libsa/catalogue.cpp

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
    3  *
    4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
    5  * 
    6  * This file contains Original Code and/or Modifications of Original Code
    7  * as defined in and that are subject to the Apple Public Source License
    8  * Version 2.0 (the 'License'). You may not use this file except in
    9  * compliance with the License. The rights granted to you under the License
   10  * may not be used to create, or enable the creation or redistribution of,
   11  * unlawful or unlicensed copies of an Apple operating system, or to
   12  * circumvent, violate, or enable the circumvention or violation of, any
   13  * terms of an Apple operating system software license agreement.
   14  * 
   15  * Please obtain a copy of the License at
   16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
   17  * 
   18  * The Original Code and all software distributed under the License are
   19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
   20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
   21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
   22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
   23  * Please see the License for the specific language governing rights and
   24  * limitations under the License.
   25  * 
   26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
   27  */
   28 #include <libkern/c++/OSContainers.h>
   29 #include <IOKit/IODeviceTreeSupport.h>
   30 #include <IOKit/IORegistryEntry.h>
   31 #include <IOKit/IOCatalogue.h>
   32 #include <IOKit/IOKitKeysPrivate.h>
   33 #include <libkern/c++/OSUnserialize.h>
   34 #include <libkern/OSByteOrder.h>
   35 #include <libsa/catalogue.h>
   36 
   37 extern "C" {
   38 #include <machine/machine_routines.h>
   39 #include <mach/host_info.h>
   40 #include <mach/kmod.h>
   41 #include <libsa/mkext.h>
   42 #include <libsa/vers_rsrc.h>
   43 #include <mach-o/loader.h>
   44 };
   45 
   46 #include <IOKit/IOLib.h>
   47 
   48 #include <IOKit/assert.h>
   49 
   50 extern "C" {
   51 extern void IODTFreeLoaderInfo( char *key, void *infoAddr, int infoSize );
   52 // extern kern_return_t host_info(host_t host,
   53 //     host_flavor_t flavor,
   54 //     host_info_t info,
   55 //     mach_msg_type_number_t  *count);
   56 extern int grade_binary(cpu_type_t exectype, cpu_subtype_t execsubtype);
   57 // Return the address of the named Mach-O segment from the currently
   58 // executing 32 bit kernel, or NULL.
   59 extern struct segment_command *getsegbyname(char *seg_name);
   60 // Return the address of the named section from the named Mach-O segment
   61 // from the currently executing 32 bit kernel, or NULL.
   62 extern struct section *getsectbyname(const char *segname, const char *sectname);
   63 };
   64 
   65 #define LOG_DELAY()
   66 
   67 #if 0
   68 #define VTYELLOW   "\033[33m"
   69 #define VTRESET    "\033[0m"
   70 #else
   71 #define VTYELLOW   ""
   72 #define VTRESET    ""
   73 #endif
   74 
   75 /*********************************************************************
   76 *********************************************************************/
   77 static OSDictionary * gStartupExtensions = 0;
   78 static OSArray * gBootLoaderObjects = 0;
   79 extern OSArray * gIOPrelinkedModules;
   80 
   81 OSDictionary * getStartupExtensions(void) {
   82     if (gStartupExtensions) {
   83         return gStartupExtensions;
   84     }
   85     gStartupExtensions = OSDictionary::withCapacity(1);
   86     assert (gStartupExtensions);
   87 
   88     return gStartupExtensions;
   89 }
   90 
   91 /* This array holds objects that are needed to be held around during
   92  * boot before kextd starts up. Currently it contains OSData objects
   93  * copied from OF entries for mkext archives in device ROMs. Because
   94  * the Device Tree support code dumps these after initially handing
   95  * them to us, we have to be able to clean them up later.
   96  */
   97 OSArray * getBootLoaderObjects(void) {
   98     if (gBootLoaderObjects) {
   99         return gBootLoaderObjects;
  100     }
  101     gBootLoaderObjects = OSArray::withCapacity(1);
  102     assert (gBootLoaderObjects);
  103 
  104     return gBootLoaderObjects;
  105 }
  106 
  107 /*********************************************************************
  108 * This function checks that a driver dict has all the required
  109 * entries and does a little bit of value checking too.
  110 *
  111 * index is nonnegative if the index of an entry from an mkext
  112 * archive.
  113 *********************************************************************/
  114 bool validateExtensionDict(OSDictionary * extension, int index) {
  115 
  116     bool result = true;
  117     bool not_a_dict = false;
  118     bool id_missing = false;
  119     bool is_kernel_resource = false;
  120     bool has_executable = false;
  121     bool ineligible_for_safe_boot = false;
  122     OSString * bundleIdentifier = NULL;    // do not release
  123     OSObject * rawValue = NULL;            // do not release
  124     OSString * stringValue = NULL;         // do not release
  125     OSBoolean * booleanValue = NULL;       // do not release
  126     OSDictionary * personalities = NULL;   // do not release
  127     OSDictionary * libraries = NULL;       // do not release
  128     OSCollectionIterator * keyIterator = NULL;  // must release
  129     OSString * key = NULL;                 // do not release
  130     VERS_version vers;
  131     VERS_version compatible_vers;
  132     char namep[16];      // unused but needed for PE_parse_boot_arg()
  133 
  134     // Info dict is a dictionary
  135     if (!OSDynamicCast(OSDictionary, extension)) {
  136         not_a_dict = true;
  137         result = false;
  138         goto finish;
  139     }
  140 
  141     // CFBundleIdentifier is a string - REQUIRED
  142     bundleIdentifier = OSDynamicCast(OSString,
  143         extension->getObject("CFBundleIdentifier"));
  144     if (!bundleIdentifier) {
  145         id_missing = true;
  146         result = false;
  147         goto finish;
  148     }
  149 
  150     // Length of CFBundleIdentifier is not >= KMOD_MAX_NAME
  151     if (bundleIdentifier->getLength() >= KMOD_MAX_NAME) {
  152         result = false;
  153         goto finish;
  154     }
  155 
  156     // CFBundlePackageType is "KEXT" - REQUIRED
  157     stringValue = OSDynamicCast(OSString,
  158         extension->getObject("CFBundlePackageType"));
  159     if (!stringValue) {
  160         result = false;
  161         goto finish;
  162     }
  163     if (!stringValue->isEqualTo("KEXT")) {
  164         result = false;
  165         goto finish;
  166     }
  167 
  168     // CFBundleVersion is a string - REQUIRED
  169     stringValue = OSDynamicCast(OSString,
  170         extension->getObject("CFBundleVersion"));
  171     if (!stringValue) {
  172         result = false;
  173         goto finish;
  174     }
  175     // CFBundleVersion is of valid form
  176     vers = VERS_parse_string(stringValue->getCStringNoCopy());
  177     if (vers < 0) {
  178         result = false;
  179         goto finish;
  180     }
  181 
  182     // OSBundleCompatibleVersion is a string - OPTIONAL
  183     rawValue = extension->getObject("OSBundleCompatibleVersion");
  184     if (rawValue) {
  185         stringValue = OSDynamicCast(OSString, rawValue);
  186         if (!stringValue) {
  187             result = false;
  188             goto finish;
  189         }
  190 
  191         // OSBundleCompatibleVersion is of valid form
  192         compatible_vers = VERS_parse_string(stringValue->getCStringNoCopy());
  193         if (compatible_vers < 0) {
  194             result = false;
  195             goto finish;
  196         }
  197 
  198         // OSBundleCompatibleVersion <= CFBundleVersion
  199         if (compatible_vers > vers) {
  200             result = false;
  201             goto finish;
  202         }
  203     }
  204 
  205     // CFBundleExecutable is a string - OPTIONAL
  206     rawValue = extension->getObject("CFBundleExecutable");
  207     if (rawValue) {
  208         stringValue = OSDynamicCast(OSString, rawValue);
  209         if (!stringValue || stringValue->getLength() == 0) {
  210             result = false;
  211             goto finish;
  212         }
  213         has_executable = true;
  214     }
  215 
  216     // OSKernelResource is a boolean value - OPTIONAL
  217     rawValue = extension->getObject("OSKernelResource");
  218     if (rawValue) {
  219         booleanValue = OSDynamicCast(OSBoolean, rawValue);
  220         if (!booleanValue) {
  221             result = false;
  222             goto finish;
  223         }
  224         is_kernel_resource = booleanValue->isTrue();
  225     }
  226 
  227     // IOKitPersonalities is a dictionary - OPTIONAL
  228     rawValue = extension->getObject("IOKitPersonalities");
  229     if (rawValue) {
  230         personalities = OSDynamicCast(OSDictionary, rawValue);
  231         if (!personalities) {
  232             result = false;
  233             goto finish;
  234         }
  235 
  236         keyIterator = OSCollectionIterator::withCollection(personalities);
  237         if (!keyIterator) {
  238             IOLog("Error: Failed to allocate iterator for personalities.\n");
  239             LOG_DELAY();
  240             result = false;
  241             goto finish;
  242         }
  243 
  244         while ((key = OSDynamicCast(OSString, keyIterator->getNextObject()))) {
  245             OSDictionary * personality = NULL;  // do not release
  246 
  247             // Each personality is a dictionary
  248             personality = OSDynamicCast(OSDictionary,
  249                 personalities->getObject(key));
  250             if (!personality) {
  251                 result = false;
  252                 goto finish;
  253             }
  254 
  255             //   IOClass exists as a string - REQUIRED
  256             if (!OSDynamicCast(OSString, personality->getObject("IOClass"))) {
  257                 result = false;
  258                 goto finish;
  259             }
  260 
  261             //   IOProviderClass exists as a string - REQUIRED
  262             if (!OSDynamicCast(OSString,
  263                 personality->getObject("IOProviderClass"))) {
  264 
  265                 result = false;
  266                 goto finish;
  267             }
  268 
  269             // CFBundleIdentifier is a string - OPTIONAL - INSERT IF ABSENT!
  270             rawValue = personality->getObject("CFBundleIdentifier");
  271             if (!rawValue) {
  272                 personality->setObject("CFBundleIdentifier", bundleIdentifier);
  273             } else {
  274                 OSString * personalityID = NULL;    // do not release
  275                 personalityID = OSDynamicCast(OSString, rawValue);
  276                 if (!personalityID) {
  277                     result = false;
  278                     goto finish;
  279                 } else {
  280                     // Length of CFBundleIdentifier is not >= KMOD_MAX_NAME
  281                     if (personalityID->getLength() >= KMOD_MAX_NAME) {
  282                         result = false;
  283                         goto finish;
  284                     }
  285                 }
  286             }
  287 
  288             // IOKitDebug is a number - OPTIONAL
  289             rawValue = personality->getObject("IOKitDebug");
  290             if (rawValue && !OSDynamicCast(OSNumber, rawValue)) {
  291                 result = false;
  292                 goto finish;
  293             }
  294         }
  295 
  296         keyIterator->release();
  297         keyIterator = NULL;
  298     }
  299 
  300 
  301     // OSBundleLibraries is a dictionary - REQUIRED if
  302     // not kernel resource & has executable
  303     //
  304     rawValue = extension->getObject("OSBundleLibraries");
  305     if (!rawValue && !is_kernel_resource && has_executable) {
  306         result = false;
  307         goto finish;
  308     }
  309 
  310     if (rawValue) {
  311         libraries = OSDynamicCast(OSDictionary, rawValue);
  312         if (!libraries) {
  313             result = false;
  314             goto finish;
  315         }
  316 
  317         keyIterator = OSCollectionIterator::withCollection(libraries);
  318         if (!keyIterator) {
  319             IOLog("Error: Failed to allocate iterator for libraries.\n");
  320             LOG_DELAY();
  321             result = false;
  322             goto finish;
  323         }
  324 
  325         while ((key = OSDynamicCast(OSString,
  326             keyIterator->getNextObject()))) {
  327 
  328             OSString * libraryVersion = NULL;  // do not release
  329 
  330             // Each key's length is not >= KMOD_MAX_NAME
  331             if (key->getLength() >= KMOD_MAX_NAME) {
  332                 result = false;
  333                 goto finish;
  334             }
  335 
  336             libraryVersion = OSDynamicCast(OSString,
  337                 libraries->getObject(key));
  338             if (!libraryVersion) {
  339                 result = false;
  340                 goto finish;
  341             }
  342 
  343             // Each value is a valid version string
  344             vers = VERS_parse_string(libraryVersion->getCStringNoCopy());
  345             if (vers < 0) {
  346                 result = false;
  347                 goto finish;
  348             }
  349         }
  350 
  351         keyIterator->release();
  352         keyIterator = NULL;
  353     }
  354 
  355     // OSBundleRequired, if present, must have a legal value.
  356     // If it is not present and if we are safe-booting,
  357     // then the kext is not eligible.
  358     //
  359     rawValue = extension->getObject("OSBundleRequired");
  360     if (rawValue) {
  361         stringValue = OSDynamicCast(OSString, rawValue);
  362         if (!stringValue) {
  363             result = false;
  364             goto finish;
  365         }
  366         if (!stringValue->isEqualTo("Root") &&
  367             !stringValue->isEqualTo("Local-Root") &&
  368             !stringValue->isEqualTo("Network-Root") &&
  369             !stringValue->isEqualTo("Safe Boot") &&
  370             !stringValue->isEqualTo("Console")) {
  371 
  372             result = false;
  373             goto finish;
  374         }
  375 
  376     } else if (PE_parse_boot_arg("-x", namep)) { /* safe boot */
  377         ineligible_for_safe_boot = true;
  378         result = false;
  379         goto finish;
  380     }
  381 
  382 
  383 finish:
  384     if (keyIterator)   keyIterator->release();
  385 
  386     if (!result) {
  387         if (ineligible_for_safe_boot) {
  388             IOLog(VTYELLOW "Skipping extension \"%s\" during safe boot "
  389                 "(no OSBundleRequired property)\n"
  390                 VTRESET,
  391                 bundleIdentifier->getCStringNoCopy());
  392         } else if (not_a_dict) {
  393             if (index > -1) {
  394                 IOLog(VTYELLOW "mkext entry %d: " VTRESET, index);
  395             } else {
  396                 IOLog(VTYELLOW "kernel extension " VTRESET);
  397             }
  398             IOLog(VTYELLOW "info dictionary isn't a dictionary\n"
  399                 VTRESET);
  400         } else if (id_missing) {
  401             if (index > -1) {
  402                 IOLog(VTYELLOW "mkext entry %d: " VTRESET, index);
  403             } else {
  404                 IOLog(VTYELLOW "kernel extension " VTRESET);
  405             }
  406             IOLog(VTYELLOW "\"CFBundleIdentifier\" property is "
  407                 "missing or not a string\n"
  408                 VTRESET);
  409         } else {
  410             IOLog(VTYELLOW "kernel extension \"%s\": info dictionary is invalid\n"
  411                 VTRESET, bundleIdentifier->getCStringNoCopy());
  412         }
  413         LOG_DELAY();
  414     }
  415 
  416     return result;
  417 }
  418 
  419 
  420 /*********************************************************************
  421 *********************************************************************/
  422 OSDictionary * compareExtensionVersions(
  423     OSDictionary * incumbent,
  424     OSDictionary * candidate) {
  425 
  426     OSDictionary * winner = NULL;
  427 
  428     OSDictionary * incumbentPlist = NULL;
  429     OSDictionary * candidatePlist = NULL;
  430     OSString * incumbentName = NULL;
  431     OSString * candidateName = NULL;
  432     OSString * incumbentVersionString = NULL;
  433     OSString * candidateVersionString = NULL;
  434     VERS_version incumbent_vers = 0;
  435     VERS_version candidate_vers = 0;
  436 
  437     incumbentPlist = OSDynamicCast(OSDictionary,
  438         incumbent->getObject("plist"));
  439     candidatePlist = OSDynamicCast(OSDictionary,
  440         candidate->getObject("plist"));
  441 
  442     if (!incumbentPlist || !candidatePlist) {
  443         IOLog("compareExtensionVersions() called with invalid "
  444             "extension dictionaries.\n");
  445         LOG_DELAY();
  446         winner = NULL;
  447         goto finish;
  448     }
  449 
  450     incumbentName = OSDynamicCast(OSString,
  451         incumbentPlist->getObject("CFBundleIdentifier"));
  452     candidateName = OSDynamicCast(OSString,
  453         candidatePlist->getObject("CFBundleIdentifier"));
  454     incumbentVersionString = OSDynamicCast(OSString,
  455         incumbentPlist->getObject("CFBundleVersion"));
  456     candidateVersionString = OSDynamicCast(OSString,
  457         candidatePlist->getObject("CFBundleVersion"));
  458 
  459     if (!incumbentName || !candidateName ||
  460         !incumbentVersionString || !candidateVersionString) {
  461 
  462         IOLog("compareExtensionVersions() called with invalid "
  463             "extension dictionaries.\n");
  464         LOG_DELAY();
  465         winner = NULL;
  466         goto finish;
  467     }
  468 
  469     if (strcmp(incumbentName->getCStringNoCopy(),
  470                candidateName->getCStringNoCopy())) {
  471 
  472         IOLog("compareExtensionVersions() called with different "
  473             "extension names (%s and %s).\n",
  474             incumbentName->getCStringNoCopy(),
  475             candidateName->getCStringNoCopy());
  476         LOG_DELAY();
  477         winner = NULL;
  478         goto finish;
  479     }
  480 
  481     incumbent_vers = VERS_parse_string(incumbentVersionString->getCStringNoCopy());
  482     if (incumbent_vers < 0) {
  483 
  484         IOLog(VTYELLOW "Error parsing version string for extension %s (%s)\n"
  485             VTRESET,
  486             incumbentName->getCStringNoCopy(),
  487             incumbentVersionString->getCStringNoCopy());
  488         LOG_DELAY();
  489         winner = NULL;
  490         goto finish;
  491     }
  492 
  493     candidate_vers = VERS_parse_string(candidateVersionString->getCStringNoCopy());
  494     if (candidate_vers < 0) {
  495 
  496         IOLog(VTYELLOW "Error parsing version string for extension %s (%s)\n"
  497             VTRESET,
  498             candidateName->getCStringNoCopy(),
  499             candidateVersionString->getCStringNoCopy());
  500         LOG_DELAY();
  501         winner = NULL;
  502         goto finish;
  503      }
  504   
  505     if (candidate_vers > incumbent_vers) {
  506         IOLog(VTYELLOW "Replacing extension \"%s\" with newer version "
  507             "(%s -> %s).\n" VTRESET,
  508             incumbentName->getCStringNoCopy(),
  509             incumbentVersionString->getCStringNoCopy(),
  510             candidateVersionString->getCStringNoCopy());
  511         LOG_DELAY();
  512         winner = candidate;
  513         goto finish;
  514     } else {
  515         IOLog(VTYELLOW "Skipping duplicate extension \"%s\" with older/same "
  516             " version (%s -> %s).\n" VTRESET,
  517             candidateName->getCStringNoCopy(),
  518             candidateVersionString->getCStringNoCopy(),
  519             incumbentVersionString->getCStringNoCopy());
  520         LOG_DELAY();
  521         winner = incumbent;
  522         goto finish;
  523     }
  524 
  525 finish:
  526 
  527     // no cleanup, how nice
  528     return winner;
  529 }
  530 
  531 
  532 /*********************************************************************
  533 * This function merges entries in the mergeFrom dictionary into the
  534 * mergeInto dictionary. If it returns false, the two dictionaries are
  535 * not altered. If it returns true, then mergeInto may have new
  536 * entries; any keys that were already present in mergeInto are
  537 * removed from mergeFrom, so that the caller can see what was
  538 * actually merged.
  539 *********************************************************************/
  540 bool mergeExtensionDictionaries(OSDictionary * mergeInto,
  541     OSDictionary * mergeFrom) {
  542 
  543     bool result = true;
  544     OSDictionary * mergeIntoCopy = NULL;       // must release
  545     OSDictionary * mergeFromCopy = NULL;       // must release
  546     OSCollectionIterator * keyIterator = NULL; // must release
  547     OSString * key;                            // don't release
  548 
  549    /* Add 1 to count to guarantee copy can grow (grr).
  550     */
  551     mergeIntoCopy = OSDictionary::withDictionary(mergeInto,
  552         mergeInto->getCount() + 1);
  553     if (!mergeIntoCopy) {
  554         IOLog("Error: Failed to copy 'into' extensions dictionary "
  555             "for merge.\n");
  556         LOG_DELAY();
  557         result = false;
  558         goto finish;
  559     }
  560 
  561    /* Add 1 to count to guarantee copy can grow (grr).
  562     */
  563     mergeFromCopy = OSDictionary::withDictionary(mergeFrom,
  564         mergeFrom->getCount() + 1);
  565     if (!mergeFromCopy) {
  566         IOLog("Error: Failed to copy 'from' extensions dictionary "
  567             "for merge.\n");
  568         LOG_DELAY();
  569         result = false;
  570         goto finish;
  571     }
  572 
  573     keyIterator = OSCollectionIterator::withCollection(mergeFrom);
  574     if (!keyIterator) {
  575         IOLog("Error: Failed to allocate iterator for extensions.\n");
  576         LOG_DELAY();
  577         result = false;
  578         goto finish;
  579     }
  580 
  581 
  582    /*****
  583     * Loop through "from" dictionary, checking if the identifier already
  584     * exists in the "into" dictionary and checking versions if it does.
  585     */
  586     while ((key = OSDynamicCast(OSString, keyIterator->getNextObject()))) {
  587         OSDictionary * incumbentExt = OSDynamicCast(OSDictionary,
  588             mergeIntoCopy->getObject(key));
  589         OSDictionary * candidateExt = OSDynamicCast(OSDictionary,
  590             mergeFrom->getObject(key));
  591 
  592         if (!incumbentExt) {
  593             if (!mergeIntoCopy->setObject(key, candidateExt)) {
  594 
  595                /* This is a fatal error, so bail.
  596                 */
  597                 IOLog("mergeExtensionDictionaries(): Failed to add "
  598                     "identifier %s\n",
  599                     key->getCStringNoCopy());
  600                 LOG_DELAY();
  601                 result = false;
  602                 goto finish;
  603             }
  604         } else {
  605             OSDictionary * mostRecentExtension =
  606                 compareExtensionVersions(incumbentExt, candidateExt);
  607 
  608             if (mostRecentExtension == incumbentExt) {
  609                 mergeFromCopy->removeObject(key);
  610             } else if (mostRecentExtension == candidateExt) {
  611 
  612                 if (!mergeIntoCopy->setObject(key, candidateExt)) {
  613 
  614                    /* This is a fatal error, so bail.
  615                     */
  616                     IOLog("mergeExtensionDictionaries(): Failed to add "
  617                         "identifier %s\n",
  618                         key->getCStringNoCopy());
  619                     LOG_DELAY();
  620                     result = false;
  621                     goto finish;
  622                 }
  623             } else /* should be NULL */ {
  624     
  625                /* This is a nonfatal error, so continue doing others.
  626                 */
  627                 IOLog("mergeExtensionDictionaries(): Error comparing "
  628                     "versions of duplicate extensions %s.\n",
  629                     key->getCStringNoCopy());
  630                 LOG_DELAY();
  631                 continue;
  632             }
  633         }
  634     }
  635 
  636 finish:
  637 
  638    /* If successful, replace the contents of the original
  639     * dictionaries with those of the modified copies.
  640     */
  641     if (result) {
  642         mergeInto->flushCollection();
  643         mergeInto->merge(mergeIntoCopy);
  644         mergeFrom->flushCollection();
  645         mergeFrom->merge(mergeFromCopy);
  646     }
  647 
  648     if (mergeIntoCopy) mergeIntoCopy->release();
  649     if (mergeFromCopy) mergeFromCopy->release();
  650     if (keyIterator)   keyIterator->release();
  651 
  652     return result;
  653 }
  654 
  655 
  656 /****
  657  * These bits are used to parse data made available by bootx.
  658  */
  659 #define BOOTX_KEXT_PREFIX       "Driver-"
  660 #define BOOTX_MULTIKEXT_PREFIX  "DriversPackage-"
  661 
  662 typedef struct MemoryMapFileInfo {
  663     UInt32 paddr;
  664     UInt32 length;
  665 } MemoryMapFileInfo;
  666 
  667 typedef struct BootxDriverInfo {
  668     char *plistAddr;
  669     long  plistLength;
  670     void *moduleAddr;
  671     long  moduleLength;
  672 } BootxDriverInfo;
  673 
  674 typedef struct MkextEntryInfo {
  675     vm_address_t  base_address;
  676     mkext_file  * fileinfo;
  677 } MkextEntryInfo;
  678 
  679 
  680 /*********************************************************************
  681 * This private function reads the data for a single extension from
  682 * the bootx memory-map's propery dict, returning a dictionary with
  683 * keys "plist" for the extension's Info.plist as a parsed OSDictionary
  684 * and "code" for the extension's executable code as an OSData.
  685 *********************************************************************/
  686 OSDictionary * readExtension(OSDictionary * propertyDict,
  687     const char * memory_map_name) {
  688 
  689     int error = 0;
  690     OSData               * bootxDriverDataObject = NULL;
  691     OSDictionary         * driverPlist = NULL;
  692     OSString             * driverName = NULL;
  693     OSData               * driverCode = NULL;
  694     OSString             * errorString = NULL;
  695     OSDictionary         * driverDict = NULL;
  696 
  697     const MemoryMapFileInfo * driverInfo = 0;
  698     BootxDriverInfo * dataBuffer;
  699 
  700     kmod_info_t          * loaded_kmod = NULL;
  701 
  702     bootxDriverDataObject = OSDynamicCast(OSData,
  703         propertyDict->getObject(memory_map_name));
  704     // don't release bootxDriverDataObject
  705 
  706     if (!bootxDriverDataObject) {
  707         IOLog("Error: No driver data object "
  708             "for device tree entry \"%s\".\n",
  709             memory_map_name);
  710         LOG_DELAY();
  711         error = 1;
  712         goto finish;
  713     }
  714 
  715     driverDict = OSDictionary::withCapacity(2);
  716     if (!driverDict) {
  717         IOLog("Error: Couldn't allocate dictionary "
  718             "for device tree entry \"%s\".\n", memory_map_name);
  719         LOG_DELAY();
  720         error = 1;
  721         goto finish;
  722     }
  723 
  724     driverInfo = (const MemoryMapFileInfo *)
  725         bootxDriverDataObject->getBytesNoCopy(0,
  726         sizeof(MemoryMapFileInfo));
  727 #if defined (__ppc__) || defined (__arm__)
  728     dataBuffer = (BootxDriverInfo *)ml_static_ptovirt(driverInfo->paddr);
  729 #elif defined (__i386__)
  730     dataBuffer = (BootxDriverInfo *)ml_boot_ptovirt(driverInfo->paddr);
  731     dataBuffer->plistAddr = (char *)ml_boot_ptovirt((vm_address_t)dataBuffer->plistAddr);
  732     if (dataBuffer->moduleAddr)
  733       dataBuffer->moduleAddr = (void *)ml_boot_ptovirt((vm_address_t)dataBuffer->moduleAddr);
  734 #else
  735 #error unsupported architecture
  736 #endif
  737     if (!dataBuffer) {
  738         IOLog("Error: No data buffer "
  739         "for device tree entry \"%s\".\n", memory_map_name);
  740         LOG_DELAY();
  741         error = 1;
  742         goto finish;
  743     }
  744 
  745     driverPlist = OSDynamicCast(OSDictionary,
  746         OSUnserializeXML(dataBuffer->plistAddr, &errorString));
  747     if (!driverPlist) {
  748         IOLog("Error: Couldn't read XML property list "
  749             "for device tree entry \"%s\".\n", memory_map_name);
  750         LOG_DELAY();
  751         if (errorString) {
  752             IOLog("XML parse error: %s.\n",
  753                 errorString->getCStringNoCopy());
  754             LOG_DELAY();
  755         }
  756         error = 1;
  757         goto finish;
  758     }
  759 
  760 
  761     driverName = OSDynamicCast(OSString,
  762         driverPlist->getObject("CFBundleIdentifier"));  // do not release
  763     if (!driverName) {
  764         IOLog("Error: Device tree entry \"%s\" has "
  765             "no \"CFBundleIdentifier\" property.\n", memory_map_name);
  766         LOG_DELAY();
  767         error = 1;
  768         goto finish;
  769     }
  770 
  771    /* Check if kmod is already loaded and is a real loadable one (has
  772     * an address).
  773     */
  774     loaded_kmod = kmod_lookupbyname_locked(driverName->getCStringNoCopy());
  775     if (loaded_kmod && loaded_kmod->address) {
  776         IOLog("Skipping new extension \"%s\"; an extension named "
  777             "\"%s\" is already loaded.\n",
  778             driverName->getCStringNoCopy(),
  779             loaded_kmod->name);
  780         LOG_DELAY();
  781         error = 1;
  782         goto finish;
  783     }
  784 
  785     if (!validateExtensionDict(driverPlist, -1)) {
  786         // validateExtensionsDict() logs an error
  787         error = 1;
  788         goto finish;
  789     }
  790 
  791     driverDict->setObject("plist", driverPlist);
  792 
  793    /* It's perfectly okay for a KEXT to have no executable.
  794     * Check that moduleAddr is nonzero before attempting to
  795     * get one.
  796     *
  797     * NOTE: The driverCode object is created "no-copy", so
  798     * it doesn't own that memory. The memory must be freed
  799     * separately from the OSData object (see
  800     * clearStartupExtensionsAndLoaderInfo() at the end of this file).
  801     */
  802     if (dataBuffer->moduleAddr && dataBuffer->moduleLength) {
  803         driverCode = OSData::withBytesNoCopy(dataBuffer->moduleAddr,
  804             dataBuffer->moduleLength);
  805         if (!driverCode) {
  806             IOLog("Error: Couldn't allocate data object "
  807                 "to hold code for device tree entry \"%s\".\n",
  808                 memory_map_name);
  809             LOG_DELAY();
  810             error = 1;
  811             goto finish;
  812         }
  813 
  814         if (driverCode) {
  815             driverDict->setObject("code", driverCode);
  816         }
  817     }
  818 
  819 finish:
  820 
  821     if (loaded_kmod) {
  822         kfree(loaded_kmod, sizeof(kmod_info_t));
  823     }
  824 
  825     // do not release bootxDriverDataObject
  826     // do not release driverName
  827 
  828     if (driverPlist) {
  829         driverPlist->release();
  830     }
  831     if (errorString) {
  832         errorString->release();
  833     }
  834     if (driverCode) {
  835         driverCode->release();
  836     }
  837     if (error) {
  838         if (driverDict) {
  839             driverDict->release();
  840             driverDict = NULL;
  841         }
  842     }
  843     return driverDict;
  844 }
  845 
  846 
  847 /*********************************************************************
  848 * Used to uncompress a single file entry in an mkext archive.
  849 *
  850 * The OSData returned does not own its memory! You must deallocate
  851 * that memory using kmem_free() before releasing the OSData().
  852 *********************************************************************/
  853 static bool uncompressFile(u_int8_t *base_address, mkext_file * fileinfo,
  854                            /* out */ OSData ** file) {
  855 
  856     bool result = true;
  857     kern_return_t kern_result;
  858     u_int8_t * uncompressed_file = 0; // kmem_free() on error
  859     OSData * uncompressedFile = 0;    // returned
  860     size_t uncompressed_size = 0;
  861 
  862     size_t offset = OSSwapBigToHostInt32(fileinfo->offset);
  863     size_t compsize = OSSwapBigToHostInt32(fileinfo->compsize);
  864     size_t realsize = OSSwapBigToHostInt32(fileinfo->realsize);
  865     time_t modifiedsecs = OSSwapBigToHostInt32(fileinfo->modifiedsecs);
  866 
  867     *file = 0;
  868 
  869    /* If these four fields are zero there's no file, but that isn't
  870     * an error.
  871     */
  872     if (offset == 0 && compsize == 0 &&
  873         realsize == 0 && modifiedsecs == 0) {
  874         goto finish;
  875     }
  876 
  877     // Add 1 for '\0' to terminate XML string!
  878     kern_result = kmem_alloc(kernel_map, (vm_offset_t *)&uncompressed_file,
  879         realsize + 1);
  880     if (kern_result != KERN_SUCCESS) {
  881         IOLog("Error: Couldn't allocate data buffer "
  882               "to uncompress file.\n");
  883         LOG_DELAY();
  884         result = false;
  885         goto finish;
  886     }
  887 
  888     uncompressedFile = OSData::withBytesNoCopy(uncompressed_file,
  889         realsize + 1);
  890     if (!uncompressedFile) {
  891         IOLog("Error: Couldn't allocate data object "
  892               "to uncompress file.\n");
  893         LOG_DELAY();
  894         result = false;
  895         goto finish;
  896     }
  897 
  898     if (compsize != 0) {
  899         uncompressed_size = decompress_lzss(uncompressed_file,
  900             base_address + offset,
  901             compsize);
  902         if (uncompressed_size != realsize) {
  903             IOLog("Error: Uncompressed file is not the length "
  904                   "recorded.\n");
  905             LOG_DELAY();
  906             result = false;
  907             goto finish;
  908         }
  909         uncompressed_file[uncompressed_size] = '\0';
  910     } else {
  911         bcopy(base_address + offset, uncompressed_file,
  912             realsize);
  913         uncompressed_file[realsize] = '\0';
  914     }
  915 
  916     *file = uncompressedFile;
  917 
  918 finish:
  919     if (!result) {
  920         if (uncompressed_file) {
  921             kmem_free(kernel_map, (vm_address_t)uncompressed_file,
  922                 realsize + 1);
  923         }
  924         if (uncompressedFile) {
  925             uncompressedFile->release();
  926             *file = 0;
  927         }
  928     }
  929     return result;
  930 }
  931 
  932 bool uncompressModule(OSData *compData, /* out */ OSData ** file) {
  933 
  934     const MkextEntryInfo *info = (const MkextEntryInfo *) compData->getBytesNoCopy();
  935 
  936     return uncompressFile((u_int8_t *) info->base_address, 
  937                           info->fileinfo, file);
  938 }
  939 
  940 
  941 /*********************************************************************
  942 * Does the work of pulling extensions out of an mkext archive located
  943 * in memory.
  944 *********************************************************************/
  945 bool extractExtensionsFromArchive(const MemoryMapFileInfo * mkext_file_info,
  946     bool vaddr,
  947     OSDictionary * extensions) {
  948 
  949     bool result = true;
  950 
  951     u_int8_t     * crc_address = 0;
  952     u_int32_t      checksum;
  953     mkext_header * mkext_data = 0;   // don't free
  954     mkext_kext   * onekext_data = 0; // don't free
  955     mkext_file   * plist_file = 0;   // don't free
  956     mkext_file   * module_file = 0;  // don't free
  957     kmod_info_t  * loaded_kmod = 0;  // must free
  958 
  959     OSData       * driverPlistDataObject = 0; // must release
  960     OSDictionary * driverPlist = 0;  // must release
  961     OSData       * driverCode = 0;   // must release
  962     OSDictionary * driverDict = 0;   // must release
  963     OSString     * moduleName = 0;   // don't release
  964     OSString     * errorString = NULL;  // must release
  965 
  966     OSData         * moduleInfo = 0;  // must release
  967     MkextEntryInfo   module_info;
  968 
  969     if (vaddr) {
  970         // addExtensionsFromArchive passes a kernel virtual address
  971         mkext_data = (mkext_header *)mkext_file_info->paddr;
  972     } else {
  973 #if defined (__ppc__) || defined (__arm__)
  974         mkext_data = (mkext_header *)ml_static_ptovirt(mkext_file_info->paddr);
  975 #elif defined (__i386__)
  976         mkext_data = (mkext_header *)ml_boot_ptovirt(mkext_file_info->paddr);
  977 #else
  978 #error unsupported architecture
  979 #endif
  980     }
  981 
  982     if (OSSwapBigToHostInt32(mkext_data->magic) != MKEXT_MAGIC ||
  983         OSSwapBigToHostInt32(mkext_data->signature) != MKEXT_SIGN) {
  984         IOLog("Error: Extension archive has invalid magic or signature.\n");
  985         LOG_DELAY();
  986         result = false;
  987         goto finish;
  988     }
  989 
  990     if (OSSwapBigToHostInt32(mkext_data->length) != mkext_file_info->length) {
  991         IOLog("Error: Mismatch between extension archive & "
  992             "recorded length.\n");
  993         LOG_DELAY();
  994         result = false;
  995         goto finish;
  996     }
  997 
  998     crc_address = (u_int8_t *)&mkext_data->version;
  999     checksum = adler32(crc_address,
 1000         (unsigned int)mkext_data +
 1001         OSSwapBigToHostInt32(mkext_data->length) - (unsigned int)crc_address);
 1002 
 1003     if (OSSwapBigToHostInt32(mkext_data->adler32) != checksum) {
 1004         IOLog("Error: Extension archive has a bad checksum.\n");
 1005         LOG_DELAY();
 1006         result = false;
 1007         goto finish;
 1008     }
 1009 
 1010     IORegistryEntry * root = IORegistryEntry::getRegistryRoot();
 1011     assert(root);
 1012     OSData * checksumObj = OSData::withBytes((void *)&checksum,
 1013         sizeof(checksum));
 1014     assert(checksumObj);
 1015     if (checksumObj) {
 1016         root->setProperty(kIOStartupMkextCRC, checksumObj);
 1017         checksumObj->release();
 1018     }
 1019 
 1020    /* If the MKEXT archive isn't fat, check that the CPU type & subtype
 1021     * match that of the running kernel.
 1022     */
 1023     if (OSSwapBigToHostInt32(mkext_data->cputype) != (UInt32)CPU_TYPE_ANY) {
 1024         kern_return_t          kresult = KERN_FAILURE;
 1025         host_basic_info_data_t hostinfo;
 1026         host_info_t            hostinfo_ptr = (host_info_t)&hostinfo;
 1027         mach_msg_type_number_t count = sizeof(hostinfo)/sizeof(integer_t);
 1028 
 1029         kresult = host_info((host_t)1, HOST_BASIC_INFO,
 1030             hostinfo_ptr, &count);
 1031         if (kresult != KERN_SUCCESS) {
 1032             IOLog("Error: Couldn't get current host info.\n");
 1033             LOG_DELAY();
 1034             result = false;
 1035             goto finish;
 1036         }
 1037         if ((UInt32)hostinfo.cpu_type !=
 1038             OSSwapBigToHostInt32(mkext_data->cputype)) {
 1039 
 1040             IOLog("Error: Extension archive doesn't contain software "
 1041                 "for this computer's CPU type.\n");
 1042             LOG_DELAY();
 1043             result = false;
 1044             goto finish;
 1045         }
 1046         if (!grade_binary(OSSwapBigToHostInt32(mkext_data->cputype),
 1047                           OSSwapBigToHostInt32(mkext_data->cpusubtype))) {
 1048             IOLog("Error: Extension archive doesn't contain software "
 1049                 "for this computer's CPU subtype.\n");
 1050             LOG_DELAY();
 1051             result = false;
 1052             goto finish;
 1053         }
 1054     }
 1055 
 1056     for (unsigned int i = 0;
 1057          i < OSSwapBigToHostInt32(mkext_data->numkexts);
 1058          i++) {
 1059 
 1060         if (loaded_kmod) {
 1061             kfree(loaded_kmod, sizeof(kmod_info_t));
 1062             loaded_kmod = 0;
 1063         }
 1064 
 1065         if (driverPlistDataObject) {
 1066             kmem_free(kernel_map,
 1067                 (unsigned int)driverPlistDataObject->getBytesNoCopy(),
 1068                 driverPlistDataObject->getLength());
 1069 
 1070             driverPlistDataObject->release();
 1071             driverPlistDataObject = NULL;
 1072         }
 1073         if (driverPlist) {
 1074             driverPlist->release();
 1075             driverPlist = NULL;
 1076         }
 1077         if (driverCode) {
 1078             driverCode->release();
 1079             driverCode = NULL;
 1080         }
 1081         if (driverDict) {
 1082             driverDict->release();
 1083             driverDict = NULL;
 1084         }
 1085         if (errorString) {
 1086             errorString->release();
 1087             errorString = NULL;
 1088         }
 1089 
 1090         onekext_data = &mkext_data->kext[i];
 1091         plist_file = &onekext_data->plist;
 1092         module_file = &onekext_data->module;
 1093 
 1094         if (!uncompressFile((u_int8_t *)mkext_data, plist_file,
 1095             &driverPlistDataObject)) {
 1096 
 1097             IOLog("Error: couldn't uncompress plist file "
 1098                 "from multikext archive entry %d.\n", i);
 1099             LOG_DELAY();
 1100             continue;
 1101         }
 1102 
 1103         if (!driverPlistDataObject) {
 1104             IOLog("Error: No property list present "
 1105                 "for multikext archive entry %d.\n", i);
 1106             LOG_DELAY();
 1107             continue;
 1108         } else {
 1109             driverPlist = OSDynamicCast(OSDictionary,
 1110                 OSUnserializeXML(
 1111                     (const char *)driverPlistDataObject->getBytesNoCopy(),
 1112                     &errorString));
 1113             if (!driverPlist) {
 1114                 IOLog("Error: Couldn't read XML property list "
 1115                       "for multikext archive entry %d.\n", i);
 1116                 LOG_DELAY();
 1117                 if (errorString) {
 1118                     IOLog("XML parse error: %s.\n",
 1119                         errorString->getCStringNoCopy());
 1120                     LOG_DELAY();
 1121                 }
 1122                 continue;
 1123             }
 1124 
 1125             if (!validateExtensionDict(driverPlist, i)) {
 1126                 // validateExtensionsDict() logs an error
 1127                 continue;
 1128             }
 1129 
 1130         }
 1131 
 1132        /* Get the extension's module name. This is used to record
 1133         * the extension.
 1134         */
 1135         moduleName = OSDynamicCast(OSString,
 1136             driverPlist->getObject("CFBundleIdentifier"));  // do not release
 1137         if (!moduleName) {
 1138             IOLog("Error: Multikext archive entry %d has "
 1139                 "no \"CFBundleIdentifier\" property.\n", i);
 1140             LOG_DELAY();
 1141             continue; // assume a kext config error & continue
 1142         }
 1143 
 1144        /* Check if kmod is already loaded and is a real loadable one (has
 1145         * an address).
 1146         */
 1147         loaded_kmod = kmod_lookupbyname_locked(moduleName->getCStringNoCopy());
 1148         if (loaded_kmod && loaded_kmod->address) {
 1149             IOLog("Skipping new extension \"%s\"; an extension named "
 1150                 "\"%s\" is already loaded.\n",
 1151                 moduleName->getCStringNoCopy(),
 1152                 loaded_kmod->name);
 1153             continue;
 1154         }
 1155 
 1156 
 1157         driverDict = OSDictionary::withCapacity(2);
 1158         if (!driverDict) {
 1159             IOLog("Error: Couldn't allocate dictionary "
 1160                   "for multikext archive entry %d.\n", i);
 1161             LOG_DELAY();
 1162             result = false;
 1163             goto finish;
 1164         }
 1165 
 1166         driverDict->setObject("plist", driverPlist);
 1167 
 1168        /*****
 1169         * Prepare an entry to hold the mkext entry info for the
 1170         * compressed binary module, if there is one. If all four fields
 1171         * of the module entry are zero, there isn't one.
 1172         */
 1173         if (!(loaded_kmod && loaded_kmod->address) && (OSSwapBigToHostInt32(module_file->offset) ||
 1174             OSSwapBigToHostInt32(module_file->compsize) ||
 1175             OSSwapBigToHostInt32(module_file->realsize) ||
 1176             OSSwapBigToHostInt32(module_file->modifiedsecs))) {
 1177 
 1178             moduleInfo = OSData::withCapacity(sizeof(MkextEntryInfo));
 1179             if (!moduleInfo) {
 1180                 IOLog("Error: Couldn't allocate data object "
 1181                       "for multikext archive entry %d.\n", i);
 1182                 LOG_DELAY();
 1183                 result = false;
 1184                 goto finish;
 1185             }
 1186 
 1187             module_info.base_address = (vm_address_t)mkext_data;
 1188             module_info.fileinfo = module_file;
 1189 
 1190             if (!moduleInfo->appendBytes(&module_info, sizeof(module_info))) {
 1191                 IOLog("Error: Couldn't record info "
 1192                       "for multikext archive entry %d.\n", i);
 1193                 LOG_DELAY();
 1194                 result = false;
 1195                 goto finish;
 1196             }
 1197 
 1198             driverDict->setObject("compressedCode", moduleInfo);
 1199         }
 1200 
 1201         OSDictionary * incumbentExt = OSDynamicCast(OSDictionary,
 1202             extensions->getObject(moduleName));
 1203 
 1204         if (!incumbentExt) {
 1205             extensions->setObject(moduleName, driverDict);
 1206         } else {
 1207             OSDictionary * mostRecentExtension =
 1208                 compareExtensionVersions(incumbentExt, driverDict);
 1209 
 1210             if (mostRecentExtension == incumbentExt) {
 1211                 /* Do nothing, we've got the most recent. */
 1212             } else if (mostRecentExtension == driverDict) {
 1213                 if (!extensions->setObject(moduleName, driverDict)) {
 1214 
 1215                    /* This is a fatal error, so bail.
 1216                     */
 1217                     IOLog("extractExtensionsFromArchive(): Failed to add "
 1218                         "identifier %s\n",
 1219                         moduleName->getCStringNoCopy());
 1220                     LOG_DELAY();
 1221                     result = false;
 1222                     goto finish;
 1223                 }
 1224             } else /* should be NULL */ {
 1225 
 1226                /* This is a nonfatal error, so continue.
 1227                 */
 1228                 IOLog("extractExtensionsFromArchive(): Error comparing "
 1229                     "versions of duplicate extensions %s.\n",
 1230                     moduleName->getCStringNoCopy());
 1231                 LOG_DELAY();
 1232                 continue;
 1233             }
 1234         }
 1235     }
 1236 
 1237 finish:
 1238 
 1239     if (loaded_kmod) kfree(loaded_kmod, sizeof(kmod_info_t));
 1240     if (driverPlistDataObject) {
 1241         kmem_free(kernel_map,
 1242             (unsigned int)driverPlistDataObject->getBytesNoCopy(),
 1243             driverPlistDataObject->getLength());
 1244         driverPlistDataObject->release();
 1245     }
 1246     if (driverPlist) driverPlist->release();
 1247     if (driverCode)  driverCode->release();
 1248     if (moduleInfo)  moduleInfo->release();
 1249     if (driverDict)  driverDict->release();
 1250     if (errorString) errorString->release();
 1251 
 1252     return result;
 1253 }
 1254 
 1255 /*********************************************************************
 1256 *
 1257 *********************************************************************/
 1258 bool readExtensions(OSDictionary * propertyDict,
 1259     const char * memory_map_name,
 1260     OSDictionary * extensions) {
 1261 
 1262     bool result = true;
 1263     OSData * mkextDataObject = 0;      // don't release
 1264     const MemoryMapFileInfo * mkext_file_info = 0; // don't free
 1265 
 1266     mkextDataObject = OSDynamicCast(OSData,
 1267         propertyDict->getObject(memory_map_name));
 1268     // don't release mkextDataObject
 1269 
 1270     if (!mkextDataObject) {
 1271         IOLog("Error: No mkext data object "
 1272             "for device tree entry \"%s\".\n",
 1273             memory_map_name);
 1274         LOG_DELAY();
 1275         result = false;
 1276         goto finish;
 1277     }
 1278 
 1279     mkext_file_info = (const MemoryMapFileInfo *)mkextDataObject->getBytesNoCopy();
 1280     if (!mkext_file_info) {
 1281         result = false;
 1282         goto finish;
 1283     }
 1284 
 1285     result = extractExtensionsFromArchive(mkext_file_info, false /*physical*/, extensions);
 1286 
 1287 finish:
 1288 
 1289     if (!result && extensions) {
 1290         extensions->flushCollection();
 1291     }
 1292 
 1293     return result;
 1294 }
 1295 
 1296 
 1297 /*********************************************************************
 1298 * Adds the personalities for an extensions dictionary to the global
 1299 * IOCatalogue.
 1300 *********************************************************************/
 1301 bool addPersonalities(OSDictionary * extensions) {
 1302     bool result = true;
 1303     OSCollectionIterator * keyIterator = NULL;  // must release
 1304     OSString             * key;          // don't release
 1305     OSDictionary * driverDict = NULL;    // don't release
 1306     OSDictionary * driverPlist = NULL;   // don't release
 1307     OSDictionary * thisDriverPersonalities = NULL;  // don't release
 1308     OSArray      * allDriverPersonalities = NULL;   // must release
 1309 
 1310     allDriverPersonalities = OSArray::withCapacity(1);
 1311     if (!allDriverPersonalities) {
 1312         IOLog("Error: Couldn't allocate personality dictionary.\n");
 1313         LOG_DELAY();
 1314         result = false;
 1315         goto finish;
 1316     }
 1317 
 1318    /* Record all personalities found so that they can be
 1319     * added to the catalogue.
 1320     * Note: Not all extensions have personalities.
 1321     */
 1322 
 1323     keyIterator = OSCollectionIterator::withCollection(extensions);
 1324     if (!keyIterator) {
 1325         IOLog("Error: Couldn't allocate iterator to record personalities.\n");
 1326         LOG_DELAY();
 1327         result = false;
 1328         goto finish;
 1329     }
 1330 
 1331     while ( ( key = OSDynamicCast(OSString,
 1332               keyIterator->getNextObject() ))) {
 1333 
 1334         driverDict = OSDynamicCast(OSDictionary,
 1335             extensions->getObject(key));
 1336         driverPlist = OSDynamicCast(OSDictionary,
 1337             driverDict->getObject("plist"));
 1338         thisDriverPersonalities = OSDynamicCast(OSDictionary,
 1339             driverPlist->getObject("IOKitPersonalities"));
 1340 
 1341         if (thisDriverPersonalities) {
 1342             OSCollectionIterator * pIterator;
 1343             OSString * locakKey;
 1344             pIterator = OSCollectionIterator::withCollection(
 1345                 thisDriverPersonalities);
 1346             if (!pIterator) {
 1347                 IOLog("Error: Couldn't allocate iterator "
 1348                     "to record extension personalities.\n");
 1349                 LOG_DELAY();
 1350                 continue;
 1351             }
 1352             while ( (locakKey = OSDynamicCast(OSString,
 1353                      pIterator->getNextObject())) ) {
 1354 
 1355                 OSDictionary * personality = OSDynamicCast(
 1356                     OSDictionary,
 1357                     thisDriverPersonalities->getObject(locakKey));
 1358                 if (personality) {
 1359                     allDriverPersonalities->setObject(personality);
 1360                 }
 1361             }
 1362             pIterator->release();
 1363         }
 1364     } /* extract personalities */
 1365 
 1366 
 1367    /* Add all personalities found to the IOCatalogue,
 1368     * but don't start matching.
 1369     */
 1370     gIOCatalogue->addDrivers(allDriverPersonalities, false);
 1371 
 1372 finish:
 1373 
 1374     if (allDriverPersonalities) allDriverPersonalities->release();
 1375     if (keyIterator) keyIterator->release();
 1376 
 1377     return result;
 1378 }
 1379 
 1380 
 1381 /*********************************************************************
 1382 * Called from IOCatalogue to add extensions from an mkext archive.
 1383 * This function makes a copy of the mkext object passed in because
 1384 * the device tree support code dumps it after calling us (indirectly
 1385 * through the IOCatalogue).
 1386 *********************************************************************/
 1387 bool addExtensionsFromArchive(OSData * mkextDataObject) {
 1388     bool result = true;
 1389 
 1390     OSDictionary * startupExtensions = NULL;  // don't release
 1391     OSArray      * bootLoaderObjects = NULL;  // don't release
 1392     OSDictionary * extensions = NULL;         // must release
 1393     MemoryMapFileInfo mkext_file_info;
 1394     OSCollectionIterator * keyIterator = NULL;   // must release
 1395     OSString             * key = NULL;           // don't release
 1396 
 1397     startupExtensions = getStartupExtensions();
 1398     if (!startupExtensions) {
 1399         IOLog("Can't record extension archive; there is no"
 1400             " extensions dictionary.\n");
 1401         LOG_DELAY();
 1402         result = false;
 1403         goto finish;
 1404     }
 1405 
 1406     bootLoaderObjects = getBootLoaderObjects();
 1407     if (! bootLoaderObjects) {
 1408         IOLog("Error: Couldn't allocate array to hold temporary objects.\n");
 1409         LOG_DELAY();
 1410         result = false;
 1411         goto finish;
 1412     }
 1413 
 1414     extensions = OSDictionary::withCapacity(2);
 1415     if (!extensions) {
 1416         IOLog("Error: Couldn't allocate dictionary to unpack "
 1417             "extension archive.\n");
 1418         LOG_DELAY();
 1419         result = false;
 1420         goto finish;
 1421     }
 1422 
 1423     mkext_file_info.paddr = (UInt32)mkextDataObject->getBytesNoCopy();
 1424     mkext_file_info.length = mkextDataObject->getLength();
 1425 
 1426    /* Save the local mkext data object so that we can deallocate it later.
 1427     */
 1428     bootLoaderObjects->setObject(mkextDataObject);
 1429 
 1430     result = extractExtensionsFromArchive(&mkext_file_info, true /*virtual*/, extensions);
 1431     if (!result) {
 1432         IOLog("Error: Failed to extract extensions from archive.\n");
 1433         LOG_DELAY();
 1434         result = false;
 1435         goto finish;
 1436     }
 1437 
 1438     result = mergeExtensionDictionaries(startupExtensions, extensions);
 1439     if (!result) {
 1440         IOLog("Error: Failed to merge new extensions into existing set.\n");
 1441         LOG_DELAY();
 1442         goto finish;
 1443     }
 1444 
 1445     result = addPersonalities(extensions);
 1446     if (!result) {
 1447         IOLog("Error: Failed to add personalities for extensions extracted "
 1448             "from archive.\n");
 1449         LOG_DELAY();
 1450         result = false;
 1451         goto finish;
 1452     }
 1453 
 1454 finish:
 1455 
 1456     if (!result) {
 1457         IOLog("Error: Failed to record extensions from archive.\n");
 1458         LOG_DELAY();
 1459     } else {
 1460         keyIterator = OSCollectionIterator::withCollection(
 1461             extensions);
 1462 
 1463         if (keyIterator) {
 1464             while ( (key = OSDynamicCast(OSString,
 1465                      keyIterator->getNextObject())) ) {
 1466 
 1467                 IOLog("Added extension \"%s\" from archive.\n",
 1468                     key->getCStringNoCopy());
 1469                 LOG_DELAY();
 1470             }
 1471             keyIterator->release();
 1472         }
 1473     }
 1474 
 1475     if (extensions) extensions->release();
 1476 
 1477     return result;
 1478 }
 1479 
 1480 
 1481 /*********************************************************************
 1482 * This function builds dictionaries for the startup extensions
 1483 * put into memory by bootx, recording each in the startup extensions
 1484 * dictionary. The dictionary format is this:
 1485 *
 1486 * {
 1487 *     "plist" = (the extension's Info.plist as an OSDictionary)
 1488 *     "code"  = (an OSData containing the executable file)
 1489 * }
 1490 *
 1491 * This function returns true if any extensions were found and
 1492 * recorded successfully, or if there are no start extensions,
 1493 * and false if an unrecoverable error occurred. An error reading
 1494 * a single extension is not considered fatal, and this function
 1495 * will simply skip the problematic extension to try the next one.
 1496 *********************************************************************/
 1497 
 1498 bool recordStartupExtensions(void) {
 1499     bool result = true;
 1500     OSDictionary         * startupExtensions = NULL; // must release
 1501     OSDictionary         * existingExtensions = NULL; // don't release
 1502     OSDictionary         * mkextExtensions = NULL;   // must release
 1503     IORegistryEntry      * bootxMemoryMap = NULL;    // must release
 1504     OSDictionary         * propertyDict = NULL;      // must release
 1505     OSCollectionIterator * keyIterator = NULL;       // must release
 1506     OSString             * key = NULL;               // don't release
 1507 
 1508     OSDictionary * newDriverDict = NULL;  // must release
 1509     OSDictionary * driverPlist = NULL; // don't release
 1510 
 1511     struct section * infosect;
 1512     struct section * symsect;
 1513     unsigned int     prelinkedCount = 0;
 1514 
 1515     existingExtensions = getStartupExtensions();
 1516     if (!existingExtensions) {
 1517         IOLog("Error: There is no dictionary for startup extensions.\n");
 1518         LOG_DELAY();
 1519         result = false;
 1520         goto finish;
 1521     }
 1522 
 1523     startupExtensions = OSDictionary::withCapacity(1);
 1524     if (!startupExtensions) {
 1525         IOLog("Error: Couldn't allocate dictionary "
 1526             "to record startup extensions.\n");
 1527         LOG_DELAY();
 1528         result = false;
 1529         goto finish;
 1530     }
 1531 
 1532     // --
 1533     // add any prelinked modules as startup extensions
 1534 
 1535     infosect   = getsectbyname("__PRELINK", "__info");
 1536     symsect    = getsectbyname("__PRELINK", "__symtab");
 1537     if (infosect && infosect->addr && infosect->size 
 1538      && symsect && symsect->addr && symsect->size) do
 1539     {
 1540         gIOPrelinkedModules = OSDynamicCast(OSArray,
 1541             OSUnserializeXML((const char *) infosect->addr, NULL));
 1542 
 1543         if (!gIOPrelinkedModules)
 1544             break;
 1545         for( unsigned int idx = 0; 
 1546                 (propertyDict = OSDynamicCast(OSDictionary, gIOPrelinkedModules->getObject(idx)));
 1547                 idx++)
 1548         {
 1549             enum { kPrelinkReservedCount = 4 };
 1550 
 1551            /* Get the extension's module name. This is used to record
 1552             * the extension. Do *not* release the moduleName.
 1553             */
 1554             OSString * moduleName = OSDynamicCast(OSString,
 1555                 propertyDict->getObject("CFBundleIdentifier"));
 1556             if (!moduleName) {
 1557                 IOLog("Error: Prelinked module entry has "
 1558                     "no \"CFBundleIdentifier\" property.\n");
 1559                 LOG_DELAY();
 1560                 continue;
 1561             }
 1562 
 1563            /* Add the kext, & its plist.
 1564             */
 1565             newDriverDict = OSDictionary::withCapacity(4);
 1566             assert(newDriverDict);
 1567             newDriverDict->setObject("plist", propertyDict);
 1568             startupExtensions->setObject(moduleName, newDriverDict);
 1569             newDriverDict->release();
 1570 
 1571            /* Add the code if present.
 1572             */
 1573             OSData * data = OSDynamicCast(OSData, propertyDict->getObject("OSBundlePrelink"));
 1574             if (data) {
 1575                 if (data->getLength() < (kPrelinkReservedCount * sizeof(UInt32))) {
 1576                     IOLog("Error: Prelinked module entry has "
 1577                         "invalid \"OSBundlePrelink\" property.\n");
 1578                     LOG_DELAY();
 1579                     continue;
 1580                 }
 1581                 const UInt32 * prelink;
 1582                 prelink = (const UInt32 *) data->getBytesNoCopy();
 1583                 kmod_info_t * kmod_info = (kmod_info_t *) OSReadBigInt32(prelink, 0);
 1584                 // end of "file" is end of symbol sect
 1585                 data = OSData::withBytesNoCopy((void *) kmod_info->address,
 1586                             symsect->addr + symsect->size - kmod_info->address);
 1587                 newDriverDict->setObject("code", data);
 1588                 data->release();
 1589                 prelinkedCount++;
 1590                 continue;
 1591             }
 1592            /* Add the symbols if present.
 1593             */
 1594             OSNumber * num = OSDynamicCast(OSNumber, propertyDict->getObject("OSBundlePrelinkSymbols"));
 1595             if (num) {
 1596                 UInt32 offset = num->unsigned32BitValue();
 1597                 data = OSData::withBytesNoCopy((void *) (symsect->addr + offset), symsect->size - offset);
 1598                 newDriverDict->setObject("code", data);
 1599                 data->release();
 1600                 prelinkedCount++;
 1601                 continue;
 1602             }
 1603         } 
 1604         if (gIOPrelinkedModules)
 1605             IOLog("%d prelinked modules\n", prelinkedCount);
 1606 
 1607         // free __info
 1608         vm_offset_t
 1609         virt = ml_static_ptovirt(infosect->addr);
 1610         if( virt) {
 1611             ml_static_mfree(virt, infosect->size);
 1612         }
 1613         newDriverDict = NULL;
 1614     }
 1615     while (false);
 1616     // --
 1617 
 1618     bootxMemoryMap =
 1619         IORegistryEntry::fromPath(
 1620             "/chosen/memory-map", // path
 1621             gIODTPlane            // plane
 1622             );
 1623     // return value is retained so be sure to release it
 1624 
 1625     if (!bootxMemoryMap) {
 1626         IOLog("Error: Couldn't read booter memory map.\n");
 1627         LOG_DELAY();
 1628         result = false;
 1629         goto finish;
 1630     }
 1631 
 1632     propertyDict = bootxMemoryMap->dictionaryWithProperties();
 1633     if (!propertyDict) {
 1634         IOLog("Error: Couldn't get property dictionary "
 1635             "from memory map.\n");
 1636         LOG_DELAY();
 1637         result = false;
 1638         goto finish;
 1639     }
 1640 
 1641     keyIterator = OSCollectionIterator::withCollection(propertyDict);
 1642     if (!keyIterator) {
 1643         IOLog("Error: Couldn't allocate iterator for driver images.\n");
 1644         LOG_DELAY();
 1645         result = false;
 1646         goto finish;
 1647     }
 1648 
 1649     while ( (key = OSDynamicCast(OSString,
 1650              keyIterator->getNextObject())) ) {
 1651        /* Clear newDriverDict & mkextExtensions upon entry to the loop,
 1652         * handling both successful and unsuccessful iterations.
 1653         */
 1654         if (newDriverDict) {
 1655             newDriverDict->release();
 1656             newDriverDict = NULL;
 1657         }
 1658         if (mkextExtensions) {
 1659             mkextExtensions->release();
 1660             mkextExtensions = NULL;
 1661         }
 1662 
 1663         const char * keyValue = key->getCStringNoCopy();
 1664 
 1665         if ( !strncmp(keyValue, BOOTX_KEXT_PREFIX,
 1666               strlen(BOOTX_KEXT_PREFIX)) ) {
 1667 
 1668            /* Read the extension from the bootx-supplied memory.
 1669             */
 1670             newDriverDict = readExtension(propertyDict, keyValue);
 1671             if (!newDriverDict) {
 1672                 IOLog("Error: Couldn't read data "
 1673                     "for device tree entry \"%s\".\n", keyValue);
 1674                 LOG_DELAY();
 1675                 continue;
 1676             }
 1677 
 1678 
 1679            /* Preprare to record the extension by getting its info plist.
 1680             */
 1681             driverPlist = OSDynamicCast(OSDictionary,
 1682                 newDriverDict->getObject("plist"));
 1683             if (!driverPlist) {
 1684                 IOLog("Error: Extension in device tree entry \"%s\" "
 1685                     "has no property list.\n", keyValue);
 1686                 LOG_DELAY();
 1687                 continue;
 1688             }
 1689 
 1690 
 1691            /* Get the extension's module name. This is used to record
 1692             * the extension. Do *not* release the moduleName.
 1693             */
 1694             OSString * moduleName = OSDynamicCast(OSString,
 1695                 driverPlist->getObject("CFBundleIdentifier"));
 1696             if (!moduleName) {
 1697                 IOLog("Error: Device tree entry \"%s\" has "
 1698                     "no \"CFBundleIdentifier\" property.\n", keyValue);
 1699                 LOG_DELAY();
 1700                 continue;
 1701             }
 1702 
 1703 
 1704            /* All has gone well so far, so record the extension under
 1705             * its module name, checking for an existing duplicate.
 1706             *
 1707             * Do not release moduleName, as it's part of the extension's
 1708             * plist.
 1709             */
 1710             OSDictionary * incumbentExt = OSDynamicCast(OSDictionary,
 1711                 startupExtensions->getObject(moduleName));
 1712 
 1713             if (!incumbentExt) {
 1714                 startupExtensions->setObject(moduleName, newDriverDict);
 1715             } else {
 1716                 OSDictionary * mostRecentExtension =
 1717                     compareExtensionVersions(incumbentExt, newDriverDict);
 1718 
 1719                 if (mostRecentExtension == incumbentExt) {
 1720                     /* Do nothing, we've got the most recent. */
 1721                 } else if (mostRecentExtension == newDriverDict) {
 1722                     if (!startupExtensions->setObject(moduleName,
 1723                          newDriverDict)) {
 1724 
 1725                        /* This is a fatal error, so bail.
 1726                         */
 1727                         IOLog("recordStartupExtensions(): Failed to add "
 1728                             "identifier %s\n",
 1729                             moduleName->getCStringNoCopy());
 1730                         LOG_DELAY();
 1731                         result = false;
 1732                         goto finish;
 1733                     }
 1734                 } else /* should be NULL */ {
 1735 
 1736                    /* This is a nonfatal error, so continue.
 1737                     */
 1738                     IOLog("recordStartupExtensions(): Error comparing "
 1739                         "versions of duplicate extensions %s.\n",
 1740                         moduleName->getCStringNoCopy());
 1741                     LOG_DELAY();
 1742                     continue;
 1743                 }
 1744             }
 1745 
 1746 
 1747         } else if ( !strncmp(keyValue, BOOTX_MULTIKEXT_PREFIX,
 1748               strlen(BOOTX_MULTIKEXT_PREFIX)) ) {
 1749 
 1750             mkextExtensions = OSDictionary::withCapacity(10);
 1751             if (!mkextExtensions) {
 1752                 IOLog("Error: Couldn't allocate dictionary to unpack "
 1753                     "multi-extension archive.\n");
 1754                 LOG_DELAY();
 1755                 result = false;
 1756                 goto finish;  // allocation failure is fatal for this routine
 1757             }
 1758             if (!readExtensions(propertyDict, keyValue, mkextExtensions)) {
 1759                 IOLog("Error: Couldn't unpack multi-extension archive.\n");
 1760                 LOG_DELAY();
 1761                 continue;
 1762             } else {
 1763                 if (!mergeExtensionDictionaries(startupExtensions,
 1764                      mkextExtensions)) {
 1765 
 1766                     IOLog("Error: Failed to merge new extensions into "
 1767                         "existing set.\n");
 1768                     LOG_DELAY();
 1769                     result = false;
 1770                     goto finish;  // merge error is fatal for this routine
 1771                 }
 1772             }
 1773         }
 1774 
 1775         // Do not release key.
 1776 
 1777     } /* while ( (key = OSDynamicCast(OSString, ...) ) ) */
 1778 
 1779     if (!mergeExtensionDictionaries(existingExtensions, startupExtensions)) {
 1780         IOLog("Error: Failed to merge new extensions into existing set.\n");
 1781         LOG_DELAY();
 1782         result = false;
 1783         goto finish;
 1784     } 
 1785 
 1786     result = addPersonalities(startupExtensions);
 1787     if (!result) {
 1788         IOLog("Error: Failed to add personalities for extensions extracted "
 1789             "from archive.\n");
 1790         LOG_DELAY();
 1791         result = false;
 1792         goto finish;
 1793     }
 1794 
 1795 finish:
 1796 
 1797     // reused so clear first!
 1798     if (keyIterator) {
 1799         keyIterator->release();
 1800         keyIterator = 0;
 1801     }
 1802 
 1803     if (!result) {
 1804         IOLog("Error: Failed to record startup extensions.\n");
 1805         LOG_DELAY();
 1806     } else {
 1807 #if DEBUG
 1808         keyIterator = OSCollectionIterator::withCollection(
 1809             startupExtensions);
 1810 
 1811         if (keyIterator) {
 1812             while ( (key = OSDynamicCast(OSString,
 1813                      keyIterator->getNextObject())) ) {
 1814 
 1815                 IOLog("Found extension \"%s\".\n",
 1816                     key->getCStringNoCopy());
 1817                 LOG_DELAY();
 1818             }
 1819             keyIterator->release();
 1820             keyIterator = 0;
 1821         }
 1822 #endif /* DEBUG */
 1823     }
 1824 
 1825     if (newDriverDict)     newDriverDict->release();
 1826     if (propertyDict)      propertyDict->release();
 1827     if (bootxMemoryMap)    bootxMemoryMap->release();
 1828     if (mkextExtensions)   mkextExtensions->release();
 1829     if (startupExtensions) startupExtensions->release();
 1830 
 1831     return result;
 1832 }
 1833 
 1834 
 1835 /*********************************************************************
 1836 * This function removes an entry from the dictionary of startup
 1837 * extensions. It's used when an extension can't be loaded, for
 1838 * whatever reason. For drivers, this allows another matching driver
 1839 * to be loaded, so that, for example, a driver for the root device
 1840 * can be found.
 1841 *********************************************************************/
 1842 void removeStartupExtension(const char * extensionName) {
 1843     OSDictionary * startupExtensions = NULL;      // don't release
 1844     OSDictionary * extensionDict = NULL;          // don't release
 1845     OSDictionary * extensionPlist = NULL;         // don't release
 1846     OSDictionary * extensionPersonalities = NULL; // don't release
 1847     OSDictionary * personality = NULL;            // don't release
 1848     OSCollectionIterator * keyIterator = NULL;    // must release
 1849     OSString     * key = NULL;                    // don't release
 1850 
 1851     startupExtensions = getStartupExtensions();
 1852     if (!startupExtensions) goto finish;
 1853 
 1854 
 1855    /* Find the extension's entry in the dictionary of
 1856     * startup extensions.
 1857     */
 1858     extensionDict = OSDynamicCast(OSDictionary,
 1859         startupExtensions->getObject(extensionName));
 1860     if (!extensionDict) goto finish;
 1861 
 1862     extensionPlist = OSDynamicCast(OSDictionary,
 1863         extensionDict->getObject("plist"));
 1864     if (!extensionPlist) goto finish;
 1865 
 1866     extensionPersonalities = OSDynamicCast(OSDictionary,
 1867         extensionPlist->getObject("IOKitPersonalities"));
 1868     if (!extensionPersonalities) goto finish;
 1869 
 1870    /* If it was there, remove it from the catalogue proper
 1871     * by calling removeDrivers(). Pass true for the second
 1872     * argument to trigger a new round of matching, and
 1873     * then remove the extension from the dictionary of startup
 1874     * extensions.
 1875     */
 1876     keyIterator = OSCollectionIterator::withCollection(
 1877         extensionPersonalities);
 1878     if (!keyIterator) {
 1879         IOLog("Error: Couldn't allocate iterator to scan"
 1880             " personalities for %s.\n", extensionName);
 1881         LOG_DELAY();
 1882     }
 1883 
 1884     while ((key = OSDynamicCast(OSString, keyIterator->getNextObject()))) {
 1885         personality = OSDynamicCast(OSDictionary,
 1886             extensionPersonalities->getObject(key));
 1887 
 1888 
 1889         if (personality) {
 1890             gIOCatalogue->removeDrivers(personality, true);
 1891         }
 1892     }
 1893 
 1894     startupExtensions->removeObject(extensionName);
 1895 
 1896 finish:
 1897 
 1898     if (keyIterator) keyIterator->release();
 1899     return;
 1900 }
 1901 
 1902 /*********************************************************************
 1903 * FIXME: This function invalidates the globals gStartupExtensions and
 1904 * FIXME: ...gBootLoaderObjects without setting them to NULL. Since
 1905 * FIXME: ...the code itself is immediately unloaded, there may not be
 1906 * FIXME: ...any reason to worry about that!
 1907 *********************************************************************/
 1908 void clearStartupExtensionsAndLoaderInfo(void)
 1909 {
 1910     OSDictionary * startupExtensions = NULL;  // must release
 1911     OSArray      * bootLoaderObjects = NULL;  // must release
 1912 
 1913     IORegistryEntry      * bootxMemoryMap = NULL;    // must release
 1914     OSDictionary         * propertyDict = NULL;      // must release
 1915     OSCollectionIterator * keyIterator = NULL;       // must release
 1916     OSString             * key = NULL;               // don't release
 1917 
 1918    /*****
 1919     * Drop any temporarily held data objects.
 1920     */
 1921     bootLoaderObjects = getBootLoaderObjects();
 1922     if (bootLoaderObjects) {
 1923         bootLoaderObjects->release();
 1924     }
 1925 
 1926    /****
 1927     * If any "code" entries in driver dictionaries are accompanied
 1928     * by "compressedCode" entries, then those data objects were
 1929     * created based of of kmem_alloc()'ed memory, which must be
 1930     * freed specially.
 1931     */
 1932     startupExtensions = getStartupExtensions();
 1933     if (startupExtensions) {
 1934         keyIterator =
 1935             OSCollectionIterator::withCollection(startupExtensions);
 1936         if (!keyIterator) {
 1937             IOLog("Error: Couldn't allocate iterator for startup "
 1938                 "extensions.\n");
 1939             LOG_DELAY();
 1940             goto memory_map;  // bail to the memory_map label
 1941         }
 1942 
 1943         while ( (key = OSDynamicCast(OSString,
 1944                  keyIterator->getNextObject())) ) {
 1945 
 1946             OSDictionary * driverDict = 0;
 1947             OSData * codeData = 0;
 1948 
 1949             driverDict = OSDynamicCast(OSDictionary,
 1950                 startupExtensions->getObject(key));
 1951             if (driverDict) {
 1952                 codeData = OSDynamicCast(OSData,
 1953                     driverDict->getObject("code"));
 1954 
 1955                 if (codeData &&
 1956                     driverDict->getObject("compressedCode")) {
 1957 
 1958                     kmem_free(kernel_map,
 1959                        (unsigned int)codeData->getBytesNoCopy(),
 1960                         codeData->getLength());
 1961                 }
 1962             }
 1963         }
 1964 
 1965         keyIterator->release();
 1966         startupExtensions->release();
 1967     }
 1968 
 1969 memory_map:
 1970 
 1971    /****
 1972     * Go through the device tree's memory map and remove any driver
 1973     * data entries.
 1974     */
 1975     bootxMemoryMap =
 1976         IORegistryEntry::fromPath(
 1977             "/chosen/memory-map", // path
 1978             gIODTPlane            // plane
 1979             );
 1980     // return value is retained so be sure to release it
 1981 
 1982     if (!bootxMemoryMap) {
 1983         IOLog("Error: Couldn't read booter memory map.\n");
 1984         LOG_DELAY();
 1985         goto finish;
 1986     }
 1987 
 1988     propertyDict = bootxMemoryMap->dictionaryWithProperties();
 1989     if (!propertyDict) {
 1990         IOLog("Error: Couldn't get property dictionary "
 1991             "from memory map.\n");
 1992         LOG_DELAY();
 1993         goto finish;
 1994     }
 1995 
 1996     keyIterator = OSCollectionIterator::withCollection(propertyDict);
 1997     if (!keyIterator) {
 1998         IOLog("Error: Couldn't allocate iterator for driver images.\n");
 1999         LOG_DELAY();
 2000         goto finish;
 2001     }
 2002 
 2003     while ( (key = OSDynamicCast(OSString,
 2004              keyIterator->getNextObject())) ) {
 2005 
 2006         const char * keyValue = key->getCStringNoCopy();
 2007 
 2008         if ( !strncmp(keyValue, BOOTX_KEXT_PREFIX,
 2009                   strlen(BOOTX_KEXT_PREFIX)) ||
 2010              !strncmp(keyValue, BOOTX_MULTIKEXT_PREFIX,
 2011                   strlen(BOOTX_MULTIKEXT_PREFIX)) ) {
 2012 
 2013             OSData            * bootxDriverDataObject = NULL;
 2014             const MemoryMapFileInfo * driverInfo = 0;
 2015 
 2016             bootxDriverDataObject = OSDynamicCast(OSData,
 2017                 propertyDict->getObject(keyValue));
 2018             // don't release bootxDriverDataObject
 2019 
 2020             if (!bootxDriverDataObject) {
 2021                 continue;
 2022             }
 2023             driverInfo = (const MemoryMapFileInfo *)
 2024                 bootxDriverDataObject->getBytesNoCopy(0,
 2025                 sizeof(MemoryMapFileInfo));
 2026             IODTFreeLoaderInfo((char *)keyValue,
 2027                 (void *)driverInfo->paddr,
 2028                 (int)driverInfo->length);
 2029         }
 2030     }
 2031 
 2032 finish:
 2033     if (bootxMemoryMap) bootxMemoryMap->release();
 2034     if (propertyDict)   propertyDict->release();
 2035     if (keyIterator)    keyIterator->release();
 2036 
 2037     return;
 2038 }

Cache object: 2e45153857b356e3b36a1f9ac8ffd4b4


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.