]>
Commit | Line | Data |
---|---|---|
26f8db7d ORL |
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 | ||
26f8db7d ORL |
22 | /* |
23 | * forward references | |
24 | */ | |
25 | static void dload_symbols(struct dload_state *dlthis); | |
26 | static void dload_data(struct dload_state *dlthis); | |
27 | static void allocate_sections(struct dload_state *dlthis); | |
28 | static void string_table_free(struct dload_state *dlthis); | |
29 | static void symbol_table_free(struct dload_state *dlthis); | |
30 | static void section_table_free(struct dload_state *dlthis); | |
31 | static void init_module_handle(struct dload_state *dlthis); | |
32 | #if BITS_PER_AU > BITS_PER_BYTE | |
33 | static char *unpack_name(struct dload_state *dlthis, u32 soffset); | |
34 | #endif | |
35 | ||
36 | static const char cinitname[] = { ".cinit" }; | |
37 | static const char loader_dllview_root[] = { "?DLModules?" }; | |
38 | ||
39 | /* | |
40 | * Error strings | |
41 | */ | |
42 | static const char readstrm[] = { "Error reading %s from input stream" }; | |
43 | static const char err_alloc[] = { "Syms->dload_allocate( %d ) failed" }; | |
44 | static const char tgtalloc[] = { | |
45 | "Target memory allocate failed, section %s size " FMT_UI32 }; | |
46 | static const char initfail[] = { "%s to target address " FMT_UI32 " failed" }; | |
47 | static const char dlvwrite[] = { "Write to DLLview list failed" }; | |
48 | static const char iconnect[] = { "Connect call to init interface failed" }; | |
49 | static const char err_checksum[] = { "Checksum failed on %s" }; | |
50 | ||
51 | /************************************************************************* | |
52 | * Procedure dload_error | |
53 | * | |
54 | * Parameters: | |
55 | * errtxt description of the error, printf style | |
56 | * ... additional information | |
57 | * | |
58 | * Effect: | |
59 | * Reports or records the error as appropriate. | |
60 | *********************************************************************** */ | |
61 | void dload_error(struct dload_state *dlthis, const char *errtxt, ...) | |
62 | { | |
63 | va_list args; | |
64 | ||
65 | va_start(args, errtxt); | |
66 | dlthis->mysym->error_report(dlthis->mysym, errtxt, args); | |
67 | va_end(args); | |
68 | dlthis->dload_errcount += 1; | |
69 | ||
70 | } /* dload_error */ | |
71 | ||
72 | #define DL_ERROR(zza, zzb) dload_error(dlthis, zza, zzb) | |
73 | ||
74 | /************************************************************************* | |
75 | * Procedure dload_syms_error | |
76 | * | |
77 | * Parameters: | |
78 | * errtxt description of the error, printf style | |
79 | * ... additional information | |
80 | * | |
81 | * Effect: | |
82 | * Reports or records the error as appropriate. | |
83 | *********************************************************************** */ | |
84 | void dload_syms_error(struct dynamic_loader_sym *syms, const char *errtxt, ...) | |
85 | { | |
86 | va_list args; | |
87 | ||
88 | va_start(args, errtxt); | |
89 | syms->error_report(syms, errtxt, args); | |
90 | va_end(args); | |
91 | } | |
92 | ||
93 | /************************************************************************* | |
94 | * Procedure dynamic_load_module | |
95 | * | |
96 | * Parameters: | |
97 | * module The input stream that supplies the module image | |
98 | * syms Host-side symbol table and malloc/free functions | |
99 | * alloc Target-side memory allocation | |
100 | * init Target-side memory initialization | |
101 | * options Option flags DLOAD_* | |
102 | * mhandle A module handle for use with Dynamic_Unload | |
103 | * | |
104 | * Effect: | |
105 | * The module image is read using *module. Target storage for the new | |
106 | * image is | |
107 | * obtained from *alloc. Symbols defined and referenced by the module are | |
108 | * managed using *syms. The image is then relocated and references | |
109 | * resolved as necessary, and the resulting executable bits are placed | |
110 | * into target memory using *init. | |
111 | * | |
112 | * Returns: | |
113 | * On a successful load, a module handle is placed in *mhandle, | |
114 | * and zero is returned. On error, the number of errors detected is | |
115 | * returned. Individual errors are reported during the load process | |
116 | * using syms->error_report(). | |
117 | ********************************************************************** */ | |
118 | int dynamic_load_module(struct dynamic_loader_stream *module, | |
119 | struct dynamic_loader_sym *syms, | |
120 | struct dynamic_loader_allocate *alloc, | |
121 | struct dynamic_loader_initialize *init, | |
122 | unsigned options, void **mhandle) | |
123 | { | |
124 | register unsigned *dp, sz; | |
125 | struct dload_state dl_state; /* internal state for this call */ | |
126 | ||
127 | /* blast our internal state */ | |
128 | dp = (unsigned *)&dl_state; | |
129 | for (sz = sizeof(dl_state) / sizeof(unsigned); sz > 0; sz -= 1) | |
130 | *dp++ = 0; | |
131 | ||
132 | /* Enable _only_ BSS initialization if enabled by user */ | |
133 | if ((options & DLOAD_INITBSS) == DLOAD_INITBSS) | |
134 | dl_state.myoptions = DLOAD_INITBSS; | |
135 | ||
136 | /* Check that mandatory arguments are present */ | |
137 | if (!module || !syms) { | |
138 | dload_error(&dl_state, "Required parameter is NULL"); | |
139 | } else { | |
140 | dl_state.strm = module; | |
141 | dl_state.mysym = syms; | |
142 | dload_headers(&dl_state); | |
143 | if (!dl_state.dload_errcount) | |
144 | dload_strings(&dl_state, false); | |
145 | if (!dl_state.dload_errcount) | |
146 | dload_sections(&dl_state); | |
147 | ||
148 | if (init && !dl_state.dload_errcount) { | |
149 | if (init->connect(init)) { | |
150 | dl_state.myio = init; | |
151 | dl_state.myalloc = alloc; | |
152 | /* do now, before reducing symbols */ | |
153 | allocate_sections(&dl_state); | |
154 | } else | |
155 | dload_error(&dl_state, iconnect); | |
156 | } | |
157 | ||
158 | if (!dl_state.dload_errcount) { | |
159 | /* fix up entry point address */ | |
160 | unsigned sref = dl_state.dfile_hdr.df_entry_secn - 1; | |
161 | if (sref < dl_state.allocated_secn_count) | |
162 | dl_state.dfile_hdr.df_entrypt += | |
163 | dl_state.ldr_sections[sref].run_addr; | |
164 | ||
165 | dload_symbols(&dl_state); | |
166 | } | |
167 | ||
168 | if (init && !dl_state.dload_errcount) | |
169 | dload_data(&dl_state); | |
170 | ||
171 | init_module_handle(&dl_state); | |
172 | ||
173 | /* dl_state.myio is init or 0 at this point. */ | |
174 | if (dl_state.myio) { | |
175 | if ((!dl_state.dload_errcount) && | |
176 | (dl_state.dfile_hdr.df_entry_secn != DN_UNDEF) && | |
177 | (!init->execute(init, | |
178 | dl_state.dfile_hdr.df_entrypt))) | |
179 | dload_error(&dl_state, "Init->Execute Failed"); | |
180 | init->release(init); | |
181 | } | |
182 | ||
183 | symbol_table_free(&dl_state); | |
184 | section_table_free(&dl_state); | |
185 | string_table_free(&dl_state); | |
186 | dload_tramp_cleanup(&dl_state); | |
187 | ||
188 | if (dl_state.dload_errcount) { | |
189 | dynamic_unload_module(dl_state.myhandle, syms, alloc, | |
190 | init); | |
191 | dl_state.myhandle = NULL; | |
192 | } | |
193 | } | |
194 | ||
195 | if (mhandle) | |
196 | *mhandle = dl_state.myhandle; /* give back the handle */ | |
197 | ||
198 | return dl_state.dload_errcount; | |
199 | } /* DLOAD_File */ | |
200 | ||
201 | /************************************************************************* | |
202 | * Procedure dynamic_open_module | |
203 | * | |
204 | * Parameters: | |
205 | * module The input stream that supplies the module image | |
206 | * syms Host-side symbol table and malloc/free functions | |
207 | * alloc Target-side memory allocation | |
208 | * init Target-side memory initialization | |
209 | * options Option flags DLOAD_* | |
210 | * mhandle A module handle for use with Dynamic_Unload | |
211 | * | |
212 | * Effect: | |
213 | * The module image is read using *module. Target storage for the new | |
214 | * image is | |
215 | * obtained from *alloc. Symbols defined and referenced by the module are | |
216 | * managed using *syms. The image is then relocated and references | |
217 | * resolved as necessary, and the resulting executable bits are placed | |
218 | * into target memory using *init. | |
219 | * | |
220 | * Returns: | |
221 | * On a successful load, a module handle is placed in *mhandle, | |
222 | * and zero is returned. On error, the number of errors detected is | |
223 | * returned. Individual errors are reported during the load process | |
224 | * using syms->error_report(). | |
225 | ********************************************************************** */ | |
226 | int | |
227 | dynamic_open_module(struct dynamic_loader_stream *module, | |
228 | struct dynamic_loader_sym *syms, | |
229 | struct dynamic_loader_allocate *alloc, | |
230 | struct dynamic_loader_initialize *init, | |
231 | unsigned options, void **mhandle) | |
232 | { | |
233 | register unsigned *dp, sz; | |
234 | struct dload_state dl_state; /* internal state for this call */ | |
235 | ||
236 | /* blast our internal state */ | |
237 | dp = (unsigned *)&dl_state; | |
238 | for (sz = sizeof(dl_state) / sizeof(unsigned); sz > 0; sz -= 1) | |
239 | *dp++ = 0; | |
240 | ||
241 | /* Enable _only_ BSS initialization if enabled by user */ | |
242 | if ((options & DLOAD_INITBSS) == DLOAD_INITBSS) | |
243 | dl_state.myoptions = DLOAD_INITBSS; | |
244 | ||
245 | /* Check that mandatory arguments are present */ | |
246 | if (!module || !syms) { | |
247 | dload_error(&dl_state, "Required parameter is NULL"); | |
248 | } else { | |
249 | dl_state.strm = module; | |
250 | dl_state.mysym = syms; | |
251 | dload_headers(&dl_state); | |
252 | if (!dl_state.dload_errcount) | |
253 | dload_strings(&dl_state, false); | |
254 | if (!dl_state.dload_errcount) | |
255 | dload_sections(&dl_state); | |
256 | ||
257 | if (init && !dl_state.dload_errcount) { | |
258 | if (init->connect(init)) { | |
259 | dl_state.myio = init; | |
260 | dl_state.myalloc = alloc; | |
261 | /* do now, before reducing symbols */ | |
262 | allocate_sections(&dl_state); | |
263 | } else | |
264 | dload_error(&dl_state, iconnect); | |
265 | } | |
266 | ||
267 | if (!dl_state.dload_errcount) { | |
268 | /* fix up entry point address */ | |
269 | unsigned sref = dl_state.dfile_hdr.df_entry_secn - 1; | |
270 | if (sref < dl_state.allocated_secn_count) | |
271 | dl_state.dfile_hdr.df_entrypt += | |
272 | dl_state.ldr_sections[sref].run_addr; | |
273 | ||
274 | dload_symbols(&dl_state); | |
275 | } | |
276 | ||
277 | init_module_handle(&dl_state); | |
278 | ||
279 | /* dl_state.myio is either 0 or init at this point. */ | |
280 | if (dl_state.myio) { | |
281 | if ((!dl_state.dload_errcount) && | |
282 | (dl_state.dfile_hdr.df_entry_secn != DN_UNDEF) && | |
283 | (!init->execute(init, | |
284 | dl_state.dfile_hdr.df_entrypt))) | |
285 | dload_error(&dl_state, "Init->Execute Failed"); | |
286 | init->release(init); | |
287 | } | |
288 | ||
289 | symbol_table_free(&dl_state); | |
290 | section_table_free(&dl_state); | |
291 | string_table_free(&dl_state); | |
292 | ||
293 | if (dl_state.dload_errcount) { | |
294 | dynamic_unload_module(dl_state.myhandle, syms, alloc, | |
295 | init); | |
296 | dl_state.myhandle = NULL; | |
297 | } | |
298 | } | |
299 | ||
300 | if (mhandle) | |
301 | *mhandle = dl_state.myhandle; /* give back the handle */ | |
302 | ||
303 | return dl_state.dload_errcount; | |
304 | } /* DLOAD_File */ | |
305 | ||
306 | /************************************************************************* | |
307 | * Procedure dload_headers | |
308 | * | |
309 | * Parameters: | |
310 | * none | |
311 | * | |
312 | * Effect: | |
313 | * Loads the DOFF header and verify record. Deals with any byte-order | |
314 | * issues and checks them for validity. | |
315 | *********************************************************************** */ | |
316 | #define COMBINED_HEADER_SIZE (sizeof(struct doff_filehdr_t)+ \ | |
317 | sizeof(struct doff_verify_rec_t)) | |
318 | ||
319 | void dload_headers(struct dload_state *dlthis) | |
320 | { | |
321 | u32 map; | |
322 | ||
323 | /* Read the header and the verify record as one. If we don't get it | |
324 | all, we're done */ | |
325 | if (dlthis->strm->read_buffer(dlthis->strm, &dlthis->dfile_hdr, | |
326 | COMBINED_HEADER_SIZE) != | |
327 | COMBINED_HEADER_SIZE) { | |
328 | DL_ERROR(readstrm, "File Headers"); | |
329 | return; | |
330 | } | |
331 | /* | |
332 | * Verify that we have the byte order of the file correct. | |
333 | * If not, must fix it before we can continue | |
334 | */ | |
335 | map = REORDER_MAP(dlthis->dfile_hdr.df_byte_reshuffle); | |
336 | if (map != REORDER_MAP(BYTE_RESHUFFLE_VALUE)) { | |
337 | /* input is either byte-shuffled or bad */ | |
338 | if ((map & 0xFCFCFCFC) == 0) { /* no obviously bogus bits */ | |
339 | dload_reorder(&dlthis->dfile_hdr, COMBINED_HEADER_SIZE, | |
340 | map); | |
341 | } | |
342 | if (dlthis->dfile_hdr.df_byte_reshuffle != | |
343 | BYTE_RESHUFFLE_VALUE) { | |
344 | /* didn't fix the problem, the byte swap map is bad */ | |
345 | dload_error(dlthis, | |
346 | "Bad byte swap map " FMT_UI32 " in header", | |
347 | dlthis->dfile_hdr.df_byte_reshuffle); | |
348 | return; | |
349 | } | |
350 | dlthis->reorder_map = map; /* keep map for future use */ | |
351 | } | |
352 | ||
353 | /* | |
354 | * Verify checksum of header and verify record | |
355 | */ | |
356 | if (~dload_checksum(&dlthis->dfile_hdr, | |
357 | sizeof(struct doff_filehdr_t)) || | |
358 | ~dload_checksum(&dlthis->verify, | |
359 | sizeof(struct doff_verify_rec_t))) { | |
360 | DL_ERROR(err_checksum, "header or verify record"); | |
361 | return; | |
362 | } | |
363 | #if HOST_ENDIANNESS | |
364 | dlthis->dfile_hdr.df_byte_reshuffle = map; /* put back for later */ | |
365 | #endif | |
366 | ||
367 | /* Check for valid target ID */ | |
368 | if ((dlthis->dfile_hdr.df_target_id != TARGET_ID) && | |
369 | -(dlthis->dfile_hdr.df_target_id != TMS470_ID)) { | |
370 | dload_error(dlthis, "Bad target ID 0x%x and TARGET_ID 0x%x", | |
371 | dlthis->dfile_hdr.df_target_id, TARGET_ID); | |
372 | return; | |
373 | } | |
374 | /* Check for valid file format */ | |
375 | if ((dlthis->dfile_hdr.df_doff_version != DOFF0)) { | |
376 | dload_error(dlthis, "Bad DOFF version 0x%x", | |
377 | dlthis->dfile_hdr.df_doff_version); | |
378 | return; | |
379 | } | |
380 | ||
381 | /* | |
382 | * Apply reasonableness checks to count fields | |
383 | */ | |
384 | if (dlthis->dfile_hdr.df_strtab_size > MAX_REASONABLE_STRINGTAB) { | |
385 | dload_error(dlthis, "Excessive string table size " FMT_UI32, | |
386 | dlthis->dfile_hdr.df_strtab_size); | |
387 | return; | |
388 | } | |
389 | if (dlthis->dfile_hdr.df_no_scns > MAX_REASONABLE_SECTIONS) { | |
390 | dload_error(dlthis, "Excessive section count 0x%x", | |
391 | dlthis->dfile_hdr.df_no_scns); | |
392 | return; | |
393 | } | |
394 | #ifndef TARGET_ENDIANNESS | |
395 | /* | |
396 | * Check that endianness does not disagree with explicit specification | |
397 | */ | |
398 | if ((dlthis->dfile_hdr.df_flags >> ALIGN_COFF_ENDIANNESS) & | |
399 | dlthis->myoptions & ENDIANNESS_MASK) { | |
400 | dload_error(dlthis, | |
401 | "Input endianness disagrees with specified option"); | |
402 | return; | |
403 | } | |
404 | dlthis->big_e_target = dlthis->dfile_hdr.df_flags & DF_BIG; | |
405 | #endif | |
406 | ||
407 | } /* dload_headers */ | |
408 | ||
409 | /* COFF Section Processing | |
410 | * | |
411 | * COFF sections are read in and retained intact. Each record is embedded | |
412 | * in a new structure that records the updated load and | |
413 | * run addresses of the section */ | |
414 | ||
415 | static const char secn_errid[] = { "section" }; | |
416 | ||
417 | /************************************************************************* | |
418 | * Procedure dload_sections | |
419 | * | |
420 | * Parameters: | |
421 | * none | |
422 | * | |
423 | * Effect: | |
424 | * Loads the section records into an internal table. | |
425 | *********************************************************************** */ | |
426 | void dload_sections(struct dload_state *dlthis) | |
427 | { | |
428 | s16 siz; | |
429 | struct doff_scnhdr_t *shp; | |
430 | unsigned nsecs = dlthis->dfile_hdr.df_no_scns; | |
431 | ||
432 | /* allocate space for the DOFF section records */ | |
433 | siz = nsecs * sizeof(struct doff_scnhdr_t); | |
434 | shp = | |
435 | (struct doff_scnhdr_t *)dlthis->mysym->dload_allocate(dlthis->mysym, | |
436 | siz); | |
437 | if (!shp) { /* not enough storage */ | |
438 | DL_ERROR(err_alloc, siz); | |
439 | return; | |
440 | } | |
441 | dlthis->sect_hdrs = shp; | |
442 | ||
443 | /* read in the section records */ | |
444 | if (dlthis->strm->read_buffer(dlthis->strm, shp, siz) != siz) { | |
445 | DL_ERROR(readstrm, secn_errid); | |
446 | return; | |
447 | } | |
448 | ||
449 | /* if we need to fix up byte order, do it now */ | |
450 | if (dlthis->reorder_map) | |
451 | dload_reorder(shp, siz, dlthis->reorder_map); | |
452 | ||
453 | /* check for validity */ | |
454 | if (~dload_checksum(dlthis->sect_hdrs, siz) != | |
455 | dlthis->verify.dv_scn_rec_checksum) { | |
456 | DL_ERROR(err_checksum, secn_errid); | |
457 | return; | |
458 | } | |
459 | ||
460 | } /* dload_sections */ | |
461 | ||
462 | /***************************************************************************** | |
463 | * Procedure allocate_sections | |
464 | * | |
465 | * Parameters: | |
466 | * alloc target memory allocator class | |
467 | * | |
468 | * Effect: | |
469 | * Assigns new (target) addresses for sections | |
470 | **************************************************************************** */ | |
471 | static void allocate_sections(struct dload_state *dlthis) | |
472 | { | |
473 | u16 curr_sect, nsecs, siz; | |
474 | struct doff_scnhdr_t *shp; | |
475 | struct ldr_section_info *asecs; | |
476 | struct my_handle *hndl; | |
477 | nsecs = dlthis->dfile_hdr.df_no_scns; | |
478 | if (!nsecs) | |
479 | return; | |
480 | if ((dlthis->myalloc == NULL) && | |
481 | (dlthis->dfile_hdr.df_target_scns > 0)) { | |
482 | DL_ERROR("Arg 3 (alloc) required but NULL", 0); | |
483 | return; | |
484 | } | |
485 | /* | |
486 | * allocate space for the module handle, which we will keep for unload | |
487 | * purposes include an additional section store for an auto-generated | |
488 | * trampoline section in case we need it. | |
489 | */ | |
490 | siz = (dlthis->dfile_hdr.df_target_scns + 1) * | |
491 | sizeof(struct ldr_section_info) + MY_HANDLE_SIZE; | |
492 | ||
493 | hndl = | |
494 | (struct my_handle *)dlthis->mysym->dload_allocate(dlthis->mysym, | |
495 | siz); | |
496 | if (!hndl) { /* not enough storage */ | |
497 | DL_ERROR(err_alloc, siz); | |
498 | return; | |
499 | } | |
500 | /* initialize the handle header */ | |
ee4317f7 RS |
501 | hndl->dm.next = hndl->dm.prev = hndl; /* circular list */ |
502 | hndl->dm.root = NULL; | |
26f8db7d ORL |
503 | hndl->dm.dbthis = 0; |
504 | dlthis->myhandle = hndl; /* save away for return */ | |
505 | /* pointer to the section list of allocated sections */ | |
506 | dlthis->ldr_sections = asecs = hndl->secns; | |
507 | /* * Insert names into all sections, make copies of | |
508 | the sections we allocate */ | |
509 | shp = dlthis->sect_hdrs; | |
510 | for (curr_sect = 0; curr_sect < nsecs; curr_sect++) { | |
511 | u32 soffset = shp->ds_offset; | |
512 | #if BITS_PER_AU <= BITS_PER_BYTE | |
513 | /* attempt to insert the name of this section */ | |
514 | if (soffset < dlthis->dfile_hdr.df_strtab_size) | |
803cd75e AU |
515 | ((struct ldr_section_info *)shp)->name = |
516 | dlthis->str_head + soffset; | |
26f8db7d ORL |
517 | else { |
518 | dload_error(dlthis, "Bad name offset in section %d", | |
519 | curr_sect); | |
803cd75e | 520 | ((struct ldr_section_info *)shp)->name = NULL; |
26f8db7d ORL |
521 | } |
522 | #endif | |
523 | /* allocate target storage for sections that require it */ | |
a563510f | 524 | if (ds_needs_allocation(shp)) { |
803cd75e | 525 | *asecs = *(struct ldr_section_info *)shp; |
26f8db7d ORL |
526 | asecs->context = 0; /* zero the context field */ |
527 | #if BITS_PER_AU > BITS_PER_BYTE | |
528 | asecs->name = unpack_name(dlthis, soffset); | |
529 | dlthis->debug_string_size = soffset + dlthis->temp_len; | |
530 | #else | |
531 | dlthis->debug_string_size = soffset; | |
532 | #endif | |
533 | if (dlthis->myalloc != NULL) { | |
534 | if (!dlthis->myalloc-> | |
535 | dload_allocate(dlthis->myalloc, asecs, | |
a563510f | 536 | ds_alignment(asecs->type))) { |
26f8db7d ORL |
537 | dload_error(dlthis, tgtalloc, |
538 | asecs->name, asecs->size); | |
539 | return; | |
540 | } | |
541 | } | |
542 | /* keep address deltas in original section table */ | |
543 | shp->ds_vaddr = asecs->load_addr - shp->ds_vaddr; | |
544 | shp->ds_paddr = asecs->run_addr - shp->ds_paddr; | |
545 | dlthis->allocated_secn_count += 1; | |
546 | } /* allocate target storage */ | |
547 | shp += 1; | |
548 | asecs += 1; | |
549 | } | |
550 | #if BITS_PER_AU <= BITS_PER_BYTE | |
551 | dlthis->debug_string_size += | |
552 | strlen(dlthis->str_head + dlthis->debug_string_size) + 1; | |
553 | #endif | |
554 | } /* allocate sections */ | |
555 | ||
556 | /************************************************************************* | |
557 | * Procedure section_table_free | |
558 | * | |
559 | * Parameters: | |
560 | * none | |
561 | * | |
562 | * Effect: | |
563 | * Frees any state used by the symbol table. | |
564 | * | |
565 | * WARNING: | |
566 | * This routine is not allowed to declare errors! | |
567 | *********************************************************************** */ | |
568 | static void section_table_free(struct dload_state *dlthis) | |
569 | { | |
570 | struct doff_scnhdr_t *shp; | |
571 | ||
572 | shp = dlthis->sect_hdrs; | |
573 | if (shp) | |
574 | dlthis->mysym->dload_deallocate(dlthis->mysym, shp); | |
575 | ||
576 | } /* section_table_free */ | |
577 | ||
578 | /************************************************************************* | |
579 | * Procedure dload_strings | |
580 | * | |
581 | * Parameters: | |
582 | * sec_names_only If true only read in the "section names" | |
583 | * portion of the string table | |
584 | * | |
585 | * Effect: | |
586 | * Loads the DOFF string table into memory. DOFF keeps all strings in a | |
587 | * big unsorted array. We just read that array into memory in bulk. | |
588 | *********************************************************************** */ | |
589 | static const char stringtbl[] = { "string table" }; | |
590 | ||
591 | void dload_strings(struct dload_state *dlthis, bool sec_names_only) | |
592 | { | |
593 | u32 ssiz; | |
594 | char *strbuf; | |
595 | ||
596 | if (sec_names_only) { | |
597 | ssiz = BYTE_TO_HOST(DOFF_ALIGN | |
598 | (dlthis->dfile_hdr.df_scn_name_size)); | |
599 | } else { | |
600 | ssiz = BYTE_TO_HOST(DOFF_ALIGN | |
601 | (dlthis->dfile_hdr.df_strtab_size)); | |
602 | } | |
603 | if (ssiz == 0) | |
604 | return; | |
605 | ||
606 | /* get some memory for the string table */ | |
607 | #if BITS_PER_AU > BITS_PER_BYTE | |
608 | strbuf = (char *)dlthis->mysym->dload_allocate(dlthis->mysym, ssiz + | |
609 | dlthis->dfile_hdr. | |
610 | df_max_str_len); | |
611 | #else | |
612 | strbuf = (char *)dlthis->mysym->dload_allocate(dlthis->mysym, ssiz); | |
613 | #endif | |
614 | if (strbuf == NULL) { | |
615 | DL_ERROR(err_alloc, ssiz); | |
616 | return; | |
617 | } | |
618 | dlthis->str_head = strbuf; | |
619 | #if BITS_PER_AU > BITS_PER_BYTE | |
620 | dlthis->str_temp = strbuf + ssiz; | |
621 | #endif | |
622 | /* read in the strings and verify them */ | |
623 | if ((unsigned)(dlthis->strm->read_buffer(dlthis->strm, strbuf, | |
624 | ssiz)) != ssiz) { | |
625 | DL_ERROR(readstrm, stringtbl); | |
626 | } | |
627 | /* if we need to fix up byte order, do it now */ | |
628 | #ifndef _BIG_ENDIAN | |
629 | if (dlthis->reorder_map) | |
630 | dload_reorder(strbuf, ssiz, dlthis->reorder_map); | |
631 | ||
632 | if ((!sec_names_only) && (~dload_checksum(strbuf, ssiz) != | |
633 | dlthis->verify.dv_str_tab_checksum)) { | |
634 | DL_ERROR(err_checksum, stringtbl); | |
635 | } | |
636 | #else | |
637 | if (dlthis->dfile_hdr.df_byte_reshuffle != | |
638 | HOST_BYTE_ORDER(REORDER_MAP(BYTE_RESHUFFLE_VALUE))) { | |
639 | /* put strings in big-endian order, not in PC order */ | |
640 | dload_reorder(strbuf, ssiz, | |
641 | HOST_BYTE_ORDER(dlthis-> | |
642 | dfile_hdr.df_byte_reshuffle)); | |
643 | } | |
644 | if ((!sec_names_only) && (~dload_reverse_checksum(strbuf, ssiz) != | |
645 | dlthis->verify.dv_str_tab_checksum)) { | |
646 | DL_ERROR(err_checksum, stringtbl); | |
647 | } | |
648 | #endif | |
649 | } /* dload_strings */ | |
650 | ||
651 | /************************************************************************* | |
652 | * Procedure string_table_free | |
653 | * | |
654 | * Parameters: | |
655 | * none | |
656 | * | |
657 | * Effect: | |
658 | * Frees any state used by the string table. | |
659 | * | |
660 | * WARNING: | |
661 | * This routine is not allowed to declare errors! | |
662 | ************************************************************************ */ | |
663 | static void string_table_free(struct dload_state *dlthis) | |
664 | { | |
665 | if (dlthis->str_head) | |
666 | dlthis->mysym->dload_deallocate(dlthis->mysym, | |
667 | dlthis->str_head); | |
668 | ||
669 | } /* string_table_free */ | |
670 | ||
671 | /* | |
672 | * Symbol Table Maintenance Functions | |
673 | * | |
674 | * COFF symbols are read by dload_symbols(), which is called after | |
675 | * sections have been allocated. Symbols which might be used in | |
676 | * relocation (ie, not debug info) are retained in an internal temporary | |
677 | * compressed table (type local_symbol). A particular symbol is recovered | |
678 | * by index by calling dload_find_symbol(). dload_find_symbol | |
679 | * reconstructs a more explicit representation (type SLOTVEC) which is | |
680 | * used by reloc.c | |
681 | */ | |
682 | /* real size of debug header */ | |
683 | #define DBG_HDR_SIZE (sizeof(struct dll_module) - sizeof(struct dll_sect)) | |
684 | ||
685 | static const char sym_errid[] = { "symbol" }; | |
686 | ||
687 | /************************************************************************** | |
688 | * Procedure dload_symbols | |
689 | * | |
690 | * Parameters: | |
691 | * none | |
692 | * | |
693 | * Effect: | |
694 | * Reads in symbols and retains ones that might be needed for relocation | |
695 | * purposes. | |
696 | *********************************************************************** */ | |
697 | /* size of symbol buffer no bigger than target data buffer, to limit stack | |
698 | * usage */ | |
699 | #define MY_SYM_BUF_SIZ (BYTE_TO_HOST(IMAGE_PACKET_SIZE)/\ | |
700 | sizeof(struct doff_syment_t)) | |
701 | ||
702 | static void dload_symbols(struct dload_state *dlthis) | |
703 | { | |
704 | u32 sym_count, siz, dsiz, symbols_left; | |
705 | u32 checks; | |
706 | struct local_symbol *sp; | |
707 | struct dynload_symbol *symp; | |
708 | struct dynload_symbol *newsym; | |
709 | ||
710 | sym_count = dlthis->dfile_hdr.df_no_syms; | |
711 | if (sym_count == 0) | |
712 | return; | |
713 | ||
714 | /* | |
715 | * We keep a local symbol table for all of the symbols in the input. | |
716 | * This table contains only section & value info, as we do not have | |
717 | * to do any name processing for locals. We reuse this storage | |
718 | * as a temporary for .dllview record construction. | |
719 | * Allocate storage for the whole table. Add 1 to the section count | |
720 | * in case a trampoline section is auto-generated as well as the | |
25985edc | 721 | * size of the trampoline section name so DLLView does't get lost. |
26f8db7d ORL |
722 | */ |
723 | ||
724 | siz = sym_count * sizeof(struct local_symbol); | |
725 | dsiz = DBG_HDR_SIZE + | |
726 | (sizeof(struct dll_sect) * dlthis->allocated_secn_count) + | |
727 | BYTE_TO_HOST_ROUND(dlthis->debug_string_size + 1); | |
728 | if (dsiz > siz) | |
729 | siz = dsiz; /* larger of symbols and .dllview temp */ | |
730 | sp = (struct local_symbol *)dlthis->mysym->dload_allocate(dlthis->mysym, | |
731 | siz); | |
732 | if (!sp) { | |
733 | DL_ERROR(err_alloc, siz); | |
734 | return; | |
735 | } | |
736 | dlthis->local_symtab = sp; | |
737 | /* Read the symbols in the input, store them in the table, and post any | |
738 | * globals to the global symbol table. In the process, externals | |
739 | become defined from the global symbol table */ | |
740 | checks = dlthis->verify.dv_sym_tab_checksum; | |
741 | symbols_left = sym_count; | |
742 | do { /* read all symbols */ | |
743 | char *sname; | |
744 | u32 val; | |
745 | s32 delta; | |
746 | struct doff_syment_t *input_sym; | |
747 | unsigned syms_in_buf; | |
748 | struct doff_syment_t my_sym_buf[MY_SYM_BUF_SIZ]; | |
749 | input_sym = my_sym_buf; | |
750 | syms_in_buf = symbols_left > MY_SYM_BUF_SIZ ? | |
751 | MY_SYM_BUF_SIZ : symbols_left; | |
752 | siz = syms_in_buf * sizeof(struct doff_syment_t); | |
753 | if (dlthis->strm->read_buffer(dlthis->strm, input_sym, siz) != | |
754 | siz) { | |
755 | DL_ERROR(readstrm, sym_errid); | |
756 | return; | |
757 | } | |
758 | if (dlthis->reorder_map) | |
759 | dload_reorder(input_sym, siz, dlthis->reorder_map); | |
760 | ||
761 | checks += dload_checksum(input_sym, siz); | |
762 | do { /* process symbols in buffer */ | |
763 | symbols_left -= 1; | |
764 | /* attempt to derive the name of this symbol */ | |
765 | sname = NULL; | |
766 | if (input_sym->dn_offset > 0) { | |
767 | #if BITS_PER_AU <= BITS_PER_BYTE | |
768 | if ((u32) input_sym->dn_offset < | |
769 | dlthis->dfile_hdr.df_strtab_size) | |
770 | sname = dlthis->str_head + | |
771 | BYTE_TO_HOST(input_sym->dn_offset); | |
772 | else | |
773 | dload_error(dlthis, | |
774 | "Bad name offset in symbol " | |
775 | " %d", symbols_left); | |
776 | #else | |
777 | sname = unpack_name(dlthis, | |
778 | input_sym->dn_offset); | |
779 | #endif | |
780 | } | |
781 | val = input_sym->dn_value; | |
782 | delta = 0; | |
783 | sp->sclass = input_sym->dn_sclass; | |
784 | sp->secnn = input_sym->dn_scnum; | |
785 | /* if this is an undefined symbol, | |
786 | * define it (or fail) now */ | |
787 | if (sp->secnn == DN_UNDEF) { | |
788 | /* pointless for static undefined */ | |
789 | if (input_sym->dn_sclass != DN_EXT) | |
790 | goto loop_cont; | |
791 | ||
792 | /* try to define symbol from previously | |
793 | * loaded images */ | |
794 | symp = dlthis->mysym->find_matching_symbol | |
795 | (dlthis->mysym, sname); | |
796 | if (!symp) { | |
797 | DL_ERROR | |
798 | ("Undefined external symbol %s", | |
799 | sname); | |
800 | goto loop_cont; | |
801 | } | |
802 | val = delta = symp->value; | |
803 | #ifdef ENABLE_TRAMP_DEBUG | |
804 | dload_syms_error(dlthis->mysym, | |
805 | "===> ext sym [%s] at %x", | |
806 | sname, val); | |
807 | #endif | |
808 | ||
809 | goto loop_cont; | |
810 | } | |
811 | /* symbol defined by this module */ | |
812 | if (sp->secnn > 0) { | |
813 | /* symbol references a section */ | |
814 | if ((unsigned)sp->secnn <= | |
815 | dlthis->allocated_secn_count) { | |
816 | /* section was allocated */ | |
817 | struct doff_scnhdr_t *srefp = | |
818 | &dlthis->sect_hdrs[sp->secnn - 1]; | |
819 | ||
820 | if (input_sym->dn_sclass == | |
821 | DN_STATLAB || | |
822 | input_sym->dn_sclass == DN_EXTLAB) { | |
823 | /* load */ | |
824 | delta = srefp->ds_vaddr; | |
825 | } else { | |
826 | /* run */ | |
827 | delta = srefp->ds_paddr; | |
828 | } | |
829 | val += delta; | |
830 | } | |
831 | goto loop_itr; | |
832 | } | |
833 | /* This symbol is an absolute symbol */ | |
834 | if (sp->secnn == DN_ABS && ((sp->sclass == DN_EXT) || | |
835 | (sp->sclass == | |
836 | DN_EXTLAB))) { | |
837 | symp = | |
838 | dlthis->mysym->find_matching_symbol(dlthis-> | |
839 | mysym, | |
840 | sname); | |
841 | if (!symp) | |
842 | goto loop_itr; | |
843 | /* This absolute symbol is already defined. */ | |
844 | if (symp->value == input_sym->dn_value) { | |
845 | /* If symbol values are equal, continue | |
846 | * but don't add to the global symbol | |
847 | * table */ | |
848 | sp->value = val; | |
849 | sp->delta = delta; | |
850 | sp += 1; | |
851 | input_sym += 1; | |
852 | continue; | |
853 | } else { | |
854 | /* If symbol values are not equal, | |
855 | * return with redefinition error */ | |
856 | DL_ERROR("Absolute symbol %s is " | |
857 | "defined multiple times with " | |
858 | "different values", sname); | |
859 | return; | |
860 | } | |
861 | } | |
862 | loop_itr: | |
863 | /* if this is a global symbol, post it to the | |
864 | * global table */ | |
865 | if (input_sym->dn_sclass == DN_EXT || | |
866 | input_sym->dn_sclass == DN_EXTLAB) { | |
867 | /* Keep this global symbol for subsequent | |
868 | * modules. Don't complain on error, to allow | |
869 | * symbol API to suppress global symbols */ | |
870 | if (!sname) | |
871 | goto loop_cont; | |
872 | ||
873 | newsym = dlthis->mysym->add_to_symbol_table | |
874 | (dlthis->mysym, sname, | |
875 | (unsigned)dlthis->myhandle); | |
876 | if (newsym) | |
877 | newsym->value = val; | |
878 | ||
879 | } /* global */ | |
880 | loop_cont: | |
881 | sp->value = val; | |
882 | sp->delta = delta; | |
883 | sp += 1; | |
884 | input_sym += 1; | |
885 | } while ((syms_in_buf -= 1) > 0); /* process sym in buf */ | |
886 | } while (symbols_left > 0); /* read all symbols */ | |
887 | if (~checks) | |
888 | dload_error(dlthis, "Checksum of symbols failed"); | |
889 | ||
890 | } /* dload_symbols */ | |
891 | ||
892 | /***************************************************************************** | |
893 | * Procedure symbol_table_free | |
894 | * | |
895 | * Parameters: | |
896 | * none | |
897 | * | |
898 | * Effect: | |
899 | * Frees any state used by the symbol table. | |
900 | * | |
901 | * WARNING: | |
902 | * This routine is not allowed to declare errors! | |
903 | **************************************************************************** */ | |
904 | static void symbol_table_free(struct dload_state *dlthis) | |
905 | { | |
906 | if (dlthis->local_symtab) { | |
907 | if (dlthis->dload_errcount) { /* blow off our symbols */ | |
908 | dlthis->mysym->purge_symbol_table(dlthis->mysym, | |
909 | (unsigned) | |
910 | dlthis->myhandle); | |
911 | } | |
912 | dlthis->mysym->dload_deallocate(dlthis->mysym, | |
913 | dlthis->local_symtab); | |
914 | } | |
915 | } /* symbol_table_free */ | |
916 | ||
917 | /* .cinit Processing | |
918 | * | |
919 | * The dynamic loader does .cinit interpretation. cload_cinit() | |
920 | * acts as a special write-to-target function, in that it takes relocated | |
921 | * data from the normal data flow, and interprets it as .cinit actions. | |
922 | * Because the normal data flow does not necessarily process the whole | |
923 | * .cinit section in one buffer, cload_cinit() must be prepared to | |
924 | * interpret the data piecemeal. A state machine is used for this | |
925 | * purpose. | |
926 | */ | |
927 | ||
928 | /* The following are only for use by reloc.c and things it calls */ | |
929 | static const struct ldr_section_info cinit_info_init = { cinitname, 0, 0, | |
930 | (ldr_addr)-1, 0, DLOAD_BSS, 0 | |
931 | }; | |
932 | ||
933 | /************************************************************************* | |
934 | * Procedure cload_cinit | |
935 | * | |
936 | * Parameters: | |
937 | * ipacket Pointer to data packet to be loaded | |
938 | * | |
939 | * Effect: | |
940 | * Interprets the data in the buffer as .cinit data, and performs the | |
941 | * appropriate initializations. | |
942 | *********************************************************************** */ | |
943 | static void cload_cinit(struct dload_state *dlthis, | |
944 | struct image_packet_t *ipacket) | |
945 | { | |
946 | #if TDATA_TO_HOST(CINIT_COUNT)*BITS_PER_AU > 16 | |
947 | s32 init_count, left; | |
948 | #else | |
949 | s16 init_count, left; | |
950 | #endif | |
951 | unsigned char *pktp = ipacket->img_data; | |
952 | unsigned char *pktend = pktp + BYTE_TO_HOST_ROUND(ipacket->packet_size); | |
953 | int temp; | |
954 | ldr_addr atmp; | |
955 | struct ldr_section_info cinit_info; | |
956 | ||
9d7d0a52 | 957 | /* PROCESS ALL THE INITIALIZATION RECORDS THE BUFFER. */ |
26f8db7d ORL |
958 | while (true) { |
959 | left = pktend - pktp; | |
960 | switch (dlthis->cinit_state) { | |
961 | case CI_COUNT: /* count field */ | |
962 | if (left < TDATA_TO_HOST(CINIT_COUNT)) | |
963 | goto loopexit; | |
964 | temp = dload_unpack(dlthis, (tgt_au_t *) pktp, | |
965 | CINIT_COUNT * TDATA_AU_BITS, 0, | |
966 | ROP_SGN); | |
967 | pktp += TDATA_TO_HOST(CINIT_COUNT); | |
968 | /* negative signifies BSS table, zero means done */ | |
969 | if (temp <= 0) { | |
970 | dlthis->cinit_state = CI_DONE; | |
971 | break; | |
972 | } | |
973 | dlthis->cinit_count = temp; | |
974 | dlthis->cinit_state = CI_ADDRESS; | |
975 | break; | |
976 | #if CINIT_ALIGN < CINIT_ADDRESS | |
977 | case CI_PARTADDRESS: | |
978 | pktp -= TDATA_TO_HOST(CINIT_ALIGN); | |
979 | /* back up pointer into space courtesy of caller */ | |
980 | *(uint16_t *) pktp = dlthis->cinit_addr; | |
981 | /* stuff in saved bits !! FALL THRU !! */ | |
982 | #endif | |
983 | case CI_ADDRESS: /* Address field for a copy packet */ | |
984 | if (left < TDATA_TO_HOST(CINIT_ADDRESS)) { | |
985 | #if CINIT_ALIGN < CINIT_ADDRESS | |
986 | if (left == TDATA_TO_HOST(CINIT_ALIGN)) { | |
987 | /* address broken into halves */ | |
988 | dlthis->cinit_addr = *(uint16_t *) pktp; | |
989 | /* remember 1st half */ | |
990 | dlthis->cinit_state = CI_PARTADDRESS; | |
991 | left = 0; | |
992 | } | |
993 | #endif | |
994 | goto loopexit; | |
995 | } | |
996 | atmp = dload_unpack(dlthis, (tgt_au_t *) pktp, | |
997 | CINIT_ADDRESS * TDATA_AU_BITS, 0, | |
998 | ROP_UNS); | |
999 | pktp += TDATA_TO_HOST(CINIT_ADDRESS); | |
1000 | #if CINIT_PAGE_BITS > 0 | |
1001 | dlthis->cinit_page = atmp & | |
1002 | ((1 << CINIT_PAGE_BITS) - 1); | |
1003 | atmp >>= CINIT_PAGE_BITS; | |
1004 | #else | |
1005 | dlthis->cinit_page = CINIT_DEFAULT_PAGE; | |
1006 | #endif | |
1007 | dlthis->cinit_addr = atmp; | |
1008 | dlthis->cinit_state = CI_COPY; | |
1009 | break; | |
1010 | case CI_COPY: /* copy bits to the target */ | |
1011 | init_count = HOST_TO_TDATA(left); | |
1012 | if (init_count > dlthis->cinit_count) | |
1013 | init_count = dlthis->cinit_count; | |
1014 | if (init_count == 0) | |
1015 | goto loopexit; /* get more bits */ | |
1016 | cinit_info = cinit_info_init; | |
1017 | cinit_info.page = dlthis->cinit_page; | |
1018 | if (!dlthis->myio->writemem(dlthis->myio, pktp, | |
1019 | TDATA_TO_TADDR | |
1020 | (dlthis->cinit_addr), | |
1021 | &cinit_info, | |
1022 | TDATA_TO_HOST(init_count))) { | |
1023 | dload_error(dlthis, initfail, "write", | |
1024 | dlthis->cinit_addr); | |
1025 | } | |
1026 | dlthis->cinit_count -= init_count; | |
1027 | if (dlthis->cinit_count <= 0) { | |
1028 | dlthis->cinit_state = CI_COUNT; | |
1029 | init_count = (init_count + CINIT_ALIGN - 1) & | |
1030 | -CINIT_ALIGN; | |
1031 | /* align to next init */ | |
1032 | } | |
1033 | pktp += TDATA_TO_HOST(init_count); | |
1034 | dlthis->cinit_addr += init_count; | |
1035 | break; | |
1036 | case CI_DONE: /* no more .cinit to do */ | |
1037 | return; | |
1038 | } /* switch (cinit_state) */ | |
1039 | } /* while */ | |
1040 | ||
1041 | loopexit: | |
1042 | if (left > 0) { | |
1043 | dload_error(dlthis, "%d bytes left over in cinit packet", left); | |
1044 | dlthis->cinit_state = CI_DONE; /* left over bytes are bad */ | |
1045 | } | |
1046 | } /* cload_cinit */ | |
1047 | ||
1048 | /* Functions to interface to reloc.c | |
1049 | * | |
1050 | * reloc.c is the relocation module borrowed from the linker, with | |
1051 | * minimal (we hope) changes for our purposes. cload_sect_data() invokes | |
1052 | * this module on a section to relocate and load the image data for that | |
1053 | * section. The actual read and write actions are supplied by the global | |
1054 | * routines below. | |
1055 | */ | |
1056 | ||
1057 | /************************************************************************ | |
1058 | * Procedure relocate_packet | |
1059 | * | |
1060 | * Parameters: | |
1061 | * ipacket Pointer to an image packet to relocate | |
1062 | * | |
1063 | * Effect: | |
1064 | * Performs the required relocations on the packet. Returns a checksum | |
1065 | * of the relocation operations. | |
1066 | *********************************************************************** */ | |
1067 | #define MY_RELOC_BUF_SIZ 8 | |
1068 | /* careful! exists at the same time as the image buffer */ | |
1069 | static int relocate_packet(struct dload_state *dlthis, | |
1070 | struct image_packet_t *ipacket, | |
1071 | u32 *checks, bool *tramps_generated) | |
1072 | { | |
1073 | u32 rnum; | |
1074 | *tramps_generated = false; | |
1075 | ||
1076 | rnum = ipacket->num_relocs; | |
1077 | do { /* all relocs */ | |
1078 | unsigned rinbuf; | |
1079 | int siz; | |
1080 | struct reloc_record_t *rp, rrec[MY_RELOC_BUF_SIZ]; | |
1081 | rp = rrec; | |
1082 | rinbuf = rnum > MY_RELOC_BUF_SIZ ? MY_RELOC_BUF_SIZ : rnum; | |
1083 | siz = rinbuf * sizeof(struct reloc_record_t); | |
1084 | if (dlthis->strm->read_buffer(dlthis->strm, rp, siz) != siz) { | |
1085 | DL_ERROR(readstrm, "relocation"); | |
1086 | return 0; | |
1087 | } | |
1088 | /* reorder the bytes if need be */ | |
1089 | if (dlthis->reorder_map) | |
1090 | dload_reorder(rp, siz, dlthis->reorder_map); | |
1091 | ||
1092 | *checks += dload_checksum(rp, siz); | |
1093 | do { | |
1094 | /* perform the relocation operation */ | |
1095 | dload_relocate(dlthis, (tgt_au_t *) ipacket->img_data, | |
1096 | rp, tramps_generated, false); | |
1097 | rp += 1; | |
1098 | rnum -= 1; | |
1099 | } while ((rinbuf -= 1) > 0); | |
1100 | } while (rnum > 0); /* all relocs */ | |
1101 | /* If trampoline(s) were generated, we need to do an update of the | |
1102 | * trampoline copy of the packet since a 2nd phase relo will be done | |
1103 | * later. */ | |
1104 | if (*tramps_generated == true) { | |
1105 | dload_tramp_pkt_udpate(dlthis, | |
1106 | (dlthis->image_secn - | |
1107 | dlthis->ldr_sections), | |
1108 | dlthis->image_offset, ipacket); | |
1109 | } | |
1110 | ||
1111 | return 1; | |
1112 | } /* dload_read_reloc */ | |
1113 | ||
1114 | #define IPH_SIZE (sizeof(struct image_packet_t) - sizeof(u32)) | |
1115 | ||
1116 | /* VERY dangerous */ | |
1117 | static const char imagepak[] = { "image packet" }; | |
1118 | ||
1119 | /************************************************************************* | |
1120 | * Procedure dload_data | |
1121 | * | |
1122 | * Parameters: | |
1123 | * none | |
1124 | * | |
1125 | * Effect: | |
1126 | * Read image data from input file, relocate it, and download it to the | |
1127 | * target. | |
1128 | *********************************************************************** */ | |
1129 | static void dload_data(struct dload_state *dlthis) | |
1130 | { | |
1131 | u16 curr_sect; | |
1132 | struct doff_scnhdr_t *sptr = dlthis->sect_hdrs; | |
1133 | struct ldr_section_info *lptr = dlthis->ldr_sections; | |
26f8db7d ORL |
1134 | u8 *dest; |
1135 | ||
1136 | struct { | |
1137 | struct image_packet_t ipacket; | |
1138 | u8 bufr[BYTE_TO_HOST(IMAGE_PACKET_SIZE)]; | |
1139 | } ibuf; | |
1140 | ||
1141 | /* Indicates whether CINIT processing has occurred */ | |
1142 | bool cinit_processed = false; | |
1143 | ||
1144 | /* Loop through the sections and load them one at a time. | |
1145 | */ | |
1146 | for (curr_sect = 0; curr_sect < dlthis->dfile_hdr.df_no_scns; | |
1147 | curr_sect += 1) { | |
a563510f | 1148 | if (ds_needs_download(sptr)) { |
26f8db7d ORL |
1149 | s32 nip; |
1150 | ldr_addr image_offset = 0; | |
1151 | /* set relocation info for this section */ | |
1152 | if (curr_sect < dlthis->allocated_secn_count) | |
1153 | dlthis->delta_runaddr = sptr->ds_paddr; | |
1154 | else { | |
803cd75e | 1155 | lptr = (struct ldr_section_info *)sptr; |
26f8db7d ORL |
1156 | dlthis->delta_runaddr = 0; |
1157 | } | |
1158 | dlthis->image_secn = lptr; | |
1159 | #if BITS_PER_AU > BITS_PER_BYTE | |
1160 | lptr->name = unpack_name(dlthis, sptr->ds_offset); | |
1161 | #endif | |
1162 | nip = sptr->ds_nipacks; | |
1163 | while ((nip -= 1) >= 0) { /* process packets */ | |
1164 | ||
1165 | s32 ipsize; | |
1166 | u32 checks; | |
1167 | bool tramp_generated = false; | |
1168 | ||
1169 | /* get the fixed header bits */ | |
1170 | if (dlthis->strm->read_buffer(dlthis->strm, | |
1171 | &ibuf.ipacket, | |
1172 | IPH_SIZE) != | |
1173 | IPH_SIZE) { | |
1174 | DL_ERROR(readstrm, imagepak); | |
1175 | return; | |
1176 | } | |
1177 | /* reorder the header if need be */ | |
1178 | if (dlthis->reorder_map) { | |
1179 | dload_reorder(&ibuf.ipacket, IPH_SIZE, | |
1180 | dlthis->reorder_map); | |
1181 | } | |
1182 | /* now read the rest of the packet */ | |
1183 | ipsize = | |
1184 | BYTE_TO_HOST(DOFF_ALIGN | |
1185 | (ibuf.ipacket.packet_size)); | |
1186 | if (ipsize > BYTE_TO_HOST(IMAGE_PACKET_SIZE)) { | |
1187 | DL_ERROR("Bad image packet size %d", | |
1188 | ipsize); | |
1189 | return; | |
1190 | } | |
1191 | dest = ibuf.bufr; | |
26f8db7d ORL |
1192 | /* End of determination */ |
1193 | ||
1194 | if (dlthis->strm->read_buffer(dlthis->strm, | |
1195 | ibuf.bufr, | |
1196 | ipsize) != | |
1197 | ipsize) { | |
1198 | DL_ERROR(readstrm, imagepak); | |
1199 | return; | |
1200 | } | |
1201 | ibuf.ipacket.img_data = dest; | |
1202 | ||
1203 | /* reorder the bytes if need be */ | |
1204 | #if !defined(_BIG_ENDIAN) || (TARGET_AU_BITS > 16) | |
1205 | if (dlthis->reorder_map) { | |
1206 | dload_reorder(dest, ipsize, | |
1207 | dlthis->reorder_map); | |
1208 | } | |
1209 | checks = dload_checksum(dest, ipsize); | |
1210 | #else | |
1211 | if (dlthis->dfile_hdr.df_byte_reshuffle != | |
1212 | TARGET_ORDER(REORDER_MAP | |
1213 | (BYTE_RESHUFFLE_VALUE))) { | |
1214 | /* put image bytes in big-endian order, | |
1215 | * not PC order */ | |
1216 | dload_reorder(dest, ipsize, | |
1217 | TARGET_ORDER | |
1218 | (dlthis->dfile_hdr. | |
1219 | df_byte_reshuffle)); | |
1220 | } | |
1221 | #if TARGET_AU_BITS > 8 | |
1222 | checks = dload_reverse_checksum16(dest, ipsize); | |
1223 | #else | |
1224 | checks = dload_reverse_checksum(dest, ipsize); | |
1225 | #endif | |
1226 | #endif | |
1227 | ||
1228 | checks += dload_checksum(&ibuf.ipacket, | |
1229 | IPH_SIZE); | |
1230 | /* relocate the image bits as needed */ | |
1231 | if (ibuf.ipacket.num_relocs) { | |
1232 | dlthis->image_offset = image_offset; | |
1233 | if (!relocate_packet(dlthis, | |
1234 | &ibuf.ipacket, | |
1235 | &checks, | |
1236 | &tramp_generated)) | |
1237 | return; /* serious error */ | |
1238 | } | |
1239 | if (~checks) | |
1240 | DL_ERROR(err_checksum, imagepak); | |
1241 | /* Only write the result to the target if no | |
1242 | * trampoline was generated. Otherwise it | |
1243 | *will be done during trampoline finalize. */ | |
1244 | ||
1245 | if (tramp_generated == false) { | |
1246 | ||
1247 | /* stuff the result into target | |
1248 | * memory */ | |
a563510f AU |
1249 | if (dload_check_type(sptr, |
1250 | DLOAD_CINIT)) { | |
26f8db7d ORL |
1251 | cload_cinit(dlthis, |
1252 | &ibuf.ipacket); | |
1253 | cinit_processed = true; | |
1254 | } else { | |
92d02930 RFE |
1255 | /* FIXME */ |
1256 | if (!dlthis->myio-> | |
1257 | writemem(dlthis-> | |
1258 | myio, | |
1259 | ibuf.bufr, | |
1260 | lptr-> | |
1261 | load_addr + | |
1262 | image_offset, | |
1263 | lptr, | |
1264 | BYTE_TO_HOST | |
1265 | (ibuf. | |
1266 | ipacket. | |
1267 | packet_size))) { | |
1268 | DL_ERROR | |
1269 | ("Write to " | |
1270 | FMT_UI32 | |
1271 | " failed", | |
1272 | lptr-> | |
1273 | load_addr + | |
1274 | image_offset); | |
26f8db7d | 1275 | } |
26f8db7d ORL |
1276 | } |
1277 | } | |
1278 | image_offset += | |
1279 | BYTE_TO_TADDR(ibuf.ipacket.packet_size); | |
1280 | } /* process packets */ | |
1281 | /* if this is a BSS section, we may want to fill it */ | |
a563510f | 1282 | if (!dload_check_type(sptr, DLOAD_BSS)) |
26f8db7d ORL |
1283 | goto loop_cont; |
1284 | ||
1285 | if (!(dlthis->myoptions & DLOAD_INITBSS)) | |
1286 | goto loop_cont; | |
1287 | ||
1288 | if (cinit_processed) { | |
1289 | /* Don't clear BSS after load-time | |
1290 | * initialization */ | |
1291 | DL_ERROR | |
1292 | ("Zero-initialization at " FMT_UI32 | |
1293 | " after " "load-time initialization!", | |
1294 | lptr->load_addr); | |
1295 | goto loop_cont; | |
1296 | } | |
1297 | /* fill the .bss area */ | |
1298 | dlthis->myio->fillmem(dlthis->myio, | |
1299 | TADDR_TO_HOST(lptr->load_addr), | |
1300 | lptr, TADDR_TO_HOST(lptr->size), | |
1301 | DLOAD_FILL_BSS); | |
1302 | goto loop_cont; | |
1303 | } | |
1304 | /* if DS_DOWNLOAD_MASK */ | |
1305 | /* If not loading, but BSS, zero initialize */ | |
a563510f | 1306 | if (!dload_check_type(sptr, DLOAD_BSS)) |
26f8db7d ORL |
1307 | goto loop_cont; |
1308 | ||
1309 | if (!(dlthis->myoptions & DLOAD_INITBSS)) | |
1310 | goto loop_cont; | |
1311 | ||
1312 | if (curr_sect >= dlthis->allocated_secn_count) | |
803cd75e | 1313 | lptr = (struct ldr_section_info *)sptr; |
26f8db7d ORL |
1314 | |
1315 | if (cinit_processed) { | |
1316 | /*Don't clear BSS after load-time initialization */ | |
1317 | DL_ERROR("Zero-initialization at " FMT_UI32 | |
1318 | " attempted after " | |
1319 | "load-time initialization!", lptr->load_addr); | |
1320 | goto loop_cont; | |
1321 | } | |
1322 | /* fill the .bss area */ | |
1323 | dlthis->myio->fillmem(dlthis->myio, | |
1324 | TADDR_TO_HOST(lptr->load_addr), lptr, | |
1325 | TADDR_TO_HOST(lptr->size), | |
1326 | DLOAD_FILL_BSS); | |
1327 | loop_cont: | |
1328 | sptr += 1; | |
1329 | lptr += 1; | |
1330 | } /* load sections */ | |
1331 | ||
1332 | /* Finalize any trampolines that were created during the load */ | |
1333 | if (dload_tramp_finalize(dlthis) == 0) { | |
1334 | DL_ERROR("Finalization of auto-trampolines (size = " FMT_UI32 | |
1335 | ") failed", dlthis->tramp.tramp_sect_next_addr); | |
1336 | } | |
1337 | } /* dload_data */ | |
1338 | ||
1339 | /************************************************************************* | |
1340 | * Procedure dload_reorder | |
1341 | * | |
1342 | * Parameters: | |
1343 | * data 32-bit aligned pointer to data to be byte-swapped | |
1344 | * dsiz size of the data to be reordered in sizeof() units. | |
1345 | * map 32-bit map defining how to reorder the data. Value | |
1346 | * must be REORDER_MAP() of some permutation | |
1347 | * of 0x00 01 02 03 | |
1348 | * | |
1349 | * Effect: | |
1350 | * Re-arranges the bytes in each word according to the map specified. | |
1351 | * | |
1352 | *********************************************************************** */ | |
1353 | /* mask for byte shift count */ | |
1354 | #define SHIFT_COUNT_MASK (3 << LOG_BITS_PER_BYTE) | |
1355 | ||
1356 | void dload_reorder(void *data, int dsiz, unsigned int map) | |
1357 | { | |
1358 | register u32 tmp, tmap, datv; | |
1359 | u32 *dp = (u32 *) data; | |
1360 | ||
1361 | map <<= LOG_BITS_PER_BYTE; /* align map with SHIFT_COUNT_MASK */ | |
1362 | do { | |
1363 | tmp = 0; | |
1364 | datv = *dp; | |
1365 | tmap = map; | |
1366 | do { | |
1367 | tmp |= (datv & BYTE_MASK) << (tmap & SHIFT_COUNT_MASK); | |
1368 | tmap >>= BITS_PER_BYTE; | |
1369 | } while (datv >>= BITS_PER_BYTE); | |
1370 | *dp++ = tmp; | |
1371 | } while ((dsiz -= sizeof(u32)) > 0); | |
1372 | } /* dload_reorder */ | |
1373 | ||
1374 | /************************************************************************* | |
1375 | * Procedure dload_checksum | |
1376 | * | |
1377 | * Parameters: | |
1378 | * data 32-bit aligned pointer to data to be checksummed | |
1379 | * siz size of the data to be checksummed in sizeof() units. | |
1380 | * | |
1381 | * Effect: | |
1382 | * Returns a checksum of the specified block | |
1383 | * | |
1384 | *********************************************************************** */ | |
1385 | u32 dload_checksum(void *data, unsigned siz) | |
1386 | { | |
1387 | u32 sum; | |
1388 | u32 *dp; | |
1389 | int left; | |
1390 | ||
1391 | sum = 0; | |
1392 | dp = (u32 *) data; | |
1393 | for (left = siz; left > 0; left -= sizeof(u32)) | |
1394 | sum += *dp++; | |
1395 | return sum; | |
1396 | } /* dload_checksum */ | |
1397 | ||
1398 | #if HOST_ENDIANNESS | |
1399 | /************************************************************************* | |
1400 | * Procedure dload_reverse_checksum | |
1401 | * | |
1402 | * Parameters: | |
1403 | * data 32-bit aligned pointer to data to be checksummed | |
1404 | * siz size of the data to be checksummed in sizeof() units. | |
1405 | * | |
1406 | * Effect: | |
1407 | * Returns a checksum of the specified block, which is assumed to be bytes | |
1408 | * in big-endian order. | |
1409 | * | |
1410 | * Notes: | |
1411 | * In a big-endian host, things like the string table are stored as bytes | |
1412 | * in host order. But dllcreate always checksums in little-endian order. | |
1413 | * It is most efficient to just handle the difference a word at a time. | |
1414 | * | |
1415 | ********************************************************************** */ | |
1416 | u32 dload_reverse_checksum(void *data, unsigned siz) | |
1417 | { | |
1418 | u32 sum, temp; | |
1419 | u32 *dp; | |
1420 | int left; | |
1421 | ||
1422 | sum = 0; | |
1423 | dp = (u32 *) data; | |
1424 | ||
1425 | for (left = siz; left > 0; left -= sizeof(u32)) { | |
1426 | temp = *dp++; | |
1427 | sum += temp << BITS_PER_BYTE * 3; | |
1428 | sum += temp >> BITS_PER_BYTE * 3; | |
1429 | sum += (temp >> BITS_PER_BYTE) & (BYTE_MASK << BITS_PER_BYTE); | |
1430 | sum += (temp & (BYTE_MASK << BITS_PER_BYTE)) << BITS_PER_BYTE; | |
1431 | } | |
1432 | ||
1433 | return sum; | |
1434 | } /* dload_reverse_checksum */ | |
1435 | ||
1436 | #if (TARGET_AU_BITS > 8) && (TARGET_AU_BITS < 32) | |
1437 | u32 dload_reverse_checksum16(void *data, unsigned siz) | |
1438 | { | |
1439 | uint_fast32_t sum, temp; | |
1440 | u32 *dp; | |
1441 | int left; | |
1442 | ||
1443 | sum = 0; | |
1444 | dp = (u32 *) data; | |
1445 | ||
1446 | for (left = siz; left > 0; left -= sizeof(u32)) { | |
1447 | temp = *dp++; | |
1448 | sum += temp << BITS_PER_BYTE * 2; | |
1449 | sum += temp >> BITS_PER_BYTE * 2; | |
1450 | } | |
1451 | ||
1452 | return sum; | |
1453 | } /* dload_reverse_checksum16 */ | |
1454 | #endif | |
1455 | #endif | |
1456 | ||
1457 | /************************************************************************* | |
1458 | * Procedure swap_words | |
1459 | * | |
1460 | * Parameters: | |
1461 | * data 32-bit aligned pointer to data to be swapped | |
1462 | * siz size of the data to be swapped. | |
1463 | * bitmap Bit map of how to swap each 32-bit word; 1 => 2 shorts, | |
1464 | * 0 => 1 long | |
1465 | * | |
1466 | * Effect: | |
1467 | * Swaps the specified data according to the specified map | |
1468 | * | |
1469 | *********************************************************************** */ | |
1470 | static void swap_words(void *data, unsigned siz, unsigned bitmap) | |
1471 | { | |
1472 | register int i; | |
1473 | #if TARGET_AU_BITS < 16 | |
1474 | register u16 *sp; | |
1475 | #endif | |
1476 | register u32 *lp; | |
1477 | ||
1478 | siz /= sizeof(u16); | |
1479 | ||
1480 | #if TARGET_AU_BITS < 16 | |
1481 | /* pass 1: do all the bytes */ | |
1482 | i = siz; | |
1483 | sp = (u16 *) data; | |
1484 | do { | |
1485 | register u16 tmp; | |
1486 | tmp = *sp; | |
1487 | *sp++ = SWAP16BY8(tmp); | |
1488 | } while ((i -= 1) > 0); | |
1489 | #endif | |
1490 | ||
1491 | #if TARGET_AU_BITS < 32 | |
1492 | /* pass 2: fixup the 32-bit words */ | |
1493 | i = siz >> 1; | |
1494 | lp = (u32 *) data; | |
1495 | do { | |
1496 | if ((bitmap & 1) == 0) { | |
1497 | register u32 tmp; | |
1498 | tmp = *lp; | |
1499 | *lp = SWAP32BY16(tmp); | |
1500 | } | |
1501 | lp += 1; | |
1502 | bitmap >>= 1; | |
1503 | } while ((i -= 1) > 0); | |
1504 | #endif | |
1505 | } /* swap_words */ | |
1506 | ||
1507 | /************************************************************************* | |
1508 | * Procedure copy_tgt_strings | |
1509 | * | |
1510 | * Parameters: | |
1511 | * dstp Destination address. Assumed to be 32-bit aligned | |
1512 | * srcp Source address. Assumed to be 32-bit aligned | |
1513 | * charcount Number of characters to copy. | |
1514 | * | |
1515 | * Effect: | |
1516 | * Copies strings from the source (which is in usual .dof file order on | |
1517 | * the loading processor) to the destination buffer (which should be in proper | |
1518 | * target addressable unit order). Makes sure the last string in the | |
1519 | * buffer is NULL terminated (for safety). | |
1520 | * Returns the first unused destination address. | |
1521 | *********************************************************************** */ | |
1522 | static char *copy_tgt_strings(void *dstp, void *srcp, unsigned charcount) | |
1523 | { | |
1524 | register tgt_au_t *src = (tgt_au_t *) srcp; | |
1525 | register tgt_au_t *dst = (tgt_au_t *) dstp; | |
1526 | register int cnt = charcount; | |
1527 | do { | |
1528 | #if TARGET_AU_BITS <= BITS_PER_AU | |
1529 | /* byte-swapping issues may exist for strings on target */ | |
1530 | *dst++ = *src++; | |
1531 | #else | |
1532 | *dst++ = *src++; | |
1533 | #endif | |
1534 | } while ((cnt -= (sizeof(tgt_au_t) * BITS_PER_AU / BITS_PER_BYTE)) > 0); | |
1535 | /*apply force to make sure that the string table has null terminator */ | |
1536 | #if (BITS_PER_AU == BITS_PER_BYTE) && (TARGET_AU_BITS == BITS_PER_BYTE) | |
1537 | dst[-1] = 0; | |
1538 | #else | |
1539 | /* little endian */ | |
1540 | dst[-1] &= (1 << (BITS_PER_AU - BITS_PER_BYTE)) - 1; | |
1541 | #endif | |
1542 | return (char *)dst; | |
1543 | } /* copy_tgt_strings */ | |
1544 | ||
1545 | /************************************************************************* | |
1546 | * Procedure init_module_handle | |
1547 | * | |
1548 | * Parameters: | |
1549 | * none | |
1550 | * | |
1551 | * Effect: | |
1552 | * Initializes the module handle we use to enable unloading, and installs | |
1553 | * the debug information required by the target. | |
1554 | * | |
1555 | * Notes: | |
1556 | * The handle returned from dynamic_load_module needs to encapsulate all the | |
1557 | * allocations done for the module, and enable them plus the modules symbols to | |
1558 | * be deallocated. | |
1559 | * | |
1560 | *********************************************************************** */ | |
1561 | #ifndef _BIG_ENDIAN | |
1562 | static const struct ldr_section_info dllview_info_init = { ".dllview", 0, 0, | |
1563 | (ldr_addr)-1, DBG_LIST_PAGE, DLOAD_DATA, 0 | |
1564 | }; | |
1565 | #else | |
1566 | static const struct ldr_section_info dllview_info_init = { ".dllview", 0, 0, | |
1567 | (ldr_addr)-1, DLOAD_DATA, DBG_LIST_PAGE, 0 | |
1568 | }; | |
1569 | #endif | |
1570 | static void init_module_handle(struct dload_state *dlthis) | |
1571 | { | |
1572 | struct my_handle *hndl; | |
1573 | u16 curr_sect; | |
1574 | struct ldr_section_info *asecs; | |
1575 | struct dll_module *dbmod; | |
1576 | struct dll_sect *dbsec; | |
1577 | struct dbg_mirror_root *mlist; | |
1578 | register char *cp; | |
1579 | struct modules_header mhdr; | |
1580 | struct ldr_section_info dllview_info; | |
1581 | struct dynload_symbol *debug_mirror_sym; | |
1582 | hndl = dlthis->myhandle; | |
1583 | if (!hndl) | |
1584 | return; /* must be errors detected, so forget it */ | |
1585 | ||
1586 | /* Store the section count */ | |
1587 | hndl->secn_count = dlthis->allocated_secn_count; | |
1588 | ||
1589 | /* If a trampoline section was created, add it in */ | |
1590 | if (dlthis->tramp.tramp_sect_next_addr != 0) | |
1591 | hndl->secn_count += 1; | |
1592 | ||
1593 | hndl->secn_count = hndl->secn_count << 1; | |
1594 | ||
1595 | hndl->secn_count = dlthis->allocated_secn_count << 1; | |
1596 | #ifndef TARGET_ENDIANNESS | |
1597 | if (dlthis->big_e_target) | |
1598 | hndl->secn_count += 1; /* flag for big-endian */ | |
1599 | #endif | |
1600 | if (dlthis->dload_errcount) | |
1601 | return; /* abandon if errors detected */ | |
1602 | /* Locate the symbol that names the header for the CCS debug list | |
1603 | of modules. If not found, we just don't generate the debug record. | |
1604 | If found, we create our modules list. We make sure to create the | |
1605 | loader_dllview_root even if there is no relocation info to record, | |
1606 | just to try to put both symbols in the same symbol table and | |
1607 | module. */ | |
1608 | debug_mirror_sym = dlthis->mysym->find_matching_symbol(dlthis->mysym, | |
1609 | loader_dllview_root); | |
1610 | if (!debug_mirror_sym) { | |
1611 | struct dynload_symbol *dlmodsym; | |
1612 | struct dbg_mirror_root *mlst; | |
1613 | ||
1614 | /* our root symbol is not yet present; | |
1615 | check if we have DLModules defined */ | |
1616 | dlmodsym = dlthis->mysym->find_matching_symbol(dlthis->mysym, | |
1617 | LINKER_MODULES_HEADER); | |
1618 | if (!dlmodsym) | |
1619 | return; /* no DLModules list so no debug info */ | |
1620 | /* if we have DLModules defined, construct our header */ | |
1621 | mlst = (struct dbg_mirror_root *) | |
1622 | dlthis->mysym->dload_allocate(dlthis->mysym, | |
1623 | sizeof(struct | |
1624 | dbg_mirror_root)); | |
1625 | if (!mlst) { | |
1626 | DL_ERROR(err_alloc, sizeof(struct dbg_mirror_root)); | |
1627 | return; | |
1628 | } | |
ee4317f7 | 1629 | mlst->next = NULL; |
26f8db7d ORL |
1630 | mlst->changes = 0; |
1631 | mlst->refcount = 0; | |
1632 | mlst->dbthis = TDATA_TO_TADDR(dlmodsym->value); | |
1633 | /* add our root symbol */ | |
1634 | debug_mirror_sym = dlthis->mysym->add_to_symbol_table | |
1635 | (dlthis->mysym, loader_dllview_root, | |
1636 | (unsigned)dlthis->myhandle); | |
1637 | if (!debug_mirror_sym) { | |
1638 | /* failed, recover memory */ | |
1639 | dlthis->mysym->dload_deallocate(dlthis->mysym, mlst); | |
1640 | return; | |
1641 | } | |
1642 | debug_mirror_sym->value = (u32) mlst; | |
1643 | } | |
1644 | /* First create the DLLview record and stuff it into the buffer. | |
1645 | Then write it to the DSP. Record pertinent locations in our hndl, | |
1646 | and add it to the per-processor list of handles with debug info. */ | |
1647 | #ifndef DEBUG_HEADER_IN_LOADER | |
1648 | mlist = (struct dbg_mirror_root *)debug_mirror_sym->value; | |
1649 | if (!mlist) | |
1650 | return; | |
1651 | #else | |
1652 | mlist = (struct dbg_mirror_root *)&debug_list_header; | |
1653 | #endif | |
ee4317f7 | 1654 | hndl->dm.root = mlist; /* set pointer to root into our handle */ |
26f8db7d ORL |
1655 | if (!dlthis->allocated_secn_count) |
1656 | return; /* no load addresses to be recorded */ | |
1657 | /* reuse temporary symbol storage */ | |
1658 | dbmod = (struct dll_module *)dlthis->local_symtab; | |
1659 | /* Create the DLLview record in the memory we retain for our handle */ | |
1660 | dbmod->num_sects = dlthis->allocated_secn_count; | |
1661 | dbmod->timestamp = dlthis->verify.dv_timdat; | |
1662 | dbmod->version = INIT_VERSION; | |
1663 | dbmod->verification = VERIFICATION; | |
1664 | asecs = dlthis->ldr_sections; | |
1665 | dbsec = dbmod->sects; | |
1666 | for (curr_sect = dlthis->allocated_secn_count; | |
1667 | curr_sect > 0; curr_sect -= 1) { | |
1668 | dbsec->sect_load_adr = asecs->load_addr; | |
1669 | dbsec->sect_run_adr = asecs->run_addr; | |
1670 | dbsec += 1; | |
1671 | asecs += 1; | |
1672 | } | |
1673 | ||
1674 | /* If a trampoline section was created go ahead and add its info */ | |
1675 | if (dlthis->tramp.tramp_sect_next_addr != 0) { | |
1676 | dbmod->num_sects++; | |
1677 | dbsec->sect_load_adr = asecs->load_addr; | |
1678 | dbsec->sect_run_adr = asecs->run_addr; | |
1679 | dbsec++; | |
1680 | asecs++; | |
1681 | } | |
1682 | ||
1683 | /* now cram in the names */ | |
1684 | cp = copy_tgt_strings(dbsec, dlthis->str_head, | |
1685 | dlthis->debug_string_size); | |
1686 | ||
1687 | /* If a trampoline section was created, add its name so DLLView | |
1688 | * can show the user the section info. */ | |
1689 | if (dlthis->tramp.tramp_sect_next_addr != 0) { | |
1690 | cp = copy_tgt_strings(cp, | |
1691 | dlthis->tramp.final_string_table, | |
1692 | strlen(dlthis->tramp.final_string_table) + | |
1693 | 1); | |
1694 | } | |
1695 | ||
1696 | /* round off the size of the debug record, and remember same */ | |
1697 | hndl->dm.dbsiz = HOST_TO_TDATA_ROUND(cp - (char *)dbmod); | |
1698 | *cp = 0; /* strictly to make our test harness happy */ | |
1699 | dllview_info = dllview_info_init; | |
1700 | dllview_info.size = TDATA_TO_TADDR(hndl->dm.dbsiz); | |
1701 | /* Initialize memory context to default heap */ | |
1702 | dllview_info.context = 0; | |
1703 | hndl->dm.context = 0; | |
1704 | /* fill in next pointer and size */ | |
ee4317f7 RS |
1705 | if (mlist->next) { |
1706 | dbmod->next_module = TADDR_TO_TDATA(mlist->next->dm.dbthis); | |
1707 | dbmod->next_module_size = mlist->next->dm.dbsiz; | |
26f8db7d ORL |
1708 | } else { |
1709 | dbmod->next_module_size = 0; | |
1710 | dbmod->next_module = 0; | |
1711 | } | |
1712 | /* allocate memory for on-DSP DLLview debug record */ | |
1713 | if (!dlthis->myalloc) | |
1714 | return; | |
1715 | if (!dlthis->myalloc->dload_allocate(dlthis->myalloc, &dllview_info, | |
1716 | HOST_TO_TADDR(sizeof(u32)))) { | |
1717 | return; | |
1718 | } | |
1719 | /* Store load address of .dllview section */ | |
1720 | hndl->dm.dbthis = dllview_info.load_addr; | |
1721 | /* Store memory context (segid) in which .dllview section | |
1722 | * was allocated */ | |
1723 | hndl->dm.context = dllview_info.context; | |
1724 | mlist->refcount += 1; | |
1725 | /* swap bytes in the entire debug record, but not the string table */ | |
1726 | if (TARGET_ENDIANNESS_DIFFERS(TARGET_BIG_ENDIAN)) { | |
1727 | swap_words(dbmod, (char *)dbsec - (char *)dbmod, | |
1728 | DLL_MODULE_BITMAP); | |
1729 | } | |
1730 | /* Update the DLLview list on the DSP write new record */ | |
1731 | if (!dlthis->myio->writemem(dlthis->myio, dbmod, | |
1732 | dllview_info.load_addr, &dllview_info, | |
1733 | TADDR_TO_HOST(dllview_info.size))) { | |
1734 | return; | |
1735 | } | |
1736 | /* write new header */ | |
1737 | mhdr.first_module_size = hndl->dm.dbsiz; | |
1738 | mhdr.first_module = TADDR_TO_TDATA(dllview_info.load_addr); | |
1739 | /* swap bytes in the module header, if needed */ | |
1740 | if (TARGET_ENDIANNESS_DIFFERS(TARGET_BIG_ENDIAN)) { | |
1741 | swap_words(&mhdr, sizeof(struct modules_header) - sizeof(u16), | |
1742 | MODULES_HEADER_BITMAP); | |
1743 | } | |
1744 | dllview_info = dllview_info_init; | |
1745 | if (!dlthis->myio->writemem(dlthis->myio, &mhdr, mlist->dbthis, | |
1746 | &dllview_info, | |
1747 | sizeof(struct modules_header) - | |
1748 | sizeof(u16))) { | |
1749 | return; | |
1750 | } | |
1751 | /* Add the module handle to this processor's list | |
1752 | of handles with debug info */ | |
ee4317f7 RS |
1753 | hndl->dm.next = mlist->next; |
1754 | if (hndl->dm.next) | |
1755 | hndl->dm.next->dm.prev = hndl; | |
1756 | hndl->dm.prev = (struct my_handle *)mlist; | |
1757 | mlist->next = hndl; /* insert after root */ | |
26f8db7d ORL |
1758 | } /* init_module_handle */ |
1759 | ||
1760 | /************************************************************************* | |
1761 | * Procedure dynamic_unload_module | |
1762 | * | |
1763 | * Parameters: | |
1764 | * mhandle A module handle from dynamic_load_module | |
1765 | * syms Host-side symbol table and malloc/free functions | |
1766 | * alloc Target-side memory allocation | |
1767 | * | |
1768 | * Effect: | |
1769 | * The module specified by mhandle is unloaded. Unloading causes all | |
1770 | * target memory to be deallocated, all symbols defined by the module to | |
1771 | * be purged, and any host-side storage used by the dynamic loader for | |
1772 | * this module to be released. | |
1773 | * | |
1774 | * Returns: | |
1775 | * Zero for success. On error, the number of errors detected is returned. | |
1776 | * Individual errors are reported using syms->error_report(). | |
1777 | *********************************************************************** */ | |
1778 | int dynamic_unload_module(void *mhandle, | |
1779 | struct dynamic_loader_sym *syms, | |
1780 | struct dynamic_loader_allocate *alloc, | |
1781 | struct dynamic_loader_initialize *init) | |
1782 | { | |
1783 | s16 curr_sect; | |
1784 | struct ldr_section_info *asecs; | |
1785 | struct my_handle *hndl; | |
1786 | struct dbg_mirror_root *root; | |
1787 | unsigned errcount = 0; | |
1788 | struct ldr_section_info dllview_info = dllview_info_init; | |
1789 | struct modules_header mhdr; | |
1790 | ||
1791 | hndl = (struct my_handle *)mhandle; | |
1792 | if (!hndl) | |
1793 | return 0; /* if handle is null, nothing to do */ | |
1794 | /* Clear out the module symbols | |
1795 | * Note that if this is the module that defined MODULES_HEADER | |
1796 | (the head of the target debug list) | |
1797 | * then this operation will blow away that symbol. | |
1798 | It will therefore be impossible for subsequent | |
1799 | * operations to add entries to this un-referenceable list. */ | |
1800 | if (!syms) | |
1801 | return 1; | |
1802 | syms->purge_symbol_table(syms, (unsigned)hndl); | |
1803 | /* Deallocate target memory for sections | |
1804 | * NOTE: The trampoline section, if created, gets deleted here, too */ | |
1805 | ||
1806 | asecs = hndl->secns; | |
1807 | if (alloc) | |
1808 | for (curr_sect = (hndl->secn_count >> 1); curr_sect > 0; | |
1809 | curr_sect -= 1) { | |
1810 | asecs->name = NULL; | |
1811 | alloc->dload_deallocate(alloc, asecs++); | |
1812 | } | |
ee4317f7 | 1813 | root = hndl->dm.root; |
26f8db7d ORL |
1814 | if (!root) { |
1815 | /* there is a debug list containing this module */ | |
1816 | goto func_end; | |
1817 | } | |
1818 | if (!hndl->dm.dbthis) { /* target-side dllview record exists */ | |
1819 | goto loop_end; | |
1820 | } | |
1821 | /* Retrieve memory context in which .dllview was allocated */ | |
1822 | dllview_info.context = hndl->dm.context; | |
ee4317f7 | 1823 | if (hndl->dm.prev == hndl) |
26f8db7d ORL |
1824 | goto exitunltgt; |
1825 | ||
1826 | /* target-side dllview record is in list */ | |
1827 | /* dequeue this record from our GPP-side mirror list */ | |
ee4317f7 RS |
1828 | hndl->dm.prev->dm.next = hndl->dm.next; |
1829 | if (hndl->dm.next) | |
1830 | hndl->dm.next->dm.prev = hndl->dm.prev; | |
26f8db7d ORL |
1831 | /* Update next_module of previous entry in target list |
1832 | * We are using mhdr here as a surrogate for either a | |
1833 | struct modules_header or a dll_module */ | |
ee4317f7 RS |
1834 | if (hndl->dm.next) { |
1835 | mhdr.first_module = TADDR_TO_TDATA(hndl->dm.next->dm.dbthis); | |
1836 | mhdr.first_module_size = hndl->dm.next->dm.dbsiz; | |
26f8db7d ORL |
1837 | } else { |
1838 | mhdr.first_module = 0; | |
1839 | mhdr.first_module_size = 0; | |
1840 | } | |
1841 | if (!init) | |
1842 | goto exitunltgt; | |
1843 | ||
1844 | if (!init->connect(init)) { | |
1845 | dload_syms_error(syms, iconnect); | |
1846 | errcount += 1; | |
1847 | goto exitunltgt; | |
1848 | } | |
1849 | /* swap bytes in the module header, if needed */ | |
1850 | if (TARGET_ENDIANNESS_DIFFERS(hndl->secn_count & 0x1)) { | |
1851 | swap_words(&mhdr, sizeof(struct modules_header) - sizeof(u16), | |
1852 | MODULES_HEADER_BITMAP); | |
1853 | } | |
ee4317f7 | 1854 | if (!init->writemem(init, &mhdr, hndl->dm.prev->dm.dbthis, |
26f8db7d ORL |
1855 | &dllview_info, sizeof(struct modules_header) - |
1856 | sizeof(mhdr.update_flag))) { | |
1857 | dload_syms_error(syms, dlvwrite); | |
1858 | errcount += 1; | |
1859 | } | |
1860 | /* update change counter */ | |
1861 | root->changes += 1; | |
1862 | if (!init->writemem(init, &(root->changes), | |
1863 | root->dbthis + HOST_TO_TADDR | |
1864 | (sizeof(mhdr.first_module) + | |
1865 | sizeof(mhdr.first_module_size)), | |
1866 | &dllview_info, sizeof(mhdr.update_flag))) { | |
1867 | dload_syms_error(syms, dlvwrite); | |
1868 | errcount += 1; | |
1869 | } | |
1870 | init->release(init); | |
1871 | exitunltgt: | |
1872 | /* release target storage */ | |
1873 | dllview_info.size = TDATA_TO_TADDR(hndl->dm.dbsiz); | |
1874 | dllview_info.load_addr = hndl->dm.dbthis; | |
1875 | if (alloc) | |
1876 | alloc->dload_deallocate(alloc, &dllview_info); | |
1877 | root->refcount -= 1; | |
1878 | /* target-side dllview record exists */ | |
1879 | loop_end: | |
1880 | #ifndef DEBUG_HEADER_IN_LOADER | |
1881 | if (root->refcount <= 0) { | |
1882 | /* if all references gone, blow off the header */ | |
1883 | /* our root symbol may be gone due to the Purge above, | |
1884 | but if not, do not destroy the root */ | |
1885 | if (syms->find_matching_symbol | |
1886 | (syms, loader_dllview_root) == NULL) | |
1887 | syms->dload_deallocate(syms, root); | |
1888 | } | |
1889 | #endif | |
1890 | func_end: | |
1891 | /* there is a debug list containing this module */ | |
1892 | syms->dload_deallocate(syms, mhandle); /* release our storage */ | |
1893 | return errcount; | |
1894 | } /* dynamic_unload_module */ | |
1895 | ||
1896 | #if BITS_PER_AU > BITS_PER_BYTE | |
1897 | /************************************************************************* | |
1898 | * Procedure unpack_name | |
1899 | * | |
1900 | * Parameters: | |
1901 | * soffset Byte offset into the string table | |
1902 | * | |
1903 | * Effect: | |
1904 | * Returns a pointer to the string specified by the offset supplied, or | |
1905 | * NULL for error. | |
1906 | * | |
1907 | *********************************************************************** */ | |
1908 | static char *unpack_name(struct dload_state *dlthis, u32 soffset) | |
1909 | { | |
1910 | u8 tmp, *src; | |
1911 | char *dst; | |
1912 | ||
1913 | if (soffset >= dlthis->dfile_hdr.df_strtab_size) { | |
1914 | dload_error(dlthis, "Bad string table offset " FMT_UI32, | |
1915 | soffset); | |
1916 | return NULL; | |
1917 | } | |
1918 | src = (uint_least8_t *) dlthis->str_head + | |
1919 | (soffset >> (LOG_BITS_PER_AU - LOG_BITS_PER_BYTE)); | |
1920 | dst = dlthis->str_temp; | |
1921 | if (soffset & 1) | |
1922 | *dst++ = *src++; /* only 1 character in first word */ | |
1923 | do { | |
1924 | tmp = *src++; | |
1925 | *dst = (tmp >> BITS_PER_BYTE); | |
1926 | if (!(*dst++)) | |
1927 | break; | |
1928 | } while ((*dst++ = tmp & BYTE_MASK)); | |
1929 | dlthis->temp_len = dst - dlthis->str_temp; | |
1930 | /* squirrel away length including terminating null */ | |
1931 | return dlthis->str_temp; | |
1932 | } /* unpack_name */ | |
1933 | #endif |