FreeCalypso > hg > freecalypso-tools
diff loadtools/flcmplboot.c @ 0:e7502631a0f9
initial import from freecalypso-sw rev 1033:5ab737ac3ad7
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Sat, 11 Jun 2016 00:13:35 +0000 |
parents | |
children | 2cd705c8116e |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loadtools/flcmplboot.c Sat Jun 11 00:13:35 2016 +0000 @@ -0,0 +1,256 @@ +/* + * This module contains the implementation of the flash erase-program-boot + * hack for brickable Compal phones. + */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <ctype.h> +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> +#include "flash.h" + +extern struct flash_bank_info flash_bank_info[2]; +extern struct flash_cmdset flash_cmdset_intel; + +extern uint32_t crc32_table[]; + +static int hack_enabled; +static uint32_t boot_sector_size; +static uint32_t ram_buffer_addr; + +/* called from hwparam.c config file parser */ +void +set_boot_reflash_hack(arg, filename_for_errs, lineno_for_errs) + char *arg; + char *filename_for_errs; + int lineno_for_errs; +{ + char *cp, *np, *ep; + + if (hack_enabled) { + fprintf(stderr, + "%s line %d: duplicate boot-reflash-hack setting\n", + filename_for_errs, lineno_for_errs); + exit(1); + } + for (cp = arg; isspace(*cp); cp++) + ; + if (!*cp || *cp == '#') { +too_few_arg: fprintf(stderr, + "%s line %d: boot-reflash-hack setting: too few arguments\n", + filename_for_errs, lineno_for_errs); + exit(1); + } + for (np = cp; *cp && !isspace(*cp); cp++) + ; + if (!*cp) + goto too_few_arg; + *cp++ = '\0'; + ram_buffer_addr = strtoul(np, &ep, 16); + if (*ep) { +invhex: fprintf(stderr, + "%s line %d: syntax error (hex arguments expected)\n", + filename_for_errs, lineno_for_errs); + exit(1); + } + while (isspace(*cp)) + cp++; + if (!*cp || *cp == '#') + goto too_few_arg; + for (np = cp; *cp && !isspace(*cp); cp++) + ; + if (*cp) + *cp++ = '\0'; + boot_sector_size = strtoul(np, &ep, 16); + if (*ep) + goto invhex; + while (isspace(*cp)) + cp++; + if (*cp && *cp != '#') { + fprintf(stderr, + "%s line %d: boot-reflash-hack setting: too many arguments\n", + filename_for_errs, lineno_for_errs); + exit(1); + } + hack_enabled = 1; +} + +static void +make_s3_record(buf, dest_addr, datalen) + u_char *buf; + uint32_t dest_addr; +{ + int totlen, i; + u_char accum; + + buf[0] = totlen = datalen + 5; + buf[1] = dest_addr >> 24; + buf[2] = dest_addr >> 16; + buf[3] = dest_addr >> 8; + buf[4] = dest_addr; + accum = 0; + for (i = 0; i < totlen; i++) + accum += buf[i]; + buf[i] = ~accum; +} + +static void +make_ml_arg(rec, buf) + u_char *rec; + char *buf; +{ + register int i, len; + register char *s; + + len = rec[0] + 1; + s = buf; + for (i = 0; i < len; i++) { + sprintf(s, "%02X", rec[i]); + s += 2; + } + *s = '\0'; +} + +flashcmd_erase_program_boot(argc, argv) + char **argv; +{ + FILE *binf; + struct stat filestat; + size_t len; + char *strtoul_endp; + char *targv[5], longarg[513]; + char shortarg1[9], shortarg2[9], shortarg3[9]; + u_char databuf[256]; + int reclen, cc, i; + uint32_t ramaddr, remlen, crcaccum; + u_long crc_from_target; + + if (!hack_enabled) { + fprintf(stderr, + "Operation not applicable to this target device\n"); + return(-1); + } + if (argc < 3 || argc > 4) { +inv: fprintf(stderr, "usage: %s %s binfile [length]\n", + argv[0], argv[1]); + return(-1); + } + if (flash_get_cfi(0) < 0) + return(-1); + if (flash_bank_info[0].geom->regions[0].sector_size + != boot_sector_size) { + fprintf(stderr, + "error: detected flash boot sector size differs from config\n"); + return(-1); + } + if (flash_bank_info[0].ops != &flash_cmdset_intel) { + fprintf(stderr, + "error: operation implemented for Intel flash only\n"); + return(-1); + } + + binf = fopen(argv[2], "r"); + if (!binf) { + perror(argv[2]); + return(-1); + } + fstat(fileno(binf), &filestat); + if (!S_ISREG(filestat.st_mode)) { + fprintf(stderr, "%s is not a regular file\n", argv[2]); + fclose(binf); + return(-1); + } + if (argc > 3) { + len = strtoul(argv[3], &strtoul_endp, 16); + if (*strtoul_endp) { + fclose(binf); + goto inv; + } + if (len > filestat.st_size) { + fprintf(stderr, + "error: specified length exceeds file length\n"); + fclose(binf); + return(-1); + } + } else + len = filestat.st_size; + if (len > boot_sector_size) { + fprintf(stderr, "error: length exceeds boot sector size\n"); + fclose(binf); + return(-1); + } + if (len & 1) { + fprintf(stderr, "error: length must be even\n"); + fclose(binf); + return(-1); + } + + printf("Loading new boot code into target RAM at %lx\n", + (u_long) ram_buffer_addr); + targv[0] = "ML"; + targv[1] = longarg; + targv[2] = 0; + ramaddr = ram_buffer_addr; + crcaccum = 0xFFFFFFFF; + for (remlen = len; remlen; remlen -= reclen) { + if (remlen >= 250) + reclen = 250; + else + reclen = remlen; + cc = fread(databuf + 5, 1, reclen, binf); + if (cc != reclen) { + fclose(binf); + fprintf(stderr, "error reading from %s\n", argv[2]); + return(-1); + } + for (i = 0; i < reclen; i++) /* update running CRC */ + crcaccum = crc32_table[crcaccum & 0xFF ^ databuf[i+5]] + ^ (crcaccum >> 8); + make_s3_record(databuf, ramaddr, reclen); + make_ml_arg(databuf, longarg); + tpinterf_make_cmd(targv); + if (tpinterf_send_cmd() < 0) { + fclose(binf); + return(-1); + } + cc = tpinterf_pass_output(1); + if (cc) { + fclose(binf); + return(cc); + } + ramaddr += reclen; + putchar('.'); + fflush(stdout); + } + putchar('\n'); + fclose(binf); + + printf("Verifying CRC-32 in target RAM\n"); + if (crc32_on_target((u_long) ram_buffer_addr, (u_long) len, + &crc_from_target) < 0) + return(-1); + if (crc_from_target == crcaccum) + printf("match (%08lX)\n", crc_from_target); + else { + fprintf(stderr, "error: CRC mismatch!\n"); + return(-1); + } + + printf("Commanding flash erase+program operation on the target\n"); + sprintf(shortarg1, "%lx", (u_long) ram_buffer_addr); + sprintf(shortarg2, "%lx", (u_long) flash_bank_info[0].base_addr); + sprintf(shortarg3, "%lx", (u_long) len); + targv[0] = "intel-rewrite-sector"; + targv[1] = shortarg1; + targv[2] = shortarg2; + targv[3] = shortarg3; + targv[4] = 0; + tpinterf_make_cmd(targv); + if (tpinterf_send_cmd() < 0) + return(-1); + return tpinterf_pass_output(20); /* 20 s timeout */ +}