diff options
Diffstat (limited to 'drivers/staging/tidspbridge/dynload/tramp.c')
-rw-r--r-- | drivers/staging/tidspbridge/dynload/tramp.c | 1143 |
1 files changed, 1143 insertions, 0 deletions
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 | } | ||