From 17cd8dd479b199420e92a60dfcacc0e175c71393 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 5 Feb 2012 19:14:24 +0100 Subject: [PATCH] Add tools --- tools/Makefile | 16 ++ tools/bin2hex.c | 83 ++++++ tools/flterm.c | 735 ++++++++++++++++++++++++++++++++++++++++++++++++ tools/mkmmimg.c | 174 ++++++++++++ tools/sfl.h | 48 ++++ 5 files changed, 1056 insertions(+) create mode 100644 tools/Makefile create mode 100644 tools/bin2hex.c create mode 100644 tools/flterm.c create mode 100644 tools/mkmmimg.c create mode 100644 tools/sfl.h diff --git a/tools/Makefile b/tools/Makefile new file mode 100644 index 00000000..0ed7497a --- /dev/null +++ b/tools/Makefile @@ -0,0 +1,16 @@ +TARGETS=bin2hex mkmmimg flterm +CC=clang + +all: $(TARGETS) + +%: %.c + $(CC) -O2 -Wall -I. -s -o $@ $< + +install: mkmmimg flterm + cp mkmmimg /usr/bin + cp flterm /usr/bin + +.PHONY: clean install + +clean: + rm -f $(TARGETS) diff --git a/tools/bin2hex.c b/tools/bin2hex.c new file mode 100644 index 00000000..e1ec2f10 --- /dev/null +++ b/tools/bin2hex.c @@ -0,0 +1,83 @@ +/* + * Milkymist SoC + * Copyright (C) 2007, 2008, 2009, 2010 Sebastien Bourdeauducq + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* WARNING: This tool is little endian in 16-bit mode + * and big endian in 32-bit mode. + */ + +#include +#include +#include + +int main(int argc, char *argv[]) +{ + int i; + int pad; + FILE *fdi, *fdo; + unsigned char w[4]; + int mode16; + + if((argc != 4) && (argc != 5)) { + fprintf(stderr, "Usage: bin2hex [16]\n"); + return 1; + } + pad = atoi(argv[3]); + if(pad <= 0) { + fprintf(stderr, "Incorrect size\n"); + return 1; + } + fdi = fopen(argv[1], "rb"); + if(!fdi) { + perror("Unable to open input file"); + return 1; + } + fdo = fopen(argv[2], "w"); + if(!fdo) { + perror("Unable to open output file"); + fclose(fdi); + return 1; + } + mode16 = (argc == 5) && (strcmp(argv[4], "16") == 0); + if(mode16) { + while(1) { + if(fread(w, 2, 1, fdi) <= 0) break; + fprintf(fdo, "%02hhx%02hhx\n", w[1], w[0]); + pad--; + } + } else { + while(1) { + if(fread(w, 4, 1, fdi) <= 0) break; + fprintf(fdo, "%02hhx%02hhx%02hhx%02hhx\n", w[0], w[1], w[2], w[3]); + pad--; + } + } + fclose(fdi); + if(pad<0) + fprintf(stderr, "Warning: Input binary is larger than specified size\n"); + if(mode16) { + for(i=0;i. + */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEFAULT_KERNELADR (0x40000000) +#define DEFAULT_CMDLINEADR (0x41000000) +#define DEFAULT_INITRDADR (0x41002000) + +#define GDBBUFLEN 1000 + +unsigned int crc16_table[256] = { + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, + 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, + 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485, + 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4, + 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC, + 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, + 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, + 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, + 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, + 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, + 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70, + 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78, + 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, + 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, + 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, + 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, + 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3, + 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, + 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, + 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, + 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, + 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, + 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0 +}; + +static int debug = 0; + +static unsigned short crc16(const void *_buffer, int len) +{ + const unsigned char *buffer = (const unsigned char *)_buffer; + unsigned short crc; + + crc = 0; + while(len-- > 0) + crc = crc16_table[((crc >> 8) ^ (*buffer++)) & 0xFF] ^ (crc << 8); + + return crc; +} + +static int write_exact(int fd, const char *data, unsigned int length) +{ + int r; + + while(length > 0) { + r = write(fd, data, length); + if(r <= 0) return 0; + length -= r; + data += r; + } + return 1; +} + +/* length, cmd and payload must be filled in */ +static int send_frame(int serialfd, struct sfl_frame *frame) +{ + unsigned short int crc; + int retry; + char reply; + + crc = crc16(&frame->cmd, frame->length+1); + frame->crc[0] = (crc & 0xff00) >> 8; + frame->crc[1] = (crc & 0x00ff); + + retry = 0; + do { + if(!write_exact(serialfd, (char *)frame, frame->length+4)) { + perror("[FLTERM] Unable to write to serial port."); + return 0; + } + /* Get the reply from the device */ + read(serialfd, &reply, 1); /* TODO: timeout */ + switch(reply) { + case SFL_ACK_SUCCESS: + retry = 0; + break; + case SFL_ACK_CRCERROR: + retry = 1; + break; + default: + fprintf(stderr, "[FLTERM] Got unknown reply '%c' from the device, aborting.\n", reply); + return 0; + } + } while(retry); + return 1; +} + +static int upload_fd(int serialfd, const char *name, int firmwarefd, unsigned int load_address) +{ + struct sfl_frame frame; + int readbytes; + int length; + int position; + unsigned int current_address; + struct timeval t0; + struct timeval t1; + int millisecs; + + length = lseek(firmwarefd, 0, SEEK_END); + lseek(firmwarefd, 0, SEEK_SET); + + printf("[FLTERM] Uploading %s (%d bytes)...\n", name, length); + + gettimeofday(&t0, NULL); + + current_address = load_address; + position = 0; + while(1) { + printf("%d%%\r", 100*position/length); + fflush(stdout); + + readbytes = read(firmwarefd, &frame.payload[4], sizeof(frame.payload) - 4); + if(readbytes < 0) { + perror("[FLTERM] Unable to read image."); + return -1; + } + if(readbytes == 0) break; + + frame.length = readbytes+4; + frame.cmd = SFL_CMD_LOAD; + frame.payload[0] = (current_address & 0xff000000) >> 24; + frame.payload[1] = (current_address & 0x00ff0000) >> 16; + frame.payload[2] = (current_address & 0x0000ff00) >> 8; + frame.payload[3] = (current_address & 0x000000ff); + + if(!send_frame(serialfd, &frame)) return -1; + + current_address += readbytes; + position += readbytes; + } + + gettimeofday(&t1, NULL); + + millisecs = (t1.tv_sec - t0.tv_sec)*1000 + (t1.tv_usec - t0.tv_usec)/1000; + + printf("[FLTERM] Upload complete (%.1fKB/s).\n", 1000.0*(double)length/((double)millisecs*1024.0)); + return length; +} + +static const char sfl_magic_req[SFL_MAGIC_LEN] = SFL_MAGIC_REQ; +static const char sfl_magic_ack[SFL_MAGIC_LEN] = SFL_MAGIC_ACK; + +static void answer_magic(int serialfd, + const char *kernel_image, unsigned int kernel_address, + const char *cmdline, unsigned int cmdline_address, + const char *initrd_image, unsigned int initrd_address) +{ + int kernelfd, initrdfd; + struct sfl_frame frame; + + printf("[FLTERM] Received firmware download request from the device.\n"); + + kernelfd = open(kernel_image, O_RDONLY); + if(kernelfd == -1) { + perror("[FLTERM] Unable to open kernel image (request ignored)."); + return; + } + initrdfd = -1; + if(initrd_image != NULL) { + initrdfd = open(initrd_image, O_RDONLY); + if(initrdfd == -1) { + perror("[FLTERM] Unable to open initrd image (request ignored)."); + close(kernelfd); + return; + } + } + + write_exact(serialfd, sfl_magic_ack, SFL_MAGIC_LEN); + + upload_fd(serialfd, "kernel", kernelfd, kernel_address); + if(cmdline != NULL) { + int len; + + printf("[FLTERM] Setting kernel command line: '%s'.\n", cmdline); + + len = strlen(cmdline)+1; + if(len > (254-4)) { + fprintf(stderr, "[FLTERM] Kernel command line too long, load aborted.\n"); + close(initrdfd); + close(kernelfd); + return; + } + frame.length = len+4; + frame.cmd = SFL_CMD_LOAD; + frame.payload[0] = (cmdline_address & 0xff000000) >> 24; + frame.payload[1] = (cmdline_address & 0x00ff0000) >> 16; + frame.payload[2] = (cmdline_address & 0x0000ff00) >> 8; + frame.payload[3] = (cmdline_address & 0x000000ff); + strcpy((char *)&frame.payload[4], cmdline); + send_frame(serialfd, &frame); + + frame.length = 4; + frame.cmd = SFL_CMD_CMDLINE; + frame.payload[0] = (cmdline_address & 0xff000000) >> 24; + frame.payload[1] = (cmdline_address & 0x00ff0000) >> 16; + frame.payload[2] = (cmdline_address & 0x0000ff00) >> 8; + frame.payload[3] = (cmdline_address & 0x000000ff); + send_frame(serialfd, &frame); + } + if(initrdfd != -1) { + int len; + + len = upload_fd(serialfd, "initrd", initrdfd, initrd_address); + if(len <= 0) return; + + frame.length = 4; + frame.cmd = SFL_CMD_INITRDSTART; + frame.payload[0] = (initrd_address & 0xff000000) >> 24; + frame.payload[1] = (initrd_address & 0x00ff0000) >> 16; + frame.payload[2] = (initrd_address & 0x0000ff00) >> 8; + frame.payload[3] = (initrd_address & 0x000000ff); + send_frame(serialfd, &frame); + + initrd_address += len-1; + + frame.length = 4; + frame.cmd = SFL_CMD_INITRDEND; + frame.payload[0] = (initrd_address & 0xff000000) >> 24; + frame.payload[1] = (initrd_address & 0x00ff0000) >> 16; + frame.payload[2] = (initrd_address & 0x0000ff00) >> 8; + frame.payload[3] = (initrd_address & 0x000000ff); + send_frame(serialfd, &frame); + } + + /* Send the jump command */ + printf("[FLTERM] Booting the device.\n"); + frame.length = 4; + frame.cmd = SFL_CMD_JUMP; + frame.payload[0] = (kernel_address & 0xff000000) >> 24; + frame.payload[1] = (kernel_address & 0x00ff0000) >> 16; + frame.payload[2] = (kernel_address & 0x0000ff00) >> 8; + frame.payload[3] = (kernel_address & 0x000000ff); + if(!send_frame(serialfd, &frame)) return; + + printf("[FLTERM] Done.\n"); + + close(initrdfd); + close(kernelfd); +} + +static int hex(unsigned char c) +{ + if(c >= 'a' && c <= 'f') { + return c - 'a' + 10; + } + if(c >= '0' && c <= '9') { + return c - '0'; + } + if(c >= 'A' && c <= 'F') { + return c - 'A' + 10; + } + return 0; +} + +/* + * This is taken from kdmx2. + * Author: Tom Rini + */ +static void gdb_process_packet(int infd, int outfd, int altfd) +{ + /* gdb packet handling */ + char gdbbuf[GDBBUFLEN + 1]; + int pos = 0; + unsigned char runcksum = 0; + unsigned char recvcksum = 0; + struct pollfd fds; + char c; + int seen_hash = 0; + + fds.fd = infd; + fds.events = POLLIN; + + memset(gdbbuf, 0, sizeof(gdbbuf)); + gdbbuf[0] = '$'; + pos++; + + while (1) { + fds.revents = 0; + if(poll(&fds, 1, 100) == 0) { + /* timeout */ + if(altfd != -1) { + write(altfd, gdbbuf, pos); + } + break; + } + if(pos == GDBBUFLEN) { + if(altfd != -1) { + write(altfd, gdbbuf, pos); + } + break; + } + read(infd, &c, 1); + gdbbuf[pos++] = c; + if(c == '#') { + seen_hash = 1; + } else if(seen_hash == 0) { + runcksum += c; + } else if(seen_hash == 1) { + recvcksum = hex(c) << 4; + seen_hash = 2; + } else if(seen_hash == 2) { + recvcksum |= hex(c); + seen_hash = 3; + } + + if(seen_hash == 3) { + /* we're done */ + runcksum %= 256; + if(recvcksum == runcksum) { + if(debug) { + fprintf(stderr, "[GDB %s]\n", gdbbuf); + } + write(outfd, gdbbuf, pos); + } else { + if(altfd != -1) { + write(altfd, gdbbuf, pos); + } + } + seen_hash = 0; + break; + } + } +} + +static void do_terminal(char *serial_port, + int doublerate, int gdb_passthrough, + const char *kernel_image, unsigned int kernel_address, + const char *cmdline, unsigned int cmdline_address, + const char *initrd_image, unsigned int initrd_address, + char *log_path) +{ + int serialfd; + int gdbfd = -1; + FILE *logfd = NULL; + struct termios my_termios; + char c; + int recognized; + struct pollfd fds[3]; + int flags; + int rsp_pending = 0; + + /* Open and configure the serial port */ + if(log_path != NULL) { + logfd = fopen(log_path, "a+"); + if(logfd == NULL) { + perror("Unable to open log file"); + return; + } + } + + serialfd = open(serial_port, O_RDWR|O_NOCTTY); + if(serialfd == -1) { + perror("Unable to open serial port"); + return; + } + + /* Thanks to Julien Schmitt (GTKTerm) for figuring out the correct parameters + * to put into that weird struct. + */ + tcgetattr(serialfd, &my_termios); + my_termios.c_cflag = doublerate ? B230400 : B115200; + my_termios.c_cflag |= CS8; + my_termios.c_cflag |= CREAD; + my_termios.c_iflag = IGNPAR | IGNBRK; + my_termios.c_cflag |= CLOCAL; + my_termios.c_oflag = 0; + my_termios.c_lflag = 0; + my_termios.c_cc[VTIME] = 0; + my_termios.c_cc[VMIN] = 1; + tcsetattr(serialfd, TCSANOW, &my_termios); + tcflush(serialfd, TCOFLUSH); + tcflush(serialfd, TCIFLUSH); + + /* Prepare the fdset for poll() */ + fds[0].fd = 0; + fds[0].events = POLLIN; + fds[1].fd = serialfd; + fds[1].events = POLLIN; + + recognized = 0; + flags = fcntl(serialfd, F_GETFL, 0); + while(1) { + if(gdbfd == -1 && gdb_passthrough) { + gdbfd = open("/dev/ptmx", O_RDWR); + if(grantpt(gdbfd) != 0) { + perror("grantpt()"); + return; + } + if(unlockpt(gdbfd) != 0) { + perror("unlockpt()"); + return; + } + printf("[GDB passthrough] use %s as GDB remote device\n", + ptsname(gdbfd)); + fds[2].fd = gdbfd; + fds[2].events = POLLIN; + } + + fds[0].revents = 0; + fds[1].revents = 0; + fds[2].revents = 0; + + /* poll() behaves strangely when the serial port descriptor is in + * blocking mode. So work around this. + */ + fcntl(serialfd, F_SETFL, flags|O_NONBLOCK); + if(poll(&fds[0], (gdbfd == -1) ? 2 : 3, -1) < 0) break; + fcntl(serialfd, F_SETFL, flags); + + if(fds[0].revents & POLLIN) { + if(read(0, &c, 1) <= 0) break; + if(write(serialfd, &c, 1) <= 0) break; + } + + if(fds[2].revents & POLLIN) { + rsp_pending = 1; + if(read(gdbfd, &c, 1) <= 0) break; + if(c == '\03') { + /* convert ETX to breaks */ + if(debug) { + fprintf(stderr, "[GDB BREAK]\n"); + } + tcsendbreak(serialfd, 0); + } else if(c == '$') { + gdb_process_packet(gdbfd, serialfd, -1); + } else if(c == '+' || c == '-') { + write(serialfd, &c, 1); + } else { + fprintf(stderr, "Internal error (line %d)", __LINE__); + exit(1); + } + } + + if(fds[2].revents & POLLHUP) { + /* close and reopen new pair */ + close(gdbfd); + gdbfd = -1; + continue; + } + + if(fds[1].revents & POLLIN) { + if(read(serialfd, &c, 1) <= 0) break; + + if(logfd && c && isascii(c)) { + fwrite(&c, sizeof(c), 1, logfd); + if(c == '\n') fflush(logfd); + } + + if(gdbfd != -1 && rsp_pending && (c == '+' || c == '-')) { + rsp_pending = 0; + write(gdbfd, &c, 1); + } else if(gdbfd != -1 && c == '$') { + gdb_process_packet(serialfd, gdbfd, 0); + } else { + /* write to terminal */ + write(0, &c, 1); + + if(kernel_image != NULL) { + if(c == sfl_magic_req[recognized]) { + recognized++; + if(recognized == SFL_MAGIC_LEN) { + /* We've got the magic string ! */ + recognized = 0; + answer_magic(serialfd, + kernel_image, kernel_address, + cmdline, cmdline_address, + initrd_image, initrd_address); + } + } else { + if(c == sfl_magic_req[0]) recognized = 1; else recognized = 0; + } + } + } + } + } + + close(serialfd); + + if(gdbfd != -1) close(gdbfd); + if(logfd) fclose(logfd); +} + +enum { + OPTION_PORT, + OPTION_GDB_PASSTHROUGH, + OPTION_DOUBLERATE, + OPTION_DEBUG, + OPTION_KERNEL, + OPTION_KERNELADR, + OPTION_CMDLINE, + OPTION_CMDLINEADR, + OPTION_INITRD, + OPTION_INITRDADR, + OPTION_LOG +}; + +static const struct option options[] = { + { + .name = "port", + .has_arg = 1, + .val = OPTION_PORT + }, + { + .name = "gdb-passthrough", + .has_arg = 0, + .val = OPTION_GDB_PASSTHROUGH + }, + { + .name = "debug", + .has_arg = 0, + .val = OPTION_DEBUG + }, + { + .name = "double-rate", + .has_arg = 0, + .val = OPTION_DOUBLERATE + }, + { + .name = "kernel", + .has_arg = 1, + .val = OPTION_KERNEL + }, + { + .name = "kernel-adr", + .has_arg = 1, + .val = OPTION_KERNELADR + }, + { + .name = "cmdline", + .has_arg = 1, + .val = OPTION_CMDLINE + }, + { + .name = "cmdline-adr", + .has_arg = 1, + .val = OPTION_CMDLINEADR + }, + { + .name = "initrd", + .has_arg = 1, + .val = OPTION_INITRD + }, + { + .name = "initrd-adr", + .has_arg = 1, + .val = OPTION_INITRDADR + }, + { + .name = "log", + .has_arg = 1, + .val = OPTION_LOG + }, + { + .name = NULL + } +}; + +static void print_usage() +{ + fprintf(stderr, "Serial boot program for Milkymist SoC - v. 2.2\n"); + fprintf(stderr, "Copyright (C) 2007, 2008, 2009, 2010, 2011 Sebastien Bourdeauducq\n"); + fprintf(stderr, "Copyright (C) 2011 Michael Walle\n"); + fprintf(stderr, "Copyright (C) 2004 MontaVista Software, Inc\n\n"); + + fprintf(stderr, "This program is free software: you can redistribute it and/or modify\n"); + fprintf(stderr, "it under the terms of the GNU General Public License as published by\n"); + fprintf(stderr, "the Free Software Foundation, version 3 of the License.\n\n"); + + fprintf(stderr, "Usage: flterm --port \n"); + fprintf(stderr, " [--double-rate] [--gdb-passthrough] [--debug]\n"); + fprintf(stderr, " [--kernel [--kernel-adr
]]\n"); + fprintf(stderr, " [--cmdline [--cmdline-adr
]]\n"); + fprintf(stderr, " [--initrd [--initrd-adr
]]\n"); + fprintf(stderr, " [--log ]\n\n"); + fprintf(stderr, "Default load addresses:\n"); + fprintf(stderr, " kernel: 0x%08x\n", DEFAULT_KERNELADR); + fprintf(stderr, " cmdline: 0x%08x\n", DEFAULT_CMDLINEADR); + fprintf(stderr, " initrd: 0x%08x\n", DEFAULT_INITRDADR); +} + +int main(int argc, char *argv[]) +{ + int opt; + char *serial_port; + int doublerate; + int gdb_passthrough; + char *kernel_image; + unsigned int kernel_address; + char *cmdline; + unsigned int cmdline_address; + char *initrd_image; + unsigned int initrd_address; + char *endptr; + char *log_path; + struct termios otty, ntty; + + /* Fetch command line arguments */ + serial_port = NULL; + doublerate = 0; + gdb_passthrough = 0; + kernel_image = NULL; + kernel_address = DEFAULT_KERNELADR; + cmdline = NULL; + cmdline_address = DEFAULT_CMDLINEADR; + initrd_image = NULL; + initrd_address = DEFAULT_INITRDADR; + log_path = NULL; + while((opt = getopt_long(argc, argv, "", options, NULL)) != -1) { + if(opt == '?') { + print_usage(); + return 1; + } + switch(opt) { + case OPTION_PORT: + free(serial_port); + serial_port = strdup(optarg); + break; + case OPTION_DOUBLERATE: + doublerate = 1; + break; + case OPTION_DEBUG: + debug = 1; + break; + case OPTION_GDB_PASSTHROUGH: + gdb_passthrough = 1; + break; + case OPTION_KERNEL: + free(kernel_image); + kernel_image = strdup(optarg); + break; + case OPTION_KERNELADR: + kernel_address = strtoul(optarg, &endptr, 0); + if(*endptr != 0) kernel_address = 0; + break; + case OPTION_CMDLINE: + free(cmdline); + cmdline = strdup(optarg); + break; + case OPTION_CMDLINEADR: + cmdline_address = strtoul(optarg, &endptr, 0); + if(*endptr != 0) cmdline_address = 0; + break; + case OPTION_INITRD: + free(initrd_image); + initrd_image = strdup(optarg); + break; + case OPTION_INITRDADR: + initrd_address = strtoul(optarg, &endptr, 0); + if(*endptr != 0) initrd_address = 0; + break; + case OPTION_LOG: + free(log_path); + log_path = strdup(optarg); + break; + } + } + + if(serial_port == NULL) { + print_usage(); + return 1; + } + + /* Banner */ + printf("[FLTERM] Starting...\n"); + + /* Set up stdin/out */ + tcgetattr(0, &otty); + ntty = otty; + ntty.c_lflag &= ~(ECHO | ICANON); + tcsetattr(0, TCSANOW, &ntty); + + /* Do the bulk of the work */ + do_terminal(serial_port, doublerate, gdb_passthrough, + kernel_image, kernel_address, + cmdline, cmdline_address, + initrd_image, initrd_address, + log_path); + + /* Restore stdin/out into their previous state */ + tcsetattr(0, TCSANOW, &otty); + + return 0; +} diff --git a/tools/mkmmimg.c b/tools/mkmmimg.c new file mode 100644 index 00000000..31ff4016 --- /dev/null +++ b/tools/mkmmimg.c @@ -0,0 +1,174 @@ +/* + * CRC32 computation tool and Milkymist image file writer + * (c) 2009, 2010, Sebastien Bourdeauducq + * Released under GNU GPL v3 + * This file is part of Milkymist. + */ + +/* crc32.c -- compute the CRC-32 of a data stream + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +const unsigned int crc_table[256] = { + 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, + 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, + 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, + 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, + 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, + 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, + 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, + 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, + 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, + 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, + 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, + 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, + 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, + 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, + 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, + 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, + 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, + 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, + 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, + 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, + 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, + 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, + 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, + 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, + 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, + 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, + 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, + 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, + 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, + 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, + 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, + 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, + 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, + 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, + 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, + 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, + 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, + 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, + 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, + 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, + 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, + 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, + 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, + 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, + 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, + 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, + 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, + 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, + 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, + 0x2d02ef8dL +}; + +#define DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8); +#define DO2(buf) DO1(buf); DO1(buf); +#define DO4(buf) DO2(buf); DO2(buf); +#define DO8(buf) DO4(buf); DO4(buf); + +static unsigned int crc32(const unsigned char *buffer, unsigned int len) +{ + unsigned int crc; + crc = 0; + crc = crc ^ 0xffffffffL; + while(len >= 8) { + DO8(buffer); + len -= 8; + } + if(len) do { + DO1(buffer); + } while(--len); + return crc ^ 0xffffffffL; +} + +int main(int argc, char *argv[]) +{ + int fd, fd_out; + unsigned char *buffer; + unsigned int length; + unsigned int crc; + + if(((argc != 2) && (argc != 3) && (argc != 4)) + || ((argc > 2) && (strcmp(argv[2], "write") && (strcmp(argv[2], "writelzma"))))) { + fprintf(stderr, "Usage: mkmmimg [write[lzma]] [dest]\n"); + return 1; + } + + fd = open(argv[1], O_RDONLY); + if(fd == -1) { + perror("open"); + return 1; + } + + length = lseek(fd, 0, SEEK_END); + lseek(fd, 0, SEEK_SET); + + buffer = mmap(NULL, length, PROT_READ, MAP_SHARED, fd, 0); + if(!buffer) { + perror("mmap"); + close(fd); + return 1; + } + crc = crc32(buffer, length); + printf("CRC32 (%s): %08x\n", argv[1], crc); + + if(argc == 3) { + /* Write the CRC32 in big endian at the end of the file */ + char b[4]; + + fd_out = open(argv[1], O_WRONLY|O_APPEND); + if(fd_out == -1) { + perror("open"); + return 1; + } + b[0] = (crc & 0xff000000) >> 24; + b[1] = (crc & 0x00ff0000) >> 16; + b[2] = (crc & 0x0000ff00) >> 8; + b[3] = (crc & 0x000000ff) >> 0; + write(fd_out, &b[0], 4); + close(fd_out); + } + + if(argc == 4) { + /* Write a new file prepended with the size and CRC */ + char b[4]; + + fd_out = open(argv[3], O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH); + if(fd_out == -1) { + perror("open"); + return 1; + } + b[0] = (length & 0xff000000) >> 24; + b[1] = (length & 0x00ff0000) >> 16; + b[2] = (length & 0x0000ff00) >> 8; + b[3] = (length & 0x000000ff) >> 0; + if(strcmp(argv[2], "writelzma") == 0) + b[0] |= 0x80; + write(fd_out, &b[0], 4); + b[0] = (crc & 0xff000000) >> 24; + b[1] = (crc & 0x00ff0000) >> 16; + b[2] = (crc & 0x0000ff00) >> 8; + b[3] = (crc & 0x000000ff) >> 0; + write(fd_out, &b[0], 4); + write(fd_out, buffer, length); + close(fd_out); + } + + munmap(buffer, length); + close(fd); + + return 0; +} diff --git a/tools/sfl.h b/tools/sfl.h new file mode 100644 index 00000000..90a205fd --- /dev/null +++ b/tools/sfl.h @@ -0,0 +1,48 @@ +/* + * Milkymist SoC + * Copyright (C) 2007, 2008, 2009 Sebastien Bourdeauducq + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __SFL_H +#define __SFL_H + +#define SFL_MAGIC_LEN 14 +#define SFL_MAGIC_REQ "sL5DdSMmkekro\n" +#define SFL_MAGIC_ACK "z6IHG7cYDID6o\n" + +struct sfl_frame { + unsigned char length; + unsigned char crc[2]; + unsigned char cmd; + unsigned char payload[255]; +} __attribute__((packed)); + +/* General commands */ +#define SFL_CMD_ABORT 0x00 +#define SFL_CMD_LOAD 0x01 +#define SFL_CMD_JUMP 0x02 + +/* Linux-specific commands */ +#define SFL_CMD_CMDLINE 0x03 +#define SFL_CMD_INITRDSTART 0x04 +#define SFL_CMD_INITRDEND 0x05 + +/* Replies */ +#define SFL_ACK_SUCCESS 'K' +#define SFL_ACK_CRCERROR 'C' +#define SFL_ACK_UNKNOWN 'U' +#define SFL_ACK_ERROR 'E' + +#endif /* __SFL_H */ -- 2.30.2