]> git.sur5r.net Git - openocd/blob - src/target/arm_semihosting.c
semihosting: support fileio operation
[openocd] / 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 = "foobar";
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 }