]> git.sur5r.net Git - openocd/blobdiff - src/target/arm_semihosting.c
ZY1000 help/usage fixups
[openocd] / src / target / arm_semihosting.c
index 5e0a2bedcd5c8520e0582797aec2694de505d50d..f4244c84d11c15985590e2abda59317f1db34fb3 100644 (file)
 #include "config.h"
 #endif
 
+#include "arm.h"
 #include "armv4_5.h"
 #include "register.h"
 #include "arm_semihosting.h"
 #include <helper/binarybuffer.h>
 #include <helper/log.h>
 
-/* TODO: this needs to be per target */
-int semihosting_active;
-int semihosting_errno;
 
 static int do_semihosting(struct target *target)
 {
-       struct arm *armv4_5 = target_to_armv4_5(target);
+       struct arm *armv4_5 = target_to_arm(target);
        uint32_t r0 = buf_get_u32(armv4_5->core_cache->reg_list[0].value, 0, 32);
        uint32_t r1 = buf_get_u32(armv4_5->core_cache->reg_list[1].value, 0, 32);
-       uint32_t lr = buf_get_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, ARMV4_5_MODE_SVC, 14).value, 0, 32);
+       uint32_t lr = buf_get_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, ARM_MODE_SVC, 14).value, 0, 32);
        uint32_t spsr = buf_get_u32(armv4_5->spsr->value, 0, 32);;
        uint8_t params[16];
        int retval, result;
@@ -59,6 +57,9 @@ static int do_semihosting(struct target *target)
         * - no validation on target provided file descriptors
         * - 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.
         */
        switch (r0) {
        case 0x01:      /* SYS_OPEN */
@@ -93,10 +94,10 @@ static int do_semihosting(struct target *target)
                                                result = dup(1);
                                } else
                                        result = open((char *)fn, mode);
-                               semihosting_errno =  errno;
+                               armv4_5->semihosting_errno =  errno;
                        } else {
                                result = -1;
-                               semihosting_errno = EINVAL;
+                               armv4_5->semihosting_errno = EINVAL;
                        }
                }
                break;
@@ -108,7 +109,7 @@ static int do_semihosting(struct target *target)
                else {
                        int fd = target_buffer_get_u32(target, params+0);
                        result = close(fd);
-                       semihosting_errno = errno;
+                       armv4_5->semihosting_errno = errno;
                }
                break;
 
@@ -147,7 +148,7 @@ static int do_semihosting(struct target *target)
                        uint8_t *buf = malloc(l);
                        if (!buf) {
                                result = -1;
-                               semihosting_errno = ENOMEM;
+                               armv4_5->semihosting_errno = ENOMEM;
                        } else {
                                retval = target_read_buffer(target, a, l, buf);
                                if (retval != ERROR_OK) {
@@ -155,7 +156,7 @@ static int do_semihosting(struct target *target)
                                        return retval;
                                }
                                result = write(fd, buf, l);
-                               semihosting_errno = errno;
+                               armv4_5->semihosting_errno = errno;
                                if (result >= 0)
                                        result = l - result;
                                free(buf);
@@ -174,10 +175,10 @@ static int do_semihosting(struct target *target)
                        uint8_t *buf = malloc(l);
                        if (!buf) {
                                result = -1;
-                               semihosting_errno = ENOMEM;
+                               armv4_5->semihosting_errno = ENOMEM;
                        } else {
                                result = read(fd, buf, l);
-                               semihosting_errno = errno;
+                               armv4_5->semihosting_errno = errno;
                                if (result > 0) {
                                        retval = target_write_buffer(target, a, result, buf);
                                        if (retval != ERROR_OK) {
@@ -217,7 +218,7 @@ static int do_semihosting(struct target *target)
                        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);
-                       semihosting_errno = errno;
+                       armv4_5->semihosting_errno = errno;
                        if (result == pos)
                                result = 0;
                }
@@ -231,14 +232,14 @@ static int do_semihosting(struct target *target)
                        int fd = target_buffer_get_u32(target, params+0);
                        off_t cur = lseek(fd, 0, SEEK_CUR);
                        if (cur == (off_t)-1) {
-                               semihosting_errno = errno;
+                               armv4_5->semihosting_errno = errno;
                                result = -1;
                                break;
                        }
                        result = lseek(fd, 0, SEEK_END);
-                       semihosting_errno = errno;
+                       armv4_5->semihosting_errno = errno;
                        if (lseek(fd, cur, SEEK_SET) == (off_t)-1) {
-                               semihosting_errno = errno;
+                               armv4_5->semihosting_errno = errno;
                                result = -1;
                        }
                }
@@ -258,10 +259,10 @@ static int do_semihosting(struct target *target)
                                        return retval;
                                fn[l] = 0;
                                result = remove((char *)fn);
-                               semihosting_errno =  errno;
+                               armv4_5->semihosting_errno =  errno;
                        } else {
                                result = -1;
-                               semihosting_errno = EINVAL;
+                               armv4_5->semihosting_errno = EINVAL;
                        }
                }
                break;
@@ -286,10 +287,10 @@ static int do_semihosting(struct target *target)
                                fn1[l1] = 0;
                                fn2[l2] = 0;
                                result = rename((char *)fn1, (char *)fn2);
-                               semihosting_errno =  errno;
+                               armv4_5->semihosting_errno =  errno;
                        } else {
                                result = -1;
-                               semihosting_errno = EINVAL;
+                               armv4_5->semihosting_errno = EINVAL;
                        }
                }
                break;
@@ -299,7 +300,7 @@ static int do_semihosting(struct target *target)
                break;
 
        case 0x13:      /* SYS_ERRNO */
-               result = semihosting_errno;
+               result = armv4_5->semihosting_errno;
                break;
 
        case 0x15:      /* SYS_GET_CMDLINE */
@@ -360,7 +361,8 @@ static int do_semihosting(struct target *target)
                case 0x20028:   /* ADP_Stopped_DivisionByZero */
                case 0x20029:   /* ADP_Stopped_OSSpecific */
                default:
-                       fprintf(stderr, "semihosting: exception %#x\n", r1);
+                       fprintf(stderr, "semihosting: exception %#x\n",
+                                       (unsigned) r1);
                }
                return target_call_event_callbacks(target, TARGET_EVENT_HALTED);
 
@@ -371,21 +373,29 @@ static int do_semihosting(struct target *target)
        case 0x30:      /* SYS_ELAPSED */
        case 0x31:      /* SYS_TICKFREQ */
        default:
-               fprintf(stderr, "semihosting: unsupported call %#x\n", r0);
+               fprintf(stderr, "semihosting: unsupported call %#x\n",
+                               (unsigned) r0);
                result = -1;
-               semihosting_errno = ENOTSUP;
+               armv4_5->semihosting_errno = ENOTSUP;
        }
 
        /* resume execution to the original mode */
+
+       /* return value in R0 */
        buf_set_u32(armv4_5->core_cache->reg_list[0].value, 0, 32, result);
        armv4_5->core_cache->reg_list[0].dirty = 1;
+
+       /* LR --> PC */
        buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, lr);
        armv4_5->core_cache->reg_list[15].dirty = 1;
-       buf_set_u32(armv4_5->core_cache->reg_list[ARMV4_5_CPSR].value, 0, 32, spsr);
-       armv4_5->core_cache->reg_list[ARMV4_5_CPSR].dirty = 1;
+
+       /* saved PSR --> current PSR */
+       buf_set_u32(armv4_5->cpsr->value, 0, 32, spsr);
+       armv4_5->cpsr->dirty = 1;
        armv4_5->core_mode = spsr & 0x1f;
        if (spsr & 0x20)
-               armv4_5->core_state = ARMV4_5_STATE_THUMB;
+               armv4_5->core_state = ARM_STATE_THUMB;
+
        return target_resume(target, 1, 0, 0, 0);
 }
 
@@ -397,42 +407,68 @@ static int do_semihosting(struct target *target)
  * or an error was encountered, in which case the caller must return
  * immediately.
  *
- * @param target Pointer to the ARM target to process
+ * @param target Pointer to the ARM target to process.  This target must
+ *     not represent an ARMv6-M or ARMv7-M processor.
  * @param retval Pointer to a location where the return code will be stored
  * @return non-zero value if a request was processed or an error encountered
  */
 int arm_semihosting(struct target *target, int *retval)
 {
-       struct arm *armv4_5 = target_to_armv4_5(target);
-       uint32_t lr, spsr;
+       struct arm *arm = target_to_arm(target);
+       uint32_t pc, lr, spsr;
+       struct reg *r;
 
-       if (!semihosting_active ||
-           armv4_5->core_mode != ARMV4_5_MODE_SVC ||
-           buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32) != 0x08)
+       if (!arm->is_semihosting || arm->core_mode != ARM_MODE_SVC)
                return 0;
 
-       lr = buf_get_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, ARMV4_5_MODE_SVC, 14).value, 0, 32);
-       spsr = buf_get_u32(armv4_5->spsr->value, 0, 32);
+       /* Check for PC == 0x00000008 or 0xffff0008: Supervisor Call vector. */
+       r = arm->core_cache->reg_list + 15;
+       pc = buf_get_u32(r->value, 0, 32);
+       if (pc != 0x00000008 && pc != 0xffff0008)
+               return 0;
+
+       r = arm_reg_current(arm, 14);
+       lr = buf_get_u32(r->value, 0, 32);
+
+       /* Core-specific code should make sure SPSR is retrieved
+        * when the above checks pass...
+        */
+       if (!arm->spsr->valid) {
+               LOG_ERROR("SPSR not valid!");
+               *retval = ERROR_FAIL;
+               return 1;
+       }
+
+       spsr = buf_get_u32(arm->spsr->value, 0, 32);
 
        /* check instruction that triggered this trap */
        if (spsr & (1 << 5)) {
-               /* was in Thumb mode */
+               /* was in Thumb (or ThumbEE) mode */
                uint8_t insn_buf[2];
                uint16_t insn;
+
                *retval = target_read_memory(target, lr-2, 2, 1, insn_buf);
                if (*retval != ERROR_OK)
                        return 1;
                insn = target_buffer_get_u16(target, insn_buf);
+
+               /* SVC 0xab */
                if (insn != 0xDFAB)
                        return 0;
+       } else if (spsr & (1 << 24)) {
+               /* was in Jazelle mode */
+               return 0;
        } else {
                /* was in ARM mode */
                uint8_t insn_buf[4];
                uint32_t insn;
+
                *retval = target_read_memory(target, lr-4, 4, 1, insn_buf);
                if (*retval != ERROR_OK)
                        return 1;
                insn = target_buffer_get_u32(target, insn_buf);
+
+               /* SVC 0x123456 */
                if (insn != 0xEF123456)
                        return 0;
        }