linux/drivers/staging/tidspbridge/pmgr/cod.c
<<
>>
Prefs
   1/*
   2 * cod.c
   3 *
   4 * DSP-BIOS Bridge driver support functions for TI OMAP processors.
   5 *
   6 * This module implements DSP code management for the DSP/BIOS Bridge
   7 * environment. It is mostly a thin wrapper.
   8 *
   9 * This module provides an interface for loading both static and
  10 * dynamic code objects onto DSP systems.
  11 *
  12 * Copyright (C) 2005-2006 Texas Instruments, Inc.
  13 *
  14 * This package is free software; you can redistribute it and/or modify
  15 * it under the terms of the GNU General Public License version 2 as
  16 * published by the Free Software Foundation.
  17 *
  18 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  19 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  20 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  21 */
  22
  23#include <linux/types.h>
  24
  25/*  ----------------------------------- Host OS */
  26#include <dspbridge/host_os.h>
  27#include <linux/fs.h>
  28#include <linux/uaccess.h>
  29
  30/*  ----------------------------------- DSP/BIOS Bridge */
  31#include <dspbridge/dbdefs.h>
  32
  33/*  ----------------------------------- Platform Manager */
  34/* Include appropriate loader header file */
  35#include <dspbridge/dbll.h>
  36
  37/*  ----------------------------------- This */
  38#include <dspbridge/cod.h>
  39
  40/*
  41 *  ======== cod_manager ========
  42 */
  43struct cod_manager {
  44        struct dbll_tar_obj *target;
  45        struct dbll_library_obj *base_lib;
  46        bool loaded;            /* Base library loaded? */
  47        u32 entry;
  48        struct dbll_fxns fxns;
  49        struct dbll_attrs attrs;
  50        char sz_zl_file[COD_MAXPATHLENGTH];
  51};
  52
  53/*
  54 *  ======== cod_libraryobj ========
  55 */
  56struct cod_libraryobj {
  57        struct dbll_library_obj *dbll_lib;
  58        struct cod_manager *cod_mgr;
  59};
  60
  61static struct dbll_fxns ldr_fxns = {
  62        (dbll_close_fxn) dbll_close,
  63        (dbll_create_fxn) dbll_create,
  64        (dbll_delete_fxn) dbll_delete,
  65        (dbll_exit_fxn) dbll_exit,
  66        (dbll_get_attrs_fxn) dbll_get_attrs,
  67        (dbll_get_addr_fxn) dbll_get_addr,
  68        (dbll_get_c_addr_fxn) dbll_get_c_addr,
  69        (dbll_get_sect_fxn) dbll_get_sect,
  70        (dbll_init_fxn) dbll_init,
  71        (dbll_load_fxn) dbll_load,
  72        (dbll_open_fxn) dbll_open,
  73        (dbll_read_sect_fxn) dbll_read_sect,
  74        (dbll_unload_fxn) dbll_unload,
  75};
  76
  77static bool no_op(void);
  78
  79/*
  80 * File operations (originally were under kfile.c)
  81 */
  82static s32 cod_f_close(struct file *filp)
  83{
  84        /* Check for valid handle */
  85        if (!filp)
  86                return -EFAULT;
  87
  88        filp_close(filp, NULL);
  89
  90        /* we can't use 0 here */
  91        return 0;
  92}
  93
  94static struct file *cod_f_open(const char *psz_file_name, const char *sz_mode)
  95{
  96        mm_segment_t fs;
  97        struct file *filp;
  98
  99        fs = get_fs();
 100        set_fs(get_ds());
 101
 102        /* ignore given mode and open file as read-only */
 103        filp = filp_open(psz_file_name, O_RDONLY, 0);
 104
 105        if (IS_ERR(filp))
 106                filp = NULL;
 107
 108        set_fs(fs);
 109
 110        return filp;
 111}
 112
 113static s32 cod_f_read(void __user *pbuffer, s32 size, s32 count,
 114                      struct file *filp)
 115{
 116        /* check for valid file handle */
 117        if (!filp)
 118                return -EFAULT;
 119
 120        if ((size > 0) && (count > 0) && pbuffer) {
 121                u32 dw_bytes_read;
 122                mm_segment_t fs;
 123
 124                /* read from file */
 125                fs = get_fs();
 126                set_fs(get_ds());
 127                dw_bytes_read = filp->f_op->read(filp, pbuffer, size * count,
 128                                                 &(filp->f_pos));
 129                set_fs(fs);
 130
 131                if (!dw_bytes_read)
 132                        return -EBADF;
 133
 134                return dw_bytes_read / size;
 135        }
 136
 137        return -EINVAL;
 138}
 139
 140static s32 cod_f_seek(struct file *filp, s32 offset, s32 origin)
 141{
 142        loff_t dw_cur_pos;
 143
 144        /* check for valid file handle */
 145        if (!filp)
 146                return -EFAULT;
 147
 148        /* based on the origin flag, move the internal pointer */
 149        dw_cur_pos = filp->f_op->llseek(filp, offset, origin);
 150
 151        if ((s32) dw_cur_pos < 0)
 152                return -EPERM;
 153
 154        /* we can't use 0 here */
 155        return 0;
 156}
 157
 158static s32 cod_f_tell(struct file *filp)
 159{
 160        loff_t dw_cur_pos;
 161
 162        if (!filp)
 163                return -EFAULT;
 164
 165        /* Get current position */
 166        dw_cur_pos = filp->f_op->llseek(filp, 0, SEEK_CUR);
 167
 168        if ((s32) dw_cur_pos < 0)
 169                return -EPERM;
 170
 171        return dw_cur_pos;
 172}
 173
 174/*
 175 *  ======== cod_close ========
 176 */
 177void cod_close(struct cod_libraryobj *lib)
 178{
 179        struct cod_manager *hmgr;
 180
 181        hmgr = lib->cod_mgr;
 182        hmgr->fxns.close_fxn(lib->dbll_lib);
 183
 184        kfree(lib);
 185}
 186
 187/*
 188 *  ======== cod_create ========
 189 *  Purpose:
 190 *      Create an object to manage code on a DSP system.
 191 *      This object can be used to load an initial program image with
 192 *      arguments that can later be expanded with
 193 *      dynamically loaded object files.
 194 *
 195 */
 196int cod_create(struct cod_manager **mgr, char *str_zl_file)
 197{
 198        struct cod_manager *mgr_new;
 199        struct dbll_attrs zl_attrs;
 200        int status = 0;
 201
 202        /* assume failure */
 203        *mgr = NULL;
 204
 205        mgr_new = kzalloc(sizeof(struct cod_manager), GFP_KERNEL);
 206        if (mgr_new == NULL)
 207                return -ENOMEM;
 208
 209        /* Set up loader functions */
 210        mgr_new->fxns = ldr_fxns;
 211
 212        /* initialize the ZL module */
 213        mgr_new->fxns.init_fxn();
 214
 215        zl_attrs.alloc = (dbll_alloc_fxn) no_op;
 216        zl_attrs.free = (dbll_free_fxn) no_op;
 217        zl_attrs.fread = (dbll_read_fxn) cod_f_read;
 218        zl_attrs.fseek = (dbll_seek_fxn) cod_f_seek;
 219        zl_attrs.ftell = (dbll_tell_fxn) cod_f_tell;
 220        zl_attrs.fclose = (dbll_f_close_fxn) cod_f_close;
 221        zl_attrs.fopen = (dbll_f_open_fxn) cod_f_open;
 222        zl_attrs.sym_lookup = NULL;
 223        zl_attrs.base_image = true;
 224        zl_attrs.log_write = NULL;
 225        zl_attrs.log_write_handle = NULL;
 226        zl_attrs.write = NULL;
 227        zl_attrs.rmm_handle = NULL;
 228        zl_attrs.input_params = NULL;
 229        zl_attrs.sym_handle = NULL;
 230        zl_attrs.sym_arg = NULL;
 231
 232        mgr_new->attrs = zl_attrs;
 233
 234        status = mgr_new->fxns.create_fxn(&mgr_new->target, &zl_attrs);
 235
 236        if (status) {
 237                cod_delete(mgr_new);
 238                return -ESPIPE;
 239        }
 240
 241        /* return the new manager */
 242        *mgr = mgr_new;
 243
 244        return 0;
 245}
 246
 247/*
 248 *  ======== cod_delete ========
 249 *  Purpose:
 250 *      Delete a code manager object.
 251 */
 252void cod_delete(struct cod_manager *cod_mgr_obj)
 253{
 254        if (cod_mgr_obj->base_lib) {
 255                if (cod_mgr_obj->loaded)
 256                        cod_mgr_obj->fxns.unload_fxn(cod_mgr_obj->base_lib,
 257                                                        &cod_mgr_obj->attrs);
 258
 259                cod_mgr_obj->fxns.close_fxn(cod_mgr_obj->base_lib);
 260        }
 261        if (cod_mgr_obj->target) {
 262                cod_mgr_obj->fxns.delete_fxn(cod_mgr_obj->target);
 263                cod_mgr_obj->fxns.exit_fxn();
 264        }
 265        kfree(cod_mgr_obj);
 266}
 267
 268/*
 269 *  ======== cod_get_base_lib ========
 270 *  Purpose:
 271 *      Get handle to the base image DBL library.
 272 */
 273int cod_get_base_lib(struct cod_manager *cod_mgr_obj,
 274                            struct dbll_library_obj **plib)
 275{
 276        int status = 0;
 277
 278        *plib = (struct dbll_library_obj *)cod_mgr_obj->base_lib;
 279
 280        return status;
 281}
 282
 283/*
 284 *  ======== cod_get_base_name ========
 285 */
 286int cod_get_base_name(struct cod_manager *cod_mgr_obj, char *sz_name,
 287                             u32 usize)
 288{
 289        int status = 0;
 290
 291        if (usize <= COD_MAXPATHLENGTH)
 292                strlcpy(sz_name, cod_mgr_obj->sz_zl_file, usize);
 293        else
 294                status = -EPERM;
 295
 296        return status;
 297}
 298
 299/*
 300 *  ======== cod_get_entry ========
 301 *  Purpose:
 302 *      Retrieve the entry point of a loaded DSP program image
 303 *
 304 */
 305int cod_get_entry(struct cod_manager *cod_mgr_obj, u32 *entry_pt)
 306{
 307        *entry_pt = cod_mgr_obj->entry;
 308
 309        return 0;
 310}
 311
 312/*
 313 *  ======== cod_get_loader ========
 314 *  Purpose:
 315 *      Get handle to the DBLL loader.
 316 */
 317int cod_get_loader(struct cod_manager *cod_mgr_obj,
 318                          struct dbll_tar_obj **loader)
 319{
 320        int status = 0;
 321
 322        *loader = (struct dbll_tar_obj *)cod_mgr_obj->target;
 323
 324        return status;
 325}
 326
 327/*
 328 *  ======== cod_get_section ========
 329 *  Purpose:
 330 *      Retrieve the starting address and length of a section in the COFF file
 331 *      given the section name.
 332 */
 333int cod_get_section(struct cod_libraryobj *lib, char *str_sect,
 334                           u32 *addr, u32 *len)
 335{
 336        struct cod_manager *cod_mgr_obj;
 337        int status = 0;
 338
 339        *addr = 0;
 340        *len = 0;
 341        if (lib != NULL) {
 342                cod_mgr_obj = lib->cod_mgr;
 343                status = cod_mgr_obj->fxns.get_sect_fxn(lib->dbll_lib, str_sect,
 344                                                        addr, len);
 345        } else {
 346                status = -ESPIPE;
 347        }
 348
 349        return status;
 350}
 351
 352/*
 353 *  ======== cod_get_sym_value ========
 354 *  Purpose:
 355 *      Retrieve the value for the specified symbol. The symbol is first
 356 *      searched for literally and then, if not found, searched for as a
 357 *      C symbol.
 358 *
 359 */
 360int cod_get_sym_value(struct cod_manager *cod_mgr_obj, char *str_sym,
 361                             u32 *pul_value)
 362{
 363        struct dbll_sym_val *dbll_sym;
 364
 365        dev_dbg(bridge, "%s: cod_mgr_obj: %p str_sym: %s pul_value: %p\n",
 366                __func__, cod_mgr_obj, str_sym, pul_value);
 367        if (cod_mgr_obj->base_lib) {
 368                if (!cod_mgr_obj->fxns.
 369                    get_addr_fxn(cod_mgr_obj->base_lib, str_sym, &dbll_sym)) {
 370                        if (!cod_mgr_obj->fxns.
 371                            get_c_addr_fxn(cod_mgr_obj->base_lib, str_sym,
 372                                                &dbll_sym))
 373                                return -ESPIPE;
 374                }
 375        } else {
 376                return -ESPIPE;
 377        }
 378
 379        *pul_value = dbll_sym->value;
 380
 381        return 0;
 382}
 383
 384/*
 385 *  ======== cod_load_base ========
 386 *  Purpose:
 387 *      Load the initial program image, optionally with command-line arguments,
 388 *      on the DSP system managed by the supplied handle. The program to be
 389 *      loaded must be the first element of the args array and must be a fully
 390 *      qualified pathname.
 391 *  Details:
 392 *      if num_argc doesn't match the number of arguments in the args array, the
 393 *      args array is searched for a NULL terminating entry, and argc is
 394 *      recalculated to reflect this.  In this way, we can support NULL
 395 *      terminating args arrays, if num_argc is very large.
 396 */
 397int cod_load_base(struct cod_manager *cod_mgr_obj, u32 num_argc, char *args[],
 398                         cod_writefxn pfn_write, void *arb, char *envp[])
 399{
 400        dbll_flags flags;
 401        struct dbll_attrs save_attrs;
 402        struct dbll_attrs new_attrs;
 403        int status;
 404        u32 i;
 405
 406        /*
 407         *  Make sure every argv[] stated in argc has a value, or change argc to
 408         *  reflect true number in NULL terminated argv array.
 409         */
 410        for (i = 0; i < num_argc; i++) {
 411                if (args[i] == NULL) {
 412                        num_argc = i;
 413                        break;
 414                }
 415        }
 416
 417        /* set the write function for this operation */
 418        cod_mgr_obj->fxns.get_attrs_fxn(cod_mgr_obj->target, &save_attrs);
 419
 420        new_attrs = save_attrs;
 421        new_attrs.write = (dbll_write_fxn) pfn_write;
 422        new_attrs.input_params = arb;
 423        new_attrs.alloc = (dbll_alloc_fxn) no_op;
 424        new_attrs.free = (dbll_free_fxn) no_op;
 425        new_attrs.log_write = NULL;
 426        new_attrs.log_write_handle = NULL;
 427
 428        /* Load the image */
 429        flags = DBLL_CODE | DBLL_DATA | DBLL_SYMB;
 430        status = cod_mgr_obj->fxns.load_fxn(cod_mgr_obj->base_lib, flags,
 431                                            &new_attrs,
 432                                            &cod_mgr_obj->entry);
 433        if (status)
 434                cod_mgr_obj->fxns.close_fxn(cod_mgr_obj->base_lib);
 435
 436        if (!status)
 437                cod_mgr_obj->loaded = true;
 438        else
 439                cod_mgr_obj->base_lib = NULL;
 440
 441        return status;
 442}
 443
 444/*
 445 *  ======== cod_open ========
 446 *      Open library for reading sections.
 447 */
 448int cod_open(struct cod_manager *hmgr, char *sz_coff_path,
 449                    u32 flags, struct cod_libraryobj **lib_obj)
 450{
 451        int status = 0;
 452        struct cod_libraryobj *lib = NULL;
 453
 454        *lib_obj = NULL;
 455
 456        lib = kzalloc(sizeof(struct cod_libraryobj), GFP_KERNEL);
 457        if (lib == NULL)
 458                status = -ENOMEM;
 459
 460        if (!status) {
 461                lib->cod_mgr = hmgr;
 462                status = hmgr->fxns.open_fxn(hmgr->target, sz_coff_path, flags,
 463                                             &lib->dbll_lib);
 464                if (!status)
 465                        *lib_obj = lib;
 466        }
 467
 468        if (status)
 469                pr_err("%s: error status 0x%x, sz_coff_path: %s flags: 0x%x\n",
 470                       __func__, status, sz_coff_path, flags);
 471        return status;
 472}
 473
 474/*
 475 *  ======== cod_open_base ========
 476 *  Purpose:
 477 *      Open base image for reading sections.
 478 */
 479int cod_open_base(struct cod_manager *hmgr, char *sz_coff_path,
 480                         dbll_flags flags)
 481{
 482        int status = 0;
 483        struct dbll_library_obj *lib;
 484
 485        /* if we previously opened a base image, close it now */
 486        if (hmgr->base_lib) {
 487                if (hmgr->loaded) {
 488                        hmgr->fxns.unload_fxn(hmgr->base_lib, &hmgr->attrs);
 489                        hmgr->loaded = false;
 490                }
 491                hmgr->fxns.close_fxn(hmgr->base_lib);
 492                hmgr->base_lib = NULL;
 493        }
 494        status = hmgr->fxns.open_fxn(hmgr->target, sz_coff_path, flags, &lib);
 495        if (!status) {
 496                /* hang onto the library for subsequent sym table usage */
 497                hmgr->base_lib = lib;
 498                strncpy(hmgr->sz_zl_file, sz_coff_path, COD_MAXPATHLENGTH - 1);
 499                hmgr->sz_zl_file[COD_MAXPATHLENGTH - 1] = '\0';
 500        }
 501
 502        if (status)
 503                pr_err("%s: error status 0x%x sz_coff_path: %s\n", __func__,
 504                       status, sz_coff_path);
 505        return status;
 506}
 507
 508/*
 509 *  ======== cod_read_section ========
 510 *  Purpose:
 511 *      Retrieve the content of a code section given the section name.
 512 */
 513int cod_read_section(struct cod_libraryobj *lib, char *str_sect,
 514                            char *str_content, u32 content_size)
 515{
 516        int status = 0;
 517
 518        if (lib != NULL)
 519                status =
 520                    lib->cod_mgr->fxns.read_sect_fxn(lib->dbll_lib, str_sect,
 521                                                     str_content, content_size);
 522        else
 523                status = -ESPIPE;
 524
 525        return status;
 526}
 527
 528/*
 529 *  ======== no_op ========
 530 *  Purpose:
 531 *      No Operation.
 532 *
 533 */
 534static bool no_op(void)
 535{
 536        return true;
 537}
 538