diff loadtools/compalload.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 b77005f6d315
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/loadtools/compalload.c	Sat Jun 11 00:13:35 2016 +0000
@@ -0,0 +1,222 @@
+/*
+ * This module implements Compal's serial code loading protocol to load
+ * what we call compalstage, a piece of code that re-enables the Calypso
+ * boot ROM and allows us to use the same loadagent which we use on
+ * freedom-enabled target devices.
+ */
+
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <termios.h>
+#include <unistd.h>
+
+extern char default_helpers_dir[];
+extern char *target_ttydev;
+extern int target_fd;
+extern struct termios target_termios;
+
+static char compalstage_pathname[MAXPATHLEN];
+static u_char *compalstage_imgbuf;
+static size_t compalstage_len, compalstage_totlen;
+static int rx_state;
+static u_char rx_msg[3];
+
+void
+set_compalstage_short(arg)
+	char *arg;
+{
+	if (strcmp(arg, "none"))
+		sprintf(compalstage_pathname, "%s/compalstage-%s.bin",
+			default_helpers_dir, arg);
+	else
+		compalstage_pathname[0] = 0;
+}
+
+void
+set_compalstage_fullpath(arg)
+	char *arg;
+{
+	strcpy(compalstage_pathname, arg);
+}
+
+static void
+compute_checksum()
+{
+	size_t i, l;
+	u_char ck;
+
+	ck = 0x02;
+	l = compalstage_len + 3;
+	for (i = 1; i < l; i++)
+		ck ^= compalstage_imgbuf[i];
+	compalstage_imgbuf[l] = ck;
+}
+
+static
+handle_rx_msg()
+{
+	static u_char download_cmd[7] = {0x1B, 0xF6, 0x02, 0x00,
+					 0x52, 0x01, 0x53};
+
+	if (rx_msg[0] == 0x41 && rx_msg[1] == 0x01 && rx_msg[2] == 0x40) {
+		printf("Received PROMPT1, sending download command\n");
+		write(target_fd, download_cmd, 7);
+		return(0);
+	} else if (rx_msg[0] == 0x41 && rx_msg[1] == 0x02 && rx_msg[2] == 0x43){
+		printf("Received PROMPT2, sending download image\n");
+		write(target_fd, compalstage_imgbuf, compalstage_totlen);
+		return(0);
+	} else if (rx_msg[0] == 0x41 && rx_msg[1] == 0x03 && rx_msg[2] == 0x42){
+	    printf("Received ACK; downloaded image should now be running!\n");
+		return(1);
+	} else if (rx_msg[0] == 0x45 && rx_msg[1] == 0x53 && rx_msg[2] == 0x16){
+		printf("Bootloader indicates bad checksum :-(\n");
+		return(0);
+	} else if (rx_msg[0] == 0x41 && rx_msg[1] == 0x03 && rx_msg[2] == 0x57){
+		printf("Bootloader indicates bad magic :-(\n");
+		return(0);
+	} else {
+	    printf("Unknown msg from bootloader: 1B F6 02 00 %02X %02X %02X\n",
+			rx_msg[0], rx_msg[1], rx_msg[2]);
+		return(0);
+	}
+}
+
+static
+handle_rx_byte(rxb)
+{
+	switch (rx_state) {
+	case 0:
+		if (rxb == 0x1B)
+			rx_state = 1;
+		return(0);
+	case 1:
+		if (rxb == 0xF6)
+			rx_state = 2;
+		else if (rxb == 0x1B)
+			rx_state = 1;
+		else
+			rx_state = 0;
+		return(0);
+	case 2:
+		if (rxb == 0x02)
+			rx_state = 3;
+		else if (rxb == 0x1B)
+			rx_state = 1;
+		else
+			rx_state = 0;
+		return(0);
+	case 3:
+		if (rxb == 0x00)
+			rx_state = 4;
+		else if (rxb == 0x1B)
+			rx_state = 1;
+		else
+			rx_state = 0;
+		return(0);
+	case 4:
+		rx_msg[0] = rxb;
+		rx_state = 5;
+		return(0);
+	case 5:
+		rx_msg[1] = rxb;
+		rx_state = 6;
+		return(0);
+	case 6:
+		rx_msg[2] = rxb;
+		rx_state = 0;
+		return handle_rx_msg();
+	}
+}
+
+static void
+read_loop()
+{
+	u_char rdbuf[16];
+	int cc, i;
+
+	for (;;) {
+		cc = read(target_fd, rdbuf, sizeof rdbuf);
+		if (cc <= 0) {
+			fprintf(stderr, "EOF/error on target tty\n");
+			exit(1);
+		}
+		for (i = 0; i < cc; i++)
+			if (handle_rx_byte(rdbuf[i]))
+				return;
+	}
+}
+
+perform_compal_stage(for_boot_rom)
+{
+	int fd;
+	struct stat st;
+	static int zero = 0;
+
+	if (!compalstage_pathname[0])
+		return(0);
+	fd = open(compalstage_pathname, O_RDONLY);
+	if (fd < 0) {
+		perror(compalstage_pathname);
+		exit(1);
+	}
+	fstat(fd, &st);
+	if (!S_ISREG(st.st_mode)) {
+		fprintf(stderr, "error: %s is not a regular file\n",
+			compalstage_pathname);
+		exit(1);
+	}
+	if (st.st_size > 65535) {
+		fprintf(stderr,
+		"error: %s exceed Compal download limit of 65535 bytes\n",
+			compalstage_pathname);
+		exit(1);
+	}
+	compalstage_len = st.st_size;
+	compalstage_totlen = compalstage_len + 4;
+	compalstage_imgbuf = malloc(compalstage_totlen);
+	if (!compalstage_imgbuf) {
+		perror("malloc");
+		exit(1);
+	}
+	compalstage_imgbuf[0] = 0x02;
+	compalstage_imgbuf[1] = compalstage_len >> 8;
+	compalstage_imgbuf[2] = compalstage_len;
+	if (read(fd, compalstage_imgbuf+3, compalstage_len) != compalstage_len){
+		fprintf(stderr, "%s: read error or short read\n",
+			compalstage_pathname);
+		exit(1);
+	}
+	close(fd);
+	compute_checksum();
+
+	printf("Using Compal stage image %s\n", compalstage_pathname);
+	cfsetispeed(&target_termios, B115200);
+	cfsetospeed(&target_termios, B115200);
+	if (tcsetattr(target_fd, TCSAFLUSH, &target_termios) < 0) {
+		perror("tcsetattr to switch baud rate");
+		exit(1);
+	}
+	ioctl(target_fd, FIONBIO, &zero);
+	printf("Waiting for PROMPT1 from target (%s) at 115200 baud\n",
+		target_ttydev);
+	read_loop();
+	free(compalstage_imgbuf);
+
+	if (for_boot_rom) {
+		cfsetispeed(&target_termios, B19200);
+		cfsetospeed(&target_termios, B19200);
+		if (tcsetattr(target_fd, TCSAFLUSH, &target_termios) < 0) {
+			perror("tcsetattr to switch baud rate");
+			exit(1);
+		}
+	}
+
+	return(1);
+}