-static
-kern_return_t kmod_load_from_cache_sym(const OSSymbol * kmod_name)
-{
- OSArray * prelinkedModules = gIOPrelinkedModules;
- kern_return_t result = KERN_FAILURE;
- OSDictionary * dict;
- OSObject * ident;
- UInt32 idx;
-
- if (!gIOPrelinkedModules)
- return KERN_FAILURE;
-
- for (idx = 0;
- (dict = (OSDictionary *) prelinkedModules->getObject(idx));
- idx++)
- {
- if ((ident = dict->getObject(kModuleKey))
- && kmod_name->isEqualTo(ident))
- break;
- }
- if (dict)
- {
- if (kernelLinkerPresent && dict->getObject("OSBundleDefer"))
- {
- kmod_load_extension((char *) kmod_name->getCStringNoCopy());
- result = kIOReturnOffline;
- }
- else
- result = start_prelink_module(idx);
- }
-
- return result;
-}
-
-extern "C" Boolean kmod_load_request(const char * moduleName, Boolean make_request)
-{
- bool ret, cacheMiss = false;
- kern_return_t kr;
- const OSSymbol * sym = 0;
- kmod_info_t * kmod_info;
-
- if (!moduleName)
- return false;
-
- /* To make sure this operation completes even if a bad extension needs
- * to be removed, take the kld lock for this whole block, spanning the
- * kmod_load_function() and remove_startup_extension_function() calls.
- */
- IOLockLock(gIOKLDLock);
- do
- {
- // Is the module already loaded?
- ret = (0 != (kmod_info = kmod_lookupbyname_locked((char *)moduleName)));
- if (ret) {
- kfree(kmod_info, sizeof(kmod_info_t));
- break;
- }
- sym = OSSymbol::withCString(moduleName);
- if (!sym) {
- ret = false;
- break;
- }
-
- kr = kmod_load_from_cache_sym(sym);
- ret = (kIOReturnSuccess == kr);
- cacheMiss = !ret;
- if (ret || !make_request || (kr == kIOReturnOffline))
- break;
-
- // If the module hasn't been loaded, then load it.
- if (!kmod_load_function) {
- IOLog("IOCatalogue: %s cannot be loaded "
- "(kmod load function not set).\n",
- moduleName);
- ret = true;
- break;
- }
-
- kr = kmod_load_function((char *)moduleName);
-
- if (ret != kIOReturnSuccess) {
- IOLog("IOCatalogue: %s cannot be loaded.\n", moduleName);
-
- /* If the extension couldn't be loaded this time,
- * make it unavailable so that no more requests are
- * made in vain. This also enables other matching
- * extensions to have a chance.
- */
- if (kernelLinkerPresent && remove_startup_extension_function) {
- (*remove_startup_extension_function)(moduleName);
- }
- ret = false;
-
- } else if (kernelLinkerPresent) {
- // If kern linker is here, the driver is actually loaded,
- // so return true.
- ret = true;
-
- } else {
- // kern linker isn't here, a request has been queued
- // but the module isn't necessarily loaded yet, so stall.
- ret = false;
- }
- }
- while (false);
-
- IOLockUnlock(gIOKLDLock);
-
- if (sym)
- {
- IOLockLock(gIOCatalogLock);
- gIOCatalogModuleRequests->setObject(sym);
- if (cacheMiss)
- gIOCatalogCacheMisses->setObject(sym);
- IOLockUnlock(gIOCatalogLock);
- }
-
- return ret;
-}
-
-extern "C" kern_return_t kmod_unload_cache(void)
-{
- OSArray * prelinkedModules = gIOPrelinkedModules;
- kern_return_t result = KERN_FAILURE;
- OSDictionary * dict;
- UInt32 idx;
- UInt32 * prelink;
- OSData * data;
-
- if (!gIOPrelinkedModules)
- return KERN_SUCCESS;
-
- IOLockLock(gIOKLDLock);
- for (idx = 0;
- (dict = (OSDictionary *) prelinkedModules->getObject(idx));
- idx++)
- {
- data = OSDynamicCast(OSData, dict->getObject("OSBundlePrelink"));
- if (!data)
- continue;
- prelink = (UInt32 *) data->getBytesNoCopy();
-
- kmod_info_t * kmod_info = (kmod_info_t *) OSReadBigInt32(prelink, 0);
- vm_offset_t
- virt = ml_static_ptovirt(kmod_info->address);
- if( virt) {
- ml_static_mfree(virt, kmod_info->size);
- }
- }
-
- gIOPrelinkedModules->release();
- gIOPrelinkedModules = 0;
-
- IOLockUnlock(gIOKLDLock);
-
- return result;
-}
-
-extern "C" kern_return_t kmod_load_from_cache(const char * kmod_name)
-{
- kern_return_t kr;
- const OSSymbol * sym = OSSymbol::withCStringNoCopy(kmod_name);
-
- if (sym)
- {
- kr = kmod_load_from_cache_sym(sym);
- sym->release();
- }
- else
- kr = kIOReturnNoMemory;
-
- return kr;
-}