view loadtools/ltdump.c @ 640:5385aca4d813

fc-loadtool module refactoring: CRC-32 functions split out
author Mychaela Falconia <falcon@freecalypso.org>
date Sun, 01 Mar 2020 18:54:29 +0000
parents 98474043ecdd
children b4070292640a
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[];

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);
}