fix bugs, add cyimg2elf

This commit is contained in:
Triss 2022-01-21 04:11:06 +01:00
parent bed7488a9c
commit 944abc69fc
6 changed files with 464 additions and 20 deletions

4
.gitignore vendored
View File

@ -4,3 +4,7 @@
fx3tool
*.img
*.txt
fx3_images/
*.elf
cyimg2elf
elf2img*

View File

@ -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

73
cyimg.h Normal file
View File

@ -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

323
cyimg2elf.c Normal file
View File

@ -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;
}

View File

@ -314,9 +314,7 @@ get_fx3_prog_handle (
}
}
}
printf("cyusb close\n");
cyusb_close ();
printf("cyusb closeD!\n");
}
}
@ -324,10 +322,10 @@ get_fx3_prog_handle (
return -2;
}
static int fx3_init_progimg(cyusb_handle* h) {
static int fx3_init_progimg(cyusb_handle** h) {
int r = 0;
r = get_fx3_prog_handle(&h);
r = get_fx3_prog_handle(h);
if (r != 0) {
fprintf (stderr, "Error: FX3 flash programmer not found\n");
return -1;
@ -371,8 +369,11 @@ fx3_i2c_read (
cyusb_handle *h,
uint8_t* dst,
int devAddr,
// unsigned short addroff,
int len)
{
printf("i2c read addr=0x%x len=0x%x\n", devAddr, len);
int r = 0;
int index = 0;
unsigned short address = 0;
@ -380,7 +381,8 @@ fx3_i2c_read (
while (len > 0) {
size = (len > MAX_WRITE_SIZE) ? MAX_WRITE_SIZE : len;
r = cyusb_control_transfer (h, 0xC0, 0xBB, devAddr, address, dst, size, VENDORCMD_TIMEOUT);
printf("i2crd devaddr=%d address=0x%x size=0x%x\n", devAddr, address, size);
r = cyusb_control_transfer (h, 0xC0, 0xBB, devAddr, address /*+ addroff*/, dst, size, VENDORCMD_TIMEOUT);
if (r != size) {
fprintf (stderr, "Error: I2C read failed\n");
return -1;
@ -456,7 +458,7 @@ fx3_i2cboot_download (
return -2;
}
printf ("Info: Writing firmware image to I2C EEPROM\n");
printf ("Info: Writing firmware image to I2C EEPROM\n");
filesize = ROUND_UP(filesize, I2C_PAGE_SIZE);
while (filesize != 0) {
@ -512,6 +514,34 @@ fx3_i2cboot_download (
return 0;
}
int fx3_i2c_readout(cyusb_handle* h, uint8_t* dst, int offset, int length)
{
int r = 0;
int address = 0;
int dstoff = 0;
while (length > 0) {
int size = length;
if (size > I2C_SLAVE_SIZE) size = I2C_SLAVE_SIZE;
/*if (size > I2C_SLAVE_SIZE) {
r = fx3_i2c_read(h, dst + dstoff, address, I2C_SLAVE_SIZE);
if (r) return r;
r = fx3_i2c_read(h, dst + dstoff + I2C_SLAVE_SIZE, address + 4, size - I2C_SLAVE_SIZE);
} else*/ {
r = fx3_i2c_read(h, dst + dstoff, address, size);
}
if (r) return r;
dstoff += size;
length -= size;
address++;
}
return 0;
}
static int
fx3_spi_read (
cyusb_handle *h,
@ -658,14 +688,14 @@ print_usage_info (
printf ("%s: FX3 firmware programmer\n\n", arg0);
printf ("Usage:\n");
printf ("\t%s -h: Print this help message\n\n", arg0);
printf ("\t%s-a status: display device status\n", arg0);
printf ("\t%s-a load -t <target> -i <img filename>: Program firmware binary from <img filename> to <target>\n", arg0);
printf ("\t%s -a status: display device status\n", arg0);
printf ("\t%s -a load -t <target> -i <img filename>: Program firmware binary from <img filename> to <target>\n", arg0);
printf ("\t\t\twhere <target> is one of:\n");
printf ("\t\t\t\t\"RAM\": Program to FX3 RAM\n");
printf ("\t\t\t\t\"I2C\": Program to I2C EEPROM\n");
printf ("\t\t\t\t\"SPI\": Program to SPI FLASH\n");
printf ("\t%s-a read -t <target> -i <filename> -o <offset> -l <length>: read data from <target> into <filename> at the specified offset and length (in bytes)\n", arg0);
printf ("\t%s-a erase -t <target> -o <offset>: erase sector #<offset> from <target>\n", arg0);
printf ("\t%s -a read -t <target> -i <filename> -o <offset> -l <length>: read data from <target> into <filename> at the specified offset and length (in bytes)\n", arg0);
printf ("\t%s -a erase -t <target> -o <offset>: erase sector #<offset> from <target>\n", arg0);
printf ("\n\n");
}
@ -794,13 +824,11 @@ int main (
r = fx3_ram_read(h, databuf, offset, length);
break;
case FW_TARGET_I2C:
r = fx3_init_progimg(h);
printf("progimg done\n");
if (r == 0) r = fx3_i2c_read(h, databuf, offset, length);
printf("read done\n");
r = fx3_init_progimg(&h);
if (r == 0) r = fx3_i2c_readout(h, databuf, offset, length);
break;
case FW_TARGET_SPI:
r = fx3_init_progimg(h);
r = fx3_init_progimg(&h);
if (r == 0) r = fx3_spi_read(h, databuf, offset, length);
break;
default:
@ -829,7 +857,7 @@ int main (
switch (tgt) {
case FW_TARGET_SPI:
r = fx3_init_progimg(h);
r = fx3_init_progimg(&h);
if (r == 0) r = fx3_spi_erase_sector(h, offset);
break;
default:

10
elf2cyimg.c Normal file
View File

@ -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[]) {
}