target/mips: Use semihosting/syscalls.h
This separates guest file descriptors from host file descriptors, and utilizes shared infrastructure for integration with gdbstub. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org> Message-Id: <20220628111701.677216-4-richard.henderson@linaro.org> Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
This commit is contained in:
parent
3d748e41c7
commit
18639a28bb
@ -20,9 +20,11 @@
|
|||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include "qemu/log.h"
|
#include "qemu/log.h"
|
||||||
|
#include "exec/gdbstub.h"
|
||||||
#include "semihosting/softmmu-uaccess.h"
|
#include "semihosting/softmmu-uaccess.h"
|
||||||
#include "semihosting/semihost.h"
|
#include "semihosting/semihost.h"
|
||||||
#include "semihosting/console.h"
|
#include "semihosting/console.h"
|
||||||
|
#include "semihosting/syscalls.h"
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
|
||||||
typedef enum UHIOp {
|
typedef enum UHIOp {
|
||||||
@ -121,101 +123,79 @@ static void report_fault(CPUMIPSState *env)
|
|||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
static int errno_mips(int host_errno)
|
static void uhi_cb(CPUState *cs, uint64_t ret, int err)
|
||||||
{
|
{
|
||||||
/* Errno values taken from asm-mips/errno.h */
|
CPUMIPSState *env = cs->env_ptr;
|
||||||
switch (host_errno) {
|
|
||||||
case 0: return 0;
|
|
||||||
case ENAMETOOLONG: return 78;
|
|
||||||
#ifdef EOVERFLOW
|
|
||||||
case EOVERFLOW: return 79;
|
|
||||||
#endif
|
|
||||||
#ifdef ELOOP
|
|
||||||
case ELOOP: return 90;
|
|
||||||
#endif
|
|
||||||
default: return EINVAL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int copy_stat_to_target(CPUMIPSState *env, const struct stat *src,
|
#define E(N) case E##N: err = UHI_E##N; break
|
||||||
target_ulong vaddr)
|
|
||||||
{
|
switch (err) {
|
||||||
hwaddr len = sizeof(struct UHIStat);
|
case 0:
|
||||||
UHIStat *dst = lock_user(VERIFY_WRITE, vaddr, len, 0);
|
break;
|
||||||
if (!dst) {
|
E(PERM);
|
||||||
|
E(NOENT);
|
||||||
|
E(INTR);
|
||||||
|
E(BADF);
|
||||||
|
E(BUSY);
|
||||||
|
E(EXIST);
|
||||||
|
E(NOTDIR);
|
||||||
|
E(ISDIR);
|
||||||
|
E(INVAL);
|
||||||
|
E(NFILE);
|
||||||
|
E(MFILE);
|
||||||
|
E(FBIG);
|
||||||
|
E(NOSPC);
|
||||||
|
E(SPIPE);
|
||||||
|
E(ROFS);
|
||||||
|
E(NAMETOOLONG);
|
||||||
|
default:
|
||||||
|
err = UHI_EINVAL;
|
||||||
|
break;
|
||||||
|
case EFAULT:
|
||||||
report_fault(env);
|
report_fault(env);
|
||||||
}
|
}
|
||||||
|
|
||||||
dst->uhi_st_dev = tswap16(src->st_dev);
|
#undef E
|
||||||
dst->uhi_st_ino = tswap16(src->st_ino);
|
|
||||||
dst->uhi_st_mode = tswap32(src->st_mode);
|
env->active_tc.gpr[2] = ret;
|
||||||
dst->uhi_st_nlink = tswap16(src->st_nlink);
|
env->active_tc.gpr[3] = err;
|
||||||
dst->uhi_st_uid = tswap16(src->st_uid);
|
|
||||||
dst->uhi_st_gid = tswap16(src->st_gid);
|
|
||||||
dst->uhi_st_rdev = tswap16(src->st_rdev);
|
|
||||||
dst->uhi_st_size = tswap64(src->st_size);
|
|
||||||
dst->uhi_st_atime = tswap64(src->st_atime);
|
|
||||||
dst->uhi_st_mtime = tswap64(src->st_mtime);
|
|
||||||
dst->uhi_st_ctime = tswap64(src->st_ctime);
|
|
||||||
#ifdef _WIN32
|
|
||||||
dst->uhi_st_blksize = 0;
|
|
||||||
dst->uhi_st_blocks = 0;
|
|
||||||
#else
|
|
||||||
dst->uhi_st_blksize = tswap64(src->st_blksize);
|
|
||||||
dst->uhi_st_blocks = tswap64(src->st_blocks);
|
|
||||||
#endif
|
|
||||||
unlock_user(dst, vaddr, len);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int get_open_flags(target_ulong target_flags)
|
static void uhi_fstat_cb(CPUState *cs, uint64_t ret, int err)
|
||||||
{
|
{
|
||||||
int open_flags = 0;
|
QEMU_BUILD_BUG_ON(sizeof(UHIStat) < sizeof(struct gdb_stat));
|
||||||
|
|
||||||
if (target_flags & UHIOpen_RDWR) {
|
if (!err) {
|
||||||
open_flags |= O_RDWR;
|
CPUMIPSState *env = cs->env_ptr;
|
||||||
} else if (target_flags & UHIOpen_WRONLY) {
|
target_ulong addr = env->active_tc.gpr[5];
|
||||||
open_flags |= O_WRONLY;
|
UHIStat *dst = lock_user(VERIFY_WRITE, addr, sizeof(UHIStat), 1);
|
||||||
} else {
|
struct gdb_stat s;
|
||||||
open_flags |= O_RDONLY;
|
|
||||||
|
if (!dst) {
|
||||||
|
report_fault(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(&s, dst, sizeof(struct gdb_stat));
|
||||||
|
memset(dst, 0, sizeof(UHIStat));
|
||||||
|
|
||||||
|
dst->uhi_st_dev = tswap16(be32_to_cpu(s.gdb_st_dev));
|
||||||
|
dst->uhi_st_ino = tswap16(be32_to_cpu(s.gdb_st_ino));
|
||||||
|
dst->uhi_st_mode = tswap32(be32_to_cpu(s.gdb_st_mode));
|
||||||
|
dst->uhi_st_nlink = tswap16(be32_to_cpu(s.gdb_st_nlink));
|
||||||
|
dst->uhi_st_uid = tswap16(be32_to_cpu(s.gdb_st_uid));
|
||||||
|
dst->uhi_st_gid = tswap16(be32_to_cpu(s.gdb_st_gid));
|
||||||
|
dst->uhi_st_rdev = tswap16(be32_to_cpu(s.gdb_st_rdev));
|
||||||
|
dst->uhi_st_size = tswap64(be64_to_cpu(s.gdb_st_size));
|
||||||
|
dst->uhi_st_atime = tswap64(be32_to_cpu(s.gdb_st_atime));
|
||||||
|
dst->uhi_st_mtime = tswap64(be32_to_cpu(s.gdb_st_mtime));
|
||||||
|
dst->uhi_st_ctime = tswap64(be32_to_cpu(s.gdb_st_ctime));
|
||||||
|
dst->uhi_st_blksize = tswap64(be64_to_cpu(s.gdb_st_blksize));
|
||||||
|
dst->uhi_st_blocks = tswap64(be64_to_cpu(s.gdb_st_blocks));
|
||||||
|
|
||||||
|
unlock_user(dst, addr, sizeof(UHIStat));
|
||||||
}
|
}
|
||||||
|
|
||||||
open_flags |= (target_flags & UHIOpen_APPEND) ? O_APPEND : 0;
|
uhi_cb(cs, ret, err);
|
||||||
open_flags |= (target_flags & UHIOpen_CREAT) ? O_CREAT : 0;
|
|
||||||
open_flags |= (target_flags & UHIOpen_TRUNC) ? O_TRUNC : 0;
|
|
||||||
open_flags |= (target_flags & UHIOpen_EXCL) ? O_EXCL : 0;
|
|
||||||
|
|
||||||
return open_flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int write_to_file(CPUMIPSState *env, target_ulong fd,
|
|
||||||
target_ulong vaddr, target_ulong len)
|
|
||||||
{
|
|
||||||
int num_of_bytes;
|
|
||||||
void *dst = lock_user(VERIFY_READ, vaddr, len, 1);
|
|
||||||
if (!dst) {
|
|
||||||
report_fault(env);
|
|
||||||
}
|
|
||||||
|
|
||||||
num_of_bytes = write(fd, dst, len);
|
|
||||||
|
|
||||||
unlock_user(dst, vaddr, 0);
|
|
||||||
return num_of_bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int read_from_file(CPUMIPSState *env, target_ulong fd,
|
|
||||||
target_ulong vaddr, target_ulong len)
|
|
||||||
{
|
|
||||||
int num_of_bytes;
|
|
||||||
void *dst = lock_user(VERIFY_WRITE, vaddr, len, 0);
|
|
||||||
if (!dst) {
|
|
||||||
report_fault(env);
|
|
||||||
}
|
|
||||||
|
|
||||||
num_of_bytes = read(fd, dst, len);
|
|
||||||
|
|
||||||
unlock_user(dst, vaddr, len);
|
|
||||||
return num_of_bytes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int copy_argn_to_target(CPUMIPSState *env, int arg_num,
|
static int copy_argn_to_target(CPUMIPSState *env, int arg_num,
|
||||||
@ -260,68 +240,59 @@ static int copy_argn_to_target(CPUMIPSState *env, int arg_num,
|
|||||||
|
|
||||||
void mips_semihosting(CPUMIPSState *env)
|
void mips_semihosting(CPUMIPSState *env)
|
||||||
{
|
{
|
||||||
|
CPUState *cs = env_cpu(env);
|
||||||
target_ulong *gpr = env->active_tc.gpr;
|
target_ulong *gpr = env->active_tc.gpr;
|
||||||
const UHIOp op = gpr[25];
|
const UHIOp op = gpr[25];
|
||||||
char *p, *p2;
|
char *p, *p2;
|
||||||
|
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case UHI_exit:
|
case UHI_exit:
|
||||||
qemu_log("UHI(%d): exit(%d)\n", op, (int)gpr[4]);
|
gdb_exit(gpr[4]);
|
||||||
exit(gpr[4]);
|
exit(gpr[4]);
|
||||||
|
|
||||||
case UHI_open:
|
case UHI_open:
|
||||||
GET_TARGET_STRING(p, gpr[4]);
|
{
|
||||||
if (!strcmp("/dev/stdin", p)) {
|
int ret = -1;
|
||||||
gpr[2] = 0;
|
|
||||||
} else if (!strcmp("/dev/stdout", p)) {
|
GET_TARGET_STRING(p, gpr[4]);
|
||||||
gpr[2] = 1;
|
if (!strcmp("/dev/stdin", p)) {
|
||||||
} else if (!strcmp("/dev/stderr", p)) {
|
ret = 0;
|
||||||
gpr[2] = 2;
|
} else if (!strcmp("/dev/stdout", p)) {
|
||||||
} else {
|
ret = 1;
|
||||||
gpr[2] = open(p, get_open_flags(gpr[5]), gpr[6]);
|
} else if (!strcmp("/dev/stderr", p)) {
|
||||||
gpr[3] = errno_mips(errno);
|
ret = 2;
|
||||||
|
}
|
||||||
|
FREE_TARGET_STRING(p, gpr[4]);
|
||||||
|
|
||||||
|
/* FIXME: reusing a guest fd doesn't seem correct. */
|
||||||
|
if (ret >= 0) {
|
||||||
|
gpr[2] = ret;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
semihost_sys_open(cs, uhi_cb, gpr[4], 0, gpr[5], gpr[6]);
|
||||||
}
|
}
|
||||||
FREE_TARGET_STRING(p, gpr[4]);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case UHI_close:
|
case UHI_close:
|
||||||
if (gpr[4] < 3) {
|
semihost_sys_close(cs, uhi_cb, gpr[4]);
|
||||||
/* ignore closing stdin/stdout/stderr */
|
|
||||||
gpr[2] = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
gpr[2] = close(gpr[4]);
|
|
||||||
gpr[3] = errno_mips(errno);
|
|
||||||
break;
|
break;
|
||||||
case UHI_read:
|
case UHI_read:
|
||||||
gpr[2] = read_from_file(env, gpr[4], gpr[5], gpr[6]);
|
semihost_sys_read(cs, uhi_cb, gpr[4], gpr[5], gpr[6]);
|
||||||
gpr[3] = errno_mips(errno);
|
|
||||||
break;
|
break;
|
||||||
case UHI_write:
|
case UHI_write:
|
||||||
gpr[2] = write_to_file(env, gpr[4], gpr[5], gpr[6]);
|
semihost_sys_write(cs, uhi_cb, gpr[4], gpr[5], gpr[6]);
|
||||||
gpr[3] = errno_mips(errno);
|
|
||||||
break;
|
break;
|
||||||
case UHI_lseek:
|
case UHI_lseek:
|
||||||
gpr[2] = lseek(gpr[4], gpr[5], gpr[6]);
|
semihost_sys_lseek(cs, uhi_cb, gpr[4], gpr[5], gpr[6]);
|
||||||
gpr[3] = errno_mips(errno);
|
|
||||||
break;
|
break;
|
||||||
case UHI_unlink:
|
case UHI_unlink:
|
||||||
GET_TARGET_STRING(p, gpr[4]);
|
semihost_sys_remove(cs, uhi_cb, gpr[4], 0);
|
||||||
gpr[2] = remove(p);
|
|
||||||
gpr[3] = errno_mips(errno);
|
|
||||||
FREE_TARGET_STRING(p, gpr[4]);
|
|
||||||
break;
|
break;
|
||||||
case UHI_fstat:
|
case UHI_fstat:
|
||||||
{
|
semihost_sys_fstat(cs, uhi_fstat_cb, gpr[4], gpr[5]);
|
||||||
struct stat sbuf;
|
|
||||||
memset(&sbuf, 0, sizeof(sbuf));
|
|
||||||
gpr[2] = fstat(gpr[4], &sbuf);
|
|
||||||
gpr[3] = errno_mips(errno);
|
|
||||||
if (gpr[2]) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
gpr[2] = copy_stat_to_target(env, &sbuf, gpr[5]);
|
|
||||||
gpr[3] = errno_mips(errno);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case UHI_argc:
|
case UHI_argc:
|
||||||
gpr[2] = semihosting_get_argc();
|
gpr[2] = semihosting_get_argc();
|
||||||
break;
|
break;
|
||||||
|
Loading…
Reference in New Issue
Block a user