diff loadtools/flprogbin.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 0dd2c87c1b63
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/loadtools/flprogbin.c	Sat Jun 11 00:13:35 2016 +0000
@@ -0,0 +1,200 @@
+/*
+ * This module implements the flash program-bin command:
+ * programming flash using a binary file as the data source.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <time.h>
+#include "flash.h"
+
+extern struct flash_bank_info flash_bank_info[2];
+extern uint32_t crc32_table[];
+
+flashcmd_progbin(argc, argv, bank)
+	char **argv;
+{
+	struct flash_bank_info *bi;
+	u_long flashoff, fileoff, len, origlen, bytesdone;
+	u_long crc_base_addr, crc_from_target;
+	uint32_t crcaccum;
+	char *strtoul_endp;
+	FILE *binf;
+	struct stat filestat;
+	char *targv[4], shortarg[10], longarg[513];
+	u_char databuf[256];
+	int reclen, cc, i;
+	time_t curtime, last_time;
+
+	if (argc < 4 || argc > 6) {
+inv:		fprintf(stderr,
+		"usage: %s %s flash-offset binfile [file-offset [length]]\n",
+			argv[0], argv[1]);
+		return(-1);
+	}
+	flashoff = strtoul(argv[2], &strtoul_endp, 16);
+	if (*strtoul_endp)
+		goto inv;
+	if (flash_get_cfi(bank) < 0)
+		return(-1);
+	bi = flash_bank_info + bank;
+	if (flashoff >= bi->geom->total_size) {
+		fprintf(stderr,
+		"error: specified flash offset exceeds bank size (0x%lx)\n",
+			(u_long) bi->geom->total_size);
+		return(-1);
+	}
+	if (flashoff & 1) {
+		fprintf(stderr, "error: flash offset must be even\n");
+		return(-1);
+	}
+	binf = fopen(argv[3], "r");
+	if (!binf) {
+		perror(argv[3]);
+		return(-1);
+	}
+	fstat(fileno(binf), &filestat);
+	if (!S_ISREG(filestat.st_mode)) {
+		fprintf(stderr, "%s is not a regular file\n", argv[3]);
+		fclose(binf);
+		return(-1);
+	}
+	if (argc > 4) {
+		fileoff = strtoul(argv[4], &strtoul_endp, 16);
+		if (*strtoul_endp) {
+			fclose(binf);
+			goto inv;
+		}
+		if (fileoff > filestat.st_size) {
+			fprintf(stderr,
+			"error: specified file offset exceeds file length\n");
+			fclose(binf);
+			return(-1);
+		}
+	} else
+		fileoff = 0;
+	if (argc > 5) {
+		len = strtoul(argv[5], &strtoul_endp, 16);
+		if (*strtoul_endp) {
+			fclose(binf);
+			goto inv;
+		}
+		if (len > filestat.st_size - fileoff) {
+			fprintf(stderr,
+		"error: specified file offset+length exceed file length\n");
+			fclose(binf);
+			return(-1);
+		}
+	} else
+		len = filestat.st_size - fileoff;
+	if (!len) {
+		printf("Length is zero - nothing to do!\n");
+		fclose(binf);
+		return(0);
+	}
+	if (len > bi->geom->total_size - flashoff) {
+		fprintf(stderr,
+	"error: specified flash offset+length exceed bank size (0x%lx)\n",
+			(u_long) bi->geom->total_size);
+		fclose(binf);
+		return(-1);
+	}
+	if (len & 1) {
+		fprintf(stderr, "error: program length must be even\n");
+		fclose(binf);
+		return(-1);
+	}
+
+	/* finally done with the arg parsing etc, can get to work now */
+	if (flash_id_check(bank, 0) < 0) {
+		fclose(binf);
+		return(-1);
+	}
+	crc_base_addr = bi->base_addr + flashoff;
+	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(binf);
+		return(-1);
+	}
+	cc = tpinterf_pass_output(1);
+	if (cc) {
+		fclose(binf);
+		return(cc);
+	}
+	if (bi->ops->prep_for_program(bi) < 0) {
+		fclose(binf);
+		return(-1);
+	}
+	fseek(binf, fileoff, SEEK_SET);
+	targv[0] = bi->ops->loadagent_program_cmd;
+	targv[1] = shortarg;
+	targv[2] = longarg;
+	targv[3] = 0;
+	printf("Programming flash: %lu (0x%lx) bytes\n", len, len);
+	origlen = len;
+	bytesdone = 0;
+	last_time = 0;
+	crcaccum = 0xFFFFFFFF;
+	while (len) {
+		if (len >= 256)
+			reclen = 256;
+		else
+			reclen = len;
+		cc = fread(databuf, 1, reclen, binf);
+		if (cc != reclen) {
+			fclose(binf);
+			fprintf(stderr, "error reading from %s\n", argv[3]);
+			return(-1);
+		}
+		for (i = 0; i < reclen; i++)	/* update running CRC */
+			crcaccum = crc32_table[crcaccum & 0xFF ^ databuf[i]]
+				^ (crcaccum >> 8);
+		sprintf(shortarg, "%lx", flashoff);
+		build_flashw_hex_string(databuf, longarg, reclen >> 1, 0);
+		tpinterf_make_cmd(targv);
+		if (tpinterf_send_cmd() < 0) {
+			fclose(binf);
+			return(-1);
+		}
+		i = tpinterf_pass_output(8);	/* 8 s timeout */
+		if (i) {
+			fclose(binf);
+			return(i);
+		}
+		flashoff += reclen;
+		len -= reclen;
+		bytesdone += reclen;
+		cc = bytesdone * 100 / origlen;
+		time(&curtime);
+		if (curtime != last_time || cc == 100) {
+			printf("\r0x%lx bytes programmed (%i%%)",
+				bytesdone, cc);
+			fflush(stdout);
+		}
+		last_time = curtime;
+	}
+	putchar('\n');
+	fclose(binf);
+
+	/* reset flash to read mode */
+	if (bi->ops->reset_cmd(bi) < 0)
+		return(-1);
+	printf("Verifying CRC-32 of programmed flash area\n");
+	if (crc32_on_target(crc_base_addr, origlen, &crc_from_target) < 0)
+		return(-1);
+	if (crc_from_target == crcaccum) {
+		printf("match (%08lX)\n", crc_from_target);
+		return(0);
+	} else {
+		fprintf(stderr, "error: CRC mismatch!\n");
+		return(-1);
+	}
+}