changeset 92:915a6fa7723e

cp2102-patch-ee-image program written, compiles
author Mychaela Falconia <falcon@freecalypso.org>
date Thu, 28 Sep 2023 01:37:43 +0000
parents f4a7ac90cf39
children a1df83d04cc9
files .hgignore cp2102/Makefile cp2102/apply_eeprom_patch.c cp2102/patch_ee_file.c
diffstat 4 files changed, 446 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Wed Sep 27 20:46:30 2023 +0000
+++ b/.hgignore	Thu Sep 28 01:37:43 2023 +0000
@@ -4,6 +4,7 @@
 
 ^cp2102/cp2102-decode-baudtab$
 ^cp2102/cp2102-decode-ee-desc$
+^cp2102/cp2102-patch-ee-image$
 ^cp2102/cp2102-read-baudtab$
 ^cp2102/cp2102-read-eeprom$
 ^cp2102/cp2102-read-partno$
--- a/cp2102/Makefile	Wed Sep 27 20:46:30 2023 +0000
+++ b/cp2102/Makefile	Thu Sep 28 01:37:43 2023 +0000
@@ -1,7 +1,7 @@
 CC=	gcc
 CFLAGS=	-O2
-PROGS=	cp2102-decode-baudtab cp2102-decode-ee-desc cp2102-read-baudtab \
-	cp2102-read-eeprom cp2102-read-partno
+PROGS=	cp2102-decode-baudtab cp2102-decode-ee-desc cp2102-patch-ee-image \
+	cp2102-read-baudtab cp2102-read-eeprom cp2102-read-partno
 NOINST=	file_rw_test
 LIBS=	../libuwrap/libuwrap.a
 
@@ -14,6 +14,8 @@
 
 DECODE_BAUDTAB_OBJS=	decode_baudtab.o decode_baudtab_main.o intel_hex_in.o
 DECODE_EEDESC_OBJS=	decode_usb_desc.o intel_hex_in.o
+PATCH_FILE_OBJS=	apply_eeprom_patch.o intel_hex_in.o intel_hex_out.o \
+			patch_ee_file.o
 READ_BAUDTAB_OBJS=	decode_baudtab.o read_baudtab.o read_eeprom.o
 READ_EEPROM_OBJS=	intel_hex_out.o read_eeprom.o read_eeprom_main.o
 RW_TEST_OBJS=		intel_hex_in.o intel_hex_out.o file_rw_test.o
@@ -26,6 +28,9 @@
 cp2102-decode-ee-desc:	${DECODE_EEDESC_OBJS}
 	${CC} ${CFLAGS} -o $@ ${DECODE_EEDESC_OBJS}
 
+cp2102-patch-ee-image:	${PATCH_FILE_OBJS}
+	${CC} ${CFLAGS} -o $@ ${PATCH_FILE_OBJS}
+
 cp2102-read-baudtab:	${READ_BAUDTAB_OBJS} ${LIBS}
 	${CC} ${CFLAGS} -o $@ ${READ_BAUDTAB_OBJS} ${LIBS} -lusb
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cp2102/apply_eeprom_patch.c	Thu Sep 28 01:37:43 2023 +0000
@@ -0,0 +1,403 @@
+/*
+ * This function implemented in this module reads a CP2102 EEPROM patch
+ * specification file (which can also be a baud rate table file) and applies
+ * patches to the EEPROM image in RAM.
+ */
+
+#include <sys/types.h>
+#include <ctype.h>
+#include <string.h>
+#include <strings.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "cp210x_defs.h"
+
+extern u_char eeprom[SIZE_EEPROM];
+
+static char cp2102_install_dir[] = "/opt/freecalypso/cp2102";
+
+static void
+apply_baud_entry(filename, lineno, args)
+	char *filename, *args;
+{
+	unsigned entry_idx, intend_baud, baudgen_val, timeout_val;
+	unsigned prescaler, extra_byte;
+	char *cp = args;
+	u_char *eerec;
+
+	if (!isdigit(*cp)) {
+inv:		fprintf(stderr, "%s line %d: invalid syntax for baud-entry\n",
+			filename, lineno);
+		exit(1);
+	}
+	entry_idx = strtoul(cp, &cp, 10);
+	while (isspace(*cp))
+		cp++;
+	if (*cp++ != ':')
+		goto inv;
+	while (isspace(*cp))
+		cp++;
+	if (!isdigit(*cp))
+		goto inv;
+	intend_baud = strtoul(cp, &cp, 10);
+	while (isspace(*cp))
+		cp++;
+	if (*cp++ != '=')
+		goto inv;
+	while (isspace(*cp))
+		cp++;
+	if (!isxdigit(*cp))
+		goto inv;
+	baudgen_val = strtoul(cp, &cp, 16);
+	while (isspace(*cp))
+		cp++;
+	if (*cp++ != ',')
+		goto inv;
+	while (isspace(*cp))
+		cp++;
+	if (!isxdigit(*cp))
+		goto inv;
+	timeout_val = strtoul(cp, &cp, 16);
+	while (isspace(*cp))
+		cp++;
+	if (*cp++ != ',')
+		goto inv;
+	while (isspace(*cp))
+		cp++;
+	if (!isdigit(*cp))
+		goto inv;
+	prescaler = strtoul(cp, &cp, 10);
+	while (isspace(*cp))
+		cp++;
+	if (*cp++ != ',')
+		goto inv;
+	while (isspace(*cp))
+		cp++;
+	if (!isdigit(*cp))
+		goto inv;
+	extra_byte = strtoul(cp, &cp, 10);
+	while (isspace(*cp))
+		cp++;
+	if (*cp && *cp != '#')
+		goto inv;
+	/* done with parsing, get to EEPROM */
+	if (entry_idx > 31) {
+		fprintf(stderr, "%s line %d: invalid baud-entry index\n",
+			filename, lineno);
+		exit(1);
+	}
+	eerec = eeprom + entry_idx * SIZE_BAUDRATE_CFG;
+	eerec[0] = baudgen_val >> 8;
+	eerec[1] = baudgen_val;
+	eerec[2] = timeout_val >> 8;
+	eerec[3] = timeout_val;
+	eerec[4] = prescaler;
+	eerec[5] = extra_byte;
+	eerec[6] = intend_baud;
+	eerec[7] = intend_baud >> 8;
+	eerec[8] = intend_baud >> 16;
+	eerec[9] = intend_baud >> 24;
+}
+
+static void
+apply_patch_8bit(filename, lineno, args)
+	char *filename, *args;
+{
+	unsigned patch_loc, patch_val;
+	char *cp = args;
+
+	if (!isxdigit(*cp)) {
+inv:		fprintf(stderr, "%s line %d: invalid syntax for patch8\n",
+			filename, lineno);
+		exit(1);
+	}
+	patch_loc = strtoul(cp, &cp, 16);
+	while (isspace(*cp))
+		cp++;
+	if (!isxdigit(*cp))
+		goto inv;
+	patch_val = strtoul(cp, &cp, 16);
+	while (isspace(*cp))
+		cp++;
+	if (*cp && *cp != '#')
+		goto inv;
+	/* validate range */
+	if (patch_loc >= EEPROM_START_ADDR &&
+	    patch_loc <= EEPROM_START_ADDR + SIZE_EEPROM - 1)
+		patch_loc -= EEPROM_START_ADDR;
+	else if (patch_loc > SIZE_EEPROM - 1) {
+		fprintf(stderr, "%s line %d: invalid patch address\n",
+			filename, lineno);
+		exit(1);
+	}
+	if (patch_val > 0xFF) {
+		fprintf(stderr,
+			"%s line %d: patch value does not fit into 8 bits\n",
+			filename, lineno);
+		exit(1);
+	}
+	/* checks done, proceed */
+	eeprom[patch_loc] = patch_val;
+}
+
+static void
+apply_patch_16bit(filename, lineno, args)
+	char *filename, *args;
+{
+	unsigned patch_loc, patch_val;
+	char *cp = args;
+
+	if (!isxdigit(*cp)) {
+inv:		fprintf(stderr, "%s line %d: invalid syntax for patch16\n",
+			filename, lineno);
+		exit(1);
+	}
+	patch_loc = strtoul(cp, &cp, 16);
+	while (isspace(*cp))
+		cp++;
+	if (!isxdigit(*cp))
+		goto inv;
+	patch_val = strtoul(cp, &cp, 16);
+	while (isspace(*cp))
+		cp++;
+	if (*cp && *cp != '#')
+		goto inv;
+	/* validate range */
+	if (patch_loc >= EEPROM_START_ADDR &&
+	    patch_loc <= EEPROM_START_ADDR + SIZE_EEPROM - 2)
+		patch_loc -= EEPROM_START_ADDR;
+	else if (patch_loc > SIZE_EEPROM - 2) {
+		fprintf(stderr, "%s line %d: invalid patch address\n",
+			filename, lineno);
+		exit(1);
+	}
+	if (patch_val > 0xFFFF) {
+		fprintf(stderr,
+			"%s line %d: patch value does not fit into 16 bits\n",
+			filename, lineno);
+		exit(1);
+	}
+	/* checks done, proceed */
+	eeprom[patch_loc] = patch_val;
+	eeprom[patch_loc+1] = patch_val >> 8;
+}
+
+static void
+apply_patch_vid(filename, lineno, args)
+	char *filename, *args;
+{
+	unsigned patch_val;
+	char *cp = args;
+
+	if (!isxdigit(*cp)) {
+inv:		fprintf(stderr, "%s line %d: invalid syntax for vid\n",
+			filename, lineno);
+		exit(1);
+	}
+	patch_val = strtoul(cp, &cp, 16);
+	while (isspace(*cp))
+		cp++;
+	if (*cp && *cp != '#')
+		goto inv;
+	/* validate range */
+	if (patch_val > 0xFFFF) {
+		fprintf(stderr, "%s line %d: VID does not fit into 16 bits\n",
+			filename, lineno);
+		exit(1);
+	}
+	/* checks done, proceed */
+	eeprom[0x390] = patch_val;
+	eeprom[0x391] = patch_val >> 8;
+}
+
+static void
+apply_patch_pid(filename, lineno, args)
+	char *filename, *args;
+{
+	unsigned patch_val;
+	char *cp = args;
+
+	if (!isxdigit(*cp)) {
+inv:		fprintf(stderr, "%s line %d: invalid syntax for pid\n",
+			filename, lineno);
+		exit(1);
+	}
+	patch_val = strtoul(cp, &cp, 16);
+	while (isspace(*cp))
+		cp++;
+	if (*cp && *cp != '#')
+		goto inv;
+	/* validate range */
+	if (patch_val > 0xFFFF) {
+		fprintf(stderr, "%s line %d: PID does not fit into 16 bits\n",
+			filename, lineno);
+		exit(1);
+	}
+	/* checks done, proceed */
+	eeprom[0x392] = patch_val;
+	eeprom[0x393] = patch_val >> 8;
+}
+
+static void
+set_string_desc(start_offset, str)
+	unsigned start_offset;
+	char *str;
+{
+	char *cp;
+	u_char *dp;
+
+	dp = eeprom + start_offset;
+	*dp++ = strlen(str) * 2 + 2;
+	*dp++ = 0x03;
+	for (cp = str; *cp; ) {
+		*dp++ = *cp++;
+		*dp++ = 0;
+	}
+}
+
+static void
+set_manuf_string(filename, lineno, arg)
+	char *filename, *arg;
+{
+	if (strlen(arg) > 29) {
+		fprintf(stderr, "%s line %d: manuf string is too long\n",
+			filename, lineno);
+		exit(1);
+	}
+	set_string_desc(0x3C3, arg);
+}
+
+static void
+set_product_string(filename, lineno, arg)
+	char *filename, *arg;
+{
+	if (strlen(arg) > 126) {
+		fprintf(stderr, "%s line %d: product string is too long\n",
+			filename, lineno);
+		exit(1);
+	}
+	set_string_desc(0x208, arg);
+}
+
+static void
+set_serial_string(filename, lineno, arg)
+	char *filename, *arg;
+{
+	if (strlen(arg) > 63) {
+		fprintf(stderr, "%s line %d: serial string is too long\n",
+			filename, lineno);
+		exit(1);
+	}
+	set_string_desc(0x307, arg);
+}
+
+static void
+apply_eeprom_patch_int(filename, inf)
+	char *filename;
+	FILE *inf;
+{
+	char linebuf[1024];
+	int lineno;
+	char *cp, *np;
+
+	for (lineno = 1; fgets(linebuf, sizeof linebuf, inf); lineno++) {
+		cp = index(linebuf, '\n');
+		if (!cp) {
+			fprintf(stderr,
+				"%s line %d: too long or unterminated\n",
+				filename, lineno);
+			exit(1);
+		}
+		*cp = '\0';
+		for (cp = linebuf; isspace(*cp); cp++)
+			;
+		if (*cp == '\0' || *cp == '#')
+			continue;
+		for (np = cp; *cp && !isspace(*cp); cp++)
+			;
+		if (*cp)
+			*cp++ = '\0';
+		while (isspace(*cp))
+			cp++;
+		if (*cp == '\0' || *cp == '#') {
+			fprintf(stderr,
+				"%s line %d: \"%s\" setting without argument\n",
+				filename, lineno, np);
+			exit(1);
+		}
+		if (!strcmp(np, "baud-entry"))
+			apply_baud_entry(filename, lineno, cp);
+		else if (!strcmp(np, "patch8"))
+			apply_patch_8bit(filename, lineno, cp);
+		else if (!strcmp(np, "patch16"))
+			apply_patch_16bit(filename, lineno, cp);
+		else if (!strcmp(np, "vid"))
+			apply_patch_vid(filename, lineno, cp);
+		else if (!strcmp(np, "pid"))
+			apply_patch_pid(filename, lineno, cp);
+		else if (!strcmp(np, "manuf"))
+			set_manuf_string(filename, lineno, cp);
+		else if (!strcmp(np, "product"))
+			set_product_string(filename, lineno, cp);
+		else if (!strcmp(np, "serial"))
+			set_serial_string(filename, lineno, cp);
+		else {
+			fprintf(stderr, "%s line %d: unknown \"%s\" setting\n",
+				filename, lineno, np);
+			exit(1);
+		}
+	}
+}
+
+static FILE *
+open_with_search(req_filename)
+	char *req_filename;
+{
+	char pathbuf[256];
+	FILE *f;
+
+	if (!index(req_filename, '/') && strlen(req_filename) < 128) {
+		sprintf(pathbuf, "%s/%s", cp2102_install_dir, req_filename);
+		f = fopen(pathbuf, "r");
+		if (f)
+			return f;
+	}
+	f = fopen(req_filename, "r");
+	return f;
+}
+
+void
+apply_eeprom_patch_file(filename)
+	char *filename;
+{
+	FILE *inf;
+
+	inf = open_with_search(filename);
+	if (!inf) {
+		perror(filename);
+		exit(1);
+	}
+	apply_eeprom_patch_int(filename, inf);
+	fclose(inf);
+}
+
+void
+apply_eeprom_patch_baud(baud_spec_name)
+	char *baud_spec_name;
+{
+	char pathbuf[256];
+	FILE *inf;
+
+	if (strlen(baud_spec_name) > 63) {
+		fprintf(stderr, "error: no buffer overflow attacks, please\n");
+		exit(1);
+	}
+	sprintf(pathbuf, "%s/baudtab-%s", cp2102_install_dir, baud_spec_name);
+	inf = fopen(pathbuf, "r");
+	if (!inf) {
+		perror(pathbuf);
+		exit(1);
+	}
+	apply_eeprom_patch_int(pathbuf, inf);
+	fclose(inf);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cp2102/patch_ee_file.c	Thu Sep 28 01:37:43 2023 +0000
@@ -0,0 +1,35 @@
+/*
+ * This program reads a CP2102 EEPROM image from an Intel HEX file,
+ * applies patches to it from a patch specification file, and writes out
+ * a new Intel HEX image.
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "cp210x_defs.h"
+
+u_char eeprom[SIZE_EEPROM];
+
+main(argc, argv)
+	char **argv;
+{
+	FILE *outf;
+
+	if (argc != 4) {
+		fprintf(stderr,
+			"usage: %s input-hex-file patch-spec output-hex-file\n",
+			argv[0]);
+		exit(1);
+	}
+	read_intel_hex(argv[1]);
+	apply_eeprom_patch_file(argv[2]);
+	outf = fopen(argv[3], "w");
+	if (!outf) {
+		perror(argv[3]);
+		exit(1);
+	}
+	intel_hex_out(eeprom, outf);
+	fclose(outf);
+	exit(0);
+}