FreeCalypso > hg > freecalypso-tools
view loadtools/flprogsrec.c @ 657:742c99c1ff52
CHANGES: fc-xram CRC-32 verification
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Tue, 03 Mar 2020 00:19:30 +0000 |
parents | a880f48d6ac0 |
children | 51bcfb251b23 |
line wrap: on
line source
/* * This module implements the flash program-srec and flash program-m0 commands: * programming flash using S-record files as the data source. */ #include <sys/types.h> #include <stdio.h> #include <stdint.h> #include <stdlib.h> #include <time.h> #include "flash.h" #include "discontig.h" #include "srecreader.h" extern struct flash_bank_info flash_bank_info[2]; extern uint32_t crc32_table[]; read_srec_img_for_flash(imgfile, is_m0, bank_size, reglistp, regcountp, totalp, tmpfilep) char *imgfile; uint32_t bank_size, *totalp; struct discontig_prog *reglistp; unsigned *regcountp; FILE **tmpfilep; { struct srecreader srr; struct discontig_prog *regp; unsigned regcount; uint32_t total_len; char tmpfilename[] = "/tmp/fc-loadtoolXXXXXX"; int rc, tmpfd, i, c; FILE *tmpfile; printf("Reading S-record image from %s\n", imgfile); srr.filename = imgfile; rc = open_srec_file(&srr); if (rc < 0) return(rc); tmpfd = mkstemp(tmpfilename); if (tmpfd < 0) { fprintf(stderr, "unable to get temp file via mkstemp()\n"); fclose(srr.openfile); return(-1); } unlink(tmpfilename); tmpfile = fdopen(tmpfd, "w+"); if (!tmpfile) { perror("fdopen"); close(tmpfd); fclose(srr.openfile); return(-1); } regp = reglistp; regcount = 0; total_len = 0; for (;;) { if (read_s_record(&srr) < 0) { /* error msg already printed */ fclose(srr.openfile); fclose(tmpfile); return(-1); } if (srr.record_type == '0') { if (srr.lineno == 1) continue; fprintf(stderr, "error: S0 record found in line %d of %s (expected in line 1 only)\n", srr.lineno, srr.filename); fclose(srr.openfile); fclose(tmpfile); return(-1); } else if (srr.record_type == '7') break; else if (srr.record_type != '3') { fprintf(stderr, "error: unsupported S%c record type in line %d of %s\n", srr.record_type, srr.lineno, srr.filename); fclose(srr.openfile); fclose(tmpfile); return(-1); } /* must be S3 */ if (s3s7_get_addr_data(&srr) < 0) { /* error msg already printed */ fclose(srr.openfile); fclose(tmpfile); return(-1); } if (srr.datalen < 1) { fprintf(stderr, "%s line %d: S3 record of zero data length ignored\n", srr.filename, srr.lineno); continue; } if (srr.addr & 1 || srr.datalen & 1) { fprintf(stderr, "%s line %d: violates word alignment requirement\n", srr.filename, srr.lineno); fclose(srr.openfile); fclose(tmpfile); return(-1); } srr.addr &= bank_size - 1; if (srr.addr + srr.datalen > bank_size) { fprintf(stderr, "%s line %d: goes past the end of the flash bank\n", srr.filename, srr.lineno); fclose(srr.openfile); fclose(tmpfile); return(-1); } /* is this the first record of the first region? */ if (!regcount) { regp->start = srr.addr; regp->end = srr.addr; regp->crc = 0xFFFFFFFF; regcount = 1; } if (srr.addr < regp->end) { fprintf(stderr, "%s line %d: address going backwards\n", srr.filename, srr.lineno); fclose(srr.openfile); fclose(tmpfile); return(-1); } if (srr.addr != regp->end) { if (regcount >= MAX_SREC_REGIONS) { fprintf(stderr, "error: %s has too many discontiguous regions\n", imgfile); fclose(srr.openfile); fclose(tmpfile); return(-1); } regp++; regcount++; regp->start = srr.addr; regp->end = srr.addr; regp->crc = 0xFFFFFFFF; } /* take in the payload */ if (is_m0) { for (i = 0; i < srr.datalen; i += 2) { c = srr.record[i+6]; regp->crc = crc32_table[regp->crc & 0xFF ^ c] ^ (regp->crc >> 8); putc(c, tmpfile); c = srr.record[i+5]; regp->crc = crc32_table[regp->crc & 0xFF ^ c] ^ (regp->crc >> 8); putc(c, tmpfile); } } else { for (i = 0; i < srr.datalen; i++) { c = srr.record[i+5]; regp->crc = crc32_table[regp->crc & 0xFF ^ c] ^ (regp->crc >> 8); putc(c, tmpfile); } } regp->end += srr.datalen; total_len += srr.datalen; } /* got S7 */ fclose(srr.openfile); if (!regcount) { fprintf(stderr, "%s line %d: S7 without any preceding S3 data records\n", srr.filename, srr.lineno); fclose(tmpfile); return(-1); } /* good read */ if (regcount == 1) printf("Got %lu (0x%lx) bytes in one contiguous region\n", (u_long) total_len, (u_long) total_len); else printf("Got %lu (0x%lx) bytes in %u discontiguous regions\n", (u_long) total_len, (u_long) total_len, regcount); *regcountp = regcount; *totalp = total_len; *tmpfilep = tmpfile; return(0); } flashcmd_progsrec_gen(bank, imgfile, is_m0) char *imgfile; { struct flash_bank_info *bi; struct discontig_prog regions[MAX_SREC_REGIONS], *regp; unsigned nregions, reg; uint32_t total_len, bytesdone, addr, len; FILE *tmpfile; char *targv[4], shortarg[10], longarg[513]; u_char databuf[256]; int reclen, cc, rc; time_t initial_time, curtime, last_time; unsigned duration, mm, ss; u_long crc_from_target; if (flash_detect(bank, 0) < 0) return(-1); bi = flash_bank_info + bank; rc = read_srec_img_for_flash(imgfile, is_m0, bi->geom->total_size, regions, &nregions, &total_len, &tmpfile); if (rc < 0) return(rc); sprintf(shortarg, "%lx", (u_long) bi->base_addr); targv[0] = bi->ops->loadagent_setbase_cmd; targv[1] = shortarg; targv[2] = 0; printf("Setting flash base address: %s %s\n", targv[0], targv[1]); tpinterf_make_cmd(targv); if (tpinterf_send_cmd() < 0) { fclose(tmpfile); return(-1); } rc = tpinterf_pass_output(1); if (rc) { fclose(tmpfile); return(rc); } if (bi->ops->prep_for_program(bi) < 0) { fclose(tmpfile); return(-1); } rewind(tmpfile); targv[0] = bi->ops->loadagent_program_cmd; targv[1] = shortarg; targv[2] = longarg; targv[3] = 0; printf("Programming flash\n"); bytesdone = 0; last_time = 0; time(&initial_time); for (reg = 0, regp = regions; reg < nregions; reg++, regp++) { addr = regp->start; len = regp->end - addr; while (len) { if (len >= 256) reclen = 256; else reclen = len; cc = fread(databuf, 1, reclen, tmpfile); if (cc != reclen) { fclose(tmpfile); fprintf(stderr, "error reading from temp file!\n"); return(-1); } sprintf(shortarg, "%lx", addr); build_flashw_hex_string(databuf, longarg, reclen >> 1, 0); tpinterf_make_cmd(targv); if (tpinterf_send_cmd() < 0) { fclose(tmpfile); return(-1); } rc = tpinterf_pass_output(8); /* 8 s timeout */ if (rc) { fclose(tmpfile); return(rc); } addr += reclen; len -= reclen; bytesdone += reclen; cc = bytesdone * 100 / total_len; time(&curtime); if (curtime != last_time || cc == 100) { printf("\r0x%lx bytes programmed (%i%%)", bytesdone, cc); fflush(stdout); } last_time = curtime; } } putchar('\n'); fclose(tmpfile); duration = last_time - initial_time; mm = duration / 60; ss = duration - mm * 60; printf("Operation completed in %um%us\n", mm, ss); /* reset flash to read mode */ if (bi->ops->reset_cmd(bi) < 0) return(-1); printf("Verifying CRC-32 of %u programmed region(s)\n", nregions); for (reg = 0, regp = regions; reg < nregions; reg++, regp++) { rc = crc32_on_target((u_long) (bi->base_addr + regp->start), (u_long) (regp->end - regp->start), &crc_from_target); if (rc < 0) return(rc); if (crc_from_target != regp->crc) { fprintf(stderr, "error: CRC mismatch!\n"); return(-1); } putchar('.'); fflush(stdout); } putchar('\n'); return(0); } flashcmd_program_srec(argc, argv, bank) char **argv; { if (argc != 3) { fprintf(stderr, "usage: %s %s image.srec\n", argv[0], argv[1]); return(-1); } return flashcmd_progsrec_gen(bank, argv[2], 0); } flashcmd_program_m0(argc, argv, bank) char **argv; { if (argc != 3) { fprintf(stderr, "usage: %s %s image.m0\n", argv[0], argv[1]); return(-1); } return flashcmd_progsrec_gen(bank, argv[2], 1); }