#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)
{
* - 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 */
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;
else {
int fd = target_buffer_get_u32(target, params+0);
result = close(fd);
- semihosting_errno = errno;
+ armv4_5->semihosting_errno = errno;
}
break;
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) {
return retval;
}
result = write(fd, buf, l);
- semihosting_errno = errno;
+ armv4_5->semihosting_errno = errno;
if (result >= 0)
result = l - result;
free(buf);
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) {
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;
}
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;
}
}
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;
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;
break;
case 0x13: /* SYS_ERRNO */
- result = semihosting_errno;
+ result = armv4_5->semihosting_errno;
break;
case 0x15: /* SYS_GET_CMDLINE */
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 */
* 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);
+ struct arm *arm = target_to_armv4_5(target);
uint32_t lr, spsr;
+ struct reg *r;
+
+ if (!arm->is_semihosting || arm->core_mode != ARMV4_5_MODE_SVC)
+ return 0;
- 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)
+ /* Check for PC == 8: Supervisor Call vector
+ * REVISIT: assumes low exception vectors, not hivecs...
+ * safer to test "was this entry from a vector catch".
+ */
+ r = arm->core_cache->reg_list + 15;
+ if (buf_get_u32(r->value, 0, 32) != 0x08)
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);
+ 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;
}