FreeCalypso > hg > freecalypso-tools
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); +}