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  */
priv_tramp_sect_tgt_alloc(struct dload_state * dlthis)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  */
priv_h2a(u8 value)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  */
priv_tramp_sym_gen_name(u32 value,char * dst)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  */
priv_tramp_string_create(struct dload_state * dlthis,u32 str_len,char * str)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  */
priv_tramp_string_find(struct dload_state * dlthis,char * str)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  */
priv_string_tbl_finalize(struct dload_state * dlthis)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  */
priv_tramp_sect_alloc(struct dload_state * dlthis,u32 tramp_size)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  */
priv_tramp_sym_create(struct dload_state * dlthis,u32 str_index,struct local_symbol * tmp_sym)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  */
priv_tramp_sym_get(struct dload_state * dlthis,u32 string_index)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  */
priv_tramp_sym_find(struct dload_state * dlthis,char * string)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  */
priv_tramp_sym_finalize(struct dload_state * dlthis)388 static int priv_tramp_sym_finalize(struct dload_state *dlthis)
389 {
390 	int ret_val = 0;
391 	struct tramp_sym *cur_sym;
392 	struct ldr_section_info *tramp_sect =
393 	    &dlthis->ldr_sections[dlthis->allocated_secn_count];
394 	struct local_symbol *new_sym;
395 
396 	/*  Allocate a table to hold a flattened version of all symbols
397 	 * created. */
398 	dlthis->tramp.final_sym_table =
399 	    (struct local_symbol *)dlthis->mysym->dload_allocate(dlthis->mysym,
400 				 (sizeof(struct local_symbol) * dlthis->tramp.
401 						  tramp_sym_next_index));
402 	if (dlthis->tramp.final_sym_table != NULL) {
403 		/*  Walk the list of all symbols, copy it over to the flattened
404 		 * table. After it has been copied, the node can be freed as
405 		 * it is no longer needed. */
406 		new_sym = dlthis->tramp.final_sym_table;
407 		cur_sym = dlthis->tramp.symbol_head;
408 		while (cur_sym != NULL) {
409 			/*  Pop it off the list */
410 			dlthis->tramp.symbol_head = cur_sym->next;
411 			if (cur_sym == dlthis->tramp.symbol_tail)
412 				dlthis->tramp.symbol_tail = NULL;
413 
414 			/*  Copy the symbol contents into the flat table */
415 			*new_sym = cur_sym->sym_info;
416 
417 			/*  Now finaize the symbol.  If it is in the tramp
418 			 * section, we need to adjust for the section start.
419 			 * If it is external then we don't need to adjust at
420 			 * all.
421 			 * NOTE: THIS CODE ASSUMES THAT THE TRAMPOLINE IS
422 			 * REFERENCED LIKE A CALL TO AN EXTERNAL SO VALUE AND
423 			 * DELTA ARE THE SAME.  SEE THE FUNCTION dload_symbols
424 			 * WHERE DN_UNDEF IS HANDLED FOR MORE REFERENCE. */
425 			if (new_sym->secnn < 0) {
426 				new_sym->value += tramp_sect->load_addr;
427 				new_sym->delta = new_sym->value;
428 			}
429 
430 			/*  Let go of the symbol node */
431 			dlthis->mysym->dload_deallocate(dlthis->mysym, cur_sym);
432 
433 			/*  Move to the next node */
434 			cur_sym = dlthis->tramp.symbol_head;
435 			new_sym++;
436 		}
437 
438 		ret_val = 1;
439 	} else
440 		dload_error(dlthis, "Failed to alloc trampoline sym table");
441 
442 	return ret_val;
443 }
444 
445 /*
446  * Function:	priv_tgt_img_gen
447  * Description: Allocate storage for and copy the target specific image data
448  *	and fix up its relocations for the new external symbol.  If
449  *	a trampoline image packet was successfully created it is added
450  *	to the trampoline list.
451  */
priv_tgt_img_gen(struct dload_state * dlthis,u32 base,u32 gen_index,struct tramp_sym * new_ext_sym)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  */
priv_pkt_relo(struct dload_state * dlthis,tgt_au_t * data,struct reloc_record_t * rp[],u32 relo_count)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  */
priv_tramp_pkt_finalize(struct dload_state * dlthis)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  */
priv_dup_pkt_finalize(struct dload_state * dlthis)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  */
priv_dup_find(struct dload_state * dlthis,s16 secnn,u32 image_offset)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  */
priv_img_pkt_dup(struct dload_state * dlthis,s16 secnn,u32 image_offset,struct image_packet_t * ipacket,struct reloc_record_t * rp,struct tramp_sym * new_tramp_sym)764 static int priv_img_pkt_dup(struct dload_state *dlthis,
765 			    s16 secnn, u32 image_offset,
766 			    struct image_packet_t *ipacket,
767 			    struct reloc_record_t *rp,
768 			    struct tramp_sym *new_tramp_sym)
769 {
770 	struct tramp_img_dup_pkt *dup_pkt = NULL;
771 	u32 new_dup_size;
772 	s32 i;
773 	int ret_val = 0;
774 	struct tramp_img_dup_relo *dup_relo = NULL;
775 
776 	/*  Determinne if this image packet is already being tracked in the
777 	   dup list for other trampolines. */
778 	dup_pkt = priv_dup_find(dlthis, secnn, image_offset);
779 
780 	if (dup_pkt == NULL) {
781 		/*  This image packet does not exist in our tracking, so create
782 		 * a new one and add it to the head of the list. */
783 		new_dup_size = sizeof(struct tramp_img_dup_pkt) +
784 		    ipacket->packet_size;
785 
786 		dup_pkt = (struct tramp_img_dup_pkt *)
787 		    dlthis->mysym->dload_allocate(dlthis->mysym, new_dup_size);
788 		if (dup_pkt != NULL) {
789 			/*  Save off the section and offset information */
790 			dup_pkt->secnn = secnn;
791 			dup_pkt->offset = image_offset;
792 			dup_pkt->relo_chain = NULL;
793 
794 			/*  Copy the original packet content */
795 			dup_pkt->img_pkt = *ipacket;
796 			dup_pkt->img_pkt.img_data = (u8 *) (dup_pkt + 1);
797 			for (i = 0; i < ipacket->packet_size; i++)
798 				*(dup_pkt->img_pkt.img_data + i) =
799 				    *(ipacket->img_data + i);
800 
801 			/*  Add the packet to the dup list */
802 			dup_pkt->next = dlthis->tramp.dup_pkts;
803 			dlthis->tramp.dup_pkts = dup_pkt;
804 		} else
805 			dload_error(dlthis, "Failed to create dup packet!");
806 	} else {
807 		/*  The image packet contents could have changed since
808 		 * trampoline detection happens during relocation of the image
809 		 * packets.  So, we need to update the image packet contents
810 		 * before adding relo information. */
811 		for (i = 0; i < dup_pkt->img_pkt.packet_size; i++)
812 			*(dup_pkt->img_pkt.img_data + i) =
813 			    *(ipacket->img_data + i);
814 	}
815 
816 	/*  Since the previous code may have allocated a new dup packet for us,
817 	   double check that we actually have one. */
818 	if (dup_pkt != NULL) {
819 		/*  Allocate a new node for the relo chain.  Each image packet
820 		 * can potentially have multiple relocations that cause a
821 		 * trampoline to be generated.  So, we keep them in a chain,
822 		 * order is not important. */
823 		dup_relo = dlthis->mysym->dload_allocate(dlthis->mysym,
824 					 sizeof(struct tramp_img_dup_relo));
825 		if (dup_relo != NULL) {
826 			/*  Copy the relo contents, adjust for the new
827 			 * trampoline and add it to the list. */
828 			dup_relo->relo = *rp;
829 			dup_relo->relo.SYMNDX = new_tramp_sym->index;
830 
831 			dup_relo->next = dup_pkt->relo_chain;
832 			dup_pkt->relo_chain = dup_relo;
833 
834 			/*  That's it, we're done.  Make sure we update our
835 			 * return value to be success since everything finished
836 			 * ok */
837 			ret_val = 1;
838 		} else
839 			dload_error(dlthis, "Unable to alloc dup relo");
840 	}
841 
842 	return ret_val;
843 }
844 
845 /*
846  * Function:	dload_tramp_avail
847  * Description: Check to see if the target supports a trampoline for this type
848  *	  of relocation.  Return true if it does, otherwise false.
849  */
dload_tramp_avail(struct dload_state * dlthis,struct reloc_record_t * rp)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  */
dload_tramp_generate(struct dload_state * dlthis,s16 secnn,u32 image_offset,struct image_packet_t * ipacket,struct reloc_record_t * rp)873 int dload_tramp_generate(struct dload_state *dlthis, s16 secnn,
874 			 u32 image_offset, struct image_packet_t *ipacket,
875 			 struct reloc_record_t *rp)
876 {
877 	u16 map_index;
878 	u16 gen_index;
879 	int ret_val = 1;
880 	char tramp_sym_str[TRAMP_SYM_PREFIX_LEN + TRAMP_SYM_HEX_ASCII_LEN];
881 	struct local_symbol *ref_sym;
882 	struct tramp_sym *new_tramp_sym;
883 	struct tramp_sym *new_ext_sym;
884 	struct tramp_string *new_tramp_str;
885 	u32 new_tramp_base;
886 	struct local_symbol tmp_sym;
887 	struct local_symbol ext_tmp_sym;
888 
889 	/*  Hash the relo type to get our generator information */
890 	map_index = HASH_FUNC(rp->TYPE);
891 	gen_index = tramp_map[map_index];
892 	if (gen_index != TRAMP_NO_GEN_AVAIL) {
893 		/*  If this is the first trampoline, create the section name in
894 		 * our string table for debug help later. */
895 		if (dlthis->tramp.string_head == NULL) {
896 			priv_tramp_string_create(dlthis,
897 						 strlen(TRAMP_SECT_NAME),
898 						 TRAMP_SECT_NAME);
899 		}
900 #ifdef ENABLE_TRAMP_DEBUG
901 		dload_syms_error(dlthis->mysym,
902 				 "Trampoline at img loc %x, references %x",
903 				 dlthis->ldr_sections[secnn].run_addr +
904 				 image_offset + rp->vaddr,
905 				 dlthis->local_symtab[rp->SYMNDX].value);
906 #endif
907 
908 		/*  Generate the trampoline string, check if already defined.
909 		 * If the relo symbol index is -1, it means we need the section
910 		 * info for relo later.  To do this we'll dummy up a symbol
911 		 * with the section delta and run addresses. */
912 		if (rp->SYMNDX == -1) {
913 			ext_tmp_sym.value =
914 			    dlthis->ldr_sections[secnn].run_addr;
915 			ext_tmp_sym.delta = dlthis->sect_hdrs[secnn].ds_paddr;
916 			ref_sym = &ext_tmp_sym;
917 		} else
918 			ref_sym = &(dlthis->local_symtab[rp->SYMNDX]);
919 
920 		priv_tramp_sym_gen_name(ref_sym->value, tramp_sym_str);
921 		new_tramp_sym = priv_tramp_sym_find(dlthis, tramp_sym_str);
922 		if (new_tramp_sym == NULL) {
923 			/*  If tramp string not defined, create it and a new
924 			 * string, and symbol for it as well as the original
925 			 * symbol which caused the trampoline. */
926 			new_tramp_str = priv_tramp_string_create(dlthis,
927 								strlen
928 								(tramp_sym_str),
929 								 tramp_sym_str);
930 			if (new_tramp_str == NULL) {
931 				dload_error(dlthis, "Failed to create new "
932 					    "trampoline string\n");
933 				ret_val = 0;
934 			} else {
935 				/*  Allocate tramp section space for the new
936 				 * tramp from the target */
937 				new_tramp_base = priv_tramp_sect_alloc(dlthis,
938 						       tramp_size_get());
939 
940 				/*  We have a string, create the new symbol and
941 				 * duplicate the external. */
942 				tmp_sym.value = new_tramp_base;
943 				tmp_sym.delta = 0;
944 				tmp_sym.secnn = -1;
945 				tmp_sym.sclass = 0;
946 				new_tramp_sym = priv_tramp_sym_create(dlthis,
947 							      new_tramp_str->
948 							      index,
949 							      &tmp_sym);
950 
951 				new_ext_sym = priv_tramp_sym_create(dlthis, -1,
952 								    ref_sym);
953 
954 				if ((new_tramp_sym != NULL) &&
955 				    (new_ext_sym != NULL)) {
956 					/*  Call the image generator to get the
957 					 * new image data and fix up its
958 					 * relocations for the external
959 					 * symbol. */
960 					ret_val = priv_tgt_img_gen(dlthis,
961 								 new_tramp_base,
962 								 gen_index,
963 								 new_ext_sym);
964 
965 					/*  Add generated image data to tramp
966 					 * image list */
967 					if (ret_val != 1) {
968 						dload_error(dlthis, "Failed to "
969 							    "create img pkt for"
970 							    " trampoline\n");
971 					}
972 				} else {
973 					dload_error(dlthis, "Failed to create "
974 						    "new tramp syms "
975 						    "(%8.8X, %8.8X)\n",
976 						    new_tramp_sym, new_ext_sym);
977 					ret_val = 0;
978 				}
979 			}
980 		}
981 
982 		/*  Duplicate the image data and relo record that caused the
983 		 * tramp, including update the relo data to point to the tramp
984 		 * symbol. */
985 		if (ret_val == 1) {
986 			ret_val = priv_img_pkt_dup(dlthis, secnn, image_offset,
987 						   ipacket, rp, new_tramp_sym);
988 			if (ret_val != 1) {
989 				dload_error(dlthis, "Failed to create dup of "
990 					    "original img pkt\n");
991 			}
992 		}
993 	}
994 
995 	return ret_val;
996 }
997 
998 /*
999  * Function:	dload_tramp_pkt_update
1000  * Description: Update the duplicate copy of this image packet, which the
1001  *	  trampoline layer is already tracking.  This is call is critical
1002  *	  to make if trampolines were generated anywhere within the
1003  *	  packet and first pass relo continued on the remainder.  The
1004  *	  trampoline layer needs the updates image data so when 2nd
1005  *	  pass relo is done during finalize the image packet can be
1006  *	  written to the target since all relo is done.
1007  */
dload_tramp_pkt_udpate(struct dload_state * dlthis,s16 secnn,u32 image_offset,struct image_packet_t * ipacket)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  */
dload_tramp_finalize(struct dload_state * dlthis)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  */
dload_tramp_cleanup(struct dload_state * dlthis)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 }
1144