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/*  ----------------------------------- Trace & Debug */
  34#include <dspbridge/dbc.h>
  35
  36/*  ----------------------------------- Platform Manager */
  37/* Include appropriate loader header file */
  38#include <dspbridge/dbll.h>
  39
  40/*  ----------------------------------- This */
  41#include <dspbridge/cod.h>
  42
  43/*
  44 *  ======== cod_manager ========
  45 */
  46struct cod_manager {
  47        struct dbll_tar_obj *target;
  48        struct dbll_library_obj *base_lib;
  49        bool loaded;            /* Base library loaded? */
  50        u32 entry;
  51        struct dbll_fxns fxns;
  52        struct dbll_attrs attrs;
  53        char sz_zl_file[COD_MAXPATHLENGTH];
  54};
  55
  56/*
  57 *  ======== cod_libraryobj ========
  58 */
  59struct cod_libraryobj {
  60        struct dbll_library_obj *dbll_lib;
  61        struct cod_manager *cod_mgr;
  62};
  63
  64static u32 refs = 0L;
  65
  66static struct dbll_fxns ldr_fxns = {
  67        (dbll_close_fxn) dbll_close,
  68        (dbll_create_fxn) dbll_create,
  69        (dbll_delete_fxn) dbll_delete,
  70        (dbll_exit_fxn) dbll_exit,
  71        (dbll_get_attrs_fxn) dbll_get_attrs,
  72        (dbll_get_addr_fxn) dbll_get_addr,
  73        (dbll_get_c_addr_fxn) dbll_get_c_addr,
  74        (dbll_get_sect_fxn) dbll_get_sect,
  75        (dbll_init_fxn) dbll_init,
  76        (dbll_load_fxn) dbll_load,
  77        (dbll_open_fxn) dbll_open,
  78        (dbll_read_sect_fxn) dbll_read_sect,
  79        (dbll_unload_fxn) dbll_unload,
  80};
  81
  82static bool no_op(void);
  83
  84/*
  85 * File operations (originally were under kfile.c)
  86 */
  87static s32 cod_f_close(struct file *filp)
  88{
  89        /* Check for valid handle */
  90        if (!filp)
  91                return -EFAULT;
  92
  93        filp_close(filp, NULL);
  94
  95        /* we can't use 0 here */
  96        return 0;
  97}
  98
  99static struct file *cod_f_open(const char *psz_file_name, const char *sz_mode)
 100{
 101        mm_segment_t fs;
 102        struct file *filp;
 103
 104        fs = get_fs();
 105        set_fs(get_ds());
 106
 107        /* ignore given mode and open file as read-only */
 108        filp = filp_open(psz_file_name, O_RDONLY, 0);
 109
 110        if (IS_ERR(filp))
 111                filp = NULL;
 112
 113        set_fs(fs);
 114
 115        return filp;
 116}
 117
 118static s32 cod_f_read(void __user *pbuffer, s32 size, s32 count,
 119                      struct file *filp)
 120{
 121        /* check for valid file handle */
 122        if (!filp)
 123                return -EFAULT;
 124
 125        if ((size > 0) && (count > 0) && pbuffer) {
 126                u32 dw_bytes_read;
 127                mm_segment_t fs;
 128
 129                /* read from file */
 130                fs = get_fs();
 131                set_fs(get_ds());
 132                dw_bytes_read = filp->f_op->read(filp, pbuffer, size * count,
 133                                                 &(filp->f_pos));
 134                set_fs(fs);
 135
 136                if (!dw_bytes_read)
 137                        return -EBADF;
 138
 139                return dw_bytes_read / size;
 140        }
 141
 142        return -EINVAL;
 143}
 144
 145static s32 cod_f_seek(struct file *filp, s32 offset, s32 origin)
 146{
 147        loff_t dw_cur_pos;
 148
 149        /* check for valid file handle */
 150        if (!filp)
 151                return -EFAULT;
 152
 153        /* based on the origin flag, move the internal pointer */
 154        dw_cur_pos = filp->f_op->llseek(filp, offset, origin);
 155
 156        if ((s32) dw_cur_pos < 0)
 157                return -EPERM;
 158
 159        /* we can't use 0 here */
 160        return 0;
 161}
 162
 163static s32 cod_f_tell(struct file *filp)
 164{
 165        loff_t dw_cur_pos;
 166
 167        if (!filp)
 168                return -EFAULT;
 169
 170        /* Get current position */
 171        dw_cur_pos = filp->f_op->llseek(filp, 0, SEEK_CUR);
 172
 173        if ((s32) dw_cur_pos < 0)
 174                return -EPERM;
 175
 176        return dw_cur_pos;
 177}
 178
 179/*
 180 *  ======== cod_close ========
 181 */
 182void cod_close(struct cod_libraryobj *lib)
 183{
 184        struct cod_manager *hmgr;
 185
 186        DBC_REQUIRE(refs > 0);
 187        DBC_REQUIRE(lib != NULL);
 188        DBC_REQUIRE(lib->cod_mgr);
 189
 190        hmgr = lib->cod_mgr;
 191        hmgr->fxns.close_fxn(lib->dbll_lib);
 192
 193        kfree(lib);
 194}
 195
 196/*
 197 *  ======== cod_create ========
 198 *  Purpose:
 199 *      Create an object to manage code on a DSP system.
 200 *      This object can be used to load an initial program image with
 201 *      arguments that can later be expanded with
 202 *      dynamically loaded object files.
 203 *
 204 */
 205int cod_create(struct cod_manager **mgr, char *str_zl_file)
 206{
 207        struct cod_manager *mgr_new;
 208        struct dbll_attrs zl_attrs;
 209        int status = 0;
 210
 211        DBC_REQUIRE(refs > 0);
 212        DBC_REQUIRE(mgr != NULL);
 213
 214        /* assume failure */
 215        *mgr = NULL;
 216
 217        mgr_new = kzalloc(sizeof(struct cod_manager), GFP_KERNEL);
 218        if (mgr_new == NULL)
 219                return -ENOMEM;
 220
 221        /* Set up loader functions */
 222        mgr_new->fxns = ldr_fxns;
 223
 224        /* initialize the ZL module */
 225        mgr_new->fxns.init_fxn();
 226
 227        zl_attrs.alloc = (dbll_alloc_fxn) no_op;
 228        zl_attrs.free = (dbll_free_fxn) no_op;
 229        zl_attrs.fread = (dbll_read_fxn) cod_f_read;
 230        zl_attrs.fseek = (dbll_seek_fxn) cod_f_seek;
 231        zl_attrs.ftell = (dbll_tell_fxn) cod_f_tell;
 232        zl_attrs.fclose = (dbll_f_close_fxn) cod_f_close;
 233        zl_attrs.fopen = (dbll_f_open_fxn) cod_f_open;
 234        zl_attrs.sym_lookup = NULL;
 235        zl_attrs.base_image = true;
 236        zl_attrs.log_write = NULL;
 237        zl_attrs.log_write_handle = NULL;
 238        zl_attrs.write = NULL;
 239        zl_attrs.rmm_handle = NULL;
 240        zl_attrs.input_params = NULL;
 241        zl_attrs.sym_handle = NULL;
 242        zl_attrs.sym_arg = NULL;
 243
 244        mgr_new->attrs = zl_attrs;
 245
 246        status = mgr_new->fxns.create_fxn(&mgr_new->target, &zl_attrs);
 247
 248        if (status) {
 249                cod_delete(mgr_new);
 250                return -ESPIPE;
 251        }
 252
 253        /* return the new manager */
 254        *mgr = mgr_new;
 255
 256        return 0;
 257}
 258
 259/*
 260 *  ======== cod_delete ========
 261 *  Purpose:
 262 *      Delete a code manager object.
 263 */
 264void cod_delete(struct cod_manager *cod_mgr_obj)
 265{
 266        DBC_REQUIRE(refs > 0);
 267        DBC_REQUIRE(cod_mgr_obj);
 268
 269        if (cod_mgr_obj->base_lib) {
 270                if (cod_mgr_obj->loaded)
 271                        cod_mgr_obj->fxns.unload_fxn(cod_mgr_obj->base_lib,
 272                                                        &cod_mgr_obj->attrs);
 273
 274                cod_mgr_obj->fxns.close_fxn(cod_mgr_obj->base_lib);
 275        }
 276        if (cod_mgr_obj->target) {
 277                cod_mgr_obj->fxns.delete_fxn(cod_mgr_obj->target);
 278                cod_mgr_obj->fxns.exit_fxn();
 279        }
 280        kfree(cod_mgr_obj);
 281}
 282
 283/*
 284 *  ======== cod_exit ========
 285 *  Purpose:
 286 *      Discontinue usage of the COD module.
 287 *
 288 */
 289void cod_exit(void)
 290{
 291        DBC_REQUIRE(refs > 0);
 292
 293        refs--;
 294
 295        DBC_ENSURE(refs >= 0);
 296}
 297
 298/*
 299 *  ======== cod_get_base_lib ========
 300 *  Purpose:
 301 *      Get handle to the base image DBL library.
 302 */
 303int cod_get_base_lib(struct cod_manager *cod_mgr_obj,
 304                            struct dbll_library_obj **plib)
 305{
 306        int status = 0;
 307
 308        DBC_REQUIRE(refs > 0);
 309        DBC_REQUIRE(cod_mgr_obj);
 310        DBC_REQUIRE(plib != NULL);
 311
 312        *plib = (struct dbll_library_obj *)cod_mgr_obj->base_lib;
 313
 314        return status;
 315}
 316
 317/*
 318 *  ======== cod_get_base_name ========
 319 */
 320int cod_get_base_name(struct cod_manager *cod_mgr_obj, char *sz_name,
 321                             u32 usize)
 322{
 323        int status = 0;
 324
 325        DBC_REQUIRE(refs > 0);
 326        DBC_REQUIRE(cod_mgr_obj);
 327        DBC_REQUIRE(sz_name != NULL);
 328
 329        if (usize <= COD_MAXPATHLENGTH)
 330                strncpy(sz_name, cod_mgr_obj->sz_zl_file, usize);
 331        else
 332                status = -EPERM;
 333
 334        return status;
 335}
 336
 337/*
 338 *  ======== cod_get_entry ========
 339 *  Purpose:
 340 *      Retrieve the entry point of a loaded DSP program image
 341 *
 342 */
 343int cod_get_entry(struct cod_manager *cod_mgr_obj, u32 *entry_pt)
 344{
 345        DBC_REQUIRE(refs > 0);
 346        DBC_REQUIRE(cod_mgr_obj);
 347        DBC_REQUIRE(entry_pt != NULL);
 348
 349        *entry_pt = cod_mgr_obj->entry;
 350
 351        return 0;
 352}
 353
 354/*
 355 *  ======== cod_get_loader ========
 356 *  Purpose:
 357 *      Get handle to the DBLL loader.
 358 */
 359int cod_get_loader(struct cod_manager *cod_mgr_obj,
 360                          struct dbll_tar_obj **loader)
 361{
 362        int status = 0;
 363
 364        DBC_REQUIRE(refs > 0);
 365        DBC_REQUIRE(cod_mgr_obj);
 366        DBC_REQUIRE(loader != NULL);
 367
 368        *loader = (struct dbll_tar_obj *)cod_mgr_obj->target;
 369
 370        return status;
 371}
 372
 373/*
 374 *  ======== cod_get_section ========
 375 *  Purpose:
 376 *      Retrieve the starting address and length of a section in the COFF file
 377 *      given the section name.
 378 */
 379int cod_get_section(struct cod_libraryobj *lib, char *str_sect,
 380                           u32 *addr, u32 *len)
 381{
 382        struct cod_manager *cod_mgr_obj;
 383        int status = 0;
 384
 385        DBC_REQUIRE(refs > 0);
 386        DBC_REQUIRE(lib != NULL);
 387        DBC_REQUIRE(lib->cod_mgr);
 388        DBC_REQUIRE(str_sect != NULL);
 389        DBC_REQUIRE(addr != NULL);
 390        DBC_REQUIRE(len != NULL);
 391
 392        *addr = 0;
 393        *len = 0;
 394        if (lib != NULL) {
 395                cod_mgr_obj = lib->cod_mgr;
 396                status = cod_mgr_obj->fxns.get_sect_fxn(lib->dbll_lib, str_sect,
 397                                                        addr, len);
 398        } else {
 399                status = -ESPIPE;
 400        }
 401
 402        DBC_ENSURE(!status || ((*addr == 0) && (*len == 0)));
 403
 404        return status;
 405}
 406
 407/*
 408 *  ======== cod_get_sym_value ========
 409 *  Purpose:
 410 *      Retrieve the value for the specified symbol. The symbol is first
 411 *      searched for literally and then, if not found, searched for as a
 412 *      C symbol.
 413 *
 414 */
 415int cod_get_sym_value(struct cod_manager *cod_mgr_obj, char *str_sym,
 416                             u32 *pul_value)
 417{
 418        struct dbll_sym_val *dbll_sym;
 419
 420        DBC_REQUIRE(refs > 0);
 421        DBC_REQUIRE(cod_mgr_obj);
 422        DBC_REQUIRE(str_sym != NULL);
 423        DBC_REQUIRE(pul_value != NULL);
 424
 425        dev_dbg(bridge, "%s: cod_mgr_obj: %p str_sym: %s pul_value: %p\n",
 426                __func__, cod_mgr_obj, str_sym, pul_value);
 427        if (cod_mgr_obj->base_lib) {
 428                if (!cod_mgr_obj->fxns.
 429                    get_addr_fxn(cod_mgr_obj->base_lib, str_sym, &dbll_sym)) {
 430                        if (!cod_mgr_obj->fxns.
 431                            get_c_addr_fxn(cod_mgr_obj->base_lib, str_sym,
 432                                                &dbll_sym))
 433                                return -ESPIPE;
 434                }
 435        } else {
 436                return -ESPIPE;
 437        }
 438
 439        *pul_value = dbll_sym->value;
 440
 441        return 0;
 442}
 443
 444/*
 445 *  ======== cod_init ========
 446 *  Purpose:
 447 *      Initialize the COD module's private state.
 448 *
 449 */
 450bool cod_init(void)
 451{
 452        bool ret = true;
 453
 454        DBC_REQUIRE(refs >= 0);
 455
 456        if (ret)
 457                refs++;
 458
 459        DBC_ENSURE((ret && refs > 0) || (!ret && refs >= 0));
 460        return ret;
 461}
 462
 463/*
 464 *  ======== cod_load_base ========
 465 *  Purpose:
 466 *      Load the initial program image, optionally with command-line arguments,
 467 *      on the DSP system managed by the supplied handle. The program to be
 468 *      loaded must be the first element of the args array and must be a fully
 469 *      qualified pathname.
 470 *  Details:
 471 *      if num_argc doesn't match the number of arguments in the args array, the
 472 *      args array is searched for a NULL terminating entry, and argc is
 473 *      recalculated to reflect this.  In this way, we can support NULL
 474 *      terminating args arrays, if num_argc is very large.
 475 */
 476int cod_load_base(struct cod_manager *cod_mgr_obj, u32 num_argc, char *args[],
 477                         cod_writefxn pfn_write, void *arb, char *envp[])
 478{
 479        dbll_flags flags;
 480        struct dbll_attrs save_attrs;
 481        struct dbll_attrs new_attrs;
 482        int status;
 483        u32 i;
 484
 485        DBC_REQUIRE(refs > 0);
 486        DBC_REQUIRE(cod_mgr_obj);
 487        DBC_REQUIRE(num_argc > 0);
 488        DBC_REQUIRE(args != NULL);
 489        DBC_REQUIRE(args[0] != NULL);
 490        DBC_REQUIRE(pfn_write != NULL);
 491        DBC_REQUIRE(cod_mgr_obj->base_lib != NULL);
 492
 493        /*
 494         *  Make sure every argv[] stated in argc has a value, or change argc to
 495         *  reflect true number in NULL terminated argv array.
 496         */
 497        for (i = 0; i < num_argc; i++) {
 498                if (args[i] == NULL) {
 499                        num_argc = i;
 500                        break;
 501                }
 502        }
 503
 504        /* set the write function for this operation */
 505        cod_mgr_obj->fxns.get_attrs_fxn(cod_mgr_obj->target, &save_attrs);
 506
 507        new_attrs = save_attrs;
 508        new_attrs.write = (dbll_write_fxn) pfn_write;
 509        new_attrs.input_params = arb;
 510        new_attrs.alloc = (dbll_alloc_fxn) no_op;
 511        new_attrs.free = (dbll_free_fxn) no_op;
 512        new_attrs.log_write = NULL;
 513        new_attrs.log_write_handle = NULL;
 514
 515        /* Load the image */
 516        flags = DBLL_CODE | DBLL_DATA | DBLL_SYMB;
 517        status = cod_mgr_obj->fxns.load_fxn(cod_mgr_obj->base_lib, flags,
 518                                            &new_attrs,
 519                                            &cod_mgr_obj->entry);
 520        if (status)
 521                cod_mgr_obj->fxns.close_fxn(cod_mgr_obj->base_lib);
 522
 523        if (!status)
 524                cod_mgr_obj->loaded = true;
 525        else
 526                cod_mgr_obj->base_lib = NULL;
 527
 528        return status;
 529}
 530
 531/*
 532 *  ======== cod_open ========
 533 *      Open library for reading sections.
 534 */
 535int cod_open(struct cod_manager *hmgr, char *sz_coff_path,
 536                    u32 flags, struct cod_libraryobj **lib_obj)
 537{
 538        int status = 0;
 539        struct cod_libraryobj *lib = NULL;
 540
 541        DBC_REQUIRE(refs > 0);
 542        DBC_REQUIRE(hmgr);
 543        DBC_REQUIRE(sz_coff_path != NULL);
 544        DBC_REQUIRE(flags == COD_NOLOAD || flags == COD_SYMB);
 545        DBC_REQUIRE(lib_obj != NULL);
 546
 547        *lib_obj = NULL;
 548
 549        lib = kzalloc(sizeof(struct cod_libraryobj), GFP_KERNEL);
 550        if (lib == NULL)
 551                status = -ENOMEM;
 552
 553        if (!status) {
 554                lib->cod_mgr = hmgr;
 555                status = hmgr->fxns.open_fxn(hmgr->target, sz_coff_path, flags,
 556                                             &lib->dbll_lib);
 557                if (!status)
 558                        *lib_obj = lib;
 559        }
 560
 561        if (status)
 562                pr_err("%s: error status 0x%x, sz_coff_path: %s flags: 0x%x\n",
 563                       __func__, status, sz_coff_path, flags);
 564        return status;
 565}
 566
 567/*
 568 *  ======== cod_open_base ========
 569 *  Purpose:
 570 *      Open base image for reading sections.
 571 */
 572int cod_open_base(struct cod_manager *hmgr, char *sz_coff_path,
 573                         dbll_flags flags)
 574{
 575        int status = 0;
 576        struct dbll_library_obj *lib;
 577
 578        DBC_REQUIRE(refs > 0);
 579        DBC_REQUIRE(hmgr);
 580        DBC_REQUIRE(sz_coff_path != NULL);
 581
 582        /* if we previously opened a base image, close it now */
 583        if (hmgr->base_lib) {
 584                if (hmgr->loaded) {
 585                        hmgr->fxns.unload_fxn(hmgr->base_lib, &hmgr->attrs);
 586                        hmgr->loaded = false;
 587                }
 588                hmgr->fxns.close_fxn(hmgr->base_lib);
 589                hmgr->base_lib = NULL;
 590        }
 591        status = hmgr->fxns.open_fxn(hmgr->target, sz_coff_path, flags, &lib);
 592        if (!status) {
 593                /* hang onto the library for subsequent sym table usage */
 594                hmgr->base_lib = lib;
 595                strncpy(hmgr->sz_zl_file, sz_coff_path, COD_MAXPATHLENGTH - 1);
 596                hmgr->sz_zl_file[COD_MAXPATHLENGTH - 1] = '\0';
 597        }
 598
 599        if (status)
 600                pr_err("%s: error status 0x%x sz_coff_path: %s\n", __func__,
 601                       status, sz_coff_path);
 602        return status;
 603}
 604
 605/*
 606 *  ======== cod_read_section ========
 607 *  Purpose:
 608 *      Retrieve the content of a code section given the section name.
 609 */
 610int cod_read_section(struct cod_libraryobj *lib, char *str_sect,
 611                            char *str_content, u32 content_size)
 612{
 613        int status = 0;
 614
 615        DBC_REQUIRE(refs > 0);
 616        DBC_REQUIRE(lib != NULL);
 617        DBC_REQUIRE(lib->cod_mgr);
 618        DBC_REQUIRE(str_sect != NULL);
 619        DBC_REQUIRE(str_content != NULL);
 620
 621        if (lib != NULL)
 622                status =
 623                    lib->cod_mgr->fxns.read_sect_fxn(lib->dbll_lib, str_sect,
 624                                                     str_content, content_size);
 625        else
 626                status = -ESPIPE;
 627
 628        return status;
 629}
 630
 631/*
 632 *  ======== no_op ========
 633 *  Purpose:
 634 *      No Operation.
 635 *
 636 */
 637static bool no_op(void)
 638{
 639        return true;
 640}
 641