]> git.sur5r.net Git - openocd/blobdiff - src/target/arm_semihosting.c
stlink: remove usb timeout magic numbers
[openocd] / src / target / arm_semihosting.c
index 2f50a4a6591a2e6c8d55214a63752eec10e3f415..bdf572ec9897cb006b159d54f610ebef6712ae24 100644 (file)
@@ -18,7 +18,7 @@
  *   You should have received a copy of the GNU General Public License     *
  *   along with this program; if not, write to the                         *
  *   Free Software Foundation, Inc.,                                       *
- *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.           *
  ***************************************************************************/
 
 /**
@@ -41,7 +41,7 @@
 #include "armv4_5.h"
 #include "arm7_9_common.h"
 #include "armv7m.h"
-#include "cortex_m3.h"
+#include "cortex_m.h"
 #include "register.h"
 #include "arm_semihosting.h"
 #include <helper/binarybuffer.h>
@@ -68,16 +68,9 @@ static int do_semihosting(struct target *target)
        struct arm *arm = target_to_arm(target);
        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);
-       uint32_t lr, spsr;
        uint8_t params[16];
        int retval, result;
 
-       if (is_arm7_9(target_to_arm7_9(target)))
-       {
-               lr = buf_get_u32(ARMV4_5_CORE_REG_MODE(arm->core_cache, ARM_MODE_SVC, 14).value, 0, 32);
-               spsr = buf_get_u32(arm->spsr->value, 0, 32);;
-       }
-
        /*
         * TODO: lots of security issues are not considered yet, such as:
         * - no validation on target provided file descriptors
@@ -146,7 +139,7 @@ static int do_semihosting(struct target *target)
        case 0x04:      /* SYS_WRITE0 */
                do {
                        unsigned char c;
-                       retval = target_read_memory(target, r1, 1, 1, &c);
+                       retval = target_read_memory(target, r1++, 1, 1, &c);
                        if (retval != ERROR_OK)
                                return retval;
                        if (!c)
@@ -330,7 +323,7 @@ static int do_semihosting(struct target *target)
                        if (l < s)
                                result = -1;
                        else {
-                               retval = target_write_buffer(target, a, s, (void*)arg);
+                               retval = target_write_buffer(target, a, s, (void *)arg);
                                if (retval != ERROR_OK)
                                        return retval;
                                result = 0;
@@ -381,9 +374,34 @@ static int do_semihosting(struct target *target)
                }
                return target_call_event_callbacks(target, TARGET_EVENT_HALTED);
 
+       case 0x12:      /* SYS_SYSTEM */
+               /* Provide SYS_SYSTEM functionality.  Uses the
+                * libc system command, there may be a reason *NOT*
+                * to use this, but as I can't think of one, I
+                * implemented it this way.
+                */
+               retval = target_read_memory(target, r1, 4, 2, params);
+               if (retval != ERROR_OK)
+                       return retval;
+               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;
+                       } 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);
+                       }
+               }
+               break;
        case 0x0d:      /* SYS_TMPNAM */
        case 0x10:      /* SYS_CLOCK */
-       case 0x12:      /* SYS_SYSTEM */
        case 0x17:      /* angel_SWIreason_EnterSVC */
        case 0x30:      /* SYS_ELAPSED */
        case 0x31:      /* SYS_TICKFREQ */
@@ -396,25 +414,35 @@ static int do_semihosting(struct target *target)
 
        /* resume execution to the original mode */
 
-       if (is_arm7_9(target_to_arm7_9(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))) {
+               uint32_t spsr;
+
                /* 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;
 
                /* LR --> PC */
-               buf_set_u32(arm->core_cache->reg_list[15].value, 0, 32, lr);
+               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
-       {
+
+       } else {
                /* resume execution, this will be pc+2 to skip over the
                 * bkpt instruction */
 
@@ -448,8 +476,7 @@ int arm_semihosting(struct target *target, int *retval)
        if (!arm->is_semihosting)
                return 0;
 
-       if (is_arm7_9(target_to_arm7_9(target)))
-       {
+       if (is_arm7_9(target_to_arm7_9(target))) {
                if (arm->core_mode != ARM_MODE_SVC)
                        return 0;
 
@@ -504,9 +531,7 @@ int arm_semihosting(struct target *target, int *retval)
                        if (insn != 0xEF123456)
                                return 0;
                }
-       }
-       else if (is_armv7m(target_to_armv7m(target)))
-       {
+       } else if (is_armv7m(target_to_armv7m(target))) {
                uint16_t insn;
 
                if (target->debug_reason != DBG_REASON_BREAKPOINT)
@@ -523,9 +548,7 @@ int arm_semihosting(struct target *target, int *retval)
                /* bkpt 0xAB */
                if (insn != 0xBEAB)
                        return 0;
-       }
-       else
-       {
+       } else {
                LOG_ERROR("Unsupported semi-hosting Target");
                return 0;
        }