78d4e33e17f33135feee967d3b23d330d6a194e7
[fw/openocd] / src / jtag / drivers / jtag_dpi.c
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2
3 /*
4  * JTAG to DPI driver
5  *
6  * Copyright (C) 2013 Franck Jullien, <elec4fun@gmail.com>
7  *
8  * Copyright (C) 2019-2020, Ampere Computing LLC
9  *
10  * See file CREDITS for list of people who contributed to this
11  * project.
12  */
13
14 #ifdef HAVE_CONFIG_H
15 #include "config.h"
16 #endif
17
18 #include <jtag/interface.h>
19 #ifdef HAVE_ARPA_INET_H
20 #include <arpa/inet.h>
21 #endif
22
23 #ifndef _WIN32
24 #include <netinet/tcp.h>
25 #endif
26
27 #define SERVER_ADDRESS  "127.0.0.1"
28 #define SERVER_PORT     5555
29
30 static uint16_t server_port = SERVER_PORT;
31 static char *server_address;
32
33 static int sockfd;
34 static struct sockaddr_in serv_addr;
35
36 static uint8_t *last_ir_buf;
37 static int last_ir_num_bits;
38
39 static int write_sock(char *buf, size_t len)
40 {
41         if (!buf) {
42                 LOG_ERROR("%s: NULL 'buf' argument, file %s, line %d",
43                         __func__, __FILE__, __LINE__);
44                 return ERROR_FAIL;
45         }
46         if (write(sockfd, buf, len) != (ssize_t)len) {
47                 LOG_ERROR("%s: %s, file %s, line %d", __func__,
48                         strerror(errno), __FILE__, __LINE__);
49                 return ERROR_FAIL;
50         }
51         return ERROR_OK;
52 }
53
54 static int read_sock(char *buf, size_t len)
55 {
56         if (!buf) {
57                 LOG_ERROR("%s: NULL 'buf' argument, file %s, line %d",
58                         __func__, __FILE__, __LINE__);
59                 return ERROR_FAIL;
60         }
61         if (read(sockfd, buf, len) != (ssize_t)len) {
62                 LOG_ERROR("%s: %s, file %s, line %d", __func__,
63                         strerror(errno), __FILE__, __LINE__);
64                 return ERROR_FAIL;
65         }
66         return ERROR_OK;
67 }
68
69 /**
70  * jtag_dpi_reset - ask to reset the JTAG device
71  * @param trst 1 if TRST is to be asserted
72  * @param srst 1 if SRST is to be asserted
73  */
74 static int jtag_dpi_reset(int trst, int srst)
75 {
76         char *buf = "reset\n";
77         int ret = ERROR_OK;
78
79         LOG_DEBUG_IO("JTAG DRIVER DEBUG: reset trst: %i srst %i", trst, srst);
80
81         if (trst == 1) {
82                 /* reset the JTAG TAP controller */
83                 ret = write_sock(buf, strlen(buf));
84                 if (ret != ERROR_OK) {
85                         LOG_ERROR("write_sock() fail, file %s, line %d",
86                                 __FILE__, __LINE__);
87                 }
88         }
89
90         if (srst == 1) {
91                 /* System target reset not supported */
92                 LOG_ERROR("DPI SRST not supported");
93                 ret = ERROR_FAIL;
94         }
95
96         return ret;
97 }
98
99 /**
100  * jtag_dpi_scan - launches a DR-scan or IR-scan
101  * @param cmd the command to launch
102  *
103  * Launch a JTAG IR-scan or DR-scan
104  *
105  * Returns ERROR_OK if OK, ERROR_xxx if a read/write error occurred.
106  */
107 static int jtag_dpi_scan(struct scan_command *cmd)
108 {
109         char buf[20];
110         uint8_t *data_buf;
111         int num_bits, bytes;
112         int ret = ERROR_OK;
113
114         num_bits = jtag_build_buffer(cmd, &data_buf);
115         if (!data_buf) {
116                 LOG_ERROR("jtag_build_buffer call failed, data_buf == NULL, "
117                         "file %s, line %d", __FILE__, __LINE__);
118                 return ERROR_FAIL;
119         }
120
121         bytes = DIV_ROUND_UP(num_bits, 8);
122         if (cmd->ir_scan) {
123                 free(last_ir_buf);
124                 last_ir_buf = (uint8_t *)malloc(bytes * sizeof(uint8_t));
125                 if (!last_ir_buf) {
126                         LOG_ERROR("%s: malloc fail, file %s, line %d",
127                                 __func__, __FILE__, __LINE__);
128                         ret = ERROR_FAIL;
129                         goto out;
130                 }
131                 memcpy(last_ir_buf, data_buf, bytes);
132                 last_ir_num_bits = num_bits;
133         }
134         snprintf(buf, sizeof(buf), "%s %d\n", cmd->ir_scan ? "ib" : "db", num_bits);
135         ret = write_sock(buf, strlen(buf));
136         if (ret != ERROR_OK) {
137                 LOG_ERROR("write_sock() fail, file %s, line %d",
138                         __FILE__, __LINE__);
139                 goto out;
140         }
141         ret = write_sock((char *)data_buf, bytes);
142         if (ret != ERROR_OK) {
143                 LOG_ERROR("write_sock() fail, file %s, line %d",
144                         __FILE__, __LINE__);
145                 goto out;
146         }
147         ret = read_sock((char *)data_buf, bytes);
148         if (ret != ERROR_OK) {
149                 LOG_ERROR("read_sock() fail, file %s, line %d",
150                         __FILE__, __LINE__);
151                 goto out;
152         }
153
154         ret = jtag_read_buffer(data_buf, cmd);
155         if (ret != ERROR_OK) {
156                 LOG_ERROR("jtag_read_buffer() fail, file %s, line %d",
157                         __FILE__, __LINE__);
158                 goto out;
159         }
160
161 out:
162         free(data_buf);
163         return ret;
164 }
165
166 static int jtag_dpi_runtest(int cycles)
167 {
168         char buf[20];
169         uint8_t *data_buf = last_ir_buf, *read_scan;
170         int num_bits = last_ir_num_bits, bytes;
171         int ret = ERROR_OK;
172
173         if (!data_buf) {
174                 LOG_ERROR("%s: NULL 'data_buf' argument, file %s, line %d",
175                         __func__, __FILE__, __LINE__);
176                 return ERROR_FAIL;
177         }
178         if (num_bits <= 0) {
179                 LOG_ERROR("%s: 'num_bits' invalid value, file %s, line %d",
180                         __func__, __FILE__, __LINE__);
181                 return ERROR_FAIL;
182         }
183
184         bytes = DIV_ROUND_UP(num_bits, 8);
185         read_scan = (uint8_t *)malloc(bytes * sizeof(uint8_t));
186         if (!read_scan) {
187                 LOG_ERROR("%s: malloc fail, file %s, line %d",
188                         __func__, __FILE__, __LINE__);
189                 return ERROR_FAIL;
190         }
191         snprintf(buf, sizeof(buf), "ib %d\n", num_bits);
192         while (cycles > 0) {
193                 ret = write_sock(buf, strlen(buf));
194                 if (ret != ERROR_OK) {
195                         LOG_ERROR("write_sock() fail, file %s, line %d",
196                                 __FILE__, __LINE__);
197                         goto out;
198                 }
199                 ret = write_sock((char *)data_buf, bytes);
200                 if (ret != ERROR_OK) {
201                         LOG_ERROR("write_sock() fail, file %s, line %d",
202                                 __FILE__, __LINE__);
203                         goto out;
204                 }
205                 ret = read_sock((char *)read_scan, bytes);
206                 if (ret != ERROR_OK) {
207                         LOG_ERROR("read_sock() fail, file %s, line %d",
208                                 __FILE__, __LINE__);
209                         goto out;
210                 }
211
212                 cycles -= num_bits + 6;
213         }
214
215 out:
216         free(read_scan);
217         return ret;
218 }
219
220 static int jtag_dpi_stableclocks(int cycles)
221 {
222         return jtag_dpi_runtest(cycles);
223 }
224
225 static int jtag_dpi_execute_queue(void)
226 {
227         struct jtag_command *cmd;
228         int ret = ERROR_OK;
229
230         for (cmd = jtag_command_queue; ret == ERROR_OK && cmd;
231              cmd = cmd->next) {
232                 switch (cmd->type) {
233                 case JTAG_RUNTEST:
234                         ret = jtag_dpi_runtest(cmd->cmd.runtest->num_cycles);
235                         break;
236                 case JTAG_STABLECLOCKS:
237                         ret = jtag_dpi_stableclocks(cmd->cmd.stableclocks->num_cycles);
238                         break;
239                 case JTAG_TLR_RESET:
240                         /* Enter Test-Logic-Reset state by asserting TRST */
241                         if (cmd->cmd.statemove->end_state == TAP_RESET)
242                                 jtag_dpi_reset(1, 0);
243                         break;
244                 case JTAG_PATHMOVE:
245                         /* unsupported */
246                         break;
247                 case JTAG_TMS:
248                         /* unsupported */
249                         break;
250                 case JTAG_SLEEP:
251                         jtag_sleep(cmd->cmd.sleep->us);
252                         break;
253                 case JTAG_SCAN:
254                         ret = jtag_dpi_scan(cmd->cmd.scan);
255                         break;
256                 default:
257                         LOG_ERROR("BUG: unknown JTAG command type 0x%X",
258                                   cmd->type);
259                         ret = ERROR_FAIL;
260                         break;
261                 }
262         }
263
264         return ret;
265 }
266
267 static int jtag_dpi_init(void)
268 {
269         sockfd = socket(AF_INET, SOCK_STREAM, 0);
270         if (sockfd < 0) {
271                 LOG_ERROR("socket: %s, function %s, file %s, line %d",
272                         strerror(errno), __func__, __FILE__, __LINE__);
273                 return ERROR_FAIL;
274         }
275
276         memset(&serv_addr, 0, sizeof(serv_addr));
277
278         serv_addr.sin_family = AF_INET;
279         serv_addr.sin_port = htons(server_port);
280
281         if (!server_address) {
282                 server_address = strdup(SERVER_ADDRESS);
283                 if (!server_address) {
284                         LOG_ERROR("%s: strdup fail, file %s, line %d",
285                                 __func__, __FILE__, __LINE__);
286                         return ERROR_FAIL;
287                 }
288         }
289
290         serv_addr.sin_addr.s_addr = inet_addr(server_address);
291
292         if (serv_addr.sin_addr.s_addr == INADDR_NONE) {
293                 LOG_ERROR("inet_addr error occurred");
294                 return ERROR_FAIL;
295         }
296
297         if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
298                 close(sockfd);
299                 LOG_ERROR("Can't connect to %s : %" PRIu16, server_address, server_port);
300                 return ERROR_FAIL;
301         }
302         if (serv_addr.sin_addr.s_addr == htonl(INADDR_LOOPBACK)) {
303                 /* This increases performance dramatically for local
304                 * connections, which is the most likely arrangement
305                 * for a DPI connection. */
306                 int flag = 1;
307                 setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(int));
308         }
309
310         LOG_INFO("Connection to %s : %" PRIu16 " succeed", server_address, server_port);
311
312         return ERROR_OK;
313 }
314
315 static int jtag_dpi_quit(void)
316 {
317         free(server_address);
318         server_address = NULL;
319
320         return close(sockfd);
321 }
322
323 COMMAND_HANDLER(jtag_dpi_set_port)
324 {
325         if (CMD_ARGC > 1)
326                 return ERROR_COMMAND_SYNTAX_ERROR;
327         else if (CMD_ARGC == 0)
328                 LOG_INFO("Using server port %" PRIu16, server_port);
329         else {
330                 COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], server_port);
331                 LOG_INFO("Set server port to %" PRIu16, server_port);
332         }
333
334         return ERROR_OK;
335 }
336
337 COMMAND_HANDLER(jtag_dpi_set_address)
338 {
339         if (CMD_ARGC > 1)
340                 return ERROR_COMMAND_SYNTAX_ERROR;
341         else if (CMD_ARGC == 0) {
342                 if (!server_address) {
343                         server_address = strdup(SERVER_ADDRESS);
344                         if (!server_address) {
345                                 LOG_ERROR("%s: strdup fail, file %s, line %d",
346                                         __func__, __FILE__, __LINE__);
347                                 return ERROR_FAIL;
348                         }
349                 }
350                 LOG_INFO("Using server address %s", server_address);
351         } else {
352                 free(server_address);
353                 server_address = strdup(CMD_ARGV[0]);
354                 if (!server_address) {
355                         LOG_ERROR("%s: strdup fail, file %s, line %d",
356                                 __func__, __FILE__, __LINE__);
357                         return ERROR_FAIL;
358                 }
359                 LOG_INFO("Set server address to %s", server_address);
360         }
361
362         return ERROR_OK;
363 }
364
365 static const struct command_registration jtag_dpi_subcommand_handlers[] = {
366         {
367                 .name = "set_port",
368                 .handler = &jtag_dpi_set_port,
369                 .mode = COMMAND_CONFIG,
370                 .help = "set the port of the DPI server",
371                 .usage = "[port]",
372         },
373         {
374                 .name = "set_address",
375                 .handler = &jtag_dpi_set_address,
376                 .mode = COMMAND_CONFIG,
377                 .help = "set the address of the DPI server",
378                 .usage = "[address]",
379         },
380         COMMAND_REGISTRATION_DONE
381 };
382
383 static const struct command_registration jtag_dpi_command_handlers[] = {
384         {
385                 .name = "jtag_dpi",
386                 .mode = COMMAND_ANY,
387                 .help = "perform jtag_dpi management",
388                 .chain = jtag_dpi_subcommand_handlers,
389                 .usage = "",
390         },
391         COMMAND_REGISTRATION_DONE
392 };
393
394 static struct jtag_interface jtag_dpi_interface = {
395         .supported = DEBUG_CAP_TMS_SEQ,
396         .execute_queue = jtag_dpi_execute_queue,
397 };
398
399 struct adapter_driver jtag_dpi_adapter_driver = {
400         .name = "jtag_dpi",
401         .transports = jtag_only,
402         .commands = jtag_dpi_command_handlers,
403         .init = jtag_dpi_init,
404         .quit = jtag_dpi_quit,
405         .reset = jtag_dpi_reset,
406         .jtag_ops = &jtag_dpi_interface,
407 };