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