remote_bitbang: Add SWD support
[openocd.git] / src / jtag / drivers / remote_bitbang.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2
3 /***************************************************************************
4 * Copyright (C) 2011 by Richard Uhler *
5 * ruhler@mit.edu *
6 * *
7 * Copyright (C) 2021 by Manuel Wick <manuel@matronix.de> *
8 ***************************************************************************/
9
10 #ifdef HAVE_CONFIG_H
11 #include "config.h"
12 #endif
13
14 #ifndef _WIN32
15 #include <sys/un.h>
16 #include <netdb.h>
17 #include <netinet/tcp.h>
18 #endif
19 #include "helper/system.h"
20 #include "helper/replacements.h"
21 #include <jtag/interface.h>
22 #include "bitbang.h"
23
24 /* arbitrary limit on host name length: */
25 #define REMOTE_BITBANG_HOST_MAX 255
26
27 static char *remote_bitbang_host;
28 static char *remote_bitbang_port;
29
30 static int remote_bitbang_fd;
31 static uint8_t remote_bitbang_send_buf[512];
32 static unsigned int remote_bitbang_send_buf_used;
33
34 /* Circular buffer. When start == end, the buffer is empty. */
35 static char remote_bitbang_recv_buf[256];
36 static unsigned int remote_bitbang_recv_buf_start;
37 static unsigned int remote_bitbang_recv_buf_end;
38
39 static bool remote_bitbang_recv_buf_full(void)
40 {
41 return remote_bitbang_recv_buf_end ==
42 ((remote_bitbang_recv_buf_start + sizeof(remote_bitbang_recv_buf) - 1) %
43 sizeof(remote_bitbang_recv_buf));
44 }
45
46 static bool remote_bitbang_recv_buf_empty(void)
47 {
48 return remote_bitbang_recv_buf_start == remote_bitbang_recv_buf_end;
49 }
50
51 static unsigned int remote_bitbang_recv_buf_contiguous_available_space(void)
52 {
53 if (remote_bitbang_recv_buf_end >= remote_bitbang_recv_buf_start) {
54 unsigned int space = sizeof(remote_bitbang_recv_buf) -
55 remote_bitbang_recv_buf_end;
56 if (remote_bitbang_recv_buf_start == 0)
57 space -= 1;
58 return space;
59 } else {
60 return remote_bitbang_recv_buf_start -
61 remote_bitbang_recv_buf_end - 1;
62 }
63 }
64
65 static int remote_bitbang_flush(void)
66 {
67 if (remote_bitbang_send_buf_used <= 0)
68 return ERROR_OK;
69
70 unsigned int offset = 0;
71 while (offset < remote_bitbang_send_buf_used) {
72 ssize_t written = write_socket(remote_bitbang_fd, remote_bitbang_send_buf + offset,
73 remote_bitbang_send_buf_used - offset);
74 if (written < 0) {
75 log_socket_error("remote_bitbang_putc");
76 remote_bitbang_send_buf_used = 0;
77 return ERROR_FAIL;
78 }
79 offset += written;
80 }
81 remote_bitbang_send_buf_used = 0;
82 return ERROR_OK;
83 }
84
85 enum block_bool {
86 NO_BLOCK,
87 BLOCK
88 };
89
90 /* Read any incoming data, placing it into the buffer. */
91 static int remote_bitbang_fill_buf(enum block_bool block)
92 {
93 if (remote_bitbang_recv_buf_empty()) {
94 /* If the buffer is empty, reset it to 0 so we get more
95 * contiguous space. */
96 remote_bitbang_recv_buf_start = 0;
97 remote_bitbang_recv_buf_end = 0;
98 }
99
100 if (block == BLOCK) {
101 if (remote_bitbang_flush() != ERROR_OK)
102 return ERROR_FAIL;
103 socket_block(remote_bitbang_fd);
104 }
105
106 bool first = true;
107 while (!remote_bitbang_recv_buf_full()) {
108 unsigned int contiguous_available_space =
109 remote_bitbang_recv_buf_contiguous_available_space();
110 ssize_t count = read_socket(remote_bitbang_fd,
111 remote_bitbang_recv_buf + remote_bitbang_recv_buf_end,
112 contiguous_available_space);
113 if (first && block == BLOCK)
114 socket_nonblock(remote_bitbang_fd);
115 first = false;
116 if (count > 0) {
117 remote_bitbang_recv_buf_end += count;
118 if (remote_bitbang_recv_buf_end == sizeof(remote_bitbang_recv_buf))
119 remote_bitbang_recv_buf_end = 0;
120 } else if (count == 0) {
121 return ERROR_OK;
122 } else if (count < 0) {
123 #ifdef _WIN32
124 if (WSAGetLastError() == WSAEWOULDBLOCK) {
125 #else
126 if (errno == EAGAIN) {
127 #endif
128 return ERROR_OK;
129 } else {
130 log_socket_error("remote_bitbang_fill_buf");
131 return ERROR_FAIL;
132 }
133 }
134 }
135
136 return ERROR_OK;
137 }
138
139 typedef enum {
140 NO_FLUSH,
141 FLUSH_SEND_BUF
142 } flush_bool_t;
143
144 static int remote_bitbang_queue(int c, flush_bool_t flush)
145 {
146 remote_bitbang_send_buf[remote_bitbang_send_buf_used++] = c;
147 if (flush == FLUSH_SEND_BUF ||
148 remote_bitbang_send_buf_used >= ARRAY_SIZE(remote_bitbang_send_buf))
149 return remote_bitbang_flush();
150 return ERROR_OK;
151 }
152
153 static int remote_bitbang_quit(void)
154 {
155 if (remote_bitbang_queue('Q', FLUSH_SEND_BUF) == ERROR_FAIL)
156 return ERROR_FAIL;
157
158 if (close_socket(remote_bitbang_fd) != 0) {
159 log_socket_error("close_socket");
160 return ERROR_FAIL;
161 }
162
163 free(remote_bitbang_host);
164 free(remote_bitbang_port);
165
166 LOG_INFO("remote_bitbang interface quit");
167 return ERROR_OK;
168 }
169
170 static bb_value_t char_to_int(int c)
171 {
172 switch (c) {
173 case '0':
174 return BB_LOW;
175 case '1':
176 return BB_HIGH;
177 default:
178 remote_bitbang_quit();
179 LOG_ERROR("remote_bitbang: invalid read response: %c(%i)", c, c);
180 return BB_ERROR;
181 }
182 }
183
184 static int remote_bitbang_sample(void)
185 {
186 if (remote_bitbang_fill_buf(NO_BLOCK) != ERROR_OK)
187 return ERROR_FAIL;
188 assert(!remote_bitbang_recv_buf_full());
189 return remote_bitbang_queue('R', NO_FLUSH);
190 }
191
192 static bb_value_t remote_bitbang_read_sample(void)
193 {
194 if (remote_bitbang_recv_buf_empty()) {
195 if (remote_bitbang_fill_buf(BLOCK) != ERROR_OK)
196 return BB_ERROR;
197 }
198 assert(!remote_bitbang_recv_buf_empty());
199 int c = remote_bitbang_recv_buf[remote_bitbang_recv_buf_start];
200 remote_bitbang_recv_buf_start =
201 (remote_bitbang_recv_buf_start + 1) % sizeof(remote_bitbang_recv_buf);
202 return char_to_int(c);
203 }
204
205 static int remote_bitbang_write(int tck, int tms, int tdi)
206 {
207 char c = '0' + ((tck ? 0x4 : 0x0) | (tms ? 0x2 : 0x0) | (tdi ? 0x1 : 0x0));
208 return remote_bitbang_queue(c, NO_FLUSH);
209 }
210
211 static int remote_bitbang_reset(int trst, int srst)
212 {
213 char c = 'r' + ((trst ? 0x2 : 0x0) | (srst ? 0x1 : 0x0));
214 /* Always flush the send buffer on reset, because the reset call need not be
215 * followed by jtag_execute_queue(). */
216 return remote_bitbang_queue(c, FLUSH_SEND_BUF);
217 }
218
219 static int remote_bitbang_blink(int on)
220 {
221 char c = on ? 'B' : 'b';
222 return remote_bitbang_queue(c, FLUSH_SEND_BUF);
223 }
224
225 static void remote_bitbang_swdio_drive(bool is_output)
226 {
227 char c = is_output ? 'O' : 'o';
228 if (remote_bitbang_queue(c, FLUSH_SEND_BUF) == ERROR_FAIL)
229 LOG_ERROR("Error setting direction for swdio");
230 }
231
232 static int remote_bitbang_swdio_read(void)
233 {
234 if (remote_bitbang_queue('c', FLUSH_SEND_BUF) != ERROR_FAIL)
235 return remote_bitbang_read_sample();
236 else
237 return BB_ERROR;
238 }
239
240 static int remote_bitbang_swd_write(int swclk, int swdio)
241 {
242 char c = 'd' + ((swclk ? 0x2 : 0x0) | (swdio ? 0x1 : 0x0));
243 return remote_bitbang_queue(c, NO_FLUSH);
244 }
245
246 static struct bitbang_interface remote_bitbang_bitbang = {
247 .buf_size = sizeof(remote_bitbang_recv_buf) - 1,
248 .sample = &remote_bitbang_sample,
249 .read_sample = &remote_bitbang_read_sample,
250 .write = &remote_bitbang_write,
251 .swdio_read = &remote_bitbang_swdio_read,
252 .swdio_drive = &remote_bitbang_swdio_drive,
253 .swd_write = &remote_bitbang_swd_write,
254 .blink = &remote_bitbang_blink,
255 };
256
257 static int remote_bitbang_init_tcp(void)
258 {
259 struct addrinfo hints = { .ai_family = AF_UNSPEC, .ai_socktype = SOCK_STREAM };
260 struct addrinfo *result, *rp;
261 int fd = 0;
262
263 LOG_INFO("Connecting to %s:%s",
264 remote_bitbang_host ? remote_bitbang_host : "localhost",
265 remote_bitbang_port);
266
267 /* Obtain address(es) matching host/port */
268 int s = getaddrinfo(remote_bitbang_host, remote_bitbang_port, &hints, &result);
269 if (s != 0) {
270 LOG_ERROR("getaddrinfo: %s\n", gai_strerror(s));
271 return ERROR_FAIL;
272 }
273
274 /* getaddrinfo() returns a list of address structures.
275 Try each address until we successfully connect(2).
276 If socket(2) (or connect(2)) fails, we (close the socket
277 and) try the next address. */
278
279 for (rp = result; rp ; rp = rp->ai_next) {
280 fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
281 if (fd == -1)
282 continue;
283
284 if (connect(fd, rp->ai_addr, rp->ai_addrlen) != -1)
285 break; /* Success */
286
287 close(fd);
288 }
289
290 /* We work hard to collapse the writes into the minimum number, so when
291 * we write something we want to get it to the other end of the
292 * connection as fast as possible. */
293 int one = 1;
294 /* On Windows optval has to be a const char *. */
295 setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (const char *)&one, sizeof(one));
296
297 freeaddrinfo(result); /* No longer needed */
298
299 if (!rp) { /* No address succeeded */
300 log_socket_error("Failed to connect");
301 return ERROR_FAIL;
302 }
303
304 return fd;
305 }
306
307 static int remote_bitbang_init_unix(void)
308 {
309 if (!remote_bitbang_host) {
310 LOG_ERROR("host/socket not specified");
311 return ERROR_FAIL;
312 }
313
314 LOG_INFO("Connecting to unix socket %s", remote_bitbang_host);
315 int fd = socket(PF_UNIX, SOCK_STREAM, 0);
316 if (fd < 0) {
317 log_socket_error("socket");
318 return ERROR_FAIL;
319 }
320
321 struct sockaddr_un addr;
322 addr.sun_family = AF_UNIX;
323 strncpy(addr.sun_path, remote_bitbang_host, sizeof(addr.sun_path));
324 addr.sun_path[sizeof(addr.sun_path)-1] = '\0';
325
326 if (connect(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < 0) {
327 log_socket_error("connect");
328 return ERROR_FAIL;
329 }
330
331 return fd;
332 }
333
334 static int remote_bitbang_init(void)
335 {
336 bitbang_interface = &remote_bitbang_bitbang;
337
338 remote_bitbang_recv_buf_start = 0;
339 remote_bitbang_recv_buf_end = 0;
340
341 LOG_INFO("Initializing remote_bitbang driver");
342 if (!remote_bitbang_port)
343 remote_bitbang_fd = remote_bitbang_init_unix();
344 else
345 remote_bitbang_fd = remote_bitbang_init_tcp();
346
347 if (remote_bitbang_fd < 0)
348 return remote_bitbang_fd;
349
350 socket_nonblock(remote_bitbang_fd);
351
352 LOG_INFO("remote_bitbang driver initialized");
353 return ERROR_OK;
354 }
355
356 COMMAND_HANDLER(remote_bitbang_handle_remote_bitbang_port_command)
357 {
358 if (CMD_ARGC == 1) {
359 uint16_t port;
360 COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], port);
361 free(remote_bitbang_port);
362 remote_bitbang_port = port == 0 ? NULL : strdup(CMD_ARGV[0]);
363 return ERROR_OK;
364 }
365 return ERROR_COMMAND_SYNTAX_ERROR;
366 }
367
368 COMMAND_HANDLER(remote_bitbang_handle_remote_bitbang_host_command)
369 {
370 if (CMD_ARGC == 1) {
371 free(remote_bitbang_host);
372 remote_bitbang_host = strdup(CMD_ARGV[0]);
373 return ERROR_OK;
374 }
375 return ERROR_COMMAND_SYNTAX_ERROR;
376 }
377
378 static const char * const remote_bitbang_transports[] = { "jtag", "swd", NULL };
379
380 static const struct command_registration remote_bitbang_subcommand_handlers[] = {
381 {
382 .name = "port",
383 .handler = remote_bitbang_handle_remote_bitbang_port_command,
384 .mode = COMMAND_CONFIG,
385 .help = "Set the port to use to connect to the remote jtag.\n"
386 " if 0 or unset, use unix sockets to connect to the remote jtag.",
387 .usage = "port_number",
388 },
389 {
390 .name = "host",
391 .handler = remote_bitbang_handle_remote_bitbang_host_command,
392 .mode = COMMAND_CONFIG,
393 .help = "Set the host to use to connect to the remote jtag.\n"
394 " if port is 0 or unset, this is the name of the unix socket to use.",
395 .usage = "host_name",
396 },
397 COMMAND_REGISTRATION_DONE,
398 };
399
400 static const struct command_registration remote_bitbang_command_handlers[] = {
401 {
402 .name = "remote_bitbang",
403 .mode = COMMAND_ANY,
404 .help = "perform remote_bitbang management",
405 .chain = remote_bitbang_subcommand_handlers,
406 .usage = "",
407 },
408 COMMAND_REGISTRATION_DONE
409 };
410
411 static int remote_bitbang_execute_queue(void)
412 {
413 /* safety: the send buffer must be empty, no leftover characters from
414 * previous transactions */
415 assert(remote_bitbang_send_buf_used == 0);
416
417 /* process the JTAG command queue */
418 int ret = bitbang_execute_queue();
419 if (ret != ERROR_OK)
420 return ret;
421
422 /* flush not-yet-sent characters, if any */
423 return remote_bitbang_flush();
424 }
425
426 static struct jtag_interface remote_bitbang_interface = {
427 .execute_queue = &remote_bitbang_execute_queue,
428 };
429
430 struct adapter_driver remote_bitbang_adapter_driver = {
431 .name = "remote_bitbang",
432 .transports = remote_bitbang_transports,
433 .commands = remote_bitbang_command_handlers,
434
435 .init = &remote_bitbang_init,
436 .quit = &remote_bitbang_quit,
437 .reset = &remote_bitbang_reset,
438
439 .jtag_ops = &remote_bitbang_interface,
440 .swd_ops = &bitbang_swd,
441 };

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)