updatefw.c 25 KB
Newer Older
1
/*******************************************************************************
2
    OpenAirInterface
3 4 5 6 7 8 9 10 11 12 13 14 15 16
    Copyright(c) 1999 - 2014 Eurecom

    OpenAirInterface is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.


    OpenAirInterface is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
17 18
    along with OpenAirInterface.The full GNU General Public License is
    included in this distribution in the file called "COPYING". If not,
19 20 21 22 23
    see <http://www.gnu.org/licenses/>.

   Contact Information
   OpenAirInterface Admin: openair_admin@eurecom.fr
   OpenAirInterface Tech : openair_tech@eurecom.fr
24
   OpenAirInterface Dev  : openair4g-devel@lists.eurecom.fr
25

ghaddab's avatar
ghaddab committed
26
   Address      : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
27 28

 *******************************************************************************/
29

30 31 32 33 34 35 36 37 38 39 40 41 42 43
/*
    C Header file <updatefw.h> for updatefw tool.

    K. Khalfallah, Aug, 2007
    kkhalfallah@free.fr
*/

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <string.h>
#include <unistd.h>
44
#include <stdint.h>
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89

#include <sys/ioctl.h>
#include "openair_device.h"

#include "elf.h"
#include "elftypes.h"
#define EM_SPARC    2
#define MAX_SIZE_STRING_TABLE    1024
#define MAX_SIZE_SECTION_NAME    32

#include "updatefw.h"

/* Interface with OpenAirInterface driver */
#define DEVICE_NAME "/dev/openair0"
#define ACCESS_MODE O_RDONLY

#define SWITCH_IS_OFF        0
#define SWITCH_IS_ON         1
static unsigned int helpflag = SWITCH_IS_OFF;
static unsigned int pflag = SWITCH_IS_OFF;
static unsigned int noexecflag = SWITCH_IS_OFF;
static unsigned int fflag = SWITCH_IS_OFF;
static unsigned int sflag = SWITCH_IS_OFF;
static unsigned int rebootflag = SWITCH_IS_OFF;
static FILE* p_elfimage;
static Elf32_Ehdr elf_Ehdr;
static Elf32_Shdr elf_Shdr;
long Shdr_pos, StringSec_pos, StringSec_size;
//char section_name[MAX_SIZE_SECTION_NAME];
char SecNameStnTable[MAX_SIZE_STRING_TABLE];
unsigned int ioctl_params[4];

#define LONGOPTIONS_NB 6
struct option updatefw_longopts[LONGOPTIONS_NB+1] = {
  {  .name = "help",        .has_arg = no_argument,       .flag = &helpflag,      .val = SWITCH_IS_ON  },
  {  .name = "firmware",    .has_arg = required_argument, .flag = NULL,           .val = 'f'           },
  {  .name = "pretend",     .has_arg = no_argument,       .flag = &pflag,         .val = SWITCH_IS_ON  },
  {  .name = "noexec",      .has_arg = no_argument,       .flag = &noexecflag,    .val = SWITCH_IS_ON  },
  {  .name = "stackptr",    .has_arg = required_argument, .flag = NULL,           .val = 's'           },
  {  .name = "forcereboot", .has_arg = no_argument,       .flag = &rebootflag,    .val = SWITCH_IS_ON  },
  {0, 0, 0, 0}
};
#define TRUE  1
#define FALSE 0

90
void show_usage(char* pgname) {
91 92
  unsigned int i;
  fprintf(stderr, "  %s : Tool to update firmware of Cardbus-MIMO-1/Leon3 card through the PCI interface,\n", pgname);
93 94 95 96
  fprintf(stderr, "    ");

  for (i=0; i<strlen(pgname); i++) fprintf(stderr, " ");

97
  fprintf(stderr, " that is, even without using the Xilinx parallel cable. The tool performs sequentially\n");
98 99 100 101
  fprintf(stderr, "    ");

  for (i=0; i<strlen(pgname); i++) fprintf(stderr, " ");

102
  fprintf(stderr, " the 5 following operations:\n");
103 104 105 106
  fprintf(stderr, "    ");

  for (i=0; i<strlen(pgname); i++) fprintf(stderr, " ");

107
  fprintf(stderr, "       1) Ask card driver to reboot (optionally)\n");
108 109 110 111
  fprintf(stderr, "    ");

  for (i=0; i<strlen(pgname); i++) fprintf(stderr, " ");

112
  fprintf(stderr, "       2) Ask card driver to transfer .text section\n");
113 114 115 116
  fprintf(stderr, "    ");

  for (i=0; i<strlen(pgname); i++) fprintf(stderr, " ");

117
  fprintf(stderr, "       3) Ask card driver to transfer .data section\n");
118 119 120 121
  fprintf(stderr, "    ");

  for (i=0; i<strlen(pgname); i++) fprintf(stderr, " ");

122
  fprintf(stderr, "       4) Ask card driver to clear .bss section\n");
123 124 125 126
  fprintf(stderr, "    ");

  for (i=0; i<strlen(pgname); i++) fprintf(stderr, " ");

127
  fprintf(stderr, "       5) Ask card driver to have Leon processor set stack-pointer\n");
128 129 130 131
  fprintf(stderr, "    ");

  for (i=0; i<strlen(pgname); i++) fprintf(stderr, " ");

132 133 134
  fprintf(stderr, "          and jump to firmware entry.\n");
  fprintf(stderr, "Usage:\n");
  fprintf(stderr, "  %s [-f|--firmware 'filename'] [-s|--stackptr value] [-b|--forcereboot]\n",pgname);
135 136 137 138
  fprintf(stderr, "   ");

  for (i=0; i<strlen(pgname); i++) fprintf(stderr, " ");

139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
  fprintf(stderr, "[-v|-vv|-vvv|-vvvv] [-h|--help] [-p|--pretend]\n\n");
  fprintf(stderr, "  [-f|--firmware ]     Mandatory option, to set the name of the executable file\n");
  fprintf(stderr, "                       of the firmware to update the remote card with.\n");
  fprintf(stderr, "                       The file should be an executable file in the Sparc32 ELF binary\n");
  fprintf(stderr, "                       format, containing at least the 3 mandatory sections .text, .data & .bss\n");
  fprintf(stderr, "  [-s|--stackptr]      Mandatory option, to set the value of the stack pointer before\n");
  fprintf(stderr, "                       giving hand to the firmware. The specified value must be an integer\n");
  fprintf(stderr, "                       number of 8 hexadecimal digits preceded by token '0x'.\n");
  fprintf(stderr, "  [-b|--forcereboot]   Force reboot of Leon processor before updating the firmware.\n");
  fprintf(stderr, "  [-p|--pretend]       Just pretend to transfer commands (ioctls) to driver, don't do it\n");
  fprintf(stderr, "                       actually. Useful together with verbose -vv switch.\n");
  fprintf(stderr, "  [-n|--noexec]        Transfer all data and text segments, but don't do actually start the code on Leon (no START_EXEC).\n");
  fprintf(stderr, "  [-v|-vv|-vvv|-vvvv]  Verbose modes.\n");
  fprintf(stderr, "  [-h|--help]          Displays this help.\n");
}

155
int get_elf_header(Elf32_Ehdr* p_Elf32_hdr, FILE* p_file) {
156 157
  int nbread;
  nbread = fread(p_Elf32_hdr, sizeof(elf_Ehdr), 1, p_file);
158

159 160 161 162
  if (nbread != 1) {
    fprintf(stderr, "Error : while reading ELF header (fread() returned %d)\n", nbread);
    exit(-1);
  }
163

164 165 166 167 168 169 170 171 172 173 174 175 176 177
  invert2(p_Elf32_hdr->e_type);            /* $$$$KMK: bad code !!! Endianess dependant ! */
  invert2(p_Elf32_hdr->e_machine);
  invert4(p_Elf32_hdr->e_version);
  invert4(p_Elf32_hdr->e_entry);
  invert4(p_Elf32_hdr->e_phoff);
  invert4(p_Elf32_hdr->e_shoff);
  invert4(p_Elf32_hdr->e_flags);
  invert2(p_Elf32_hdr->e_ehsize);
  invert2(p_Elf32_hdr->e_phentsize);
  invert2(p_Elf32_hdr->e_phnum);
  invert2(p_Elf32_hdr->e_shentsize);
  invert2(p_Elf32_hdr->e_shnum);
  invert2(p_Elf32_hdr->e_shstrndx);
  return (p_Elf32_hdr->e_type == ET_EXEC)
178 179 180 181 182
         && (p_Elf32_hdr->e_machine == EM_SPARC)
         && (p_Elf32_hdr->e_version == EV_CURRENT)
         && (p_Elf32_hdr->e_ident[EI_CLASS] == ELFCLASS32)
         && (p_Elf32_hdr->e_ident[EI_DATA] == ELFDATA2MSB)
         && (p_Elf32_hdr->e_ident[EI_VERSION] == EV_CURRENT);
183 184
}

185
int get_elf_section_header(Elf32_Shdr* p_Elf32_Shdr, FILE* p_file, unsigned int section_ndx) {
186 187 188 189 190 191
  int nbread;
  /* retrieve the position of the section header table */
  fseek(p_file, Shdr_pos + (section_ndx * elf_Ehdr.e_shentsize), 0);
  /* set file pointer to the position of the section header section_ndx */
  // seekrst = fseek(p_file, (long), 0);
  nbread = fread(p_Elf32_Shdr, sizeof(elf_Shdr), 1, p_file);
192

193 194 195 196
  if (nbread != 1) {
    fprintf(stderr, "Error : while reading elf section header (fread() returned %d)\n", nbread);
    exit(-1);
  }
197

198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
  invert4(p_Elf32_Shdr->sh_name);            /* $$$$KMK: bad code !!! Endianess dependant ! */
  invert4(p_Elf32_Shdr->sh_type);
  invert4(p_Elf32_Shdr->sh_flags);
  invert4(p_Elf32_Shdr->sh_addr);
  invert4(p_Elf32_Shdr->sh_offset);
  invert4(p_Elf32_Shdr->sh_size);
  invert4(p_Elf32_Shdr->sh_link);
  invert4(p_Elf32_Shdr->sh_info);
  invert4(p_Elf32_Shdr->sh_addralign);
  invert4(p_Elf32_Shdr->sh_entsize);
  //fseek(p_file, StringSec_pos + p_Elf32_Shdr->sh_name, 0);
  //fread();
  //strcpy(sname, );
  return nbread;
}

214
void find_and_transfer_section(char* section_name, unsigned int verboselevel) {
215 216 217 218 219 220 221 222 223
  /* Interface with driver */
  int ioctlretval;
  int ifile;
  char* section_content;
  int nbread;
  unsigned int secnb = 0;

  for (secnb = 0 ; secnb < elf_Ehdr.e_shnum; secnb++) {
    get_elf_section_header(&elf_Shdr, p_elfimage, secnb);
224

225 226 227
    if (!strcmp(SecNameStnTable + elf_Shdr.sh_name, section_name)) {
      if (verboselevel >= VERBOSE_LEVEL_SECTION_DETAILS)
        printf("Info: ok, found section %s (as section nb. %d)\n", SecNameStnTable + elf_Shdr.sh_name, secnb);
228

229 230 231 232 233 234 235 236 237 238
      /* Check that section size is a multiple of 4 bytes. */
      if (elf_Shdr.sh_size % 4) {
        fprintf(stderr, "Error: section %s has a non-multiple-of-4-bytes size (%d).\n",
                SecNameStnTable + elf_Shdr.sh_name, elf_Shdr.sh_size);
        fclose(p_elfimage);
        exit(-1);
      } else if (verboselevel >= VERBOSE_LEVEL_SECTION_DETAILS) {
        printf("Info: ok, section %s has size %d bytes (multiple of 4 bytes).\n",
               SecNameStnTable + elf_Shdr.sh_name, elf_Shdr.sh_size);
      }
239

240 241
      /* Dynamically allocate a chunk of memory to store the section into. */
      section_content = (char*)malloc(elf_Shdr.sh_size);
242

243 244 245 246 247 248 249 250 251 252 253 254
      /* Fail if the address returned by malloc does not fit in 32 bits.
       * The kernel driver gets this address as 32 bits and uses it to copy
       * from userspace. If the address does not fit into 32 bits the kernel
       * will copy garbage or fail to copy completely.
       * To be reworked if things do not work on some setups.
       */
      if (sizeof(char*) > 4 && (((uintptr_t)section_content)>>32)) {
        fprintf(stderr, "FATAL ERROR: an internal serious problem has been encountered.\n");
        fprintf(stderr, "Contact the authors so as to solve this issue.\n");
        exit(-1);
      }

255 256 257 258 259 260 261 262 263
      if (!section_content) {
        fprintf(stderr, "Error: could not dynamically allocate %d bytes for section %s.\n",
                elf_Shdr.sh_size, SecNameStnTable + elf_Shdr.sh_name);
        fclose(p_elfimage);
        exit(-1);
      } else if (verboselevel >= VERBOSE_LEVEL_IOCTL) {
        printf("Info: ok, dynamically allocated a %d bytes buffer for section %s.\n",
               elf_Shdr.sh_size, SecNameStnTable + elf_Shdr.sh_name);
      }
264

265 266 267 268
      /* Position the file cursor at the begining of proper section. */
      fseek(p_elfimage, (long)(elf_Shdr.sh_offset), 0);
      /* Copy the section's content into this temporary buffer. */
      nbread = fread(section_content, elf_Shdr.sh_size, 1, p_elfimage);
269

270 271 272 273 274 275 276 277 278
      if (nbread != 1) {
        fprintf(stderr, "Error: could not read %d bytes from ELF file into dynamic buffer.\n", elf_Shdr.sh_size);
        free(section_content);
        fclose(p_elfimage);
        exit(-1);
      } else if (verboselevel >= VERBOSE_LEVEL_IOCTL) {
        printf("Info: ok, copied content of section %s into dynamic buffer (%d bytes copied).\n",
               SecNameStnTable + elf_Shdr.sh_name, elf_Shdr.sh_size);
      }
279

280 281 282
      /* Open the special device file. */
      if (!pflag) {
        ifile = open(DEVICE_NAME, ACCESS_MODE, 0);
283

284 285 286 287 288 289 290 291
        if (ifile<0) {
          fprintf(stderr, "Error: could not open %s (open() returned %d, errno=%u)\n", DEVICE_NAME, ifile, errno);
          free(section_content);
          fclose(p_elfimage);
          exit(-1);
        } else if (verboselevel >= VERBOSE_LEVEL_IOCTL) {
          printf("Info: ok, successfully opened %s.\n", DEVICE_NAME);
        }
292

293 294 295 296
        /* Collect control data for ioctl. */
        ioctl_params[0] = UPDATE_FIRMWARE_TRANSFER_BLOCK;
        ioctl_params[1] = elf_Shdr.sh_addr;
        ioctl_params[2] = elf_Shdr.sh_size / 4;
297 298 299 300 301 302 303
        /* This is wrong on x86_64 because a pointer is 64 bits and
         * an unsigned int is only 32 bits.
         * The compiler emits a warning, but the test
         * above on the value of section_content makes it work
         * (hopefully).
         * To be changed if things do not work.
         */
304 305 306 307 308
        ioctl_params[3] = (unsigned int)((unsigned int*)section_content);
        //invert4(ioctl_params[1]);
        //invert4(ioctl_params[2]);
        /* Call ioctl driver */
        ioctlretval = ioctl(ifile, openair_UPDATE_FIRMWARE, ioctl_params);
309

310 311 312 313 314 315 316 317 318 319
        if (ioctlretval) {
          fprintf(stderr, "Error: ioctl on %s failed.\n", DEVICE_NAME);
          close(ifile);
          free(section_content);
          fclose(p_elfimage);
          exit(-1);
        } else if (verboselevel >= VERBOSE_LEVEL_IOCTL) {
          printf("Info: ok, successful ioctl on %s for section %s.\n",
                 DEVICE_NAME, SecNameStnTable + elf_Shdr.sh_name);
        }
320

321 322
        close(ifile);
      } /* pflag */
323

324 325 326 327 328
      free(section_content);
    } /* section_name */
  } /* for secnb */
}

329
void find_and_clear_section_bss(unsigned int verboselevel) {
330 331 332 333 334 335 336
  /* Interface with driver */
  int ioctlretval;
  int ifile;
  unsigned int secnb = 0;

  for (secnb = 0 ; secnb < elf_Ehdr.e_shnum; secnb++) {
    get_elf_section_header(&elf_Shdr, p_elfimage, secnb);
337

338 339 340
    if (!strcmp(SecNameStnTable + elf_Shdr.sh_name, ".bss")) {
      if (verboselevel >= VERBOSE_LEVEL_SECTION_DETAILS)
        printf("Info: ok, found section %s (as section nb. %d)\n", SecNameStnTable + elf_Shdr.sh_name, secnb);
341

342 343 344
      /* Open the special device file. */
      if (!pflag) {
        ifile = open(DEVICE_NAME, ACCESS_MODE, 0);
345

346 347 348 349 350 351 352
        if (ifile<0) {
          fprintf(stderr, "Error: could not open %s (open() returned %d, errno=%u)\n", DEVICE_NAME, ifile, errno);
          fclose(p_elfimage);
          exit(-1);
        } else if (verboselevel >= VERBOSE_LEVEL_IOCTL) {
          printf("Info: ok, successfully opened %s.\n", DEVICE_NAME);
        }
353

354 355 356 357 358 359 360 361
        /* Collect control data for ioctl. */
        ioctl_params[0] = UPDATE_FIRMWARE_CLEAR_BSS;
        ioctl_params[1] = elf_Shdr.sh_addr;
        ioctl_params[2] = elf_Shdr.sh_size;
        //invert4(ioctl_params[1]);
        //invert4(ioctl_params[2]);
        /* Call ioctl driver */
        ioctlretval = ioctl(ifile, openair_UPDATE_FIRMWARE, ioctl_params);
362

363 364 365 366 367 368 369 370 371
        if (ioctlretval) {
          fprintf(stderr, "Error: ioctl on %s failed.\n", DEVICE_NAME);
          close(ifile);
          fclose(p_elfimage);
          exit(-1);
        } else if (verboselevel >= VERBOSE_LEVEL_IOCTL) {
          printf("Info: ok, successful ioctl on %s for section %s.\n",
                 DEVICE_NAME, SecNameStnTable + elf_Shdr.sh_name);
        }
372

373 374 375 376 377 378
        close(ifile);
      } /* pflag */
    } /* section_name */
  } /* for secnb */
}

379
int main(int argc, char** argv) {
380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402
  /* Interface with driver */
  int ioctlretval;
  int ifile;
  /* Interface with getopt_long() libC function */
  int getoptret;
  int indexptr;
  int erroroption = FALSE;
  char* p_str_fwn = NULL;
  char* p_str_stkptr = NULL;
  char* filename;
  unsigned int verboselevel = 0;
  unsigned int i;
  char* c;
  unsigned int stackpointer = 0;
  unsigned int ioctl_test_gok = 0;
  unsigned int do_UPDATE_FIRMWARE_START_EXECUTION = 1;

  /*****************
   * Parse options *
   *****************/
  while ((getoptret = getopt_long_only (argc, argv, "f:vhpns:b", updatefw_longopts, &indexptr)) != -1)
    switch (getoptret) {
      /* Without-argument options */
403
    case 0: /* means that the option just sets a flag. Nothing has to be done,
404
                 since getopt_long already sets the flag. */
405 406
      break;

407
      /* With-argument options & equivalent short options */
408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440
    case 'v':
      verboselevel++;
      break;

    case 'h': /* short switch -h was used */
      helpflag = SWITCH_IS_ON;
      break;

    case 'p': /* short switch -p was used */
      pflag = SWITCH_IS_ON;
      break;

    case 'n': /* short switch -n was used */
      noexecflag = SWITCH_IS_ON;
      break;

    case 'f': /* short switch -f was used */
      fflag = SWITCH_IS_ON;
      p_str_fwn = optarg;
      break;

    case 's': /* short switch -s was used */
      sflag = SWITCH_IS_ON;
      p_str_stkptr = optarg;
      break;

    case 'b': /* short switch -b was used */
      rebootflag = SWITCH_IS_ON;
      break;

    default:
      erroroption = TRUE;
      break;
441
    };
442

443 444 445 446 447 448 449 450 451 452
  /* End of while */

  /********************************
   * Check consistency of options *
   ********************************/
  /* First, any irregularity in the use of the options ? Leave. */
  if (erroroption == TRUE) {
    fprintf(stderr, "%s: Misuse (--help to show usage)\n", argv[0]);
    exit(-1);
  }
453

454 455 456 457 458
  /* Let print the help if it has been explicitly asked for */
  if (helpflag == SWITCH_IS_ON) {
    show_usage(argv[0]);
    exit(0);
  }
459

460 461 462 463 464
  /* Check that mandatory firmware option was specified */
  if (fflag != SWITCH_IS_ON) {
    fprintf(stderr, "%s: missing mandatory [-f|--firmware] option (--help to show usage).\n", argv[0]);
    exit(-1);
  }
465

466 467 468 469 470
  /* Check that mandatory stack pointer option was specified */
  if (sflag != SWITCH_IS_ON) {
    fprintf(stderr, "%s: missing mandatory [-s|--stackptr] option (--help to show usage).\n", argv[0]);
    exit(-1);
  }
471

472 473 474 475 476 477
  /* Check consistency of stack pointer value. */
  /* 1/2 - The address must start with the 2 characters '0x' and be exactly 10 characters long. */
  if ((strncmp(p_str_stkptr, "0x", 2)) || (strlen(p_str_stkptr) != 10)) { /* 10 is for 0x + 8 hex digits. */
    fprintf(stderr, "%s: Invalid value to [s|--stackptr] option (--help to show usage).\n", argv[0]);
    exit(-1);
  }
478

479 480 481
  /* 2/2 - The address must only be made of hexadecimal digits. */
  for (i=0,c=p_str_stkptr+2; i < 8 ; i++,c++) {
    if (!
482 483 484 485 486
        (   ((*c >= '0') && (*c <= '9'))
            || ((*c >= 'a') && (*c <= 'f'))
            || ((*c >= 'A') && (*c <= 'F'))
        )
       ) {
487 488 489
      fprintf(stderr, "%s: Invalid value to [s|--stackptr] option (--help to show usage).\n", argv[0]);
      exit(-1);
    }
490

491 492 493 494 495 496 497 498
    /* Transcode string hexadecinmal value into binary value */
    if ((*c <= '9') && (*c >= '0'))
      stackpointer |= (*c - '0') << 28-(i*4);
    else if ((*c <= 'F') && (*c >= 'A'))
      stackpointer |= ((*c - 'A') + 10) << 28-(i*4);
    else if ((*c <= 'f') && (*c >= 'a'))
      stackpointer |= ((*c - 'a') + 10) << 28-(i*4);
  }
499

500 501 502
  /* Open firmware file in READ_ONLY mode. */
  filename = p_str_fwn;
  p_elfimage = fopen(filename, READ_FILE_MODE);
503

504 505 506 507
  if (p_elfimage == NULL) {
    fprintf(stderr, "Error : could not open file <%s> in %s mode.\n", filename, READ_FILE_MODE);
    exit(-1);
  }
508

509 510
  if (verboselevel >= VERBOSE_LEVEL_ACCESS_FILES)
    printf("Info: using file <%s> (successfully opened in %s mode).\n", filename, READ_FILE_MODE);
511

512 513 514 515 516 517
  /* Read elf binary image file */
  /* Get informations from header file */
  if (!(get_elf_header(&elf_Ehdr, p_elfimage))) {
    fprintf(stderr, "Error : file doesn't match expected format.\n");
    exit(-1);
  }
518

519 520 521 522 523 524 525 526 527 528 529
  if (verboselevel >= VERBOSE_LEVEL_ACCESS_FILES)
    printf("Info: ok, file matches expected format.\n");

  /* record the position of the section header table in the file */
  fseek(p_elfimage, (long)(elf_Ehdr.e_shoff), 0);
  Shdr_pos = ftell(p_elfimage);
  /* record the position of the section name string table */
  get_elf_section_header(&elf_Shdr, p_elfimage, elf_Ehdr.e_shstrndx);
  fseek(p_elfimage, (long)(elf_Shdr.sh_offset), 0);
  StringSec_pos = ftell(p_elfimage);
  StringSec_size = elf_Shdr.sh_size;
530

531 532 533
  /* copy the string table into global variable */
  if (StringSec_size > MAX_SIZE_STRING_TABLE) {
    fprintf(stderr, "Error: section name string table too big (%d > %d);"
534
            " increase max. allowed value in source code and recompile\n",
535 536 537
            StringSec_size, MAX_SIZE_STRING_TABLE);
    exit(-1);
  }
538

539 540 541 542 543 544 545 546 547
  fread(SecNameStnTable, 1, StringSec_size, p_elfimage);

  /* Action 1: force reboot (if option was specified) */
  if (verboselevel >= VERBOSE_LEVEL_MAIN_STEPS) {
    if (rebootflag == SWITCH_IS_ON)
      printf("Info: entering action #1 (forcing reboot of Leon).\n");
    else
      printf("Info: squeezed action #1 (forcing reboot of Leon).\n");
  }
548

549 550
  if ((rebootflag == SWITCH_IS_ON) && (!pflag)) {
    ifile = open(DEVICE_NAME, ACCESS_MODE, 0);
551

552 553 554 555 556 557 558
    if (ifile<0) {
      fprintf(stderr, "Error: could not open %s (open() returned %d, errno=%u).\n", DEVICE_NAME, ifile, errno);
      fclose(p_elfimage);
      exit(-1);
    } else if (verboselevel >= VERBOSE_LEVEL_IOCTL) {
      printf("Info: ok, successfully opened %s.\n", DEVICE_NAME);
    }
559

560 561 562
    ioctl_params[0] = UPDATE_FIRMWARE_FORCE_REBOOT;
    /* Call ioctl driver */
    ioctlretval = ioctl(ifile, openair_UPDATE_FIRMWARE, ioctl_params);
563

564 565 566 567 568 569 570 571
    if (ioctlretval) {
      fprintf(stderr, "Error: ioctl on %s failed.\n", DEVICE_NAME);
      close(ifile);
      fclose(p_elfimage);
      exit(-1);
    } else if (verboselevel >= VERBOSE_LEVEL_IOCTL) {
      printf("Info: ok, successful ioctl on %s to force reboot.\n", DEVICE_NAME);
    }
572

573 574 575 576 577 578 579 580 581 582 583
    /* If the card received the boot order, then
         1) The firmware who handled the order must have cleared the BOOT_GOK bit
            before rebooting ;
         2) Boot-strap should once again set it back upon its init operations.
       So we wait for this bit to be set again before issuing the rest of the
       update-firmware operations (transfer loadable sections and so on...).
       Note: putting the polling loop here is better than to have it in the
       openair driver, because it avoids hanging the kernel if the card was
       ever not to reboot cleanly. If the loop was to not end, user can simply
       gives up the update-firmware operation by issuing a Ctrl-C. */
    ioctl_params[0] = UPDATE_FIRMWARE_TEST_GOK;
584

585 586 587
    /* Call ioctl driver */
    if (verboselevel >= VERBOSE_LEVEL_MAIN_STEPS)
      printf("Info: waiting for GOK bit (as acknowledge of reboot command) - May take a few seconds...\n");
588

589
    ioctl_test_gok = 0;
590

591 592 593 594
    do {
      ioctlretval = ioctl(ifile, openair_UPDATE_FIRMWARE, ioctl_params);
      ioctl_test_gok++;
      sleep(1); /* sleep 1 second */
595

596 597 598
      if (!(ioctl_test_gok % 10))
        printf("Warning: card does not seem to have rebooted cleanly (no GOK bit). Still trying ([Ctrl-C] to abort).\n");
    } while (ioctlretval);
599

600 601
    if (verboselevel >= VERBOSE_LEVEL_IOCTL)
      printf("Info: ok, card set again GOK bit (after %u seconds).\n", ioctl_test_gok);
602

603 604
    close(ifile);
  } /* rebootflag && pflag */
605

606 607 608 609 610
  if ((verboselevel >= VERBOSE_LEVEL_MAIN_STEPS) && (rebootflag == SWITCH_IS_ON))
    printf("Info: action #1 done.\n");

  /* Action 2: Find the .text section */
  if (verboselevel >= VERBOSE_LEVEL_MAIN_STEPS) printf("Info: entering action #2 (Transfer .text section).\n");
611

612 613
  find_and_transfer_section(".text", verboselevel);
  sleep(1);
614

615 616 617 618
  if (verboselevel >= VERBOSE_LEVEL_MAIN_STEPS) printf("Info: action #2 done.\n");

  /* Action 3 : Find the .data section */
  if (verboselevel >= VERBOSE_LEVEL_MAIN_STEPS) printf("Info: entering action #3 (Transfer .data section).\n");
619

620 621
  find_and_transfer_section(".data", verboselevel);
  sleep(1);
622

623 624 625 626
  if (verboselevel >= VERBOSE_LEVEL_MAIN_STEPS) printf("Info: action #3 done.\n");

  /* Action 4 : Find the .bss  section */
  if (verboselevel >= VERBOSE_LEVEL_MAIN_STEPS) printf("Info: entering action #4 (Clear .bss section).\n");
627

628 629
  find_and_clear_section_bss(verboselevel);
  sleep(1);
630

631 632 633 634
  if (verboselevel >= VERBOSE_LEVEL_MAIN_STEPS) printf("Info: action #4 done.\n");

  /* Action 5 : Find the entry address */
  if (verboselevel >= VERBOSE_LEVEL_MAIN_STEPS) printf("Info: entering action #5 (Jump to firmware/set stack-pointer).\n");
635

636 637
  if (verboselevel >= VERBOSE_LEVEL_SECTION_DETAILS)
    printf("Info: Firmware entry point = 0x%08x, setting stack pointer = 0x%08x.\n", elf_Ehdr.e_entry, stackpointer);
638

639 640 641
  /* Open the special device file. */
  if (!pflag) {
    ifile = open(DEVICE_NAME, ACCESS_MODE, 0);
642

643 644 645 646 647 648 649
    if (ifile<0) {
      fprintf(stderr, "Error: could not open %s (open() returned %d, errno=%u).\n", DEVICE_NAME, ifile, errno);
      fclose(p_elfimage);
      exit(-1);
    } else if (verboselevel >= VERBOSE_LEVEL_IOCTL) {
      printf("Info: ok, successfully opened %s.\n", DEVICE_NAME);
    }
650

651 652 653 654
    /* Collect control data for ioctl. */
    ioctl_params[0] = UPDATE_FIRMWARE_START_EXECUTION;
    ioctl_params[1] = elf_Ehdr.e_entry;
    ioctl_params[2] = stackpointer;
655

656 657 658 659 660
    //invert4(ioctl_params[1]);
    //invert4(ioctl_params[2]);
    /* Call ioctl driver */
    if ( noexecflag == SWITCH_IS_OFF ) {
      ioctlretval = ioctl(ifile, openair_UPDATE_FIRMWARE, ioctl_params);
661

662 663 664 665 666 667 668 669 670
      if (ioctlretval) {
        fprintf(stderr, "Error: ioctl on %s failed.\n", DEVICE_NAME);
        close(ifile);
        fclose(p_elfimage);
        exit(-1);
      } else if (verboselevel >= VERBOSE_LEVEL_IOCTL) {
        printf("Info: ok, successful ioctl on %s for stack-pointer setting/firmware-execution.\n", DEVICE_NAME);
      }
    }
671

672 673
    close(ifile);
  } /* pflag */
674

675
  if (verboselevel >= VERBOSE_LEVEL_MAIN_STEPS) printf("Info: action #5 done.\n");
676

677 678 679 680
  fclose(p_elfimage);

  /* Did we pretend ? */
  if (pflag) printf("Nothing done.\n");
681

682 683
  exit(0);
}