aboutsummaryrefslogtreecommitdiff
path: root/semihosting/syscalls.c
diff options
context:
space:
mode:
authorRichard Henderson <richard.henderson@linaro.org>2022-04-28 12:04:44 -0700
committerRichard Henderson <richard.henderson@linaro.org>2022-06-28 04:35:52 +0530
commit9a89470449a5171eb1bd06f681361e0888d15cf7 (patch)
treeb7b7537fe55caf844a34969fc229ded15d46998e /semihosting/syscalls.c
parent40f1219a8b2f95808ed5a18798dbce1b57fef211 (diff)
semihosting: Split out semihost_sys_lseek
Split out the non-ARM specific portions of SYS_SEEK to a reusable function. This handles all GuestFD. Isolate the curious ARM-specific return value processing to a new callback, common_semi_seek_cb. Expand the internal type of the offset to int64_t, and provide the whence argument, which will be required by m68k and nios2 semihosting. Note that gdb_do_syscall %x reads target_ulong, not int. Reviewed-by: Luc Michel <lmichel@kalray.eu> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Diffstat (limited to 'semihosting/syscalls.c')
-rw-r--r--semihosting/syscalls.c81
1 files changed, 81 insertions, 0 deletions
diff --git a/semihosting/syscalls.c b/semihosting/syscalls.c
index eefbae74f1..9e3eb464b5 100644
--- a/semihosting/syscalls.c
+++ b/semihosting/syscalls.c
@@ -114,6 +114,13 @@ static void gdb_write(CPUState *cs, gdb_syscall_complete_cb complete,
(target_ulong)gf->hostfd, buf, len);
}
+static void gdb_lseek(CPUState *cs, gdb_syscall_complete_cb complete,
+ GuestFD *gf, int64_t off, int gdb_whence)
+{
+ gdb_do_syscall(complete, "lseek,%x,%lx,%x",
+ (target_ulong)gf->hostfd, off, (target_ulong)gdb_whence);
+}
+
/*
* Host semihosting syscall implementations.
*/
@@ -216,6 +223,29 @@ static void host_write(CPUState *cs, gdb_syscall_complete_cb complete,
unlock_user(ptr, buf, 0);
}
+static void host_lseek(CPUState *cs, gdb_syscall_complete_cb complete,
+ GuestFD *gf, int64_t off, int whence)
+{
+ /* So far, all hosts use the same values. */
+ QEMU_BUILD_BUG_ON(GDB_SEEK_SET != SEEK_SET);
+ QEMU_BUILD_BUG_ON(GDB_SEEK_CUR != SEEK_CUR);
+ QEMU_BUILD_BUG_ON(GDB_SEEK_END != SEEK_END);
+
+ off_t ret = off;
+ int err = 0;
+
+ if (ret == off) {
+ ret = lseek(gf->hostfd, ret, whence);
+ if (ret == -1) {
+ err = errno;
+ }
+ } else {
+ ret = -1;
+ err = EINVAL;
+ }
+ complete(cs, ret, err);
+}
+
/*
* Static file semihosting syscall implementations.
*/
@@ -241,6 +271,33 @@ static void staticfile_read(CPUState *cs, gdb_syscall_complete_cb complete,
unlock_user(ptr, buf, len);
}
+static void staticfile_lseek(CPUState *cs, gdb_syscall_complete_cb complete,
+ GuestFD *gf, int64_t off, int gdb_whence)
+{
+ int64_t ret;
+
+ switch (gdb_whence) {
+ case GDB_SEEK_SET:
+ ret = off;
+ break;
+ case GDB_SEEK_CUR:
+ ret = gf->staticfile.off + off;
+ break;
+ case GDB_SEEK_END:
+ ret = gf->staticfile.len + off;
+ break;
+ default:
+ ret = -1;
+ break;
+ }
+ if (ret >= 0 && ret <= gf->staticfile.len) {
+ gf->staticfile.off = ret;
+ complete(cs, ret, 0);
+ } else {
+ complete(cs, -1, EINVAL);
+ }
+}
+
/*
* Syscall entry points.
*/
@@ -356,3 +413,27 @@ void semihost_sys_write(CPUState *cs, gdb_syscall_complete_cb complete,
complete(cs, -1, EBADF);
}
}
+
+void semihost_sys_lseek(CPUState *cs, gdb_syscall_complete_cb complete,
+ int fd, int64_t off, int gdb_whence)
+{
+ GuestFD *gf = get_guestfd(fd);
+
+ if (!gf) {
+ complete(cs, -1, EBADF);
+ return;
+ }
+ switch (gf->type) {
+ case GuestFDGDB:
+ gdb_lseek(cs, complete, gf, off, gdb_whence);
+ return;
+ case GuestFDHost:
+ host_lseek(cs, complete, gf, off, gdb_whence);
+ break;
+ case GuestFDStatic:
+ staticfile_lseek(cs, complete, gf, off, gdb_whence);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+}