tizen 2.4 release
[profile/mobile/platform/kernel/linux-3.10-sc7730.git] / drivers / staging / tidspbridge / dynload / tramp.c
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         char *prefix = TRAMP_SYM_PREFIX;
90         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 finalize 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         /*  Determine 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 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 }