mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge tag 'pull-semi-20220628' of https://gitlab.com/rth7680/qemu into staging
Semihosting syscall reorg: * Split out semihosting/syscalls.c with common implementations. * Reorg arm-compat-semi.c to use syscalls.c. * Minor prep cleanups to m68k, mips, nios2. # -----BEGIN PGP SIGNATURE----- # # iQFRBAABCgA7FiEEekgeeIaLTbaoWgXAZN846K9+IV8FAmK6iSodHHJpY2hhcmQu # aGVuZGVyc29uQGxpbmFyby5vcmcACgkQZN846K9+IV8SEwgAmmowW2oeFA9uCrwz # gUJo17AJ+RmRF/zXHyu5CPswylvfwH0zJXAm5BV7P/pVdyaL36b8YcgSEf+EWLsf # rLFHxCshTYEnZSk6yFtWk5bn5azfevHm9/ObPeS9XGL4seQqGy7C/FReoTQ7/zI0 # W3zUDd3bWah3fXw8XYgSzh/RCrC5E2gFFc1G1g+6SIVZ7pbgkre2rRk5WMmylCLd # jf9pmyswrheaKumCoBxU/S4XDgxVpaf3khiIqdbo8A20MDGnK/SZUWsBwJLK3QB8 # SKKv8o1ovbnl/HykABaszCIkO/LIu6SX3LoK7pF2CujkgSuwEN3WW0DOml6+b3fU # J7YeZg== # =sTbM # -----END PGP SIGNATURE----- # gpg: Signature made Tue 28 Jun 2022 10:22:58 AM +0530 # gpg: using RSA key 7A481E78868B4DB6A85A05C064DF38E8AF7E215F # gpg: issuer "richard.henderson@linaro.org" # gpg: Good signature from "Richard Henderson <richard.henderson@linaro.org>" [ultimate] * tag 'pull-semi-20220628' of https://gitlab.com/rth7680/qemu: (60 commits) target/nios2: Move nios2-semi.c to nios2_softmmu_ss target/nios2: Eliminate nios2_semi_is_lseek target/mips: Drop pread and pwrite syscalls from semihosting target/mips: Add UHI errno values target/mips: Use an exception for semihosting target/m68k: Make semihosting system only target/m68k: Eliminate m68k_semi_is_fseek semihosting: Create semihost_sys_poll_one semihosting: Remove qemu_semihosting_console_outs semihosting: Use console_out_gf for SYS_WRITE0 semihosting: Remove qemu_semihosting_console_outc semihosting: Use console_out_gf for SYS_WRITEC semihosting: Use console_in_gf for SYS_READC semihosting: Create qemu_semihosting_guestfd_init semihosting: Add GuestFDConsole semihosting: Create qemu_semihosting_console_write semihosting: Cleanup chardev init semihosting: Expand qemu_semihosting_console_inc to read semihosting: Pass CPUState to qemu_semihosting_console_inc semihosting: Fix docs comment for qemu_semihosting_console_inc ... Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
@@ -21,6 +21,13 @@ void tlb_set_dirty(CPUState *cpu, target_ulong vaddr)
|
||||
{
|
||||
}
|
||||
|
||||
int probe_access_flags(CPUArchState *env, target_ulong addr,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
bool nonfault, void **phost, uintptr_t retaddr)
|
||||
{
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
void *probe_access(CPUArchState *env, target_ulong addr, int size,
|
||||
MMUAccessType access_type, int mmu_idx, uintptr_t retaddr)
|
||||
{
|
||||
|
||||
@@ -2,4 +2,5 @@ TARGET_ARCH=aarch64
|
||||
TARGET_BASE_ARCH=arm
|
||||
TARGET_XML_FILES= gdb-xml/aarch64-core.xml gdb-xml/aarch64-fpu.xml
|
||||
TARGET_HAS_BFLT=y
|
||||
CONFIG_SEMIHOSTING=y
|
||||
CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
|
||||
|
||||
@@ -3,4 +3,5 @@ TARGET_BASE_ARCH=arm
|
||||
TARGET_BIG_ENDIAN=y
|
||||
TARGET_XML_FILES= gdb-xml/aarch64-core.xml gdb-xml/aarch64-fpu.xml
|
||||
TARGET_HAS_BFLT=y
|
||||
CONFIG_SEMIHOSTING=y
|
||||
CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
|
||||
|
||||
@@ -3,4 +3,5 @@ TARGET_SYSTBL_ABI=common,oabi
|
||||
TARGET_SYSTBL=syscall.tbl
|
||||
TARGET_XML_FILES= gdb-xml/arm-core.xml gdb-xml/arm-vfp.xml gdb-xml/arm-vfp3.xml gdb-xml/arm-vfp-sysregs.xml gdb-xml/arm-neon.xml gdb-xml/arm-m-profile.xml gdb-xml/arm-m-profile-mve.xml
|
||||
TARGET_HAS_BFLT=y
|
||||
CONFIG_SEMIHOSTING=y
|
||||
CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
|
||||
|
||||
@@ -4,4 +4,5 @@ TARGET_SYSTBL=syscall.tbl
|
||||
TARGET_BIG_ENDIAN=y
|
||||
TARGET_XML_FILES= gdb-xml/arm-core.xml gdb-xml/arm-vfp.xml gdb-xml/arm-vfp3.xml gdb-xml/arm-vfp-sysregs.xml gdb-xml/arm-neon.xml gdb-xml/arm-m-profile.xml gdb-xml/arm-m-profile-mve.xml
|
||||
TARGET_HAS_BFLT=y
|
||||
CONFIG_SEMIHOSTING=y
|
||||
CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
|
||||
|
||||
@@ -2,4 +2,5 @@ TARGET_ARCH=riscv32
|
||||
TARGET_BASE_ARCH=riscv
|
||||
TARGET_ABI_DIR=riscv
|
||||
TARGET_XML_FILES= gdb-xml/riscv-32bit-cpu.xml gdb-xml/riscv-32bit-fpu.xml gdb-xml/riscv-64bit-fpu.xml gdb-xml/riscv-32bit-virtual.xml
|
||||
CONFIG_SEMIHOSTING=y
|
||||
CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
|
||||
|
||||
@@ -2,4 +2,5 @@ TARGET_ARCH=riscv64
|
||||
TARGET_BASE_ARCH=riscv
|
||||
TARGET_ABI_DIR=riscv
|
||||
TARGET_XML_FILES= gdb-xml/riscv-64bit-cpu.xml gdb-xml/riscv-32bit-fpu.xml gdb-xml/riscv-64bit-fpu.xml gdb-xml/riscv-64bit-virtual.xml
|
||||
CONFIG_SEMIHOSTING=y
|
||||
CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
|
||||
|
||||
@@ -1878,14 +1878,46 @@ static void handle_read_all_regs(GArray *params, void *user_ctx)
|
||||
static void handle_file_io(GArray *params, void *user_ctx)
|
||||
{
|
||||
if (params->len >= 1 && gdbserver_state.current_syscall_cb) {
|
||||
target_ulong ret, err;
|
||||
uint64_t ret;
|
||||
int err;
|
||||
|
||||
ret = (target_ulong)get_param(params, 0)->val_ull;
|
||||
ret = get_param(params, 0)->val_ull;
|
||||
if (params->len >= 2) {
|
||||
err = (target_ulong)get_param(params, 1)->val_ull;
|
||||
err = get_param(params, 1)->val_ull;
|
||||
} else {
|
||||
err = 0;
|
||||
}
|
||||
|
||||
/* Convert GDB error numbers back to host error numbers. */
|
||||
#define E(X) case GDB_E##X: err = E##X; break
|
||||
switch (err) {
|
||||
case 0:
|
||||
break;
|
||||
E(PERM);
|
||||
E(NOENT);
|
||||
E(INTR);
|
||||
E(BADF);
|
||||
E(ACCES);
|
||||
E(FAULT);
|
||||
E(BUSY);
|
||||
E(EXIST);
|
||||
E(NODEV);
|
||||
E(NOTDIR);
|
||||
E(ISDIR);
|
||||
E(INVAL);
|
||||
E(NFILE);
|
||||
E(MFILE);
|
||||
E(FBIG);
|
||||
E(NOSPC);
|
||||
E(SPIPE);
|
||||
E(ROFS);
|
||||
E(NAMETOOLONG);
|
||||
default:
|
||||
err = EINVAL;
|
||||
break;
|
||||
}
|
||||
#undef E
|
||||
|
||||
gdbserver_state.current_syscall_cb(gdbserver_state.c_cpu, ret, err);
|
||||
gdbserver_state.current_syscall_cb = NULL;
|
||||
}
|
||||
|
||||
+62
-2
@@ -10,11 +10,71 @@
|
||||
#define GDB_WATCHPOINT_READ 3
|
||||
#define GDB_WATCHPOINT_ACCESS 4
|
||||
|
||||
/* For gdb file i/o remote protocol open flags. */
|
||||
#define GDB_O_RDONLY 0
|
||||
#define GDB_O_WRONLY 1
|
||||
#define GDB_O_RDWR 2
|
||||
#define GDB_O_APPEND 8
|
||||
#define GDB_O_CREAT 0x200
|
||||
#define GDB_O_TRUNC 0x400
|
||||
#define GDB_O_EXCL 0x800
|
||||
|
||||
/* For gdb file i/o remote protocol errno values */
|
||||
#define GDB_EPERM 1
|
||||
#define GDB_ENOENT 2
|
||||
#define GDB_EINTR 4
|
||||
#define GDB_EBADF 9
|
||||
#define GDB_EACCES 13
|
||||
#define GDB_EFAULT 14
|
||||
#define GDB_EBUSY 16
|
||||
#define GDB_EEXIST 17
|
||||
#define GDB_ENODEV 19
|
||||
#define GDB_ENOTDIR 20
|
||||
#define GDB_EISDIR 21
|
||||
#define GDB_EINVAL 22
|
||||
#define GDB_ENFILE 23
|
||||
#define GDB_EMFILE 24
|
||||
#define GDB_EFBIG 27
|
||||
#define GDB_ENOSPC 28
|
||||
#define GDB_ESPIPE 29
|
||||
#define GDB_EROFS 30
|
||||
#define GDB_ENAMETOOLONG 91
|
||||
#define GDB_EUNKNOWN 9999
|
||||
|
||||
/* For gdb file i/o remote protocol lseek whence. */
|
||||
#define GDB_SEEK_SET 0
|
||||
#define GDB_SEEK_CUR 1
|
||||
#define GDB_SEEK_END 2
|
||||
|
||||
/* For gdb file i/o stat/fstat. */
|
||||
typedef uint32_t gdb_mode_t;
|
||||
typedef uint32_t gdb_time_t;
|
||||
|
||||
struct gdb_stat {
|
||||
uint32_t gdb_st_dev; /* device */
|
||||
uint32_t gdb_st_ino; /* inode */
|
||||
gdb_mode_t gdb_st_mode; /* protection */
|
||||
uint32_t gdb_st_nlink; /* number of hard links */
|
||||
uint32_t gdb_st_uid; /* user ID of owner */
|
||||
uint32_t gdb_st_gid; /* group ID of owner */
|
||||
uint32_t gdb_st_rdev; /* device type (if inode device) */
|
||||
uint64_t gdb_st_size; /* total size, in bytes */
|
||||
uint64_t gdb_st_blksize; /* blocksize for filesystem I/O */
|
||||
uint64_t gdb_st_blocks; /* number of blocks allocated */
|
||||
gdb_time_t gdb_st_atime; /* time of last access */
|
||||
gdb_time_t gdb_st_mtime; /* time of last modification */
|
||||
gdb_time_t gdb_st_ctime; /* time of last change */
|
||||
} QEMU_PACKED;
|
||||
|
||||
struct gdb_timeval {
|
||||
gdb_time_t tv_sec; /* second */
|
||||
uint64_t tv_usec; /* microsecond */
|
||||
} QEMU_PACKED;
|
||||
|
||||
#ifdef NEED_CPU_H
|
||||
#include "cpu.h"
|
||||
|
||||
typedef void (*gdb_syscall_complete_cb)(CPUState *cpu,
|
||||
target_ulong ret, target_ulong err);
|
||||
typedef void (*gdb_syscall_complete_cb)(CPUState *cpu, uint64_t ret, int err);
|
||||
|
||||
/**
|
||||
* gdb_do_syscall:
|
||||
|
||||
@@ -1,101 +0,0 @@
|
||||
/*
|
||||
* Helper routines to provide target memory access for semihosting
|
||||
* syscalls in system emulation mode.
|
||||
*
|
||||
* Copyright (c) 2007 CodeSourcery.
|
||||
*
|
||||
* This code is licensed under the GPL
|
||||
*/
|
||||
|
||||
#ifndef SOFTMMU_SEMI_H
|
||||
#define SOFTMMU_SEMI_H
|
||||
|
||||
#include "cpu.h"
|
||||
|
||||
static inline uint64_t softmmu_tget64(CPUArchState *env, target_ulong addr)
|
||||
{
|
||||
uint64_t val;
|
||||
|
||||
cpu_memory_rw_debug(env_cpu(env), addr, (uint8_t *)&val, 8, 0);
|
||||
return tswap64(val);
|
||||
}
|
||||
|
||||
static inline uint32_t softmmu_tget32(CPUArchState *env, target_ulong addr)
|
||||
{
|
||||
uint32_t val;
|
||||
|
||||
cpu_memory_rw_debug(env_cpu(env), addr, (uint8_t *)&val, 4, 0);
|
||||
return tswap32(val);
|
||||
}
|
||||
|
||||
static inline uint32_t softmmu_tget8(CPUArchState *env, target_ulong addr)
|
||||
{
|
||||
uint8_t val;
|
||||
|
||||
cpu_memory_rw_debug(env_cpu(env), addr, &val, 1, 0);
|
||||
return val;
|
||||
}
|
||||
|
||||
#define get_user_u64(arg, p) ({ arg = softmmu_tget64(env, p); 0; })
|
||||
#define get_user_u32(arg, p) ({ arg = softmmu_tget32(env, p) ; 0; })
|
||||
#define get_user_u8(arg, p) ({ arg = softmmu_tget8(env, p) ; 0; })
|
||||
#define get_user_ual(arg, p) get_user_u32(arg, p)
|
||||
|
||||
static inline void softmmu_tput64(CPUArchState *env,
|
||||
target_ulong addr, uint64_t val)
|
||||
{
|
||||
val = tswap64(val);
|
||||
cpu_memory_rw_debug(env_cpu(env), addr, (uint8_t *)&val, 8, 1);
|
||||
}
|
||||
|
||||
static inline void softmmu_tput32(CPUArchState *env,
|
||||
target_ulong addr, uint32_t val)
|
||||
{
|
||||
val = tswap32(val);
|
||||
cpu_memory_rw_debug(env_cpu(env), addr, (uint8_t *)&val, 4, 1);
|
||||
}
|
||||
#define put_user_u64(arg, p) ({ softmmu_tput64(env, p, arg) ; 0; })
|
||||
#define put_user_u32(arg, p) ({ softmmu_tput32(env, p, arg) ; 0; })
|
||||
#define put_user_ual(arg, p) put_user_u32(arg, p)
|
||||
|
||||
static void *softmmu_lock_user(CPUArchState *env,
|
||||
target_ulong addr, target_ulong len, int copy)
|
||||
{
|
||||
uint8_t *p;
|
||||
/* TODO: Make this something that isn't fixed size. */
|
||||
p = malloc(len);
|
||||
if (p && copy) {
|
||||
cpu_memory_rw_debug(env_cpu(env), addr, p, len, 0);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
#define lock_user(type, p, len, copy) softmmu_lock_user(env, p, len, copy)
|
||||
static char *softmmu_lock_user_string(CPUArchState *env, target_ulong addr)
|
||||
{
|
||||
char *p;
|
||||
char *s;
|
||||
uint8_t c;
|
||||
/* TODO: Make this something that isn't fixed size. */
|
||||
s = p = malloc(1024);
|
||||
if (!s) {
|
||||
return NULL;
|
||||
}
|
||||
do {
|
||||
cpu_memory_rw_debug(env_cpu(env), addr, &c, 1, 0);
|
||||
addr++;
|
||||
*(p++) = c;
|
||||
} while (c);
|
||||
return s;
|
||||
}
|
||||
#define lock_user_string(p) softmmu_lock_user_string(env, p)
|
||||
static void softmmu_unlock_user(CPUArchState *env, void *p, target_ulong addr,
|
||||
target_ulong len)
|
||||
{
|
||||
if (len) {
|
||||
cpu_memory_rw_debug(env_cpu(env), addr, p, len, 1);
|
||||
}
|
||||
free(p);
|
||||
}
|
||||
#define unlock_user(s, args, len) softmmu_unlock_user(env, s, args, len)
|
||||
|
||||
#endif
|
||||
@@ -34,6 +34,6 @@
|
||||
#ifndef COMMON_SEMI_H
|
||||
#define COMMON_SEMI_H
|
||||
|
||||
target_ulong do_common_semihosting(CPUState *cs);
|
||||
void do_common_semihosting(CPUState *cs);
|
||||
|
||||
#endif /* COMMON_SEMI_H */
|
||||
@@ -12,46 +12,33 @@
|
||||
#include "cpu.h"
|
||||
|
||||
/**
|
||||
* qemu_semihosting_console_outs:
|
||||
* @env: CPUArchState
|
||||
* @s: host address of null terminated guest string
|
||||
* qemu_semihosting_console_read:
|
||||
* @cs: CPUState
|
||||
* @buf: host buffer
|
||||
* @len: buffer size
|
||||
*
|
||||
* Send a null terminated guest string to the debug console. This may
|
||||
* be the remote gdb session if a softmmu guest is currently being
|
||||
* debugged.
|
||||
* Receive at least one character from debug console. As this call may
|
||||
* block if no data is available we suspend the CPU and will re-execute the
|
||||
* instruction when data is there. Therefore two conditions must be met:
|
||||
*
|
||||
* Returns: number of bytes written.
|
||||
*/
|
||||
int qemu_semihosting_console_outs(CPUArchState *env, target_ulong s);
|
||||
|
||||
/**
|
||||
* qemu_semihosting_console_outc:
|
||||
* @env: CPUArchState
|
||||
* @s: host address of null terminated guest string
|
||||
*
|
||||
* Send single character from guest memory to the debug console. This
|
||||
* may be the remote gdb session if a softmmu guest is currently being
|
||||
* debugged.
|
||||
*
|
||||
* Returns: nothing
|
||||
*/
|
||||
void qemu_semihosting_console_outc(CPUArchState *env, target_ulong c);
|
||||
|
||||
/**
|
||||
* qemu_semihosting_console_inc:
|
||||
* @env: CPUArchState
|
||||
*
|
||||
* Receive single character from debug console. This may be the remote
|
||||
* gdb session if a softmmu guest is currently being debugged. As this
|
||||
* call may block if no data is available we suspend the CPU and will
|
||||
* re-execute the instruction when data is there. Therefore two
|
||||
* conditions must be met:
|
||||
* - CPUState is synchronized before calling this function
|
||||
* - pc is only updated once the character is successfully returned
|
||||
*
|
||||
* Returns: character read OR cpu_loop_exit!
|
||||
* Returns: number of characters read, OR cpu_loop_exit!
|
||||
*/
|
||||
target_ulong qemu_semihosting_console_inc(CPUArchState *env);
|
||||
int qemu_semihosting_console_read(CPUState *cs, void *buf, int len);
|
||||
|
||||
/**
|
||||
* qemu_semihosting_console_write:
|
||||
* @buf: host buffer
|
||||
* @len: buffer size
|
||||
*
|
||||
* Write len bytes from buf to the debug console.
|
||||
*
|
||||
* Returns: number of bytes written -- this should only ever be short
|
||||
* on some sort of i/o error.
|
||||
*/
|
||||
int qemu_semihosting_console_write(void *buf, int len);
|
||||
|
||||
/**
|
||||
* qemu_semihosting_log_out:
|
||||
@@ -66,4 +53,20 @@ target_ulong qemu_semihosting_console_inc(CPUArchState *env);
|
||||
*/
|
||||
int qemu_semihosting_log_out(const char *s, int len);
|
||||
|
||||
/*
|
||||
* qemu_semihosting_console_block_until_ready:
|
||||
* @cs: CPUState
|
||||
*
|
||||
* If no data is available we suspend the CPU and will re-execute the
|
||||
* instruction when data is available.
|
||||
*/
|
||||
void qemu_semihosting_console_block_until_ready(CPUState *cs);
|
||||
|
||||
/**
|
||||
* qemu_semihosting_console_ready:
|
||||
*
|
||||
* Return true if characters are available for read; does not block.
|
||||
*/
|
||||
bool qemu_semihosting_console_ready(void);
|
||||
|
||||
#endif /* SEMIHOST_CONSOLE_H */
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Hosted file support for semihosting syscalls.
|
||||
*
|
||||
* Copyright (c) 2005, 2007 CodeSourcery.
|
||||
* Copyright (c) 2019 Linaro
|
||||
* Copyright © 2020 by Keith Packard <keithp@keithp.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef SEMIHOSTING_GUESTFD_H
|
||||
#define SEMIHOSTING_GUESTFD_H
|
||||
|
||||
typedef enum GuestFDType {
|
||||
GuestFDUnused = 0,
|
||||
GuestFDHost,
|
||||
GuestFDGDB,
|
||||
GuestFDStatic,
|
||||
GuestFDConsole,
|
||||
} GuestFDType;
|
||||
|
||||
/*
|
||||
* Guest file descriptors are integer indexes into an array of
|
||||
* these structures (we will dynamically resize as necessary).
|
||||
*/
|
||||
typedef struct GuestFD {
|
||||
GuestFDType type;
|
||||
union {
|
||||
int hostfd;
|
||||
struct {
|
||||
const uint8_t *data;
|
||||
size_t len;
|
||||
size_t off;
|
||||
} staticfile;
|
||||
};
|
||||
} GuestFD;
|
||||
|
||||
/*
|
||||
* For ARM semihosting, we have a separate structure for routing
|
||||
* data for the console which is outside the guest fd address space.
|
||||
*/
|
||||
extern GuestFD console_in_gf;
|
||||
extern GuestFD console_out_gf;
|
||||
|
||||
/**
|
||||
* alloc_guestfd:
|
||||
*
|
||||
* Allocate an unused GuestFD index. The associated guestfd index
|
||||
* will still be GuestFDUnused until it is initialized.
|
||||
*/
|
||||
int alloc_guestfd(void);
|
||||
|
||||
/**
|
||||
* dealloc_guestfd:
|
||||
* @guestfd: GuestFD index
|
||||
*
|
||||
* Deallocate a GuestFD index. The associated GuestFD structure
|
||||
* will be recycled for a subsequent allocation.
|
||||
*/
|
||||
void dealloc_guestfd(int guestfd);
|
||||
|
||||
/**
|
||||
* get_guestfd:
|
||||
* @guestfd: GuestFD index
|
||||
*
|
||||
* Return the GuestFD structure associated with an initialized @guestfd,
|
||||
* or NULL if it has not been allocated, or hasn't been initialized.
|
||||
*/
|
||||
GuestFD *get_guestfd(int guestfd);
|
||||
|
||||
/**
|
||||
* associate_guestfd:
|
||||
* @guestfd: GuestFD index
|
||||
* @hostfd: host file descriptor
|
||||
*
|
||||
* Initialize the GuestFD for @guestfd to GuestFDHost using @hostfd.
|
||||
*/
|
||||
void associate_guestfd(int guestfd, int hostfd);
|
||||
|
||||
/**
|
||||
* staticfile_guestfd:
|
||||
* @guestfd: GuestFD index
|
||||
* @data: data to be read
|
||||
* @len: length of @data
|
||||
*
|
||||
* Initialize the GuestFD for @guestfd to GuestFDStatic.
|
||||
* The @len bytes at @data will be returned to the guest on reads.
|
||||
*/
|
||||
void staticfile_guestfd(int guestfd, const uint8_t *data, size_t len);
|
||||
|
||||
#endif /* SEMIHOSTING_GUESTFD_H */
|
||||
@@ -51,14 +51,6 @@ static inline const char *semihosting_get_cmdline(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline Chardev *semihosting_get_chardev(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
static inline void qemu_semihosting_console_init(void)
|
||||
{
|
||||
}
|
||||
#else /* !CONFIG_USER_ONLY */
|
||||
bool semihosting_enabled(void);
|
||||
SemihostingTarget semihosting_get_target(void);
|
||||
@@ -66,12 +58,12 @@ const char *semihosting_get_arg(int i);
|
||||
int semihosting_get_argc(void);
|
||||
const char *semihosting_get_cmdline(void);
|
||||
void semihosting_arg_fallback(const char *file, const char *cmd);
|
||||
Chardev *semihosting_get_chardev(void);
|
||||
/* for vl.c hooks */
|
||||
void qemu_semihosting_enable(void);
|
||||
int qemu_semihosting_config_options(const char *opt);
|
||||
void qemu_semihosting_connect_chardevs(void);
|
||||
void qemu_semihosting_console_init(void);
|
||||
void qemu_semihosting_chardev_init(void);
|
||||
void qemu_semihosting_console_init(Chardev *);
|
||||
#endif /* CONFIG_USER_ONLY */
|
||||
void qemu_semihosting_guestfd_init(void);
|
||||
|
||||
#endif /* SEMIHOST_H */
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Helper routines to provide target memory access for semihosting
|
||||
* syscalls in system emulation mode.
|
||||
*
|
||||
* Copyright (c) 2007 CodeSourcery.
|
||||
*
|
||||
* This code is licensed under the GPL
|
||||
*/
|
||||
|
||||
#ifndef SEMIHOSTING_SOFTMMU_UACCESS_H
|
||||
#define SEMIHOSTING_SOFTMMU_UACCESS_H
|
||||
|
||||
#include "cpu.h"
|
||||
|
||||
#define get_user_u64(val, addr) \
|
||||
({ uint64_t val_ = 0; \
|
||||
int ret_ = cpu_memory_rw_debug(env_cpu(env), (addr), \
|
||||
&val_, sizeof(val_), 0); \
|
||||
(val) = tswap64(val_); ret_; })
|
||||
|
||||
#define get_user_u32(val, addr) \
|
||||
({ uint32_t val_ = 0; \
|
||||
int ret_ = cpu_memory_rw_debug(env_cpu(env), (addr), \
|
||||
&val_, sizeof(val_), 0); \
|
||||
(val) = tswap32(val_); ret_; })
|
||||
|
||||
#define get_user_u8(val, addr) \
|
||||
({ uint8_t val_ = 0; \
|
||||
int ret_ = cpu_memory_rw_debug(env_cpu(env), (addr), \
|
||||
&val_, sizeof(val_), 0); \
|
||||
(val) = val_; ret_; })
|
||||
|
||||
#define get_user_ual(arg, p) get_user_u32(arg, p)
|
||||
|
||||
#define put_user_u64(val, addr) \
|
||||
({ uint64_t val_ = tswap64(val); \
|
||||
cpu_memory_rw_debug(env_cpu(env), (addr), &val_, sizeof(val_), 1); })
|
||||
|
||||
#define put_user_u32(val, addr) \
|
||||
({ uint32_t val_ = tswap32(val); \
|
||||
cpu_memory_rw_debug(env_cpu(env), (addr), &val_, sizeof(val_), 1); })
|
||||
|
||||
#define put_user_ual(arg, p) put_user_u32(arg, p)
|
||||
|
||||
void *softmmu_lock_user(CPUArchState *env, target_ulong addr,
|
||||
target_ulong len, bool copy);
|
||||
#define lock_user(type, p, len, copy) softmmu_lock_user(env, p, len, copy)
|
||||
|
||||
char *softmmu_lock_user_string(CPUArchState *env, target_ulong addr);
|
||||
#define lock_user_string(p) softmmu_lock_user_string(env, p)
|
||||
|
||||
void softmmu_unlock_user(CPUArchState *env, void *p,
|
||||
target_ulong addr, target_ulong len);
|
||||
#define unlock_user(s, args, len) softmmu_unlock_user(env, s, args, len)
|
||||
|
||||
ssize_t softmmu_strlen_user(CPUArchState *env, target_ulong addr);
|
||||
#define target_strlen(p) softmmu_strlen_user(env, p)
|
||||
|
||||
#endif /* SEMIHOSTING_SOFTMMU_UACCESS_H */
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Syscall implementations for semihosting.
|
||||
*
|
||||
* Copyright (c) 2022 Linaro
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef SEMIHOSTING_SYSCALLS_H
|
||||
#define SEMIHOSTING_SYSCALLS_H
|
||||
|
||||
/*
|
||||
* Argument loading from the guest is performed by the caller;
|
||||
* results are returned via the 'complete' callback.
|
||||
*
|
||||
* String operands are in address/len pairs. The len argument may be 0
|
||||
* (when the semihosting abi does not already provide the length),
|
||||
* or non-zero (where it should include the terminating zero).
|
||||
*/
|
||||
|
||||
typedef struct GuestFD GuestFD;
|
||||
|
||||
void semihost_sys_open(CPUState *cs, gdb_syscall_complete_cb complete,
|
||||
target_ulong fname, target_ulong fname_len,
|
||||
int gdb_flags, int mode);
|
||||
|
||||
void semihost_sys_close(CPUState *cs, gdb_syscall_complete_cb complete,
|
||||
int fd);
|
||||
|
||||
void semihost_sys_read(CPUState *cs, gdb_syscall_complete_cb complete,
|
||||
int fd, target_ulong buf, target_ulong len);
|
||||
|
||||
void semihost_sys_read_gf(CPUState *cs, gdb_syscall_complete_cb complete,
|
||||
GuestFD *gf, target_ulong buf, target_ulong len);
|
||||
|
||||
void semihost_sys_write(CPUState *cs, gdb_syscall_complete_cb complete,
|
||||
int fd, target_ulong buf, target_ulong len);
|
||||
|
||||
void semihost_sys_write_gf(CPUState *cs, gdb_syscall_complete_cb complete,
|
||||
GuestFD *gf, target_ulong buf, target_ulong len);
|
||||
|
||||
void semihost_sys_lseek(CPUState *cs, gdb_syscall_complete_cb complete,
|
||||
int fd, int64_t off, int gdb_whence);
|
||||
|
||||
void semihost_sys_isatty(CPUState *cs, gdb_syscall_complete_cb complete,
|
||||
int fd);
|
||||
|
||||
void semihost_sys_flen(CPUState *cs, gdb_syscall_complete_cb fstat_cb,
|
||||
gdb_syscall_complete_cb flen_cb,
|
||||
int fd, target_ulong fstat_addr);
|
||||
|
||||
void semihost_sys_fstat(CPUState *cs, gdb_syscall_complete_cb complete,
|
||||
int fd, target_ulong addr);
|
||||
|
||||
void semihost_sys_stat(CPUState *cs, gdb_syscall_complete_cb complete,
|
||||
target_ulong fname, target_ulong fname_len,
|
||||
target_ulong addr);
|
||||
|
||||
void semihost_sys_remove(CPUState *cs, gdb_syscall_complete_cb complete,
|
||||
target_ulong fname, target_ulong fname_len);
|
||||
|
||||
void semihost_sys_rename(CPUState *cs, gdb_syscall_complete_cb complete,
|
||||
target_ulong oname, target_ulong oname_len,
|
||||
target_ulong nname, target_ulong nname_len);
|
||||
|
||||
void semihost_sys_system(CPUState *cs, gdb_syscall_complete_cb complete,
|
||||
target_ulong cmd, target_ulong cmd_len);
|
||||
|
||||
void semihost_sys_gettimeofday(CPUState *cs, gdb_syscall_complete_cb complete,
|
||||
target_ulong tv_addr, target_ulong tz_addr);
|
||||
|
||||
void semihost_sys_poll_one(CPUState *cs, gdb_syscall_complete_cb complete,
|
||||
int fd, GIOCondition cond, int timeout);
|
||||
|
||||
#endif /* SEMIHOSTING_SYSCALLS_H */
|
||||
@@ -154,7 +154,7 @@ void cpu_loop(CPUARMState *env)
|
||||
force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc);
|
||||
break;
|
||||
case EXCP_SEMIHOST:
|
||||
env->xregs[0] = do_common_semihosting(cs);
|
||||
do_common_semihosting(cs);
|
||||
env->pc += 4;
|
||||
break;
|
||||
case EXCP_YIELD:
|
||||
|
||||
@@ -449,7 +449,7 @@ void cpu_loop(CPUARMState *env)
|
||||
}
|
||||
break;
|
||||
case EXCP_SEMIHOST:
|
||||
env->regs[0] = do_common_semihosting(cs);
|
||||
do_common_semihosting(cs);
|
||||
env->regs[15] += env->thumb ? 2 : 4;
|
||||
break;
|
||||
case EXCP_INTERRUPT:
|
||||
|
||||
@@ -36,11 +36,6 @@ void cpu_loop(CPUM68KState *env)
|
||||
process_queued_cpu_work(cs);
|
||||
|
||||
switch(trapnr) {
|
||||
case EXCP_HALT_INSN:
|
||||
/* Semihosing syscall. */
|
||||
env->pc += 4;
|
||||
do_m68k_semihosting(env, env->dregs[0]);
|
||||
break;
|
||||
case EXCP_ILLEGAL:
|
||||
case EXCP_LINEA:
|
||||
case EXCP_LINEF:
|
||||
|
||||
@@ -54,6 +54,10 @@
|
||||
#include "loader.h"
|
||||
#include "user-mmap.h"
|
||||
|
||||
#ifdef CONFIG_SEMIHOSTING
|
||||
#include "semihosting/semihost.h"
|
||||
#endif
|
||||
|
||||
#ifndef AT_FLAGS_PRESERVE_ARGV0
|
||||
#define AT_FLAGS_PRESERVE_ARGV0_BIT 0
|
||||
#define AT_FLAGS_PRESERVE_ARGV0 (1 << AT_FLAGS_PRESERVE_ARGV0_BIT)
|
||||
@@ -906,6 +910,11 @@ int main(int argc, char **argv, char **envp)
|
||||
}
|
||||
gdb_handlesig(cpu, 0);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SEMIHOSTING
|
||||
qemu_semihosting_guestfd_init();
|
||||
#endif
|
||||
|
||||
cpu_loop(env);
|
||||
/* never exits */
|
||||
return 0;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user