view loadtools/ltdump.c @ 416:30f6d1c32c6f

doc/Flash-boot-defect article removed (no longer relevant) This article is no longer relevant because the issue in question only affected one (1) defective FCDEV3B board which was not and never will be sold.
author Mychaela Falconia <falcon@freecalypso.org>
date Fri, 26 Oct 2018 07:11:08 +0000
parents e7502631a0f9
children 98474043ecdd
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_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];
	int stat;

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