721515552c9d0463c18b21d3052254caa85cc668
[fw/openocd] / src / target / target_request.c
1 /***************************************************************************
2  *   Copyright (C) 2007 by Dominic Rath                                    *
3  *   Dominic.Rath@gmx.de                                                   *
4  *                                                                         *
5  *   Copyright (C) 2007,2008 Ã˜yvind Harboe                                 *
6  *   oyvind.harboe@zylin.com                                               *
7  *                                                                         *
8  *   Copyright (C) 2008 by Spencer Oliver                                  *
9  *   spen@spen-soft.co.uk                                                  *
10  *                                                                         *
11  *   This program is free software; you can redistribute it and/or modify  *
12  *   it under the terms of the GNU General Public License as published by  *
13  *   the Free Software Foundation; either version 2 of the License, or     *
14  *   (at your option) any later version.                                   *
15  *                                                                         *
16  *   This program is distributed in the hope that it will be useful,       *
17  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
18  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
19  *   GNU General Public License for more details.                          *
20  *                                                                         *
21  *   You should have received a copy of the GNU General Public License     *
22  *   along with this program; if not, write to the                         *
23  *   Free Software Foundation, Inc.,                                       *
24  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
25  ***************************************************************************/
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif
29
30 #include "target.h"
31 #include "target_request.h"
32 #include "target_type.h"
33 #include "binarybuffer.h"
34 #include "trace.h"
35 #include "log.h"
36
37
38 static struct command *target_request_cmd = NULL;
39 static int charmsg_mode = 0;
40
41 static int target_asciimsg(struct target *target, uint32_t length)
42 {
43         char *msg = malloc(CEIL(length + 1, 4) * 4);
44         struct debug_msg_receiver *c = target->dbgmsg;
45
46         target->type->target_request_data(target, CEIL(length, 4), (uint8_t*)msg);
47         msg[length] = 0;
48
49         LOG_DEBUG("%s", msg);
50
51         while (c)
52         {
53                 command_print(c->cmd_ctx, "%s", msg);
54                 c = c->next;
55         }
56
57         return ERROR_OK;
58 }
59
60 static int target_charmsg(struct target *target, uint8_t msg)
61 {
62         LOG_USER_N("%c", msg);
63
64         return ERROR_OK;
65 }
66
67 static int target_hexmsg(struct target *target, int size, uint32_t length)
68 {
69         uint8_t *data = malloc(CEIL(length * size, 4) * 4);
70         char line[128];
71         int line_len;
72         struct debug_msg_receiver *c = target->dbgmsg;
73         uint32_t i;
74
75         LOG_DEBUG("size: %i, length: %i", (int)size, (int)length);
76
77         target->type->target_request_data(target, CEIL(length * size, 4), (uint8_t*)data);
78
79         line_len = 0;
80         for (i = 0; i < length; i++)
81         {
82                 switch (size)
83                 {
84                         case 4:
85                                 line_len += snprintf(line + line_len, 128 - line_len, "%8.8" PRIx32 " ", le_to_h_u32(data + (4*i)));
86                                 break;
87                         case 2:
88                                 line_len += snprintf(line + line_len, 128 - line_len, "%4.4x ", le_to_h_u16(data + (2*i)));
89                                 break;
90                         case 1:
91                                 line_len += snprintf(line + line_len, 128 - line_len, "%2.2x ", data[i]);
92                                 break;
93                 }
94
95                 if ((i%8 == 7) || (i == length - 1))
96                 {
97                         LOG_DEBUG("%s", line);
98
99                         while (c)
100                         {
101                                 command_print(c->cmd_ctx, "%s", line);
102                                 c = c->next;
103                         }
104                         c = target->dbgmsg;
105                         line_len = 0;
106                 }
107         }
108
109         free(data);
110
111         return ERROR_OK;
112 }
113
114 /* handle requests from the target received by a target specific
115  * side-band channel (e.g. ARM7/9 DCC)
116  */
117 int target_request(struct target *target, uint32_t request)
118 {
119         target_req_cmd_t target_req_cmd = request & 0xff;
120
121         if (charmsg_mode) {
122                 target_charmsg(target, target_req_cmd);
123                 return ERROR_OK;
124         }
125         switch (target_req_cmd)
126         {
127                 case TARGET_REQ_TRACEMSG:
128                         trace_point(target, (request & 0xffffff00) >> 8);
129                         break;
130                 case TARGET_REQ_DEBUGMSG:
131                         if (((request & 0xff00) >> 8) == 0)
132                         {
133                                 target_asciimsg(target, (request & 0xffff0000) >> 16);
134                         }
135                         else
136                         {
137                                 target_hexmsg(target, (request & 0xff00) >> 8, (request & 0xffff0000) >> 16);
138                         }
139                         break;
140                 case TARGET_REQ_DEBUGCHAR:
141                         target_charmsg(target, (request & 0x00ff0000) >> 16);
142                         break;
143 /*              case TARGET_REQ_SEMIHOSTING:
144  *                      break;
145  */
146                 default:
147                         LOG_ERROR("unknown target request: %2.2x", target_req_cmd);
148                         break;
149         }
150
151         return ERROR_OK;
152 }
153
154 static int add_debug_msg_receiver(struct command_context *cmd_ctx, struct target *target)
155 {
156         struct debug_msg_receiver **p = &target->dbgmsg;
157
158         if (target == NULL)
159                 return ERROR_INVALID_ARGUMENTS;
160
161         /* see if there's already a list */
162         if (*p)
163         {
164                 /* find end of linked list */
165                 p = &target->dbgmsg;
166                 while ((*p)->next)
167                         p = &((*p)->next);
168                 p = &((*p)->next);
169         }
170
171         /* add new debug message receiver */
172         (*p) = malloc(sizeof(struct debug_msg_receiver));
173         (*p)->cmd_ctx = cmd_ctx;
174         (*p)->next = NULL;
175
176         /* enable callback */
177         target->dbg_msg_enabled = 1;
178
179         return ERROR_OK;
180 }
181
182 static struct debug_msg_receiver* find_debug_msg_receiver(struct command_context *cmd_ctx, struct target *target)
183 {
184         int do_all_targets = 0;
185         struct debug_msg_receiver **p = &target->dbgmsg;
186
187         /* if no target has been specified search all of them */
188         if (target == NULL)
189         {
190                 /* if no targets haven been specified */
191                 if (all_targets == NULL)
192                         return NULL;
193
194                 target = all_targets;
195                 do_all_targets = 1;
196         }
197
198         do
199         {
200                 while (*p)
201                 {
202                         if ((*p)->cmd_ctx == cmd_ctx)
203                         {
204                                 return *p;
205                         }
206                         p = &((*p)->next);
207                 }
208
209                 target = target->next;
210         } while (target && do_all_targets);
211
212         return NULL;
213 }
214
215 int delete_debug_msg_receiver(struct command_context *cmd_ctx, struct target *target)
216 {
217         struct debug_msg_receiver **p;
218         struct debug_msg_receiver *c;
219         int do_all_targets = 0;
220
221         /* if no target has been specified search all of them */
222         if (target == NULL)
223         {
224                 /* if no targets haven been specified */
225                 if (all_targets == NULL)
226                         return ERROR_OK;
227
228                 target = all_targets;
229                 do_all_targets = 1;
230         }
231
232         do
233         {
234                 p = &target->dbgmsg;
235                 c = *p;
236                 while (c)
237                 {
238                         struct debug_msg_receiver *next = c->next;
239                         if (c->cmd_ctx == cmd_ctx)
240                         {
241                                 *p = next;
242                                 free(c);
243                                 if (*p == NULL)
244                                 {
245                                         /* disable callback */
246                                         target->dbg_msg_enabled = 0;
247                                 }
248                                 return ERROR_OK;
249                         }
250                         else
251                                 p = &(c->next);
252                         c = next;
253                 }
254
255                 target = target->next;
256         } while (target && do_all_targets);
257
258         return ERROR_OK;
259 }
260
261 COMMAND_HANDLER(handle_target_request_debugmsgs_command)
262 {
263         struct target *target = get_current_target(cmd_ctx);
264
265         int receiving = 0;
266
267         /* see if reciever is already registered */
268         if (find_debug_msg_receiver(cmd_ctx, target) != NULL)
269                 receiving = 1;
270
271         if (argc > 0)
272         {
273                 if (!strcmp(args[0], "enable") || !strcmp(args[0], "charmsg"))
274                 {
275                         /* don't register if this command context is already receiving */
276                         if (!receiving)
277                         {
278                                 receiving = 1;
279                                 add_debug_msg_receiver(cmd_ctx, target);
280                         }
281                         charmsg_mode = !strcmp(args[0], "charmsg");
282                 }
283                 else if (!strcmp(args[0], "disable"))
284                 {
285                         /* no need to delete a receiver if none is registered */
286                         if (receiving)
287                         {
288                                 receiving = 0;
289                                 delete_debug_msg_receiver(cmd_ctx, target);
290                         }
291                 }
292                 else
293                 {
294                         command_print(cmd_ctx, "usage: target_request debugmsgs ['enable'|'disable'|'charmsg']");
295                 }
296         }
297
298         command_print(cmd_ctx, "receiving debug messages from current target %s",
299                       (receiving) ? (charmsg_mode?"charmsg":"enabled") : "disabled");
300         return ERROR_OK;
301 }
302
303 int target_request_register_commands(struct command_context *cmd_ctx)
304 {
305         target_request_cmd =
306                 register_command(cmd_ctx, NULL, "target_request", NULL, COMMAND_ANY, "target_request commands");
307
308         register_command(cmd_ctx, target_request_cmd, "debugmsgs", handle_target_request_debugmsgs_command,
309                 COMMAND_EXEC, "enable/disable reception of debug messages from target");
310
311         return ERROR_OK;
312 }