Fix common misspellings
[deliverable/linux.git] / drivers / staging / tidspbridge / rmgr / nldr.c
1 /*
2 * nldr.c
3 *
4 * DSP-BIOS Bridge driver support functions for TI OMAP processors.
5 *
6 * DSP/BIOS Bridge dynamic + overlay Node loader.
7 *
8 * Copyright (C) 2005-2006 Texas Instruments, Inc.
9 *
10 * This package is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 *
14 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
16 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
17 */
18
19 #include <linux/types.h>
20
21 #include <dspbridge/host_os.h>
22
23 #include <dspbridge/dbdefs.h>
24
25 #include <dspbridge/dbc.h>
26
27 /* Platform manager */
28 #include <dspbridge/cod.h>
29 #include <dspbridge/dev.h>
30
31 /* Resource manager */
32 #include <dspbridge/dbll.h>
33 #include <dspbridge/dbdcd.h>
34 #include <dspbridge/rmm.h>
35 #include <dspbridge/uuidutil.h>
36
37 #include <dspbridge/nldr.h>
38 #include <linux/lcm.h>
39
40 /* Name of section containing dynamic load mem */
41 #define DYNMEMSECT ".dspbridge_mem"
42
43 /* Name of section containing dependent library information */
44 #define DEPLIBSECT ".dspbridge_deplibs"
45
46 /* Max depth of recursion for loading node's dependent libraries */
47 #define MAXDEPTH 5
48
49 /* Max number of persistent libraries kept by a node */
50 #define MAXLIBS 5
51
52 /*
53 * Defines for extracting packed dynamic load memory requirements from two
54 * masks.
55 * These defines must match node.cdb and dynm.cdb
56 * Format of data/code mask is:
57 * uuuuuuuu|fueeeeee|fudddddd|fucccccc|
58 * where
59 * u = unused
60 * cccccc = preferred/required dynamic mem segid for create phase data/code
61 * dddddd = preferred/required dynamic mem segid for delete phase data/code
62 * eeeeee = preferred/req. dynamic mem segid for execute phase data/code
63 * f = flag indicating if memory is preferred or required:
64 * f = 1 if required, f = 0 if preferred.
65 *
66 * The 6 bits of the segid are interpreted as follows:
67 *
68 * If the 6th bit (bit 5) is not set, then this specifies a memory segment
69 * between 0 and 31 (a maximum of 32 dynamic loading memory segments).
70 * If the 6th bit (bit 5) is set, segid has the following interpretation:
71 * segid = 32 - Any internal memory segment can be used.
72 * segid = 33 - Any external memory segment can be used.
73 * segid = 63 - Any memory segment can be used (in this case the
74 * required/preferred flag is irrelevant).
75 *
76 */
77 /* Maximum allowed dynamic loading memory segments */
78 #define MAXMEMSEGS 32
79
80 #define MAXSEGID 3 /* Largest possible (real) segid */
81 #define MEMINTERNALID 32 /* Segid meaning use internal mem */
82 #define MEMEXTERNALID 33 /* Segid meaning use external mem */
83 #define NULLID 63 /* Segid meaning no memory req/pref */
84 #define FLAGBIT 7 /* 7th bit is pref./req. flag */
85 #define SEGMASK 0x3f /* Bits 0 - 5 */
86
87 #define CREATEBIT 0 /* Create segid starts at bit 0 */
88 #define DELETEBIT 8 /* Delete segid starts at bit 8 */
89 #define EXECUTEBIT 16 /* Execute segid starts at bit 16 */
90
91 /*
92 * Masks that define memory type. Must match defines in dynm.cdb.
93 */
94 #define DYNM_CODE 0x2
95 #define DYNM_DATA 0x4
96 #define DYNM_CODEDATA (DYNM_CODE | DYNM_DATA)
97 #define DYNM_INTERNAL 0x8
98 #define DYNM_EXTERNAL 0x10
99
100 /*
101 * Defines for packing memory requirement/preference flags for code and
102 * data of each of the node's phases into one mask.
103 * The bit is set if the segid is required for loading code/data of the
104 * given phase. The bit is not set, if the segid is preferred only.
105 *
106 * These defines are also used as indeces into a segid array for the node.
107 * eg node's segid[CREATEDATAFLAGBIT] is the memory segment id that the
108 * create phase data is required or preferred to be loaded into.
109 */
110 #define CREATEDATAFLAGBIT 0
111 #define CREATECODEFLAGBIT 1
112 #define EXECUTEDATAFLAGBIT 2
113 #define EXECUTECODEFLAGBIT 3
114 #define DELETEDATAFLAGBIT 4
115 #define DELETECODEFLAGBIT 5
116 #define MAXFLAGS 6
117
118 /*
119 * These names may be embedded in overlay sections to identify which
120 * node phase the section should be overlayed.
121 */
122 #define PCREATE "create"
123 #define PDELETE "delete"
124 #define PEXECUTE "execute"
125
126 static inline bool is_equal_uuid(struct dsp_uuid *uuid1,
127 struct dsp_uuid *uuid2)
128 {
129 return !memcmp(uuid1, uuid2, sizeof(struct dsp_uuid));
130 }
131
132 /*
133 * ======== mem_seg_info ========
134 * Format of dynamic loading memory segment info in coff file.
135 * Must match dynm.h55.
136 */
137 struct mem_seg_info {
138 u32 segid; /* Dynamic loading memory segment number */
139 u32 base;
140 u32 len;
141 u32 type; /* Mask of DYNM_CODE, DYNM_INTERNAL, etc. */
142 };
143
144 /*
145 * ======== lib_node ========
146 * For maintaining a tree of library dependencies.
147 */
148 struct lib_node {
149 struct dbll_library_obj *lib; /* The library */
150 u16 dep_libs; /* Number of dependent libraries */
151 struct lib_node *dep_libs_tree; /* Dependent libraries of lib */
152 };
153
154 /*
155 * ======== ovly_sect ========
156 * Information needed to overlay a section.
157 */
158 struct ovly_sect {
159 struct ovly_sect *next_sect;
160 u32 sect_load_addr; /* Load address of section */
161 u32 sect_run_addr; /* Run address of section */
162 u32 size; /* Size of section */
163 u16 page; /* DBL_CODE, DBL_DATA */
164 };
165
166 /*
167 * ======== ovly_node ========
168 * For maintaining a list of overlay nodes, with sections that need to be
169 * overlayed for each of the nodes phases.
170 */
171 struct ovly_node {
172 struct dsp_uuid uuid;
173 char *node_name;
174 struct ovly_sect *create_sects_list;
175 struct ovly_sect *delete_sects_list;
176 struct ovly_sect *execute_sects_list;
177 struct ovly_sect *other_sects_list;
178 u16 create_sects;
179 u16 delete_sects;
180 u16 execute_sects;
181 u16 other_sects;
182 u16 create_ref;
183 u16 delete_ref;
184 u16 execute_ref;
185 u16 other_ref;
186 };
187
188 /*
189 * ======== nldr_object ========
190 * Overlay loader object.
191 */
192 struct nldr_object {
193 struct dev_object *dev_obj; /* Device object */
194 struct dcd_manager *dcd_mgr; /* Proc/Node data manager */
195 struct dbll_tar_obj *dbll; /* The DBL loader */
196 struct dbll_library_obj *base_lib; /* Base image library */
197 struct rmm_target_obj *rmm; /* Remote memory manager for DSP */
198 struct dbll_fxns ldr_fxns; /* Loader function table */
199 struct dbll_attrs ldr_attrs; /* attrs to pass to loader functions */
200 nldr_ovlyfxn ovly_fxn; /* "write" for overlay nodes */
201 nldr_writefxn write_fxn; /* "write" for dynamic nodes */
202 struct ovly_node *ovly_table; /* Table of overlay nodes */
203 u16 ovly_nodes; /* Number of overlay nodes in base */
204 u16 ovly_nid; /* Index for tracking overlay nodes */
205 u16 dload_segs; /* Number of dynamic load mem segs */
206 u32 *seg_table; /* memtypes of dynamic memory segs
207 * indexed by segid
208 */
209 u16 dsp_mau_size; /* Size of DSP MAU */
210 u16 dsp_word_size; /* Size of DSP word */
211 };
212
213 /*
214 * ======== nldr_nodeobject ========
215 * Dynamic node object. This object is created when a node is allocated.
216 */
217 struct nldr_nodeobject {
218 struct nldr_object *nldr_obj; /* Dynamic loader handle */
219 void *priv_ref; /* Handle to pass to dbl_write_fxn */
220 struct dsp_uuid uuid; /* Node's UUID */
221 bool dynamic; /* Dynamically loaded node? */
222 bool overlay; /* Overlay node? */
223 bool *phase_split; /* Multiple phase libraries? */
224 struct lib_node root; /* Library containing node phase */
225 struct lib_node create_lib; /* Library with create phase lib */
226 struct lib_node execute_lib; /* Library with execute phase lib */
227 struct lib_node delete_lib; /* Library with delete phase lib */
228 /* libs remain loaded until Delete */
229 struct lib_node pers_lib_table[MAXLIBS];
230 s32 pers_libs; /* Number of persistent libraries */
231 /* Path in lib dependency tree */
232 struct dbll_library_obj *lib_path[MAXDEPTH + 1];
233 enum nldr_phase phase; /* Node phase currently being loaded */
234
235 /*
236 * Dynamic loading memory segments for data and code of each phase.
237 */
238 u16 seg_id[MAXFLAGS];
239
240 /*
241 * Mask indicating whether each mem segment specified in seg_id[]
242 * is preferred or required.
243 * For example
244 * if (code_data_flag_mask & (1 << EXECUTEDATAFLAGBIT)) != 0,
245 * then it is required to load execute phase data into the memory
246 * specified by seg_id[EXECUTEDATAFLAGBIT].
247 */
248 u32 code_data_flag_mask;
249 };
250
251 /* Dynamic loader function table */
252 static struct dbll_fxns ldr_fxns = {
253 (dbll_close_fxn) dbll_close,
254 (dbll_create_fxn) dbll_create,
255 (dbll_delete_fxn) dbll_delete,
256 (dbll_exit_fxn) dbll_exit,
257 (dbll_get_attrs_fxn) dbll_get_attrs,
258 (dbll_get_addr_fxn) dbll_get_addr,
259 (dbll_get_c_addr_fxn) dbll_get_c_addr,
260 (dbll_get_sect_fxn) dbll_get_sect,
261 (dbll_init_fxn) dbll_init,
262 (dbll_load_fxn) dbll_load,
263 (dbll_open_fxn) dbll_open,
264 (dbll_read_sect_fxn) dbll_read_sect,
265 (dbll_unload_fxn) dbll_unload,
266 };
267
268 static u32 refs; /* module reference count */
269
270 static int add_ovly_info(void *handle, struct dbll_sect_info *sect_info,
271 u32 addr, u32 bytes);
272 static int add_ovly_node(struct dsp_uuid *uuid_obj,
273 enum dsp_dcdobjtype obj_type, void *handle);
274 static int add_ovly_sect(struct nldr_object *nldr_obj,
275 struct ovly_sect **lst,
276 struct dbll_sect_info *sect_inf,
277 bool *exists, u32 addr, u32 bytes);
278 static s32 fake_ovly_write(void *handle, u32 dsp_address, void *buf, u32 bytes,
279 s32 mtype);
280 static void free_sects(struct nldr_object *nldr_obj,
281 struct ovly_sect *phase_sects, u16 alloc_num);
282 static bool get_symbol_value(void *handle, void *parg, void *rmm_handle,
283 char *sym_name, struct dbll_sym_val **sym);
284 static int load_lib(struct nldr_nodeobject *nldr_node_obj,
285 struct lib_node *root, struct dsp_uuid uuid,
286 bool root_prstnt,
287 struct dbll_library_obj **lib_path,
288 enum nldr_phase phase, u16 depth);
289 static int load_ovly(struct nldr_nodeobject *nldr_node_obj,
290 enum nldr_phase phase);
291 static int remote_alloc(void **ref, u16 mem_sect, u32 size,
292 u32 align, u32 *dsp_address,
293 s32 segmnt_id,
294 s32 req, bool reserve);
295 static int remote_free(void **ref, u16 space, u32 dsp_address, u32 size,
296 bool reserve);
297
298 static void unload_lib(struct nldr_nodeobject *nldr_node_obj,
299 struct lib_node *root);
300 static void unload_ovly(struct nldr_nodeobject *nldr_node_obj,
301 enum nldr_phase phase);
302 static bool find_in_persistent_lib_array(struct nldr_nodeobject *nldr_node_obj,
303 struct dbll_library_obj *lib);
304
305 /*
306 * ======== nldr_allocate ========
307 */
308 int nldr_allocate(struct nldr_object *nldr_obj, void *priv_ref,
309 const struct dcd_nodeprops *node_props,
310 struct nldr_nodeobject **nldr_nodeobj,
311 bool *pf_phase_split)
312 {
313 struct nldr_nodeobject *nldr_node_obj = NULL;
314 int status = 0;
315
316 DBC_REQUIRE(refs > 0);
317 DBC_REQUIRE(node_props != NULL);
318 DBC_REQUIRE(nldr_nodeobj != NULL);
319 DBC_REQUIRE(nldr_obj);
320
321 /* Initialize handle in case of failure */
322 *nldr_nodeobj = NULL;
323 /* Allocate node object */
324 nldr_node_obj = kzalloc(sizeof(struct nldr_nodeobject), GFP_KERNEL);
325
326 if (nldr_node_obj == NULL) {
327 status = -ENOMEM;
328 } else {
329 nldr_node_obj->phase_split = pf_phase_split;
330 nldr_node_obj->pers_libs = 0;
331 nldr_node_obj->nldr_obj = nldr_obj;
332 nldr_node_obj->priv_ref = priv_ref;
333 /* Save node's UUID. */
334 nldr_node_obj->uuid = node_props->ndb_props.ui_node_id;
335 /*
336 * Determine if node is a dynamically loaded node from
337 * ndb_props.
338 */
339 if (node_props->load_type == NLDR_DYNAMICLOAD) {
340 /* Dynamic node */
341 nldr_node_obj->dynamic = true;
342 /*
343 * Extract memory requirements from ndb_props masks
344 */
345 /* Create phase */
346 nldr_node_obj->seg_id[CREATEDATAFLAGBIT] = (u16)
347 (node_props->data_mem_seg_mask >> CREATEBIT) &
348 SEGMASK;
349 nldr_node_obj->code_data_flag_mask |=
350 ((node_props->data_mem_seg_mask >>
351 (CREATEBIT + FLAGBIT)) & 1) << CREATEDATAFLAGBIT;
352 nldr_node_obj->seg_id[CREATECODEFLAGBIT] = (u16)
353 (node_props->code_mem_seg_mask >>
354 CREATEBIT) & SEGMASK;
355 nldr_node_obj->code_data_flag_mask |=
356 ((node_props->code_mem_seg_mask >>
357 (CREATEBIT + FLAGBIT)) & 1) << CREATECODEFLAGBIT;
358 /* Execute phase */
359 nldr_node_obj->seg_id[EXECUTEDATAFLAGBIT] = (u16)
360 (node_props->data_mem_seg_mask >>
361 EXECUTEBIT) & SEGMASK;
362 nldr_node_obj->code_data_flag_mask |=
363 ((node_props->data_mem_seg_mask >>
364 (EXECUTEBIT + FLAGBIT)) & 1) <<
365 EXECUTEDATAFLAGBIT;
366 nldr_node_obj->seg_id[EXECUTECODEFLAGBIT] = (u16)
367 (node_props->code_mem_seg_mask >>
368 EXECUTEBIT) & SEGMASK;
369 nldr_node_obj->code_data_flag_mask |=
370 ((node_props->code_mem_seg_mask >>
371 (EXECUTEBIT + FLAGBIT)) & 1) <<
372 EXECUTECODEFLAGBIT;
373 /* Delete phase */
374 nldr_node_obj->seg_id[DELETEDATAFLAGBIT] = (u16)
375 (node_props->data_mem_seg_mask >> DELETEBIT) &
376 SEGMASK;
377 nldr_node_obj->code_data_flag_mask |=
378 ((node_props->data_mem_seg_mask >>
379 (DELETEBIT + FLAGBIT)) & 1) << DELETEDATAFLAGBIT;
380 nldr_node_obj->seg_id[DELETECODEFLAGBIT] = (u16)
381 (node_props->code_mem_seg_mask >>
382 DELETEBIT) & SEGMASK;
383 nldr_node_obj->code_data_flag_mask |=
384 ((node_props->code_mem_seg_mask >>
385 (DELETEBIT + FLAGBIT)) & 1) << DELETECODEFLAGBIT;
386 } else {
387 /* Non-dynamically loaded nodes are part of the
388 * base image */
389 nldr_node_obj->root.lib = nldr_obj->base_lib;
390 /* Check for overlay node */
391 if (node_props->load_type == NLDR_OVLYLOAD)
392 nldr_node_obj->overlay = true;
393
394 }
395 *nldr_nodeobj = (struct nldr_nodeobject *)nldr_node_obj;
396 }
397 /* Cleanup on failure */
398 if (status && nldr_node_obj)
399 kfree(nldr_node_obj);
400
401 DBC_ENSURE((!status && *nldr_nodeobj)
402 || (status && *nldr_nodeobj == NULL));
403 return status;
404 }
405
406 /*
407 * ======== nldr_create ========
408 */
409 int nldr_create(struct nldr_object **nldr,
410 struct dev_object *hdev_obj,
411 const struct nldr_attrs *pattrs)
412 {
413 struct cod_manager *cod_mgr; /* COD manager */
414 char *psz_coff_buf = NULL;
415 char sz_zl_file[COD_MAXPATHLENGTH];
416 struct nldr_object *nldr_obj = NULL;
417 struct dbll_attrs save_attrs;
418 struct dbll_attrs new_attrs;
419 dbll_flags flags;
420 u32 ul_entry;
421 u16 dload_segs = 0;
422 struct mem_seg_info *mem_info_obj;
423 u32 ul_len = 0;
424 u32 ul_addr;
425 struct rmm_segment *rmm_segs = NULL;
426 u16 i;
427 int status = 0;
428 DBC_REQUIRE(refs > 0);
429 DBC_REQUIRE(nldr != NULL);
430 DBC_REQUIRE(hdev_obj != NULL);
431 DBC_REQUIRE(pattrs != NULL);
432 DBC_REQUIRE(pattrs->ovly != NULL);
433 DBC_REQUIRE(pattrs->write != NULL);
434
435 /* Allocate dynamic loader object */
436 nldr_obj = kzalloc(sizeof(struct nldr_object), GFP_KERNEL);
437 if (nldr_obj) {
438 nldr_obj->dev_obj = hdev_obj;
439 /* warning, lazy status checking alert! */
440 dev_get_cod_mgr(hdev_obj, &cod_mgr);
441 if (cod_mgr) {
442 status = cod_get_loader(cod_mgr, &nldr_obj->dbll);
443 DBC_ASSERT(!status);
444 status = cod_get_base_lib(cod_mgr, &nldr_obj->base_lib);
445 DBC_ASSERT(!status);
446 status =
447 cod_get_base_name(cod_mgr, sz_zl_file,
448 COD_MAXPATHLENGTH);
449 DBC_ASSERT(!status);
450 }
451 status = 0;
452 /* end lazy status checking */
453 nldr_obj->dsp_mau_size = pattrs->dsp_mau_size;
454 nldr_obj->dsp_word_size = pattrs->dsp_word_size;
455 nldr_obj->ldr_fxns = ldr_fxns;
456 if (!(nldr_obj->ldr_fxns.init_fxn()))
457 status = -ENOMEM;
458
459 } else {
460 status = -ENOMEM;
461 }
462 /* Create the DCD Manager */
463 if (!status)
464 status = dcd_create_manager(NULL, &nldr_obj->dcd_mgr);
465
466 /* Get dynamic loading memory sections from base lib */
467 if (!status) {
468 status =
469 nldr_obj->ldr_fxns.get_sect_fxn(nldr_obj->base_lib,
470 DYNMEMSECT, &ul_addr,
471 &ul_len);
472 if (!status) {
473 psz_coff_buf =
474 kzalloc(ul_len * nldr_obj->dsp_mau_size,
475 GFP_KERNEL);
476 if (!psz_coff_buf)
477 status = -ENOMEM;
478 } else {
479 /* Ok to not have dynamic loading memory */
480 status = 0;
481 ul_len = 0;
482 dev_dbg(bridge, "%s: failed - no dynamic loading mem "
483 "segments: 0x%x\n", __func__, status);
484 }
485 }
486 if (!status && ul_len > 0) {
487 /* Read section containing dynamic load mem segments */
488 status =
489 nldr_obj->ldr_fxns.read_sect_fxn(nldr_obj->base_lib,
490 DYNMEMSECT, psz_coff_buf,
491 ul_len);
492 }
493 if (!status && ul_len > 0) {
494 /* Parse memory segment data */
495 dload_segs = (u16) (*((u32 *) psz_coff_buf));
496 if (dload_segs > MAXMEMSEGS)
497 status = -EBADF;
498 }
499 /* Parse dynamic load memory segments */
500 if (!status && dload_segs > 0) {
501 rmm_segs = kzalloc(sizeof(struct rmm_segment) * dload_segs,
502 GFP_KERNEL);
503 nldr_obj->seg_table =
504 kzalloc(sizeof(u32) * dload_segs, GFP_KERNEL);
505 if (rmm_segs == NULL || nldr_obj->seg_table == NULL) {
506 status = -ENOMEM;
507 } else {
508 nldr_obj->dload_segs = dload_segs;
509 mem_info_obj = (struct mem_seg_info *)(psz_coff_buf +
510 sizeof(u32));
511 for (i = 0; i < dload_segs; i++) {
512 rmm_segs[i].base = (mem_info_obj + i)->base;
513 rmm_segs[i].length = (mem_info_obj + i)->len;
514 rmm_segs[i].space = 0;
515 nldr_obj->seg_table[i] =
516 (mem_info_obj + i)->type;
517 dev_dbg(bridge,
518 "(proc) DLL MEMSEGMENT: %d, "
519 "Base: 0x%x, Length: 0x%x\n", i,
520 rmm_segs[i].base, rmm_segs[i].length);
521 }
522 }
523 }
524 /* Create Remote memory manager */
525 if (!status)
526 status = rmm_create(&nldr_obj->rmm, rmm_segs, dload_segs);
527
528 if (!status) {
529 /* set the alloc, free, write functions for loader */
530 nldr_obj->ldr_fxns.get_attrs_fxn(nldr_obj->dbll, &save_attrs);
531 new_attrs = save_attrs;
532 new_attrs.alloc = (dbll_alloc_fxn) remote_alloc;
533 new_attrs.free = (dbll_free_fxn) remote_free;
534 new_attrs.sym_lookup = (dbll_sym_lookup) get_symbol_value;
535 new_attrs.sym_handle = nldr_obj;
536 new_attrs.write = (dbll_write_fxn) pattrs->write;
537 nldr_obj->ovly_fxn = pattrs->ovly;
538 nldr_obj->write_fxn = pattrs->write;
539 nldr_obj->ldr_attrs = new_attrs;
540 }
541 kfree(rmm_segs);
542
543 kfree(psz_coff_buf);
544
545 /* Get overlay nodes */
546 if (!status) {
547 status =
548 cod_get_base_name(cod_mgr, sz_zl_file, COD_MAXPATHLENGTH);
549 /* lazy check */
550 DBC_ASSERT(!status);
551 /* First count number of overlay nodes */
552 status =
553 dcd_get_objects(nldr_obj->dcd_mgr, sz_zl_file,
554 add_ovly_node, (void *)nldr_obj);
555 /* Now build table of overlay nodes */
556 if (!status && nldr_obj->ovly_nodes > 0) {
557 /* Allocate table for overlay nodes */
558 nldr_obj->ovly_table =
559 kzalloc(sizeof(struct ovly_node) *
560 nldr_obj->ovly_nodes, GFP_KERNEL);
561 /* Put overlay nodes in the table */
562 nldr_obj->ovly_nid = 0;
563 status = dcd_get_objects(nldr_obj->dcd_mgr, sz_zl_file,
564 add_ovly_node,
565 (void *)nldr_obj);
566 }
567 }
568 /* Do a fake reload of the base image to get overlay section info */
569 if (!status && nldr_obj->ovly_nodes > 0) {
570 save_attrs.write = fake_ovly_write;
571 save_attrs.log_write = add_ovly_info;
572 save_attrs.log_write_handle = nldr_obj;
573 flags = DBLL_CODE | DBLL_DATA | DBLL_SYMB;
574 status = nldr_obj->ldr_fxns.load_fxn(nldr_obj->base_lib, flags,
575 &save_attrs, &ul_entry);
576 }
577 if (!status) {
578 *nldr = (struct nldr_object *)nldr_obj;
579 } else {
580 if (nldr_obj)
581 nldr_delete((struct nldr_object *)nldr_obj);
582
583 *nldr = NULL;
584 }
585 /* FIXME:Temp. Fix. Must be removed */
586 DBC_ENSURE((!status && *nldr) || (status && *nldr == NULL));
587 return status;
588 }
589
590 /*
591 * ======== nldr_delete ========
592 */
593 void nldr_delete(struct nldr_object *nldr_obj)
594 {
595 struct ovly_sect *ovly_section;
596 struct ovly_sect *next;
597 u16 i;
598 DBC_REQUIRE(refs > 0);
599 DBC_REQUIRE(nldr_obj);
600
601 nldr_obj->ldr_fxns.exit_fxn();
602 if (nldr_obj->rmm)
603 rmm_delete(nldr_obj->rmm);
604
605 kfree(nldr_obj->seg_table);
606
607 if (nldr_obj->dcd_mgr)
608 dcd_destroy_manager(nldr_obj->dcd_mgr);
609
610 /* Free overlay node information */
611 if (nldr_obj->ovly_table) {
612 for (i = 0; i < nldr_obj->ovly_nodes; i++) {
613 ovly_section =
614 nldr_obj->ovly_table[i].create_sects_list;
615 while (ovly_section) {
616 next = ovly_section->next_sect;
617 kfree(ovly_section);
618 ovly_section = next;
619 }
620 ovly_section =
621 nldr_obj->ovly_table[i].delete_sects_list;
622 while (ovly_section) {
623 next = ovly_section->next_sect;
624 kfree(ovly_section);
625 ovly_section = next;
626 }
627 ovly_section =
628 nldr_obj->ovly_table[i].execute_sects_list;
629 while (ovly_section) {
630 next = ovly_section->next_sect;
631 kfree(ovly_section);
632 ovly_section = next;
633 }
634 ovly_section = nldr_obj->ovly_table[i].other_sects_list;
635 while (ovly_section) {
636 next = ovly_section->next_sect;
637 kfree(ovly_section);
638 ovly_section = next;
639 }
640 }
641 kfree(nldr_obj->ovly_table);
642 }
643 kfree(nldr_obj);
644 }
645
646 /*
647 * ======== nldr_exit ========
648 * Discontinue usage of NLDR module.
649 */
650 void nldr_exit(void)
651 {
652 DBC_REQUIRE(refs > 0);
653
654 refs--;
655
656 if (refs == 0)
657 rmm_exit();
658
659 DBC_ENSURE(refs >= 0);
660 }
661
662 /*
663 * ======== nldr_get_fxn_addr ========
664 */
665 int nldr_get_fxn_addr(struct nldr_nodeobject *nldr_node_obj,
666 char *str_fxn, u32 * addr)
667 {
668 struct dbll_sym_val *dbll_sym;
669 struct nldr_object *nldr_obj;
670 int status = 0;
671 bool status1 = false;
672 s32 i = 0;
673 struct lib_node root = { NULL, 0, NULL };
674 DBC_REQUIRE(refs > 0);
675 DBC_REQUIRE(nldr_node_obj);
676 DBC_REQUIRE(addr != NULL);
677 DBC_REQUIRE(str_fxn != NULL);
678
679 nldr_obj = nldr_node_obj->nldr_obj;
680 /* Called from node_create(), node_delete(), or node_run(). */
681 if (nldr_node_obj->dynamic && *nldr_node_obj->phase_split) {
682 switch (nldr_node_obj->phase) {
683 case NLDR_CREATE:
684 root = nldr_node_obj->create_lib;
685 break;
686 case NLDR_EXECUTE:
687 root = nldr_node_obj->execute_lib;
688 break;
689 case NLDR_DELETE:
690 root = nldr_node_obj->delete_lib;
691 break;
692 default:
693 DBC_ASSERT(false);
694 break;
695 }
696 } else {
697 /* for Overlay nodes or non-split Dynamic nodes */
698 root = nldr_node_obj->root;
699 }
700 status1 =
701 nldr_obj->ldr_fxns.get_c_addr_fxn(root.lib, str_fxn, &dbll_sym);
702 if (!status1)
703 status1 =
704 nldr_obj->ldr_fxns.get_addr_fxn(root.lib, str_fxn,
705 &dbll_sym);
706
707 /* If symbol not found, check dependent libraries */
708 if (!status1) {
709 for (i = 0; i < root.dep_libs; i++) {
710 status1 =
711 nldr_obj->ldr_fxns.get_addr_fxn(root.dep_libs_tree
712 [i].lib, str_fxn,
713 &dbll_sym);
714 if (!status1) {
715 status1 =
716 nldr_obj->ldr_fxns.
717 get_c_addr_fxn(root.dep_libs_tree[i].lib,
718 str_fxn, &dbll_sym);
719 }
720 if (status1) {
721 /* Symbol found */
722 break;
723 }
724 }
725 }
726 /* Check persistent libraries */
727 if (!status1) {
728 for (i = 0; i < nldr_node_obj->pers_libs; i++) {
729 status1 =
730 nldr_obj->ldr_fxns.
731 get_addr_fxn(nldr_node_obj->pers_lib_table[i].lib,
732 str_fxn, &dbll_sym);
733 if (!status1) {
734 status1 =
735 nldr_obj->ldr_fxns.
736 get_c_addr_fxn(nldr_node_obj->pers_lib_table
737 [i].lib, str_fxn, &dbll_sym);
738 }
739 if (status1) {
740 /* Symbol found */
741 break;
742 }
743 }
744 }
745
746 if (status1)
747 *addr = dbll_sym->value;
748 else
749 status = -ESPIPE;
750
751 return status;
752 }
753
754 /*
755 * ======== nldr_get_rmm_manager ========
756 * Given a NLDR object, retrieve RMM Manager Handle
757 */
758 int nldr_get_rmm_manager(struct nldr_object *nldr,
759 struct rmm_target_obj **rmm_mgr)
760 {
761 int status = 0;
762 struct nldr_object *nldr_obj = nldr;
763 DBC_REQUIRE(rmm_mgr != NULL);
764
765 if (nldr) {
766 *rmm_mgr = nldr_obj->rmm;
767 } else {
768 *rmm_mgr = NULL;
769 status = -EFAULT;
770 }
771
772 DBC_ENSURE(!status || (rmm_mgr != NULL && *rmm_mgr == NULL));
773
774 return status;
775 }
776
777 /*
778 * ======== nldr_init ========
779 * Initialize the NLDR module.
780 */
781 bool nldr_init(void)
782 {
783 DBC_REQUIRE(refs >= 0);
784
785 if (refs == 0)
786 rmm_init();
787
788 refs++;
789
790 DBC_ENSURE(refs > 0);
791 return true;
792 }
793
794 /*
795 * ======== nldr_load ========
796 */
797 int nldr_load(struct nldr_nodeobject *nldr_node_obj,
798 enum nldr_phase phase)
799 {
800 struct nldr_object *nldr_obj;
801 struct dsp_uuid lib_uuid;
802 int status = 0;
803
804 DBC_REQUIRE(refs > 0);
805 DBC_REQUIRE(nldr_node_obj);
806
807 nldr_obj = nldr_node_obj->nldr_obj;
808
809 if (nldr_node_obj->dynamic) {
810 nldr_node_obj->phase = phase;
811
812 lib_uuid = nldr_node_obj->uuid;
813
814 /* At this point, we may not know if node is split into
815 * different libraries. So we'll go ahead and load the
816 * library, and then save the pointer to the appropriate
817 * location after we know. */
818
819 status =
820 load_lib(nldr_node_obj, &nldr_node_obj->root, lib_uuid,
821 false, nldr_node_obj->lib_path, phase, 0);
822
823 if (!status) {
824 if (*nldr_node_obj->phase_split) {
825 switch (phase) {
826 case NLDR_CREATE:
827 nldr_node_obj->create_lib =
828 nldr_node_obj->root;
829 break;
830
831 case NLDR_EXECUTE:
832 nldr_node_obj->execute_lib =
833 nldr_node_obj->root;
834 break;
835
836 case NLDR_DELETE:
837 nldr_node_obj->delete_lib =
838 nldr_node_obj->root;
839 break;
840
841 default:
842 DBC_ASSERT(false);
843 break;
844 }
845 }
846 }
847 } else {
848 if (nldr_node_obj->overlay)
849 status = load_ovly(nldr_node_obj, phase);
850
851 }
852
853 return status;
854 }
855
856 /*
857 * ======== nldr_unload ========
858 */
859 int nldr_unload(struct nldr_nodeobject *nldr_node_obj,
860 enum nldr_phase phase)
861 {
862 int status = 0;
863 struct lib_node *root_lib = NULL;
864 s32 i = 0;
865
866 DBC_REQUIRE(refs > 0);
867 DBC_REQUIRE(nldr_node_obj);
868
869 if (nldr_node_obj != NULL) {
870 if (nldr_node_obj->dynamic) {
871 if (*nldr_node_obj->phase_split) {
872 switch (phase) {
873 case NLDR_CREATE:
874 root_lib = &nldr_node_obj->create_lib;
875 break;
876 case NLDR_EXECUTE:
877 root_lib = &nldr_node_obj->execute_lib;
878 break;
879 case NLDR_DELETE:
880 root_lib = &nldr_node_obj->delete_lib;
881 /* Unload persistent libraries */
882 for (i = 0;
883 i < nldr_node_obj->pers_libs;
884 i++) {
885 unload_lib(nldr_node_obj,
886 &nldr_node_obj->
887 pers_lib_table[i]);
888 }
889 nldr_node_obj->pers_libs = 0;
890 break;
891 default:
892 DBC_ASSERT(false);
893 break;
894 }
895 } else {
896 /* Unload main library */
897 root_lib = &nldr_node_obj->root;
898 }
899 if (root_lib)
900 unload_lib(nldr_node_obj, root_lib);
901 } else {
902 if (nldr_node_obj->overlay)
903 unload_ovly(nldr_node_obj, phase);
904
905 }
906 }
907 return status;
908 }
909
910 /*
911 * ======== add_ovly_info ========
912 */
913 static int add_ovly_info(void *handle, struct dbll_sect_info *sect_info,
914 u32 addr, u32 bytes)
915 {
916 char *node_name;
917 char *sect_name = (char *)sect_info->name;
918 bool sect_exists = false;
919 char seps = ':';
920 char *pch;
921 u16 i;
922 struct nldr_object *nldr_obj = (struct nldr_object *)handle;
923 int status = 0;
924
925 /* Is this an overlay section (load address != run address)? */
926 if (sect_info->sect_load_addr == sect_info->sect_run_addr)
927 goto func_end;
928
929 /* Find the node it belongs to */
930 for (i = 0; i < nldr_obj->ovly_nodes; i++) {
931 node_name = nldr_obj->ovly_table[i].node_name;
932 DBC_REQUIRE(node_name);
933 if (strncmp(node_name, sect_name + 1, strlen(node_name)) == 0) {
934 /* Found the node */
935 break;
936 }
937 }
938 if (!(i < nldr_obj->ovly_nodes))
939 goto func_end;
940
941 /* Determine which phase this section belongs to */
942 for (pch = sect_name + 1; *pch && *pch != seps; pch++)
943 ;
944
945 if (*pch) {
946 pch++; /* Skip over the ':' */
947 if (strncmp(pch, PCREATE, strlen(PCREATE)) == 0) {
948 status =
949 add_ovly_sect(nldr_obj,
950 &nldr_obj->
951 ovly_table[i].create_sects_list,
952 sect_info, &sect_exists, addr, bytes);
953 if (!status && !sect_exists)
954 nldr_obj->ovly_table[i].create_sects++;
955
956 } else if (strncmp(pch, PDELETE, strlen(PDELETE)) == 0) {
957 status =
958 add_ovly_sect(nldr_obj,
959 &nldr_obj->
960 ovly_table[i].delete_sects_list,
961 sect_info, &sect_exists, addr, bytes);
962 if (!status && !sect_exists)
963 nldr_obj->ovly_table[i].delete_sects++;
964
965 } else if (strncmp(pch, PEXECUTE, strlen(PEXECUTE)) == 0) {
966 status =
967 add_ovly_sect(nldr_obj,
968 &nldr_obj->
969 ovly_table[i].execute_sects_list,
970 sect_info, &sect_exists, addr, bytes);
971 if (!status && !sect_exists)
972 nldr_obj->ovly_table[i].execute_sects++;
973
974 } else {
975 /* Put in "other" sectins */
976 status =
977 add_ovly_sect(nldr_obj,
978 &nldr_obj->
979 ovly_table[i].other_sects_list,
980 sect_info, &sect_exists, addr, bytes);
981 if (!status && !sect_exists)
982 nldr_obj->ovly_table[i].other_sects++;
983
984 }
985 }
986 func_end:
987 return status;
988 }
989
990 /*
991 * ======== add_ovly_node =========
992 * Callback function passed to dcd_get_objects.
993 */
994 static int add_ovly_node(struct dsp_uuid *uuid_obj,
995 enum dsp_dcdobjtype obj_type, void *handle)
996 {
997 struct nldr_object *nldr_obj = (struct nldr_object *)handle;
998 char *node_name = NULL;
999 char *pbuf = NULL;
1000 u32 len;
1001 struct dcd_genericobj obj_def;
1002 int status = 0;
1003
1004 if (obj_type != DSP_DCDNODETYPE)
1005 goto func_end;
1006
1007 status =
1008 dcd_get_object_def(nldr_obj->dcd_mgr, uuid_obj, obj_type,
1009 &obj_def);
1010 if (status)
1011 goto func_end;
1012
1013 /* If overlay node, add to the list */
1014 if (obj_def.obj_data.node_obj.load_type == NLDR_OVLYLOAD) {
1015 if (nldr_obj->ovly_table == NULL) {
1016 nldr_obj->ovly_nodes++;
1017 } else {
1018 /* Add node to table */
1019 nldr_obj->ovly_table[nldr_obj->ovly_nid].uuid =
1020 *uuid_obj;
1021 DBC_REQUIRE(obj_def.obj_data.node_obj.ndb_props.
1022 ac_name);
1023 len =
1024 strlen(obj_def.obj_data.node_obj.ndb_props.ac_name);
1025 node_name = obj_def.obj_data.node_obj.ndb_props.ac_name;
1026 pbuf = kzalloc(len + 1, GFP_KERNEL);
1027 if (pbuf == NULL) {
1028 status = -ENOMEM;
1029 } else {
1030 strncpy(pbuf, node_name, len);
1031 nldr_obj->ovly_table[nldr_obj->ovly_nid].
1032 node_name = pbuf;
1033 nldr_obj->ovly_nid++;
1034 }
1035 }
1036 }
1037 /* These were allocated in dcd_get_object_def */
1038 kfree(obj_def.obj_data.node_obj.str_create_phase_fxn);
1039
1040 kfree(obj_def.obj_data.node_obj.str_execute_phase_fxn);
1041
1042 kfree(obj_def.obj_data.node_obj.str_delete_phase_fxn);
1043
1044 kfree(obj_def.obj_data.node_obj.str_i_alg_name);
1045
1046 func_end:
1047 return status;
1048 }
1049
1050 /*
1051 * ======== add_ovly_sect ========
1052 */
1053 static int add_ovly_sect(struct nldr_object *nldr_obj,
1054 struct ovly_sect **lst,
1055 struct dbll_sect_info *sect_inf,
1056 bool *exists, u32 addr, u32 bytes)
1057 {
1058 struct ovly_sect *new_sect = NULL;
1059 struct ovly_sect *last_sect;
1060 struct ovly_sect *ovly_section;
1061 int status = 0;
1062
1063 ovly_section = last_sect = *lst;
1064 *exists = false;
1065 while (ovly_section) {
1066 /*
1067 * Make sure section has not already been added. Multiple
1068 * 'write' calls may be made to load the section.
1069 */
1070 if (ovly_section->sect_load_addr == addr) {
1071 /* Already added */
1072 *exists = true;
1073 break;
1074 }
1075 last_sect = ovly_section;
1076 ovly_section = ovly_section->next_sect;
1077 }
1078
1079 if (!ovly_section) {
1080 /* New section */
1081 new_sect = kzalloc(sizeof(struct ovly_sect), GFP_KERNEL);
1082 if (new_sect == NULL) {
1083 status = -ENOMEM;
1084 } else {
1085 new_sect->sect_load_addr = addr;
1086 new_sect->sect_run_addr = sect_inf->sect_run_addr +
1087 (addr - sect_inf->sect_load_addr);
1088 new_sect->size = bytes;
1089 new_sect->page = sect_inf->type;
1090 }
1091
1092 /* Add to the list */
1093 if (!status) {
1094 if (*lst == NULL) {
1095 /* First in the list */
1096 *lst = new_sect;
1097 } else {
1098 last_sect->next_sect = new_sect;
1099 }
1100 }
1101 }
1102
1103 return status;
1104 }
1105
1106 /*
1107 * ======== fake_ovly_write ========
1108 */
1109 static s32 fake_ovly_write(void *handle, u32 dsp_address, void *buf, u32 bytes,
1110 s32 mtype)
1111 {
1112 return (s32) bytes;
1113 }
1114
1115 /*
1116 * ======== free_sects ========
1117 */
1118 static void free_sects(struct nldr_object *nldr_obj,
1119 struct ovly_sect *phase_sects, u16 alloc_num)
1120 {
1121 struct ovly_sect *ovly_section = phase_sects;
1122 u16 i = 0;
1123 bool ret;
1124
1125 while (ovly_section && i < alloc_num) {
1126 /* 'Deallocate' */
1127 /* segid - page not supported yet */
1128 /* Reserved memory */
1129 ret =
1130 rmm_free(nldr_obj->rmm, 0, ovly_section->sect_run_addr,
1131 ovly_section->size, true);
1132 DBC_ASSERT(ret);
1133 ovly_section = ovly_section->next_sect;
1134 i++;
1135 }
1136 }
1137
1138 /*
1139 * ======== get_symbol_value ========
1140 * Find symbol in library's base image. If not there, check dependent
1141 * libraries.
1142 */
1143 static bool get_symbol_value(void *handle, void *parg, void *rmm_handle,
1144 char *sym_name, struct dbll_sym_val **sym)
1145 {
1146 struct nldr_object *nldr_obj = (struct nldr_object *)handle;
1147 struct nldr_nodeobject *nldr_node_obj =
1148 (struct nldr_nodeobject *)rmm_handle;
1149 struct lib_node *root = (struct lib_node *)parg;
1150 u16 i;
1151 bool status = false;
1152
1153 /* check the base image */
1154 status = nldr_obj->ldr_fxns.get_addr_fxn(nldr_obj->base_lib,
1155 sym_name, sym);
1156 if (!status)
1157 status =
1158 nldr_obj->ldr_fxns.get_c_addr_fxn(nldr_obj->base_lib,
1159 sym_name, sym);
1160
1161 /*
1162 * Check in root lib itself. If the library consists of
1163 * multiple object files linked together, some symbols in the
1164 * library may need to be resolved.
1165 */
1166 if (!status) {
1167 status = nldr_obj->ldr_fxns.get_addr_fxn(root->lib, sym_name,
1168 sym);
1169 if (!status) {
1170 status =
1171 nldr_obj->ldr_fxns.get_c_addr_fxn(root->lib,
1172 sym_name, sym);
1173 }
1174 }
1175
1176 /*
1177 * Check in root lib's dependent libraries, but not dependent
1178 * libraries' dependents.
1179 */
1180 if (!status) {
1181 for (i = 0; i < root->dep_libs; i++) {
1182 status =
1183 nldr_obj->ldr_fxns.get_addr_fxn(root->
1184 dep_libs_tree
1185 [i].lib,
1186 sym_name, sym);
1187 if (!status) {
1188 status =
1189 nldr_obj->ldr_fxns.
1190 get_c_addr_fxn(root->dep_libs_tree[i].lib,
1191 sym_name, sym);
1192 }
1193 if (status) {
1194 /* Symbol found */
1195 break;
1196 }
1197 }
1198 }
1199 /*
1200 * Check in persistent libraries
1201 */
1202 if (!status) {
1203 for (i = 0; i < nldr_node_obj->pers_libs; i++) {
1204 status =
1205 nldr_obj->ldr_fxns.
1206 get_addr_fxn(nldr_node_obj->pers_lib_table[i].lib,
1207 sym_name, sym);
1208 if (!status) {
1209 status = nldr_obj->ldr_fxns.get_c_addr_fxn
1210 (nldr_node_obj->pers_lib_table[i].lib,
1211 sym_name, sym);
1212 }
1213 if (status) {
1214 /* Symbol found */
1215 break;
1216 }
1217 }
1218 }
1219
1220 return status;
1221 }
1222
1223 /*
1224 * ======== load_lib ========
1225 * Recursively load library and all its dependent libraries. The library
1226 * we're loading is specified by a uuid.
1227 */
1228 static int load_lib(struct nldr_nodeobject *nldr_node_obj,
1229 struct lib_node *root, struct dsp_uuid uuid,
1230 bool root_prstnt,
1231 struct dbll_library_obj **lib_path,
1232 enum nldr_phase phase, u16 depth)
1233 {
1234 struct nldr_object *nldr_obj = nldr_node_obj->nldr_obj;
1235 u16 nd_libs = 0; /* Number of dependent libraries */
1236 u16 np_libs = 0; /* Number of persistent libraries */
1237 u16 nd_libs_loaded = 0; /* Number of dep. libraries loaded */
1238 u16 i;
1239 u32 entry;
1240 u32 dw_buf_size = NLDR_MAXPATHLENGTH;
1241 dbll_flags flags = DBLL_SYMB | DBLL_CODE | DBLL_DATA | DBLL_DYNAMIC;
1242 struct dbll_attrs new_attrs;
1243 char *psz_file_name = NULL;
1244 struct dsp_uuid *dep_lib_uui_ds = NULL;
1245 bool *persistent_dep_libs = NULL;
1246 int status = 0;
1247 bool lib_status = false;
1248 struct lib_node *dep_lib;
1249
1250 if (depth > MAXDEPTH) {
1251 /* Error */
1252 DBC_ASSERT(false);
1253 }
1254 root->lib = NULL;
1255 /* Allocate a buffer for library file name of size DBL_MAXPATHLENGTH */
1256 psz_file_name = kzalloc(DBLL_MAXPATHLENGTH, GFP_KERNEL);
1257 if (psz_file_name == NULL)
1258 status = -ENOMEM;
1259
1260 if (!status) {
1261 /* Get the name of the library */
1262 if (depth == 0) {
1263 status =
1264 dcd_get_library_name(nldr_node_obj->nldr_obj->
1265 dcd_mgr, &uuid, psz_file_name,
1266 &dw_buf_size, phase,
1267 nldr_node_obj->phase_split);
1268 } else {
1269 /* Dependent libraries are registered with a phase */
1270 status =
1271 dcd_get_library_name(nldr_node_obj->nldr_obj->
1272 dcd_mgr, &uuid, psz_file_name,
1273 &dw_buf_size, NLDR_NOPHASE,
1274 NULL);
1275 }
1276 }
1277 if (!status) {
1278 /* Open the library, don't load symbols */
1279 status =
1280 nldr_obj->ldr_fxns.open_fxn(nldr_obj->dbll, psz_file_name,
1281 DBLL_NOLOAD, &root->lib);
1282 }
1283 /* Done with file name */
1284 kfree(psz_file_name);
1285
1286 /* Check to see if library not already loaded */
1287 if (!status && root_prstnt) {
1288 lib_status =
1289 find_in_persistent_lib_array(nldr_node_obj, root->lib);
1290 /* Close library */
1291 if (lib_status) {
1292 nldr_obj->ldr_fxns.close_fxn(root->lib);
1293 return 0;
1294 }
1295 }
1296 if (!status) {
1297 /* Check for circular dependencies. */
1298 for (i = 0; i < depth; i++) {
1299 if (root->lib == lib_path[i]) {
1300 /* This condition could be checked by a
1301 * tool at build time. */
1302 status = -EILSEQ;
1303 }
1304 }
1305 }
1306 if (!status) {
1307 /* Add library to current path in dependency tree */
1308 lib_path[depth] = root->lib;
1309 depth++;
1310 /* Get number of dependent libraries */
1311 status =
1312 dcd_get_num_dep_libs(nldr_node_obj->nldr_obj->dcd_mgr,
1313 &uuid, &nd_libs, &np_libs, phase);
1314 }
1315 DBC_ASSERT(nd_libs >= np_libs);
1316 if (!status) {
1317 if (!(*nldr_node_obj->phase_split))
1318 np_libs = 0;
1319
1320 /* nd_libs = #of dependent libraries */
1321 root->dep_libs = nd_libs - np_libs;
1322 if (nd_libs > 0) {
1323 dep_lib_uui_ds = kzalloc(sizeof(struct dsp_uuid) *
1324 nd_libs, GFP_KERNEL);
1325 persistent_dep_libs =
1326 kzalloc(sizeof(bool) * nd_libs, GFP_KERNEL);
1327 if (!dep_lib_uui_ds || !persistent_dep_libs)
1328 status = -ENOMEM;
1329
1330 if (root->dep_libs > 0) {
1331 /* Allocate arrays for dependent lib UUIDs,
1332 * lib nodes */
1333 root->dep_libs_tree = kzalloc
1334 (sizeof(struct lib_node) *
1335 (root->dep_libs), GFP_KERNEL);
1336 if (!(root->dep_libs_tree))
1337 status = -ENOMEM;
1338
1339 }
1340
1341 if (!status) {
1342 /* Get the dependent library UUIDs */
1343 status =
1344 dcd_get_dep_libs(nldr_node_obj->
1345 nldr_obj->dcd_mgr, &uuid,
1346 nd_libs, dep_lib_uui_ds,
1347 persistent_dep_libs,
1348 phase);
1349 }
1350 }
1351 }
1352
1353 /*
1354 * Recursively load dependent libraries.
1355 */
1356 if (!status) {
1357 for (i = 0; i < nd_libs; i++) {
1358 /* If root library is NOT persistent, and dep library
1359 * is, then record it. If root library IS persistent,
1360 * the deplib is already included */
1361 if (!root_prstnt && persistent_dep_libs[i] &&
1362 *nldr_node_obj->phase_split) {
1363 if ((nldr_node_obj->pers_libs) >= MAXLIBS) {
1364 status = -EILSEQ;
1365 break;
1366 }
1367
1368 /* Allocate library outside of phase */
1369 dep_lib =
1370 &nldr_node_obj->pers_lib_table
1371 [nldr_node_obj->pers_libs];
1372 } else {
1373 if (root_prstnt)
1374 persistent_dep_libs[i] = true;
1375
1376 /* Allocate library within phase */
1377 dep_lib = &root->dep_libs_tree[nd_libs_loaded];
1378 }
1379
1380 status = load_lib(nldr_node_obj, dep_lib,
1381 dep_lib_uui_ds[i],
1382 persistent_dep_libs[i], lib_path,
1383 phase, depth);
1384
1385 if (!status) {
1386 if ((status != 0) &&
1387 !root_prstnt && persistent_dep_libs[i] &&
1388 *nldr_node_obj->phase_split) {
1389 (nldr_node_obj->pers_libs)++;
1390 } else {
1391 if (!persistent_dep_libs[i] ||
1392 !(*nldr_node_obj->phase_split)) {
1393 nd_libs_loaded++;
1394 }
1395 }
1396 } else {
1397 break;
1398 }
1399 }
1400 }
1401
1402 /* Now we can load the root library */
1403 if (!status) {
1404 new_attrs = nldr_obj->ldr_attrs;
1405 new_attrs.sym_arg = root;
1406 new_attrs.rmm_handle = nldr_node_obj;
1407 new_attrs.input_params = nldr_node_obj->priv_ref;
1408 new_attrs.base_image = false;
1409
1410 status =
1411 nldr_obj->ldr_fxns.load_fxn(root->lib, flags, &new_attrs,
1412 &entry);
1413 }
1414
1415 /*
1416 * In case of failure, unload any dependent libraries that
1417 * were loaded, and close the root library.
1418 * (Persistent libraries are unloaded from the very top)
1419 */
1420 if (status) {
1421 if (phase != NLDR_EXECUTE) {
1422 for (i = 0; i < nldr_node_obj->pers_libs; i++)
1423 unload_lib(nldr_node_obj,
1424 &nldr_node_obj->pers_lib_table[i]);
1425
1426 nldr_node_obj->pers_libs = 0;
1427 }
1428 for (i = 0; i < nd_libs_loaded; i++)
1429 unload_lib(nldr_node_obj, &root->dep_libs_tree[i]);
1430
1431 if (root->lib)
1432 nldr_obj->ldr_fxns.close_fxn(root->lib);
1433
1434 }
1435
1436 /* Going up one node in the dependency tree */
1437 depth--;
1438
1439 kfree(dep_lib_uui_ds);
1440 dep_lib_uui_ds = NULL;
1441
1442 kfree(persistent_dep_libs);
1443 persistent_dep_libs = NULL;
1444
1445 return status;
1446 }
1447
1448 /*
1449 * ======== load_ovly ========
1450 */
1451 static int load_ovly(struct nldr_nodeobject *nldr_node_obj,
1452 enum nldr_phase phase)
1453 {
1454 struct nldr_object *nldr_obj = nldr_node_obj->nldr_obj;
1455 struct ovly_node *po_node = NULL;
1456 struct ovly_sect *phase_sects = NULL;
1457 struct ovly_sect *other_sects_list = NULL;
1458 u16 i;
1459 u16 alloc_num = 0;
1460 u16 other_alloc = 0;
1461 u16 *ref_count = NULL;
1462 u16 *other_ref = NULL;
1463 u32 bytes;
1464 struct ovly_sect *ovly_section;
1465 int status = 0;
1466
1467 /* Find the node in the table */
1468 for (i = 0; i < nldr_obj->ovly_nodes; i++) {
1469 if (is_equal_uuid
1470 (&nldr_node_obj->uuid, &nldr_obj->ovly_table[i].uuid)) {
1471 /* Found it */
1472 po_node = &(nldr_obj->ovly_table[i]);
1473 break;
1474 }
1475 }
1476
1477 DBC_ASSERT(i < nldr_obj->ovly_nodes);
1478
1479 if (!po_node) {
1480 status = -ENOENT;
1481 goto func_end;
1482 }
1483
1484 switch (phase) {
1485 case NLDR_CREATE:
1486 ref_count = &(po_node->create_ref);
1487 other_ref = &(po_node->other_ref);
1488 phase_sects = po_node->create_sects_list;
1489 other_sects_list = po_node->other_sects_list;
1490 break;
1491
1492 case NLDR_EXECUTE:
1493 ref_count = &(po_node->execute_ref);
1494 phase_sects = po_node->execute_sects_list;
1495 break;
1496
1497 case NLDR_DELETE:
1498 ref_count = &(po_node->delete_ref);
1499 phase_sects = po_node->delete_sects_list;
1500 break;
1501
1502 default:
1503 DBC_ASSERT(false);
1504 break;
1505 }
1506
1507 if (ref_count == NULL)
1508 goto func_end;
1509
1510 if (*ref_count != 0)
1511 goto func_end;
1512
1513 /* 'Allocate' memory for overlay sections of this phase */
1514 ovly_section = phase_sects;
1515 while (ovly_section) {
1516 /* allocate *//* page not supported yet */
1517 /* reserve *//* align */
1518 status = rmm_alloc(nldr_obj->rmm, 0, ovly_section->size, 0,
1519 &(ovly_section->sect_run_addr), true);
1520 if (!status) {
1521 ovly_section = ovly_section->next_sect;
1522 alloc_num++;
1523 } else {
1524 break;
1525 }
1526 }
1527 if (other_ref && *other_ref == 0) {
1528 /* 'Allocate' memory for other overlay sections
1529 * (create phase) */
1530 if (!status) {
1531 ovly_section = other_sects_list;
1532 while (ovly_section) {
1533 /* page not supported *//* align */
1534 /* reserve */
1535 status =
1536 rmm_alloc(nldr_obj->rmm, 0,
1537 ovly_section->size, 0,
1538 &(ovly_section->sect_run_addr),
1539 true);
1540 if (!status) {
1541 ovly_section = ovly_section->next_sect;
1542 other_alloc++;
1543 } else {
1544 break;
1545 }
1546 }
1547 }
1548 }
1549 if (*ref_count == 0) {
1550 if (!status) {
1551 /* Load sections for this phase */
1552 ovly_section = phase_sects;
1553 while (ovly_section && !status) {
1554 bytes =
1555 (*nldr_obj->ovly_fxn) (nldr_node_obj->
1556 priv_ref,
1557 ovly_section->
1558 sect_run_addr,
1559 ovly_section->
1560 sect_load_addr,
1561 ovly_section->size,
1562 ovly_section->page);
1563 if (bytes != ovly_section->size)
1564 status = -EPERM;
1565
1566 ovly_section = ovly_section->next_sect;
1567 }
1568 }
1569 }
1570 if (other_ref && *other_ref == 0) {
1571 if (!status) {
1572 /* Load other sections (create phase) */
1573 ovly_section = other_sects_list;
1574 while (ovly_section && !status) {
1575 bytes =
1576 (*nldr_obj->ovly_fxn) (nldr_node_obj->
1577 priv_ref,
1578 ovly_section->
1579 sect_run_addr,
1580 ovly_section->
1581 sect_load_addr,
1582 ovly_section->size,
1583 ovly_section->page);
1584 if (bytes != ovly_section->size)
1585 status = -EPERM;
1586
1587 ovly_section = ovly_section->next_sect;
1588 }
1589 }
1590 }
1591 if (status) {
1592 /* 'Deallocate' memory */
1593 free_sects(nldr_obj, phase_sects, alloc_num);
1594 free_sects(nldr_obj, other_sects_list, other_alloc);
1595 }
1596 func_end:
1597 if (!status && (ref_count != NULL)) {
1598 *ref_count += 1;
1599 if (other_ref)
1600 *other_ref += 1;
1601
1602 }
1603
1604 return status;
1605 }
1606
1607 /*
1608 * ======== remote_alloc ========
1609 */
1610 static int remote_alloc(void **ref, u16 mem_sect, u32 size,
1611 u32 align, u32 *dsp_address,
1612 s32 segmnt_id, s32 req,
1613 bool reserve)
1614 {
1615 struct nldr_nodeobject *hnode = (struct nldr_nodeobject *)ref;
1616 struct nldr_object *nldr_obj;
1617 struct rmm_target_obj *rmm;
1618 u16 mem_phase_bit = MAXFLAGS;
1619 u16 segid = 0;
1620 u16 i;
1621 u16 mem_sect_type;
1622 u32 word_size;
1623 struct rmm_addr *rmm_addr_obj = (struct rmm_addr *)dsp_address;
1624 bool mem_load_req = false;
1625 int status = -ENOMEM; /* Set to fail */
1626 DBC_REQUIRE(hnode);
1627 DBC_REQUIRE(mem_sect == DBLL_CODE || mem_sect == DBLL_DATA ||
1628 mem_sect == DBLL_BSS);
1629 nldr_obj = hnode->nldr_obj;
1630 rmm = nldr_obj->rmm;
1631 /* Convert size to DSP words */
1632 word_size =
1633 (size + nldr_obj->dsp_word_size -
1634 1) / nldr_obj->dsp_word_size;
1635 /* Modify memory 'align' to account for DSP cache line size */
1636 align = lcm(GEM_CACHE_LINE_SIZE, align);
1637 dev_dbg(bridge, "%s: memory align to 0x%x\n", __func__, align);
1638 if (segmnt_id != -1) {
1639 rmm_addr_obj->segid = segmnt_id;
1640 segid = segmnt_id;
1641 mem_load_req = req;
1642 } else {
1643 switch (hnode->phase) {
1644 case NLDR_CREATE:
1645 mem_phase_bit = CREATEDATAFLAGBIT;
1646 break;
1647 case NLDR_DELETE:
1648 mem_phase_bit = DELETEDATAFLAGBIT;
1649 break;
1650 case NLDR_EXECUTE:
1651 mem_phase_bit = EXECUTEDATAFLAGBIT;
1652 break;
1653 default:
1654 DBC_ASSERT(false);
1655 break;
1656 }
1657 if (mem_sect == DBLL_CODE)
1658 mem_phase_bit++;
1659
1660 if (mem_phase_bit < MAXFLAGS)
1661 segid = hnode->seg_id[mem_phase_bit];
1662
1663 /* Determine if there is a memory loading requirement */
1664 if ((hnode->code_data_flag_mask >> mem_phase_bit) & 0x1)
1665 mem_load_req = true;
1666
1667 }
1668 mem_sect_type = (mem_sect == DBLL_CODE) ? DYNM_CODE : DYNM_DATA;
1669
1670 /* Find an appropriate segment based on mem_sect */
1671 if (segid == NULLID) {
1672 /* No memory requirements of preferences */
1673 DBC_ASSERT(!mem_load_req);
1674 goto func_cont;
1675 }
1676 if (segid <= MAXSEGID) {
1677 DBC_ASSERT(segid < nldr_obj->dload_segs);
1678 /* Attempt to allocate from segid first. */
1679 rmm_addr_obj->segid = segid;
1680 status =
1681 rmm_alloc(rmm, segid, word_size, align, dsp_address, false);
1682 if (status) {
1683 dev_dbg(bridge, "%s: Unable allocate from segment %d\n",
1684 __func__, segid);
1685 }
1686 } else {
1687 /* segid > MAXSEGID ==> Internal or external memory */
1688 DBC_ASSERT(segid == MEMINTERNALID || segid == MEMEXTERNALID);
1689 /* Check for any internal or external memory segment,
1690 * depending on segid. */
1691 mem_sect_type |= segid == MEMINTERNALID ?
1692 DYNM_INTERNAL : DYNM_EXTERNAL;
1693 for (i = 0; i < nldr_obj->dload_segs; i++) {
1694 if ((nldr_obj->seg_table[i] & mem_sect_type) !=
1695 mem_sect_type)
1696 continue;
1697
1698 status = rmm_alloc(rmm, i, word_size, align,
1699 dsp_address, false);
1700 if (!status) {
1701 /* Save segid for freeing later */
1702 rmm_addr_obj->segid = i;
1703 break;
1704 }
1705 }
1706 }
1707 func_cont:
1708 /* Haven't found memory yet, attempt to find any segment that works */
1709 if (status == -ENOMEM && !mem_load_req) {
1710 dev_dbg(bridge, "%s: Preferred segment unavailable, trying "
1711 "another\n", __func__);
1712 for (i = 0; i < nldr_obj->dload_segs; i++) {
1713 /* All bits of mem_sect_type must be set */
1714 if ((nldr_obj->seg_table[i] & mem_sect_type) !=
1715 mem_sect_type)
1716 continue;
1717
1718 status = rmm_alloc(rmm, i, word_size, align,
1719 dsp_address, false);
1720 if (!status) {
1721 /* Save segid */
1722 rmm_addr_obj->segid = i;
1723 break;
1724 }
1725 }
1726 }
1727
1728 return status;
1729 }
1730
1731 static int remote_free(void **ref, u16 space, u32 dsp_address,
1732 u32 size, bool reserve)
1733 {
1734 struct nldr_object *nldr_obj = (struct nldr_object *)ref;
1735 struct rmm_target_obj *rmm;
1736 u32 word_size;
1737 int status = -ENOMEM; /* Set to fail */
1738
1739 DBC_REQUIRE(nldr_obj);
1740
1741 rmm = nldr_obj->rmm;
1742
1743 /* Convert size to DSP words */
1744 word_size =
1745 (size + nldr_obj->dsp_word_size -
1746 1) / nldr_obj->dsp_word_size;
1747
1748 if (rmm_free(rmm, space, dsp_address, word_size, reserve))
1749 status = 0;
1750
1751 return status;
1752 }
1753
1754 /*
1755 * ======== unload_lib ========
1756 */
1757 static void unload_lib(struct nldr_nodeobject *nldr_node_obj,
1758 struct lib_node *root)
1759 {
1760 struct dbll_attrs new_attrs;
1761 struct nldr_object *nldr_obj = nldr_node_obj->nldr_obj;
1762 u16 i;
1763
1764 DBC_ASSERT(root != NULL);
1765
1766 /* Unload dependent libraries */
1767 for (i = 0; i < root->dep_libs; i++)
1768 unload_lib(nldr_node_obj, &root->dep_libs_tree[i]);
1769
1770 root->dep_libs = 0;
1771
1772 new_attrs = nldr_obj->ldr_attrs;
1773 new_attrs.rmm_handle = nldr_obj->rmm;
1774 new_attrs.input_params = nldr_node_obj->priv_ref;
1775 new_attrs.base_image = false;
1776 new_attrs.sym_arg = root;
1777
1778 if (root->lib) {
1779 /* Unload the root library */
1780 nldr_obj->ldr_fxns.unload_fxn(root->lib, &new_attrs);
1781 nldr_obj->ldr_fxns.close_fxn(root->lib);
1782 }
1783
1784 /* Free dependent library list */
1785 kfree(root->dep_libs_tree);
1786 root->dep_libs_tree = NULL;
1787 }
1788
1789 /*
1790 * ======== unload_ovly ========
1791 */
1792 static void unload_ovly(struct nldr_nodeobject *nldr_node_obj,
1793 enum nldr_phase phase)
1794 {
1795 struct nldr_object *nldr_obj = nldr_node_obj->nldr_obj;
1796 struct ovly_node *po_node = NULL;
1797 struct ovly_sect *phase_sects = NULL;
1798 struct ovly_sect *other_sects_list = NULL;
1799 u16 i;
1800 u16 alloc_num = 0;
1801 u16 other_alloc = 0;
1802 u16 *ref_count = NULL;
1803 u16 *other_ref = NULL;
1804
1805 /* Find the node in the table */
1806 for (i = 0; i < nldr_obj->ovly_nodes; i++) {
1807 if (is_equal_uuid
1808 (&nldr_node_obj->uuid, &nldr_obj->ovly_table[i].uuid)) {
1809 /* Found it */
1810 po_node = &(nldr_obj->ovly_table[i]);
1811 break;
1812 }
1813 }
1814
1815 DBC_ASSERT(i < nldr_obj->ovly_nodes);
1816
1817 if (!po_node)
1818 /* TODO: Should we print warning here? */
1819 return;
1820
1821 switch (phase) {
1822 case NLDR_CREATE:
1823 ref_count = &(po_node->create_ref);
1824 phase_sects = po_node->create_sects_list;
1825 alloc_num = po_node->create_sects;
1826 break;
1827 case NLDR_EXECUTE:
1828 ref_count = &(po_node->execute_ref);
1829 phase_sects = po_node->execute_sects_list;
1830 alloc_num = po_node->execute_sects;
1831 break;
1832 case NLDR_DELETE:
1833 ref_count = &(po_node->delete_ref);
1834 other_ref = &(po_node->other_ref);
1835 phase_sects = po_node->delete_sects_list;
1836 /* 'Other' overlay sections are unloaded in the delete phase */
1837 other_sects_list = po_node->other_sects_list;
1838 alloc_num = po_node->delete_sects;
1839 other_alloc = po_node->other_sects;
1840 break;
1841 default:
1842 DBC_ASSERT(false);
1843 break;
1844 }
1845 DBC_ASSERT(ref_count && (*ref_count > 0));
1846 if (ref_count && (*ref_count > 0)) {
1847 *ref_count -= 1;
1848 if (other_ref) {
1849 DBC_ASSERT(*other_ref > 0);
1850 *other_ref -= 1;
1851 }
1852 }
1853
1854 if (ref_count && *ref_count == 0) {
1855 /* 'Deallocate' memory */
1856 free_sects(nldr_obj, phase_sects, alloc_num);
1857 }
1858 if (other_ref && *other_ref == 0)
1859 free_sects(nldr_obj, other_sects_list, other_alloc);
1860 }
1861
1862 /*
1863 * ======== find_in_persistent_lib_array ========
1864 */
1865 static bool find_in_persistent_lib_array(struct nldr_nodeobject *nldr_node_obj,
1866 struct dbll_library_obj *lib)
1867 {
1868 s32 i = 0;
1869
1870 for (i = 0; i < nldr_node_obj->pers_libs; i++) {
1871 if (lib == nldr_node_obj->pers_lib_table[i].lib)
1872 return true;
1873
1874 }
1875
1876 return false;
1877 }
1878
1879 #ifdef CONFIG_TIDSPBRIDGE_BACKTRACE
1880 /**
1881 * nldr_find_addr() - Find the closest symbol to the given address based on
1882 * dynamic node object.
1883 *
1884 * @nldr_node: Dynamic node object
1885 * @sym_addr: Given address to find the dsp symbol
1886 * @offset_range: offset range to look for dsp symbol
1887 * @offset_output: Symbol Output address
1888 * @sym_name: String with the dsp symbol
1889 *
1890 * This function finds the node library for a given address and
1891 * retrieves the dsp symbol by calling dbll_find_dsp_symbol.
1892 */
1893 int nldr_find_addr(struct nldr_nodeobject *nldr_node, u32 sym_addr,
1894 u32 offset_range, void *offset_output, char *sym_name)
1895 {
1896 int status = 0;
1897 bool status1 = false;
1898 s32 i = 0;
1899 struct lib_node root = { NULL, 0, NULL };
1900 DBC_REQUIRE(refs > 0);
1901 DBC_REQUIRE(offset_output != NULL);
1902 DBC_REQUIRE(sym_name != NULL);
1903 pr_debug("%s(0x%x, 0x%x, 0x%x, 0x%x, %s)\n", __func__, (u32) nldr_node,
1904 sym_addr, offset_range, (u32) offset_output, sym_name);
1905
1906 if (nldr_node->dynamic && *nldr_node->phase_split) {
1907 switch (nldr_node->phase) {
1908 case NLDR_CREATE:
1909 root = nldr_node->create_lib;
1910 break;
1911 case NLDR_EXECUTE:
1912 root = nldr_node->execute_lib;
1913 break;
1914 case NLDR_DELETE:
1915 root = nldr_node->delete_lib;
1916 break;
1917 default:
1918 DBC_ASSERT(false);
1919 break;
1920 }
1921 } else {
1922 /* for Overlay nodes or non-split Dynamic nodes */
1923 root = nldr_node->root;
1924 }
1925
1926 status1 = dbll_find_dsp_symbol(root.lib, sym_addr,
1927 offset_range, offset_output, sym_name);
1928
1929 /* If symbol not found, check dependent libraries */
1930 if (!status1)
1931 for (i = 0; i < root.dep_libs; i++) {
1932 status1 = dbll_find_dsp_symbol(
1933 root.dep_libs_tree[i].lib, sym_addr,
1934 offset_range, offset_output, sym_name);
1935 if (status1)
1936 /* Symbol found */
1937 break;
1938 }
1939 /* Check persistent libraries */
1940 if (!status1)
1941 for (i = 0; i < nldr_node->pers_libs; i++) {
1942 status1 = dbll_find_dsp_symbol(
1943 nldr_node->pers_lib_table[i].lib, sym_addr,
1944 offset_range, offset_output, sym_name);
1945 if (status1)
1946 /* Symbol found */
1947 break;
1948 }
1949
1950 if (!status1) {
1951 pr_debug("%s: Address 0x%x not found in range %d.\n",
1952 __func__, sym_addr, offset_range);
1953 status = -ESPIPE;
1954 }
1955
1956 return status;
1957 }
1958 #endif
This page took 0.096092 seconds and 5 git commands to generate.