i2c-eg20t: change timeout value 50msec to 1000msec
[zen-stable.git] / drivers / staging / tidspbridge / dynload / tramp.c
blob60d22ea470556843afb5a48ef9f6ce262e664e44
1 /*
2 * tramp.c
4 * DSP-BIOS Bridge driver support functions for TI OMAP processors.
6 * Copyright (C) 2009 Texas Instruments, Inc.
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.
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.
17 #include "header.h"
19 #if TMS32060
20 #include "tramp_table_c6000.c"
21 #endif
23 #define MAX_RELOS_PER_PASS 4
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.
30 static int priv_tramp_sect_tgt_alloc(struct dload_state *dlthis)
32 int ret_val = 0;
33 struct ldr_section_info *sect_info;
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];
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));
54 if (ret_val == 0)
55 dload_error(dlthis, "Failed to allocate target memory for"
56 " trampoline");
58 return ret_val;
62 * Function: priv_h2a
63 * Description: Helper function to convert a hex value to its ASCII
64 * representation. Used for trampoline symbol name generation.
66 static u8 priv_h2a(u8 value)
68 if (value > 0xF)
69 return 0xFF;
71 if (value <= 9)
72 value += 0x30;
73 else
74 value += 0x37;
76 return value;
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.
86 static void priv_tramp_sym_gen_name(u32 value, char *dst)
88 u32 i;
89 char *prefix = TRAMP_SYM_PREFIX;
90 char *dst_local = dst;
91 u8 tmp;
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;
97 /* Copy the prefix to start */
98 for (i = 0; i < strlen(TRAMP_SYM_PREFIX); i++) {
99 *dst_local = *(prefix + i);
100 dst_local++;
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
120 /* NULL terminate */
121 *dst_local = 0;
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.
130 static struct tramp_string *priv_tramp_string_create(struct dload_state *dlthis,
131 u32 str_len, char *str)
133 struct tramp_string *new_string = NULL;
134 u32 i;
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;
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;
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;
163 dlthis->tramp.string_tail = new_string;
165 /* Copy the string over to the new object */
166 for (i = 0; i < str_len; i++)
167 new_string->str[i] = str[i];
170 return new_string;
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.
178 static struct tramp_string *priv_tramp_string_find(struct dload_state *dlthis,
179 char *str)
181 struct tramp_string *cur_str = NULL;
182 struct tramp_string *ret_val = NULL;
183 u32 i;
184 u32 str_len = strlen(str);
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;
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;
202 if (i == str_len)
203 ret_val = cur_str;
206 return ret_val;
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.
215 static int priv_string_tbl_finalize(struct dload_state *dlthis)
217 int ret_val = 0;
218 struct tramp_string *cur_string;
219 char *cur_loc;
220 char *tmp;
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;
240 /* Copy the string contents */
241 for (tmp = cur_string->str;
242 *tmp != '\0'; tmp++, cur_loc++)
243 *cur_loc = *tmp;
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++;
250 /* Free the string node, we don't need it any more. */
251 dlthis->mysym->dload_deallocate(dlthis->mysym,
252 cur_string);
254 /* Move our pointer to the next one */
255 cur_string = dlthis->tramp.string_head;
258 /* Update our return value to success */
259 ret_val = 1;
260 } else
261 dload_error(dlthis, "Failed to allocate trampoline "
262 "string table");
264 return ret_val;
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.
274 static u32 priv_tramp_sect_alloc(struct dload_state *dlthis, u32 tramp_size)
276 u32 ret_val;
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);
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;
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.
299 static struct tramp_sym *priv_tramp_sym_create(struct dload_state *dlthis,
300 u32 str_index,
301 struct local_symbol *tmp_sym)
303 struct tramp_sym *new_sym = NULL;
304 u32 i;
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;
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++;
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;
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;
333 dlthis->tramp.symbol_tail = new_sym;
336 return new_sym;
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.
345 static struct tramp_sym *priv_tramp_sym_get(struct dload_state *dlthis,
346 u32 string_index)
348 struct tramp_sym *sym_found = NULL;
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;
357 return sym_found;
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.
366 static struct tramp_sym *priv_tramp_sym_find(struct dload_state *dlthis,
367 char *string)
369 struct tramp_sym *sym_found = NULL;
370 struct tramp_string *str_found = NULL;
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);
378 return sym_found;
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.
388 static int priv_tramp_sym_finalize(struct dload_state *dlthis)
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;
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;
414 /* Copy the symbol contents into the flat table */
415 *new_sym = cur_sym->sym_info;
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;
430 /* Let go of the symbol node */
431 dlthis->mysym->dload_deallocate(dlthis->mysym, cur_sym);
433 /* Move to the next node */
434 cur_sym = dlthis->tramp.symbol_head;
435 new_sym++;
438 ret_val = 1;
439 } else
440 dload_error(dlthis, "Failed to alloc trampoline sym table");
442 return ret_val;
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.
452 static int priv_tgt_img_gen(struct dload_state *dlthis, u32 base,
453 u32 gen_index, struct tramp_sym *new_ext_sym)
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;
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;
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++;
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;
487 /* Add it to the trampoline list. */
488 new_img_pkt->next = dlthis->tramp.tramp_pkts;
489 dlthis->tramp.tramp_pkts = new_img_pkt;
491 ret_val = 1;
494 return ret_val;
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.
506 static int priv_pkt_relo(struct dload_state *dlthis, tgt_au_t * data,
507 struct reloc_record_t *rp[], u32 relo_count)
509 int ret_val = 1;
510 u32 i;
511 bool tmp;
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);
519 return ret_val;
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.
531 static int priv_tramp_pkt_finalize(struct dload_state *dlthis)
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];
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;
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;
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
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;
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;
587 relos_done += i;
588 cur_relo += i;
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);
610 /* Done with the pkt, let it go */
611 dlthis->mysym->dload_deallocate(dlthis->mysym, cur_pkt);
613 /* Get the next packet to process */
614 cur_pkt = dlthis->tramp.tramp_pkts;
618 return ret_val;
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.
631 static int priv_dup_pkt_finalize(struct dload_state *dlthis)
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;
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;
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;
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;
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;
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;
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--;
695 /* DO NOT ADVANCE cur_relo, IT IS ALREADY READY TO
696 * GO! */
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);
719 dlthis->mysym->dload_deallocate(dlthis->mysym, cur_pkt);
721 /* Advance to the next packet */
722 cur_pkt = dlthis->tramp.dup_pkts;
726 return ret_val;
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.
735 static struct tramp_img_dup_pkt *priv_dup_find(struct dload_state *dlthis,
736 s16 secnn, u32 image_offset)
738 struct tramp_img_dup_pkt *cur_pkt = NULL;
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;
749 return cur_pkt;
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.
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)
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;
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);
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;
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;
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);
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);
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;
831 dup_relo->next = dup_pkt->relo_chain;
832 dup_pkt->relo_chain = dup_relo;
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");
842 return ret_val;
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.
850 bool dload_tramp_avail(struct dload_state *dlthis, struct reloc_record_t *rp)
852 bool ret_val = false;
853 u16 map_index;
854 u16 gen_index;
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;
862 return ret_val;
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.
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)
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;
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);
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
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]);
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());
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);
951 new_ext_sym = priv_tramp_sym_create(dlthis, -1,
952 ref_sym);
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);
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");
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;
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");
995 return ret_val;
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.
1008 int dload_tramp_pkt_udpate(struct dload_state *dlthis, s16 secnn,
1009 u32 image_offset, struct image_packet_t *ipacket)
1011 struct tramp_img_dup_pkt *dup_pkt = NULL;
1012 s32 i;
1013 int ret_val = 0;
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);
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);
1031 return ret_val;
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.
1042 int dload_tramp_finalize(struct dload_state *dlthis)
1044 int ret_val = 1;
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);
1051 /* Do target allocation for section BEFORE finalizing
1052 * symbols. */
1053 if (ret_val != 0)
1054 ret_val = priv_tramp_sect_tgt_alloc(dlthis);
1056 /* Finalize symbols with their correct target information and
1057 * flatten */
1058 if (ret_val != 0)
1059 ret_val = priv_tramp_sym_finalize(dlthis);
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);
1067 /* Perform a 2nd pass relocation on the dup list. */
1068 if (ret_val != 0)
1069 ret_val = priv_dup_pkt_finalize(dlthis);
1072 return ret_val;
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.
1083 void dload_tramp_cleanup(struct dload_state *dlthis)
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;
1092 /* If there were no tramps generated, just return */
1093 if (tramp->tramp_sect_next_addr == 0)
1094 return;
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;
1103 dlthis->mysym->dload_deallocate(dlthis->mysym, cur_sym);
1106 if (tramp->final_sym_table != NULL)
1107 dlthis->mysym->dload_deallocate(dlthis->mysym,
1108 tramp->final_sym_table);
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;
1116 dlthis->mysym->dload_deallocate(dlthis->mysym, cur_string);
1119 if (tramp->final_string_table != NULL)
1120 dlthis->mysym->dload_deallocate(dlthis->mysym,
1121 tramp->final_string_table);
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);
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;
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);
1141 dlthis->mysym->dload_deallocate(dlthis->mysym, cur_dup_pkt);