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. */
51 struct dcd_manager {
52 struct cod_manager *cod_mgr; /* Handle to COD manager object. */
53 };
54
55 /* Pointer to the registry support key */
56 static struct list_head reg_key_list;
57 static DEFINE_SPINLOCK(dbdcd_lock);
58
59 /* Global reference variables. */
60 static u32 refs;
61 static u32 enum_refs;
62
63 /* Helper function prototypes. */
64 static s32 atoi(char *psz_buf);
65 static int get_attrs_from_buf(char *psz_buf, u32 ul_buf_size,
66 enum dsp_dcdobjtype obj_type,
67 struct dcd_genericobj *gen_obj);
68 static void compress_buf(char *psz_buf, u32 ul_buf_size, s32 char_size);
69 static char dsp_char2_gpp_char(char *word, s32 dsp_char_size);
70 static 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 */
dcd_auto_register(struct dcd_manager * hdcd_mgr,char * sz_coff_path)83 int 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 */
dcd_auto_unregister(struct dcd_manager * hdcd_mgr,char * sz_coff_path)105 int 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 */
dcd_create_manager(char * sz_zl_dll_name,struct dcd_manager ** dcd_mgr)127 int 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);
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
162 func_end:
163 return status;
164 }
165
166 /*
167 * ======== dcd_destroy_manager ========
168 * Purpose:
169 * Frees DCD Manager object.
170 */
dcd_destroy_manager(struct dcd_manager * hdcd_mgr)171 int 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 */
dcd_enumerate_object(s32 index,enum dsp_dcdobjtype obj_type,struct dsp_uuid * uuid_obj)196 int 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 */
dcd_exit(void)307 void 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 */
dcd_get_dep_libs(struct dcd_manager * hdcd_mgr,struct dsp_uuid * uuid_obj,u16 num_libs,struct dsp_uuid * dep_lib_uuids,bool * prstnt_dep_libs,enum nldr_phase phase)328 int 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 */
dcd_get_num_dep_libs(struct dcd_manager * hdcd_mgr,struct dsp_uuid * uuid_obj,u16 * num_libs,u16 * num_pers_libs,enum nldr_phase phase)352 int 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 */
dcd_get_object_def(struct dcd_manager * hdcd_mgr,struct dsp_uuid * obj_uuid,enum dsp_dcdobjtype obj_type,struct dcd_genericobj * obj_def)377 int 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 if (psz_coff_buf == NULL) {
491 status = -ENOMEM;
492 goto func_end;
493 }
494 #ifdef _DB_TIOMAP
495 if (strstr(dcd_key->path, "iva") == NULL) {
496 /* Locate section by objectID and read its content. */
497 status =
498 cod_read_section(lib, sz_sect_name, psz_coff_buf, ul_len);
499 } else {
500 status =
501 cod_read_section(lib, sz_sect_name, psz_coff_buf, ul_len);
502 dev_dbg(bridge, "%s: Skipped Byte swap for IVA!!\n", __func__);
503 }
504 #else
505 status = cod_read_section(lib, sz_sect_name, psz_coff_buf, ul_len);
506 #endif
507 if (!status) {
508 /* Compres DSP buffer to conform to PC format. */
509 if (strstr(dcd_key->path, "iva") == NULL) {
510 compress_buf(psz_coff_buf, ul_len, DSPWORDSIZE);
511 } else {
512 compress_buf(psz_coff_buf, ul_len, 1);
513 dev_dbg(bridge, "%s: Compressing IVA COFF buffer by 1 "
514 "for IVA!!\n", __func__);
515 }
516
517 /* Parse the content of the COFF buffer. */
518 status =
519 get_attrs_from_buf(psz_coff_buf, ul_len, obj_type, obj_def);
520 if (status)
521 status = -EACCES;
522 } else {
523 status = -EACCES;
524 }
525
526 /* Free the previously allocated dynamic buffer. */
527 kfree(psz_coff_buf);
528 func_end:
529 if (lib)
530 cod_close(lib);
531
532 kfree(sz_uuid);
533
534 return status;
535 }
536
537 /*
538 * ======== dcd_get_objects ========
539 */
dcd_get_objects(struct dcd_manager * hdcd_mgr,char * sz_coff_path,dcd_registerfxn register_fxn,void * handle)540 int dcd_get_objects(struct dcd_manager *hdcd_mgr,
541 char *sz_coff_path, dcd_registerfxn register_fxn,
542 void *handle)
543 {
544 struct dcd_manager *dcd_mgr_obj = hdcd_mgr;
545 int status = 0;
546 char *psz_coff_buf;
547 char *psz_cur;
548 struct cod_libraryobj *lib = NULL;
549 u32 ul_addr = 0; /* Used by cod_get_section */
550 u32 ul_len = 0; /* Used by cod_get_section */
551 char seps[] = ":, ";
552 char *token = NULL;
553 struct dsp_uuid dsp_uuid_obj;
554 s32 object_type;
555
556 DBC_REQUIRE(refs > 0);
557 if (!hdcd_mgr) {
558 status = -EFAULT;
559 goto func_end;
560 }
561
562 /* Open DSP coff file, don't load symbols. */
563 status = cod_open(dcd_mgr_obj->cod_mgr, sz_coff_path, COD_NOLOAD, &lib);
564 if (status) {
565 status = -EACCES;
566 goto func_cont;
567 }
568
569 /* Get DCD_RESIGER_SECTION section information. */
570 status = cod_get_section(lib, DCD_REGISTER_SECTION, &ul_addr, &ul_len);
571 if (status || !(ul_len > 0)) {
572 status = -EACCES;
573 goto func_cont;
574 }
575
576 /* Allocate zeroed buffer. */
577 psz_coff_buf = kzalloc(ul_len + 4, GFP_KERNEL);
578 if (psz_coff_buf == NULL) {
579 status = -ENOMEM;
580 goto func_cont;
581 }
582 #ifdef _DB_TIOMAP
583 if (strstr(sz_coff_path, "iva") == NULL) {
584 /* Locate section by objectID and read its content. */
585 status = cod_read_section(lib, DCD_REGISTER_SECTION,
586 psz_coff_buf, ul_len);
587 } else {
588 dev_dbg(bridge, "%s: Skipped Byte swap for IVA!!\n", __func__);
589 status = cod_read_section(lib, DCD_REGISTER_SECTION,
590 psz_coff_buf, ul_len);
591 }
592 #else
593 status =
594 cod_read_section(lib, DCD_REGISTER_SECTION, psz_coff_buf, ul_len);
595 #endif
596 if (!status) {
597 /* Compress DSP buffer to conform to PC format. */
598 if (strstr(sz_coff_path, "iva") == NULL) {
599 compress_buf(psz_coff_buf, ul_len, DSPWORDSIZE);
600 } else {
601 compress_buf(psz_coff_buf, ul_len, 1);
602 dev_dbg(bridge, "%s: Compress COFF buffer with 1 word "
603 "for IVA!!\n", __func__);
604 }
605
606 /* Read from buffer and register object in buffer. */
607 psz_cur = psz_coff_buf;
608 while ((token = strsep(&psz_cur, seps)) && *token != '\0') {
609 /* Retrieve UUID string. */
610 uuid_uuid_from_string(token, &dsp_uuid_obj);
611
612 /* Retrieve object type */
613 token = strsep(&psz_cur, seps);
614
615 /* Retrieve object type */
616 object_type = atoi(token);
617
618 /*
619 * Apply register_fxn to the found DCD object.
620 * Possible actions include:
621 *
622 * 1) Register found DCD object.
623 * 2) Unregister found DCD object (when handle == NULL)
624 * 3) Add overlay node.
625 */
626 status =
627 register_fxn(&dsp_uuid_obj, object_type, handle);
628 if (status) {
629 /* if error occurs, break from while loop. */
630 break;
631 }
632 }
633 } else {
634 status = -EACCES;
635 }
636
637 /* Free the previously allocated dynamic buffer. */
638 kfree(psz_coff_buf);
639 func_cont:
640 if (lib)
641 cod_close(lib);
642
643 func_end:
644 return status;
645 }
646
647 /*
648 * ======== dcd_get_library_name ========
649 * Purpose:
650 * Retrieves the library name for the given UUID.
651 *
652 */
dcd_get_library_name(struct dcd_manager * hdcd_mgr,struct dsp_uuid * uuid_obj,char * str_lib_name,u32 * buff_size,enum nldr_phase phase,bool * phase_split)653 int dcd_get_library_name(struct dcd_manager *hdcd_mgr,
654 struct dsp_uuid *uuid_obj,
655 char *str_lib_name,
656 u32 *buff_size,
657 enum nldr_phase phase, bool *phase_split)
658 {
659 char sz_reg_key[DCD_MAXPATHLENGTH];
660 char sz_uuid[MAXUUIDLEN];
661 u32 dw_key_len; /* Len of REG key. */
662 char sz_obj_type[MAX_INT2CHAR_LENGTH]; /* str. rep. of obj_type. */
663 int status = 0;
664 struct dcd_key_elem *dcd_key = NULL;
665
666 DBC_REQUIRE(uuid_obj != NULL);
667 DBC_REQUIRE(str_lib_name != NULL);
668 DBC_REQUIRE(buff_size != NULL);
669 DBC_REQUIRE(hdcd_mgr);
670
671 dev_dbg(bridge, "%s: hdcd_mgr %p, uuid_obj %p, str_lib_name %p,"
672 " buff_size %p\n", __func__, hdcd_mgr, uuid_obj, str_lib_name,
673 buff_size);
674
675 /*
676 * Pre-determine final key length. It's length of DCD_REGKEY +
677 * "_\0" + length of sz_obj_type string + terminating NULL.
678 */
679 dw_key_len = strlen(DCD_REGKEY) + 1 + sizeof(sz_obj_type) + 1;
680 DBC_ASSERT(dw_key_len < DCD_MAXPATHLENGTH);
681
682 /* Create proper REG key; concatenate DCD_REGKEY with obj_type. */
683 strncpy(sz_reg_key, DCD_REGKEY, strlen(DCD_REGKEY) + 1);
684 if ((strlen(sz_reg_key) + strlen("_\0")) < DCD_MAXPATHLENGTH)
685 strncat(sz_reg_key, "_\0", 2);
686 else
687 status = -EPERM;
688
689 switch (phase) {
690 case NLDR_CREATE:
691 /* create phase type */
692 sprintf(sz_obj_type, "%d", DSP_DCDCREATELIBTYPE);
693 break;
694 case NLDR_EXECUTE:
695 /* execute phase type */
696 sprintf(sz_obj_type, "%d", DSP_DCDEXECUTELIBTYPE);
697 break;
698 case NLDR_DELETE:
699 /* delete phase type */
700 sprintf(sz_obj_type, "%d", DSP_DCDDELETELIBTYPE);
701 break;
702 case NLDR_NOPHASE:
703 /* known to be a dependent library */
704 sprintf(sz_obj_type, "%d", DSP_DCDLIBRARYTYPE);
705 break;
706 default:
707 status = -EINVAL;
708 DBC_ASSERT(false);
709 }
710 if (!status) {
711 if ((strlen(sz_reg_key) + strlen(sz_obj_type)) <
712 DCD_MAXPATHLENGTH) {
713 strncat(sz_reg_key, sz_obj_type,
714 strlen(sz_obj_type) + 1);
715 } else {
716 status = -EPERM;
717 }
718 /* Create UUID value to find match in registry. */
719 uuid_uuid_to_string(uuid_obj, sz_uuid, MAXUUIDLEN);
720 if ((strlen(sz_reg_key) + MAXUUIDLEN) < DCD_MAXPATHLENGTH)
721 strncat(sz_reg_key, sz_uuid, MAXUUIDLEN);
722 else
723 status = -EPERM;
724 }
725 if (!status) {
726 spin_lock(&dbdcd_lock);
727 list_for_each_entry(dcd_key, ®_key_list, link) {
728 /* See if the name matches. */
729 if (!strncmp(dcd_key->name, sz_reg_key,
730 strlen(sz_reg_key) + 1))
731 break;
732 }
733 spin_unlock(&dbdcd_lock);
734 }
735
736 if (&dcd_key->link == ®_key_list)
737 status = -ENOKEY;
738
739 /* If can't find, phases might be registered as generic LIBRARYTYPE */
740 if (status && phase != NLDR_NOPHASE) {
741 if (phase_split)
742 *phase_split = false;
743
744 strncpy(sz_reg_key, DCD_REGKEY, strlen(DCD_REGKEY) + 1);
745 if ((strlen(sz_reg_key) + strlen("_\0")) <
746 DCD_MAXPATHLENGTH) {
747 strncat(sz_reg_key, "_\0", 2);
748 } else {
749 status = -EPERM;
750 }
751 sprintf(sz_obj_type, "%d", DSP_DCDLIBRARYTYPE);
752 if ((strlen(sz_reg_key) + strlen(sz_obj_type))
753 < DCD_MAXPATHLENGTH) {
754 strncat(sz_reg_key, sz_obj_type,
755 strlen(sz_obj_type) + 1);
756 } else {
757 status = -EPERM;
758 }
759 uuid_uuid_to_string(uuid_obj, sz_uuid, MAXUUIDLEN);
760 if ((strlen(sz_reg_key) + MAXUUIDLEN) < DCD_MAXPATHLENGTH)
761 strncat(sz_reg_key, sz_uuid, MAXUUIDLEN);
762 else
763 status = -EPERM;
764
765 spin_lock(&dbdcd_lock);
766 list_for_each_entry(dcd_key, ®_key_list, link) {
767 /* See if the name matches. */
768 if (!strncmp(dcd_key->name, sz_reg_key,
769 strlen(sz_reg_key) + 1))
770 break;
771 }
772 spin_unlock(&dbdcd_lock);
773
774 status = (&dcd_key->link != ®_key_list) ?
775 0 : -ENOKEY;
776 }
777
778 if (!status)
779 memcpy(str_lib_name, dcd_key->path, strlen(dcd_key->path) + 1);
780 return status;
781 }
782
783 /*
784 * ======== dcd_init ========
785 * Purpose:
786 * Initialize the DCD module.
787 */
dcd_init(void)788 bool dcd_init(void)
789 {
790 bool init_cod;
791 bool ret = true;
792
793 DBC_REQUIRE(refs >= 0);
794
795 if (refs == 0) {
796 /* Initialize required modules. */
797 init_cod = cod_init();
798
799 if (!init_cod) {
800 ret = false;
801 /* Exit initialized modules. */
802 if (init_cod)
803 cod_exit();
804 }
805
806 INIT_LIST_HEAD(®_key_list);
807 }
808
809 if (ret)
810 refs++;
811
812 DBC_ENSURE((ret && (refs > 0)) || (!ret && (refs == 0)));
813
814 return ret;
815 }
816
817 /*
818 * ======== dcd_register_object ========
819 * Purpose:
820 * Registers a node or a processor with the DCD.
821 * If psz_path_name == NULL, unregister the specified DCD object.
822 */
dcd_register_object(struct dsp_uuid * uuid_obj,enum dsp_dcdobjtype obj_type,char * psz_path_name)823 int dcd_register_object(struct dsp_uuid *uuid_obj,
824 enum dsp_dcdobjtype obj_type,
825 char *psz_path_name)
826 {
827 int status = 0;
828 char sz_reg_key[DCD_MAXPATHLENGTH];
829 char sz_uuid[MAXUUIDLEN + 1];
830 u32 dw_path_size = 0;
831 u32 dw_key_len; /* Len of REG key. */
832 char sz_obj_type[MAX_INT2CHAR_LENGTH]; /* str. rep. of obj_type. */
833 struct dcd_key_elem *dcd_key = NULL;
834
835 DBC_REQUIRE(refs > 0);
836 DBC_REQUIRE(uuid_obj != NULL);
837 DBC_REQUIRE((obj_type == DSP_DCDNODETYPE) ||
838 (obj_type == DSP_DCDPROCESSORTYPE) ||
839 (obj_type == DSP_DCDLIBRARYTYPE) ||
840 (obj_type == DSP_DCDCREATELIBTYPE) ||
841 (obj_type == DSP_DCDEXECUTELIBTYPE) ||
842 (obj_type == DSP_DCDDELETELIBTYPE));
843
844 dev_dbg(bridge, "%s: object UUID %p, obj_type %d, szPathName %s\n",
845 __func__, uuid_obj, obj_type, psz_path_name);
846
847 /*
848 * Pre-determine final key length. It's length of DCD_REGKEY +
849 * "_\0" + length of sz_obj_type string + terminating NULL.
850 */
851 dw_key_len = strlen(DCD_REGKEY) + 1 + sizeof(sz_obj_type) + 1;
852 DBC_ASSERT(dw_key_len < DCD_MAXPATHLENGTH);
853
854 /* Create proper REG key; concatenate DCD_REGKEY with obj_type. */
855 strncpy(sz_reg_key, DCD_REGKEY, strlen(DCD_REGKEY) + 1);
856 if ((strlen(sz_reg_key) + strlen("_\0")) < DCD_MAXPATHLENGTH)
857 strncat(sz_reg_key, "_\0", 2);
858 else {
859 status = -EPERM;
860 goto func_end;
861 }
862
863 status = snprintf(sz_obj_type, MAX_INT2CHAR_LENGTH, "%d", obj_type);
864 if (status == -1) {
865 status = -EPERM;
866 } else {
867 status = 0;
868 if ((strlen(sz_reg_key) + strlen(sz_obj_type)) <
869 DCD_MAXPATHLENGTH) {
870 strncat(sz_reg_key, sz_obj_type,
871 strlen(sz_obj_type) + 1);
872 } else
873 status = -EPERM;
874
875 /* Create UUID value to set in registry. */
876 uuid_uuid_to_string(uuid_obj, sz_uuid, MAXUUIDLEN);
877 if ((strlen(sz_reg_key) + MAXUUIDLEN) < DCD_MAXPATHLENGTH)
878 strncat(sz_reg_key, sz_uuid, MAXUUIDLEN);
879 else
880 status = -EPERM;
881 }
882
883 if (status)
884 goto func_end;
885
886 /*
887 * If psz_path_name != NULL, perform registration, otherwise,
888 * perform unregistration.
889 */
890
891 if (psz_path_name) {
892 dw_path_size = strlen(psz_path_name) + 1;
893 spin_lock(&dbdcd_lock);
894 list_for_each_entry(dcd_key, ®_key_list, link) {
895 /* See if the name matches. */
896 if (!strncmp(dcd_key->name, sz_reg_key,
897 strlen(sz_reg_key) + 1))
898 break;
899 }
900 spin_unlock(&dbdcd_lock);
901 if (&dcd_key->link == ®_key_list) {
902 /*
903 * Add new reg value (UUID+obj_type)
904 * with COFF path info
905 */
906
907 dcd_key = kmalloc(sizeof(struct dcd_key_elem),
908 GFP_KERNEL);
909 if (!dcd_key) {
910 status = -ENOMEM;
911 goto func_end;
912 }
913
914 dcd_key->path = kmalloc(strlen(sz_reg_key) + 1,
915 GFP_KERNEL);
916
917 if (!dcd_key->path) {
918 kfree(dcd_key);
919 status = -ENOMEM;
920 goto func_end;
921 }
922
923 strncpy(dcd_key->name, sz_reg_key,
924 strlen(sz_reg_key) + 1);
925 strncpy(dcd_key->path, psz_path_name ,
926 dw_path_size);
927 spin_lock(&dbdcd_lock);
928 list_add_tail(&dcd_key->link, ®_key_list);
929 spin_unlock(&dbdcd_lock);
930 } else {
931 /* Make sure the new data is the same. */
932 if (strncmp(dcd_key->path, psz_path_name,
933 dw_path_size)) {
934 /* The caller needs a different data size! */
935 kfree(dcd_key->path);
936 dcd_key->path = kmalloc(dw_path_size,
937 GFP_KERNEL);
938 if (dcd_key->path == NULL) {
939 status = -ENOMEM;
940 goto func_end;
941 }
942 }
943
944 /* We have a match! Copy out the data. */
945 memcpy(dcd_key->path, psz_path_name, dw_path_size);
946 }
947 dev_dbg(bridge, "%s: psz_path_name=%s, dw_path_size=%d\n",
948 __func__, psz_path_name, dw_path_size);
949 } else {
950 /* Deregister an existing object */
951 spin_lock(&dbdcd_lock);
952 list_for_each_entry(dcd_key, ®_key_list, link) {
953 if (!strncmp(dcd_key->name, sz_reg_key,
954 strlen(sz_reg_key) + 1)) {
955 list_del(&dcd_key->link);
956 kfree(dcd_key->path);
957 kfree(dcd_key);
958 break;
959 }
960 }
961 spin_unlock(&dbdcd_lock);
962 if (&dcd_key->link == ®_key_list)
963 status = -EPERM;
964 }
965
966 if (!status) {
967 /*
968 * Because the node database has been updated through a
969 * successful object registration/de-registration operation,
970 * we need to reset the object enumeration counter to allow
971 * current enumerations to reflect this update in the node
972 * database.
973 */
974 enum_refs = 0;
975 }
976 func_end:
977 return status;
978 }
979
980 /*
981 * ======== dcd_unregister_object ========
982 * Call DCD_Register object with psz_path_name set to NULL to
983 * perform actual object de-registration.
984 */
dcd_unregister_object(struct dsp_uuid * uuid_obj,enum dsp_dcdobjtype obj_type)985 int dcd_unregister_object(struct dsp_uuid *uuid_obj,
986 enum dsp_dcdobjtype obj_type)
987 {
988 int status = 0;
989
990 DBC_REQUIRE(refs > 0);
991 DBC_REQUIRE(uuid_obj != NULL);
992 DBC_REQUIRE((obj_type == DSP_DCDNODETYPE) ||
993 (obj_type == DSP_DCDPROCESSORTYPE) ||
994 (obj_type == DSP_DCDLIBRARYTYPE) ||
995 (obj_type == DSP_DCDCREATELIBTYPE) ||
996 (obj_type == DSP_DCDEXECUTELIBTYPE) ||
997 (obj_type == DSP_DCDDELETELIBTYPE));
998
999 /*
1000 * When dcd_register_object is called with NULL as pathname,
1001 * it indicates an unregister object operation.
1002 */
1003 status = dcd_register_object(uuid_obj, obj_type, NULL);
1004
1005 return status;
1006 }
1007
1008 /*
1009 **********************************************************************
1010 * DCD Helper Functions
1011 **********************************************************************
1012 */
1013
1014 /*
1015 * ======== atoi ========
1016 * Purpose:
1017 * This function converts strings in decimal or hex format to integers.
1018 */
atoi(char * psz_buf)1019 static s32 atoi(char *psz_buf)
1020 {
1021 char *pch = psz_buf;
1022 s32 base = 0;
1023
1024 while (isspace(*pch))
1025 pch++;
1026
1027 if (*pch == '-' || *pch == '+') {
1028 base = 10;
1029 pch++;
1030 } else if (*pch && tolower(pch[strlen(pch) - 1]) == 'h') {
1031 base = 16;
1032 }
1033
1034 return simple_strtoul(pch, NULL, base);
1035 }
1036
1037 /*
1038 * ======== get_attrs_from_buf ========
1039 * Purpose:
1040 * Parse the content of a buffer filled with DSP-side data and
1041 * retrieve an object's attributes from it. IMPORTANT: Assume the
1042 * buffer has been converted from DSP format to GPP format.
1043 */
get_attrs_from_buf(char * psz_buf,u32 ul_buf_size,enum dsp_dcdobjtype obj_type,struct dcd_genericobj * gen_obj)1044 static int get_attrs_from_buf(char *psz_buf, u32 ul_buf_size,
1045 enum dsp_dcdobjtype obj_type,
1046 struct dcd_genericobj *gen_obj)
1047 {
1048 int status = 0;
1049 char seps[] = ", ";
1050 char *psz_cur;
1051 char *token;
1052 s32 token_len = 0;
1053 u32 i = 0;
1054 #ifdef _DB_TIOMAP
1055 s32 entry_id;
1056 #endif
1057
1058 DBC_REQUIRE(psz_buf != NULL);
1059 DBC_REQUIRE(ul_buf_size != 0);
1060 DBC_REQUIRE((obj_type == DSP_DCDNODETYPE)
1061 || (obj_type == DSP_DCDPROCESSORTYPE));
1062 DBC_REQUIRE(gen_obj != NULL);
1063
1064 switch (obj_type) {
1065 case DSP_DCDNODETYPE:
1066 /*
1067 * Parse COFF sect buffer to retrieve individual tokens used
1068 * to fill in object attrs.
1069 */
1070 psz_cur = psz_buf;
1071 token = strsep(&psz_cur, seps);
1072
1073 /* u32 cb_struct */
1074 gen_obj->obj_data.node_obj.ndb_props.cb_struct =
1075 (u32) atoi(token);
1076 token = strsep(&psz_cur, seps);
1077
1078 /* dsp_uuid ui_node_id */
1079 uuid_uuid_from_string(token,
1080 &gen_obj->obj_data.node_obj.ndb_props.
1081 ui_node_id);
1082 token = strsep(&psz_cur, seps);
1083
1084 /* ac_name */
1085 DBC_REQUIRE(token);
1086 token_len = strlen(token);
1087 if (token_len > DSP_MAXNAMELEN - 1)
1088 token_len = DSP_MAXNAMELEN - 1;
1089
1090 strncpy(gen_obj->obj_data.node_obj.ndb_props.ac_name,
1091 token, token_len);
1092 gen_obj->obj_data.node_obj.ndb_props.ac_name[token_len] = '\0';
1093 token = strsep(&psz_cur, seps);
1094 /* u32 ntype */
1095 gen_obj->obj_data.node_obj.ndb_props.ntype = atoi(token);
1096 token = strsep(&psz_cur, seps);
1097 /* u32 cache_on_gpp */
1098 gen_obj->obj_data.node_obj.ndb_props.cache_on_gpp = atoi(token);
1099 token = strsep(&psz_cur, seps);
1100 /* dsp_resourcereqmts dsp_resource_reqmts */
1101 gen_obj->obj_data.node_obj.ndb_props.dsp_resource_reqmts.
1102 cb_struct = (u32) atoi(token);
1103 token = strsep(&psz_cur, seps);
1104
1105 gen_obj->obj_data.node_obj.ndb_props.
1106 dsp_resource_reqmts.static_data_size = atoi(token);
1107 token = strsep(&psz_cur, seps);
1108 gen_obj->obj_data.node_obj.ndb_props.
1109 dsp_resource_reqmts.global_data_size = atoi(token);
1110 token = strsep(&psz_cur, seps);
1111 gen_obj->obj_data.node_obj.ndb_props.
1112 dsp_resource_reqmts.program_mem_size = atoi(token);
1113 token = strsep(&psz_cur, seps);
1114 gen_obj->obj_data.node_obj.ndb_props.
1115 dsp_resource_reqmts.wc_execution_time = atoi(token);
1116 token = strsep(&psz_cur, seps);
1117 gen_obj->obj_data.node_obj.ndb_props.
1118 dsp_resource_reqmts.wc_period = atoi(token);
1119 token = strsep(&psz_cur, seps);
1120
1121 gen_obj->obj_data.node_obj.ndb_props.
1122 dsp_resource_reqmts.wc_deadline = atoi(token);
1123 token = strsep(&psz_cur, seps);
1124
1125 gen_obj->obj_data.node_obj.ndb_props.
1126 dsp_resource_reqmts.avg_exection_time = atoi(token);
1127 token = strsep(&psz_cur, seps);
1128
1129 gen_obj->obj_data.node_obj.ndb_props.
1130 dsp_resource_reqmts.minimum_period = atoi(token);
1131 token = strsep(&psz_cur, seps);
1132
1133 /* s32 prio */
1134 gen_obj->obj_data.node_obj.ndb_props.prio = atoi(token);
1135 token = strsep(&psz_cur, seps);
1136
1137 /* u32 stack_size */
1138 gen_obj->obj_data.node_obj.ndb_props.stack_size = atoi(token);
1139 token = strsep(&psz_cur, seps);
1140
1141 /* u32 sys_stack_size */
1142 gen_obj->obj_data.node_obj.ndb_props.sys_stack_size =
1143 atoi(token);
1144 token = strsep(&psz_cur, seps);
1145
1146 /* u32 stack_seg */
1147 gen_obj->obj_data.node_obj.ndb_props.stack_seg = atoi(token);
1148 token = strsep(&psz_cur, seps);
1149
1150 /* u32 message_depth */
1151 gen_obj->obj_data.node_obj.ndb_props.message_depth =
1152 atoi(token);
1153 token = strsep(&psz_cur, seps);
1154
1155 /* u32 num_input_streams */
1156 gen_obj->obj_data.node_obj.ndb_props.num_input_streams =
1157 atoi(token);
1158 token = strsep(&psz_cur, seps);
1159
1160 /* u32 num_output_streams */
1161 gen_obj->obj_data.node_obj.ndb_props.num_output_streams =
1162 atoi(token);
1163 token = strsep(&psz_cur, seps);
1164
1165 /* u32 timeout */
1166 gen_obj->obj_data.node_obj.ndb_props.timeout = atoi(token);
1167 token = strsep(&psz_cur, seps);
1168
1169 /* char *str_create_phase_fxn */
1170 DBC_REQUIRE(token);
1171 token_len = strlen(token);
1172 gen_obj->obj_data.node_obj.str_create_phase_fxn =
1173 kzalloc(token_len + 1, GFP_KERNEL);
1174 strncpy(gen_obj->obj_data.node_obj.str_create_phase_fxn,
1175 token, token_len);
1176 gen_obj->obj_data.node_obj.str_create_phase_fxn[token_len] =
1177 '\0';
1178 token = strsep(&psz_cur, seps);
1179
1180 /* char *str_execute_phase_fxn */
1181 DBC_REQUIRE(token);
1182 token_len = strlen(token);
1183 gen_obj->obj_data.node_obj.str_execute_phase_fxn =
1184 kzalloc(token_len + 1, GFP_KERNEL);
1185 strncpy(gen_obj->obj_data.node_obj.str_execute_phase_fxn,
1186 token, token_len);
1187 gen_obj->obj_data.node_obj.str_execute_phase_fxn[token_len] =
1188 '\0';
1189 token = strsep(&psz_cur, seps);
1190
1191 /* char *str_delete_phase_fxn */
1192 DBC_REQUIRE(token);
1193 token_len = strlen(token);
1194 gen_obj->obj_data.node_obj.str_delete_phase_fxn =
1195 kzalloc(token_len + 1, GFP_KERNEL);
1196 strncpy(gen_obj->obj_data.node_obj.str_delete_phase_fxn,
1197 token, token_len);
1198 gen_obj->obj_data.node_obj.str_delete_phase_fxn[token_len] =
1199 '\0';
1200 token = strsep(&psz_cur, seps);
1201
1202 /* Segment id for message buffers */
1203 gen_obj->obj_data.node_obj.msg_segid = atoi(token);
1204 token = strsep(&psz_cur, seps);
1205
1206 /* Message notification type */
1207 gen_obj->obj_data.node_obj.msg_notify_type = atoi(token);
1208 token = strsep(&psz_cur, seps);
1209
1210 /* char *str_i_alg_name */
1211 if (token) {
1212 token_len = strlen(token);
1213 gen_obj->obj_data.node_obj.str_i_alg_name =
1214 kzalloc(token_len + 1, GFP_KERNEL);
1215 strncpy(gen_obj->obj_data.node_obj.str_i_alg_name,
1216 token, token_len);
1217 gen_obj->obj_data.node_obj.str_i_alg_name[token_len] =
1218 '\0';
1219 token = strsep(&psz_cur, seps);
1220 }
1221
1222 /* Load type (static, dynamic, or overlay) */
1223 if (token) {
1224 gen_obj->obj_data.node_obj.load_type = atoi(token);
1225 token = strsep(&psz_cur, seps);
1226 }
1227
1228 /* Dynamic load data requirements */
1229 if (token) {
1230 gen_obj->obj_data.node_obj.data_mem_seg_mask =
1231 atoi(token);
1232 token = strsep(&psz_cur, seps);
1233 }
1234
1235 /* Dynamic load code requirements */
1236 if (token) {
1237 gen_obj->obj_data.node_obj.code_mem_seg_mask =
1238 atoi(token);
1239 token = strsep(&psz_cur, seps);
1240 }
1241
1242 /* Extract node profiles into node properties */
1243 if (token) {
1244
1245 gen_obj->obj_data.node_obj.ndb_props.count_profiles =
1246 atoi(token);
1247 for (i = 0;
1248 i <
1249 gen_obj->obj_data.node_obj.
1250 ndb_props.count_profiles; i++) {
1251 token = strsep(&psz_cur, seps);
1252 if (token) {
1253 /* Heap Size for the node */
1254 gen_obj->obj_data.node_obj.
1255 ndb_props.node_profiles[i].
1256 heap_size = atoi(token);
1257 }
1258 }
1259 }
1260 token = strsep(&psz_cur, seps);
1261 if (token) {
1262 gen_obj->obj_data.node_obj.ndb_props.stack_seg_name =
1263 (u32) (token);
1264 }
1265
1266 break;
1267
1268 case DSP_DCDPROCESSORTYPE:
1269 /*
1270 * Parse COFF sect buffer to retrieve individual tokens used
1271 * to fill in object attrs.
1272 */
1273 psz_cur = psz_buf;
1274 token = strsep(&psz_cur, seps);
1275
1276 gen_obj->obj_data.proc_info.cb_struct = atoi(token);
1277 token = strsep(&psz_cur, seps);
1278
1279 gen_obj->obj_data.proc_info.processor_family = atoi(token);
1280 token = strsep(&psz_cur, seps);
1281
1282 gen_obj->obj_data.proc_info.processor_type = atoi(token);
1283 token = strsep(&psz_cur, seps);
1284
1285 gen_obj->obj_data.proc_info.clock_rate = atoi(token);
1286 token = strsep(&psz_cur, seps);
1287
1288 gen_obj->obj_data.proc_info.internal_mem_size = atoi(token);
1289 token = strsep(&psz_cur, seps);
1290
1291 gen_obj->obj_data.proc_info.external_mem_size = atoi(token);
1292 token = strsep(&psz_cur, seps);
1293
1294 gen_obj->obj_data.proc_info.processor_id = atoi(token);
1295 token = strsep(&psz_cur, seps);
1296
1297 gen_obj->obj_data.proc_info.ty_running_rtos = atoi(token);
1298 token = strsep(&psz_cur, seps);
1299
1300 gen_obj->obj_data.proc_info.node_min_priority = atoi(token);
1301 token = strsep(&psz_cur, seps);
1302
1303 gen_obj->obj_data.proc_info.node_max_priority = atoi(token);
1304
1305 #ifdef _DB_TIOMAP
1306 /* Proc object may contain additional(extended) attributes. */
1307 /* attr must match proc.hxx */
1308 for (entry_id = 0; entry_id < 7; entry_id++) {
1309 token = strsep(&psz_cur, seps);
1310 gen_obj->obj_data.ext_proc_obj.ty_tlb[entry_id].
1311 gpp_phys = atoi(token);
1312
1313 token = strsep(&psz_cur, seps);
1314 gen_obj->obj_data.ext_proc_obj.ty_tlb[entry_id].
1315 dsp_virt = atoi(token);
1316 }
1317 #endif
1318
1319 break;
1320
1321 default:
1322 status = -EPERM;
1323 break;
1324 }
1325
1326 return status;
1327 }
1328
1329 /*
1330 * ======== CompressBuffer ========
1331 * Purpose:
1332 * Compress the DSP buffer, if necessary, to conform to PC format.
1333 */
compress_buf(char * psz_buf,u32 ul_buf_size,s32 char_size)1334 static void compress_buf(char *psz_buf, u32 ul_buf_size, s32 char_size)
1335 {
1336 char *p;
1337 char ch;
1338 char *q;
1339
1340 p = psz_buf;
1341 if (p == NULL)
1342 return;
1343
1344 for (q = psz_buf; q < (psz_buf + ul_buf_size);) {
1345 ch = dsp_char2_gpp_char(q, char_size);
1346 if (ch == '\\') {
1347 q += char_size;
1348 ch = dsp_char2_gpp_char(q, char_size);
1349 switch (ch) {
1350 case 't':
1351 *p = '\t';
1352 break;
1353
1354 case 'n':
1355 *p = '\n';
1356 break;
1357
1358 case 'r':
1359 *p = '\r';
1360 break;
1361
1362 case '0':
1363 *p = '\0';
1364 break;
1365
1366 default:
1367 *p = ch;
1368 break;
1369 }
1370 } else {
1371 *p = ch;
1372 }
1373 p++;
1374 q += char_size;
1375 }
1376
1377 /* NULL out remainder of buffer. */
1378 while (p < q)
1379 *p++ = '\0';
1380 }
1381
1382 /*
1383 * ======== dsp_char2_gpp_char ========
1384 * Purpose:
1385 * Convert DSP char to host GPP char in a portable manner
1386 */
dsp_char2_gpp_char(char * word,s32 dsp_char_size)1387 static char dsp_char2_gpp_char(char *word, s32 dsp_char_size)
1388 {
1389 char ch = '\0';
1390 char *ch_src;
1391 s32 i;
1392
1393 for (ch_src = word, i = dsp_char_size; i > 0; i--)
1394 ch |= *ch_src++;
1395
1396 return ch;
1397 }
1398
1399 /*
1400 * ======== get_dep_lib_info ========
1401 */
get_dep_lib_info(struct dcd_manager * hdcd_mgr,struct dsp_uuid * uuid_obj,u16 * num_libs,u16 * num_pers_libs,struct dsp_uuid * dep_lib_uuids,bool * prstnt_dep_libs,enum nldr_phase phase)1402 static int get_dep_lib_info(struct dcd_manager *hdcd_mgr,
1403 struct dsp_uuid *uuid_obj,
1404 u16 *num_libs,
1405 u16 *num_pers_libs,
1406 struct dsp_uuid *dep_lib_uuids,
1407 bool *prstnt_dep_libs,
1408 enum nldr_phase phase)
1409 {
1410 struct dcd_manager *dcd_mgr_obj = hdcd_mgr;
1411 char *psz_coff_buf = NULL;
1412 char *psz_cur;
1413 char *psz_file_name = NULL;
1414 struct cod_libraryobj *lib = NULL;
1415 u32 ul_addr = 0; /* Used by cod_get_section */
1416 u32 ul_len = 0; /* Used by cod_get_section */
1417 u32 dw_data_size = COD_MAXPATHLENGTH;
1418 char seps[] = ", ";
1419 char *token = NULL;
1420 bool get_uuids = (dep_lib_uuids != NULL);
1421 u16 dep_libs = 0;
1422 int status = 0;
1423
1424 DBC_REQUIRE(refs > 0);
1425
1426 DBC_REQUIRE(hdcd_mgr);
1427 DBC_REQUIRE(num_libs != NULL);
1428 DBC_REQUIRE(uuid_obj != NULL);
1429
1430 /* Initialize to 0 dependent libraries, if only counting number of
1431 * dependent libraries */
1432 if (!get_uuids) {
1433 *num_libs = 0;
1434 *num_pers_libs = 0;
1435 }
1436
1437 /* Allocate a buffer for file name */
1438 psz_file_name = kzalloc(dw_data_size, GFP_KERNEL);
1439 if (psz_file_name == NULL) {
1440 status = -ENOMEM;
1441 } else {
1442 /* Get the name of the library */
1443 status = dcd_get_library_name(hdcd_mgr, uuid_obj, psz_file_name,
1444 &dw_data_size, phase, NULL);
1445 }
1446
1447 /* Open the library */
1448 if (!status) {
1449 status = cod_open(dcd_mgr_obj->cod_mgr, psz_file_name,
1450 COD_NOLOAD, &lib);
1451 }
1452 if (!status) {
1453 /* Get dependent library section information. */
1454 status = cod_get_section(lib, DEPLIBSECT, &ul_addr, &ul_len);
1455
1456 if (status) {
1457 /* Ok, no dependent libraries */
1458 ul_len = 0;
1459 status = 0;
1460 }
1461 }
1462
1463 if (status || !(ul_len > 0))
1464 goto func_cont;
1465
1466 /* Allocate zeroed buffer. */
1467 psz_coff_buf = kzalloc(ul_len + 4, GFP_KERNEL);
1468 if (psz_coff_buf == NULL)
1469 status = -ENOMEM;
1470
1471 /* Read section contents. */
1472 status = cod_read_section(lib, DEPLIBSECT, psz_coff_buf, ul_len);
1473 if (status)
1474 goto func_cont;
1475
1476 /* Compress and format DSP buffer to conform to PC format. */
1477 compress_buf(psz_coff_buf, ul_len, DSPWORDSIZE);
1478
1479 /* Read from buffer */
1480 psz_cur = psz_coff_buf;
1481 while ((token = strsep(&psz_cur, seps)) && *token != '\0') {
1482 if (get_uuids) {
1483 if (dep_libs >= *num_libs) {
1484 /* Gone beyond the limit */
1485 break;
1486 } else {
1487 /* Retrieve UUID string. */
1488 uuid_uuid_from_string(token,
1489 &(dep_lib_uuids
1490 [dep_libs]));
1491 /* Is this library persistent? */
1492 token = strsep(&psz_cur, seps);
1493 prstnt_dep_libs[dep_libs] = atoi(token);
1494 dep_libs++;
1495 }
1496 } else {
1497 /* Advanc to next token */
1498 token = strsep(&psz_cur, seps);
1499 if (atoi(token))
1500 (*num_pers_libs)++;
1501
1502 /* Just counting number of dependent libraries */
1503 (*num_libs)++;
1504 }
1505 }
1506 func_cont:
1507 if (lib)
1508 cod_close(lib);
1509
1510 /* Free previously allocated dynamic buffers. */
1511 kfree(psz_file_name);
1512
1513 kfree(psz_coff_buf);
1514
1515 return status;
1516 }
1517