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 */ 30static 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 */ 66static 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 */ 86static 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 */ 130static 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 */ 178static 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 */ 215static 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 */ 274static 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 */ 299static 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 */ 345static 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 */ 366static 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 */ 388static 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 */ 452static 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 */ 506static 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 */ 531static 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 */ 631static 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 */ 735static 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 */ 764static 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 */ 850bool 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 */ 873int 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 */ 1008int 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 */ 1042int 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 */ 1083void 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