diff loadtools/flcmplboot.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 2cd705c8116e
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/loadtools/flcmplboot.c	Sat Jun 11 00:13:35 2016 +0000
@@ -0,0 +1,256 @@
+/*
+ * This module contains the implementation of the flash erase-program-boot
+ * hack for brickable Compal phones.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include "flash.h"
+
+extern struct flash_bank_info flash_bank_info[2];
+extern struct flash_cmdset flash_cmdset_intel;
+
+extern uint32_t crc32_table[];
+
+static int hack_enabled;
+static uint32_t boot_sector_size;
+static uint32_t ram_buffer_addr;
+
+/* called from hwparam.c config file parser */
+void
+set_boot_reflash_hack(arg, filename_for_errs, lineno_for_errs)
+	char *arg;
+	char *filename_for_errs;
+	int lineno_for_errs;
+{
+	char *cp, *np, *ep;
+
+	if (hack_enabled) {
+		fprintf(stderr,
+			"%s line %d: duplicate boot-reflash-hack setting\n",
+			filename_for_errs, lineno_for_errs);
+		exit(1);
+	}
+	for (cp = arg; isspace(*cp); cp++)
+		;
+	if (!*cp || *cp == '#') {
+too_few_arg:	fprintf(stderr,
+		"%s line %d: boot-reflash-hack setting: too few arguments\n",
+			filename_for_errs, lineno_for_errs);
+		exit(1);
+	}
+	for (np = cp; *cp && !isspace(*cp); cp++)
+		;
+	if (!*cp)
+		goto too_few_arg;
+	*cp++ = '\0';
+	ram_buffer_addr = strtoul(np, &ep, 16);
+	if (*ep) {
+invhex:		fprintf(stderr,
+			"%s line %d: syntax error (hex arguments expected)\n",
+			filename_for_errs, lineno_for_errs);
+		exit(1);
+	}
+	while (isspace(*cp))
+		cp++;
+	if (!*cp || *cp == '#')
+		goto too_few_arg;
+	for (np = cp; *cp && !isspace(*cp); cp++)
+		;
+	if (*cp)
+		*cp++ = '\0';
+	boot_sector_size = strtoul(np, &ep, 16);
+	if (*ep)
+		goto invhex;
+	while (isspace(*cp))
+		cp++;
+	if (*cp && *cp != '#') {
+		fprintf(stderr,
+		"%s line %d: boot-reflash-hack setting: too many arguments\n",
+			filename_for_errs, lineno_for_errs);
+		exit(1);
+	}
+	hack_enabled = 1;
+}
+
+static void
+make_s3_record(buf, dest_addr, datalen)
+	u_char *buf;
+	uint32_t dest_addr;
+{
+	int totlen, i;
+	u_char accum;
+
+	buf[0] = totlen = datalen + 5;
+	buf[1] = dest_addr >> 24;
+	buf[2] = dest_addr >> 16;
+	buf[3] = dest_addr >> 8;
+	buf[4] = dest_addr;
+	accum = 0;
+	for (i = 0; i < totlen; i++)
+		accum += buf[i];
+	buf[i] = ~accum;
+}
+
+static void
+make_ml_arg(rec, buf)
+	u_char *rec;
+	char *buf;
+{
+	register int i, len;
+	register char *s;
+
+	len = rec[0] + 1;
+	s = buf;
+	for (i = 0; i < len; i++) {
+		sprintf(s, "%02X", rec[i]);
+		s += 2;
+	}
+	*s = '\0';
+}
+
+flashcmd_erase_program_boot(argc, argv)
+	char **argv;
+{
+	FILE *binf;
+	struct stat filestat;
+	size_t len;
+	char *strtoul_endp;
+	char *targv[5], longarg[513];
+	char shortarg1[9], shortarg2[9], shortarg3[9];
+	u_char databuf[256];
+	int reclen, cc, i;
+	uint32_t ramaddr, remlen, crcaccum;
+	u_long crc_from_target;
+
+	if (!hack_enabled) {
+		fprintf(stderr,
+			"Operation not applicable to this target device\n");
+		return(-1);
+	}
+	if (argc < 3 || argc > 4) {
+inv:		fprintf(stderr, "usage: %s %s binfile [length]\n",
+			argv[0], argv[1]);
+		return(-1);
+	}
+	if (flash_get_cfi(0) < 0)
+		return(-1);
+	if (flash_bank_info[0].geom->regions[0].sector_size
+			!= boot_sector_size) {
+		fprintf(stderr,
+		"error: detected flash boot sector size differs from config\n");
+		return(-1);
+	}
+	if (flash_bank_info[0].ops != &flash_cmdset_intel) {
+		fprintf(stderr,
+			"error: operation implemented for Intel flash only\n");
+		return(-1);
+	}
+
+	binf = fopen(argv[2], "r");
+	if (!binf) {
+		perror(argv[2]);
+		return(-1);
+	}
+	fstat(fileno(binf), &filestat);
+	if (!S_ISREG(filestat.st_mode)) {
+		fprintf(stderr, "%s is not a regular file\n", argv[2]);
+		fclose(binf);
+		return(-1);
+	}
+	if (argc > 3) {
+		len = strtoul(argv[3], &strtoul_endp, 16);
+		if (*strtoul_endp) {
+			fclose(binf);
+			goto inv;
+		}
+		if (len > filestat.st_size) {
+			fprintf(stderr,
+			    "error: specified length exceeds file length\n");
+			fclose(binf);
+			return(-1);
+		}
+	} else
+		len = filestat.st_size;
+	if (len > boot_sector_size) {
+		fprintf(stderr, "error: length exceeds boot sector size\n");
+		fclose(binf);
+		return(-1);
+	}
+	if (len & 1) {
+		fprintf(stderr, "error: length must be even\n");
+		fclose(binf);
+		return(-1);
+	}
+
+	printf("Loading new boot code into target RAM at %lx\n",
+		(u_long) ram_buffer_addr);
+	targv[0] = "ML";
+	targv[1] = longarg;
+	targv[2] = 0;
+	ramaddr = ram_buffer_addr;
+	crcaccum = 0xFFFFFFFF;
+	for (remlen = len; remlen; remlen -= reclen) {
+		if (remlen >= 250)
+			reclen = 250;
+		else
+			reclen = remlen;
+		cc = fread(databuf + 5, 1, reclen, binf);
+		if (cc != reclen) {
+			fclose(binf);
+			fprintf(stderr, "error reading from %s\n", argv[2]);
+			return(-1);
+		}
+		for (i = 0; i < reclen; i++)	/* update running CRC */
+			crcaccum = crc32_table[crcaccum & 0xFF ^ databuf[i+5]]
+				^ (crcaccum >> 8);
+		make_s3_record(databuf, ramaddr, reclen);
+		make_ml_arg(databuf, longarg);
+		tpinterf_make_cmd(targv);
+		if (tpinterf_send_cmd() < 0) {
+			fclose(binf);
+			return(-1);
+		}
+		cc = tpinterf_pass_output(1);
+		if (cc) {
+			fclose(binf);
+			return(cc);
+		}
+		ramaddr += reclen;
+		putchar('.');
+		fflush(stdout);
+	}
+	putchar('\n');
+	fclose(binf);
+
+	printf("Verifying CRC-32 in target RAM\n");
+	if (crc32_on_target((u_long) ram_buffer_addr, (u_long) len,
+				&crc_from_target) < 0)
+		return(-1);
+	if (crc_from_target == crcaccum)
+		printf("match (%08lX)\n", crc_from_target);
+	else {
+		fprintf(stderr, "error: CRC mismatch!\n");
+		return(-1);
+	}
+
+	printf("Commanding flash erase+program operation on the target\n");
+	sprintf(shortarg1, "%lx", (u_long) ram_buffer_addr);
+	sprintf(shortarg2, "%lx", (u_long) flash_bank_info[0].base_addr);
+	sprintf(shortarg3, "%lx", (u_long) len);
+	targv[0] = "intel-rewrite-sector";
+	targv[1] = shortarg1;
+	targv[2] = shortarg2;
+	targv[3] = shortarg3;
+	targv[4] = 0;
+	tpinterf_make_cmd(targv);
+	if (tpinterf_send_cmd() < 0)
+		return(-1);
+	return tpinterf_pass_output(20);	/* 20 s timeout */
+}