f31f901f0b7bd328e19f7319f796aab2645d1780
[openocd.git] / src / target / arm_semihosting.c
1 /***************************************************************************
2 * Copyright (C) 2009 by Marvell Technology Group Ltd. *
3 * Written by Nicolas Pitre <nico@marvell.com> *
4 * *
5 * Copyright (C) 2010 by Spencer Oliver *
6 * spen@spen-soft.co.uk *
7 * *
8 * Copyright (C) 2016 by Square, Inc. *
9 * Steven Stallion <stallion@squareup.com> *
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, see <http://www.gnu.org/licenses/>. *
23 ***************************************************************************/
24
25 /**
26 * @file
27 * Hold ARM semihosting support.
28 *
29 * Semihosting enables code running on an ARM target to use the I/O
30 * facilities on the host computer. The target application must be linked
31 * against a library that forwards operation requests by using the SVC
32 * instruction trapped at the Supervisor Call vector by the debugger.
33 * Details can be found in chapter 8 of DUI0203I_rvct_developer_guide.pdf
34 * from ARM Ltd.
35 */
36
37 #ifdef HAVE_CONFIG_H
38 #include "config.h"
39 #endif
40
41 #include "arm.h"
42 #include "armv4_5.h"
43 #include "arm7_9_common.h"
44 #include "armv7m.h"
45 #include "armv7a.h"
46 #include "cortex_m.h"
47 #include "register.h"
48 #include "arm_opcodes.h"
49 #include "target_type.h"
50 #include "arm_semihosting.h"
51 #include <helper/binarybuffer.h>
52 #include <helper/log.h>
53 #include <sys/stat.h>
54
55 static const int open_modeflags[12] = {
56 O_RDONLY,
57 O_RDONLY | O_BINARY,
58 O_RDWR,
59 O_RDWR | O_BINARY,
60 O_WRONLY | O_CREAT | O_TRUNC,
61 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
62 O_RDWR | O_CREAT | O_TRUNC,
63 O_RDWR | O_CREAT | O_TRUNC | O_BINARY,
64 O_WRONLY | O_CREAT | O_APPEND,
65 O_WRONLY | O_CREAT | O_APPEND | O_BINARY,
66 O_RDWR | O_CREAT | O_APPEND,
67 O_RDWR | O_CREAT | O_APPEND | O_BINARY
68 };
69
70 static int post_result(struct target *target)
71 {
72 struct arm *arm = target_to_arm(target);
73
74 /* REVISIT this looks wrong ... ARM11 and Cortex-A8
75 * should work this way at least sometimes.
76 */
77 if (is_arm7_9(target_to_arm7_9(target)) ||
78 is_armv7a(target_to_armv7a(target))) {
79 uint32_t spsr;
80
81 /* return value in R0 */
82 buf_set_u32(arm->core_cache->reg_list[0].value, 0, 32, arm->semihosting_result);
83 arm->core_cache->reg_list[0].dirty = 1;
84
85 /* LR --> PC */
86 buf_set_u32(arm->core_cache->reg_list[15].value, 0, 32,
87 buf_get_u32(arm_reg_current(arm, 14)->value, 0, 32));
88 arm->core_cache->reg_list[15].dirty = 1;
89
90 /* saved PSR --> current PSR */
91 spsr = buf_get_u32(arm->spsr->value, 0, 32);
92
93 /* REVISIT should this be arm_set_cpsr(arm, spsr)
94 * instead of a partially unrolled version?
95 */
96
97 buf_set_u32(arm->cpsr->value, 0, 32, spsr);
98 arm->cpsr->dirty = 1;
99 arm->core_mode = spsr & 0x1f;
100 if (spsr & 0x20)
101 arm->core_state = ARM_STATE_THUMB;
102
103 } else {
104 /* resume execution, this will be pc+2 to skip over the
105 * bkpt instruction */
106
107 /* return result in R0 */
108 buf_set_u32(arm->core_cache->reg_list[0].value, 0, 32, arm->semihosting_result);
109 arm->core_cache->reg_list[0].dirty = 1;
110 }
111
112 return ERROR_OK;
113 }
114
115 static int do_semihosting(struct target *target)
116 {
117 struct arm *arm = target_to_arm(target);
118 struct gdb_fileio_info *fileio_info = target->fileio_info;
119 uint32_t r0 = buf_get_u32(arm->core_cache->reg_list[0].value, 0, 32);
120 uint32_t r1 = buf_get_u32(arm->core_cache->reg_list[1].value, 0, 32);
121 uint8_t params[16];
122 int retval;
123
124 /*
125 * TODO: lots of security issues are not considered yet, such as:
126 * - no validation on target provided file descriptors
127 * - no safety checks on opened/deleted/renamed file paths
128 * Beware the target app you use this support with.
129 *
130 * TODO: unsupported semihosting fileio operations could be
131 * implemented if we had a small working area at our disposal.
132 */
133 switch ((arm->semihosting_op = r0)) {
134 case 0x01: /* SYS_OPEN */
135 retval = target_read_memory(target, r1, 4, 3, params);
136 if (retval != ERROR_OK)
137 return retval;
138 else {
139 uint32_t a = target_buffer_get_u32(target, params+0);
140 uint32_t m = target_buffer_get_u32(target, params+4);
141 uint32_t l = target_buffer_get_u32(target, params+8);
142 uint8_t fn[256];
143 retval = target_read_memory(target, a, 1, l, fn);
144 if (retval != ERROR_OK)
145 return retval;
146 fn[l] = 0;
147 if (arm->is_semihosting_fileio) {
148 if (strcmp((char *)fn, ":tt") == 0)
149 arm->semihosting_result = 0;
150 else {
151 arm->semihosting_hit_fileio = true;
152 fileio_info->identifier = "open";
153 fileio_info->param_1 = a;
154 fileio_info->param_2 = l;
155 fileio_info->param_3 = open_modeflags[m];
156 fileio_info->param_4 = 0644;
157 }
158 } else {
159 if (l <= 255 && m <= 11) {
160 if (strcmp((char *)fn, ":tt") == 0) {
161 if (m < 4)
162 arm->semihosting_result = dup(STDIN_FILENO);
163 else
164 arm->semihosting_result = dup(STDOUT_FILENO);
165 } else {
166 /* cygwin requires the permission setting
167 * otherwise it will fail to reopen a previously
168 * written file */
169 arm->semihosting_result = open((char *)fn, open_modeflags[m], 0644);
170 }
171 arm->semihosting_errno = errno;
172 } else {
173 arm->semihosting_result = -1;
174 arm->semihosting_errno = EINVAL;
175 }
176 }
177 }
178 break;
179
180 case 0x02: /* SYS_CLOSE */
181 retval = target_read_memory(target, r1, 4, 1, params);
182 if (retval != ERROR_OK)
183 return retval;
184 else {
185 int fd = target_buffer_get_u32(target, params+0);
186 if (arm->is_semihosting_fileio) {
187 arm->semihosting_hit_fileio = true;
188 fileio_info->identifier = "close";
189 fileio_info->param_1 = fd;
190 } else {
191 arm->semihosting_result = close(fd);
192 arm->semihosting_errno = errno;
193 }
194 }
195 break;
196
197 case 0x03: /* SYS_WRITEC */
198 if (arm->is_semihosting_fileio) {
199 arm->semihosting_hit_fileio = true;
200 fileio_info->identifier = "write";
201 fileio_info->param_1 = 1;
202 fileio_info->param_2 = r1;
203 fileio_info->param_3 = 1;
204 } else {
205 unsigned char c;
206 retval = target_read_memory(target, r1, 1, 1, &c);
207 if (retval != ERROR_OK)
208 return retval;
209 putchar(c);
210 arm->semihosting_result = 0;
211 }
212 break;
213
214 case 0x04: /* SYS_WRITE0 */
215 if (arm->is_semihosting_fileio) {
216 size_t count = 0;
217 for (uint32_t a = r1;; a++) {
218 unsigned char c;
219 retval = target_read_memory(target, a, 1, 1, &c);
220 if (retval != ERROR_OK)
221 return retval;
222 if (c == '\0')
223 break;
224 count++;
225 }
226 arm->semihosting_hit_fileio = true;
227 fileio_info->identifier = "write";
228 fileio_info->param_1 = 1;
229 fileio_info->param_2 = r1;
230 fileio_info->param_3 = count;
231 } else {
232 do {
233 unsigned char c;
234 retval = target_read_memory(target, r1++, 1, 1, &c);
235 if (retval != ERROR_OK)
236 return retval;
237 if (!c)
238 break;
239 putchar(c);
240 } while (1);
241 arm->semihosting_result = 0;
242 }
243 break;
244
245 case 0x05: /* SYS_WRITE */
246 retval = target_read_memory(target, r1, 4, 3, params);
247 if (retval != ERROR_OK)
248 return retval;
249 else {
250 int fd = target_buffer_get_u32(target, params+0);
251 uint32_t a = target_buffer_get_u32(target, params+4);
252 size_t l = target_buffer_get_u32(target, params+8);
253 if (arm->is_semihosting_fileio) {
254 arm->semihosting_hit_fileio = true;
255 fileio_info->identifier = "write";
256 fileio_info->param_1 = fd;
257 fileio_info->param_2 = a;
258 fileio_info->param_3 = l;
259 } else {
260 uint8_t *buf = malloc(l);
261 if (!buf) {
262 arm->semihosting_result = -1;
263 arm->semihosting_errno = ENOMEM;
264 } else {
265 retval = target_read_buffer(target, a, l, buf);
266 if (retval != ERROR_OK) {
267 free(buf);
268 return retval;
269 }
270 arm->semihosting_result = write(fd, buf, l);
271 arm->semihosting_errno = errno;
272 if (arm->semihosting_result >= 0)
273 arm->semihosting_result = l - arm->semihosting_result;
274 free(buf);
275 }
276 }
277 }
278 break;
279
280 case 0x06: /* SYS_READ */
281 retval = target_read_memory(target, r1, 4, 3, params);
282 if (retval != ERROR_OK)
283 return retval;
284 else {
285 int fd = target_buffer_get_u32(target, params+0);
286 uint32_t a = target_buffer_get_u32(target, params+4);
287 ssize_t l = target_buffer_get_u32(target, params+8);
288 if (arm->is_semihosting_fileio) {
289 arm->semihosting_hit_fileio = true;
290 fileio_info->identifier = "read";
291 fileio_info->param_1 = fd;
292 fileio_info->param_2 = a;
293 fileio_info->param_3 = l;
294 } else {
295 uint8_t *buf = malloc(l);
296 if (!buf) {
297 arm->semihosting_result = -1;
298 arm->semihosting_errno = ENOMEM;
299 } else {
300 arm->semihosting_result = read(fd, buf, l);
301 arm->semihosting_errno = errno;
302 if (arm->semihosting_result >= 0) {
303 retval = target_write_buffer(target, a, arm->semihosting_result, buf);
304 if (retval != ERROR_OK) {
305 free(buf);
306 return retval;
307 }
308 arm->semihosting_result = l - arm->semihosting_result;
309 }
310 free(buf);
311 }
312 }
313 }
314 break;
315
316 case 0x07: /* SYS_READC */
317 if (arm->is_semihosting_fileio) {
318 LOG_ERROR("SYS_READC not supported by semihosting fileio");
319 return ERROR_FAIL;
320 }
321 arm->semihosting_result = getchar();
322 break;
323
324 case 0x08: /* SYS_ISERROR */
325 retval = target_read_memory(target, r1, 4, 1, params);
326 if (retval != ERROR_OK)
327 return retval;
328 arm->semihosting_result = (target_buffer_get_u32(target, params+0) != 0);
329 break;
330
331 case 0x09: /* SYS_ISTTY */
332 if (arm->is_semihosting_fileio) {
333 arm->semihosting_hit_fileio = true;
334 fileio_info->identifier = "isatty";
335 fileio_info->param_1 = r1;
336 } else {
337 retval = target_read_memory(target, r1, 4, 1, params);
338 if (retval != ERROR_OK)
339 return retval;
340 arm->semihosting_result = isatty(target_buffer_get_u32(target, params+0));
341 }
342 break;
343
344 case 0x0a: /* SYS_SEEK */
345 retval = target_read_memory(target, r1, 4, 2, params);
346 if (retval != ERROR_OK)
347 return retval;
348 else {
349 int fd = target_buffer_get_u32(target, params+0);
350 off_t pos = target_buffer_get_u32(target, params+4);
351 if (arm->is_semihosting_fileio) {
352 arm->semihosting_hit_fileio = true;
353 fileio_info->identifier = "lseek";
354 fileio_info->param_1 = fd;
355 fileio_info->param_2 = pos;
356 fileio_info->param_3 = SEEK_SET;
357 } else {
358 arm->semihosting_result = lseek(fd, pos, SEEK_SET);
359 arm->semihosting_errno = errno;
360 if (arm->semihosting_result == pos)
361 arm->semihosting_result = 0;
362 }
363 }
364 break;
365
366 case 0x0c: /* SYS_FLEN */
367 if (arm->is_semihosting_fileio) {
368 LOG_ERROR("SYS_FLEN not supported by semihosting fileio");
369 return ERROR_FAIL;
370 }
371 retval = target_read_memory(target, r1, 4, 1, params);
372 if (retval != ERROR_OK)
373 return retval;
374 else {
375 int fd = target_buffer_get_u32(target, params+0);
376 struct stat buf;
377 arm->semihosting_result = fstat(fd, &buf);
378 if (arm->semihosting_result == -1) {
379 arm->semihosting_errno = errno;
380 arm->semihosting_result = -1;
381 break;
382 }
383 arm->semihosting_result = buf.st_size;
384 }
385 break;
386
387 case 0x0e: /* SYS_REMOVE */
388 retval = target_read_memory(target, r1, 4, 2, params);
389 if (retval != ERROR_OK)
390 return retval;
391 else {
392 uint32_t a = target_buffer_get_u32(target, params+0);
393 uint32_t l = target_buffer_get_u32(target, params+4);
394 if (arm->is_semihosting_fileio) {
395 arm->semihosting_hit_fileio = true;
396 fileio_info->identifier = "unlink";
397 fileio_info->param_1 = a;
398 fileio_info->param_2 = l;
399 } else {
400 if (l <= 255) {
401 uint8_t fn[256];
402 retval = target_read_memory(target, a, 1, l, fn);
403 if (retval != ERROR_OK)
404 return retval;
405 fn[l] = 0;
406 arm->semihosting_result = remove((char *)fn);
407 arm->semihosting_errno = errno;
408 } else {
409 arm->semihosting_result = -1;
410 arm->semihosting_errno = EINVAL;
411 }
412 }
413 }
414 break;
415
416 case 0x0f: /* SYS_RENAME */
417 retval = target_read_memory(target, r1, 4, 4, params);
418 if (retval != ERROR_OK)
419 return retval;
420 else {
421 uint32_t a1 = target_buffer_get_u32(target, params+0);
422 uint32_t l1 = target_buffer_get_u32(target, params+4);
423 uint32_t a2 = target_buffer_get_u32(target, params+8);
424 uint32_t l2 = target_buffer_get_u32(target, params+12);
425 if (arm->is_semihosting_fileio) {
426 arm->semihosting_hit_fileio = true;
427 fileio_info->identifier = "rename";
428 fileio_info->param_1 = a1;
429 fileio_info->param_2 = l1;
430 fileio_info->param_3 = a2;
431 fileio_info->param_4 = l2;
432 } else {
433 if (l1 <= 255 && l2 <= 255) {
434 uint8_t fn1[256], fn2[256];
435 retval = target_read_memory(target, a1, 1, l1, fn1);
436 if (retval != ERROR_OK)
437 return retval;
438 retval = target_read_memory(target, a2, 1, l2, fn2);
439 if (retval != ERROR_OK)
440 return retval;
441 fn1[l1] = 0;
442 fn2[l2] = 0;
443 arm->semihosting_result = rename((char *)fn1, (char *)fn2);
444 arm->semihosting_errno = errno;
445 } else {
446 arm->semihosting_result = -1;
447 arm->semihosting_errno = EINVAL;
448 }
449 }
450 }
451 break;
452
453 case 0x11: /* SYS_TIME */
454 arm->semihosting_result = time(NULL);
455 break;
456
457 case 0x13: /* SYS_ERRNO */
458 arm->semihosting_result = arm->semihosting_errno;
459 break;
460
461 case 0x15: /* SYS_GET_CMDLINE */
462 retval = target_read_memory(target, r1, 4, 2, params);
463 if (retval != ERROR_OK)
464 return retval;
465 else {
466 uint32_t a = target_buffer_get_u32(target, params+0);
467 uint32_t l = target_buffer_get_u32(target, params+4);
468 char *arg = arm->semihosting_cmdline != NULL ? arm->semihosting_cmdline : "";
469 uint32_t s = strlen(arg) + 1;
470 if (l < s)
471 arm->semihosting_result = -1;
472 else {
473 retval = target_write_buffer(target, a, s, (uint8_t *)arg);
474 if (retval != ERROR_OK)
475 return retval;
476 arm->semihosting_result = 0;
477 }
478 }
479 break;
480
481 case 0x16: /* SYS_HEAPINFO */
482 retval = target_read_memory(target, r1, 4, 1, params);
483 if (retval != ERROR_OK)
484 return retval;
485 else {
486 uint32_t a = target_buffer_get_u32(target, params+0);
487 /* tell the remote we have no idea */
488 memset(params, 0, 4*4);
489 retval = target_write_memory(target, a, 4, 4, params);
490 if (retval != ERROR_OK)
491 return retval;
492 arm->semihosting_result = 0;
493 }
494 break;
495
496 case 0x18: /* angel_SWIreason_ReportException */
497 switch (r1) {
498 case 0x20026: /* ADP_Stopped_ApplicationExit */
499 fprintf(stderr, "semihosting: *** application exited ***\n");
500 break;
501 case 0x20000: /* ADP_Stopped_BranchThroughZero */
502 case 0x20001: /* ADP_Stopped_UndefinedInstr */
503 case 0x20002: /* ADP_Stopped_SoftwareInterrupt */
504 case 0x20003: /* ADP_Stopped_PrefetchAbort */
505 case 0x20004: /* ADP_Stopped_DataAbort */
506 case 0x20005: /* ADP_Stopped_AddressException */
507 case 0x20006: /* ADP_Stopped_IRQ */
508 case 0x20007: /* ADP_Stopped_FIQ */
509 case 0x20020: /* ADP_Stopped_BreakPoint */
510 case 0x20021: /* ADP_Stopped_WatchPoint */
511 case 0x20022: /* ADP_Stopped_StepComplete */
512 case 0x20023: /* ADP_Stopped_RunTimeErrorUnknown */
513 case 0x20024: /* ADP_Stopped_InternalError */
514 case 0x20025: /* ADP_Stopped_UserInterruption */
515 case 0x20027: /* ADP_Stopped_StackOverflow */
516 case 0x20028: /* ADP_Stopped_DivisionByZero */
517 case 0x20029: /* ADP_Stopped_OSSpecific */
518 default:
519 fprintf(stderr, "semihosting: exception %#x\n",
520 (unsigned) r1);
521 }
522 return target_call_event_callbacks(target, TARGET_EVENT_HALTED);
523
524 case 0x12: /* SYS_SYSTEM */
525 /* Provide SYS_SYSTEM functionality. Uses the
526 * libc system command, there may be a reason *NOT*
527 * to use this, but as I can't think of one, I
528 * implemented it this way.
529 */
530 retval = target_read_memory(target, r1, 4, 2, params);
531 if (retval != ERROR_OK)
532 return retval;
533 else {
534 uint32_t len = target_buffer_get_u32(target, params+4);
535 uint32_t c_ptr = target_buffer_get_u32(target, params);
536 if (arm->is_semihosting_fileio) {
537 arm->semihosting_hit_fileio = true;
538 fileio_info->identifier = "system";
539 fileio_info->param_1 = c_ptr;
540 fileio_info->param_2 = len;
541 } else {
542 uint8_t cmd[256];
543 if (len > 255) {
544 arm->semihosting_result = -1;
545 arm->semihosting_errno = EINVAL;
546 } else {
547 memset(cmd, 0x0, 256);
548 retval = target_read_memory(target, c_ptr, 1, len, cmd);
549 if (retval != ERROR_OK)
550 return retval;
551 else
552 arm->semihosting_result = system((const char *)cmd);
553 }
554 }
555 }
556 break;
557 case 0x0d: /* SYS_TMPNAM */
558 case 0x10: /* SYS_CLOCK */
559 case 0x17: /* angel_SWIreason_EnterSVC */
560 case 0x30: /* SYS_ELAPSED */
561 case 0x31: /* SYS_TICKFREQ */
562 default:
563 fprintf(stderr, "semihosting: unsupported call %#x\n",
564 (unsigned) r0);
565 arm->semihosting_result = -1;
566 arm->semihosting_errno = ENOTSUP;
567 }
568
569 return ERROR_OK;
570 }
571
572 static int get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fileio_info)
573 {
574 struct arm *arm = target_to_arm(target);
575
576 /* To avoid uneccessary duplication, semihosting prepares the
577 * fileio_info structure out-of-band when the target halts. See
578 * do_semihosting for more detail.
579 */
580 if (!arm->is_semihosting_fileio || !arm->semihosting_hit_fileio)
581 return ERROR_FAIL;
582
583 return ERROR_OK;
584 }
585
586 static int gdb_fileio_end(struct target *target, int result, int fileio_errno, bool ctrl_c)
587 {
588 struct arm *arm = target_to_arm(target);
589 struct gdb_fileio_info *fileio_info = target->fileio_info;
590
591 /* clear pending status */
592 arm->semihosting_hit_fileio = false;
593
594 arm->semihosting_result = result;
595 arm->semihosting_errno = fileio_errno;
596
597 /* Some fileio results do not match up with what the semihosting
598 * operation expects; for these operations, we munge the results
599 * below:
600 */
601 switch (arm->semihosting_op) {
602 case 0x05: /* SYS_WRITE */
603 if (result < 0)
604 arm->semihosting_result = fileio_info->param_3;
605 else
606 arm->semihosting_result = 0;
607 break;
608
609 case 0x06: /* SYS_READ */
610 if (result == (int)fileio_info->param_3)
611 arm->semihosting_result = 0;
612 if (result <= 0)
613 arm->semihosting_result = fileio_info->param_3;
614 break;
615
616 case 0x0a: /* SYS_SEEK */
617 if (result > 0)
618 arm->semihosting_result = 0;
619 break;
620 }
621
622 return post_result(target);
623 }
624
625 /**
626 * Initialize ARM semihosting support.
627 *
628 * @param target Pointer to the ARM target to initialize.
629 * @return An error status if there is a problem during initialization.
630 */
631 int arm_semihosting_init(struct target *target)
632 {
633 target->fileio_info = malloc(sizeof(*target->fileio_info));
634 if (target->fileio_info == NULL) {
635 LOG_ERROR("out of memory");
636 return ERROR_FAIL;
637 }
638
639 target->type->get_gdb_fileio_info = get_gdb_fileio_info;
640 target->type->gdb_fileio_end = gdb_fileio_end;
641
642 return ERROR_OK;
643 }
644
645 /**
646 * Checks for and processes an ARM semihosting request. This is meant
647 * to be called when the target is stopped due to a debug mode entry.
648 * If the value 0 is returned then there was nothing to process. A non-zero
649 * return value signifies that a request was processed and the target resumed,
650 * or an error was encountered, in which case the caller must return
651 * immediately.
652 *
653 * @param target Pointer to the ARM target to process. This target must
654 * not represent an ARMv6-M or ARMv7-M processor.
655 * @param retval Pointer to a location where the return code will be stored
656 * @return non-zero value if a request was processed or an error encountered
657 */
658 int arm_semihosting(struct target *target, int *retval)
659 {
660 struct arm *arm = target_to_arm(target);
661 struct armv7a_common *armv7a = target_to_armv7a(target);
662 uint32_t pc, lr, spsr;
663 struct reg *r;
664
665 if (!arm->is_semihosting)
666 return 0;
667
668 if (is_arm7_9(target_to_arm7_9(target)) ||
669 is_armv7a(armv7a)) {
670 uint32_t vbar = 0x00000000;
671
672 if (arm->core_mode != ARM_MODE_SVC)
673 return 0;
674
675 if (is_armv7a(armv7a)) {
676 struct arm_dpm *dpm = armv7a->arm.dpm;
677
678 *retval = dpm->prepare(dpm);
679 if (*retval == ERROR_OK) {
680 *retval = dpm->instr_read_data_r0(dpm,
681 ARMV4_5_MRC(15, 0, 0, 12, 0, 0),
682 &vbar);
683
684 dpm->finish(dpm);
685
686 if (*retval != ERROR_OK)
687 return 1;
688 } else {
689 return 1;
690 }
691 }
692
693 /* Check for PC == 0x00000008 or 0xffff0008: Supervisor Call vector. */
694 r = arm->pc;
695 pc = buf_get_u32(r->value, 0, 32);
696 if (pc != (vbar + 0x00000008) && pc != 0xffff0008)
697 return 0;
698
699 r = arm_reg_current(arm, 14);
700 lr = buf_get_u32(r->value, 0, 32);
701
702 /* Core-specific code should make sure SPSR is retrieved
703 * when the above checks pass...
704 */
705 if (!arm->spsr->valid) {
706 LOG_ERROR("SPSR not valid!");
707 *retval = ERROR_FAIL;
708 return 1;
709 }
710
711 spsr = buf_get_u32(arm->spsr->value, 0, 32);
712
713 /* check instruction that triggered this trap */
714 if (spsr & (1 << 5)) {
715 /* was in Thumb (or ThumbEE) mode */
716 uint8_t insn_buf[2];
717 uint16_t insn;
718
719 *retval = target_read_memory(target, lr-2, 2, 1, insn_buf);
720 if (*retval != ERROR_OK)
721 return 1;
722 insn = target_buffer_get_u16(target, insn_buf);
723
724 /* SVC 0xab */
725 if (insn != 0xDFAB)
726 return 0;
727 } else if (spsr & (1 << 24)) {
728 /* was in Jazelle mode */
729 return 0;
730 } else {
731 /* was in ARM mode */
732 uint8_t insn_buf[4];
733 uint32_t insn;
734
735 *retval = target_read_memory(target, lr-4, 4, 1, insn_buf);
736 if (*retval != ERROR_OK)
737 return 1;
738 insn = target_buffer_get_u32(target, insn_buf);
739
740 /* SVC 0x123456 */
741 if (insn != 0xEF123456)
742 return 0;
743 }
744 } else if (is_armv7m(target_to_armv7m(target))) {
745 uint16_t insn;
746
747 if (target->debug_reason != DBG_REASON_BREAKPOINT)
748 return 0;
749
750 r = arm->pc;
751 pc = buf_get_u32(r->value, 0, 32);
752
753 pc &= ~1;
754 *retval = target_read_u16(target, pc, &insn);
755 if (*retval != ERROR_OK)
756 return 1;
757
758 /* bkpt 0xAB */
759 if (insn != 0xBEAB)
760 return 0;
761 } else {
762 LOG_ERROR("Unsupported semi-hosting Target");
763 return 0;
764 }
765
766 /* Perform semihosting if we are not waiting on a fileio
767 * operation to complete.
768 */
769 if (!arm->semihosting_hit_fileio) {
770 *retval = do_semihosting(target);
771 if (*retval != ERROR_OK) {
772 LOG_ERROR("Failed semihosting operation");
773 return 0;
774 }
775 }
776
777 /* Post result to target if we are not waiting on a fileio
778 * operation to complete:
779 */
780 if (!arm->semihosting_hit_fileio) {
781 *retval = post_result(target);
782 if (*retval != ERROR_OK) {
783 LOG_ERROR("Failed to post semihosting result");
784 return 0;
785 }
786
787 *retval = target_resume(target, 1, 0, 0, 0);
788 if (*retval != ERROR_OK) {
789 LOG_ERROR("Failed to resume target");
790 return 0;
791 }
792
793 return 1;
794 }
795
796 return 0;
797 }

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)