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