Loading...
libsa/kmod.cpp xnu-792 xnu-123.5
--- xnu/xnu-792/libsa/kmod.cpp
+++ xnu/xnu-123.5/libsa/kmod.cpp
@@ -37,10 +37,13 @@
 #include <mach_loader.h>
 };
 
-#include "kld_patch.h"
-
 
 extern "C" {
+extern load_return_t fatfile_getarch(
+    void            * vp,       // normally a (struct vnode *)
+    vm_offset_t       data_ptr,
+    struct fat_arch * archret);
+
 extern kern_return_t
 kmod_create_internal(
             kmod_info_t *info,
@@ -59,179 +62,19 @@
 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);
+extern void flush_dcache(vm_offset_t addr, unsigned cnt, int phys);
+extern void invalidate_icache(vm_offset_t addr, unsigned cnt, int phys);
 };
 
 
+IOLock * kld_lock;
+
+
 #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;
-}
+#define VTYELLOW   "\033[33m"
+#define VTRESET    "\033[0m"
+
 
 /*********************************************************************
 * This function builds a uniqued, in-order list of modules that need
@@ -239,7 +82,7 @@
 * list ends with kmod_name itself.
 *********************************************************************/
 static
-OSArray * getDependencyListForKmod(const char * kmod_name) {
+OSArray * getDependencyListForKmod(char * kmod_name) {
 
     int error = 0;
 
@@ -318,9 +161,6 @@
         goto finish;
     }
 
-
-   /* Okay, let's get started.
-    */
     dependencyList->setObject(extName);
 
 
@@ -379,9 +219,9 @@
             goto finish;
         }
 
-        curExtDepDict = OSDynamicCast(OSDictionary,
-              curExtPlist->getObject("OSBundleLibraries"));
-        if (curExtDepDict) {
+      curExtDepDict = OSDynamicCast(OSDictionary,
+          curExtPlist->getObject("OSBundleLibraries"));
+      if (curExtDepDict) {
             OSCollectionIterator * keyIterator =
                 OSCollectionIterator::withCollection(curExtDepDict);
 
@@ -397,19 +237,6 @@
                      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);
             }
 
@@ -446,9 +273,7 @@
 
    /* 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).
+    * value because we need some non-NULL value.
     */
     i = originalList->getCount();
 
@@ -459,9 +284,7 @@
             OSString * item = OSDynamicCast(OSString,
                 originalList->getObject(i));
 
-            if ( (!encounteredNames->getObject(item)) &&
-                 kextIsADependency(item)) {
-
+            if ( ! encounteredNames->getObject(item) ) {
                 encounteredNames->setObject(item, originalList);
                 dependencyList->setObject(item);
             }
@@ -469,6 +292,7 @@
     }
 
 
+
 finish:
 
     if (originalList) {
@@ -490,6 +314,209 @@
 
 /*********************************************************************
 *********************************************************************/
+static bool verifyCompatibleVersions(OSArray * dependencyList) {
+    bool result = true;
+
+    OSString * requestedModuleName = NULL;
+
+    OSDictionary * extensionsDict = NULL;
+    int count, i;
+    OSString * curName = NULL;
+    OSDictionary * curExt = NULL;
+    OSDictionary * curExtPlist = NULL;
+
+    OSBoolean * isKernelResource = NULL;
+
+    OSDictionary * dependencies = NULL;
+    OSCollectionIterator * dependencyIterator = NULL; // must release
+    OSString * dependencyName = NULL;
+    OSString * curExtDependencyVersion = NULL;
+    UInt32 cur_ext_required_dependency_vers;
+
+    OSDictionary * dependency = NULL;
+    OSDictionary * dependencyPlist = NULL;
+
+    OSString * dependencyVersion = NULL;
+    OSString * dependencyCompatibleVersion = NULL;
+    UInt32 dependency_vers;
+    UInt32 dependency_compat_vers;
+
+
+   /* Get the dictionary of startup extensions.
+    * This is keyed by module name.
+    */
+    extensionsDict = getStartupExtensions();
+    if (!extensionsDict) {
+        IOLog("verifyCompatibleVersions(): No extensions dictionary.\n");
+        LOG_DELAY();
+        result = false;
+        goto finish;
+    }
+    
+
+    count = dependencyList->getCount();
+    if (!count) {
+        IOLog("verifyCompatibleVersions(): "
+            "Invoked with no dependency list.\n");
+        LOG_DELAY();
+        result = false;
+        goto finish;
+    }
+
+    requestedModuleName = OSDynamicCast(OSString,
+        dependencyList->getObject(count - 1));
+
+    for (i = count - 1; i >= 0; i--) {
+
+        if (dependencyIterator) {
+            dependencyIterator->release();
+            dependencyIterator = NULL;
+        }
+
+        curName = OSDynamicCast(OSString, dependencyList->getObject(i));
+        if (!curName) {
+            IOLog("verifyCompatibleVersions(): Internal error (1).\n");
+            LOG_DELAY();
+            result = false;
+            goto finish;
+        }
+
+        curExt = OSDynamicCast(OSDictionary,
+            extensionsDict->getObject(curName));
+        if (!curExt) {
+            IOLog("verifyCompatibleVersions(): Internal error (2).\n");
+            LOG_DELAY();
+            result = false;
+            goto finish;
+        }
+
+        curExtPlist = OSDynamicCast(OSDictionary,
+            curExt->getObject("plist"));
+        if (!curExtPlist) {
+            IOLog("verifyCompatibleVersions(): Internal error (3).\n");
+            LOG_DELAY();
+            result = false;
+            goto finish;
+        }
+
+
+       /* In-kernel extensions don't need to check dependencies.
+        */
+        isKernelResource = OSDynamicCast(OSBoolean,
+            curExtPlist->getObject("OSKernelResource"));
+        if (isKernelResource && isKernelResource->isTrue()) {
+            continue;
+        }
+
+        dependencies = OSDynamicCast(OSDictionary,
+            curExtPlist->getObject("OSBundleLibraries"));
+        if (!dependencies || dependencies->getCount() < 1) {
+            IOLog(VTYELLOW "verifyCompatibleVersions(): Extension \"%s\" "
+                "declares no dependencies.\n" VTRESET,
+                curName->getCStringNoCopy());
+            LOG_DELAY();
+            result = false;
+            goto finish;
+        }
+
+        dependencyIterator =
+            OSCollectionIterator::withCollection(dependencies);
+        if (!curExtPlist) {
+            IOLog("verifyCompatibleVersions(): Internal error (4).\n");
+            LOG_DELAY();
+            result = false;
+            goto finish;
+        }
+
+        while ((dependencyName = OSDynamicCast(OSString,
+            dependencyIterator->getNextObject()))) {
+
+            curExtDependencyVersion = OSDynamicCast(OSString,
+                dependencies->getObject(dependencyName));
+            if (!curExtDependencyVersion) {
+                IOLog("verifyCompatibleVersions(): Internal error (5).\n");
+                LOG_DELAY();
+                result = false;
+                goto finish;
+            }
+
+            dependency = OSDynamicCast(OSDictionary,
+                extensionsDict->getObject(dependencyName));
+            if (!dependency) {
+                IOLog("verifyCompatibleVersions(): Internal error (6).\n");
+                LOG_DELAY();
+                result = false;
+                goto finish;
+            }
+
+            dependencyPlist = OSDynamicCast(OSDictionary,
+                dependency->getObject("plist"));
+            if (!dependencyPlist) {
+                IOLog("verifyCompatibleVersions(): Internal error (7).\n");
+                LOG_DELAY();
+                result = false;
+                goto finish;
+            }
+
+            dependencyVersion = OSDynamicCast(OSString,
+                dependencyPlist->getObject("CFBundleVersion"));
+            if (!curExtDependencyVersion) {
+                IOLog(VTYELLOW "Dependency extension \"%s\" doesn't declare a "
+                    "version.\n" VTRESET,
+                    dependencyName->getCStringNoCopy());
+                LOG_DELAY();
+                result = false;
+                goto finish;
+            }
+
+            dependencyCompatibleVersion = OSDynamicCast(OSString,
+                dependencyPlist->getObject("OSBundleCompatibleVersion"));
+            if (!dependencyCompatibleVersion) {
+                IOLog(VTYELLOW "Dependency extension \"%s\" doesn't declare a "
+                    "compatible version.\n" VTRESET,
+                    dependencyName->getCStringNoCopy());
+                LOG_DELAY();
+                result = false;
+                goto finish;
+            }
+
+IOLog("\033[33m    %s (needs %s, compat-current is %s-%s).\n" VTRESET, 
+    dependencyName->getCStringNoCopy(),
+    curExtDependencyVersion->getCStringNoCopy(),
+    dependencyCompatibleVersion->getCStringNoCopy(),
+    dependencyVersion->getCStringNoCopy());
+LOG_DELAY();
+
+            if (!VERS_parse_string(curExtDependencyVersion->getCStringNoCopy(),
+                 &cur_ext_required_dependency_vers)) {
+            }
+            if (!VERS_parse_string(dependencyVersion->getCStringNoCopy(),
+                 &dependency_vers)) {
+            }
+            if (!VERS_parse_string(dependencyCompatibleVersion->getCStringNoCopy(),
+                 &dependency_compat_vers)) {
+            }
+
+            if (cur_ext_required_dependency_vers > dependency_vers ||
+                cur_ext_required_dependency_vers < dependency_compat_vers) {
+
+                IOLog(VTYELLOW "Cannot load extension \"%s\": dependencies "
+                    "\"%s\" and \"%s\" are not of compatible versions.\n" VTRESET,
+                    requestedModuleName->getCStringNoCopy(),
+                    curName->getCStringNoCopy(),
+                    dependencyName->getCStringNoCopy());
+                LOG_DELAY();
+                result = false;
+                goto finish;
+            }
+        }
+    }
+
+finish:
+    return result;
+}
+
+
 /* Used in address_for_loaded_kmod.
  */
 static kmod_info_t * g_current_kmod_info = NULL;
@@ -546,7 +573,7 @@
         return 0;
     }
 
-    round_headers_size = round_page_32(headers_size);
+    round_headers_size = round_page(headers_size);
     headers_pad = round_headers_size - headers_size;
 
     link_load_address = (unsigned long)g_current_kmod_info->address +
@@ -582,13 +609,13 @@
     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_headers_size  = round_page(headers_size);
+    round_segments_size = round_page(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);
+        round_size, TRUE);
     if (k_result != KERN_SUCCESS) {
         IOLog("alloc_for_kmod(): Can't allocate memory.\n");
         LOG_DELAY();
@@ -607,35 +634,36 @@
 
     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;
+int get_text_info_for_kmod(const char * kmod_name,
+    char ** text_address,
+    unsigned long * text_size) {
 
     // None of these needs to be released.
     OSDictionary * extensionsDict;
     OSDictionary * kmodDict;
-    OSData * compressedCode = 0;
-
-    // Driver Code may need to be released
     OSData * driverCode;
+
+    vm_offset_t kmod_address;
+    typedef union {
+        struct mach_header mach_header;
+        struct fat_header  fat_header;
+    } kmod_header_composite;
+    kmod_header_composite * kmod_headers;
+
 
    /* 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");
+        IOLog("text_address_for_kmod(): No extensions dictionary.\n");
         LOG_DELAY();
         return 0;
     }
@@ -643,104 +671,99 @@
     kmodDict = OSDynamicCast(OSDictionary,
         extensionsDict->getObject(kmod_name));
     if (!kmodDict) {
-        IOLog("map_and_patch(): "
+        IOLog("text_address_for_kmod(): "
             "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;
+    if (!driverCode) {
+        IOLog("text_address_for_kmod(): "
+            "Extension \"%s\" has no \"code\" property.\n",
+            kmod_name);
+        LOG_DELAY();
+        return 0;
+    }
+
+    kmod_address = (vm_offset_t)driverCode->getBytesNoCopy();
+    kmod_headers = (kmod_header_composite *)kmod_address;
+
+   /* Now extract the appropriate code from the executable data.
+    */
+    if (kmod_headers->mach_header.magic == MH_MAGIC) {
+
+        *text_address = (char *)kmod_address;
+        *text_size = driverCode->getLength();
+        return 1;
+
+    } else if (kmod_headers->fat_header.magic == FAT_MAGIC ||
+               kmod_headers->fat_header.magic == FAT_CIGAM) {
+                             // CIGAM is byte-swapped MAGIC
+
+        load_return_t load_return;
+        struct fat_arch fatinfo;
+
+        load_return = fatfile_getarch(NULL, kmod_address, &fatinfo);
+        if (load_return != LOAD_SUCCESS) {
+            IOLog("text_address_for_kmod(): Extension \"%s\" "
+                "doesn't contain code for this computer.\n", kmod_name);
+            LOG_DELAY();
+            return 0;
+        }
+
+        *text_address = (char *)(kmod_address + fatinfo.offset);
+        *text_size = fatinfo.size;
+        return 1;
+
+    } else {
+        IOLog("text_address_for_kmod(): Extension \"%s\" either "
+            "isn't code or doesn't contain code for this computer.\n",
+            kmod_name);
+        LOG_DELAY();
+        return 0;
+    }
+
+    return 1;
 }
+
 
 /*********************************************************************
 *********************************************************************/
-bool stamp_kmod(const char * kmod_name, kmod_info_t * kmod_info) {
+bool verify_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);
+    UInt32 plist_vers;
+    UInt32 kmod_vers;
+
+    if (strncmp(kmod_name, kmod_info->name, sizeof(kmod_info->name))) {
+        IOLog("verify_kmod(): kmod loaded as \"%s\" has different "
+            "identifier \"%s\".\n", kmod_name, kmod_info->name);
         LOG_DELAY();
         result = false;
         goto finish;
     }
 
-    strcpy(kmod_info->name, kmod_name);
+    if (!VERS_parse_string(kmod_info->version,
+         &kmod_vers)) {
+
+        IOLog(VTYELLOW "verify_kmod(): kmod \"%s\" has an invalid "
+            "version.\n" VTRESET, kmod_info->name);
+        LOG_DELAY();
+        result = false;
+        goto finish;
+    }
+
 
    /* Get the dictionary of startup extensions.
     * This is keyed by module name.
     */
     extensionsDict = getStartupExtensions();
     if (!extensionsDict) {
-        IOLog("stamp_kmod(): No extensions dictionary.\n");
+        IOLog("verify_kmod(): No extensions dictionary.\n");
         LOG_DELAY();
         result = false;
         goto finish;
@@ -749,7 +772,7 @@
     kmodDict = OSDynamicCast(OSDictionary,
         extensionsDict->getObject(kmod_name));
     if (!kmodDict) {
-        IOLog("stamp_kmod(): Can't find record for kmod \"%s\".\n",
+        IOLog("verify_kmod(): Can't find record for kmod \"%s\".\n",
             kmod_name);
         LOG_DELAY();
         result = false;
@@ -757,53 +780,52 @@
     }
 
     plist = OSDynamicCast(OSDictionary,
-        kmodDict->getObject("plist"));
+        extensionsDict->getObject("plist"));
     if (!kmodDict) {
-        IOLog("stamp_kmod(): Kmod \"%s\" has no property list.\n",
+        IOLog("verify_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"));
+        extensionsDict->getObject("CFBundleVersion"));
     if (!versionString) {
-        IOLog("stamp_kmod(): Kmod \"%s\" has no \"CFBundleVersion\" "
-            "property.\n",
+        IOLog(VTYELLOW "verify_kmod(): Kmod \"%s\" has no \"CFBundleVersion\" "
+            "property.\n" VTRESET,
             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");
+    if (!VERS_parse_string(versionString->getCStringNoCopy(),
+         &plist_vers)) {
+
+        IOLog(VTYELLOW "verify_kmod(): Property list for kmod \"%s\" has "
+            "an invalid version.\n" VTRESET, kmod_info->name);
         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);
+    if (kmod_vers != plist_vers) {
+        IOLog(VTYELLOW "verify_kmod(): Kmod \"%s\" and its property list "
+            "claim different versions (%s & %s).\n" VTRESET,
+            kmod_info->name,
+            kmod_info->version,
+            versionString->getCStringNoCopy());
         LOG_DELAY();
         result = false;
         goto finish;
     }
 
-    strcpy(kmod_info->version, plist_version);
-
-    result = true;
 
 finish:
+
+    // FIXME: make this really return the result after conversion
+    return true;
 
     return result;
 }
@@ -831,8 +853,7 @@
     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_info_t * kmod_info;
     kmod_t        kmod_id;
 
 
@@ -860,8 +881,8 @@
 
    /* 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) {
+    kmod_info = kmod_lookupbyname(requested_kmod_name);
+    if (kmod_info) {
         // FIXME: Need to check for version mismatch if already loaded.
         result = KERN_SUCCESS;
         goto finish;
@@ -884,9 +905,6 @@
         goto finish;
     }
 
-    bzero(kmod_dependencies, num_dependencies *
-        sizeof(kmod_info_t *));
-
     for (i = 0; i < num_dependencies; i++) {
 
         currentKmodName = OSDynamicCast(OSString,
@@ -903,7 +921,7 @@
         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_info = kmod_lookupbyname(current_kmod_name);
         g_current_kmod_name = current_kmod_name;
 
         if (!g_current_kmod_info) {
@@ -928,27 +946,20 @@
         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);
+        if (!get_text_info_for_kmod(current_kmod_name,
+             &kmod_address, &kmod_size)) {
+
+            IOLog("get_text_info_for_kmod() failed for dependency kmod "
+                "\"%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);
+            current_kmod_name,
+            (char *)kmod_address,
+            kmod_size);
 
         if (kld_result) {
             do_kld_unload = 1;
@@ -975,26 +986,19 @@
     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);
+    if (!get_text_info_for_kmod(requested_kmod_name,
+         &kmod_address, &kmod_size)) {
+        IOLog("load_kmod: get_text_info_for_kmod() failed for "
+            "kmod \"%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);
+        requested_kmod_name,
+        (char *)kmod_address,
+        kmod_size);
 
     if (kld_result) {
         do_kld_unload = 1;
@@ -1017,7 +1021,7 @@
     // 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),
+        (char *)link_buffer_address + round_page(link_header_size),
         link_load_size - link_header_size);
 
 
@@ -1032,8 +1036,8 @@
     }
 
 
-    if (!stamp_kmod(requested_kmod_name, kmod_info)) {
-        // stamp_kmod() logs a meaningful message
+    if (!verify_kmod(requested_kmod_name, kmod_info)) {
+        // verify_kmod() logs a meaningful message
         result = KERN_FAILURE;
         goto finish;
     }
@@ -1045,13 +1049,13 @@
     */
     kmod_info->address = link_buffer_address;
     kmod_info->size = link_buffer_size;
-    kmod_info->hdr_size = round_page_32(link_header_size);
+    kmod_info->hdr_size = round_page(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);
+    flush_dcache(link_buffer_address, link_buffer_size, false);
+    invalidate_icache(link_buffer_address, link_buffer_size, false);
 
 
    /* Register the new kmod with the kernel proper.
@@ -1064,11 +1068,9 @@
         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.
     */
@@ -1102,14 +1104,11 @@
 
 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.
@@ -1119,11 +1118,6 @@
     }
 
     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 *));
     }
@@ -1152,17 +1146,25 @@
 __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
+    kmod_info_t * kmod_info;
     OSArray * dependencyList = NULL;     // must release
     OSArray * curDependencyList = NULL;  // must release
 
+
+   /* This must be the very first thing done by this function.
+    */
+    IOLockLock(kld_lock);
+
+
    /* See if the kmod is already loaded.
     */
-    kmod_info = kmod_lookupbyname_locked(kmod_name);
+    kmod_info = kmod_lookupbyname(kmod_name);
     if (kmod_info) {  // NOT checked
         result = KERN_SUCCESS;
         goto finish;
     }
+
+    // FIXME: Need to check whether kmod is built into the kernel!
 
    /* It isn't loaded; build a dependency list and
     * load those.
@@ -1179,6 +1181,21 @@
         goto finish;
     }
 
+    if (!verifyCompatibleVersions(dependencyList)) {
+        IOLog(VTYELLOW "load_kernel_extension(): "
+            "Version mismatch for kernel extension \"%s\".\n" VTRESET,
+            kmod_name);
+        LOG_DELAY();
+#if 0
+// FIXME: This is currently a warning only; when kexts are updated
+// this will become an error.
+        result = KERN_FAILURE;
+        goto finish;
+#else
+        IOLog(VTYELLOW "Loading anyway.\n" VTRESET);
+#endif 0
+    }
+
     count = dependencyList->getCount();
     for (i = 0; i < count; i++) {
         kern_return_t load_result;
@@ -1189,34 +1206,22 @@
             dependencyList->getObject(i));
         cur_kmod_name = curKmodName->getCStringNoCopy();
         curDependencyList = getDependencyListForKmod(cur_kmod_name);
-        if (!curDependencyList) {
+
+        load_result = load_kmod(curDependencyList);
+        if (load_result != KERN_SUCCESS) {
             IOLog("load_kernel_extension(): "
-                "Can't get dependencies for kernel extension \"%s\".\n",
+                "load_kmod() failed for kmod \"%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;
-        }
+            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();
@@ -1227,5 +1232,9 @@
         curDependencyList = NULL;
     }
 
+   /* This must be the very last thing done before returning.
+    */
+    IOLockUnlock(kld_lock);
+
     return result;
 }