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, &reg_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 == &reg_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, &reg_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, &reg_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 == &reg_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, &reg_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 == &reg_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, &reg_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 != &reg_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(&reg_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, &reg_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 == &reg_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, &reg_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, &reg_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 == &reg_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