semihosting: support fileio operation
[openocd.git] / src / target / arm_semihosting.c
index 63335ff3c7abad524febfc0a31ba374bdd3a3581..252511962da1bdbda1fe1430ad0dd6bc0df4bb84 100644 (file)
@@ -5,6 +5,9 @@
  *   Copyright (C) 2010 by Spencer Oliver                                  *
  *   spen@spen-soft.co.uk                                                  *
  *                                                                         *
+ *   Copyright (C) 2016 by Square, Inc.                                    *
+ *   Steven Stallion <stallion@squareup.com>                               *
+ *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
  *   it under the terms of the GNU General Public License as published by  *
  *   the Free Software Foundation; either version 2 of the License, or     *
@@ -43,6 +46,7 @@
 #include "cortex_m.h"
 #include "register.h"
 #include "arm_opcodes.h"
+#include "target_type.h"
 #include "arm_semihosting.h"
 #include <helper/binarybuffer.h>
 #include <helper/log.h>
@@ -63,13 +67,59 @@ static const int open_modeflags[12] = {
        O_RDWR | O_CREAT | O_APPEND | O_BINARY
 };
 
+static int post_result(struct target *target)
+{
+       struct arm *arm = target_to_arm(target);
+
+       /* REVISIT this looks wrong ... ARM11 and Cortex-A8
+        * should work this way at least sometimes.
+        */
+       if (is_arm7_9(target_to_arm7_9(target)) ||
+           is_armv7a(target_to_armv7a(target))) {
+               uint32_t spsr;
+
+               /* return value in R0 */
+               buf_set_u32(arm->core_cache->reg_list[0].value, 0, 32, arm->semihosting_result);
+               arm->core_cache->reg_list[0].dirty = 1;
+
+               /* LR --> PC */
+               buf_set_u32(arm->core_cache->reg_list[15].value, 0, 32,
+                       buf_get_u32(arm_reg_current(arm, 14)->value, 0, 32));
+               arm->core_cache->reg_list[15].dirty = 1;
+
+               /* saved PSR --> current PSR */
+               spsr = buf_get_u32(arm->spsr->value, 0, 32);
+
+               /* REVISIT should this be arm_set_cpsr(arm, spsr)
+                * instead of a partially unrolled version?
+                */
+
+               buf_set_u32(arm->cpsr->value, 0, 32, spsr);
+               arm->cpsr->dirty = 1;
+               arm->core_mode = spsr & 0x1f;
+               if (spsr & 0x20)
+                       arm->core_state = ARM_STATE_THUMB;
+
+       } else {
+               /* resume execution, this will be pc+2 to skip over the
+                * bkpt instruction */
+
+               /* return result in R0 */
+               buf_set_u32(arm->core_cache->reg_list[0].value, 0, 32, arm->semihosting_result);
+               arm->core_cache->reg_list[0].dirty = 1;
+       }
+
+       return ERROR_OK;
+}
+
 static int do_semihosting(struct target *target)
 {
        struct arm *arm = target_to_arm(target);
+       struct gdb_fileio_info *fileio_info = target->fileio_info;
        uint32_t r0 = buf_get_u32(arm->core_cache->reg_list[0].value, 0, 32);
        uint32_t r1 = buf_get_u32(arm->core_cache->reg_list[1].value, 0, 32);
        uint8_t params[16];
-       int retval, result;
+       int retval;
 
        /*
         * TODO: lots of security issues are not considered yet, such as:
@@ -77,10 +127,10 @@ static int do_semihosting(struct target *target)
         * - no safety checks on opened/deleted/renamed file paths
         * Beware the target app you use this support with.
         *
-        * TODO: explore mapping requests to GDB's "File-I/O Remote
-        * Protocol Extension" ... when GDB is active.
+        * TODO: unsupported semihosting fileio operations could be
+        * implemented if we had a small working area at our disposal.
         */
-       switch (r0) {
+       switch ((arm->semihosting_op = r0)) {
        case 0x01:      /* SYS_OPEN */
                retval = target_read_memory(target, r1, 4, 3, params);
                if (retval != ERROR_OK)
@@ -89,27 +139,40 @@ static int do_semihosting(struct target *target)
                        uint32_t a = target_buffer_get_u32(target, params+0);
                        uint32_t m = target_buffer_get_u32(target, params+4);
                        uint32_t l = target_buffer_get_u32(target, params+8);
-                       if (l <= 255 && m <= 11) {
-                               uint8_t fn[256];
-                               retval = target_read_memory(target, a, 1, l, fn);
-                               if (retval != ERROR_OK)
-                                       return retval;
-                               fn[l] = 0;
-                               if (strcmp((char *)fn, ":tt") == 0) {
-                                       if (m < 4)
-                                               result = dup(STDIN_FILENO);
-                                       else
-                                               result = dup(STDOUT_FILENO);
-                               } else {
-                                       /* cygwin requires the permission setting
-                                        * otherwise it will fail to reopen a previously
-                                        * written file */
-                                       result = open((char *)fn, open_modeflags[m], 0644);
+                       uint8_t fn[256];
+                       retval = target_read_memory(target, a, 1, l, fn);
+                       if (retval != ERROR_OK)
+                               return retval;
+                       fn[l] = 0;
+                       if (arm->is_semihosting_fileio) {
+                               if (strcmp((char *)fn, ":tt") == 0)
+                                       arm->semihosting_result = 0;
+                               else {
+                                       arm->semihosting_hit_fileio = true;
+                                       fileio_info->identifier = "open";
+                                       fileio_info->param_1 = a;
+                                       fileio_info->param_2 = l;
+                                       fileio_info->param_3 = open_modeflags[m];
+                                       fileio_info->param_4 = 0644;
                                }
-                               arm->semihosting_errno =  errno;
                        } else {
-                               result = -1;
-                               arm->semihosting_errno = EINVAL;
+                               if (l <= 255 && m <= 11) {
+                                       if (strcmp((char *)fn, ":tt") == 0) {
+                                               if (m < 4)
+                                                       arm->semihosting_result = dup(STDIN_FILENO);
+                                               else
+                                                       arm->semihosting_result = dup(STDOUT_FILENO);
+                                       } else {
+                                               /* cygwin requires the permission setting
+                                                * otherwise it will fail to reopen a previously
+                                                * written file */
+                                               arm->semihosting_result = open((char *)fn, open_modeflags[m], 0644);
+                                       }
+                                       arm->semihosting_errno =  errno;
+                               } else {
+                                       arm->semihosting_result = -1;
+                                       arm->semihosting_errno = EINVAL;
+                               }
                        }
                }
                break;
@@ -120,33 +183,63 @@ static int do_semihosting(struct target *target)
                        return retval;
                else {
                        int fd = target_buffer_get_u32(target, params+0);
-                       result = close(fd);
-                       arm->semihosting_errno = errno;
+                       if (arm->is_semihosting_fileio) {
+                               arm->semihosting_hit_fileio = true;
+                               fileio_info->identifier = "close";
+                               fileio_info->param_1 = fd;
+                       } else {
+                               arm->semihosting_result = close(fd);
+                               arm->semihosting_errno = errno;
+                       }
                }
                break;
 
        case 0x03:      /* SYS_WRITEC */
-               {
+               if (arm->is_semihosting_fileio) {
+                       arm->semihosting_hit_fileio = true;
+                       fileio_info->identifier = "write";
+                       fileio_info->param_1 = 1;
+                       fileio_info->param_2 = r1;
+                       fileio_info->param_3 = 1;
+               } else {
                        unsigned char c;
                        retval = target_read_memory(target, r1, 1, 1, &c);
                        if (retval != ERROR_OK)
                                return retval;
                        putchar(c);
-                       result = 0;
+                       arm->semihosting_result = 0;
                }
                break;
 
        case 0x04:      /* SYS_WRITE0 */
-               do {
-                       unsigned char c;
-                       retval = target_read_memory(target, r1++, 1, 1, &c);
-                       if (retval != ERROR_OK)
-                               return retval;
-                       if (!c)
-                               break;
-                       putchar(c);
-               } while (1);
-               result = 0;
+               if (arm->is_semihosting_fileio) {
+                       size_t count = 0;
+                       for (uint32_t a = r1;; a++) {
+                               unsigned char c;
+                               retval = target_read_memory(target, a, 1, 1, &c);
+                               if (retval != ERROR_OK)
+                                       return retval;
+                               if (c == '\0')
+                                       break;
+                               count++;
+                       }
+                       arm->semihosting_hit_fileio = true;
+                       fileio_info->identifier = "write";
+                       fileio_info->param_1 = 1;
+                       fileio_info->param_2 = r1;
+                       fileio_info->param_3 = count;
+               } else {
+                       do {
+                               unsigned char c;
+                               retval = target_read_memory(target, r1++, 1, 1, &c);
+                               if (retval != ERROR_OK)
+                                       return retval;
+                               if (!c)
+                                       break;
+                               putchar(c);
+                       } while (1);
+                       arm->semihosting_result = 0;
+               }
                break;
 
        case 0x05:      /* SYS_WRITE */
@@ -157,21 +250,29 @@ static int do_semihosting(struct target *target)
                        int fd = target_buffer_get_u32(target, params+0);
                        uint32_t a = target_buffer_get_u32(target, params+4);
                        size_t l = target_buffer_get_u32(target, params+8);
-                       uint8_t *buf = malloc(l);
-                       if (!buf) {
-                               result = -1;
-                               arm->semihosting_errno = ENOMEM;
+                       if (arm->is_semihosting_fileio) {
+                               arm->semihosting_hit_fileio = true;
+                               fileio_info->identifier = "write";
+                               fileio_info->param_1 = fd;
+                               fileio_info->param_2 = a;
+                               fileio_info->param_3 = l;
                        } else {
-                               retval = target_read_buffer(target, a, l, buf);
-                               if (retval != ERROR_OK) {
+                               uint8_t *buf = malloc(l);
+                               if (!buf) {
+                                       arm->semihosting_result = -1;
+                                       arm->semihosting_errno = ENOMEM;
+                               } else {
+                                       retval = target_read_buffer(target, a, l, buf);
+                                       if (retval != ERROR_OK) {
+                                               free(buf);
+                                               return retval;
+                                       }
+                                       arm->semihosting_result = write(fd, buf, l);
+                                       arm->semihosting_errno = errno;
+                                       if (arm->semihosting_result >= 0)
+                                               arm->semihosting_result = l - arm->semihosting_result;
                                        free(buf);
-                                       return retval;
                                }
-                               result = write(fd, buf, l);
-                               arm->semihosting_errno = errno;
-                               if (result >= 0)
-                                       result = l - result;
-                               free(buf);
                        }
                }
                break;
@@ -184,42 +285,60 @@ static int do_semihosting(struct target *target)
                        int fd = target_buffer_get_u32(target, params+0);
                        uint32_t a = target_buffer_get_u32(target, params+4);
                        ssize_t l = target_buffer_get_u32(target, params+8);
-                       uint8_t *buf = malloc(l);
-                       if (!buf) {
-                               result = -1;
-                               arm->semihosting_errno = ENOMEM;
+                       if (arm->is_semihosting_fileio) {
+                               arm->semihosting_hit_fileio = true;
+                               fileio_info->identifier = "read";
+                               fileio_info->param_1 = fd;
+                               fileio_info->param_2 = a;
+                               fileio_info->param_3 = l;
                        } else {
-                               result = read(fd, buf, l);
-                               arm->semihosting_errno = errno;
-                               if (result >= 0) {
-                                       retval = target_write_buffer(target, a, result, buf);
-                                       if (retval != ERROR_OK) {
-                                               free(buf);
-                                               return retval;
+                               uint8_t *buf = malloc(l);
+                               if (!buf) {
+                                       arm->semihosting_result = -1;
+                                       arm->semihosting_errno = ENOMEM;
+                               } else {
+                                       arm->semihosting_result = read(fd, buf, l);
+                                       arm->semihosting_errno = errno;
+                                       if (arm->semihosting_result >= 0) {
+                                               retval = target_write_buffer(target, a, arm->semihosting_result, buf);
+                                               if (retval != ERROR_OK) {
+                                                       free(buf);
+                                                       return retval;
+                                               }
+                                               arm->semihosting_result = l - arm->semihosting_result;
                                        }
-                                       result = l - result;
+                                       free(buf);
                                }
-                               free(buf);
                        }
                }
                break;
 
        case 0x07:      /* SYS_READC */
-               result = getchar();
+               if (arm->is_semihosting_fileio) {
+                       LOG_ERROR("SYS_READC not supported by semihosting fileio");
+                       return ERROR_FAIL;
+               }
+               arm->semihosting_result = getchar();
                break;
 
        case 0x08:      /* SYS_ISERROR */
                retval = target_read_memory(target, r1, 4, 1, params);
                if (retval != ERROR_OK)
                        return retval;
-               result = (target_buffer_get_u32(target, params+0) != 0);
+               arm->semihosting_result = (target_buffer_get_u32(target, params+0) != 0);
                break;
 
        case 0x09:      /* SYS_ISTTY */
-               retval = target_read_memory(target, r1, 4, 1, params);
-               if (retval != ERROR_OK)
-                       return retval;
-               result = isatty(target_buffer_get_u32(target, params+0));
+               if (arm->is_semihosting_fileio) {
+                       arm->semihosting_hit_fileio = true;
+                       fileio_info->identifier = "isatty";
+                       fileio_info->param_1 = r1;
+               } else {
+                       retval = target_read_memory(target, r1, 4, 1, params);
+                       if (retval != ERROR_OK)
+                               return retval;
+                       arm->semihosting_result = isatty(target_buffer_get_u32(target, params+0));
+               }
                break;
 
        case 0x0a:      /* SYS_SEEK */
@@ -229,27 +348,39 @@ static int do_semihosting(struct target *target)
                else {
                        int fd = target_buffer_get_u32(target, params+0);
                        off_t pos = target_buffer_get_u32(target, params+4);
-                       result = lseek(fd, pos, SEEK_SET);
-                       arm->semihosting_errno = errno;
-                       if (result == pos)
-                               result = 0;
+                       if (arm->is_semihosting_fileio) {
+                               arm->semihosting_hit_fileio = true;
+                               fileio_info->identifier = "lseek";
+                               fileio_info->param_1 = fd;
+                               fileio_info->param_2 = pos;
+                               fileio_info->param_3 = SEEK_SET;
+                       } else {
+                               arm->semihosting_result = lseek(fd, pos, SEEK_SET);
+                               arm->semihosting_errno = errno;
+                               if (arm->semihosting_result == pos)
+                                       arm->semihosting_result = 0;
+                       }
                }
                break;
 
        case 0x0c:      /* SYS_FLEN */
+               if (arm->is_semihosting_fileio) {
+                       LOG_ERROR("SYS_FLEN not supported by semihosting fileio");
+                       return ERROR_FAIL;
+               }
                retval = target_read_memory(target, r1, 4, 1, params);
                if (retval != ERROR_OK)
                        return retval;
                else {
                        int fd = target_buffer_get_u32(target, params+0);
                        struct stat buf;
-                       result = fstat(fd, &buf);
-                       if (result == -1) {
+                       arm->semihosting_result = fstat(fd, &buf);
+                       if (arm->semihosting_result == -1) {
                                arm->semihosting_errno = errno;
-                               result = -1;
+                               arm->semihosting_result = -1;
                                break;
                        }
-                       result = buf.st_size;
+                       arm->semihosting_result = buf.st_size;
                }
                break;
 
@@ -260,17 +391,24 @@ static int do_semihosting(struct target *target)
                else {
                        uint32_t a = target_buffer_get_u32(target, params+0);
                        uint32_t l = target_buffer_get_u32(target, params+4);
-                       if (l <= 255) {
-                               uint8_t fn[256];
-                               retval = target_read_memory(target, a, 1, l, fn);
-                               if (retval != ERROR_OK)
-                                       return retval;
-                               fn[l] = 0;
-                               result = remove((char *)fn);
-                               arm->semihosting_errno =  errno;
+                       if (arm->is_semihosting_fileio) {
+                               arm->semihosting_hit_fileio = true;
+                               fileio_info->identifier = "unlink";
+                               fileio_info->param_1 = a;
+                               fileio_info->param_2 = l;
                        } else {
-                               result = -1;
-                               arm->semihosting_errno = EINVAL;
+                               if (l <= 255) {
+                                       uint8_t fn[256];
+                                       retval = target_read_memory(target, a, 1, l, fn);
+                                       if (retval != ERROR_OK)
+                                               return retval;
+                                       fn[l] = 0;
+                                       arm->semihosting_result = remove((char *)fn);
+                                       arm->semihosting_errno =  errno;
+                               } else {
+                                       arm->semihosting_result = -1;
+                                       arm->semihosting_errno = EINVAL;
+                               }
                        }
                }
                break;
@@ -284,31 +422,40 @@ static int do_semihosting(struct target *target)
                        uint32_t l1 = target_buffer_get_u32(target, params+4);
                        uint32_t a2 = target_buffer_get_u32(target, params+8);
                        uint32_t l2 = target_buffer_get_u32(target, params+12);
-                       if (l1 <= 255 && l2 <= 255) {
-                               uint8_t fn1[256], fn2[256];
-                               retval = target_read_memory(target, a1, 1, l1, fn1);
-                               if (retval != ERROR_OK)
-                                       return retval;
-                               retval = target_read_memory(target, a2, 1, l2, fn2);
-                               if (retval != ERROR_OK)
-                                       return retval;
-                               fn1[l1] = 0;
-                               fn2[l2] = 0;
-                               result = rename((char *)fn1, (char *)fn2);
-                               arm->semihosting_errno =  errno;
+                       if (arm->is_semihosting_fileio) {
+                               arm->semihosting_hit_fileio = true;
+                               fileio_info->identifier = "rename";
+                               fileio_info->param_1 = a1;
+                               fileio_info->param_2 = l1;
+                               fileio_info->param_3 = a2;
+                               fileio_info->param_4 = l2;
                        } else {
-                               result = -1;
-                               arm->semihosting_errno = EINVAL;
+                               if (l1 <= 255 && l2 <= 255) {
+                                       uint8_t fn1[256], fn2[256];
+                                       retval = target_read_memory(target, a1, 1, l1, fn1);
+                                       if (retval != ERROR_OK)
+                                               return retval;
+                                       retval = target_read_memory(target, a2, 1, l2, fn2);
+                                       if (retval != ERROR_OK)
+                                               return retval;
+                                       fn1[l1] = 0;
+                                       fn2[l2] = 0;
+                                       arm->semihosting_result = rename((char *)fn1, (char *)fn2);
+                                       arm->semihosting_errno =  errno;
+                               } else {
+                                       arm->semihosting_result = -1;
+                                       arm->semihosting_errno = EINVAL;
+                               }
                        }
                }
                break;
 
        case 0x11:      /* SYS_TIME */
-               result = time(NULL);
+               arm->semihosting_result = time(NULL);
                break;
 
        case 0x13:      /* SYS_ERRNO */
-               result = arm->semihosting_errno;
+               arm->semihosting_result = arm->semihosting_errno;
                break;
 
        case 0x15:      /* SYS_GET_CMDLINE */
@@ -321,12 +468,12 @@ static int do_semihosting(struct target *target)
                        char *arg = "foobar";
                        uint32_t s = strlen(arg) + 1;
                        if (l < s)
-                               result = -1;
+                               arm->semihosting_result = -1;
                        else {
                                retval = target_write_buffer(target, a, s, (uint8_t *)arg);
                                if (retval != ERROR_OK)
                                        return retval;
-                               result = 0;
+                               arm->semihosting_result = 0;
                        }
                }
                break;
@@ -342,7 +489,7 @@ static int do_semihosting(struct target *target)
                        retval = target_write_memory(target, a, 4, 4, params);
                        if (retval != ERROR_OK)
                                return retval;
-                       result = 0;
+                       arm->semihosting_result = 0;
                }
                break;
 
@@ -386,17 +533,24 @@ static int do_semihosting(struct target *target)
                else {
                        uint32_t len = target_buffer_get_u32(target, params+4);
                        uint32_t c_ptr = target_buffer_get_u32(target, params);
-                       uint8_t cmd[256];
-                       if (len > 255) {
-                               result = -1;
-                               arm->semihosting_errno = EINVAL;
+                       if (arm->is_semihosting_fileio) {
+                               arm->semihosting_hit_fileio = true;
+                               fileio_info->identifier = "system";
+                               fileio_info->param_1 = c_ptr;
+                               fileio_info->param_2 = len;
                        } else {
-                               memset(cmd, 0x0, 256);
-                               retval = target_read_memory(target, c_ptr, 1, len, cmd);
-                               if (retval != ERROR_OK)
-                                       return retval;
-                               else
-                                       result = system((const char *)cmd);
+                               uint8_t cmd[256];
+                               if (len > 255) {
+                                       arm->semihosting_result = -1;
+                                       arm->semihosting_errno = EINVAL;
+                               } else {
+                                       memset(cmd, 0x0, 256);
+                                       retval = target_read_memory(target, c_ptr, 1, len, cmd);
+                                       if (retval != ERROR_OK)
+                                               return retval;
+                                       else
+                                               arm->semihosting_result = system((const char *)cmd);
+                               }
                        }
                }
                break;
@@ -408,51 +562,84 @@ static int do_semihosting(struct target *target)
        default:
                fprintf(stderr, "semihosting: unsupported call %#x\n",
                                (unsigned) r0);
-               result = -1;
+               arm->semihosting_result = -1;
                arm->semihosting_errno = ENOTSUP;
        }
 
-       /* resume execution to the original mode */
+       return ERROR_OK;
+}
 
-       /* REVISIT this looks wrong ... ARM11 and Cortex-A8
-        * should work this way at least sometimes.
+static int get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fileio_info)
+{
+       struct arm *arm = target_to_arm(target);
+
+       /* To avoid uneccessary duplication, semihosting prepares the
+        * fileio_info structure out-of-band when the target halts. See
+        * do_semihosting for more detail.
         */
-       if (is_arm7_9(target_to_arm7_9(target)) ||
-           is_armv7a(target_to_armv7a(target))) {
-               uint32_t spsr;
+       if (!arm->is_semihosting_fileio || !arm->semihosting_hit_fileio)
+               return ERROR_FAIL;
 
-               /* return value in R0 */
-               buf_set_u32(arm->core_cache->reg_list[0].value, 0, 32, result);
-               arm->core_cache->reg_list[0].dirty = 1;
+       return ERROR_OK;
+}
 
-               /* LR --> PC */
-               buf_set_u32(arm->core_cache->reg_list[15].value, 0, 32,
-                       buf_get_u32(arm_reg_current(arm, 14)->value, 0, 32));
-               arm->core_cache->reg_list[15].dirty = 1;
+static int gdb_fileio_end(struct target *target, int result, int fileio_errno, bool ctrl_c)
+{
+       struct arm *arm = target_to_arm(target);
+       struct gdb_fileio_info *fileio_info = target->fileio_info;
 
-               /* saved PSR --> current PSR */
-               spsr = buf_get_u32(arm->spsr->value, 0, 32);
+       /* clear pending status */
+       arm->semihosting_hit_fileio = false;
 
-               /* REVISIT should this be arm_set_cpsr(arm, spsr)
-                * instead of a partially unrolled version?
-                */
+       arm->semihosting_result = result;
+       arm->semihosting_errno = fileio_errno;
 
-               buf_set_u32(arm->cpsr->value, 0, 32, spsr);
-               arm->cpsr->dirty = 1;
-               arm->core_mode = spsr & 0x1f;
-               if (spsr & 0x20)
-                       arm->core_state = ARM_STATE_THUMB;
+       /* Some fileio results do not match up with what the semihosting
+        * operation expects; for these operations, we munge the results
+        * below:
+        */
+       switch (arm->semihosting_op) {
+       case 0x05:      /* SYS_WRITE */
+               if (result < 0)
+                       arm->semihosting_result = fileio_info->param_3;
+               else
+                       arm->semihosting_result = 0;
+               break;
 
-       } else {
-               /* resume execution, this will be pc+2 to skip over the
-                * bkpt instruction */
+       case 0x06:      /* SYS_READ */
+               if (result == (int)fileio_info->param_3)
+                       arm->semihosting_result = 0;
+               if (result <= 0)
+                       arm->semihosting_result = fileio_info->param_3;
+               break;
 
-               /* return result in R0 */
-               buf_set_u32(arm->core_cache->reg_list[0].value, 0, 32, result);
-               arm->core_cache->reg_list[0].dirty = 1;
+       case 0x0a:      /* SYS_SEEK */
+               if (result > 0)
+                       arm->semihosting_result = 0;
+               break;
        }
 
-       return target_resume(target, 1, 0, 0, 0);
+       return post_result(target);
+}
+
+/**
+ * Initialize ARM semihosting support.
+ *
+ * @param target Pointer to the ARM target to initialize.
+ * @return An error status if there is a problem during initialization.
+ */
+int arm_semihosting_init(struct target *target)
+{
+       target->fileio_info = malloc(sizeof(*target->fileio_info));
+       if (target->fileio_info == NULL) {
+               LOG_ERROR("out of memory");
+               return ERROR_FAIL;
+       }
+
+       target->type->get_gdb_fileio_info = get_gdb_fileio_info;
+       target->type->gdb_fileio_end = gdb_fileio_end;
+
+       return ERROR_OK;
 }
 
 /**
@@ -576,6 +763,35 @@ int arm_semihosting(struct target *target, int *retval)
                return 0;
        }
 
-       *retval = do_semihosting(target);
-       return 1;
+       /* Perform semihosting if we are not waiting on a fileio
+        * operation to complete.
+        */
+       if (!arm->semihosting_hit_fileio) {
+               *retval = do_semihosting(target);
+               if (*retval != ERROR_OK) {
+                       LOG_ERROR("Failed semihosting operation");
+                       return 0;
+               }
+       }
+
+       /* Post result to target if we are not waiting on a fileio
+        * operation to complete:
+        */
+       if (!arm->semihosting_hit_fileio) {
+               *retval = post_result(target);
+               if (*retval != ERROR_OK) {
+                       LOG_ERROR("Failed to post semihosting result");
+                       return 0;
+               }
+
+               *retval = target_resume(target, 1, 0, 0, 0);
+               if (*retval != ERROR_OK) {
+                       LOG_ERROR("Failed to resume target");
+                       return 0;
+               }
+
+               return 1;
+       }
+
+       return 0;
 }

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)