fx3tool/cyimg2elf.c

324 lines
8.4 KiB
C

#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <elf.h>
#include "cyimg.h"
static const uint32_t i2ceep_sizes[] = {
4096,
8192,
16384,
32768,
65536, // also Atmel 128k and ST 256k
131072, // Microchip (except 24LC1026)
};
static const uint32_t i2c_speeds_khz[] = { 100, 400, 1000 };
static const uint32_t spi_speeds_mhz[] = { 10, 20, 30 };
static bool validate_cyimg(size_t size, const uint8_t* data) {
if (size < 4) return false;
uint16_t wSignature = data[0] | (((uint16_t)data[1]) << 8);
if (wSignature != CYIMG_MAGIC) return false;
if (data[3] == CYIMG_IMAGETYPE_USBIDS)
return size == 8; // nothing else to verify
if (data[3] != CYIMG_IMAGETYPE_REGULAR) return false;
size_t cpos = 4;
printf("size=0x%zx\n", size);
while (true) {
//printf("cpos=0x%zx\n", cpos);
if (cpos + 8 > size) return false;
struct cyimg_section sec;
sec.dLength = CYIMG_R32(&data[cpos])*4;
cpos += 4;
sec.dAddress = CYIMG_R32(&data[cpos]);
cpos += 4;
printf("len=0x%x addr=0x%x\n", sec.dLength, sec.dAddress);
if (sec.dAddress & 3) return false;
if (sec.dLength == 0) break;
cpos += sec.dLength;
}
//printf("cpos+4=0x%zx size=0x%zx\n", cpos+4, size);
return true;//cpos + 4 == size; // checksum
}
static bool validate_checksum(size_t size, const uint8_t* data) {
if (size < 4) return false;
if (data[3] == CYIMG_IMAGETYPE_USBIDS)
return true; // nothing else to verify
if (data[3] != CYIMG_IMAGETYPE_REGULAR) return false;
size_t cpos = 4;
uint32_t ckcalc = CYIMG_CHECKSUM_INIT;
while (true) {
if (cpos + 8 > size) return false;
struct cyimg_section sec;
sec.dLength = CYIMG_R32(&data[cpos])*4;
cpos += 4;
sec.dAddress = CYIMG_R32(&data[cpos]);
cpos += 4;
if (sec.dLength == 0) break;
ckcalc = cyimg_checksum_calc(ckcalc, sec.dLength, &data[cpos]);
cpos += sec.dLength;
}
if (cpos + 4 != size) return false;
return ckcalc == CYIMG_R32(&data[cpos]);
}
static int write_usbids(FILE* out, size_t size, const uint8_t* data) {
size_t outsize = sizeof(Elf32_Ehdr) + sizeof(Elf32_Phdr) + 2*(sizeof(Elf32_Nhdr)+4+4);
uint8_t* buf = calloc(1, outsize);
Elf32_Ehdr* ehdr = (Elf32_Ehdr*)&buf[0];
Elf32_Phdr* phdr = (Elf32_Phdr*)&ehdr[1];
Elf32_Nhdr* nhdr = (Elf32_Nhdr*)&phdr[1];
uint8_t* ndata = (uint8_t*)&nhdr[1];
Elf32_Nhdr* nhdr2 = (Elf32_Nhdr*)&ndata[8];
uint8_t* ndata2 = (uint8_t*)&nhdr2[1];
ehdr->e_ident[0] = 0x7f;
ehdr->e_ident[1] = 'E';
ehdr->e_ident[2] = 'L';
ehdr->e_ident[3] = 'F';
ehdr->e_ident[4] = ELFCLASS32;
//#ifdef __LITTLE_ENDIAN__
ehdr->e_ident[5] = ELFDATA2LSB;
//#else
// ehdr->e_ident[5] = ELFDATA2MSB;
//#endif
ehdr->e_ident[6] = EV_CURRENT;
ehdr->e_ident[7] = ELFOSABI_SYSV;
ehdr->e_type = ET_EXEC;
ehdr->e_machine = EM_ARM;
ehdr->e_version = EV_CURRENT;
ehdr->e_phoff = sizeof(Elf32_Ehdr);
ehdr->e_phentsize = sizeof(Elf32_Phdr);
ehdr->e_phnum = 1;
phdr->p_type = PT_NOTE;
phdr->p_offset = sizeof(Elf32_Ehdr)+sizeof(Elf32_Phdr);
phdr->p_vaddr = sizeof(Elf32_Ehdr)+sizeof(Elf32_Phdr);
phdr->p_paddr = sizeof(Elf32_Ehdr)+sizeof(Elf32_Phdr);
phdr->p_filesz = 2*sizeof(Elf32_Nhdr)+2*4+4+2;
phdr->p_memsz = 2*sizeof(Elf32_Nhdr)+2*4+4+2;
phdr->p_flags = PF_R;
phdr->p_align = 4;
nhdr->n_namesz = 4;
nhdr->n_descsz = 4;
nhdr->n_type = ELF_FX3_NOTE_TYPE_USBVIDPID;
ndata[0] = 'F'; ndata[1] = 'X'; ndata[2] = '3'; ndata[3] = '\0';
ndata[4] = data[4]; ndata[5] = data[5]; ndata[6] = data[6]; ndata[7] = data[7];
nhdr2->n_namesz = 4;
nhdr2->n_descsz = 2;
nhdr2->n_type = ELF_FX3_NOTE_TYPE_IMAGECTLTYPE;
ndata2[0] = 'F'; ndata2[1] = 'X'; ndata2[2] = '3'; ndata2[3] = '\0';
ndata2[4] = data[2]; ndata2[5] = data[3];
if (fwrite(buf, 1, outsize, out) != outsize) {
fprintf(stderr, "E: cannot write to output.\n");
return 1;
}
return 0;
}
static int write_regular(FILE* out, size_t size, const uint8_t* data) {
uint32_t nsections = 0,
totalsize = 0,
entrypt = 0;
uint32_t curoff = 4;
while (true) {
uint32_t len = CYIMG_R32(&data[curoff])*4;
curoff += 4;
uint32_t addr = CYIMG_R32(&data[curoff]);
curoff += 4;
if (len == 0) {
entrypt = addr;
break;
}
printf("section: addr=0x%x off=0x%x size=0x%x\n", addr, curoff, len);
totalsize += len;
curoff += len;
++nsections;
}
printf("totalsize=0x%lx nsections=0x%lx\n", totalsize, nsections);
struct { uint32_t addr, off, size; } insections[nsections];
curoff = 4;
for (size_t i = 0; i < nsections; ++i) {
uint32_t len = CYIMG_R32(&data[curoff])*4;
curoff += 4;
uint32_t addr = CYIMG_R32(&data[curoff]);
curoff += 4;
if (len == 0) break;
printf("insection %zu: addr=0x%x off=0x%x size=0x%x\n", i, addr, curoff, len);
insections[i].addr = addr;
insections[i].off = curoff;
insections[i].size = len;
curoff += len;
}
// TODO: allocate data for:
// * EHDR
// * n+1 PHDRs
// * n sections
// * 1 note for bImageCTL/bImageType
// * data
size_t outsize = sizeof(Elf32_Ehdr) + sizeof(Elf32_Phdr)*(1+nsections)
+ totalsize + (sizeof(Elf32_Nhdr)+4+2 +2);
uint8_t* buf = calloc(1, outsize);
Elf32_Ehdr* ehdr = (Elf32_Ehdr*)(buf + 0);
Elf32_Phdr* phdr = (Elf32_Phdr*)(buf + sizeof(Elf32_Ehdr));
/*uint8_t* sdata = buf + sizeof(Elf32_Ehdr) + (nsections+1)*sizeof(Elf32_Phdr);
Elf32_Nhdr* nhdr = (Elf32_Nhdr*)(sdata + totalsize);
uint8_t* ndata = sdata + totalsize + sizeof(Elf32_Nhdr);*/
Elf32_Nhdr* nhdr = (Elf32_Nhdr*)(buf + sizeof(Elf32_Ehdr) + (nsections+1)*sizeof(Elf32_Phdr));
uint8_t* ndata = buf + sizeof(Elf32_Ehdr) + (nsections+1)*sizeof(Elf32_Phdr) + sizeof(Elf32_Nhdr);
uint8_t* sdata = ndata + 8;
ehdr->e_ident[0] = 0x7f;
ehdr->e_ident[1] = 'E';
ehdr->e_ident[2] = 'L';
ehdr->e_ident[3] = 'F';
ehdr->e_ident[4] = ELFCLASS32;
//#ifdef __LITTLE_ENDIAN__
ehdr->e_ident[5] = ELFDATA2LSB;
//#else
// ehdr->e_ident[5] = ELFDATA2MSB;
//#endif
ehdr->e_ident[6] = EV_CURRENT;
ehdr->e_ident[7] = ELFOSABI_SYSV;
ehdr->e_type = ET_EXEC;
ehdr->e_machine = EM_ARM;
ehdr->e_version = EV_CURRENT;
ehdr->e_entry = entrypt;
ehdr->e_phoff = sizeof(Elf32_Ehdr);
ehdr->e_phentsize = sizeof(Elf32_Phdr);
ehdr->e_phnum = 1 + nsections;
for (size_t i = 0, coff = 0; i < nsections; ++i) {
phdr[i].p_type = PT_LOAD;
phdr[i].p_offset = coff + (size_t)sdata - (size_t)ehdr;
phdr[i].p_vaddr = insections[i].addr;
phdr[i].p_paddr = insections[i].addr;
phdr[i].p_filesz = insections[i].size;
phdr[i].p_memsz = insections[i].size;
phdr[i].p_flags = PF_R|PF_W|PF_X;
phdr[i].p_align = 4;
printf("dest=%p src=%p, size=0x%x\n", sdata+coff, data+insections[i].off, insections[i].size);
memcpy(sdata + coff, data + insections[i].off, insections[i].size);
coff += insections[i].size;
}
phdr[nsections].p_type = PT_NOTE;
phdr[nsections].p_offset = (size_t)nhdr - (size_t)ehdr;
phdr[nsections].p_vaddr = (size_t)nhdr - (size_t)ehdr;
phdr[nsections].p_paddr = (size_t)nhdr - (size_t)ehdr;
phdr[nsections].p_filesz = sizeof(Elf32_Nhdr)+4+2;
phdr[nsections].p_memsz = sizeof(Elf32_Nhdr)+4+2;
phdr[nsections].p_flags = PF_R;
phdr[nsections].p_align = 4;
nhdr->n_namesz = 4;
nhdr->n_descsz = 2;
nhdr->n_type = ELF_FX3_NOTE_TYPE_IMAGECTLTYPE;
ndata[0] = 'F'; ndata[1] = 'X'; ndata[2] = '3'; ndata[3] = '\0';
ndata[4] = data[2]; ndata[5] = data[3];
if (fwrite(buf, 1, outsize, out) != outsize) {
fprintf(stderr, "E: cannot write to output.\n");
return 1;
}
return 0;
}
int main(int argc, char* argv[]) {
if (argc != 2 && argc != 3) {
fprintf(stderr, "Usage: %s <input file.img> [<output file.elf>]\n", argv[0]);
return 1;
}
FILE* f = fopen(argv[1], "rb");
if (!f) {
fprintf(stderr, "E: cannot open file '%s'\n", argv[1]);
return 1;
}
struct stat st;
if (fstat(fileno(f), &st)) {
fprintf(stderr, "E: cannot stat file '%s'\n", argv[1]);
return 1;
}
uint8_t* data = (uint8_t*)calloc(1, st.st_size);
if (fread(data, 1, st.st_size, f) != st.st_size) {
fprintf(stderr, "E: read error.\n");
return 1;
}
fclose(f);
if (!validate_cyimg(st.st_size, data)) {
fprintf(stderr, "E: file does not contain a valid Cypress FX3 image.\n");
return 1;
}
if (!validate_checksum(st.st_size, data)) {
fprintf(stderr, "W: invalid checksum.\n");
}
f = stdout;
if (argc == 3) {
f = fopen(argv[2], "wb");
if (!f) {
fprintf(stderr, "E: cannot open output file '%s'\n", argv[2]);
return 1;
}
}
int r = 1;
if (data[3] == CYIMG_IMAGETYPE_USBIDS) {
r = write_usbids(f, st.st_size, data);
} else if (data[3] == CYIMG_IMAGETYPE_REGULAR) {
r = write_regular(f, st.st_size, data);
}
if (argc == 3) fclose(f);
free(data);
return 0;
}