This is an automated email from Gerrit. Tarek BOCHKATI (tarek.bouchk...@gmail.com) just uploaded a new patch set to Gerrit, which you can find at http://openocd.zylin.com/5633
-- gerrit commit b34cbab3f64b271753124806ba9ba5de6e68da1c Author: Tarek BOCHKATI <tarek.bouchk...@gmail.com> Date: Tue Apr 28 00:13:28 2020 +0100 stlink: support of ST-LINK server using stlink-dap [RFC/WIP] Quote: The ST-LINK server is an application to share the debug interface of a single ST-LINK board among several host applications, typically a debugging tool and a monitoring tool. ST-LINK server allows several applications to connect to the same ST-Link through sockets (TCP). To use ST-LINK server: - using stlink-dap : use 'st-link use_stlink_server [port]' - using hla : [WIP] Change-Id: I9b79f65267f04b1e978709934892160e65bd2d6d Signed-off-by: Tarek BOCHKATI <tarek.bouchk...@gmail.com> diff --git a/src/jtag/drivers/stlink_usb.c b/src/jtag/drivers/stlink_usb.c index ec7be09..aebccdb 100644 --- a/src/jtag/drivers/stlink_usb.c +++ b/src/jtag/drivers/stlink_usb.c @@ -45,6 +45,17 @@ #include <target/cortex_m.h> +#if WIN32 +#include <winsock2.h> +#else +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <sys/uio.h> +#include <netinet/tcp.h> +#endif + #include "libusb_helper.h" #ifdef HAVE_LIBUSB1 @@ -129,6 +140,17 @@ struct stlink_usb_priv_s { struct libusb_transfer *trans; }; +struct stlink_server_priv_s { + /** */ + int fd; + /** */ + bool connected; + /** */ + uint32_t device_id; + /** */ + uint32_t connect_id; +}; + struct stlink_interface_s { /** */ void *priv; @@ -326,6 +348,39 @@ struct stlink_usb_handle_s { #define REQUEST_SENSE 0x03 #define REQUEST_SENSE_LENGTH 18 +/* STLINK TCP commands */ +#define STLINK_TCP_CMD_REFRESH_DEVICE_LIST 0x00 +#define STLINK_TCP_CMD_GET_NB_DEV 0x01 +#define STLINK_TCP_CMD_GET_DEV_INFO 0x02 +#define STLINK_TCP_CMD_OPEN_DEV 0x03 +#define STLINK_TCP_CMD_CLOSE_DEV 0x04 +#define STLINK_TCP_CMD_SEND_USB_CMD 0x05 +#define STLINK_TCP_CMD_GET_SERVER_VERSION 0x06 +#define STLINK_TCP_CMD_GET_NB_OF_DEV_CLIENTS 0x07 + +/* STLINK TCP constants */ +#define OPENOCD_STLINK_TCP_API_VERSION 1 +#define STLINK_TCP_REQUEST_WRITE 0 +#define STLINK_TCP_REQUEST_READ 1 +#define STLINK_TCP_REQUEST_READ_SWO 3 +#define STLINK_TCP_SS_SIZE 4 +#define STLINK_TCP_USB_CMD_SIZE 32 +#define STLINK_TCP_SERIAL_SIZE 32 +#define STLINK_TCP_SEND_BUFFER_SIZE 2048 +#define STLINK_TCP_RECV_BUFFER_SIZE 10240 + +/* STLINK TCP command status */ +#define STLINK_TCP_SS_OK 0x00000001 +#define STLINK_TCP_SS_MEMORY_PROBLEM 0x00001000 +#define STLINK_TCP_SS_TIMEOUT 0x00001001 +#define STLINK_TCP_SS_BAD_PARAMETER 0x00001002 +#define STLINK_TCP_SS_OPEN_ERR 0x00001003 +#define STLINK_TCP_SS_TRUNCATED_DATA 0x00001052 +#define STLINK_TCP_SS_CMD_NOT_AVAILABLE 0x00001053 +#define STLINK_TCP_SS_TCP_ERROR 0x00002001 +#define STLINK_TCP_SS_TCP_CANT_CONNECT 0x00002002 +#define STLINK_TCP_SS_WIN32_ERROR 0x00010000 + /* * Map the relevant features, quirks and workaround for specific firmware * version of stlink @@ -741,6 +796,105 @@ static int stlink_usb_xfer_noerrcheck(void *handle, const uint8_t *buf, int size return ERROR_OK; } +static int stlink_server_send_cmd(void *handle, const uint8_t *cmd, int cmd_size, + uint8_t *data, int data_size, bool check_tcp_status) +{ + struct stlink_usb_handle_s *h = handle; + struct stlink_server_priv_s *itf_priv = h->itf->priv; + + assert(handle != NULL); + + /* send the TCP command */ + int sent_size = send(itf_priv->fd, (char *) cmd, cmd_size, 0); + if (sent_size != cmd_size) { + LOG_ERROR("failed to send USB CMD"); + if (sent_size == -1) + LOG_DEBUG("socket send error: %s (errno %d)", strerror(errno), errno); + else + LOG_DEBUG("sent size %d (expected %d)", sent_size, cmd_size); + return ERROR_FAIL; + } + + /* read the TCP response */ + int received_size = recv(itf_priv->fd, (char *) data, data_size, 0); + if (received_size != data_size) { + LOG_ERROR("failed to receive USB CMD response"); + if (received_size == -1) + LOG_DEBUG("socket recv error: %s (errno %d)", strerror(errno), errno); + else + LOG_DEBUG("received size %d (expected %d)", received_size, data_size); + return ERROR_FAIL; + } + + if (check_tcp_status) { + uint32_t tcp_ss = le_to_h_u32(data); + if (tcp_ss != STLINK_TCP_SS_OK) { + LOG_ERROR("TCP error status 0x%X", tcp_ss); + return ERROR_FAIL; + } + } + + return ERROR_OK; +} + +/** */ +static int stlink_server_xfer(void *handle, const uint8_t *buf, int size) +{ + struct stlink_usb_handle_s *h = handle; + struct stlink_server_priv_s *itf_priv = h->itf->priv; + + uint8_t cmdbuf[STLINK_TCP_SEND_BUFFER_SIZE]; + uint8_t databuf[STLINK_TCP_RECV_BUFFER_SIZE]; + int cmd_size = STLINK_TCP_USB_CMD_SIZE; + int data_size = STLINK_TCP_SS_SIZE; + + assert(handle != NULL); + + /* prepare the TCP command */ + cmdbuf[0] = STLINK_TCP_CMD_SEND_USB_CMD; + memset(&cmdbuf[1], 0, 3); /* reserved for alignment and future use, must be zero */ + h_u32_to_le(&cmdbuf[4], itf_priv->connect_id); + memcpy(&cmdbuf[8], h->cmdbuf, 16); + cmdbuf[24] = h->direction; + memset(&cmdbuf[25], 0, 3); /* reserved for alignment and future use, must be zero */ + + h_u32_to_le(&cmdbuf[28], size); + + /* + * if the xfer is a write request (tx_ep) + * > then buf content will be copied + * into &cmdbuf[32]. + * else : the xfer is a read or trace read request (rx_ep or trace_ep) + * > the buf content will be filled from &databuf[4]. + * + * note : if h->direction is trace_ep, h->cmdbuf is zeros. + */ + + if (h->direction == h->tx_ep) { /* STLINK_TCP_REQUEST_WRITE */ + cmd_size += size; + if (cmd_size > STLINK_TCP_SEND_BUFFER_SIZE) { + LOG_ERROR("STLINK_TCP command buffer overflow"); + return ERROR_FAIL; + } + memcpy(&cmdbuf[32], buf, size); + } else { /* STLINK_TCP_REQUEST_READ or STLINK_TCP_REQUEST_READ_SWO */ + data_size += size; + if (data_size > STLINK_TCP_RECV_BUFFER_SIZE) { + LOG_ERROR("STLINK_TCP data buffer overflow"); + return ERROR_FAIL; + } + } + + int ret = stlink_server_send_cmd(h, cmdbuf, cmd_size, databuf, data_size, true); + if (ret != ERROR_OK) + return ret; + + if (h->direction != h->tx_ep) + memcpy((uint8_t *) buf, &databuf[STLINK_TCP_SS_SIZE], size); + + return ERROR_OK; +} + /** Converts an STLINK status code held in the first byte of a response to an openocd error, logs any error/wait status as debug output. @@ -2737,6 +2891,38 @@ static int stlink_usb_close(void *handle) } /** */ +static int stlink_server_close(void *handle) +{ + struct stlink_usb_handle_s *h = handle; + struct stlink_server_priv_s *itf_priv = h->itf->priv; + + int ret = ERROR_OK; + uint8_t cmdbuf[STLINK_TCP_SEND_BUFFER_SIZE]; + uint8_t databuf[STLINK_TCP_RECV_BUFFER_SIZE]; + + if (h && itf_priv->connected) { + if (itf_priv->connect_id) { + stlink_usb_exit_mode(h); + + /* close the stlink */ + cmdbuf[0] = STLINK_TCP_CMD_CLOSE_DEV; + memset(&cmdbuf[1], 0, 4); /* reserved */ + h_u32_to_le(&cmdbuf[4], itf_priv->connect_id); + ret = stlink_server_send_cmd(h, cmdbuf, 8, databuf, 4, true); + if (ret != ERROR_OK) + LOG_ERROR("cannot close the STLINK"); + } + + if (close_socket(itf_priv->fd) != 0) { + LOG_ERROR("error closing the socket"); + LOG_DEBUG("close error: %s (errno %d)", strerror(errno), errno); + } + } + + return ret; +} + +/** */ static int stlink_close(void *handle) { struct stlink_usb_handle_s *h = handle; @@ -2931,6 +3117,188 @@ static int stlink_usb_open(void *handle, struct hl_interface_param_s *param) return ERROR_OK; } +static int stlink_server_open(void *handle, struct hl_interface_param_s *param) +{ + struct stlink_usb_handle_s *h = handle; + struct stlink_server_priv_s *itf_priv = h->itf->priv; + int ret; + uint8_t cmdbuf[STLINK_TCP_SEND_BUFFER_SIZE]; + uint8_t databuf[STLINK_TCP_RECV_BUFFER_SIZE]; + + /* SWIM is not supported using stlink-server */ + if (h->st_mode == STLINK_MODE_DEBUG_SWIM) { + LOG_ERROR("stlink-server does not support SWIM mode"); + return ERROR_FAIL; + } + + /* configure directions */ + h->rx_ep = STLINK_TCP_REQUEST_READ; + h->tx_ep = STLINK_TCP_REQUEST_WRITE; + h->trace_ep = STLINK_TCP_REQUEST_READ_SWO; + + itf_priv->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + itf_priv->connected = false; + itf_priv->device_id = 0; + itf_priv->connect_id = 0; + + struct sockaddr_in serv; + memset(&serv, 0, sizeof(struct sockaddr_in)); + serv.sin_family = AF_INET; + serv.sin_port = htons(param->stlink_server_port); + serv.sin_addr.s_addr = inet_addr("127.0.0.1"); + + LOG_DEBUG("socket : %x", itf_priv->fd); + + int res; + + int flag = 1; + res = setsockopt(itf_priv->fd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(flag)); + if (res == -1) { + LOG_ERROR("cannot set sock option 'TCP_NODELEAY', errno: %s", strerror(errno)); + return ERROR_FAIL; + } + + int a = 49152; + res = setsockopt(itf_priv->fd, SOL_SOCKET, SO_RCVBUF, (char *) &a, sizeof(a)); + if (res == -1) { + LOG_ERROR("cannot set sock option 'SO_RCVBUF', errno: %s", strerror(errno)); + return ERROR_FAIL; + } + + res = setsockopt(itf_priv->fd, SOL_SOCKET, SO_SNDBUF, (char *) &a, sizeof(a)); + if (res == -1) { + LOG_ERROR("cannot set sock option 'SO_SNDBUF', errno: %s", strerror(errno)); + return ERROR_FAIL; + } + + if (connect(itf_priv->fd, (const struct sockaddr *) &serv, sizeof(serv)) == -1) { + LOG_ERROR("cannot connect to stlink server"); + return ERROR_FAIL; + } + + itf_priv->connected = true; + + LOG_INFO("connected to stlink-server"); + + /* print stlink-server version */ + cmdbuf[0] = STLINK_TCP_CMD_GET_SERVER_VERSION; + cmdbuf[1] = OPENOCD_STLINK_TCP_API_VERSION; + memset(&cmdbuf[2], 0, 2); /* reserved */ + ret = stlink_server_send_cmd(h, cmdbuf, 4, databuf, 16, false); + if (ret != ERROR_OK) { + LOG_ERROR("cannot get the stlink-server version"); + return ERROR_FAIL; + } + + uint32_t api_ver = le_to_h_u32(&databuf[0]); + uint32_t ver_major = le_to_h_u32(&databuf[4]); + uint32_t ver_minor = le_to_h_u32(&databuf[8]); + uint32_t ver_build = le_to_h_u32(&databuf[12]); + LOG_INFO("stlink-server API v%d, version %d.%d.%d", + api_ver, ver_major, ver_minor, ver_build); + + /* refresh stlink list (re-enumerate) */ + cmdbuf[0] = STLINK_TCP_CMD_REFRESH_DEVICE_LIST; + cmdbuf[1] = 0; /* don't clear the list, just refresh it */ + ret = stlink_server_send_cmd(h, cmdbuf, 2, databuf, 4, true); + if (ret != ERROR_OK) + return ret; + + /* get the number of connected stlinks */ + cmdbuf[0] = STLINK_TCP_CMD_GET_NB_DEV; + ret = stlink_server_send_cmd(h, cmdbuf, 1, databuf, 4, false); + if (ret != ERROR_OK) + return ret; + + uint32_t connected_stlinks = le_to_h_u32(databuf); + + if (connected_stlinks == 0) { + LOG_ERROR("no ST-LINK detected"); + return ERROR_FAIL; + } + + LOG_DEBUG("%d ST-LINK detected", connected_stlinks); + + /* list all connected ST-Link and seek for the requested vid:pid and serial */ + uint8_t serial[STLINK_TCP_SERIAL_SIZE+1] = {0}; + uint8_t stlink_used; + bool stlink_id_matched = false; + bool stlink_serial_matched = (param->serial == NULL); + + for (uint32_t stlink_id = 0; stlink_id < connected_stlinks; stlink_id++) { + /* get the stlink info */ + cmdbuf[0] = STLINK_TCP_CMD_GET_DEV_INFO; + cmdbuf[1] = (uint8_t) stlink_id; + memset(&cmdbuf[2], 0, 2); /* reserved */ + h_u32_to_le(&cmdbuf[4], 41); /* size of TDeviceInfo2 */ + ret = stlink_server_send_cmd(h, cmdbuf, 8, databuf, 45, true); + if (ret != ERROR_OK) + return ret; + + itf_priv->device_id = le_to_h_u32(&databuf[4]); + memcpy(serial, &databuf[8], STLINK_TCP_SERIAL_SIZE); + h->vid = le_to_h_u16(&databuf[40]); + h->pid = le_to_h_u16(&databuf[42]); + stlink_used = databuf[44]; + + /* check the vid:pid */ + for (int i = 0; param->vid[i]; i++) { + if (param->vid[i] == h->vid && param->pid[i] == h->pid) { + stlink_id_matched = true; + break; + } + } + + if (!stlink_id_matched) + continue; + + /* check the serial if specified */ + if (param->serial) + stlink_serial_matched = strcmp(param->serial, (const char *) serial) == 0; + + if (!stlink_serial_matched) + LOG_DEBUG("Device serial number '%s' doesn't match requested serial '%s'", + (const char *) serial, param->serial); + else /* exit the search loop if there is match */ + break; + } + + if (!stlink_id_matched) { + LOG_ERROR("ST-LINK open failed (vid/pid mismatch)"); + return ERROR_FAIL; + } + + if (!stlink_serial_matched) { + LOG_ERROR("ST-LINK open failed (serial mismatch)"); + return ERROR_FAIL; + } + + /* check if device is 'exclusively' used by another application */ + if (stlink_used) { + LOG_ERROR("the selected device is already used"); + return ERROR_FAIL; + } + + LOG_DEBUG("transport: vid: 0x%04x pid: 0x%04x serial: %s", h->vid, h->pid, serial); + + /* now let's open the stlink */ + cmdbuf[0] = STLINK_TCP_CMD_OPEN_DEV; + memset(&cmdbuf[1], 0, 4); /* reserved */ + h_u32_to_le(&cmdbuf[4], itf_priv->device_id); + ret = stlink_server_send_cmd(h, cmdbuf, 8, databuf, 8, true); + if (ret != ERROR_OK) + return ret; + + itf_priv->connect_id = le_to_h_u32(&databuf[4]); + + /* get stlink version */ + ret = stlink_usb_version(h); + if (ret != ERROR_OK) + return ERROR_FAIL; + + return ERROR_OK; +} + static struct stlink_interface_s stlink_usb_itf = { .open = stlink_usb_open, .close = stlink_usb_close, @@ -2938,6 +3306,13 @@ static struct stlink_interface_s stlink_usb_itf = { .read = stlink_usb_bulk_read, }; +static struct stlink_interface_s stlink_server_itf = { + .open = stlink_server_open, + .close = stlink_server_close, + .xfer = stlink_server_xfer, + .read = stlink_server_xfer, +}; + static int stlink_open(struct hl_interface_param_s *param, enum stlink_mode mode, void **fd) { struct stlink_usb_handle_s *h; @@ -2959,8 +3334,13 @@ static int stlink_open(struct hl_interface_param_s *param, enum stlink_mode mode param->serial ? param->serial : ""); } - h->itf = &stlink_usb_itf; - h->itf->priv = calloc(1, sizeof(struct stlink_usb_priv_s)); + if (param->use_stlink_server) { + h->itf = &stlink_server_itf; + h->itf->priv = calloc(1, sizeof(struct stlink_server_priv_s)); + } else { + h->itf = &stlink_usb_itf; + h->itf->priv = calloc(1, sizeof(struct stlink_usb_priv_s)); + } if (h->itf->priv == NULL || h->itf->open(h, param) != ERROR_OK) goto error_open; @@ -3691,6 +4071,20 @@ COMMAND_HANDLER(stlink_dap_vid_pid) } /** */ +COMMAND_HANDLER(stlink_dap_use_stlink_server_command) +{ + stlink_dap_param.use_stlink_server = true; + stlink_dap_param.stlink_server_port = 7184; /* default stlink-server port */ + + if (CMD_ARGC > 1) + LOG_ERROR("maximum expected arguments is 1"); + else if (CMD_ARGC > 0) + COMMAND_PARSE_NUMBER(u16, CMD_ARGV[CMD_ARGC - 1], stlink_dap_param.stlink_server_port); + + return ERROR_OK; +} + +/** */ static const struct command_registration stlink_dap_subcommand_handlers[] = { { .name = "serial", @@ -3706,6 +4100,13 @@ static const struct command_registration stlink_dap_subcommand_handlers[] = { .help = "USB VID and PID of the adapter", .usage = "(vid pid)+", }, + { + .name = "use_stlink_server", + .handler = &stlink_dap_use_stlink_server_command, + .mode = COMMAND_CONFIG, + .help = "use stlink-server instead of direct usb transactions", + .usage = "[port]", + }, COMMAND_REGISTRATION_DONE }; diff --git a/src/jtag/hla/hla_interface.c b/src/jtag/hla/hla_interface.c index 6d5cdc5..a764d87 100644 --- a/src/jtag/hla/hla_interface.c +++ b/src/jtag/hla/hla_interface.c @@ -35,7 +35,7 @@ #include <target/target.h> -static struct hl_interface_s hl_if = { {0, 0, { 0 }, { 0 }, HL_TRANSPORT_UNKNOWN, false, -1}, 0, 0 }; +static struct hl_interface_s hl_if = { {0, 0, { 0 }, { 0 }, HL_TRANSPORT_UNKNOWN, false, -1, false, 7184}, 0, 0 }; int hl_interface_open(enum hl_transports tr) { @@ -321,28 +321,28 @@ static const struct command_registration hl_interface_command_handlers[] = { .mode = COMMAND_CONFIG, .help = "set the serial number of the adapter", .usage = "serial_string", - }, + }, { .name = "hla_layout", .handler = &hl_interface_handle_layout_command, .mode = COMMAND_CONFIG, .help = "set the layout of the adapter", .usage = "layout_name", - }, + }, { .name = "hla_vid_pid", .handler = &hl_interface_handle_vid_pid_command, .mode = COMMAND_CONFIG, .help = "the vendor and product ID of the adapter", .usage = "(vid pid)* ", - }, - { + }, + { .name = "hla_command", .handler = &interface_handle_hla_command, .mode = COMMAND_EXEC, .help = "execute a custom adapter-specific command", .usage = "hla_command <command>", - }, + }, COMMAND_REGISTRATION_DONE }; diff --git a/src/jtag/hla/hla_interface.h b/src/jtag/hla/hla_interface.h index b6e4a8b..80c6d63 100644 --- a/src/jtag/hla/hla_interface.h +++ b/src/jtag/hla/hla_interface.h @@ -46,6 +46,10 @@ struct hl_interface_param_s { bool connect_under_reset; /** Initial interface clock clock speed */ int initial_interface_speed; + /** */ + bool use_stlink_server; + /** */ + uint16_t stlink_server_port; }; struct hl_interface_s { -- _______________________________________________ OpenOCD-devel mailing list OpenOCD-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/openocd-devel