view loadtools/ltdump.c @ 923:10b4bed10192

gsm-fw/L1: fix for the DSP patch corruption bug The L1 code we got from the LoCosto fw contains a feature for DSP CPU load measurement. This feature is a LoCosto-ism, i.e., not applicable to earlier DBB chips (Calypso) with their respective earlier DSP ROMs. Most of the code dealing with that feature is conditionalized as #if (DSP >= 38), but one spot was missed, and the MCU code was writing into an API word dealing with this feature. In TCS211 this DSP API word happens to be used by the DSP code patch, hence that write was corrupting the patched DSP code.
author Mychaela Falconia <falcon@ivan.Harhan.ORG>
date Mon, 19 Oct 2015 17:13:56 +0000
parents b3ed63722eb5
children
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);
}