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

Reply via email to