1517 lines
38 KiB
C
1517 lines
38 KiB
C
/*
|
|
* dbdcd.c
|
|
*
|
|
* DSP-BIOS Bridge driver support functions for TI OMAP processors.
|
|
*
|
|
* This file contains the implementation of the DSP/BIOS Bridge
|
|
* Configuration Database (DCD).
|
|
*
|
|
* Notes:
|
|
* The fxn dcd_get_objects can apply a callback fxn to each DCD object
|
|
* that is located in a specified COFF file. At the moment,
|
|
* dcd_auto_register, dcd_auto_unregister, and NLDR module all use
|
|
* dcd_get_objects.
|
|
*
|
|
* 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>
|
|
|
|
/* ----------------------------------- DSP/BIOS Bridge */
|
|
#include <dspbridge/dbdefs.h>
|
|
/* ----------------------------------- Trace & Debug */
|
|
#include <dspbridge/dbc.h>
|
|
|
|
/* ----------------------------------- Platform Manager */
|
|
#include <dspbridge/cod.h>
|
|
|
|
/* ----------------------------------- Others */
|
|
#include <dspbridge/uuidutil.h>
|
|
|
|
/* ----------------------------------- This */
|
|
#include <dspbridge/dbdcd.h>
|
|
|
|
/* ----------------------------------- Global defines. */
|
|
#define MAX_INT2CHAR_LENGTH 16 /* Max int2char len of 32 bit int */
|
|
|
|
/* Name of section containing dependent libraries */
|
|
#define DEPLIBSECT ".dspbridge_deplibs"
|
|
|
|
/* DCD specific structures. */
|
|
struct dcd_manager {
|
|
struct cod_manager *cod_mgr; /* Handle to COD manager object. */
|
|
};
|
|
|
|
/* Pointer to the registry support key */
|
|
static struct list_head reg_key_list;
|
|
static DEFINE_SPINLOCK(dbdcd_lock);
|
|
|
|
/* Global reference variables. */
|
|
static u32 refs;
|
|
static u32 enum_refs;
|
|
|
|
/* Helper function prototypes. */
|
|
static s32 atoi(char *psz_buf);
|
|
static int get_attrs_from_buf(char *psz_buf, u32 ul_buf_size,
|
|
enum dsp_dcdobjtype obj_type,
|
|
struct dcd_genericobj *gen_obj);
|
|
static void compress_buf(char *psz_buf, u32 ul_buf_size, s32 char_size);
|
|
static char dsp_char2_gpp_char(char *word, s32 dsp_char_size);
|
|
static int get_dep_lib_info(struct dcd_manager *hdcd_mgr,
|
|
struct dsp_uuid *uuid_obj,
|
|
u16 *num_libs,
|
|
u16 *num_pers_libs,
|
|
struct dsp_uuid *dep_lib_uuids,
|
|
bool *prstnt_dep_libs,
|
|
enum nldr_phase phase);
|
|
|
|
/*
|
|
* ======== dcd_auto_register ========
|
|
* Purpose:
|
|
* Parses the supplied image and resigsters with DCD.
|
|
*/
|
|
int dcd_auto_register(struct dcd_manager *hdcd_mgr,
|
|
char *sz_coff_path)
|
|
{
|
|
int status = 0;
|
|
|
|
DBC_REQUIRE(refs > 0);
|
|
|
|
if (hdcd_mgr)
|
|
status = dcd_get_objects(hdcd_mgr, sz_coff_path,
|
|
(dcd_registerfxn) dcd_register_object,
|
|
(void *)sz_coff_path);
|
|
else
|
|
status = -EFAULT;
|
|
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
* ======== dcd_auto_unregister ========
|
|
* Purpose:
|
|
* Parses the supplied DSP image and unresiters from DCD.
|
|
*/
|
|
int dcd_auto_unregister(struct dcd_manager *hdcd_mgr,
|
|
char *sz_coff_path)
|
|
{
|
|
int status = 0;
|
|
|
|
DBC_REQUIRE(refs > 0);
|
|
|
|
if (hdcd_mgr)
|
|
status = dcd_get_objects(hdcd_mgr, sz_coff_path,
|
|
(dcd_registerfxn) dcd_register_object,
|
|
NULL);
|
|
else
|
|
status = -EFAULT;
|
|
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
* ======== dcd_create_manager ========
|
|
* Purpose:
|
|
* Creates DCD manager.
|
|
*/
|
|
int dcd_create_manager(char *sz_zl_dll_name,
|
|
struct dcd_manager **dcd_mgr)
|
|
{
|
|
struct cod_manager *cod_mgr; /* COD manager handle */
|
|
struct dcd_manager *dcd_mgr_obj = NULL; /* DCD Manager pointer */
|
|
int status = 0;
|
|
|
|
DBC_REQUIRE(refs >= 0);
|
|
DBC_REQUIRE(dcd_mgr);
|
|
|
|
status = cod_create(&cod_mgr, sz_zl_dll_name, NULL);
|
|
if (status)
|
|
goto func_end;
|
|
|
|
/* Create a DCD object. */
|
|
dcd_mgr_obj = kzalloc(sizeof(struct dcd_manager), GFP_KERNEL);
|
|
if (dcd_mgr_obj != NULL) {
|
|
/* Fill out the object. */
|
|
dcd_mgr_obj->cod_mgr = cod_mgr;
|
|
|
|
/* Return handle to this DCD interface. */
|
|
*dcd_mgr = dcd_mgr_obj;
|
|
} else {
|
|
status = -ENOMEM;
|
|
|
|
/*
|
|
* If allocation of DcdManager object failed, delete the
|
|
* COD manager.
|
|
*/
|
|
cod_delete(cod_mgr);
|
|
}
|
|
|
|
DBC_ENSURE((!status) ||
|
|
((dcd_mgr_obj == NULL) && (status == -ENOMEM)));
|
|
|
|
func_end:
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
* ======== dcd_destroy_manager ========
|
|
* Purpose:
|
|
* Frees DCD Manager object.
|
|
*/
|
|
int dcd_destroy_manager(struct dcd_manager *hdcd_mgr)
|
|
{
|
|
struct dcd_manager *dcd_mgr_obj = hdcd_mgr;
|
|
int status = -EFAULT;
|
|
|
|
DBC_REQUIRE(refs >= 0);
|
|
|
|
if (hdcd_mgr) {
|
|
/* Delete the COD manager. */
|
|
cod_delete(dcd_mgr_obj->cod_mgr);
|
|
|
|
/* Deallocate a DCD manager object. */
|
|
kfree(dcd_mgr_obj);
|
|
|
|
status = 0;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
* ======== dcd_enumerate_object ========
|
|
* Purpose:
|
|
* Enumerates objects in the DCD.
|
|
*/
|
|
int dcd_enumerate_object(s32 index, enum dsp_dcdobjtype obj_type,
|
|
struct dsp_uuid *uuid_obj)
|
|
{
|
|
int status = 0;
|
|
char sz_reg_key[DCD_MAXPATHLENGTH];
|
|
char sz_value[DCD_MAXPATHLENGTH];
|
|
struct dsp_uuid dsp_uuid_obj;
|
|
char sz_obj_type[MAX_INT2CHAR_LENGTH]; /* str. rep. of obj_type. */
|
|
u32 dw_key_len = 0;
|
|
struct dcd_key_elem *dcd_key;
|
|
int len;
|
|
|
|
DBC_REQUIRE(refs >= 0);
|
|
DBC_REQUIRE(index >= 0);
|
|
DBC_REQUIRE(uuid_obj != NULL);
|
|
|
|
if ((index != 0) && (enum_refs == 0)) {
|
|
/*
|
|
* If an enumeration is being performed on an index greater
|
|
* than zero, then the current enum_refs must have been
|
|
* incremented to greater than zero.
|
|
*/
|
|
status = -EIDRM;
|
|
} else {
|
|
/*
|
|
* Pre-determine final key length. It's length of DCD_REGKEY +
|
|
* "_\0" + length of sz_obj_type string + terminating NULL.
|
|
*/
|
|
dw_key_len = strlen(DCD_REGKEY) + 1 + sizeof(sz_obj_type) + 1;
|
|
DBC_ASSERT(dw_key_len < DCD_MAXPATHLENGTH);
|
|
|
|
/* Create proper REG key; concatenate DCD_REGKEY with
|
|
* obj_type. */
|
|
strncpy(sz_reg_key, DCD_REGKEY, strlen(DCD_REGKEY) + 1);
|
|
if ((strlen(sz_reg_key) + strlen("_\0")) <
|
|
DCD_MAXPATHLENGTH) {
|
|
strncat(sz_reg_key, "_\0", 2);
|
|
} else {
|
|
status = -EPERM;
|
|
}
|
|
|
|
/* This snprintf is guaranteed not to exceed max size of an
|
|
* integer. */
|
|
status = snprintf(sz_obj_type, MAX_INT2CHAR_LENGTH, "%d",
|
|
obj_type);
|
|
|
|
if (status == -1) {
|
|
status = -EPERM;
|
|
} else {
|
|
status = 0;
|
|
if ((strlen(sz_reg_key) + strlen(sz_obj_type)) <
|
|
DCD_MAXPATHLENGTH) {
|
|
strncat(sz_reg_key, sz_obj_type,
|
|
strlen(sz_obj_type) + 1);
|
|
} else {
|
|
status = -EPERM;
|
|
}
|
|
}
|
|
|
|
if (!status) {
|
|
len = strlen(sz_reg_key);
|
|
spin_lock(&dbdcd_lock);
|
|
list_for_each_entry(dcd_key, ®_key_list, link) {
|
|
if (!strncmp(dcd_key->name, sz_reg_key, len)
|
|
&& !index--) {
|
|
strncpy(sz_value, &dcd_key->name[len],
|
|
strlen(&dcd_key->name[len]) + 1);
|
|
break;
|
|
}
|
|
}
|
|
spin_unlock(&dbdcd_lock);
|
|
|
|
if (&dcd_key->link == ®_key_list)
|
|
status = -ENODATA;
|
|
}
|
|
|
|
if (!status) {
|
|
/* Create UUID value using string retrieved from
|
|
* registry. */
|
|
uuid_uuid_from_string(sz_value, &dsp_uuid_obj);
|
|
|
|
*uuid_obj = dsp_uuid_obj;
|
|
|
|
/* Increment enum_refs to update reference count. */
|
|
enum_refs++;
|
|
|
|
status = 0;
|
|
} else if (status == -ENODATA) {
|
|
/* At the end of enumeration. Reset enum_refs. */
|
|
enum_refs = 0;
|
|
|
|
/*
|
|
* TODO: Revisit, this is not an errror case but code
|
|
* expects non-zero value.
|
|
*/
|
|
status = ENODATA;
|
|
} else {
|
|
status = -EPERM;
|
|
}
|
|
}
|
|
|
|
DBC_ENSURE(uuid_obj || (status == -EPERM));
|
|
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
* ======== dcd_exit ========
|
|
* Purpose:
|
|
* Discontinue usage of the DCD module.
|
|
*/
|
|
void dcd_exit(void)
|
|
{
|
|
struct dcd_key_elem *rv, *rv_tmp;
|
|
DBC_REQUIRE(refs > 0);
|
|
|
|
refs--;
|
|
if (refs == 0) {
|
|
cod_exit();
|
|
list_for_each_entry_safe(rv, rv_tmp, ®_key_list, link) {
|
|
list_del(&rv->link);
|
|
kfree(rv->path);
|
|
kfree(rv);
|
|
}
|
|
}
|
|
|
|
DBC_ENSURE(refs >= 0);
|
|
}
|
|
|
|
/*
|
|
* ======== dcd_get_dep_libs ========
|
|
*/
|
|
int dcd_get_dep_libs(struct dcd_manager *hdcd_mgr,
|
|
struct dsp_uuid *uuid_obj,
|
|
u16 num_libs, struct dsp_uuid *dep_lib_uuids,
|
|
bool *prstnt_dep_libs,
|
|
enum nldr_phase phase)
|
|
{
|
|
int status = 0;
|
|
|
|
DBC_REQUIRE(refs > 0);
|
|
DBC_REQUIRE(hdcd_mgr);
|
|
DBC_REQUIRE(uuid_obj != NULL);
|
|
DBC_REQUIRE(dep_lib_uuids != NULL);
|
|
DBC_REQUIRE(prstnt_dep_libs != NULL);
|
|
|
|
status =
|
|
get_dep_lib_info(hdcd_mgr, uuid_obj, &num_libs, NULL, dep_lib_uuids,
|
|
prstnt_dep_libs, phase);
|
|
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
* ======== dcd_get_num_dep_libs ========
|
|
*/
|
|
int dcd_get_num_dep_libs(struct dcd_manager *hdcd_mgr,
|
|
struct dsp_uuid *uuid_obj,
|
|
u16 *num_libs, u16 *num_pers_libs,
|
|
enum nldr_phase phase)
|
|
{
|
|
int status = 0;
|
|
|
|
DBC_REQUIRE(refs > 0);
|
|
DBC_REQUIRE(hdcd_mgr);
|
|
DBC_REQUIRE(num_libs != NULL);
|
|
DBC_REQUIRE(num_pers_libs != NULL);
|
|
DBC_REQUIRE(uuid_obj != NULL);
|
|
|
|
status = get_dep_lib_info(hdcd_mgr, uuid_obj, num_libs, num_pers_libs,
|
|
NULL, NULL, phase);
|
|
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
* ======== dcd_get_object_def ========
|
|
* Purpose:
|
|
* Retrieves the properties of a node or processor based on the UUID and
|
|
* object type.
|
|
*/
|
|
int dcd_get_object_def(struct dcd_manager *hdcd_mgr,
|
|
struct dsp_uuid *obj_uuid,
|
|
enum dsp_dcdobjtype obj_type,
|
|
struct dcd_genericobj *obj_def)
|
|
{
|
|
struct dcd_manager *dcd_mgr_obj = hdcd_mgr; /* ptr to DCD mgr */
|
|
struct cod_libraryobj *lib = NULL;
|
|
int status = 0;
|
|
u32 ul_addr = 0; /* Used by cod_get_section */
|
|
u32 ul_len = 0; /* Used by cod_get_section */
|
|
u32 dw_buf_size; /* Used by REG functions */
|
|
char sz_reg_key[DCD_MAXPATHLENGTH];
|
|
char *sz_uuid; /*[MAXUUIDLEN]; */
|
|
struct dcd_key_elem *dcd_key = NULL;
|
|
char sz_sect_name[MAXUUIDLEN + 2]; /* ".[UUID]\0" */
|
|
char *psz_coff_buf;
|
|
u32 dw_key_len; /* Len of REG key. */
|
|
char sz_obj_type[MAX_INT2CHAR_LENGTH]; /* str. rep. of obj_type. */
|
|
|
|
DBC_REQUIRE(refs > 0);
|
|
DBC_REQUIRE(obj_def != NULL);
|
|
DBC_REQUIRE(obj_uuid != NULL);
|
|
|
|
sz_uuid = kzalloc(MAXUUIDLEN, GFP_KERNEL);
|
|
if (!sz_uuid) {
|
|
status = -ENOMEM;
|
|
goto func_end;
|
|
}
|
|
|
|
if (!hdcd_mgr) {
|
|
status = -EFAULT;
|
|
goto func_end;
|
|
}
|
|
|
|
/* Pre-determine final key length. It's length of DCD_REGKEY +
|
|
* "_\0" + length of sz_obj_type string + terminating NULL */
|
|
dw_key_len = strlen(DCD_REGKEY) + 1 + sizeof(sz_obj_type) + 1;
|
|
DBC_ASSERT(dw_key_len < DCD_MAXPATHLENGTH);
|
|
|
|
/* Create proper REG key; concatenate DCD_REGKEY with obj_type. */
|
|
strncpy(sz_reg_key, DCD_REGKEY, strlen(DCD_REGKEY) + 1);
|
|
|
|
if ((strlen(sz_reg_key) + strlen("_\0")) < DCD_MAXPATHLENGTH)
|
|
strncat(sz_reg_key, "_\0", 2);
|
|
else
|
|
status = -EPERM;
|
|
|
|
status = snprintf(sz_obj_type, MAX_INT2CHAR_LENGTH, "%d", obj_type);
|
|
if (status == -1) {
|
|
status = -EPERM;
|
|
} else {
|
|
status = 0;
|
|
|
|
if ((strlen(sz_reg_key) + strlen(sz_obj_type)) <
|
|
DCD_MAXPATHLENGTH) {
|
|
strncat(sz_reg_key, sz_obj_type,
|
|
strlen(sz_obj_type) + 1);
|
|
} else {
|
|
status = -EPERM;
|
|
}
|
|
|
|
/* Create UUID value to set in registry. */
|
|
uuid_uuid_to_string(obj_uuid, sz_uuid, MAXUUIDLEN);
|
|
|
|
if ((strlen(sz_reg_key) + MAXUUIDLEN) < DCD_MAXPATHLENGTH)
|
|
strncat(sz_reg_key, sz_uuid, MAXUUIDLEN);
|
|
else
|
|
status = -EPERM;
|
|
|
|
/* Retrieve paths from the registry based on struct dsp_uuid */
|
|
dw_buf_size = DCD_MAXPATHLENGTH;
|
|
}
|
|
if (!status) {
|
|
spin_lock(&dbdcd_lock);
|
|
list_for_each_entry(dcd_key, ®_key_list, link) {
|
|
if (!strncmp(dcd_key->name, sz_reg_key,
|
|
strlen(sz_reg_key) + 1))
|
|
break;
|
|
}
|
|
spin_unlock(&dbdcd_lock);
|
|
if (&dcd_key->link == ®_key_list) {
|
|
status = -ENOKEY;
|
|
goto func_end;
|
|
}
|
|
}
|
|
|
|
|
|
/* Open COFF file. */
|
|
status = cod_open(dcd_mgr_obj->cod_mgr, dcd_key->path,
|
|
COD_NOLOAD, &lib);
|
|
if (status) {
|
|
status = -EACCES;
|
|
goto func_end;
|
|
}
|
|
|
|
/* Ensure sz_uuid + 1 is not greater than sizeof sz_sect_name. */
|
|
DBC_ASSERT((strlen(sz_uuid) + 1) < sizeof(sz_sect_name));
|
|
|
|
/* Create section name based on node UUID. A period is
|
|
* pre-pended to the UUID string to form the section name.
|
|
* I.e. ".24BC8D90_BB45_11d4_B756_006008BDB66F" */
|
|
strncpy(sz_sect_name, ".", 2);
|
|
strncat(sz_sect_name, sz_uuid, strlen(sz_uuid));
|
|
|
|
/* Get section information. */
|
|
status = cod_get_section(lib, sz_sect_name, &ul_addr, &ul_len);
|
|
if (status) {
|
|
status = -EACCES;
|
|
goto func_end;
|
|
}
|
|
|
|
/* Allocate zeroed buffer. */
|
|
psz_coff_buf = kzalloc(ul_len + 4, GFP_KERNEL);
|
|
if (psz_coff_buf == NULL) {
|
|
status = -ENOMEM;
|
|
goto func_end;
|
|
}
|
|
#ifdef _DB_TIOMAP
|
|
if (strstr(dcd_key->path, "iva") == NULL) {
|
|
/* Locate section by objectID and read its content. */
|
|
status =
|
|
cod_read_section(lib, sz_sect_name, psz_coff_buf, ul_len);
|
|
} else {
|
|
status =
|
|
cod_read_section(lib, sz_sect_name, psz_coff_buf, ul_len);
|
|
dev_dbg(bridge, "%s: Skipped Byte swap for IVA!!\n", __func__);
|
|
}
|
|
#else
|
|
status = cod_read_section(lib, sz_sect_name, psz_coff_buf, ul_len);
|
|
#endif
|
|
if (!status) {
|
|
/* Compres DSP buffer to conform to PC format. */
|
|
if (strstr(dcd_key->path, "iva") == NULL) {
|
|
compress_buf(psz_coff_buf, ul_len, DSPWORDSIZE);
|
|
} else {
|
|
compress_buf(psz_coff_buf, ul_len, 1);
|
|
dev_dbg(bridge, "%s: Compressing IVA COFF buffer by 1 "
|
|
"for IVA!!\n", __func__);
|
|
}
|
|
|
|
/* Parse the content of the COFF buffer. */
|
|
status =
|
|
get_attrs_from_buf(psz_coff_buf, ul_len, obj_type, obj_def);
|
|
if (status)
|
|
status = -EACCES;
|
|
} else {
|
|
status = -EACCES;
|
|
}
|
|
|
|
/* Free the previously allocated dynamic buffer. */
|
|
kfree(psz_coff_buf);
|
|
func_end:
|
|
if (lib)
|
|
cod_close(lib);
|
|
|
|
kfree(sz_uuid);
|
|
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
* ======== dcd_get_objects ========
|
|
*/
|
|
int dcd_get_objects(struct dcd_manager *hdcd_mgr,
|
|
char *sz_coff_path, dcd_registerfxn register_fxn,
|
|
void *handle)
|
|
{
|
|
struct dcd_manager *dcd_mgr_obj = hdcd_mgr;
|
|
int status = 0;
|
|
char *psz_coff_buf;
|
|
char *psz_cur;
|
|
struct cod_libraryobj *lib = NULL;
|
|
u32 ul_addr = 0; /* Used by cod_get_section */
|
|
u32 ul_len = 0; /* Used by cod_get_section */
|
|
char seps[] = ":, ";
|
|
char *token = NULL;
|
|
struct dsp_uuid dsp_uuid_obj;
|
|
s32 object_type;
|
|
|
|
DBC_REQUIRE(refs > 0);
|
|
if (!hdcd_mgr) {
|
|
status = -EFAULT;
|
|
goto func_end;
|
|
}
|
|
|
|
/* Open DSP coff file, don't load symbols. */
|
|
status = cod_open(dcd_mgr_obj->cod_mgr, sz_coff_path, COD_NOLOAD, &lib);
|
|
if (status) {
|
|
status = -EACCES;
|
|
goto func_cont;
|
|
}
|
|
|
|
/* Get DCD_RESIGER_SECTION section information. */
|
|
status = cod_get_section(lib, DCD_REGISTER_SECTION, &ul_addr, &ul_len);
|
|
if (status || !(ul_len > 0)) {
|
|
status = -EACCES;
|
|
goto func_cont;
|
|
}
|
|
|
|
/* Allocate zeroed buffer. */
|
|
psz_coff_buf = kzalloc(ul_len + 4, GFP_KERNEL);
|
|
if (psz_coff_buf == NULL) {
|
|
status = -ENOMEM;
|
|
goto func_cont;
|
|
}
|
|
#ifdef _DB_TIOMAP
|
|
if (strstr(sz_coff_path, "iva") == NULL) {
|
|
/* Locate section by objectID and read its content. */
|
|
status = cod_read_section(lib, DCD_REGISTER_SECTION,
|
|
psz_coff_buf, ul_len);
|
|
} else {
|
|
dev_dbg(bridge, "%s: Skipped Byte swap for IVA!!\n", __func__);
|
|
status = cod_read_section(lib, DCD_REGISTER_SECTION,
|
|
psz_coff_buf, ul_len);
|
|
}
|
|
#else
|
|
status =
|
|
cod_read_section(lib, DCD_REGISTER_SECTION, psz_coff_buf, ul_len);
|
|
#endif
|
|
if (!status) {
|
|
/* Compress DSP buffer to conform to PC format. */
|
|
if (strstr(sz_coff_path, "iva") == NULL) {
|
|
compress_buf(psz_coff_buf, ul_len, DSPWORDSIZE);
|
|
} else {
|
|
compress_buf(psz_coff_buf, ul_len, 1);
|
|
dev_dbg(bridge, "%s: Compress COFF buffer with 1 word "
|
|
"for IVA!!\n", __func__);
|
|
}
|
|
|
|
/* Read from buffer and register object in buffer. */
|
|
psz_cur = psz_coff_buf;
|
|
while ((token = strsep(&psz_cur, seps)) && *token != '\0') {
|
|
/* Retrieve UUID string. */
|
|
uuid_uuid_from_string(token, &dsp_uuid_obj);
|
|
|
|
/* Retrieve object type */
|
|
token = strsep(&psz_cur, seps);
|
|
|
|
/* Retrieve object type */
|
|
object_type = atoi(token);
|
|
|
|
/*
|
|
* Apply register_fxn to the found DCD object.
|
|
* Possible actions include:
|
|
*
|
|
* 1) Register found DCD object.
|
|
* 2) Unregister found DCD object (when handle == NULL)
|
|
* 3) Add overlay node.
|
|
*/
|
|
status =
|
|
register_fxn(&dsp_uuid_obj, object_type, handle);
|
|
if (status) {
|
|
/* if error occurs, break from while loop. */
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
status = -EACCES;
|
|
}
|
|
|
|
/* Free the previously allocated dynamic buffer. */
|
|
kfree(psz_coff_buf);
|
|
func_cont:
|
|
if (lib)
|
|
cod_close(lib);
|
|
|
|
func_end:
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
* ======== dcd_get_library_name ========
|
|
* Purpose:
|
|
* Retrieves the library name for the given UUID.
|
|
*
|
|
*/
|
|
int dcd_get_library_name(struct dcd_manager *hdcd_mgr,
|
|
struct dsp_uuid *uuid_obj,
|
|
char *str_lib_name,
|
|
u32 *buff_size,
|
|
enum nldr_phase phase, bool *phase_split)
|
|
{
|
|
char sz_reg_key[DCD_MAXPATHLENGTH];
|
|
char sz_uuid[MAXUUIDLEN];
|
|
u32 dw_key_len; /* Len of REG key. */
|
|
char sz_obj_type[MAX_INT2CHAR_LENGTH]; /* str. rep. of obj_type. */
|
|
int status = 0;
|
|
struct dcd_key_elem *dcd_key = NULL;
|
|
|
|
DBC_REQUIRE(uuid_obj != NULL);
|
|
DBC_REQUIRE(str_lib_name != NULL);
|
|
DBC_REQUIRE(buff_size != NULL);
|
|
DBC_REQUIRE(hdcd_mgr);
|
|
|
|
dev_dbg(bridge, "%s: hdcd_mgr %p, uuid_obj %p, str_lib_name %p,"
|
|
" buff_size %p\n", __func__, hdcd_mgr, uuid_obj, str_lib_name,
|
|
buff_size);
|
|
|
|
/*
|
|
* Pre-determine final key length. It's length of DCD_REGKEY +
|
|
* "_\0" + length of sz_obj_type string + terminating NULL.
|
|
*/
|
|
dw_key_len = strlen(DCD_REGKEY) + 1 + sizeof(sz_obj_type) + 1;
|
|
DBC_ASSERT(dw_key_len < DCD_MAXPATHLENGTH);
|
|
|
|
/* Create proper REG key; concatenate DCD_REGKEY with obj_type. */
|
|
strncpy(sz_reg_key, DCD_REGKEY, strlen(DCD_REGKEY) + 1);
|
|
if ((strlen(sz_reg_key) + strlen("_\0")) < DCD_MAXPATHLENGTH)
|
|
strncat(sz_reg_key, "_\0", 2);
|
|
else
|
|
status = -EPERM;
|
|
|
|
switch (phase) {
|
|
case NLDR_CREATE:
|
|
/* create phase type */
|
|
sprintf(sz_obj_type, "%d", DSP_DCDCREATELIBTYPE);
|
|
break;
|
|
case NLDR_EXECUTE:
|
|
/* execute phase type */
|
|
sprintf(sz_obj_type, "%d", DSP_DCDEXECUTELIBTYPE);
|
|
break;
|
|
case NLDR_DELETE:
|
|
/* delete phase type */
|
|
sprintf(sz_obj_type, "%d", DSP_DCDDELETELIBTYPE);
|
|
break;
|
|
case NLDR_NOPHASE:
|
|
/* known to be a dependent library */
|
|
sprintf(sz_obj_type, "%d", DSP_DCDLIBRARYTYPE);
|
|
break;
|
|
default:
|
|
status = -EINVAL;
|
|
DBC_ASSERT(false);
|
|
}
|
|
if (!status) {
|
|
if ((strlen(sz_reg_key) + strlen(sz_obj_type)) <
|
|
DCD_MAXPATHLENGTH) {
|
|
strncat(sz_reg_key, sz_obj_type,
|
|
strlen(sz_obj_type) + 1);
|
|
} else {
|
|
status = -EPERM;
|
|
}
|
|
/* Create UUID value to find match in registry. */
|
|
uuid_uuid_to_string(uuid_obj, sz_uuid, MAXUUIDLEN);
|
|
if ((strlen(sz_reg_key) + MAXUUIDLEN) < DCD_MAXPATHLENGTH)
|
|
strncat(sz_reg_key, sz_uuid, MAXUUIDLEN);
|
|
else
|
|
status = -EPERM;
|
|
}
|
|
if (!status) {
|
|
spin_lock(&dbdcd_lock);
|
|
list_for_each_entry(dcd_key, ®_key_list, link) {
|
|
/* See if the name matches. */
|
|
if (!strncmp(dcd_key->name, sz_reg_key,
|
|
strlen(sz_reg_key) + 1))
|
|
break;
|
|
}
|
|
spin_unlock(&dbdcd_lock);
|
|
}
|
|
|
|
if (&dcd_key->link == ®_key_list)
|
|
status = -ENOKEY;
|
|
|
|
/* If can't find, phases might be registered as generic LIBRARYTYPE */
|
|
if (status && phase != NLDR_NOPHASE) {
|
|
if (phase_split)
|
|
*phase_split = false;
|
|
|
|
strncpy(sz_reg_key, DCD_REGKEY, strlen(DCD_REGKEY) + 1);
|
|
if ((strlen(sz_reg_key) + strlen("_\0")) <
|
|
DCD_MAXPATHLENGTH) {
|
|
strncat(sz_reg_key, "_\0", 2);
|
|
} else {
|
|
status = -EPERM;
|
|
}
|
|
sprintf(sz_obj_type, "%d", DSP_DCDLIBRARYTYPE);
|
|
if ((strlen(sz_reg_key) + strlen(sz_obj_type))
|
|
< DCD_MAXPATHLENGTH) {
|
|
strncat(sz_reg_key, sz_obj_type,
|
|
strlen(sz_obj_type) + 1);
|
|
} else {
|
|
status = -EPERM;
|
|
}
|
|
uuid_uuid_to_string(uuid_obj, sz_uuid, MAXUUIDLEN);
|
|
if ((strlen(sz_reg_key) + MAXUUIDLEN) < DCD_MAXPATHLENGTH)
|
|
strncat(sz_reg_key, sz_uuid, MAXUUIDLEN);
|
|
else
|
|
status = -EPERM;
|
|
|
|
spin_lock(&dbdcd_lock);
|
|
list_for_each_entry(dcd_key, ®_key_list, link) {
|
|
/* See if the name matches. */
|
|
if (!strncmp(dcd_key->name, sz_reg_key,
|
|
strlen(sz_reg_key) + 1))
|
|
break;
|
|
}
|
|
spin_unlock(&dbdcd_lock);
|
|
|
|
status = (&dcd_key->link != ®_key_list) ?
|
|
0 : -ENOKEY;
|
|
}
|
|
|
|
if (!status)
|
|
memcpy(str_lib_name, dcd_key->path, strlen(dcd_key->path) + 1);
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
* ======== dcd_init ========
|
|
* Purpose:
|
|
* Initialize the DCD module.
|
|
*/
|
|
bool dcd_init(void)
|
|
{
|
|
bool init_cod;
|
|
bool ret = true;
|
|
|
|
DBC_REQUIRE(refs >= 0);
|
|
|
|
if (refs == 0) {
|
|
/* Initialize required modules. */
|
|
init_cod = cod_init();
|
|
|
|
if (!init_cod) {
|
|
ret = false;
|
|
/* Exit initialized modules. */
|
|
if (init_cod)
|
|
cod_exit();
|
|
}
|
|
|
|
INIT_LIST_HEAD(®_key_list);
|
|
}
|
|
|
|
if (ret)
|
|
refs++;
|
|
|
|
DBC_ENSURE((ret && (refs > 0)) || (!ret && (refs == 0)));
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* ======== dcd_register_object ========
|
|
* Purpose:
|
|
* Registers a node or a processor with the DCD.
|
|
* If psz_path_name == NULL, unregister the specified DCD object.
|
|
*/
|
|
int dcd_register_object(struct dsp_uuid *uuid_obj,
|
|
enum dsp_dcdobjtype obj_type,
|
|
char *psz_path_name)
|
|
{
|
|
int status = 0;
|
|
char sz_reg_key[DCD_MAXPATHLENGTH];
|
|
char sz_uuid[MAXUUIDLEN + 1];
|
|
u32 dw_path_size = 0;
|
|
u32 dw_key_len; /* Len of REG key. */
|
|
char sz_obj_type[MAX_INT2CHAR_LENGTH]; /* str. rep. of obj_type. */
|
|
struct dcd_key_elem *dcd_key = NULL;
|
|
|
|
DBC_REQUIRE(refs > 0);
|
|
DBC_REQUIRE(uuid_obj != NULL);
|
|
DBC_REQUIRE((obj_type == DSP_DCDNODETYPE) ||
|
|
(obj_type == DSP_DCDPROCESSORTYPE) ||
|
|
(obj_type == DSP_DCDLIBRARYTYPE) ||
|
|
(obj_type == DSP_DCDCREATELIBTYPE) ||
|
|
(obj_type == DSP_DCDEXECUTELIBTYPE) ||
|
|
(obj_type == DSP_DCDDELETELIBTYPE));
|
|
|
|
dev_dbg(bridge, "%s: object UUID %p, obj_type %d, szPathName %s\n",
|
|
__func__, uuid_obj, obj_type, psz_path_name);
|
|
|
|
/*
|
|
* Pre-determine final key length. It's length of DCD_REGKEY +
|
|
* "_\0" + length of sz_obj_type string + terminating NULL.
|
|
*/
|
|
dw_key_len = strlen(DCD_REGKEY) + 1 + sizeof(sz_obj_type) + 1;
|
|
DBC_ASSERT(dw_key_len < DCD_MAXPATHLENGTH);
|
|
|
|
/* Create proper REG key; concatenate DCD_REGKEY with obj_type. */
|
|
strncpy(sz_reg_key, DCD_REGKEY, strlen(DCD_REGKEY) + 1);
|
|
if ((strlen(sz_reg_key) + strlen("_\0")) < DCD_MAXPATHLENGTH)
|
|
strncat(sz_reg_key, "_\0", 2);
|
|
else {
|
|
status = -EPERM;
|
|
goto func_end;
|
|
}
|
|
|
|
status = snprintf(sz_obj_type, MAX_INT2CHAR_LENGTH, "%d", obj_type);
|
|
if (status == -1) {
|
|
status = -EPERM;
|
|
} else {
|
|
status = 0;
|
|
if ((strlen(sz_reg_key) + strlen(sz_obj_type)) <
|
|
DCD_MAXPATHLENGTH) {
|
|
strncat(sz_reg_key, sz_obj_type,
|
|
strlen(sz_obj_type) + 1);
|
|
} else
|
|
status = -EPERM;
|
|
|
|
/* Create UUID value to set in registry. */
|
|
uuid_uuid_to_string(uuid_obj, sz_uuid, MAXUUIDLEN);
|
|
if ((strlen(sz_reg_key) + MAXUUIDLEN) < DCD_MAXPATHLENGTH)
|
|
strncat(sz_reg_key, sz_uuid, MAXUUIDLEN);
|
|
else
|
|
status = -EPERM;
|
|
}
|
|
|
|
if (status)
|
|
goto func_end;
|
|
|
|
/*
|
|
* If psz_path_name != NULL, perform registration, otherwise,
|
|
* perform unregistration.
|
|
*/
|
|
|
|
if (psz_path_name) {
|
|
dw_path_size = strlen(psz_path_name) + 1;
|
|
spin_lock(&dbdcd_lock);
|
|
list_for_each_entry(dcd_key, ®_key_list, link) {
|
|
/* See if the name matches. */
|
|
if (!strncmp(dcd_key->name, sz_reg_key,
|
|
strlen(sz_reg_key) + 1))
|
|
break;
|
|
}
|
|
spin_unlock(&dbdcd_lock);
|
|
if (&dcd_key->link == ®_key_list) {
|
|
/*
|
|
* Add new reg value (UUID+obj_type)
|
|
* with COFF path info
|
|
*/
|
|
|
|
dcd_key = kmalloc(sizeof(struct dcd_key_elem),
|
|
GFP_KERNEL);
|
|
if (!dcd_key) {
|
|
status = -ENOMEM;
|
|
goto func_end;
|
|
}
|
|
|
|
dcd_key->path = kmalloc(strlen(sz_reg_key) + 1,
|
|
GFP_KERNEL);
|
|
|
|
if (!dcd_key->path) {
|
|
kfree(dcd_key);
|
|
status = -ENOMEM;
|
|
goto func_end;
|
|
}
|
|
|
|
strncpy(dcd_key->name, sz_reg_key,
|
|
strlen(sz_reg_key) + 1);
|
|
strncpy(dcd_key->path, psz_path_name ,
|
|
dw_path_size);
|
|
spin_lock(&dbdcd_lock);
|
|
list_add_tail(&dcd_key->link, ®_key_list);
|
|
spin_unlock(&dbdcd_lock);
|
|
} else {
|
|
/* Make sure the new data is the same. */
|
|
if (strncmp(dcd_key->path, psz_path_name,
|
|
dw_path_size)) {
|
|
/* The caller needs a different data size! */
|
|
kfree(dcd_key->path);
|
|
dcd_key->path = kmalloc(dw_path_size,
|
|
GFP_KERNEL);
|
|
if (dcd_key->path == NULL) {
|
|
status = -ENOMEM;
|
|
goto func_end;
|
|
}
|
|
}
|
|
|
|
/* We have a match! Copy out the data. */
|
|
memcpy(dcd_key->path, psz_path_name, dw_path_size);
|
|
}
|
|
dev_dbg(bridge, "%s: psz_path_name=%s, dw_path_size=%d\n",
|
|
__func__, psz_path_name, dw_path_size);
|
|
} else {
|
|
/* Deregister an existing object */
|
|
spin_lock(&dbdcd_lock);
|
|
list_for_each_entry(dcd_key, ®_key_list, link) {
|
|
if (!strncmp(dcd_key->name, sz_reg_key,
|
|
strlen(sz_reg_key) + 1)) {
|
|
list_del(&dcd_key->link);
|
|
kfree(dcd_key->path);
|
|
kfree(dcd_key);
|
|
break;
|
|
}
|
|
}
|
|
spin_unlock(&dbdcd_lock);
|
|
if (&dcd_key->link == ®_key_list)
|
|
status = -EPERM;
|
|
}
|
|
|
|
if (!status) {
|
|
/*
|
|
* Because the node database has been updated through a
|
|
* successful object registration/de-registration operation,
|
|
* we need to reset the object enumeration counter to allow
|
|
* current enumerations to reflect this update in the node
|
|
* database.
|
|
*/
|
|
enum_refs = 0;
|
|
}
|
|
func_end:
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
* ======== dcd_unregister_object ========
|
|
* Call DCD_Register object with psz_path_name set to NULL to
|
|
* perform actual object de-registration.
|
|
*/
|
|
int dcd_unregister_object(struct dsp_uuid *uuid_obj,
|
|
enum dsp_dcdobjtype obj_type)
|
|
{
|
|
int status = 0;
|
|
|
|
DBC_REQUIRE(refs > 0);
|
|
DBC_REQUIRE(uuid_obj != NULL);
|
|
DBC_REQUIRE((obj_type == DSP_DCDNODETYPE) ||
|
|
(obj_type == DSP_DCDPROCESSORTYPE) ||
|
|
(obj_type == DSP_DCDLIBRARYTYPE) ||
|
|
(obj_type == DSP_DCDCREATELIBTYPE) ||
|
|
(obj_type == DSP_DCDEXECUTELIBTYPE) ||
|
|
(obj_type == DSP_DCDDELETELIBTYPE));
|
|
|
|
/*
|
|
* When dcd_register_object is called with NULL as pathname,
|
|
* it indicates an unregister object operation.
|
|
*/
|
|
status = dcd_register_object(uuid_obj, obj_type, NULL);
|
|
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
**********************************************************************
|
|
* DCD Helper Functions
|
|
**********************************************************************
|
|
*/
|
|
|
|
/*
|
|
* ======== atoi ========
|
|
* Purpose:
|
|
* This function converts strings in decimal or hex format to integers.
|
|
*/
|
|
static s32 atoi(char *psz_buf)
|
|
{
|
|
char *pch = psz_buf;
|
|
s32 base = 0;
|
|
|
|
while (isspace(*pch))
|
|
pch++;
|
|
|
|
if (*pch == '-' || *pch == '+') {
|
|
base = 10;
|
|
pch++;
|
|
} else if (*pch && tolower(pch[strlen(pch) - 1]) == 'h') {
|
|
base = 16;
|
|
}
|
|
|
|
return simple_strtoul(pch, NULL, base);
|
|
}
|
|
|
|
/*
|
|
* ======== get_attrs_from_buf ========
|
|
* Purpose:
|
|
* Parse the content of a buffer filled with DSP-side data and
|
|
* retrieve an object's attributes from it. IMPORTANT: Assume the
|
|
* buffer has been converted from DSP format to GPP format.
|
|
*/
|
|
static int get_attrs_from_buf(char *psz_buf, u32 ul_buf_size,
|
|
enum dsp_dcdobjtype obj_type,
|
|
struct dcd_genericobj *gen_obj)
|
|
{
|
|
int status = 0;
|
|
char seps[] = ", ";
|
|
char *psz_cur;
|
|
char *token;
|
|
s32 token_len = 0;
|
|
u32 i = 0;
|
|
#ifdef _DB_TIOMAP
|
|
s32 entry_id;
|
|
#endif
|
|
|
|
DBC_REQUIRE(psz_buf != NULL);
|
|
DBC_REQUIRE(ul_buf_size != 0);
|
|
DBC_REQUIRE((obj_type == DSP_DCDNODETYPE)
|
|
|| (obj_type == DSP_DCDPROCESSORTYPE));
|
|
DBC_REQUIRE(gen_obj != NULL);
|
|
|
|
switch (obj_type) {
|
|
case DSP_DCDNODETYPE:
|
|
/*
|
|
* Parse COFF sect buffer to retrieve individual tokens used
|
|
* to fill in object attrs.
|
|
*/
|
|
psz_cur = psz_buf;
|
|
token = strsep(&psz_cur, seps);
|
|
|
|
/* u32 cb_struct */
|
|
gen_obj->obj_data.node_obj.ndb_props.cb_struct =
|
|
(u32) atoi(token);
|
|
token = strsep(&psz_cur, seps);
|
|
|
|
/* dsp_uuid ui_node_id */
|
|
uuid_uuid_from_string(token,
|
|
&gen_obj->obj_data.node_obj.ndb_props.
|
|
ui_node_id);
|
|
token = strsep(&psz_cur, seps);
|
|
|
|
/* ac_name */
|
|
DBC_REQUIRE(token);
|
|
token_len = strlen(token);
|
|
if (token_len > DSP_MAXNAMELEN - 1)
|
|
token_len = DSP_MAXNAMELEN - 1;
|
|
|
|
strncpy(gen_obj->obj_data.node_obj.ndb_props.ac_name,
|
|
token, token_len);
|
|
gen_obj->obj_data.node_obj.ndb_props.ac_name[token_len] = '\0';
|
|
token = strsep(&psz_cur, seps);
|
|
/* u32 ntype */
|
|
gen_obj->obj_data.node_obj.ndb_props.ntype = atoi(token);
|
|
token = strsep(&psz_cur, seps);
|
|
/* u32 cache_on_gpp */
|
|
gen_obj->obj_data.node_obj.ndb_props.cache_on_gpp = atoi(token);
|
|
token = strsep(&psz_cur, seps);
|
|
/* dsp_resourcereqmts dsp_resource_reqmts */
|
|
gen_obj->obj_data.node_obj.ndb_props.dsp_resource_reqmts.
|
|
cb_struct = (u32) atoi(token);
|
|
token = strsep(&psz_cur, seps);
|
|
|
|
gen_obj->obj_data.node_obj.ndb_props.
|
|
dsp_resource_reqmts.static_data_size = atoi(token);
|
|
token = strsep(&psz_cur, seps);
|
|
gen_obj->obj_data.node_obj.ndb_props.
|
|
dsp_resource_reqmts.global_data_size = atoi(token);
|
|
token = strsep(&psz_cur, seps);
|
|
gen_obj->obj_data.node_obj.ndb_props.
|
|
dsp_resource_reqmts.program_mem_size = atoi(token);
|
|
token = strsep(&psz_cur, seps);
|
|
gen_obj->obj_data.node_obj.ndb_props.
|
|
dsp_resource_reqmts.uwc_execution_time = atoi(token);
|
|
token = strsep(&psz_cur, seps);
|
|
gen_obj->obj_data.node_obj.ndb_props.
|
|
dsp_resource_reqmts.uwc_period = atoi(token);
|
|
token = strsep(&psz_cur, seps);
|
|
|
|
gen_obj->obj_data.node_obj.ndb_props.
|
|
dsp_resource_reqmts.uwc_deadline = atoi(token);
|
|
token = strsep(&psz_cur, seps);
|
|
|
|
gen_obj->obj_data.node_obj.ndb_props.
|
|
dsp_resource_reqmts.avg_exection_time = atoi(token);
|
|
token = strsep(&psz_cur, seps);
|
|
|
|
gen_obj->obj_data.node_obj.ndb_props.
|
|
dsp_resource_reqmts.minimum_period = atoi(token);
|
|
token = strsep(&psz_cur, seps);
|
|
|
|
/* s32 prio */
|
|
gen_obj->obj_data.node_obj.ndb_props.prio = atoi(token);
|
|
token = strsep(&psz_cur, seps);
|
|
|
|
/* u32 stack_size */
|
|
gen_obj->obj_data.node_obj.ndb_props.stack_size = atoi(token);
|
|
token = strsep(&psz_cur, seps);
|
|
|
|
/* u32 sys_stack_size */
|
|
gen_obj->obj_data.node_obj.ndb_props.sys_stack_size =
|
|
atoi(token);
|
|
token = strsep(&psz_cur, seps);
|
|
|
|
/* u32 stack_seg */
|
|
gen_obj->obj_data.node_obj.ndb_props.stack_seg = atoi(token);
|
|
token = strsep(&psz_cur, seps);
|
|
|
|
/* u32 message_depth */
|
|
gen_obj->obj_data.node_obj.ndb_props.message_depth =
|
|
atoi(token);
|
|
token = strsep(&psz_cur, seps);
|
|
|
|
/* u32 num_input_streams */
|
|
gen_obj->obj_data.node_obj.ndb_props.num_input_streams =
|
|
atoi(token);
|
|
token = strsep(&psz_cur, seps);
|
|
|
|
/* u32 num_output_streams */
|
|
gen_obj->obj_data.node_obj.ndb_props.num_output_streams =
|
|
atoi(token);
|
|
token = strsep(&psz_cur, seps);
|
|
|
|
/* u32 utimeout */
|
|
gen_obj->obj_data.node_obj.ndb_props.utimeout = atoi(token);
|
|
token = strsep(&psz_cur, seps);
|
|
|
|
/* char *pstr_create_phase_fxn */
|
|
DBC_REQUIRE(token);
|
|
token_len = strlen(token);
|
|
gen_obj->obj_data.node_obj.pstr_create_phase_fxn =
|
|
kzalloc(token_len + 1, GFP_KERNEL);
|
|
strncpy(gen_obj->obj_data.node_obj.pstr_create_phase_fxn,
|
|
token, token_len);
|
|
gen_obj->obj_data.node_obj.pstr_create_phase_fxn[token_len] =
|
|
'\0';
|
|
token = strsep(&psz_cur, seps);
|
|
|
|
/* char *pstr_execute_phase_fxn */
|
|
DBC_REQUIRE(token);
|
|
token_len = strlen(token);
|
|
gen_obj->obj_data.node_obj.pstr_execute_phase_fxn =
|
|
kzalloc(token_len + 1, GFP_KERNEL);
|
|
strncpy(gen_obj->obj_data.node_obj.pstr_execute_phase_fxn,
|
|
token, token_len);
|
|
gen_obj->obj_data.node_obj.pstr_execute_phase_fxn[token_len] =
|
|
'\0';
|
|
token = strsep(&psz_cur, seps);
|
|
|
|
/* char *pstr_delete_phase_fxn */
|
|
DBC_REQUIRE(token);
|
|
token_len = strlen(token);
|
|
gen_obj->obj_data.node_obj.pstr_delete_phase_fxn =
|
|
kzalloc(token_len + 1, GFP_KERNEL);
|
|
strncpy(gen_obj->obj_data.node_obj.pstr_delete_phase_fxn,
|
|
token, token_len);
|
|
gen_obj->obj_data.node_obj.pstr_delete_phase_fxn[token_len] =
|
|
'\0';
|
|
token = strsep(&psz_cur, seps);
|
|
|
|
/* Segment id for message buffers */
|
|
gen_obj->obj_data.node_obj.msg_segid = atoi(token);
|
|
token = strsep(&psz_cur, seps);
|
|
|
|
/* Message notification type */
|
|
gen_obj->obj_data.node_obj.msg_notify_type = atoi(token);
|
|
token = strsep(&psz_cur, seps);
|
|
|
|
/* char *pstr_i_alg_name */
|
|
if (token) {
|
|
token_len = strlen(token);
|
|
gen_obj->obj_data.node_obj.pstr_i_alg_name =
|
|
kzalloc(token_len + 1, GFP_KERNEL);
|
|
strncpy(gen_obj->obj_data.node_obj.pstr_i_alg_name,
|
|
token, token_len);
|
|
gen_obj->obj_data.node_obj.pstr_i_alg_name[token_len] =
|
|
'\0';
|
|
token = strsep(&psz_cur, seps);
|
|
}
|
|
|
|
/* Load type (static, dynamic, or overlay) */
|
|
if (token) {
|
|
gen_obj->obj_data.node_obj.us_load_type = atoi(token);
|
|
token = strsep(&psz_cur, seps);
|
|
}
|
|
|
|
/* Dynamic load data requirements */
|
|
if (token) {
|
|
gen_obj->obj_data.node_obj.ul_data_mem_seg_mask =
|
|
atoi(token);
|
|
token = strsep(&psz_cur, seps);
|
|
}
|
|
|
|
/* Dynamic load code requirements */
|
|
if (token) {
|
|
gen_obj->obj_data.node_obj.ul_code_mem_seg_mask =
|
|
atoi(token);
|
|
token = strsep(&psz_cur, seps);
|
|
}
|
|
|
|
/* Extract node profiles into node properties */
|
|
if (token) {
|
|
|
|
gen_obj->obj_data.node_obj.ndb_props.count_profiles =
|
|
atoi(token);
|
|
for (i = 0;
|
|
i <
|
|
gen_obj->obj_data.node_obj.
|
|
ndb_props.count_profiles; i++) {
|
|
token = strsep(&psz_cur, seps);
|
|
if (token) {
|
|
/* Heap Size for the node */
|
|
gen_obj->obj_data.node_obj.
|
|
ndb_props.node_profiles[i].
|
|
ul_heap_size = atoi(token);
|
|
}
|
|
}
|
|
}
|
|
token = strsep(&psz_cur, seps);
|
|
if (token) {
|
|
gen_obj->obj_data.node_obj.ndb_props.stack_seg_name =
|
|
(u32) (token);
|
|
}
|
|
|
|
break;
|
|
|
|
case DSP_DCDPROCESSORTYPE:
|
|
/*
|
|
* Parse COFF sect buffer to retrieve individual tokens used
|
|
* to fill in object attrs.
|
|
*/
|
|
psz_cur = psz_buf;
|
|
token = strsep(&psz_cur, seps);
|
|
|
|
gen_obj->obj_data.proc_info.cb_struct = atoi(token);
|
|
token = strsep(&psz_cur, seps);
|
|
|
|
gen_obj->obj_data.proc_info.processor_family = atoi(token);
|
|
token = strsep(&psz_cur, seps);
|
|
|
|
gen_obj->obj_data.proc_info.processor_type = atoi(token);
|
|
token = strsep(&psz_cur, seps);
|
|
|
|
gen_obj->obj_data.proc_info.clock_rate = atoi(token);
|
|
token = strsep(&psz_cur, seps);
|
|
|
|
gen_obj->obj_data.proc_info.ul_internal_mem_size = atoi(token);
|
|
token = strsep(&psz_cur, seps);
|
|
|
|
gen_obj->obj_data.proc_info.ul_external_mem_size = atoi(token);
|
|
token = strsep(&psz_cur, seps);
|
|
|
|
gen_obj->obj_data.proc_info.processor_id = atoi(token);
|
|
token = strsep(&psz_cur, seps);
|
|
|
|
gen_obj->obj_data.proc_info.ty_running_rtos = atoi(token);
|
|
token = strsep(&psz_cur, seps);
|
|
|
|
gen_obj->obj_data.proc_info.node_min_priority = atoi(token);
|
|
token = strsep(&psz_cur, seps);
|
|
|
|
gen_obj->obj_data.proc_info.node_max_priority = atoi(token);
|
|
|
|
#ifdef _DB_TIOMAP
|
|
/* Proc object may contain additional(extended) attributes. */
|
|
/* attr must match proc.hxx */
|
|
for (entry_id = 0; entry_id < 7; entry_id++) {
|
|
token = strsep(&psz_cur, seps);
|
|
gen_obj->obj_data.ext_proc_obj.ty_tlb[entry_id].
|
|
ul_gpp_phys = atoi(token);
|
|
|
|
token = strsep(&psz_cur, seps);
|
|
gen_obj->obj_data.ext_proc_obj.ty_tlb[entry_id].
|
|
ul_dsp_virt = atoi(token);
|
|
}
|
|
#endif
|
|
|
|
break;
|
|
|
|
default:
|
|
status = -EPERM;
|
|
break;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
* ======== CompressBuffer ========
|
|
* Purpose:
|
|
* Compress the DSP buffer, if necessary, to conform to PC format.
|
|
*/
|
|
static void compress_buf(char *psz_buf, u32 ul_buf_size, s32 char_size)
|
|
{
|
|
char *p;
|
|
char ch;
|
|
char *q;
|
|
|
|
p = psz_buf;
|
|
if (p == NULL)
|
|
return;
|
|
|
|
for (q = psz_buf; q < (psz_buf + ul_buf_size);) {
|
|
ch = dsp_char2_gpp_char(q, char_size);
|
|
if (ch == '\\') {
|
|
q += char_size;
|
|
ch = dsp_char2_gpp_char(q, char_size);
|
|
switch (ch) {
|
|
case 't':
|
|
*p = '\t';
|
|
break;
|
|
|
|
case 'n':
|
|
*p = '\n';
|
|
break;
|
|
|
|
case 'r':
|
|
*p = '\r';
|
|
break;
|
|
|
|
case '0':
|
|
*p = '\0';
|
|
break;
|
|
|
|
default:
|
|
*p = ch;
|
|
break;
|
|
}
|
|
} else {
|
|
*p = ch;
|
|
}
|
|
p++;
|
|
q += char_size;
|
|
}
|
|
|
|
/* NULL out remainder of buffer. */
|
|
while (p < q)
|
|
*p++ = '\0';
|
|
}
|
|
|
|
/*
|
|
* ======== dsp_char2_gpp_char ========
|
|
* Purpose:
|
|
* Convert DSP char to host GPP char in a portable manner
|
|
*/
|
|
static char dsp_char2_gpp_char(char *word, s32 dsp_char_size)
|
|
{
|
|
char ch = '\0';
|
|
char *ch_src;
|
|
s32 i;
|
|
|
|
for (ch_src = word, i = dsp_char_size; i > 0; i--)
|
|
ch |= *ch_src++;
|
|
|
|
return ch;
|
|
}
|
|
|
|
/*
|
|
* ======== get_dep_lib_info ========
|
|
*/
|
|
static int get_dep_lib_info(struct dcd_manager *hdcd_mgr,
|
|
struct dsp_uuid *uuid_obj,
|
|
u16 *num_libs,
|
|
u16 *num_pers_libs,
|
|
struct dsp_uuid *dep_lib_uuids,
|
|
bool *prstnt_dep_libs,
|
|
enum nldr_phase phase)
|
|
{
|
|
struct dcd_manager *dcd_mgr_obj = hdcd_mgr;
|
|
char *psz_coff_buf = NULL;
|
|
char *psz_cur;
|
|
char *psz_file_name = NULL;
|
|
struct cod_libraryobj *lib = NULL;
|
|
u32 ul_addr = 0; /* Used by cod_get_section */
|
|
u32 ul_len = 0; /* Used by cod_get_section */
|
|
u32 dw_data_size = COD_MAXPATHLENGTH;
|
|
char seps[] = ", ";
|
|
char *token = NULL;
|
|
bool get_uuids = (dep_lib_uuids != NULL);
|
|
u16 dep_libs = 0;
|
|
int status = 0;
|
|
|
|
DBC_REQUIRE(refs > 0);
|
|
|
|
DBC_REQUIRE(hdcd_mgr);
|
|
DBC_REQUIRE(num_libs != NULL);
|
|
DBC_REQUIRE(uuid_obj != NULL);
|
|
|
|
/* Initialize to 0 dependent libraries, if only counting number of
|
|
* dependent libraries */
|
|
if (!get_uuids) {
|
|
*num_libs = 0;
|
|
*num_pers_libs = 0;
|
|
}
|
|
|
|
/* Allocate a buffer for file name */
|
|
psz_file_name = kzalloc(dw_data_size, GFP_KERNEL);
|
|
if (psz_file_name == NULL) {
|
|
status = -ENOMEM;
|
|
} else {
|
|
/* Get the name of the library */
|
|
status = dcd_get_library_name(hdcd_mgr, uuid_obj, psz_file_name,
|
|
&dw_data_size, phase, NULL);
|
|
}
|
|
|
|
/* Open the library */
|
|
if (!status) {
|
|
status = cod_open(dcd_mgr_obj->cod_mgr, psz_file_name,
|
|
COD_NOLOAD, &lib);
|
|
}
|
|
if (!status) {
|
|
/* Get dependent library section information. */
|
|
status = cod_get_section(lib, DEPLIBSECT, &ul_addr, &ul_len);
|
|
|
|
if (status) {
|
|
/* Ok, no dependent libraries */
|
|
ul_len = 0;
|
|
status = 0;
|
|
}
|
|
}
|
|
|
|
if (status || !(ul_len > 0))
|
|
goto func_cont;
|
|
|
|
/* Allocate zeroed buffer. */
|
|
psz_coff_buf = kzalloc(ul_len + 4, GFP_KERNEL);
|
|
if (psz_coff_buf == NULL)
|
|
status = -ENOMEM;
|
|
|
|
/* Read section contents. */
|
|
status = cod_read_section(lib, DEPLIBSECT, psz_coff_buf, ul_len);
|
|
if (status)
|
|
goto func_cont;
|
|
|
|
/* Compress and format DSP buffer to conform to PC format. */
|
|
compress_buf(psz_coff_buf, ul_len, DSPWORDSIZE);
|
|
|
|
/* Read from buffer */
|
|
psz_cur = psz_coff_buf;
|
|
while ((token = strsep(&psz_cur, seps)) && *token != '\0') {
|
|
if (get_uuids) {
|
|
if (dep_libs >= *num_libs) {
|
|
/* Gone beyond the limit */
|
|
break;
|
|
} else {
|
|
/* Retrieve UUID string. */
|
|
uuid_uuid_from_string(token,
|
|
&(dep_lib_uuids
|
|
[dep_libs]));
|
|
/* Is this library persistent? */
|
|
token = strsep(&psz_cur, seps);
|
|
prstnt_dep_libs[dep_libs] = atoi(token);
|
|
dep_libs++;
|
|
}
|
|
} else {
|
|
/* Advanc to next token */
|
|
token = strsep(&psz_cur, seps);
|
|
if (atoi(token))
|
|
(*num_pers_libs)++;
|
|
|
|
/* Just counting number of dependent libraries */
|
|
(*num_libs)++;
|
|
}
|
|
}
|
|
func_cont:
|
|
if (lib)
|
|
cod_close(lib);
|
|
|
|
/* Free previously allocated dynamic buffers. */
|
|
kfree(psz_file_name);
|
|
|
|
kfree(psz_coff_buf);
|
|
|
|
return status;
|
|
}
|