Пример #1
0
void
KLDBootstrap::readBooterExtensions(void)
{
    IORegistryEntry           * booterMemoryMap         = NULL;  // must release
    OSDictionary              * propertyDict            = NULL;  // must release
    OSCollectionIterator      * keyIterator             = NULL;  // must release
    OSString                  * deviceTreeName          = NULL;  // do not release
    
    const _DeviceTreeBuffer   * deviceTreeBuffer        = NULL;  // do not free
    char                      * booterDataPtr           = NULL;  // do not free
    OSData                    * booterData              = NULL;  // must release

    OSKext                    * aKext                   = NULL;  // must release

    OSKextLog(/* kext */ NULL,
        kOSKextLogProgressLevel |
        kOSKextLogDirectoryScanFlag | kOSKextLogKextBookkeepingFlag,
        "Reading startup extensions from booter memory.");
    
    booterMemoryMap = IORegistryEntry::fromPath( "/chosen/memory-map", gIODTPlane);

    if (!booterMemoryMap) {
        OSKextLog(/* kext */ NULL,
            kOSKextLogErrorLevel |
            kOSKextLogGeneralFlag | kOSKextLogDirectoryScanFlag,
            "Can't read booter memory map.");
        goto finish;
    }

    propertyDict = booterMemoryMap->dictionaryWithProperties();
    if (!propertyDict) {
        OSKextLog(/* kext */ NULL,
            kOSKextLogErrorLevel |
            kOSKextLogDirectoryScanFlag,
            "Can't get property dictionary from memory map.");
        goto finish;
    }

    keyIterator = OSCollectionIterator::withCollection(propertyDict);
    if (!keyIterator) {
        OSKextLog(/* kext */ NULL,
            kOSKextLogErrorLevel |
            kOSKextLogGeneralFlag,
            "Can't allocate iterator for driver images.");
        goto finish;
    }

    /* Create dictionary of excluded kexts
     */
    OSKext::createExcludeListFromBooterData(propertyDict, keyIterator);
    keyIterator->reset();

    while ( ( deviceTreeName =
        OSDynamicCast(OSString, keyIterator->getNextObject() ))) {

        const char * devTreeNameCString = deviceTreeName->getCStringNoCopy();
        OSData * deviceTreeEntry = OSDynamicCast(OSData,
            propertyDict->getObject(deviceTreeName));

       /* Clear out the booterData from the prior iteration.
        */
        OSSafeReleaseNULL(booterData);

        /* If there is no entry for the name, we can't do much with it. */
        if (!deviceTreeEntry) {
            continue;
        }

        /* Make sure it is a kext */
        if (strncmp(devTreeNameCString,
                    BOOTER_KEXT_PREFIX,
                    CONST_STRLEN(BOOTER_KEXT_PREFIX))) {
            continue;
        }

        deviceTreeBuffer = (const _DeviceTreeBuffer *)
            deviceTreeEntry->getBytesNoCopy(0, sizeof(deviceTreeBuffer));
        if (!deviceTreeBuffer) {
           /* We can't get to the data, so we can't do anything,
            * not even free it from physical memory (if it's there).
            */
            OSKextLog(/* kext */ NULL,
                kOSKextLogErrorLevel |
                kOSKextLogDirectoryScanFlag,
                "Device tree entry %s has NULL pointer.",
                devTreeNameCString);
            goto finish;  // xxx - continue, panic?
        }

        booterDataPtr = (char *)ml_static_ptovirt(deviceTreeBuffer->paddr);
        if (!booterDataPtr) {
            OSKextLog(/* kext */ NULL,
                kOSKextLogErrorLevel |
                kOSKextLogDirectoryScanFlag,
                "Can't get virtual address for device tree entry %s.",
                devTreeNameCString);
            goto finish;
        }

       /* Wrap the booter data buffer in an OSData and set a dealloc function
        * so it will take care of the physical memory when freed. Kexts will
        * retain the booterData for as long as they need it. Remove the entry
        * from the booter memory map after this is done.
        */
        booterData = OSData::withBytesNoCopy(booterDataPtr,
            deviceTreeBuffer->length);
        if (!booterData) {
            OSKextLog(/* kext */ NULL,
                kOSKextLogErrorLevel |
                kOSKextLogGeneralFlag,
                "Error - Can't allocate OSData wrapper for device tree entry %s.",
                devTreeNameCString);
            goto finish;
        }
        booterData->setDeallocFunction(osdata_phys_free);

        /* Create the kext for the entry, then release it, because the
         * kext system keeps them around until explicitly removed.
         * Any creation/registration failures are already logged for us.
         */
        OSKext * newKext = OSKext::withBooterData(deviceTreeName, booterData);
        OSSafeReleaseNULL(newKext);

        booterMemoryMap->removeProperty(deviceTreeName);

    } /* while ( (deviceTreeName = OSDynamicCast(OSString, ...) ) ) */

finish:

    OSSafeReleaseNULL(booterMemoryMap);
    OSSafeReleaseNULL(propertyDict);
    OSSafeReleaseNULL(keyIterator);
    OSSafeReleaseNULL(booterData);
    OSSafeReleaseNULL(aKext);
    return;
}