diff options
Diffstat (limited to 'bsd-user')
-rw-r--r-- | bsd-user/arm/target.h | 21 | ||||
-rw-r--r-- | bsd-user/arm/target_arch_cpu.h | 139 | ||||
-rw-r--r-- | bsd-user/arm/target_arch_thread.h | 4 | ||||
-rw-r--r-- | bsd-user/bsd-file.h | 30 | ||||
-rw-r--r-- | bsd-user/freebsd/meson.build | 1 | ||||
-rw-r--r-- | bsd-user/freebsd/os-syscall.c | 92 | ||||
-rw-r--r-- | bsd-user/i386/target.h | 21 | ||||
-rw-r--r-- | bsd-user/i386/target_arch_cpu.h | 84 | ||||
-rw-r--r-- | bsd-user/main.c | 14 | ||||
-rw-r--r-- | bsd-user/meson.build | 1 | ||||
-rw-r--r-- | bsd-user/qemu.h | 24 | ||||
-rw-r--r-- | bsd-user/syscall.c | 516 | ||||
-rw-r--r-- | bsd-user/syscall_defs.h | 47 | ||||
-rw-r--r-- | bsd-user/x86_64/target.h | 21 | ||||
-rw-r--r-- | bsd-user/x86_64/target_arch_cpu.h | 85 | ||||
-rw-r--r-- | bsd-user/x86_64/target_arch_thread.h | 4 |
16 files changed, 362 insertions, 742 deletions
diff --git a/bsd-user/arm/target.h b/bsd-user/arm/target.h new file mode 100644 index 0000000000..419c039b68 --- /dev/null +++ b/bsd-user/arm/target.h @@ -0,0 +1,21 @@ +/* + * Intel general target stuff that's common to all i386 details + * + * Copyright (c) 2022 M. Warner Losh <imp@bsdimp.com> + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef TARGET_H +#define TARGET_H + +/* + * arm EABI 'lumps' the registers for 64-bit args. + */ +static inline bool regpairs_aligned(void *cpu_env) +{ + return true; +} + +#endif /* ! TARGET_H */ + diff --git a/bsd-user/arm/target_arch_cpu.h b/bsd-user/arm/target_arch_cpu.h index b087db48fa..afb7814a8d 100644 --- a/bsd-user/arm/target_arch_cpu.h +++ b/bsd-user/arm/target_arch_cpu.h @@ -40,7 +40,6 @@ static inline void target_cpu_init(CPUARMState *env, static inline void target_cpu_loop(CPUARMState *env) { int trapnr, si_signo, si_code; - unsigned int n; CPUState *cs = env_cpu(env); for (;;) { @@ -66,82 +65,76 @@ static inline void target_cpu_loop(CPUARMState *env) break; case EXCP_SWI: { - n = env->regs[7]; - if (bsd_type == target_freebsd) { - int ret; - abi_ulong params = get_sp_from_cpustate(env); - int32_t syscall_nr = n; - int32_t arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8; + int ret; + abi_ulong params = get_sp_from_cpustate(env); + int32_t syscall_nr = env->regs[7]; + int32_t arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8; - /* See arm/arm/syscall.c cpu_fetch_syscall_args() */ - if (syscall_nr == TARGET_FREEBSD_NR_syscall) { - syscall_nr = env->regs[0]; - arg1 = env->regs[1]; - arg2 = env->regs[2]; - arg3 = env->regs[3]; - get_user_s32(arg4, params); - params += sizeof(int32_t); - get_user_s32(arg5, params); - params += sizeof(int32_t); - get_user_s32(arg6, params); - params += sizeof(int32_t); - get_user_s32(arg7, params); - arg8 = 0; - } else if (syscall_nr == TARGET_FREEBSD_NR___syscall) { - syscall_nr = env->regs[0]; - arg1 = env->regs[2]; - arg2 = env->regs[3]; - get_user_s32(arg3, params); - params += sizeof(int32_t); - get_user_s32(arg4, params); - params += sizeof(int32_t); - get_user_s32(arg5, params); - params += sizeof(int32_t); - get_user_s32(arg6, params); - arg7 = 0; - arg8 = 0; - } else { - arg1 = env->regs[0]; - arg2 = env->regs[1]; - arg3 = env->regs[2]; - arg4 = env->regs[3]; - get_user_s32(arg5, params); - params += sizeof(int32_t); - get_user_s32(arg6, params); - params += sizeof(int32_t); - get_user_s32(arg7, params); - params += sizeof(int32_t); - get_user_s32(arg8, params); - } - ret = do_freebsd_syscall(env, syscall_nr, arg1, arg2, arg3, - arg4, arg5, arg6, arg7, arg8); + /* See arm/arm/syscall.c cpu_fetch_syscall_args() */ + if (syscall_nr == TARGET_FREEBSD_NR_syscall) { + syscall_nr = env->regs[0]; + arg1 = env->regs[1]; + arg2 = env->regs[2]; + arg3 = env->regs[3]; + get_user_s32(arg4, params); + params += sizeof(int32_t); + get_user_s32(arg5, params); + params += sizeof(int32_t); + get_user_s32(arg6, params); + params += sizeof(int32_t); + get_user_s32(arg7, params); + arg8 = 0; + } else if (syscall_nr == TARGET_FREEBSD_NR___syscall) { + syscall_nr = env->regs[0]; + arg1 = env->regs[2]; + arg2 = env->regs[3]; + get_user_s32(arg3, params); + params += sizeof(int32_t); + get_user_s32(arg4, params); + params += sizeof(int32_t); + get_user_s32(arg5, params); + params += sizeof(int32_t); + get_user_s32(arg6, params); + arg7 = 0; + arg8 = 0; + } else { + arg1 = env->regs[0]; + arg2 = env->regs[1]; + arg3 = env->regs[2]; + arg4 = env->regs[3]; + get_user_s32(arg5, params); + params += sizeof(int32_t); + get_user_s32(arg6, params); + params += sizeof(int32_t); + get_user_s32(arg7, params); + params += sizeof(int32_t); + get_user_s32(arg8, params); + } + ret = do_freebsd_syscall(env, syscall_nr, arg1, arg2, arg3, + arg4, arg5, arg6, arg7, arg8); + /* + * Compare to arm/arm/vm_machdep.c + * cpu_set_syscall_retval() + */ + if (-TARGET_EJUSTRETURN == ret) { /* - * Compare to arm/arm/vm_machdep.c - * cpu_set_syscall_retval() + * Returning from a successful sigreturn syscall. + * Avoid clobbering register state. */ - if (-TARGET_EJUSTRETURN == ret) { - /* - * Returning from a successful sigreturn syscall. - * Avoid clobbering register state. - */ - break; - } - if (-TARGET_ERESTART == ret) { - env->regs[15] -= env->thumb ? 2 : 4; - break; - } - if ((unsigned int)ret >= (unsigned int)(-515)) { - ret = -ret; - cpsr_write(env, CPSR_C, CPSR_C, CPSRWriteByInstr); - env->regs[0] = ret; - } else { - cpsr_write(env, 0, CPSR_C, CPSRWriteByInstr); - env->regs[0] = ret; /* XXX need to handle lseek()? */ - /* env->regs[1] = 0; */ - } + break; + } + if (-TARGET_ERESTART == ret) { + env->regs[15] -= env->thumb ? 2 : 4; + break; + } + if ((unsigned int)ret >= (unsigned int)(-515)) { + ret = -ret; + cpsr_write(env, CPSR_C, CPSR_C, CPSRWriteByInstr); + env->regs[0] = ret; } else { - fprintf(stderr, "qemu: bsd_type (= %d) syscall " - "not supported\n", bsd_type); + cpsr_write(env, 0, CPSR_C, CPSRWriteByInstr); + env->regs[0] = ret; /* XXX need to handle lseek()? */ + /* env->regs[1] = 0; */ } } break; diff --git a/bsd-user/arm/target_arch_thread.h b/bsd-user/arm/target_arch_thread.h index 11c7f76583..fcafca2408 100644 --- a/bsd-user/arm/target_arch_thread.h +++ b/bsd-user/arm/target_arch_thread.h @@ -62,9 +62,7 @@ static inline void target_thread_init(struct target_pt_regs *regs, } regs->ARM_pc = infop->entry & 0xfffffffe; regs->ARM_sp = stack; - if (bsd_type == target_freebsd) { - regs->ARM_lr = infop->entry & 0xfffffffe; - } + regs->ARM_lr = infop->entry & 0xfffffffe; /* * FreeBSD kernel passes the ps_strings pointer in r0. This is used by some * programs to set status messages that we see in ps. bsd-user doesn't diff --git a/bsd-user/bsd-file.h b/bsd-user/bsd-file.h new file mode 100644 index 0000000000..f0c3f347ec --- /dev/null +++ b/bsd-user/bsd-file.h @@ -0,0 +1,30 @@ +/* + * file related system call shims and definitions + * + * Copyright (c) 2013 Stacey D. Son + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef BSD_FILE_H_ +#define BSD_FILE_H_ + +#include "qemu/path.h" + +extern struct iovec *lock_iovec(int type, abi_ulong target_addr, int count, + int copy); +extern void unlock_iovec(struct iovec *vec, abi_ulong target_addr, int count, + int copy); + +#endif /* !BSD_FILE_H_ */ diff --git a/bsd-user/freebsd/meson.build b/bsd-user/freebsd/meson.build index 4b69cca7b9..f87c788e84 100644 --- a/bsd-user/freebsd/meson.build +++ b/bsd-user/freebsd/meson.build @@ -1,3 +1,4 @@ bsd_user_ss.add(files( 'os-sys.c', + 'os-syscall.c', )) diff --git a/bsd-user/freebsd/os-syscall.c b/bsd-user/freebsd/os-syscall.c new file mode 100644 index 0000000000..a17ff9f6ec --- /dev/null +++ b/bsd-user/freebsd/os-syscall.c @@ -0,0 +1,92 @@ +/* + * BSD syscalls + * + * Copyright (c) 2003-2008 Fabrice Bellard + * Copyright (c) 2013-2014 Stacey D. Son + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +/* + * We need the FreeBSD "legacy" definitions. Rust needs the FreeBSD 11 system + * calls since it doesn't use libc at all, so we have to emulate that despite + * FreeBSD 11 being EOL'd. + */ +#define _WANT_FREEBSD11_STAT +#define _WANT_FREEBSD11_STATFS +#define _WANT_FREEBSD11_DIRENT +#define _WANT_KERNEL_ERRNO +#define _WANT_SEMUN +#include "qemu/osdep.h" +#include "qemu/cutils.h" +#include "qemu/path.h" +#include <sys/syscall.h> +#include <sys/param.h> +#include <sys/sysctl.h> +#include <utime.h> + +#include "qemu.h" +#include "qemu-common.h" +#include "signal-common.h" +#include "user/syscall-trace.h" + +#include "bsd-file.h" + +void target_set_brk(abi_ulong new_brk) +{ +} + +/* + * errno conversion. + */ +abi_long get_errno(abi_long ret) +{ + if (ret == -1) { + return -host_to_target_errno(errno); + } else { + return ret; + } +} + +int host_to_target_errno(int err) +{ + /* + * All the BSDs have the property that the error numbers are uniform across + * all architectures for a given BSD, though they may vary between different + * BSDs. + */ + return err; +} + +bool is_error(abi_long ret) +{ + return (abi_ulong)ret >= (abi_ulong)(-4096); +} + +/* + * do_syscall() should always have a single exit point at the end so that + * actions, such as logging of syscall results, can be performed. All errnos + * that do_syscall() returns must be -TARGET_<errcode>. + */ +abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1, + abi_long arg2, abi_long arg3, abi_long arg4, + abi_long arg5, abi_long arg6, abi_long arg7, + abi_long arg8) +{ + return 0; +} + +void syscall_init(void) +{ +} diff --git a/bsd-user/i386/target.h b/bsd-user/i386/target.h new file mode 100644 index 0000000000..9b9df047a3 --- /dev/null +++ b/bsd-user/i386/target.h @@ -0,0 +1,21 @@ +/* + * Intel general target stuff that's common to all i386 details + * + * Copyright (c) 2022 M. Warner Losh <imp@bsdimp.com> + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef TARGET_ARCH_H +#define TARGET_ARCH_H + +/* + * i386 doesn't 'lump' the registers for 64-bit args. + */ +static inline bool regpairs_aligned(void *cpu_env) +{ + return false; +} + +#endif /* ! TARGET_ARCH_H */ + diff --git a/bsd-user/i386/target_arch_cpu.h b/bsd-user/i386/target_arch_cpu.h index 3cbf69d8af..9da22202d4 100644 --- a/bsd-user/i386/target_arch_cpu.h +++ b/bsd-user/i386/target_arch_cpu.h @@ -116,55 +116,45 @@ static inline void target_cpu_loop(CPUX86State *env) process_queued_cpu_work(cs); switch (trapnr) { - case 0x80: + case 0x80: { /* syscall from int $0x80 */ - if (bsd_type == target_freebsd) { - abi_ulong params = (abi_ulong) env->regs[R_ESP] + - sizeof(int32_t); - int32_t syscall_nr = env->regs[R_EAX]; - int32_t arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8; - - if (syscall_nr == TARGET_FREEBSD_NR_syscall) { - get_user_s32(syscall_nr, params); - params += sizeof(int32_t); - } else if (syscall_nr == TARGET_FREEBSD_NR___syscall) { - get_user_s32(syscall_nr, params); - params += sizeof(int64_t); - } - get_user_s32(arg1, params); - params += sizeof(int32_t); - get_user_s32(arg2, params); - params += sizeof(int32_t); - get_user_s32(arg3, params); - params += sizeof(int32_t); - get_user_s32(arg4, params); - params += sizeof(int32_t); - get_user_s32(arg5, params); - params += sizeof(int32_t); - get_user_s32(arg6, params); - params += sizeof(int32_t); - get_user_s32(arg7, params); + abi_ulong params = (abi_ulong) env->regs[R_ESP] + + sizeof(int32_t); + int32_t syscall_nr = env->regs[R_EAX]; + int32_t arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8; + + if (syscall_nr == TARGET_FREEBSD_NR_syscall) { + get_user_s32(syscall_nr, params); params += sizeof(int32_t); - get_user_s32(arg8, params); - env->regs[R_EAX] = do_freebsd_syscall(env, - syscall_nr, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8); - } else { /* if (bsd_type == target_openbsd) */ - env->regs[R_EAX] = do_openbsd_syscall(env, - env->regs[R_EAX], - env->regs[R_EBX], - env->regs[R_ECX], - env->regs[R_EDX], - env->regs[R_ESI], - env->regs[R_EDI], - env->regs[R_EBP]); + } else if (syscall_nr == TARGET_FREEBSD_NR___syscall) { + get_user_s32(syscall_nr, params); + params += sizeof(int64_t); + } + get_user_s32(arg1, params); + params += sizeof(int32_t); + get_user_s32(arg2, params); + params += sizeof(int32_t); + get_user_s32(arg3, params); + params += sizeof(int32_t); + get_user_s32(arg4, params); + params += sizeof(int32_t); + get_user_s32(arg5, params); + params += sizeof(int32_t); + get_user_s32(arg6, params); + params += sizeof(int32_t); + get_user_s32(arg7, params); + params += sizeof(int32_t); + get_user_s32(arg8, params); + env->regs[R_EAX] = do_freebsd_syscall(env, + syscall_nr, + arg1, + arg2, + arg3, + arg4, + arg5, + arg6, + arg7, + arg8); } if (((abi_ulong)env->regs[R_EAX]) >= (abi_ulong)(-515)) { env->regs[R_EAX] = -env->regs[R_EAX]; diff --git a/bsd-user/main.c b/bsd-user/main.c index f1d58e905e..88d347d05e 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -96,7 +96,6 @@ unsigned long reserved_va; static const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX; const char *qemu_uname_release; -enum BSDType bsd_type; char qemu_proc_pathname[PATH_MAX]; /* full path to exeutable */ unsigned long target_maxtsiz = TARGET_MAXTSIZ; /* max text size */ @@ -164,7 +163,6 @@ static void usage(void) "-E var=value sets/modifies targets environment variable(s)\n" "-U var unsets targets environment variable(s)\n" "-B address set guest_base address to address\n" - "-bsd type select emulated BSD type FreeBSD/NetBSD/OpenBSD (default)\n" "\n" "Debug options:\n" "-d item1[,...] enable logging of specified items\n" @@ -285,7 +283,6 @@ int main(int argc, char **argv) const char *gdbstub = NULL; char **target_environ, **wrk; envlist_t *envlist = NULL; - bsd_type = HOST_DEFAULT_BSD_TYPE; char *argv0 = NULL; adjust_ssize(); @@ -392,17 +389,6 @@ int main(int argc, char **argv) have_guest_base = true; } else if (!strcmp(r, "drop-ld-preload")) { (void) envlist_unsetenv(envlist, "LD_PRELOAD"); - } else if (!strcmp(r, "bsd")) { - if (!strcasecmp(argv[optind], "freebsd")) { - bsd_type = target_freebsd; - } else if (!strcasecmp(argv[optind], "netbsd")) { - bsd_type = target_netbsd; - } else if (!strcasecmp(argv[optind], "openbsd")) { - bsd_type = target_openbsd; - } else { - usage(); - } - optind++; } else if (!strcmp(r, "seed")) { seed_optarg = optarg; } else if (!strcmp(r, "singlestep")) { diff --git a/bsd-user/meson.build b/bsd-user/meson.build index 8380fa44c2..5243122fc5 100644 --- a/bsd-user/meson.build +++ b/bsd-user/meson.build @@ -13,7 +13,6 @@ bsd_user_ss.add(files( 'mmap.c', 'signal.c', 'strace.c', - 'syscall.c', 'uaccess.c', )) diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h index 02921ac8b3..af272c2a80 100644 --- a/bsd-user/qemu.h +++ b/bsd-user/qemu.h @@ -29,19 +29,13 @@ extern char **environ; -enum BSDType { - target_freebsd, - target_netbsd, - target_openbsd, -}; -extern enum BSDType bsd_type; - #include "exec/user/thunk.h" #include "target_arch.h" #include "syscall_defs.h" #include "target_syscall.h" #include "target_os_vmparam.h" #include "target_os_signal.h" +#include "target.h" #include "exec/gdbstub.h" /* @@ -253,9 +247,10 @@ extern unsigned long target_dflssiz; extern unsigned long target_maxssiz; extern unsigned long target_sgrowsiz; -/* syscall.c */ +/* os-syscall.c */ abi_long get_errno(abi_long ret); bool is_error(abi_long ret); +int host_to_target_errno(int err); /* os-sys.c */ abi_long do_freebsd_sysarch(void *cpu_env, abi_long arg1, abi_long arg2); @@ -467,6 +462,19 @@ static inline void *lock_user_string(abi_ulong guest_addr) #define unlock_user_struct(host_ptr, guest_addr, copy) \ unlock_user(host_ptr, guest_addr, (copy) ? sizeof(*host_ptr) : 0) +static inline uint64_t target_arg64(uint32_t word0, uint32_t word1) +{ +#if TARGET_ABI_BITS == 32 +#ifdef TARGET_WORDS_BIGENDIAN + return ((uint64_t)word0 << 32) | word1; +#else + return ((uint64_t)word1 << 32) | word0; +#endif +#else /* TARGET_ABI_BITS != 32 */ + return word0; +#endif /* TARGET_ABI_BITS != 32 */ +} + #include <pthread.h> #include "user/safe-syscall.h" diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c deleted file mode 100644 index d3322760f4..0000000000 --- a/bsd-user/syscall.c +++ /dev/null @@ -1,516 +0,0 @@ -/* - * BSD syscalls - * - * Copyright (c) 2003 - 2008 Fabrice Bellard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. - */ -#include "qemu/osdep.h" -#include "qemu/cutils.h" -#include "qemu/path.h" -#include <sys/syscall.h> -#include <sys/param.h> -#include <sys/sysctl.h> -#include <utime.h> - -#include "qemu.h" -#include "qemu-common.h" -#include "user/syscall-trace.h" - -//#define DEBUG - -static abi_ulong target_brk; -static abi_ulong target_original_brk; - -abi_long get_errno(abi_long ret) -{ - if (ret == -1) { - /* XXX need to translate host -> target errnos here */ - return -(errno); - } - return ret; -} - -#define target_to_host_bitmask(x, tbl) (x) - -bool is_error(abi_long ret) -{ - return (abi_ulong)ret >= (abi_ulong)(-4096); -} - -void target_set_brk(abi_ulong new_brk) -{ - target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk); -} - -/* do_obreak() must return target errnos. */ -static abi_long do_obreak(abi_ulong new_brk) -{ - abi_ulong brk_page; - abi_long mapped_addr; - int new_alloc_size; - - if (!new_brk) - return 0; - if (new_brk < target_original_brk) - return -TARGET_EINVAL; - - brk_page = HOST_PAGE_ALIGN(target_brk); - - /* If the new brk is less than this, set it and we're done... */ - if (new_brk < brk_page) { - target_brk = new_brk; - return 0; - } - - /* We need to allocate more memory after the brk... */ - new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page + 1); - mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size, - PROT_READ|PROT_WRITE, - MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0)); - - if (!is_error(mapped_addr)) - target_brk = new_brk; - else - return mapped_addr; - - return 0; -} - -#ifdef __FreeBSD__ -/* - * XXX this uses the undocumented oidfmt interface to find the kind of - * a requested sysctl, see /sys/kern/kern_sysctl.c:sysctl_sysctl_oidfmt() - * (this is mostly copied from src/sbin/sysctl/sysctl.c) - */ -static int -oidfmt(int *oid, int len, char *fmt, uint32_t *kind) -{ - int qoid[CTL_MAXNAME+2]; - uint8_t buf[BUFSIZ]; - int i; - size_t j; - - qoid[0] = 0; - qoid[1] = 4; - memcpy(qoid + 2, oid, len * sizeof(int)); - - j = sizeof(buf); - i = sysctl(qoid, len + 2, buf, &j, 0, 0); - if (i) - return i; - - if (kind) - *kind = *(uint32_t *)buf; - - if (fmt) - strcpy(fmt, (char *)(buf + sizeof(uint32_t))); - return (0); -} - -/* - * try and convert sysctl return data for the target. - * XXX doesn't handle CTLTYPE_OPAQUE and CTLTYPE_STRUCT. - */ -static int sysctl_oldcvt(void *holdp, size_t holdlen, uint32_t kind) -{ - switch (kind & CTLTYPE) { - case CTLTYPE_INT: - case CTLTYPE_UINT: - *(uint32_t *)holdp = tswap32(*(uint32_t *)holdp); - break; -#ifdef TARGET_ABI32 - case CTLTYPE_LONG: - case CTLTYPE_ULONG: - *(uint32_t *)holdp = tswap32(*(long *)holdp); - break; -#else - case CTLTYPE_LONG: - *(uint64_t *)holdp = tswap64(*(long *)holdp); - break; - case CTLTYPE_ULONG: - *(uint64_t *)holdp = tswap64(*(unsigned long *)holdp); - break; -#endif -#ifdef CTLTYPE_U64 - case CTLTYPE_S64: - case CTLTYPE_U64: -#else - case CTLTYPE_QUAD: -#endif - *(uint64_t *)holdp = tswap64(*(uint64_t *)holdp); - break; - case CTLTYPE_STRING: - break; - default: - /* XXX unhandled */ - return -1; - } - return 0; -} - -/* XXX this needs to be emulated on non-FreeBSD hosts... */ -static abi_long do_freebsd_sysctl(abi_ulong namep, int32_t namelen, abi_ulong oldp, - abi_ulong oldlenp, abi_ulong newp, abi_ulong newlen) -{ - abi_long ret; - void *hnamep, *holdp, *hnewp = NULL; - size_t holdlen; - abi_ulong oldlen = 0; - int32_t *snamep = g_malloc(sizeof(int32_t) * namelen), *p, *q, i; - uint32_t kind = 0; - - if (oldlenp) - get_user_ual(oldlen, oldlenp); - if (!(hnamep = lock_user(VERIFY_READ, namep, namelen, 1))) - return -TARGET_EFAULT; - if (newp && !(hnewp = lock_user(VERIFY_READ, newp, newlen, 1))) - return -TARGET_EFAULT; - if (!(holdp = lock_user(VERIFY_WRITE, oldp, oldlen, 0))) - return -TARGET_EFAULT; - holdlen = oldlen; - for (p = hnamep, q = snamep, i = 0; i < namelen; p++, i++) - *q++ = tswap32(*p); - oidfmt(snamep, namelen, NULL, &kind); - /* XXX swap hnewp */ - ret = get_errno(sysctl(snamep, namelen, holdp, &holdlen, hnewp, newlen)); - if (!ret) - sysctl_oldcvt(holdp, holdlen, kind); - put_user_ual(holdlen, oldlenp); - unlock_user(hnamep, namep, 0); - unlock_user(holdp, oldp, holdlen); - if (hnewp) - unlock_user(hnewp, newp, 0); - g_free(snamep); - return ret; -} -#endif - -/* FIXME - * lock_iovec()/unlock_iovec() have a return code of 0 for success where - * other lock functions have a return code of 0 for failure. - */ -static abi_long lock_iovec(int type, struct iovec *vec, abi_ulong target_addr, - int count, int copy) -{ - struct target_iovec *target_vec; - abi_ulong base; - int i; - - target_vec = lock_user(VERIFY_READ, target_addr, count * sizeof(struct target_iovec), 1); - if (!target_vec) - return -TARGET_EFAULT; - for (i = 0;i < count; i++) { - base = tswapl(target_vec[i].iov_base); - vec[i].iov_len = tswapl(target_vec[i].iov_len); - if (vec[i].iov_len != 0) { - vec[i].iov_base = lock_user(type, base, vec[i].iov_len, copy); - /* Don't check lock_user return value. We must call writev even - if a element has invalid base address. */ - } else { - /* zero length pointer is ignored */ - vec[i].iov_base = NULL; - } - } - unlock_user (target_vec, target_addr, 0); - return 0; -} - -static abi_long unlock_iovec(struct iovec *vec, abi_ulong target_addr, - int count, int copy) -{ - struct target_iovec *target_vec; - abi_ulong base; - int i; - - target_vec = lock_user(VERIFY_READ, target_addr, count * sizeof(struct target_iovec), 1); - if (!target_vec) - return -TARGET_EFAULT; - for (i = 0;i < count; i++) { - if (target_vec[i].iov_base) { - base = tswapl(target_vec[i].iov_base); - unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0); - } - } - unlock_user (target_vec, target_addr, 0); - - return 0; -} - -/* do_syscall() should always have a single exit point at the end so - that actions, such as logging of syscall results, can be performed. - All errnos that do_syscall() returns must be -TARGET_<errcode>. */ -abi_long do_freebsd_syscall(void *cpu_env, int num, abi_long arg1, - abi_long arg2, abi_long arg3, abi_long arg4, - abi_long arg5, abi_long arg6, abi_long arg7, - abi_long arg8) -{ - CPUState *cpu = env_cpu(cpu_env); - abi_long ret; - void *p; - -#ifdef DEBUG - gemu_log("freebsd syscall %d\n", num); -#endif - record_syscall_start(cpu, num, arg1, arg2, arg3, arg4, arg5, arg6, 0, 0); - - if (do_strace) - print_freebsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6); - - switch (num) { - case TARGET_FREEBSD_NR_exit: -#ifdef CONFIG_GPROF - _mcleanup(); -#endif - gdb_exit(arg1); - qemu_plugin_user_exit(); - /* XXX: should free thread stack and CPU env */ - _exit(arg1); - ret = 0; /* avoid warning */ - break; - case TARGET_FREEBSD_NR_read: - if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0))) - goto efault; - ret = get_errno(read(arg1, p, arg3)); - unlock_user(p, arg2, ret); - break; - case TARGET_FREEBSD_NR_write: - if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1))) - goto efault; - ret = get_errno(write(arg1, p, arg3)); - unlock_user(p, arg2, 0); - break; - case TARGET_FREEBSD_NR_writev: - { - int count = arg3; - struct iovec *vec; - - vec = alloca(count * sizeof(struct iovec)); - if (lock_iovec(VERIFY_READ, vec, arg2, count, 1) < 0) - goto efault; - ret = get_errno(writev(arg1, vec, count)); - unlock_iovec(vec, arg2, count, 0); - } - break; - case TARGET_FREEBSD_NR_open: - if (!(p = lock_user_string(arg1))) - goto efault; - ret = get_errno(open(path(p), - target_to_host_bitmask(arg2, fcntl_flags_tbl), - arg3)); - unlock_user(p, arg1, 0); - break; - case TARGET_FREEBSD_NR_mmap: - ret = get_errno(target_mmap(arg1, arg2, arg3, - target_to_host_bitmask(arg4, mmap_flags_tbl), - arg5, - arg6)); - break; - case TARGET_FREEBSD_NR_mprotect: - ret = get_errno(target_mprotect(arg1, arg2, arg3)); - break; - case TARGET_FREEBSD_NR_break: - ret = do_obreak(arg1); - break; -#ifdef __FreeBSD__ - case TARGET_FREEBSD_NR___sysctl: - ret = do_freebsd_sysctl(arg1, arg2, arg3, arg4, arg5, arg6); - break; -#endif - case TARGET_FREEBSD_NR_sysarch: - ret = do_freebsd_sysarch(cpu_env, arg1, arg2); - break; - case TARGET_FREEBSD_NR_syscall: - case TARGET_FREEBSD_NR___syscall: - ret = do_freebsd_syscall(cpu_env,arg1 & 0xffff,arg2,arg3,arg4,arg5,arg6,arg7,arg8,0); - break; - default: - ret = get_errno(syscall(num, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)); - break; - } - fail: -#ifdef DEBUG - gemu_log(" = %ld\n", ret); -#endif - if (do_strace) - print_freebsd_syscall_ret(num, ret); - - record_syscall_return(cpu, num, ret); - return ret; - efault: - ret = -TARGET_EFAULT; - goto fail; -} - -abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long arg1, - abi_long arg2, abi_long arg3, abi_long arg4, - abi_long arg5, abi_long arg6) -{ - CPUState *cpu = env_cpu(cpu_env); - abi_long ret; - void *p; - -#ifdef DEBUG - gemu_log("netbsd syscall %d\n", num); -#endif - - record_syscall_start(cpu, num, arg1, arg2, arg3, arg4, arg5, arg6, 0, 0); - - if (do_strace) - print_netbsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6); - - switch (num) { - case TARGET_NETBSD_NR_exit: -#ifdef CONFIG_GPROF - _mcleanup(); -#endif - gdb_exit(arg1); - qemu_plugin_user_exit(); - /* XXX: should free thread stack and CPU env */ - _exit(arg1); - ret = 0; /* avoid warning */ - break; - case TARGET_NETBSD_NR_read: - if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0))) - goto efault; - ret = get_errno(read(arg1, p, arg3)); - unlock_user(p, arg2, ret); - break; - case TARGET_NETBSD_NR_write: - if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1))) - goto efault; - ret = get_errno(write(arg1, p, arg3)); - unlock_user(p, arg2, 0); - break; - case TARGET_NETBSD_NR_open: - if (!(p = lock_user_string(arg1))) - goto efault; - ret = get_errno(open(path(p), - target_to_host_bitmask(arg2, fcntl_flags_tbl), - arg3)); - unlock_user(p, arg1, 0); - break; - case TARGET_NETBSD_NR_mmap: - ret = get_errno(target_mmap(arg1, arg2, arg3, - target_to_host_bitmask(arg4, mmap_flags_tbl), - arg5, - arg6)); - break; - case TARGET_NETBSD_NR_mprotect: - ret = get_errno(target_mprotect(arg1, arg2, arg3)); - break; - case TARGET_NETBSD_NR_syscall: - case TARGET_NETBSD_NR___syscall: - ret = do_netbsd_syscall(cpu_env,arg1 & 0xffff,arg2,arg3,arg4,arg5,arg6,0); - break; - default: - ret = syscall(num, arg1, arg2, arg3, arg4, arg5, arg6); - break; - } - fail: -#ifdef DEBUG - gemu_log(" = %ld\n", ret); -#endif - if (do_strace) - print_netbsd_syscall_ret(num, ret); - - record_syscall_return(cpu, num, ret); - return ret; - efault: - ret = -TARGET_EFAULT; - goto fail; -} - -abi_long do_openbsd_syscall(void *cpu_env, int num, abi_long arg1, - abi_long arg2, abi_long arg3, abi_long arg4, - abi_long arg5, abi_long arg6) -{ - CPUState *cpu = env_cpu(cpu_env); - abi_long ret; - void *p; - -#ifdef DEBUG - gemu_log("openbsd syscall %d\n", num); -#endif - - record_syscall_start(cpu, num, arg1, arg2, arg3, arg4, arg5, arg6, 0, 0); - - if (do_strace) - print_openbsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6); - - switch (num) { - case TARGET_OPENBSD_NR_exit: -#ifdef CONFIG_GPROF - _mcleanup(); -#endif - gdb_exit(arg1); - qemu_plugin_user_exit(); - /* XXX: should free thread stack and CPU env */ - _exit(arg1); - ret = 0; /* avoid warning */ - break; - case TARGET_OPENBSD_NR_read: - if (!(p = lock_user(VERIFY_WRITE, arg2, arg3, 0))) - goto efault; - ret = get_errno(read(arg1, p, arg3)); - unlock_user(p, arg2, ret); - break; - case TARGET_OPENBSD_NR_write: - if (!(p = lock_user(VERIFY_READ, arg2, arg3, 1))) - goto efault; - ret = get_errno(write(arg1, p, arg3)); - unlock_user(p, arg2, 0); - break; - case TARGET_OPENBSD_NR_open: - if (!(p = lock_user_string(arg1))) - goto efault; - ret = get_errno(open(path(p), - target_to_host_bitmask(arg2, fcntl_flags_tbl), - arg3)); - unlock_user(p, arg1, 0); - break; - case TARGET_OPENBSD_NR_mmap: - ret = get_errno(target_mmap(arg1, arg2, arg3, - target_to_host_bitmask(arg4, mmap_flags_tbl), - arg5, - arg6)); - break; - case TARGET_OPENBSD_NR_mprotect: - ret = get_errno(target_mprotect(arg1, arg2, arg3)); - break; - case TARGET_OPENBSD_NR_syscall: - case TARGET_OPENBSD_NR___syscall: - ret = do_openbsd_syscall(cpu_env,arg1 & 0xffff,arg2,arg3,arg4,arg5,arg6,0); - break; - default: - ret = syscall(num, arg1, arg2, arg3, arg4, arg5, arg6); - break; - } - fail: -#ifdef DEBUG - gemu_log(" = %ld\n", ret); -#endif - if (do_strace) - print_openbsd_syscall_ret(num, ret); - - record_syscall_return(cpu, num, ret); - return ret; - efault: - ret = -TARGET_EFAULT; - goto fail; -} - -void syscall_init(void) -{ -} diff --git a/bsd-user/syscall_defs.h b/bsd-user/syscall_defs.h index 62b472b990..c3bf14f38f 100644 --- a/bsd-user/syscall_defs.h +++ b/bsd-user/syscall_defs.h @@ -179,4 +179,51 @@ struct target_freebsd__wrusage { struct target_freebsd_rusage wru_children; }; +#define safe_syscall0(type, name) \ +type safe_##name(void) \ +{ \ + return safe_syscall(SYS_##name); \ +} + +#define safe_syscall1(type, name, type1, arg1) \ +type safe_##name(type1 arg1) \ +{ \ + return safe_syscall(SYS_##name, arg1); \ +} + +#define safe_syscall2(type, name, type1, arg1, type2, arg2) \ +type safe_##name(type1 arg1, type2 arg2) \ +{ \ + return safe_syscall(SYS_##name, arg1, arg2); \ +} + +#define safe_syscall3(type, name, type1, arg1, type2, arg2, type3, arg3) \ +type safe_##name(type1 arg1, type2 arg2, type3 arg3) \ +{ \ + return safe_syscall(SYS_##name, arg1, arg2, arg3); \ +} + +#define safe_syscall4(type, name, type1, arg1, type2, arg2, type3, arg3, \ + type4, arg4) \ +type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) \ +{ \ + return safe_syscall(SYS_##name, arg1, arg2, arg3, arg4); \ +} + +#define safe_syscall5(type, name, type1, arg1, type2, arg2, type3, arg3, \ + type4, arg4, type5, arg5) \ +type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ + type5 arg5) \ +{ \ + return safe_syscall(SYS_##name, arg1, arg2, arg3, arg4, arg5); \ +} + +#define safe_syscall6(type, name, type1, arg1, type2, arg2, type3, arg3, \ + type4, arg4, type5, arg5, type6, arg6) \ +type safe_##name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ + type5 arg5, type6 arg6) \ +{ \ + return safe_syscall(SYS_##name, arg1, arg2, arg3, arg4, arg5, arg6); \ +} + #endif /* ! _SYSCALL_DEFS_H_ */ diff --git a/bsd-user/x86_64/target.h b/bsd-user/x86_64/target.h new file mode 100644 index 0000000000..8956631db1 --- /dev/null +++ b/bsd-user/x86_64/target.h @@ -0,0 +1,21 @@ +/* + * Intel general target stuff that's common to all x86_64 details + * + * Copyright (c) 2022 M. Warner Losh <imp@bsdimp.com> + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef TARGET_H +#define TARGET_H + +/* + * x86 doesn't 'lump' the registers for 64-bit args, all args are 64 bits. + */ +static inline bool regpairs_aligned(void *cpu_env) +{ + return false; +} + +#endif /* ! TARGET_H */ + diff --git a/bsd-user/x86_64/target_arch_cpu.h b/bsd-user/x86_64/target_arch_cpu.h index 0a9c0f0894..5be2f02416 100644 --- a/bsd-user/x86_64/target_arch_cpu.h +++ b/bsd-user/x86_64/target_arch_cpu.h @@ -124,85 +124,16 @@ static inline void target_cpu_loop(CPUX86State *env) process_queued_cpu_work(cs); switch (trapnr) { - case 0x80: - /* syscall from int $0x80 */ - if (bsd_type == target_freebsd) { - abi_ulong params = (abi_ulong) env->regs[R_ESP] + - sizeof(int32_t); - int32_t syscall_nr = env->regs[R_EAX]; - int32_t arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8; - - if (syscall_nr == TARGET_FREEBSD_NR_syscall) { - get_user_s32(syscall_nr, params); - params += sizeof(int32_t); - } else if (syscall_nr == TARGET_FREEBSD_NR___syscall) { - get_user_s32(syscall_nr, params); - params += sizeof(int64_t); - } - get_user_s32(arg1, params); - params += sizeof(int32_t); - get_user_s32(arg2, params); - params += sizeof(int32_t); - get_user_s32(arg3, params); - params += sizeof(int32_t); - get_user_s32(arg4, params); - params += sizeof(int32_t); - get_user_s32(arg5, params); - params += sizeof(int32_t); - get_user_s32(arg6, params); - params += sizeof(int32_t); - get_user_s32(arg7, params); - params += sizeof(int32_t); - get_user_s32(arg8, params); - env->regs[R_EAX] = do_freebsd_syscall(env, - syscall_nr, - arg1, - arg2, - arg3, - arg4, - arg5, - arg6, - arg7, - arg8); - } else { /* if (bsd_type == target_openbsd) */ - env->regs[R_EAX] = do_openbsd_syscall(env, - env->regs[R_EAX], - env->regs[R_EBX], - env->regs[R_ECX], - env->regs[R_EDX], - env->regs[R_ESI], - env->regs[R_EDI], - env->regs[R_EBP]); - } - if (((abi_ulong)env->regs[R_EAX]) >= (abi_ulong)(-515)) { - env->regs[R_EAX] = -env->regs[R_EAX]; - env->eflags |= CC_C; - } else { - env->eflags &= ~CC_C; - } - break; - case EXCP_SYSCALL: /* syscall from syscall instruction */ - if (bsd_type == target_freebsd) { - env->regs[R_EAX] = do_freebsd_syscall(env, - env->regs[R_EAX], - env->regs[R_EDI], - env->regs[R_ESI], - env->regs[R_EDX], - env->regs[R_ECX], - env->regs[8], - env->regs[9], 0, 0); - } else { /* if (bsd_type == target_openbsd) */ - env->regs[R_EAX] = do_openbsd_syscall(env, - env->regs[R_EAX], - env->regs[R_EDI], - env->regs[R_ESI], - env->regs[R_EDX], - env->regs[10], - env->regs[8], - env->regs[9]); - } + env->regs[R_EAX] = do_freebsd_syscall(env, + env->regs[R_EAX], + env->regs[R_EDI], + env->regs[R_ESI], + env->regs[R_EDX], + env->regs[R_ECX], + env->regs[8], + env->regs[9], 0, 0); env->eip = env->exception_next_eip; if (((abi_ulong)env->regs[R_EAX]) >= (abi_ulong)(-515)) { env->regs[R_EAX] = -env->regs[R_EAX]; diff --git a/bsd-user/x86_64/target_arch_thread.h b/bsd-user/x86_64/target_arch_thread.h index d105e43fd3..b745d7ffeb 100644 --- a/bsd-user/x86_64/target_arch_thread.h +++ b/bsd-user/x86_64/target_arch_thread.h @@ -32,9 +32,7 @@ static inline void target_thread_init(struct target_pt_regs *regs, regs->rax = 0; regs->rsp = infop->start_stack; regs->rip = infop->entry; - if (bsd_type == target_freebsd) { - regs->rdi = infop->start_stack; - } + regs->rdi = infop->start_stack; } #endif /* !_TARGET_ARCH_THREAD_H_ */ |