X-Git-Url: https://review.openocd.org/gitweb?a=blobdiff_plain;ds=sidebyside;f=src%2Ftarget%2Farm_semihosting.c;h=9b853d9f942d08da4fc29412238948ca6a09eaaa;hb=ff5deeeeaa4f394931e3c5ccfb4cfd33beda0743;hp=d71fbaef02bd0544f6ad0cceec5021604507ec1d;hpb=87589043faf8cdb954c602c988698c40fcf9c108;p=openocd.git diff --git a/src/target/arm_semihosting.c b/src/target/arm_semihosting.c index d71fbaef02..9b853d9f94 100644 --- a/src/target/arm_semihosting.c +++ b/src/target/arm_semihosting.c @@ -2,6 +2,9 @@ * Copyright (C) 2009 by Marvell Technology Group Ltd. * * Written by Nicolas Pitre * * * + * Copyright (C) 2010 by Spencer Oliver * + * spen@spen-soft.co.uk * + * * * 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 * @@ -34,12 +37,28 @@ #include "config.h" #endif +#include "arm.h" #include "armv4_5.h" #include "register.h" #include "arm_semihosting.h" #include #include - +#include + +static int open_modeflags[12] = { + O_RDONLY, + O_RDONLY | O_BINARY, + O_RDWR, + O_RDWR | O_BINARY, + O_WRONLY | O_CREAT | O_TRUNC, + O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, + O_RDWR | O_CREAT | O_TRUNC, + O_RDWR | O_CREAT | O_TRUNC | O_BINARY, + O_WRONLY | O_CREAT | O_APPEND, + O_WRONLY | O_CREAT | O_APPEND | O_BINARY, + O_RDWR | O_CREAT | O_APPEND, + O_RDWR | O_CREAT | O_APPEND | O_BINARY +}; static int do_semihosting(struct target *target) { @@ -71,28 +90,21 @@ static int do_semihosting(struct target *target) uint32_t l = target_buffer_get_u32(target, params+8); if (l <= 255 && m <= 11) { uint8_t fn[256]; - int mode; retval = target_read_memory(target, a, 1, l, fn); if (retval != ERROR_OK) return retval; fn[l] = 0; - if (m & 0x2) - mode = O_RDWR; - else if (m & 0xc) - mode = O_WRONLY; - else - mode = O_RDONLY; - if (m >= 8) - mode |= O_CREAT|O_APPEND; - else if (m >= 4) - mode |= O_CREAT|O_TRUNC; if (strcmp((char *)fn, ":tt") == 0) { - if ((mode & 3) == 0) - result = dup(0); + if (m < 4) + result = dup(STDIN_FILENO); else - result = dup(1); - } else - result = open((char *)fn, mode); + 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); + } armv4_5->semihosting_errno = errno; } else { result = -1; @@ -178,7 +190,7 @@ static int do_semihosting(struct target *target) } else { result = read(fd, buf, l); armv4_5->semihosting_errno = errno; - if (result > 0) { + if (result >= 0) { retval = target_write_buffer(target, a, result, buf); if (retval != ERROR_OK) { free(buf); @@ -229,18 +241,14 @@ static int do_semihosting(struct target *target) return retval; else { int fd = target_buffer_get_u32(target, params+0); - off_t cur = lseek(fd, 0, SEEK_CUR); - if (cur == (off_t)-1) { + struct stat buf; + result = fstat(fd, &buf); + if (result == -1) { armv4_5->semihosting_errno = errno; result = -1; break; } - result = lseek(fd, 0, SEEK_END); - armv4_5->semihosting_errno = errno; - if (lseek(fd, cur, SEEK_SET) == (off_t)-1) { - armv4_5->semihosting_errno = errno; - result = -1; - } + result = buf.st_size; } break; @@ -379,15 +387,22 @@ static int do_semihosting(struct target *target) } /* 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 = ARM_STATE_THUMB; + return target_resume(target, 1, 0, 0, 0); } @@ -407,18 +422,16 @@ static int do_semihosting(struct target *target) int arm_semihosting(struct target *target, int *retval) { struct arm *arm = target_to_arm(target); - uint32_t lr, spsr; + uint32_t pc, lr, spsr; struct reg *r; if (!arm->is_semihosting || arm->core_mode != ARM_MODE_SVC) return 0; - /* Check for PC == 8: Supervisor Call vector - * REVISIT: assumes low exception vectors, not hivecs... - * safer to test "was this entry from a vector catch". - */ + /* Check for PC == 0x00000008 or 0xffff0008: Supervisor Call vector. */ r = arm->core_cache->reg_list + 15; - if (buf_get_u32(r->value, 0, 32) != 0x08) + pc = buf_get_u32(r->value, 0, 32); + if (pc != 0x00000008 && pc != 0xffff0008) return 0; r = arm_reg_current(arm, 14);