From 470457e22a1b5537013603d5e367c51e47bb61bf Mon Sep 17 00:00:00 2001 From: James Date: Mon, 5 May 2014 17:50:20 +0100 Subject: fish --- libdpf/bootload.c | 379 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 379 insertions(+) create mode 100644 libdpf/bootload.c (limited to 'libdpf/bootload.c') diff --git a/libdpf/bootload.c b/libdpf/bootload.c new file mode 100644 index 0000000..2d882cf --- /dev/null +++ b/libdpf/bootload.c @@ -0,0 +1,379 @@ +// Bootstream generator for Buildwin firmware loader +// +// (c) 2011, +// +// + +#include "dpf.h" +#include "usbuser.h" // our user defined flash commands +#include +#include +#include +#include + +// Jump offsets for USB command: +#define JMP_LOAD 0x0dae +#define JMP_SPILIB 0x11bf +#define JMP_USER 0x1000 + +#define PAGESIZE 256 +#define BUFSIZE (64 - 6) +#define PKTSIZE (64 - 7) + +typedef struct { + unsigned char len; + unsigned char chk; + unsigned char jmp[2]; + union { + // Structures for various backends + // The default memory loader: + struct { + unsigned char offset[2]; // XDATA memory dest address + unsigned char buf[BUFSIZE]; // Binary data to write + } loader; + struct { + unsigned char opcode; // SPI operation opcode + unsigned char wnum; // Number of bytes to send (Host -> DPF) + unsigned char rnum; // Number of bytes to recv (DPF -> Host) + unsigned char seq[PKTSIZE]; // SPI cmd sequence + } spi; + } u; +} UsbMsg; + +#define OPCODE_SPISEL 0x01 // assert SELECT +#define OPCODE_CRYPT0 0x02 +#define OPCODE_CRYPT1 0x04 +#define OPCODE_SPIDES 0x10 // assert DESELECT + +int validate(UsbMsg *msg) +{ + unsigned short c = 0; + unsigned char *b = (unsigned char *) msg; + unsigned short l = msg->len; + + if (l < 6 || l > 64) return -1; + + while (l--) { + c += *b++; + } + + msg->chk -= c; + + return 0; +} + +void hexdump(unsigned char *buf, unsigned long n) +{ + int i = 0; + int c = 0; + + while (i < n) { + printf("%02x ", buf[i]); + c++; + if (c == 16) { c = 0; printf("\n"); } + i++; + } + if (c) + printf("\n"); +} + +int transmit(DPFContext *dpf, UsbMsg *m) +{ + int error; + unsigned char *s = (unsigned char *) m; + // hexdump(s, m->len); + error = usb_rawwrite(dpf->dev.udev, s, m->len); + if (error < 0) { + perror("Writing to USB"); + } + return error; +} + +int spilib_process(DPFContext *h, UsbMsg *umsg, unsigned char *out) +{ + int error; + umsg->jmp[0] = JMP_SPILIB & 0xff; umsg->jmp[1] = JMP_SPILIB >> 8; + umsg->len = 7 + umsg->u.spi.wnum; + + validate(umsg); + error = transmit(h, umsg); + if (umsg->u.spi.rnum > 0 && error >= 0) { + error = usb_rawread(h->dev.udev, out, 64); + } + if (error < 0) perror("Reading USB"); + else error = 0; + return error; +} + +int go_hid(DPFContext *dpf, ADDR jmpoffset) +{ + UsbMsg umsg; + umsg.jmp[0] = jmpoffset; umsg.jmp[1] = jmpoffset >> 8; + umsg.len = 8; + validate(&umsg); + return transmit(dpf, &umsg); +} + +int load(DPFContext *dpf, FILE *f, uint16_t jmpoffset) +{ + int size; + UsbMsg umsg; + + unsigned short offset = jmpoffset - 0x800; + + umsg.jmp[0] = JMP_LOAD & 0xff; umsg.jmp[1] = JMP_LOAD >> 8; + umsg.chk = 0xce; + size = fread(umsg.u.loader.buf, 1, BUFSIZE, f); + if (size < 0) return size; + + while (size > 0) { + umsg.u.loader.offset[0] = offset; + umsg.u.loader.offset[1] = offset >> 8; + umsg.len = sizeof(UsbMsg) - BUFSIZE + size; + offset += size; + validate(&umsg); + transmit(dpf, &umsg); + size = fread(umsg.u.loader.buf, 1, BUFSIZE, f); + } + + // And jump into the code: + if (jmpoffset != 0x0000) { + go_hid(dpf, jmpoffset); + } + return size; +} +/* Flash stuff, HID wrapped */ + +static unsigned char s_rbuf[64]; + +static +int flash_probe_hid(DPFContext *h, unsigned char *id) +{ + int error; + UsbMsg umsg; + FILE *f; + + // First, load spilib.bin + f = fopen("spilib.bin", "rb"); + + if (!f) { + printf("failed to open flash driver\n"); + return -1; + } + umsg.u.spi.opcode = OPCODE_SPISEL | OPCODE_SPIDES; + + error = load(h, f, 0x0000); // Load, but do not execute + fclose(f); + usleep(500000); + if (error == 0) { + umsg.u.spi.wnum = 1; + umsg.u.spi.rnum = 4; + umsg.u.spi.seq[0] = SPM_RDID; + error = spilib_process(h, &umsg, s_rbuf); + id[0] = s_rbuf[0]; id[1] = s_rbuf[1]; id[2] = s_rbuf[2]; + } + return error; +} + +static +int flash_cmd_hid(DPFContext *h, int command, int cmdlen, ADDR addr) +{ + UsbMsg umsg; + umsg.u.spi.opcode = OPCODE_SPISEL | OPCODE_SPIDES; + umsg.u.spi.wnum = cmdlen; + umsg.u.spi.rnum = 0; + umsg.u.spi.seq[0] = command; + umsg.u.spi.seq[1] = addr >> 16; + umsg.u.spi.seq[2] = addr >> 8; + umsg.u.spi.seq[3] = addr; + + return spilib_process(h, &umsg, 0); +} + +int flash_status_hid(DPFHANDLE h, uint8_t *status) +{ + int error; + UsbMsg umsg; + umsg.u.spi.opcode = OPCODE_SPISEL | OPCODE_SPIDES; + umsg.u.spi.wnum = 1; + umsg.u.spi.rnum = 1; + umsg.u.spi.seq[0] = SPM_RDSR; + + error = spilib_process(h, &umsg, s_rbuf); + *status = s_rbuf[0]; + return error; +} + +static +int chunk_read(DPFContext *h, unsigned char *buf, ADDR offset, int len) +{ + int error; + UsbMsg umsg; + + if (len > PKTSIZE) len = PKTSIZE; + + umsg.u.spi.opcode = OPCODE_SPISEL | OPCODE_SPIDES; + umsg.u.spi.wnum = 4; + umsg.u.spi.rnum = PKTSIZE; + umsg.u.spi.seq[0] = SPM_READ; + umsg.u.spi.seq[1] = offset >> 16; + umsg.u.spi.seq[2] = offset >> 8; + umsg.u.spi.seq[3] = offset; + + error = spilib_process(h, &umsg, buf); + if (error < 0) return error; + + return len; +} + + +static +int flash_read_hid(DPFContext *h, unsigned char *buf, ADDR offset, int len) +{ + int n; + + while (len > 0) { + n = chunk_read(h, buf, offset, len); + if (n < 0) return n; + len -= n; offset += n; buf += n; + } + return 0; +} + +int fill_spimsg(UsbMsg *umsg, const unsigned char *buf, + unsigned short offset, int len) +{ + int n = PKTSIZE - offset; + if (len > n) len = n; + memcpy(&umsg->u.spi.seq[offset], buf, len); + umsg->u.spi.wnum = offset + len; + return len; +} + +static +int flash_writechunk_hid(DPFContext *h, + const unsigned char *buf, ADDR offset, int len) +{ + UsbMsg umsg; + int error; + int n; + + if (len > PAGESIZE) len = PAGESIZE; + + umsg.u.spi.rnum = 0; + umsg.u.spi.seq[0] = SPM_PP; + umsg.u.spi.seq[1] = offset >> 16; + umsg.u.spi.seq[2] = offset >> 8; + umsg.u.spi.seq[3] = offset; + + n = fill_spimsg(&umsg, buf, 4, len); + len -= n; buf += n; offset += n; + + umsg.u.spi.opcode = OPCODE_SPISEL; + error = spilib_process(h, &umsg, 0); + if (error < 0) return error; + + umsg.u.spi.opcode = 0; + while (len > PKTSIZE) { + n = fill_spimsg(&umsg, buf, 0, PKTSIZE); + error = spilib_process(h, &umsg, 0); + if (error < 0) return error; + len -= n; buf += n; offset += n; + } + + umsg.u.spi.opcode = OPCODE_SPIDES; + fill_spimsg(&umsg, buf, 0, len); + error = spilib_process(h, &umsg, 0); + if (error < 0) return error; + + return PAGESIZE; +} + +int blk_write(DPFContext *h, ADDR dst, const unsigned char *src, + unsigned short len) +{ + static UsbMsg umsg; + + if (len > BUFSIZE) len = BUFSIZE; + + umsg.jmp[0] = JMP_LOAD & 0xff; umsg.jmp[1] = JMP_LOAD >> 8; + memcpy(umsg.u.loader.buf, src, len); + umsg.u.loader.offset[0] = dst; + umsg.u.loader.offset[1] = dst >> 8; + umsg.len = sizeof(UsbMsg) - BUFSIZE + len; + + validate(&umsg); + transmit(h, &umsg); + return len; +} + +int mem_write_hid(DPFContext *h, + ADDR dst, const unsigned char *src, unsigned short n) +{ + int len; + + while (n > 0) { + len = blk_write(h, dst, src, n); + n -= len; src += len; dst += len; + } + return n; +} + + +AccessMethods +hid_methods = { + .mem_read = NULL, + .mem_write = mem_write_hid, + .go = go_hid, + .bootstrap = NULL, + .flash_probe = flash_probe_hid, + .flash_cmd = flash_cmd_hid, + .flash_status = flash_status_hid, + .flash_read = flash_read_hid, + .flash_writechunk = flash_writechunk_hid, + .flash_lock = NULL, +}; + + +#ifdef TEST +int main(int argc, char **argv) +{ + FILE *f; + int error; + DPFHANDLE dpf; + uint16_t startaddr = 0x1000; + + if (argc >= 2) { + + f = fopen(argv[1], "rb"); + + if (!f) { + printf("failed to open file\n"); + return -1; + } + if (argc == 3) { + startaddr = strtol(argv[2], NULL, 16); + printf("Starting at %04x\n", startaddr); + } + + error = dpf_open("usb0", &dpf); + if (error < 0) { + printf("Failed to open DPF\n"); + return error; + } + if (dpf->mode == MODE_USBHID) { + error = load(dpf, f, startaddr); + } else { + printf("Not in BOOTLOAD mode! Press Reset and hold MENU\n"); + } + dpf_close(dpf); + } else { + printf("Needs boot image argument\n"); + } + + if (error < 0) { + printf("Error\n"); + } + return error; +} +#endif -- cgit v1.2.3