parent
bed7488a9c
commit
944abc69fc
@ -1,12 +1,18 @@ |
||||
|
||||
default: all |
||||
|
||||
all: fx3tool |
||||
CFLAGS += -g -Og
|
||||
CXXFLAGS += $(CFLAGS)
|
||||
|
||||
fx3tool: cyusb.h download_fx3.cpp libcyusb.cpp |
||||
$(CXX) -o "$@" $^ -lusb-1.0
|
||||
all: fx3tool cyimg2elf |
||||
|
||||
fx3tool: download_fx3.cpp libcyusb.cpp cyusb.h |
||||
$(CXX) $(CXXFLAGS) -o "$@" download_fx3.cpp libcyusb.cpp -lusb-1.0
|
||||
|
||||
cyimg2elf: cyimg2elf.c cyimg.h |
||||
$(CC) $(CFLAGS) -o "$@" "$<"
|
||||
|
||||
clean: |
||||
@$(RM) -v fx3tool
|
||||
@$(RM) -v fx3tool cyimg2elf
|
||||
|
||||
.PHONY: all default clean |
||||
|
@ -0,0 +1,73 @@ |
||||
|
||||
#ifndef CYIMG_H_ |
||||
#define CYIMG_H_ |
||||
|
||||
#include <stddef.h> |
||||
#include <stdint.h> |
||||
|
||||
//#ifdef __LITTLE_ENDIAN__
|
||||
#define CYIMG_MAGIC ('C'|(((uint16_t)'Y')<<8)) |
||||
//#else
|
||||
//#define CYIMG_MAGIC ((((uint16_t)'C')<<8)|'Y')
|
||||
//#endif
|
||||
|
||||
#define CYIMG_R32(d) (((uint32_t)(d)[0]<<0)|((uint32_t)(d)[1]<<8)|((uint32_t)(d)[2]<<16)|((uint32_t)(d)[3]<<24)) |
||||
|
||||
#define CYIMG_IMAGECTL_EXECUTABLE_MASK (1<<0) |
||||
#define CYIMG_IMAGECTL_EXECUTABLE_LSB ( 0) |
||||
|
||||
#define CYIMG_IMAGECTL_I2CROMSIZE_MASK (7<<1) |
||||
#define CYIMG_IMAGECTL_I2CROMSIZE_LSB ( 1) |
||||
|
||||
#define CYIMG_IMAGECTL_SPISPEED_MASK (3<<4) |
||||
#define CYIMG_IMAGECTL_SPISPEED_LSB ( 4) |
||||
|
||||
#define CYIMG_IMAGETYPE_REGULAR 0xB0 |
||||
#define CYIMG_IMAGETYPE_USBIDS 0xB2 |
||||
|
||||
struct cyimg_section { |
||||
uint32_t dLength; // in 32-bit units
|
||||
uint32_t dAddress; // aligned to 32 bits
|
||||
// data follows immediately after
|
||||
}; |
||||
|
||||
struct cyimg_hdr { |
||||
uint16_t wSignature; |
||||
|
||||
uint8_t bImageCTL; |
||||
// bit 0: executable?
|
||||
// bit 1..3: I2C EEPROM size
|
||||
// bit 4..5: SPI speed (10/20/30/reserved MHz) OR I2C speed (100/400/1000/reserved kHz)
|
||||
// bit 6..7: reserved (zero)
|
||||
|
||||
uint8_t bImageType; |
||||
// 0xB0: regular firmware image
|
||||
// 0xB2: firmware image with VID/PID in 1st section
|
||||
|
||||
struct cyimg_section usb_info; // optional (see bImageType)
|
||||
}; |
||||
|
||||
struct cyimg_footer { |
||||
struct cyimg_section entry; |
||||
uint32_t dChecksum; |
||||
}; |
||||
|
||||
#define CYIMG_CHECKSUM_INIT 0 |
||||
|
||||
static inline uint32_t cyimg_checksum_calc(uint32_t init, size_t length, |
||||
const uint8_t* data) { |
||||
uint32_t v = init; |
||||
|
||||
for (size_t i = 0; i < length; ++i) v += CYIMG_R32(&data[i]); |
||||
|
||||
return v; |
||||
} |
||||
|
||||
// ---
|
||||
|
||||
#define ELF_FX3_NOTE_NAME "FX3" |
||||
#define ELF_FX3_NOTE_TYPE_IMAGECTLTYPE 1 |
||||
#define ELF_FX3_NOTE_TYPE_USBVIDPID 2 |
||||
|
||||
#endif |
||||
|
@ -0,0 +1,323 @@ |
||||
|
||||
#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; |
||||
} |
||||
|
@ -0,0 +1,10 @@ |
||||
|
||||
#include <stdint.h> |
||||
#include <stdio.h> |
||||
#include <sys/types.h> |
||||
#include <sys/stat.h> |
||||
#include <elf.h> |
||||
|
||||
int main(int argc, char* argv[]) { |
||||
|
||||
} |
Loading…
Reference in new issue