aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/tidspbridge/pmgr/cod.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/tidspbridge/pmgr/cod.c')
-rw-r--r--drivers/staging/tidspbridge/pmgr/cod.c652
1 files changed, 652 insertions, 0 deletions
diff --git a/drivers/staging/tidspbridge/pmgr/cod.c b/drivers/staging/tidspbridge/pmgr/cod.c
new file mode 100644
index 000000000000..52989ab67cfb
--- /dev/null
+++ b/drivers/staging/tidspbridge/pmgr/cod.c
@@ -0,0 +1,652 @@
+/*
+ * cod.c
+ *
+ * DSP-BIOS Bridge driver support functions for TI OMAP processors.
+ *
+ * This module implements DSP code management for the DSP/BIOS Bridge
+ * environment. It is mostly a thin wrapper.
+ *
+ * This module provides an interface for loading both static and
+ * dynamic code objects onto DSP systems.
+ *
+ * Copyright (C) 2005-2006 Texas Instruments, Inc.
+ *
+ * This package is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include <linux/types.h>
+
+/* ----------------------------------- Host OS */
+#include <dspbridge/host_os.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+
+/* ----------------------------------- DSP/BIOS Bridge */
+#include <dspbridge/dbdefs.h>
+
+/* ----------------------------------- Trace & Debug */
+#include <dspbridge/dbc.h>
+
+/* ----------------------------------- OS Adaptation Layer */
+#include <dspbridge/ldr.h>
+
+/* ----------------------------------- Platform Manager */
+/* Include appropriate loader header file */
+#include <dspbridge/dbll.h>
+
+/* ----------------------------------- This */
+#include <dspbridge/cod.h>
+
+/*
+ * ======== cod_manager ========
+ */
+struct cod_manager {
+ struct dbll_tar_obj *target;
+ struct dbll_library_obj *base_lib;
+ bool loaded; /* Base library loaded? */
+ u32 ul_entry;
+ struct ldr_module *dll_obj;
+ struct dbll_fxns fxns;
+ struct dbll_attrs attrs;
+ char sz_zl_file[COD_MAXPATHLENGTH];
+};
+
+/*
+ * ======== cod_libraryobj ========
+ */
+struct cod_libraryobj {
+ struct dbll_library_obj *dbll_lib;
+ struct cod_manager *cod_mgr;
+};
+
+static u32 refs = 0L;
+
+static struct dbll_fxns ldr_fxns = {
+ (dbll_close_fxn) dbll_close,
+ (dbll_create_fxn) dbll_create,
+ (dbll_delete_fxn) dbll_delete,
+ (dbll_exit_fxn) dbll_exit,
+ (dbll_get_attrs_fxn) dbll_get_attrs,
+ (dbll_get_addr_fxn) dbll_get_addr,
+ (dbll_get_c_addr_fxn) dbll_get_c_addr,
+ (dbll_get_sect_fxn) dbll_get_sect,
+ (dbll_init_fxn) dbll_init,
+ (dbll_load_fxn) dbll_load,
+ (dbll_load_sect_fxn) dbll_load_sect,
+ (dbll_open_fxn) dbll_open,
+ (dbll_read_sect_fxn) dbll_read_sect,
+ (dbll_set_attrs_fxn) dbll_set_attrs,
+ (dbll_unload_fxn) dbll_unload,
+ (dbll_unload_sect_fxn) dbll_unload_sect,
+};
+
+static bool no_op(void);
+
+/*
+ * File operations (originally were under kfile.c)
+ */
+static s32 cod_f_close(struct file *filp)
+{
+ /* Check for valid handle */
+ if (!filp)
+ return -EFAULT;
+
+ filp_close(filp, NULL);
+
+ /* we can't use 0 here */
+ return 0;
+}
+
+static struct file *cod_f_open(const char *psz_file_name, const char *sz_mode)
+{
+ mm_segment_t fs;
+ struct file *filp;
+
+ fs = get_fs();
+ set_fs(get_ds());
+
+ /* ignore given mode and open file as read-only */
+ filp = filp_open(psz_file_name, O_RDONLY, 0);
+
+ if (IS_ERR(filp))
+ filp = NULL;
+
+ set_fs(fs);
+
+ return filp;
+}
+
+static s32 cod_f_read(void __user *pbuffer, s32 size, s32 count,
+ struct file *filp)
+{
+ /* check for valid file handle */
+ if (!filp)
+ return -EFAULT;
+
+ if ((size > 0) && (count > 0) && pbuffer) {
+ u32 dw_bytes_read;
+ mm_segment_t fs;
+
+ /* read from file */
+ fs = get_fs();
+ set_fs(get_ds());
+ dw_bytes_read = filp->f_op->read(filp, pbuffer, size * count,
+ &(filp->f_pos));
+ set_fs(fs);
+
+ if (!dw_bytes_read)
+ return -EBADF;
+
+ return dw_bytes_read / size;
+ }
+
+ return -EINVAL;
+}
+
+static s32 cod_f_seek(struct file *filp, s32 offset, s32 origin)
+{
+ loff_t dw_cur_pos;
+
+ /* check for valid file handle */
+ if (!filp)
+ return -EFAULT;
+
+ /* based on the origin flag, move the internal pointer */
+ dw_cur_pos = filp->f_op->llseek(filp, offset, origin);
+
+ if ((s32) dw_cur_pos < 0)
+ return -EPERM;
+
+ /* we can't use 0 here */
+ return 0;
+}
+
+static s32 cod_f_tell(struct file *filp)
+{
+ loff_t dw_cur_pos;
+
+ if (!filp)
+ return -EFAULT;
+
+ /* Get current position */
+ dw_cur_pos = filp->f_op->llseek(filp, 0, SEEK_CUR);
+
+ if ((s32) dw_cur_pos < 0)
+ return -EPERM;
+
+ return dw_cur_pos;
+}
+
+/*
+ * ======== cod_close ========
+ */
+void cod_close(struct cod_libraryobj *lib)
+{
+ struct cod_manager *hmgr;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(lib != NULL);
+ DBC_REQUIRE(lib->cod_mgr);
+
+ hmgr = lib->cod_mgr;
+ hmgr->fxns.close_fxn(lib->dbll_lib);
+
+ kfree(lib);
+}
+
+/*
+ * ======== cod_create ========
+ * Purpose:
+ * Create an object to manage code on a DSP system.
+ * This object can be used to load an initial program image with
+ * arguments that can later be expanded with
+ * dynamically loaded object files.
+ *
+ */
+int cod_create(struct cod_manager **mgr, char *str_zl_file,
+ const struct cod_attrs *attrs)
+{
+ struct cod_manager *mgr_new;
+ struct dbll_attrs zl_attrs;
+ int status = 0;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(mgr != NULL);
+
+ /* assume failure */
+ *mgr = NULL;
+
+ /* we don't support non-default attrs yet */
+ if (attrs != NULL)
+ return -ENOSYS;
+
+ mgr_new = kzalloc(sizeof(struct cod_manager), GFP_KERNEL);
+ if (mgr_new == NULL)
+ return -ENOMEM;
+
+ /* Set up loader functions */
+ mgr_new->fxns = ldr_fxns;
+
+ /* initialize the ZL module */
+ mgr_new->fxns.init_fxn();
+
+ zl_attrs.alloc = (dbll_alloc_fxn) no_op;
+ zl_attrs.free = (dbll_free_fxn) no_op;
+ zl_attrs.fread = (dbll_read_fxn) cod_f_read;
+ zl_attrs.fseek = (dbll_seek_fxn) cod_f_seek;
+ zl_attrs.ftell = (dbll_tell_fxn) cod_f_tell;
+ zl_attrs.fclose = (dbll_f_close_fxn) cod_f_close;
+ zl_attrs.fopen = (dbll_f_open_fxn) cod_f_open;
+ zl_attrs.sym_lookup = NULL;
+ zl_attrs.base_image = true;
+ zl_attrs.log_write = NULL;
+ zl_attrs.log_write_handle = NULL;
+ zl_attrs.write = NULL;
+ zl_attrs.rmm_handle = NULL;
+ zl_attrs.input_params = NULL;
+ zl_attrs.sym_handle = NULL;
+ zl_attrs.sym_arg = NULL;
+
+ mgr_new->attrs = zl_attrs;
+
+ status = mgr_new->fxns.create_fxn(&mgr_new->target, &zl_attrs);
+
+ if (status) {
+ cod_delete(mgr_new);
+ return -ESPIPE;
+ }
+
+ /* return the new manager */
+ *mgr = mgr_new;
+
+ return 0;
+}
+
+/*
+ * ======== cod_delete ========
+ * Purpose:
+ * Delete a code manager object.
+ */
+void cod_delete(struct cod_manager *cod_mgr_obj)
+{
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(cod_mgr_obj);
+
+ if (cod_mgr_obj->base_lib) {
+ if (cod_mgr_obj->loaded)
+ cod_mgr_obj->fxns.unload_fxn(cod_mgr_obj->base_lib,
+ &cod_mgr_obj->attrs);
+
+ cod_mgr_obj->fxns.close_fxn(cod_mgr_obj->base_lib);
+ }
+ if (cod_mgr_obj->target) {
+ cod_mgr_obj->fxns.delete_fxn(cod_mgr_obj->target);
+ cod_mgr_obj->fxns.exit_fxn();
+ }
+ kfree(cod_mgr_obj);
+}
+
+/*
+ * ======== cod_exit ========
+ * Purpose:
+ * Discontinue usage of the COD module.
+ *
+ */
+void cod_exit(void)
+{
+ DBC_REQUIRE(refs > 0);
+
+ refs--;
+
+ DBC_ENSURE(refs >= 0);
+}
+
+/*
+ * ======== cod_get_base_lib ========
+ * Purpose:
+ * Get handle to the base image DBL library.
+ */
+int cod_get_base_lib(struct cod_manager *cod_mgr_obj,
+ struct dbll_library_obj **plib)
+{
+ int status = 0;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(cod_mgr_obj);
+ DBC_REQUIRE(plib != NULL);
+
+ *plib = (struct dbll_library_obj *)cod_mgr_obj->base_lib;
+
+ return status;
+}
+
+/*
+ * ======== cod_get_base_name ========
+ */
+int cod_get_base_name(struct cod_manager *cod_mgr_obj, char *sz_name,
+ u32 usize)
+{
+ int status = 0;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(cod_mgr_obj);
+ DBC_REQUIRE(sz_name != NULL);
+
+ if (usize <= COD_MAXPATHLENGTH)
+ strncpy(sz_name, cod_mgr_obj->sz_zl_file, usize);
+ else
+ status = -EPERM;
+
+ return status;
+}
+
+/*
+ * ======== cod_get_entry ========
+ * Purpose:
+ * Retrieve the entry point of a loaded DSP program image
+ *
+ */
+int cod_get_entry(struct cod_manager *cod_mgr_obj, u32 *entry_pt)
+{
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(cod_mgr_obj);
+ DBC_REQUIRE(entry_pt != NULL);
+
+ *entry_pt = cod_mgr_obj->ul_entry;
+
+ return 0;
+}
+
+/*
+ * ======== cod_get_loader ========
+ * Purpose:
+ * Get handle to the DBLL loader.
+ */
+int cod_get_loader(struct cod_manager *cod_mgr_obj,
+ struct dbll_tar_obj **loader)
+{
+ int status = 0;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(cod_mgr_obj);
+ DBC_REQUIRE(loader != NULL);
+
+ *loader = (struct dbll_tar_obj *)cod_mgr_obj->target;
+
+ return status;
+}
+
+/*
+ * ======== cod_get_section ========
+ * Purpose:
+ * Retrieve the starting address and length of a section in the COFF file
+ * given the section name.
+ */
+int cod_get_section(struct cod_libraryobj *lib, char *str_sect,
+ u32 *addr, u32 *len)
+{
+ struct cod_manager *cod_mgr_obj;
+ int status = 0;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(lib != NULL);
+ DBC_REQUIRE(lib->cod_mgr);
+ DBC_REQUIRE(str_sect != NULL);
+ DBC_REQUIRE(addr != NULL);
+ DBC_REQUIRE(len != NULL);
+
+ *addr = 0;
+ *len = 0;
+ if (lib != NULL) {
+ cod_mgr_obj = lib->cod_mgr;
+ status = cod_mgr_obj->fxns.get_sect_fxn(lib->dbll_lib, str_sect,
+ addr, len);
+ } else {
+ status = -ESPIPE;
+ }
+
+ DBC_ENSURE(!status || ((*addr == 0) && (*len == 0)));
+
+ return status;
+}
+
+/*
+ * ======== cod_get_sym_value ========
+ * Purpose:
+ * Retrieve the value for the specified symbol. The symbol is first
+ * searched for literally and then, if not found, searched for as a
+ * C symbol.
+ *
+ */
+int cod_get_sym_value(struct cod_manager *cod_mgr_obj, char *str_sym,
+ u32 *pul_value)
+{
+ struct dbll_sym_val *dbll_sym;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(cod_mgr_obj);
+ DBC_REQUIRE(str_sym != NULL);
+ DBC_REQUIRE(pul_value != NULL);
+
+ dev_dbg(bridge, "%s: cod_mgr_obj: %p str_sym: %s pul_value: %p\n",
+ __func__, cod_mgr_obj, str_sym, pul_value);
+ if (cod_mgr_obj->base_lib) {
+ if (!cod_mgr_obj->fxns.
+ get_addr_fxn(cod_mgr_obj->base_lib, str_sym, &dbll_sym)) {
+ if (!cod_mgr_obj->fxns.
+ get_c_addr_fxn(cod_mgr_obj->base_lib, str_sym,
+ &dbll_sym))
+ return -ESPIPE;
+ }
+ } else {
+ return -ESPIPE;
+ }
+
+ *pul_value = dbll_sym->value;
+
+ return 0;
+}
+
+/*
+ * ======== cod_init ========
+ * Purpose:
+ * Initialize the COD module's private state.
+ *
+ */
+bool cod_init(void)
+{
+ bool ret = true;
+
+ DBC_REQUIRE(refs >= 0);
+
+ if (ret)
+ refs++;
+
+ DBC_ENSURE((ret && refs > 0) || (!ret && refs >= 0));
+ return ret;
+}
+
+/*
+ * ======== cod_load_base ========
+ * Purpose:
+ * Load the initial program image, optionally with command-line arguments,
+ * on the DSP system managed by the supplied handle. The program to be
+ * loaded must be the first element of the args array and must be a fully
+ * qualified pathname.
+ * Details:
+ * if num_argc doesn't match the number of arguments in the args array, the
+ * args array is searched for a NULL terminating entry, and argc is
+ * recalculated to reflect this. In this way, we can support NULL
+ * terminating args arrays, if num_argc is very large.
+ */
+int cod_load_base(struct cod_manager *cod_mgr_obj, u32 num_argc, char *args[],
+ cod_writefxn pfn_write, void *arb, char *envp[])
+{
+ dbll_flags flags;
+ struct dbll_attrs save_attrs;
+ struct dbll_attrs new_attrs;
+ int status;
+ u32 i;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(cod_mgr_obj);
+ DBC_REQUIRE(num_argc > 0);
+ DBC_REQUIRE(args != NULL);
+ DBC_REQUIRE(args[0] != NULL);
+ DBC_REQUIRE(pfn_write != NULL);
+ DBC_REQUIRE(cod_mgr_obj->base_lib != NULL);
+
+ /*
+ * Make sure every argv[] stated in argc has a value, or change argc to
+ * reflect true number in NULL terminated argv array.
+ */
+ for (i = 0; i < num_argc; i++) {
+ if (args[i] == NULL) {
+ num_argc = i;
+ break;
+ }
+ }
+
+ /* set the write function for this operation */
+ cod_mgr_obj->fxns.get_attrs_fxn(cod_mgr_obj->target, &save_attrs);
+
+ new_attrs = save_attrs;
+ new_attrs.write = (dbll_write_fxn) pfn_write;
+ new_attrs.input_params = arb;
+ new_attrs.alloc = (dbll_alloc_fxn) no_op;
+ new_attrs.free = (dbll_free_fxn) no_op;
+ new_attrs.log_write = NULL;
+ new_attrs.log_write_handle = NULL;
+
+ /* Load the image */
+ flags = DBLL_CODE | DBLL_DATA | DBLL_SYMB;
+ status = cod_mgr_obj->fxns.load_fxn(cod_mgr_obj->base_lib, flags,
+ &new_attrs,
+ &cod_mgr_obj->ul_entry);
+ if (status)
+ cod_mgr_obj->fxns.close_fxn(cod_mgr_obj->base_lib);
+
+ if (!status)
+ cod_mgr_obj->loaded = true;
+ else
+ cod_mgr_obj->base_lib = NULL;
+
+ return status;
+}
+
+/*
+ * ======== cod_open ========
+ * Open library for reading sections.
+ */
+int cod_open(struct cod_manager *hmgr, char *sz_coff_path,
+ u32 flags, struct cod_libraryobj **lib_obj)
+{
+ int status = 0;
+ struct cod_libraryobj *lib = NULL;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(hmgr);
+ DBC_REQUIRE(sz_coff_path != NULL);
+ DBC_REQUIRE(flags == COD_NOLOAD || flags == COD_SYMB);
+ DBC_REQUIRE(lib_obj != NULL);
+
+ *lib_obj = NULL;
+
+ lib = kzalloc(sizeof(struct cod_libraryobj), GFP_KERNEL);
+ if (lib == NULL)
+ status = -ENOMEM;
+
+ if (!status) {
+ lib->cod_mgr = hmgr;
+ status = hmgr->fxns.open_fxn(hmgr->target, sz_coff_path, flags,
+ &lib->dbll_lib);
+ if (!status)
+ *lib_obj = lib;
+ }
+
+ if (status)
+ pr_err("%s: error status 0x%x, sz_coff_path: %s flags: 0x%x\n",
+ __func__, status, sz_coff_path, flags);
+ return status;
+}
+
+/*
+ * ======== cod_open_base ========
+ * Purpose:
+ * Open base image for reading sections.
+ */
+int cod_open_base(struct cod_manager *hmgr, char *sz_coff_path,
+ dbll_flags flags)
+{
+ int status = 0;
+ struct dbll_library_obj *lib;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(hmgr);
+ DBC_REQUIRE(sz_coff_path != NULL);
+
+ /* if we previously opened a base image, close it now */
+ if (hmgr->base_lib) {
+ if (hmgr->loaded) {
+ hmgr->fxns.unload_fxn(hmgr->base_lib, &hmgr->attrs);
+ hmgr->loaded = false;
+ }
+ hmgr->fxns.close_fxn(hmgr->base_lib);
+ hmgr->base_lib = NULL;
+ }
+ status = hmgr->fxns.open_fxn(hmgr->target, sz_coff_path, flags, &lib);
+ if (!status) {
+ /* hang onto the library for subsequent sym table usage */
+ hmgr->base_lib = lib;
+ strncpy(hmgr->sz_zl_file, sz_coff_path, COD_MAXPATHLENGTH - 1);
+ hmgr->sz_zl_file[COD_MAXPATHLENGTH - 1] = '\0';
+ }
+
+ if (status)
+ pr_err("%s: error status 0x%x sz_coff_path: %s\n", __func__,
+ status, sz_coff_path);
+ return status;
+}
+
+/*
+ * ======== cod_read_section ========
+ * Purpose:
+ * Retrieve the content of a code section given the section name.
+ */
+int cod_read_section(struct cod_libraryobj *lib, char *str_sect,
+ char *str_content, u32 content_size)
+{
+ int status = 0;
+
+ DBC_REQUIRE(refs > 0);
+ DBC_REQUIRE(lib != NULL);
+ DBC_REQUIRE(lib->cod_mgr);
+ DBC_REQUIRE(str_sect != NULL);
+ DBC_REQUIRE(str_content != NULL);
+
+ if (lib != NULL)
+ status =
+ lib->cod_mgr->fxns.read_sect_fxn(lib->dbll_lib, str_sect,
+ str_content, content_size);
+ else
+ status = -ESPIPE;
+
+ return status;
+}
+
+/*
+ * ======== no_op ========
+ * Purpose:
+ * No Operation.
+ *
+ */
+static bool no_op(void)
+{
+ return true;
+}