]> git.saurik.com Git - apple/xnu.git/blobdiff - iokit/Kernel/IOCatalogue.cpp
xnu-792.10.96.tar.gz
[apple/xnu.git] / iokit / Kernel / IOCatalogue.cpp
index 10c17ea279f6a5dded038fd7060bcc3a1e6653a9..2d05a9b4ae315a7262c383cdc7d2b23c48f04a2c 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 1998-2004 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -46,8 +46,8 @@ extern "C" {
 extern "C" {
 int IODTGetLoaderInfo( char *key, void **infoAddr, int *infoSize );
 extern void IODTFreeLoaderInfo( char *key, void *infoAddr, int infoSize );
 extern "C" {
 int IODTGetLoaderInfo( char *key, void **infoAddr, int *infoSize );
 extern void IODTFreeLoaderInfo( char *key, void *infoAddr, int infoSize );
-extern void OSRuntimeUnloadCPPForSegment(
-    struct segment_command * segment);
+/* operates on 32 bit segments */
+extern void OSRuntimeUnloadCPPForSegment(struct segment_command * segment);
 };
 
 
 };
 
 
@@ -202,7 +202,7 @@ kern_return_t start_prelink_module(UInt32 moduleIndex)
            if (depInfo)
            {
                kr = kmod_retain(KMOD_PACK_IDS(id, depInfo->id));
            if (depInfo)
            {
                kr = kmod_retain(KMOD_PACK_IDS(id, depInfo->id));
-               kfree((vm_offset_t) depInfo, sizeof(kmod_info_t));
+               kfree(depInfo, sizeof(kmod_info_t));
            } else
                IOLog("%s: NO DEP %s\n", kmod_info->name, str->getCStringNoCopy());
        }
            } else
                IOLog("%s: NO DEP %s\n", kmod_info->name, str->getCStringNoCopy());
        }
@@ -275,7 +275,7 @@ extern "C" Boolean kmod_load_request(const char * moduleName, Boolean make_reque
        // Is the module already loaded?
        ret = (0 != (kmod_info = kmod_lookupbyname_locked((char *)moduleName)));
        if (ret) {
        // Is the module already loaded?
        ret = (0 != (kmod_info = kmod_lookupbyname_locked((char *)moduleName)));
        if (ret) {
-           kfree((vm_offset_t) kmod_info, sizeof(kmod_info_t));
+           kfree(kmod_info, sizeof(kmod_info_t));
            break;
        }
        sym = OSSymbol::withCString(moduleName);
            break;
        }
        sym = OSSymbol::withCString(moduleName);
@@ -295,6 +295,7 @@ extern "C" Boolean kmod_load_request(const char * moduleName, Boolean make_reque
             IOLog("IOCatalogue: %s cannot be loaded "
                 "(kmod load function not set).\n",
                 moduleName);
             IOLog("IOCatalogue: %s cannot be loaded "
                 "(kmod load function not set).\n",
                 moduleName);
+           ret = true;
            break;
        }
 
            break;
        }
 
@@ -453,7 +454,6 @@ void IOCatalogue::initialize( void )
 // Initialize the IOCatalog object.
 bool IOCatalogue::init(OSArray * initArray)
 {
 // Initialize the IOCatalog object.
 bool IOCatalogue::init(OSArray * initArray)
 {
-    IORegistryEntry      * entry;
     OSDictionary         * dict;
     
     if ( !super::init() )
     OSDictionary         * dict;
     
     if ( !super::init() )
@@ -485,10 +485,6 @@ bool IOCatalogue::init(OSArray * initArray)
     thread_call_func_delayed( ping, this, deadline );
 #endif
 
     thread_call_func_delayed( ping, this, deadline );
 #endif
 
-    entry = IORegistryEntry::getRegistryRoot();
-    if ( entry )
-        entry->setProperty(kIOCatalogueKey, this);
-
     return true;
 }
 
     return true;
 }
 
@@ -841,7 +837,7 @@ IOReturn IOCatalogue::unloadModule( OSString * moduleName ) const
             if ( k_info->stop &&
                  !((ret = k_info->stop(k_info, 0)) == kIOReturnSuccess) ) {
 
             if ( k_info->stop &&
                  !((ret = k_info->stop(k_info, 0)) == kIOReturnSuccess) ) {
 
-                kfree((vm_offset_t) k_info, sizeof(kmod_info_t));
+                kfree(k_info, sizeof(kmod_info_t));
                 return ret;
            }
             
                 return ret;
            }
             
@@ -850,18 +846,16 @@ IOReturn IOCatalogue::unloadModule( OSString * moduleName ) const
     }
  
     if (k_info) {
     }
  
     if (k_info) {
-        kfree((vm_offset_t) k_info, sizeof(kmod_info_t));
+        kfree(k_info, sizeof(kmod_info_t));
     }
 
     return ret;
 }
 
     }
 
     return ret;
 }
 
-static IOReturn _terminateDrivers( OSArray * array, OSDictionary * matching )
+static IOReturn _terminateDrivers( OSDictionary * matching )
 {
 {
-    OSCollectionIterator * tables;
     OSDictionary         * dict;
     OSIterator           * iter;
     OSDictionary         * dict;
     OSIterator           * iter;
-    OSArray              * arrayCopy;
     IOService            * service;
     IOReturn               ret;
 
     IOService            * service;
     IOReturn               ret;
 
@@ -900,9 +894,17 @@ static IOReturn _terminateDrivers( OSArray * array, OSDictionary * matching )
     } while( !service && !iter->isValid());
     iter->release();
 
     } while( !service && !iter->isValid());
     iter->release();
 
+    return ret;
+}
+
+static IOReturn _removeDrivers( OSArray * array, OSDictionary * matching )
+{
+    OSCollectionIterator * tables;
+    OSDictionary         * dict;
+    OSArray              * arrayCopy;
+    IOReturn               ret = kIOReturnSuccess;
+
     // remove configs from catalog.
     // remove configs from catalog.
-    if ( ret != kIOReturnSuccess ) 
-        return ret;
 
     arrayCopy = OSArray::withCapacity(100);
     if ( !arrayCopy )
 
     arrayCopy = OSArray::withCapacity(100);
     if ( !arrayCopy )
@@ -938,9 +940,10 @@ IOReturn IOCatalogue::terminateDrivers( OSDictionary * matching )
 {
     IOReturn ret;
 
 {
     IOReturn ret;
 
-    ret = kIOReturnSuccess;
+    ret = _terminateDrivers(matching);
     IOLockLock( lock );
     IOLockLock( lock );
-    ret = _terminateDrivers(array, matching);
+    if (kIOReturnSuccess == ret)
+       ret = _removeDrivers(array, matching);
     kernelTables->reset();
     IOLockUnlock( lock );
 
     kernelTables->reset();
     IOLockUnlock( lock );
 
@@ -960,9 +963,10 @@ IOReturn IOCatalogue::terminateDriversForModule(
 
     dict->setObject(gIOModuleIdentifierKey, moduleName);
 
 
     dict->setObject(gIOModuleIdentifierKey, moduleName);
 
+    ret = _terminateDrivers(dict);
     IOLockLock( lock );
     IOLockLock( lock );
-
-    ret = _terminateDrivers(array, dict);
+    if (kIOReturnSuccess == ret)
+       ret = _removeDrivers(array, dict);
     kernelTables->reset();
 
     // Unload the module itself.
     kernelTables->reset();
 
     // Unload the module itself.
@@ -1039,18 +1043,10 @@ void IOCatalogue::reset(void)
 
 bool IOCatalogue::serialize(OSSerialize * s) const
 {
 
 bool IOCatalogue::serialize(OSSerialize * s) const
 {
-    bool ret;
-    
     if ( !s )
         return false;
 
     if ( !s )
         return false;
 
-    IOLockLock( lock );
-
-    ret = array->serialize(s);
-
-    IOLockUnlock( lock );
-
-    return ret;
+    return super::serialize(s);
 }
 
 bool IOCatalogue::serializeData(IOOptionBits kind, OSSerialize * s) const
 }
 
 bool IOCatalogue::serializeData(IOOptionBits kind, OSSerialize * s) const
@@ -1122,6 +1118,8 @@ bool IOCatalogue::recordStartupExtensions(void) {
 
 
 /*********************************************************************
 
 
 /*********************************************************************
+* This function operates on sections retrieved from the currently running
+* 32 bit mach kernel.
 *********************************************************************/
 bool IOCatalogue::addExtensionsFromArchive(OSData * mkext)
 {
 *********************************************************************/
 bool IOCatalogue::addExtensionsFromArchive(OSData * mkext)
 {
@@ -1164,18 +1162,22 @@ bool IOCatalogue::addExtensionsFromArchive(OSData * mkext)
     return result;
 }
 
     return result;
 }
 
-
 /*********************************************************************
 * This function clears out all references to the in-kernel linker,
 * frees the list of startup extensions in extensionDict, and
 * deallocates the kernel's __KLD segment to reclaim that memory.
 /*********************************************************************
 * This function clears out all references to the in-kernel linker,
 * frees the list of startup extensions in extensionDict, and
 * deallocates the kernel's __KLD segment to reclaim that memory.
+*
+* The segments it operates on are strictly 32 bit segments.
 *********************************************************************/
 kern_return_t IOCatalogue::removeKernelLinker(void) {
     kern_return_t result = KERN_SUCCESS;
 *********************************************************************/
 kern_return_t IOCatalogue::removeKernelLinker(void) {
     kern_return_t result = KERN_SUCCESS;
-    struct segment_command * segment;
+    struct segment_command * segmentLE, *segmentKLD;
+    boolean_t  keepsyms = FALSE;
+#if __ppc__
     char * dt_segment_name;
     void * segment_paddress;
     int    segment_size;
     char * dt_segment_name;
     void * segment_paddress;
     int    segment_size;
+#endif
 
    /* This must be the very first thing done by this function.
     */
 
    /* This must be the very first thing done by this function.
     */
@@ -1190,6 +1192,8 @@ kern_return_t IOCatalogue::removeKernelLinker(void) {
         goto finish;
     }
 
         goto finish;
     }
 
+    PE_parse_boot_arg("keepsyms", &keepsyms);
     IOLog("Jettisoning kernel linker.\n");
 
     kernelLinkerPresent = 0;
     IOLog("Jettisoning kernel linker.\n");
 
     kernelLinkerPresent = 0;
@@ -1209,25 +1213,24 @@ kern_return_t IOCatalogue::removeKernelLinker(void) {
     * memory so that any cross-dependencies (not that there
     * should be any) are handled.
     */
     * memory so that any cross-dependencies (not that there
     * should be any) are handled.
     */
-    segment = getsegbyname("__KLD");
-    if (!segment) {
+    segmentKLD = getsegbyname("__KLD");
+    if (!segmentKLD) {
         IOLog("error removing kernel linker: can't find %s segment\n",
             "__KLD");
         result = KERN_FAILURE;
         goto finish;
     }
         IOLog("error removing kernel linker: can't find %s segment\n",
             "__KLD");
         result = KERN_FAILURE;
         goto finish;
     }
-    OSRuntimeUnloadCPPForSegment(segment);
+    OSRuntimeUnloadCPPForSegment(segmentKLD);
 
 
-    segment = getsegbyname("__LINKEDIT");
-    if (!segment) {
+    segmentLE = getsegbyname("__LINKEDIT");
+    if (!segmentLE) {
         IOLog("error removing kernel linker: can't find %s segment\n",
             "__LINKEDIT");
         result = KERN_FAILURE;
         goto finish;
     }
         IOLog("error removing kernel linker: can't find %s segment\n",
             "__LINKEDIT");
         result = KERN_FAILURE;
         goto finish;
     }
-    OSRuntimeUnloadCPPForSegment(segment);
-
-
+    OSRuntimeUnloadCPPForSegment(segmentLE);
+#if __ppc__
    /* Free the memory that was set up by bootx.
     */
     dt_segment_name = "Kernel-__KLD";
    /* Free the memory that was set up by bootx.
     */
     dt_segment_name = "Kernel-__KLD";
@@ -1235,12 +1238,29 @@ kern_return_t IOCatalogue::removeKernelLinker(void) {
         IODTFreeLoaderInfo(dt_segment_name, (void *)segment_paddress,
             (int)segment_size);
     }
         IODTFreeLoaderInfo(dt_segment_name, (void *)segment_paddress,
             (int)segment_size);
     }
-
+#elif __i386__
+    /* On x86, use the mapping data from the segment load command to
+     * unload KLD and LINKEDIT directly, unless the keepsyms boot-arg
+     * was enabled. This may invalidate any assumptions about 
+     * "avail_start" defining the lower bound for valid physical addresses.
+     */
+    if (!keepsyms && segmentKLD->vmaddr && segmentKLD->vmsize)
+           ml_static_mfree(segmentKLD->vmaddr, segmentKLD->vmsize);
+#else
+#error arch
+#endif
+#if __ppc__
     dt_segment_name = "Kernel-__LINKEDIT";
     if (0 == IODTGetLoaderInfo(dt_segment_name, &segment_paddress, &segment_size)) {
         IODTFreeLoaderInfo(dt_segment_name, (void *)segment_paddress,
             (int)segment_size);
     }
     dt_segment_name = "Kernel-__LINKEDIT";
     if (0 == IODTGetLoaderInfo(dt_segment_name, &segment_paddress, &segment_size)) {
         IODTFreeLoaderInfo(dt_segment_name, (void *)segment_paddress,
             (int)segment_size);
     }
+#elif __i386__
+    if (!keepsyms && segmentLE->vmaddr && segmentLE->vmsize)
+           ml_static_mfree(segmentLE->vmaddr, segmentLE->vmsize);
+#else
+#error arch
+#endif
 
     struct section * sect;
     sect = getsectbyname("__PRELINK", "__symtab");
 
     struct section * sect;
     sect = getsectbyname("__PRELINK", "__symtab");
@@ -1261,3 +1281,20 @@ finish:
 
     return result;
 }
 
     return result;
 }
+
+/*********************************************************************
+* This function stops the catalogue from making kextd requests during
+* shutdown.
+*********************************************************************/
+void IOCatalogue::disableExternalLinker(void) {
+    IOLockLock(gIOKLDLock);
+   /* If kmod_load_extension (the kextd requester function) is in use,
+    * disable new module requests.
+    */
+    if (kmod_load_function == &kmod_load_extension) {
+       kmod_load_function = NULL;
+    }
+
+    IOLockUnlock(gIOKLDLock);
+}
+