view loadtools/ltdump.c @ 610:98474043ecdd

fc-loadtool dump2file operations: added Rx time reporting
author Mychaela Falconia <falcon@freecalypso.org>
date Mon, 24 Feb 2020 19:32:43 +0000
parents e7502631a0f9
children 5385aca4d813
line wrap: on
line source

/*
 * This module implements the dump2bin and dump2srec functionality
 * of fc-loadtool.
 */

#include <sys/types.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include <time.h>

extern uint32_t crc32_table[];
extern char target_response_line[];

crc32_on_target(area_base, area_len, retptr)
	u_long area_base, area_len, *retptr;
{
	char arg1[10], arg2[10], *argv[4];
	int stat;
	char *strtoul_endp;

	sprintf(arg1, "%lx", area_base);
	sprintf(arg2, "%lx", area_len);
	argv[0] = "crc32";
	argv[1] = arg1;
	argv[2] = arg2;
	argv[3] = 0;
	tpinterf_make_cmd(argv);
	if (tpinterf_send_cmd() < 0)
		return(-1);
	stat = tpinterf_capture_output_oneline(10);	/* 10 s timeout */
	if (stat != 1) {
errout:		fprintf(stderr, "error: malformed response to crc32 command\n");
		return(-1);
	}
	if (strlen(target_response_line) != 8)
		goto errout;
	*retptr = strtoul(target_response_line, &strtoul_endp, 16);
	if (strtoul_endp != target_response_line + 8)
		goto errout;
	return(0);
}

cmd_crc32(argc, argv)
	char **argv;
{
	u_long area_base, area_len;
	char *strtoul_endp;
	u_long crc_result;
	int stat;

	area_base = strtoul(argv[1], &strtoul_endp, 16);
	if (*strtoul_endp) {
inv:		fprintf(stderr, "usage: crc32 hex-start hex-len\n");
		return(-1);
	}
	area_len = strtoul(argv[2], &strtoul_endp, 16);
	if (*strtoul_endp)
		goto inv;
	stat = crc32_on_target(area_base, area_len, &crc_result);
	if (stat == 0)
		printf("%08lX\n", crc_result);
	return(stat);
}

/* the actual dump facility */

static FILE *dump_outfile;
static int dump_save_srec;
static uint32_t dump_nextaddr, dump_crcaccum;
static uint32_t dump_total_len, dump_progress_len;
static u_char dump_binrec[0x86];
static time_t dump_initial_time, dump_last_time;

static char dumpsrec_s0_line[] = "S007000044554D50C2\n";
static char dumpsrec_s7_line[] = "S70500000000FA\n";

static
dump_receiver(line)
	char *line;
{
	int i, b;
	u_char sr_cksum;
	uint32_t addr_from_srec;
	time_t curtime;

	if (strncmp(line, "S385", 4)) {
		fprintf(stderr,
			"error: target response is not the expected S385...\n");
		return(-1);
	}
	for (i = 0; i < 0x86; i++) {
		b = decode_hex_byte(line + i*2 + 2);
		if (b < 0) {
			fprintf(stderr,
			"data from target: S-record hex decode error\n");
			return(-1);
		}
		dump_binrec[i] = b;
	}
	sr_cksum = 0;
	for (i = 0; i < 0x86; i++)
		sr_cksum += dump_binrec[i];
	if (sr_cksum != 0xFF) {
		fprintf(stderr, "data from target: bad S-record checksum\n");
		return(-1);
	}
	/* basic S-record format OK; now verify the address */
	addr_from_srec = ((uint32_t) dump_binrec[1] << 24) |
			 ((uint32_t) dump_binrec[2] << 16) |
			 ((uint32_t) dump_binrec[3] << 8) |
			  (uint32_t) dump_binrec[4];
	if (addr_from_srec != dump_nextaddr) {
		fprintf(stderr,
			"error: S3 record from target has the wrong address\n");
		return(-1);
	}
	/* all checks passed - save it */
	if (dump_save_srec) {
		if (!dump_progress_len)
			fputs(dumpsrec_s0_line, dump_outfile);
		fprintf(dump_outfile, "%s\n", line);
	} else
		fwrite(dump_binrec + 5, 1, 0x80, dump_outfile);
	/* update running CRC */
	for (i = 0; i < 0x80; i++)
		dump_crcaccum = crc32_table[dump_crcaccum & 0xFF ^
						dump_binrec[i+5]] ^
				(dump_crcaccum >> 8);
	/* progress indication */
	dump_progress_len += 0x80;
	i = dump_progress_len * 100 / dump_total_len;
	time(&curtime);
	if (curtime != dump_last_time || i == 100) {
		printf("\rRx %lu out of %lu bytes (%i%%)",
			(u_long) dump_progress_len, (u_long) dump_total_len, i);
		fflush(stdout);
	}
	dump_nextaddr += 0x80;
	dump_last_time = curtime;
	return(1);
}

loadtool_memdump(start_addr, area_len, filename, fmt_srec)
	u_long start_addr, area_len;
	char *filename;
{
	u_long target_crc_init, target_crc_fin;
	char *target_argv[4], target_arg1[10], target_arg2[10];
	unsigned duration, mm, ss;
	int stat;

	if (!area_len) {
		fprintf(stderr,
			"error: dump of zero length is not supported\n");
		return(-1);
	}
	if (start_addr & 0x7F || area_len & 0x7F) {
		fprintf(stderr,
		"error: implementation limit: 128-byte alignment required\n");
		return(-1);
	}
	printf("Requesting initial CRC-32 of the area from target...\n");
	stat = crc32_on_target(start_addr, area_len, &target_crc_init);
	if (stat)
		return(stat);
	printf("got %08lX\n", target_crc_init);
	dump_outfile = fopen(filename, "w");
	if (!dump_outfile) {
		perror(filename);
		return(-1);
	}
	dump_save_srec = fmt_srec;
	dump_nextaddr = start_addr;
	dump_crcaccum = 0xFFFFFFFF;
	dump_total_len = area_len;
	dump_progress_len = 0;

	printf("Requesting memory dump...\n");
	time(&dump_initial_time);
	sprintf(target_arg1, "%lx", start_addr);
	sprintf(target_arg2, "%lx", area_len);
	target_argv[0] = "DUMP";
	target_argv[1] = target_arg1;
	target_argv[2] = target_arg2;
	target_argv[3] = 0;
	tpinterf_make_cmd(target_argv);
	stat = tpinterf_send_cmd();
	if (stat < 0) {
		fclose(dump_outfile);
		return(stat);
	}
	stat = tpinterf_capture_output(2, dump_receiver);
	if (stat < 0) {
		fclose(dump_outfile);
		return(stat);
	}
	putchar('\n');	/* after last progress line */

	/* sanity checks */
	if (dump_nextaddr != start_addr + area_len) {
		fclose(dump_outfile);
		fprintf(stderr,
		"error: received dump length does not match expected\n");
		return(-1);
	}
	if (dump_crcaccum != (uint32_t) target_crc_init) {
		fclose(dump_outfile);
		fprintf(stderr, "error: CRC mismatch (computed %lX)\n",
			(u_long) dump_crcaccum);
		return(-1);
	}
	if (fmt_srec)
		fputs(dumpsrec_s7_line, dump_outfile);
	fclose(dump_outfile);
	duration = dump_last_time - dump_initial_time;
	mm = duration / 60;
	ss = duration - mm * 60;
	printf("Dump stream received in %um%us\n", mm, ss);

	printf("Requesting another CRC-32 of the area from target...\n");
	stat = crc32_on_target(start_addr, area_len, &target_crc_fin);
	if (stat)
		return(stat);
	if (target_crc_fin == target_crc_init) {
		printf("match, dump successful\n");
		return(0);
	} else {
		fprintf(stderr, "mismatch: got %lX this time\n",
			target_crc_fin);
		return(-1);
	}
}

cmd_dump2bin(argc, argv)
	char **argv;
{
	u_long area_base, area_len;
	char *strtoul_endp;

	area_base = strtoul(argv[1], &strtoul_endp, 16);
	if (*strtoul_endp) {
inv:		fprintf(stderr, "usage: dump2bin hex-start hex-len outfile\n");
		return(-1);
	}
	area_len = strtoul(argv[2], &strtoul_endp, 16);
	if (*strtoul_endp)
		goto inv;
	return loadtool_memdump(area_base, area_len, argv[3], 0);
}

cmd_dump2srec(argc, argv)
	char **argv;
{
	u_long area_base, area_len;
	char *strtoul_endp;

	area_base = strtoul(argv[1], &strtoul_endp, 16);
	if (*strtoul_endp) {
inv:		fprintf(stderr, "usage: dump2srec hex-start hex-len outfile\n");
		return(-1);
	}
	area_len = strtoul(argv[2], &strtoul_endp, 16);
	if (*strtoul_endp)
		goto inv;
	return loadtool_memdump(area_base, area_len, argv[3], 1);
}