diff --git a/src/platforms/hosted/Makefile.inc b/src/platforms/hosted/Makefile.inc index 139c9cf..656f450 100644 --- a/src/platforms/hosted/Makefile.inc +++ b/src/platforms/hosted/Makefile.inc @@ -1,21 +1,35 @@ SYS = $(shell $(CC) -dumpmachine) CFLAGS += -DENABLE_DEBUG -DPLATFORM_HAS_DEBUG CFLAGS +=-I ./target -I./platforms/pc -LDFLAGS += -lusb-1.0 -CFLAGS += $(shell pkg-config --cflags libftdi1) -LDFLAGS += $(shell pkg-config --libs libftdi1) -ifneq (, $(findstring mingw, $(SYS))) + +ifneq (, $(findstring linux, $(SYS))) +SRC += serial_unix.c +CFLAGS += -fsanitize=address +LDFLAGS += -lasan +else ifneq (, $(findstring mingw, $(SYS))) SRC += serial_win.c LDFLAGS += -lws2_32 +LDFLAGS += -lhid -lsetupapi else ifneq (, $(findstring cygwin, $(SYS))) SRC += serial_win.c LDFLAGS += -lws2_32 -else -SRC += serial_unix.c +LDFLAGS += -lhid -lsetupapi +#https://github.com/dmlc/xgboost/issues/1945 indicates macosx as indicator +else ifneq (filter, macosx darwin, $(SYS))) +LDFLAGS += -lhid -lsetupapi +LDFLAGS += hidapi/mac/.libs/libhidapi.a -framework IOKit +LDFLAGS += -framework CoreFoundation hidapi/mac/.libs/libhidapi.a +CFLAGS += -Ihidapi/hidapi endif + +LDFLAGS += -lusb-1.0 +CFLAGS += $(shell pkg-config --cflags libftdi1) +LDFLAGS += $(shell pkg-config --libs libftdi1) + VPATH += platforms/pc SRC += timing.c cl_utils.c utils.c libusb_utils.c SRC += stlinkv2.c SRC += bmp_remote.c remote_swdptap.c remote_jtagtap.c SRC += ftdi_bmp.c libftdi_swdptap.c libftdi_jtagtap.c +SRC += jlink.c jlink_adiv5_swdp.c jlink_jtagtap.c PC_HOSTED = 1 diff --git a/src/platforms/hosted/jlink.c b/src/platforms/hosted/jlink.c new file mode 100644 index 0000000..d5453e0 --- /dev/null +++ b/src/platforms/hosted/jlink.c @@ -0,0 +1,239 @@ +/* + * This file is part of the Black Magic Debug project. + * + * Copyright (C) 2020 Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de) + * + * 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 3 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, see . + */ +/* Base on code from git://repo.or.cz/libjaylink.git + * and https://github.com/afaerber/jlink.git*/ + +#include "general.h" +#include "gdb_if.h" +#include "adiv5.h" +#include "exception.h" + +#include +#include +#include +#include +#include + +#include "cl_utils.h" +#include "jlink.h" + +#define USB_PID_SEGGER 0x1366 + +/* Only two devices PIDS tested so long */ +#define USB_VID_SEGGER_0101 0x0101 +#define USB_VID_SEGGER_0105 0x0105 + +static void jlink_print_caps(bmp_info_t *info) +{ + uint8_t cmd[1] = {CMD_GET_CAPS}; + uint8_t res[4]; + send_recv(info->usb_link, cmd, 1, res, sizeof(res)); + uint32_t caps = res[0] | (res[1] << 8) | (res[2] << 16) | (res[3] << 24); + printf("Caps %" PRIx32 "\n", caps); + if (caps & JLINK_CAP_GET_HW_VERSION) { + uint8_t cmd[1] = {CMD_GET_HW_VERSION}; + send_recv(info->usb_link, cmd, 1, NULL, 0); + send_recv(info->usb_link, NULL, 0, res, sizeof(res)); + printf("HW: Type %d, Major %d, Minor %d, Rev %d\n", + res[3], res[2], res[1], res[0]); + } +} +static void jlink_print_speed(bmp_info_t *info) +{ + uint8_t cmd[1] = {CMD_GET_SPEED}; + uint8_t res[6]; + send_recv(info->usb_link, cmd, 1, res, sizeof(res)); + uint32_t speed = res[0] | (res[1] << 8) | (res[2] << 16) | (res[3] << 24); + double freq_mhz = speed / 1000000.0; + uint16_t divisor = res[4] | (res[5] << 8); + printf("Emulator speed %3.1f MHz, Mindiv %d\n", freq_mhz, divisor); +} + +static void jlink_print_version(bmp_info_t *info) +{ + uint8_t cmd[1] = {CMD_GET_VERSION}; + uint8_t len_str[2]; + send_recv(info->usb_link, cmd, 1, len_str, sizeof(len_str)); + uint8_t version[0x70]; + send_recv(info->usb_link, NULL, 0, version, sizeof(version)); + printf("%s\n", version ); +} + +static void jlink_print_interfaces(bmp_info_t *info) +{ + uint8_t cmd[2] = {CMD_GET_SELECT_IF, JLINK_IF_GET_ACTIVE}; + uint8_t res[4]; + send_recv(info->usb_link, cmd, 2, res, sizeof(res)); + cmd[1] = JLINK_IF_GET_AVAILABLE; + uint8_t res1[4]; + send_recv(info->usb_link, cmd, 2, res1, sizeof(res1)); + printf("%s active", (res[0] == SELECT_IF_SWD) ? "SWD": + (res[0] == SELECT_IF_JTAG) ? "JTAG" : "NONE"); + uint8_t other_interface = res1[0] - (res[0] + 1); + if (other_interface) + printf(", %s available", + (other_interface == JLINK_IF_SWD) ? "SWD": "JTAG"); + else + printf(", %s not available", + ((res[0] + 1) == JLINK_IF_SWD) ? "JTAG": "SWD"); + printf("\n"); +} + +static void jlink_info(bmp_info_t *info) +{ + jlink_print_version(info); + jlink_print_speed(info); + jlink_print_caps(info); + jlink_print_interfaces(info); +} + +/* On success endpoints are set and return 0, !0 else */ +static int initialize_handle(bmp_info_t *info, libusb_device *dev) +{ + struct libusb_config_descriptor *config; + int ret = libusb_get_active_config_descriptor(dev, &config); + if (ret != LIBUSB_SUCCESS) { + fprintf(stderr, "Failed to get configuration descriptor: %s.", + libusb_error_name(ret)); + return -1; + } + const struct libusb_interface *interface; + bool found_interface = false; + const struct libusb_interface_descriptor *desc; + for (int i = 0; i < config->bNumInterfaces; i++) { + interface = &config->interface[i]; + desc = &interface->altsetting[0]; + if (desc->bInterfaceClass != LIBUSB_CLASS_VENDOR_SPEC) + continue; + if (desc->bInterfaceSubClass != LIBUSB_CLASS_VENDOR_SPEC) + continue; + if (desc->bNumEndpoints < 2) + continue; + found_interface = true; + if (libusb_claim_interface ( + info->usb_link->ul_libusb_device_handle, i)) { + fprintf(stderr, " Can not claim handle\n"); + found_interface = false; + } + break; + } + if (!found_interface) { + fprintf(stderr, "No suitable interface found."); + libusb_free_config_descriptor(config); + return -1; + } + for (int i = 0; i < desc->bNumEndpoints; i++) { + const struct libusb_endpoint_descriptor *epdesc = &desc->endpoint[i]; + if (epdesc->bEndpointAddress & LIBUSB_ENDPOINT_IN) { + info->usb_link->ep_rx = epdesc->bEndpointAddress; + } else { + info->usb_link->ep_tx = epdesc->bEndpointAddress; + } + } + libusb_free_config_descriptor(config); + return 0; +} +/* Return 0 if single J-Link device connected or + * serial given matches one of several J-Link devices. + */ +int jlink_init(bmp_info_t *info) +{ + usb_link_t *jl = calloc(1, sizeof(usb_link_t)); + if (!jl) + return -1; + info->usb_link = jl; + jl->ul_libusb_ctx = info->libusb_ctx; + int ret = -1; + libusb_device **devs; + if (libusb_get_device_list(info->libusb_ctx, &devs) < 0) { + fprintf(stderr, "libusb_get_device_list() failed"); + return ret; + } + int i = 0; + for (; devs[i]; i++) { + libusb_device *dev = devs[i]; + struct libusb_device_descriptor desc; + if (libusb_get_device_descriptor(dev, &desc) < 0) { + fprintf(stderr, "libusb_get_device_descriptor() failed"); + goto error;; + } + if (desc.idVendor != USB_PID_SEGGER) + continue; + if ((desc.idProduct != USB_VID_SEGGER_0101) && + (desc.idProduct != USB_VID_SEGGER_0105)) + continue; + int res = libusb_open(dev, &jl->ul_libusb_device_handle); + if (res != LIBUSB_SUCCESS) + continue; + char buf[32]; + res = libusb_get_string_descriptor_ascii(jl->ul_libusb_device_handle, + desc.iSerialNumber, (uint8_t*) buf, sizeof(buf)); + if ((res <= 0) || (!strstr(buf, info->serial))) { + libusb_close(jl->ul_libusb_device_handle); + continue; + } + break; + } + if (!devs[i]) + goto error; + if (initialize_handle(info, devs[i])) + goto error; + jl->req_trans = libusb_alloc_transfer(0); + jl->rep_trans = libusb_alloc_transfer(0); + if (!jl->req_trans || !jl->rep_trans || + !jl->ep_tx || !jl->ep_rx) { + fprintf(stderr,"Device setup failed\n"); + goto error; + } + libusb_free_device_list(devs, 1); + jlink_info(info); + return 0; + error: + libusb_free_device_list(devs, 1); + return -1; + +} + +const char *jlink_target_voltage(bmp_info_t *info) +{ + uint8_t cmd[1] = {CMD_GET_HW_STATUS}; + uint8_t res[8]; + send_recv(info->usb_link, cmd, 1, res, sizeof(res)); + uint16_t mVolt = res[0] | (res[1] << 8); + static char ret[7]; + sprintf(ret, "%2d.%03d", mVolt / 1000, mVolt % 1000); + return ret; +} + +static bool srst_status = false; +void jlink_srst_set_val(bmp_info_t *info, bool assert) +{ + uint8_t cmd[1]; + cmd[0]= (assert)? CMD_HW_RESET0: CMD_HW_RESET1; + send_recv(info->usb_link, cmd, 1, NULL, 0); + platform_delay(2); + srst_status = assert; +} + +bool jlink_srst_get_val(bmp_info_t *info) { + uint8_t cmd[1] = {CMD_GET_HW_STATUS}; + uint8_t res[8]; + send_recv(info->usb_link, cmd, 1, res, sizeof(res)); + return !(res[6]); +} diff --git a/src/platforms/hosted/jlink.h b/src/platforms/hosted/jlink.h new file mode 100644 index 0000000..27e81bf --- /dev/null +++ b/src/platforms/hosted/jlink.h @@ -0,0 +1,53 @@ +/* + * This file is part of the Black Magic Debug project. + * + * Copyright (C) 2019 Uwe Bonnes + * + * 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 3 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, see . + */ +#if !defined(__JLINK_H_) +#define __JLINK_H_ + +#include "jtagtap.h" + +/** @cond PRIVATE */ +#define CMD_GET_VERSION 0x01 +#define CMD_GET_HW_STATUS 0x07 +#define CMD_GET_SPEED 0xc0 +#define CMD_GET_SELECT_IF 0xc7 +#define CMD_HW_JTAG3 0xcf +#define CMD_HW_RESET0 0xdc +#define CMD_HW_RESET1 0xdd +#define CMD_GET_CAPS 0xe8 +#define CMD_GET_EXT_CAPS 0xed +#define CMD_GET_HW_VERSION 0xf0 + +#define JLINK_IF_GET_ACTIVE 0xfe +#define JLINK_IF_GET_AVAILABLE 0xff + +#define JLINK_CAP_GET_HW_VERSION 2 +#define JLINK_IF_JTAG 1 +#define JLINK_IF_SWD 2 + +#define SELECT_IF_JTAG 0 +#define SELECT_IF_SWD 1 + + +int jlink_init(bmp_info_t *info); +int jlink_swdp_scan(bmp_info_t *info); +int jlink_jtagtap_init(bmp_info_t *info, jtag_proc_t *jtag_proc); +const char *jlink_target_voltage(bmp_info_t *info); +void jlink_srst_set_val(bmp_info_t *info, bool assert); +bool jlink_srst_get_val(bmp_info_t *info); +#endif diff --git a/src/platforms/hosted/jlink_adiv5_swdp.c b/src/platforms/hosted/jlink_adiv5_swdp.c new file mode 100644 index 0000000..06da0a1 --- /dev/null +++ b/src/platforms/hosted/jlink_adiv5_swdp.c @@ -0,0 +1,372 @@ +/* + * This file is part of the Black Magic Debug project. + * + * Copyright (C) 2011 Black Sphere Technologies Ltd. + * Written by Gareth McMullin + * Copyright (C) 2019 Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de) + * + * 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 3 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, see . + */ + +/* This file implements the SW-DP specific functions of the + * ARM Debug Interface v5 Architecure Specification, ARM doc IHI0031A. + */ + +#include "general.h" +#include "exception.h" +#include "target.h" +#include "target_internal.h" +#include "adiv5.h" +#include "jlink.h" +#include "cl_utils.h" + +#define SWDP_ACK_OK 0x01 +#define SWDP_ACK_WAIT 0x02 +#define SWDP_ACK_FAULT 0x04 + +static uint32_t jlink_adiv5_swdp_read(ADIv5_DP_t *dp, uint16_t addr); + +static uint32_t jlink_adiv5_swdp_error(ADIv5_DP_t *dp); + +static uint32_t jlink_adiv5_swdp_low_access(ADIv5_DP_t *dp, uint8_t RnW, + uint16_t addr, uint32_t value); + +static void jlink_adiv5_swdp_abort(ADIv5_DP_t *dp, uint32_t abort); + +enum { + SWDIO_WRITE = 0, + SWDIO_READ +}; + +/* Write at least 50 bits high, two bits low and read DP_IDR and put +* idle cyccles at the end*/ +static int line_reset(bmp_info_t *info) +{ + uint8_t cmd[44]; + cmd[0] = CMD_HW_JTAG3; + cmd[1] = 0; + /* write 19 Bytes.*/ + cmd[2] = 19 * 8; + cmd[3] = 0; + uint8_t *direction = cmd + 4; + direction[0] = 0; + direction[1] = 0; + direction[2] = 0; + direction[3] = 0; + direction[4] = 0; + direction[5] = 0xff; + direction[6] = 0xff; + direction[7] = 0xff; + direction[8] = 0xff; + direction[9] = 0xff; + direction[10] = 0xff; + direction[11] = 0xff; + direction[12] = 0xff; + direction[13] = 0xff; + direction[14] = 0x0; + direction[15] = 0x0; + direction[16] = 0x0; + direction[17] = 0x0; + direction[18] = 0xe0; + uint8_t *data = direction + 19; + data[5] = 0xff; + data[6] = 0xff; + data[7] = 0xff; + data[8] = 0xff; + data[9] = 0xff; + data[10] = 0xff; + data[11] = 0xff; + data[12] = 0; + data[13] = 0xa5; + data[18] = 0; + + uint8_t res[18]; + send_recv(info->usb_link, cmd, 42, res, 19); + send_recv(info->usb_link, NULL, 0, res, 1); + + if (res[0] != 0) { + fprintf(stderr, "Line reset failed\n"); + return -1; + } + return 0; +} + +static int swdptap_init(bmp_info_t *info) +{ + if (cl_debuglevel) + printf("swdptap_init\n"); + uint8_t cmd[2] = {CMD_GET_SELECT_IF, JLINK_IF_GET_AVAILABLE}; + uint8_t res[4]; + send_recv(info->usb_link, cmd, 2, res, sizeof(res)); + if (!(res[0] & JLINK_IF_SWD)) + return -1; + cmd[1] = SELECT_IF_SWD; + send_recv(info->usb_link, cmd, 2, res, sizeof(res)); + platform_delay(10); + /* Set speed 256 kHz*/ + unsigned int speed = 2000; + uint8_t jtag_speed[3] = {5, speed & 0xff, speed >> 8}; + send_recv(info->usb_link, jtag_speed, 3, NULL, 0); + return 0; +} + +int jlink_swdp_scan(bmp_info_t *info) +{ + swdptap_init(info); + target_list_free(); + ADIv5_DP_t *dp = (void*)calloc(1, sizeof(*dp)); + if (!dp) /* calloc failed: heap exhaustion */ + return 0; + uint8_t cmd[44]; + cmd[0] = CMD_HW_JTAG3; + cmd[1] = 0; + /* write 18 Bytes.*/ + cmd[2] = 17 * 8; + cmd[3] = 0; + uint8_t *direction = cmd + 4; + direction[0] = 0xff; + direction[1] = 0xff; + direction[2] = 0xff; + direction[3] = 0xff; + direction[4] = 0xff; + direction[5] = 0xff; + direction[6] = 0xff; + direction[7] = 0xff; + direction[8] = 0xff; + direction[9] = 0xff; + direction[10] = 0xff; + direction[11] = 0xff; + direction[12] = 0xff; + direction[13] = 0xff; + direction[14] = 0xff; + direction[15] = 0xff; + direction[16] = 0xff; + uint8_t *data = direction + 17; + data[0] = 0xff; + data[1] = 0xff; + data[2] = 0xff; + data[3] = 0xff; + data[4] = 0xff; + data[5] = 0xff; + data[6] = 0xff; + data[7] = 0x9e; + data[8] = 0xe7; + data[9] = 0xff; + data[10] = 0xff; + data[11] = 0xff; + data[12] = 0xff; + data[13] = 0xff; + data[14] = 0xff; + data[15] = 0; + data[16] = 0; + + uint8_t res[18]; + send_recv(info->usb_link, cmd, 38, res, 17); + send_recv(info->usb_link, NULL, 0, res, 1); + + if (res[0] != 0) { + fprintf(stderr, "Line reset failed\n"); + return 0; + } + dp->idcode = jlink_adiv5_swdp_low_access(dp, 1, ADIV5_DP_IDCODE, 0); + dp->dp_read = jlink_adiv5_swdp_read; + dp->error = jlink_adiv5_swdp_error; + dp->low_access = jlink_adiv5_swdp_low_access; + dp->abort = jlink_adiv5_swdp_abort; + + jlink_adiv5_swdp_error(dp); + adiv5_dp_init(dp); + return target_list?1:0; +} + +void ap_decode_access(uint16_t addr, uint8_t RnW) +{ + if (RnW) + printf("Read "); + else + printf("Write "); + switch(addr) { + case 0x00: + if (RnW) + printf("DP_DPIDR: "); + else + printf("DP_ABORT: "); + break; + case 0x004: printf("CTRL/STAT: "); + break; + case 0x008: + if (RnW) + printf("RESEND: "); + else + printf("DP_SELECT: "); + break; + case 0x00c: printf("DP_RDBUFF: "); + break; + case 0x100: printf("AP_CSW: "); + break; + case 0x104: printf("AP_TAR: "); + break; + case 0x10c: printf("AP_DRW: "); + break; + case 0x1f8: printf("AP_BASE: "); + break; + case 0x1fc: printf("AP_IDR: "); + break; + } +} + +static uint32_t jlink_adiv5_swdp_read(ADIv5_DP_t *dp, uint16_t addr) +{ + if (cl_debuglevel) + printf("jlink_adiv5_swdp_read 0x%04x\n", addr); + if (addr & ADIV5_APnDP) { + adiv5_dp_low_access(dp, ADIV5_LOW_READ, addr, 0); + return adiv5_dp_low_access(dp, ADIV5_LOW_READ, + ADIV5_DP_RDBUFF, 0); + } else { + return jlink_adiv5_swdp_low_access(dp, ADIV5_LOW_READ, addr, 0); + } +} + +static uint32_t jlink_adiv5_swdp_error(ADIv5_DP_t *dp) +{ + uint32_t err, clr = 0; + err = jlink_adiv5_swdp_read(dp, ADIV5_DP_CTRLSTAT) & + (ADIV5_DP_CTRLSTAT_STICKYORUN | ADIV5_DP_CTRLSTAT_STICKYCMP | + ADIV5_DP_CTRLSTAT_STICKYERR | ADIV5_DP_CTRLSTAT_WDATAERR); + + if(err & ADIV5_DP_CTRLSTAT_STICKYORUN) + clr |= ADIV5_DP_ABORT_ORUNERRCLR; + if(err & ADIV5_DP_CTRLSTAT_STICKYCMP) + clr |= ADIV5_DP_ABORT_STKCMPCLR; + if(err & ADIV5_DP_CTRLSTAT_STICKYERR) + clr |= ADIV5_DP_ABORT_STKERRCLR; + if(err & ADIV5_DP_CTRLSTAT_WDATAERR) + clr |= ADIV5_DP_ABORT_WDERRCLR; + if (clr) + adiv5_dp_write(dp, ADIV5_DP_ABORT, clr); + if (dp->fault) + err |= 0x8000; + dp->fault = 0; + + return err; +} + +static uint32_t jlink_adiv5_swdp_low_access(ADIv5_DP_t *dp, uint8_t RnW, + uint16_t addr, uint32_t value) +{ + if (cl_debuglevel) { + if (RnW) { + if (cl_debuglevel > 0) { + ap_decode_access(addr, RnW); + printf(" start:\n"); + } + }else{ + ap_decode_access(addr, RnW); + printf(" %08" PRIx32 "\n", value); + } + } + bool APnDP = addr & ADIV5_APnDP; + uint8_t addr8 = addr & 0xff; + uint8_t request = 0x81; + uint32_t response = 0; + uint8_t ack; + platform_timeout timeout; + + if(APnDP && dp->fault) return 0; + + if(APnDP) request ^= 0x22; + if(RnW) request ^= 0x24; + + addr8 &= 0xC; + request |= (addr8 << 1) & 0x18; + if((addr8 == 4) || (addr8 == 8)) + request ^= 0x20; + uint8_t cmd[16]; + uint8_t res[8]; + cmd[0] = CMD_HW_JTAG3; + cmd[1] = 0; + cmd[2] = 13; + cmd[3] = 0; + cmd[4] = 0xff; + cmd[5] = 0xe3; + cmd[6] = request << 2; + cmd[7] = request >> 6; + platform_timeout_set(&timeout, 2000); + do { + send_recv(info.usb_link, cmd, 8, res, 2); + send_recv(info.usb_link, NULL, 0, res, 1); + if (res[0] != 0) + raise_exception(EXCEPTION_ERROR, "Low access setup failed"); + ack = res[1] >> 2; + ack &= 7; + } while (ack == SWDP_ACK_WAIT && !platform_timeout_is_expired(&timeout)); + if (ack == SWDP_ACK_WAIT) + raise_exception(EXCEPTION_TIMEOUT, "SWDP ACK timeout"); + + if(ack == SWDP_ACK_FAULT) { + if (cl_debuglevel) + fprintf(stderr, "Fault\n"); + dp->fault = 1; + return 0; + } + + if(ack != SWDP_ACK_OK) { + if (cl_debuglevel) + fprintf(stderr, "Protocol\n"); + line_reset(&info); + return 0; + } + cmd[3] = 0; + /* Always prepend an idle cycle (SWDIO = 0)!*/ + if(RnW) { + memset(cmd + 4, 0, 10); + cmd[2] = 34; + cmd[8] = 0xfe; + cmd[13] = 0; + send_recv(info.usb_link, cmd, 14, res, 5); + send_recv(info.usb_link, NULL, 0, res + 5, 1); + if (res[5] != 0) + raise_exception(EXCEPTION_ERROR, "Low access read failed"); + response = res[0] | res[1] << 8 | res[2] << 16 | res[3] << 24; + int parity = res[4] & 1; + int bit_count = __builtin_popcount (response) + parity; + if (cl_debuglevel ) { + ap_decode_access(addr, RnW);; + printf("0x%08" PRIx32 "\n", response); + } + if (bit_count & 1) /* Give up on parity error */ + raise_exception(EXCEPTION_ERROR, "SWDP Parity error"); + } else { + cmd[2] = 35; + memset(cmd + 4, 0xff, 5); + cmd[ 9] = ((value << 2) & 0xfc); + cmd[10] = ((value >> 6) & 0xff); + cmd[11] = ((value >> 14) & 0xff); + cmd[12] = ((value >> 22) & 0xff); + cmd[13] = ((value >> 30) & 0x03); + int bit_count = __builtin_popcount(value); + cmd[13] |= ((bit_count & 1) ? 4 : 0); + send_recv(info.usb_link, cmd, 14, res, 5); + send_recv(info.usb_link, NULL, 0, res, 1); + if (res[0] != 0) + raise_exception(EXCEPTION_ERROR, "Low access write failed"); + } + return response; +} + +static void jlink_adiv5_swdp_abort(ADIv5_DP_t *dp, uint32_t abort) +{ + adiv5_dp_write(dp, ADIV5_DP_ABORT, abort); +} diff --git a/src/platforms/hosted/jlink_jtagtap.c b/src/platforms/hosted/jlink_jtagtap.c new file mode 100644 index 0000000..d69d904 --- /dev/null +++ b/src/platforms/hosted/jlink_jtagtap.c @@ -0,0 +1,176 @@ +/* + * This file is part of the Black Magic Debug project. + * + * Copyright (C) 2020 Uwe Bonnes bon@elektron.ikp.physik.tu-darmstadt.de + * + * 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 3 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, see . + */ + +/* Low level JTAG implementation using jlink. + * + */ + +#include +#include +#include + +#include + +#include "general.h" +#include "exception.h" + +#include "jlink.h" +#include "cl_utils.h" + +static void jtagtap_reset(void) +{ + jtagtap_soft_reset(); +} + +static void jtagtap_tms_seq(uint32_t MS, int ticks) +{ + if (cl_debuglevel) + printf("jtagtap_tms_seq 0x%08" PRIx32 ", ticks %d\n", MS, ticks); + int len = (ticks + 7) / 8; + uint8_t cmd[12]; + cmd[0] = CMD_HW_JTAG3; + cmd[1] = 0; + cmd[2] = ticks; + cmd[3] = 0; + uint8_t *tms = cmd + 4; + for (int i = 0; i < len; i++) { + *tms = MS & 0xff; + *(tms + len) = *tms; + tms++; + MS >>= 8; + } + uint8_t res[4]; + send_recv(info.usb_link, cmd, 4 + 2 * len, res, len); + send_recv(info.usb_link, NULL, 0, res, 1); + if (res[0] != 0) + raise_exception(EXCEPTION_ERROR, "tagtap_tms_seq failed"); +} + +static void jtagtap_tdi_tdo_seq(uint8_t *DO, const uint8_t final_tms, + const uint8_t *DI, int ticks) +{ + if (!ticks) + return; + int len = (ticks + 7) / 8; + if (cl_debuglevel) { + printf("jtagtap_tdi_tdo %s, ticks %d, DI: ", + (final_tms) ? "Final TMS" : "", ticks); + for (int i = 0; i < len; i++) { + printf("%02x", DI[i]); + } + printf("\n"); + } + uint8_t *cmd = alloca(4 + 2 * len); + cmd[0] = CMD_HW_JTAG3; + cmd[1] = 0; + cmd[2] = ticks; + cmd[3] = 0; + uint8_t *tms = cmd + 4; + for (int i = 0; i < len; i++) + *tms++ = 0; + if (final_tms) + cmd[4 + (ticks - 1) / 8] |= (1 << ((ticks - 1) % 8)); + uint8_t *tdi = tms; + if (DI) + for (int i = 0; i < len; i++) + *tdi++ = DI[i]; + if (DO) + send_recv(info.usb_link, cmd, 4 + 2 * len, DO, len); + else + send_recv(info.usb_link, cmd, 4 + 2 * len, cmd, len); + uint8_t res[1]; + send_recv(info.usb_link, NULL, 0, res, 1); + if (res[0] != 0) + raise_exception(EXCEPTION_ERROR, "jtagtap_tdi_tdi failed"); +} + +static void jtagtap_tdi_seq(const uint8_t final_tms, const uint8_t *DI, + int ticks) +{ + return jtagtap_tdi_tdo_seq(NULL, final_tms, DI, ticks); +} + +static uint8_t jtagtap_next(uint8_t dTMS, uint8_t dTDI) +{ + if (cl_debuglevel) + printf("jtagtap_next TMS 0x%02x, TDI %02x\n", dTMS, dTDI); + uint8_t cmd[6]; + cmd[0] = CMD_HW_JTAG3; + cmd[1] = 0; + cmd[2] = 1; + cmd[3] = 0; + cmd[4] = (dTMS) ? 0xff : 0; + cmd[5] = (dTDI) ? 0xff : 0; + uint8_t ret[1]; + send_recv(info.usb_link, cmd, 6, ret, 1); + uint8_t res[1]; + send_recv(info.usb_link, NULL, 0, res, 1); + if (res[0] != 0) + raise_exception(EXCEPTION_ERROR, "jtagtap_next failed"); + return (ret[0] & 1); +} + +int jlink_jtagtap_init(bmp_info_t *info, jtag_proc_t *jtag_proc) +{ + if (cl_debuglevel) + printf("jtap_init\n"); + uint8_t cmd_switch[2] = {CMD_GET_SELECT_IF, JLINK_IF_GET_AVAILABLE}; + uint8_t res[4]; + send_recv(info->usb_link, cmd_switch, 2, res, sizeof(res)); + if (!(res[0] & JLINK_IF_JTAG)) { + fprintf(stderr, "JTAG not available\n"); + return -1; + } + cmd_switch[1] = SELECT_IF_JTAG; + send_recv(info->usb_link, cmd_switch, 2, res, sizeof(res)); + platform_delay(10); + /* Set speed 256 kHz*/ + unsigned int speed = 2000; + uint8_t jtag_speed[3] = {5, speed & 0xff, speed >> 8}; + send_recv(info->usb_link, jtag_speed, 3, NULL, 0); + uint8_t cmd[44]; + cmd[0] = CMD_HW_JTAG3; + cmd[1] = 0; + /* write 8 Bytes.*/ + cmd[2] = 9 * 8; + cmd[3] = 0; + uint8_t *tms = cmd + 4; + tms[0] = 0xff; + tms[1] = 0xff; + tms[2] = 0xff; + tms[3] = 0xff; + tms[4] = 0xff; + tms[5] = 0xff; + tms[6] = 0xff; + tms[7] = 0x3c; + tms[8] = 0xe7; + send_recv(info->usb_link, cmd, 4 + 2 * 9, cmd, 9); + send_recv(info->usb_link, NULL, 0, res, 1); + + if (res[0] != 0) { + fprintf(stderr, "Switch to JTAGt failed\n"); + return 0; + } + jtag_proc->jtagtap_reset = jtagtap_reset; + jtag_proc->jtagtap_next =jtagtap_next; + jtag_proc->jtagtap_tms_seq = jtagtap_tms_seq; + jtag_proc->jtagtap_tdi_tdo_seq = jtagtap_tdi_tdo_seq; + jtag_proc->jtagtap_tdi_seq = jtagtap_tdi_seq; + return 0; +} diff --git a/src/platforms/hosted/platform.c b/src/platforms/hosted/platform.c index c061e73..75df055 100644 --- a/src/platforms/hosted/platform.c +++ b/src/platforms/hosted/platform.c @@ -35,6 +35,7 @@ #include "bmp_remote.h" #include "stlinkv2.h" #include "ftdi_bmp.h" +#include "jlink.h" #define VENDOR_ID_BMP 0x1d50 #define PRODUCT_ID_BMP 0x6018 @@ -49,6 +50,8 @@ #define PRODUCT_ID_STLINKV3 0x374f #define PRODUCT_ID_STLINKV3E 0x374e +#define VENDOR_ID_SEGGER 0x1366 + bmp_info_t info; swd_proc_t swd_proc; @@ -166,7 +169,9 @@ static int find_debuggers( BMP_CL_OPTIONS_t *cl_opts,bmp_info_t *info) fprintf(stderr, "INFO: STLINKV1 not supported\n"); continue; } - } else { + } else if (desc.idVendor == VENDOR_ID_SEGGER) { + type = BMP_TYPE_JLINK; + } else{ continue; } found_debuggers ++; @@ -226,7 +231,7 @@ void platform_init(int argc, char **argv) } else if (find_debuggers(&cl_opts, &info)) { exit(-1); } - printf("Using %s %s %s\n", info.serial, + printf("Using %04x:%04x %s %s %s\n", info.vid, info.pid, info.serial, info.manufacturer, info.product); switch (info.bmp_type) { @@ -241,6 +246,10 @@ void platform_init(int argc, char **argv) break; case BMP_TYPE_LIBFTDI: break; + case BMP_TYPE_JLINK: + if (jlink_init(&info)) + exit(-1); + break; default: exit(-1); } @@ -273,6 +282,8 @@ int platform_adiv5_swdp_scan(void) free(dp); break; } + case BMP_TYPE_JLINK: + return jlink_swdp_scan(&info); default: return 0; } @@ -285,8 +296,8 @@ int platform_swdptap_init(void) case BMP_TYPE_BMP: return remote_swdptap_init(&swd_proc); case BMP_TYPE_STLINKV2: + case BMP_TYPE_JLINK: return 0; - break; case BMP_TYPE_LIBFTDI: return libftdi_swdptap_init(&swd_proc); default: @@ -300,6 +311,7 @@ int platform_jtag_scan(const uint8_t *lrlens) switch (info.bmp_type) { case BMP_TYPE_BMP: case BMP_TYPE_LIBFTDI: + case BMP_TYPE_JLINK: return jtag_scan(lrlens); case BMP_TYPE_STLINKV2: return jtag_scan_stlinkv2(&info, lrlens); @@ -318,6 +330,8 @@ int platform_jtagtap_init(void) return 0; case BMP_TYPE_LIBFTDI: return libftdi_jtagtap_init(&jtag_proc); + case BMP_TYPE_JLINK: + return jlink_jtagtap_init(&info, &jtag_proc); default: return -1; } @@ -339,6 +353,7 @@ int platform_jtag_dp_init(ADIv5_DP_t *dp) switch (info.bmp_type) { case BMP_TYPE_BMP: case BMP_TYPE_LIBFTDI: + case BMP_TYPE_JLINK: return 0; case BMP_TYPE_STLINKV2: return stlink_jtag_dp_init(dp); @@ -376,6 +391,8 @@ const char *platform_target_voltage(void) return stlink_target_voltage(&info); case BMP_TYPE_LIBFTDI: return libftdi_target_voltage(); + case BMP_TYPE_JLINK: + return jlink_target_voltage(&info); default: break; } @@ -389,6 +406,8 @@ void platform_srst_set_val(bool assert) return stlink_srst_set_val(&info, assert); case BMP_TYPE_BMP: return remote_srst_set_val(assert); + case BMP_TYPE_JLINK: + return jlink_srst_set_val(&info, assert); default: break; } @@ -401,6 +420,8 @@ bool platform_srst_get_val(void) return remote_srst_get_val(); case BMP_TYPE_STLINKV2: return stlink_srst_get_val(); + case BMP_TYPE_JLINK: + return jlink_srst_get_val(&info); default: break; } diff --git a/src/platforms/hosted/stlinkv2.c b/src/platforms/hosted/stlinkv2.c index 133606f..2d50a72 100644 --- a/src/platforms/hosted/stlinkv2.c +++ b/src/platforms/hosted/stlinkv2.c @@ -332,7 +332,7 @@ static int stlink_usb_error_check(uint8_t *data, bool verbose) } } -static int send_recv_retry(uint8_t *txbuf, size_t txsize, +static int stlink_send_recv_retry(uint8_t *txbuf, size_t txsize, uint8_t *rxbuf, size_t rxsize) { uint32_t start = platform_time_ms(); @@ -400,7 +400,7 @@ static void stlink_version(bmp_info_t *info) uint8_t data[12]; int size = send_recv(info->usb_link, cmd, 16, data, 12); if (size == -1) { - printf("[!] send_recv STLINK_APIV3_GET_VERSION_EX\n"); + printf("[!] stlink_send_recv STLINK_APIV3_GET_VERSION_EX\n"); } Stlink.ver_stlink = data[0]; Stlink.ver_swim = data[1]; @@ -415,7 +415,7 @@ static void stlink_version(bmp_info_t *info) uint8_t data[6]; int size = send_recv(info->usb_link, cmd, 16, data, 6); if (size == -1) { - printf("[!] send_recv STLINK_GET_VERSION_EX\n"); + printf("[!] stlink_send_recv STLINK_GET_VERSION_EX\n"); } Stlink.vid = data[3] << 8 | data[2]; Stlink.pid = data[5] << 8 | data[4]; @@ -766,7 +766,7 @@ static int stlink_read_dp_register(uint16_t port, uint16_t addr, uint32_t *reg) cmd[4] = addr & 0xff; DEBUG_STLINK("Read DP, Addr 0x%04" PRIx16 ": \n", addr); uint8_t data[8]; - int res = send_recv_retry(cmd, 16, data, 8); + int res = stlink_send_recv_retry(cmd, 16, data, 8); if (res == STLINK_ERROR_OK) { uint32_t ret = data[4] | data[5] << 8 | data[6] << 16 | data[7] << 24; DEBUG_STLINK("0x%08" PRIx32" \n", ret); @@ -791,7 +791,7 @@ static int stlink_write_dp_register(uint16_t port, uint16_t addr, uint32_t val) val & 0xff, (val >> 8) & 0xff, (val >> 16) & 0xff, (val >> 24) & 0xff}; uint8_t data[2]; - send_recv_retry(cmd, 16, data, 2); + stlink_send_recv_retry(cmd, 16, data, 2); DEBUG_STLINK("Write DP, Addr 0x%04" PRIx16 ": 0x%08" PRIx32 " \n", addr, val); return stlink_usb_error_check(data, true);