1/* 2 * dbdcd.c 3 * 4 * DSP-BIOS Bridge driver support functions for TI OMAP processors. 5 * 6 * This file contains the implementation of the DSP/BIOS Bridge 7 * Configuration Database (DCD). 8 * 9 * Notes: 10 * The fxn dcd_get_objects can apply a callback fxn to each DCD object 11 * that is located in a specified COFF file. At the moment, 12 * dcd_auto_register, dcd_auto_unregister, and NLDR module all use 13 * dcd_get_objects. 14 * 15 * Copyright (C) 2005-2006 Texas Instruments, Inc. 16 * 17 * This package is free software; you can redistribute it and/or modify 18 * it under the terms of the GNU General Public License version 2 as 19 * published by the Free Software Foundation. 20 * 21 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 23 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 24 */ 25#include <linux/types.h> 26 27/* ----------------------------------- Host OS */ 28#include <dspbridge/host_os.h> 29 30/* ----------------------------------- DSP/BIOS Bridge */ 31#include <dspbridge/dbdefs.h> 32/* ----------------------------------- Trace & Debug */ 33#include <dspbridge/dbc.h> 34 35/* ----------------------------------- Platform Manager */ 36#include <dspbridge/cod.h> 37 38/* ----------------------------------- Others */ 39#include <dspbridge/uuidutil.h> 40 41/* ----------------------------------- This */ 42#include <dspbridge/dbdcd.h> 43 44/* ----------------------------------- Global defines. */ 45#define MAX_INT2CHAR_LENGTH 16 /* Max int2char len of 32 bit int */ 46 47/* Name of section containing dependent libraries */ 48#define DEPLIBSECT ".dspbridge_deplibs" 49 50/* DCD specific structures. */ 51struct dcd_manager { 52 struct cod_manager *cod_mgr; /* Handle to COD manager object. */ 53}; 54 55/* Pointer to the registry support key */ 56static struct list_head reg_key_list; 57static DEFINE_SPINLOCK(dbdcd_lock); 58 59/* Global reference variables. */ 60static u32 refs; 61static u32 enum_refs; 62 63/* Helper function prototypes. */ 64static s32 atoi(char *psz_buf); 65static int get_attrs_from_buf(char *psz_buf, u32 ul_buf_size, 66 enum dsp_dcdobjtype obj_type, 67 struct dcd_genericobj *gen_obj); 68static void compress_buf(char *psz_buf, u32 ul_buf_size, s32 char_size); 69static char dsp_char2_gpp_char(char *word, s32 dsp_char_size); 70static int get_dep_lib_info(struct dcd_manager *hdcd_mgr, 71 struct dsp_uuid *uuid_obj, 72 u16 *num_libs, 73 u16 *num_pers_libs, 74 struct dsp_uuid *dep_lib_uuids, 75 bool *prstnt_dep_libs, 76 enum nldr_phase phase); 77 78/* 79 * ======== dcd_auto_register ======== 80 * Purpose: 81 * Parses the supplied image and resigsters with DCD. 82 */ 83int dcd_auto_register(struct dcd_manager *hdcd_mgr, 84 char *sz_coff_path) 85{ 86 int status = 0; 87 88 DBC_REQUIRE(refs > 0); 89 90 if (hdcd_mgr) 91 status = dcd_get_objects(hdcd_mgr, sz_coff_path, 92 (dcd_registerfxn) dcd_register_object, 93 (void *)sz_coff_path); 94 else 95 status = -EFAULT; 96 97 return status; 98} 99 100/* 101 * ======== dcd_auto_unregister ======== 102 * Purpose: 103 * Parses the supplied DSP image and unresiters from DCD. 104 */ 105int dcd_auto_unregister(struct dcd_manager *hdcd_mgr, 106 char *sz_coff_path) 107{ 108 int status = 0; 109 110 DBC_REQUIRE(refs > 0); 111 112 if (hdcd_mgr) 113 status = dcd_get_objects(hdcd_mgr, sz_coff_path, 114 (dcd_registerfxn) dcd_register_object, 115 NULL); 116 else 117 status = -EFAULT; 118 119 return status; 120} 121 122/* 123 * ======== dcd_create_manager ======== 124 * Purpose: 125 * Creates DCD manager. 126 */ 127int dcd_create_manager(char *sz_zl_dll_name, 128 struct dcd_manager **dcd_mgr) 129{ 130 struct cod_manager *cod_mgr; /* COD manager handle */ 131 struct dcd_manager *dcd_mgr_obj = NULL; /* DCD Manager pointer */ 132 int status = 0; 133 134 DBC_REQUIRE(refs >= 0); 135 DBC_REQUIRE(dcd_mgr); 136 137 status = cod_create(&cod_mgr, sz_zl_dll_name, NULL); 138 if (status) 139 goto func_end; 140 141 /* Create a DCD object. */ 142 dcd_mgr_obj = kzalloc(sizeof(struct dcd_manager), GFP_KERNEL); 143 if (dcd_mgr_obj != NULL) { 144 /* Fill out the object. */ 145 dcd_mgr_obj->cod_mgr = cod_mgr; 146 147 /* Return handle to this DCD interface. */ 148 *dcd_mgr = dcd_mgr_obj; 149 } else { 150 status = -ENOMEM; 151 152 /* 153 * If allocation of DcdManager object failed, delete the 154 * COD manager. 155 */ 156 cod_delete(cod_mgr); 157 } 158 159 DBC_ENSURE((!status) || 160 ((dcd_mgr_obj == NULL) && (status == -ENOMEM))); 161 162func_end: 163 return status; 164} 165 166/* 167 * ======== dcd_destroy_manager ======== 168 * Purpose: 169 * Frees DCD Manager object. 170 */ 171int dcd_destroy_manager(struct dcd_manager *hdcd_mgr) 172{ 173 struct dcd_manager *dcd_mgr_obj = hdcd_mgr; 174 int status = -EFAULT; 175 176 DBC_REQUIRE(refs >= 0); 177 178 if (hdcd_mgr) { 179 /* Delete the COD manager. */ 180 cod_delete(dcd_mgr_obj->cod_mgr); 181 182 /* Deallocate a DCD manager object. */ 183 kfree(dcd_mgr_obj); 184 185 status = 0; 186 } 187 188 return status; 189} 190 191/* 192 * ======== dcd_enumerate_object ======== 193 * Purpose: 194 * Enumerates objects in the DCD. 195 */ 196int dcd_enumerate_object(s32 index, enum dsp_dcdobjtype obj_type, 197 struct dsp_uuid *uuid_obj) 198{ 199 int status = 0; 200 char sz_reg_key[DCD_MAXPATHLENGTH]; 201 char sz_value[DCD_MAXPATHLENGTH]; 202 struct dsp_uuid dsp_uuid_obj; 203 char sz_obj_type[MAX_INT2CHAR_LENGTH]; /* str. rep. of obj_type. */ 204 u32 dw_key_len = 0; 205 struct dcd_key_elem *dcd_key; 206 int len; 207 208 DBC_REQUIRE(refs >= 0); 209 DBC_REQUIRE(index >= 0); 210 DBC_REQUIRE(uuid_obj != NULL); 211 212 if ((index != 0) && (enum_refs == 0)) { 213 /* 214 * If an enumeration is being performed on an index greater 215 * than zero, then the current enum_refs must have been 216 * incremented to greater than zero. 217 */ 218 status = -EIDRM; 219 } else { 220 /* 221 * Pre-determine final key length. It's length of DCD_REGKEY + 222 * "_\0" + length of sz_obj_type string + terminating NULL. 223 */ 224 dw_key_len = strlen(DCD_REGKEY) + 1 + sizeof(sz_obj_type) + 1; 225 DBC_ASSERT(dw_key_len < DCD_MAXPATHLENGTH); 226 227 /* Create proper REG key; concatenate DCD_REGKEY with 228 * obj_type. */ 229 strncpy(sz_reg_key, DCD_REGKEY, strlen(DCD_REGKEY) + 1); 230 if ((strlen(sz_reg_key) + strlen("_\0")) < 231 DCD_MAXPATHLENGTH) { 232 strncat(sz_reg_key, "_\0", 2); 233 } else { 234 status = -EPERM; 235 } 236 237 /* This snprintf is guaranteed not to exceed max size of an 238 * integer. */ 239 status = snprintf(sz_obj_type, MAX_INT2CHAR_LENGTH, "%d", 240 obj_type); 241 242 if (status == -1) { 243 status = -EPERM; 244 } else { 245 status = 0; 246 if ((strlen(sz_reg_key) + strlen(sz_obj_type)) < 247 DCD_MAXPATHLENGTH) { 248 strncat(sz_reg_key, sz_obj_type, 249 strlen(sz_obj_type) + 1); 250 } else { 251 status = -EPERM; 252 } 253 } 254 255 if (!status) { 256 len = strlen(sz_reg_key); 257 spin_lock(&dbdcd_lock); 258 list_for_each_entry(dcd_key, ®_key_list, link) { 259 if (!strncmp(dcd_key->name, sz_reg_key, len) 260 && !index--) { 261 strncpy(sz_value, &dcd_key->name[len], 262 strlen(&dcd_key->name[len]) + 1); 263 break; 264 } 265 } 266 spin_unlock(&dbdcd_lock); 267 268 if (&dcd_key->link == ®_key_list) 269 status = -ENODATA; 270 } 271 272 if (!status) { 273 /* Create UUID value using string retrieved from 274 * registry. */ 275 uuid_uuid_from_string(sz_value, &dsp_uuid_obj); 276 277 *uuid_obj = dsp_uuid_obj; 278 279 /* Increment enum_refs to update reference count. */ 280 enum_refs++; 281 282 status = 0; 283 } else if (status == -ENODATA) { 284 /* At the end of enumeration. Reset enum_refs. */ 285 enum_refs = 0; 286 287 /* 288 * TODO: Revisit, this is not an errror case but code 289 * expects non-zero value. 290 */ 291 status = ENODATA; 292 } else { 293 status = -EPERM; 294 } 295 } 296 297 DBC_ENSURE(uuid_obj || (status == -EPERM)); 298 299 return status; 300} 301 302/* 303 * ======== dcd_exit ======== 304 * Purpose: 305 * Discontinue usage of the DCD module. 306 */ 307void dcd_exit(void) 308{ 309 struct dcd_key_elem *rv, *rv_tmp; 310 DBC_REQUIRE(refs > 0); 311 312 refs--; 313 if (refs == 0) { 314 cod_exit(); 315 list_for_each_entry_safe(rv, rv_tmp, ®_key_list, link) { 316 list_del(&rv->link); 317 kfree(rv->path); 318 kfree(rv); 319 } 320 } 321 322 DBC_ENSURE(refs >= 0); 323} 324 325/* 326 * ======== dcd_get_dep_libs ======== 327 */ 328int dcd_get_dep_libs(struct dcd_manager *hdcd_mgr, 329 struct dsp_uuid *uuid_obj, 330 u16 num_libs, struct dsp_uuid *dep_lib_uuids, 331 bool *prstnt_dep_libs, 332 enum nldr_phase phase) 333{ 334 int status = 0; 335 336 DBC_REQUIRE(refs > 0); 337 DBC_REQUIRE(hdcd_mgr); 338 DBC_REQUIRE(uuid_obj != NULL); 339 DBC_REQUIRE(dep_lib_uuids != NULL); 340 DBC_REQUIRE(prstnt_dep_libs != NULL); 341 342 status = 343 get_dep_lib_info(hdcd_mgr, uuid_obj, &num_libs, NULL, dep_lib_uuids, 344 prstnt_dep_libs, phase); 345 346 return status; 347} 348 349/* 350 * ======== dcd_get_num_dep_libs ======== 351 */ 352int dcd_get_num_dep_libs(struct dcd_manager *hdcd_mgr, 353 struct dsp_uuid *uuid_obj, 354 u16 *num_libs, u16 *num_pers_libs, 355 enum nldr_phase phase) 356{ 357 int status = 0; 358 359 DBC_REQUIRE(refs > 0); 360 DBC_REQUIRE(hdcd_mgr); 361 DBC_REQUIRE(num_libs != NULL); 362 DBC_REQUIRE(num_pers_libs != NULL); 363 DBC_REQUIRE(uuid_obj != NULL); 364 365 status = get_dep_lib_info(hdcd_mgr, uuid_obj, num_libs, num_pers_libs, 366 NULL, NULL, phase); 367 368 return status; 369} 370 371/* 372 * ======== dcd_get_object_def ======== 373 * Purpose: 374 * Retrieves the properties of a node or processor based on the UUID and 375 * object type. 376 */ 377int dcd_get_object_def(struct dcd_manager *hdcd_mgr, 378 struct dsp_uuid *obj_uuid, 379 enum dsp_dcdobjtype obj_type, 380 struct dcd_genericobj *obj_def) 381{ 382 struct dcd_manager *dcd_mgr_obj = hdcd_mgr; /* ptr to DCD mgr */ 383 struct cod_libraryobj *lib = NULL; 384 int status = 0; 385 u32 ul_addr = 0; /* Used by cod_get_section */ 386 u32 ul_len = 0; /* Used by cod_get_section */ 387 u32 dw_buf_size; /* Used by REG functions */ 388 char sz_reg_key[DCD_MAXPATHLENGTH]; 389 char *sz_uuid; /*[MAXUUIDLEN]; */ 390 struct dcd_key_elem *dcd_key = NULL; 391 char sz_sect_name[MAXUUIDLEN + 2]; /* ".[UUID]\0" */ 392 char *psz_coff_buf; 393 u32 dw_key_len; /* Len of REG key. */ 394 char sz_obj_type[MAX_INT2CHAR_LENGTH]; /* str. rep. of obj_type. */ 395 396 DBC_REQUIRE(refs > 0); 397 DBC_REQUIRE(obj_def != NULL); 398 DBC_REQUIRE(obj_uuid != NULL); 399 400 sz_uuid = kzalloc(MAXUUIDLEN, GFP_KERNEL); 401 if (!sz_uuid) { 402 status = -ENOMEM; 403 goto func_end; 404 } 405 406 if (!hdcd_mgr) { 407 status = -EFAULT; 408 goto func_end; 409 } 410 411 /* Pre-determine final key length. It's length of DCD_REGKEY + 412 * "_\0" + length of sz_obj_type string + terminating NULL */ 413 dw_key_len = strlen(DCD_REGKEY) + 1 + sizeof(sz_obj_type) + 1; 414 DBC_ASSERT(dw_key_len < DCD_MAXPATHLENGTH); 415 416 /* Create proper REG key; concatenate DCD_REGKEY with obj_type. */ 417 strncpy(sz_reg_key, DCD_REGKEY, strlen(DCD_REGKEY) + 1); 418 419 if ((strlen(sz_reg_key) + strlen("_\0")) < DCD_MAXPATHLENGTH) 420 strncat(sz_reg_key, "_\0", 2); 421 else 422 status = -EPERM; 423 424 status = snprintf(sz_obj_type, MAX_INT2CHAR_LENGTH, "%d", obj_type); 425 if (status == -1) { 426 status = -EPERM; 427 } else { 428 status = 0; 429 430 if ((strlen(sz_reg_key) + strlen(sz_obj_type)) < 431 DCD_MAXPATHLENGTH) { 432 strncat(sz_reg_key, sz_obj_type, 433 strlen(sz_obj_type) + 1); 434 } else { 435 status = -EPERM; 436 } 437 438 /* Create UUID value to set in registry. */ 439 uuid_uuid_to_string(obj_uuid, sz_uuid, MAXUUIDLEN); 440 441 if ((strlen(sz_reg_key) + MAXUUIDLEN) < DCD_MAXPATHLENGTH) 442 strncat(sz_reg_key, sz_uuid, MAXUUIDLEN); 443 else 444 status = -EPERM; 445 446 /* Retrieve paths from the registry based on struct dsp_uuid */ 447 dw_buf_size = DCD_MAXPATHLENGTH; 448 } 449 if (!status) { 450 spin_lock(&dbdcd_lock); 451 list_for_each_entry(dcd_key, ®_key_list, link) { 452 if (!strncmp(dcd_key->name, sz_reg_key, 453 strlen(sz_reg_key) + 1)) 454 break; 455 } 456 spin_unlock(&dbdcd_lock); 457 if (&dcd_key->link == ®_key_list) { 458 status = -ENOKEY; 459 goto func_end; 460 } 461 } 462 463 464 /* Open COFF file. */ 465 status = cod_open(dcd_mgr_obj->cod_mgr, dcd_key->path, 466 COD_NOLOAD, &lib); 467 if (status) { 468 status = -EACCES; 469 goto func_end; 470 } 471 472 /* Ensure sz_uuid + 1 is not greater than sizeof sz_sect_name. */ 473 DBC_ASSERT((strlen(sz_uuid) + 1) < sizeof(sz_sect_name)); 474 475 /* Create section name based on node UUID. A period is 476 * pre-pended to the UUID string to form the section name. 477 * I.e. ".24BC8D90_BB45_11d4_B756_006008BDB66F" */ 478 strncpy(sz_sect_name, ".", 2); 479 strncat(sz_sect_name, sz_uuid, strlen(sz_uuid)); 480 481 /* Get section information. */ 482 status = cod_get_section(lib, sz_sect_name, &ul_addr, &ul_len); 483 if (status) { 484 status = -EACCES; 485 goto func_end; 486 } 487 488 /* Allocate zeroed buffer. */ 489 psz_coff_buf = kzalloc(ul_len + 4, GFP_KERNEL); 490#ifdef _DB_TIOMAP 491 if (strstr(dcd_key->path, "iva") == NULL) { 492 /* Locate section by objectID and read its content. */ 493 status = 494 cod_read_section(lib, sz_sect_name, psz_coff_buf, ul_len); 495 } else { 496 status = 497 cod_read_section(lib, sz_sect_name, psz_coff_buf, ul_len); 498 dev_dbg(bridge, "%s: Skipped Byte swap for IVA!!\n", __func__); 499 } 500#else 501 status = cod_read_section(lib, sz_sect_name, psz_coff_buf, ul_len); 502#endif 503 if (!status) { 504 /* Compres DSP buffer to conform to PC format. */ 505 if (strstr(dcd_key->path, "iva") == NULL) { 506 compress_buf(psz_coff_buf, ul_len, DSPWORDSIZE); 507 } else { 508 compress_buf(psz_coff_buf, ul_len, 1); 509 dev_dbg(bridge, "%s: Compressing IVA COFF buffer by 1 " 510 "for IVA!!\n", __func__); 511 } 512 513 /* Parse the content of the COFF buffer. */ 514 status = 515 get_attrs_from_buf(psz_coff_buf, ul_len, obj_type, obj_def); 516 if (status) 517 status = -EACCES; 518 } else { 519 status = -EACCES; 520 } 521 522 /* Free the previously allocated dynamic buffer. */ 523 kfree(psz_coff_buf); 524func_end: 525 if (lib) 526 cod_close(lib); 527 528 kfree(sz_uuid); 529 530 return status; 531} 532 533/* 534 * ======== dcd_get_objects ======== 535 */ 536int dcd_get_objects(struct dcd_manager *hdcd_mgr, 537 char *sz_coff_path, dcd_registerfxn register_fxn, 538 void *handle) 539{ 540 struct dcd_manager *dcd_mgr_obj = hdcd_mgr; 541 int status = 0; 542 char *psz_coff_buf; 543 char *psz_cur; 544 struct cod_libraryobj *lib = NULL; 545 u32 ul_addr = 0; /* Used by cod_get_section */ 546 u32 ul_len = 0; /* Used by cod_get_section */ 547 char seps[] = ":, "; 548 char *token = NULL; 549 struct dsp_uuid dsp_uuid_obj; 550 s32 object_type; 551 552 DBC_REQUIRE(refs > 0); 553 if (!hdcd_mgr) { 554 status = -EFAULT; 555 goto func_end; 556 } 557 558 /* Open DSP coff file, don't load symbols. */ 559 status = cod_open(dcd_mgr_obj->cod_mgr, sz_coff_path, COD_NOLOAD, &lib); 560 if (status) { 561 status = -EACCES; 562 goto func_cont; 563 } 564 565 /* Get DCD_RESIGER_SECTION section information. */ 566 status = cod_get_section(lib, DCD_REGISTER_SECTION, &ul_addr, &ul_len); 567 if (status || !(ul_len > 0)) { 568 status = -EACCES; 569 goto func_cont; 570 } 571 572 /* Allocate zeroed buffer. */ 573 psz_coff_buf = kzalloc(ul_len + 4, GFP_KERNEL); 574#ifdef _DB_TIOMAP 575 if (strstr(sz_coff_path, "iva") == NULL) { 576 /* Locate section by objectID and read its content. */ 577 status = cod_read_section(lib, DCD_REGISTER_SECTION, 578 psz_coff_buf, ul_len); 579 } else { 580 dev_dbg(bridge, "%s: Skipped Byte swap for IVA!!\n", __func__); 581 status = cod_read_section(lib, DCD_REGISTER_SECTION, 582 psz_coff_buf, ul_len); 583 } 584#else 585 status = 586 cod_read_section(lib, DCD_REGISTER_SECTION, psz_coff_buf, ul_len); 587#endif 588 if (!status) { 589 /* Compress DSP buffer to conform to PC format. */ 590 if (strstr(sz_coff_path, "iva") == NULL) { 591 compress_buf(psz_coff_buf, ul_len, DSPWORDSIZE); 592 } else { 593 compress_buf(psz_coff_buf, ul_len, 1); 594 dev_dbg(bridge, "%s: Compress COFF buffer with 1 word " 595 "for IVA!!\n", __func__); 596 } 597 598 /* Read from buffer and register object in buffer. */ 599 psz_cur = psz_coff_buf; 600 while ((token = strsep(&psz_cur, seps)) && *token != '\0') { 601 /* Retrieve UUID string. */ 602 uuid_uuid_from_string(token, &dsp_uuid_obj); 603 604 /* Retrieve object type */ 605 token = strsep(&psz_cur, seps); 606 607 /* Retrieve object type */ 608 object_type = atoi(token); 609 610 /* 611 * Apply register_fxn to the found DCD object. 612 * Possible actions include: 613 * 614 * 1) Register found DCD object. 615 * 2) Unregister found DCD object (when handle == NULL) 616 * 3) Add overlay node. 617 */ 618 status = 619 register_fxn(&dsp_uuid_obj, object_type, handle); 620 if (status) { 621 /* if error occurs, break from while loop. */ 622 break; 623 } 624 } 625 } else { 626 status = -EACCES; 627 } 628 629 /* Free the previously allocated dynamic buffer. */ 630 kfree(psz_coff_buf); 631func_cont: 632 if (lib) 633 cod_close(lib); 634 635func_end: 636 return status; 637} 638 639/* 640 * ======== dcd_get_library_name ======== 641 * Purpose: 642 * Retrieves the library name for the given UUID. 643 * 644 */ 645int dcd_get_library_name(struct dcd_manager *hdcd_mgr, 646 struct dsp_uuid *uuid_obj, 647 char *str_lib_name, 648 u32 *buff_size, 649 enum nldr_phase phase, bool *phase_split) 650{ 651 char sz_reg_key[DCD_MAXPATHLENGTH]; 652 char sz_uuid[MAXUUIDLEN]; 653 u32 dw_key_len; /* Len of REG key. */ 654 char sz_obj_type[MAX_INT2CHAR_LENGTH]; /* str. rep. of obj_type. */ 655 int status = 0; 656 struct dcd_key_elem *dcd_key = NULL; 657 658 DBC_REQUIRE(uuid_obj != NULL); 659 DBC_REQUIRE(str_lib_name != NULL); 660 DBC_REQUIRE(buff_size != NULL); 661 DBC_REQUIRE(hdcd_mgr); 662 663 dev_dbg(bridge, "%s: hdcd_mgr %p, uuid_obj %p, str_lib_name %p," 664 " buff_size %p\n", __func__, hdcd_mgr, uuid_obj, str_lib_name, 665 buff_size); 666 667 /* 668 * Pre-determine final key length. It's length of DCD_REGKEY + 669 * "_\0" + length of sz_obj_type string + terminating NULL. 670 */ 671 dw_key_len = strlen(DCD_REGKEY) + 1 + sizeof(sz_obj_type) + 1; 672 DBC_ASSERT(dw_key_len < DCD_MAXPATHLENGTH); 673 674 /* Create proper REG key; concatenate DCD_REGKEY with obj_type. */ 675 strncpy(sz_reg_key, DCD_REGKEY, strlen(DCD_REGKEY) + 1); 676 if ((strlen(sz_reg_key) + strlen("_\0")) < DCD_MAXPATHLENGTH) 677 strncat(sz_reg_key, "_\0", 2); 678 else 679 status = -EPERM; 680 681 switch (phase) { 682 case NLDR_CREATE: 683 /* create phase type */ 684 sprintf(sz_obj_type, "%d", DSP_DCDCREATELIBTYPE); 685 break; 686 case NLDR_EXECUTE: 687 /* execute phase type */ 688 sprintf(sz_obj_type, "%d", DSP_DCDEXECUTELIBTYPE); 689 break; 690 case NLDR_DELETE: 691 /* delete phase type */ 692 sprintf(sz_obj_type, "%d", DSP_DCDDELETELIBTYPE); 693 break; 694 case NLDR_NOPHASE: 695 /* known to be a dependent library */ 696 sprintf(sz_obj_type, "%d", DSP_DCDLIBRARYTYPE); 697 break; 698 default: 699 status = -EINVAL; 700 DBC_ASSERT(false); 701 } 702 if (!status) { 703 if ((strlen(sz_reg_key) + strlen(sz_obj_type)) < 704 DCD_MAXPATHLENGTH) { 705 strncat(sz_reg_key, sz_obj_type, 706 strlen(sz_obj_type) + 1); 707 } else { 708 status = -EPERM; 709 } 710 /* Create UUID value to find match in registry. */ 711 uuid_uuid_to_string(uuid_obj, sz_uuid, MAXUUIDLEN); 712 if ((strlen(sz_reg_key) + MAXUUIDLEN) < DCD_MAXPATHLENGTH) 713 strncat(sz_reg_key, sz_uuid, MAXUUIDLEN); 714 else 715 status = -EPERM; 716 } 717 if (!status) { 718 spin_lock(&dbdcd_lock); 719 list_for_each_entry(dcd_key, ®_key_list, link) { 720 /* See if the name matches. */ 721 if (!strncmp(dcd_key->name, sz_reg_key, 722 strlen(sz_reg_key) + 1)) 723 break; 724 } 725 spin_unlock(&dbdcd_lock); 726 } 727 728 if (&dcd_key->link == ®_key_list) 729 status = -ENOKEY; 730 731 /* If can't find, phases might be registered as generic LIBRARYTYPE */ 732 if (status && phase != NLDR_NOPHASE) { 733 if (phase_split) 734 *phase_split = false; 735 736 strncpy(sz_reg_key, DCD_REGKEY, strlen(DCD_REGKEY) + 1); 737 if ((strlen(sz_reg_key) + strlen("_\0")) < 738 DCD_MAXPATHLENGTH) { 739 strncat(sz_reg_key, "_\0", 2); 740 } else { 741 status = -EPERM; 742 } 743 sprintf(sz_obj_type, "%d", DSP_DCDLIBRARYTYPE); 744 if ((strlen(sz_reg_key) + strlen(sz_obj_type)) 745 < DCD_MAXPATHLENGTH) { 746 strncat(sz_reg_key, sz_obj_type, 747 strlen(sz_obj_type) + 1); 748 } else { 749 status = -EPERM; 750 } 751 uuid_uuid_to_string(uuid_obj, sz_uuid, MAXUUIDLEN); 752 if ((strlen(sz_reg_key) + MAXUUIDLEN) < DCD_MAXPATHLENGTH) 753 strncat(sz_reg_key, sz_uuid, MAXUUIDLEN); 754 else 755 status = -EPERM; 756 757 spin_lock(&dbdcd_lock); 758 list_for_each_entry(dcd_key, ®_key_list, link) { 759 /* See if the name matches. */ 760 if (!strncmp(dcd_key->name, sz_reg_key, 761 strlen(sz_reg_key) + 1)) 762 break; 763 } 764 spin_unlock(&dbdcd_lock); 765 766 status = (&dcd_key->link != ®_key_list) ? 767 0 : -ENOKEY; 768 } 769 770 if (!status) 771 memcpy(str_lib_name, dcd_key->path, strlen(dcd_key->path) + 1); 772 return status; 773} 774 775/* 776 * ======== dcd_init ======== 777 * Purpose: 778 * Initialize the DCD module. 779 */ 780bool dcd_init(void) 781{ 782 bool init_cod; 783 bool ret = true; 784 785 DBC_REQUIRE(refs >= 0); 786 787 if (refs == 0) { 788 /* Initialize required modules. */ 789 init_cod = cod_init(); 790 791 if (!init_cod) { 792 ret = false; 793 /* Exit initialized modules. */ 794 if (init_cod) 795 cod_exit(); 796 } 797 798 INIT_LIST_HEAD(®_key_list); 799 } 800 801 if (ret) 802 refs++; 803 804 DBC_ENSURE((ret && (refs > 0)) || (!ret && (refs == 0))); 805 806 return ret; 807} 808 809/* 810 * ======== dcd_register_object ======== 811 * Purpose: 812 * Registers a node or a processor with the DCD. 813 * If psz_path_name == NULL, unregister the specified DCD object. 814 */ 815int dcd_register_object(struct dsp_uuid *uuid_obj, 816 enum dsp_dcdobjtype obj_type, 817 char *psz_path_name) 818{ 819 int status = 0; 820 char sz_reg_key[DCD_MAXPATHLENGTH]; 821 char sz_uuid[MAXUUIDLEN + 1]; 822 u32 dw_path_size = 0; 823 u32 dw_key_len; /* Len of REG key. */ 824 char sz_obj_type[MAX_INT2CHAR_LENGTH]; /* str. rep. of obj_type. */ 825 struct dcd_key_elem *dcd_key = NULL; 826 827 DBC_REQUIRE(refs > 0); 828 DBC_REQUIRE(uuid_obj != NULL); 829 DBC_REQUIRE((obj_type == DSP_DCDNODETYPE) || 830 (obj_type == DSP_DCDPROCESSORTYPE) || 831 (obj_type == DSP_DCDLIBRARYTYPE) || 832 (obj_type == DSP_DCDCREATELIBTYPE) || 833 (obj_type == DSP_DCDEXECUTELIBTYPE) || 834 (obj_type == DSP_DCDDELETELIBTYPE)); 835 836 dev_dbg(bridge, "%s: object UUID %p, obj_type %d, szPathName %s\n", 837 __func__, uuid_obj, obj_type, psz_path_name); 838 839 /* 840 * Pre-determine final key length. It's length of DCD_REGKEY + 841 * "_\0" + length of sz_obj_type string + terminating NULL. 842 */ 843 dw_key_len = strlen(DCD_REGKEY) + 1 + sizeof(sz_obj_type) + 1; 844 DBC_ASSERT(dw_key_len < DCD_MAXPATHLENGTH); 845 846 /* Create proper REG key; concatenate DCD_REGKEY with obj_type. */ 847 strncpy(sz_reg_key, DCD_REGKEY, strlen(DCD_REGKEY) + 1); 848 if ((strlen(sz_reg_key) + strlen("_\0")) < DCD_MAXPATHLENGTH) 849 strncat(sz_reg_key, "_\0", 2); 850 else { 851 status = -EPERM; 852 goto func_end; 853 } 854 855 status = snprintf(sz_obj_type, MAX_INT2CHAR_LENGTH, "%d", obj_type); 856 if (status == -1) { 857 status = -EPERM; 858 } else { 859 status = 0; 860 if ((strlen(sz_reg_key) + strlen(sz_obj_type)) < 861 DCD_MAXPATHLENGTH) { 862 strncat(sz_reg_key, sz_obj_type, 863 strlen(sz_obj_type) + 1); 864 } else 865 status = -EPERM; 866 867 /* Create UUID value to set in registry. */ 868 uuid_uuid_to_string(uuid_obj, sz_uuid, MAXUUIDLEN); 869 if ((strlen(sz_reg_key) + MAXUUIDLEN) < DCD_MAXPATHLENGTH) 870 strncat(sz_reg_key, sz_uuid, MAXUUIDLEN); 871 else 872 status = -EPERM; 873 } 874 875 if (status) 876 goto func_end; 877 878 /* 879 * If psz_path_name != NULL, perform registration, otherwise, 880 * perform unregistration. 881 */ 882 883 if (psz_path_name) { 884 dw_path_size = strlen(psz_path_name) + 1; 885 spin_lock(&dbdcd_lock); 886 list_for_each_entry(dcd_key, ®_key_list, link) { 887 /* See if the name matches. */ 888 if (!strncmp(dcd_key->name, sz_reg_key, 889 strlen(sz_reg_key) + 1)) 890 break; 891 } 892 spin_unlock(&dbdcd_lock); 893 if (&dcd_key->link == ®_key_list) { 894 /* 895 * Add new reg value (UUID+obj_type) 896 * with COFF path info 897 */ 898 899 dcd_key = kmalloc(sizeof(struct dcd_key_elem), 900 GFP_KERNEL); 901 if (!dcd_key) { 902 status = -ENOMEM; 903 goto func_end; 904 } 905 906 dcd_key->path = kmalloc(strlen(sz_reg_key) + 1, 907 GFP_KERNEL); 908 909 if (!dcd_key->path) { 910 kfree(dcd_key); 911 status = -ENOMEM; 912 goto func_end; 913 } 914 915 strncpy(dcd_key->name, sz_reg_key, 916 strlen(sz_reg_key) + 1); 917 strncpy(dcd_key->path, psz_path_name , 918 dw_path_size); 919 spin_lock(&dbdcd_lock); 920 list_add_tail(&dcd_key->link, ®_key_list); 921 spin_unlock(&dbdcd_lock); 922 } else { 923 /* Make sure the new data is the same. */ 924 if (strncmp(dcd_key->path, psz_path_name, 925 dw_path_size)) { 926 /* The caller needs a different data size! */ 927 kfree(dcd_key->path); 928 dcd_key->path = kmalloc(dw_path_size, 929 GFP_KERNEL); 930 if (dcd_key->path == NULL) { 931 status = -ENOMEM; 932 goto func_end; 933 } 934 } 935 936 /* We have a match! Copy out the data. */ 937 memcpy(dcd_key->path, psz_path_name, dw_path_size); 938 } 939 dev_dbg(bridge, "%s: psz_path_name=%s, dw_path_size=%d\n", 940 __func__, psz_path_name, dw_path_size); 941 } else { 942 /* Deregister an existing object */ 943 spin_lock(&dbdcd_lock); 944 list_for_each_entry(dcd_key, ®_key_list, link) { 945 if (!strncmp(dcd_key->name, sz_reg_key, 946 strlen(sz_reg_key) + 1)) { 947 list_del(&dcd_key->link); 948 kfree(dcd_key->path); 949 kfree(dcd_key); 950 break; 951 } 952 } 953 spin_unlock(&dbdcd_lock); 954 if (&dcd_key->link == ®_key_list) 955 status = -EPERM; 956 } 957 958 if (!status) { 959 /* 960 * Because the node database has been updated through a 961 * successful object registration/de-registration operation, 962 * we need to reset the object enumeration counter to allow 963 * current enumerations to reflect this update in the node 964 * database. 965 */ 966 enum_refs = 0; 967 } 968func_end: 969 return status; 970} 971 972/* 973 * ======== dcd_unregister_object ======== 974 * Call DCD_Register object with psz_path_name set to NULL to 975 * perform actual object de-registration. 976 */ 977int dcd_unregister_object(struct dsp_uuid *uuid_obj, 978 enum dsp_dcdobjtype obj_type) 979{ 980 int status = 0; 981 982 DBC_REQUIRE(refs > 0); 983 DBC_REQUIRE(uuid_obj != NULL); 984 DBC_REQUIRE((obj_type == DSP_DCDNODETYPE) || 985 (obj_type == DSP_DCDPROCESSORTYPE) || 986 (obj_type == DSP_DCDLIBRARYTYPE) || 987 (obj_type == DSP_DCDCREATELIBTYPE) || 988 (obj_type == DSP_DCDEXECUTELIBTYPE) || 989 (obj_type == DSP_DCDDELETELIBTYPE)); 990 991 /* 992 * When dcd_register_object is called with NULL as pathname, 993 * it indicates an unregister object operation. 994 */ 995 status = dcd_register_object(uuid_obj, obj_type, NULL); 996 997 return status; 998} 999 1000/* 1001 ********************************************************************** 1002 * DCD Helper Functions 1003 ********************************************************************** 1004 */ 1005 1006/* 1007 * ======== atoi ======== 1008 * Purpose: 1009 * This function converts strings in decimal or hex format to integers. 1010 */ 1011static s32 atoi(char *psz_buf) 1012{ 1013 char *pch = psz_buf; 1014 s32 base = 0; 1015 unsigned long res; 1016 int ret_val; 1017 1018 while (isspace(*pch)) 1019 pch++; 1020 1021 if (*pch == '-' || *pch == '+') { 1022 base = 10; 1023 pch++; 1024 } else if (*pch && tolower(pch[strlen(pch) - 1]) == 'h') { 1025 base = 16; 1026 } 1027 1028 ret_val = strict_strtoul(pch, base, &res); 1029 1030 return ret_val ? : res; 1031} 1032 1033/* 1034 * ======== get_attrs_from_buf ======== 1035 * Purpose: 1036 * Parse the content of a buffer filled with DSP-side data and 1037 * retrieve an object's attributes from it. IMPORTANT: Assume the 1038 * buffer has been converted from DSP format to GPP format. 1039 */ 1040static int get_attrs_from_buf(char *psz_buf, u32 ul_buf_size, 1041 enum dsp_dcdobjtype obj_type, 1042 struct dcd_genericobj *gen_obj) 1043{ 1044 int status = 0; 1045 char seps[] = ", "; 1046 char *psz_cur; 1047 char *token; 1048 s32 token_len = 0; 1049 u32 i = 0; 1050#ifdef _DB_TIOMAP 1051 s32 entry_id; 1052#endif 1053 1054 DBC_REQUIRE(psz_buf != NULL); 1055 DBC_REQUIRE(ul_buf_size != 0); 1056 DBC_REQUIRE((obj_type == DSP_DCDNODETYPE) 1057 || (obj_type == DSP_DCDPROCESSORTYPE)); 1058 DBC_REQUIRE(gen_obj != NULL); 1059 1060 switch (obj_type) { 1061 case DSP_DCDNODETYPE: 1062 /* 1063 * Parse COFF sect buffer to retrieve individual tokens used 1064 * to fill in object attrs. 1065 */ 1066 psz_cur = psz_buf; 1067 token = strsep(&psz_cur, seps); 1068 1069 /* u32 cb_struct */ 1070 gen_obj->obj_data.node_obj.ndb_props.cb_struct = 1071 (u32) atoi(token); 1072 token = strsep(&psz_cur, seps); 1073 1074 /* dsp_uuid ui_node_id */ 1075 uuid_uuid_from_string(token, 1076 &gen_obj->obj_data.node_obj.ndb_props. 1077 ui_node_id); 1078 token = strsep(&psz_cur, seps); 1079 1080 /* ac_name */ 1081 DBC_REQUIRE(token); 1082 token_len = strlen(token); 1083 if (token_len > DSP_MAXNAMELEN - 1) 1084 token_len = DSP_MAXNAMELEN - 1; 1085 1086 strncpy(gen_obj->obj_data.node_obj.ndb_props.ac_name, 1087 token, token_len); 1088 gen_obj->obj_data.node_obj.ndb_props.ac_name[token_len] = '\0'; 1089 token = strsep(&psz_cur, seps); 1090 /* u32 ntype */ 1091 gen_obj->obj_data.node_obj.ndb_props.ntype = atoi(token); 1092 token = strsep(&psz_cur, seps); 1093 /* u32 cache_on_gpp */ 1094 gen_obj->obj_data.node_obj.ndb_props.cache_on_gpp = atoi(token); 1095 token = strsep(&psz_cur, seps); 1096 /* dsp_resourcereqmts dsp_resource_reqmts */ 1097 gen_obj->obj_data.node_obj.ndb_props.dsp_resource_reqmts. 1098 cb_struct = (u32) atoi(token); 1099 token = strsep(&psz_cur, seps); 1100 1101 gen_obj->obj_data.node_obj.ndb_props. 1102 dsp_resource_reqmts.static_data_size = atoi(token); 1103 token = strsep(&psz_cur, seps); 1104 gen_obj->obj_data.node_obj.ndb_props. 1105 dsp_resource_reqmts.global_data_size = atoi(token); 1106 token = strsep(&psz_cur, seps); 1107 gen_obj->obj_data.node_obj.ndb_props. 1108 dsp_resource_reqmts.program_mem_size = atoi(token); 1109 token = strsep(&psz_cur, seps); 1110 gen_obj->obj_data.node_obj.ndb_props. 1111 dsp_resource_reqmts.uwc_execution_time = atoi(token); 1112 token = strsep(&psz_cur, seps); 1113 gen_obj->obj_data.node_obj.ndb_props. 1114 dsp_resource_reqmts.uwc_period = atoi(token); 1115 token = strsep(&psz_cur, seps); 1116 1117 gen_obj->obj_data.node_obj.ndb_props. 1118 dsp_resource_reqmts.uwc_deadline = atoi(token); 1119 token = strsep(&psz_cur, seps); 1120 1121 gen_obj->obj_data.node_obj.ndb_props. 1122 dsp_resource_reqmts.avg_exection_time = atoi(token); 1123 token = strsep(&psz_cur, seps); 1124 1125 gen_obj->obj_data.node_obj.ndb_props. 1126 dsp_resource_reqmts.minimum_period = atoi(token); 1127 token = strsep(&psz_cur, seps); 1128 1129 /* s32 prio */ 1130 gen_obj->obj_data.node_obj.ndb_props.prio = atoi(token); 1131 token = strsep(&psz_cur, seps); 1132 1133 /* u32 stack_size */ 1134 gen_obj->obj_data.node_obj.ndb_props.stack_size = atoi(token); 1135 token = strsep(&psz_cur, seps); 1136 1137 /* u32 sys_stack_size */ 1138 gen_obj->obj_data.node_obj.ndb_props.sys_stack_size = 1139 atoi(token); 1140 token = strsep(&psz_cur, seps); 1141 1142 /* u32 stack_seg */ 1143 gen_obj->obj_data.node_obj.ndb_props.stack_seg = atoi(token); 1144 token = strsep(&psz_cur, seps); 1145 1146 /* u32 message_depth */ 1147 gen_obj->obj_data.node_obj.ndb_props.message_depth = 1148 atoi(token); 1149 token = strsep(&psz_cur, seps); 1150 1151 /* u32 num_input_streams */ 1152 gen_obj->obj_data.node_obj.ndb_props.num_input_streams = 1153 atoi(token); 1154 token = strsep(&psz_cur, seps); 1155 1156 /* u32 num_output_streams */ 1157 gen_obj->obj_data.node_obj.ndb_props.num_output_streams = 1158 atoi(token); 1159 token = strsep(&psz_cur, seps); 1160 1161 /* u32 utimeout */ 1162 gen_obj->obj_data.node_obj.ndb_props.utimeout = atoi(token); 1163 token = strsep(&psz_cur, seps); 1164 1165 /* char *pstr_create_phase_fxn */ 1166 DBC_REQUIRE(token); 1167 token_len = strlen(token); 1168 gen_obj->obj_data.node_obj.pstr_create_phase_fxn = 1169 kzalloc(token_len + 1, GFP_KERNEL); 1170 strncpy(gen_obj->obj_data.node_obj.pstr_create_phase_fxn, 1171 token, token_len); 1172 gen_obj->obj_data.node_obj.pstr_create_phase_fxn[token_len] = 1173 '\0'; 1174 token = strsep(&psz_cur, seps); 1175 1176 /* char *pstr_execute_phase_fxn */ 1177 DBC_REQUIRE(token); 1178 token_len = strlen(token); 1179 gen_obj->obj_data.node_obj.pstr_execute_phase_fxn = 1180 kzalloc(token_len + 1, GFP_KERNEL); 1181 strncpy(gen_obj->obj_data.node_obj.pstr_execute_phase_fxn, 1182 token, token_len); 1183 gen_obj->obj_data.node_obj.pstr_execute_phase_fxn[token_len] = 1184 '\0'; 1185 token = strsep(&psz_cur, seps); 1186 1187 /* char *pstr_delete_phase_fxn */ 1188 DBC_REQUIRE(token); 1189 token_len = strlen(token); 1190 gen_obj->obj_data.node_obj.pstr_delete_phase_fxn = 1191 kzalloc(token_len + 1, GFP_KERNEL); 1192 strncpy(gen_obj->obj_data.node_obj.pstr_delete_phase_fxn, 1193 token, token_len); 1194 gen_obj->obj_data.node_obj.pstr_delete_phase_fxn[token_len] = 1195 '\0'; 1196 token = strsep(&psz_cur, seps); 1197 1198 /* Segment id for message buffers */ 1199 gen_obj->obj_data.node_obj.msg_segid = atoi(token); 1200 token = strsep(&psz_cur, seps); 1201 1202 /* Message notification type */ 1203 gen_obj->obj_data.node_obj.msg_notify_type = atoi(token); 1204 token = strsep(&psz_cur, seps); 1205 1206 /* char *pstr_i_alg_name */ 1207 if (token) { 1208 token_len = strlen(token); 1209 gen_obj->obj_data.node_obj.pstr_i_alg_name = 1210 kzalloc(token_len + 1, GFP_KERNEL); 1211 strncpy(gen_obj->obj_data.node_obj.pstr_i_alg_name, 1212 token, token_len); 1213 gen_obj->obj_data.node_obj.pstr_i_alg_name[token_len] = 1214 '\0'; 1215 token = strsep(&psz_cur, seps); 1216 } 1217 1218 /* Load type (static, dynamic, or overlay) */ 1219 if (token) { 1220 gen_obj->obj_data.node_obj.us_load_type = atoi(token); 1221 token = strsep(&psz_cur, seps); 1222 } 1223 1224 /* Dynamic load data requirements */ 1225 if (token) { 1226 gen_obj->obj_data.node_obj.ul_data_mem_seg_mask = 1227 atoi(token); 1228 token = strsep(&psz_cur, seps); 1229 } 1230 1231 /* Dynamic load code requirements */ 1232 if (token) { 1233 gen_obj->obj_data.node_obj.ul_code_mem_seg_mask = 1234 atoi(token); 1235 token = strsep(&psz_cur, seps); 1236 } 1237 1238 /* Extract node profiles into node properties */ 1239 if (token) { 1240 1241 gen_obj->obj_data.node_obj.ndb_props.count_profiles = 1242 atoi(token); 1243 for (i = 0; 1244 i < 1245 gen_obj->obj_data.node_obj. 1246 ndb_props.count_profiles; i++) { 1247 token = strsep(&psz_cur, seps); 1248 if (token) { 1249 /* Heap Size for the node */ 1250 gen_obj->obj_data.node_obj. 1251 ndb_props.node_profiles[i]. 1252 ul_heap_size = atoi(token); 1253 } 1254 } 1255 } 1256 token = strsep(&psz_cur, seps); 1257 if (token) { 1258 gen_obj->obj_data.node_obj.ndb_props.stack_seg_name = 1259 (u32) (token); 1260 } 1261 1262 break; 1263 1264 case DSP_DCDPROCESSORTYPE: 1265 /* 1266 * Parse COFF sect buffer to retrieve individual tokens used 1267 * to fill in object attrs. 1268 */ 1269 psz_cur = psz_buf; 1270 token = strsep(&psz_cur, seps); 1271 1272 gen_obj->obj_data.proc_info.cb_struct = atoi(token); 1273 token = strsep(&psz_cur, seps); 1274 1275 gen_obj->obj_data.proc_info.processor_family = atoi(token); 1276 token = strsep(&psz_cur, seps); 1277 1278 gen_obj->obj_data.proc_info.processor_type = atoi(token); 1279 token = strsep(&psz_cur, seps); 1280 1281 gen_obj->obj_data.proc_info.clock_rate = atoi(token); 1282 token = strsep(&psz_cur, seps); 1283 1284 gen_obj->obj_data.proc_info.ul_internal_mem_size = atoi(token); 1285 token = strsep(&psz_cur, seps); 1286 1287 gen_obj->obj_data.proc_info.ul_external_mem_size = atoi(token); 1288 token = strsep(&psz_cur, seps); 1289 1290 gen_obj->obj_data.proc_info.processor_id = atoi(token); 1291 token = strsep(&psz_cur, seps); 1292 1293 gen_obj->obj_data.proc_info.ty_running_rtos = atoi(token); 1294 token = strsep(&psz_cur, seps); 1295 1296 gen_obj->obj_data.proc_info.node_min_priority = atoi(token); 1297 token = strsep(&psz_cur, seps); 1298 1299 gen_obj->obj_data.proc_info.node_max_priority = atoi(token); 1300 1301#ifdef _DB_TIOMAP 1302 /* Proc object may contain additional(extended) attributes. */ 1303 /* attr must match proc.hxx */ 1304 for (entry_id = 0; entry_id < 7; entry_id++) { 1305 token = strsep(&psz_cur, seps); 1306 gen_obj->obj_data.ext_proc_obj.ty_tlb[entry_id]. 1307 ul_gpp_phys = atoi(token); 1308 1309 token = strsep(&psz_cur, seps); 1310 gen_obj->obj_data.ext_proc_obj.ty_tlb[entry_id]. 1311 ul_dsp_virt = atoi(token); 1312 } 1313#endif 1314 1315 break; 1316 1317 default: 1318 status = -EPERM; 1319 break; 1320 } 1321 1322 return status; 1323} 1324 1325/* 1326 * ======== CompressBuffer ======== 1327 * Purpose: 1328 * Compress the DSP buffer, if necessary, to conform to PC format. 1329 */ 1330static void compress_buf(char *psz_buf, u32 ul_buf_size, s32 char_size) 1331{ 1332 char *p; 1333 char ch; 1334 char *q; 1335 1336 p = psz_buf; 1337 if (p == NULL) 1338 return; 1339 1340 for (q = psz_buf; q < (psz_buf + ul_buf_size);) { 1341 ch = dsp_char2_gpp_char(q, char_size); 1342 if (ch == '\\') { 1343 q += char_size; 1344 ch = dsp_char2_gpp_char(q, char_size); 1345 switch (ch) { 1346 case 't': 1347 *p = '\t'; 1348 break; 1349 1350 case 'n': 1351 *p = '\n'; 1352 break; 1353 1354 case 'r': 1355 *p = '\r'; 1356 break; 1357 1358 case '0': 1359 *p = '\0'; 1360 break; 1361 1362 default: 1363 *p = ch; 1364 break; 1365 } 1366 } else { 1367 *p = ch; 1368 } 1369 p++; 1370 q += char_size; 1371 } 1372 1373 /* NULL out remainder of buffer. */ 1374 while (p < q) 1375 *p++ = '\0'; 1376} 1377 1378/* 1379 * ======== dsp_char2_gpp_char ======== 1380 * Purpose: 1381 * Convert DSP char to host GPP char in a portable manner 1382 */ 1383static char dsp_char2_gpp_char(char *word, s32 dsp_char_size) 1384{ 1385 char ch = '\0'; 1386 char *ch_src; 1387 s32 i; 1388 1389 for (ch_src = word, i = dsp_char_size; i > 0; i--) 1390 ch |= *ch_src++; 1391 1392 return ch; 1393} 1394 1395/* 1396 * ======== get_dep_lib_info ======== 1397 */ 1398static int get_dep_lib_info(struct dcd_manager *hdcd_mgr, 1399 struct dsp_uuid *uuid_obj, 1400 u16 *num_libs, 1401 u16 *num_pers_libs, 1402 struct dsp_uuid *dep_lib_uuids, 1403 bool *prstnt_dep_libs, 1404 enum nldr_phase phase) 1405{ 1406 struct dcd_manager *dcd_mgr_obj = hdcd_mgr; 1407 char *psz_coff_buf = NULL; 1408 char *psz_cur; 1409 char *psz_file_name = NULL; 1410 struct cod_libraryobj *lib = NULL; 1411 u32 ul_addr = 0; /* Used by cod_get_section */ 1412 u32 ul_len = 0; /* Used by cod_get_section */ 1413 u32 dw_data_size = COD_MAXPATHLENGTH; 1414 char seps[] = ", "; 1415 char *token = NULL; 1416 bool get_uuids = (dep_lib_uuids != NULL); 1417 u16 dep_libs = 0; 1418 int status = 0; 1419 1420 DBC_REQUIRE(refs > 0); 1421 1422 DBC_REQUIRE(hdcd_mgr); 1423 DBC_REQUIRE(num_libs != NULL); 1424 DBC_REQUIRE(uuid_obj != NULL); 1425 1426 /* Initialize to 0 dependent libraries, if only counting number of 1427 * dependent libraries */ 1428 if (!get_uuids) { 1429 *num_libs = 0; 1430 *num_pers_libs = 0; 1431 } 1432 1433 /* Allocate a buffer for file name */ 1434 psz_file_name = kzalloc(dw_data_size, GFP_KERNEL); 1435 if (psz_file_name == NULL) { 1436 status = -ENOMEM; 1437 } else { 1438 /* Get the name of the library */ 1439 status = dcd_get_library_name(hdcd_mgr, uuid_obj, psz_file_name, 1440 &dw_data_size, phase, NULL); 1441 } 1442 1443 /* Open the library */ 1444 if (!status) { 1445 status = cod_open(dcd_mgr_obj->cod_mgr, psz_file_name, 1446 COD_NOLOAD, &lib); 1447 } 1448 if (!status) { 1449 /* Get dependent library section information. */ 1450 status = cod_get_section(lib, DEPLIBSECT, &ul_addr, &ul_len); 1451 1452 if (status) { 1453 /* Ok, no dependent libraries */ 1454 ul_len = 0; 1455 status = 0; 1456 } 1457 } 1458 1459 if (status || !(ul_len > 0)) 1460 goto func_cont; 1461 1462 /* Allocate zeroed buffer. */ 1463 psz_coff_buf = kzalloc(ul_len + 4, GFP_KERNEL); 1464 if (psz_coff_buf == NULL) 1465 status = -ENOMEM; 1466 1467 /* Read section contents. */ 1468 status = cod_read_section(lib, DEPLIBSECT, psz_coff_buf, ul_len); 1469 if (status) 1470 goto func_cont; 1471 1472 /* Compress and format DSP buffer to conform to PC format. */ 1473 compress_buf(psz_coff_buf, ul_len, DSPWORDSIZE); 1474 1475 /* Read from buffer */ 1476 psz_cur = psz_coff_buf; 1477 while ((token = strsep(&psz_cur, seps)) && *token != '\0') { 1478 if (get_uuids) { 1479 if (dep_libs >= *num_libs) { 1480 /* Gone beyond the limit */ 1481 break; 1482 } else { 1483 /* Retrieve UUID string. */ 1484 uuid_uuid_from_string(token, 1485 &(dep_lib_uuids 1486 [dep_libs])); 1487 /* Is this library persistent? */ 1488 token = strsep(&psz_cur, seps); 1489 prstnt_dep_libs[dep_libs] = atoi(token); 1490 dep_libs++; 1491 } 1492 } else { 1493 /* Advanc to next token */ 1494 token = strsep(&psz_cur, seps); 1495 if (atoi(token)) 1496 (*num_pers_libs)++; 1497 1498 /* Just counting number of dependent libraries */ 1499 (*num_libs)++; 1500 } 1501 } 1502func_cont: 1503 if (lib) 1504 cod_close(lib); 1505 1506 /* Free previously allocated dynamic buffers. */ 1507 kfree(psz_file_name); 1508 1509 kfree(psz_coff_buf); 1510 1511 return status; 1512} 1513