git-svn-id: http://svn.eurecom.fr/openair4G/trunk@5713 818b1a75-f10b-46b9-bf7c-635c3b92a50f
554 lines
23 KiB
C
554 lines
23 KiB
C
/*******************************************************************************
|
|
OpenAirInterface
|
|
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
|
|
along with OpenAirInterface.The full GNU General Public License is
|
|
included in this distribution in the file called "COPYING". If not,
|
|
see <http://www.gnu.org/licenses/>.
|
|
|
|
Contact Information
|
|
OpenAirInterface Admin: openair_admin@eurecom.fr
|
|
OpenAirInterface Tech : openair_tech@eurecom.fr
|
|
OpenAirInterface Dev : openair4g-devel@eurecom.fr
|
|
|
|
Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
|
|
|
|
*******************************************************************************/
|
|
/*
|
|
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>
|
|
|
|
#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 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 5
|
|
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 = "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
|
|
|
|
void show_usage(char* pgname) {
|
|
unsigned int i;
|
|
fprintf(stderr, " %s : Tool to update firmware of Cardbus-MIMO-1/Leon3 card through the PCI interface,\n", pgname);
|
|
fprintf(stderr, " "); for (i=0;i<strlen(pgname);i++) fprintf(stderr, " ");
|
|
fprintf(stderr, " that is, even without using the Xilinx parallel cable. The tool performs sequentially\n");
|
|
fprintf(stderr, " "); for (i=0;i<strlen(pgname);i++) fprintf(stderr, " ");
|
|
fprintf(stderr, " the 5 following operations:\n");
|
|
fprintf(stderr, " "); for (i=0;i<strlen(pgname);i++) fprintf(stderr, " ");
|
|
fprintf(stderr, " 1) Ask card driver to reboot (optionally)\n");
|
|
fprintf(stderr, " "); for (i=0;i<strlen(pgname);i++) fprintf(stderr, " ");
|
|
fprintf(stderr, " 2) Ask card driver to transfer .text section\n");
|
|
fprintf(stderr, " "); for (i=0;i<strlen(pgname);i++) fprintf(stderr, " ");
|
|
fprintf(stderr, " 3) Ask card driver to transfer .data section\n");
|
|
fprintf(stderr, " "); for (i=0;i<strlen(pgname);i++) fprintf(stderr, " ");
|
|
fprintf(stderr, " 4) Ask card driver to clear .bss section\n");
|
|
fprintf(stderr, " "); for (i=0;i<strlen(pgname);i++) fprintf(stderr, " ");
|
|
fprintf(stderr, " 5) Ask card driver to have Leon processor set stack-pointer\n");
|
|
fprintf(stderr, " "); for (i=0;i<strlen(pgname);i++) fprintf(stderr, " ");
|
|
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);
|
|
fprintf(stderr, " "); for (i=0;i<strlen(pgname);i++) fprintf(stderr, " ");
|
|
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, " [-v|-vv|-vvv|-vvvv] Verbose modes.\n");
|
|
fprintf(stderr, " [-h|--help] Displays this help.\n");
|
|
}
|
|
|
|
int get_elf_header(Elf32_Ehdr* p_Elf32_hdr, FILE* p_file) {
|
|
int nbread;
|
|
nbread = fread(p_Elf32_hdr, sizeof(elf_Ehdr), 1, p_file);
|
|
if (nbread != 1) {
|
|
fprintf(stderr, "Error : while reading ELF header (fread() returned %d)\n", nbread);
|
|
exit(-1);
|
|
}
|
|
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)
|
|
&& (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);
|
|
}
|
|
|
|
int get_elf_section_header(Elf32_Shdr* p_Elf32_Shdr, FILE* p_file, unsigned int section_ndx) {
|
|
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);
|
|
if (nbread != 1) {
|
|
fprintf(stderr, "Error : while reading elf section header (fread() returned %d)\n", nbread);
|
|
exit(-1);
|
|
}
|
|
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;
|
|
}
|
|
|
|
void find_and_transfer_section(char* section_name, unsigned int verboselevel) {
|
|
/* 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);
|
|
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);
|
|
/* 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);
|
|
}
|
|
/* Dynamically allocate a chunk of memory to store the section into. */
|
|
section_content = (char*)malloc(elf_Shdr.sh_size);
|
|
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);
|
|
}
|
|
/* 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);
|
|
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);
|
|
}
|
|
/* Open the special device file. */
|
|
if (!pflag) {
|
|
ifile = open(DEVICE_NAME, ACCESS_MODE, 0);
|
|
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);
|
|
}
|
|
/* 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;
|
|
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);
|
|
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);
|
|
}
|
|
close(ifile);
|
|
} /* pflag */
|
|
free(section_content);
|
|
} /* section_name */
|
|
} /* for secnb */
|
|
}
|
|
|
|
void find_and_clear_section_bss(unsigned int verboselevel) {
|
|
/* 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);
|
|
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);
|
|
/* Open the special device file. */
|
|
if (!pflag) {
|
|
ifile = open(DEVICE_NAME, ACCESS_MODE, 0);
|
|
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);
|
|
}
|
|
/* 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);
|
|
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);
|
|
}
|
|
close(ifile);
|
|
} /* pflag */
|
|
} /* section_name */
|
|
} /* for secnb */
|
|
}
|
|
|
|
int main(int argc, char** argv) {
|
|
/* 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;
|
|
|
|
/*****************
|
|
* Parse options *
|
|
*****************/
|
|
while ((getoptret = getopt_long_only (argc, argv, "f:vhps:b", updatefw_longopts, &indexptr)) != -1)
|
|
switch (getoptret) {
|
|
/* Without-argument options */
|
|
case 0: /* means that the option just sets a flag. Nothing has to be done,
|
|
since getopt_long already sets the flag. */
|
|
break;
|
|
/* With-argument options & equivalent short options */
|
|
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 '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;
|
|
};
|
|
/* 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);
|
|
}
|
|
/* Let print the help if it has been explicitly asked for */
|
|
if (helpflag == SWITCH_IS_ON) {
|
|
show_usage(argv[0]);
|
|
exit(0);
|
|
}
|
|
/* 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);
|
|
}
|
|
/* 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);
|
|
}
|
|
/* 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);
|
|
}
|
|
/* 2/2 - The address must only be made of hexadecimal digits. */
|
|
for (i=0,c=p_str_stkptr+2; i < 8 ; i++,c++) {
|
|
if (!
|
|
( ((*c >= '0') && (*c <= '9'))
|
|
|| ((*c >= 'a') && (*c <= 'f'))
|
|
|| ((*c >= 'A') && (*c <= 'F'))
|
|
)
|
|
) {
|
|
fprintf(stderr, "%s: Invalid value to [s|--stackptr] option (--help to show usage).\n", argv[0]);
|
|
exit(-1);
|
|
}
|
|
/* 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);
|
|
}
|
|
/* Open firmware file in READ_ONLY mode. */
|
|
filename = p_str_fwn;
|
|
p_elfimage = fopen(filename, READ_FILE_MODE);
|
|
if (p_elfimage == NULL) {
|
|
fprintf(stderr, "Error : could not open file <%s> in %s mode.\n", filename, READ_FILE_MODE);
|
|
exit(-1);
|
|
}
|
|
if (verboselevel >= VERBOSE_LEVEL_ACCESS_FILES)
|
|
printf("Info: using file <%s> (successfully opened in %s mode).\n", filename, READ_FILE_MODE);
|
|
/* 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);
|
|
}
|
|
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;
|
|
/* 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);"
|
|
" increase max. allowed value in source code and recompile\n",
|
|
StringSec_size, MAX_SIZE_STRING_TABLE);
|
|
exit(-1);
|
|
}
|
|
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");
|
|
}
|
|
if ((rebootflag == SWITCH_IS_ON) && (!pflag)) {
|
|
ifile = open(DEVICE_NAME, ACCESS_MODE, 0);
|
|
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);
|
|
}
|
|
ioctl_params[0] = UPDATE_FIRMWARE_FORCE_REBOOT;
|
|
/* Call ioctl driver */
|
|
ioctlretval = ioctl(ifile, openair_UPDATE_FIRMWARE, ioctl_params);
|
|
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);
|
|
}
|
|
/* 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;
|
|
/* 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");
|
|
ioctl_test_gok = 0;
|
|
do {
|
|
ioctlretval = ioctl(ifile, openair_UPDATE_FIRMWARE, ioctl_params);
|
|
ioctl_test_gok++;
|
|
sleep(1); /* sleep 1 second */
|
|
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);
|
|
if (verboselevel >= VERBOSE_LEVEL_IOCTL)
|
|
printf("Info: ok, card set again GOK bit (after %u seconds).\n", ioctl_test_gok);
|
|
close(ifile);
|
|
} /* rebootflag && pflag */
|
|
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");
|
|
find_and_transfer_section(".text", verboselevel);
|
|
sleep(1);
|
|
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");
|
|
find_and_transfer_section(".data", verboselevel);
|
|
sleep(1);
|
|
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");
|
|
find_and_clear_section_bss(verboselevel);
|
|
sleep(1);
|
|
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");
|
|
if (verboselevel >= VERBOSE_LEVEL_SECTION_DETAILS)
|
|
printf("Info: Firmware entry point = 0x%08x, setting stack pointer = 0x%08x.\n", elf_Ehdr.e_entry, stackpointer);
|
|
/* Open the special device file. */
|
|
if (!pflag) {
|
|
ifile = open(DEVICE_NAME, ACCESS_MODE, 0);
|
|
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);
|
|
}
|
|
/* Collect control data for ioctl. */
|
|
ioctl_params[0] = UPDATE_FIRMWARE_START_EXECUTION;
|
|
ioctl_params[1] = elf_Ehdr.e_entry;
|
|
ioctl_params[2] = stackpointer;
|
|
//invert4(ioctl_params[1]);
|
|
//invert4(ioctl_params[2]);
|
|
/* Call ioctl driver */
|
|
ioctlretval = ioctl(ifile, openair_UPDATE_FIRMWARE, ioctl_params);
|
|
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);
|
|
}
|
|
close(ifile);
|
|
} /* pflag */
|
|
if (verboselevel >= VERBOSE_LEVEL_MAIN_STEPS) printf("Info: action #5 done.\n");
|
|
|
|
fclose(p_elfimage);
|
|
|
|
/* Did we pretend ? */
|
|
if (pflag) printf("Nothing done.\n");
|
|
exit(0);
|
|
}
|