X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/0c530ab8987f0ae6a1a3d9284f40182b88852816..2d21ac55c334faf3a56e5634905ed6987fc787d4:/libsa/kmod.cpp diff --git a/libsa/kmod.cpp b/libsa/kmod.cpp deleted file mode 100644 index 2847e9f15..000000000 --- a/libsa/kmod.cpp +++ /dev/null @@ -1,1231 +0,0 @@ -/* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -#include -#include -#include -#include -#include -#include - -extern "C" { -#include -#include -#include -#include -#include -#include -#include -#include -}; - -#include "kld_patch.h" - - -extern "C" { -extern kern_return_t -kmod_create_internal( - kmod_info_t *info, - kmod_t *id); - -extern kern_return_t -kmod_destroy_internal(kmod_t id); - -extern kern_return_t -kmod_start_or_stop( - kmod_t id, - int start, - kmod_args_t *data, - mach_msg_type_number_t *dataCount); - -extern kern_return_t kmod_retain(kmod_t id); -extern kern_return_t kmod_release(kmod_t id); - -extern void flush_dcache64(addr64_t addr, unsigned cnt, int phys); -extern void invalidate_icache64(addr64_t addr, unsigned cnt, int phys); -}; - - -#define LOG_DELAY() - -#define VTYELLOW "\033[33m" -#define VTRESET "\033[0m" - - - - -/********************************************************************* -* -*********************************************************************/ -bool verifyCompatibility(OSString * extName, OSString * requiredVersion) -{ - OSDictionary * extensionsDict; // don't release - OSDictionary * extDict; // don't release - OSDictionary * extPlist; // don't release - OSString * extVersion; // don't release - OSString * extCompatVersion; // don't release - UInt32 ext_version; - UInt32 ext_compat_version; - UInt32 required_version; - - /* Get the dictionary of startup extensions. - * This is keyed by module name. - */ - extensionsDict = getStartupExtensions(); - if (!extensionsDict) { - IOLog("verifyCompatibility(): No extensions dictionary.\n"); - return false; - } - - /* Get the requested extension's dictionary entry and its property - * list, containing module dependencies. - */ - extDict = OSDynamicCast(OSDictionary, - extensionsDict->getObject(extName)); - - if (!extDict) { - IOLog("verifyCompatibility(): " - "Extension \"%s\" cannot be found.\n", - extName->getCStringNoCopy()); - return false; - } - - extPlist = OSDynamicCast(OSDictionary, extDict->getObject("plist")); - if (!extPlist) { - IOLog("verifyCompatibility(): " - "Extension \"%s\" has no property list.\n", - extName->getCStringNoCopy()); - return false; - } - - - extVersion = OSDynamicCast(OSString, - extPlist->getObject("CFBundleVersion")); - if (!extVersion) { - IOLog("verifyCompatibility(): " - "Extension \"%s\" has no \"CFBundleVersion\" property.\n", - extName->getCStringNoCopy()); - return false; - } - - extCompatVersion = OSDynamicCast(OSString, - extPlist->getObject("OSBundleCompatibleVersion")); - if (!extCompatVersion) { - IOLog("verifyCompatibility(): " - "Extension \"%s\" has no \"OSBundleCompatibleVersion\" property.\n", - extName->getCStringNoCopy()); - return false; - } - - if (!VERS_parse_string(requiredVersion->getCStringNoCopy(), - &required_version)) { - IOLog("verifyCompatibility(): " - "Can't parse required version \"%s\" of dependency %s.\n", - requiredVersion->getCStringNoCopy(), - extName->getCStringNoCopy()); - return false; - } - if (!VERS_parse_string(extVersion->getCStringNoCopy(), - &ext_version)) { - IOLog("verifyCompatibility(): " - "Can't parse version \"%s\" of dependency %s.\n", - extVersion->getCStringNoCopy(), - extName->getCStringNoCopy()); - return false; - } - if (!VERS_parse_string(extCompatVersion->getCStringNoCopy(), - &ext_compat_version)) { - IOLog("verifyCompatibility(): " - "Can't parse compatible version \"%s\" of dependency %s.\n", - extCompatVersion->getCStringNoCopy(), - extName->getCStringNoCopy()); - return false; - } - - if (required_version > ext_version || required_version < ext_compat_version) { - return false; - } - - return true; -} - -/********************************************************************* -*********************************************************************/ -static -Boolean kextIsADependency(OSString * name) { - Boolean result = true; - OSDictionary * extensionsDict = 0; // don't release - OSDictionary * extDict = 0; // don't release - OSDictionary * extPlist = 0; // don't release - OSBoolean * isKernelResourceObj = 0; // don't release - OSData * driverCode = 0; // don't release - OSData * compressedCode = 0; // don't release - - extensionsDict = getStartupExtensions(); - if (!extensionsDict) { - IOLog("kextIsADependency(): No extensions dictionary.\n"); - LOG_DELAY(); - result = false; - goto finish; - } - - - extDict = OSDynamicCast(OSDictionary, - extensionsDict->getObject(name)); - if (!extDict) { - IOLog("kextIsADependency(): " - "Extension \"%s\" cannot be found.\n", - name->getCStringNoCopy()); - LOG_DELAY(); - result = false; - goto finish; - } - - extPlist = OSDynamicCast(OSDictionary, extDict->getObject("plist")); - if (!extPlist) { - IOLog("getDependencyListForKmod(): " - "Extension \"%s\" has no property list.\n", - name->getCStringNoCopy()); - LOG_DELAY(); - result = false; - goto finish; - } - - /* A kext that is a kernel component is still a dependency, as there - * are fake kmod entries for them. - */ - isKernelResourceObj = OSDynamicCast(OSBoolean, - extPlist->getObject("OSKernelResource")); - if (isKernelResourceObj && isKernelResourceObj->isTrue()) { - result = true; - goto finish; - } - - driverCode = OSDynamicCast(OSData, extDict->getObject("code")); - compressedCode = OSDynamicCast(OSData, - extDict->getObject("compressedCode")); - - if (!driverCode && !compressedCode) { - result = false; - goto finish; - } - -finish: - - return result; -} - -/********************************************************************* -* This function builds a uniqued, in-order list of modules that need -* to be loaded in order for kmod_name to be successfully loaded. This -* list ends with kmod_name itself. -*********************************************************************/ -static -OSArray * getDependencyListForKmod(const char * kmod_name) { - - int error = 0; - - OSDictionary * extensionsDict; // don't release - OSDictionary * extDict; // don't release - OSDictionary * extPlist; // don't release - OSString * extName; // don't release - OSArray * dependencyList = NULL; // return value, caller releases - unsigned int i; - - /* These are used to remove duplicates from the dependency list. - */ - OSArray * originalList = NULL; // must be released - OSDictionary * encounteredNames = NULL; // must be release - - - /* Get the dictionary of startup extensions. - * This is keyed by module name. - */ - extensionsDict = getStartupExtensions(); - if (!extensionsDict) { - IOLog("getDependencyListForKmod(): No extensions dictionary.\n"); - LOG_DELAY(); - error = 1; - goto finish; - } - - - /* Get the requested extension's dictionary entry and its property - * list, containing module dependencies. - */ - extDict = OSDynamicCast(OSDictionary, - extensionsDict->getObject(kmod_name)); - - if (!extDict) { - IOLog("getDependencyListForKmod(): " - "Extension \"%s\" cannot be found.\n", - kmod_name); - LOG_DELAY(); - error = 1; - goto finish; - } - - extPlist = OSDynamicCast(OSDictionary, extDict->getObject("plist")); - if (!extPlist) { - IOLog("getDependencyListForKmod(): " - "Extension \"%s\" has no property list.\n", - kmod_name); - LOG_DELAY(); - error = 1; - goto finish; - } - - - /* Verify that the retrieved entry's "CFBundleIdentifier" property exists. - * This will be added to the dependency list. - */ - extName = OSDynamicCast(OSString, - extPlist->getObject("CFBundleIdentifier")); - if (!extName) { - IOLog("getDependencyListForKmod(): " - "Extension \"%s\" has no \"CFBundleIdentifier\" property.\n", - kmod_name); - LOG_DELAY(); - error = 1; - goto finish; - } - - dependencyList = OSArray::withCapacity(10); - if (!dependencyList) { - IOLog("getDependencyListForKmod(): " - "Couldn't allocate dependency array for extension \"%s\".\n", - kmod_name); - LOG_DELAY(); - error = 1; - goto finish; - } - - - /* Okay, let's get started. - */ - dependencyList->setObject(extName); - - - /* Here's a slightly tricky bit. This loop iterates through - * the dependency list until it runs off the end. Each time - * through, however, any number of dependencies can be added - * to the end of the list. Eventually some extensions won't - * have any more dependencies, no more names will be added - * to the list, and this loop will terminate. - */ - for (i = 0; i < dependencyList->getCount(); i++) { - - // None of these needs to be released, as they're all from plists. - OSString * curName; - OSDictionary * curExtDict; - OSDictionary * curExtDepDict; - OSDictionary * curExtPlist; - OSString * curDepName; - - - /* An arbitrary limit to prevent infinite loops. - */ - if (i > 255) { - IOLog("getDependencyListForKmod(): " - "max dependency list length exceeded for " - "extension \"%s\".\n", - kmod_name); - LOG_DELAY(); - error = 1; - goto finish; - } - - curName = OSDynamicCast(OSString, dependencyList->getObject(i)); - - curExtDict = OSDynamicCast(OSDictionary, - extensionsDict->getObject(curName)); - if (!curExtDict) { - IOLog("getDependencyListForKmod(): " - "Extension \"%s\", required for extension \"%s\", " - "is not available.\n", - curName->getCStringNoCopy(), kmod_name); - LOG_DELAY(); - error = 1; - goto finish; - } - - curExtPlist = OSDynamicCast(OSDictionary, - curExtDict->getObject("plist")); - if (!curExtPlist) { - IOLog("getDependencyListForKmod(): " - "Extension \"%s\", required for extension \"%s\", " - "has no property list.\n", - curName->getCStringNoCopy(), kmod_name); - LOG_DELAY(); - error = 1; - goto finish; - } - - curExtDepDict = OSDynamicCast(OSDictionary, - curExtPlist->getObject("OSBundleLibraries")); - if (curExtDepDict) { - OSCollectionIterator * keyIterator = - OSCollectionIterator::withCollection(curExtDepDict); - - if (!keyIterator) { - IOLog("getDependencyListForKmod(): " - "Couldn't allocate iterator for extension " - "\"%s\".\n", kmod_name); - LOG_DELAY(); - error = 1; - goto finish; - } - while ( (curDepName = - OSDynamicCast(OSString, - keyIterator->getNextObject())) ) { - - OSString * requiredVersion = OSDynamicCast(OSString, - curExtDepDict->getObject(curDepName)); - - if (!verifyCompatibility(curDepName, requiredVersion)) { - IOLog("getDependencyListForKmod(): " - "Dependency %s of %s is not compatible or is unavailable.\n", - curDepName->getCStringNoCopy(), - curName->getCStringNoCopy()); - LOG_DELAY(); - error = 1; - goto finish; - } - - dependencyList->setObject(curDepName); - } - - keyIterator->release(); - } - } - - - /***** - * The dependency list now exists in the reverse order of required loads, - * and may have duplicates. Now we turn the list around and remove - * duplicates. - */ - originalList = dependencyList; - dependencyList = OSArray::withCapacity(originalList->getCount()); - if (!dependencyList) { - IOLog("getDependenciesForKmod(): " - "Couldn't allocate reversal dependency list for extension " - "\"%s\".\n", kmod_name); - LOG_DELAY(); - error = 1; - goto finish; - } - encounteredNames = OSDictionary::withCapacity(originalList->getCount()); - if (!encounteredNames) { - IOLog("getDependenciesForKmod(): " - "Couldn't allocate list of encountered names for extension " - "\"%s\".\n", kmod_name); - LOG_DELAY(); - error = 1; - goto finish; - } - - - /* Go backward through the original list, using the encounteredNames - * dictionary to check for duplicates. We put originalList in as the - * value because we need some non-NULL value. Here we also drop any - * extensions that aren't proper dependencies (that is, any that are - * nonkernel kexts without code). - */ - i = originalList->getCount(); - - if (i > 0) { - do { - i--; - - OSString * item = OSDynamicCast(OSString, - originalList->getObject(i)); - - if ( (!encounteredNames->getObject(item)) && - kextIsADependency(item)) { - - encounteredNames->setObject(item, originalList); - dependencyList->setObject(item); - } - } while (i > 0); - } - - -finish: - - if (originalList) { - originalList->release(); - } - if (encounteredNames) { - encounteredNames->release(); - } - if (error) { - if (dependencyList) { - dependencyList->release(); - dependencyList = NULL; - } - } - - return dependencyList; -} - - -/********************************************************************* -*********************************************************************/ -/* Used in address_for_loaded_kmod. - */ -static kmod_info_t * g_current_kmod_info = NULL; -static const char * g_current_kmod_name = NULL; - -/* Globals to pass link buffer info from - * address_for_loaded_kmod() and alloc_for_kmod() - * to load_kmod(). - * - * link_load_address is the address used to lay - * down the linked code. It gets adjusted by the - * pad between the headers size and a full page - * multiple. If an error occurs this gets set to - * zero so that the kld client code can detect - * an address or allocation error even if kld - * returns success. - * - * link_load_size is the size of the image as - * created by kld_load_from_memory(). link_buffer_size - * is the size of the buffer allocated for the final - * laid-down image, and is adjusted by rounding the - * load size and header size up to full-page multiples. - * - * link_buffer_address is set only by alloc_for_kmod(); - * its value is used as a check if kld_load_from_memory() - * fails so that the buffer can be deallocated. - */ -static unsigned long link_load_address = 0; -static unsigned long link_load_size = 0; -static unsigned long link_buffer_size = 0; -static unsigned long link_header_size = 0; -static unsigned long link_buffer_address = 0; - - -/********************************************************************* -* This function is registered before kmod_load_from_memory() is -* invoked to build symbol table entries for an already-loaded -* kmod. This function just checks the g_current_kmod_info variable -* to gets its load address, and futzes it by the header offset (pad). -* See lower comments for more info on load address futzing. -*********************************************************************/ -static -unsigned long address_for_loaded_kmod( - unsigned long size, - unsigned long headers_size) { - - unsigned long round_headers_size; - unsigned long headers_pad; - - if (!g_current_kmod_info) { - IOLog("address_for_loaded_kmod(): No current kmod.\n"); - LOG_DELAY(); - link_load_address = 0; // error sentinel for kld client - return 0; - } - - round_headers_size = round_page_32(headers_size); - headers_pad = round_headers_size - headers_size; - - link_load_address = (unsigned long)g_current_kmod_info->address + - headers_pad; - - return link_load_address; -} - - -/********************************************************************* -* This function is registered before kmod_load_from_memory() is -* invoked to actually load a new kmod. It rounds up the header and -* total sizes and vm_allocates a buffer for the kmod. Now, KLD doesn't -* enforce any alignment of headers or segments, and we want to make -* sure that the executable code of the kmod lies on a page boundary. -* to do so, this function figures the pad between the actual header -* size and the page-rounded header size, and returns that offset into -* the allocated buffer. After kmod_load_from_memory() returns, its -* caller will move the mach_header struct back to the beginning of the -* allocated buffer so that the kmod_info_t structure contains the -* correct address. -*********************************************************************/ -static -unsigned long alloc_for_kmod( - unsigned long size, - unsigned long headers_size) { - - vm_address_t buffer = 0; - kern_return_t k_result; - - unsigned long round_headers_size; - unsigned long round_segments_size; - unsigned long round_size; - unsigned long headers_pad; - - round_headers_size = round_page_32(headers_size); - round_segments_size = round_page_32(size - headers_size); - round_size = round_headers_size + round_segments_size; - headers_pad = round_headers_size - headers_size; - - k_result = vm_allocate(kernel_map, (vm_offset_t *)&buffer, - round_size, VM_FLAGS_ANYWHERE); - if (k_result != KERN_SUCCESS) { - IOLog("alloc_for_kmod(): Can't allocate memory.\n"); - LOG_DELAY(); - link_buffer_address = 0; // make sure it's clear - link_load_address = 0; // error sentinel for kld client - return 0; - } - - link_load_size = size; - - link_buffer_address = buffer; - link_buffer_size = round_size; - link_header_size = headers_size; // NOT rounded! - - link_load_address = link_buffer_address + headers_pad; - - return link_load_address; -} - -/********************************************************************* -* This function reads the startup extensions dictionary to get the -* address and length of the executable data for the requested kmod. -*********************************************************************/ -static -int map_and_patch(const char * kmod_name) { - - char *address; - - // Does the kld system already know about this kmod? - address = (char *) kld_file_getaddr(kmod_name, NULL); - if (address) - return 1; - - // None of these needs to be released. - OSDictionary * extensionsDict; - OSDictionary * kmodDict; - OSData * compressedCode = 0; - - // Driver Code may need to be released - OSData * driverCode; - - /* Get the requested kmod's info dictionary from the global - * startup extensions dictionary. - */ - extensionsDict = getStartupExtensions(); - if (!extensionsDict) { - IOLog("map_and_patch(): No extensions dictionary.\n"); - LOG_DELAY(); - return 0; - } - - kmodDict = OSDynamicCast(OSDictionary, - extensionsDict->getObject(kmod_name)); - if (!kmodDict) { - IOLog("map_and_patch(): " - "Extension \"%s\" cannot be found.\n", kmod_name); - LOG_DELAY(); - return 0; - } - - Boolean ret = false; - - driverCode = OSDynamicCast(OSData, kmodDict->getObject("code")); - if (driverCode) { - ret = kld_file_map(kmod_name, - (unsigned char *) driverCode->getBytesNoCopy(), - (size_t) driverCode->getLength(), - /* isKmem */ false); - } - else { // May be an compressed extension - - // If we have a compressed segment the uncompressModule - // will return a new OSData object that points to the kmem_alloced - // memory. Note we don't take a reference to driverCode so later - // when we release it we will actually free this driver. Ownership - // of the kmem has been handed of to kld_file. - compressedCode = OSDynamicCast(OSData, - kmodDict->getObject("compressedCode")); - if (!compressedCode) { - IOLog("map_and_patch(): " - "Extension \"%s\" has no \"code\" property.\n", kmod_name); - LOG_DELAY(); - return 0; - } - if (!uncompressModule(compressedCode, &driverCode)) { - IOLog("map_and_patch(): " - "Extension \"%s\" Couldn't uncompress code.\n", kmod_name); - LOG_DELAY(); - return 0; - } - - unsigned char *driver = (unsigned char *) driverCode->getBytesNoCopy(); - size_t driverSize = driverCode->getLength(); - - ret = kld_file_map(kmod_name, driver, driverSize, /* isKmem */ true); - driverCode->release(); - if (!ret) - kmem_free(kernel_map, (vm_address_t) driver, driverSize); - } - - if (!ret) { - IOLog("map_and_patch(): " - "Extension \"%s\" Didn't successfully load.\n", kmod_name); - LOG_DELAY(); - return 0; - } - - ret = TRUE; - if (!kld_file_patch_OSObjects(kmod_name)) { - IOLog("map_and_patch(): " - "Extension \"%s\" Error binding OSObjects.\n", kmod_name); - LOG_DELAY(); - - // RY: Instead of returning here, set the return value. - // We still need to call kld_file_prepare_for_link because - // we might have patched files outside of the driver. Don't - // worry, it will know to ignore the damaged file - ret = FALSE; - } - - // Now repair any damage that the kld patcher may have done to the image - kld_file_prepare_for_link(); - - return ret; -} - -/********************************************************************* -*********************************************************************/ -bool stamp_kmod(const char * kmod_name, kmod_info_t * kmod_info) { - bool result = false; - OSDictionary * extensionsDict = NULL; // don't release - OSDictionary * kmodDict = NULL; // don't release - OSDictionary * plist = NULL; // don't release - OSString * versionString = NULL; // don't release - const char * plist_version = NULL; // don't free - - if (strlen(kmod_name) + 1 > KMOD_MAX_NAME) { - IOLog("stamp_kmod(): Kext identifier \"%s\" is too long.\n", - kmod_name); - LOG_DELAY(); - result = false; - goto finish; - } - - strcpy(kmod_info->name, kmod_name); - - /* Get the dictionary of startup extensions. - * This is keyed by module name. - */ - extensionsDict = getStartupExtensions(); - if (!extensionsDict) { - IOLog("stamp_kmod(): No extensions dictionary.\n"); - LOG_DELAY(); - result = false; - goto finish; - } - - kmodDict = OSDynamicCast(OSDictionary, - extensionsDict->getObject(kmod_name)); - if (!kmodDict) { - IOLog("stamp_kmod(): Can't find record for kmod \"%s\".\n", - kmod_name); - LOG_DELAY(); - result = false; - goto finish; - } - - plist = OSDynamicCast(OSDictionary, - kmodDict->getObject("plist")); - if (!kmodDict) { - IOLog("stamp_kmod(): Kmod \"%s\" has no property list.\n", - kmod_name); - LOG_DELAY(); - result = false; - goto finish; - } - - /***** - * Get the kext's version and stuff it into the kmod. This used - * to be a check that the kext & kmod had the same version, but - * now we just overwrite the kmod's version. - */ - - versionString = OSDynamicCast(OSString, - plist->getObject("CFBundleVersion")); - if (!versionString) { - IOLog("stamp_kmod(): Kmod \"%s\" has no \"CFBundleVersion\" " - "property.\n", - kmod_name); - LOG_DELAY(); - result = false; - goto finish; - } - - plist_version = versionString->getCStringNoCopy(); - if (!plist_version) { - IOLog("stamp_kmod(): Can't get C string for kext version.\n"); - LOG_DELAY(); - result = false; - goto finish; - } - - if (strlen(plist_version) + 1 > KMOD_MAX_NAME) { - IOLog("stamp_kmod(): Version \"%s\" of kext \"%s\" is too long.\n", - plist_version, kmod_name); - LOG_DELAY(); - result = false; - goto finish; - } - - strcpy(kmod_info->version, plist_version); - - result = true; - -finish: - - return result; -} - - -/********************************************************************* -* This function takes a dependency list containing a series of -* already-loaded module names, followed by a single name for a module -* that hasn't yet been loaded. It invokes kld_load_from_memory() to -* build symbol info for the already-loaded modules, and then finally -* loads the actually requested module. -*********************************************************************/ -static -kern_return_t load_kmod(OSArray * dependencyList) { - kern_return_t result = KERN_SUCCESS; - - unsigned int num_dependencies = 0; - kmod_info_t ** kmod_dependencies = NULL; - unsigned int i; - OSString * requestedKmodName; // don't release - const char * requested_kmod_name; - OSString * currentKmodName; // don't release - char * kmod_address; - unsigned long kmod_size; - struct mach_header * kmod_header; - unsigned long kld_result; - int do_kld_unload = 0; - kmod_info_t * kmod_info_freeme = 0; - kmod_info_t * kmod_info = 0; - kmod_t kmod_id; - - - /* Separate the requested kmod from its dependencies. - */ - i = dependencyList->getCount(); - if (i == 0) { - IOLog("load_kmod(): Called with empty list.\n"); - LOG_DELAY(); - result = KERN_FAILURE; - goto finish; - } else { - i--; // make i be the index of the last entry - } - - requestedKmodName = OSDynamicCast(OSString, dependencyList->getObject(i)); - if (!requestedKmodName) { - IOLog("load_kmod(): Called with invalid list of kmod names.\n"); - LOG_DELAY(); - result = KERN_FAILURE; - goto finish; - } - requested_kmod_name = requestedKmodName->getCStringNoCopy(); - dependencyList->removeObject(i); - - /* If the requested kmod is already loaded, there's no work to do. - */ - kmod_info_freeme = kmod_lookupbyname_locked(requested_kmod_name); - if (kmod_info_freeme) { - // FIXME: Need to check for version mismatch if already loaded. - result = KERN_SUCCESS; - goto finish; - } - - - /* Do the KLD loads for the already-loaded modules in order to get - * their symbols. - */ - kld_address_func(&address_for_loaded_kmod); - - num_dependencies = dependencyList->getCount(); - kmod_dependencies = (kmod_info_t **)kalloc(num_dependencies * - sizeof(kmod_info_t *)); - if (!kmod_dependencies) { - IOLog("load_kmod(): Failed to allocate memory for dependency array " - "during load of kmod \"%s\".\n", requested_kmod_name); - LOG_DELAY(); - result = KERN_FAILURE; - goto finish; - } - - bzero(kmod_dependencies, num_dependencies * - sizeof(kmod_info_t *)); - - for (i = 0; i < num_dependencies; i++) { - - currentKmodName = OSDynamicCast(OSString, - dependencyList->getObject(i)); - - if (!currentKmodName) { - IOLog("load_kmod(): Invalid dependency name at index %d for " - "kmod \"%s\".\n", i, requested_kmod_name); - LOG_DELAY(); - result = KERN_FAILURE; - goto finish; - } - - const char * current_kmod_name = currentKmodName->getCStringNoCopy(); - - // These globals are needed by the kld_address functions - g_current_kmod_info = kmod_lookupbyname_locked(current_kmod_name); - g_current_kmod_name = current_kmod_name; - - if (!g_current_kmod_info) { - IOLog("load_kmod(): Missing dependency \"%s\".\n", - current_kmod_name); - LOG_DELAY(); - result = KERN_FAILURE; - goto finish; - } - - /* Record the current kmod as a dependency of the requested - * one. This will be used in building references after the - * load is complete. - */ - kmod_dependencies[i] = g_current_kmod_info; - - /* If the current kmod's size is zero it means that we have a - * fake in-kernel dependency. If so then don't have to arrange - * for its symbol table to be reloaded as it is - * part of the kernel's symbol table.. - */ - if (!g_current_kmod_info->size) - continue; - - if (!kld_file_merge_OSObjects(current_kmod_name)) { - IOLog("load_kmod(): Can't merge OSObjects \"%s\".\n", - current_kmod_name); - LOG_DELAY(); - result = KERN_FAILURE; - goto finish; - } - - kmod_address = (char *) - kld_file_getaddr(current_kmod_name, (long *) &kmod_size); - if (!kmod_address) { - - IOLog("load_kmod() failed for dependency kmod " - "\"%s\".\n", current_kmod_name); - LOG_DELAY(); - result = KERN_FAILURE; - goto finish; - } - - kld_result = kld_load_from_memory(&kmod_header, - current_kmod_name, kmod_address, kmod_size); - - if (kld_result) { - do_kld_unload = 1; - } - - if (!kld_result || !link_load_address) { - IOLog("kld_load_from_memory() failed for dependency kmod " - "\"%s\".\n", current_kmod_name); - LOG_DELAY(); - result = KERN_FAILURE; - goto finish; - } - - kld_forget_symbol("_kmod_info"); - } - - /***** - * Now that we've done all the dependencies, which should have already - * been loaded, we do the last requested module, which should not have - * already been loaded. - */ - kld_address_func(&alloc_for_kmod); - - g_current_kmod_name = requested_kmod_name; - g_current_kmod_info = 0; // there is no kmod yet - - if (!map_and_patch(requested_kmod_name)) { - IOLog("load_kmod: map_and_patch() failed for " - "kmod \"%s\".\n", requested_kmod_name); - LOG_DELAY(); - result = KERN_FAILURE; - goto finish; - } - - kmod_address = (char *) - kld_file_getaddr(requested_kmod_name, (long *) &kmod_size); - if (!kmod_address) { - IOLog("load_kmod: kld_file_getaddr() failed internal error " - "on \"%s\".\n", requested_kmod_name); - LOG_DELAY(); - result = KERN_FAILURE; - goto finish; - } - - kld_result = kld_load_from_memory(&kmod_header, - requested_kmod_name, kmod_address, kmod_size); - - if (kld_result) { - do_kld_unload = 1; - } - - if (!kld_result || !link_load_address) { - IOLog("load_kmod(): kld_load_from_memory() failed for " - "kmod \"%s\".\n", requested_kmod_name); - LOG_DELAY(); - result = KERN_FAILURE; - goto finish; - } - - - /* Copy the linked header and image into the vm_allocated buffer. - * Move each onto the appropriate page-aligned boundary as given - * by the global link_... variables. - */ - bzero((char *)link_buffer_address, link_buffer_size); - // bcopy() is (from, to, length) - bcopy((char *)kmod_header, (char *)link_buffer_address, link_header_size); - bcopy((char *)kmod_header + link_header_size, - (char *)link_buffer_address + round_page_32(link_header_size), - link_load_size - link_header_size); - - - /* Get the kmod_info struct for the newly-loaded kmod. - */ - if (!kld_lookup("_kmod_info", (unsigned long *)&kmod_info)) { - IOLog("kld_lookup() of \"_kmod_info\" failed for " - "kmod \"%s\".\n", requested_kmod_name); - LOG_DELAY(); - result = KERN_FAILURE; - goto finish; - } - - - if (!stamp_kmod(requested_kmod_name, kmod_info)) { - // stamp_kmod() logs a meaningful message - result = KERN_FAILURE; - goto finish; - } - - - /* kld_lookup of _kmod_info yielded the actual linked address, - * so now that we've copied the data into its real place, - * we can set this stuff. - */ - kmod_info->address = link_buffer_address; - kmod_info->size = link_buffer_size; - kmod_info->hdr_size = round_page_32(link_header_size); - - /* We've written data and instructions, so *flush* the data cache - * and *invalidate* the instruction cache. - */ - flush_dcache64((addr64_t)link_buffer_address, link_buffer_size, false); - invalidate_icache64((addr64_t)link_buffer_address, link_buffer_size, false); - - - /* Register the new kmod with the kernel proper. - */ - if (kmod_create_internal(kmod_info, &kmod_id) != KERN_SUCCESS) { - IOLog("load_kmod(): kmod_create() failed for " - "kmod \"%s\".\n", requested_kmod_name); - LOG_DELAY(); - result = KERN_FAILURE; - goto finish; - } - -#if DEBUG - IOLog("kmod id %d successfully created at 0x%lx, size %ld.\n", - (unsigned int)kmod_id, link_buffer_address, link_buffer_size); - LOG_DELAY(); -#endif /* DEBUG */ - - /* Record dependencies for the newly-loaded kmod. - */ - for (i = 0; i < num_dependencies; i++) { - kmod_info_t * cur_dependency_info; - kmod_t packed_id; - cur_dependency_info = kmod_dependencies[i]; - packed_id = KMOD_PACK_IDS(kmod_id, cur_dependency_info->id); - if (kmod_retain(packed_id) != KERN_SUCCESS) { - IOLog("load_kmod(): kmod_retain() failed for " - "kmod \"%s\".\n", requested_kmod_name); - LOG_DELAY(); - kmod_destroy_internal(kmod_id); - result = KERN_FAILURE; - goto finish; - } - } - - /* Start the kmod (which invokes constructors for I/O Kit - * drivers. - */ - // kmod_start_or_stop(id, start?, user data, datalen) - if (kmod_start_or_stop(kmod_id, 1, 0, 0) != KERN_SUCCESS) { - IOLog("load_kmod(): kmod_start_or_stop() failed for " - "kmod \"%s\".\n", requested_kmod_name); - LOG_DELAY(); - kmod_destroy_internal(kmod_id); - result = KERN_FAILURE; - goto finish; - } - -finish: - - if (kmod_info_freeme) { - kfree((unsigned int)kmod_info_freeme, sizeof(kmod_info_t)); - } - - /* Only do a kld_unload_all() if at least one load happened. - */ - if (do_kld_unload) { - kld_unload_all(/* deallocate sets */ 1); - } - - /* If the link failed, blow away the allocated link buffer. - */ - if (result != KERN_SUCCESS && link_buffer_address) { - vm_deallocate(kernel_map, link_buffer_address, link_buffer_size); - } - - if (kmod_dependencies) { - for (i = 0; i < num_dependencies; i++) { - if (kmod_dependencies[i]) { - kfree((unsigned int)kmod_dependencies[i], sizeof(kmod_info_t)); - } - } - kfree((unsigned int)kmod_dependencies, - num_dependencies * sizeof(kmod_info_t *)); - } - - /* Reset these static global variables for the next call. - */ - g_current_kmod_name = NULL; - g_current_kmod_info = NULL; - link_buffer_address = 0; - link_load_address = 0; - link_load_size = 0; - link_buffer_size = 0; - link_header_size = 0; - - return result; -} - - -/********************************************************************* -* This is the function that IOCatalogue calls in order to load a kmod. -* It first checks whether the kmod is already loaded. If the kmod -* isn't loaded, this function builds a dependency list and calls -* load_kmod() repeatedly to guarantee that each dependency is in fact -* loaded. -*********************************************************************/ -__private_extern__ -kern_return_t load_kernel_extension(char * kmod_name) { - kern_return_t result = KERN_SUCCESS; - kmod_info_t * kmod_info = 0; // must free - OSArray * dependencyList = NULL; // must release - OSArray * curDependencyList = NULL; // must release - - /* See if the kmod is already loaded. - */ - kmod_info = kmod_lookupbyname_locked(kmod_name); - if (kmod_info) { // NOT checked - result = KERN_SUCCESS; - goto finish; - } - - /* It isn't loaded; build a dependency list and - * load those. - */ - unsigned int count; - unsigned int i; - dependencyList = getDependencyListForKmod(kmod_name); - if (!dependencyList) { - IOLog("load_kernel_extension(): " - "Can't get dependencies for kernel extension \"%s\".\n", - kmod_name); - LOG_DELAY(); - result = KERN_FAILURE; - goto finish; - } - - count = dependencyList->getCount(); - for (i = 0; i < count; i++) { - kern_return_t load_result; - OSString * curKmodName; // don't release - const char * cur_kmod_name; - - curKmodName = OSDynamicCast(OSString, - dependencyList->getObject(i)); - cur_kmod_name = curKmodName->getCStringNoCopy(); - curDependencyList = getDependencyListForKmod(cur_kmod_name); - if (!curDependencyList) { - IOLog("load_kernel_extension(): " - "Can't get dependencies for kernel extension \"%s\".\n", - cur_kmod_name); - LOG_DELAY(); - result = KERN_FAILURE; - goto finish; - } else { - load_result = load_kmod(curDependencyList); - if (load_result != KERN_SUCCESS) { - IOLog("load_kernel_extension(): " - "load_kmod() failed for kmod \"%s\".\n", - cur_kmod_name); - LOG_DELAY(); - result = load_result; - goto finish; - } - curDependencyList->release(); - curDependencyList = NULL; - } - } - - -finish: - - if (kmod_info) { - kfree((unsigned int)kmod_info, sizeof(kmod_info_t)); - } - - if (dependencyList) { - dependencyList->release(); - dependencyList = NULL; - } - if (curDependencyList) { - curDependencyList->release(); - curDependencyList = NULL; - } - - return result; -}