linux/drivers/staging/tidspbridge/dynload/tramp.c
<<
>>
Prefs
   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 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 */
 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        /*  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 */
 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 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