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