view loadtools/compalload.c @ 1034:405b5469abc4 default tip

top README: repository change notice
author Mychaela Falconia <falcon@freecalypso.org>
date Sun, 12 Jun 2016 19:06:34 +0000
parents 7b3fd0e2a352
children
line wrap: on
line source

/*
 * 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);
}