Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
tramp.c
Go to the documentation of this file.
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 =
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,
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,
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,
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,
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  */
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 }