diff options
Diffstat (limited to 'scripts/imx/imx-usb-loader.c')
-rw-r--r-- | scripts/imx/imx-usb-loader.c | 671 |
1 files changed, 282 insertions, 389 deletions
diff --git a/scripts/imx/imx-usb-loader.c b/scripts/imx/imx-usb-loader.c index 195b27b8ee..ed27831386 100644 --- a/scripts/imx/imx-usb-loader.c +++ b/scripts/imx/imx-usb-loader.c @@ -32,10 +32,21 @@ #include <stdlib.h> #include <libusb.h> #include <getopt.h> +#include <linux/kernel.h> + +#include "imx.h" #define get_min(a, b) (((a) < (b)) ? (a) : (b)) +#define FT_APP 0xaa +#define FT_CSF 0xcc +#define FT_DCD 0xee +#define FT_LOAD_ONLY 0x00 + int verbose; +static int skip_image_dcd; +static struct libusb_device_handle *usb_dev_handle; +static struct usb_id *usb_id; struct mach_id { struct mach_id * next; @@ -53,11 +64,6 @@ struct mach_id { unsigned short max_transfer; }; -#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) -#ifndef offsetof -#define offsetof(TYPE, MEMBER) __builtin_offsetof(TYPE, MEMBER) -#endif - struct usb_work { char filename[256]; unsigned char dcd; @@ -194,9 +200,10 @@ static libusb_device *find_imx_dev(libusb_device **devs, struct mach_id **pp_id) return NULL; } -static void dump_long(unsigned char *src, unsigned cnt, unsigned addr) +static void dump_long(const void *src, unsigned cnt, unsigned addr) { - unsigned *p = (unsigned *)src; + const unsigned *p = (unsigned *)src; + while (cnt >= 32) { printf("%08x: %08x %08x %08x %08x %08x %08x %08x %08x\n", addr, p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]); @@ -215,9 +222,9 @@ static void dump_long(unsigned char *src, unsigned cnt, unsigned addr) } } -static void dump_bytes(unsigned char *src, unsigned cnt, unsigned addr) +static void dump_bytes(const void *src, unsigned cnt, unsigned addr) { - unsigned char *p = src; + const unsigned char *p = src; int i; while (cnt >= 16) { @@ -297,12 +304,11 @@ static long get_file_size(FILE *xfile) * EP2IN - bulk in * (max packet size of 512 bytes) */ -static int transfer(struct libusb_device_handle *h, int report, unsigned char *p, unsigned cnt, - int* last_trans, struct usb_id *p_id) +static int transfer(int report, unsigned char *p, unsigned cnt, int *last_trans) { int err; - if (cnt > p_id->mach_id->max_transfer) - cnt = p_id->mach_id->max_transfer; + if (cnt > usb_id->mach_id->max_transfer) + cnt = usb_id->mach_id->max_transfer; if (verbose > 4) { printf("report=%i\n", report); @@ -310,9 +316,10 @@ static int transfer(struct libusb_device_handle *h, int report, unsigned char *p dump_bytes(p, cnt, 0); } - if (p_id->mach_id->mode == MODE_BULK) { + if (usb_id->mach_id->mode == MODE_BULK) { *last_trans = 0; - err = libusb_bulk_transfer(h, (report < 3) ? 1 : 2 + EP_IN, p, cnt, last_trans, 1000); + err = libusb_bulk_transfer(usb_dev_handle, + (report < 3) ? 1 : 2 + EP_IN, p, cnt, last_trans, 1000); } else { unsigned char tmp[1028]; @@ -320,7 +327,7 @@ static int transfer(struct libusb_device_handle *h, int report, unsigned char *p if (report < 3) { memcpy(&tmp[1], p, cnt); - err = libusb_control_transfer(h, + err = libusb_control_transfer(usb_dev_handle, CTRL_OUT, HID_SET_REPORT, (HID_REPORT_TYPE_OUTPUT << 8) | report, @@ -332,7 +339,8 @@ static int transfer(struct libusb_device_handle *h, int report, unsigned char *p } else { *last_trans = 0; memset(&tmp[1], 0, cnt); - err = libusb_interrupt_transfer(h, 1 + EP_IN, tmp, cnt + 1, last_trans, 1000); + err = libusb_interrupt_transfer(usb_dev_handle, + 1 + EP_IN, tmp, cnt + 1, last_trans, 1000); if (err >= 0) { if (tmp[0] == (unsigned char)report) { if (*last_trans > 1) { @@ -354,7 +362,7 @@ static int transfer(struct libusb_device_handle *h, int report, unsigned char *p return err; } -int do_status(libusb_device_handle *h, struct usb_id *p_id) +int do_status(void) { int last_trans; unsigned char tmp[64]; @@ -369,14 +377,14 @@ int do_status(libusb_device_handle *h, struct usb_id *p_id) }; for (;;) { - err = transfer(h, 1, (unsigned char*)status_command, 16, &last_trans, p_id); + err = transfer(1, (unsigned char*)status_command, 16, &last_trans); if (verbose > 2) printf("report 1, wrote %i bytes, err=%i\n", last_trans, err); memset(tmp, 0, sizeof(tmp)); - err = transfer(h, 3, tmp, 64, &last_trans, p_id); + err = transfer(3, tmp, 64, &last_trans); if (verbose > 2) { printf("report 3, read %i bytes, err=%i\n", last_trans, err); @@ -392,8 +400,8 @@ int do_status(libusb_device_handle *h, struct usb_id *p_id) break; } - if (p_id->mach_id->mode == MODE_HID) { - err = transfer(h, 4, tmp, sizeof(tmp), &last_trans, p_id); + if (usb_id->mach_id->mode == MODE_HID) { + err = transfer(4, tmp, sizeof(tmp), &last_trans); if (err) printf("4 in err=%i, last_trans=%i %02x %02x %02x %02x\n", err, last_trans, tmp[0], tmp[1], tmp[2], tmp[3]); @@ -402,43 +410,9 @@ int do_status(libusb_device_handle *h, struct usb_id *p_id) return err; } -struct boot_data { - uint32_t dest; - uint32_t image_len; - uint32_t plugin; -}; - -struct imx_flash_header_v2 { -#define IVT_BARKER 0x402000d1 - uint32_t barker; - uint32_t start_addr; - uint32_t reserv1; - uint32_t dcd_ptr; - uint32_t boot_data_ptr; /* struct boot_data * */ - uint32_t self_ptr; /* struct imx_flash_header_v2 *, this - boot_data.start = offset linked at */ - uint32_t app_code_csf; - uint32_t reserv2; -}; - -/* - * MX51 header type - */ -struct imx_flash_header_v1 { - uint32_t app_start_addr; -#define APP_BARKER 0xb1 -#define DCD_BARKER 0xb17219e9 - uint32_t app_barker; - uint32_t csf_ptr; - uint32_t dcd_ptr_ptr; - uint32_t srk_ptr; - uint32_t dcd_ptr; - uint32_t app_dest_ptr; -}; - #define V(a) (((a) >> 24) & 0xff), (((a) >> 16) & 0xff), (((a) >> 8) & 0xff), ((a) & 0xff) -static int read_memory(struct libusb_device_handle *h, struct usb_id *p_id, - unsigned addr, unsigned char *dest, unsigned cnt) +static int read_memory(unsigned addr, unsigned char *dest, unsigned cnt) { static unsigned char read_reg_command[] = { 1, @@ -466,7 +440,7 @@ static int read_memory(struct libusb_device_handle *h, struct usb_id *p_id, read_reg_command[10] = (unsigned char)(cnt); for (;;) { - err = transfer(h, 1, read_reg_command, 16, &last_trans, p_id); + err = transfer(1, read_reg_command, 16, &last_trans); if (!err) break; printf("read_reg_command err=%i, last_trans=%i\n", err, last_trans); @@ -476,7 +450,7 @@ static int read_memory(struct libusb_device_handle *h, struct usb_id *p_id, retry++; } - err = transfer(h, 3, tmp, 4, &last_trans, p_id); + err = transfer(3, tmp, 4, &last_trans); if (err) { printf("r3 in err=%i, last_trans=%i %02x %02x %02x %02x\n", err, last_trans, tmp[0], tmp[1], tmp[2], tmp[3]); @@ -487,7 +461,7 @@ static int read_memory(struct libusb_device_handle *h, struct usb_id *p_id, while (rem) { tmp[0] = tmp[1] = tmp[2] = tmp[3] = 0; - err = transfer(h, 4, tmp, 64, &last_trans, p_id); + err = transfer(4, tmp, 64, &last_trans); if (err) { printf("r4 in err=%i, last_trans=%i %02x %02x %02x %02x cnt=%u rem=%d\n", err, last_trans, tmp[0], tmp[1], tmp[2], tmp[3], cnt, rem); @@ -511,8 +485,7 @@ static int read_memory(struct libusb_device_handle *h, struct usb_id *p_id, return err; } -static int write_memory(struct libusb_device_handle *h, struct usb_id *p_id, - unsigned addr, unsigned val, int width) +static int write_memory(unsigned addr, unsigned val, int width) { int retry = 0; int last_trans; @@ -555,7 +528,7 @@ static int write_memory(struct libusb_device_handle *h, struct usb_id *p_id, write_reg_command[14] = (unsigned char)(val); for (;;) { - err = transfer(h, 1, write_reg_command, 16, &last_trans, p_id); + err = transfer(1, write_reg_command, 16, &last_trans); if (!err) break; printf("write_reg_command err=%i, last_trans=%i\n", err, last_trans); @@ -567,7 +540,7 @@ static int write_memory(struct libusb_device_handle *h, struct usb_id *p_id, memset(tmp, 0, sizeof(tmp)); - err = transfer(h, 3, tmp, sizeof(tmp), &last_trans, p_id); + err = transfer(3, tmp, sizeof(tmp), &last_trans); if (err) { printf("w3 in err=%i, last_trans=%i %02x %02x %02x %02x\n", err, last_trans, tmp[0], tmp[1], tmp[2], tmp[3]); @@ -576,25 +549,109 @@ static int write_memory(struct libusb_device_handle *h, struct usb_id *p_id, memset(tmp, 0, sizeof(tmp)); - err = transfer(h, 4, tmp, sizeof(tmp), &last_trans, p_id); + err = transfer(4, tmp, sizeof(tmp), &last_trans); if (err) printf("w4 in err=%i, last_trans=%i %02x %02x %02x %02x\n", err, last_trans, tmp[0], tmp[1], tmp[2], tmp[3]); return err; } -static int write_dcd_table_ivt(struct libusb_device_handle *h, struct usb_id *p_id, - struct imx_flash_header_v2 *hdr, unsigned char *file_start, unsigned cnt) +static int load_file(void *buf, unsigned len, unsigned dladdr, unsigned char type) +{ + static unsigned char dl_command[] = { + 0x04, + 0x04, + V(0), /* address */ + 0x00, /* format */ + V(0x00000020), /* data count */ + V(0), /* data */ + 0xaa, /* type */ + }; + int last_trans, err; + int retry = 0; + unsigned transfer_size = 0; + unsigned char tmp[64]; + void *p; + int cnt; + + dl_command[2] = (unsigned char)(dladdr >> 24); + dl_command[3] = (unsigned char)(dladdr >> 16); + dl_command[4] = (unsigned char)(dladdr >> 8); + dl_command[5] = (unsigned char)(dladdr); + + dl_command[7] = (unsigned char)(len >> 24); + dl_command[8] = (unsigned char)(len >> 16); + dl_command[9] = (unsigned char)(len >> 8); + dl_command[10] = (unsigned char)(len); + dl_command[15] = type; + + for (;;) { + err = transfer(1, dl_command, 16, &last_trans); + if (!err) + break; + + printf("dl_command err=%i, last_trans=%i\n", err, last_trans); + + if (retry > 5) + return -4; + retry++; + } + + retry = 0; + + if (usb_id->mach_id->mode == MODE_BULK) { + err = transfer(3, tmp, sizeof(tmp), &last_trans); + if (err) + printf("in err=%i, last_trans=%i %02x %02x %02x %02x\n", + err, last_trans, tmp[0], tmp[1], tmp[2], tmp[3]); + } + + p = buf; + cnt = len; + + while (1) { + int now = get_min(cnt, usb_id->mach_id->max_transfer); + + if (!now) + break; + + err = transfer(2, p, now, &now); + if (err) { + printf("dl_command err=%i, last_trans=%i\n", err, last_trans); + return err; + } + + p += now; + cnt -= now; + } + + if (usb_id->mach_id->mode == MODE_HID) { + err = transfer(3, tmp, sizeof(tmp), &last_trans); + if (err) + printf("3 in err=%i, last_trans=%i %02x %02x %02x %02x\n", + err, last_trans, tmp[0], tmp[1], tmp[2], tmp[3]); + err = transfer(4, tmp, sizeof(tmp), &last_trans); + if (err) + printf("4 in err=%i, last_trans=%i %02x %02x %02x %02x\n", + err, last_trans, tmp[0], tmp[1], tmp[2], tmp[3]); + } else { + do_status(); + } + + return transfer_size; +} + +static int write_dcd_table_ivt(struct imx_flash_header_v2 *hdr, unsigned char *file_start, unsigned cnt) { unsigned char *dcd_end; unsigned m_length; -#define cvt_dest_to_src (((unsigned char *)hdr) - hdr->self_ptr) +#define cvt_dest_to_src (((unsigned char *)hdr) - hdr->self) unsigned char* dcd; unsigned char* file_end = file_start + cnt; int err = 0; if (!hdr->dcd_ptr) { - printf("No dcd table, barker=%x\n", hdr->barker); + printf("No dcd table in this ivt\n"); return 0; /* nothing to do */ } @@ -646,7 +703,7 @@ static int write_dcd_table_ivt(struct libusb_device_handle *h, struct usb_id *p_ unsigned val = (dcd[4] << 24) | (dcd[5] << 16) | (dcd[6] << 8) | dcd[7]; dcd += 8; - err = write_memory(h, p_id, addr, val, 4); + err = write_memory(addr, val, 4); if (err < 0) return err; } @@ -654,27 +711,27 @@ static int write_dcd_table_ivt(struct libusb_device_handle *h, struct usb_id *p_ return err; } -static int get_dcd_range_old(struct imx_flash_header_v1 *hdr, +static int get_dcd_range_old(struct imx_flash_header *hdr, unsigned char *file_start, unsigned cnt, unsigned char **pstart, unsigned char **pend) { unsigned char *dcd_end; unsigned m_length; -#define cvt_dest_to_src_old (((unsigned char *)&hdr->dcd_ptr) - hdr->dcd_ptr_ptr) +#define cvt_dest_to_src_old (((unsigned char *)&hdr->dcd) - hdr->dcd_ptr_ptr) unsigned char* dcd; unsigned val; unsigned char* file_end = file_start + cnt; - if (!hdr->dcd_ptr) { - printf("No dcd table, barker=%x\n", hdr->app_barker); - *pstart = *pend = ((unsigned char *)hdr) + sizeof(struct imx_flash_header_v1); + if (!hdr->dcd) { + printf("No dcd table, barker=%x\n", hdr->app_code_barker); + *pstart = *pend = ((unsigned char *)hdr) + sizeof(struct imx_flash_header); return 0; /* nothing to do */ } - dcd = hdr->dcd_ptr + cvt_dest_to_src_old; + dcd = hdr->dcd + cvt_dest_to_src_old; if ((dcd < file_start) || ((dcd + 8) > file_end)) { - printf("bad dcd_ptr %08x\n", hdr->dcd_ptr); + printf("bad dcd_ptr %08x\n", hdr->dcd); return -1; } @@ -701,8 +758,7 @@ static int get_dcd_range_old(struct imx_flash_header_v1 *hdr, return 0; } -static int write_dcd_table_old(struct libusb_device_handle *h, struct usb_id *p_id, - struct imx_flash_header_v1 *hdr, unsigned char *file_start, unsigned cnt) +static int write_dcd_table_old(struct imx_flash_header *hdr, unsigned char *file_start, unsigned cnt) { unsigned val; unsigned char *dcd_end; @@ -723,14 +779,14 @@ static int write_dcd_table_old(struct libusb_device_handle *h, struct usb_id *p_ case 1: if (verbose > 1) printf("type=%08x *0x%08x = 0x%08x\n", type, addr, val); - err = write_memory(h, p_id, addr, val, 1); + err = write_memory(addr, val, 1); if (err < 0) return err; break; case 4: if (verbose > 1) printf("type=%08x *0x%08x = 0x%08x\n", type, addr, val); - err = write_memory(h, p_id, addr, val, 4); + err = write_memory(addr, val, 4); if (err < 0) return err; break; @@ -747,117 +803,79 @@ static int write_dcd_table_old(struct libusb_device_handle *h, struct usb_id *p_ return err; } -static int verify_memory(struct libusb_device_handle *h, struct usb_id *p_id, - FILE *xfile, unsigned offset, unsigned addr, unsigned size, - unsigned char *verify_buffer, unsigned verify_cnt) +static int verify_memory(const void *buf, unsigned len, unsigned addr) { - int mismatch = 0; - unsigned char file_buf[1024]; - fseek(xfile, offset + verify_cnt, SEEK_SET); - - while (size) { - unsigned char mem_buf[64]; - unsigned char *p = file_buf; - int cnt = addr & 0x3f; - int request = get_min(size, sizeof(file_buf)); - - if (cnt) { - cnt = 64 - cnt; - if (request > cnt) - request = cnt; - } + int ret, mismatch = 0; + void *readbuf; + unsigned offset = 0, now; - if (verify_cnt) { - p = verify_buffer; - cnt = get_min(request, verify_cnt); - verify_buffer += cnt; - verify_cnt -= cnt; - } else { - cnt = fread(p, 1, request, xfile); - if (cnt <= 0) { - printf("Unexpected end of file, request=0x%0x, size=0x%x, cnt=%i\n", - request, size, cnt); - return -1; - } - } - - size -= cnt; - - while (cnt) { - int ret; + readbuf = malloc(len); + if (!readbuf) + return -ENOMEM; - request = get_min(cnt, sizeof(mem_buf)); - - ret = read_memory(h, p_id, addr, mem_buf, request); - if (ret < 0) - return ret; - - if (memcmp(p, mem_buf, request)) { - unsigned char * m = mem_buf; - if (!mismatch) - printf("!!!!mismatch\n"); - mismatch++; - - while (request) { - unsigned req = get_min(request, 32); - if (memcmp(p, m, req)) { - dump_long(p, req, offset); - dump_long(m, req, addr); - printf("\n"); - } - p += req; - m+= req; - offset += req; - addr += req; - cnt -= req; - request -= req; - } - if (mismatch >= 5) - return -1; - } - p += request; - offset += request; - addr += request; - cnt -= request; + ret = read_memory(addr, readbuf, len); + if (ret < 0) + goto err; + + while (len) { + now = get_min(len, 32); + + if (memcmp(buf + offset, readbuf + offset, now)) { + printf("mismatch at offset 0x%08x. expected:\n", offset); + dump_long(buf + offset, now, addr + offset); + printf("read:\n"); + dump_long(readbuf + offset, now, addr + offset); + ret = -EINVAL; + mismatch++; + if (mismatch > 4) + goto err; } + + len -= now; + offset += now; } - return mismatch ? -1 : 0; +err: + free(readbuf); + + return ret; } -static int is_header(struct usb_id *p_id, unsigned char *p) +static int is_header(unsigned char *p) { - struct imx_flash_header_v1 *ohdr = (struct imx_flash_header_v1 *)p; + struct imx_flash_header *ohdr = (struct imx_flash_header *)p; struct imx_flash_header_v2 *hdr = (struct imx_flash_header_v2 *)p; - switch (p_id->mach_id->header_type) { + switch (usb_id->mach_id->header_type) { case HDR_MX51: - if (ohdr->app_barker == 0xb1) + if (ohdr->app_code_barker == 0xb1) return 1; break; case HDR_MX53: - if (hdr->barker == IVT_BARKER) + if (hdr->header.tag == TAG_IVT_HEADER && hdr->header.version == IVT_VERSION) return 1; } return 0; } -static int perform_dcd(struct libusb_device_handle *h, struct usb_id *p_id, unsigned char *p, - unsigned char *file_start, unsigned cnt) +static int perform_dcd(unsigned char *p, unsigned char *file_start, unsigned cnt) { - struct imx_flash_header_v1 *ohdr = (struct imx_flash_header_v1 *)p; + struct imx_flash_header *ohdr = (struct imx_flash_header *)p; struct imx_flash_header_v2 *hdr = (struct imx_flash_header_v2 *)p; int ret = 0; - switch (p_id->mach_id->header_type) { + if (skip_image_dcd) + return 0; + + switch (usb_id->mach_id->header_type) { case HDR_MX51: - ret = write_dcd_table_old(h, p_id, ohdr, file_start, cnt); - ohdr->dcd_ptr = 0; + ret = write_dcd_table_old(ohdr, file_start, cnt); + ohdr->dcd_block_len = 0; break; case HDR_MX53: - ret = write_dcd_table_ivt(h, p_id, hdr, file_start, cnt); + ret = write_dcd_table_ivt(hdr, file_start, cnt); hdr->dcd_ptr = 0; break; @@ -866,16 +884,15 @@ static int perform_dcd(struct libusb_device_handle *h, struct usb_id *p_id, unsi return ret; } -static int clear_dcd_ptr(struct libusb_device_handle *h, struct usb_id *p_id, - unsigned char *p, unsigned char *file_start, unsigned cnt) +static int clear_dcd_ptr(unsigned char *p, unsigned char *file_start, unsigned cnt) { - struct imx_flash_header_v1 *ohdr = (struct imx_flash_header_v1 *)p; + struct imx_flash_header *ohdr = (struct imx_flash_header *)p; struct imx_flash_header_v2 *hdr = (struct imx_flash_header_v2 *)p; - switch (p_id->mach_id->header_type) { + switch (usb_id->mach_id->header_type) { case HDR_MX51: - printf("clear dcd_ptr=0x%08x\n", ohdr->dcd_ptr); - ohdr->dcd_ptr = 0; + printf("clear dcd_ptr=0x%08x\n", ohdr->dcd); + ohdr->dcd = 0; break; case HDR_MX53: printf("clear dcd_ptr=0x%08x\n", hdr->dcd_ptr); @@ -885,21 +902,21 @@ static int clear_dcd_ptr(struct libusb_device_handle *h, struct usb_id *p_id, return 0; } -static int get_dl_start(struct usb_id *p_id, unsigned char *p, unsigned char *file_start, +static int get_dl_start(unsigned char *p, unsigned char *file_start, unsigned cnt, unsigned *dladdr, unsigned *max_length, unsigned *plugin, unsigned *header_addr) { unsigned char* file_end = file_start + cnt; - switch (p_id->mach_id->header_type) { + switch (usb_id->mach_id->header_type) { case HDR_MX51: { - struct imx_flash_header_v1 *ohdr = (struct imx_flash_header_v1 *)p; + struct imx_flash_header *ohdr = (struct imx_flash_header *)p; unsigned char *dcd_end; unsigned char* dcd; int err = get_dcd_range_old(ohdr, file_start, cnt, &dcd, &dcd_end); - *dladdr = ohdr->app_dest_ptr; - *header_addr = ohdr->dcd_ptr_ptr - offsetof(struct imx_flash_header_v1, dcd_ptr); + *dladdr = ohdr->app_dest; + *header_addr = ohdr->dcd_ptr_ptr - offsetof(struct imx_flash_header, dcd); *plugin = 0; if (err >= 0) *max_length = dcd_end[0] | (dcd_end[1] << 8) | (dcd_end[2] << 16) | (dcd_end[3] << 24); @@ -911,20 +928,18 @@ static int get_dl_start(struct usb_id *p_id, unsigned char *p, unsigned char *fi unsigned char *bd; struct imx_flash_header_v2 *hdr = (struct imx_flash_header_v2 *)p; - *dladdr = hdr->self_ptr; - *header_addr = hdr->self_ptr; + *dladdr = hdr->self; + *header_addr = hdr->self; bd = hdr->boot_data_ptr + cvt_dest_to_src; if ((bd < file_start) || ((bd + 4) > file_end)) { printf("bad boot_data_ptr %08x\n", hdr->boot_data_ptr); return -1; } - *dladdr = ((struct boot_data *)bd)->dest; - *max_length = ((struct boot_data *)bd)->image_len; - *plugin = ((struct boot_data *)bd)->plugin; - ((struct boot_data *)bd)->plugin = 0; - - hdr->boot_data_ptr = 0; + *dladdr = ((struct imx_boot_data *)bd)->start; + *max_length = ((struct imx_boot_data *)bd)->size; + *plugin = ((struct imx_boot_data *)bd)->plugin; + ((struct imx_boot_data *)bd)->plugin = 0; break; } @@ -932,8 +947,7 @@ static int get_dl_start(struct usb_id *p_id, unsigned char *p, unsigned char *fi return 0; } -static int process_header(struct libusb_device_handle *h, struct usb_id *p_id, - struct usb_work *curr, unsigned char *buf, int cnt, +static int process_header(struct usb_work *curr, unsigned char *buf, int cnt, unsigned *p_dladdr, unsigned *p_max_length, unsigned *p_plugin, unsigned *p_header_addr) { @@ -946,17 +960,17 @@ static int process_header(struct libusb_device_handle *h, struct usb_id *p_id, for (header_offset = 0; header_offset < header_max; header_offset += header_inc, p += header_inc) { - if (!is_header(p_id, p)) + if (!is_header(p)) continue; - ret = get_dl_start(p_id, p, buf, cnt, p_dladdr, p_max_length, p_plugin, p_header_addr); + ret = get_dl_start(p, buf, cnt, p_dladdr, p_max_length, p_plugin, p_header_addr); if (ret < 0) { printf("!!get_dl_start returned %i\n", ret); return ret; } if (curr->dcd) { - ret = perform_dcd(h, p_id, p, buf, cnt); + ret = perform_dcd(p, buf, cnt); if (ret < 0) { printf("!!perform_dcd returned %i\n", ret); return ret; @@ -969,7 +983,7 @@ static int process_header(struct libusb_device_handle *h, struct usb_id *p_id, } if (curr->clear_dcd) { - ret = clear_dcd_ptr(h, p_id, p, buf, cnt); + ret = clear_dcd_ptr(p, buf, cnt); if (ret < 0) { printf("!!clear_dcd returned %i\n", ret); return ret; @@ -995,137 +1009,7 @@ static int process_header(struct libusb_device_handle *h, struct usb_id *p_id, return -ENODEV; } -static int load_file(struct libusb_device_handle *h, struct usb_id *p_id, - unsigned char *p, int cnt, unsigned char *buf, unsigned buf_cnt, - unsigned dladdr, unsigned fsize, unsigned char type, FILE* xfile) -{ - static unsigned char dl_command[] = { - 0x04, - 0x04, - V(0), /* address */ - 0x00, /* format */ - V(0x00000020), /* data count */ - V(0), /* data */ - 0xaa, /* type */ - }; - int last_trans, err; - int retry = 0; - unsigned transfer_size = 0; - int max = p_id->mach_id->max_transfer; - unsigned char tmp[64]; - - dl_command[2] = (unsigned char)(dladdr >> 24); - dl_command[3] = (unsigned char)(dladdr >> 16); - dl_command[4] = (unsigned char)(dladdr >> 8); - dl_command[5] = (unsigned char)(dladdr); - - dl_command[7] = (unsigned char)(fsize >> 24); - dl_command[8] = (unsigned char)(fsize >> 16); - dl_command[9] = (unsigned char)(fsize >> 8); - dl_command[10] = (unsigned char)(fsize); - dl_command[15] = type; - - for (;;) { - err = transfer(h, 1, dl_command, 16, &last_trans, p_id); - if (!err) - break; - - printf("dl_command err=%i, last_trans=%i\n", err, last_trans); - - if (retry > 5) - return -4; - retry++; - } - - retry = 0; - - if (p_id->mach_id->mode == MODE_BULK) { - err = transfer(h, 3, tmp, sizeof(tmp), &last_trans, p_id); - if (err) - printf("in err=%i, last_trans=%i %02x %02x %02x %02x\n", - err, last_trans, tmp[0], tmp[1], tmp[2], tmp[3]); - } - - while (1) { - int retry; - - if (cnt > (int)(fsize - transfer_size)) - cnt = (fsize - transfer_size); - - if (cnt <= 0) - break; - - retry = 0; - - while (cnt) { - err = transfer(h, 2, p, get_min(cnt, max), &last_trans, p_id); - if (err) { - printf("out err=%i, last_trans=%i cnt=0x%x max=0x%x transfer_size=0x%X retry=%i\n", - err, last_trans, cnt, max, transfer_size, retry); - if (retry >= 10) { - printf("Giving up\n"); - return err; - } - if (max >= 16) - max >>= 1; - else - max <<= 1; - usleep(10000); - retry++; - continue; - } - max = p_id->mach_id->max_transfer; - retry = 0; - if (cnt < last_trans) { - printf("error: last_trans=0x%x, attempted only=0%x\n", last_trans, cnt); - cnt = last_trans; - } - if (!last_trans) { - printf("Nothing last_trans, err=%i\n", err); - break; - } - p += last_trans; - cnt -= last_trans; - transfer_size += last_trans; - } - - if (!last_trans) - break; - - if (feof(xfile)) - break; - - cnt = fsize - transfer_size; - if (cnt <= 0) - break; - - cnt = fread(buf, 1 , get_min(cnt, buf_cnt), xfile); - p = buf; - } - - if (p_id->mach_id->mode == MODE_HID) { - err = transfer(h, 3, tmp, sizeof(tmp), &last_trans, p_id); - if (err) - printf("3 in err=%i, last_trans=%i %02x %02x %02x %02x\n", - err, last_trans, tmp[0], tmp[1], tmp[2], tmp[3]); - err = transfer(h, 4, tmp, sizeof(tmp), &last_trans, p_id); - if (err) - printf("4 in err=%i, last_trans=%i %02x %02x %02x %02x\n", - err, last_trans, tmp[0], tmp[1], tmp[2], tmp[3]); - } else { - do_status(h, p_id); - } - - return transfer_size; -} - -#define FT_APP 0xaa -#define FT_CSF 0xcc -#define FT_DCD 0xee -#define FT_LOAD_ONLY 0x00 - -static int do_irom_download(struct libusb_device_handle *h, struct usb_id *p_id, - struct usb_work *curr, int verify) +static int do_irom_download(struct usb_work *curr, int verify) { static unsigned char jump_command[] = {0x0b,0x0b, V(0), 0x00, V(0x00000000), V(0), 0x00}; @@ -1137,10 +1021,9 @@ static int do_irom_download(struct libusb_device_handle *h, struct usb_id *p_id, int cnt; unsigned file_base; int last_trans, err; -#define BUF_SIZE (1024*16) unsigned char *buf = NULL; + unsigned char *image; unsigned char *verify_buffer = NULL; - unsigned verify_cnt; unsigned char *p; unsigned char tmp[64]; unsigned dladdr = 0; @@ -1149,7 +1032,6 @@ static int do_irom_download(struct libusb_device_handle *h, struct usb_id *p_id, unsigned header_addr = 0; unsigned skip = 0; - unsigned transfer_size=0; int retry = 0; xfile = fopen(curr->filename, "rb" ); @@ -1158,26 +1040,29 @@ static int do_irom_download(struct libusb_device_handle *h, struct usb_id *p_id, return -5; } - buf = malloc(BUF_SIZE); - if (!buf) { - printf("error, out of memory\n"); + fsize = get_file_size(xfile); + if (fsize < 0x20) { + printf("error, file: %s is too small\n", curr->filename); ret = -2; goto cleanup; } - fsize = get_file_size(xfile); - - cnt = fread(buf, 1 , BUF_SIZE, xfile); - - if (cnt < 0x20) { - printf("error, file: %s is too small\n", curr->filename); + buf = malloc(fsize); + if (!buf) { + printf("error, out of memory\n"); ret = -2; goto cleanup; } + cnt = fread(buf, 1 , fsize, xfile); + if (cnt < fsize) { + printf("error, cannot read %s\n", curr->filename); + return -1; + } + max_length = fsize; - ret = process_header(h, p_id, curr, buf, cnt, + ret = process_header(curr, buf, cnt, &dladdr, &max_length, &plugin, &header_addr); if (ret < 0) goto cleanup; @@ -1206,7 +1091,7 @@ static int do_irom_download(struct libusb_device_handle *h, struct usb_id *p_id, type = (curr->plug || curr->jump_mode) ? FT_APP : FT_LOAD_ONLY; - if (p_id->mach_id->mode == MODE_BULK && type == FT_APP) { + if (usb_id->mach_id->mode == MODE_BULK && type == FT_APP) { /* No jump command, dladdr should point to header */ dladdr = header_addr; } @@ -1218,22 +1103,9 @@ static int do_irom_download(struct libusb_device_handle *h, struct usb_id *p_id, skip = dladdr - file_base; - if (skip > cnt) { - if (skip > fsize) { - printf("skip(0x%08x) > fsize(0x%08x) file_base=0x%08x, header_offset=0x%x\n", - skip, fsize, file_base, header_offset); - ret = -4; - goto cleanup; - } - - fseek(xfile, skip, SEEK_SET); - cnt -= skip; - fsize -= skip; - skip = 0; - cnt = fread(buf, 1 , BUF_SIZE, xfile); - } + image = buf + skip; - p = &buf[skip]; + p = image; cnt -= skip; fsize -= skip; @@ -1241,13 +1113,7 @@ static int do_irom_download(struct libusb_device_handle *h, struct usb_id *p_id, fsize = max_length; if (verify) { - /* - * we need to save header for verification - * because some of the file is changed - * before download - */ - verify_buffer = malloc(cnt); - verify_cnt = cnt; + verify_buffer = malloc(64); if (!verify_buffer) { printf("error, out of memory\n"); @@ -1255,9 +1121,9 @@ static int do_irom_download(struct libusb_device_handle *h, struct usb_id *p_id, goto cleanup; } - memcpy(verify_buffer, p, cnt); + memcpy(verify_buffer, p, 64); - if ((type == FT_APP) && (p_id->mach_id->mode != MODE_HID)) { + if ((type == FT_APP) && (usb_id->mach_id->mode != MODE_HID)) { type = FT_LOAD_ONLY; verify = 2; } @@ -1266,19 +1132,16 @@ static int do_irom_download(struct libusb_device_handle *h, struct usb_id *p_id, printf("loading binary file(%s) to %08x, skip=0x%x, fsize=%u type=%d...\n", curr->filename, dladdr, skip, fsize, type); - ret = load_file(h, p_id, p, cnt, buf, BUF_SIZE, - dladdr, fsize, type, xfile); + ret = load_file(image, fsize, dladdr, type); if (ret < 0) goto cleanup; printf("binary file successfully loaded\n"); - transfer_size = ret; - if (verify) { printf("verifying file...\n"); - ret = verify_memory(h, p_id, xfile, skip, dladdr, fsize, verify_buffer, verify_cnt); + ret = verify_memory(image, fsize, dladdr); if (ret < 0) { printf("verifying failed\n"); goto cleanup; @@ -1287,18 +1150,19 @@ static int do_irom_download(struct libusb_device_handle *h, struct usb_id *p_id, printf("file successfully verified\n"); if (verify == 2) { - if (verify_cnt > 64) - verify_cnt = 64; - ret = load_file(h, p_id, verify_buffer, verify_cnt, - buf, BUF_SIZE, dladdr, verify_cnt, - FT_APP, xfile); + /* + * In bulk mode we do not have an explicit jump command, + * so we load part of the image again with type FT_APP + * this time. + */ + ret = load_file(verify_buffer, 64, dladdr, FT_APP); if (ret < 0) goto cleanup; } } - if (p_id->mach_id->mode == MODE_HID && type == FT_APP) { + if (usb_id->mach_id->mode == MODE_HID && type == FT_APP) { printf("jumping to 0x%08x\n", header_addr); jump_command[2] = (unsigned char)(header_addr >> 24); @@ -1310,7 +1174,7 @@ static int do_irom_download(struct libusb_device_handle *h, struct usb_id *p_id, retry = 0; for (;;) { - err = transfer(h, 1, jump_command, 16, &last_trans, p_id); + err = transfer(1, jump_command, 16, &last_trans); if (!err) break; @@ -1323,14 +1187,14 @@ static int do_irom_download(struct libusb_device_handle *h, struct usb_id *p_id, } memset(tmp, 0, sizeof(tmp)); - err = transfer(h, 3, tmp, sizeof(tmp), &last_trans, p_id); + err = transfer(3, tmp, sizeof(tmp), &last_trans); if (err) printf("j3 in err=%i, last_trans=%i %02x %02x %02x %02x\n", err, last_trans, tmp[0], tmp[1], tmp[2], tmp[3]); } - ret = (fsize == transfer_size) ? 0 : -16; + ret = 0; cleanup: fclose(xfile); free(verify_buffer); @@ -1339,10 +1203,28 @@ cleanup: return ret; } +static int write_mem(struct config_data *data, uint32_t addr, uint32_t val, int width) +{ + printf("wr 0x%08x 0x%08x\n", addr, val); + + return write_memory(addr, val, width); +} + +static int parse_initfile(const char *filename) +{ + struct config_data data = { + .write_mem = write_mem, + }; + + return parse_config(&data, filename); +} + static void usage(const char *prgname) { fprintf(stderr, "usage: %s [OPTIONS] [FILENAME]\n\n" "-c check correctness of flashed image\n" + "-i <cfgfile> Specify custom SoC initialization file\n" + "-s skip DCD included in image\n" "-v verbose (give multiple times to increase)\n" "-h this help\n", prgname); exit(1); @@ -1350,7 +1232,6 @@ static void usage(const char *prgname) int main(int argc, char *argv[]) { - struct usb_id *p_id = NULL; struct mach_id *mach; libusb_device **devs; libusb_device *dev; @@ -1358,13 +1239,13 @@ int main(int argc, char *argv[]) int err; int ret = 1; ssize_t cnt; - libusb_device_handle *h = NULL; int config = 0; int verify = 0; struct usb_work w = {}; int opt; + char *initfile = NULL; - while ((opt = getopt(argc, argv, "cvh")) != -1) { + while ((opt = getopt(argc, argv, "cvhi:s")) != -1) { switch (opt) { case 'c': verify = 1; @@ -1374,6 +1255,12 @@ int main(int argc, char *argv[]) break; case 'h': usage(argv[0]); + case 'i': + initfile = optarg; + break; + case 's': + skip_image_dcd = 1; + break; default: exit(1); } @@ -1406,7 +1293,7 @@ int main(int argc, char *argv[]) goto out; } - err = libusb_open(dev, &h); + err = libusb_open(dev, &usb_dev_handle); if (err) { fprintf(stderr, "Could not open device vid=0x%x pid=0x%x err=%d\n", mach->vid, mach->pid, err); @@ -1415,44 +1302,50 @@ int main(int argc, char *argv[]) libusb_free_device_list(devs, 1); - libusb_get_configuration(h, &config); + libusb_get_configuration(usb_dev_handle, &config); - if (libusb_kernel_driver_active(h, 0)) - libusb_detach_kernel_driver(h, 0); + if (libusb_kernel_driver_active(usb_dev_handle, 0)) + libusb_detach_kernel_driver(usb_dev_handle, 0); - err = libusb_claim_interface(h, 0); + err = libusb_claim_interface(usb_dev_handle, 0); if (err) { printf("Claim failed\n"); goto out; } - p_id = malloc(sizeof(*p_id)); - if (!p_id) { + usb_id = malloc(sizeof(*usb_id)); + if (!usb_id) { perror("malloc"); exit(1); } - p_id->mach_id = mach; + usb_id->mach_id = mach; - err = do_status(h, p_id); + err = do_status(); if (err) { printf("status failed\n"); goto out; } - err = do_irom_download(h, p_id, &w, verify); + if (initfile) { + err = parse_initfile(initfile); + if (err) + goto out; + } + + err = do_irom_download(&w, verify); if (err) { - err = do_status(h, p_id); + err = do_status(); goto out; } ret = 0; out: - if (p_id) - free(p_id); + if (usb_id) + free(usb_id); - if (h) - libusb_close(h); + if (usb_dev_handle) + libusb_close(usb_dev_handle); libusb_exit(NULL); |