semihosting: support fileio operation 66/3566/6
authorSteven Stallion <stallion@squareup.com>
Fri, 22 Jul 2016 20:43:11 +0000 (15:43 -0500)
committerPaul Fertser <fercerpav@gmail.com>
Thu, 8 Dec 2016 12:32:58 +0000 (12:32 +0000)
This patch adds support for bridging semihosting to GDB's File-I/O
remote protocol extension. For the most part operations match up 1:1,
however some require a working area to complete successfully, namely
operations that devolve to read, stat, and gettimeofday.

A new command was added to enable support for fileio named `arm
semihosting_fileio`, which ensures that the default behavior remains
intact for those that prefer it.

Finally, redundant logging was removed from the target_arch_state
function; this permits ARM targets to quiesce log output when polling
for a fileio reply. This prevents filling the logs with halt/resume
messages when using semihosting fileio.

Change-Id: Ifbb864fc2373336a501cc0332675b887b552e1ee
Signed-off-by: Steven Stallion <stallion@squareup.com>
Reviewed-on: http://openocd.zylin.com/3566
Tested-by: jenkins
Reviewed-by: Steven Stallion <sstallion@gmail.com>
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
12 files changed:
doc/openocd.texi
src/target/arm.h
src/target/arm7tdmi.c
src/target/arm9tdmi.c
src/target/arm_semihosting.c
src/target/arm_semihosting.h
src/target/armv4_5.c
src/target/armv7m.c
src/target/cortex_a.c
src/target/cortex_m.c
src/target/hla_target.c
src/target/target.c

index 372683a9ccc2e1313f1d47339479ed22c77f2bac..1cca4ab11a626d8f43982aaa0955203213de7317 100644 (file)
@@ -7404,6 +7404,17 @@ requests by using a special SVC instruction that is trapped at the
 Supervisor Call vector by OpenOCD.
 @end deffn
 
+@deffn Command {arm semihosting_fileio} [@option{enable}|@option{disable}]
+@cindex ARM semihosting
+Display status of semihosting fileio, after optionally changing that
+status.
+
+Enabling this option forwards semihosting I/O to GDB process using the
+File-I/O remote protocol extension. This is especially useful for
+interacting with remote files or displaying console messages in the
+debugger.
+@end deffn
+
 @section ARMv4 and ARMv5 Architecture
 @cindex ARMv4
 @cindex ARMv5
index 28022e3d2d905eb4c20550d060f72dad4c46ca7d..226dd65689a15add147d39c3ac652b885e6edd09 100644 (file)
@@ -130,6 +130,18 @@ struct arm {
        /** Flag reporting whether semihosting is active. */
        bool is_semihosting;
 
+       /** Flag reporting whether semihosting fileio is active. */
+       bool is_semihosting_fileio;
+
+       /** Flag reporting whether semihosting fileio operation is active. */
+       bool semihosting_hit_fileio;
+
+       /** Current semihosting operation. */
+       int semihosting_op;
+
+       /** Current semihosting result. */
+       int semihosting_result;
+
        /** Value to be returned by semihosting SYS_ERRNO request. */
        int semihosting_errno;
 
index 58ab0279669772e42642a01996fa8d2784ee0cb0..9dcb302d9c88d2b12e9cd6d4e9e410bd422b44f1 100644 (file)
@@ -30,6 +30,7 @@
 #include "target_type.h"
 #include "register.h"
 #include "arm_opcodes.h"
+#include "arm_semihosting.h"
 
 /*
  * For information about ARM7TDMI, see ARM DDI 0210C (r4p1)
@@ -615,7 +616,7 @@ static void arm7tdmi_build_reg_cache(struct target *target)
 int arm7tdmi_init_target(struct command_context *cmd_ctx, struct target *target)
 {
        arm7tdmi_build_reg_cache(target);
-
+       arm_semihosting_init(target);
        return ERROR_OK;
 }
 
index eed965a376ee9f069f7526949278e1241c612476..82b430f88d5583caa45c668396fd025c95ec99a8 100644 (file)
@@ -30,6 +30,7 @@
 #include "target_type.h"
 #include "register.h"
 #include "arm_opcodes.h"
+#include "arm_semihosting.h"
 
 /*
  * NOTE:  this holds code that's used with multiple ARM9 processors:
@@ -714,6 +715,7 @@ int arm9tdmi_init_target(struct command_context *cmd_ctx,
                struct target *target)
 {
        arm9tdmi_build_reg_cache(target);
+       arm_semihosting_init(target);
        return ERROR_OK;
 }
 
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;
 }
index 7b5c0b2de91e1a7e1f15ae2a6fe315f93e5cee5e..011f19f00cec633fdc69be169f394ef0ee2dfa1a 100644 (file)
@@ -19,6 +19,7 @@
 #ifndef OPENOCD_TARGET_ARM_SEMIHOSTING_H
 #define OPENOCD_TARGET_ARM_SEMIHOSTING_H
 
+int arm_semihosting_init(struct target *target);
 int arm_semihosting(struct target *target, int *retval);
 
 #endif /* OPENOCD_TARGET_ARM_SEMIHOSTING_H */
index 1a31d40ce24f51a923c0a136858c5ed474cf5f5d..624a2543db49909dfcc096e91f539d2d00c19fb9 100644 (file)
@@ -666,14 +666,19 @@ int arm_arch_state(struct target *target)
                return ERROR_FAIL;
        }
 
+       /* avoid filling log waiting for fileio reply */
+       if (arm->semihosting_hit_fileio)
+               return ERROR_OK;
+
        LOG_USER("target halted in %s state due to %s, current mode: %s\n"
-               "cpsr: 0x%8.8" PRIx32 " pc: 0x%8.8" PRIx32 "%s",
+               "cpsr: 0x%8.8" PRIx32 " pc: 0x%8.8" PRIx32 "%s%s",
                arm_state_strings[arm->core_state],
                debug_reason_name(target),
                arm_mode_name(arm->core_mode),
                buf_get_u32(arm->cpsr->value, 0, 32),
                buf_get_u32(arm->pc->value, 0, 32),
-               arm->is_semihosting ? ", semihosting" : "");
+               arm->is_semihosting ? ", semihosting" : "",
+               arm->is_semihosting_fileio ? " fileio" : "");
 
        return ERROR_OK;
 }
@@ -1055,6 +1060,37 @@ COMMAND_HANDLER(handle_arm_semihosting_command)
        return ERROR_OK;
 }
 
+COMMAND_HANDLER(handle_arm_semihosting_fileio_command)
+{
+       struct target *target = get_current_target(CMD_CTX);
+
+       if (target == NULL) {
+               LOG_ERROR("No target selected");
+               return ERROR_FAIL;
+       }
+
+       struct arm *arm = target_to_arm(target);
+
+       if (!is_arm(arm)) {
+               command_print(CMD_CTX, "current target isn't an ARM");
+               return ERROR_FAIL;
+       }
+
+       if (!arm->is_semihosting) {
+               command_print(CMD_CTX, "semihosting is not enabled");
+               return ERROR_FAIL;
+       }
+
+       if (CMD_ARGC > 0)
+               COMMAND_PARSE_ENABLE(CMD_ARGV[0], arm->is_semihosting_fileio);
+
+       command_print(CMD_CTX, "semihosting fileio is %s",
+               arm->is_semihosting_fileio
+               ? "enabled" : "disabled");
+
+       return ERROR_OK;
+}
+
 static const struct command_registration arm_exec_command_handlers[] = {
        {
                .name = "reg",
@@ -1097,6 +1133,13 @@ static const struct command_registration arm_exec_command_handlers[] = {
                .usage = "['enable'|'disable']",
                .help = "activate support for semihosting operations",
        },
+       {
+               "semihosting_fileio",
+               .handler = handle_arm_semihosting_fileio_command,
+               .mode = COMMAND_EXEC,
+               .usage = "['enable'|'disable']",
+               .help = "activate support for semihosting fileio operations",
+       },
 
        COMMAND_REGISTRATION_DONE
 };
index 60b244aae38b51a879a03ebaea6f148752a636f6..64d18d75aa800c9848f48adcbde507528f1f6c61 100644 (file)
@@ -536,11 +536,15 @@ int armv7m_arch_state(struct target *target)
        struct arm *arm = &armv7m->arm;
        uint32_t ctrl, sp;
 
+       /* avoid filling log waiting for fileio reply */
+       if (arm->semihosting_hit_fileio)
+               return ERROR_OK;
+
        ctrl = buf_get_u32(arm->core_cache->reg_list[ARMV7M_CONTROL].value, 0, 32);
        sp = buf_get_u32(arm->core_cache->reg_list[ARMV7M_R13].value, 0, 32);
 
        LOG_USER("target halted due to %s, current mode: %s %s\n"
-               "xPSR: %#8.8" PRIx32 " pc: %#8.8" PRIx32 " %csp: %#8.8" PRIx32 "%s",
+               "xPSR: %#8.8" PRIx32 " pc: %#8.8" PRIx32 " %csp: %#8.8" PRIx32 "%s%s",
                debug_reason_name(target),
                arm_mode_name(arm->core_mode),
                armv7m_exception_string(armv7m->exception_number),
@@ -548,7 +552,8 @@ int armv7m_arch_state(struct target *target)
                buf_get_u32(arm->pc->value, 0, 32),
                (ctrl & 0x02) ? 'p' : 'm',
                sp,
-               arm->is_semihosting ? ", semihosting" : "");
+               arm->is_semihosting ? ", semihosting" : "",
+               arm->is_semihosting_fileio ? " fileio" : "");
 
        return ERROR_OK;
 }
index 91fa48e1adcc1e56aabb13a3b8e0ef7387a5f28a..ed2f6137705fd5e96925d05993f29876ed040b16 100644 (file)
@@ -3103,6 +3103,7 @@ static int cortex_a_init_target(struct command_context *cmd_ctx,
        struct target *target)
 {
        /* examine_first() does a bunch of this */
+       arm_semihosting_init(target);
        return ERROR_OK;
 }
 
index 4270f8f332ec6a9c1f1bfef0026f438e60e51707..f674cc527c0a6a7c7e5fa6fa616436c3607663f6 100644 (file)
@@ -1696,6 +1696,7 @@ static int cortex_m_init_target(struct command_context *cmd_ctx,
        struct target *target)
 {
        armv7m_build_reg_cache(target);
+       arm_semihosting_init(target);
        return ERROR_OK;
 }
 
index e02abc42eda227e3f26fe8055b598db1acba40c4..feeb11f667c3b2d867967664aae8ba448ea949ed 100644 (file)
@@ -341,7 +341,7 @@ static int adapter_init_target(struct command_context *cmd_ctx,
        LOG_DEBUG("%s", __func__);
 
        armv7m_build_reg_cache(target);
-
+       arm_semihosting_init(target);
        return ERROR_OK;
 }
 
index 26bae4b69a5ed13907f2b1833d5dff085dc2520e..17902a51c8ac7c46d54d707c82f3e0d1faaf547f 100644 (file)
@@ -1944,13 +1944,10 @@ int target_arch_state(struct target *target)
 {
        int retval;
        if (target == NULL) {
-               LOG_USER("No target has been configured");
+               LOG_WARNING("No target has been configured");
                return ERROR_OK;
        }
 
-       LOG_USER("%s: target state: %s", target_name(target),
-                target_state_name(target));
-
        if (target->state != TARGET_HALTED)
                return ERROR_OK;
 

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)