Implemented FET bootloader support (memory read only).

This commit is contained in:
Daniel Beer 2010-01-08 18:39:07 +13:00
parent 0f15fd3e21
commit 1baa04a565
7 changed files with 363 additions and 15 deletions

View File

@ -25,7 +25,8 @@ clean:
.SUFFIXES: .c .o .SUFFIXES: .c .o
mspdebug: main.o fet.o rf2500.o dis.o uif.o ihex.o elf32.o stab.o util.o mspdebug: main.o fet.o rf2500.o dis.o uif.o ihex.o elf32.o stab.o util.o \
bsl.o
$(CC) $(CFLAGS) -o $@ $^ -lusb $(CC) $(CFLAGS) -o $@ $^ -lusb
.c.o: .c.o:

299
bsl.c Normal file
View File

@ -0,0 +1,299 @@
/* MSPDebug - debugging tool for the eZ430
* Copyright (C) 2009 Daniel Beer
*
* 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include "device.h"
static const struct fet_transport *trans;
static int bufio_get_bytes(u_int8_t *data, int len)
{
while (len) {
int r = trans->recv(data, len);
if (r < 0)
return -1;
data += r;
len -= r;
}
return 0;
}
#define DATA_HDR 0x80
#define DATA_ACK 0x90
#define DATA_NAK 0xA0
static int bsl_ack(void)
{
u_int8_t reply;
if (trans->recv(&reply, 1) < 0) {
fprintf(stderr, "bsl: failed to receive reply\n");
return -1;
}
if (reply == DATA_NAK) {
fprintf(stderr, "bsl: received NAK\n");
return -1;
}
if (reply != DATA_ACK) {
fprintf(stderr, "bsl: bad ack character: %x\n", reply);
return -1;
}
return 0;
}
static int bsl_sync(void)
{
static const u_int8_t c = DATA_HDR;
int tries = 2;
trans->flush();
while (tries--)
if (!trans->send(&c, 1) && !bsl_ack())
return 0;
fprintf(stderr, "bsl: sync failed\n");
return -1;
}
static int send_command(int code, u_int16_t addr,
const u_int8_t *data, int len)
{
u_int8_t pktbuf[256];
u_int8_t cklow = 0xff;
u_int8_t ckhigh = 0xff;
int pktlen = data ? len + 4 : 4;
int i;
if (pktlen + 6 > sizeof(pktbuf)) {
fprintf(stderr, "bsl: payload too large: %d\n", len);
return -1;
}
pktbuf[0] = DATA_HDR;
pktbuf[1] = code;
pktbuf[2] = pktlen;
pktbuf[3] = pktlen;
pktbuf[4] = addr & 0xff;
pktbuf[5] = addr >> 8;
pktbuf[6] = len & 0xff;
pktbuf[7] = len >> 8;
if (data)
memcpy(pktbuf + 8, data, len);
for (i = 0; i < pktlen + 4; i += 2)
cklow ^= pktbuf[i];
for (i = 1; i < pktlen + 4; i += 2)
ckhigh ^= pktbuf[i];
pktbuf[pktlen + 4] = cklow;
pktbuf[pktlen + 5] = ckhigh;
return trans->send(pktbuf, pktlen + 6);
}
static u_int8_t reply_buf[256];
static int reply_len;
static int verify_checksum(void)
{
u_int8_t cklow = 0xff;
u_int8_t ckhigh = 0xff;
int i;
for (i = 0; i < reply_len; i += 2)
cklow ^= reply_buf[i];
for (i = 1; i < reply_len; i += 2)
ckhigh ^= reply_buf[i];
if (cklow || ckhigh) {
fprintf(stderr, "bsl: checksum invalid (%02x %02x)\n",
cklow, ckhigh);
return -1;
}
return 0;
}
static int fetch_reply(void)
{
reply_len = 0;
for (;;) {
int r = trans->recv(reply_buf + reply_len,
sizeof(reply_buf) - reply_len);
if (r < 0)
return -1;
reply_len += r;
if (reply_buf[0] == DATA_ACK) {
return 0;
} else if (reply_buf[0] == DATA_HDR) {
if (reply_len >= 6 &&
reply_len == reply_buf[2] + 6)
return verify_checksum();
} else if (reply_buf[0] == DATA_NAK) {
fprintf(stderr, "bsl: received NAK\n");
return -1;
} else {
fprintf(stderr, "bsl: unknown reply type: %02x\n",
reply_buf[0]);
return -1;
}
if (reply_len >= sizeof(reply_buf)) {
fprintf(stderr, "bsl: reply buffer overflow\n");
return -1;
}
}
}
static int bsl_xfer(int command_code, u_int16_t addr, const u_int8_t *txdata,
int len)
{
if (bsl_sync() < 0 ||
send_command(command_code, addr, txdata, len) < 0 ||
fetch_reply() < 0) {
fprintf(stderr, "bsl: failed on command 0x%02x "
"(addr = 0x%04x, len = 0x%04x)\n",
command_code, addr, len);
return -1;
}
return 0;
}
#define CMD_TX_DATA 0x38
#define CMD_ERASE 0x39
#define CMD_RX_DATA 0x3a
#define CMD_RESET 0x3b
static void bsl_close(void)
{
if (trans) {
bsl_xfer(CMD_RESET, 0, NULL, 0);
trans->close();
trans = NULL;
}
}
static int bsl_control(device_ctl_t type)
{
fprintf(stderr, "bsl: CPU control is not implemented\n");
return -1;
}
static int bsl_wait(void)
{
return 0;
}
static int bsl_breakpoint(u_int16_t addr)
{
fprintf(stderr, "bsl: breakpoints are not implemented\n");
return -1;
}
static int bsl_getregs(u_int16_t *regs)
{
fprintf(stderr, "bsl: register fetch is not implemented\n");
return -1;
}
static int bsl_setregs(const u_int16_t *regs)
{
fprintf(stderr, "bsl: register store is not implemented\n");
return -1;
}
static int bsl_writemem(u_int16_t addr, const u_int8_t *mem, int len)
{
fprintf(stderr, "bsl: memory write is not implemented\n");
return -1;
}
static int bsl_readmem(u_int16_t addr, u_int8_t *mem, int len)
{
while (len) {
int count = len;
if (count > 128)
count = 128;
if (bsl_xfer(CMD_TX_DATA, addr, NULL, count) < 0) {
fprintf(stderr, "bsl: failed to read memory\n");
return -1;
}
if (count > reply_buf[2])
count = reply_buf[2];
memcpy(mem, reply_buf + 4, count);
mem += count;
len -= count;
}
return 0;
}
const static struct device bsl_device = {
.close = bsl_close,
.control = bsl_control,
.wait = bsl_wait,
.breakpoint = bsl_breakpoint,
.getregs = bsl_getregs,
.setregs = bsl_setregs,
.writemem = bsl_writemem,
.readmem = bsl_readmem
};
const struct device *fet_open_bl(const struct fet_transport *tr)
{
u_int8_t buf[16];
trans = tr;
/* Enter bootloader command */
if (trans->send((u_int8_t *)"\x7e\x24\x01\x9d\x5a\x7e", 6) < 0 ||
bufio_get_bytes(buf, 8) < 0) {
fprintf(stderr, "bsl: failed to init bootloader\n");
return NULL;
}
usleep(500000);
return &bsl_device;
}

View File

@ -51,4 +51,7 @@ struct device {
const struct device *fet_open(const struct fet_transport *transport, const struct device *fet_open(const struct fet_transport *transport,
int proto_flags, int vcc_mv); int proto_flags, int vcc_mv);
/* MSP430 FET Bootloader implementation. */
const struct device *fet_open_bl(const struct fet_transport *transport);
#endif #endif

15
main.c
View File

@ -616,7 +616,7 @@ static void reader_loop(void)
static void usage(const char *progname) static void usage(const char *progname)
{ {
fprintf(stderr, fprintf(stderr,
"Usage: %s [-u device] [-j] [-v voltage] [command ...]\n" "Usage: %s [-u device] [-j] [-B] [-v voltage] [command ...]\n"
"\n" "\n"
" -u device\n" " -u device\n"
" Open the given tty device (MSP430 UIF compatible devices).\n" " Open the given tty device (MSP430 UIF compatible devices).\n"
@ -624,6 +624,8 @@ static void usage(const char *progname)
" Use JTAG, rather than spy-bi-wire (UIF devices only).\n" " Use JTAG, rather than spy-bi-wire (UIF devices only).\n"
" -v voltage\n" " -v voltage\n"
" Set the supply voltage, in millivolts.\n" " Set the supply voltage, in millivolts.\n"
" -B\n"
" Debug the FET itself through the bootloader.\n"
"\n" "\n"
"By default, the first RF2500 device on the USB bus is opened.\n" "By default, the first RF2500 device on the USB bus is opened.\n"
"\n" "\n"
@ -639,6 +641,7 @@ int main(int argc, char **argv)
int opt; int opt;
int flags = 0; int flags = 0;
int want_jtag = 0; int want_jtag = 0;
int want_bootloader = 0;
int vcc_mv = 3000; int vcc_mv = 3000;
puts( puts(
@ -647,7 +650,7 @@ int main(int argc, char **argv)
"This is free software; see the source for copying conditions. There is NO\n" "This is free software; see the source for copying conditions. There is NO\n"
"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"); "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n");
while ((opt = getopt(argc, argv, "u:jv:")) >= 0) while ((opt = getopt(argc, argv, "u:jv:B")) >= 0)
switch (opt) { switch (opt) {
case 'u': case 'u':
uif_device = optarg; uif_device = optarg;
@ -661,6 +664,10 @@ int main(int argc, char **argv)
want_jtag = 1; want_jtag = 1;
break; break;
case 'B':
want_bootloader = 1;
break;
default: default:
usage(argv[0]); usage(argv[0]);
return -1; return -1;
@ -679,10 +686,14 @@ int main(int argc, char **argv)
/* Then initialize the device */ /* Then initialize the device */
if (!want_jtag) if (!want_jtag)
flags |= FET_PROTO_SPYBIWIRE; flags |= FET_PROTO_SPYBIWIRE;
if (want_bootloader)
msp430_dev = fet_open_bl(trans);
else
msp430_dev = fet_open(trans, flags, vcc_mv); msp430_dev = fet_open(trans, flags, vcc_mv);
if (!msp430_dev) if (!msp430_dev)
return -1; return -1;
/* Process commands */
if (optind < argc) { if (optind < argc) {
while (optind < argc) while (optind < argc)
process_command(argv[optind++]); process_command(argv[optind++]);

View File

@ -127,12 +127,14 @@ static u_int8_t usbtr_buf[64];
static int usbtr_len; static int usbtr_len;
static int usbtr_offset; static int usbtr_offset;
static void usbtr_flush(void) static int usbtr_flush(void)
{ {
char buf[64]; char buf[64];
while (usb_bulk_read(usbtr_handle, USB_FET_IN_EP, while (usb_bulk_read(usbtr_handle, USB_FET_IN_EP,
buf, sizeof(buf), 100) >= 0); buf, sizeof(buf), 100) >= 0);
return 0;
} }
static int usbtr_recv(u_int8_t *databuf, int max_len) static int usbtr_recv(u_int8_t *databuf, int max_len)
@ -174,6 +176,7 @@ static void usbtr_close(void)
} }
static const struct fet_transport usbtr_transport = { static const struct fet_transport usbtr_transport = {
.flush = usbtr_flush,
.send = usbtr_send, .send = usbtr_send,
.recv = usbtr_recv, .recv = usbtr_recv,
.close = usbtr_close .close = usbtr_close

View File

@ -27,6 +27,7 @@
* high-level functions. * high-level functions.
*/ */
struct fet_transport { struct fet_transport {
int (*flush)(void);
int (*send)(const u_int8_t *data, int len); int (*send)(const u_int8_t *data, int len);
int (*recv)(u_int8_t *data, int max_len); int (*recv)(u_int8_t *data, int max_len);
void (*close)(void); void (*close)(void);

46
uif.c
View File

@ -61,22 +61,41 @@ static int serial_send(const u_int8_t *data, int len)
static int serial_recv(u_int8_t *data, int max_len) static int serial_recv(u_int8_t *data, int max_len)
{ {
int len; int r;
assert (serial_fd >= 0); assert (serial_fd >= 0);
len = read(serial_fd, data, max_len); do {
struct timeval tv = {
.tv_sec = 5,
.tv_usec = 0
};
if (len < 0) { fd_set set;
perror("serial_recv");
FD_ZERO(&set);
FD_SET(serial_fd, &set);
r = select(serial_fd + 1, &set, NULL, NULL, &tv);
if (r > 0)
r = read(serial_fd, data, max_len);
if (r < 0 && errno != EINTR) {
perror("bls: read error");
return -1; return -1;
} }
if (!r) {
fprintf(stderr, "bls: read timeout\n");
return -1;
}
} while (r <= 0);
#ifdef DEBUG_SERIAL #ifdef DEBUG_SERIAL
puts("Serial transfer in:"); puts("Serial transfer in:");
hexdump(0, data, len); hexdump(0, data, r);
#endif #endif
return len; return r;
} }
static void serial_close(void) static void serial_close(void)
@ -86,7 +105,18 @@ static void serial_close(void)
close(serial_fd); close(serial_fd);
} }
static int serial_flush(void)
{
if (tcflush(serial_fd, TCIFLUSH) < 0) {
perror("uif: tcflush");
return -1;
}
return 0;
}
static const struct fet_transport serial_transport = { static const struct fet_transport serial_transport = {
.flush = serial_flush,
.send = serial_send, .send = serial_send,
.recv = serial_recv, .recv = serial_recv,
.close = serial_close .close = serial_close
@ -100,7 +130,7 @@ const struct fet_transport *uif_open(const char *device)
serial_fd = open(device, O_RDWR | O_NOCTTY); serial_fd = open(device, O_RDWR | O_NOCTTY);
if (serial_fd < 0) { if (serial_fd < 0) {
fprintf(stderr, "uif_open: open: %s: %s\n", fprintf(stderr, "uif: open: %s: %s\n",
device, strerror(errno)); device, strerror(errno));
return NULL; return NULL;
} }
@ -109,7 +139,7 @@ const struct fet_transport *uif_open(const char *device)
cfmakeraw(&attr); cfmakeraw(&attr);
cfsetspeed(&attr, B460800); cfsetspeed(&attr, B460800);
if (tcsetattr(serial_fd, TCSAFLUSH, &attr) < 0) { if (tcsetattr(serial_fd, TCSAFLUSH, &attr) < 0) {
fprintf(stderr, "uif_open: tcsetattr: %s: %s\n", fprintf(stderr, "uif: tcsetattr: %s: %s\n",
device, strerror(errno)); device, strerror(errno));
return NULL; return NULL;
} }