darwin-xnu/libsa/catalogue.cpp
<<
>>
Prefs
   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
  30extern "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
  43extern "C" {
  44extern 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);
  49extern 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.
  52extern 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.
  55extern 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*********************************************************************/
  70static OSDictionary * gStartupExtensions = 0;
  71static OSArray * gBootLoaderObjects = 0;
  72extern OSArray * gIOPrelinkedModules;
  73
  74OSDictionary * 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 */
  90OSArray * 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*********************************************************************/
 107bool 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
 369finish:
 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*********************************************************************/
 403OSDictionary * 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
 506finish:
 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*********************************************************************/
 521bool 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
 617finish:
 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
 643typedef struct MemoryMapFileInfo {
 644    UInt32 paddr;
 645    UInt32 length;
 646} MemoryMapFileInfo;
 647
 648typedef struct BootxDriverInfo {
 649    char *plistAddr;
 650    long  plistLength;
 651    void *moduleAddr;
 652    long  moduleLength;
 653} BootxDriverInfo;
 654
 655typedef 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*********************************************************************/
 667OSDictionary * 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
 801finish:
 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*********************************************************************/
 835static 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
 900finish:
 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
 914bool 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*********************************************************************/
 927bool 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
1203finish:
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*********************************************************************/
1224bool 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
1253finish:
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*********************************************************************/
1267bool 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
1338finish:
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*********************************************************************/
1353bool 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
1420finish:
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
1464bool 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
1761finish:
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*********************************************************************/
1808void 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
1862finish:
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*********************************************************************/
1874void 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
1935memory_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
1998finish:
1999    if (bootxMemoryMap) bootxMemoryMap->release();
2000    if (propertyDict)   propertyDict->release();
2001    if (keyIterator)    keyIterator->release();
2002
2003    return;
2004}
2005
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.