/* * $Id: bdmlib.c,v 1.5 2005/11/04 14:33:54 ppisa Exp $ * * Remote debugging interface for 683xx via Background Debug Mode * needs a driver, which controls the BDM interface. * written by G.Magin * (C) 1996 Technische Universitaet Muenchen, Lehrstuhl fuer Prozessrechner * (C) 1997 G. Magin * * Modified by Pavel Pisa pisa@cmp.felk.cvut.cz 1998 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, 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; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* * NOTE: * This file is assumed to be runnable only on Linux/i386 because of * HW-restrictions: the driver is currently only available on i386-Linux * So byte-swapping and alignment is handled directly, violating the * GNU-coding standards. However, the "dirty spots" are restricted in this * file. The accompanying application backend file (e.g. remote-bdm.c for * gdb) is not affected by this restriction. * * If anybody wants to port to e.g. Sparc, byte-sex has to be handled in * a more general way. */ #include #include #include #include #include #include #include #include #include #include #include #include /* #define SUPPORT_RAMINIT 0 */ /* force ram_init to be loaded */ #define RAMINIT_FILENAME "ram_init" #define RESETINIT_FILENAME "cpu32init" #define END_MACRO 0 #define BEGIN_MACRO 1 #define NO_SUFFIX_MACRO 2 #define BDMLIB_REQUIRED_DRIVER_VERSION 2 /* * version 1 (cannot be accessed by ioctl): release 3/95 * version 2 (includes SENSE ioctl + ICD): release 7/96 */ #ifdef BDMLIB_FORGDB #include "defs.h" #endif #ifndef PROTO /* this is missing in current ansidecl.h - remove it later gm */ #if defined (__STDC__) || defined (_AIX) || (defined (__mips) && defined (_SYSTYPE_SVR4)) #define PROTO(type, name, arglist) type name arglist #define PARAMS(paramlist) paramlist #define ANSI_PROTOTYPES 1 #else /* Not ANSI C. */ #define PROTO(type, name, arglist) type name () #define PARAMS(paramlist) () #endif /* ANSI C. */ #endif #include #include "bdmlib.h" #include "bdm.h" static int bdm_fd; /* default delay for interface */ #define BDM_DEFAULT_DELAY 75 static int bdm_delay=-1; #define BDM_DODPRINTF (1<<0) #define BDM_GOTEXCEPTION (1<<1) #define BDM_DEBUG_NAME "bdm-dbg.log" static int bdm_flags = 0; static int mbar_used = 0; static u_long mbar_default_val = 0; extern char hashmark; extern int bdm_autoreset; extern int bdm_ttcu; static void dbprintf(const char *format, ...); #if !defined BDMLIB_FORGDB /* * this is borrowed from gdb utils.c */ static void error(const char *format, ...) { va_list args; va_start(args, format); vfprintf(stderr, format, args); fprintf(stderr, "\n"); va_end(args); } static void fprintf_filtered(FILE *fp, const char *format, ...) { va_list args; va_start(args, format); vfprintf(fp, format, args); fprintf(fp, "\n"); va_end(args); } #define printf_filtered printf #define xmalloc malloc #define gdb_stderr stderr #endif void bdmlib_setdebug(int switch_on) { if (switch_on) bdm_flags |= BDM_DODPRINTF; else bdm_flags &= ~BDM_DODPRINTF; dbprintf("Setting Debug to %d\n", switch_on); } int bdmlib_querydebug(void) { return (bdm_flags & BDM_DODPRINTF); } /* startofcleanup */ int bdmlib_isopen(void) { return (bdm_fd != 0); } /* filter to put out bdm specific status messages */ char * bdmlib_getstatus_str(bdmstatus status) { int st; static char put_buffer[128]; *put_buffer = '\0'; st = (int) status; if (st < 0) { return bdmlib_geterror_str(status); } if (status & BDM_TARGETNC) { strcat(put_buffer, "NotConnected "); return put_buffer; } strcat(put_buffer, "Connected "); if (status & BDM_TARGETPOWER) { strcat(put_buffer, "PowerFail "); return put_buffer; } strcat(put_buffer, "PowerOK "); if (status & BDM_TARGETSTOPPED) strcat(put_buffer, "Frozen "); else strcat(put_buffer, "Running "); if (status & BDM_TARGETRESET) strcat(put_buffer, "Reset "); return put_buffer; } static struct _err_messages { int err_num; char *err_msg; } err_messages[] = { { BDM_FAULT_UNKNOWN, "bdm driver recognized unknown fault" } , { BDM_FAULT_POWER, "target power failed" } , { BDM_FAULT_CABLE, "cable disconnected" } , { BDM_FAULT_RESPONSE, "no response from target via bdm" } , { BDM_FAULT_RESET, "target got a reset" } , { BDM_FAULT_PORT, "wrong bdm port" } , { BDM_FAULT_BERR, "bus error occured on access via bdm" } , { BDM_FAULT_NVC, "bdm internal error: no valid command to bdm" } , { BDM_NO_ERROR, "No error" } , { BDM_ERR_NOT_OPEN, "bdm device is not open" } , { BDM_ERR_ILL_IOCTL, "ioctl code does not match library ioctl type" } , { BDM_ERR_WRITE_FAIL, "write to processor failed" } , { BDM_ERR_READ_FAIL, "read from processor failed" } , { BDM_ERR_ILL_SIZE, "illegal variable size" } , { BDM_ERR_OPEN, "open error" } , { BDM_ERR_LOAD, "error on loading binary file" } , { BDM_ERR_MACROFILE, "error on loading macro" } , { BDM_ERR_SECTION, "error on loading section" } , { BDM_ERR_VERSION, "driver version conflict" } , }; static int err_msg_len = sizeof(err_messages) / sizeof(struct _err_messages); /* filter to pick out bdm specific error messages */ char * bdmlib_geterror_str(int err) { int i; static char put_buffer[128]; for (i = 0; i < err_msg_len; i++) { if (err == err_messages[i].err_num) return err_messages[i].err_msg; } strncpy(put_buffer, strerror(-err), 128); return put_buffer; } #define do_case(x) case x: ret = #x; break; static char * bdmlib_getioctlname(int ioctl) { char *ret; switch (ioctl) { do_case(BDM_INIT); do_case(BDM_DEINIT); do_case(BDM_RESET_CHIP); do_case(BDM_RESTART_CHIP); do_case(BDM_STOP_CHIP); do_case(BDM_STEP_CHIP); do_case(BDM_GET_STATUS); do_case(BDM_SPEED); do_case(BDM_RELEASE_CHIP); do_case(BDM_DEBUG_LEVEL); do_case(BDM_GET_VERSION); do_case(BDM_SENSECABLE); default: ret = "Unknown ioctl"; } return ret; } int bdmlib_setioctl(u_int code, u_int val) { if (bdmlib_isopen()) { switch (code) { case BDM_SENSECABLE: case BDM_DEBUG_LEVEL: break; case BDM_SPEED: bdm_delay = val; break; default: return BDM_ERR_ILL_IOCTL; } return ioctl(bdm_fd, code, (u_long) val); } else { return BDM_ERR_NOT_OPEN; } } int bdmlib_ioctl(u_int code) { int ret; if (bdmlib_isopen()) { switch (code) { case BDM_INIT: case BDM_RESET_CHIP: case BDM_STOP_CHIP: case BDM_RESTART_CHIP: case BDM_RELEASE_CHIP: case BDM_STEP_CHIP: if ((ret = ioctl(bdm_fd, code, (u_long) NULL)) == -1) { dbprintf("bdmlib_ioctl %s failed; error %d %s\n", bdmlib_getioctlname(code), errno, bdmlib_geterror_str(errno)); return -errno; } else { return BDM_NO_ERROR; } break; default: return BDM_ERR_ILL_IOCTL; } } else { return BDM_ERR_NOT_OPEN; } } /* * get status of interface */ bdmstatus bdmlib_getstatus(void) { if (bdmlib_isopen()) { return ioctl(bdm_fd, BDM_GET_STATUS, NULL); } else { return BDM_ERR_NOT_OPEN; } } int bdmlib_go(void) { u_short buf; int ret; dbprintf("bdmlib_go\n"); #if MORE_DEBUGGING bdmlib_showpc(); #endif /* MORE_DEBUGGING */ if (bdmlib_isopen()) { buf = BDM_GO_CMD; ret = write(bdm_fd, &buf, 2); if ((ret < 0) || (ret != 2)) { dbprintf("bdm_go: write_error %d\n", errno); return -errno; } } else { return BDM_ERR_NOT_OPEN; } return BDM_NO_ERROR; } int bdmlib_set_mbar(u_long mbar_val) { int ret; bdmlib_set_sys_reg(BDM_REG_DFC, 7); bdmlib_set_sys_reg(BDM_REG_SFC, 7); ret = bdmlib_write_var((caddr_t)0x3ff00, BDM_SIZE_LONG, mbar_val); if(ret >= 0){ mbar_used = 1; mbar_default_val = mbar_val; } bdmlib_set_sys_reg(BDM_REG_DFC, 5); bdmlib_set_sys_reg(BDM_REG_SFC, 5); return ret; } int bdmlib_reset(void) { #if SUPPORT_RAMINIT u_long dummy; #endif int ret; dbprintf("bdmlib_reset ttcu %d\n", bdm_ttcu); if ((ret = bdmlib_ioctl(BDM_RESTART_CHIP))) { return ret; } #if MORE_DEBUGGING printf("bdmlib_reset: RESTART_CHIP replies %d %s\n", ret, bdmlib_geterror_str(ret)); printf("status: %s\n", bdmlib_getstatus_str(bdmlib_getstatus())); #endif /* MORE_DEBUGGING */ /* * it cannot break anything to set right SFC and DFC * adress space for memory accesses */ bdmlib_set_sys_reg(BDM_REG_DFC, 5); bdmlib_set_sys_reg(BDM_REG_SFC, 5); /* * The 68360 targets requires setup of MBAR to enable access * to integrated modules and system configuration registers */ if(mbar_used) { bdmlib_set_mbar(mbar_default_val); } /* * in case we have a monitor in place, we might want to let him do * the basic setup, let it come to the prompt... */ if (bdm_ttcu) { if ((ret = bdmlib_go())) /* let the monitor come up.... */ return ret; usleep(bdm_ttcu); ret = bdmlib_ioctl(BDM_STOP_CHIP); } #if SUPPORT_RAMINIT if ((ret = bdmlib_do_load_binary(RAMINIT_FILENAME, &dummy)) < 0) { fprintf_filtered(gdb_stderr, "Warning: %s for file `%s'\n", bdmlib_geterror_str(ret), RAMINIT_FILENAME); } #endif /* SUPPORT_RAMINIT */ bdmlib_do_load_macro(RESETINIT_FILENAME, NO_SUFFIX_MACRO); fprintf(stdout, "\r"); fflush(stdout); return ret; } #define swaps(x) \ ((u_short)((((u_short)(x) & 0x00ff) << 8) | \ (((u_short)(x) & 0xff00) >> 8))) #define swapl(x) \ ((u_int)((((u_int)(x) & 0x000000ffU) << 24) | \ (((u_int)(x) & 0x0000ff00U) << 8) | \ (((u_int)(x) & 0x00ff0000U) >> 8) | \ (((u_int)(x) & 0xff000000U) >> 24))) static u_short * bdmlib_conv_short_to_buf(u_short * buf, u_short val, int endianness) { if (endianness) { *buf++ = swaps(val); } else { *buf++ = val; } return buf; } /* conv long in host format (little endian) to buf (target format = big e) */ static u_short * bdmlib_conv_long_to_buf(u_short * buf, u_long val, int endianness) { if (endianness) { *buf++ = swaps(val & 0xffff); *buf++ = swaps(val >> 16); } else { *buf++ = val >> 16; *buf++ = val & 0xffff; } return buf; } /* buf representation to a single short */ static u_short * bdmlib_conv_buf_to_short(u_short * buf, u_short * val, int endianness) { if (endianness) { *val = *buf++; } else { *val = swaps(*buf); buf++; } return buf; } /* buf representation to a single long */ static u_short * bdmlib_conv_buf_to_long(u_short * buf, u_long * val, int endianness) { if (endianness) { *val = (buf[0] << 16) | buf[1]; } else { *val = (swaps(buf[1]) << 16) | swaps(buf[0]); } buf += 2; return buf; } /* * put a char stream of 4 bytes into a long; * endianness=0: interprete char as little end * else interprete char as big endian */ static u_char * bdmlib_conv_char_to_long(u_char * buf, u_long * val, int endianness) { int i; union { u_long l; u_char c[4]; } u; if (endianness) { for (i = 3; i >= 0; i--) u.c[i] = *buf++; } else { for (i = 0; i < 4; i++) u.c[i] = *buf++; } *val = u.l; return buf; } /* put a char stream of 2 bytes into a short */ static u_char * bdmlib_conv_char_to_short(u_char * buf, u_short * val, int endianness) { int i; union { u_short s; u_char c[2]; } u; if (endianness) { for (i = 1; i >= 0; i--) u.c[i] = *buf++; } else { for (i = 0; i < 2; i++) u.c[i] = *buf++; } *val = u.s; return buf; } /* put a long to a char stream */ static u_char * bdmlib_conv_long_to_char(u_char * buf, u_long val, int endianness) { int i; union { u_long l; u_char c[4]; } u; u.l = val; if (endianness) { for (i = 3; i >= 0; i--) *buf++ = u.c[i]; } else { for (i = 0; i < 4; i++) *buf++ = u.c[i]; } return buf; } /* put a short to a char stream */ static u_char * bdmlib_conv_short_to_char(u_char * buf, u_short val, int endianness) { int i; union { u_short s; u_char c[2]; } u; u.s = val; if (endianness) { for (i = 1; i >= 0; i--) *buf++ = u.c[i]; } else { for (i = 0; i < 2; i++) *buf++ = u.c[i]; } return buf; } int bdmlib_get_sys_reg(u_int reg, u_int * ret_val) { u_short send; u_short recv[2]; int ret; send = BDM_RSREG_CMD | (reg & 0xf); if (!bdmlib_isopen()) return BDM_ERR_NOT_OPEN; ret = write(bdm_fd, &send, 2); if (ret == 2) { ret = read(bdm_fd, recv, 4); } else { dbprintf("bdmlib_get_sys_reg error on send: errno %d\n", errno); return -errno; } bdmlib_conv_buf_to_long(recv, (u_long *) ret_val, 0); return (ret == 4) ? BDM_NO_ERROR : -errno; } int bdmlib_set_sys_reg(u_int reg, u_int cont) { u_short send[3]; int ret; if (!bdmlib_isopen()) return BDM_ERR_NOT_OPEN; send[0] = BDM_WSREG_CMD | (reg & 0xf); bdmlib_conv_long_to_buf(&send[1], cont, 0); if ((ret = write(bdm_fd, send, 6)) != 6) { dbprintf("bdmlib_set_sys_reg error: reg %#x cont %#x error %d\n", reg, cont, errno); return -errno; } return BDM_NO_ERROR; } int bdmlib_get_reg(u_int reg, u_int * ret_val) { u_short send; u_short recv[2]; int ret; if (!bdmlib_isopen()) return BDM_ERR_NOT_OPEN; send = BDM_RREG_CMD | (reg & 0xf); ret = write(bdm_fd, &send, 2); if (ret == 2) { ret = read(bdm_fd, recv, 4); } else { dbprintf("bdmlib_get_reg: error on send ret %d\n", errno); return -errno; } /* get target format, as conversion will be done in higher levels */ bdmlib_conv_buf_to_long(recv, (u_long *) ret_val, 0); return (ret == 4) ? BDM_NO_ERROR : -errno; } int bdmlib_set_reg(u_int reg, u_int cont) { u_short send[3]; int ret; if (!bdmlib_isopen()) return BDM_ERR_NOT_OPEN; send[0] = BDM_WREG_CMD | (reg & 0xf); bdmlib_conv_long_to_buf(&send[1], cont, 0); if ((ret = write(bdm_fd, send, 6)) != 6) { dbprintf("bdmlib_set_reg error: reg %#x to cont %#x error %#d\n", reg, cont, errno); return -errno; } return BDM_NO_ERROR; } int bdmlib_write_var(caddr_t adr, u_short size, u_int val) { u_short buf[6], *b_ptr = buf; int w_buf_len, r_buf_len; int written; dbprintf("bdmlib_write_var: addr %#x cont %#x\n", adr, val); if (!bdmlib_isopen()) return BDM_ERR_NOT_OPEN; size &= 0x00c0; *b_ptr++ = (BDM_WRITE_CMD | size); /* no need for byte swapping, as adr is already a valid long; so use 0 */ b_ptr = bdmlib_conv_long_to_buf(b_ptr, (u_long) adr, 0); switch (size) { case BDM_SIZE_LONG: b_ptr = bdmlib_conv_long_to_buf(b_ptr, val, 0); w_buf_len = 5; break; case BDM_SIZE_WORD: b_ptr = bdmlib_conv_short_to_buf(b_ptr, val, 0); w_buf_len = 4; break; case BDM_SIZE_BYTE: *b_ptr++ = (u_short) (val & 0xff); w_buf_len = 4; break; default: w_buf_len = 0; dbprintf("error! bdmlib_write_var: unknown size %#x\n", size); return BDM_ERR_ILL_SIZE; } if ((written = write(bdm_fd, buf, w_buf_len * 2)) != w_buf_len * 2) { dbprintf("error! bdmlib_write_var: write returns %d errno %d\n", written, errno); written = errno; } if ((r_buf_len = read(bdm_fd, buf, 2)) != 2) { dbprintf( "bdmlib_write_var: verify read return val expected 2 is %d errno %d\n", r_buf_len, errno); return -errno; } if (written == (w_buf_len*2)) { return BDM_NO_ERROR; } else { return -written; } } #if 1 /* slower but reliable method for writting, main solved problem is waiting for ready after memory access achieved by read in bdm_write_var */ int bdmlib_write_block(caddr_t in_adr, u_int size, u_char * bl_ptr) { u_short buf[8]; int fills, got_size = 0; u_long ul; u_short us; u_char uc; u_int first_acc; dbprintf("bdmlib_write_block size %#x to adr %#x ", size, in_adr); first_acc = 4 - ((u_long) in_adr & 0x3); if (size < first_acc) { switch (size) { case 0: return 0; case 1: first_acc = 1; break; case 2: case 3: first_acc = first_acc&1? 1: 2; break; } } switch (first_acc) { case 4: bl_ptr = bdmlib_conv_char_to_long(bl_ptr, &ul, 1); if (bdmlib_write_var(in_adr, BDM_SIZE_LONG, ul) < 0) { return got_size; } got_size += 4; break; case 3: uc = *bl_ptr++; if (bdmlib_write_var(in_adr, BDM_SIZE_BYTE, uc) < 0) { return got_size; } in_adr += 1; got_size += 1; /* fall through to 'word' */ case 2: bl_ptr = bdmlib_conv_char_to_short(bl_ptr, &us, 1); if (bdmlib_write_var(in_adr, BDM_SIZE_WORD, us) < 0) { return got_size; } got_size += 2; break; case 1: uc = *bl_ptr++; if (bdmlib_write_var(in_adr, BDM_SIZE_BYTE, uc) < 0) { return got_size; } got_size += 1; break; default: ; /* cannot happen */ } buf[0] = BDM_FILL_CMD | BDM_SIZE_LONG; fills = (size - got_size) / 4; while (fills--) { bl_ptr = bdmlib_conv_char_to_long(bl_ptr, &ul, 1); bdmlib_conv_long_to_buf(&buf[1], ul, 0); if (write(bdm_fd, &buf[0], 6) !=6) { return got_size; } if (read(bdm_fd, &buf[1], 2) != 2) { return got_size; } got_size += 4; } if (size - got_size >= 2) { buf[0] = (BDM_FILL_CMD | BDM_SIZE_WORD); bl_ptr = bdmlib_conv_char_to_short(bl_ptr, &us, 1); bdmlib_conv_short_to_buf(&buf[1], us, 0); if(write(bdm_fd, &buf[0], 4)!=4) return got_size; if (read(bdm_fd, &buf[0], 2) != 2) return got_size; got_size += 2; } if (size - got_size) { buf[0] = (BDM_FILL_CMD | BDM_SIZE_BYTE); buf[1] = *bl_ptr++; if(write(bdm_fd, &buf[0], 4)!=4) return got_size; if (read(bdm_fd, &buf[0], 2) != 2) return got_size; got_size += 1; } if (size - got_size) { /* cannot happen */ error("internal error: bdmlib_write_block - cannot happen"); } return got_size; } #else int bdmlib_write_block(caddr_t in_adr, u_int size, u_char * block) { u_short *buf, *buf_ptr; int buf_len = 0; /* valid len of buf to writecmd in shorts */ u_char *bl_ptr; u_int adr; int fills, put_size; u_long ul; u_short us; u_int first_acc; dbprintf("bdmlib_write_block size %#x to adr %#x\n", size, in_adr); if (!bdmlib_isopen()) return BDM_ERR_NOT_OPEN; first_acc = 4 - ((u_long) in_adr & 0x3); if (size < first_acc) { switch (size) { case 0: return 0; case 1: first_acc = 1; break; case 2: case 3: first_acc = first_acc&1? 1: 2; break; } } put_size = size; adr = (u_int) in_adr; bl_ptr = block; buf_ptr = buf = xmalloc((size / 4 + 5) * 6); /* * per 4 bytes 3 shorts for fill-long-cmd * + 3 short for initial write-long-cmd + addr * = 1 * 3 shorts * + worst case both a write-byte and write-short on begin & end * = 4 * 3 shorts */ switch (first_acc) { case 4: *buf_ptr++ = (BDM_WRITE_CMD | BDM_SIZE_LONG); *buf_ptr++ = (adr & 0xffff0000) >> 16; /* h-Address */ *buf_ptr++ = (adr & 0x0000ffff); /* l-Address */ bl_ptr = bdmlib_conv_char_to_long(bl_ptr, &ul, 1); buf_ptr = bdmlib_conv_long_to_buf(buf_ptr, ul, 0); adr += 4; size -= 4; buf_len = 5; break; case 3: *buf_ptr++ = (BDM_WRITE_CMD | BDM_SIZE_BYTE); *buf_ptr++ = (adr & 0xffff0000) >> 16; /* h-Address */ *buf_ptr++ = (adr & 0x0000ffff); /* l-Address */ *buf_ptr++ = *bl_ptr++; adr += 1; size -= 1; buf_len = 4; /* fall through to 'word' */ case 2: *buf_ptr++ = (BDM_WRITE_CMD | BDM_SIZE_WORD); *buf_ptr++ = (adr & 0xffff0000) >> 16; /* h-Address */ *buf_ptr++ = (adr & 0x0000ffff); /* l-Address */ bl_ptr = bdmlib_conv_char_to_short(bl_ptr, &us, 1); buf_ptr = bdmlib_conv_short_to_buf(buf_ptr, us, 0); adr += 2; size -= 2; buf_len += 4; break; case 1: *buf_ptr++ = (BDM_WRITE_CMD | BDM_SIZE_BYTE); *buf_ptr++ = (adr & 0xffff0000) >> 16; /* h-Address */ *buf_ptr++ = (adr & 0x0000ffff); /* l-Address */ *buf_ptr++ = *bl_ptr++; adr += 1; size -= 1; buf_len = 4; break; default: /* cannot happen */ } fills = size / 4; size -= fills * 4; buf_len += (fills * 3); while (fills--) { *buf_ptr++ = (BDM_FILL_CMD | BDM_SIZE_LONG); bl_ptr = bdmlib_conv_char_to_long(bl_ptr, &ul, 1); buf_ptr = bdmlib_conv_long_to_buf(buf_ptr, ul, 0); } if(size>=2){ *buf_ptr++ = (BDM_FILL_CMD | BDM_SIZE_WORD); bl_ptr = bdmlib_conv_char_to_short(bl_ptr, &us, 1); buf_ptr = bdmlib_conv_short_to_buf(buf_ptr, us, 0); buf_len += 2; size -= 2; } if(size>=1){ *buf_ptr++ = (BDM_FILL_CMD | BDM_SIZE_BYTE); *buf_ptr++ = *bl_ptr; buf_len += 2; size--; } if(size){ error("internal error: bdmlib_write_block: size=%d!=0",size); } /* now we have a whole buf we can send in one chunk to 'write' */ buf_len *= 2; /* now buflen in bytes */ if ((size = write(bdm_fd, buf, buf_len)) != buf_len) { dbprintf("error! bdmlib_write_block: write %d returns %d errno %d %s\n", buf_len, size, errno, bdmlib_geterror_str(-errno)); put_size = 0; } /* * FIXME: needs more persistence on trying to write; analyze reason * for not writing, and if possible, try again with rest of the buf * give up on detected bus-err */ free(buf); return put_size; } #endif /* return format in *val is target byte ordering */ int bdmlib_read_var(caddr_t adr, u_short size, void *val) { u_short buf[6], *b_ptr = buf; int count; /* u_char *cptr; u_short *sptr; u_long *lptr; */ dbprintf("bdmlib_read_var size %#x from adr %#x ", size, adr); if (!bdmlib_isopen()) return BDM_ERR_NOT_OPEN; size &= 0x00c0; *b_ptr++ = (BDM_READ_CMD | size); /* no need for byte swapping, as adr is already a valid long; so use 0 */ b_ptr = bdmlib_conv_long_to_buf(b_ptr, (u_long) adr, 0); if ((count = write(bdm_fd, buf, 6)) != 6) { dbprintf("bdmlib_read_var error: write returns %d\n", count); return BDM_ERR_WRITE_FAIL; } switch (size) { case BDM_SIZE_LONG: if ((count = read(bdm_fd, buf, 4)) == 4) { *(u_long *) val = (buf[0] << 16) | buf[1]; } break; case BDM_SIZE_WORD: if ((count = read(bdm_fd, buf, 2)) == 2) { *(u_short *) val = (u_short) buf[0]; /* sptr = (u_short*) val; *sptr = (u_short) buf[0]; */ } break; case BDM_SIZE_BYTE: if ((count = read(bdm_fd, buf, 2)) == 2) { count = 1; *(u_char *) val = (u_char) (buf[0] & 0xff); /* cptr = (u_char*)val; *cptr = (u_char) (buf[0] & 0xff); */ } break; default: dbprintf("\n\terror! bdmlib_read_var: unknown size %#x\n", size); } if (count < 0) { dbprintf("\nerror %d (%s)\n", errno, bdmlib_geterror_str(errno)); return -errno; } /* val = (u_int*) ((u_long)val & ~3); */ dbprintf(" cont %#x\n", *(u_long *) ((long) val & ~3)); return count; /* _must_ return count */ } int bdmlib_read_block(caddr_t in_adr, u_int size, u_char * bl_ptr) { u_short buf[8]; u_short dump_cmd; int dumps, got_size = 0; u_long ul; u_short us; u_char uc; u_int first_acc; dbprintf("bdmlib_read_block size %#x from adr %#x ", size, in_adr); first_acc = 4 - ((u_long) in_adr & 0x3); if (size < first_acc) { switch (size) { case 0: return 0; case 1: first_acc = 1; break; case 2: case 3: first_acc = first_acc&1? 1: 2; break; } } switch (first_acc) { case 4: if (bdmlib_read_var(in_adr, BDM_SIZE_LONG, &ul) != 4) { return got_size; } bl_ptr = bdmlib_conv_long_to_char(bl_ptr, ul, 1); got_size += 4; break; case 3: if (bdmlib_read_var(in_adr, BDM_SIZE_BYTE, &uc) != 1) { return got_size; } *bl_ptr++ = uc; got_size += 1; in_adr += 1; /* fall through to 'word' */ case 2: if (bdmlib_read_var(in_adr, BDM_SIZE_WORD, &us) != 2) { return got_size; } bl_ptr = bdmlib_conv_short_to_char(bl_ptr, us, 1); got_size += 2; break; case 1: if (bdmlib_read_var(in_adr, BDM_SIZE_BYTE, &uc) != 1) { return got_size; } *bl_ptr++ = uc; got_size += 1; break; default: ; /* cannot happen */ } dump_cmd = BDM_DUMP_CMD | BDM_SIZE_LONG; dumps = (size - got_size) / 4; while (dumps--) { write(bdm_fd, &dump_cmd, 2); if (read(bdm_fd, &buf, 4) != 4) { return got_size; } bdmlib_conv_buf_to_long(buf, &ul, 1); bl_ptr = bdmlib_conv_long_to_char(bl_ptr, ul, 1); got_size += 4; } if (size - got_size >= 2) { dump_cmd = BDM_DUMP_CMD | BDM_SIZE_WORD; write(bdm_fd, &dump_cmd, 2); if (read(bdm_fd, &buf, 2) != 2) { return got_size; } bdmlib_conv_buf_to_short(buf, &us, 1); bl_ptr = bdmlib_conv_short_to_char(bl_ptr, us, 1); got_size += 2; } if (size - got_size) { dump_cmd = BDM_DUMP_CMD | BDM_SIZE_BYTE; write(bdm_fd, &dump_cmd, 2); if (read(bdm_fd, &buf, 2) != 2) { return got_size; } *bl_ptr++ = *buf & 0xff; got_size += 1; } if (size - got_size) { /* cannot happen */ error("internal error: bdmlib_read_block - cannot happen"); } return got_size; } void bdmlib_propeller(u_long addr, FILE * fp) { static char *str = "\\|/-"; static int index; if (!hashmark) return; fprintf(fp, "%c 0x%08lx\b\b\b\b\b\b\b\b\b\b\b\b", str[index++], addr); fflush(fp); index %= 4; } /* * Open a connection the target via bdm * name is the devicename of bdm and the filename to be used * used for communication. */ int bdmlib_open(char *name) { int ret; int version; if (bdmlib_isopen()) { dbprintf("bdmlib_open: tried to open twice\n"); return BDM_ERR_OPEN; } if ((bdm_fd = open(name, O_RDWR)) < 0) { dbprintf( "bdmlib_open: Warning trouble on opening %s: reply %d errno %d\n", name, bdm_fd, errno); fprintf(stderr, "Warning: trouble on opening %s: %s\n", name, bdmlib_geterror_str(-errno)); bdm_fd = 0; /* mark unused */ return BDM_FAULT_PORT; } bdmlib_ioctl(BDM_INIT); if (bdm_delay>=0) { /* delay has been set before */ bdmlib_setioctl(BDM_SPEED, bdm_delay); } else { bdmlib_setioctl(BDM_SPEED, BDM_DEFAULT_DELAY); } if (((ret = ioctl(bdm_fd, BDM_GET_VERSION, (u_long) &version)) < 0) || (version < BDMLIB_REQUIRED_DRIVER_VERSION)) { if (ret < 0) version = 1; fprintf(stderr, "Error:\tBDM device driver version conflict.\n"); fprintf(stderr, "\tyou need at least version %d, currently installed is version %d.\n", BDMLIB_REQUIRED_DRIVER_VERSION, version); fprintf(stderr, "\tAborting operation\n"); close(bdm_fd); return BDM_ERR_VERSION; } return BDM_NO_ERROR; } int bdmlib_close(quitting) int quitting; { dbprintf("bdmlib_close: quitting %d\n", quitting); if (quitting) { bdmlib_reset(); bdmlib_ioctl(BDM_RELEASE_CHIP); } close(bdm_fd); bdm_fd = 0; return BDM_NO_ERROR; } #define swap_l(x) (x>>24) | ((x>>8)&0xff00) | ((x<<8)&0xff0000) | ((x&0xff)<<24) void bdmlib_showpc(void) { u_int sr, usp, ssp, vbr; u_int pcc, rpc, a7; bdmlib_get_sys_reg(BDM_REG_SR, &sr); bdmlib_get_sys_reg(BDM_REG_USP, &usp); bdmlib_get_reg(BDM_REG_A7, &a7); bdmlib_get_sys_reg(BDM_REG_SSP, &ssp); printf(" SR: %9x USP: %9x A7: %9x SSP: %9x\n", swap_l(sr), swap_l(usp), swap_l(a7), swap_l(ssp)); bdmlib_get_sys_reg(BDM_REG_PCC, &pcc); bdmlib_get_sys_reg(BDM_REG_RPC, &rpc); bdmlib_get_sys_reg(BDM_REG_VBR, &vbr); printf("PCC: %9x RPC: %9x VBR: %9x\n", swap_l(pcc), swap_l(rpc), swap_l(vbr)); } #define LINE_LEN 256 static char * get_line(FILE * f, int *line_nr) { static char line_buf[LINE_LEN]; while (!feof(f)) { fgets(line_buf, LINE_LEN, f); (*line_nr)++; if (line_buf[0] == '#') continue; if (line_buf[0] == '\n') continue; if (line_buf[0] == '\0') continue; return line_buf; } return NULL; } /* * retval is just if we found the macro file, no errors! */ int bdmlib_do_load_macro(char *file_name, int which_suffix) { char m_name[256]; FILE *m_file; char *lptr; char cmd; int line_nr, ret, size; bfd_vma addr1, addr2; short size_tag; u_char *buf; int errorcount = 0; char * begin_suffix = ".bdmmb", *end_suffix = ".bdmme", *no_suffix = ""; char * suffix; dbprintf("bdmlib_do_load_macro %s suffix %d\n", file_name, which_suffix); strcpy(m_name, file_name); if ((lptr = rindex(m_name, '.')) != 0) { *lptr = '\0'; } switch (which_suffix) { case BEGIN_MACRO: suffix = begin_suffix; break; case END_MACRO: suffix = end_suffix; break; case NO_SUFFIX_MACRO: suffix = no_suffix; break; default: suffix = no_suffix; } strcat(m_name, suffix); if ((m_file = fopen(m_name, "r")) == NULL) { dbprintf("\tno macro file found\n"); return BDM_ERR_MACROFILE; /* no macro file available, quit silently */ } if (!(bdmlib_getstatus() & BDM_TARGETSTOPPED)) { dbprintf("\twarning: chip needs stopping\n"); bdmlib_ioctl(BDM_STOP_CHIP); } line_nr = 0; while ((lptr = get_line(m_file, &line_nr))) { cmd = *lptr++; addr1 = strtoul (lptr, &lptr, 0); addr2 = strtoul (lptr, &lptr, 0); size = strtol (lptr, &lptr, 0); bdmlib_propeller(addr1, stdout); switch (toupper(cmd)) { case 'W': dbprintf("\twrite to addr %#x cont %#x size %d\n", addr1, addr2, size); switch (size) { case 1: size_tag = BDM_SIZE_BYTE; size = 8; break; case 2: size_tag = BDM_SIZE_WORD; size = 8; break; case 4: size_tag = BDM_SIZE_LONG; size = 10; break; default: error("\ Error in processing macro %s line %d 'W' command:\n\t\ size must be either 1,2,4 bytes, '%d' is not allowed", m_name, line_nr, size); continue; } if ((ret = bdmlib_write_var((caddr_t) addr1, size_tag, (u_int) addr2)) < 0) { errorcount++; dbprintf("\ Error in processing macro %s line %d 'W' command:\n\t\ bdm_write size mismatch: send %d returned %d errno %d", m_name, line_nr, size, ret, errno); } break; case 'C': dbprintf("\tcopy from %#x to %#x size %d\n", addr1, addr2, size); buf = xmalloc(size); if ((ret = bdmlib_read_block((caddr_t) addr1, size, buf)) != size) { errorcount++; error("\ Error in processing macro %s line %d 'C' command:\n\t\ bdm_copy size mismatch on read from %#x: wanted %d got %d", m_name, line_nr, addr1, size, ret); } else { { int i; for (i = 0; i < size; i++) { if (!(i % 16)) printf("\n0x%08X: ", (unsigned int) addr1 + i); printf("0x%02X ", buf[i]); } printf("\n"); } if ((ret = bdmlib_write_block((caddr_t) addr2, size, buf)) != size) { errorcount++; error("\ Error in processing macro %s line %d 'C' command:\n\t\ bdm_copy size mismatch on write to %#x: wanted %d got %d", m_name, line_nr, addr2, size, ret); } } free(buf); break; case 'Z': dbprintf("\tzero from %#x with %#x size %#x\n", addr1, addr2 & 0xff, size); buf = xmalloc(size); memset(buf, addr2, size); if ((ret = bdmlib_write_block((caddr_t) addr1, size, buf)) != size) { errorcount++; error("\ Error in processing macro %s line %d 'Z' command:\n\t\ bdm_set size mismatch on write to %#x: wanted %d got %d", m_name, line_nr, addr1, size, ret); } free(buf); break; case 'M': dbprintf("\tMBAR setup to %#x\n", addr1); if ((ret = bdmlib_set_mbar((u_long) addr1))) { errorcount++; error("\ Error in processing macro %s line %d 'M' command:\n\t\ MBAR set returned %d", m_name, line_nr, ret); } break; #if DEBUGGING_MACROS case 'T': { int i; buf = xmalloc(size); for (i = 0; i < size; i++) buf[i] = i; bdmlib_write_block(addr1, size, buf); free(buf); } break; #endif /* DEBUGGING_MACROS */ default: dbprintf("\tcmd %c unknown\n", cmd); } } if (hashmark) { printf(" \b\b\b\b\b\b\b\b\b\b\b\b"); fflush(stdout); } if(m_file) fclose(m_file); dbprintf("\tfinished macro. errorcount %d\n", errorcount); return 0; /* * dont give back errorcount, errors will show up on binary * download also. */ } bdmlib_bfilt_t * bdmlib_bfilt=NULL; int bdmlib_wrb_filt(bdmlib_bfilt_t * filt, caddr_t in_adr, u_int size, u_char * bl_ptr) { int ret, part_ret; u_int part_size; if (!size) return 0; while (filt) { if((in_adr<=filt->end_adr)&& (in_adr+size-1>=filt->begin_adr)) { ret = 0; if(in_adrbegin_adr) { part_size=filt->begin_adr-in_adr; part_ret=bdmlib_wrb_filt(filt->next,in_adr,part_size,bl_ptr); ret+=part_ret; if(part_ret!=part_size) return ret; in_adr+=part_size; bl_ptr+=part_size; size-=part_size; } part_size=filt->end_adr-in_adr+1; if (part_size>=size) { part_size=size; size=0; } else size-=part_size; part_ret=filt->wrb_filt(filt,in_adr,part_size,bl_ptr); ret+=part_ret; if(part_ret!=part_size) { dbprintf("write error on filt write, address 0x%lx size %d acknowledged %d errno %d\n", (long)in_adr, part_size, part_ret, errno); return ret; } in_adr+=part_size; bl_ptr+=part_size; if(!size) return ret; ret+=bdmlib_wrb_filt(filt->next,in_adr,size,bl_ptr); return ret; } filt=filt->next; } /* regular memory block write */ if ((ret = bdmlib_write_block(in_adr, size, bl_ptr)) != size) { dbprintf("write error on block write, written %d acknowledged %d errno %d\n", size, ret, errno); return ret; } return ret; } int bdmlib_load_use_lma=0; static int load_section_error; static void bdmlib_load_section(bfd * abfd, sec_ptr sec, PTR ignore) { u_long addr; u_long dfc; u_long load_bytes; file_ptr offset; int ret, cnt; char cbuf[512]; dbprintf("bdmlib_load_section:\n\tsection %s index %d\n", sec->name, sec->index); dbprintf("\tflags %#x raw_size 0x%08lx cooked_size 0x%08lx\n", sec->flags, (long)bfd_get_section_limit(abfd, sec), (long)bfd_get_section_size(sec)); dbprintf("\tvma %#x lma %#x output_offset %#x\n", sec->vma, sec->lma, sec->output_offset); if ((load_section_error < 0) || ((bfd_get_section_flags(abfd, sec) & SEC_LOAD) == 0)) { return; } if (bfd_get_section_flags(abfd, sec) & SEC_CODE) dfc = 0x6; /* Supervisor program space */ else dfc = 0x5; /* Supervisor data space */ if ((ret = bdmlib_set_sys_reg(BDM_REG_DFC, dfc)) < 0) { load_section_error = ret; return; } if(!bdmlib_load_use_lma) addr = bfd_section_vma(abfd, sec); else addr = bfd_section_lma(abfd, sec); /* there used to be bfd_get_section_size_before_reloc() */ if ((load_bytes = bfd_section_size(abfd,sec)) == 0) return; offset = 0; while (load_bytes) { if (load_bytes > sizeof(cbuf)) { cnt = sizeof(cbuf); } else { cnt = load_bytes; } if (!bfd_get_section_contents(abfd, sec, cbuf, offset, cnt)) { dbprintf("read error section %s\n", sec->name); load_section_error = BDM_ERR_LOAD; return; } if ((ret = bdmlib_wrb_filt(bdmlib_bfilt,(caddr_t) addr, cnt, cbuf)) != cnt) { dbprintf("write error on block write, written %d acknowledged %d errno %d\n", cnt, ret, errno); load_section_error = BDM_ERR_LOAD; return; } load_bytes -= cnt; addr += cnt; offset += cnt; bdmlib_propeller(addr, stdout); } } static int bfd_initialized; static bfd * prepare_binary(char *file_name) { bfd *abfd; if (!bfd_initialized) { bfd_init(); bfd_initialized = 1; } abfd = bfd_openr(file_name, 0); if (!abfd) { dbprintf("Unable to open file %s\n", file_name); return NULL; } if (bfd_check_format(abfd, bfd_object) == 0) { dbprintf("File %s is not an object file\n", file_name); bfd_close(abfd); return NULL; } return abfd; } /* * load a binary file, returns error codes */ int bdmlib_do_load_binary(char *file_name, char *entry_name, u_long *entry_pt) { bfd *abfd; int ret; u_long entry_addr = 0; if ((abfd = prepare_binary(file_name)) == NULL) return BDM_ERR_OPEN; if (entry_name) while (isspace(*entry_name)) entry_name++; if (entry_name && isdigit(*entry_name)) { entry_addr = strtoul (entry_name, NULL, 0); } else if (entry_name) { long i, symcnt; asymbol **symtab; if ((i=bfd_get_symtab_upper_bound(abfd))<=0 || !(symtab=malloc(i))) return BDM_ERR_OPEN; if ((symcnt = bfd_canonicalize_symtab (abfd, symtab))<0) return BDM_ERR_OPEN; for (i=0; iname)) { entry_addr = symtab[i]->section->vma + symtab[i]->value; break; } } } else { entry_addr = bfd_get_start_address(abfd); } if(entry_pt) *entry_pt = entry_addr; load_section_error = BDM_NO_ERROR; if (!(bdmlib_getstatus() & BDM_TARGETSTOPPED) && ((ret = bdmlib_ioctl(BDM_STOP_CHIP)))) { dbprintf("bdmlib_do_load_binary: %d %s\n", errno, bdmlib_geterror_str(-errno)); return -errno; } bfd_map_over_sections(abfd, bdmlib_load_section, NULL); if (hashmark) { printf(" . \b\b\b\b\b\b\b\b\b\b\b\b"); fflush(stdout); } bfd_close(abfd); return load_section_error; } int bdmlib_do_load_binary_section(char *file_name, char *section_name) { bfd *abfd; asection *sec; int ret; if ((abfd = prepare_binary(file_name)) == NULL) return BDM_ERR_OPEN; if ((sec = bfd_get_section_by_name(abfd, section_name)) == NULL) return BDM_ERR_SECTION; load_section_error = BDM_NO_ERROR; if (!(bdmlib_getstatus() & BDM_TARGETSTOPPED) && ((ret = bdmlib_ioctl(BDM_STOP_CHIP)))) { dbprintf("bdmlib_do_load_binary: %d %s\n", errno, bdmlib_geterror_str(-errno)); return -errno; } if (hashmark) { printf(" "); fflush(stdout); } bdmlib_load_section(abfd, sec, NULL); if (hashmark) { printf("\r \r"); fflush(stdout); } bfd_close(abfd); return load_section_error; } /* * Load a file. * This is supposed to be coff here, but bfd should handle other formats... * * use a macro for target specific manipulations, eg. setting * chipselect, switching memory banks, etc. */ int bdmlib_load(char *file, char *entry_name, u_long * entry_pt) { int ret = 0; u_int sfc, dfc; int we_have_macro_files = 0; #if SUPPORT_RAMINIT u_long dummy; #endif if (!bdmlib_isopen()) return BDM_ERR_NOT_OPEN; dbprintf("bdmlib_load: program name %s\n", file); if (bdm_autoreset) bdmlib_reset(); if (!(bdmlib_getstatus() & BDM_TARGETSTOPPED)) if ((ret = bdmlib_ioctl(BDM_STOP_CHIP))) { fprintf_filtered(gdb_stderr, "%s", bdmlib_geterror_str(ret)); error("Download failed\n"); return ret; /* this is for non-gdb applications */ } bdmlib_set_sys_reg(BDM_REG_DFC, 5); if ((ret = bdmlib_set_sys_reg(BDM_REG_SFC, 5)) < 0) { return ret; } bdmlib_get_sys_reg(BDM_REG_DFC, &dfc); bdmlib_get_sys_reg(BDM_REG_SFC, &sfc); dbprintf("\tDFC %x SFC %x\n", dfc, sfc); we_have_macro_files = !bdmlib_do_load_macro(file, BEGIN_MACRO); #if SUPPORT_RAMINIT if ((ret = bdmlib_do_load_binary(RAMINIT_FILENAME, &dummy)) < 0) { error("ram_init load error.\n"); } #endif /* SUPPORT_RAMINIT */ if ((ret = bdmlib_do_load_binary(file, entry_name, entry_pt)) < 0) { error("Download failed."); return ret; } if (we_have_macro_files) bdmlib_do_load_macro(file, END_MACRO); return BDM_NO_ERROR; } static FILE *debug_fp; static int open_debug(void) { if ((debug_fp = fopen(BDM_DEBUG_NAME, "w")) == NULL) { perror("bdm-dbprintf"); fprintf_filtered(gdb_stderr, "bdm: opening debug %s\n", BDM_DEBUG_NAME); return -1; } return 0; } /* debug printf for Log-file */ void dbprintf(const char *format, ...) { va_list ap; if (bdm_flags & BDM_DODPRINTF) { if ((!debug_fp) && open_debug()) return; va_start(ap, format); vfprintf(debug_fp, format, ap); fflush(debug_fp); va_end(ap); } else if (debug_fp) { fclose(debug_fp); debug_fp = NULL; } } void bdmlib_log(const char *format, ...) { va_list ap; /* * this would normally call dbprintf(); however it seems not possible * to do nested varargs calls.... */ if (bdm_flags & BDM_DODPRINTF) { if ((!debug_fp) && open_debug()) return; va_start(ap, format); fprintf(debug_fp, "%s: ", #if defined BDMLIB_FORGDB "GDB" #elif defined BDMLIB_FORFLT "FLT" #else "???" #endif ); vfprintf(debug_fp, format, ap); fflush(debug_fp); va_end(ap); } else if (debug_fp) { fclose(debug_fp); debug_fp = NULL; } }