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