aboutsummaryrefslogtreecommitdiff
path: root/src/target/semihosting_common.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/target/semihosting_common.c')
-rw-r--r--src/target/semihosting_common.c149
1 files changed, 113 insertions, 36 deletions
diff --git a/src/target/semihosting_common.c b/src/target/semihosting_common.c
index 6c91876..f7acc60 100644
--- a/src/target/semihosting_common.c
+++ b/src/target/semihosting_common.c
@@ -223,7 +223,10 @@ static ssize_t semihosting_write(struct semihosting *semihosting, int fd, void *
return semihosting_redirect_write(semihosting, buf, size);
/* default write */
- return write(fd, buf, size);
+ int result = write(fd, buf, size);
+ if (result == -1)
+ semihosting->sys_errno = errno;
+ return result;
}
static ssize_t semihosting_redirect_read(struct semihosting *semihosting, void *buf, int size)
@@ -268,7 +271,8 @@ static inline ssize_t semihosting_read(struct semihosting *semihosting, int fd,
/* default read */
ssize_t result = read(fd, buf, size);
- semihosting->sys_errno = errno;
+ if (result == -1)
+ semihosting->sys_errno = errno;
return result;
}
@@ -294,6 +298,66 @@ static inline int semihosting_getchar(struct semihosting *semihosting, int fd)
*/
static char *semihosting_user_op_params;
+const char *semihosting_opcode_to_str(const uint64_t opcode)
+{
+ switch (opcode) {
+ case SEMIHOSTING_SYS_CLOSE:
+ return "CLOSE";
+ case SEMIHOSTING_SYS_CLOCK:
+ return "CLOCK";
+ case SEMIHOSTING_SYS_ELAPSED:
+ return "ELAPSED";
+ case SEMIHOSTING_SYS_ERRNO:
+ return "ERRNO";
+ case SEMIHOSTING_SYS_EXIT:
+ return "EXIT";
+ case SEMIHOSTING_SYS_EXIT_EXTENDED:
+ return "EXIT_EXTENDED";
+ case SEMIHOSTING_SYS_FLEN:
+ return "FLEN";
+ case SEMIHOSTING_SYS_GET_CMDLINE:
+ return "GET_CMDLINE";
+ case SEMIHOSTING_SYS_HEAPINFO:
+ return "HEAPINFO";
+ case SEMIHOSTING_SYS_ISERROR:
+ return "ISERROR";
+ case SEMIHOSTING_SYS_ISTTY:
+ return "ISTTY";
+ case SEMIHOSTING_SYS_OPEN:
+ return "OPEN";
+ case SEMIHOSTING_SYS_READ:
+ return "READ";
+ case SEMIHOSTING_SYS_READC:
+ return "READC";
+ case SEMIHOSTING_SYS_REMOVE:
+ return "REMOVE";
+ case SEMIHOSTING_SYS_RENAME:
+ return "RENAME";
+ case SEMIHOSTING_SYS_SEEK:
+ return "SEEK";
+ case SEMIHOSTING_SYS_SYSTEM:
+ return "SYSTEM";
+ case SEMIHOSTING_SYS_TICKFREQ:
+ return "TICKFREQ";
+ case SEMIHOSTING_SYS_TIME:
+ return "TIME";
+ case SEMIHOSTING_SYS_TMPNAM:
+ return "TMPNAM";
+ case SEMIHOSTING_SYS_WRITE:
+ return "WRITE";
+ case SEMIHOSTING_SYS_WRITEC:
+ return "WRITEC";
+ case SEMIHOSTING_SYS_WRITE0:
+ return "WRITE0";
+ case SEMIHOSTING_USER_CMD_0X100 ... SEMIHOSTING_USER_CMD_0X1FF:
+ return "USER_CMD";
+ case SEMIHOSTING_ARM_RESERVED_START ... SEMIHOSTING_ARM_RESERVED_END:
+ return "ARM_RESERVED_CMD";
+ default:
+ return "<unknown>";
+ }
+}
+
/**
* Portable implementation of ARM semihosting calls.
* Performs the currently pending semihosting operation
@@ -323,8 +387,9 @@ int semihosting_common(struct target *target)
/* Enough space to hold 4 long words. */
uint8_t fields[4*8];
- LOG_DEBUG("op=0x%x, param=0x%" PRIx64, semihosting->op,
- semihosting->param);
+ LOG_DEBUG("op=0x%x (%s), param=0x%" PRIx64, semihosting->op,
+ semihosting_opcode_to_str(semihosting->op),
+ semihosting->param);
switch (semihosting->op) {
@@ -388,12 +453,7 @@ int semihosting_common(struct target *target)
(fd == 0) ? "stdin" :
(fd == 1) ? "stdout" : "stderr");
/* Just pretend success */
- if (semihosting->is_fileio) {
- semihosting->result = 0;
- } else {
- semihosting->result = 0;
- semihosting->sys_errno = 0;
- }
+ semihosting->result = 0;
break;
}
/* Close the descriptor */
@@ -403,7 +463,8 @@ int semihosting_common(struct target *target)
fileio_info->param_1 = fd;
} else {
semihosting->result = close(fd);
- semihosting->sys_errno = errno;
+ if (semihosting->result == -1)
+ semihosting->sys_errno = errno;
LOG_DEBUG("close(%d)=%" PRId64, fd, semihosting->result);
}
}
@@ -781,7 +842,8 @@ int semihosting_common(struct target *target)
int fd = semihosting_get_field(target, 0, fields);
// isatty() on Windows may return any non-zero value if fd is a terminal
semihosting->result = isatty(fd) ? 1 : 0;
- semihosting->sys_errno = errno;
+ if (semihosting->result == 0)
+ semihosting->sys_errno = errno;
LOG_DEBUG("isatty(%d)=%" PRId64, fd, semihosting->result);
}
break;
@@ -873,14 +935,16 @@ int semihosting_common(struct target *target)
semihosting->result = -1;
semihosting->sys_errno = EINVAL;
} else if (strcmp((char *)fn, ":tt") == 0) {
- if (mode == 0)
+ if (mode == 0) {
semihosting->result = 0;
- else if (mode == 4)
+ } else if (mode == 4) {
semihosting->result = 1;
- else if (mode == 8)
+ } else if (mode == 8) {
semihosting->result = 2;
- else
+ } else {
semihosting->result = -1;
+ semihosting->sys_errno = EINVAL;
+ }
} else {
semihosting->hit_fileio = true;
fileio_info->identifier = "open";
@@ -895,25 +959,23 @@ int semihosting_common(struct target *target)
* - 0-3 ("r") for stdin,
* - 4-7 ("w") for stdout,
* - 8-11 ("a") for stderr */
+ int fd;
if (mode < 4) {
- int fd = dup(STDIN_FILENO);
- semihosting->result = fd;
+ fd = dup(STDIN_FILENO);
semihosting->stdin_fd = fd;
- semihosting->sys_errno = errno;
- LOG_DEBUG("dup(STDIN)=%" PRId64, semihosting->result);
+ LOG_DEBUG("dup(STDIN)=%d", fd);
} else if (mode < 8) {
- int fd = dup(STDOUT_FILENO);
- semihosting->result = fd;
+ fd = dup(STDOUT_FILENO);
semihosting->stdout_fd = fd;
- semihosting->sys_errno = errno;
- LOG_DEBUG("dup(STDOUT)=%" PRId64, semihosting->result);
+ LOG_DEBUG("dup(STDOUT)=%d", fd);
} else {
- int fd = dup(STDERR_FILENO);
- semihosting->result = fd;
+ fd = dup(STDERR_FILENO);
semihosting->stderr_fd = fd;
- semihosting->sys_errno = errno;
- LOG_DEBUG("dup(STDERR)=%" PRId64, semihosting->result);
+ LOG_DEBUG("dup(STDERR)=%d", fd);
}
+ semihosting->result = fd;
+ if (fd == -1)
+ semihosting->sys_errno = errno;
} else {
/* cygwin requires the permission setting
* otherwise it will fail to reopen a previously
@@ -921,7 +983,8 @@ int semihosting_common(struct target *target)
semihosting->result = open((char *)fn,
open_host_modeflags[mode],
0644);
- semihosting->sys_errno = errno;
+ if (semihosting->result == -1)
+ semihosting->sys_errno = errno;
LOG_DEBUG("open('%s')=%" PRId64, fn, semihosting->result);
}
}
@@ -1070,7 +1133,8 @@ int semihosting_common(struct target *target)
}
fn[len] = 0;
semihosting->result = remove((char *)fn);
- semihosting->sys_errno = errno;
+ if (semihosting->result == -1)
+ semihosting->sys_errno = errno;
LOG_DEBUG("remove('%s')=%" PRId64, fn, semihosting->result);
free(fn);
@@ -1139,7 +1203,9 @@ int semihosting_common(struct target *target)
fn2[len2] = 0;
semihosting->result = rename((char *)fn1,
(char *)fn2);
- semihosting->sys_errno = errno;
+ // rename() on Windows returns nonzero on error
+ if (semihosting->result != 0)
+ semihosting->sys_errno = errno;
LOG_DEBUG("rename('%s', '%s')=%" PRId64 " %d", fn1, fn2, semihosting->result, errno);
free(fn1);
free(fn2);
@@ -1184,7 +1250,8 @@ int semihosting_common(struct target *target)
fileio_info->param_3 = SEEK_SET;
} else {
semihosting->result = lseek(fd, pos, SEEK_SET);
- semihosting->sys_errno = errno;
+ if (semihosting->result == -1)
+ semihosting->sys_errno = errno;
LOG_DEBUG("lseek(%d, %d)=%" PRId64, fd, (int)pos, semihosting->result);
if (semihosting->result == pos)
semihosting->result = 0;
@@ -1322,7 +1389,6 @@ int semihosting_common(struct target *target)
return retval;
}
semihosting->result = semihosting_write(semihosting, fd, buf, len);
- semihosting->sys_errno = errno;
LOG_DEBUG("write(%d, 0x%" PRIx64 ", %zu)=%" PRId64,
fd,
addr,
@@ -1470,8 +1536,9 @@ int semihosting_common(struct target *target)
retval = target_read_buffer(target, addr, len,
(uint8_t *)(semihosting_user_op_params));
if (retval != ERROR_OK) {
- LOG_ERROR("Failed to read from target, semihosting op=0x%x",
- semihosting->op);
+ LOG_ERROR("Failed to read from target, semihosting op=0x%x (%s)",
+ semihosting->op,
+ semihosting_opcode_to_str(semihosting->op));
free(semihosting_user_op_params);
semihosting_user_op_params = NULL;
return retval;
@@ -1609,7 +1676,6 @@ static int semihosting_common_fileio_end(struct target *target, int result,
semihosting->hit_fileio = false;
semihosting->result = result;
- semihosting->sys_errno = fileio_errno;
/*
* Some fileio results do not match up with what the semihosting
@@ -1631,6 +1697,17 @@ static int semihosting_common_fileio_end(struct target *target, int result,
break;
}
+ bool fileio_failed = false;
+ if (semihosting->op == SEMIHOSTING_SYS_ISTTY)
+ fileio_failed = (semihosting->result == 0);
+ else if (semihosting->op == SEMIHOSTING_SYS_RENAME)
+ fileio_failed = (semihosting->result != 0);
+ else
+ fileio_failed = (semihosting->result == -1);
+
+ if (fileio_failed)
+ semihosting->sys_errno = fileio_errno;
+
return semihosting->post_result(target);
}