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