@@ -375,6 +375,64 @@ static const void *library_entry(const void *library, u32 magic,
return NULL;
}
+/**
+ * irx_first_import_library - first imported library entry
+ * @ehdr: ELF header of module
+ *
+ * Return: first imported library entry, or %NULL
+ */
+static const struct irx_import_library *irx_first_import_library(
+ const struct elf32_hdr *ehdr)
+{
+ return library_entry(NULL, IOPMOD_IMPORT_MAGIC, ehdr);
+}
+
+/**
+ * same_import_library - are the two imported libraries the same?
+ * @a: first imported library
+ * @b: second imported library
+ *
+ * Return: %true if the libraries have the same name, otherwise %false
+ */
+static bool same_import_library(
+ const struct irx_import_library *a,
+ const struct irx_import_library *b)
+{
+ return strncmp(a->name, b->name, sizeof(a->name)) == 0;
+}
+
+/**
+ * irx_next_import_library - next imported library entry
+ * @library: current library entry
+ * @ehdr: ELF header of module
+ *
+ * Return: imported library entry following the current library entry, or %NULL
+ */
+static const struct irx_import_library *irx_next_import_library(
+ const struct irx_import_library *library, const struct elf32_hdr *ehdr)
+{
+ const struct irx_import_library *next = library;
+
+ while (next) {
+ if (!same_import_library(next, library))
+ return next;
+
+ next = library_entry(next, IOPMOD_IMPORT_MAGIC, ehdr);
+ }
+
+ return next;
+}
+
+/**
+ * irx_for_each_import_library - iterate over imported libraries
+ * @library: &struct irx_import_library loop cursor
+ * @ehdr: ELF header of module to iterate
+ */
+#define irx_for_each_import_library(library, ehdr) \
+ for ((library) = irx_first_import_library((ehdr)); \
+ (library); \
+ (library) = irx_next_import_library((library), (ehdr)))
+
/**
* irx_first_export_library - first exported library entry
* @ehdr: ELF header of module
@@ -488,6 +546,45 @@ static bool irx_identify(const void *buffer, size_t size)
return elf_identify(buffer, size) && irx_iopmod(buffer) != NULL;
}
+/**
+ * library_provided_by_module - is the library provided by the module?
+ * @name: name of the library to search for
+ * @ehdr: ELF header of module
+ *
+ * Return: %true if the module provides the library, otherwise %false
+ */
+static bool library_provided_by_module(const char *name,
+ const struct elf32_hdr *ehdr)
+{
+ const struct irx_export_library *library;
+
+ irx_for_each_export_library (library, ehdr)
+ if (strncmp(name, library->name, sizeof(library->name)) == 0)
+ return true;
+
+ return false;
+}
+
+/**
+ * library_provided_by_rom - is the library provided by the ROM directory?
+ * @name: name of the library to search for
+ * @dir: ROM directory
+ *
+ * Return: %true if some ROM file in the ROM directory provides the library,
+ * otherwise %false
+ */
+static bool library_provided_by_rom(const char *name, const struct rom_dir dir)
+{
+ struct rom_file file;
+
+ rom_for_each_file (file, dir)
+ if (irx_identify(file.data, file.size))
+ if (library_provided_by_module(name, file.data))
+ return true;
+
+ return false;
+}
+
/**
* library_provided_by_firmware - is the library provided by linked firmware?
* @name: name of the library to search for
@@ -506,6 +603,24 @@ static bool library_provided_by_firmware(const char *name)
return false;
}
+/**
+ * library_provided - is the library provided?
+ * @name: name of the library to search for
+ *
+ * As a simplification it is assumed that if a ROM file provides the given
+ * library, then the ROM file has been prelinked into the IOP.
+ *
+ * The IOP linker will deal with issues related to version compatibility.
+ *
+ * Return: %true if the library is provided, otherwise %false
+ */
+static bool library_provided(const char *name)
+{
+ return library_provided_by_rom(name, rom0_dir) ||
+ library_provided_by_rom(name, rom1_dir) ||
+ library_provided_by_firmware(name);
+}
+
/**
* register_libraries - register libraries provided by the given module
* @ehdr: IOP module
@@ -615,6 +730,52 @@ static int iop_module_link_buffer(const void *buf, size_t nbyte,
static int iop_module_request_firmware(
const char *name, int version, const char *arg);
+/**
+ * iop_module_request_dependencies - resolve and prelink dependencies for
+ * requested IOP module
+ * @ehdr: IOP module to request dependencies for
+ * @requesting_name: name of IOP module requesting dependencies
+ *
+ * Return: 0 on success, otherwise a negative error number
+ */
+static int iop_module_request_dependencies(const struct elf32_hdr *ehdr,
+ const char *requesting_name)
+{
+ const struct irx_import_library *library;
+
+ irx_for_each_import_library (library, ehdr) {
+ char library_name[sizeof(library->name) + 1] = { };
+ int err;
+
+ /* Convert the library name to a NUL-terminated string. */
+ memcpy(library_name, library->name, sizeof(library->name));
+
+ if (library_provided(library_name)) {
+ pr_debug("iop-module: %s dependency on %s provided\n",
+ requesting_name, library_name);
+ continue;
+ }
+
+ pr_debug("iop-module: %s module depends on %s library version %u.%u\n",
+ requesting_name, library_name,
+ major_version(library->version),
+ minor_version(library->version));
+
+ err = iop_module_request_firmware(
+ library_name, library->version, NULL);
+ if (err < 0) {
+ pr_err("iop-module: %s dependency on %s failed to resolve with %d\n",
+ requesting_name, library_name, err);
+ return err;
+ }
+
+ pr_debug("iop-module: %s dependency on %s resolved\n",
+ requesting_name, library_name);
+ }
+
+ return 0;
+}
+
/**
* iop_module_request_firmware - link IOP module as firmware
* @name: name of requested module
@@ -669,8 +830,13 @@ static int iop_module_request_firmware(
goto err_incompatible;
}
+ err = iop_module_request_dependencies(ehdr, name);
+ if (err < 0)
+ goto err_dependency;
+
err = iop_module_link_buffer(fw->data, fw->size, arg);
+err_dependency:
err_incompatible:
err_identify:
err_request:
As a simplification it is assumed that if a ROM file provides the given library dependency, then the ROM file has been prelinked into the IOP. Hopefully, ROM file dependencies will be kept to a minimum, and new modules are instead tailored for Linux. Signed-off-by: Fredrik Noring <noring@nocrew.org> --- drivers/ps2/iop-module.c | 166 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 166 insertions(+)