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

Cache object: 92c9b388f5cd5c3378c28f87c933764f


[ 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.