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

Cache object: 8fb1d90b5a940a445ebfd063a2332f79


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