changeset 628:9c5b0629e346

fc-loadtool SREC programming revamp implemented, compiles
author Mychaela Falconia <falcon@freecalypso.org>
date Sat, 29 Feb 2020 02:14:30 +0000
parents d04502de49ed
children 0f70fe9395c4
files loadtools/flash.h loadtools/flprogsrec.c
diffstat 2 files changed, 236 insertions(+), 66 deletions(-) [+]
line wrap: on
line diff
--- a/loadtools/flash.h	Fri Feb 28 06:07:19 2020 +0000
+++ b/loadtools/flash.h	Sat Feb 29 02:14:30 2020 +0000
@@ -71,3 +71,11 @@
 	struct sector_info	*sectors;
 	int			detect_done;
 };
+
+/* support for flashing discontiguous S-record images */
+
+struct discontig_prog {
+	uint32_t	start;
+	uint32_t	end;
+	uint32_t	crc;
+};
--- a/loadtools/flprogsrec.c	Fri Feb 28 06:07:19 2020 +0000
+++ b/loadtools/flprogsrec.c	Sat Feb 29 02:14:30 2020 +0000
@@ -12,74 +12,79 @@
 #include "srecreader.h"
 
 extern struct flash_bank_info flash_bank_info[2];
+extern uint32_t crc32_table[];
 
-flashcmd_progsrec_gen(bank, imgfile, is_m0)
-	char *imgfile;
-{
-	struct flash_bank_info *bi;
-	struct srecreader srr;
-	char *targv[4], shortarg[10], longarg[513];
-	int resp;
-	unsigned long rec_count;
-	time_t start_time, finish_time;
-	unsigned duration, mm, ss;
+#define	MAX_SREC_REGIONS	256
 
-	if (flash_detect(bank, 0) < 0)
-		return(-1);
-	bi = flash_bank_info + bank;
+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;
-	resp = open_srec_file(&srr);
-	if (resp < 0)
-		return(resp);
-	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) {
+	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);
 	}
-	resp = tpinterf_pass_output(1);
-	if (resp) {
-		fclose(srr.openfile);
-		return(resp);
-	}
-	if (bi->ops->prep_for_program(bi) < 0) {
+	unlink(tmpfilename);
+	tmpfile = fdopen(tmpfd, "w+");
+	if (!tmpfile) {
+		perror("fdopen");
+		close(tmpfd);
 		fclose(srr.openfile);
 		return(-1);
 	}
-	targv[0] = bi->ops->loadagent_program_cmd;
-	targv[1] = shortarg;
-	targv[2] = longarg;
-	targv[3] = 0;
-	for (rec_count = 0; ; ) {
+	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,
-	"Warning: S0 record found in line %d of %s (expected in line 1 only)\n",
+	"error: S0 record found in line %d of %s (expected in line 1 only)\n",
 				srr.lineno, srr.filename);
-			continue;
-		} else if (srr.record_type == '7') {
-			time(&finish_time);
+			fclose(srr.openfile);
+			fclose(tmpfile);
+			return(-1);
+		} else if (srr.record_type == '7')
 			break;
-		} else if (srr.record_type != '3') {
+		else if (srr.record_type != '3') {
 			fprintf(stderr,
-		"Warning: unsupported S%c record type in line %d of %s\n",
+			"error: unsupported S%c record type in line %d of %s\n",
 				srr.record_type, srr.lineno, srr.filename);
-			continue;
+			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) {
@@ -93,51 +98,208 @@
 			"%s line %d: violates word alignment requirement\n",
 				srr.filename, srr.lineno);
 			fclose(srr.openfile);
+			fclose(tmpfile);
 			return(-1);
 		}
-		srr.addr &= bi->geom->total_size - 1;
-		if (srr.addr + srr.datalen > bi->geom->total_size) {
+		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 (!rec_count) {
-		    printf("Programming flash, each \'.\' is 100 S-records\n");
-			time(&start_time);
+		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;
 		}
-		sprintf(shortarg, "%lx", (u_long) srr.addr);
-		build_flashw_hex_string(srr.record + 5, longarg,
-					srr.datalen >> 1, is_m0);
-		tpinterf_make_cmd(targv);
-		if (tpinterf_send_cmd() < 0) {
-			fclose(srr.openfile);
-			return(-1);
+		/* 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);
+			}
 		}
-		resp = tpinterf_pass_output(8);	/* 8 s timeout */
-		if (resp) {
-			fclose(srr.openfile);
-			return(resp);
-		}
-		rec_count++;
-		if (rec_count % 100 == 0) {
-			putchar('.');
-			fflush(stdout);
-		}
+		regp->end += srr.datalen;
+		total_len += srr.datalen;
 	}
 	/* got S7 */
 	fclose(srr.openfile);
-	if (!rec_count) {
+	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);
 	}
-	duration = finish_time - start_time;
+	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("\nOperation completed in %um%us\n", mm, ss);
+	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) 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);
 }