kernel-ark/drivers/staging/tidspbridge/pmgr/cod.c
Rene Sapiens 13b18c29ec staging: ti dspbridge: Rename words with camel case.
The intention of this patch is to rename the remaining variables with camel
case. Variables will be renamed avoiding camel case and Hungarian notation.
The words to be renamed in this patch are:
========================================
pPhysAddr to phys_addr
pPhysicalAddress to physical_address
ppIntfFxns to if_fxns
pProcLoadStat to proc_load_stat
pProcStat to proc_lstat
ppSym to sym_val
pRefData to ref_data
pRef to ref
preservedBit to preserved_bit
pResult to result
procID to proc_id
pSectInfo to sect_inf
pSrc to src
pstrContent to str_content
pstrDummyFile to str_dummy_file
pstrExecFile to str_exec_file
========================================

Signed-off-by: Rene Sapiens <rene.sapiens@ti.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2010-07-22 10:45:36 -07:00

659 lines
15 KiB
C

/*
* 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.
*/
/* ----------------------------------- Host OS */
#include <dspbridge/host_os.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
/* ----------------------------------- DSP/BIOS Bridge */
#include <dspbridge/std.h>
#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>
/* magic number for handle validation */
#define MAGIC 0xc001beef
/* macro to validate COD manager handles */
#define IS_VALID(h) ((h) != NULL && (h)->ul_magic == MAGIC)
/*
* ======== 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];
u32 ul_magic;
};
/*
* ======== 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 *pszMode)
{
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(IS_VALID(((struct cod_libraryobj *)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(OUT struct cod_manager **mgr, char *str_dummy_file,
IN OPTIONAL 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;
mgr_new->ul_magic = MAGIC;
/* 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 (DSP_FAILED(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 *hmgr)
{
DBC_REQUIRE(refs > 0);
DBC_REQUIRE(IS_VALID(hmgr));
if (hmgr->base_lib) {
if (hmgr->loaded)
hmgr->fxns.unload_fxn(hmgr->base_lib, &hmgr->attrs);
hmgr->fxns.close_fxn(hmgr->base_lib);
}
if (hmgr->target) {
hmgr->fxns.delete_fxn(hmgr->target);
hmgr->fxns.exit_fxn();
}
hmgr->ul_magic = ~MAGIC;
kfree(hmgr);
}
/*
* ======== 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(IS_VALID(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 *pszName,
u32 usize)
{
int status = 0;
DBC_REQUIRE(refs > 0);
DBC_REQUIRE(IS_VALID(cod_mgr_obj));
DBC_REQUIRE(pszName != NULL);
if (usize <= COD_MAXPATHLENGTH)
strncpy(pszName, 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 *pulEntry)
{
DBC_REQUIRE(refs > 0);
DBC_REQUIRE(IS_VALID(cod_mgr_obj));
DBC_REQUIRE(pulEntry != NULL);
*pulEntry = 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(IS_VALID(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, IN char *pstrSect,
OUT u32 *puAddr, OUT u32 *puLen)
{
struct cod_manager *cod_mgr_obj;
int status = 0;
DBC_REQUIRE(refs > 0);
DBC_REQUIRE(lib != NULL);
DBC_REQUIRE(IS_VALID(lib->cod_mgr));
DBC_REQUIRE(pstrSect != NULL);
DBC_REQUIRE(puAddr != NULL);
DBC_REQUIRE(puLen != NULL);
*puAddr = 0;
*puLen = 0;
if (lib != NULL) {
cod_mgr_obj = lib->cod_mgr;
status = cod_mgr_obj->fxns.get_sect_fxn(lib->dbll_lib, pstrSect,
puAddr, puLen);
} else {
status = -ESPIPE;
}
DBC_ENSURE(DSP_SUCCEEDED(status) || ((*puAddr == 0) && (*puLen == 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 *hmgr, char *pstrSym,
u32 *pul_value)
{
struct dbll_sym_val *dbll_sym;
DBC_REQUIRE(refs > 0);
DBC_REQUIRE(IS_VALID(hmgr));
DBC_REQUIRE(pstrSym != NULL);
DBC_REQUIRE(pul_value != NULL);
dev_dbg(bridge, "%s: hmgr: %p pstrSym: %s pul_value: %p\n",
__func__, hmgr, pstrSym, pul_value);
if (hmgr->base_lib) {
if (!hmgr->fxns.
get_addr_fxn(hmgr->base_lib, pstrSym, &dbll_sym)) {
if (!hmgr->fxns.
get_c_addr_fxn(hmgr->base_lib, pstrSym, &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 *hmgr, 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(IS_VALID(hmgr));
DBC_REQUIRE(num_argc > 0);
DBC_REQUIRE(args != NULL);
DBC_REQUIRE(args[0] != NULL);
DBC_REQUIRE(pfn_write != NULL);
DBC_REQUIRE(hmgr->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 */
hmgr->fxns.get_attrs_fxn(hmgr->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 = hmgr->fxns.load_fxn(hmgr->base_lib, flags, &new_attrs,
&hmgr->ul_entry);
if (DSP_FAILED(status))
hmgr->fxns.close_fxn(hmgr->base_lib);
if (DSP_SUCCEEDED(status))
hmgr->loaded = true;
else
hmgr->base_lib = NULL;
return status;
}
/*
* ======== cod_open ========
* Open library for reading sections.
*/
int cod_open(struct cod_manager *hmgr, IN char *pszCoffPath,
u32 flags, struct cod_libraryobj **lib_obj)
{
int status = 0;
struct cod_libraryobj *lib = NULL;
DBC_REQUIRE(refs > 0);
DBC_REQUIRE(IS_VALID(hmgr));
DBC_REQUIRE(pszCoffPath != 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 (DSP_SUCCEEDED(status)) {
lib->cod_mgr = hmgr;
status = hmgr->fxns.open_fxn(hmgr->target, pszCoffPath, flags,
&lib->dbll_lib);
if (DSP_SUCCEEDED(status))
*lib_obj = lib;
}
if (DSP_FAILED(status))
pr_err("%s: error status 0x%x, pszCoffPath: %s flags: 0x%x\n",
__func__, status, pszCoffPath, flags);
return status;
}
/*
* ======== cod_open_base ========
* Purpose:
* Open base image for reading sections.
*/
int cod_open_base(struct cod_manager *hmgr, IN char *pszCoffPath,
dbll_flags flags)
{
int status = 0;
struct dbll_library_obj *lib;
DBC_REQUIRE(refs > 0);
DBC_REQUIRE(IS_VALID(hmgr));
DBC_REQUIRE(pszCoffPath != 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, pszCoffPath, flags, &lib);
if (DSP_SUCCEEDED(status)) {
/* hang onto the library for subsequent sym table usage */
hmgr->base_lib = lib;
strncpy(hmgr->sz_zl_file, pszCoffPath, COD_MAXPATHLENGTH - 1);
hmgr->sz_zl_file[COD_MAXPATHLENGTH - 1] = '\0';
}
if (DSP_FAILED(status))
pr_err("%s: error status 0x%x pszCoffPath: %s\n", __func__,
status, pszCoffPath);
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, IN char *pstrSect,
OUT char *str_content, IN u32 content_size)
{
int status = 0;
DBC_REQUIRE(refs > 0);
DBC_REQUIRE(lib != NULL);
DBC_REQUIRE(IS_VALID(lib->cod_mgr));
DBC_REQUIRE(pstrSect != NULL);
DBC_REQUIRE(str_content != NULL);
if (lib != NULL)
status =
lib->cod_mgr->fxns.read_sect_fxn(lib->dbll_lib, pstrSect,
str_content, content_size);
else
status = -ESPIPE;
return status;
}
/*
* ======== no_op ========
* Purpose:
* No Operation.
*
*/
static bool no_op(void)
{
return true;
}