FreeCalypso > hg > freecalypso-sw
view loadtools/flcmplboot.c @ 416:c2e14cc15c23
flash erase-program-boot: implemented CRC check before flashing
author | Michael Spacefalcon <msokolov@ivan.Harhan.ORG> |
---|---|
date | Tue, 17 Jun 2014 07:33:25 +0000 |
parents | b2487cfd68fd |
children |
line wrap: on
line source
/* * 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 */ }