1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* Copyright (C) 2020 by Daniel Anselmi <danselmi@gmx.ch> */
8 #include <helper/bits.h>
9 #include <helper/time_support.h>
10 #include <jtag/jtag.h>
11 #include <server/server.h>
12 #include <target/target.h>
17 #define IPDBG_BUFFER_SIZE 16384
18 #define IPDBG_MIN_NUM_OF_OPTIONS 2
19 #define IPDBG_MAX_NUM_OF_OPTIONS 14
20 #define IPDBG_MIN_DR_LENGTH 11
21 #define IPDBG_MAX_DR_LENGTH 13
22 #define IPDBG_TCP_PORT_STR_MAX_LENGTH 6
24 /* private connection data for IPDBG */
28 char buffer
[IPDBG_BUFFER_SIZE
];
31 struct ipdbg_connection
{
32 struct ipdbg_fifo dn_fifo
;
33 struct ipdbg_fifo up_fifo
;
37 struct ipdbg_service
{
38 struct ipdbg_hub
*hub
;
39 struct ipdbg_service
*next
;
41 struct ipdbg_connection connection
;
45 struct ipdbg_virtual_ir_info
{
52 uint32_t user_instruction
;
54 uint32_t active_connections
;
55 uint32_t active_services
;
59 uint32_t last_dn_tool
;
60 struct ipdbg_hub
*next
;
62 struct connection
**connections
;
63 uint8_t data_register_length
;
65 struct ipdbg_virtual_ir_info
*virtual_ir
;
68 static struct ipdbg_hub
*ipdbg_first_hub
;
70 static struct ipdbg_service
*ipdbg_first_service
;
72 static void ipdbg_init_fifo(struct ipdbg_fifo
*fifo
)
78 static bool ipdbg_fifo_is_empty(struct ipdbg_fifo
*fifo
)
80 return fifo
->count
== 0;
83 static bool ipdbg_fifo_is_full(struct ipdbg_fifo
*fifo
)
85 return fifo
->count
== IPDBG_BUFFER_SIZE
;
88 static void ipdbg_zero_rd_idx(struct ipdbg_fifo
*fifo
)
90 if (fifo
->rd_idx
== 0)
93 size_t ri
= fifo
->rd_idx
;
94 for (size_t idx
= 0; idx
< fifo
->count
; ++idx
)
95 fifo
->buffer
[idx
] = fifo
->buffer
[ri
++];
99 static void ipdbg_append_to_fifo(struct ipdbg_fifo
*fifo
, char data
)
101 if (ipdbg_fifo_is_full(fifo
))
104 ipdbg_zero_rd_idx(fifo
);
105 fifo
->buffer
[fifo
->count
++] = data
;
108 static char ipdbg_get_from_fifo(struct ipdbg_fifo
*fifo
)
110 if (ipdbg_fifo_is_empty(fifo
))
114 return fifo
->buffer
[fifo
->rd_idx
++];
117 static int ipdbg_move_buffer_to_connection(struct connection
*conn
, struct ipdbg_fifo
*fifo
)
119 if (ipdbg_fifo_is_empty(fifo
))
122 struct ipdbg_connection
*connection
= conn
->priv
;
123 if (connection
->closed
)
124 return ERROR_SERVER_REMOTE_CLOSED
;
126 ipdbg_zero_rd_idx(fifo
);
127 size_t bytes_written
= connection_write(conn
, fifo
->buffer
, fifo
->count
);
128 if (bytes_written
!= fifo
->count
) {
129 LOG_ERROR("error during write: %zu != %zu", bytes_written
, fifo
->count
);
130 connection
->closed
= true;
131 return ERROR_SERVER_REMOTE_CLOSED
;
134 fifo
->count
-= bytes_written
;
139 static int ipdbg_max_tools_from_data_register_length(uint8_t data_register_length
)
142 data_register_length
-= 10; /* 8 bit payload, 1 xoff-flag, 1 valid-flag; remaining bits used to select tool*/
143 while (data_register_length
--)
146 /* last tool is used to reset JtagCDC and transfer "XON" to host*/
147 return max_tools
- 1;
150 static struct ipdbg_service
*ipdbg_find_service(struct ipdbg_hub
*hub
, uint8_t tool
)
152 struct ipdbg_service
*service
;
153 for (service
= ipdbg_first_service
; service
; service
= service
->next
) {
154 if (service
->hub
== hub
&& service
->tool
== tool
)
160 static void ipdbg_add_service(struct ipdbg_service
*service
)
162 struct ipdbg_service
*iservice
;
163 if (ipdbg_first_service
) {
164 for (iservice
= ipdbg_first_service
; iservice
->next
; iservice
= iservice
->next
)
166 iservice
->next
= service
;
168 ipdbg_first_service
= service
;
171 static int ipdbg_create_service(struct ipdbg_hub
*hub
, uint8_t tool
, struct ipdbg_service
**service
, uint16_t port
)
173 *service
= calloc(1, sizeof(struct ipdbg_service
));
175 LOG_ERROR("Out of memory");
179 (*service
)->hub
= hub
;
180 (*service
)->tool
= tool
;
181 (*service
)->port
= port
;
186 static int ipdbg_remove_service(struct ipdbg_service
*service
)
188 if (!ipdbg_first_service
)
191 if (service
== ipdbg_first_service
) {
192 ipdbg_first_service
= ipdbg_first_service
->next
;
196 for (struct ipdbg_service
*iservice
= ipdbg_first_service
; iservice
->next
; iservice
= iservice
->next
) {
197 if (service
== iservice
->next
) {
198 iservice
->next
= service
->next
;
205 static struct ipdbg_hub
*ipdbg_find_hub(struct jtag_tap
*tap
,
206 uint32_t user_instruction
, struct ipdbg_virtual_ir_info
*virtual_ir
)
208 struct ipdbg_hub
*hub
= NULL
;
209 for (hub
= ipdbg_first_hub
; hub
; hub
= hub
->next
) {
210 if (hub
->tap
== tap
&& hub
->user_instruction
== user_instruction
) {
211 if ((!virtual_ir
&& !hub
->virtual_ir
) ||
212 (virtual_ir
&& hub
->virtual_ir
&&
213 virtual_ir
->instruction
== hub
->virtual_ir
->instruction
&&
214 virtual_ir
->length
== hub
->virtual_ir
->length
&&
215 virtual_ir
->value
== hub
->virtual_ir
->value
)) {
223 static void ipdbg_add_hub(struct ipdbg_hub
*hub
)
225 struct ipdbg_hub
*ihub
;
226 if (ipdbg_first_hub
) {
227 for (ihub
= ipdbg_first_hub
; ihub
->next
; ihub
= ihub
->next
)
231 ipdbg_first_hub
= hub
;
234 static int ipdbg_create_hub(struct jtag_tap
*tap
, uint32_t user_instruction
, uint8_t data_register_length
,
235 struct ipdbg_virtual_ir_info
*virtual_ir
, struct ipdbg_hub
**hub
)
238 struct ipdbg_hub
*new_hub
= calloc(1, sizeof(struct ipdbg_hub
));
241 LOG_ERROR("Out of memory");
245 new_hub
->max_tools
= ipdbg_max_tools_from_data_register_length(data_register_length
);
246 new_hub
->connections
= calloc(new_hub
->max_tools
, sizeof(struct connection
*));
247 if (!new_hub
->connections
) {
250 LOG_ERROR("Out of memory");
254 new_hub
->user_instruction
= user_instruction
;
255 new_hub
->data_register_length
= data_register_length
;
256 new_hub
->valid_mask
= BIT(data_register_length
- 1);
257 new_hub
->xoff_mask
= BIT(data_register_length
- 2);
258 new_hub
->tool_mask
= (new_hub
->xoff_mask
- 1) >> 8;
259 new_hub
->last_dn_tool
= new_hub
->tool_mask
;
260 new_hub
->virtual_ir
= virtual_ir
;
267 static void ipdbg_free_hub(struct ipdbg_hub
*hub
)
271 free(hub
->connections
);
272 free(hub
->virtual_ir
);
276 static int ipdbg_remove_hub(struct ipdbg_hub
*hub
)
278 if (!ipdbg_first_hub
)
280 if (hub
== ipdbg_first_hub
) {
281 ipdbg_first_hub
= ipdbg_first_hub
->next
;
285 for (struct ipdbg_hub
*ihub
= ipdbg_first_hub
; ihub
->next
; ihub
= ihub
->next
) {
286 if (hub
== ihub
->next
) {
287 ihub
->next
= hub
->next
;
295 static void ipdbg_init_scan_field(struct scan_field
*fields
, uint8_t *in_value
, int num_bits
, const uint8_t *out_value
)
297 fields
->check_mask
= NULL
;
298 fields
->check_value
= NULL
;
299 fields
->in_value
= in_value
;
300 fields
->num_bits
= num_bits
;
301 fields
->out_value
= out_value
;
304 static int ipdbg_shift_instr(struct ipdbg_hub
*hub
, uint32_t instr
)
309 struct jtag_tap
*tap
= hub
->tap
;
313 if (buf_get_u32(tap
->cur_instr
, 0, tap
->ir_length
) == instr
) {
314 /* there is already the requested instruction in the ir */
318 uint8_t *ir_out_val
= calloc(DIV_ROUND_UP(tap
->ir_length
, 8), 1);
320 LOG_ERROR("Out of memory");
323 buf_set_u32(ir_out_val
, 0, tap
->ir_length
, instr
);
325 struct scan_field fields
;
326 ipdbg_init_scan_field(&fields
, NULL
, tap
->ir_length
, ir_out_val
);
327 jtag_add_ir_scan(tap
, &fields
, TAP_IDLE
);
328 int retval
= jtag_execute_queue();
335 static int ipdbg_shift_vir(struct ipdbg_hub
*hub
)
340 if (!hub
->virtual_ir
)
343 int retval
= ipdbg_shift_instr(hub
, hub
->virtual_ir
->instruction
);
344 if (retval
!= ERROR_OK
)
347 struct jtag_tap
*tap
= hub
->tap
;
351 uint8_t *dr_out_val
= calloc(DIV_ROUND_UP(hub
->virtual_ir
->length
, 8), 1);
353 LOG_ERROR("Out of memory");
356 buf_set_u32(dr_out_val
, 0, hub
->virtual_ir
->length
, hub
->virtual_ir
->value
);
358 struct scan_field fields
;
359 ipdbg_init_scan_field(&fields
, NULL
, hub
->virtual_ir
->length
, dr_out_val
);
360 jtag_add_dr_scan(tap
, 1, &fields
, TAP_IDLE
);
361 retval
= jtag_execute_queue();
368 static int ipdbg_shift_data(struct ipdbg_hub
*hub
, uint32_t dn_data
, uint32_t *up_data
)
373 struct jtag_tap
*tap
= hub
->tap
;
377 uint8_t *dr_out_val
= calloc(DIV_ROUND_UP(hub
->data_register_length
, 8), 1);
379 LOG_ERROR("Out of memory");
382 buf_set_u32(dr_out_val
, 0, hub
->data_register_length
, dn_data
);
384 uint8_t *dr_in_val
= NULL
;
386 dr_in_val
= calloc(DIV_ROUND_UP(hub
->data_register_length
, 8), 1);
388 LOG_ERROR("Out of memory");
394 struct scan_field fields
;
395 ipdbg_init_scan_field(&fields
, dr_in_val
, hub
->data_register_length
, dr_out_val
);
396 jtag_add_dr_scan(tap
, 1, &fields
, TAP_IDLE
);
397 int retval
= jtag_execute_queue();
399 if (up_data
&& retval
== ERROR_OK
)
400 *up_data
= buf_get_u32(dr_in_val
, 0, hub
->data_register_length
);
408 static int ipdbg_distribute_data_from_hub(struct ipdbg_hub
*hub
, uint32_t up
)
410 const bool valid_up_data
= up
& hub
->valid_mask
;
414 const size_t tool
= (up
>> 8) & hub
->tool_mask
;
415 if (tool
== hub
->tool_mask
) {
416 const uint8_t xon_cmd
= up
& 0x00ff;
417 hub
->dn_xoff
&= ~xon_cmd
;
418 LOG_INFO("received xon cmd: %d\n", xon_cmd
);
422 struct connection
*conn
= hub
->connections
[tool
];
424 struct ipdbg_connection
*connection
= conn
->priv
;
425 if (ipdbg_fifo_is_full(&connection
->up_fifo
)) {
426 int retval
= ipdbg_move_buffer_to_connection(conn
, &connection
->up_fifo
);
427 if (retval
!= ERROR_OK
)
430 ipdbg_append_to_fifo(&connection
->up_fifo
, up
);
435 static int ipdbg_jtag_transfer_byte(struct ipdbg_hub
*hub
, size_t tool
, struct ipdbg_connection
*connection
)
437 uint32_t dn
= hub
->valid_mask
| ((tool
& hub
->tool_mask
) << 8) |
438 (0x00fful
& ipdbg_get_from_fifo(&connection
->dn_fifo
));
440 int ret
= ipdbg_shift_data(hub
, dn
, &up
);
444 ret
= ipdbg_distribute_data_from_hub(hub
, up
);
448 if ((up
& hub
->xoff_mask
) && (hub
->last_dn_tool
!= hub
->max_tools
)) {
449 hub
->dn_xoff
|= BIT(hub
->last_dn_tool
);
450 LOG_INFO("tool %d sent xoff", hub
->last_dn_tool
);
453 hub
->last_dn_tool
= tool
;
458 static int ipdbg_polling_callback(void *priv
)
460 struct ipdbg_hub
*hub
= priv
;
462 int ret
= ipdbg_shift_vir(hub
);
466 ret
= ipdbg_shift_instr(hub
, hub
->user_instruction
);
470 /* transfer dn buffers to jtag-hub */
471 unsigned int num_transfers
= 0;
472 for (size_t tool
= 0; tool
< hub
->max_tools
; ++tool
) {
473 struct connection
*conn
= hub
->connections
[tool
];
474 if (conn
&& conn
->priv
) {
475 struct ipdbg_connection
*connection
= conn
->priv
;
476 while (((hub
->dn_xoff
& BIT(tool
)) == 0) && !ipdbg_fifo_is_empty(&connection
->dn_fifo
)) {
477 ret
= ipdbg_jtag_transfer_byte(hub
, tool
, connection
);
485 /* some transfers to get data from jtag-hub in case there is no dn data */
486 while (num_transfers
++ < hub
->max_tools
) {
490 int retval
= ipdbg_shift_data(hub
, dn
, &up
);
491 if (retval
!= ERROR_OK
)
494 retval
= ipdbg_distribute_data_from_hub(hub
, up
);
495 if (retval
!= ERROR_OK
)
499 /* write from up fifos to sockets */
500 for (size_t tool
= 0; tool
< hub
->max_tools
; ++tool
) {
501 struct connection
*conn
= hub
->connections
[tool
];
502 if (conn
&& conn
->priv
) {
503 struct ipdbg_connection
*connection
= conn
->priv
;
504 int retval
= ipdbg_move_buffer_to_connection(conn
, &connection
->up_fifo
);
505 if (retval
!= ERROR_OK
)
513 static int ipdbg_start_polling(struct ipdbg_service
*service
, struct connection
*connection
)
515 struct ipdbg_hub
*hub
= service
->hub
;
516 hub
->connections
[service
->tool
] = connection
;
517 hub
->active_connections
++;
518 if (hub
->active_connections
> 1) {
519 /* hub is already initialized */
523 const uint32_t reset_hub
= hub
->valid_mask
| ((hub
->max_tools
) << 8);
525 int ret
= ipdbg_shift_vir(hub
);
529 ret
= ipdbg_shift_instr(hub
, hub
->user_instruction
);
533 ret
= ipdbg_shift_data(hub
, reset_hub
, NULL
);
534 hub
->last_dn_tool
= hub
->tool_mask
;
539 LOG_INFO("IPDBG start_polling");
541 const int time_ms
= 20;
542 const int periodic
= 1;
543 return target_register_timer_callback(ipdbg_polling_callback
, time_ms
, periodic
, hub
);
546 static int ipdbg_stop_polling(struct ipdbg_service
*service
)
548 struct ipdbg_hub
*hub
= service
->hub
;
549 hub
->connections
[service
->tool
] = NULL
;
550 hub
->active_connections
--;
551 if (hub
->active_connections
== 0) {
552 LOG_INFO("IPDBG stop_polling");
554 return target_unregister_timer_callback(ipdbg_polling_callback
, hub
);
560 static int ipdbg_on_new_connection(struct connection
*connection
)
562 struct ipdbg_service
*service
= connection
->service
->priv
;
563 connection
->priv
= &service
->connection
;
564 /* initialize ipdbg connection information */
565 ipdbg_init_fifo(&service
->connection
.up_fifo
);
566 ipdbg_init_fifo(&service
->connection
.dn_fifo
);
568 int retval
= ipdbg_start_polling(service
, connection
);
569 if (retval
!= ERROR_OK
) {
570 LOG_ERROR("BUG: ipdbg_start_polling failed");
574 struct ipdbg_connection
*conn
= connection
->priv
;
575 conn
->closed
= false;
577 LOG_INFO("New IPDBG Connection");
582 static int ipdbg_on_connection_input(struct connection
*connection
)
584 struct ipdbg_connection
*conn
= connection
->priv
;
585 struct ipdbg_fifo
*fifo
= &conn
->dn_fifo
;
587 if (ipdbg_fifo_is_full(fifo
))
590 ipdbg_zero_rd_idx(fifo
);
591 int bytes_read
= connection_read(connection
, fifo
->buffer
+ fifo
->count
, IPDBG_BUFFER_SIZE
- fifo
->count
);
592 if (bytes_read
<= 0) {
594 LOG_ERROR("error during read: %s", strerror(errno
));
595 return ERROR_SERVER_REMOTE_CLOSED
;
598 fifo
->count
+= bytes_read
;
603 static int ipdbg_on_connection_closed(struct connection
*connection
)
605 struct ipdbg_connection
*conn
= connection
->priv
;
607 LOG_INFO("Closed IPDBG Connection");
609 return ipdbg_stop_polling(connection
->service
->priv
);
612 static const struct service_driver ipdbg_service_driver
= {
614 .new_connection_during_keep_alive_handler
= NULL
,
615 .new_connection_handler
= ipdbg_on_new_connection
,
616 .input_handler
= ipdbg_on_connection_input
,
617 .connection_closed_handler
= ipdbg_on_connection_closed
,
618 .keep_client_alive_handler
= NULL
,
621 static int ipdbg_start(uint16_t port
, struct jtag_tap
*tap
, uint32_t user_instruction
,
622 uint8_t data_register_length
, struct ipdbg_virtual_ir_info
*virtual_ir
, uint8_t tool
)
624 LOG_INFO("starting ipdbg service on port %d for tool %d", port
, tool
);
626 struct ipdbg_hub
*hub
= ipdbg_find_hub(tap
, user_instruction
, virtual_ir
);
629 if (hub
->data_register_length
!= data_register_length
) {
630 LOG_DEBUG("hub must have the same data_register_length for all tools");
634 int retval
= ipdbg_create_hub(tap
, user_instruction
, data_register_length
, virtual_ir
, &hub
);
635 if (retval
!= ERROR_OK
)
639 struct ipdbg_service
*service
= NULL
;
640 int retval
= ipdbg_create_service(hub
, tool
, &service
, port
);
642 if (retval
!= ERROR_OK
|| !service
) {
643 if (hub
->active_services
== 0 && hub
->active_connections
== 0)
648 char port_str_buffer
[IPDBG_TCP_PORT_STR_MAX_LENGTH
];
649 snprintf(port_str_buffer
, IPDBG_TCP_PORT_STR_MAX_LENGTH
, "%u", port
);
650 retval
= add_service(&ipdbg_service_driver
, port_str_buffer
, 1, service
);
651 if (retval
== ERROR_OK
) {
652 ipdbg_add_service(service
);
653 if (hub
->active_services
== 0 && hub
->active_connections
== 0)
655 hub
->active_services
++;
657 if (hub
->active_services
== 0 && hub
->active_connections
== 0)
665 static int ipdbg_stop(struct jtag_tap
*tap
, uint32_t user_instruction
,
666 struct ipdbg_virtual_ir_info
*virtual_ir
, uint8_t tool
)
668 struct ipdbg_hub
*hub
= ipdbg_find_hub(tap
, user_instruction
, virtual_ir
);
673 struct ipdbg_service
*service
= ipdbg_find_service(hub
, tool
);
677 int retval
= ipdbg_remove_service(service
);
678 if (retval
!= ERROR_OK
) {
679 LOG_ERROR("BUG: ipdbg_remove_service failed");
683 char port_str_buffer
[IPDBG_TCP_PORT_STR_MAX_LENGTH
];
684 snprintf(port_str_buffer
, IPDBG_TCP_PORT_STR_MAX_LENGTH
, "%u", service
->port
);
685 retval
= remove_service("ipdbg", port_str_buffer
);
686 /* The ipdbg_service structure is freed by server.c:remove_service().
687 There the "priv" pointer is freed.*/
688 if (retval
!= ERROR_OK
) {
689 LOG_ERROR("BUG: remove_service failed");
692 hub
->active_services
--;
693 if (hub
->active_connections
== 0 && hub
->active_services
== 0) {
694 retval
= ipdbg_remove_hub(hub
);
695 if (retval
!= ERROR_OK
) {
696 LOG_ERROR("BUG: ipdbg_remove_hub failed");
704 COMMAND_HANDLER(handle_ipdbg_command
)
706 struct jtag_tap
*tap
= NULL
;
707 uint16_t port
= 4242;
709 uint32_t user_instruction
= 0x00;
710 uint8_t data_register_length
= IPDBG_MAX_DR_LENGTH
;
712 bool hub_configured
= false;
713 bool has_virtual_ir
= false;
714 uint32_t virtual_ir_instruction
= 0x00e;
715 uint32_t virtual_ir_length
= 5;
716 uint32_t virtual_ir_value
= 0x11;
717 struct ipdbg_virtual_ir_info
*virtual_ir
= NULL
;
720 if ((CMD_ARGC
< IPDBG_MIN_NUM_OF_OPTIONS
) || (CMD_ARGC
> IPDBG_MAX_NUM_OF_OPTIONS
))
721 return ERROR_COMMAND_SYNTAX_ERROR
;
723 for (unsigned int i
= 0; i
< CMD_ARGC
; ++i
) {
724 if (strcmp(CMD_ARGV
[i
], "-tap") == 0) {
725 if (i
+ 1 >= CMD_ARGC
|| CMD_ARGV
[i
+ 1][0] == '-') {
726 command_print(CMD
, "no TAP given");
729 tap
= jtag_tap_by_string(CMD_ARGV
[i
+ 1]);
731 command_print(CMD
, "Tap %s unknown", CMD_ARGV
[i
+ 1]);
735 } else if (strcmp(CMD_ARGV
[i
], "-hub") == 0) {
736 COMMAND_PARSE_ADDITIONAL_NUMBER(u32
, i
, user_instruction
, "ir_value to select hub");
737 hub_configured
= true;
738 COMMAND_PARSE_OPTIONAL_NUMBER(u8
, i
, data_register_length
);
739 if (data_register_length
< IPDBG_MIN_DR_LENGTH
||
740 data_register_length
> IPDBG_MAX_DR_LENGTH
) {
741 command_print(CMD
, "length of \"user\"-data register must be at least %d and at most %d.",
742 IPDBG_MIN_DR_LENGTH
, IPDBG_MAX_DR_LENGTH
);
745 } else if (strcmp(CMD_ARGV
[i
], "-pld") == 0) {
747 if (i
>= CMD_ARGC
|| CMD_ARGV
[i
][0] == '-')
748 return ERROR_COMMAND_SYNTAX_ERROR
;
749 struct pld_device
*device
= get_pld_device_by_name_or_numstr(CMD_ARGV
[i
]);
750 if (!device
|| !device
->driver
) {
751 command_print(CMD
, "pld device '#%s' is out of bounds or unknown", CMD_ARGV
[i
]);
754 COMMAND_PARSE_OPTIONAL_NUMBER(int, i
, user_num
);
755 struct pld_ipdbg_hub pld_hub
;
756 struct pld_driver
*driver
= device
->driver
;
757 if (!driver
->get_ipdbg_hub
) {
758 command_print(CMD
, "pld driver has no ipdbg support");
761 if (driver
->get_ipdbg_hub(user_num
, device
, &pld_hub
) != ERROR_OK
) {
762 command_print(CMD
, "unable to retrieve hub from pld driver");
766 command_print(CMD
, "no tap received from pld driver");
769 hub_configured
= true;
770 user_instruction
= pld_hub
.user_ir_code
;
773 } else if (strcmp(CMD_ARGV
[i
], "-vir") == 0) {
774 COMMAND_PARSE_OPTIONAL_NUMBER(u32
, i
, virtual_ir_value
);
775 COMMAND_PARSE_OPTIONAL_NUMBER(u32
, i
, virtual_ir_length
);
776 COMMAND_PARSE_OPTIONAL_NUMBER(u32
, i
, virtual_ir_instruction
);
777 has_virtual_ir
= true;
778 } else if (strcmp(CMD_ARGV
[i
], "-port") == 0) {
779 COMMAND_PARSE_ADDITIONAL_NUMBER(u16
, i
, port
, "port number");
780 } else if (strcmp(CMD_ARGV
[i
], "-tool") == 0) {
781 COMMAND_PARSE_ADDITIONAL_NUMBER(u8
, i
, tool
, "tool");
782 } else if (strcmp(CMD_ARGV
[i
], "-stop") == 0) {
784 } else if (strcmp(CMD_ARGV
[i
], "-start") == 0) {
787 command_print(CMD
, "Unknown argument: %s", CMD_ARGV
[i
]);
793 command_print(CMD
, "no valid tap selected");
797 if (!hub_configured
) {
798 command_print(CMD
, "hub not configured correctly");
802 if (tool
>= ipdbg_max_tools_from_data_register_length(data_register_length
)) {
803 command_print(CMD
, "Tool: %d is invalid", tool
);
807 if (has_virtual_ir
) {
808 virtual_ir
= calloc(1, sizeof(struct ipdbg_virtual_ir_info
));
810 LOG_ERROR("Out of memory");
813 virtual_ir
->instruction
= virtual_ir_instruction
;
814 virtual_ir
->length
= virtual_ir_length
;
815 virtual_ir
->value
= virtual_ir_value
;
819 return ipdbg_start(port
, tap
, user_instruction
, data_register_length
, virtual_ir
, tool
);
821 return ipdbg_stop(tap
, user_instruction
, virtual_ir
, tool
);
824 static const struct command_registration ipdbg_command_handlers
[] = {
827 .handler
= handle_ipdbg_command
,
828 .mode
= COMMAND_EXEC
,
829 .help
= "Starts or stops an IPDBG JTAG-Host server.",
830 .usage
= "[-start|-stop] -tap device.tap -hub ir_value [dr_length]"
831 " [-port number] [-tool number] [-vir [vir_value [length [instr_code]]]]",
833 COMMAND_REGISTRATION_DONE
836 int ipdbg_register_commands(struct command_context
*cmd_ctx
)
838 return register_commands(cmd_ctx
, NULL
, ipdbg_command_handlers
);
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)