diff options
author | Omar Ramirez Luna <omar.ramirez@ti.com> | 2010-06-23 09:02:02 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-06-23 18:39:08 -0400 |
commit | 26f8db7d2e20218272cbf889edfdb8328b4cd9c3 (patch) | |
tree | 67a45300822a63cddae83fb8d120a3001fd830ff /drivers/staging/tidspbridge/dynload | |
parent | 6a88a4fe0937325f1fc3df835f3e9b1698992899 (diff) |
staging: ti dspbridge: add DOFF binaries loader
Add TI's DSP Bridge DOFF binaries dynamic loader driver sources
Signed-off-by: Omar Ramirez Luna <omar.ramirez@ti.com>
Signed-off-by: Kanigeri, Hari <h-kanigeri2@ti.com>
Signed-off-by: Ameya Palande <ameya.palande@nokia.com>
Signed-off-by: Guzman Lugo, Fernando <fernando.lugo@ti.com>
Signed-off-by: Hebbar, Shivananda <x0hebbar@ti.com>
Signed-off-by: Ramos Falcon, Ernesto <ernesto@ti.com>
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
Signed-off-by: Anna, Suman <s-anna@ti.com>
Signed-off-by: Gupta, Ramesh <grgupta@ti.com>
Signed-off-by: Gomez Castellanos, Ivan <ivan.gomez@ti.com>
Signed-off-by: Andy Shevchenko <ext-andriy.shevchenko@nokia.com>
Signed-off-by: Armando Uribe De Leon <x0095078@ti.com>
Signed-off-by: Deepak Chitriki <deepak.chitriki@ti.com>
Signed-off-by: Menon, Nishanth <nm@ti.com>
Signed-off-by: Phil Carmody <ext-phil.2.carmody@nokia.com>
Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/staging/tidspbridge/dynload')
-rw-r--r-- | drivers/staging/tidspbridge/dynload/cload.c | 1960 | ||||
-rw-r--r-- | drivers/staging/tidspbridge/dynload/dload_internal.h | 351 | ||||
-rw-r--r-- | drivers/staging/tidspbridge/dynload/doff.h | 344 | ||||
-rw-r--r-- | drivers/staging/tidspbridge/dynload/getsection.c | 416 | ||||
-rw-r--r-- | drivers/staging/tidspbridge/dynload/header.h | 55 | ||||
-rw-r--r-- | drivers/staging/tidspbridge/dynload/module_list.h | 159 | ||||
-rw-r--r-- | drivers/staging/tidspbridge/dynload/params.h | 226 | ||||
-rw-r--r-- | drivers/staging/tidspbridge/dynload/reloc.c | 484 | ||||
-rw-r--r-- | drivers/staging/tidspbridge/dynload/reloc_table.h | 102 | ||||
-rw-r--r-- | drivers/staging/tidspbridge/dynload/reloc_table_c6000.c | 257 | ||||
-rw-r--r-- | drivers/staging/tidspbridge/dynload/tramp.c | 1143 | ||||
-rw-r--r-- | drivers/staging/tidspbridge/dynload/tramp_table_c6000.c | 164 |
12 files changed, 5661 insertions, 0 deletions
diff --git a/drivers/staging/tidspbridge/dynload/cload.c b/drivers/staging/tidspbridge/dynload/cload.c new file mode 100644 index 00000000000..d4f71b585a5 --- /dev/null +++ b/drivers/staging/tidspbridge/dynload/cload.c | |||
@@ -0,0 +1,1960 @@ | |||
1 | /* | ||
2 | * cload.c | ||
3 | * | ||
4 | * DSP-BIOS Bridge driver support functions for TI OMAP processors. | ||
5 | * | ||
6 | * Copyright (C) 2005-2006 Texas Instruments, Inc. | ||
7 | * | ||
8 | * This package is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR | ||
13 | * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED | ||
14 | * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. | ||
15 | */ | ||
16 | |||
17 | #include "header.h" | ||
18 | |||
19 | #include "module_list.h" | ||
20 | #define LINKER_MODULES_HEADER ("_" MODULES_HEADER) | ||
21 | |||
22 | /* | ||
23 | * we use the fact that DOFF section records are shaped just like | ||
24 | * ldr_section_info to reduce our section storage usage. This macro marks | ||
25 | * the places where that assumption is made | ||
26 | */ | ||
27 | #define DOFFSEC_IS_LDRSEC(pdoffsec) ((struct ldr_section_info *)(pdoffsec)) | ||
28 | |||
29 | /* | ||
30 | * forward references | ||
31 | */ | ||
32 | static void dload_symbols(struct dload_state *dlthis); | ||
33 | static void dload_data(struct dload_state *dlthis); | ||
34 | static void allocate_sections(struct dload_state *dlthis); | ||
35 | static void string_table_free(struct dload_state *dlthis); | ||
36 | static void symbol_table_free(struct dload_state *dlthis); | ||
37 | static void section_table_free(struct dload_state *dlthis); | ||
38 | static void init_module_handle(struct dload_state *dlthis); | ||
39 | #if BITS_PER_AU > BITS_PER_BYTE | ||
40 | static char *unpack_name(struct dload_state *dlthis, u32 soffset); | ||
41 | #endif | ||
42 | |||
43 | static const char cinitname[] = { ".cinit" }; | ||
44 | static const char loader_dllview_root[] = { "?DLModules?" }; | ||
45 | |||
46 | /* | ||
47 | * Error strings | ||
48 | */ | ||
49 | static const char readstrm[] = { "Error reading %s from input stream" }; | ||
50 | static const char err_alloc[] = { "Syms->dload_allocate( %d ) failed" }; | ||
51 | static const char tgtalloc[] = { | ||
52 | "Target memory allocate failed, section %s size " FMT_UI32 }; | ||
53 | static const char initfail[] = { "%s to target address " FMT_UI32 " failed" }; | ||
54 | static const char dlvwrite[] = { "Write to DLLview list failed" }; | ||
55 | static const char iconnect[] = { "Connect call to init interface failed" }; | ||
56 | static const char err_checksum[] = { "Checksum failed on %s" }; | ||
57 | |||
58 | /************************************************************************* | ||
59 | * Procedure dload_error | ||
60 | * | ||
61 | * Parameters: | ||
62 | * errtxt description of the error, printf style | ||
63 | * ... additional information | ||
64 | * | ||
65 | * Effect: | ||
66 | * Reports or records the error as appropriate. | ||
67 | *********************************************************************** */ | ||
68 | void dload_error(struct dload_state *dlthis, const char *errtxt, ...) | ||
69 | { | ||
70 | va_list args; | ||
71 | |||
72 | va_start(args, errtxt); | ||
73 | dlthis->mysym->error_report(dlthis->mysym, errtxt, args); | ||
74 | va_end(args); | ||
75 | dlthis->dload_errcount += 1; | ||
76 | |||
77 | } /* dload_error */ | ||
78 | |||
79 | #define DL_ERROR(zza, zzb) dload_error(dlthis, zza, zzb) | ||
80 | |||
81 | /************************************************************************* | ||
82 | * Procedure dload_syms_error | ||
83 | * | ||
84 | * Parameters: | ||
85 | * errtxt description of the error, printf style | ||
86 | * ... additional information | ||
87 | * | ||
88 | * Effect: | ||
89 | * Reports or records the error as appropriate. | ||
90 | *********************************************************************** */ | ||
91 | void dload_syms_error(struct dynamic_loader_sym *syms, const char *errtxt, ...) | ||
92 | { | ||
93 | va_list args; | ||
94 | |||
95 | va_start(args, errtxt); | ||
96 | syms->error_report(syms, errtxt, args); | ||
97 | va_end(args); | ||
98 | } | ||
99 | |||
100 | /************************************************************************* | ||
101 | * Procedure dynamic_load_module | ||
102 | * | ||
103 | * Parameters: | ||
104 | * module The input stream that supplies the module image | ||
105 | * syms Host-side symbol table and malloc/free functions | ||
106 | * alloc Target-side memory allocation | ||
107 | * init Target-side memory initialization | ||
108 | * options Option flags DLOAD_* | ||
109 | * mhandle A module handle for use with Dynamic_Unload | ||
110 | * | ||
111 | * Effect: | ||
112 | * The module image is read using *module. Target storage for the new | ||
113 | * image is | ||
114 | * obtained from *alloc. Symbols defined and referenced by the module are | ||
115 | * managed using *syms. The image is then relocated and references | ||
116 | * resolved as necessary, and the resulting executable bits are placed | ||
117 | * into target memory using *init. | ||
118 | * | ||
119 | * Returns: | ||
120 | * On a successful load, a module handle is placed in *mhandle, | ||
121 | * and zero is returned. On error, the number of errors detected is | ||
122 | * returned. Individual errors are reported during the load process | ||
123 | * using syms->error_report(). | ||
124 | ********************************************************************** */ | ||
125 | int dynamic_load_module(struct dynamic_loader_stream *module, | ||
126 | struct dynamic_loader_sym *syms, | ||
127 | struct dynamic_loader_allocate *alloc, | ||
128 | struct dynamic_loader_initialize *init, | ||
129 | unsigned options, void **mhandle) | ||
130 | { | ||
131 | register unsigned *dp, sz; | ||
132 | struct dload_state dl_state; /* internal state for this call */ | ||
133 | |||
134 | /* blast our internal state */ | ||
135 | dp = (unsigned *)&dl_state; | ||
136 | for (sz = sizeof(dl_state) / sizeof(unsigned); sz > 0; sz -= 1) | ||
137 | *dp++ = 0; | ||
138 | |||
139 | /* Enable _only_ BSS initialization if enabled by user */ | ||
140 | if ((options & DLOAD_INITBSS) == DLOAD_INITBSS) | ||
141 | dl_state.myoptions = DLOAD_INITBSS; | ||
142 | |||
143 | /* Check that mandatory arguments are present */ | ||
144 | if (!module || !syms) { | ||
145 | dload_error(&dl_state, "Required parameter is NULL"); | ||
146 | } else { | ||
147 | dl_state.strm = module; | ||
148 | dl_state.mysym = syms; | ||
149 | dload_headers(&dl_state); | ||
150 | if (!dl_state.dload_errcount) | ||
151 | dload_strings(&dl_state, false); | ||
152 | if (!dl_state.dload_errcount) | ||
153 | dload_sections(&dl_state); | ||
154 | |||
155 | if (init && !dl_state.dload_errcount) { | ||
156 | if (init->connect(init)) { | ||
157 | dl_state.myio = init; | ||
158 | dl_state.myalloc = alloc; | ||
159 | /* do now, before reducing symbols */ | ||
160 | allocate_sections(&dl_state); | ||
161 | } else | ||
162 | dload_error(&dl_state, iconnect); | ||
163 | } | ||
164 | |||
165 | if (!dl_state.dload_errcount) { | ||
166 | /* fix up entry point address */ | ||
167 | unsigned sref = dl_state.dfile_hdr.df_entry_secn - 1; | ||
168 | if (sref < dl_state.allocated_secn_count) | ||
169 | dl_state.dfile_hdr.df_entrypt += | ||
170 | dl_state.ldr_sections[sref].run_addr; | ||
171 | |||
172 | dload_symbols(&dl_state); | ||
173 | } | ||
174 | |||
175 | if (init && !dl_state.dload_errcount) | ||
176 | dload_data(&dl_state); | ||
177 | |||
178 | init_module_handle(&dl_state); | ||
179 | |||
180 | /* dl_state.myio is init or 0 at this point. */ | ||
181 | if (dl_state.myio) { | ||
182 | if ((!dl_state.dload_errcount) && | ||
183 | (dl_state.dfile_hdr.df_entry_secn != DN_UNDEF) && | ||
184 | (!init->execute(init, | ||
185 | dl_state.dfile_hdr.df_entrypt))) | ||
186 | dload_error(&dl_state, "Init->Execute Failed"); | ||
187 | init->release(init); | ||
188 | } | ||
189 | |||
190 | symbol_table_free(&dl_state); | ||
191 | section_table_free(&dl_state); | ||
192 | string_table_free(&dl_state); | ||
193 | dload_tramp_cleanup(&dl_state); | ||
194 | |||
195 | if (dl_state.dload_errcount) { | ||
196 | dynamic_unload_module(dl_state.myhandle, syms, alloc, | ||
197 | init); | ||
198 | dl_state.myhandle = NULL; | ||
199 | } | ||
200 | } | ||
201 | |||
202 | if (mhandle) | ||
203 | *mhandle = dl_state.myhandle; /* give back the handle */ | ||
204 | |||
205 | return dl_state.dload_errcount; | ||
206 | } /* DLOAD_File */ | ||
207 | |||
208 | /************************************************************************* | ||
209 | * Procedure dynamic_open_module | ||
210 | * | ||
211 | * Parameters: | ||
212 | * module The input stream that supplies the module image | ||
213 | * syms Host-side symbol table and malloc/free functions | ||
214 | * alloc Target-side memory allocation | ||
215 | * init Target-side memory initialization | ||
216 | * options Option flags DLOAD_* | ||
217 | * mhandle A module handle for use with Dynamic_Unload | ||
218 | * | ||
219 | * Effect: | ||
220 | * The module image is read using *module. Target storage for the new | ||
221 | * image is | ||
222 | * obtained from *alloc. Symbols defined and referenced by the module are | ||
223 | * managed using *syms. The image is then relocated and references | ||
224 | * resolved as necessary, and the resulting executable bits are placed | ||
225 | * into target memory using *init. | ||
226 | * | ||
227 | * Returns: | ||
228 | * On a successful load, a module handle is placed in *mhandle, | ||
229 | * and zero is returned. On error, the number of errors detected is | ||
230 | * returned. Individual errors are reported during the load process | ||
231 | * using syms->error_report(). | ||
232 | ********************************************************************** */ | ||
233 | int | ||
234 | dynamic_open_module(struct dynamic_loader_stream *module, | ||
235 | struct dynamic_loader_sym *syms, | ||
236 | struct dynamic_loader_allocate *alloc, | ||
237 | struct dynamic_loader_initialize *init, | ||
238 | unsigned options, void **mhandle) | ||
239 | { | ||
240 | register unsigned *dp, sz; | ||
241 | struct dload_state dl_state; /* internal state for this call */ | ||
242 | |||
243 | /* blast our internal state */ | ||
244 | dp = (unsigned *)&dl_state; | ||
245 | for (sz = sizeof(dl_state) / sizeof(unsigned); sz > 0; sz -= 1) | ||
246 | *dp++ = 0; | ||
247 | |||
248 | /* Enable _only_ BSS initialization if enabled by user */ | ||
249 | if ((options & DLOAD_INITBSS) == DLOAD_INITBSS) | ||
250 | dl_state.myoptions = DLOAD_INITBSS; | ||
251 | |||
252 | /* Check that mandatory arguments are present */ | ||
253 | if (!module || !syms) { | ||
254 | dload_error(&dl_state, "Required parameter is NULL"); | ||
255 | } else { | ||
256 | dl_state.strm = module; | ||
257 | dl_state.mysym = syms; | ||
258 | dload_headers(&dl_state); | ||
259 | if (!dl_state.dload_errcount) | ||
260 | dload_strings(&dl_state, false); | ||
261 | if (!dl_state.dload_errcount) | ||
262 | dload_sections(&dl_state); | ||
263 | |||
264 | if (init && !dl_state.dload_errcount) { | ||
265 | if (init->connect(init)) { | ||
266 | dl_state.myio = init; | ||
267 | dl_state.myalloc = alloc; | ||
268 | /* do now, before reducing symbols */ | ||
269 | allocate_sections(&dl_state); | ||
270 | } else | ||
271 | dload_error(&dl_state, iconnect); | ||
272 | } | ||
273 | |||
274 | if (!dl_state.dload_errcount) { | ||
275 | /* fix up entry point address */ | ||
276 | unsigned sref = dl_state.dfile_hdr.df_entry_secn - 1; | ||
277 | if (sref < dl_state.allocated_secn_count) | ||
278 | dl_state.dfile_hdr.df_entrypt += | ||
279 | dl_state.ldr_sections[sref].run_addr; | ||
280 | |||
281 | dload_symbols(&dl_state); | ||
282 | } | ||
283 | |||
284 | init_module_handle(&dl_state); | ||
285 | |||
286 | /* dl_state.myio is either 0 or init at this point. */ | ||
287 | if (dl_state.myio) { | ||
288 | if ((!dl_state.dload_errcount) && | ||
289 | (dl_state.dfile_hdr.df_entry_secn != DN_UNDEF) && | ||
290 | (!init->execute(init, | ||
291 | dl_state.dfile_hdr.df_entrypt))) | ||
292 | dload_error(&dl_state, "Init->Execute Failed"); | ||
293 | init->release(init); | ||
294 | } | ||
295 | |||
296 | symbol_table_free(&dl_state); | ||
297 | section_table_free(&dl_state); | ||
298 | string_table_free(&dl_state); | ||
299 | |||
300 | if (dl_state.dload_errcount) { | ||
301 | dynamic_unload_module(dl_state.myhandle, syms, alloc, | ||
302 | init); | ||
303 | dl_state.myhandle = NULL; | ||
304 | } | ||
305 | } | ||
306 | |||
307 | if (mhandle) | ||
308 | *mhandle = dl_state.myhandle; /* give back the handle */ | ||
309 | |||
310 | return dl_state.dload_errcount; | ||
311 | } /* DLOAD_File */ | ||
312 | |||
313 | /************************************************************************* | ||
314 | * Procedure dload_headers | ||
315 | * | ||
316 | * Parameters: | ||
317 | * none | ||
318 | * | ||
319 | * Effect: | ||
320 | * Loads the DOFF header and verify record. Deals with any byte-order | ||
321 | * issues and checks them for validity. | ||
322 | *********************************************************************** */ | ||
323 | #define COMBINED_HEADER_SIZE (sizeof(struct doff_filehdr_t)+ \ | ||
324 | sizeof(struct doff_verify_rec_t)) | ||
325 | |||
326 | void dload_headers(struct dload_state *dlthis) | ||
327 | { | ||
328 | u32 map; | ||
329 | |||
330 | /* Read the header and the verify record as one. If we don't get it | ||
331 | all, we're done */ | ||
332 | if (dlthis->strm->read_buffer(dlthis->strm, &dlthis->dfile_hdr, | ||
333 | COMBINED_HEADER_SIZE) != | ||
334 | COMBINED_HEADER_SIZE) { | ||
335 | DL_ERROR(readstrm, "File Headers"); | ||
336 | return; | ||
337 | } | ||
338 | /* | ||
339 | * Verify that we have the byte order of the file correct. | ||
340 | * If not, must fix it before we can continue | ||
341 | */ | ||
342 | map = REORDER_MAP(dlthis->dfile_hdr.df_byte_reshuffle); | ||
343 | if (map != REORDER_MAP(BYTE_RESHUFFLE_VALUE)) { | ||
344 | /* input is either byte-shuffled or bad */ | ||
345 | if ((map & 0xFCFCFCFC) == 0) { /* no obviously bogus bits */ | ||
346 | dload_reorder(&dlthis->dfile_hdr, COMBINED_HEADER_SIZE, | ||
347 | map); | ||
348 | } | ||
349 | if (dlthis->dfile_hdr.df_byte_reshuffle != | ||
350 | BYTE_RESHUFFLE_VALUE) { | ||
351 | /* didn't fix the problem, the byte swap map is bad */ | ||
352 | dload_error(dlthis, | ||
353 | "Bad byte swap map " FMT_UI32 " in header", | ||
354 | dlthis->dfile_hdr.df_byte_reshuffle); | ||
355 | return; | ||
356 | } | ||
357 | dlthis->reorder_map = map; /* keep map for future use */ | ||
358 | } | ||
359 | |||
360 | /* | ||
361 | * Verify checksum of header and verify record | ||
362 | */ | ||
363 | if (~dload_checksum(&dlthis->dfile_hdr, | ||
364 | sizeof(struct doff_filehdr_t)) || | ||
365 | ~dload_checksum(&dlthis->verify, | ||
366 | sizeof(struct doff_verify_rec_t))) { | ||
367 | DL_ERROR(err_checksum, "header or verify record"); | ||
368 | return; | ||
369 | } | ||
370 | #if HOST_ENDIANNESS | ||
371 | dlthis->dfile_hdr.df_byte_reshuffle = map; /* put back for later */ | ||
372 | #endif | ||
373 | |||
374 | /* Check for valid target ID */ | ||
375 | if ((dlthis->dfile_hdr.df_target_id != TARGET_ID) && | ||
376 | -(dlthis->dfile_hdr.df_target_id != TMS470_ID)) { | ||
377 | dload_error(dlthis, "Bad target ID 0x%x and TARGET_ID 0x%x", | ||
378 | dlthis->dfile_hdr.df_target_id, TARGET_ID); | ||
379 | return; | ||
380 | } | ||
381 | /* Check for valid file format */ | ||
382 | if ((dlthis->dfile_hdr.df_doff_version != DOFF0)) { | ||
383 | dload_error(dlthis, "Bad DOFF version 0x%x", | ||
384 | dlthis->dfile_hdr.df_doff_version); | ||
385 | return; | ||
386 | } | ||
387 | |||
388 | /* | ||
389 | * Apply reasonableness checks to count fields | ||
390 | */ | ||
391 | if (dlthis->dfile_hdr.df_strtab_size > MAX_REASONABLE_STRINGTAB) { | ||
392 | dload_error(dlthis, "Excessive string table size " FMT_UI32, | ||
393 | dlthis->dfile_hdr.df_strtab_size); | ||
394 | return; | ||
395 | } | ||
396 | if (dlthis->dfile_hdr.df_no_scns > MAX_REASONABLE_SECTIONS) { | ||
397 | dload_error(dlthis, "Excessive section count 0x%x", | ||
398 | dlthis->dfile_hdr.df_no_scns); | ||
399 | return; | ||
400 | } | ||
401 | #ifndef TARGET_ENDIANNESS | ||
402 | /* | ||
403 | * Check that endianness does not disagree with explicit specification | ||
404 | */ | ||
405 | if ((dlthis->dfile_hdr.df_flags >> ALIGN_COFF_ENDIANNESS) & | ||
406 | dlthis->myoptions & ENDIANNESS_MASK) { | ||
407 | dload_error(dlthis, | ||
408 | "Input endianness disagrees with specified option"); | ||
409 | return; | ||
410 | } | ||
411 | dlthis->big_e_target = dlthis->dfile_hdr.df_flags & DF_BIG; | ||
412 | #endif | ||
413 | |||
414 | } /* dload_headers */ | ||
415 | |||
416 | /* COFF Section Processing | ||
417 | * | ||
418 | * COFF sections are read in and retained intact. Each record is embedded | ||
419 | * in a new structure that records the updated load and | ||
420 | * run addresses of the section */ | ||
421 | |||
422 | static const char secn_errid[] = { "section" }; | ||
423 | |||
424 | /************************************************************************* | ||
425 | * Procedure dload_sections | ||
426 | * | ||
427 | * Parameters: | ||
428 | * none | ||
429 | * | ||
430 | * Effect: | ||
431 | * Loads the section records into an internal table. | ||
432 | *********************************************************************** */ | ||
433 | void dload_sections(struct dload_state *dlthis) | ||
434 | { | ||
435 | s16 siz; | ||
436 | struct doff_scnhdr_t *shp; | ||
437 | unsigned nsecs = dlthis->dfile_hdr.df_no_scns; | ||
438 | |||
439 | /* allocate space for the DOFF section records */ | ||
440 | siz = nsecs * sizeof(struct doff_scnhdr_t); | ||
441 | shp = | ||
442 | (struct doff_scnhdr_t *)dlthis->mysym->dload_allocate(dlthis->mysym, | ||
443 | siz); | ||
444 | if (!shp) { /* not enough storage */ | ||
445 | DL_ERROR(err_alloc, siz); | ||
446 | return; | ||
447 | } | ||
448 | dlthis->sect_hdrs = shp; | ||
449 | |||
450 | /* read in the section records */ | ||
451 | if (dlthis->strm->read_buffer(dlthis->strm, shp, siz) != siz) { | ||
452 | DL_ERROR(readstrm, secn_errid); | ||
453 | return; | ||
454 | } | ||
455 | |||
456 | /* if we need to fix up byte order, do it now */ | ||
457 | if (dlthis->reorder_map) | ||
458 | dload_reorder(shp, siz, dlthis->reorder_map); | ||
459 | |||
460 | /* check for validity */ | ||
461 | if (~dload_checksum(dlthis->sect_hdrs, siz) != | ||
462 | dlthis->verify.dv_scn_rec_checksum) { | ||
463 | DL_ERROR(err_checksum, secn_errid); | ||
464 | return; | ||
465 | } | ||
466 | |||
467 | } /* dload_sections */ | ||
468 | |||
469 | /***************************************************************************** | ||
470 | * Procedure allocate_sections | ||
471 | * | ||
472 | * Parameters: | ||
473 | * alloc target memory allocator class | ||
474 | * | ||
475 | * Effect: | ||
476 | * Assigns new (target) addresses for sections | ||
477 | **************************************************************************** */ | ||
478 | static void allocate_sections(struct dload_state *dlthis) | ||
479 | { | ||
480 | u16 curr_sect, nsecs, siz; | ||
481 | struct doff_scnhdr_t *shp; | ||
482 | struct ldr_section_info *asecs; | ||
483 | struct my_handle *hndl; | ||
484 | nsecs = dlthis->dfile_hdr.df_no_scns; | ||
485 | if (!nsecs) | ||
486 | return; | ||
487 | if ((dlthis->myalloc == NULL) && | ||
488 | (dlthis->dfile_hdr.df_target_scns > 0)) { | ||
489 | DL_ERROR("Arg 3 (alloc) required but NULL", 0); | ||
490 | return; | ||
491 | } | ||
492 | /* | ||
493 | * allocate space for the module handle, which we will keep for unload | ||
494 | * purposes include an additional section store for an auto-generated | ||
495 | * trampoline section in case we need it. | ||
496 | */ | ||
497 | siz = (dlthis->dfile_hdr.df_target_scns + 1) * | ||
498 | sizeof(struct ldr_section_info) + MY_HANDLE_SIZE; | ||
499 | |||
500 | hndl = | ||
501 | (struct my_handle *)dlthis->mysym->dload_allocate(dlthis->mysym, | ||
502 | siz); | ||
503 | if (!hndl) { /* not enough storage */ | ||
504 | DL_ERROR(err_alloc, siz); | ||
505 | return; | ||
506 | } | ||
507 | /* initialize the handle header */ | ||
508 | hndl->dm.hnext = hndl->dm.hprev = hndl; /* circular list */ | ||
509 | hndl->dm.hroot = NULL; | ||
510 | hndl->dm.dbthis = 0; | ||
511 | dlthis->myhandle = hndl; /* save away for return */ | ||
512 | /* pointer to the section list of allocated sections */ | ||
513 | dlthis->ldr_sections = asecs = hndl->secns; | ||
514 | /* * Insert names into all sections, make copies of | ||
515 | the sections we allocate */ | ||
516 | shp = dlthis->sect_hdrs; | ||
517 | for (curr_sect = 0; curr_sect < nsecs; curr_sect++) { | ||
518 | u32 soffset = shp->ds_offset; | ||
519 | #if BITS_PER_AU <= BITS_PER_BYTE | ||
520 | /* attempt to insert the name of this section */ | ||
521 | if (soffset < dlthis->dfile_hdr.df_strtab_size) | ||
522 | DOFFSEC_IS_LDRSEC(shp)->name = dlthis->str_head + | ||
523 | soffset; | ||
524 | else { | ||
525 | dload_error(dlthis, "Bad name offset in section %d", | ||
526 | curr_sect); | ||
527 | DOFFSEC_IS_LDRSEC(shp)->name = NULL; | ||
528 | } | ||
529 | #endif | ||
530 | /* allocate target storage for sections that require it */ | ||
531 | if (DS_NEEDS_ALLOCATION(shp)) { | ||
532 | *asecs = *DOFFSEC_IS_LDRSEC(shp); | ||
533 | asecs->context = 0; /* zero the context field */ | ||
534 | #if BITS_PER_AU > BITS_PER_BYTE | ||
535 | asecs->name = unpack_name(dlthis, soffset); | ||
536 | dlthis->debug_string_size = soffset + dlthis->temp_len; | ||
537 | #else | ||
538 | dlthis->debug_string_size = soffset; | ||
539 | #endif | ||
540 | if (dlthis->myalloc != NULL) { | ||
541 | if (!dlthis->myalloc-> | ||
542 | dload_allocate(dlthis->myalloc, asecs, | ||
543 | DS_ALIGNMENT(asecs->type))) { | ||
544 | dload_error(dlthis, tgtalloc, | ||
545 | asecs->name, asecs->size); | ||
546 | return; | ||
547 | } | ||
548 | } | ||
549 | /* keep address deltas in original section table */ | ||
550 | shp->ds_vaddr = asecs->load_addr - shp->ds_vaddr; | ||
551 | shp->ds_paddr = asecs->run_addr - shp->ds_paddr; | ||
552 | dlthis->allocated_secn_count += 1; | ||
553 | } /* allocate target storage */ | ||
554 | shp += 1; | ||
555 | asecs += 1; | ||
556 | } | ||
557 | #if BITS_PER_AU <= BITS_PER_BYTE | ||
558 | dlthis->debug_string_size += | ||
559 | strlen(dlthis->str_head + dlthis->debug_string_size) + 1; | ||
560 | #endif | ||
561 | } /* allocate sections */ | ||
562 | |||
563 | /************************************************************************* | ||
564 | * Procedure section_table_free | ||
565 | * | ||
566 | * Parameters: | ||
567 | * none | ||
568 | * | ||
569 | * Effect: | ||
570 | * Frees any state used by the symbol table. | ||
571 | * | ||
572 | * WARNING: | ||
573 | * This routine is not allowed to declare errors! | ||
574 | *********************************************************************** */ | ||
575 | static void section_table_free(struct dload_state *dlthis) | ||
576 | { | ||
577 | struct doff_scnhdr_t *shp; | ||
578 | |||
579 | shp = dlthis->sect_hdrs; | ||
580 | if (shp) | ||
581 | dlthis->mysym->dload_deallocate(dlthis->mysym, shp); | ||
582 | |||
583 | } /* section_table_free */ | ||
584 | |||
585 | /************************************************************************* | ||
586 | * Procedure dload_strings | ||
587 | * | ||
588 | * Parameters: | ||
589 | * sec_names_only If true only read in the "section names" | ||
590 | * portion of the string table | ||
591 | * | ||
592 | * Effect: | ||
593 | * Loads the DOFF string table into memory. DOFF keeps all strings in a | ||
594 | * big unsorted array. We just read that array into memory in bulk. | ||
595 | *********************************************************************** */ | ||
596 | static const char stringtbl[] = { "string table" }; | ||
597 | |||
598 | void dload_strings(struct dload_state *dlthis, bool sec_names_only) | ||
599 | { | ||
600 | u32 ssiz; | ||
601 | char *strbuf; | ||
602 | |||
603 | if (sec_names_only) { | ||
604 | ssiz = BYTE_TO_HOST(DOFF_ALIGN | ||
605 | (dlthis->dfile_hdr.df_scn_name_size)); | ||
606 | } else { | ||
607 | ssiz = BYTE_TO_HOST(DOFF_ALIGN | ||
608 | (dlthis->dfile_hdr.df_strtab_size)); | ||
609 | } | ||
610 | if (ssiz == 0) | ||
611 | return; | ||
612 | |||
613 | /* get some memory for the string table */ | ||
614 | #if BITS_PER_AU > BITS_PER_BYTE | ||
615 | strbuf = (char *)dlthis->mysym->dload_allocate(dlthis->mysym, ssiz + | ||
616 | dlthis->dfile_hdr. | ||
617 | df_max_str_len); | ||
618 | #else | ||
619 | strbuf = (char *)dlthis->mysym->dload_allocate(dlthis->mysym, ssiz); | ||
620 | #endif | ||
621 | if (strbuf == NULL) { | ||
622 | DL_ERROR(err_alloc, ssiz); | ||
623 | return; | ||
624 | } | ||
625 | dlthis->str_head = strbuf; | ||
626 | #if BITS_PER_AU > BITS_PER_BYTE | ||
627 | dlthis->str_temp = strbuf + ssiz; | ||
628 | #endif | ||
629 | /* read in the strings and verify them */ | ||
630 | if ((unsigned)(dlthis->strm->read_buffer(dlthis->strm, strbuf, | ||
631 | ssiz)) != ssiz) { | ||
632 | DL_ERROR(readstrm, stringtbl); | ||
633 | } | ||
634 | /* if we need to fix up byte order, do it now */ | ||
635 | #ifndef _BIG_ENDIAN | ||
636 | if (dlthis->reorder_map) | ||
637 | dload_reorder(strbuf, ssiz, dlthis->reorder_map); | ||
638 | |||
639 | if ((!sec_names_only) && (~dload_checksum(strbuf, ssiz) != | ||
640 | dlthis->verify.dv_str_tab_checksum)) { | ||
641 | DL_ERROR(err_checksum, stringtbl); | ||
642 | } | ||
643 | #else | ||
644 | if (dlthis->dfile_hdr.df_byte_reshuffle != | ||
645 | HOST_BYTE_ORDER(REORDER_MAP(BYTE_RESHUFFLE_VALUE))) { | ||
646 | /* put strings in big-endian order, not in PC order */ | ||
647 | dload_reorder(strbuf, ssiz, | ||
648 | HOST_BYTE_ORDER(dlthis-> | ||
649 | dfile_hdr.df_byte_reshuffle)); | ||
650 | } | ||
651 | if ((!sec_names_only) && (~dload_reverse_checksum(strbuf, ssiz) != | ||
652 | dlthis->verify.dv_str_tab_checksum)) { | ||
653 | DL_ERROR(err_checksum, stringtbl); | ||
654 | } | ||
655 | #endif | ||
656 | } /* dload_strings */ | ||
657 | |||
658 | /************************************************************************* | ||
659 | * Procedure string_table_free | ||
660 | * | ||
661 | * Parameters: | ||
662 | * none | ||
663 | * | ||
664 | * Effect: | ||
665 | * Frees any state used by the string table. | ||
666 | * | ||
667 | * WARNING: | ||
668 | * This routine is not allowed to declare errors! | ||
669 | ************************************************************************ */ | ||
670 | static void string_table_free(struct dload_state *dlthis) | ||
671 | { | ||
672 | if (dlthis->str_head) | ||
673 | dlthis->mysym->dload_deallocate(dlthis->mysym, | ||
674 | dlthis->str_head); | ||
675 | |||
676 | } /* string_table_free */ | ||
677 | |||
678 | /* | ||
679 | * Symbol Table Maintenance Functions | ||
680 | * | ||
681 | * COFF symbols are read by dload_symbols(), which is called after | ||
682 | * sections have been allocated. Symbols which might be used in | ||
683 | * relocation (ie, not debug info) are retained in an internal temporary | ||
684 | * compressed table (type local_symbol). A particular symbol is recovered | ||
685 | * by index by calling dload_find_symbol(). dload_find_symbol | ||
686 | * reconstructs a more explicit representation (type SLOTVEC) which is | ||
687 | * used by reloc.c | ||
688 | */ | ||
689 | /* real size of debug header */ | ||
690 | #define DBG_HDR_SIZE (sizeof(struct dll_module) - sizeof(struct dll_sect)) | ||
691 | |||
692 | static const char sym_errid[] = { "symbol" }; | ||
693 | |||
694 | /************************************************************************** | ||
695 | * Procedure dload_symbols | ||
696 | * | ||
697 | * Parameters: | ||
698 | * none | ||
699 | * | ||
700 | * Effect: | ||
701 | * Reads in symbols and retains ones that might be needed for relocation | ||
702 | * purposes. | ||
703 | *********************************************************************** */ | ||
704 | /* size of symbol buffer no bigger than target data buffer, to limit stack | ||
705 | * usage */ | ||
706 | #define MY_SYM_BUF_SIZ (BYTE_TO_HOST(IMAGE_PACKET_SIZE)/\ | ||
707 | sizeof(struct doff_syment_t)) | ||
708 | |||
709 | static void dload_symbols(struct dload_state *dlthis) | ||
710 | { | ||
711 | u32 sym_count, siz, dsiz, symbols_left; | ||
712 | u32 checks; | ||
713 | struct local_symbol *sp; | ||
714 | struct dynload_symbol *symp; | ||
715 | struct dynload_symbol *newsym; | ||
716 | |||
717 | sym_count = dlthis->dfile_hdr.df_no_syms; | ||
718 | if (sym_count == 0) | ||
719 | return; | ||
720 | |||
721 | /* | ||
722 | * We keep a local symbol table for all of the symbols in the input. | ||
723 | * This table contains only section & value info, as we do not have | ||
724 | * to do any name processing for locals. We reuse this storage | ||
725 | * as a temporary for .dllview record construction. | ||
726 | * Allocate storage for the whole table. Add 1 to the section count | ||
727 | * in case a trampoline section is auto-generated as well as the | ||
728 | * size of the trampoline section name so DLLView doens't get lost. | ||
729 | */ | ||
730 | |||
731 | siz = sym_count * sizeof(struct local_symbol); | ||
732 | dsiz = DBG_HDR_SIZE + | ||
733 | (sizeof(struct dll_sect) * dlthis->allocated_secn_count) + | ||
734 | BYTE_TO_HOST_ROUND(dlthis->debug_string_size + 1); | ||
735 | if (dsiz > siz) | ||
736 | siz = dsiz; /* larger of symbols and .dllview temp */ | ||
737 | sp = (struct local_symbol *)dlthis->mysym->dload_allocate(dlthis->mysym, | ||
738 | siz); | ||
739 | if (!sp) { | ||
740 | DL_ERROR(err_alloc, siz); | ||
741 | return; | ||
742 | } | ||
743 | dlthis->local_symtab = sp; | ||
744 | /* Read the symbols in the input, store them in the table, and post any | ||
745 | * globals to the global symbol table. In the process, externals | ||
746 | become defined from the global symbol table */ | ||
747 | checks = dlthis->verify.dv_sym_tab_checksum; | ||
748 | symbols_left = sym_count; | ||
749 | do { /* read all symbols */ | ||
750 | char *sname; | ||
751 | u32 val; | ||
752 | s32 delta; | ||
753 | struct doff_syment_t *input_sym; | ||
754 | unsigned syms_in_buf; | ||
755 | struct doff_syment_t my_sym_buf[MY_SYM_BUF_SIZ]; | ||
756 | input_sym = my_sym_buf; | ||
757 | syms_in_buf = symbols_left > MY_SYM_BUF_SIZ ? | ||
758 | MY_SYM_BUF_SIZ : symbols_left; | ||
759 | siz = syms_in_buf * sizeof(struct doff_syment_t); | ||
760 | if (dlthis->strm->read_buffer(dlthis->strm, input_sym, siz) != | ||
761 | siz) { | ||
762 | DL_ERROR(readstrm, sym_errid); | ||
763 | return; | ||
764 | } | ||
765 | if (dlthis->reorder_map) | ||
766 | dload_reorder(input_sym, siz, dlthis->reorder_map); | ||
767 | |||
768 | checks += dload_checksum(input_sym, siz); | ||
769 | do { /* process symbols in buffer */ | ||
770 | symbols_left -= 1; | ||
771 | /* attempt to derive the name of this symbol */ | ||
772 | sname = NULL; | ||
773 | if (input_sym->dn_offset > 0) { | ||
774 | #if BITS_PER_AU <= BITS_PER_BYTE | ||
775 | if ((u32) input_sym->dn_offset < | ||
776 | dlthis->dfile_hdr.df_strtab_size) | ||
777 | sname = dlthis->str_head + | ||
778 | BYTE_TO_HOST(input_sym->dn_offset); | ||
779 | else | ||
780 | dload_error(dlthis, | ||
781 | "Bad name offset in symbol " | ||
782 | " %d", symbols_left); | ||
783 | #else | ||
784 | sname = unpack_name(dlthis, | ||
785 | input_sym->dn_offset); | ||
786 | #endif | ||
787 | } | ||
788 | val = input_sym->dn_value; | ||
789 | delta = 0; | ||
790 | sp->sclass = input_sym->dn_sclass; | ||
791 | sp->secnn = input_sym->dn_scnum; | ||
792 | /* if this is an undefined symbol, | ||
793 | * define it (or fail) now */ | ||
794 | if (sp->secnn == DN_UNDEF) { | ||
795 | /* pointless for static undefined */ | ||
796 | if (input_sym->dn_sclass != DN_EXT) | ||
797 | goto loop_cont; | ||
798 | |||
799 | /* try to define symbol from previously | ||
800 | * loaded images */ | ||
801 | symp = dlthis->mysym->find_matching_symbol | ||
802 | (dlthis->mysym, sname); | ||
803 | if (!symp) { | ||
804 | DL_ERROR | ||
805 | ("Undefined external symbol %s", | ||
806 | sname); | ||
807 | goto loop_cont; | ||
808 | } | ||
809 | val = delta = symp->value; | ||
810 | #ifdef ENABLE_TRAMP_DEBUG | ||
811 | dload_syms_error(dlthis->mysym, | ||
812 | "===> ext sym [%s] at %x", | ||
813 | sname, val); | ||
814 | #endif | ||
815 | |||
816 | goto loop_cont; | ||
817 | } | ||
818 | /* symbol defined by this module */ | ||
819 | if (sp->secnn > 0) { | ||
820 | /* symbol references a section */ | ||
821 | if ((unsigned)sp->secnn <= | ||
822 | dlthis->allocated_secn_count) { | ||
823 | /* section was allocated */ | ||
824 | struct doff_scnhdr_t *srefp = | ||
825 | &dlthis->sect_hdrs[sp->secnn - 1]; | ||
826 | |||
827 | if (input_sym->dn_sclass == | ||
828 | DN_STATLAB || | ||
829 | input_sym->dn_sclass == DN_EXTLAB) { | ||
830 | /* load */ | ||
831 | delta = srefp->ds_vaddr; | ||
832 | } else { | ||
833 | /* run */ | ||
834 | delta = srefp->ds_paddr; | ||
835 | } | ||
836 | val += delta; | ||
837 | } | ||
838 | goto loop_itr; | ||
839 | } | ||
840 | /* This symbol is an absolute symbol */ | ||
841 | if (sp->secnn == DN_ABS && ((sp->sclass == DN_EXT) || | ||
842 | (sp->sclass == | ||
843 | DN_EXTLAB))) { | ||
844 | symp = | ||
845 | dlthis->mysym->find_matching_symbol(dlthis-> | ||
846 | mysym, | ||
847 | sname); | ||
848 | if (!symp) | ||
849 | goto loop_itr; | ||
850 | /* This absolute symbol is already defined. */ | ||
851 | if (symp->value == input_sym->dn_value) { | ||
852 | /* If symbol values are equal, continue | ||
853 | * but don't add to the global symbol | ||
854 | * table */ | ||
855 | sp->value = val; | ||
856 | sp->delta = delta; | ||
857 | sp += 1; | ||
858 | input_sym += 1; | ||
859 | continue; | ||
860 | } else { | ||
861 | /* If symbol values are not equal, | ||
862 | * return with redefinition error */ | ||
863 | DL_ERROR("Absolute symbol %s is " | ||
864 | "defined multiple times with " | ||
865 | "different values", sname); | ||
866 | return; | ||
867 | } | ||
868 | } | ||
869 | loop_itr: | ||
870 | /* if this is a global symbol, post it to the | ||
871 | * global table */ | ||
872 | if (input_sym->dn_sclass == DN_EXT || | ||
873 | input_sym->dn_sclass == DN_EXTLAB) { | ||
874 | /* Keep this global symbol for subsequent | ||
875 | * modules. Don't complain on error, to allow | ||
876 | * symbol API to suppress global symbols */ | ||
877 | if (!sname) | ||
878 | goto loop_cont; | ||
879 | |||
880 | newsym = dlthis->mysym->add_to_symbol_table | ||
881 | (dlthis->mysym, sname, | ||
882 | (unsigned)dlthis->myhandle); | ||
883 | if (newsym) | ||
884 | newsym->value = val; | ||
885 | |||
886 | } /* global */ | ||
887 | loop_cont: | ||
888 | sp->value = val; | ||
889 | sp->delta = delta; | ||
890 | sp += 1; | ||
891 | input_sym += 1; | ||
892 | } while ((syms_in_buf -= 1) > 0); /* process sym in buf */ | ||
893 | } while (symbols_left > 0); /* read all symbols */ | ||
894 | if (~checks) | ||
895 | dload_error(dlthis, "Checksum of symbols failed"); | ||
896 | |||
897 | } /* dload_symbols */ | ||
898 | |||
899 | /***************************************************************************** | ||
900 | * Procedure symbol_table_free | ||
901 | * | ||
902 | * Parameters: | ||
903 | * none | ||
904 | * | ||
905 | * Effect: | ||
906 | * Frees any state used by the symbol table. | ||
907 | * | ||
908 | * WARNING: | ||
909 | * This routine is not allowed to declare errors! | ||
910 | **************************************************************************** */ | ||
911 | static void symbol_table_free(struct dload_state *dlthis) | ||
912 | { | ||
913 | if (dlthis->local_symtab) { | ||
914 | if (dlthis->dload_errcount) { /* blow off our symbols */ | ||
915 | dlthis->mysym->purge_symbol_table(dlthis->mysym, | ||
916 | (unsigned) | ||
917 | dlthis->myhandle); | ||
918 | } | ||
919 | dlthis->mysym->dload_deallocate(dlthis->mysym, | ||
920 | dlthis->local_symtab); | ||
921 | } | ||
922 | } /* symbol_table_free */ | ||
923 | |||
924 | /* .cinit Processing | ||
925 | * | ||
926 | * The dynamic loader does .cinit interpretation. cload_cinit() | ||
927 | * acts as a special write-to-target function, in that it takes relocated | ||
928 | * data from the normal data flow, and interprets it as .cinit actions. | ||
929 | * Because the normal data flow does not necessarily process the whole | ||
930 | * .cinit section in one buffer, cload_cinit() must be prepared to | ||
931 | * interpret the data piecemeal. A state machine is used for this | ||
932 | * purpose. | ||
933 | */ | ||
934 | |||
935 | /* The following are only for use by reloc.c and things it calls */ | ||
936 | static const struct ldr_section_info cinit_info_init = { cinitname, 0, 0, | ||
937 | (ldr_addr)-1, 0, DLOAD_BSS, 0 | ||
938 | }; | ||
939 | |||
940 | /************************************************************************* | ||
941 | * Procedure cload_cinit | ||
942 | * | ||
943 | * Parameters: | ||
944 | * ipacket Pointer to data packet to be loaded | ||
945 | * | ||
946 | * Effect: | ||
947 | * Interprets the data in the buffer as .cinit data, and performs the | ||
948 | * appropriate initializations. | ||
949 | *********************************************************************** */ | ||
950 | static void cload_cinit(struct dload_state *dlthis, | ||
951 | struct image_packet_t *ipacket) | ||
952 | { | ||
953 | #if TDATA_TO_HOST(CINIT_COUNT)*BITS_PER_AU > 16 | ||
954 | s32 init_count, left; | ||
955 | #else | ||
956 | s16 init_count, left; | ||
957 | #endif | ||
958 | unsigned char *pktp = ipacket->img_data; | ||
959 | unsigned char *pktend = pktp + BYTE_TO_HOST_ROUND(ipacket->packet_size); | ||
960 | int temp; | ||
961 | ldr_addr atmp; | ||
962 | struct ldr_section_info cinit_info; | ||
963 | |||
964 | /* PROCESS ALL THE INITIALIZATION RECORDS IN THE BUFFER. */ | ||
965 | while (true) { | ||
966 | left = pktend - pktp; | ||
967 | switch (dlthis->cinit_state) { | ||
968 | case CI_COUNT: /* count field */ | ||
969 | if (left < TDATA_TO_HOST(CINIT_COUNT)) | ||
970 | goto loopexit; | ||
971 | temp = dload_unpack(dlthis, (tgt_au_t *) pktp, | ||
972 | CINIT_COUNT * TDATA_AU_BITS, 0, | ||
973 | ROP_SGN); | ||
974 | pktp += TDATA_TO_HOST(CINIT_COUNT); | ||
975 | /* negative signifies BSS table, zero means done */ | ||
976 | if (temp <= 0) { | ||
977 | dlthis->cinit_state = CI_DONE; | ||
978 | break; | ||
979 | } | ||
980 | dlthis->cinit_count = temp; | ||
981 | dlthis->cinit_state = CI_ADDRESS; | ||
982 | break; | ||
983 | #if CINIT_ALIGN < CINIT_ADDRESS | ||
984 | case CI_PARTADDRESS: | ||
985 | pktp -= TDATA_TO_HOST(CINIT_ALIGN); | ||
986 | /* back up pointer into space courtesy of caller */ | ||
987 | *(uint16_t *) pktp = dlthis->cinit_addr; | ||
988 | /* stuff in saved bits !! FALL THRU !! */ | ||
989 | #endif | ||
990 | case CI_ADDRESS: /* Address field for a copy packet */ | ||
991 | if (left < TDATA_TO_HOST(CINIT_ADDRESS)) { | ||
992 | #if CINIT_ALIGN < CINIT_ADDRESS | ||
993 | if (left == TDATA_TO_HOST(CINIT_ALIGN)) { | ||
994 | /* address broken into halves */ | ||
995 | dlthis->cinit_addr = *(uint16_t *) pktp; | ||
996 | /* remember 1st half */ | ||
997 | dlthis->cinit_state = CI_PARTADDRESS; | ||
998 | left = 0; | ||
999 | } | ||
1000 | #endif | ||
1001 | goto loopexit; | ||
1002 | } | ||
1003 | atmp = dload_unpack(dlthis, (tgt_au_t *) pktp, | ||
1004 | CINIT_ADDRESS * TDATA_AU_BITS, 0, | ||
1005 | ROP_UNS); | ||
1006 | pktp += TDATA_TO_HOST(CINIT_ADDRESS); | ||
1007 | #if CINIT_PAGE_BITS > 0 | ||
1008 | dlthis->cinit_page = atmp & | ||
1009 | ((1 << CINIT_PAGE_BITS) - 1); | ||
1010 | atmp >>= CINIT_PAGE_BITS; | ||
1011 | #else | ||
1012 | dlthis->cinit_page = CINIT_DEFAULT_PAGE; | ||
1013 | #endif | ||
1014 | dlthis->cinit_addr = atmp; | ||
1015 | dlthis->cinit_state = CI_COPY; | ||
1016 | break; | ||
1017 | case CI_COPY: /* copy bits to the target */ | ||
1018 | init_count = HOST_TO_TDATA(left); | ||
1019 | if (init_count > dlthis->cinit_count) | ||
1020 | init_count = dlthis->cinit_count; | ||
1021 | if (init_count == 0) | ||
1022 | goto loopexit; /* get more bits */ | ||
1023 | cinit_info = cinit_info_init; | ||
1024 | cinit_info.page = dlthis->cinit_page; | ||
1025 | if (!dlthis->myio->writemem(dlthis->myio, pktp, | ||
1026 | TDATA_TO_TADDR | ||
1027 | (dlthis->cinit_addr), | ||
1028 | &cinit_info, | ||
1029 | TDATA_TO_HOST(init_count))) { | ||
1030 | dload_error(dlthis, initfail, "write", | ||
1031 | dlthis->cinit_addr); | ||
1032 | } | ||
1033 | dlthis->cinit_count -= init_count; | ||
1034 | if (dlthis->cinit_count <= 0) { | ||
1035 | dlthis->cinit_state = CI_COUNT; | ||
1036 | init_count = (init_count + CINIT_ALIGN - 1) & | ||
1037 | -CINIT_ALIGN; | ||
1038 | /* align to next init */ | ||
1039 | } | ||
1040 | pktp += TDATA_TO_HOST(init_count); | ||
1041 | dlthis->cinit_addr += init_count; | ||
1042 | break; | ||
1043 | case CI_DONE: /* no more .cinit to do */ | ||
1044 | return; | ||
1045 | } /* switch (cinit_state) */ | ||
1046 | } /* while */ | ||
1047 | |||
1048 | loopexit: | ||
1049 | if (left > 0) { | ||
1050 | dload_error(dlthis, "%d bytes left over in cinit packet", left); | ||
1051 | dlthis->cinit_state = CI_DONE; /* left over bytes are bad */ | ||
1052 | } | ||
1053 | } /* cload_cinit */ | ||
1054 | |||
1055 | /* Functions to interface to reloc.c | ||
1056 | * | ||
1057 | * reloc.c is the relocation module borrowed from the linker, with | ||
1058 | * minimal (we hope) changes for our purposes. cload_sect_data() invokes | ||
1059 | * this module on a section to relocate and load the image data for that | ||
1060 | * section. The actual read and write actions are supplied by the global | ||
1061 | * routines below. | ||
1062 | */ | ||
1063 | |||
1064 | /************************************************************************ | ||
1065 | * Procedure relocate_packet | ||
1066 | * | ||
1067 | * Parameters: | ||
1068 | * ipacket Pointer to an image packet to relocate | ||
1069 | * | ||
1070 | * Effect: | ||
1071 | * Performs the required relocations on the packet. Returns a checksum | ||
1072 | * of the relocation operations. | ||
1073 | *********************************************************************** */ | ||
1074 | #define MY_RELOC_BUF_SIZ 8 | ||
1075 | /* careful! exists at the same time as the image buffer */ | ||
1076 | static int relocate_packet(struct dload_state *dlthis, | ||
1077 | struct image_packet_t *ipacket, | ||
1078 | u32 *checks, bool *tramps_generated) | ||
1079 | { | ||
1080 | u32 rnum; | ||
1081 | *tramps_generated = false; | ||
1082 | |||
1083 | rnum = ipacket->num_relocs; | ||
1084 | do { /* all relocs */ | ||
1085 | unsigned rinbuf; | ||
1086 | int siz; | ||
1087 | struct reloc_record_t *rp, rrec[MY_RELOC_BUF_SIZ]; | ||
1088 | rp = rrec; | ||
1089 | rinbuf = rnum > MY_RELOC_BUF_SIZ ? MY_RELOC_BUF_SIZ : rnum; | ||
1090 | siz = rinbuf * sizeof(struct reloc_record_t); | ||
1091 | if (dlthis->strm->read_buffer(dlthis->strm, rp, siz) != siz) { | ||
1092 | DL_ERROR(readstrm, "relocation"); | ||
1093 | return 0; | ||
1094 | } | ||
1095 | /* reorder the bytes if need be */ | ||
1096 | if (dlthis->reorder_map) | ||
1097 | dload_reorder(rp, siz, dlthis->reorder_map); | ||
1098 | |||
1099 | *checks += dload_checksum(rp, siz); | ||
1100 | do { | ||
1101 | /* perform the relocation operation */ | ||
1102 | dload_relocate(dlthis, (tgt_au_t *) ipacket->img_data, | ||
1103 | rp, tramps_generated, false); | ||
1104 | rp += 1; | ||
1105 | rnum -= 1; | ||
1106 | } while ((rinbuf -= 1) > 0); | ||
1107 | } while (rnum > 0); /* all relocs */ | ||
1108 | /* If trampoline(s) were generated, we need to do an update of the | ||
1109 | * trampoline copy of the packet since a 2nd phase relo will be done | ||
1110 | * later. */ | ||
1111 | if (*tramps_generated == true) { | ||
1112 | dload_tramp_pkt_udpate(dlthis, | ||
1113 | (dlthis->image_secn - | ||
1114 | dlthis->ldr_sections), | ||
1115 | dlthis->image_offset, ipacket); | ||
1116 | } | ||
1117 | |||
1118 | return 1; | ||
1119 | } /* dload_read_reloc */ | ||
1120 | |||
1121 | #define IPH_SIZE (sizeof(struct image_packet_t) - sizeof(u32)) | ||
1122 | |||
1123 | /* VERY dangerous */ | ||
1124 | static const char imagepak[] = { "image packet" }; | ||
1125 | |||
1126 | /************************************************************************* | ||
1127 | * Procedure dload_data | ||
1128 | * | ||
1129 | * Parameters: | ||
1130 | * none | ||
1131 | * | ||
1132 | * Effect: | ||
1133 | * Read image data from input file, relocate it, and download it to the | ||
1134 | * target. | ||
1135 | *********************************************************************** */ | ||
1136 | static void dload_data(struct dload_state *dlthis) | ||
1137 | { | ||
1138 | u16 curr_sect; | ||
1139 | struct doff_scnhdr_t *sptr = dlthis->sect_hdrs; | ||
1140 | struct ldr_section_info *lptr = dlthis->ldr_sections; | ||
1141 | #ifdef OPT_ZERO_COPY_LOADER | ||
1142 | bool zero_copy = false; | ||
1143 | #endif | ||
1144 | u8 *dest; | ||
1145 | |||
1146 | struct { | ||
1147 | struct image_packet_t ipacket; | ||
1148 | u8 bufr[BYTE_TO_HOST(IMAGE_PACKET_SIZE)]; | ||
1149 | } ibuf; | ||
1150 | |||
1151 | /* Indicates whether CINIT processing has occurred */ | ||
1152 | bool cinit_processed = false; | ||
1153 | |||
1154 | /* Loop through the sections and load them one at a time. | ||
1155 | */ | ||
1156 | for (curr_sect = 0; curr_sect < dlthis->dfile_hdr.df_no_scns; | ||
1157 | curr_sect += 1) { | ||
1158 | if (DS_NEEDS_DOWNLOAD(sptr)) { | ||
1159 | s32 nip; | ||
1160 | ldr_addr image_offset = 0; | ||
1161 | /* set relocation info for this section */ | ||
1162 | if (curr_sect < dlthis->allocated_secn_count) | ||
1163 | dlthis->delta_runaddr = sptr->ds_paddr; | ||
1164 | else { | ||
1165 | lptr = DOFFSEC_IS_LDRSEC(sptr); | ||
1166 | dlthis->delta_runaddr = 0; | ||
1167 | } | ||
1168 | dlthis->image_secn = lptr; | ||
1169 | #if BITS_PER_AU > BITS_PER_BYTE | ||
1170 | lptr->name = unpack_name(dlthis, sptr->ds_offset); | ||
1171 | #endif | ||
1172 | nip = sptr->ds_nipacks; | ||
1173 | while ((nip -= 1) >= 0) { /* process packets */ | ||
1174 | |||
1175 | s32 ipsize; | ||
1176 | u32 checks; | ||
1177 | bool tramp_generated = false; | ||
1178 | |||
1179 | /* get the fixed header bits */ | ||
1180 | if (dlthis->strm->read_buffer(dlthis->strm, | ||
1181 | &ibuf.ipacket, | ||
1182 | IPH_SIZE) != | ||
1183 | IPH_SIZE) { | ||
1184 | DL_ERROR(readstrm, imagepak); | ||
1185 | return; | ||
1186 | } | ||
1187 | /* reorder the header if need be */ | ||
1188 | if (dlthis->reorder_map) { | ||
1189 | dload_reorder(&ibuf.ipacket, IPH_SIZE, | ||
1190 | dlthis->reorder_map); | ||
1191 | } | ||
1192 | /* now read the rest of the packet */ | ||
1193 | ipsize = | ||
1194 | BYTE_TO_HOST(DOFF_ALIGN | ||
1195 | (ibuf.ipacket.packet_size)); | ||
1196 | if (ipsize > BYTE_TO_HOST(IMAGE_PACKET_SIZE)) { | ||
1197 | DL_ERROR("Bad image packet size %d", | ||
1198 | ipsize); | ||
1199 | return; | ||
1200 | } | ||
1201 | dest = ibuf.bufr; | ||
1202 | #ifdef OPT_ZERO_COPY_LOADER | ||
1203 | zero_copy = false; | ||
1204 | if (DLOAD_SECT_TYPE(sptr) != DLOAD_CINIT) { | ||
1205 | dlthis->myio->writemem(dlthis->myio, | ||
1206 | &dest, | ||
1207 | lptr->load_addr + | ||
1208 | image_offset, | ||
1209 | lptr, 0); | ||
1210 | zero_copy = (dest != ibuf.bufr); | ||
1211 | } | ||
1212 | #endif | ||
1213 | /* End of determination */ | ||
1214 | |||
1215 | if (dlthis->strm->read_buffer(dlthis->strm, | ||
1216 | ibuf.bufr, | ||
1217 | ipsize) != | ||
1218 | ipsize) { | ||
1219 | DL_ERROR(readstrm, imagepak); | ||
1220 | return; | ||
1221 | } | ||
1222 | ibuf.ipacket.img_data = dest; | ||
1223 | |||
1224 | /* reorder the bytes if need be */ | ||
1225 | #if !defined(_BIG_ENDIAN) || (TARGET_AU_BITS > 16) | ||
1226 | if (dlthis->reorder_map) { | ||
1227 | dload_reorder(dest, ipsize, | ||
1228 | dlthis->reorder_map); | ||
1229 | } | ||
1230 | checks = dload_checksum(dest, ipsize); | ||
1231 | #else | ||
1232 | if (dlthis->dfile_hdr.df_byte_reshuffle != | ||
1233 | TARGET_ORDER(REORDER_MAP | ||
1234 | (BYTE_RESHUFFLE_VALUE))) { | ||
1235 | /* put image bytes in big-endian order, | ||
1236 | * not PC order */ | ||
1237 | dload_reorder(dest, ipsize, | ||
1238 | TARGET_ORDER | ||
1239 | (dlthis->dfile_hdr. | ||
1240 | df_byte_reshuffle)); | ||
1241 | } | ||
1242 | #if TARGET_AU_BITS > 8 | ||
1243 | checks = dload_reverse_checksum16(dest, ipsize); | ||
1244 | #else | ||
1245 | checks = dload_reverse_checksum(dest, ipsize); | ||
1246 | #endif | ||
1247 | #endif | ||
1248 | |||
1249 | checks += dload_checksum(&ibuf.ipacket, | ||
1250 | IPH_SIZE); | ||
1251 | /* relocate the image bits as needed */ | ||
1252 | if (ibuf.ipacket.num_relocs) { | ||
1253 | dlthis->image_offset = image_offset; | ||
1254 | if (!relocate_packet(dlthis, | ||
1255 | &ibuf.ipacket, | ||
1256 | &checks, | ||
1257 | &tramp_generated)) | ||
1258 | return; /* serious error */ | ||
1259 | } | ||
1260 | if (~checks) | ||
1261 | DL_ERROR(err_checksum, imagepak); | ||
1262 | /* Only write the result to the target if no | ||
1263 | * trampoline was generated. Otherwise it | ||
1264 | *will be done during trampoline finalize. */ | ||
1265 | |||
1266 | if (tramp_generated == false) { | ||
1267 | |||
1268 | /* stuff the result into target | ||
1269 | * memory */ | ||
1270 | if (DLOAD_SECT_TYPE(sptr) == | ||
1271 | DLOAD_CINIT) { | ||
1272 | cload_cinit(dlthis, | ||
1273 | &ibuf.ipacket); | ||
1274 | cinit_processed = true; | ||
1275 | } else { | ||
1276 | #ifdef OPT_ZERO_COPY_LOADER | ||
1277 | if (!zero_copy) { | ||
1278 | #endif | ||
1279 | /* FIXME */ | ||
1280 | if (!dlthis->myio-> | ||
1281 | writemem(dlthis-> | ||
1282 | myio, | ||
1283 | ibuf.bufr, | ||
1284 | lptr-> | ||
1285 | load_addr + | ||
1286 | image_offset, | ||
1287 | lptr, | ||
1288 | BYTE_TO_HOST | ||
1289 | (ibuf. | ||
1290 | ipacket. | ||
1291 | packet_size))) { | ||
1292 | DL_ERROR | ||
1293 | ("Write to " | ||
1294 | FMT_UI32 | ||
1295 | " failed", | ||
1296 | lptr-> | ||
1297 | load_addr + | ||
1298 | image_offset); | ||
1299 | } | ||
1300 | #ifdef OPT_ZERO_COPY_LOADER | ||
1301 | } | ||
1302 | #endif | ||
1303 | } | ||
1304 | } | ||
1305 | image_offset += | ||
1306 | BYTE_TO_TADDR(ibuf.ipacket.packet_size); | ||
1307 | } /* process packets */ | ||
1308 | /* if this is a BSS section, we may want to fill it */ | ||
1309 | if (DLOAD_SECT_TYPE(sptr) != DLOAD_BSS) | ||
1310 | goto loop_cont; | ||
1311 | |||
1312 | if (!(dlthis->myoptions & DLOAD_INITBSS)) | ||
1313 | goto loop_cont; | ||
1314 | |||
1315 | if (cinit_processed) { | ||
1316 | /* Don't clear BSS after load-time | ||
1317 | * initialization */ | ||
1318 | DL_ERROR | ||
1319 | ("Zero-initialization at " FMT_UI32 | ||
1320 | " after " "load-time initialization!", | ||
1321 | lptr->load_addr); | ||
1322 | goto loop_cont; | ||
1323 | } | ||
1324 | /* fill the .bss area */ | ||
1325 | dlthis->myio->fillmem(dlthis->myio, | ||
1326 | TADDR_TO_HOST(lptr->load_addr), | ||
1327 | lptr, TADDR_TO_HOST(lptr->size), | ||
1328 | DLOAD_FILL_BSS); | ||
1329 | goto loop_cont; | ||
1330 | } | ||
1331 | /* if DS_DOWNLOAD_MASK */ | ||
1332 | /* If not loading, but BSS, zero initialize */ | ||
1333 | if (DLOAD_SECT_TYPE(sptr) != DLOAD_BSS) | ||
1334 | goto loop_cont; | ||
1335 | |||
1336 | if (!(dlthis->myoptions & DLOAD_INITBSS)) | ||
1337 | goto loop_cont; | ||
1338 | |||
1339 | if (curr_sect >= dlthis->allocated_secn_count) | ||
1340 | lptr = DOFFSEC_IS_LDRSEC(sptr); | ||
1341 | |||
1342 | if (cinit_processed) { | ||
1343 | /*Don't clear BSS after load-time initialization */ | ||
1344 | DL_ERROR("Zero-initialization at " FMT_UI32 | ||
1345 | " attempted after " | ||
1346 | "load-time initialization!", lptr->load_addr); | ||
1347 | goto loop_cont; | ||
1348 | } | ||
1349 | /* fill the .bss area */ | ||
1350 | dlthis->myio->fillmem(dlthis->myio, | ||
1351 | TADDR_TO_HOST(lptr->load_addr), lptr, | ||
1352 | TADDR_TO_HOST(lptr->size), | ||
1353 | DLOAD_FILL_BSS); | ||
1354 | loop_cont: | ||
1355 | sptr += 1; | ||
1356 | lptr += 1; | ||
1357 | } /* load sections */ | ||
1358 | |||
1359 | /* Finalize any trampolines that were created during the load */ | ||
1360 | if (dload_tramp_finalize(dlthis) == 0) { | ||
1361 | DL_ERROR("Finalization of auto-trampolines (size = " FMT_UI32 | ||
1362 | ") failed", dlthis->tramp.tramp_sect_next_addr); | ||
1363 | } | ||
1364 | } /* dload_data */ | ||
1365 | |||
1366 | /************************************************************************* | ||
1367 | * Procedure dload_reorder | ||
1368 | * | ||
1369 | * Parameters: | ||
1370 | * data 32-bit aligned pointer to data to be byte-swapped | ||
1371 | * dsiz size of the data to be reordered in sizeof() units. | ||
1372 | * map 32-bit map defining how to reorder the data. Value | ||
1373 | * must be REORDER_MAP() of some permutation | ||
1374 | * of 0x00 01 02 03 | ||
1375 | * | ||
1376 | * Effect: | ||
1377 | * Re-arranges the bytes in each word according to the map specified. | ||
1378 | * | ||
1379 | *********************************************************************** */ | ||
1380 | /* mask for byte shift count */ | ||
1381 | #define SHIFT_COUNT_MASK (3 << LOG_BITS_PER_BYTE) | ||
1382 | |||
1383 | void dload_reorder(void *data, int dsiz, unsigned int map) | ||
1384 | { | ||
1385 | register u32 tmp, tmap, datv; | ||
1386 | u32 *dp = (u32 *) data; | ||
1387 | |||
1388 | map <<= LOG_BITS_PER_BYTE; /* align map with SHIFT_COUNT_MASK */ | ||
1389 | do { | ||
1390 | tmp = 0; | ||
1391 | datv = *dp; | ||
1392 | tmap = map; | ||
1393 | do { | ||
1394 | tmp |= (datv & BYTE_MASK) << (tmap & SHIFT_COUNT_MASK); | ||
1395 | tmap >>= BITS_PER_BYTE; | ||
1396 | } while (datv >>= BITS_PER_BYTE); | ||
1397 | *dp++ = tmp; | ||
1398 | } while ((dsiz -= sizeof(u32)) > 0); | ||
1399 | } /* dload_reorder */ | ||
1400 | |||
1401 | /************************************************************************* | ||
1402 | * Procedure dload_checksum | ||
1403 | * | ||
1404 | * Parameters: | ||
1405 | * data 32-bit aligned pointer to data to be checksummed | ||
1406 | * siz size of the data to be checksummed in sizeof() units. | ||
1407 | * | ||
1408 | * Effect: | ||
1409 | * Returns a checksum of the specified block | ||
1410 | * | ||
1411 | *********************************************************************** */ | ||
1412 | u32 dload_checksum(void *data, unsigned siz) | ||
1413 | { | ||
1414 | u32 sum; | ||
1415 | u32 *dp; | ||
1416 | int left; | ||
1417 | |||
1418 | sum = 0; | ||
1419 | dp = (u32 *) data; | ||
1420 | for (left = siz; left > 0; left -= sizeof(u32)) | ||
1421 | sum += *dp++; | ||
1422 | return sum; | ||
1423 | } /* dload_checksum */ | ||
1424 | |||
1425 | #if HOST_ENDIANNESS | ||
1426 | /************************************************************************* | ||
1427 | * Procedure dload_reverse_checksum | ||
1428 | * | ||
1429 | * Parameters: | ||
1430 | * data 32-bit aligned pointer to data to be checksummed | ||
1431 | * siz size of the data to be checksummed in sizeof() units. | ||
1432 | * | ||
1433 | * Effect: | ||
1434 | * Returns a checksum of the specified block, which is assumed to be bytes | ||
1435 | * in big-endian order. | ||
1436 | * | ||
1437 | * Notes: | ||
1438 | * In a big-endian host, things like the string table are stored as bytes | ||
1439 | * in host order. But dllcreate always checksums in little-endian order. | ||
1440 | * It is most efficient to just handle the difference a word at a time. | ||
1441 | * | ||
1442 | ********************************************************************** */ | ||
1443 | u32 dload_reverse_checksum(void *data, unsigned siz) | ||
1444 | { | ||
1445 | u32 sum, temp; | ||
1446 | u32 *dp; | ||
1447 | int left; | ||
1448 | |||
1449 | sum = 0; | ||
1450 | dp = (u32 *) data; | ||
1451 | |||
1452 | for (left = siz; left > 0; left -= sizeof(u32)) { | ||
1453 | temp = *dp++; | ||
1454 | sum += temp << BITS_PER_BYTE * 3; | ||
1455 | sum += temp >> BITS_PER_BYTE * 3; | ||
1456 | sum += (temp >> BITS_PER_BYTE) & (BYTE_MASK << BITS_PER_BYTE); | ||
1457 | sum += (temp & (BYTE_MASK << BITS_PER_BYTE)) << BITS_PER_BYTE; | ||
1458 | } | ||
1459 | |||
1460 | return sum; | ||
1461 | } /* dload_reverse_checksum */ | ||
1462 | |||
1463 | #if (TARGET_AU_BITS > 8) && (TARGET_AU_BITS < 32) | ||
1464 | u32 dload_reverse_checksum16(void *data, unsigned siz) | ||
1465 | { | ||
1466 | uint_fast32_t sum, temp; | ||
1467 | u32 *dp; | ||
1468 | int left; | ||
1469 | |||
1470 | sum = 0; | ||
1471 | dp = (u32 *) data; | ||
1472 | |||
1473 | for (left = siz; left > 0; left -= sizeof(u32)) { | ||
1474 | temp = *dp++; | ||
1475 | sum += temp << BITS_PER_BYTE * 2; | ||
1476 | sum += temp >> BITS_PER_BYTE * 2; | ||
1477 | } | ||
1478 | |||
1479 | return sum; | ||
1480 | } /* dload_reverse_checksum16 */ | ||
1481 | #endif | ||
1482 | #endif | ||
1483 | |||
1484 | /************************************************************************* | ||
1485 | * Procedure swap_words | ||
1486 | * | ||
1487 | * Parameters: | ||
1488 | * data 32-bit aligned pointer to data to be swapped | ||
1489 | * siz size of the data to be swapped. | ||
1490 | * bitmap Bit map of how to swap each 32-bit word; 1 => 2 shorts, | ||
1491 | * 0 => 1 long | ||
1492 | * | ||
1493 | * Effect: | ||
1494 | * Swaps the specified data according to the specified map | ||
1495 | * | ||
1496 | *********************************************************************** */ | ||
1497 | static void swap_words(void *data, unsigned siz, unsigned bitmap) | ||
1498 | { | ||
1499 | register int i; | ||
1500 | #if TARGET_AU_BITS < 16 | ||
1501 | register u16 *sp; | ||
1502 | #endif | ||
1503 | register u32 *lp; | ||
1504 | |||
1505 | siz /= sizeof(u16); | ||
1506 | |||
1507 | #if TARGET_AU_BITS < 16 | ||
1508 | /* pass 1: do all the bytes */ | ||
1509 | i = siz; | ||
1510 | sp = (u16 *) data; | ||
1511 | do { | ||
1512 | register u16 tmp; | ||
1513 | tmp = *sp; | ||
1514 | *sp++ = SWAP16BY8(tmp); | ||
1515 | } while ((i -= 1) > 0); | ||
1516 | #endif | ||
1517 | |||
1518 | #if TARGET_AU_BITS < 32 | ||
1519 | /* pass 2: fixup the 32-bit words */ | ||
1520 | i = siz >> 1; | ||
1521 | lp = (u32 *) data; | ||
1522 | do { | ||
1523 | if ((bitmap & 1) == 0) { | ||
1524 | register u32 tmp; | ||
1525 | tmp = *lp; | ||
1526 | *lp = SWAP32BY16(tmp); | ||
1527 | } | ||
1528 | lp += 1; | ||
1529 | bitmap >>= 1; | ||
1530 | } while ((i -= 1) > 0); | ||
1531 | #endif | ||
1532 | } /* swap_words */ | ||
1533 | |||
1534 | /************************************************************************* | ||
1535 | * Procedure copy_tgt_strings | ||
1536 | * | ||
1537 | * Parameters: | ||
1538 | * dstp Destination address. Assumed to be 32-bit aligned | ||
1539 | * srcp Source address. Assumed to be 32-bit aligned | ||
1540 | * charcount Number of characters to copy. | ||
1541 | * | ||
1542 | * Effect: | ||
1543 | * Copies strings from the source (which is in usual .dof file order on | ||
1544 | * the loading processor) to the destination buffer (which should be in proper | ||
1545 | * target addressable unit order). Makes sure the last string in the | ||
1546 | * buffer is NULL terminated (for safety). | ||
1547 | * Returns the first unused destination address. | ||
1548 | *********************************************************************** */ | ||
1549 | static char *copy_tgt_strings(void *dstp, void *srcp, unsigned charcount) | ||
1550 | { | ||
1551 | register tgt_au_t *src = (tgt_au_t *) srcp; | ||
1552 | register tgt_au_t *dst = (tgt_au_t *) dstp; | ||
1553 | register int cnt = charcount; | ||
1554 | do { | ||
1555 | #if TARGET_AU_BITS <= BITS_PER_AU | ||
1556 | /* byte-swapping issues may exist for strings on target */ | ||
1557 | *dst++ = *src++; | ||
1558 | #else | ||
1559 | *dst++ = *src++; | ||
1560 | #endif | ||
1561 | } while ((cnt -= (sizeof(tgt_au_t) * BITS_PER_AU / BITS_PER_BYTE)) > 0); | ||
1562 | /*apply force to make sure that the string table has null terminator */ | ||
1563 | #if (BITS_PER_AU == BITS_PER_BYTE) && (TARGET_AU_BITS == BITS_PER_BYTE) | ||
1564 | dst[-1] = 0; | ||
1565 | #else | ||
1566 | /* little endian */ | ||
1567 | dst[-1] &= (1 << (BITS_PER_AU - BITS_PER_BYTE)) - 1; | ||
1568 | #endif | ||
1569 | return (char *)dst; | ||
1570 | } /* copy_tgt_strings */ | ||
1571 | |||
1572 | /************************************************************************* | ||
1573 | * Procedure init_module_handle | ||
1574 | * | ||
1575 | * Parameters: | ||
1576 | * none | ||
1577 | * | ||
1578 | * Effect: | ||
1579 | * Initializes the module handle we use to enable unloading, and installs | ||
1580 | * the debug information required by the target. | ||
1581 | * | ||
1582 | * Notes: | ||
1583 | * The handle returned from dynamic_load_module needs to encapsulate all the | ||
1584 | * allocations done for the module, and enable them plus the modules symbols to | ||
1585 | * be deallocated. | ||
1586 | * | ||
1587 | *********************************************************************** */ | ||
1588 | #ifndef _BIG_ENDIAN | ||
1589 | static const struct ldr_section_info dllview_info_init = { ".dllview", 0, 0, | ||
1590 | (ldr_addr)-1, DBG_LIST_PAGE, DLOAD_DATA, 0 | ||
1591 | }; | ||
1592 | #else | ||
1593 | static const struct ldr_section_info dllview_info_init = { ".dllview", 0, 0, | ||
1594 | (ldr_addr)-1, DLOAD_DATA, DBG_LIST_PAGE, 0 | ||
1595 | }; | ||
1596 | #endif | ||
1597 | static void init_module_handle(struct dload_state *dlthis) | ||
1598 | { | ||
1599 | struct my_handle *hndl; | ||
1600 | u16 curr_sect; | ||
1601 | struct ldr_section_info *asecs; | ||
1602 | struct dll_module *dbmod; | ||
1603 | struct dll_sect *dbsec; | ||
1604 | struct dbg_mirror_root *mlist; | ||
1605 | register char *cp; | ||
1606 | struct modules_header mhdr; | ||
1607 | struct ldr_section_info dllview_info; | ||
1608 | struct dynload_symbol *debug_mirror_sym; | ||
1609 | hndl = dlthis->myhandle; | ||
1610 | if (!hndl) | ||
1611 | return; /* must be errors detected, so forget it */ | ||
1612 | |||
1613 | /* Store the section count */ | ||
1614 | hndl->secn_count = dlthis->allocated_secn_count; | ||
1615 | |||
1616 | /* If a trampoline section was created, add it in */ | ||
1617 | if (dlthis->tramp.tramp_sect_next_addr != 0) | ||
1618 | hndl->secn_count += 1; | ||
1619 | |||
1620 | hndl->secn_count = hndl->secn_count << 1; | ||
1621 | |||
1622 | hndl->secn_count = dlthis->allocated_secn_count << 1; | ||
1623 | #ifndef TARGET_ENDIANNESS | ||
1624 | if (dlthis->big_e_target) | ||
1625 | hndl->secn_count += 1; /* flag for big-endian */ | ||
1626 | #endif | ||
1627 | if (dlthis->dload_errcount) | ||
1628 | return; /* abandon if errors detected */ | ||
1629 | /* Locate the symbol that names the header for the CCS debug list | ||
1630 | of modules. If not found, we just don't generate the debug record. | ||
1631 | If found, we create our modules list. We make sure to create the | ||
1632 | loader_dllview_root even if there is no relocation info to record, | ||
1633 | just to try to put both symbols in the same symbol table and | ||
1634 | module. */ | ||
1635 | debug_mirror_sym = dlthis->mysym->find_matching_symbol(dlthis->mysym, | ||
1636 | loader_dllview_root); | ||
1637 | if (!debug_mirror_sym) { | ||
1638 | struct dynload_symbol *dlmodsym; | ||
1639 | struct dbg_mirror_root *mlst; | ||
1640 | |||
1641 | /* our root symbol is not yet present; | ||
1642 | check if we have DLModules defined */ | ||
1643 | dlmodsym = dlthis->mysym->find_matching_symbol(dlthis->mysym, | ||
1644 | LINKER_MODULES_HEADER); | ||
1645 | if (!dlmodsym) | ||
1646 | return; /* no DLModules list so no debug info */ | ||
1647 | /* if we have DLModules defined, construct our header */ | ||
1648 | mlst = (struct dbg_mirror_root *) | ||
1649 | dlthis->mysym->dload_allocate(dlthis->mysym, | ||
1650 | sizeof(struct | ||
1651 | dbg_mirror_root)); | ||
1652 | if (!mlst) { | ||
1653 | DL_ERROR(err_alloc, sizeof(struct dbg_mirror_root)); | ||
1654 | return; | ||
1655 | } | ||
1656 | mlst->hnext = NULL; | ||
1657 | mlst->changes = 0; | ||
1658 | mlst->refcount = 0; | ||
1659 | mlst->dbthis = TDATA_TO_TADDR(dlmodsym->value); | ||
1660 | /* add our root symbol */ | ||
1661 | debug_mirror_sym = dlthis->mysym->add_to_symbol_table | ||
1662 | (dlthis->mysym, loader_dllview_root, | ||
1663 | (unsigned)dlthis->myhandle); | ||
1664 | if (!debug_mirror_sym) { | ||
1665 | /* failed, recover memory */ | ||
1666 | dlthis->mysym->dload_deallocate(dlthis->mysym, mlst); | ||
1667 | return; | ||
1668 | } | ||
1669 | debug_mirror_sym->value = (u32) mlst; | ||
1670 | } | ||
1671 | /* First create the DLLview record and stuff it into the buffer. | ||
1672 | Then write it to the DSP. Record pertinent locations in our hndl, | ||
1673 | and add it to the per-processor list of handles with debug info. */ | ||
1674 | #ifndef DEBUG_HEADER_IN_LOADER | ||
1675 | mlist = (struct dbg_mirror_root *)debug_mirror_sym->value; | ||
1676 | if (!mlist) | ||
1677 | return; | ||
1678 | #else | ||
1679 | mlist = (struct dbg_mirror_root *)&debug_list_header; | ||
1680 | #endif | ||
1681 | hndl->dm.hroot = mlist; /* set pointer to root into our handle */ | ||
1682 | if (!dlthis->allocated_secn_count) | ||
1683 | return; /* no load addresses to be recorded */ | ||
1684 | /* reuse temporary symbol storage */ | ||
1685 | dbmod = (struct dll_module *)dlthis->local_symtab; | ||
1686 | /* Create the DLLview record in the memory we retain for our handle */ | ||
1687 | dbmod->num_sects = dlthis->allocated_secn_count; | ||
1688 | dbmod->timestamp = dlthis->verify.dv_timdat; | ||
1689 | dbmod->version = INIT_VERSION; | ||
1690 | dbmod->verification = VERIFICATION; | ||
1691 | asecs = dlthis->ldr_sections; | ||
1692 | dbsec = dbmod->sects; | ||
1693 | for (curr_sect = dlthis->allocated_secn_count; | ||
1694 | curr_sect > 0; curr_sect -= 1) { | ||
1695 | dbsec->sect_load_adr = asecs->load_addr; | ||
1696 | dbsec->sect_run_adr = asecs->run_addr; | ||
1697 | dbsec += 1; | ||
1698 | asecs += 1; | ||
1699 | } | ||
1700 | |||
1701 | /* If a trampoline section was created go ahead and add its info */ | ||
1702 | if (dlthis->tramp.tramp_sect_next_addr != 0) { | ||
1703 | dbmod->num_sects++; | ||
1704 | dbsec->sect_load_adr = asecs->load_addr; | ||
1705 | dbsec->sect_run_adr = asecs->run_addr; | ||
1706 | dbsec++; | ||
1707 | asecs++; | ||
1708 | } | ||
1709 | |||
1710 | /* now cram in the names */ | ||
1711 | cp = copy_tgt_strings(dbsec, dlthis->str_head, | ||
1712 | dlthis->debug_string_size); | ||
1713 | |||
1714 | /* If a trampoline section was created, add its name so DLLView | ||
1715 | * can show the user the section info. */ | ||
1716 | if (dlthis->tramp.tramp_sect_next_addr != 0) { | ||
1717 | cp = copy_tgt_strings(cp, | ||
1718 | dlthis->tramp.final_string_table, | ||
1719 | strlen(dlthis->tramp.final_string_table) + | ||
1720 | 1); | ||
1721 | } | ||
1722 | |||
1723 | /* round off the size of the debug record, and remember same */ | ||
1724 | hndl->dm.dbsiz = HOST_TO_TDATA_ROUND(cp - (char *)dbmod); | ||
1725 | *cp = 0; /* strictly to make our test harness happy */ | ||
1726 | dllview_info = dllview_info_init; | ||
1727 | dllview_info.size = TDATA_TO_TADDR(hndl->dm.dbsiz); | ||
1728 | /* Initialize memory context to default heap */ | ||
1729 | dllview_info.context = 0; | ||
1730 | hndl->dm.context = 0; | ||
1731 | /* fill in next pointer and size */ | ||
1732 | if (mlist->hnext) { | ||
1733 | dbmod->next_module = TADDR_TO_TDATA(mlist->hnext->dm.dbthis); | ||
1734 | dbmod->next_module_size = mlist->hnext->dm.dbsiz; | ||
1735 | } else { | ||
1736 | dbmod->next_module_size = 0; | ||
1737 | dbmod->next_module = 0; | ||
1738 | } | ||
1739 | /* allocate memory for on-DSP DLLview debug record */ | ||
1740 | if (!dlthis->myalloc) | ||
1741 | return; | ||
1742 | if (!dlthis->myalloc->dload_allocate(dlthis->myalloc, &dllview_info, | ||
1743 | HOST_TO_TADDR(sizeof(u32)))) { | ||
1744 | return; | ||
1745 | } | ||
1746 | /* Store load address of .dllview section */ | ||
1747 | hndl->dm.dbthis = dllview_info.load_addr; | ||
1748 | /* Store memory context (segid) in which .dllview section | ||
1749 | * was allocated */ | ||
1750 | hndl->dm.context = dllview_info.context; | ||
1751 | mlist->refcount += 1; | ||
1752 | /* swap bytes in the entire debug record, but not the string table */ | ||
1753 | if (TARGET_ENDIANNESS_DIFFERS(TARGET_BIG_ENDIAN)) { | ||
1754 | swap_words(dbmod, (char *)dbsec - (char *)dbmod, | ||
1755 | DLL_MODULE_BITMAP); | ||
1756 | } | ||
1757 | /* Update the DLLview list on the DSP write new record */ | ||
1758 | if (!dlthis->myio->writemem(dlthis->myio, dbmod, | ||
1759 | dllview_info.load_addr, &dllview_info, | ||
1760 | TADDR_TO_HOST(dllview_info.size))) { | ||
1761 | return; | ||
1762 | } | ||
1763 | /* write new header */ | ||
1764 | mhdr.first_module_size = hndl->dm.dbsiz; | ||
1765 | mhdr.first_module = TADDR_TO_TDATA(dllview_info.load_addr); | ||
1766 | /* swap bytes in the module header, if needed */ | ||
1767 | if (TARGET_ENDIANNESS_DIFFERS(TARGET_BIG_ENDIAN)) { | ||
1768 | swap_words(&mhdr, sizeof(struct modules_header) - sizeof(u16), | ||
1769 | MODULES_HEADER_BITMAP); | ||
1770 | } | ||
1771 | dllview_info = dllview_info_init; | ||
1772 | if (!dlthis->myio->writemem(dlthis->myio, &mhdr, mlist->dbthis, | ||
1773 | &dllview_info, | ||
1774 | sizeof(struct modules_header) - | ||
1775 | sizeof(u16))) { | ||
1776 | return; | ||
1777 | } | ||
1778 | /* Add the module handle to this processor's list | ||
1779 | of handles with debug info */ | ||
1780 | hndl->dm.hnext = mlist->hnext; | ||
1781 | if (hndl->dm.hnext) | ||
1782 | hndl->dm.hnext->dm.hprev = hndl; | ||
1783 | hndl->dm.hprev = (struct my_handle *)mlist; | ||
1784 | mlist->hnext = hndl; /* insert after root */ | ||
1785 | } /* init_module_handle */ | ||
1786 | |||
1787 | /************************************************************************* | ||
1788 | * Procedure dynamic_unload_module | ||
1789 | * | ||
1790 | * Parameters: | ||
1791 | * mhandle A module handle from dynamic_load_module | ||
1792 | * syms Host-side symbol table and malloc/free functions | ||
1793 | * alloc Target-side memory allocation | ||
1794 | * | ||
1795 | * Effect: | ||
1796 | * The module specified by mhandle is unloaded. Unloading causes all | ||
1797 | * target memory to be deallocated, all symbols defined by the module to | ||
1798 | * be purged, and any host-side storage used by the dynamic loader for | ||
1799 | * this module to be released. | ||
1800 | * | ||
1801 | * Returns: | ||
1802 | * Zero for success. On error, the number of errors detected is returned. | ||
1803 | * Individual errors are reported using syms->error_report(). | ||
1804 | *********************************************************************** */ | ||
1805 | int dynamic_unload_module(void *mhandle, | ||
1806 | struct dynamic_loader_sym *syms, | ||
1807 | struct dynamic_loader_allocate *alloc, | ||
1808 | struct dynamic_loader_initialize *init) | ||
1809 | { | ||
1810 | s16 curr_sect; | ||
1811 | struct ldr_section_info *asecs; | ||
1812 | struct my_handle *hndl; | ||
1813 | struct dbg_mirror_root *root; | ||
1814 | unsigned errcount = 0; | ||
1815 | struct ldr_section_info dllview_info = dllview_info_init; | ||
1816 | struct modules_header mhdr; | ||
1817 | |||
1818 | hndl = (struct my_handle *)mhandle; | ||
1819 | if (!hndl) | ||
1820 | return 0; /* if handle is null, nothing to do */ | ||
1821 | /* Clear out the module symbols | ||
1822 | * Note that if this is the module that defined MODULES_HEADER | ||
1823 | (the head of the target debug list) | ||
1824 | * then this operation will blow away that symbol. | ||
1825 | It will therefore be impossible for subsequent | ||
1826 | * operations to add entries to this un-referenceable list. */ | ||
1827 | if (!syms) | ||
1828 | return 1; | ||
1829 | syms->purge_symbol_table(syms, (unsigned)hndl); | ||
1830 | /* Deallocate target memory for sections | ||
1831 | * NOTE: The trampoline section, if created, gets deleted here, too */ | ||
1832 | |||
1833 | asecs = hndl->secns; | ||
1834 | if (alloc) | ||
1835 | for (curr_sect = (hndl->secn_count >> 1); curr_sect > 0; | ||
1836 | curr_sect -= 1) { | ||
1837 | asecs->name = NULL; | ||
1838 | alloc->dload_deallocate(alloc, asecs++); | ||
1839 | } | ||
1840 | root = hndl->dm.hroot; | ||
1841 | if (!root) { | ||
1842 | /* there is a debug list containing this module */ | ||
1843 | goto func_end; | ||
1844 | } | ||
1845 | if (!hndl->dm.dbthis) { /* target-side dllview record exists */ | ||
1846 | goto loop_end; | ||
1847 | } | ||
1848 | /* Retrieve memory context in which .dllview was allocated */ | ||
1849 | dllview_info.context = hndl->dm.context; | ||
1850 | if (hndl->dm.hprev == hndl) | ||
1851 | goto exitunltgt; | ||
1852 | |||
1853 | /* target-side dllview record is in list */ | ||
1854 | /* dequeue this record from our GPP-side mirror list */ | ||
1855 | hndl->dm.hprev->dm.hnext = hndl->dm.hnext; | ||
1856 | if (hndl->dm.hnext) | ||
1857 | hndl->dm.hnext->dm.hprev = hndl->dm.hprev; | ||
1858 | /* Update next_module of previous entry in target list | ||
1859 | * We are using mhdr here as a surrogate for either a | ||
1860 | struct modules_header or a dll_module */ | ||
1861 | if (hndl->dm.hnext) { | ||
1862 | mhdr.first_module = TADDR_TO_TDATA(hndl->dm.hnext->dm.dbthis); | ||
1863 | mhdr.first_module_size = hndl->dm.hnext->dm.dbsiz; | ||
1864 | } else { | ||
1865 | mhdr.first_module = 0; | ||
1866 | mhdr.first_module_size = 0; | ||
1867 | } | ||
1868 | if (!init) | ||
1869 | goto exitunltgt; | ||
1870 | |||
1871 | if (!init->connect(init)) { | ||
1872 | dload_syms_error(syms, iconnect); | ||
1873 | errcount += 1; | ||
1874 | goto exitunltgt; | ||
1875 | } | ||
1876 | /* swap bytes in the module header, if needed */ | ||
1877 | if (TARGET_ENDIANNESS_DIFFERS(hndl->secn_count & 0x1)) { | ||
1878 | swap_words(&mhdr, sizeof(struct modules_header) - sizeof(u16), | ||
1879 | MODULES_HEADER_BITMAP); | ||
1880 | } | ||
1881 | if (!init->writemem(init, &mhdr, hndl->dm.hprev->dm.dbthis, | ||
1882 | &dllview_info, sizeof(struct modules_header) - | ||
1883 | sizeof(mhdr.update_flag))) { | ||
1884 | dload_syms_error(syms, dlvwrite); | ||
1885 | errcount += 1; | ||
1886 | } | ||
1887 | /* update change counter */ | ||
1888 | root->changes += 1; | ||
1889 | if (!init->writemem(init, &(root->changes), | ||
1890 | root->dbthis + HOST_TO_TADDR | ||
1891 | (sizeof(mhdr.first_module) + | ||
1892 | sizeof(mhdr.first_module_size)), | ||
1893 | &dllview_info, sizeof(mhdr.update_flag))) { | ||
1894 | dload_syms_error(syms, dlvwrite); | ||
1895 | errcount += 1; | ||
1896 | } | ||
1897 | init->release(init); | ||
1898 | exitunltgt: | ||
1899 | /* release target storage */ | ||
1900 | dllview_info.size = TDATA_TO_TADDR(hndl->dm.dbsiz); | ||
1901 | dllview_info.load_addr = hndl->dm.dbthis; | ||
1902 | if (alloc) | ||
1903 | alloc->dload_deallocate(alloc, &dllview_info); | ||
1904 | root->refcount -= 1; | ||
1905 | /* target-side dllview record exists */ | ||
1906 | loop_end: | ||
1907 | #ifndef DEBUG_HEADER_IN_LOADER | ||
1908 | if (root->refcount <= 0) { | ||
1909 | /* if all references gone, blow off the header */ | ||
1910 | /* our root symbol may be gone due to the Purge above, | ||
1911 | but if not, do not destroy the root */ | ||
1912 | if (syms->find_matching_symbol | ||
1913 | (syms, loader_dllview_root) == NULL) | ||
1914 | syms->dload_deallocate(syms, root); | ||
1915 | } | ||
1916 | #endif | ||
1917 | func_end: | ||
1918 | /* there is a debug list containing this module */ | ||
1919 | syms->dload_deallocate(syms, mhandle); /* release our storage */ | ||
1920 | return errcount; | ||
1921 | } /* dynamic_unload_module */ | ||
1922 | |||
1923 | #if BITS_PER_AU > BITS_PER_BYTE | ||
1924 | /************************************************************************* | ||
1925 | * Procedure unpack_name | ||
1926 | * | ||
1927 | * Parameters: | ||
1928 | * soffset Byte offset into the string table | ||
1929 | * | ||
1930 | * Effect: | ||
1931 | * Returns a pointer to the string specified by the offset supplied, or | ||
1932 | * NULL for error. | ||
1933 | * | ||
1934 | *********************************************************************** */ | ||
1935 | static char *unpack_name(struct dload_state *dlthis, u32 soffset) | ||
1936 | { | ||
1937 | u8 tmp, *src; | ||
1938 | char *dst; | ||
1939 | |||
1940 | if (soffset >= dlthis->dfile_hdr.df_strtab_size) { | ||
1941 | dload_error(dlthis, "Bad string table offset " FMT_UI32, | ||
1942 | soffset); | ||
1943 | return NULL; | ||
1944 | } | ||
1945 | src = (uint_least8_t *) dlthis->str_head + | ||
1946 | (soffset >> (LOG_BITS_PER_AU - LOG_BITS_PER_BYTE)); | ||
1947 | dst = dlthis->str_temp; | ||
1948 | if (soffset & 1) | ||
1949 | *dst++ = *src++; /* only 1 character in first word */ | ||
1950 | do { | ||
1951 | tmp = *src++; | ||
1952 | *dst = (tmp >> BITS_PER_BYTE); | ||
1953 | if (!(*dst++)) | ||
1954 | break; | ||
1955 | } while ((*dst++ = tmp & BYTE_MASK)); | ||
1956 | dlthis->temp_len = dst - dlthis->str_temp; | ||
1957 | /* squirrel away length including terminating null */ | ||
1958 | return dlthis->str_temp; | ||
1959 | } /* unpack_name */ | ||
1960 | #endif | ||
diff --git a/drivers/staging/tidspbridge/dynload/dload_internal.h b/drivers/staging/tidspbridge/dynload/dload_internal.h new file mode 100644 index 00000000000..803756198bc --- /dev/null +++ b/drivers/staging/tidspbridge/dynload/dload_internal.h | |||
@@ -0,0 +1,351 @@ | |||
1 | /* | ||
2 | * dload_internal.h | ||
3 | * | ||
4 | * DSP-BIOS Bridge driver support functions for TI OMAP processors. | ||
5 | * | ||
6 | * Copyright (C) 2005-2006 Texas Instruments, Inc. | ||
7 | * | ||
8 | * This package is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR | ||
13 | * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED | ||
14 | * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. | ||
15 | */ | ||
16 | |||
17 | #ifndef _DLOAD_INTERNAL_ | ||
18 | #define _DLOAD_INTERNAL_ | ||
19 | |||
20 | #include <linux/types.h> | ||
21 | |||
22 | /* | ||
23 | * Internal state definitions for the dynamic loader | ||
24 | */ | ||
25 | |||
26 | #define TRUE 1 | ||
27 | #define FALSE 0 | ||
28 | |||
29 | /* type used for relocation intermediate results */ | ||
30 | typedef s32 rvalue; | ||
31 | |||
32 | /* unsigned version of same; must have at least as many bits */ | ||
33 | typedef u32 urvalue; | ||
34 | |||
35 | /* | ||
36 | * Dynamic loader configuration constants | ||
37 | */ | ||
38 | /* error issued if input has more sections than this limit */ | ||
39 | #define REASONABLE_SECTION_LIMIT 100 | ||
40 | |||
41 | /* (Addressable unit) value used to clear BSS section */ | ||
42 | #define DLOAD_FILL_BSS 0 | ||
43 | |||
44 | /* | ||
45 | * Reorder maps explained (?) | ||
46 | * | ||
47 | * The doff file format defines a 32-bit pattern used to determine the | ||
48 | * byte order of an image being read. That value is | ||
49 | * BYTE_RESHUFFLE_VALUE == 0x00010203 | ||
50 | * For purposes of the reorder routine, we would rather have the all-is-OK | ||
51 | * for 32-bits pattern be 0x03020100. This first macro makes the | ||
52 | * translation from doff file header value to MAP value: */ | ||
53 | #define REORDER_MAP(rawmap) ((rawmap) ^ 0x3030303) | ||
54 | /* This translation is made in dload_headers. Thereafter, the all-is-OK | ||
55 | * value for the maps stored in dlthis is REORDER_MAP(BYTE_RESHUFFLE_VALUE). | ||
56 | * But sadly, not all bits of the doff file are 32-bit integers. | ||
57 | * The notable exceptions are strings and image bits. | ||
58 | * Strings obey host byte order: */ | ||
59 | #if defined(_BIG_ENDIAN) | ||
60 | #define HOST_BYTE_ORDER(cookedmap) ((cookedmap) ^ 0x3030303) | ||
61 | #else | ||
62 | #define HOST_BYTE_ORDER(cookedmap) (cookedmap) | ||
63 | #endif | ||
64 | /* Target bits consist of target AUs (could be bytes, or 16-bits, | ||
65 | * or 32-bits) stored as an array in host order. A target order | ||
66 | * map is defined by: */ | ||
67 | #if !defined(_BIG_ENDIAN) || TARGET_AU_BITS > 16 | ||
68 | #define TARGET_ORDER(cookedmap) (cookedmap) | ||
69 | #elif TARGET_AU_BITS > 8 | ||
70 | #define TARGET_ORDER(cookedmap) ((cookedmap) ^ 0x2020202) | ||
71 | #else | ||
72 | #define TARGET_ORDER(cookedmap) ((cookedmap) ^ 0x3030303) | ||
73 | #endif | ||
74 | |||
75 | /* forward declaration for handle returned by dynamic loader */ | ||
76 | struct my_handle; | ||
77 | |||
78 | /* | ||
79 | * a list of module handles, which mirrors the debug list on the target | ||
80 | */ | ||
81 | struct dbg_mirror_root { | ||
82 | /* must be same as dbg_mirror_list; __DLModules address on target */ | ||
83 | u32 dbthis; | ||
84 | struct my_handle *hnext; /* must be same as dbg_mirror_list */ | ||
85 | u16 changes; /* change counter */ | ||
86 | u16 refcount; /* number of modules referencing this root */ | ||
87 | }; | ||
88 | |||
89 | struct dbg_mirror_list { | ||
90 | u32 dbthis; | ||
91 | struct my_handle *hnext, *hprev; | ||
92 | struct dbg_mirror_root *hroot; | ||
93 | u16 dbsiz; | ||
94 | u32 context; /* Save context for .dllview memory allocation */ | ||
95 | }; | ||
96 | |||
97 | #define VARIABLE_SIZE 1 | ||
98 | /* | ||
99 | * the structure we actually return as an opaque module handle | ||
100 | */ | ||
101 | struct my_handle { | ||
102 | struct dbg_mirror_list dm; /* !!! must be first !!! */ | ||
103 | /* sections following << 1, LSB is set for big-endian target */ | ||
104 | u16 secn_count; | ||
105 | struct ldr_section_info secns[VARIABLE_SIZE]; | ||
106 | }; | ||
107 | #define MY_HANDLE_SIZE (sizeof(struct my_handle) -\ | ||
108 | sizeof(struct ldr_section_info)) | ||
109 | /* real size of my_handle */ | ||
110 | |||
111 | /* | ||
112 | * reduced symbol structure used for symbols during relocation | ||
113 | */ | ||
114 | struct local_symbol { | ||
115 | s32 value; /* Relocated symbol value */ | ||
116 | s32 delta; /* Original value in input file */ | ||
117 | s16 secnn; /* section number */ | ||
118 | s16 sclass; /* symbol class */ | ||
119 | }; | ||
120 | |||
121 | /* | ||
122 | * Trampoline data structures | ||
123 | */ | ||
124 | #define TRAMP_NO_GEN_AVAIL 65535 | ||
125 | #define TRAMP_SYM_PREFIX "__$dbTR__" | ||
126 | #define TRAMP_SECT_NAME ".dbTR" | ||
127 | /* MUST MATCH THE LENGTH ABOVE!! */ | ||
128 | #define TRAMP_SYM_PREFIX_LEN 9 | ||
129 | /* Includes NULL termination */ | ||
130 | #define TRAMP_SYM_HEX_ASCII_LEN 9 | ||
131 | |||
132 | #define GET_CONTAINER(ptr, type, field) ((type *)((unsigned long)ptr -\ | ||
133 | (unsigned long)(&((type *)0)->field))) | ||
134 | #ifndef FIELD_OFFSET | ||
135 | #define FIELD_OFFSET(type, field) ((unsigned long)(&((type *)0)->field)) | ||
136 | #endif | ||
137 | |||
138 | /* | ||
139 | The trampoline code for the target is located in a table called | ||
140 | "tramp_gen_info" with is indexed by looking up the index in the table | ||
141 | "tramp_map". The tramp_map index is acquired using the target | ||
142 | HASH_FUNC on the relocation type that caused the trampoline. Each | ||
143 | trampoline code table entry MUST follow this format: | ||
144 | |||
145 | |----------------------------------------------| | ||
146 | | tramp_gen_code_hdr | | ||
147 | |----------------------------------------------| | ||
148 | | Trampoline image code | | ||
149 | | (the raw instruction code for the target) | | ||
150 | |----------------------------------------------| | ||
151 | | Relocation entries for the image code | | ||
152 | |----------------------------------------------| | ||
153 | |||
154 | This is very similar to how image data is laid out in the DOFF file | ||
155 | itself. | ||
156 | */ | ||
157 | struct tramp_gen_code_hdr { | ||
158 | u32 tramp_code_size; /* in BYTES */ | ||
159 | u32 num_relos; | ||
160 | u32 relo_offset; /* in BYTES */ | ||
161 | }; | ||
162 | |||
163 | struct tramp_img_pkt { | ||
164 | struct tramp_img_pkt *next; /* MUST BE FIRST */ | ||
165 | u32 base; | ||
166 | struct tramp_gen_code_hdr hdr; | ||
167 | u8 payload[VARIABLE_SIZE]; | ||
168 | }; | ||
169 | |||
170 | struct tramp_img_dup_relo { | ||
171 | struct tramp_img_dup_relo *next; | ||
172 | struct reloc_record_t relo; | ||
173 | }; | ||
174 | |||
175 | struct tramp_img_dup_pkt { | ||
176 | struct tramp_img_dup_pkt *next; /* MUST BE FIRST */ | ||
177 | s16 secnn; | ||
178 | u32 offset; | ||
179 | struct image_packet_t img_pkt; | ||
180 | struct tramp_img_dup_relo *relo_chain; | ||
181 | |||
182 | /* PAYLOAD OF IMG PKT FOLLOWS */ | ||
183 | }; | ||
184 | |||
185 | struct tramp_sym { | ||
186 | struct tramp_sym *next; /* MUST BE FIRST */ | ||
187 | u32 index; | ||
188 | u32 str_index; | ||
189 | struct local_symbol sym_info; | ||
190 | }; | ||
191 | |||
192 | struct tramp_string { | ||
193 | struct tramp_string *next; /* MUST BE FIRST */ | ||
194 | u32 index; | ||
195 | char str[VARIABLE_SIZE]; /* NULL terminated */ | ||
196 | }; | ||
197 | |||
198 | struct tramp_info { | ||
199 | u32 tramp_sect_next_addr; | ||
200 | struct ldr_section_info sect_info; | ||
201 | |||
202 | struct tramp_sym *symbol_head; | ||
203 | struct tramp_sym *symbol_tail; | ||
204 | u32 tramp_sym_next_index; | ||
205 | struct local_symbol *final_sym_table; | ||
206 | |||
207 | struct tramp_string *string_head; | ||
208 | struct tramp_string *string_tail; | ||
209 | u32 tramp_string_next_index; | ||
210 | u32 tramp_string_size; | ||
211 | char *final_string_table; | ||
212 | |||
213 | struct tramp_img_pkt *tramp_pkts; | ||
214 | struct tramp_img_dup_pkt *dup_pkts; | ||
215 | }; | ||
216 | |||
217 | /* | ||
218 | * States of the .cinit state machine | ||
219 | */ | ||
220 | enum cinit_mode { | ||
221 | CI_COUNT = 0, /* expecting a count */ | ||
222 | CI_ADDRESS, /* expecting an address */ | ||
223 | #if CINIT_ALIGN < CINIT_ADDRESS /* handle case of partial address field */ | ||
224 | CI_PARTADDRESS, /* have only part of the address */ | ||
225 | #endif | ||
226 | CI_COPY, /* in the middle of copying data */ | ||
227 | CI_DONE /* end of .cinit table */ | ||
228 | }; | ||
229 | |||
230 | /* | ||
231 | * The internal state of the dynamic loader, which is passed around as | ||
232 | * an object | ||
233 | */ | ||
234 | struct dload_state { | ||
235 | struct dynamic_loader_stream *strm; /* The module input stream */ | ||
236 | struct dynamic_loader_sym *mysym; /* Symbols for this session */ | ||
237 | /* target memory allocator */ | ||
238 | struct dynamic_loader_allocate *myalloc; | ||
239 | struct dynamic_loader_initialize *myio; /* target memory initializer */ | ||
240 | unsigned myoptions; /* Options parameter dynamic_load_module */ | ||
241 | |||
242 | char *str_head; /* Pointer to string table */ | ||
243 | #if BITS_PER_AU > BITS_PER_BYTE | ||
244 | char *str_temp; /* Pointer to temporary buffer for strings */ | ||
245 | /* big enough to hold longest string */ | ||
246 | unsigned temp_len; /* length of last temporary string */ | ||
247 | char *xstrings; /* Pointer to buffer for expanded */ | ||
248 | /* strings for sec names */ | ||
249 | #endif | ||
250 | /* Total size of strings for DLLView section names */ | ||
251 | unsigned debug_string_size; | ||
252 | /* Pointer to parallel section info for allocated sections only */ | ||
253 | struct doff_scnhdr_t *sect_hdrs; /* Pointer to section table */ | ||
254 | struct ldr_section_info *ldr_sections; | ||
255 | #if TMS32060 | ||
256 | /* The address of the start of the .bss section */ | ||
257 | ldr_addr bss_run_base; | ||
258 | #endif | ||
259 | struct local_symbol *local_symtab; /* Relocation symbol table */ | ||
260 | |||
261 | /* pointer to DL section info for the section being relocated */ | ||
262 | struct ldr_section_info *image_secn; | ||
263 | /* change in run address for current section during relocation */ | ||
264 | ldr_addr delta_runaddr; | ||
265 | ldr_addr image_offset; /* offset of current packet in section */ | ||
266 | enum cinit_mode cinit_state; /* current state of cload_cinit() */ | ||
267 | int cinit_count; /* the current count */ | ||
268 | ldr_addr cinit_addr; /* the current address */ | ||
269 | s16 cinit_page; /* the current page */ | ||
270 | /* Handle to be returned by dynamic_load_module */ | ||
271 | struct my_handle *myhandle; | ||
272 | unsigned dload_errcount; /* Total # of errors reported so far */ | ||
273 | /* Number of target sections that require allocation and relocation */ | ||
274 | unsigned allocated_secn_count; | ||
275 | #ifndef TARGET_ENDIANNESS | ||
276 | int big_e_target; /* Target data in big-endian format */ | ||
277 | #endif | ||
278 | /* map for reordering bytes, 0 if not needed */ | ||
279 | u32 reorder_map; | ||
280 | struct doff_filehdr_t dfile_hdr; /* DOFF file header structure */ | ||
281 | struct doff_verify_rec_t verify; /* Verify record */ | ||
282 | |||
283 | struct tramp_info tramp; /* Trampoline data, if needed */ | ||
284 | |||
285 | int relstkidx; /* index into relocation value stack */ | ||
286 | /* relocation value stack used in relexp.c */ | ||
287 | rvalue relstk[STATIC_EXPR_STK_SIZE]; | ||
288 | |||
289 | }; | ||
290 | |||
291 | #ifdef TARGET_ENDIANNESS | ||
292 | #define TARGET_BIG_ENDIAN TARGET_ENDIANNESS | ||
293 | #else | ||
294 | #define TARGET_BIG_ENDIAN (dlthis->big_e_target) | ||
295 | #endif | ||
296 | |||
297 | /* | ||
298 | * Exports from cload.c to rest of the world | ||
299 | */ | ||
300 | extern void dload_error(struct dload_state *dlthis, const char *errtxt, ...); | ||
301 | extern void dload_syms_error(struct dynamic_loader_sym *syms, | ||
302 | const char *errtxt, ...); | ||
303 | extern void dload_headers(struct dload_state *dlthis); | ||
304 | extern void dload_strings(struct dload_state *dlthis, bool sec_names_only); | ||
305 | extern void dload_sections(struct dload_state *dlthis); | ||
306 | extern void dload_reorder(void *data, int dsiz, u32 map); | ||
307 | extern u32 dload_checksum(void *data, unsigned siz); | ||
308 | |||
309 | #if HOST_ENDIANNESS | ||
310 | extern uint32_t dload_reverse_checksum(void *data, unsigned siz); | ||
311 | #if (TARGET_AU_BITS > 8) && (TARGET_AU_BITS < 32) | ||
312 | extern uint32_t dload_reverse_checksum16(void *data, unsigned siz); | ||
313 | #endif | ||
314 | #endif | ||
315 | |||
316 | #define IS_DATA_SCN(zzz) (DLOAD_SECTION_TYPE((zzz)->type) != DLOAD_TEXT) | ||
317 | #define IS_DATA_SCN_NUM(zzz) \ | ||
318 | (DLOAD_SECT_TYPE(&dlthis->sect_hdrs[(zzz)-1]) != DLOAD_TEXT) | ||
319 | |||
320 | /* | ||
321 | * exported by reloc.c | ||
322 | */ | ||
323 | extern void dload_relocate(struct dload_state *dlthis, tgt_au_t * data, | ||
324 | struct reloc_record_t *rp, bool * tramps_generated, | ||
325 | bool second_pass); | ||
326 | |||
327 | extern rvalue dload_unpack(struct dload_state *dlthis, tgt_au_t * data, | ||
328 | int fieldsz, int offset, unsigned sgn); | ||
329 | |||
330 | extern int dload_repack(struct dload_state *dlthis, rvalue val, tgt_au_t * data, | ||
331 | int fieldsz, int offset, unsigned sgn); | ||
332 | |||
333 | /* | ||
334 | * exported by tramp.c | ||
335 | */ | ||
336 | extern bool dload_tramp_avail(struct dload_state *dlthis, | ||
337 | struct reloc_record_t *rp); | ||
338 | |||
339 | int dload_tramp_generate(struct dload_state *dlthis, s16 secnn, | ||
340 | u32 image_offset, struct image_packet_t *ipacket, | ||
341 | struct reloc_record_t *rp); | ||
342 | |||
343 | extern int dload_tramp_pkt_udpate(struct dload_state *dlthis, | ||
344 | s16 secnn, u32 image_offset, | ||
345 | struct image_packet_t *ipacket); | ||
346 | |||
347 | extern int dload_tramp_finalize(struct dload_state *dlthis); | ||
348 | |||
349 | extern void dload_tramp_cleanup(struct dload_state *dlthis); | ||
350 | |||
351 | #endif /* _DLOAD_INTERNAL_ */ | ||
diff --git a/drivers/staging/tidspbridge/dynload/doff.h b/drivers/staging/tidspbridge/dynload/doff.h new file mode 100644 index 00000000000..5bf99240f9f --- /dev/null +++ b/drivers/staging/tidspbridge/dynload/doff.h | |||
@@ -0,0 +1,344 @@ | |||
1 | /* | ||
2 | * doff.h | ||
3 | * | ||
4 | * DSP-BIOS Bridge driver support functions for TI OMAP processors. | ||
5 | * | ||
6 | * Structures & definitions used for dynamically loaded modules file format. | ||
7 | * This format is a reformatted version of COFF. It optimizes the layout for | ||
8 | * the dynamic loader. | ||
9 | * | ||
10 | * .dof files, when viewed as a sequence of 32-bit integers, look the same | ||
11 | * on big-endian and little-endian machines. | ||
12 | * | ||
13 | * Copyright (C) 2005-2006 Texas Instruments, Inc. | ||
14 | * | ||
15 | * This package is free software; you can redistribute it and/or modify | ||
16 | * it under the terms of the GNU General Public License version 2 as | ||
17 | * published by the Free Software Foundation. | ||
18 | * | ||
19 | * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR | ||
20 | * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED | ||
21 | * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. | ||
22 | */ | ||
23 | |||
24 | #ifndef _DOFF_H | ||
25 | #define _DOFF_H | ||
26 | |||
27 | #ifndef UINT32_C | ||
28 | #define UINT32_C(zzz) ((u32)zzz) | ||
29 | #endif | ||
30 | |||
31 | #define BYTE_RESHUFFLE_VALUE UINT32_C(0x00010203) | ||
32 | |||
33 | /* DOFF file header containing fields categorizing the remainder of the file */ | ||
34 | struct doff_filehdr_t { | ||
35 | |||
36 | /* string table size, including filename, in bytes */ | ||
37 | u32 df_strtab_size; | ||
38 | |||
39 | /* entry point if one exists */ | ||
40 | u32 df_entrypt; | ||
41 | |||
42 | /* identifies byte ordering of file; | ||
43 | * always set to BYTE_RESHUFFLE_VALUE */ | ||
44 | u32 df_byte_reshuffle; | ||
45 | |||
46 | /* Size of the string table up to and including the last section name */ | ||
47 | /* Size includes the name of the COFF file also */ | ||
48 | u32 df_scn_name_size; | ||
49 | |||
50 | #ifndef _BIG_ENDIAN | ||
51 | /* number of symbols */ | ||
52 | u16 df_no_syms; | ||
53 | |||
54 | /* length in bytes of the longest string, including terminating NULL */ | ||
55 | /* excludes the name of the file */ | ||
56 | u16 df_max_str_len; | ||
57 | |||
58 | /* total number of sections including no-load ones */ | ||
59 | u16 df_no_scns; | ||
60 | |||
61 | /* number of sections containing target code allocated or downloaded */ | ||
62 | u16 df_target_scns; | ||
63 | |||
64 | /* unique id for dll file format & version */ | ||
65 | u16 df_doff_version; | ||
66 | |||
67 | /* identifies ISA */ | ||
68 | u16 df_target_id; | ||
69 | |||
70 | /* useful file flags */ | ||
71 | u16 df_flags; | ||
72 | |||
73 | /* section reference for entry point, N_UNDEF for none, */ | ||
74 | /* N_ABS for absolute address */ | ||
75 | s16 df_entry_secn; | ||
76 | #else | ||
77 | /* length of the longest string, including terminating NULL */ | ||
78 | u16 df_max_str_len; | ||
79 | |||
80 | /* number of symbols */ | ||
81 | u16 df_no_syms; | ||
82 | |||
83 | /* number of sections containing target code allocated or downloaded */ | ||
84 | u16 df_target_scns; | ||
85 | |||
86 | /* total number of sections including no-load ones */ | ||
87 | u16 df_no_scns; | ||
88 | |||
89 | /* identifies ISA */ | ||
90 | u16 df_target_id; | ||
91 | |||
92 | /* unique id for dll file format & version */ | ||
93 | u16 df_doff_version; | ||
94 | |||
95 | /* section reference for entry point, N_UNDEF for none, */ | ||
96 | /* N_ABS for absolute address */ | ||
97 | s16 df_entry_secn; | ||
98 | |||
99 | /* useful file flags */ | ||
100 | u16 df_flags; | ||
101 | #endif | ||
102 | /* checksum for file header record */ | ||
103 | u32 df_checksum; | ||
104 | |||
105 | }; | ||
106 | |||
107 | /* flags in the df_flags field */ | ||
108 | #define DF_LITTLE 0x100 | ||
109 | #define DF_BIG 0x200 | ||
110 | #define DF_BYTE_ORDER (DF_LITTLE | DF_BIG) | ||
111 | |||
112 | /* Supported processors */ | ||
113 | #define TMS470_ID 0x97 | ||
114 | #define LEAD_ID 0x98 | ||
115 | #define TMS32060_ID 0x99 | ||
116 | #define LEAD3_ID 0x9c | ||
117 | |||
118 | /* Primary processor for loading */ | ||
119 | #if TMS32060 | ||
120 | #define TARGET_ID TMS32060_ID | ||
121 | #endif | ||
122 | |||
123 | /* Verification record containing values used to test integrity of the bits */ | ||
124 | struct doff_verify_rec_t { | ||
125 | |||
126 | /* time and date stamp */ | ||
127 | u32 dv_timdat; | ||
128 | |||
129 | /* checksum for all section records */ | ||
130 | u32 dv_scn_rec_checksum; | ||
131 | |||
132 | /* checksum for string table */ | ||
133 | u32 dv_str_tab_checksum; | ||
134 | |||
135 | /* checksum for symbol table */ | ||
136 | u32 dv_sym_tab_checksum; | ||
137 | |||
138 | /* checksum for verification record */ | ||
139 | u32 dv_verify_rec_checksum; | ||
140 | |||
141 | }; | ||
142 | |||
143 | /* String table is an array of null-terminated strings. The first entry is | ||
144 | * the filename, which is added by DLLcreate. No new structure definitions | ||
145 | * are required. | ||
146 | */ | ||
147 | |||
148 | /* Section Records including information on the corresponding image packets */ | ||
149 | /* | ||
150 | * !!WARNING!! | ||
151 | * | ||
152 | * This structure is expected to match in form ldr_section_info in | ||
153 | * dynamic_loader.h | ||
154 | */ | ||
155 | |||
156 | struct doff_scnhdr_t { | ||
157 | |||
158 | s32 ds_offset; /* offset into string table of name */ | ||
159 | s32 ds_paddr; /* RUN address, in target AU */ | ||
160 | s32 ds_vaddr; /* LOAD address, in target AU */ | ||
161 | s32 ds_size; /* section size, in target AU */ | ||
162 | #ifndef _BIG_ENDIAN | ||
163 | u16 ds_page; /* memory page id */ | ||
164 | u16 ds_flags; /* section flags */ | ||
165 | #else | ||
166 | u16 ds_flags; /* section flags */ | ||
167 | u16 ds_page; /* memory page id */ | ||
168 | #endif | ||
169 | u32 ds_first_pkt_offset; | ||
170 | /* Absolute byte offset into the file */ | ||
171 | /* where the first image record resides */ | ||
172 | |||
173 | s32 ds_nipacks; /* number of image packets */ | ||
174 | |||
175 | }; | ||
176 | |||
177 | /* Symbol table entry */ | ||
178 | struct doff_syment_t { | ||
179 | |||
180 | s32 dn_offset; /* offset into string table of name */ | ||
181 | s32 dn_value; /* value of symbol */ | ||
182 | #ifndef _BIG_ENDIAN | ||
183 | s16 dn_scnum; /* section number */ | ||
184 | s16 dn_sclass; /* storage class */ | ||
185 | #else | ||
186 | s16 dn_sclass; /* storage class */ | ||
187 | s16 dn_scnum; /* section number, 1-based */ | ||
188 | #endif | ||
189 | |||
190 | }; | ||
191 | |||
192 | /* special values for dn_scnum */ | ||
193 | #define DN_UNDEF 0 /* undefined symbol */ | ||
194 | #define DN_ABS (-1) /* value of symbol is absolute */ | ||
195 | /* special values for dn_sclass */ | ||
196 | #define DN_EXT 2 | ||
197 | #define DN_STATLAB 20 | ||
198 | #define DN_EXTLAB 21 | ||
199 | |||
200 | /* Default value of image bits in packet */ | ||
201 | /* Configurable by user on the command line */ | ||
202 | #define IMAGE_PACKET_SIZE 1024 | ||
203 | |||
204 | /* An image packet contains a chunk of data from a section along with */ | ||
205 | /* information necessary for its processing. */ | ||
206 | struct image_packet_t { | ||
207 | |||
208 | s32 num_relocs; /* number of relocations for */ | ||
209 | /* this packet */ | ||
210 | |||
211 | s32 packet_size; /* number of bytes in array */ | ||
212 | /* "bits" occupied by */ | ||
213 | /* valid data. Could be */ | ||
214 | /* < IMAGE_PACKET_SIZE to */ | ||
215 | /* prevent splitting a */ | ||
216 | /* relocation across packets. */ | ||
217 | /* Last packet of a section */ | ||
218 | /* will most likely contain */ | ||
219 | /* < IMAGE_PACKET_SIZE bytes */ | ||
220 | /* of valid data */ | ||
221 | |||
222 | s32 img_chksum; /* Checksum for image packet */ | ||
223 | /* and the corresponding */ | ||
224 | /* relocation records */ | ||
225 | |||
226 | u8 *img_data; /* Actual data in section */ | ||
227 | |||
228 | }; | ||
229 | |||
230 | /* The relocation structure definition matches the COFF version. Offsets */ | ||
231 | /* however are relative to the image packet base not the section base. */ | ||
232 | struct reloc_record_t { | ||
233 | |||
234 | s32 vaddr; | ||
235 | |||
236 | /* expressed in target AUs */ | ||
237 | |||
238 | union { | ||
239 | struct { | ||
240 | #ifndef _BIG_ENDIAN | ||
241 | u8 _offset; /* bit offset of rel fld */ | ||
242 | u8 _fieldsz; /* size of rel fld */ | ||
243 | u8 _wordsz; /* # bytes containing rel fld */ | ||
244 | u8 _dum1; | ||
245 | u16 _dum2; | ||
246 | u16 _type; | ||
247 | #else | ||
248 | unsigned _dum1:8; | ||
249 | unsigned _wordsz:8; /* # bytes containing rel fld */ | ||
250 | unsigned _fieldsz:8; /* size of rel fld */ | ||
251 | unsigned _offset:8; /* bit offset of rel fld */ | ||
252 | u16 _type; | ||
253 | u16 _dum2; | ||
254 | #endif | ||
255 | } _r_field; | ||
256 | |||
257 | struct { | ||
258 | u32 _spc; /* image packet relative PC */ | ||
259 | #ifndef _BIG_ENDIAN | ||
260 | u16 _dum; | ||
261 | u16 _type; /* relocation type */ | ||
262 | #else | ||
263 | u16 _type; /* relocation type */ | ||
264 | u16 _dum; | ||
265 | #endif | ||
266 | } _r_spc; | ||
267 | |||
268 | struct { | ||
269 | u32 _uval; /* constant value */ | ||
270 | #ifndef _BIG_ENDIAN | ||
271 | u16 _dum; | ||
272 | u16 _type; /* relocation type */ | ||
273 | #else | ||
274 | u16 _type; /* relocation type */ | ||
275 | u16 _dum; | ||
276 | #endif | ||
277 | } _r_uval; | ||
278 | |||
279 | struct { | ||
280 | s32 _symndx; /* 32-bit sym tbl index */ | ||
281 | #ifndef _BIG_ENDIAN | ||
282 | u16 _disp; /* extra addr encode data */ | ||
283 | u16 _type; /* relocation type */ | ||
284 | #else | ||
285 | u16 _type; /* relocation type */ | ||
286 | u16 _disp; /* extra addr encode data */ | ||
287 | #endif | ||
288 | } _r_sym; | ||
289 | } _u_reloc; | ||
290 | |||
291 | }; | ||
292 | |||
293 | /* abbreviations for convenience */ | ||
294 | #ifndef TYPE | ||
295 | #define TYPE _u_reloc._r_sym._type | ||
296 | #define UVAL _u_reloc._r_uval._uval | ||
297 | #define SYMNDX _u_reloc._r_sym._symndx | ||
298 | #define OFFSET _u_reloc._r_field._offset | ||
299 | #define FIELDSZ _u_reloc._r_field._fieldsz | ||
300 | #define WORDSZ _u_reloc._r_field._wordsz | ||
301 | #define R_DISP _u_reloc._r_sym._disp | ||
302 | #endif | ||
303 | |||
304 | /**************************************************************************** */ | ||
305 | /* */ | ||
306 | /* Important DOFF macros used for file processing */ | ||
307 | /* */ | ||
308 | /**************************************************************************** */ | ||
309 | |||
310 | /* DOFF Versions */ | ||
311 | #define DOFF0 0 | ||
312 | |||
313 | /* Return the address/size >= to addr that is at a 32-bit boundary */ | ||
314 | /* This assumes that a byte is 8 bits */ | ||
315 | #define DOFF_ALIGN(addr) (((addr) + 3) & ~UINT32_C(3)) | ||
316 | |||
317 | /**************************************************************************** */ | ||
318 | /* */ | ||
319 | /* The DOFF section header flags field is laid out as follows: */ | ||
320 | /* */ | ||
321 | /* Bits 0-3 : Section Type */ | ||
322 | /* Bit 4 : Set when section requires target memory to be allocated by DL */ | ||
323 | /* Bit 5 : Set when section requires downloading */ | ||
324 | /* Bits 8-11: Alignment, same as COFF */ | ||
325 | /* */ | ||
326 | /**************************************************************************** */ | ||
327 | |||
328 | /* Enum for DOFF section types (bits 0-3 of flag): See dynamic_loader.h */ | ||
329 | |||
330 | /* Macros to help processing of sections */ | ||
331 | #define DLOAD_SECT_TYPE(s_hdr) ((s_hdr)->ds_flags & 0xF) | ||
332 | |||
333 | /* DS_ALLOCATE indicates whether a section needs space on the target */ | ||
334 | #define DS_ALLOCATE_MASK 0x10 | ||
335 | #define DS_NEEDS_ALLOCATION(s_hdr) ((s_hdr)->ds_flags & DS_ALLOCATE_MASK) | ||
336 | |||
337 | /* DS_DOWNLOAD indicates that the loader needs to copy bits */ | ||
338 | #define DS_DOWNLOAD_MASK 0x20 | ||
339 | #define DS_NEEDS_DOWNLOAD(s_hdr) ((s_hdr)->ds_flags & DS_DOWNLOAD_MASK) | ||
340 | |||
341 | /* Section alignment requirement in AUs */ | ||
342 | #define DS_ALIGNMENT(ds_flags) (1 << (((ds_flags) >> 8) & 0xF)) | ||
343 | |||
344 | #endif /* _DOFF_H */ | ||
diff --git a/drivers/staging/tidspbridge/dynload/getsection.c b/drivers/staging/tidspbridge/dynload/getsection.c new file mode 100644 index 00000000000..029898fc091 --- /dev/null +++ b/drivers/staging/tidspbridge/dynload/getsection.c | |||
@@ -0,0 +1,416 @@ | |||
1 | /* | ||
2 | * getsection.c | ||
3 | * | ||
4 | * DSP-BIOS Bridge driver support functions for TI OMAP processors. | ||
5 | * | ||
6 | * Copyright (C) 2005-2006 Texas Instruments, Inc. | ||
7 | * | ||
8 | * This package is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR | ||
13 | * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED | ||
14 | * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. | ||
15 | */ | ||
16 | |||
17 | #include <dspbridge/getsection.h> | ||
18 | #include "header.h" | ||
19 | |||
20 | /* | ||
21 | * Error strings | ||
22 | */ | ||
23 | static const char readstrm[] = { "Error reading %s from input stream" }; | ||
24 | static const char seek[] = { "Set file position to %d failed" }; | ||
25 | static const char isiz[] = { "Bad image packet size %d" }; | ||
26 | static const char err_checksum[] = { "Checksum failed on %s" }; | ||
27 | |||
28 | static const char err_reloc[] = { "dload_get_section unable to read" | ||
29 | "sections containing relocation entries" | ||
30 | }; | ||
31 | |||
32 | #if BITS_PER_AU > BITS_PER_BYTE | ||
33 | static const char err_alloc[] = { "Syms->dload_allocate( %d ) failed" }; | ||
34 | static const char stbl[] = { "Bad string table offset " FMT_UI32 }; | ||
35 | #endif | ||
36 | |||
37 | /* | ||
38 | * we use the fact that DOFF section records are shaped just like | ||
39 | * ldr_section_info to reduce our section storage usage. These macros | ||
40 | * marks the places where that assumption is made | ||
41 | */ | ||
42 | #define DOFFSEC_IS_LDRSEC(pdoffsec) ((struct ldr_section_info *)(pdoffsec)) | ||
43 | #define LDRSEC_IS_DOFFSEC(ldrsec) ((struct doff_scnhdr_t *)(ldrsec)) | ||
44 | |||
45 | /************************************************************** */ | ||
46 | /********************* SUPPORT FUNCTIONS ********************** */ | ||
47 | /************************************************************** */ | ||
48 | |||
49 | #if BITS_PER_AU > BITS_PER_BYTE | ||
50 | /************************************************************************** | ||
51 | * Procedure unpack_sec_name | ||
52 | * | ||
53 | * Parameters: | ||
54 | * dlthis Handle from dload_module_open for this module | ||
55 | * soffset Byte offset into the string table | ||
56 | * dst Place to store the expanded string | ||
57 | * | ||
58 | * Effect: | ||
59 | * Stores a string from the string table into the destination, expanding | ||
60 | * it in the process. Returns a pointer just past the end of the stored | ||
61 | * string on success, or NULL on failure. | ||
62 | * | ||
63 | ************************************************************************ */ | ||
64 | static char *unpack_sec_name(struct dload_state *dlthis, u32 soffset, char *dst) | ||
65 | { | ||
66 | u8 tmp, *src; | ||
67 | |||
68 | if (soffset >= dlthis->dfile_hdr.df_scn_name_size) { | ||
69 | dload_error(dlthis, stbl, soffset); | ||
70 | return NULL; | ||
71 | } | ||
72 | src = (u8 *) dlthis->str_head + | ||
73 | (soffset >> (LOG_BITS_PER_AU - LOG_BITS_PER_BYTE)); | ||
74 | if (soffset & 1) | ||
75 | *dst++ = *src++; /* only 1 character in first word */ | ||
76 | do { | ||
77 | tmp = *src++; | ||
78 | *dst = (tmp >> BITS_PER_BYTE) | ||
79 | if (!(*dst++)) | ||
80 | break; | ||
81 | } while ((*dst++ = tmp & BYTE_MASK)); | ||
82 | |||
83 | return dst; | ||
84 | } | ||
85 | |||
86 | /************************************************************************** | ||
87 | * Procedure expand_sec_names | ||
88 | * | ||
89 | * Parameters: | ||
90 | * dlthis Handle from dload_module_open for this module | ||
91 | * | ||
92 | * Effect: | ||
93 | * Allocates a buffer, unpacks and copies strings from string table into it. | ||
94 | * Stores a pointer to the buffer into a state variable. | ||
95 | ************************************************************************* */ | ||
96 | static void expand_sec_names(struct dload_state *dlthis) | ||
97 | { | ||
98 | char *xstrings, *curr, *next; | ||
99 | u32 xsize; | ||
100 | u16 sec; | ||
101 | struct ldr_section_info *shp; | ||
102 | /* assume worst-case size requirement */ | ||
103 | xsize = dlthis->dfile_hdr.df_max_str_len * dlthis->dfile_hdr.df_no_scns; | ||
104 | xstrings = (char *)dlthis->mysym->dload_allocate(dlthis->mysym, xsize); | ||
105 | if (xstrings == NULL) { | ||
106 | dload_error(dlthis, err_alloc, xsize); | ||
107 | return; | ||
108 | } | ||
109 | dlthis->xstrings = xstrings; | ||
110 | /* For each sec, copy and expand its name */ | ||
111 | curr = xstrings; | ||
112 | for (sec = 0; sec < dlthis->dfile_hdr.df_no_scns; sec++) { | ||
113 | shp = DOFFSEC_IS_LDRSEC(&dlthis->sect_hdrs[sec]); | ||
114 | next = unpack_sec_name(dlthis, *(u32 *) &shp->name, curr); | ||
115 | if (next == NULL) | ||
116 | break; /* error */ | ||
117 | shp->name = curr; | ||
118 | curr = next; | ||
119 | } | ||
120 | } | ||
121 | |||
122 | #endif | ||
123 | |||
124 | /************************************************************** */ | ||
125 | /********************* EXPORTED FUNCTIONS ********************* */ | ||
126 | /************************************************************** */ | ||
127 | |||
128 | /************************************************************************** | ||
129 | * Procedure dload_module_open | ||
130 | * | ||
131 | * Parameters: | ||
132 | * module The input stream that supplies the module image | ||
133 | * syms Host-side malloc/free and error reporting functions. | ||
134 | * Other methods are unused. | ||
135 | * | ||
136 | * Effect: | ||
137 | * Reads header information from a dynamic loader module using the | ||
138 | specified | ||
139 | * stream object, and returns a handle for the module information. This | ||
140 | * handle may be used in subsequent query calls to obtain information | ||
141 | * contained in the module. | ||
142 | * | ||
143 | * Returns: | ||
144 | * NULL if an error is encountered, otherwise a module handle for use | ||
145 | * in subsequent operations. | ||
146 | ************************************************************************* */ | ||
147 | void *dload_module_open(struct dynamic_loader_stream *module, | ||
148 | struct dynamic_loader_sym *syms) | ||
149 | { | ||
150 | struct dload_state *dlthis; /* internal state for this call */ | ||
151 | unsigned *dp, sz; | ||
152 | u32 sec_start; | ||
153 | #if BITS_PER_AU <= BITS_PER_BYTE | ||
154 | u16 sec; | ||
155 | #endif | ||
156 | |||
157 | /* Check that mandatory arguments are present */ | ||
158 | if (!module || !syms) { | ||
159 | if (syms != NULL) | ||
160 | dload_syms_error(syms, "Required parameter is NULL"); | ||
161 | |||
162 | return NULL; | ||
163 | } | ||
164 | |||
165 | dlthis = (struct dload_state *) | ||
166 | syms->dload_allocate(syms, sizeof(struct dload_state)); | ||
167 | if (!dlthis) { | ||
168 | /* not enough storage */ | ||
169 | dload_syms_error(syms, "Can't allocate module info"); | ||
170 | return NULL; | ||
171 | } | ||
172 | |||
173 | /* clear our internal state */ | ||
174 | dp = (unsigned *)dlthis; | ||
175 | for (sz = sizeof(struct dload_state) / sizeof(unsigned); | ||
176 | sz > 0; sz -= 1) | ||
177 | *dp++ = 0; | ||
178 | |||
179 | dlthis->strm = module; | ||
180 | dlthis->mysym = syms; | ||
181 | |||
182 | /* read in the doff image and store in our state variable */ | ||
183 | dload_headers(dlthis); | ||
184 | |||
185 | if (!dlthis->dload_errcount) | ||
186 | dload_strings(dlthis, true); | ||
187 | |||
188 | /* skip ahead past the unread portion of the string table */ | ||
189 | sec_start = sizeof(struct doff_filehdr_t) + | ||
190 | sizeof(struct doff_verify_rec_t) + | ||
191 | BYTE_TO_HOST(DOFF_ALIGN(dlthis->dfile_hdr.df_strtab_size)); | ||
192 | |||
193 | if (dlthis->strm->set_file_posn(dlthis->strm, sec_start) != 0) { | ||
194 | dload_error(dlthis, seek, sec_start); | ||
195 | return NULL; | ||
196 | } | ||
197 | |||
198 | if (!dlthis->dload_errcount) | ||
199 | dload_sections(dlthis); | ||
200 | |||
201 | if (dlthis->dload_errcount) { | ||
202 | dload_module_close(dlthis); /* errors, blow off our state */ | ||
203 | dlthis = NULL; | ||
204 | return NULL; | ||
205 | } | ||
206 | #if BITS_PER_AU > BITS_PER_BYTE | ||
207 | /* Expand all section names from the string table into the */ | ||
208 | /* state variable, and convert section names from a relative */ | ||
209 | /* string table offset to a pointers to the expanded string. */ | ||
210 | expand_sec_names(dlthis); | ||
211 | #else | ||
212 | /* Convert section names from a relative string table offset */ | ||
213 | /* to a pointer into the string table. */ | ||
214 | for (sec = 0; sec < dlthis->dfile_hdr.df_no_scns; sec++) { | ||
215 | struct ldr_section_info *shp = | ||
216 | DOFFSEC_IS_LDRSEC(&dlthis->sect_hdrs[sec]); | ||
217 | shp->name = dlthis->str_head + *(u32 *) &shp->name; | ||
218 | } | ||
219 | #endif | ||
220 | |||
221 | return dlthis; | ||
222 | } | ||
223 | |||
224 | /*************************************************************************** | ||
225 | * Procedure dload_get_section_info | ||
226 | * | ||
227 | * Parameters: | ||
228 | * minfo Handle from dload_module_open for this module | ||
229 | * sectionName Pointer to the string name of the section desired | ||
230 | * sectionInfo Address of a section info structure pointer to be | ||
231 | * initialized | ||
232 | * | ||
233 | * Effect: | ||
234 | * Finds the specified section in the module information, and initializes | ||
235 | * the provided struct ldr_section_info pointer. | ||
236 | * | ||
237 | * Returns: | ||
238 | * true for success, false for section not found | ||
239 | ************************************************************************* */ | ||
240 | int dload_get_section_info(void *minfo, const char *sectionName, | ||
241 | const struct ldr_section_info **const sectionInfo) | ||
242 | { | ||
243 | struct dload_state *dlthis; | ||
244 | struct ldr_section_info *shp; | ||
245 | u16 sec; | ||
246 | |||
247 | dlthis = (struct dload_state *)minfo; | ||
248 | if (!dlthis) | ||
249 | return false; | ||
250 | |||
251 | for (sec = 0; sec < dlthis->dfile_hdr.df_no_scns; sec++) { | ||
252 | shp = DOFFSEC_IS_LDRSEC(&dlthis->sect_hdrs[sec]); | ||
253 | if (strcmp(sectionName, shp->name) == 0) { | ||
254 | *sectionInfo = shp; | ||
255 | return true; | ||
256 | } | ||
257 | } | ||
258 | |||
259 | return false; | ||
260 | } | ||
261 | |||
262 | #define IPH_SIZE (sizeof(struct image_packet_t) - sizeof(u32)) | ||
263 | #define REVERSE_REORDER_MAP(rawmap) ((rawmap) ^ 0x3030303) | ||
264 | |||
265 | /************************************************************************** | ||
266 | * Procedure dload_get_section | ||
267 | * | ||
268 | * Parameters: | ||
269 | * minfo Handle from dload_module_open for this module | ||
270 | * sectionInfo Pointer to a section info structure for the desired | ||
271 | * section | ||
272 | * sectionData Buffer to contain the section initialized data | ||
273 | * | ||
274 | * Effect: | ||
275 | * Copies the initialized data for the specified section into the | ||
276 | * supplied buffer. | ||
277 | * | ||
278 | * Returns: | ||
279 | * true for success, false for section not found | ||
280 | ************************************************************************* */ | ||
281 | int dload_get_section(void *minfo, | ||
282 | const struct ldr_section_info *sectionInfo, | ||
283 | void *sectionData) | ||
284 | { | ||
285 | struct dload_state *dlthis; | ||
286 | u32 pos; | ||
287 | struct doff_scnhdr_t *sptr = NULL; | ||
288 | s32 nip; | ||
289 | struct image_packet_t ipacket; | ||
290 | s32 ipsize; | ||
291 | u32 checks; | ||
292 | s8 *dest = (s8 *) sectionData; | ||
293 | |||
294 | dlthis = (struct dload_state *)minfo; | ||
295 | if (!dlthis) | ||
296 | return false; | ||
297 | sptr = LDRSEC_IS_DOFFSEC(sectionInfo); | ||
298 | if (sptr == NULL) | ||
299 | return false; | ||
300 | |||
301 | /* skip ahead to the start of the first packet */ | ||
302 | pos = BYTE_TO_HOST(DOFF_ALIGN((u32) sptr->ds_first_pkt_offset)); | ||
303 | if (dlthis->strm->set_file_posn(dlthis->strm, pos) != 0) { | ||
304 | dload_error(dlthis, seek, pos); | ||
305 | return false; | ||
306 | } | ||
307 | |||
308 | nip = sptr->ds_nipacks; | ||
309 | while ((nip -= 1) >= 0) { /* for each packet */ | ||
310 | /* get the fixed header bits */ | ||
311 | if (dlthis->strm->read_buffer(dlthis->strm, &ipacket, | ||
312 | IPH_SIZE) != IPH_SIZE) { | ||
313 | dload_error(dlthis, readstrm, "image packet"); | ||
314 | return false; | ||
315 | } | ||
316 | /* reorder the header if need be */ | ||
317 | if (dlthis->reorder_map) | ||
318 | dload_reorder(&ipacket, IPH_SIZE, dlthis->reorder_map); | ||
319 | |||
320 | /* Now read the packet image bits. Note: round the size up to | ||
321 | * the next multiple of 4 bytes; this is what checksum | ||
322 | * routines want. */ | ||
323 | ipsize = BYTE_TO_HOST(DOFF_ALIGN(ipacket.packet_size)); | ||
324 | if (ipsize > BYTE_TO_HOST(IMAGE_PACKET_SIZE)) { | ||
325 | dload_error(dlthis, isiz, ipsize); | ||
326 | return false; | ||
327 | } | ||
328 | if (dlthis->strm->read_buffer | ||
329 | (dlthis->strm, dest, ipsize) != ipsize) { | ||
330 | dload_error(dlthis, readstrm, "image packet"); | ||
331 | return false; | ||
332 | } | ||
333 | /* reorder the bytes if need be */ | ||
334 | #if !defined(_BIG_ENDIAN) || (TARGET_AU_BITS > 16) | ||
335 | if (dlthis->reorder_map) | ||
336 | dload_reorder(dest, ipsize, dlthis->reorder_map); | ||
337 | |||
338 | checks = dload_checksum(dest, ipsize); | ||
339 | #else | ||
340 | if (dlthis->dfile_hdr.df_byte_reshuffle != | ||
341 | TARGET_ORDER(REORDER_MAP(BYTE_RESHUFFLE_VALUE))) { | ||
342 | /* put image bytes in big-endian order, not PC order */ | ||
343 | dload_reorder(dest, ipsize, | ||
344 | TARGET_ORDER(dlthis-> | ||
345 | dfile_hdr.df_byte_reshuffle)); | ||
346 | } | ||
347 | #if TARGET_AU_BITS > 8 | ||
348 | checks = dload_reverse_checksum16(dest, ipsize); | ||
349 | #else | ||
350 | checks = dload_reverse_checksum(dest, ipsize); | ||
351 | #endif | ||
352 | #endif | ||
353 | checks += dload_checksum(&ipacket, IPH_SIZE); | ||
354 | |||
355 | /* NYI: unable to handle relocation entries here. Reloc | ||
356 | * entries referring to fields that span the packet boundaries | ||
357 | * may result in packets of sizes that are not multiple of | ||
358 | * 4 bytes. Our checksum implementation works on 32-bit words | ||
359 | * only. */ | ||
360 | if (ipacket.num_relocs != 0) { | ||
361 | dload_error(dlthis, err_reloc, ipsize); | ||
362 | return false; | ||
363 | } | ||
364 | |||
365 | if (~checks) { | ||
366 | dload_error(dlthis, err_checksum, "image packet"); | ||
367 | return false; | ||
368 | } | ||
369 | |||
370 | /*Advance destination ptr by the size of the just-read packet */ | ||
371 | dest += ipsize; | ||
372 | } | ||
373 | |||
374 | return true; | ||
375 | } | ||
376 | |||
377 | /*************************************************************************** | ||
378 | * Procedure dload_module_close | ||
379 | * | ||
380 | * Parameters: | ||
381 | * minfo Handle from dload_module_open for this module | ||
382 | * | ||
383 | * Effect: | ||
384 | * Releases any storage associated with the module handle. On return, | ||
385 | * the module handle is invalid. | ||
386 | * | ||
387 | * Returns: | ||
388 | * Zero for success. On error, the number of errors detected is returned. | ||
389 | * Individual errors are reported using syms->error_report(), where syms was | ||
390 | * an argument to dload_module_open | ||
391 | ************************************************************************* */ | ||
392 | void dload_module_close(void *minfo) | ||
393 | { | ||
394 | struct dload_state *dlthis; | ||
395 | |||
396 | dlthis = (struct dload_state *)minfo; | ||
397 | if (!dlthis) | ||
398 | return; | ||
399 | |||
400 | if (dlthis->str_head) | ||
401 | dlthis->mysym->dload_deallocate(dlthis->mysym, | ||
402 | dlthis->str_head); | ||
403 | |||
404 | if (dlthis->sect_hdrs) | ||
405 | dlthis->mysym->dload_deallocate(dlthis->mysym, | ||
406 | dlthis->sect_hdrs); | ||
407 | |||
408 | #if BITS_PER_AU > BITS_PER_BYTE | ||
409 | if (dlthis->xstrings) | ||
410 | dlthis->mysym->dload_deallocate(dlthis->mysym, | ||
411 | dlthis->xstrings); | ||
412 | |||
413 | #endif | ||
414 | |||
415 | dlthis->mysym->dload_deallocate(dlthis->mysym, dlthis); | ||
416 | } | ||
diff --git a/drivers/staging/tidspbridge/dynload/header.h b/drivers/staging/tidspbridge/dynload/header.h new file mode 100644 index 00000000000..5cef3600157 --- /dev/null +++ b/drivers/staging/tidspbridge/dynload/header.h | |||
@@ -0,0 +1,55 @@ | |||
1 | /* | ||
2 | * header.h | ||
3 | * | ||
4 | * DSP-BIOS Bridge driver support functions for TI OMAP processors. | ||
5 | * | ||
6 | * Copyright (C) 2005-2006 Texas Instruments, Inc. | ||
7 | * | ||
8 | * This package is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR | ||
13 | * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED | ||
14 | * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. | ||
15 | */ | ||
16 | |||
17 | #define TRUE 1 | ||
18 | #define FALSE 0 | ||
19 | #ifndef NULL | ||
20 | #define NULL 0 | ||
21 | #endif | ||
22 | |||
23 | #include <linux/string.h> | ||
24 | #define DL_STRCMP strcmp | ||
25 | |||
26 | /* maximum parenthesis nesting in relocation stack expressions */ | ||
27 | #define STATIC_EXPR_STK_SIZE 10 | ||
28 | |||
29 | #include <linux/types.h> | ||
30 | |||
31 | #include "doff.h" | ||
32 | #include <dspbridge/dynamic_loader.h> | ||
33 | #include "params.h" | ||
34 | #include "dload_internal.h" | ||
35 | #include "reloc_table.h" | ||
36 | |||
37 | /* | ||
38 | * Plausibility limits | ||
39 | * | ||
40 | * These limits are imposed upon the input DOFF file as a check for validity. | ||
41 | * They are hard limits, in that the load will fail if they are exceeded. | ||
42 | * The numbers selected are arbitrary, in that the loader implementation does | ||
43 | * not require these limits. | ||
44 | */ | ||
45 | |||
46 | /* maximum number of bytes in string table */ | ||
47 | #define MAX_REASONABLE_STRINGTAB (0x100000) | ||
48 | /* maximum number of code,data,etc. sections */ | ||
49 | #define MAX_REASONABLE_SECTIONS (200) | ||
50 | /* maximum number of linker symbols */ | ||
51 | #define MAX_REASONABLE_SYMBOLS (100000) | ||
52 | |||
53 | /* shift count to align F_BIG with DLOAD_LITTLE */ | ||
54 | #define ALIGN_COFF_ENDIANNESS 7 | ||
55 | #define ENDIANNESS_MASK (DF_BYTE_ORDER >> ALIGN_COFF_ENDIANNESS) | ||
diff --git a/drivers/staging/tidspbridge/dynload/module_list.h b/drivers/staging/tidspbridge/dynload/module_list.h new file mode 100644 index 00000000000..a216bb131a4 --- /dev/null +++ b/drivers/staging/tidspbridge/dynload/module_list.h | |||
@@ -0,0 +1,159 @@ | |||
1 | /* | ||
2 | * dspbridge/mpu_driver/src/dynload/module_list.h | ||
3 | * | ||
4 | * DSP-BIOS Bridge driver support functions for TI OMAP processors. | ||
5 | * | ||
6 | * Copyright (C) 2008 Texas Instruments, Inc. | ||
7 | * | ||
8 | * This package is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR | ||
13 | * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED | ||
14 | * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. | ||
15 | */ | ||
16 | |||
17 | /* | ||
18 | * This C header file gives the layout of the data structure created by the | ||
19 | * dynamic loader to describe the set of modules loaded into the DSP. | ||
20 | * | ||
21 | * Linked List Structure: | ||
22 | * ---------------------- | ||
23 | * The data structure defined here is a singly-linked list. The list | ||
24 | * represents the set of modules which are currently loaded in the DSP memory. | ||
25 | * The first entry in the list is a header record which contains a flag | ||
26 | * representing the state of the list. The rest of the entries in the list | ||
27 | * are module records. | ||
28 | * | ||
29 | * Global symbol _DLModules designates the first record in the list (i.e. the | ||
30 | * header record). This symbol must be defined in any program that wishes to | ||
31 | * use DLLview plug-in. | ||
32 | * | ||
33 | * String Representation: | ||
34 | * ---------------------- | ||
35 | * The string names of the module and its sections are stored in a block of | ||
36 | * memory which follows the module record itself. The strings are ordered: | ||
37 | * module name first, followed by section names in order from the first | ||
38 | * section to the last. String names are tightly packed arrays of 8-bit | ||
39 | * characters (two characters per 16-bit word on the C55x). Strings are | ||
40 | * zero-byte-terminated. | ||
41 | * | ||
42 | * Creating and updating the list: | ||
43 | * ------------------------------- | ||
44 | * Upon loading a new module into the DSP memory the dynamic loader inserts a | ||
45 | * new module record as the first module record in the list. The fields of | ||
46 | * this module record are initialized to reflect the properties of the module. | ||
47 | * The dynamic loader does NOT increment the flag/counter in the list's header | ||
48 | * record. | ||
49 | * | ||
50 | * Upon unloading a module from the DSP memory the dynamic loader removes the | ||
51 | * module's record from this list. The dynamic loader also increments the | ||
52 | * flag/counter in the list's header record to indicate that the list has been | ||
53 | * changed. | ||
54 | */ | ||
55 | |||
56 | #ifndef _MODULE_LIST_H_ | ||
57 | #define _MODULE_LIST_H_ | ||
58 | |||
59 | #include <linux/types.h> | ||
60 | |||
61 | /* Global pointer to the modules_header structure */ | ||
62 | #define MODULES_HEADER "_DLModules" | ||
63 | #define MODULES_HEADER_NO_UNDERSCORE "DLModules" | ||
64 | |||
65 | /* Initial version number */ | ||
66 | #define INIT_VERSION 1 | ||
67 | |||
68 | /* Verification number -- to be recorded in each module record */ | ||
69 | #define VERIFICATION 0x79 | ||
70 | |||
71 | /* forward declarations */ | ||
72 | struct dll_module; | ||
73 | struct dll_sect; | ||
74 | |||
75 | /* the first entry in the list is the modules_header record; | ||
76 | * its address is contained in the global _DLModules pointer */ | ||
77 | struct modules_header { | ||
78 | |||
79 | /* | ||
80 | * Address of the first dll_module record in the list or NULL. | ||
81 | * Note: for C55x this is a word address (C55x data is | ||
82 | * word-addressable) | ||
83 | */ | ||
84 | u32 first_module; | ||
85 | |||
86 | /* Combined storage size (in target addressable units) of the | ||
87 | * dll_module record which follows this header record, or zero | ||
88 | * if the list is empty. This size includes the module's string table. | ||
89 | * Note: for C55x the unit is a 16-bit word */ | ||
90 | u16 first_module_size; | ||
91 | |||
92 | /* Counter is incremented whenever a module record is removed from | ||
93 | * the list */ | ||
94 | u16 update_flag; | ||
95 | |||
96 | }; | ||
97 | |||
98 | /* for each 32-bits in above structure, a bitmap, LSB first, whose bits are: | ||
99 | * 0 => a 32-bit value, 1 => 2 16-bit values */ | ||
100 | /* swapping bitmap for type modules_header */ | ||
101 | #define MODULES_HEADER_BITMAP 0x2 | ||
102 | |||
103 | /* information recorded about each section in a module */ | ||
104 | struct dll_sect { | ||
105 | |||
106 | /* Load-time address of the section. | ||
107 | * Note: for C55x this is a byte address for program sections, and | ||
108 | * a word address for data sections. C55x program memory is | ||
109 | * byte-addressable, while data memory is word-addressable. */ | ||
110 | u32 sect_load_adr; | ||
111 | |||
112 | /* Run-time address of the section. | ||
113 | * Note 1: for C55x this is a byte address for program sections, and | ||
114 | * a word address for data sections. | ||
115 | * Note 2: for C55x two most significant bits of this field indicate | ||
116 | * the section type: '00' for a code section, '11' for a data section | ||
117 | * (C55 addresses are really only 24-bits wide). */ | ||
118 | u32 sect_run_adr; | ||
119 | |||
120 | }; | ||
121 | |||
122 | /* the rest of the entries in the list are module records */ | ||
123 | struct dll_module { | ||
124 | |||
125 | /* Address of the next dll_module record in the list, or 0 if this is | ||
126 | * the last record in the list. | ||
127 | * Note: for C55x this is a word address (C55x data is | ||
128 | * word-addressable) */ | ||
129 | u32 next_module; | ||
130 | |||
131 | /* Combined storage size (in target addressable units) of the | ||
132 | * dll_module record which follows this one, or zero if this is the | ||
133 | * last record in the list. This size includes the module's string | ||
134 | * table. | ||
135 | * Note: for C55x the unit is a 16-bit word. */ | ||
136 | u16 next_module_size; | ||
137 | |||
138 | /* version number of the tooling; set to INIT_VERSION for Phase 1 */ | ||
139 | u16 version; | ||
140 | |||
141 | /* the verification word; set to VERIFICATION */ | ||
142 | u16 verification; | ||
143 | |||
144 | /* Number of sections in the sects array */ | ||
145 | u16 num_sects; | ||
146 | |||
147 | /* Module's "unique" id; copy of the timestamp from the host | ||
148 | * COFF file */ | ||
149 | u32 timestamp; | ||
150 | |||
151 | /* Array of num_sects elements of the module's section records */ | ||
152 | struct dll_sect sects[1]; | ||
153 | }; | ||
154 | |||
155 | /* for each 32 bits in above structure, a bitmap, LSB first, whose bits are: | ||
156 | * 0 => a 32-bit value, 1 => 2 16-bit values */ | ||
157 | #define DLL_MODULE_BITMAP 0x6 /* swapping bitmap for type dll_module */ | ||
158 | |||
159 | #endif /* _MODULE_LIST_H_ */ | ||
diff --git a/drivers/staging/tidspbridge/dynload/params.h b/drivers/staging/tidspbridge/dynload/params.h new file mode 100644 index 00000000000..d797fcd3b66 --- /dev/null +++ b/drivers/staging/tidspbridge/dynload/params.h | |||
@@ -0,0 +1,226 @@ | |||
1 | /* | ||
2 | * params.h | ||
3 | * | ||
4 | * DSP-BIOS Bridge driver support functions for TI OMAP processors. | ||
5 | * | ||
6 | * This file defines host and target properties for all machines | ||
7 | * supported by the dynamic loader. To be tedious... | ||
8 | * | ||
9 | * host: the machine on which the dynamic loader runs | ||
10 | * target: the machine that the dynamic loader is loading | ||
11 | * | ||
12 | * Host and target may or may not be the same, depending upon the particular | ||
13 | * use. | ||
14 | * | ||
15 | * Copyright (C) 2005-2006 Texas Instruments, Inc. | ||
16 | * | ||
17 | * This package is free software; you can redistribute it and/or modify | ||
18 | * it under the terms of the GNU General Public License version 2 as | ||
19 | * published by the Free Software Foundation. | ||
20 | * | ||
21 | * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR | ||
22 | * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED | ||
23 | * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. | ||
24 | */ | ||
25 | |||
26 | /****************************************************************************** | ||
27 | * | ||
28 | * Host Properties | ||
29 | * | ||
30 | **************************************************************************** */ | ||
31 | |||
32 | #define BITS_PER_BYTE 8 /* bits in the standard PC/SUN byte */ | ||
33 | #define LOG_BITS_PER_BYTE 3 /* log base 2 of same */ | ||
34 | #define BYTE_MASK ((1U<<BITS_PER_BYTE)-1) | ||
35 | |||
36 | #if defined(__TMS320C55X__) || defined(_TMS320C5XX) | ||
37 | #define BITS_PER_AU 16 | ||
38 | #define LOG_BITS_PER_AU 4 | ||
39 | /* use this print string in error messages for uint32_t */ | ||
40 | #define FMT_UI32 "0x%lx" | ||
41 | #define FMT8_UI32 "%08lx" /* same but no 0x, fixed width field */ | ||
42 | #else | ||
43 | /* bits in the smallest addressable data storage unit */ | ||
44 | #define BITS_PER_AU 8 | ||
45 | /* log base 2 of the same; useful for shift counts */ | ||
46 | #define LOG_BITS_PER_AU 3 | ||
47 | #define FMT_UI32 "0x%x" | ||
48 | #define FMT8_UI32 "%08x" | ||
49 | #endif | ||
50 | |||
51 | /* generic fastest method for swapping bytes and shorts */ | ||
52 | #define SWAP32BY16(zz) (((zz) << 16) | ((zz) >> 16)) | ||
53 | #define SWAP16BY8(zz) (((zz) << 8) | ((zz) >> 8)) | ||
54 | |||
55 | /* !! don't be tempted to insert type definitions here; use <stdint.h> !! */ | ||
56 | |||
57 | /****************************************************************************** | ||
58 | * | ||
59 | * Target Properties | ||
60 | * | ||
61 | **************************************************************************** */ | ||
62 | |||
63 | /*-------------------------------------------------------------------------- */ | ||
64 | /* TMS320C6x Target Specific Parameters (byte-addressable) */ | ||
65 | /*-------------------------------------------------------------------------- */ | ||
66 | #if TMS32060 | ||
67 | #define MEMORG 0x0L /* Size of configured memory */ | ||
68 | #define MEMSIZE 0x0L /* (full address space) */ | ||
69 | |||
70 | #define CINIT_ALIGN 8 /* alignment of cinit record in TDATA AUs */ | ||
71 | #define CINIT_COUNT 4 /* width of count field in TDATA AUs */ | ||
72 | #define CINIT_ADDRESS 4 /* width of address field in TDATA AUs */ | ||
73 | #define CINIT_PAGE_BITS 0 /* Number of LSBs of address that | ||
74 | * are page number */ | ||
75 | |||
76 | #define LENIENT_SIGNED_RELEXPS 0 /* DOES SIGNED ALLOW MAX UNSIGNED */ | ||
77 | |||
78 | #undef TARGET_ENDIANNESS /* may be big or little endian */ | ||
79 | |||
80 | /* align a target address to a word boundary */ | ||
81 | #define TARGET_WORD_ALIGN(zz) (((zz) + 0x3) & -0x4) | ||
82 | #endif | ||
83 | |||
84 | /*-------------------------------------------------------------------------- | ||
85 | * | ||
86 | * DEFAULT SETTINGS and DERIVED PROPERTIES | ||
87 | * | ||
88 | * This section establishes defaults for values not specified above | ||
89 | *-------------------------------------------------------------------------- */ | ||
90 | #ifndef TARGET_AU_BITS | ||
91 | #define TARGET_AU_BITS 8 /* width of the target addressable unit */ | ||
92 | #define LOG_TARGET_AU_BITS 3 /* log2 of same */ | ||
93 | #endif | ||
94 | |||
95 | #ifndef CINIT_DEFAULT_PAGE | ||
96 | #define CINIT_DEFAULT_PAGE 0 /* default .cinit page number */ | ||
97 | #endif | ||
98 | |||
99 | #ifndef DATA_RUN2LOAD | ||
100 | #define DATA_RUN2LOAD(zz) (zz) /* translate data run address to load address */ | ||
101 | #endif | ||
102 | |||
103 | #ifndef DBG_LIST_PAGE | ||
104 | #define DBG_LIST_PAGE 0 /* page number for .dllview section */ | ||
105 | #endif | ||
106 | |||
107 | #ifndef TARGET_WORD_ALIGN | ||
108 | /* align a target address to a word boundary */ | ||
109 | #define TARGET_WORD_ALIGN(zz) (zz) | ||
110 | #endif | ||
111 | |||
112 | #ifndef TDATA_TO_TADDR | ||
113 | #define TDATA_TO_TADDR(zz) (zz) /* target data address to target AU address */ | ||
114 | #define TADDR_TO_TDATA(zz) (zz) /* target AU address to target data address */ | ||
115 | #define TDATA_AU_BITS TARGET_AU_BITS /* bits per data AU */ | ||
116 | #define LOG_TDATA_AU_BITS LOG_TARGET_AU_BITS | ||
117 | #endif | ||
118 | |||
119 | /* | ||
120 | * | ||
121 | * Useful properties and conversions derived from the above | ||
122 | * | ||
123 | */ | ||
124 | |||
125 | /* | ||
126 | * Conversions between host and target addresses | ||
127 | */ | ||
128 | #if LOG_BITS_PER_AU == LOG_TARGET_AU_BITS | ||
129 | /* translate target addressable unit to host address */ | ||
130 | #define TADDR_TO_HOST(x) (x) | ||
131 | /* translate host address to target addressable unit */ | ||
132 | #define HOST_TO_TADDR(x) (x) | ||
133 | #elif LOG_BITS_PER_AU > LOG_TARGET_AU_BITS | ||
134 | #define TADDR_TO_HOST(x) ((x) >> (LOG_BITS_PER_AU-LOG_TARGET_AU_BITS)) | ||
135 | #define HOST_TO_TADDR(x) ((x) << (LOG_BITS_PER_AU-LOG_TARGET_AU_BITS)) | ||
136 | #else | ||
137 | #define TADDR_TO_HOST(x) ((x) << (LOG_TARGET_AU_BITS-LOG_BITS_PER_AU)) | ||
138 | #define HOST_TO_TADDR(x) ((x) >> (LOG_TARGET_AU_BITS-LOG_BITS_PER_AU)) | ||
139 | #endif | ||
140 | |||
141 | #if LOG_BITS_PER_AU == LOG_TDATA_AU_BITS | ||
142 | /* translate target addressable unit to host address */ | ||
143 | #define TDATA_TO_HOST(x) (x) | ||
144 | /* translate host address to target addressable unit */ | ||
145 | #define HOST_TO_TDATA(x) (x) | ||
146 | /* translate host address to target addressable unit, round up */ | ||
147 | #define HOST_TO_TDATA_ROUND(x) (x) | ||
148 | /* byte offset to host offset, rounded up for TDATA size */ | ||
149 | #define BYTE_TO_HOST_TDATA_ROUND(x) BYTE_TO_HOST_ROUND(x) | ||
150 | #elif LOG_BITS_PER_AU > LOG_TDATA_AU_BITS | ||
151 | #define TDATA_TO_HOST(x) ((x) >> (LOG_BITS_PER_AU-LOG_TDATA_AU_BITS)) | ||
152 | #define HOST_TO_TDATA(x) ((x) << (LOG_BITS_PER_AU-LOG_TDATA_AU_BITS)) | ||
153 | #define HOST_TO_TDATA_ROUND(x) ((x) << (LOG_BITS_PER_AU-LOG_TDATA_AU_BITS)) | ||
154 | #define BYTE_TO_HOST_TDATA_ROUND(x) BYTE_TO_HOST_ROUND(x) | ||
155 | #else | ||
156 | #define TDATA_TO_HOST(x) ((x) << (LOG_TDATA_AU_BITS-LOG_BITS_PER_AU)) | ||
157 | #define HOST_TO_TDATA(x) ((x) >> (LOG_TDATA_AU_BITS-LOG_BITS_PER_AU)) | ||
158 | #define HOST_TO_TDATA_ROUND(x) (((x) +\ | ||
159 | (1<<(LOG_TDATA_AU_BITS-LOG_BITS_PER_AU))-1) >>\ | ||
160 | (LOG_TDATA_AU_BITS-LOG_BITS_PER_AU)) | ||
161 | #define BYTE_TO_HOST_TDATA_ROUND(x) (BYTE_TO_HOST((x) +\ | ||
162 | (1<<(LOG_TDATA_AU_BITS-LOG_BITS_PER_BYTE))-1) &\ | ||
163 | -(TDATA_AU_BITS/BITS_PER_AU)) | ||
164 | #endif | ||
165 | |||
166 | /* | ||
167 | * Input in DOFF format is always expresed in bytes, regardless of loading host | ||
168 | * so we wind up converting from bytes to target and host units even when the | ||
169 | * host is not a byte machine. | ||
170 | */ | ||
171 | #if LOG_BITS_PER_AU == LOG_BITS_PER_BYTE | ||
172 | #define BYTE_TO_HOST(x) (x) | ||
173 | #define BYTE_TO_HOST_ROUND(x) (x) | ||
174 | #define HOST_TO_BYTE(x) (x) | ||
175 | #elif LOG_BITS_PER_AU >= LOG_BITS_PER_BYTE | ||
176 | #define BYTE_TO_HOST(x) ((x) >> (LOG_BITS_PER_AU - LOG_BITS_PER_BYTE)) | ||
177 | #define BYTE_TO_HOST_ROUND(x) ((x + (BITS_PER_AU/BITS_PER_BYTE-1)) >>\ | ||
178 | (LOG_BITS_PER_AU - LOG_BITS_PER_BYTE)) | ||
179 | #define HOST_TO_BYTE(x) ((x) << (LOG_BITS_PER_AU - LOG_BITS_PER_BYTE)) | ||
180 | #else | ||
181 | /* lets not try to deal with sub-8-bit byte machines */ | ||
182 | #endif | ||
183 | |||
184 | #if LOG_TARGET_AU_BITS == LOG_BITS_PER_BYTE | ||
185 | /* translate target addressable unit to byte address */ | ||
186 | #define TADDR_TO_BYTE(x) (x) | ||
187 | /* translate byte address to target addressable unit */ | ||
188 | #define BYTE_TO_TADDR(x) (x) | ||
189 | #elif LOG_TARGET_AU_BITS > LOG_BITS_PER_BYTE | ||
190 | #define TADDR_TO_BYTE(x) ((x) << (LOG_TARGET_AU_BITS-LOG_BITS_PER_BYTE)) | ||
191 | #define BYTE_TO_TADDR(x) ((x) >> (LOG_TARGET_AU_BITS-LOG_BITS_PER_BYTE)) | ||
192 | #else | ||
193 | /* lets not try to deal with sub-8-bit byte machines */ | ||
194 | #endif | ||
195 | |||
196 | #ifdef _BIG_ENDIAN | ||
197 | #define HOST_ENDIANNESS 1 | ||
198 | #else | ||
199 | #define HOST_ENDIANNESS 0 | ||
200 | #endif | ||
201 | |||
202 | #ifdef TARGET_ENDIANNESS | ||
203 | #define TARGET_ENDIANNESS_DIFFERS(rtend) (HOST_ENDIANNESS^TARGET_ENDIANNESS) | ||
204 | #elif HOST_ENDIANNESS | ||
205 | #define TARGET_ENDIANNESS_DIFFERS(rtend) (!(rtend)) | ||
206 | #else | ||
207 | #define TARGET_ENDIANNESS_DIFFERS(rtend) (rtend) | ||
208 | #endif | ||
209 | |||
210 | /* the unit in which we process target image data */ | ||
211 | #if TARGET_AU_BITS <= 8 | ||
212 | typedef u8 tgt_au_t; | ||
213 | #elif TARGET_AU_BITS <= 16 | ||
214 | typedef u16 tgt_au_t; | ||
215 | #else | ||
216 | typedef u32 tgt_au_t; | ||
217 | #endif | ||
218 | |||
219 | /* size of that unit */ | ||
220 | #if TARGET_AU_BITS < BITS_PER_AU | ||
221 | #define TGTAU_BITS BITS_PER_AU | ||
222 | #define LOG_TGTAU_BITS LOG_BITS_PER_AU | ||
223 | #else | ||
224 | #define TGTAU_BITS TARGET_AU_BITS | ||
225 | #define LOG_TGTAU_BITS LOG_TARGET_AU_BITS | ||
226 | #endif | ||
diff --git a/drivers/staging/tidspbridge/dynload/reloc.c b/drivers/staging/tidspbridge/dynload/reloc.c new file mode 100644 index 00000000000..316a38c2a1f --- /dev/null +++ b/drivers/staging/tidspbridge/dynload/reloc.c | |||
@@ -0,0 +1,484 @@ | |||
1 | /* | ||
2 | * reloc.c | ||
3 | * | ||
4 | * DSP-BIOS Bridge driver support functions for TI OMAP processors. | ||
5 | * | ||
6 | * Copyright (C) 2005-2006 Texas Instruments, Inc. | ||
7 | * | ||
8 | * This package is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR | ||
13 | * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED | ||
14 | * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. | ||
15 | */ | ||
16 | |||
17 | #include "header.h" | ||
18 | |||
19 | #if TMS32060 | ||
20 | /* the magic symbol for the start of BSS */ | ||
21 | static const char bsssymbol[] = { ".bss" }; | ||
22 | #endif | ||
23 | |||
24 | #if TMS32060 | ||
25 | #include "reloc_table_c6000.c" | ||
26 | #endif | ||
27 | |||
28 | #if TMS32060 | ||
29 | /* From coff.h - ignore these relocation operations */ | ||
30 | #define R_C60ALIGN 0x76 /* C60: Alignment info for compressor */ | ||
31 | #define R_C60FPHEAD 0x77 /* C60: Explicit assembly directive */ | ||
32 | #define R_C60NOCMP 0x100 /* C60: Don't compress this code scn */ | ||
33 | #endif | ||
34 | |||
35 | /************************************************************************** | ||
36 | * Procedure dload_unpack | ||
37 | * | ||
38 | * Parameters: | ||
39 | * data pointer to storage unit containing lowest host address of | ||
40 | * image data | ||
41 | * fieldsz Size of bit field, 0 < fieldsz <= sizeof(rvalue)*BITS_PER_AU | ||
42 | * offset Offset from LSB, 0 <= offset < BITS_PER_AU | ||
43 | * sgn Signedness of the field (ROP_SGN, ROP_UNS, ROP_MAX, ROP_ANY) | ||
44 | * | ||
45 | * Effect: | ||
46 | * Extracts the specified field and returns it. | ||
47 | ************************************************************************* */ | ||
48 | rvalue dload_unpack(struct dload_state *dlthis, tgt_au_t * data, int fieldsz, | ||
49 | int offset, unsigned sgn) | ||
50 | { | ||
51 | register rvalue objval; | ||
52 | register int shift, direction; | ||
53 | register tgt_au_t *dp = data; | ||
54 | |||
55 | fieldsz -= 1; /* avoid nastiness with 32-bit shift of 32-bit value */ | ||
56 | /* * collect up enough bits to contain the desired field */ | ||
57 | if (TARGET_BIG_ENDIAN) { | ||
58 | dp += (fieldsz + offset) >> LOG_TGTAU_BITS; | ||
59 | direction = -1; | ||
60 | } else | ||
61 | direction = 1; | ||
62 | objval = *dp >> offset; | ||
63 | shift = TGTAU_BITS - offset; | ||
64 | while (shift <= fieldsz) { | ||
65 | dp += direction; | ||
66 | objval += (rvalue) *dp << shift; | ||
67 | shift += TGTAU_BITS; | ||
68 | } | ||
69 | |||
70 | /* * sign or zero extend the value appropriately */ | ||
71 | if (sgn == ROP_UNS) | ||
72 | objval &= (2 << fieldsz) - 1; | ||
73 | else { | ||
74 | shift = sizeof(rvalue) * BITS_PER_AU - 1 - fieldsz; | ||
75 | objval = (objval << shift) >> shift; | ||
76 | } | ||
77 | |||
78 | return objval; | ||
79 | |||
80 | } /* dload_unpack */ | ||
81 | |||
82 | /************************************************************************** | ||
83 | * Procedure dload_repack | ||
84 | * | ||
85 | * Parameters: | ||
86 | * val Value to insert | ||
87 | * data Pointer to storage unit containing lowest host address of | ||
88 | * image data | ||
89 | * fieldsz Size of bit field, 0 < fieldsz <= sizeof(rvalue)*BITS_PER_AU | ||
90 | * offset Offset from LSB, 0 <= offset < BITS_PER_AU | ||
91 | * sgn Signedness of the field (ROP_SGN, ROP_UNS, ROP_MAX, ROP_ANY) | ||
92 | * | ||
93 | * Effect: | ||
94 | * Stuffs the specified value in the specified field. Returns 0 for | ||
95 | * success | ||
96 | * or 1 if the value will not fit in the specified field according to the | ||
97 | * specified signedness rule. | ||
98 | ************************************************************************* */ | ||
99 | static const unsigned char ovf_limit[] = { 1, 2, 2 }; | ||
100 | |||
101 | int dload_repack(struct dload_state *dlthis, rvalue val, tgt_au_t * data, | ||
102 | int fieldsz, int offset, unsigned sgn) | ||
103 | { | ||
104 | register urvalue objval, mask; | ||
105 | register int shift, direction; | ||
106 | register tgt_au_t *dp = data; | ||
107 | |||
108 | fieldsz -= 1; /* avoid nastiness with 32-bit shift of 32-bit value */ | ||
109 | /* clip the bits */ | ||
110 | mask = ((UINT32_C(2) << fieldsz) - 1); | ||
111 | objval = (val & mask); | ||
112 | /* * store the bits through the specified mask */ | ||
113 | if (TARGET_BIG_ENDIAN) { | ||
114 | dp += (fieldsz + offset) >> LOG_TGTAU_BITS; | ||
115 | direction = -1; | ||
116 | } else | ||
117 | direction = 1; | ||
118 | |||
119 | /* insert LSBs */ | ||
120 | *dp = (*dp & ~(mask << offset)) + (objval << offset); | ||
121 | shift = TGTAU_BITS - offset; | ||
122 | /* align mask and objval with AU boundary */ | ||
123 | objval >>= shift; | ||
124 | mask >>= shift; | ||
125 | |||
126 | while (mask) { | ||
127 | dp += direction; | ||
128 | *dp = (*dp & ~mask) + objval; | ||
129 | objval >>= TGTAU_BITS; | ||
130 | mask >>= TGTAU_BITS; | ||
131 | } | ||
132 | |||
133 | /* | ||
134 | * check for overflow | ||
135 | */ | ||
136 | if (sgn) { | ||
137 | unsigned tmp = (val >> fieldsz) + (sgn & 0x1); | ||
138 | if (tmp > ovf_limit[sgn - 1]) | ||
139 | return 1; | ||
140 | } | ||
141 | return 0; | ||
142 | |||
143 | } /* dload_repack */ | ||
144 | |||
145 | /* lookup table for the scaling amount in a C6x instruction */ | ||
146 | #if TMS32060 | ||
147 | #define SCALE_BITS 4 /* there are 4 bits in the scale field */ | ||
148 | #define SCALE_MASK 0x7 /* we really only use the bottom 3 bits */ | ||
149 | static const u8 c60_scale[SCALE_MASK + 1] = { | ||
150 | 1, 0, 0, 0, 1, 1, 2, 2 | ||
151 | }; | ||
152 | #endif | ||
153 | |||
154 | /************************************************************************** | ||
155 | * Procedure dload_relocate | ||
156 | * | ||
157 | * Parameters: | ||
158 | * data Pointer to base of image data | ||
159 | * rp Pointer to relocation operation | ||
160 | * | ||
161 | * Effect: | ||
162 | * Performs the specified relocation operation | ||
163 | ************************************************************************* */ | ||
164 | void dload_relocate(struct dload_state *dlthis, tgt_au_t * data, | ||
165 | struct reloc_record_t *rp, bool * tramps_genereted, | ||
166 | bool second_pass) | ||
167 | { | ||
168 | rvalue val, reloc_amt, orig_val = 0; | ||
169 | unsigned int fieldsz = 0; | ||
170 | unsigned int offset = 0; | ||
171 | unsigned int reloc_info = 0; | ||
172 | unsigned int reloc_action = 0; | ||
173 | register int rx = 0; | ||
174 | rvalue *stackp = NULL; | ||
175 | int top; | ||
176 | struct local_symbol *svp = NULL; | ||
177 | #ifdef RFV_SCALE | ||
178 | unsigned int scale = 0; | ||
179 | #endif | ||
180 | struct image_packet_t *img_pkt = NULL; | ||
181 | |||
182 | /* The image packet data struct is only used during first pass | ||
183 | * relocation in the event that a trampoline is needed. 2nd pass | ||
184 | * relocation doesn't guarantee that data is coming from an | ||
185 | * image_packet_t structure. See cload.c, dload_data for how img_data is | ||
186 | * set. If that changes this needs to be updated!!! */ | ||
187 | if (second_pass == false) | ||
188 | img_pkt = (struct image_packet_t *)((u8 *) data - | ||
189 | sizeof(struct | ||
190 | image_packet_t)); | ||
191 | |||
192 | rx = HASH_FUNC(rp->TYPE); | ||
193 | while (rop_map1[rx] != rp->TYPE) { | ||
194 | rx = HASH_L(rop_map2[rx]); | ||
195 | if (rx < 0) { | ||
196 | #if TMS32060 | ||
197 | switch (rp->TYPE) { | ||
198 | case R_C60ALIGN: | ||
199 | case R_C60NOCMP: | ||
200 | case R_C60FPHEAD: | ||
201 | /* Ignore these reloc types and return */ | ||
202 | break; | ||
203 | default: | ||
204 | /* Unknown reloc type, print error and return */ | ||
205 | dload_error(dlthis, "Bad coff operator 0x%x", | ||
206 | rp->TYPE); | ||
207 | } | ||
208 | #else | ||
209 | dload_error(dlthis, "Bad coff operator 0x%x", rp->TYPE); | ||
210 | #endif | ||
211 | return; | ||
212 | } | ||
213 | } | ||
214 | rx = HASH_I(rop_map2[rx]); | ||
215 | if ((rx < (sizeof(rop_action) / sizeof(u16))) | ||
216 | && (rx < (sizeof(rop_info) / sizeof(u16))) && (rx > 0)) { | ||
217 | reloc_action = rop_action[rx]; | ||
218 | reloc_info = rop_info[rx]; | ||
219 | } else { | ||
220 | dload_error(dlthis, "Buffer Overflow - Array Index Out " | ||
221 | "of Bounds"); | ||
222 | } | ||
223 | |||
224 | /* Compute the relocation amount for the referenced symbol, if any */ | ||
225 | reloc_amt = rp->UVAL; | ||
226 | if (RFV_SYM(reloc_info)) { /* relocation uses a symbol reference */ | ||
227 | /* If this is first pass, use the module local symbol table, | ||
228 | * else use the trampoline symbol table. */ | ||
229 | if (second_pass == false) { | ||
230 | if ((u32) rp->SYMNDX < dlthis->dfile_hdr.df_no_syms) { | ||
231 | /* real symbol reference */ | ||
232 | svp = &dlthis->local_symtab[rp->SYMNDX]; | ||
233 | reloc_amt = (RFV_SYM(reloc_info) == ROP_SYMD) ? | ||
234 | svp->delta : svp->value; | ||
235 | } | ||
236 | /* reloc references current section */ | ||
237 | else if (rp->SYMNDX == -1) { | ||
238 | reloc_amt = (RFV_SYM(reloc_info) == ROP_SYMD) ? | ||
239 | dlthis->delta_runaddr : | ||
240 | dlthis->image_secn->run_addr; | ||
241 | } | ||
242 | } | ||
243 | } | ||
244 | /* relocation uses a symbol reference */ | ||
245 | /* Handle stack adjustment */ | ||
246 | val = 0; | ||
247 | top = RFV_STK(reloc_info); | ||
248 | if (top) { | ||
249 | top += dlthis->relstkidx - RSTK_UOP; | ||
250 | if (top >= STATIC_EXPR_STK_SIZE) { | ||
251 | dload_error(dlthis, | ||
252 | "Expression stack overflow in %s at offset " | ||
253 | FMT_UI32, dlthis->image_secn->name, | ||
254 | rp->vaddr + dlthis->image_offset); | ||
255 | return; | ||
256 | } | ||
257 | val = dlthis->relstk[dlthis->relstkidx]; | ||
258 | dlthis->relstkidx = top; | ||
259 | stackp = &dlthis->relstk[top]; | ||
260 | } | ||
261 | /* Derive field position and size, if we need them */ | ||
262 | if (reloc_info & ROP_RW) { /* read or write action in our future */ | ||
263 | fieldsz = RFV_WIDTH(reloc_action); | ||
264 | if (fieldsz) { /* field info from table */ | ||
265 | offset = RFV_POSN(reloc_action); | ||
266 | if (TARGET_BIG_ENDIAN) | ||
267 | /* make sure vaddr is the lowest target | ||
268 | * address containing bits */ | ||
269 | rp->vaddr += RFV_BIGOFF(reloc_info); | ||
270 | } else { /* field info from relocation op */ | ||
271 | fieldsz = rp->FIELDSZ; | ||
272 | offset = rp->OFFSET; | ||
273 | if (TARGET_BIG_ENDIAN) | ||
274 | /* make sure vaddr is the lowest target | ||
275 | address containing bits */ | ||
276 | rp->vaddr += (rp->WORDSZ - offset - fieldsz) | ||
277 | >> LOG_TARGET_AU_BITS; | ||
278 | } | ||
279 | data = (tgt_au_t *) ((char *)data + TADDR_TO_HOST(rp->vaddr)); | ||
280 | /* compute lowest host location of referenced data */ | ||
281 | #if BITS_PER_AU > TARGET_AU_BITS | ||
282 | /* conversion from target address to host address may lose | ||
283 | address bits; add loss to offset */ | ||
284 | if (TARGET_BIG_ENDIAN) { | ||
285 | offset += -((rp->vaddr << LOG_TARGET_AU_BITS) + | ||
286 | offset + fieldsz) & | ||
287 | (BITS_PER_AU - TARGET_AU_BITS); | ||
288 | } else { | ||
289 | offset += (rp->vaddr << LOG_TARGET_AU_BITS) & | ||
290 | (BITS_PER_AU - 1); | ||
291 | } | ||
292 | #endif | ||
293 | #ifdef RFV_SCALE | ||
294 | scale = RFV_SCALE(reloc_info); | ||
295 | #endif | ||
296 | } | ||
297 | /* read the object value from the current image, if so ordered */ | ||
298 | if (reloc_info & ROP_R) { | ||
299 | /* relocation reads current image value */ | ||
300 | val = dload_unpack(dlthis, data, fieldsz, offset, | ||
301 | RFV_SIGN(reloc_info)); | ||
302 | /* Save off the original value in case the relo overflows and | ||
303 | * we can trampoline it. */ | ||
304 | orig_val = val; | ||
305 | |||
306 | #ifdef RFV_SCALE | ||
307 | val <<= scale; | ||
308 | #endif | ||
309 | } | ||
310 | /* perform the necessary arithmetic */ | ||
311 | switch (RFV_ACTION(reloc_action)) { /* relocation actions */ | ||
312 | case RACT_VAL: | ||
313 | break; | ||
314 | case RACT_ASGN: | ||
315 | val = reloc_amt; | ||
316 | break; | ||
317 | case RACT_ADD: | ||
318 | val += reloc_amt; | ||
319 | break; | ||
320 | case RACT_PCR: | ||
321 | /*----------------------------------------------------------- | ||
322 | * Handle special cases of jumping from absolute sections | ||
323 | * (special reloc type) or to absolute destination | ||
324 | * (symndx == -1). In either case, set the appropriate | ||
325 | * relocation amount to 0. | ||
326 | *----------------------------------------------------------- */ | ||
327 | if (rp->SYMNDX == -1) | ||
328 | reloc_amt = 0; | ||
329 | val += reloc_amt - dlthis->delta_runaddr; | ||
330 | break; | ||
331 | case RACT_ADDISP: | ||
332 | val += rp->R_DISP + reloc_amt; | ||
333 | break; | ||
334 | case RACT_ASGPC: | ||
335 | val = dlthis->image_secn->run_addr + reloc_amt; | ||
336 | break; | ||
337 | case RACT_PLUS: | ||
338 | if (stackp != NULL) | ||
339 | val += *stackp; | ||
340 | break; | ||
341 | case RACT_SUB: | ||
342 | if (stackp != NULL) | ||
343 | val = *stackp - val; | ||
344 | break; | ||
345 | case RACT_NEG: | ||
346 | val = -val; | ||
347 | break; | ||
348 | case RACT_MPY: | ||
349 | if (stackp != NULL) | ||
350 | val *= *stackp; | ||
351 | break; | ||
352 | case RACT_DIV: | ||
353 | if (stackp != NULL) | ||
354 | val = *stackp / val; | ||
355 | break; | ||
356 | case RACT_MOD: | ||
357 | if (stackp != NULL) | ||
358 | val = *stackp % val; | ||
359 | break; | ||
360 | case RACT_SR: | ||
361 | if (val >= sizeof(rvalue) * BITS_PER_AU) | ||
362 | val = 0; | ||
363 | else if (stackp != NULL) | ||
364 | val = (urvalue) *stackp >> val; | ||
365 | break; | ||
366 | case RACT_ASR: | ||
367 | if (val >= sizeof(rvalue) * BITS_PER_AU) | ||
368 | val = sizeof(rvalue) * BITS_PER_AU - 1; | ||
369 | else if (stackp != NULL) | ||
370 | val = *stackp >> val; | ||
371 | break; | ||
372 | case RACT_SL: | ||
373 | if (val >= sizeof(rvalue) * BITS_PER_AU) | ||
374 | val = 0; | ||
375 | else if (stackp != NULL) | ||
376 | val = *stackp << val; | ||
377 | break; | ||
378 | case RACT_AND: | ||
379 | if (stackp != NULL) | ||
380 | val &= *stackp; | ||
381 | break; | ||
382 | case RACT_OR: | ||
383 | if (stackp != NULL) | ||
384 | val |= *stackp; | ||
385 | break; | ||
386 | case RACT_XOR: | ||
387 | if (stackp != NULL) | ||
388 | val ^= *stackp; | ||
389 | break; | ||
390 | case RACT_NOT: | ||
391 | val = ~val; | ||
392 | break; | ||
393 | #if TMS32060 | ||
394 | case RACT_C6SECT: | ||
395 | /* actually needed address of secn containing symbol */ | ||
396 | if (svp != NULL) { | ||
397 | if (rp->SYMNDX >= 0) | ||
398 | if (svp->secnn > 0) | ||
399 | reloc_amt = dlthis->ldr_sections | ||
400 | [svp->secnn - 1].run_addr; | ||
401 | } | ||
402 | /* !!! FALL THRU !!! */ | ||
403 | case RACT_C6BASE: | ||
404 | if (dlthis->bss_run_base == 0) { | ||
405 | struct dynload_symbol *symp; | ||
406 | symp = dlthis->mysym->find_matching_symbol | ||
407 | (dlthis->mysym, bsssymbol); | ||
408 | /* lookup value of global BSS base */ | ||
409 | if (symp) | ||
410 | dlthis->bss_run_base = symp->value; | ||
411 | else | ||
412 | dload_error(dlthis, | ||
413 | "Global BSS base referenced in %s " | ||
414 | "offset" FMT_UI32 " but not " | ||
415 | "defined", | ||
416 | dlthis->image_secn->name, | ||
417 | rp->vaddr + dlthis->image_offset); | ||
418 | } | ||
419 | reloc_amt -= dlthis->bss_run_base; | ||
420 | /* !!! FALL THRU !!! */ | ||
421 | case RACT_C6DSPL: | ||
422 | /* scale factor determined by 3 LSBs of field */ | ||
423 | scale = c60_scale[val & SCALE_MASK]; | ||
424 | offset += SCALE_BITS; | ||
425 | fieldsz -= SCALE_BITS; | ||
426 | val >>= SCALE_BITS; /* ignore the scale field hereafter */ | ||
427 | val <<= scale; | ||
428 | val += reloc_amt; /* do the usual relocation */ | ||
429 | if (((1 << scale) - 1) & val) | ||
430 | dload_error(dlthis, | ||
431 | "Unaligned reference in %s offset " | ||
432 | FMT_UI32, dlthis->image_secn->name, | ||
433 | rp->vaddr + dlthis->image_offset); | ||
434 | break; | ||
435 | #endif | ||
436 | } /* relocation actions */ | ||
437 | /* * Put back result as required */ | ||
438 | if (reloc_info & ROP_W) { /* relocation writes image value */ | ||
439 | #ifdef RFV_SCALE | ||
440 | val >>= scale; | ||
441 | #endif | ||
442 | if (dload_repack(dlthis, val, data, fieldsz, offset, | ||
443 | RFV_SIGN(reloc_info))) { | ||
444 | /* Check to see if this relo can be trampolined, | ||
445 | * but only in first phase relocation. 2nd phase | ||
446 | * relocation cannot trampoline. */ | ||
447 | if ((second_pass == false) && | ||
448 | (dload_tramp_avail(dlthis, rp) == true)) { | ||
449 | |||
450 | /* Before generating the trampoline, restore | ||
451 | * the value to its original so the 2nd pass | ||
452 | * relo will work. */ | ||
453 | dload_repack(dlthis, orig_val, data, fieldsz, | ||
454 | offset, RFV_SIGN(reloc_info)); | ||
455 | if (!dload_tramp_generate(dlthis, | ||
456 | (dlthis->image_secn - | ||
457 | dlthis->ldr_sections), | ||
458 | dlthis->image_offset, | ||
459 | img_pkt, rp)) { | ||
460 | dload_error(dlthis, | ||
461 | "Failed to " | ||
462 | "generate trampoline for " | ||
463 | "bit overflow"); | ||
464 | dload_error(dlthis, | ||
465 | "Relocation val " FMT_UI32 | ||
466 | " overflows %d bits in %s " | ||
467 | "offset " FMT_UI32, val, | ||
468 | fieldsz, | ||
469 | dlthis->image_secn->name, | ||
470 | dlthis->image_offset + | ||
471 | rp->vaddr); | ||
472 | } else | ||
473 | *tramps_genereted = true; | ||
474 | } else { | ||
475 | dload_error(dlthis, "Relocation value " | ||
476 | FMT_UI32 " overflows %d bits in %s" | ||
477 | " offset " FMT_UI32, val, fieldsz, | ||
478 | dlthis->image_secn->name, | ||
479 | dlthis->image_offset + rp->vaddr); | ||
480 | } | ||
481 | } | ||
482 | } else if (top) | ||
483 | *stackp = val; | ||
484 | } /* reloc_value */ | ||
diff --git a/drivers/staging/tidspbridge/dynload/reloc_table.h b/drivers/staging/tidspbridge/dynload/reloc_table.h new file mode 100644 index 00000000000..6aab03d4668 --- /dev/null +++ b/drivers/staging/tidspbridge/dynload/reloc_table.h | |||
@@ -0,0 +1,102 @@ | |||
1 | /* | ||
2 | * reloc_table.h | ||
3 | * | ||
4 | * DSP-BIOS Bridge driver support functions for TI OMAP processors. | ||
5 | * | ||
6 | * Copyright (C) 2005-2006 Texas Instruments, Inc. | ||
7 | * | ||
8 | * This package is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR | ||
13 | * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED | ||
14 | * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. | ||
15 | */ | ||
16 | |||
17 | #ifndef _RELOC_TABLE_H_ | ||
18 | #define _RELOC_TABLE_H_ | ||
19 | /* | ||
20 | * Table of relocation operator properties | ||
21 | */ | ||
22 | #include <linux/types.h> | ||
23 | |||
24 | /* How does this relocation operation access the program image? */ | ||
25 | #define ROP_N 0 /* does not access image */ | ||
26 | #define ROP_R 1 /* read from image */ | ||
27 | #define ROP_W 2 /* write to image */ | ||
28 | #define ROP_RW 3 /* read from and write to image */ | ||
29 | |||
30 | /* For program image access, what are the overflow rules for the bit field? */ | ||
31 | /* Beware! Procedure repack depends on this encoding */ | ||
32 | #define ROP_ANY 0 /* no overflow ever, just truncate the value */ | ||
33 | #define ROP_SGN 1 /* signed field */ | ||
34 | #define ROP_UNS 2 /* unsigned field */ | ||
35 | #define ROP_MAX 3 /* allow maximum range of either signed or unsigned */ | ||
36 | |||
37 | /* How does the relocation operation use the symbol reference */ | ||
38 | #define ROP_IGN 0 /* no symbol is referenced */ | ||
39 | #define ROP_LIT 0 /* use rp->UVAL literal field */ | ||
40 | #define ROP_SYM 1 /* symbol value is used in relocation */ | ||
41 | #define ROP_SYMD 2 /* delta value vs last link is used */ | ||
42 | |||
43 | /* How does the reloc op use the stack? */ | ||
44 | #define RSTK_N 0 /* Does not use */ | ||
45 | #define RSTK_POP 1 /* Does a POP */ | ||
46 | #define RSTK_UOP 2 /* Unary op, stack position unaffected */ | ||
47 | #define RSTK_PSH 3 /* Does a push */ | ||
48 | |||
49 | /* | ||
50 | * Computational actions performed by the dynamic loader | ||
51 | */ | ||
52 | enum dload_actions { | ||
53 | /* don't alter the current val (from stack or mem fetch) */ | ||
54 | RACT_VAL, | ||
55 | /* set value to reference amount (from symbol reference) */ | ||
56 | RACT_ASGN, | ||
57 | RACT_ADD, /* add reference to value */ | ||
58 | RACT_PCR, /* add reference minus PC delta to value */ | ||
59 | RACT_ADDISP, /* add reference plus R_DISP */ | ||
60 | RACT_ASGPC, /* set value to section addr plus reference */ | ||
61 | |||
62 | RACT_PLUS, /* stack + */ | ||
63 | RACT_SUB, /* stack - */ | ||
64 | RACT_NEG, /* stack unary - */ | ||
65 | |||
66 | RACT_MPY, /* stack * */ | ||
67 | RACT_DIV, /* stack / */ | ||
68 | RACT_MOD, /* stack % */ | ||
69 | |||
70 | RACT_SR, /* stack unsigned >> */ | ||
71 | RACT_ASR, /* stack signed >> */ | ||
72 | RACT_SL, /* stack << */ | ||
73 | RACT_AND, /* stack & */ | ||
74 | RACT_OR, /* stack | */ | ||
75 | RACT_XOR, /* stack ^ */ | ||
76 | RACT_NOT, /* stack ~ */ | ||
77 | RACT_C6SECT, /* for C60 R_SECT op */ | ||
78 | RACT_C6BASE, /* for C60 R_BASE op */ | ||
79 | RACT_C6DSPL, /* for C60 scaled 15-bit displacement */ | ||
80 | RACT_PCR23T /* for ARM Thumb long branch */ | ||
81 | }; | ||
82 | |||
83 | /* | ||
84 | * macros used to extract values | ||
85 | */ | ||
86 | #define RFV_POSN(aaa) ((aaa) & 0xF) | ||
87 | #define RFV_WIDTH(aaa) (((aaa) >> 4) & 0x3F) | ||
88 | #define RFV_ACTION(aaa) ((aaa) >> 10) | ||
89 | |||
90 | #define RFV_SIGN(iii) (((iii) >> 2) & 0x3) | ||
91 | #define RFV_SYM(iii) (((iii) >> 4) & 0x3) | ||
92 | #define RFV_STK(iii) (((iii) >> 6) & 0x3) | ||
93 | #define RFV_ACCS(iii) ((iii) & 0x3) | ||
94 | |||
95 | #if (TMS32060) | ||
96 | #define RFV_SCALE(iii) ((iii) >> 11) | ||
97 | #define RFV_BIGOFF(iii) (((iii) >> 8) & 0x7) | ||
98 | #else | ||
99 | #define RFV_BIGOFF(iii) ((iii) >> 8) | ||
100 | #endif | ||
101 | |||
102 | #endif /* _RELOC_TABLE_H_ */ | ||
diff --git a/drivers/staging/tidspbridge/dynload/reloc_table_c6000.c b/drivers/staging/tidspbridge/dynload/reloc_table_c6000.c new file mode 100644 index 00000000000..8ae3b38f398 --- /dev/null +++ b/drivers/staging/tidspbridge/dynload/reloc_table_c6000.c | |||
@@ -0,0 +1,257 @@ | |||
1 | /* | ||
2 | * reloc_table_c6000.c | ||
3 | * | ||
4 | * DSP-BIOS Bridge driver support functions for TI OMAP processors. | ||
5 | * | ||
6 | * Copyright (C) 2005-2006 Texas Instruments, Inc. | ||
7 | * | ||
8 | * This package is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR | ||
13 | * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED | ||
14 | * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. | ||
15 | */ | ||
16 | |||
17 | /* Tables generated for c6000 */ | ||
18 | |||
19 | #define HASH_FUNC(zz) (((((zz) + 1) * UINT32_C(1845)) >> 11) & 63) | ||
20 | #define HASH_L(zz) ((zz) >> 8) | ||
21 | #define HASH_I(zz) ((zz) & 0xFF) | ||
22 | |||
23 | static const u16 rop_map1[] = { | ||
24 | 0, | ||
25 | 1, | ||
26 | 2, | ||
27 | 20, | ||
28 | 4, | ||
29 | 5, | ||
30 | 6, | ||
31 | 15, | ||
32 | 80, | ||
33 | 81, | ||
34 | 82, | ||
35 | 83, | ||
36 | 84, | ||
37 | 85, | ||
38 | 86, | ||
39 | 87, | ||
40 | 17, | ||
41 | 18, | ||
42 | 19, | ||
43 | 21, | ||
44 | 16, | ||
45 | 16394, | ||
46 | 16404, | ||
47 | 65535, | ||
48 | 65535, | ||
49 | 65535, | ||
50 | 65535, | ||
51 | 65535, | ||
52 | 65535, | ||
53 | 32, | ||
54 | 65535, | ||
55 | 65535, | ||
56 | 65535, | ||
57 | 65535, | ||
58 | 65535, | ||
59 | 65535, | ||
60 | 40, | ||
61 | 112, | ||
62 | 113, | ||
63 | 65535, | ||
64 | 16384, | ||
65 | 16385, | ||
66 | 16386, | ||
67 | 16387, | ||
68 | 16388, | ||
69 | 16389, | ||
70 | 16390, | ||
71 | 16391, | ||
72 | 16392, | ||
73 | 16393, | ||
74 | 16395, | ||
75 | 16396, | ||
76 | 16397, | ||
77 | 16398, | ||
78 | 16399, | ||
79 | 16400, | ||
80 | 16401, | ||
81 | 16402, | ||
82 | 16403, | ||
83 | 16405, | ||
84 | 16406, | ||
85 | 65535, | ||
86 | 65535, | ||
87 | 65535 | ||
88 | }; | ||
89 | |||
90 | static const s16 rop_map2[] = { | ||
91 | -256, | ||
92 | -255, | ||
93 | -254, | ||
94 | -245, | ||
95 | -253, | ||
96 | -252, | ||
97 | -251, | ||
98 | -250, | ||
99 | -241, | ||
100 | -240, | ||
101 | -239, | ||
102 | -238, | ||
103 | -237, | ||
104 | -236, | ||
105 | 1813, | ||
106 | 5142, | ||
107 | -248, | ||
108 | -247, | ||
109 | 778, | ||
110 | -244, | ||
111 | -249, | ||
112 | -221, | ||
113 | -211, | ||
114 | -1, | ||
115 | -1, | ||
116 | -1, | ||
117 | -1, | ||
118 | -1, | ||
119 | -1, | ||
120 | -243, | ||
121 | -1, | ||
122 | -1, | ||
123 | -1, | ||
124 | -1, | ||
125 | -1, | ||
126 | -1, | ||
127 | -242, | ||
128 | -233, | ||
129 | -232, | ||
130 | -1, | ||
131 | -231, | ||
132 | -230, | ||
133 | -229, | ||
134 | -228, | ||
135 | -227, | ||
136 | -226, | ||
137 | -225, | ||
138 | -224, | ||
139 | -223, | ||
140 | 5410, | ||
141 | -220, | ||
142 | -219, | ||
143 | -218, | ||
144 | -217, | ||
145 | -216, | ||
146 | -215, | ||
147 | -214, | ||
148 | -213, | ||
149 | 5676, | ||
150 | -210, | ||
151 | -209, | ||
152 | -1, | ||
153 | -1, | ||
154 | -1 | ||
155 | }; | ||
156 | |||
157 | static const u16 rop_action[] = { | ||
158 | 2560, | ||
159 | 2304, | ||
160 | 2304, | ||
161 | 2432, | ||
162 | 2432, | ||
163 | 2560, | ||
164 | 2176, | ||
165 | 2304, | ||
166 | 2560, | ||
167 | 3200, | ||
168 | 3328, | ||
169 | 3584, | ||
170 | 3456, | ||
171 | 2304, | ||
172 | 4208, | ||
173 | 20788, | ||
174 | 21812, | ||
175 | 3415, | ||
176 | 3245, | ||
177 | 2311, | ||
178 | 4359, | ||
179 | 19764, | ||
180 | 2311, | ||
181 | 3191, | ||
182 | 3280, | ||
183 | 6656, | ||
184 | 7680, | ||
185 | 8704, | ||
186 | 9728, | ||
187 | 10752, | ||
188 | 11776, | ||
189 | 12800, | ||
190 | 13824, | ||
191 | 14848, | ||
192 | 15872, | ||
193 | 16896, | ||
194 | 17920, | ||
195 | 18944, | ||
196 | 0, | ||
197 | 0, | ||
198 | 0, | ||
199 | 0, | ||
200 | 1536, | ||
201 | 1536, | ||
202 | 1536, | ||
203 | 5632, | ||
204 | 512, | ||
205 | 0 | ||
206 | }; | ||
207 | |||
208 | static const u16 rop_info[] = { | ||
209 | 0, | ||
210 | 35, | ||
211 | 35, | ||
212 | 35, | ||
213 | 35, | ||
214 | 35, | ||
215 | 35, | ||
216 | 35, | ||
217 | 35, | ||
218 | 39, | ||
219 | 39, | ||
220 | 39, | ||
221 | 39, | ||
222 | 35, | ||
223 | 34, | ||
224 | 283, | ||
225 | 299, | ||
226 | 4135, | ||
227 | 4391, | ||
228 | 291, | ||
229 | 33059, | ||
230 | 283, | ||
231 | 295, | ||
232 | 4647, | ||
233 | 4135, | ||
234 | 64, | ||
235 | 64, | ||
236 | 128, | ||
237 | 64, | ||
238 | 64, | ||
239 | 64, | ||
240 | 64, | ||
241 | 64, | ||
242 | 64, | ||
243 | 64, | ||
244 | 64, | ||
245 | 64, | ||
246 | 128, | ||
247 | 201, | ||
248 | 197, | ||
249 | 74, | ||
250 | 70, | ||
251 | 208, | ||
252 | 196, | ||
253 | 200, | ||
254 | 192, | ||
255 | 192, | ||
256 | 66 | ||
257 | }; | ||
diff --git a/drivers/staging/tidspbridge/dynload/tramp.c b/drivers/staging/tidspbridge/dynload/tramp.c new file mode 100644 index 00000000000..7b593fc2b69 --- /dev/null +++ b/drivers/staging/tidspbridge/dynload/tramp.c | |||
@@ -0,0 +1,1143 @@ | |||
1 | /* | ||
2 | * tramp.c | ||
3 | * | ||
4 | * DSP-BIOS Bridge driver support functions for TI OMAP processors. | ||
5 | * | ||
6 | * Copyright (C) 2009 Texas Instruments, Inc. | ||
7 | * | ||
8 | * This package is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR | ||
13 | * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED | ||
14 | * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. | ||
15 | */ | ||
16 | |||
17 | #include "header.h" | ||
18 | |||
19 | #if TMS32060 | ||
20 | #include "tramp_table_c6000.c" | ||
21 | #endif | ||
22 | |||
23 | #define MAX_RELOS_PER_PASS 4 | ||
24 | |||
25 | /* | ||
26 | * Function: priv_tramp_sect_tgt_alloc | ||
27 | * Description: Allocate target memory for the trampoline section. The | ||
28 | * target mem size is easily obtained as the next available address. | ||
29 | */ | ||
30 | static int priv_tramp_sect_tgt_alloc(struct dload_state *dlthis) | ||
31 | { | ||
32 | int ret_val = 0; | ||
33 | struct ldr_section_info *sect_info; | ||
34 | |||
35 | /* Populate the trampoline loader section and allocate it on the | ||
36 | * target. The section name is ALWAYS the first string in the final | ||
37 | * string table for trampolines. The trampoline section is always | ||
38 | * 1 beyond the total number of allocated sections. */ | ||
39 | sect_info = &dlthis->ldr_sections[dlthis->allocated_secn_count]; | ||
40 | |||
41 | sect_info->name = dlthis->tramp.final_string_table; | ||
42 | sect_info->size = dlthis->tramp.tramp_sect_next_addr; | ||
43 | sect_info->context = 0; | ||
44 | sect_info->type = | ||
45 | (4 << 8) | DLOAD_TEXT | DS_ALLOCATE_MASK | DS_DOWNLOAD_MASK; | ||
46 | sect_info->page = 0; | ||
47 | sect_info->run_addr = 0; | ||
48 | sect_info->load_addr = 0; | ||
49 | ret_val = dlthis->myalloc->dload_allocate(dlthis->myalloc, | ||
50 | sect_info, | ||
51 | DS_ALIGNMENT | ||
52 | (sect_info->type)); | ||
53 | |||
54 | if (ret_val == 0) | ||
55 | dload_error(dlthis, "Failed to allocate target memory for" | ||
56 | " trampoline"); | ||
57 | |||
58 | return ret_val; | ||
59 | } | ||
60 | |||
61 | /* | ||
62 | * Function: priv_h2a | ||
63 | * Description: Helper function to convert a hex value to its ASCII | ||
64 | * representation. Used for trampoline symbol name generation. | ||
65 | */ | ||
66 | static u8 priv_h2a(u8 value) | ||
67 | { | ||
68 | if (value > 0xF) | ||
69 | return 0xFF; | ||
70 | |||
71 | if (value <= 9) | ||
72 | value += 0x30; | ||
73 | else | ||
74 | value += 0x37; | ||
75 | |||
76 | return value; | ||
77 | } | ||
78 | |||
79 | /* | ||
80 | * Function: priv_tramp_sym_gen_name | ||
81 | * Description: Generate a trampoline symbol name (ASCII) using the value | ||
82 | * of the symbol. This places the new name into the user buffer. | ||
83 | * The name is fixed in length and of the form: __$dbTR__xxxxxxxx | ||
84 | * (where "xxxxxxxx" is the hex value. | ||
85 | */ | ||
86 | static void priv_tramp_sym_gen_name(u32 value, char *dst) | ||
87 | { | ||
88 | u32 i; | ||
89 | volatile char *prefix = TRAMP_SYM_PREFIX; | ||
90 | volatile char *dst_local = dst; | ||
91 | u8 tmp; | ||
92 | |||
93 | /* Clear out the destination, including the ending NULL */ | ||
94 | for (i = 0; i < (TRAMP_SYM_PREFIX_LEN + TRAMP_SYM_HEX_ASCII_LEN); i++) | ||
95 | *(dst_local + i) = 0; | ||
96 | |||
97 | /* Copy the prefix to start */ | ||
98 | for (i = 0; i < strlen(TRAMP_SYM_PREFIX); i++) { | ||
99 | *dst_local = *(prefix + i); | ||
100 | dst_local++; | ||
101 | } | ||
102 | |||
103 | /* Now convert the value passed in to a string equiv of the hex */ | ||
104 | for (i = 0; i < sizeof(value); i++) { | ||
105 | #ifndef _BIG_ENDIAN | ||
106 | tmp = *(((u8 *) &value) + (sizeof(value) - 1) - i); | ||
107 | *dst_local = priv_h2a((tmp & 0xF0) >> 4); | ||
108 | dst_local++; | ||
109 | *dst_local = priv_h2a(tmp & 0x0F); | ||
110 | dst_local++; | ||
111 | #else | ||
112 | tmp = *(((u8 *) &value) + i); | ||
113 | *dst_local = priv_h2a((tmp & 0xF0) >> 4); | ||
114 | dst_local++; | ||
115 | *dst_local = priv_h2a(tmp & 0x0F); | ||
116 | dst_local++; | ||
117 | #endif | ||
118 | } | ||
119 | |||
120 | /* NULL terminate */ | ||
121 | *dst_local = 0; | ||
122 | } | ||
123 | |||
124 | /* | ||
125 | * Function: priv_tramp_string_create | ||
126 | * Description: Create a new string specific to the trampoline loading and add | ||
127 | * it to the trampoline string list. This list contains the | ||
128 | * trampoline section name and trampoline point symbols. | ||
129 | */ | ||
130 | static struct tramp_string *priv_tramp_string_create(struct dload_state *dlthis, | ||
131 | u32 str_len, char *str) | ||
132 | { | ||
133 | struct tramp_string *new_string = NULL; | ||
134 | u32 i; | ||
135 | |||
136 | /* Create a new string object with the specified size. */ | ||
137 | new_string = | ||
138 | (struct tramp_string *)dlthis->mysym->dload_allocate(dlthis->mysym, | ||
139 | (sizeof | ||
140 | (struct | ||
141 | tramp_string) | ||
142 | + str_len + | ||
143 | 1)); | ||
144 | if (new_string != NULL) { | ||
145 | /* Clear the string first. This ensures the ending NULL is | ||
146 | * present and the optimizer won't touch it. */ | ||
147 | for (i = 0; i < (sizeof(struct tramp_string) + str_len + 1); | ||
148 | i++) | ||
149 | *((u8 *) new_string + i) = 0; | ||
150 | |||
151 | /* Add this string to our virtual table by assigning it the | ||
152 | * next index and pushing it to the tail of the list. */ | ||
153 | new_string->index = dlthis->tramp.tramp_string_next_index; | ||
154 | dlthis->tramp.tramp_string_next_index++; | ||
155 | dlthis->tramp.tramp_string_size += str_len + 1; | ||
156 | |||
157 | new_string->next = NULL; | ||
158 | if (dlthis->tramp.string_head == NULL) | ||
159 | dlthis->tramp.string_head = new_string; | ||
160 | else | ||
161 | dlthis->tramp.string_tail->next = new_string; | ||
162 | |||
163 | dlthis->tramp.string_tail = new_string; | ||
164 | |||
165 | /* Copy the string over to the new object */ | ||
166 | for (i = 0; i < str_len; i++) | ||
167 | new_string->str[i] = str[i]; | ||
168 | } | ||
169 | |||
170 | return new_string; | ||
171 | } | ||
172 | |||
173 | /* | ||
174 | * Function: priv_tramp_string_find | ||
175 | * Description: Walk the trampoline string list and find a match for the | ||
176 | * provided string. If not match is found, NULL is returned. | ||
177 | */ | ||
178 | static struct tramp_string *priv_tramp_string_find(struct dload_state *dlthis, | ||
179 | char *str) | ||
180 | { | ||
181 | struct tramp_string *cur_str = NULL; | ||
182 | struct tramp_string *ret_val = NULL; | ||
183 | u32 i; | ||
184 | u32 str_len = strlen(str); | ||
185 | |||
186 | for (cur_str = dlthis->tramp.string_head; | ||
187 | (ret_val == NULL) && (cur_str != NULL); cur_str = cur_str->next) { | ||
188 | /* If the string lengths aren't equal, don't bother | ||
189 | * comparing */ | ||
190 | if (str_len != strlen(cur_str->str)) | ||
191 | continue; | ||
192 | |||
193 | /* Walk the strings until one of them ends */ | ||
194 | for (i = 0; i < str_len; i++) { | ||
195 | /* If they don't match in the current position then | ||
196 | * break out now, no sense in continuing to look at | ||
197 | * this string. */ | ||
198 | if (str[i] != cur_str->str[i]) | ||
199 | break; | ||
200 | } | ||
201 | |||
202 | if (i == str_len) | ||
203 | ret_val = cur_str; | ||
204 | } | ||
205 | |||
206 | return ret_val; | ||
207 | } | ||
208 | |||
209 | /* | ||
210 | * Function: priv_string_tbl_finalize | ||
211 | * Description: Flatten the trampoline string list into a table of NULL | ||
212 | * terminated strings. This is the same format of string table | ||
213 | * as used by the COFF/DOFF file. | ||
214 | */ | ||
215 | static int priv_string_tbl_finalize(struct dload_state *dlthis) | ||
216 | { | ||
217 | int ret_val = 0; | ||
218 | struct tramp_string *cur_string; | ||
219 | char *cur_loc; | ||
220 | char *tmp; | ||
221 | |||
222 | /* Allocate enough space for all strings that have been created. The | ||
223 | * table is simply all strings concatenated together will NULL | ||
224 | * endings. */ | ||
225 | dlthis->tramp.final_string_table = | ||
226 | (char *)dlthis->mysym->dload_allocate(dlthis->mysym, | ||
227 | dlthis->tramp. | ||
228 | tramp_string_size); | ||
229 | if (dlthis->tramp.final_string_table != NULL) { | ||
230 | /* We got our buffer, walk the list and release the nodes as* | ||
231 | * we go */ | ||
232 | cur_loc = dlthis->tramp.final_string_table; | ||
233 | cur_string = dlthis->tramp.string_head; | ||
234 | while (cur_string != NULL) { | ||
235 | /* Move the head/tail pointers */ | ||
236 | dlthis->tramp.string_head = cur_string->next; | ||
237 | if (dlthis->tramp.string_tail == cur_string) | ||
238 | dlthis->tramp.string_tail = NULL; | ||
239 | |||
240 | /* Copy the string contents */ | ||
241 | for (tmp = cur_string->str; | ||
242 | *tmp != '\0'; tmp++, cur_loc++) | ||
243 | *cur_loc = *tmp; | ||
244 | |||
245 | /* Pick up the NULL termination since it was missed by | ||
246 | * breaking using it to end the above loop. */ | ||
247 | *cur_loc = '\0'; | ||
248 | cur_loc++; | ||
249 | |||
250 | /* Free the string node, we don't need it any more. */ | ||
251 | dlthis->mysym->dload_deallocate(dlthis->mysym, | ||
252 | cur_string); | ||
253 | |||
254 | /* Move our pointer to the next one */ | ||
255 | cur_string = dlthis->tramp.string_head; | ||
256 | } | ||
257 | |||
258 | /* Update our return value to success */ | ||
259 | ret_val = 1; | ||
260 | } else | ||
261 | dload_error(dlthis, "Failed to allocate trampoline " | ||
262 | "string table"); | ||
263 | |||
264 | return ret_val; | ||
265 | } | ||
266 | |||
267 | /* | ||
268 | * Function: priv_tramp_sect_alloc | ||
269 | * Description: Virtually allocate space from the trampoline section. This | ||
270 | * function returns the next offset within the trampoline section | ||
271 | * that is available and moved the next available offset by the | ||
272 | * requested size. NO TARGET ALLOCATION IS DONE AT THIS TIME. | ||
273 | */ | ||
274 | static u32 priv_tramp_sect_alloc(struct dload_state *dlthis, u32 tramp_size) | ||
275 | { | ||
276 | u32 ret_val; | ||
277 | |||
278 | /* If the next available address is 0, this is our first allocation. | ||
279 | * Create a section name string to go into the string table . */ | ||
280 | if (dlthis->tramp.tramp_sect_next_addr == 0) { | ||
281 | dload_syms_error(dlthis->mysym, "*** WARNING *** created " | ||
282 | "dynamic TRAMPOLINE section for module %s", | ||
283 | dlthis->str_head); | ||
284 | } | ||
285 | |||
286 | /* Reserve space for the new trampoline */ | ||
287 | ret_val = dlthis->tramp.tramp_sect_next_addr; | ||
288 | dlthis->tramp.tramp_sect_next_addr += tramp_size; | ||
289 | return ret_val; | ||
290 | } | ||
291 | |||
292 | /* | ||
293 | * Function: priv_tramp_sym_create | ||
294 | * Description: Allocate and create a new trampoline specific symbol and add | ||
295 | * it to the trampoline symbol list. These symbols will include | ||
296 | * trampoline points as well as the external symbols they | ||
297 | * reference. | ||
298 | */ | ||
299 | static struct tramp_sym *priv_tramp_sym_create(struct dload_state *dlthis, | ||
300 | u32 str_index, | ||
301 | struct local_symbol *tmp_sym) | ||
302 | { | ||
303 | struct tramp_sym *new_sym = NULL; | ||
304 | u32 i; | ||
305 | |||
306 | /* Allocate new space for the symbol in the symbol table. */ | ||
307 | new_sym = | ||
308 | (struct tramp_sym *)dlthis->mysym->dload_allocate(dlthis->mysym, | ||
309 | sizeof(struct tramp_sym)); | ||
310 | if (new_sym != NULL) { | ||
311 | for (i = 0; i != sizeof(struct tramp_sym); i++) | ||
312 | *((char *)new_sym + i) = 0; | ||
313 | |||
314 | /* Assign this symbol the next symbol index for easier | ||
315 | * reference later during relocation. */ | ||
316 | new_sym->index = dlthis->tramp.tramp_sym_next_index; | ||
317 | dlthis->tramp.tramp_sym_next_index++; | ||
318 | |||
319 | /* Populate the symbol information. At this point any | ||
320 | * trampoline symbols will be the offset location, not the | ||
321 | * final. Copy over the symbol info to start, then be sure to | ||
322 | * get the string index from the trampoline string table. */ | ||
323 | new_sym->sym_info = *tmp_sym; | ||
324 | new_sym->str_index = str_index; | ||
325 | |||
326 | /* Push the new symbol to the tail of the symbol table list */ | ||
327 | new_sym->next = NULL; | ||
328 | if (dlthis->tramp.symbol_head == NULL) | ||
329 | dlthis->tramp.symbol_head = new_sym; | ||
330 | else | ||
331 | dlthis->tramp.symbol_tail->next = new_sym; | ||
332 | |||
333 | dlthis->tramp.symbol_tail = new_sym; | ||
334 | } | ||
335 | |||
336 | return new_sym; | ||
337 | } | ||
338 | |||
339 | /* | ||
340 | * Function: priv_tramp_sym_get | ||
341 | * Description: Search for the symbol with the matching string index (from | ||
342 | * the trampoline string table) and return the trampoline | ||
343 | * symbol object, if found. Otherwise return NULL. | ||
344 | */ | ||
345 | static struct tramp_sym *priv_tramp_sym_get(struct dload_state *dlthis, | ||
346 | u32 string_index) | ||
347 | { | ||
348 | struct tramp_sym *sym_found = NULL; | ||
349 | |||
350 | /* Walk the symbol table list and search vs. the string index */ | ||
351 | for (sym_found = dlthis->tramp.symbol_head; | ||
352 | sym_found != NULL; sym_found = sym_found->next) { | ||
353 | if (sym_found->str_index == string_index) | ||
354 | break; | ||
355 | } | ||
356 | |||
357 | return sym_found; | ||
358 | } | ||
359 | |||
360 | /* | ||
361 | * Function: priv_tramp_sym_find | ||
362 | * Description: Search for a trampoline symbol based on the string name of | ||
363 | * the symbol. Return the symbol object, if found, otherwise | ||
364 | * return NULL. | ||
365 | */ | ||
366 | static struct tramp_sym *priv_tramp_sym_find(struct dload_state *dlthis, | ||
367 | char *string) | ||
368 | { | ||
369 | struct tramp_sym *sym_found = NULL; | ||
370 | struct tramp_string *str_found = NULL; | ||
371 | |||
372 | /* First, search for the string, then search for the sym based on the | ||
373 | string index. */ | ||
374 | str_found = priv_tramp_string_find(dlthis, string); | ||
375 | if (str_found != NULL) | ||
376 | sym_found = priv_tramp_sym_get(dlthis, str_found->index); | ||
377 | |||
378 | return sym_found; | ||
379 | } | ||
380 | |||
381 | /* | ||
382 | * Function: priv_tramp_sym_finalize | ||
383 | * Description: Allocate a flat symbol table for the trampoline section, | ||
384 | * put each trampoline symbol into the table, adjust the | ||
385 | * symbol value based on the section address on the target and | ||
386 | * free the trampoline symbol list nodes. | ||
387 | */ | ||
388 | static int priv_tramp_sym_finalize(struct dload_state *dlthis) | ||
389 | { | ||
390 | int ret_val = 0; | ||
391 | struct tramp_sym *cur_sym; | ||
392 | struct ldr_section_info *tramp_sect = | ||
393 | &dlthis->ldr_sections[dlthis->allocated_secn_count]; | ||
394 | struct local_symbol *new_sym; | ||
395 | |||
396 | /* Allocate a table to hold a flattened version of all symbols | ||
397 | * created. */ | ||
398 | dlthis->tramp.final_sym_table = | ||
399 | (struct local_symbol *)dlthis->mysym->dload_allocate(dlthis->mysym, | ||
400 | (sizeof(struct local_symbol) * dlthis->tramp. | ||
401 | tramp_sym_next_index)); | ||
402 | if (dlthis->tramp.final_sym_table != NULL) { | ||
403 | /* Walk the list of all symbols, copy it over to the flattened | ||
404 | * table. After it has been copied, the node can be freed as | ||
405 | * it is no longer needed. */ | ||
406 | new_sym = dlthis->tramp.final_sym_table; | ||
407 | cur_sym = dlthis->tramp.symbol_head; | ||
408 | while (cur_sym != NULL) { | ||
409 | /* Pop it off the list */ | ||
410 | dlthis->tramp.symbol_head = cur_sym->next; | ||
411 | if (cur_sym == dlthis->tramp.symbol_tail) | ||
412 | dlthis->tramp.symbol_tail = NULL; | ||
413 | |||
414 | /* Copy the symbol contents into the flat table */ | ||
415 | *new_sym = cur_sym->sym_info; | ||
416 | |||
417 | /* Now finaize the symbol. If it is in the tramp | ||
418 | * section, we need to adjust for the section start. | ||
419 | * If it is external then we don't need to adjust at | ||
420 | * all. | ||
421 | * NOTE: THIS CODE ASSUMES THAT THE TRAMPOLINE IS | ||
422 | * REFERENCED LIKE A CALL TO AN EXTERNAL SO VALUE AND | ||
423 | * DELTA ARE THE SAME. SEE THE FUNCTION dload_symbols | ||
424 | * WHERE DN_UNDEF IS HANDLED FOR MORE REFERENCE. */ | ||
425 | if (new_sym->secnn < 0) { | ||
426 | new_sym->value += tramp_sect->load_addr; | ||
427 | new_sym->delta = new_sym->value; | ||
428 | } | ||
429 | |||
430 | /* Let go of the symbol node */ | ||
431 | dlthis->mysym->dload_deallocate(dlthis->mysym, cur_sym); | ||
432 | |||
433 | /* Move to the next node */ | ||
434 | cur_sym = dlthis->tramp.symbol_head; | ||
435 | new_sym++; | ||
436 | } | ||
437 | |||
438 | ret_val = 1; | ||
439 | } else | ||
440 | dload_error(dlthis, "Failed to alloc trampoline sym table"); | ||
441 | |||
442 | return ret_val; | ||
443 | } | ||
444 | |||
445 | /* | ||
446 | * Function: priv_tgt_img_gen | ||
447 | * Description: Allocate storage for and copy the target specific image data | ||
448 | * and fix up its relocations for the new external symbol. If | ||
449 | * a trampoline image packet was successfully created it is added | ||
450 | * to the trampoline list. | ||
451 | */ | ||
452 | static int priv_tgt_img_gen(struct dload_state *dlthis, u32 base, | ||
453 | u32 gen_index, struct tramp_sym *new_ext_sym) | ||
454 | { | ||
455 | struct tramp_img_pkt *new_img_pkt = NULL; | ||
456 | u32 i; | ||
457 | u32 pkt_size = tramp_img_pkt_size_get(); | ||
458 | u8 *gen_tbl_entry; | ||
459 | u8 *pkt_data; | ||
460 | struct reloc_record_t *cur_relo; | ||
461 | int ret_val = 0; | ||
462 | |||
463 | /* Allocate a new image packet and set it up. */ | ||
464 | new_img_pkt = | ||
465 | (struct tramp_img_pkt *)dlthis->mysym->dload_allocate(dlthis->mysym, | ||
466 | pkt_size); | ||
467 | if (new_img_pkt != NULL) { | ||
468 | /* Save the base, this is where it goes in the section */ | ||
469 | new_img_pkt->base = base; | ||
470 | |||
471 | /* Copy over the image data and relos from the target table */ | ||
472 | pkt_data = (u8 *) &new_img_pkt->hdr; | ||
473 | gen_tbl_entry = (u8 *) &tramp_gen_info[gen_index]; | ||
474 | for (i = 0; i < pkt_size; i++) { | ||
475 | *pkt_data = *gen_tbl_entry; | ||
476 | pkt_data++; | ||
477 | gen_tbl_entry++; | ||
478 | } | ||
479 | |||
480 | /* Update the relocations to point to the external symbol */ | ||
481 | cur_relo = | ||
482 | (struct reloc_record_t *)((u8 *) &new_img_pkt->hdr + | ||
483 | new_img_pkt->hdr.relo_offset); | ||
484 | for (i = 0; i < new_img_pkt->hdr.num_relos; i++) | ||
485 | cur_relo[i].SYMNDX = new_ext_sym->index; | ||
486 | |||
487 | /* Add it to the trampoline list. */ | ||
488 | new_img_pkt->next = dlthis->tramp.tramp_pkts; | ||
489 | dlthis->tramp.tramp_pkts = new_img_pkt; | ||
490 | |||
491 | ret_val = 1; | ||
492 | } | ||
493 | |||
494 | return ret_val; | ||
495 | } | ||
496 | |||
497 | /* | ||
498 | * Function: priv_pkt_relo | ||
499 | * Description: Take the provided image data and the collection of relocations | ||
500 | * for it and perform the relocations. Note that all relocations | ||
501 | * at this stage are considered SECOND PASS since the original | ||
502 | * image has already been processed in the first pass. This means | ||
503 | * TRAMPOLINES ARE TREATED AS 2ND PASS even though this is really | ||
504 | * the first (and only) relocation that will be performed on them. | ||
505 | */ | ||
506 | static int priv_pkt_relo(struct dload_state *dlthis, tgt_au_t * data, | ||
507 | struct reloc_record_t *rp[], u32 relo_count) | ||
508 | { | ||
509 | int ret_val = 1; | ||
510 | u32 i; | ||
511 | bool tmp; | ||
512 | |||
513 | /* Walk through all of the relos and process them. This function is | ||
514 | * the equivalent of relocate_packet() from cload.c, but specialized | ||
515 | * for trampolines and 2nd phase relocations. */ | ||
516 | for (i = 0; i < relo_count; i++) | ||
517 | dload_relocate(dlthis, data, rp[i], &tmp, true); | ||
518 | |||
519 | return ret_val; | ||
520 | } | ||
521 | |||
522 | /* | ||
523 | * Function: priv_tramp_pkt_finalize | ||
524 | * Description: Walk the list of all trampoline packets and finalize them. | ||
525 | * Each trampoline image packet will be relocated now that the | ||
526 | * trampoline section has been allocated on the target. Once | ||
527 | * all of the relocations are done the trampoline image data | ||
528 | * is written into target memory and the trampoline packet | ||
529 | * is freed: it is no longer needed after this point. | ||
530 | */ | ||
531 | static int priv_tramp_pkt_finalize(struct dload_state *dlthis) | ||
532 | { | ||
533 | int ret_val = 1; | ||
534 | struct tramp_img_pkt *cur_pkt = NULL; | ||
535 | struct reloc_record_t *relos[MAX_RELOS_PER_PASS]; | ||
536 | u32 relos_done; | ||
537 | u32 i; | ||
538 | struct reloc_record_t *cur_relo; | ||
539 | struct ldr_section_info *sect_info = | ||
540 | &dlthis->ldr_sections[dlthis->allocated_secn_count]; | ||
541 | |||
542 | /* Walk the list of trampoline packets and relocate each packet. This | ||
543 | * function is the trampoline equivalent of dload_data() from | ||
544 | * cload.c. */ | ||
545 | cur_pkt = dlthis->tramp.tramp_pkts; | ||
546 | while ((ret_val != 0) && (cur_pkt != NULL)) { | ||
547 | /* Remove the pkt from the list */ | ||
548 | dlthis->tramp.tramp_pkts = cur_pkt->next; | ||
549 | |||
550 | /* Setup section and image offset information for the relo */ | ||
551 | dlthis->image_secn = sect_info; | ||
552 | dlthis->image_offset = cur_pkt->base; | ||
553 | dlthis->delta_runaddr = sect_info->run_addr; | ||
554 | |||
555 | /* Walk through all relos for the packet */ | ||
556 | relos_done = 0; | ||
557 | cur_relo = (struct reloc_record_t *)((u8 *) &cur_pkt->hdr + | ||
558 | cur_pkt->hdr.relo_offset); | ||
559 | while (relos_done < cur_pkt->hdr.num_relos) { | ||
560 | #ifdef ENABLE_TRAMP_DEBUG | ||
561 | dload_syms_error(dlthis->mysym, | ||
562 | "===> Trampoline %x branches to %x", | ||
563 | sect_info->run_addr + | ||
564 | dlthis->image_offset, | ||
565 | dlthis-> | ||
566 | tramp.final_sym_table[cur_relo-> | ||
567 | SYMNDX].value); | ||
568 | #endif | ||
569 | |||
570 | for (i = 0; | ||
571 | ((i < MAX_RELOS_PER_PASS) && | ||
572 | ((i + relos_done) < cur_pkt->hdr.num_relos)); i++) | ||
573 | relos[i] = cur_relo + i; | ||
574 | |||
575 | /* Do the actual relo */ | ||
576 | ret_val = priv_pkt_relo(dlthis, | ||
577 | (tgt_au_t *) &cur_pkt->payload, | ||
578 | relos, i); | ||
579 | if (ret_val == 0) { | ||
580 | dload_error(dlthis, | ||
581 | "Relocation of trampoline pkt at %x" | ||
582 | " failed", cur_pkt->base + | ||
583 | sect_info->run_addr); | ||
584 | break; | ||
585 | } | ||
586 | |||
587 | relos_done += i; | ||
588 | cur_relo += i; | ||
589 | } | ||
590 | |||
591 | /* Make sure we didn't hit a problem */ | ||
592 | if (ret_val != 0) { | ||
593 | /* Relos are done for the packet, write it to the | ||
594 | * target */ | ||
595 | ret_val = dlthis->myio->writemem(dlthis->myio, | ||
596 | &cur_pkt->payload, | ||
597 | sect_info->load_addr + | ||
598 | cur_pkt->base, | ||
599 | sect_info, | ||
600 | BYTE_TO_HOST | ||
601 | (cur_pkt->hdr. | ||
602 | tramp_code_size)); | ||
603 | if (ret_val == 0) { | ||
604 | dload_error(dlthis, | ||
605 | "Write to " FMT_UI32 " failed", | ||
606 | sect_info->load_addr + | ||
607 | cur_pkt->base); | ||
608 | } | ||
609 | |||
610 | /* Done with the pkt, let it go */ | ||
611 | dlthis->mysym->dload_deallocate(dlthis->mysym, cur_pkt); | ||
612 | |||
613 | /* Get the next packet to process */ | ||
614 | cur_pkt = dlthis->tramp.tramp_pkts; | ||
615 | } | ||
616 | } | ||
617 | |||
618 | return ret_val; | ||
619 | } | ||
620 | |||
621 | /* | ||
622 | * Function: priv_dup_pkt_finalize | ||
623 | * Description: Walk the list of duplicate image packets and finalize them. | ||
624 | * Each duplicate packet will be relocated again for the | ||
625 | * relocations that previously failed and have been adjusted | ||
626 | * to point at a trampoline. Once all relocations for a packet | ||
627 | * have been done, write the packet into target memory. The | ||
628 | * duplicate packet and its relocation chain are all freed | ||
629 | * after use here as they are no longer needed after this. | ||
630 | */ | ||
631 | static int priv_dup_pkt_finalize(struct dload_state *dlthis) | ||
632 | { | ||
633 | int ret_val = 1; | ||
634 | struct tramp_img_dup_pkt *cur_pkt; | ||
635 | struct tramp_img_dup_relo *cur_relo; | ||
636 | struct reloc_record_t *relos[MAX_RELOS_PER_PASS]; | ||
637 | struct doff_scnhdr_t *sect_hdr = NULL; | ||
638 | s32 i; | ||
639 | |||
640 | /* Similar to the trampoline pkt finalize, this function walks each dup | ||
641 | * pkt that was generated and performs all relocations that were | ||
642 | * deferred to a 2nd pass. This is the equivalent of dload_data() from | ||
643 | * cload.c, but does not need the additional reorder and checksum | ||
644 | * processing as it has already been done. */ | ||
645 | cur_pkt = dlthis->tramp.dup_pkts; | ||
646 | while ((ret_val != 0) && (cur_pkt != NULL)) { | ||
647 | /* Remove the node from the list, we'll be freeing it | ||
648 | * shortly */ | ||
649 | dlthis->tramp.dup_pkts = cur_pkt->next; | ||
650 | |||
651 | /* Setup the section and image offset for relocation */ | ||
652 | dlthis->image_secn = &dlthis->ldr_sections[cur_pkt->secnn]; | ||
653 | dlthis->image_offset = cur_pkt->offset; | ||
654 | |||
655 | /* In order to get the delta run address, we need to reference | ||
656 | * the original section header. It's a bit ugly, but needed | ||
657 | * for relo. */ | ||
658 | i = (s32) (dlthis->image_secn - dlthis->ldr_sections); | ||
659 | sect_hdr = dlthis->sect_hdrs + i; | ||
660 | dlthis->delta_runaddr = sect_hdr->ds_paddr; | ||
661 | |||
662 | /* Walk all relos in the chain and process each. */ | ||
663 | cur_relo = cur_pkt->relo_chain; | ||
664 | while (cur_relo != NULL) { | ||
665 | /* Process them a chunk at a time to be efficient */ | ||
666 | for (i = 0; (i < MAX_RELOS_PER_PASS) | ||
667 | && (cur_relo != NULL); | ||
668 | i++, cur_relo = cur_relo->next) { | ||
669 | relos[i] = &cur_relo->relo; | ||
670 | cur_pkt->relo_chain = cur_relo->next; | ||
671 | } | ||
672 | |||
673 | /* Do the actual relo */ | ||
674 | ret_val = priv_pkt_relo(dlthis, | ||
675 | cur_pkt->img_pkt.img_data, | ||
676 | relos, i); | ||
677 | if (ret_val == 0) { | ||
678 | dload_error(dlthis, | ||
679 | "Relocation of dup pkt at %x" | ||
680 | " failed", cur_pkt->offset + | ||
681 | dlthis->image_secn->run_addr); | ||
682 | break; | ||
683 | } | ||
684 | |||
685 | /* Release all of these relos, we're done with them */ | ||
686 | while (i > 0) { | ||
687 | dlthis->mysym->dload_deallocate(dlthis->mysym, | ||
688 | GET_CONTAINER | ||
689 | (relos[i - 1], | ||
690 | struct tramp_img_dup_relo, | ||
691 | relo)); | ||
692 | i--; | ||
693 | } | ||
694 | |||
695 | /* DO NOT ADVANCE cur_relo, IT IS ALREADY READY TO | ||
696 | * GO! */ | ||
697 | } | ||
698 | |||
699 | /* Done with all relos. Make sure we didn't have a problem and | ||
700 | * write it out to the target */ | ||
701 | if (ret_val != 0) { | ||
702 | ret_val = dlthis->myio->writemem(dlthis->myio, | ||
703 | cur_pkt->img_pkt. | ||
704 | img_data, | ||
705 | dlthis->image_secn-> | ||
706 | load_addr + | ||
707 | cur_pkt->offset, | ||
708 | dlthis->image_secn, | ||
709 | BYTE_TO_HOST | ||
710 | (cur_pkt->img_pkt. | ||
711 | packet_size)); | ||
712 | if (ret_val == 0) { | ||
713 | dload_error(dlthis, | ||
714 | "Write to " FMT_UI32 " failed", | ||
715 | dlthis->image_secn->load_addr + | ||
716 | cur_pkt->offset); | ||
717 | } | ||
718 | |||
719 | dlthis->mysym->dload_deallocate(dlthis->mysym, cur_pkt); | ||
720 | |||
721 | /* Advance to the next packet */ | ||
722 | cur_pkt = dlthis->tramp.dup_pkts; | ||
723 | } | ||
724 | } | ||
725 | |||
726 | return ret_val; | ||
727 | } | ||
728 | |||
729 | /* | ||
730 | * Function: priv_dup_find | ||
731 | * Description: Walk the list of existing duplicate packets and find a | ||
732 | * match based on the section number and image offset. Return | ||
733 | * the duplicate packet if found, otherwise NULL. | ||
734 | */ | ||
735 | static struct tramp_img_dup_pkt *priv_dup_find(struct dload_state *dlthis, | ||
736 | s16 secnn, u32 image_offset) | ||
737 | { | ||
738 | struct tramp_img_dup_pkt *cur_pkt = NULL; | ||
739 | |||
740 | for (cur_pkt = dlthis->tramp.dup_pkts; | ||
741 | cur_pkt != NULL; cur_pkt = cur_pkt->next) { | ||
742 | if ((cur_pkt->secnn == secnn) && | ||
743 | (cur_pkt->offset == image_offset)) { | ||
744 | /* Found a match, break out */ | ||
745 | break; | ||
746 | } | ||
747 | } | ||
748 | |||
749 | return cur_pkt; | ||
750 | } | ||
751 | |||
752 | /* | ||
753 | * Function: priv_img_pkt_dup | ||
754 | * Description: Duplicate the original image packet. If this is the first | ||
755 | * time this image packet has been seen (based on section number | ||
756 | * and image offset), create a new duplicate packet and add it | ||
757 | * to the dup packet list. If not, just get the existing one and | ||
758 | * update it with the current packet contents (since relocation | ||
759 | * on the packet is still ongoing in first pass.) Create a | ||
760 | * duplicate of the provided relocation, but update it to point | ||
761 | * to the new trampoline symbol. Add the new relocation dup to | ||
762 | * the dup packet's relo chain for 2nd pass relocation later. | ||
763 | */ | ||
764 | static int priv_img_pkt_dup(struct dload_state *dlthis, | ||
765 | s16 secnn, u32 image_offset, | ||
766 | struct image_packet_t *ipacket, | ||
767 | struct reloc_record_t *rp, | ||
768 | struct tramp_sym *new_tramp_sym) | ||
769 | { | ||
770 | struct tramp_img_dup_pkt *dup_pkt = NULL; | ||
771 | u32 new_dup_size; | ||
772 | s32 i; | ||
773 | int ret_val = 0; | ||
774 | struct tramp_img_dup_relo *dup_relo = NULL; | ||
775 | |||
776 | /* Determinne if this image packet is already being tracked in the | ||
777 | dup list for other trampolines. */ | ||
778 | dup_pkt = priv_dup_find(dlthis, secnn, image_offset); | ||
779 | |||
780 | if (dup_pkt == NULL) { | ||
781 | /* This image packet does not exist in our tracking, so create | ||
782 | * a new one and add it to the head of the list. */ | ||
783 | new_dup_size = sizeof(struct tramp_img_dup_pkt) + | ||
784 | ipacket->packet_size; | ||
785 | |||
786 | dup_pkt = (struct tramp_img_dup_pkt *) | ||
787 | dlthis->mysym->dload_allocate(dlthis->mysym, new_dup_size); | ||
788 | if (dup_pkt != NULL) { | ||
789 | /* Save off the section and offset information */ | ||
790 | dup_pkt->secnn = secnn; | ||
791 | dup_pkt->offset = image_offset; | ||
792 | dup_pkt->relo_chain = NULL; | ||
793 | |||
794 | /* Copy the original packet content */ | ||
795 | dup_pkt->img_pkt = *ipacket; | ||
796 | dup_pkt->img_pkt.img_data = (u8 *) (dup_pkt + 1); | ||
797 | for (i = 0; i < ipacket->packet_size; i++) | ||
798 | *(dup_pkt->img_pkt.img_data + i) = | ||
799 | *(ipacket->img_data + i); | ||
800 | |||
801 | /* Add the packet to the dup list */ | ||
802 | dup_pkt->next = dlthis->tramp.dup_pkts; | ||
803 | dlthis->tramp.dup_pkts = dup_pkt; | ||
804 | } else | ||
805 | dload_error(dlthis, "Failed to create dup packet!"); | ||
806 | } else { | ||
807 | /* The image packet contents could have changed since | ||
808 | * trampoline detection happens during relocation of the image | ||
809 | * packets. So, we need to update the image packet contents | ||
810 | * before adding relo information. */ | ||
811 | for (i = 0; i < dup_pkt->img_pkt.packet_size; i++) | ||
812 | *(dup_pkt->img_pkt.img_data + i) = | ||
813 | *(ipacket->img_data + i); | ||
814 | } | ||
815 | |||
816 | /* Since the previous code may have allocated a new dup packet for us, | ||
817 | double check that we actually have one. */ | ||
818 | if (dup_pkt != NULL) { | ||
819 | /* Allocate a new node for the relo chain. Each image packet | ||
820 | * can potentially have multiple relocations that cause a | ||
821 | * trampoline to be generated. So, we keep them in a chain, | ||
822 | * order is not important. */ | ||
823 | dup_relo = dlthis->mysym->dload_allocate(dlthis->mysym, | ||
824 | sizeof(struct tramp_img_dup_relo)); | ||
825 | if (dup_relo != NULL) { | ||
826 | /* Copy the relo contents, adjust for the new | ||
827 | * trampoline and add it to the list. */ | ||
828 | dup_relo->relo = *rp; | ||
829 | dup_relo->relo.SYMNDX = new_tramp_sym->index; | ||
830 | |||
831 | dup_relo->next = dup_pkt->relo_chain; | ||
832 | dup_pkt->relo_chain = dup_relo; | ||
833 | |||
834 | /* That's it, we're done. Make sure we update our | ||
835 | * return value to be success since everything finished | ||
836 | * ok */ | ||
837 | ret_val = 1; | ||
838 | } else | ||
839 | dload_error(dlthis, "Unable to alloc dup relo"); | ||
840 | } | ||
841 | |||
842 | return ret_val; | ||
843 | } | ||
844 | |||
845 | /* | ||
846 | * Function: dload_tramp_avail | ||
847 | * Description: Check to see if the target supports a trampoline for this type | ||
848 | * of relocation. Return true if it does, otherwise false. | ||
849 | */ | ||
850 | bool dload_tramp_avail(struct dload_state *dlthis, struct reloc_record_t *rp) | ||
851 | { | ||
852 | bool ret_val = false; | ||
853 | u16 map_index; | ||
854 | u16 gen_index; | ||
855 | |||
856 | /* Check type hash vs. target tramp table */ | ||
857 | map_index = HASH_FUNC(rp->TYPE); | ||
858 | gen_index = tramp_map[map_index]; | ||
859 | if (gen_index != TRAMP_NO_GEN_AVAIL) | ||
860 | ret_val = true; | ||
861 | |||
862 | return ret_val; | ||
863 | } | ||
864 | |||
865 | /* | ||
866 | * Function: dload_tramp_generate | ||
867 | * Description: Create a new trampoline for the provided image packet and | ||
868 | * relocation causing problems. This will create the trampoline | ||
869 | * as well as duplicate/update the image packet and relocation | ||
870 | * causing the problem, which will be relo'd again during | ||
871 | * finalization. | ||
872 | */ | ||
873 | int dload_tramp_generate(struct dload_state *dlthis, s16 secnn, | ||
874 | u32 image_offset, struct image_packet_t *ipacket, | ||
875 | struct reloc_record_t *rp) | ||
876 | { | ||
877 | u16 map_index; | ||
878 | u16 gen_index; | ||
879 | int ret_val = 1; | ||
880 | char tramp_sym_str[TRAMP_SYM_PREFIX_LEN + TRAMP_SYM_HEX_ASCII_LEN]; | ||
881 | struct local_symbol *ref_sym; | ||
882 | struct tramp_sym *new_tramp_sym; | ||
883 | struct tramp_sym *new_ext_sym; | ||
884 | struct tramp_string *new_tramp_str; | ||
885 | u32 new_tramp_base; | ||
886 | struct local_symbol tmp_sym; | ||
887 | struct local_symbol ext_tmp_sym; | ||
888 | |||
889 | /* Hash the relo type to get our generator information */ | ||
890 | map_index = HASH_FUNC(rp->TYPE); | ||
891 | gen_index = tramp_map[map_index]; | ||
892 | if (gen_index != TRAMP_NO_GEN_AVAIL) { | ||
893 | /* If this is the first trampoline, create the section name in | ||
894 | * our string table for debug help later. */ | ||
895 | if (dlthis->tramp.string_head == NULL) { | ||
896 | priv_tramp_string_create(dlthis, | ||
897 | strlen(TRAMP_SECT_NAME), | ||
898 | TRAMP_SECT_NAME); | ||
899 | } | ||
900 | #ifdef ENABLE_TRAMP_DEBUG | ||
901 | dload_syms_error(dlthis->mysym, | ||
902 | "Trampoline at img loc %x, references %x", | ||
903 | dlthis->ldr_sections[secnn].run_addr + | ||
904 | image_offset + rp->vaddr, | ||
905 | dlthis->local_symtab[rp->SYMNDX].value); | ||
906 | #endif | ||
907 | |||
908 | /* Generate the trampoline string, check if already defined. | ||
909 | * If the relo symbol index is -1, it means we need the section | ||
910 | * info for relo later. To do this we'll dummy up a symbol | ||
911 | * with the section delta and run addresses. */ | ||
912 | if (rp->SYMNDX == -1) { | ||
913 | ext_tmp_sym.value = | ||
914 | dlthis->ldr_sections[secnn].run_addr; | ||
915 | ext_tmp_sym.delta = dlthis->sect_hdrs[secnn].ds_paddr; | ||
916 | ref_sym = &ext_tmp_sym; | ||
917 | } else | ||
918 | ref_sym = &(dlthis->local_symtab[rp->SYMNDX]); | ||
919 | |||
920 | priv_tramp_sym_gen_name(ref_sym->value, tramp_sym_str); | ||
921 | new_tramp_sym = priv_tramp_sym_find(dlthis, tramp_sym_str); | ||
922 | if (new_tramp_sym == NULL) { | ||
923 | /* If tramp string not defined, create it and a new | ||
924 | * string, and symbol for it as well as the original | ||
925 | * symbol which caused the trampoline. */ | ||
926 | new_tramp_str = priv_tramp_string_create(dlthis, | ||
927 | strlen | ||
928 | (tramp_sym_str), | ||
929 | tramp_sym_str); | ||
930 | if (new_tramp_str == NULL) { | ||
931 | dload_error(dlthis, "Failed to create new " | ||
932 | "trampoline string\n"); | ||
933 | ret_val = 0; | ||
934 | } else { | ||
935 | /* Allocate tramp section space for the new | ||
936 | * tramp from the target */ | ||
937 | new_tramp_base = priv_tramp_sect_alloc(dlthis, | ||
938 | tramp_size_get()); | ||
939 | |||
940 | /* We have a string, create the new symbol and | ||
941 | * duplicate the external. */ | ||
942 | tmp_sym.value = new_tramp_base; | ||
943 | tmp_sym.delta = 0; | ||
944 | tmp_sym.secnn = -1; | ||
945 | tmp_sym.sclass = 0; | ||
946 | new_tramp_sym = priv_tramp_sym_create(dlthis, | ||
947 | new_tramp_str-> | ||
948 | index, | ||
949 | &tmp_sym); | ||
950 | |||
951 | new_ext_sym = priv_tramp_sym_create(dlthis, -1, | ||
952 | ref_sym); | ||
953 | |||
954 | if ((new_tramp_sym != NULL) && | ||
955 | (new_ext_sym != NULL)) { | ||
956 | /* Call the image generator to get the | ||
957 | * new image data and fix up its | ||
958 | * relocations for the external | ||
959 | * symbol. */ | ||
960 | ret_val = priv_tgt_img_gen(dlthis, | ||
961 | new_tramp_base, | ||
962 | gen_index, | ||
963 | new_ext_sym); | ||
964 | |||
965 | /* Add generated image data to tramp | ||
966 | * image list */ | ||
967 | if (ret_val != 1) { | ||
968 | dload_error(dlthis, "Failed to " | ||
969 | "create img pkt for" | ||
970 | " trampoline\n"); | ||
971 | } | ||
972 | } else { | ||
973 | dload_error(dlthis, "Failed to create " | ||
974 | "new tramp syms " | ||
975 | "(%8.8X, %8.8X)\n", | ||
976 | new_tramp_sym, new_ext_sym); | ||
977 | ret_val = 0; | ||
978 | } | ||
979 | } | ||
980 | } | ||
981 | |||
982 | /* Duplicate the image data and relo record that caused the | ||
983 | * tramp, including update the relo data to point to the tramp | ||
984 | * symbol. */ | ||
985 | if (ret_val == 1) { | ||
986 | ret_val = priv_img_pkt_dup(dlthis, secnn, image_offset, | ||
987 | ipacket, rp, new_tramp_sym); | ||
988 | if (ret_val != 1) { | ||
989 | dload_error(dlthis, "Failed to create dup of " | ||
990 | "original img pkt\n"); | ||
991 | } | ||
992 | } | ||
993 | } | ||
994 | |||
995 | return ret_val; | ||
996 | } | ||
997 | |||
998 | /* | ||
999 | * Function: dload_tramp_pkt_update | ||
1000 | * Description: Update the duplicate copy of this image packet, which the | ||
1001 | * trampoline layer is already tracking. This is call is critical | ||
1002 | * to make if trampolines were generated anywhere within the | ||
1003 | * packet and first pass relo continued on the remainder. The | ||
1004 | * trampoline layer needs the updates image data so when 2nd | ||
1005 | * pass relo is done during finalize the image packet can be | ||
1006 | * written to the target since all relo is done. | ||
1007 | */ | ||
1008 | int dload_tramp_pkt_udpate(struct dload_state *dlthis, s16 secnn, | ||
1009 | u32 image_offset, struct image_packet_t *ipacket) | ||
1010 | { | ||
1011 | struct tramp_img_dup_pkt *dup_pkt = NULL; | ||
1012 | s32 i; | ||
1013 | int ret_val = 0; | ||
1014 | |||
1015 | /* Find the image packet in question, the caller needs us to update it | ||
1016 | since a trampoline was previously generated. */ | ||
1017 | dup_pkt = priv_dup_find(dlthis, secnn, image_offset); | ||
1018 | if (dup_pkt != NULL) { | ||
1019 | for (i = 0; i < dup_pkt->img_pkt.packet_size; i++) | ||
1020 | *(dup_pkt->img_pkt.img_data + i) = | ||
1021 | *(ipacket->img_data + i); | ||
1022 | |||
1023 | ret_val = 1; | ||
1024 | } else { | ||
1025 | dload_error(dlthis, | ||
1026 | "Unable to find existing DUP pkt for %x, offset %x", | ||
1027 | secnn, image_offset); | ||
1028 | |||
1029 | } | ||
1030 | |||
1031 | return ret_val; | ||
1032 | } | ||
1033 | |||
1034 | /* | ||
1035 | * Function: dload_tramp_finalize | ||
1036 | * Description: If any trampolines were created, finalize everything on the | ||
1037 | * target by allocating the trampoline section on the target, | ||
1038 | * finalizing the trampoline symbols, finalizing the trampoline | ||
1039 | * packets (write the new section to target memory) and finalize | ||
1040 | * the duplicate packets by doing 2nd pass relo over them. | ||
1041 | */ | ||
1042 | int dload_tramp_finalize(struct dload_state *dlthis) | ||
1043 | { | ||
1044 | int ret_val = 1; | ||
1045 | |||
1046 | if (dlthis->tramp.tramp_sect_next_addr != 0) { | ||
1047 | /* Finalize strings into a flat table. This is needed so it | ||
1048 | * can be added to the debug string table later. */ | ||
1049 | ret_val = priv_string_tbl_finalize(dlthis); | ||
1050 | |||
1051 | /* Do target allocation for section BEFORE finalizing | ||
1052 | * symbols. */ | ||
1053 | if (ret_val != 0) | ||
1054 | ret_val = priv_tramp_sect_tgt_alloc(dlthis); | ||
1055 | |||
1056 | /* Finalize symbols with their correct target information and | ||
1057 | * flatten */ | ||
1058 | if (ret_val != 0) | ||
1059 | ret_val = priv_tramp_sym_finalize(dlthis); | ||
1060 | |||
1061 | /* Finalize all trampoline packets. This performs the | ||
1062 | * relocation on the packets as well as writing them to target | ||
1063 | * memory. */ | ||
1064 | if (ret_val != 0) | ||
1065 | ret_val = priv_tramp_pkt_finalize(dlthis); | ||
1066 | |||
1067 | /* Perform a 2nd pass relocation on the dup list. */ | ||
1068 | if (ret_val != 0) | ||
1069 | ret_val = priv_dup_pkt_finalize(dlthis); | ||
1070 | } | ||
1071 | |||
1072 | return ret_val; | ||
1073 | } | ||
1074 | |||
1075 | /* | ||
1076 | * Function: dload_tramp_cleanup | ||
1077 | * Description: Release all temporary resources used in the trampoline layer. | ||
1078 | * Note that the target memory which may have been allocated and | ||
1079 | * written to store the trampolines is NOT RELEASED HERE since it | ||
1080 | * is potentially still in use. It is automatically released | ||
1081 | * when the module is unloaded. | ||
1082 | */ | ||
1083 | void dload_tramp_cleanup(struct dload_state *dlthis) | ||
1084 | { | ||
1085 | struct tramp_info *tramp = &dlthis->tramp; | ||
1086 | struct tramp_sym *cur_sym; | ||
1087 | struct tramp_string *cur_string; | ||
1088 | struct tramp_img_pkt *cur_tramp_pkt; | ||
1089 | struct tramp_img_dup_pkt *cur_dup_pkt; | ||
1090 | struct tramp_img_dup_relo *cur_dup_relo; | ||
1091 | |||
1092 | /* If there were no tramps generated, just return */ | ||
1093 | if (tramp->tramp_sect_next_addr == 0) | ||
1094 | return; | ||
1095 | |||
1096 | /* Destroy all tramp information */ | ||
1097 | for (cur_sym = tramp->symbol_head; | ||
1098 | cur_sym != NULL; cur_sym = tramp->symbol_head) { | ||
1099 | tramp->symbol_head = cur_sym->next; | ||
1100 | if (tramp->symbol_tail == cur_sym) | ||
1101 | tramp->symbol_tail = NULL; | ||
1102 | |||
1103 | dlthis->mysym->dload_deallocate(dlthis->mysym, cur_sym); | ||
1104 | } | ||
1105 | |||
1106 | if (tramp->final_sym_table != NULL) | ||
1107 | dlthis->mysym->dload_deallocate(dlthis->mysym, | ||
1108 | tramp->final_sym_table); | ||
1109 | |||
1110 | for (cur_string = tramp->string_head; | ||
1111 | cur_string != NULL; cur_string = tramp->string_head) { | ||
1112 | tramp->string_head = cur_string->next; | ||
1113 | if (tramp->string_tail == cur_string) | ||
1114 | tramp->string_tail = NULL; | ||
1115 | |||
1116 | dlthis->mysym->dload_deallocate(dlthis->mysym, cur_string); | ||
1117 | } | ||
1118 | |||
1119 | if (tramp->final_string_table != NULL) | ||
1120 | dlthis->mysym->dload_deallocate(dlthis->mysym, | ||
1121 | tramp->final_string_table); | ||
1122 | |||
1123 | for (cur_tramp_pkt = tramp->tramp_pkts; | ||
1124 | cur_tramp_pkt != NULL; cur_tramp_pkt = tramp->tramp_pkts) { | ||
1125 | tramp->tramp_pkts = cur_tramp_pkt->next; | ||
1126 | dlthis->mysym->dload_deallocate(dlthis->mysym, cur_tramp_pkt); | ||
1127 | } | ||
1128 | |||
1129 | for (cur_dup_pkt = tramp->dup_pkts; | ||
1130 | cur_dup_pkt != NULL; cur_dup_pkt = tramp->dup_pkts) { | ||
1131 | tramp->dup_pkts = cur_dup_pkt->next; | ||
1132 | |||
1133 | for (cur_dup_relo = cur_dup_pkt->relo_chain; | ||
1134 | cur_dup_relo != NULL; | ||
1135 | cur_dup_relo = cur_dup_pkt->relo_chain) { | ||
1136 | cur_dup_pkt->relo_chain = cur_dup_relo->next; | ||
1137 | dlthis->mysym->dload_deallocate(dlthis->mysym, | ||
1138 | cur_dup_relo); | ||
1139 | } | ||
1140 | |||
1141 | dlthis->mysym->dload_deallocate(dlthis->mysym, cur_dup_pkt); | ||
1142 | } | ||
1143 | } | ||
diff --git a/drivers/staging/tidspbridge/dynload/tramp_table_c6000.c b/drivers/staging/tidspbridge/dynload/tramp_table_c6000.c new file mode 100644 index 00000000000..e38d631b321 --- /dev/null +++ b/drivers/staging/tidspbridge/dynload/tramp_table_c6000.c | |||
@@ -0,0 +1,164 @@ | |||
1 | /* | ||
2 | * tramp_table_c6000.c | ||
3 | * | ||
4 | * DSP-BIOS Bridge driver support functions for TI OMAP processors. | ||
5 | * | ||
6 | * Copyright (C) 2005-2006 Texas Instruments, Inc. | ||
7 | * | ||
8 | * This package is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR | ||
13 | * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED | ||
14 | * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. | ||
15 | */ | ||
16 | |||
17 | #include "dload_internal.h" | ||
18 | |||
19 | /* These are defined in coff.h, but may not be available on all platforms | ||
20 | so we'll go ahead and define them here. */ | ||
21 | #ifndef R_C60LO16 | ||
22 | #define R_C60LO16 0x54 /* C60: MVK Low Half Register */ | ||
23 | #define R_C60HI16 0x55 /* C60: MVKH/MVKLH High Half Register */ | ||
24 | #endif | ||
25 | |||
26 | #define C6X_TRAMP_WORD_COUNT 8 | ||
27 | #define C6X_TRAMP_MAX_RELOS 8 | ||
28 | |||
29 | /* THIS HASH FUNCTION MUST MATCH THE ONE IN reloc_table_c6000.c */ | ||
30 | #define HASH_FUNC(zz) (((((zz) + 1) * UINT32_C(1845)) >> 11) & 63) | ||
31 | |||
32 | /* THIS MUST MATCH reloc_record_t FOR A SYMBOL BASED RELO */ | ||
33 | struct c6000_relo_record { | ||
34 | s32 vaddr; | ||
35 | s32 symndx; | ||
36 | #ifndef _BIG_ENDIAN | ||
37 | u16 disp; | ||
38 | u16 type; | ||
39 | #else | ||
40 | u16 type; | ||
41 | u16 disp; | ||
42 | #endif | ||
43 | }; | ||
44 | |||
45 | struct c6000_gen_code { | ||
46 | struct tramp_gen_code_hdr hdr; | ||
47 | u32 tramp_instrs[C6X_TRAMP_WORD_COUNT]; | ||
48 | struct c6000_relo_record relos[C6X_TRAMP_MAX_RELOS]; | ||
49 | }; | ||
50 | |||
51 | /* Hash mapping for relos that can cause trampolines. */ | ||
52 | static const u16 tramp_map[] = { | ||
53 | 65535, | ||
54 | 65535, | ||
55 | 65535, | ||
56 | 65535, | ||
57 | 65535, | ||
58 | 65535, | ||
59 | 65535, | ||
60 | 65535, | ||
61 | 65535, | ||
62 | 65535, | ||
63 | 0, | ||
64 | 65535, | ||
65 | 65535, | ||
66 | 65535, | ||
67 | 65535, | ||
68 | 65535, | ||
69 | 65535, | ||
70 | 65535, | ||
71 | 65535, | ||
72 | 65535, | ||
73 | 65535, | ||
74 | 65535, | ||
75 | 65535, | ||
76 | 65535, | ||
77 | 65535, | ||
78 | 65535, | ||
79 | 65535, | ||
80 | 65535, | ||
81 | 65535, | ||
82 | 65535, | ||
83 | 65535, | ||
84 | 65535, | ||
85 | 65535, | ||
86 | 65535, | ||
87 | 65535, | ||
88 | 65535, | ||
89 | 65535, | ||
90 | 65535, | ||
91 | 65535, | ||
92 | 65535, | ||
93 | 65535, | ||
94 | 65535, | ||
95 | 65535, | ||
96 | 65535, | ||
97 | 65535, | ||
98 | 65535, | ||
99 | 65535, | ||
100 | 65535, | ||
101 | 65535, | ||
102 | 65535, | ||
103 | 65535, | ||
104 | 65535, | ||
105 | 65535, | ||
106 | 65535, | ||
107 | 65535, | ||
108 | 65535, | ||
109 | 65535, | ||
110 | 65535, | ||
111 | 65535, | ||
112 | 65535, | ||
113 | 65535, | ||
114 | 65535, | ||
115 | 65535, | ||
116 | 65535 | ||
117 | }; | ||
118 | |||
119 | static const struct c6000_gen_code tramp_gen_info[] = { | ||
120 | /* Tramp caused by R_C60PCR21 */ | ||
121 | { | ||
122 | /* Header - 8 instructions, 2 relos */ | ||
123 | { | ||
124 | sizeof(u32) * C6X_TRAMP_WORD_COUNT, | ||
125 | 2, | ||
126 | FIELD_OFFSET(struct c6000_gen_code, relos) | ||
127 | }, | ||
128 | |||
129 | /* Trampoline instructions */ | ||
130 | { | ||
131 | 0x053C54F7, /* STW.D2T2 B10, *sp--[2] */ | ||
132 | 0x0500002A, /* || MVK.S2 <blank>, B10 */ | ||
133 | 0x0500006A, /* MVKH.S2 <blank>, B10 */ | ||
134 | 0x00280362, /* B.S2 B10 */ | ||
135 | 0x053C52E6, /* LDW.D2T2 *++sp[2], B10 */ | ||
136 | 0x00006000, /* NOP 4 */ | ||
137 | 0x00000000, /* NOP */ | ||
138 | 0x00000000 /* NOP */ | ||
139 | }, | ||
140 | |||
141 | /* Relocations */ | ||
142 | { | ||
143 | {4, 0, 0, R_C60LO16}, | ||
144 | {8, 0, 0, R_C60HI16}, | ||
145 | {0, 0, 0, 0x0000}, | ||
146 | {0, 0, 0, 0x0000}, | ||
147 | {0, 0, 0, 0x0000}, | ||
148 | {0, 0, 0, 0x0000}, | ||
149 | {0, 0, 0, 0x0000}, | ||
150 | {0, 0, 0, 0x0000} | ||
151 | } | ||
152 | } | ||
153 | }; | ||
154 | |||
155 | /* TARGET SPECIFIC FUNCTIONS THAT MUST BE DEFINED */ | ||
156 | static u32 tramp_size_get(void) | ||
157 | { | ||
158 | return sizeof(u32) * C6X_TRAMP_WORD_COUNT; | ||
159 | } | ||
160 | |||
161 | static u32 tramp_img_pkt_size_get(void) | ||
162 | { | ||
163 | return sizeof(struct c6000_gen_code); | ||
164 | } | ||